UNPKG

@zaplify/gcp-pubsub

Version:

Cloud Pub/Sub Client Library for Node.js

876 lines 32.6 kB
"use strict"; /*! * Copyright 2014 Google Inc. All Rights Reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.PubSub = void 0; const paginator_1 = require("@google-cloud/paginator"); const projectify_1 = require("@google-cloud/projectify"); const extend = require("extend"); const google_auth_library_1 = require("google-auth-library"); const gax = require("google-gax"); // eslint-disable-next-line @typescript-eslint/no-var-requires const PKG = require('../../package.json'); // eslint-disable-next-line @typescript-eslint/no-var-requires const v1 = require('./v1'); const util_1 = require("./util"); const schema_1 = require("./schema"); const snapshot_1 = require("./snapshot"); const subscription_1 = require("./subscription"); const topic_1 = require("./topic"); /** * Project ID placeholder. * @type {string} * @private */ const PROJECT_ID_PLACEHOLDER = '{{projectId}}'; /** * @typedef {object} ClientConfig * @property {string} [projectId] The project ID from the Google Developer's * Console, e.g. 'grape-spaceship-123'. We will also check the environment * variable `GCLOUD_PROJECT` for your project ID. If your app is running in * an environment which supports {@link * https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application * Application Default Credentials}, your project ID will be detected * automatically. * @property {string} [keyFilename] Full path to the a .json, .pem, or .p12 key * downloaded from the Google Developers Console. If you provide a path to a * JSON file, the `projectId` option above is not necessary. NOTE: .pem and * .p12 require you to specify the `email` option as well. * @property {string} [apiEndpoint] The `apiEndpoint` from options will set the * host. If not set, the `PUBSUB_EMULATOR_HOST` environment variable from the * gcloud SDK is honored. We also check the `CLOUD_API_ENDPOINT_OVERRIDES_PUBSUB` * environment variable used by `gcloud alpha pubsub`. Otherwise the actual API * endpoint will be used. Note that if the URL doesn't end in '.googleapis.com', * we will assume that it's an emulator and disable strict SSL checks. * @property {string} [email] Account email address. Required when using a .pem * or .p12 keyFilename. * @property {object} [credentials] Credentials object. * @property {string} [credentials.client_email] * @property {string} [credentials.private_key] * @property {boolean} [autoRetry=true] Automatically retry requests if the * response is related to rate limits or certain intermittent server errors. * We will exponentially backoff subsequent requests by default. * @property {Constructor} [promise] Custom promise module to use instead of * native Promises. */ /** * [Cloud Pub/Sub](https://developers.google.com/pubsub/overview) is a * reliable, many-to-many, asynchronous messaging service from Cloud * Platform. * * @class * * @see [Cloud Pub/Sub overview]{@link https://developers.google.com/pubsub/overview} * * @param {ClientConfig} [options] Configuration options. * * @example Import the client library * ``` * const {PubSub} = require('@google-cloud/pubsub'); * * ``` * @example Create a client that uses <a href="https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application">Application Default Credentials (ADC)</a>: * ``` * const pubsub = new PubSub(); * * ``` * @example Create a client with <a href="https://cloud.google.com/docs/authentication/production#obtaining_and_providing_service_account_credentials_manually">explicit credentials</a>: * ``` * const pubsub = new PubSub({ * projectId: 'your-project-id', * keyFilename: '/path/to/keyfile.json' * }); * * ``` * @example <caption>include:samples/quickstart.js</caption> * region_tag:pubsub_quickstart_create_topic * Full quickstart example: */ class PubSub { constructor(options) { this.getSubscriptionsStream = paginator_1.paginator.streamify('getSubscriptions'); this.getSnapshotsStream = paginator_1.paginator.streamify('getSnapshots'); this.getTopicsStream = paginator_1.paginator.streamify('getTopics'); this.isOpen = true; options = Object.assign({}, options || {}); // Needed for potentially large responses that may come from using exactly-once delivery. // This will get passed down to grpc client objects. const maxMetadataSize = 'grpc.max_metadata_size'; // eslint-disable-next-line @typescript-eslint/no-explicit-any const optionsAny = options; if (optionsAny[maxMetadataSize] === undefined) { optionsAny[maxMetadataSize] = 4 * 1024 * 1024; // 4 MiB } // Determine what scopes are needed. // It is the union of the scopes on both clients. const clientClasses = [v1.SubscriberClient, v1.PublisherClient]; const allScopes = {}; for (const clientClass of clientClasses) { for (const scope of clientClass.scopes) { allScopes[scope] = true; } } this.options = Object.assign({ libName: 'gccl', libVersion: PKG.version, scopes: Object.keys(allScopes), }, options); /** * @name PubSub#isEmulator * @type {boolean} */ this.isEmulator = false; this.determineBaseUrl_(); this.api = {}; this.auth = new google_auth_library_1.GoogleAuth(this.options); this.projectId = this.options.projectId || PROJECT_ID_PLACEHOLDER; if (this.projectId !== PROJECT_ID_PLACEHOLDER) { this.name = PubSub.formatName_(this.projectId); } } /** * Returns true if we have actually resolved the full project name. * * @returns {boolean} true if the name is resolved. */ get isIdResolved() { return this.projectId.indexOf(PROJECT_ID_PLACEHOLDER) < 0; } close(callback) { const definedCallback = callback || (() => { }); if (this.isOpen) { this.isOpen = false; this.closeAllClients_() .then(() => { var _a; return (_a = this.schemaClient) === null || _a === void 0 ? void 0 : _a.close(); }) .then(() => { definedCallback(null); }) .catch(definedCallback); } else { definedCallback(null); } } /** * Create a schema in the project. * * @see [Schemas: create API Documentation]{@link https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.schemas/create} * @see {@link Schema#create} * * @throws {Error} If a schema ID or name is not provided. * @throws {Error} If an invalid SchemaType is provided. * @throws {Error} If an invalid schema definition is provided. * * @param {string} schemaId The name or ID of the subscription. * @param {SchemaType} type The type of the schema (Protobuf, Avro, etc). * @param {string} definition The text describing the schema in terms of the type. * @param {object} [options] Request configuration options, outlined * here: https://googleapis.github.io/gax-nodejs/interfaces/CallOptions.html. * @returns {Promise<Schema>} * * @example Create a schema. * ``` * const {PubSub} = require('@google-cloud/pubsub'); * const pubsub = new PubSub(); * * await pubsub.createSchema( * 'messageType', * SchemaTypes.Avro, * '{...avro definition...}' * ); * ``` */ async createSchema(schemaId, type, definition, gaxOpts) { // This populates projectId for us. await this.getClientConfig(); const schemaName = schema_1.Schema.formatName_(this.projectId, schemaId); const request = { parent: this.name, schemaId, schema: { name: schemaName, type, definition, }, }; const client = await this.getSchemaClient_(); await client.createSchema(request, gaxOpts); return new schema_1.Schema(this, schemaName); } createSubscription(topic, name, optionsOrCallback, callback) { if (typeof topic !== 'string' && !(topic instanceof topic_1.Topic)) { throw new Error('A Topic is required for a new subscription.'); } if (typeof name !== 'string') { throw new Error('A subscription name is required.'); } if (typeof topic === 'string') { topic = this.topic(topic); } let options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {}; callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : callback; // Make a deep copy of options to not pollute caller object. options = extend(true, {}, options); const gaxOpts = options.gaxOpts; const flowControl = options.flowControl; delete options.gaxOpts; delete options.flowControl; const metadata = subscription_1.Subscription.formatMetadata_(options); let subscriptionCtorOptions = flowControl ? { flowControl } : {}; subscriptionCtorOptions = Object.assign(subscriptionCtorOptions, metadata); const subscription = this.subscription(name, subscriptionCtorOptions); const reqOpts = Object.assign(metadata, { topic: topic.name, name: subscription.name, }); this.request({ client: 'SubscriberClient', method: 'createSubscription', reqOpts, gaxOpts, }, (err, resp) => { if (err) { callback(err, null, resp); return; } subscription.metadata = resp; callback(null, subscription, resp); }); } createTopic(name, optsOrCallback, callback) { const reqOpts = typeof name === 'string' ? { name, } : name; // We don't allow a blank name, but this will let topic() handle that case. const topic = this.topic(reqOpts.name || ''); // Topic#constructor might have canonicalized the name. reqOpts.name = topic.name; const gaxOpts = typeof optsOrCallback === 'object' ? optsOrCallback : {}; callback = typeof optsOrCallback === 'function' ? optsOrCallback : callback; this.request({ client: 'PublisherClient', method: 'createTopic', reqOpts, gaxOpts, }, (err, resp) => { if (err) { callback(err, null, resp); return; } topic.metadata = resp; callback(null, topic, resp); }); } detachSubscription(name, optsOrCallback, callback) { if (typeof name !== 'string') { throw new Error('A subscription name is required.'); } const sub = this.subscription(name); const reqOpts = { subscription: sub.name, }; const gaxOpts = typeof optsOrCallback === 'object' ? optsOrCallback : {}; callback = typeof optsOrCallback === 'function' ? optsOrCallback : callback; this.request({ client: 'PublisherClient', method: 'detachSubscription', reqOpts, gaxOpts: gaxOpts, }, callback); } /** * Determine the appropriate endpoint to use for API requests, first trying * the `apiEndpoint` parameter. If that isn't set, we try the Pub/Sub emulator * environment variable (PUBSUB_EMULATOR_HOST). If that is also null, we try * the standard `gcloud alpha pubsub` environment variable * (CLOUDSDK_API_ENDPOINT_OVERRIDES_PUBSUB). Otherwise the default production * API is used. * * Note that if the URL doesn't end in '.googleapis.com', we will assume that * it's an emulator and disable strict SSL checks. * * @private */ determineBaseUrl_() { // We allow an override from the client object options, or from // one of these variables. The CLOUDSDK variable is provided for // compatibility with the `gcloud alpha` utility. const gcloudVarName = 'CLOUDSDK_API_ENDPOINT_OVERRIDES_PUBSUB'; const emulatorVarName = 'PUBSUB_EMULATOR_HOST'; const apiEndpoint = this.options.apiEndpoint || process.env[emulatorVarName] || process.env[gcloudVarName]; if (!apiEndpoint) { return; } // Parse the URL into a hostname and port, if possible. const leadingProtocol = new RegExp('^https?://'); const trailingSlashes = new RegExp('/*$'); const baseUrlParts = apiEndpoint .replace(leadingProtocol, '') .replace(trailingSlashes, '') .split(':'); this.options.servicePath = baseUrlParts[0]; if (!baseUrlParts[1]) { // No port was given -- figure it out from the protocol. if (apiEndpoint.startsWith('https')) { this.options.port = 443; } else if (apiEndpoint.startsWith('http')) { this.options.port = 80; } else { this.options.port = undefined; } } else { this.options.port = parseInt(baseUrlParts[1], 10); } // If this looks like a GCP URL of some kind, don't go into emulator // mode. Otherwise, supply a fake SSL provider so a real cert isn't // required for running the emulator. const officialUrlMatch = this.options.servicePath.endsWith('.googleapis.com'); if (!officialUrlMatch) { const grpcInstance = this.options.grpc || gax.grpc; this.options.sslCreds = grpcInstance.credentials.createInsecure(); this.isEmulator = true; } if (!this.options.projectId && process.env.PUBSUB_PROJECT_ID) { this.options.projectId = process.env.PUBSUB_PROJECT_ID; } } /** * Get a list of schemas associated with your project. * * The returned AsyncIterable will resolve to {@link google.pubsub.v1.ISchema} objects. * * This method returns an async iterable. These objects can be adapted * to work in a Promise/then framework, as well as with callbacks, but * this discussion is considered out of scope for these docs. * * @see [Schemas: list API Documentation]{@link https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.schemas/list} * @see [More about async iterators]{@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of} * * @param {google.pubsub.v1.SchemaView} [view] The type of schema objects * requested, which should be an enum value from {@link SchemaViews}. Defaults * to Full. * @param {object} [options] Request configuration options, outlined * here: https://googleapis.github.io/gax-nodejs/interfaces/CallOptions.html. * @returns {AsyncIterable<ISchema>} * * @example * ``` * for await (const s of pubsub.listSchemas()) { * const moreInfo = await s.get(); * } * ``` */ async *listSchemas(view = schema_1.SchemaViews.Basic, options) { const client = await this.getSchemaClient_(); const query = { parent: this.name, view, }; for await (const s of client.listSchemasAsync(query, options)) { yield s; } } getSnapshots(optsOrCallback, callback) { const options = typeof optsOrCallback === 'object' ? optsOrCallback : {}; callback = typeof optsOrCallback === 'function' ? optsOrCallback : callback; const reqOpts = Object.assign({ project: PubSub.formatName_(this.projectId), }, options); delete reqOpts.gaxOpts; delete reqOpts.autoPaginate; const gaxOpts = Object.assign({ autoPaginate: options.autoPaginate, }, options.gaxOpts); this.request({ client: 'SubscriberClient', method: 'listSnapshots', reqOpts, gaxOpts, }, (err, rawSnapshots, ...args) => { let snapshots; if (rawSnapshots) { snapshots = rawSnapshots.map((snapshot) => { const snapshotInstance = this.snapshot(snapshot.name); snapshotInstance.metadata = snapshot; return snapshotInstance; }); } callback(err, snapshots, ...args); }); } getSubscriptions(optsOrCallback, callback) { const options = typeof optsOrCallback === 'object' ? optsOrCallback : {}; callback = typeof optsOrCallback === 'function' ? optsOrCallback : callback; let topic = options.topic; if (topic) { if (!(topic instanceof topic_1.Topic)) { topic = this.topic(topic); } return topic.getSubscriptions(options, callback); } const reqOpts = Object.assign({}, options); reqOpts.project = 'projects/' + this.projectId; delete reqOpts.gaxOpts; delete reqOpts.autoPaginate; const gaxOpts = Object.assign({ autoPaginate: options.autoPaginate, }, options.gaxOpts); this.request({ client: 'SubscriberClient', method: 'listSubscriptions', reqOpts, gaxOpts, }, (err, rawSubs, ...args) => { let subscriptions; if (rawSubs) { subscriptions = rawSubs.map((sub) => { const subscriptionInstance = this.subscription(sub.name); subscriptionInstance.metadata = sub; return subscriptionInstance; }); } callback(err, subscriptions, ...args); }); } getTopics(optsOrCallback, callback) { const options = typeof optsOrCallback === 'object' ? optsOrCallback : {}; callback = typeof optsOrCallback === 'function' ? optsOrCallback : callback; const reqOpts = Object.assign({ project: 'projects/' + this.projectId, }, options); delete reqOpts.gaxOpts; delete reqOpts.autoPaginate; const gaxOpts = Object.assign({ autoPaginate: options.autoPaginate, }, options.gaxOpts); this.request({ client: 'PublisherClient', method: 'listTopics', reqOpts, gaxOpts, }, (err, rawTopics, ...args) => { let topics; if (rawTopics) { topics = rawTopics.map(topic => { const topicInstance = this.topic(topic.name); topicInstance.metadata = topic; return topicInstance; }); } callback(err, topics, ...args); }); } /** * Retrieve a client configuration, suitable for passing into a GAPIC * 'v1' class constructor. This will fill out projectId, emulator URLs, * and so forth. * * @returns {Promise<ClientConfig>} the filled client configuration. */ async getClientConfig() { if (!this.projectId || this.projectId === PROJECT_ID_PLACEHOLDER) { let projectId; try { projectId = await this.auth.getProjectId(); } catch (e) { if (!this.isEmulator) { throw e; } projectId = ''; } this.projectId = projectId; this.name = PubSub.formatName_(this.projectId); this.options.projectId = projectId; } return this.options; } /** * Gets a schema client, creating one if needed. * @private */ async getSchemaClient_() { if (!this.schemaClient) { const options = await this.getClientConfig(); this.schemaClient = new v1.SchemaServiceClient(options); } return this.schemaClient; } /** * Callback function to PubSub.getClient_(). * @private * @callback GetClientCallback * @param err - Error, if any. * @param gaxClient - The gax client specified in RequestConfig.client. * Typed any since it's importing Javascript source. */ /** * Get the PubSub client object. * * @private * * @param {object} config Configuration object. * @param {object} config.gaxOpts GAX options. * @param {function} config.method The gax method to call. * @param {object} config.reqOpts Request options. * @param {function} [callback] The callback function. */ getClient_(config, callback) { this.getClientAsync_(config).then(client => callback(null, client), callback); } /** * Get the PubSub client object. * * @private * * @param {object} config Configuration object. * @param {object} config.gaxOpts GAX options. * @param {function} config.method The gax method to call. * @param {object} config.reqOpts Request options. * @returns {Promise} */ async getClientAsync_(config) { // Make sure we've got a fully created config with projectId and such. const options = await this.getClientConfig(); let gaxClient = this.api[config.client]; if (!gaxClient) { // Lazily instantiate client. gaxClient = new v1[config.client](options); this.api[config.client] = gaxClient; } return gaxClient; } /** * Close all open client objects. * * @private * * @returns {Promise} */ async closeAllClients_() { const promises = []; for (const clientConfig of Object.keys(this.api)) { const gaxClient = this.api[clientConfig]; promises.push(gaxClient.close()); delete this.api[clientConfig]; } await Promise.all(promises); } /** * Funnel all API requests through this method, to be sure we have a project * ID. * * @private * * @param {object} config Configuration object. * @param {object} config.gaxOpts GAX options. * @param {function} config.method The gax method to call. * @param {object} config.reqOpts Request options. * @param {function} [callback] The callback function. */ request(config, callback) { // This prevents further requests, in case any publishers were hanging around. if (!this.isOpen) { const statusObject = { code: 0, details: 'Cannot use a closed PubSub object.', metadata: null, }; const err = new Error(statusObject.details); Object.assign(err, statusObject); callback(err); return; } this.getClient_(config, (err, client) => { if (err) { callback(err); return; } let reqOpts = extend(true, {}, config.reqOpts); reqOpts = (0, projectify_1.replaceProjectIdToken)(reqOpts, this.projectId); client[config.method](reqOpts, config.gaxOpts, callback); }); } /** * Create a Schema object, representing a schema within the project. * See {@link PubSub#createSchema} or {@link Schema#create} to create a schema. * * @throws {Error} If a name is not provided. * * @param {string} name The ID or name of the schema. * @returns {Schema} A {@link Schema} instance. * * @example * ``` * const {PubSub} = require('@google-cloud/pubsub'); * const pubsub = new PubSub(); * * const schema = pubsub.schema('my-schema'); * ``` */ schema(idOrName) { return new schema_1.Schema(this, idOrName); } /** * Create a Snapshot object. See {@link Subscription#createSnapshot} to * create a snapshot. * * @throws {Error} If a name is not provided. * * @param {string} name The name of the snapshot. * @returns {Snapshot} A {@link Snapshot} instance. * * @example * ``` * const {PubSub} = require('@google-cloud/pubsub'); * const pubsub = new PubSub(); * * const snapshot = pubsub.snapshot('my-snapshot'); * ``` */ snapshot(name) { if (typeof name !== 'string') { throw new Error('You must supply a valid name for the snapshot.'); } return new snapshot_1.Snapshot(this, name); } /** * Create a Subscription object. This command by itself will not run any API * requests. You will receive a {@link Subscription} object, * which will allow you to interact with a subscription. * * @throws {Error} If subscription name is omitted. * * @param {string} name Name of the subscription. * @param {SubscriberOptions} [options] Configuration object. * @returns {Subscription} A {@link Subscription} instance. * * @example * ``` * const {PubSub} = require('@google-cloud/pubsub'); * const pubsub = new PubSub(); * * const subscription = pubsub.subscription('my-subscription'); * * // Register a listener for `message` events. * subscription.on('message', function(message) { * // Called every time a message is received. * // message.id = ID of the message. * // message.ackId = ID used to acknowledge the message receival. * // message.data = Contents of the message. * // message.attributes = Attributes of the message. * // message.publishTime = Date when Pub/Sub received the message. * }); * ``` */ subscription(name, options) { if (!name) { throw new Error('A name must be specified for a subscription.'); } return new subscription_1.Subscription(this, name, options); } /** * Create a Topic object. See {@link PubSub#createTopic} to create a topic. * * @throws {Error} If a name is not provided. * * @param {string} name The name of the topic. * @param {PublishOptions} [options] Publisher configuration object. * @returns {Topic} A {@link Topic} instance. * * @example * ``` * const {PubSub} = require('@google-cloud/pubsub'); * const pubsub = new PubSub(); * * const topic = pubsub.topic('my-topic'); * ``` */ topic(name, options) { if (!name) { throw new Error('A name must be specified for a topic.'); } return new topic_1.Topic(this, name, options); } /** * Validate a schema definition. * * @see [Schemas: validateSchema API Documentation]{@link https://cloud.google.com/pubsub/docs/reference/rest/v1/projects.schemas/validate} * * @throws {Error} if the validation fails. * * @param {ISchema} schema The schema definition you wish to validate. * @param {object} [options] Request configuration options, outlined * here: https://googleapis.github.io/gax-nodejs/interfaces/CallOptions.html. * @returns {Promise<void>} */ async validateSchema(schema, gaxOpts) { const client = await this.getSchemaClient_(); await client.validateSchema({ parent: this.name, schema, }, gaxOpts); } /*! * Format the name of a project. A project's full name is in the * format of projects/{projectId}. * * The GAPIC client should do this for us, but since we maintain * names rather than IDs, this is simpler. * * @private */ static formatName_(name) { if (typeof name !== 'string') { throw new Error('A name is required to identify a project.'); } // Simple check if the name is already formatted. if (name.indexOf('/') > -1) { return name; } return `projects/${name}`; } } exports.PubSub = PubSub; /** * Get a list of the {@link Snapshot} objects as a readable object stream. * * @method PubSub#getSnapshotsStream * @param {GetSnapshotsRequest} [options] Configuration object. See * {@link PubSub#getSnapshots} for a complete list of options. * @returns {ReadableStream} A readable stream of {@link Snapshot} instances. * * @example * ``` * const {PubSub} = require('@google-cloud/pubsub'); * const pubsub = new PubSub(); * * pubsub.getSnapshotsStream() * .on('error', console.error) * .on('data', function(snapshot) { * // snapshot is a Snapshot object. * }) * .on('end', function() { * // All snapshots retrieved. * }); * * //- * // If you anticipate many results, you can end a stream early to prevent * // unnecessary processing and API requests. * //- * pubsub.getSnapshotsStream() * .on('data', function(snapshot) { * this.end(); * }); * ``` */ /** * Get a list of the {@link Subscription} objects registered to all of * your project's topics as a readable object stream. * * @method PubSub#getSubscriptionsStream * @param {GetSubscriptionsRequest} [options] Configuration object. See * {@link PubSub#getSubscriptions} for a complete list of options. * @returns {ReadableStream} A readable stream of {@link Subscription} instances. * * @example * ``` * const {PubSub} = require('@google-cloud/pubsub'); * const pubsub = new PubSub(); * * pubsub.getSubscriptionsStream() * .on('error', console.error) * .on('data', function(subscription) { * // subscription is a Subscription object. * }) * .on('end', function() { * // All subscriptions retrieved. * }); * * //- * // If you anticipate many results, you can end a stream early to prevent * // unnecessary processing and API requests. * //- * pubsub.getSubscriptionsStream() * .on('data', function(subscription) { * this.end(); * }); * ``` */ /** * Get a list of the {module:pubsub/topic} objects registered to your project as * a readable object stream. * * @method PubSub#getTopicsStream * @param {GetTopicsRequest} [options] Configuration object. See * {@link PubSub#getTopics} for a complete list of options. * @returns {ReadableStream} A readable stream of {@link Topic} instances. * * @example * ``` * const {PubSub} = require('@google-cloud/pubsub'); * const pubsub = new PubSub(); * * pubsub.getTopicsStream() * .on('error', console.error) * .on('data', function(topic) { * // topic is a Topic object. * }) * .on('end', function() { * // All topics retrieved. * }); * * //- * // If you anticipate many results, you can end a stream early to prevent * // unnecessary processing and API requests. * //- * pubsub.getTopicsStream() * .on('data', function(topic) { * this.end(); * }); * ``` */ /*! Developer Documentation * * These methods can be auto-paginated. */ paginator_1.paginator.extend(PubSub, ['getSnapshots', 'getSubscriptions', 'getTopics']); /*! Developer Documentation * * Existing async methods (except for streams) will return a Promise in the event * that a callback is omitted. Future methods will not allow for a callback. * (Use .then() on the returned Promise instead.) */ (0, util_1.promisifySome)(PubSub, PubSub.prototype, [ 'close', 'createSubscription', 'createTopic', 'detachSubscription', 'getSnapshots', 'getSubscriptions', 'getTopics', ]); //# sourceMappingURL=pubsub.js.map