}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('albums');
+ *
+ * bucket.getFiles(function(err, files) {
+ * if (!err) {
+ * // files is an array of File objects.
+ * }
+ * });
+ *
+ * //-
+ * // If your bucket has versioning enabled, you can get all of your files
+ * // scoped to their generation.
+ * //-
+ * bucket.getFiles({
+ * versions: true
+ * }, function(err, files) {
+ * // Each file is scoped to its generation.
+ * });
+ *
+ * //-
+ * // To control how many API requests are made and page through the results
+ * // manually, set `autoPaginate` to `false`.
+ * //-
+ * const callback = function(err, files, nextQuery, apiResponse) {
+ * if (nextQuery) {
+ * // More results exist.
+ * bucket.getFiles(nextQuery, callback);
+ * }
+ *
+ * // The `metadata` property is populated for you with the metadata at the
+ * // time of fetching.
+ * files[0].metadata;
+ *
+ * // However, in cases where you are concerned the metadata could have
+ * // changed, use the `getMetadata` method.
+ * files[0].getMetadata(function(err, metadata) {});
+ * };
+ *
+ * bucket.getFiles({
+ * autoPaginate: false
+ * }, callback);
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * bucket.getFiles().then(function(data) {
+ * const files = data[0];
+ * });
+ *
+ * ```
+ * @example
+ * Simulating a File System
With `autoPaginate: false`, it's possible to iterate over files which incorporate a common structure using a delimiter.
Consider the following remote objects:
- "a"
- "a/b/c/d"
- "b/d/e"
Using a delimiter of `/` will return a single file, "a".
`apiResponse.prefixes` will return the "sub-directories" that were found:
- "a/"
- "b/"
+ * ```
+ * bucket.getFiles({
+ * autoPaginate: false,
+ * delimiter: '/'
+ * }, function(err, files, nextQuery, apiResponse) {
+ * // files = [
+ * // {File} // File object for file "a"
+ * // ]
+ *
+ * // apiResponse.prefixes = [
+ * // 'a/',
+ * // 'b/'
+ * // ]
+ * });
+ * ```
+ *
+ * @example
+ * Using prefixes, it's now possible to simulate a file system with follow-up requests.
+ * ```
+ * bucket.getFiles({
+ * autoPaginate: false,
+ * delimiter: '/',
+ * prefix: 'a/'
+ * }, function(err, files, nextQuery, apiResponse) {
+ * // No files found within "directory" a.
+ * // files = []
+ *
+ * // However, a "sub-directory" was found.
+ * // This prefix can be used to continue traversing the "file system".
+ * // apiResponse.prefixes = [
+ * // 'a/b/'
+ * // ]
+ * });
+ * ```
+ *
+ * @example include:samples/files.js
+ * region_tag:storage_list_files
+ * Another example:
+ *
+ * @example include:samples/files.js
+ * region_tag:storage_list_files_with_prefix
+ * Example of listing files, filtered by a prefix:
+ */
+ getFiles(queryOrCallback, callback) {
+ let query = typeof queryOrCallback === 'object' ? queryOrCallback : {};
+ if (!callback) {
+ callback = queryOrCallback;
+ }
+ query = Object.assign({}, query);
+ this.request({
+ uri: '/o',
+ qs: query,
+ }, (err, resp) => {
+ if (err) {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ callback(err, null, null, resp);
+ return;
+ }
+ const itemsArray = resp.items ? resp.items : [];
+ const files = itemsArray.map((file) => {
+ const options = {};
+ if (query.versions) {
+ options.generation = file.generation;
+ }
+ if (file.kmsKeyName) {
+ options.kmsKeyName = file.kmsKeyName;
+ }
+ const fileInstance = this.file(file.name, options);
+ fileInstance.metadata = file;
+ return fileInstance;
+ });
+ let nextQuery = null;
+ if (resp.nextPageToken) {
+ nextQuery = Object.assign({}, query, {
+ pageToken: resp.nextPageToken,
+ });
+ }
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ callback(null, files, nextQuery, resp);
+ });
+ }
+ /**
+ * @deprecated
+ * @typedef {object} GetLabelsOptions Configuration options for Bucket#getLabels().
+ * @param {string} [userProject] The ID of the project which will be
+ * billed for the request.
+ */
+ /**
+ * @deprecated
+ * @typedef {array} GetLabelsResponse
+ * @property {object} 0 Object of labels currently set on this bucket.
+ */
+ /**
+ * @deprecated
+ * @callback GetLabelsCallback
+ * @param {?Error} err Request error, if any.
+ * @param {object} labels Object of labels currently set on this bucket.
+ */
+ /**
+ * @deprecated Use getMetadata directly.
+ * Get the labels currently set on this bucket.
+ *
+ * @param {object} [options] Configuration options.
+ * @param {string} [options.userProject] The ID of the project which will be
+ * billed for the request.
+ * @param {GetLabelsCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('albums');
+ *
+ * bucket.getLabels(function(err, labels) {
+ * if (err) {
+ * // Error handling omitted.
+ * }
+ *
+ * // labels = {
+ * // label: 'labelValue',
+ * // ...
+ * // }
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * bucket.getLabels().then(function(data) {
+ * const labels = data[0];
+ * });
+ * ```
+ */
+ getLabels(optionsOrCallback, callback) {
+ let options = {};
+ if (typeof optionsOrCallback === 'function') {
+ callback = optionsOrCallback;
+ }
+ else if (optionsOrCallback) {
+ options = optionsOrCallback;
+ }
+ this.getMetadata(options, (err, metadata) => {
+ if (err) {
+ callback(err, null);
+ return;
+ }
+ callback(null, (metadata === null || metadata === void 0 ? void 0 : metadata.labels) || {});
+ });
+ }
+ /**
+ * @typedef {object} GetNotificationsOptions Configuration options for Bucket#getNotification().
+ * @property {string} [userProject] The ID of the project which will be
+ * billed for the request.
+ */
+ /**
+ * @callback GetNotificationsCallback
+ * @param {?Error} err Request error, if any.
+ * @param {Notification[]} notifications Array of {@link Notification}
+ * instances.
+ * @param {object} apiResponse The full API response.
+ */
+ /**
+ * @typedef {array} GetNotificationsResponse
+ * @property {Notification[]} 0 Array of {@link Notification} instances.
+ * @property {object} 1 The full API response.
+ */
+ /**
+ * Retrieves a list of notification subscriptions for a given bucket.
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/notifications/list| Notifications: list}
+ *
+ * @param {GetNotificationsOptions} [options] Configuration options.
+ * @param {string} [options.userProject] The ID of the project which will be
+ * billed for the request.
+ * @param {GetNotificationsCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('my-bucket');
+ *
+ * bucket.getNotifications(function(err, notifications, apiResponse) {
+ * if (!err) {
+ * // notifications is an array of Notification objects.
+ * }
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * bucket.getNotifications().then(function(data) {
+ * const notifications = data[0];
+ * const apiResponse = data[1];
+ * });
+ *
+ * ```
+ * @example include:samples/listNotifications.js
+ * region_tag:storage_list_bucket_notifications
+ * Another example:
+ */
+ getNotifications(optionsOrCallback, callback) {
+ let options = {};
+ if (typeof optionsOrCallback === 'function') {
+ callback = optionsOrCallback;
+ }
+ else if (optionsOrCallback) {
+ options = optionsOrCallback;
+ }
+ this.request({
+ uri: '/notificationConfigs',
+ qs: options,
+ }, (err, resp) => {
+ if (err) {
+ callback(err, null, resp);
+ return;
+ }
+ const itemsArray = resp.items ? resp.items : [];
+ const notifications = itemsArray.map((notification) => {
+ const notificationInstance = this.notification(notification.id);
+ notificationInstance.metadata = notification;
+ return notificationInstance;
+ });
+ callback(null, notifications, resp);
+ });
+ }
+ /**
+ * @typedef {array} GetSignedUrlResponse
+ * @property {object} 0 The signed URL.
+ */
+ /**
+ * @callback GetSignedUrlCallback
+ * @param {?Error} err Request error, if any.
+ * @param {object} url The signed URL.
+ */
+ /**
+ * @typedef {object} GetBucketSignedUrlConfig
+ * @property {string} action Only listing objects within a bucket (HTTP: GET) is supported for bucket-level signed URLs.
+ * @property {*} expires A timestamp when this link will expire. Any value
+ * given is passed to `new Date()`.
+ * Note: 'v4' supports maximum duration of 7 days (604800 seconds) from now.
+ * @property {string} [version='v2'] The signing version to use, either
+ * 'v2' or 'v4'.
+ * @property {boolean} [virtualHostedStyle=false] Use virtual hosted-style
+ * URLs ('https://mybucket.storage.googleapis.com/...') instead of path-style
+ * ('https://storage.googleapis.com/mybucket/...'). Virtual hosted-style URLs
+ * should generally be preferred instaed of path-style URL.
+ * Currently defaults to `false` for path-style, although this may change in a
+ * future major-version release.
+ * @property {string} [cname] The cname for this bucket, i.e.,
+ * "https://cdn.example.com".
+ * See [reference]{@link https://cloud.google.com/storage/docs/access-control/signed-urls#example}
+ * @property {object} [extensionHeaders] If these headers are used, the
+ * server will check to make sure that the client provides matching
+ * values. See {@link https://cloud.google.com/storage/docs/access-control/signed-urls#about-canonical-extension-headers| Canonical extension headers}
+ * for the requirements of this feature, most notably:
+ * - The header name must be prefixed with `x-goog-`
+ * - The header name must be all lowercase
+ *
+ * Note: Multi-valued header passed as an array in the extensionHeaders
+ * object is converted into a string, delimited by `,` with
+ * no space. Requests made using the signed URL will need to
+ * delimit multi-valued headers using a single `,` as well, or
+ * else the server will report a mismatched signature.
+ * @property {object} [queryParams] Additional query parameters to include
+ * in the signed URL.
+ */
+ /**
+ * Get a signed URL to allow limited time access to a bucket.
+ *
+ * In Google Cloud Platform environments, such as Cloud Functions and App
+ * Engine, you usually don't provide a `keyFilename` or `credentials` during
+ * instantiation. In those environments, we call the
+ * {@link https://cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/signBlob| signBlob API}
+ * to create a signed URL. That API requires either the
+ * `https://www.googleapis.com/auth/iam` or
+ * `https://www.googleapis.com/auth/cloud-platform` scope, so be sure they are
+ * enabled.
+ *
+ * See {@link https://cloud.google.com/storage/docs/access-control/signed-urls| Signed URLs Reference}
+ *
+ * @throws {Error} if an expiration timestamp from the past is given.
+ *
+ * @param {GetBucketSignedUrlConfig} config Configuration object.
+ * @param {string} config.action Currently only supports "list" (HTTP: GET).
+ * @param {*} config.expires A timestamp when this link will expire. Any value
+ * given is passed to `new Date()`.
+ * Note: 'v4' supports maximum duration of 7 days (604800 seconds) from now.
+ * @param {string} [config.version='v2'] The signing version to use, either
+ * 'v2' or 'v4'.
+ * @param {boolean} [config.virtualHostedStyle=false] Use virtual hosted-style
+ * URLs ('https://mybucket.storage.googleapis.com/...') instead of path-style
+ * ('https://storage.googleapis.com/mybucket/...'). Virtual hosted-style URLs
+ * should generally be preferred instaed of path-style URL.
+ * Currently defaults to `false` for path-style, although this may change in a
+ * future major-version release.
+ * @param {string} [config.cname] The cname for this bucket, i.e.,
+ * "https://cdn.example.com".
+ * See [reference]{@link https://cloud.google.com/storage/docs/access-control/signed-urls#example}
+ * @param {object} [config.extensionHeaders] If these headers are used, the
+ * server will check to make sure that the client provides matching
+ * values. See {@link https://cloud.google.com/storage/docs/access-control/signed-urls#about-canonical-extension-headers| Canonical extension headers}
+ * for the requirements of this feature, most notably:
+ * - The header name must be prefixed with `x-goog-`
+ * - The header name must be all lowercase
+ *
+ * Note: Multi-valued header passed as an array in the extensionHeaders
+ * object is converted into a string, delimited by `,` with
+ * no space. Requests made using the signed URL will need to
+ * delimit multi-valued headers using a single `,` as well, or
+ * else the server will report a mismatched signature.
+ * @property {object} [config.queryParams] Additional query parameters to include
+ * in the signed URL.
+ * @param {GetSignedUrlCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * //-
+ * // Generate a URL that allows temporary access to list files in a bucket.
+ * //-
+ * const request = require('request');
+ *
+ * const config = {
+ * action: 'list',
+ * expires: '03-17-2025'
+ * };
+ *
+ * bucket.getSignedUrl(config, function(err, url) {
+ * if (err) {
+ * console.error(err);
+ * return;
+ * }
+ *
+ * // The bucket is now available to be listed from this URL.
+ * request(url, function(err, resp) {
+ * // resp.statusCode = 200
+ * });
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * bucket.getSignedUrl(config).then(function(data) {
+ * const url = data[0];
+ * });
+ * ```
+ */
+ getSignedUrl(cfg, callback) {
+ const method = BucketActionToHTTPMethod[cfg.action];
+ const signConfig = {
+ method,
+ expires: cfg.expires,
+ version: cfg.version,
+ cname: cfg.cname,
+ extensionHeaders: cfg.extensionHeaders || {},
+ queryParams: cfg.queryParams || {},
+ host: cfg.host,
+ signingEndpoint: cfg.signingEndpoint,
+ };
+ if (!this.signer) {
+ this.signer = new signer_js_1.URLSigner(this.storage.authClient, this, undefined, this.storage);
+ }
+ this.signer
+ .getSignedUrl(signConfig)
+ .then(signedUrl => callback(null, signedUrl), callback);
+ }
+ /**
+ * @callback BucketLockCallback
+ * @param {?Error} err Request error, if any.
+ * @param {object} apiResponse The full API response.
+ */
+ /**
+ * Lock a previously-defined retention policy. This will prevent changes to
+ * the policy.
+ *
+ * @throws {Error} if a metageneration is not provided.
+ *
+ * @param {number|string} metageneration The bucket's metageneration. This is
+ * accesssible from calling {@link File#getMetadata}.
+ * @param {BucketLockCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const storage = require('@google-cloud/storage')();
+ * const bucket = storage.bucket('albums');
+ *
+ * const metageneration = 2;
+ *
+ * bucket.lock(metageneration, function(err, apiResponse) {});
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * bucket.lock(metageneration).then(function(data) {
+ * const apiResponse = data[0];
+ * });
+ * ```
+ */
+ lock(metageneration, callback) {
+ const metatype = typeof metageneration;
+ if (metatype !== 'number' && metatype !== 'string') {
+ throw new Error(BucketExceptionMessages.METAGENERATION_NOT_PROVIDED);
+ }
+ this.request({
+ method: 'POST',
+ uri: '/lockRetentionPolicy',
+ qs: {
+ ifMetagenerationMatch: metageneration,
+ },
+ }, callback);
+ }
+ /**
+ * @typedef {array} MakeBucketPrivateResponse
+ * @property {File[]} 0 List of files made private.
+ */
+ /**
+ * @callback MakeBucketPrivateCallback
+ * @param {?Error} err Request error, if any.
+ * @param {File[]} files List of files made private.
+ */
+ /**
+ * @typedef {object} MakeBucketPrivateOptions
+ * @property {boolean} [includeFiles=false] Make each file in the bucket
+ * private.
+ * @property {Metadata} [metadata] Define custom metadata properties to define
+ * along with the operation.
+ * @property {boolean} [force] Queue errors occurred while making files
+ * private until all files have been processed.
+ * @property {string} [userProject] The ID of the project which will be
+ * billed for the request.
+ */
+ /**
+ * Make the bucket listing private.
+ *
+ * You may also choose to make the contents of the bucket private by
+ * specifying `includeFiles: true`. This will automatically run
+ * {@link File#makePrivate} for every file in the bucket.
+ *
+ * When specifying `includeFiles: true`, use `force: true` to delay execution
+ * of your callback until all files have been processed. By default, the
+ * callback is executed after the first error. Use `force` to queue such
+ * errors until all files have been processed, after which they will be
+ * returned as an array as the first argument to your callback.
+ *
+ * NOTE: This may cause the process to be long-running and use a high number
+ * of requests. Use with caution.
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/buckets/patch| Buckets: patch API Documentation}
+ *
+ * @param {MakeBucketPrivateOptions} [options] Configuration options.
+ * @param {boolean} [options.includeFiles=false] Make each file in the bucket
+ * private.
+ * @param {Metadata} [options.metadata] Define custom metadata properties to define
+ * along with the operation.
+ * @param {boolean} [options.force] Queue errors occurred while making files
+ * private until all files have been processed.
+ * @param {string} [options.userProject] The ID of the project which will be
+ * billed for the request.
+ * @param {MakeBucketPrivateCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('albums');
+ *
+ * //-
+ * // Make the bucket private.
+ * //-
+ * bucket.makePrivate(function(err) {});
+ *
+ * //-
+ * // Make the bucket and its contents private.
+ * //-
+ * const opts = {
+ * includeFiles: true
+ * };
+ *
+ * bucket.makePrivate(opts, function(err, files) {
+ * // `err`:
+ * // The first error to occur, otherwise null.
+ * //
+ * // `files`:
+ * // Array of files successfully made private in the bucket.
+ * });
+ *
+ * //-
+ * // Make the bucket and its contents private, using force to suppress errors
+ * // until all files have been processed.
+ * //-
+ * const opts = {
+ * includeFiles: true,
+ * force: true
+ * };
+ *
+ * bucket.makePrivate(opts, function(errors, files) {
+ * // `errors`:
+ * // Array of errors if any occurred, otherwise null.
+ * //
+ * // `files`:
+ * // Array of files successfully made private in the bucket.
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * bucket.makePrivate(opts).then(function(data) {
+ * const files = data[0];
+ * });
+ * ```
+ */
+ makePrivate(optionsOrCallback, callback) {
+ var _a, _b, _c, _d;
+ const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
+ callback =
+ typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
+ options.private = true;
+ const query = {
+ predefinedAcl: 'projectPrivate',
+ };
+ if (options.userProject) {
+ query.userProject = options.userProject;
+ }
+ if ((_a = options.preconditionOpts) === null || _a === void 0 ? void 0 : _a.ifGenerationMatch) {
+ query.ifGenerationMatch = options.preconditionOpts.ifGenerationMatch;
+ }
+ if ((_b = options.preconditionOpts) === null || _b === void 0 ? void 0 : _b.ifGenerationNotMatch) {
+ query.ifGenerationNotMatch =
+ options.preconditionOpts.ifGenerationNotMatch;
+ }
+ if ((_c = options.preconditionOpts) === null || _c === void 0 ? void 0 : _c.ifMetagenerationMatch) {
+ query.ifMetagenerationMatch =
+ options.preconditionOpts.ifMetagenerationMatch;
+ }
+ if ((_d = options.preconditionOpts) === null || _d === void 0 ? void 0 : _d.ifMetagenerationNotMatch) {
+ query.ifMetagenerationNotMatch =
+ options.preconditionOpts.ifMetagenerationNotMatch;
+ }
+ // You aren't allowed to set both predefinedAcl & acl properties on a bucket
+ // so acl must explicitly be nullified.
+ const metadata = { ...options.metadata, acl: null };
+ this.setMetadata(metadata, query, (err) => {
+ if (err) {
+ callback(err);
+ }
+ const internalCall = () => {
+ if (options.includeFiles) {
+ return (0, util_1.promisify)(this.makeAllFilesPublicPrivate_).call(this, options);
+ }
+ return Promise.resolve([]);
+ };
+ internalCall()
+ .then(files => callback(null, files))
+ .catch(callback);
+ });
+ }
+ /**
+ * @typedef {object} MakeBucketPublicOptions
+ * @property {boolean} [includeFiles=false] Make each file in the bucket
+ * private.
+ * @property {boolean} [force] Queue errors occurred while making files
+ * private until all files have been processed.
+ */
+ /**
+ * @callback MakeBucketPublicCallback
+ * @param {?Error} err Request error, if any.
+ * @param {File[]} files List of files made public.
+ */
+ /**
+ * @typedef {array} MakeBucketPublicResponse
+ * @property {File[]} 0 List of files made public.
+ */
+ /**
+ * Make the bucket publicly readable.
+ *
+ * You may also choose to make the contents of the bucket publicly readable by
+ * specifying `includeFiles: true`. This will automatically run
+ * {@link File#makePublic} for every file in the bucket.
+ *
+ * When specifying `includeFiles: true`, use `force: true` to delay execution
+ * of your callback until all files have been processed. By default, the
+ * callback is executed after the first error. Use `force` to queue such
+ * errors until all files have been processed, after which they will be
+ * returned as an array as the first argument to your callback.
+ *
+ * NOTE: This may cause the process to be long-running and use a high number
+ * of requests. Use with caution.
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/buckets/patch| Buckets: patch API Documentation}
+ *
+ * @param {MakeBucketPublicOptions} [options] Configuration options.
+ * @param {boolean} [options.includeFiles=false] Make each file in the bucket
+ * private.
+ * @param {boolean} [options.force] Queue errors occurred while making files
+ * private until all files have been processed.
+ * @param {MakeBucketPublicCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('albums');
+ *
+ * //-
+ * // Make the bucket publicly readable.
+ * //-
+ * bucket.makePublic(function(err) {});
+ *
+ * //-
+ * // Make the bucket and its contents publicly readable.
+ * //-
+ * const opts = {
+ * includeFiles: true
+ * };
+ *
+ * bucket.makePublic(opts, function(err, files) {
+ * // `err`:
+ * // The first error to occur, otherwise null.
+ * //
+ * // `files`:
+ * // Array of files successfully made public in the bucket.
+ * });
+ *
+ * //-
+ * // Make the bucket and its contents publicly readable, using force to
+ * // suppress errors until all files have been processed.
+ * //-
+ * const opts = {
+ * includeFiles: true,
+ * force: true
+ * };
+ *
+ * bucket.makePublic(opts, function(errors, files) {
+ * // `errors`:
+ * // Array of errors if any occurred, otherwise null.
+ * //
+ * // `files`:
+ * // Array of files successfully made public in the bucket.
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * bucket.makePublic(opts).then(function(data) {
+ * const files = data[0];
+ * });
+ * ```
+ */
+ makePublic(optionsOrCallback, callback) {
+ const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
+ callback =
+ typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
+ const req = { public: true, ...options };
+ this.acl
+ .add({
+ entity: 'allUsers',
+ role: 'READER',
+ })
+ .then(() => {
+ return this.acl.default.add({
+ entity: 'allUsers',
+ role: 'READER',
+ });
+ })
+ .then(() => {
+ if (req.includeFiles) {
+ return (0, util_1.promisify)(this.makeAllFilesPublicPrivate_).call(this, req);
+ }
+ return [];
+ })
+ .then(files => callback(null, files), callback);
+ }
+ /**
+ * Get a reference to a Cloud Pub/Sub Notification.
+ *
+ * @param {string} id ID of notification.
+ * @returns {Notification}
+ * @see Notification
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('my-bucket');
+ * const notification = bucket.notification('1');
+ * ```
+ */
+ notification(id) {
+ if (!id) {
+ throw new Error(BucketExceptionMessages.SUPPLY_NOTIFICATION_ID);
+ }
+ return new notification_js_1.Notification(this, id);
+ }
+ /**
+ * Remove an already-existing retention policy from this bucket, if it is not
+ * locked.
+ *
+ * @param {SetBucketMetadataCallback} [callback] Callback function.
+ * @param {SetBucketMetadataOptions} [options] Options, including precondition options
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const storage = require('@google-cloud/storage')();
+ * const bucket = storage.bucket('albums');
+ *
+ * bucket.removeRetentionPeriod(function(err, apiResponse) {});
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * bucket.removeRetentionPeriod().then(function(data) {
+ * const apiResponse = data[0];
+ * });
+ * ```
+ */
+ removeRetentionPeriod(optionsOrCallback, callback) {
+ const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
+ callback =
+ typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
+ this.setMetadata({
+ retentionPolicy: null,
+ }, options, callback);
+ }
+ /**
+ * Makes request and applies userProject query parameter if necessary.
+ *
+ * @private
+ *
+ * @param {object} reqOpts - The request options.
+ * @param {function} callback - The callback function.
+ */
+ request(reqOpts, callback) {
+ if (this.userProject && (!reqOpts.qs || !reqOpts.qs.userProject)) {
+ reqOpts.qs = { ...reqOpts.qs, userProject: this.userProject };
+ }
+ return super.request(reqOpts, callback);
+ }
+ /**
+ * @deprecated
+ * @typedef {array} SetLabelsResponse
+ * @property {object} 0 The bucket metadata.
+ */
+ /**
+ * @deprecated
+ * @callback SetLabelsCallback
+ * @param {?Error} err Request error, if any.
+ * @param {object} metadata The bucket metadata.
+ */
+ /**
+ * @deprecated
+ * @typedef {object} SetLabelsOptions Configuration options for Bucket#setLabels().
+ * @property {string} [userProject] The ID of the project which will be
+ * billed for the request.
+ */
+ /**
+ * @deprecated Use setMetadata directly.
+ * Set labels on the bucket.
+ *
+ * This makes an underlying call to {@link Bucket#setMetadata}, which
+ * is a PATCH request. This means an individual label can be overwritten, but
+ * unmentioned labels will not be touched.
+ *
+ * @param {object} labels Labels to set on the bucket.
+ * @param {SetLabelsOptions} [options] Configuration options.
+ * @param {string} [options.userProject] The ID of the project which will be
+ * billed for the request.
+ * @param {SetLabelsCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('albums');
+ *
+ * const labels = {
+ * labelone: 'labelonevalue',
+ * labeltwo: 'labeltwovalue'
+ * };
+ *
+ * bucket.setLabels(labels, function(err, metadata) {
+ * if (!err) {
+ * // Labels set successfully.
+ * }
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * bucket.setLabels(labels).then(function(data) {
+ * const metadata = data[0];
+ * });
+ * ```
+ */
+ setLabels(labels, optionsOrCallback, callback) {
+ const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
+ callback =
+ typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
+ callback = callback || index_js_1.util.noop;
+ this.setMetadata({ labels }, options, callback);
+ }
+ setMetadata(metadata, optionsOrCallback, cb) {
+ const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
+ cb =
+ typeof optionsOrCallback === 'function'
+ ? optionsOrCallback
+ : cb;
+ this.disableAutoRetryConditionallyIdempotent_(this.methods.setMetadata, AvailableServiceObjectMethods.setMetadata, options);
+ super
+ .setMetadata(metadata, options)
+ .then(resp => cb(null, ...resp))
+ .catch(cb)
+ .finally(() => {
+ this.storage.retryOptions.autoRetry = this.instanceRetryValue;
+ });
+ }
+ /**
+ * Lock all objects contained in the bucket, based on their creation time. Any
+ * attempt to overwrite or delete objects younger than the retention period
+ * will result in a `PERMISSION_DENIED` error.
+ *
+ * An unlocked retention policy can be modified or removed from the bucket via
+ * {@link File#removeRetentionPeriod} and {@link File#setRetentionPeriod}. A
+ * locked retention policy cannot be removed or shortened in duration for the
+ * lifetime of the bucket. Attempting to remove or decrease period of a locked
+ * retention policy will result in a `PERMISSION_DENIED` error. You can still
+ * increase the policy.
+ *
+ * @param {*} duration In seconds, the minimum retention time for all objects
+ * contained in this bucket.
+ * @param {SetBucketMetadataCallback} [callback] Callback function.
+ * @param {SetBucketMetadataCallback} [options] Options, including precondition options.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const storage = require('@google-cloud/storage')();
+ * const bucket = storage.bucket('albums');
+ *
+ * const DURATION_SECONDS = 15780000; // 6 months.
+ *
+ * //-
+ * // Lock the objects in this bucket for 6 months.
+ * //-
+ * bucket.setRetentionPeriod(DURATION_SECONDS, function(err, apiResponse) {});
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * bucket.setRetentionPeriod(DURATION_SECONDS).then(function(data) {
+ * const apiResponse = data[0];
+ * });
+ * ```
+ */
+ setRetentionPeriod(duration, optionsOrCallback, callback) {
+ const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
+ callback =
+ typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
+ this.setMetadata({
+ retentionPolicy: {
+ retentionPeriod: duration.toString(),
+ },
+ }, options, callback);
+ }
+ /**
+ *
+ * @typedef {object} Cors
+ * @property {number} [maxAgeSeconds] The number of seconds the browser is
+ * allowed to make requests before it must repeat the preflight request.
+ * @property {string[]} [method] HTTP method allowed for cross origin resource
+ * sharing with this bucket.
+ * @property {string[]} [origin] an origin allowed for cross origin resource
+ * sharing with this bucket.
+ * @property {string[]} [responseHeader] A header allowed for cross origin
+ * resource sharing with this bucket.
+ */
+ /**
+ * This can be used to set the CORS configuration on the bucket.
+ *
+ * The configuration will be overwritten with the value passed into this.
+ *
+ * @param {Cors[]} corsConfiguration The new CORS configuration to set
+ * @param {number} [corsConfiguration.maxAgeSeconds] The number of seconds the browser is
+ * allowed to make requests before it must repeat the preflight request.
+ * @param {string[]} [corsConfiguration.method] HTTP method allowed for cross origin resource
+ * sharing with this bucket.
+ * @param {string[]} [corsConfiguration.origin] an origin allowed for cross origin resource
+ * sharing with this bucket.
+ * @param {string[]} [corsConfiguration.responseHeader] A header allowed for cross origin
+ * resource sharing with this bucket.
+ * @param {SetBucketMetadataCallback} [callback] Callback function.
+ * @param {SetBucketMetadataOptions} [options] Options, including precondition options.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const storage = require('@google-cloud/storage')();
+ * const bucket = storage.bucket('albums');
+ *
+ * const corsConfiguration = [{maxAgeSeconds: 3600}]; // 1 hour
+ * bucket.setCorsConfiguration(corsConfiguration);
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * bucket.setCorsConfiguration(corsConfiguration).then(function(data) {
+ * const apiResponse = data[0];
+ * });
+ * ```
+ */
+ setCorsConfiguration(corsConfiguration, optionsOrCallback, callback) {
+ const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
+ callback =
+ typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
+ this.setMetadata({
+ cors: corsConfiguration,
+ }, options, callback);
+ }
+ /**
+ * @typedef {object} SetBucketStorageClassOptions
+ * @property {string} [userProject] - The ID of the project which will be
+ * billed for the request.
+ */
+ /**
+ * @callback SetBucketStorageClassCallback
+ * @param {?Error} err Request error, if any.
+ */
+ /**
+ * Set the default storage class for new files in this bucket.
+ *
+ * See {@link https://cloud.google.com/storage/docs/storage-classes| Storage Classes}
+ *
+ * @param {string} storageClass The new storage class. (`standard`,
+ * `nearline`, `coldline`, or `archive`).
+ * **Note:** The storage classes `multi_regional`, `regional`, and
+ * `durable_reduced_availability` are now legacy and will be deprecated in
+ * the future.
+ * @param {object} [options] Configuration options.
+ * @param {string} [options.userProject] - The ID of the project which will be
+ * billed for the request.
+ * @param {SetStorageClassCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('albums');
+ *
+ * bucket.setStorageClass('nearline', function(err, apiResponse) {
+ * if (err) {
+ * // Error handling omitted.
+ * }
+ *
+ * // The storage class was updated successfully.
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * bucket.setStorageClass('nearline').then(function() {});
+ * ```
+ */
+ setStorageClass(storageClass, optionsOrCallback, callback) {
+ const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
+ callback =
+ typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
+ // In case we get input like `storageClass`, convert to `storage_class`.
+ storageClass = storageClass
+ .replace(/-/g, '_')
+ .replace(/([a-z])([A-Z])/g, (_, low, up) => {
+ return low + '_' + up;
+ })
+ .toUpperCase();
+ this.setMetadata({ storageClass }, options, callback);
+ }
+ /**
+ * Set a user project to be billed for all requests made from this Bucket
+ * object and any files referenced from this Bucket object.
+ *
+ * @param {string} userProject The user project.
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('albums');
+ *
+ * bucket.setUserProject('grape-spaceship-123');
+ * ```
+ */
+ setUserProject(userProject) {
+ this.userProject = userProject;
+ const methods = [
+ 'create',
+ 'delete',
+ 'exists',
+ 'get',
+ 'getMetadata',
+ 'setMetadata',
+ ];
+ methods.forEach(method => {
+ const methodConfig = this.methods[method];
+ if (typeof methodConfig === 'object') {
+ if (typeof methodConfig.reqOpts === 'object') {
+ Object.assign(methodConfig.reqOpts.qs, { userProject });
+ }
+ else {
+ methodConfig.reqOpts = {
+ qs: { userProject },
+ };
+ }
+ }
+ });
+ }
+ /**
+ * @typedef {object} UploadOptions Configuration options for Bucket#upload().
+ * @property {string|File} [destination] The place to save
+ * your file. If given a string, the file will be uploaded to the bucket
+ * using the string as a filename. When given a File object, your local
+ * file will be uploaded to the File object's bucket and under the File
+ * object's name. Lastly, when this argument is omitted, the file is uploaded
+ * to your bucket using the name of the local file.
+ * @property {string} [encryptionKey] A custom encryption key. See
+ * {@link https://cloud.google.com/storage/docs/encryption#customer-supplied| Customer-supplied Encryption Keys}.
+ * @property {boolean} [gzip] Automatically gzip the file. This will set
+ * `options.metadata.contentEncoding` to `gzip`.
+ * @property {string} [kmsKeyName] The name of the Cloud KMS key that will
+ * be used to encrypt the object. Must be in the format:
+ * `projects/my-project/locations/location/keyRings/my-kr/cryptoKeys/my-key`.
+ * @property {object} [metadata] See an
+ * {@link https://cloud.google.com/storage/docs/json_api/v1/objects/insert#request_properties_JSON| Objects: insert request body}.
+ * @property {string} [offset] The starting byte of the upload stream, for
+ * resuming an interrupted upload. Defaults to 0.
+ * @property {string} [predefinedAcl] Apply a predefined set of access
+ * controls to this object.
+ *
+ * Acceptable values are:
+ * - **`authenticatedRead`** - Object owner gets `OWNER` access, and
+ * `allAuthenticatedUsers` get `READER` access.
+ *
+ * - **`bucketOwnerFullControl`** - Object owner gets `OWNER` access, and
+ * project team owners get `OWNER` access.
+ *
+ * - **`bucketOwnerRead`** - Object owner gets `OWNER` access, and project
+ * team owners get `READER` access.
+ *
+ * - **`private`** - Object owner gets `OWNER` access.
+ *
+ * - **`projectPrivate`** - Object owner gets `OWNER` access, and project
+ * team members get access according to their roles.
+ *
+ * - **`publicRead`** - Object owner gets `OWNER` access, and `allUsers`
+ * get `READER` access.
+ * @property {boolean} [private] Make the uploaded file private. (Alias for
+ * `options.predefinedAcl = 'private'`)
+ * @property {boolean} [public] Make the uploaded file public. (Alias for
+ * `options.predefinedAcl = 'publicRead'`)
+ * @property {boolean} [resumable=true] Resumable uploads are automatically
+ * enabled and must be shut off explicitly by setting to false.
+ * @property {number} [timeout=60000] Set the HTTP request timeout in
+ * milliseconds. This option is not available for resumable uploads.
+ * Default: `60000`
+ * @property {string} [uri] The URI for an already-created resumable
+ * upload. See {@link File#createResumableUpload}.
+ * @property {string} [userProject] The ID of the project which will be
+ * billed for the request.
+ * @property {string|boolean} [validation] Possible values: `"md5"`,
+ * `"crc32c"`, or `false`. By default, data integrity is validated with an
+ * MD5 checksum for maximum reliability. CRC32c will provide better
+ * performance with less reliability. You may also choose to skip
+ * validation completely, however this is **not recommended**.
+ */
+ /**
+ * @typedef {array} UploadResponse
+ * @property {object} 0 The uploaded {@link File}.
+ * @property {object} 1 The full API response.
+ */
+ /**
+ * @callback UploadCallback
+ * @param {?Error} err Request error, if any.
+ * @param {object} file The uploaded {@link File}.
+ * @param {object} apiResponse The full API response.
+ */
+ /**
+ * Upload a file to the bucket. This is a convenience method that wraps
+ * {@link File#createWriteStream}.
+ *
+ * Resumable uploads are enabled by default
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload#uploads| Upload Options (Simple or Resumable)}
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/objects/insert| Objects: insert API Documentation}
+ *
+ * @param {string} pathString The fully qualified path to the file you
+ * wish to upload to your bucket.
+ * @param {UploadOptions} [options] Configuration options.
+ * @param {string|File} [options.destination] The place to save
+ * your file. If given a string, the file will be uploaded to the bucket
+ * using the string as a filename. When given a File object, your local
+ * file will be uploaded to the File object's bucket and under the File
+ * object's name. Lastly, when this argument is omitted, the file is uploaded
+ * to your bucket using the name of the local file.
+ * @param {string} [options.encryptionKey] A custom encryption key. See
+ * {@link https://cloud.google.com/storage/docs/encryption#customer-supplied| Customer-supplied Encryption Keys}.
+ * @param {boolean} [options.gzip] Automatically gzip the file. This will set
+ * `options.metadata.contentEncoding` to `gzip`.
+ * @param {string} [options.kmsKeyName] The name of the Cloud KMS key that will
+ * be used to encrypt the object. Must be in the format:
+ * `projects/my-project/locations/location/keyRings/my-kr/cryptoKeys/my-key`.
+ * @param {object} [options.metadata] See an
+ * {@link https://cloud.google.com/storage/docs/json_api/v1/objects/insert#request_properties_JSON| Objects: insert request body}.
+ * @param {string} [options.offset] The starting byte of the upload stream, for
+ * resuming an interrupted upload. Defaults to 0.
+ * @param {string} [options.predefinedAcl] Apply a predefined set of access
+ * controls to this object.
+ * Acceptable values are:
+ * - **`authenticatedRead`** - Object owner gets `OWNER` access, and
+ * `allAuthenticatedUsers` get `READER` access.
+ *
+ * - **`bucketOwnerFullControl`** - Object owner gets `OWNER` access, and
+ * project team owners get `OWNER` access.
+ *
+ * - **`bucketOwnerRead`** - Object owner gets `OWNER` access, and project
+ * team owners get `READER` access.
+ *
+ * - **`private`** - Object owner gets `OWNER` access.
+ *
+ * - **`projectPrivate`** - Object owner gets `OWNER` access, and project
+ * team members get access according to their roles.
+ *
+ * - **`publicRead`** - Object owner gets `OWNER` access, and `allUsers`
+ * get `READER` access.
+ * @param {boolean} [options.private] Make the uploaded file private. (Alias for
+ * `options.predefinedAcl = 'private'`)
+ * @param {boolean} [options.public] Make the uploaded file public. (Alias for
+ * `options.predefinedAcl = 'publicRead'`)
+ * @param {boolean} [options.resumable=true] Resumable uploads are automatically
+ * enabled and must be shut off explicitly by setting to false.
+ * @param {number} [options.timeout=60000] Set the HTTP request timeout in
+ * milliseconds. This option is not available for resumable uploads.
+ * Default: `60000`
+ * @param {string} [options.uri] The URI for an already-created resumable
+ * upload. See {@link File#createResumableUpload}.
+ * @param {string} [options.userProject] The ID of the project which will be
+ * billed for the request.
+ * @param {string|boolean} [options.validation] Possible values: `"md5"`,
+ * `"crc32c"`, or `false`. By default, data integrity is validated with an
+ * MD5 checksum for maximum reliability. CRC32c will provide better
+ * performance with less reliability. You may also choose to skip
+ * validation completely, however this is **not recommended**.
+ * @param {UploadCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('albums');
+ *
+ * //-
+ * // Upload a file from a local path.
+ * //-
+ * bucket.upload('/local/path/image.png', function(err, file, apiResponse) {
+ * // Your bucket now contains:
+ * // - "image.png" (with the contents of `/local/path/image.png')
+ *
+ * // `file` is an instance of a File object that refers to your new file.
+ * });
+ *
+ *
+ * //-
+ * // It's not always that easy. You will likely want to specify the filename
+ * // used when your new file lands in your bucket.
+ * //
+ * // You may also want to set metadata or customize other options.
+ * //-
+ * const options = {
+ * destination: 'new-image.png',
+ * validation: 'crc32c',
+ * metadata: {
+ * metadata: {
+ * event: 'Fall trip to the zoo'
+ * }
+ * }
+ * };
+ *
+ * bucket.upload('local-image.png', options, function(err, file) {
+ * // Your bucket now contains:
+ * // - "new-image.png" (with the contents of `local-image.png')
+ *
+ * // `file` is an instance of a File object that refers to your new file.
+ * });
+ *
+ * //-
+ * // You can also have a file gzip'd on the fly.
+ * //-
+ * bucket.upload('index.html', { gzip: true }, function(err, file) {
+ * // Your bucket now contains:
+ * // - "index.html" (automatically compressed with gzip)
+ *
+ * // Downloading the file with `file.download` will automatically decode
+ * the
+ * // file.
+ * });
+ *
+ * //-
+ * // You may also re-use a File object, {File}, that references
+ * // the file you wish to create or overwrite.
+ * //-
+ * const options = {
+ * destination: bucket.file('existing-file.png'),
+ * resumable: false
+ * };
+ *
+ * bucket.upload('local-img.png', options, function(err, newFile) {
+ * // Your bucket now contains:
+ * // - "existing-file.png" (with the contents of `local-img.png')
+ *
+ * // Note:
+ * // The `newFile` parameter is equal to `file`.
+ * });
+ *
+ * //-
+ * // To use
+ * //
+ * // Customer-supplied Encryption Keys, provide the `encryptionKey`
+ * option.
+ * //-
+ * const crypto = require('crypto');
+ * const encryptionKey = crypto.randomBytes(32);
+ *
+ * bucket.upload('img.png', {
+ * encryptionKey: encryptionKey
+ * }, function(err, newFile) {
+ * // `img.png` was uploaded with your custom encryption key.
+ *
+ * // `newFile` is already configured to use the encryption key when making
+ * // operations on the remote object.
+ *
+ * // However, to use your encryption key later, you must create a `File`
+ * // instance with the `key` supplied:
+ * const file = bucket.file('img.png', {
+ * encryptionKey: encryptionKey
+ * });
+ *
+ * // Or with `file#setEncryptionKey`:
+ * const file = bucket.file('img.png');
+ * file.setEncryptionKey(encryptionKey);
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * bucket.upload('local-image.png').then(function(data) {
+ * const file = data[0];
+ * });
+ *
+ * To upload a file from a URL, use {@link File#createWriteStream}.
+ *
+ * ```
+ * @example include:samples/files.js
+ * region_tag:storage_upload_file
+ * Another example:
+ *
+ * @example include:samples/encryption.js
+ * region_tag:storage_upload_encrypted_file
+ * Example of uploading an encrypted file:
+ */
+ upload(pathString, optionsOrCallback, callback) {
+ var _a, _b;
+ const upload = (numberOfRetries) => {
+ const returnValue = (0, async_retry_1.default)(async (bail) => {
+ await new Promise((resolve, reject) => {
+ var _a, _b;
+ if (numberOfRetries === 0 &&
+ ((_b = (_a = newFile === null || newFile === void 0 ? void 0 : newFile.storage) === null || _a === void 0 ? void 0 : _a.retryOptions) === null || _b === void 0 ? void 0 : _b.autoRetry)) {
+ newFile.storage.retryOptions.autoRetry = false;
+ }
+ const writable = newFile.createWriteStream(options);
+ if (options.onUploadProgress) {
+ writable.on('progress', options.onUploadProgress);
+ }
+ fs.createReadStream(pathString)
+ .on('error', bail)
+ .pipe(writable)
+ .on('error', err => {
+ if (this.storage.retryOptions.autoRetry &&
+ this.storage.retryOptions.retryableErrorFn(err)) {
+ return reject(err);
+ }
+ else {
+ return bail(err);
+ }
+ })
+ .on('finish', () => {
+ return resolve();
+ });
+ });
+ }, {
+ retries: numberOfRetries,
+ factor: this.storage.retryOptions.retryDelayMultiplier,
+ maxTimeout: this.storage.retryOptions.maxRetryDelay * 1000, //convert to milliseconds
+ maxRetryTime: this.storage.retryOptions.totalTimeout * 1000, //convert to milliseconds
+ });
+ if (!callback) {
+ return returnValue;
+ }
+ else {
+ return returnValue
+ .then(() => {
+ if (callback) {
+ return callback(null, newFile, newFile.metadata);
+ }
+ })
+ .catch(callback);
+ }
+ };
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ if (global['GCLOUD_SANDBOX_ENV']) {
+ return;
+ }
+ let options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
+ callback =
+ typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
+ options = Object.assign({
+ metadata: {},
+ }, options);
+ // Do not retry if precondition option ifGenerationMatch is not set
+ // because this is a file operation
+ let maxRetries = this.storage.retryOptions.maxRetries;
+ if ((((_a = options === null || options === void 0 ? void 0 : options.preconditionOpts) === null || _a === void 0 ? void 0 : _a.ifGenerationMatch) === undefined &&
+ ((_b = this.instancePreconditionOpts) === null || _b === void 0 ? void 0 : _b.ifGenerationMatch) === undefined &&
+ this.storage.retryOptions.idempotencyStrategy ===
+ storage_js_1.IdempotencyStrategy.RetryConditional) ||
+ this.storage.retryOptions.idempotencyStrategy ===
+ storage_js_1.IdempotencyStrategy.RetryNever) {
+ maxRetries = 0;
+ }
+ let newFile;
+ if (options.destination instanceof file_js_1.File) {
+ newFile = options.destination;
+ }
+ else if (options.destination !== null &&
+ typeof options.destination === 'string') {
+ // Use the string as the name of the file.
+ newFile = this.file(options.destination, {
+ encryptionKey: options.encryptionKey,
+ kmsKeyName: options.kmsKeyName,
+ preconditionOpts: this.instancePreconditionOpts,
+ });
+ }
+ else {
+ // Resort to using the name of the incoming file.
+ const destination = path.basename(pathString);
+ newFile = this.file(destination, {
+ encryptionKey: options.encryptionKey,
+ kmsKeyName: options.kmsKeyName,
+ preconditionOpts: this.instancePreconditionOpts,
+ });
+ }
+ upload(maxRetries);
+ }
+ /**
+ * @private
+ *
+ * @typedef {object} MakeAllFilesPublicPrivateOptions
+ * @property {boolean} [force] Suppress errors until all files have been
+ * processed.
+ * @property {boolean} [private] Make files private.
+ * @property {boolean} [public] Make files public.
+ * @property {string} [userProject] The ID of the project which will be
+ * billed for the request.
+ */
+ /**
+ * @private
+ *
+ * @callback SetBucketMetadataCallback
+ * @param {?Error} err Request error, if any.
+ * @param {File[]} files Files that were updated.
+ */
+ /**
+ * @typedef {array} MakeAllFilesPublicPrivateResponse
+ * @property {File[]} 0 List of files affected.
+ */
+ /**
+ * Iterate over all of a bucket's files, calling `file.makePublic()` (public)
+ * or `file.makePrivate()` (private) on each.
+ *
+ * Operations are performed in parallel, up to 10 at once. The first error
+ * breaks the loop, and will execute the provided callback with it. Specify
+ * `{ force: true }` to suppress the errors.
+ *
+ * @private
+ *
+ * @param {MakeAllFilesPublicPrivateOptions} [options] Configuration options.
+ * @param {boolean} [options.force] Suppress errors until all files have been
+ * processed.
+ * @param {boolean} [options.private] Make files private.
+ * @param {boolean} [options.public] Make files public.
+ * @param {string} [options.userProject] The ID of the project which will be
+ * billed for the request.
+
+ * @param {MakeAllFilesPublicPrivateCallback} callback Callback function.
+ *
+ * @return {Promise}
+ */
+ makeAllFilesPublicPrivate_(optionsOrCallback, callback) {
+ const MAX_PARALLEL_LIMIT = 10;
+ const errors = [];
+ const updatedFiles = [];
+ const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
+ callback =
+ typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
+ const processFile = async (file) => {
+ try {
+ await (options.public ? file.makePublic() : file.makePrivate(options));
+ updatedFiles.push(file);
+ }
+ catch (e) {
+ if (!options.force) {
+ throw e;
+ }
+ errors.push(e);
+ }
+ };
+ this.getFiles(options)
+ .then(([files]) => {
+ const limit = (0, p_limit_1.default)(MAX_PARALLEL_LIMIT);
+ const promises = files.map(file => {
+ return limit(() => processFile(file));
+ });
+ return Promise.all(promises);
+ })
+ .then(() => callback(errors.length > 0 ? errors : null, updatedFiles), err => callback(err, updatedFiles));
+ }
+ getId() {
+ return this.id;
+ }
+ disableAutoRetryConditionallyIdempotent_(
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ coreOpts,
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ methodType, localPreconditionOptions) {
+ var _a, _b;
+ if (typeof coreOpts === 'object' &&
+ ((_b = (_a = coreOpts === null || coreOpts === void 0 ? void 0 : coreOpts.reqOpts) === null || _a === void 0 ? void 0 : _a.qs) === null || _b === void 0 ? void 0 : _b.ifMetagenerationMatch) === undefined &&
+ (localPreconditionOptions === null || localPreconditionOptions === void 0 ? void 0 : localPreconditionOptions.ifMetagenerationMatch) === undefined &&
+ (methodType === AvailableServiceObjectMethods.setMetadata ||
+ methodType === AvailableServiceObjectMethods.delete) &&
+ this.storage.retryOptions.idempotencyStrategy ===
+ storage_js_1.IdempotencyStrategy.RetryConditional) {
+ this.storage.retryOptions.autoRetry = false;
+ }
+ else if (this.storage.retryOptions.idempotencyStrategy ===
+ storage_js_1.IdempotencyStrategy.RetryNever) {
+ this.storage.retryOptions.autoRetry = false;
+ }
+ }
+}
+exports.Bucket = Bucket;
+/*! Developer Documentation
+ *
+ * These methods can be auto-paginated.
+ */
+paginator_1.paginator.extend(Bucket, 'getFiles');
+/*! Developer Documentation
+ *
+ * All async methods (except for streams) will return a Promise in the event
+ * that a callback is omitted.
+ */
+(0, promisify_1.promisifyAll)(Bucket, {
+ exclude: ['cloudStorageURI', 'request', 'file', 'notification'],
+});
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/channel.d.ts b/node_modules/@google-cloud/storage/build/cjs/src/channel.d.ts
new file mode 100644
index 0000000..6bb52b9
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/channel.d.ts
@@ -0,0 +1,33 @@
+import { BaseMetadata, ServiceObject } from './nodejs-common/index.js';
+import { Storage } from './storage.js';
+export interface StopCallback {
+ (err: Error | null, apiResponse?: unknown): void;
+}
+/**
+ * Create a channel object to interact with a Cloud Storage channel.
+ *
+ * See {@link https://cloud.google.com/storage/docs/object-change-notification| Object Change Notification}
+ *
+ * @class
+ *
+ * @param {string} id The ID of the channel.
+ * @param {string} resourceId The resource ID of the channel.
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const channel = storage.channel('id', 'resource-id');
+ * ```
+ */
+declare class Channel extends ServiceObject {
+ constructor(storage: Storage, id: string, resourceId: string);
+ stop(): Promise;
+ stop(callback: StopCallback): void;
+}
+/**
+ * Reference to the {@link Channel} class.
+ * @name module:@google-cloud/storage.Channel
+ * @see Channel
+ */
+export { Channel };
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/channel.js b/node_modules/@google-cloud/storage/build/cjs/src/channel.js
new file mode 100644
index 0000000..5b9c91c
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/channel.js
@@ -0,0 +1,104 @@
+"use strict";
+// Copyright 2019 Google LLC
+//
+// 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.Channel = void 0;
+const index_js_1 = require("./nodejs-common/index.js");
+const promisify_1 = require("@google-cloud/promisify");
+/**
+ * Create a channel object to interact with a Cloud Storage channel.
+ *
+ * See {@link https://cloud.google.com/storage/docs/object-change-notification| Object Change Notification}
+ *
+ * @class
+ *
+ * @param {string} id The ID of the channel.
+ * @param {string} resourceId The resource ID of the channel.
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const channel = storage.channel('id', 'resource-id');
+ * ```
+ */
+class Channel extends index_js_1.ServiceObject {
+ constructor(storage, id, resourceId) {
+ const config = {
+ parent: storage,
+ baseUrl: '/channels',
+ // An ID shouldn't be included in the API requests.
+ // RE:
+ // https://github.com/GoogleCloudPlatform/google-cloud-node/issues/1145
+ id: '',
+ methods: {
+ // Only need `request`.
+ },
+ };
+ super(config);
+ this.metadata.id = id;
+ this.metadata.resourceId = resourceId;
+ }
+ /**
+ * @typedef {array} StopResponse
+ * @property {object} 0 The full API response.
+ */
+ /**
+ * @callback StopCallback
+ * @param {?Error} err Request error, if any.
+ * @param {object} apiResponse The full API response.
+ */
+ /**
+ * Stop this channel.
+ *
+ * @param {StopCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const channel = storage.channel('id', 'resource-id');
+ * channel.stop(function(err, apiResponse) {
+ * if (!err) {
+ * // Channel stopped successfully.
+ * }
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * channel.stop().then(function(data) {
+ * const apiResponse = data[0];
+ * });
+ * ```
+ */
+ stop(callback) {
+ callback = callback || index_js_1.util.noop;
+ this.request({
+ method: 'POST',
+ uri: '/stop',
+ json: this.metadata,
+ }, (err, apiResponse) => {
+ callback(err, apiResponse);
+ });
+ }
+}
+exports.Channel = Channel;
+/*! Developer Documentation
+ *
+ * All async methods (except for streams) will return a Promise in the event
+ * that a callback is omitted.
+ */
+(0, promisify_1.promisifyAll)(Channel);
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/crc32c.d.ts b/node_modules/@google-cloud/storage/build/cjs/src/crc32c.d.ts
new file mode 100644
index 0000000..a15bd96
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/crc32c.d.ts
@@ -0,0 +1,145 @@
+///
+///
+import { PathLike } from 'fs';
+/**
+ * Ported from {@link https://github.com/google/crc32c/blob/21fc8ef30415a635e7351ffa0e5d5367943d4a94/src/crc32c_portable.cc#L16-L59 github.com/google/crc32c}
+ */
+declare const CRC32C_EXTENSIONS: readonly [0, 4067132163, 3778769143, 324072436, 3348797215, 904991772, 648144872, 3570033899, 2329499855, 2024987596, 1809983544, 2575936315, 1296289744, 3207089363, 2893594407, 1578318884, 274646895, 3795141740, 4049975192, 51262619, 3619967088, 632279923, 922689671, 3298075524, 2592579488, 1760304291, 2075979607, 2312596564, 1562183871, 2943781820, 3156637768, 1313733451, 549293790, 3537243613, 3246849577, 871202090, 3878099393, 357341890, 102525238, 4101499445, 2858735121, 1477399826, 1264559846, 3107202533, 1845379342, 2677391885, 2361733625, 2125378298, 820201905, 3263744690, 3520608582, 598981189, 4151959214, 85089709, 373468761, 3827903834, 3124367742, 1213305469, 1526817161, 2842354314, 2107672161, 2412447074, 2627466902, 1861252501, 1098587580, 3004210879, 2688576843, 1378610760, 2262928035, 1955203488, 1742404180, 2511436119, 3416409459, 969524848, 714683780, 3639785095, 205050476, 4266873199, 3976438427, 526918040, 1361435347, 2739821008, 2954799652, 1114974503, 2529119692, 1691668175, 2005155131, 2247081528, 3690758684, 697762079, 986182379, 3366744552, 476452099, 3993867776, 4250756596, 255256311, 1640403810, 2477592673, 2164122517, 1922457750, 2791048317, 1412925310, 1197962378, 3037525897, 3944729517, 427051182, 170179418, 4165941337, 746937522, 3740196785, 3451792453, 1070968646, 1905808397, 2213795598, 2426610938, 1657317369, 3053634322, 1147748369, 1463399397, 2773627110, 4215344322, 153784257, 444234805, 3893493558, 1021025245, 3467647198, 3722505002, 797665321, 2197175160, 1889384571, 1674398607, 2443626636, 1164749927, 3070701412, 2757221520, 1446797203, 137323447, 4198817972, 3910406976, 461344835, 3484808360, 1037989803, 781091935, 3705997148, 2460548119, 1623424788, 1939049696, 2180517859, 1429367560, 2807687179, 3020495871, 1180866812, 410100952, 3927582683, 4182430767, 186734380, 3756733383, 763408580, 1053836080, 3434856499, 2722870694, 1344288421, 1131464017, 2971354706, 1708204729, 2545590714, 2229949006, 1988219213, 680717673, 3673779818, 3383336350, 1002577565, 4010310262, 493091189, 238226049, 4233660802, 2987750089, 1082061258, 1395524158, 2705686845, 1972364758, 2279892693, 2494862625, 1725896226, 952904198, 3399985413, 3656866545, 731699698, 4283874585, 222117402, 510512622, 3959836397, 3280807620, 837199303, 582374963, 3504198960, 68661723, 4135334616, 3844915500, 390545967, 1230274059, 3141532936, 2825850620, 1510247935, 2395924756, 2091215383, 1878366691, 2644384480, 3553878443, 565732008, 854102364, 3229815391, 340358836, 3861050807, 4117890627, 119113024, 1493875044, 2875275879, 3090270611, 1247431312, 2660249211, 1828433272, 2141937292, 2378227087, 3811616794, 291187481, 34330861, 4032846830, 615137029, 3603020806, 3314634738, 939183345, 1776939221, 2609017814, 2295496738, 2058945313, 2926798794, 1545135305, 1330124605, 3173225534, 4084100981, 17165430, 307568514, 3762199681, 888469610, 3332340585, 3587147933, 665062302, 2042050490, 2346497209, 2559330125, 1793573966, 3190661285, 1279665062, 1595330642, 2910671697];
+declare const CRC32C_EXTENSION_TABLE: Int32Array;
+/** An interface for CRC32C hashing and validation */
+interface CRC32CValidator {
+ /**
+ * A method returning the CRC32C as a base64-encoded string.
+ *
+ * @example
+ * Hashing the string 'data' should return 'rth90Q=='
+ *
+ * ```js
+ * const buffer = Buffer.from('data');
+ * crc32c.update(buffer);
+ * crc32c.toString(); // 'rth90Q=='
+ * ```
+ **/
+ toString: () => string;
+ /**
+ * A method validating a base64-encoded CRC32C string.
+ *
+ * @example
+ * Should return `true` if the value matches, `false` otherwise
+ *
+ * ```js
+ * const buffer = Buffer.from('data');
+ * crc32c.update(buffer);
+ * crc32c.validate('DkjKuA=='); // false
+ * crc32c.validate('rth90Q=='); // true
+ * ```
+ */
+ validate: (value: string) => boolean;
+ /**
+ * A method for passing `Buffer`s for CRC32C generation.
+ *
+ * @example
+ * Hashing buffers from 'some ' and 'text\n'
+ *
+ * ```js
+ * const buffer1 = Buffer.from('some ');
+ * crc32c.update(buffer1);
+ *
+ * const buffer2 = Buffer.from('text\n');
+ * crc32c.update(buffer2);
+ *
+ * crc32c.toString(); // 'DkjKuA=='
+ * ```
+ */
+ update: (data: Buffer) => void;
+}
+/** A function that generates a CRC32C Validator */
+interface CRC32CValidatorGenerator {
+ /** Should return a new, ready-to-use `CRC32CValidator` */
+ (): CRC32CValidator;
+}
+declare const CRC32C_DEFAULT_VALIDATOR_GENERATOR: CRC32CValidatorGenerator;
+declare const CRC32C_EXCEPTION_MESSAGES: {
+ readonly INVALID_INIT_BASE64_RANGE: (l: number) => string;
+ readonly INVALID_INIT_BUFFER_LENGTH: (l: number) => string;
+ readonly INVALID_INIT_INTEGER: (l: number) => string;
+};
+declare class CRC32C implements CRC32CValidator {
+ #private;
+ /**
+ * Constructs a new `CRC32C` object.
+ *
+ * Reconstruction is recommended via the `CRC32C.from` static method.
+ *
+ * @param initialValue An initial CRC32C value - a signed 32-bit integer.
+ */
+ constructor(initialValue?: number);
+ /**
+ * Calculates a CRC32C from a provided buffer.
+ *
+ * Implementation inspired from:
+ * - {@link https://github.com/google/crc32c/blob/21fc8ef30415a635e7351ffa0e5d5367943d4a94/src/crc32c_portable.cc github.com/google/crc32c}
+ * - {@link https://github.com/googleapis/python-crc32c/blob/a595e758c08df445a99c3bf132ee8e80a3ec4308/src/google_crc32c/python.py github.com/googleapis/python-crc32c}
+ * - {@link https://github.com/googleapis/java-storage/pull/1376/files github.com/googleapis/java-storage}
+ *
+ * @param data The `Buffer` to generate the CRC32C from
+ */
+ update(data: Buffer): void;
+ /**
+ * Validates a provided input to the current CRC32C value.
+ *
+ * @param input A Buffer, `CRC32C`-compatible object, base64-encoded data (string), or signed 32-bit integer
+ */
+ validate(input: Buffer | CRC32CValidator | string | number): boolean;
+ /**
+ * Returns a `Buffer` representation of the CRC32C value
+ */
+ toBuffer(): Buffer;
+ /**
+ * Returns a JSON-compatible, base64-encoded representation of the CRC32C value.
+ *
+ * See {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify `JSON#stringify`}
+ */
+ toJSON(): string;
+ /**
+ * Returns a base64-encoded representation of the CRC32C value.
+ *
+ * See {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString `Object#toString`}
+ */
+ toString(): string;
+ /**
+ * Returns the `number` representation of the CRC32C value as a signed 32-bit integer
+ *
+ * See {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf `Object#valueOf`}
+ */
+ valueOf(): number;
+ static readonly CRC32C_EXTENSIONS: readonly [0, 4067132163, 3778769143, 324072436, 3348797215, 904991772, 648144872, 3570033899, 2329499855, 2024987596, 1809983544, 2575936315, 1296289744, 3207089363, 2893594407, 1578318884, 274646895, 3795141740, 4049975192, 51262619, 3619967088, 632279923, 922689671, 3298075524, 2592579488, 1760304291, 2075979607, 2312596564, 1562183871, 2943781820, 3156637768, 1313733451, 549293790, 3537243613, 3246849577, 871202090, 3878099393, 357341890, 102525238, 4101499445, 2858735121, 1477399826, 1264559846, 3107202533, 1845379342, 2677391885, 2361733625, 2125378298, 820201905, 3263744690, 3520608582, 598981189, 4151959214, 85089709, 373468761, 3827903834, 3124367742, 1213305469, 1526817161, 2842354314, 2107672161, 2412447074, 2627466902, 1861252501, 1098587580, 3004210879, 2688576843, 1378610760, 2262928035, 1955203488, 1742404180, 2511436119, 3416409459, 969524848, 714683780, 3639785095, 205050476, 4266873199, 3976438427, 526918040, 1361435347, 2739821008, 2954799652, 1114974503, 2529119692, 1691668175, 2005155131, 2247081528, 3690758684, 697762079, 986182379, 3366744552, 476452099, 3993867776, 4250756596, 255256311, 1640403810, 2477592673, 2164122517, 1922457750, 2791048317, 1412925310, 1197962378, 3037525897, 3944729517, 427051182, 170179418, 4165941337, 746937522, 3740196785, 3451792453, 1070968646, 1905808397, 2213795598, 2426610938, 1657317369, 3053634322, 1147748369, 1463399397, 2773627110, 4215344322, 153784257, 444234805, 3893493558, 1021025245, 3467647198, 3722505002, 797665321, 2197175160, 1889384571, 1674398607, 2443626636, 1164749927, 3070701412, 2757221520, 1446797203, 137323447, 4198817972, 3910406976, 461344835, 3484808360, 1037989803, 781091935, 3705997148, 2460548119, 1623424788, 1939049696, 2180517859, 1429367560, 2807687179, 3020495871, 1180866812, 410100952, 3927582683, 4182430767, 186734380, 3756733383, 763408580, 1053836080, 3434856499, 2722870694, 1344288421, 1131464017, 2971354706, 1708204729, 2545590714, 2229949006, 1988219213, 680717673, 3673779818, 3383336350, 1002577565, 4010310262, 493091189, 238226049, 4233660802, 2987750089, 1082061258, 1395524158, 2705686845, 1972364758, 2279892693, 2494862625, 1725896226, 952904198, 3399985413, 3656866545, 731699698, 4283874585, 222117402, 510512622, 3959836397, 3280807620, 837199303, 582374963, 3504198960, 68661723, 4135334616, 3844915500, 390545967, 1230274059, 3141532936, 2825850620, 1510247935, 2395924756, 2091215383, 1878366691, 2644384480, 3553878443, 565732008, 854102364, 3229815391, 340358836, 3861050807, 4117890627, 119113024, 1493875044, 2875275879, 3090270611, 1247431312, 2660249211, 1828433272, 2141937292, 2378227087, 3811616794, 291187481, 34330861, 4032846830, 615137029, 3603020806, 3314634738, 939183345, 1776939221, 2609017814, 2295496738, 2058945313, 2926798794, 1545135305, 1330124605, 3173225534, 4084100981, 17165430, 307568514, 3762199681, 888469610, 3332340585, 3587147933, 665062302, 2042050490, 2346497209, 2559330125, 1793573966, 3190661285, 1279665062, 1595330642, 2910671697];
+ static readonly CRC32C_EXTENSION_TABLE: Int32Array;
+ /**
+ * Generates a `CRC32C` from a compatible buffer format.
+ *
+ * @param value 4-byte `ArrayBufferView`/`Buffer`/`TypedArray`
+ */
+ private static fromBuffer;
+ static fromFile(file: PathLike): Promise;
+ /**
+ * Generates a `CRC32C` from 4-byte base64-encoded data (string).
+ *
+ * @param value 4-byte base64-encoded data (string)
+ */
+ private static fromString;
+ /**
+ * Generates a `CRC32C` from a safe, unsigned 32-bit integer.
+ *
+ * @param value an unsigned 32-bit integer
+ */
+ private static fromNumber;
+ /**
+ * Generates a `CRC32C` from a variety of compatable types.
+ * Note: strings are treated as input, not as file paths to read from.
+ *
+ * @param value A number, 4-byte `ArrayBufferView`/`Buffer`/`TypedArray`, or 4-byte base64-encoded data (string)
+ */
+ static from(value: ArrayBuffer | ArrayBufferView | CRC32CValidator | string | number): CRC32C;
+}
+export { CRC32C, CRC32C_DEFAULT_VALIDATOR_GENERATOR, CRC32C_EXCEPTION_MESSAGES, CRC32C_EXTENSIONS, CRC32C_EXTENSION_TABLE, CRC32CValidator, CRC32CValidatorGenerator, };
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/crc32c.js b/node_modules/@google-cloud/storage/build/cjs/src/crc32c.js
new file mode 100644
index 0000000..8847edd
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/crc32c.js
@@ -0,0 +1,254 @@
+"use strict";
+// Copyright 2022 Google LLC
+//
+// 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.
+var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
+ if (kind === "m") throw new TypeError("Private method is not writable");
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
+};
+var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var _CRC32C_crc32c;
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.CRC32C_EXTENSION_TABLE = exports.CRC32C_EXTENSIONS = exports.CRC32C_EXCEPTION_MESSAGES = exports.CRC32C_DEFAULT_VALIDATOR_GENERATOR = exports.CRC32C = void 0;
+const fs_1 = require("fs");
+/**
+ * Ported from {@link https://github.com/google/crc32c/blob/21fc8ef30415a635e7351ffa0e5d5367943d4a94/src/crc32c_portable.cc#L16-L59 github.com/google/crc32c}
+ */
+const CRC32C_EXTENSIONS = [
+ 0x00000000, 0xf26b8303, 0xe13b70f7, 0x1350f3f4, 0xc79a971f, 0x35f1141c,
+ 0x26a1e7e8, 0xd4ca64eb, 0x8ad958cf, 0x78b2dbcc, 0x6be22838, 0x9989ab3b,
+ 0x4d43cfd0, 0xbf284cd3, 0xac78bf27, 0x5e133c24, 0x105ec76f, 0xe235446c,
+ 0xf165b798, 0x030e349b, 0xd7c45070, 0x25afd373, 0x36ff2087, 0xc494a384,
+ 0x9a879fa0, 0x68ec1ca3, 0x7bbcef57, 0x89d76c54, 0x5d1d08bf, 0xaf768bbc,
+ 0xbc267848, 0x4e4dfb4b, 0x20bd8ede, 0xd2d60ddd, 0xc186fe29, 0x33ed7d2a,
+ 0xe72719c1, 0x154c9ac2, 0x061c6936, 0xf477ea35, 0xaa64d611, 0x580f5512,
+ 0x4b5fa6e6, 0xb93425e5, 0x6dfe410e, 0x9f95c20d, 0x8cc531f9, 0x7eaeb2fa,
+ 0x30e349b1, 0xc288cab2, 0xd1d83946, 0x23b3ba45, 0xf779deae, 0x05125dad,
+ 0x1642ae59, 0xe4292d5a, 0xba3a117e, 0x4851927d, 0x5b016189, 0xa96ae28a,
+ 0x7da08661, 0x8fcb0562, 0x9c9bf696, 0x6ef07595, 0x417b1dbc, 0xb3109ebf,
+ 0xa0406d4b, 0x522bee48, 0x86e18aa3, 0x748a09a0, 0x67dafa54, 0x95b17957,
+ 0xcba24573, 0x39c9c670, 0x2a993584, 0xd8f2b687, 0x0c38d26c, 0xfe53516f,
+ 0xed03a29b, 0x1f682198, 0x5125dad3, 0xa34e59d0, 0xb01eaa24, 0x42752927,
+ 0x96bf4dcc, 0x64d4cecf, 0x77843d3b, 0x85efbe38, 0xdbfc821c, 0x2997011f,
+ 0x3ac7f2eb, 0xc8ac71e8, 0x1c661503, 0xee0d9600, 0xfd5d65f4, 0x0f36e6f7,
+ 0x61c69362, 0x93ad1061, 0x80fde395, 0x72966096, 0xa65c047d, 0x5437877e,
+ 0x4767748a, 0xb50cf789, 0xeb1fcbad, 0x197448ae, 0x0a24bb5a, 0xf84f3859,
+ 0x2c855cb2, 0xdeeedfb1, 0xcdbe2c45, 0x3fd5af46, 0x7198540d, 0x83f3d70e,
+ 0x90a324fa, 0x62c8a7f9, 0xb602c312, 0x44694011, 0x5739b3e5, 0xa55230e6,
+ 0xfb410cc2, 0x092a8fc1, 0x1a7a7c35, 0xe811ff36, 0x3cdb9bdd, 0xceb018de,
+ 0xdde0eb2a, 0x2f8b6829, 0x82f63b78, 0x709db87b, 0x63cd4b8f, 0x91a6c88c,
+ 0x456cac67, 0xb7072f64, 0xa457dc90, 0x563c5f93, 0x082f63b7, 0xfa44e0b4,
+ 0xe9141340, 0x1b7f9043, 0xcfb5f4a8, 0x3dde77ab, 0x2e8e845f, 0xdce5075c,
+ 0x92a8fc17, 0x60c37f14, 0x73938ce0, 0x81f80fe3, 0x55326b08, 0xa759e80b,
+ 0xb4091bff, 0x466298fc, 0x1871a4d8, 0xea1a27db, 0xf94ad42f, 0x0b21572c,
+ 0xdfeb33c7, 0x2d80b0c4, 0x3ed04330, 0xccbbc033, 0xa24bb5a6, 0x502036a5,
+ 0x4370c551, 0xb11b4652, 0x65d122b9, 0x97baa1ba, 0x84ea524e, 0x7681d14d,
+ 0x2892ed69, 0xdaf96e6a, 0xc9a99d9e, 0x3bc21e9d, 0xef087a76, 0x1d63f975,
+ 0x0e330a81, 0xfc588982, 0xb21572c9, 0x407ef1ca, 0x532e023e, 0xa145813d,
+ 0x758fe5d6, 0x87e466d5, 0x94b49521, 0x66df1622, 0x38cc2a06, 0xcaa7a905,
+ 0xd9f75af1, 0x2b9cd9f2, 0xff56bd19, 0x0d3d3e1a, 0x1e6dcdee, 0xec064eed,
+ 0xc38d26c4, 0x31e6a5c7, 0x22b65633, 0xd0ddd530, 0x0417b1db, 0xf67c32d8,
+ 0xe52cc12c, 0x1747422f, 0x49547e0b, 0xbb3ffd08, 0xa86f0efc, 0x5a048dff,
+ 0x8ecee914, 0x7ca56a17, 0x6ff599e3, 0x9d9e1ae0, 0xd3d3e1ab, 0x21b862a8,
+ 0x32e8915c, 0xc083125f, 0x144976b4, 0xe622f5b7, 0xf5720643, 0x07198540,
+ 0x590ab964, 0xab613a67, 0xb831c993, 0x4a5a4a90, 0x9e902e7b, 0x6cfbad78,
+ 0x7fab5e8c, 0x8dc0dd8f, 0xe330a81a, 0x115b2b19, 0x020bd8ed, 0xf0605bee,
+ 0x24aa3f05, 0xd6c1bc06, 0xc5914ff2, 0x37faccf1, 0x69e9f0d5, 0x9b8273d6,
+ 0x88d28022, 0x7ab90321, 0xae7367ca, 0x5c18e4c9, 0x4f48173d, 0xbd23943e,
+ 0xf36e6f75, 0x0105ec76, 0x12551f82, 0xe03e9c81, 0x34f4f86a, 0xc69f7b69,
+ 0xd5cf889d, 0x27a40b9e, 0x79b737ba, 0x8bdcb4b9, 0x988c474d, 0x6ae7c44e,
+ 0xbe2da0a5, 0x4c4623a6, 0x5f16d052, 0xad7d5351,
+];
+exports.CRC32C_EXTENSIONS = CRC32C_EXTENSIONS;
+const CRC32C_EXTENSION_TABLE = new Int32Array(CRC32C_EXTENSIONS);
+exports.CRC32C_EXTENSION_TABLE = CRC32C_EXTENSION_TABLE;
+const CRC32C_DEFAULT_VALIDATOR_GENERATOR = () => new CRC32C();
+exports.CRC32C_DEFAULT_VALIDATOR_GENERATOR = CRC32C_DEFAULT_VALIDATOR_GENERATOR;
+const CRC32C_EXCEPTION_MESSAGES = {
+ INVALID_INIT_BASE64_RANGE: (l) => `base64-encoded data expected to equal 4 bytes, not ${l}`,
+ INVALID_INIT_BUFFER_LENGTH: (l) => `Buffer expected to equal 4 bytes, not ${l}`,
+ INVALID_INIT_INTEGER: (l) => `Number expected to be a safe, unsigned 32-bit integer, not ${l}`,
+};
+exports.CRC32C_EXCEPTION_MESSAGES = CRC32C_EXCEPTION_MESSAGES;
+class CRC32C {
+ /**
+ * Constructs a new `CRC32C` object.
+ *
+ * Reconstruction is recommended via the `CRC32C.from` static method.
+ *
+ * @param initialValue An initial CRC32C value - a signed 32-bit integer.
+ */
+ constructor(initialValue = 0) {
+ /** Current CRC32C value */
+ _CRC32C_crc32c.set(this, 0);
+ __classPrivateFieldSet(this, _CRC32C_crc32c, initialValue, "f");
+ }
+ /**
+ * Calculates a CRC32C from a provided buffer.
+ *
+ * Implementation inspired from:
+ * - {@link https://github.com/google/crc32c/blob/21fc8ef30415a635e7351ffa0e5d5367943d4a94/src/crc32c_portable.cc github.com/google/crc32c}
+ * - {@link https://github.com/googleapis/python-crc32c/blob/a595e758c08df445a99c3bf132ee8e80a3ec4308/src/google_crc32c/python.py github.com/googleapis/python-crc32c}
+ * - {@link https://github.com/googleapis/java-storage/pull/1376/files github.com/googleapis/java-storage}
+ *
+ * @param data The `Buffer` to generate the CRC32C from
+ */
+ update(data) {
+ let current = __classPrivateFieldGet(this, _CRC32C_crc32c, "f") ^ 0xffffffff;
+ for (const d of data) {
+ const tablePoly = CRC32C.CRC32C_EXTENSION_TABLE[(d ^ current) & 0xff];
+ current = tablePoly ^ (current >>> 8);
+ }
+ __classPrivateFieldSet(this, _CRC32C_crc32c, current ^ 0xffffffff, "f");
+ }
+ /**
+ * Validates a provided input to the current CRC32C value.
+ *
+ * @param input A Buffer, `CRC32C`-compatible object, base64-encoded data (string), or signed 32-bit integer
+ */
+ validate(input) {
+ if (typeof input === 'number') {
+ return input === __classPrivateFieldGet(this, _CRC32C_crc32c, "f");
+ }
+ else if (typeof input === 'string') {
+ return input === this.toString();
+ }
+ else if (Buffer.isBuffer(input)) {
+ return Buffer.compare(input, this.toBuffer()) === 0;
+ }
+ else {
+ // `CRC32C`-like object
+ return input.toString() === this.toString();
+ }
+ }
+ /**
+ * Returns a `Buffer` representation of the CRC32C value
+ */
+ toBuffer() {
+ const buffer = Buffer.alloc(4);
+ buffer.writeInt32BE(__classPrivateFieldGet(this, _CRC32C_crc32c, "f"));
+ return buffer;
+ }
+ /**
+ * Returns a JSON-compatible, base64-encoded representation of the CRC32C value.
+ *
+ * See {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify `JSON#stringify`}
+ */
+ toJSON() {
+ return this.toString();
+ }
+ /**
+ * Returns a base64-encoded representation of the CRC32C value.
+ *
+ * See {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/toString `Object#toString`}
+ */
+ toString() {
+ return this.toBuffer().toString('base64');
+ }
+ /**
+ * Returns the `number` representation of the CRC32C value as a signed 32-bit integer
+ *
+ * See {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/valueOf `Object#valueOf`}
+ */
+ valueOf() {
+ return __classPrivateFieldGet(this, _CRC32C_crc32c, "f");
+ }
+ /**
+ * Generates a `CRC32C` from a compatible buffer format.
+ *
+ * @param value 4-byte `ArrayBufferView`/`Buffer`/`TypedArray`
+ */
+ static fromBuffer(value) {
+ let buffer;
+ if (Buffer.isBuffer(value)) {
+ buffer = value;
+ }
+ else if ('buffer' in value) {
+ // `ArrayBufferView`
+ buffer = Buffer.from(value.buffer);
+ }
+ else {
+ // `ArrayBuffer`
+ buffer = Buffer.from(value);
+ }
+ if (buffer.byteLength !== 4) {
+ throw new RangeError(CRC32C_EXCEPTION_MESSAGES.INVALID_INIT_BUFFER_LENGTH(buffer.byteLength));
+ }
+ return new CRC32C(buffer.readInt32BE());
+ }
+ static async fromFile(file) {
+ const crc32c = new CRC32C();
+ await new Promise((resolve, reject) => {
+ (0, fs_1.createReadStream)(file)
+ .on('data', (d) => crc32c.update(d))
+ .on('end', resolve)
+ .on('error', reject);
+ });
+ return crc32c;
+ }
+ /**
+ * Generates a `CRC32C` from 4-byte base64-encoded data (string).
+ *
+ * @param value 4-byte base64-encoded data (string)
+ */
+ static fromString(value) {
+ const buffer = Buffer.from(value, 'base64');
+ if (buffer.byteLength !== 4) {
+ throw new RangeError(CRC32C_EXCEPTION_MESSAGES.INVALID_INIT_BASE64_RANGE(buffer.byteLength));
+ }
+ return this.fromBuffer(buffer);
+ }
+ /**
+ * Generates a `CRC32C` from a safe, unsigned 32-bit integer.
+ *
+ * @param value an unsigned 32-bit integer
+ */
+ static fromNumber(value) {
+ if (!Number.isSafeInteger(value) || value > 2 ** 32 || value < -(2 ** 32)) {
+ throw new RangeError(CRC32C_EXCEPTION_MESSAGES.INVALID_INIT_INTEGER(value));
+ }
+ return new CRC32C(value);
+ }
+ /**
+ * Generates a `CRC32C` from a variety of compatable types.
+ * Note: strings are treated as input, not as file paths to read from.
+ *
+ * @param value A number, 4-byte `ArrayBufferView`/`Buffer`/`TypedArray`, or 4-byte base64-encoded data (string)
+ */
+ static from(value) {
+ if (typeof value === 'number') {
+ return this.fromNumber(value);
+ }
+ else if (typeof value === 'string') {
+ return this.fromString(value);
+ }
+ else if ('byteLength' in value) {
+ // `ArrayBuffer` | `Buffer` | `ArrayBufferView`
+ return this.fromBuffer(value);
+ }
+ else {
+ // `CRC32CValidator`/`CRC32C`-like
+ return this.fromString(value.toString());
+ }
+ }
+}
+exports.CRC32C = CRC32C;
+_CRC32C_crc32c = new WeakMap();
+CRC32C.CRC32C_EXTENSIONS = CRC32C_EXTENSIONS;
+CRC32C.CRC32C_EXTENSION_TABLE = CRC32C_EXTENSION_TABLE;
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/file.d.ts b/node_modules/@google-cloud/storage/build/cjs/src/file.d.ts
new file mode 100644
index 0000000..2b315a8
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/file.d.ts
@@ -0,0 +1,961 @@
+///
+///
+///
+///
+import { BodyResponseCallback, DecorateRequestOptions, GetConfig, MetadataCallback, ServiceObject, SetMetadataResponse } from './nodejs-common/index.js';
+import * as resumableUpload from './resumable-upload.js';
+import { Writable, Readable, PipelineSource } from 'stream';
+import * as http from 'http';
+import { PreconditionOptions, Storage } from './storage.js';
+import { AvailableServiceObjectMethods, Bucket } from './bucket.js';
+import { Acl, AclMetadata } from './acl.js';
+import { GetSignedUrlResponse, GetSignedUrlCallback, URLSigner, SignerGetSignedUrlConfig, Query } from './signer.js';
+import { Duplexify, GCCL_GCS_CMD_KEY } from './nodejs-common/util.js';
+import { CRC32C, CRC32CValidatorGenerator } from './crc32c.js';
+import { URL } from 'url';
+import { BaseMetadata, DeleteCallback, DeleteOptions, GetResponse, InstanceResponseCallback, RequestResponse, SetMetadataOptions } from './nodejs-common/service-object.js';
+import * as r from 'teeny-request';
+export type GetExpirationDateResponse = [Date];
+export interface GetExpirationDateCallback {
+ (err: Error | null, expirationDate?: Date | null, apiResponse?: unknown): void;
+}
+export interface PolicyDocument {
+ string: string;
+ base64: string;
+ signature: string;
+}
+export type SaveData = string | Buffer | PipelineSource;
+export type GenerateSignedPostPolicyV2Response = [PolicyDocument];
+export interface GenerateSignedPostPolicyV2Callback {
+ (err: Error | null, policy?: PolicyDocument): void;
+}
+export interface GenerateSignedPostPolicyV2Options {
+ equals?: string[] | string[][];
+ expires: string | number | Date;
+ startsWith?: string[] | string[][];
+ acl?: string;
+ successRedirect?: string;
+ successStatus?: string;
+ contentLengthRange?: {
+ min?: number;
+ max?: number;
+ };
+ /**
+ * @example
+ * 'https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/'
+ */
+ signingEndpoint?: string;
+}
+export interface PolicyFields {
+ [key: string]: string;
+}
+export interface GenerateSignedPostPolicyV4Options {
+ expires: string | number | Date;
+ bucketBoundHostname?: string;
+ virtualHostedStyle?: boolean;
+ conditions?: object[];
+ fields?: PolicyFields;
+ /**
+ * @example
+ * 'https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/'
+ */
+ signingEndpoint?: string;
+}
+export interface GenerateSignedPostPolicyV4Callback {
+ (err: Error | null, output?: SignedPostPolicyV4Output): void;
+}
+export type GenerateSignedPostPolicyV4Response = [SignedPostPolicyV4Output];
+export interface SignedPostPolicyV4Output {
+ url: string;
+ fields: PolicyFields;
+}
+export interface GetSignedUrlConfig extends Pick {
+ action: 'read' | 'write' | 'delete' | 'resumable';
+ version?: 'v2' | 'v4';
+ virtualHostedStyle?: boolean;
+ cname?: string;
+ contentMd5?: string;
+ contentType?: string;
+ expires: string | number | Date;
+ accessibleAt?: string | number | Date;
+ extensionHeaders?: http.OutgoingHttpHeaders;
+ promptSaveAs?: string;
+ responseDisposition?: string;
+ responseType?: string;
+ queryParams?: Query;
+}
+export interface GetFileMetadataOptions {
+ userProject?: string;
+}
+export type GetFileMetadataResponse = [FileMetadata, unknown];
+export interface GetFileMetadataCallback {
+ (err: Error | null, metadata?: FileMetadata, apiResponse?: unknown): void;
+}
+export interface GetFileOptions extends GetConfig {
+ userProject?: string;
+ generation?: number;
+ softDeleted?: boolean;
+}
+export type GetFileResponse = [File, unknown];
+export interface GetFileCallback {
+ (err: Error | null, file?: File, apiResponse?: unknown): void;
+}
+export interface FileExistsOptions {
+ userProject?: string;
+}
+export type FileExistsResponse = [boolean];
+export interface FileExistsCallback {
+ (err: Error | null, exists?: boolean): void;
+}
+export interface DeleteFileOptions {
+ ignoreNotFound?: boolean;
+ userProject?: string;
+}
+export type DeleteFileResponse = [unknown];
+export interface DeleteFileCallback {
+ (err: Error | null, apiResponse?: unknown): void;
+}
+export type PredefinedAcl = 'authenticatedRead' | 'bucketOwnerFullControl' | 'bucketOwnerRead' | 'private' | 'projectPrivate' | 'publicRead';
+type PublicResumableUploadOptions = 'chunkSize' | 'highWaterMark' | 'isPartialUpload' | 'metadata' | 'origin' | 'offset' | 'predefinedAcl' | 'private' | 'public' | 'uri' | 'userProject';
+export interface CreateResumableUploadOptions extends Pick {
+ /**
+ * A CRC32C to resume from when continuing a previous upload. It is recommended
+ * to capture the `crc32c` event from previous upload sessions to provide in
+ * subsequent requests in order to accurately track the upload. This is **required**
+ * when validating a final portion of the uploaded object.
+ *
+ * @see {@link CRC32C.from} for possible values.
+ */
+ resumeCRC32C?: Parameters<(typeof CRC32C)['from']>[0];
+ preconditionOpts?: PreconditionOptions;
+ [GCCL_GCS_CMD_KEY]?: resumableUpload.UploadConfig[typeof GCCL_GCS_CMD_KEY];
+}
+export type CreateResumableUploadResponse = [string];
+export interface CreateResumableUploadCallback {
+ (err: Error | null, uri?: string): void;
+}
+export interface CreateWriteStreamOptions extends CreateResumableUploadOptions {
+ contentType?: string;
+ gzip?: string | boolean;
+ resumable?: boolean;
+ timeout?: number;
+ validation?: string | boolean;
+}
+export interface MakeFilePrivateOptions {
+ metadata?: FileMetadata;
+ strict?: boolean;
+ userProject?: string;
+ preconditionOpts?: PreconditionOptions;
+}
+export type MakeFilePrivateResponse = [unknown];
+export type MakeFilePrivateCallback = SetFileMetadataCallback;
+export interface IsPublicCallback {
+ (err: Error | null, resp?: boolean): void;
+}
+export type IsPublicResponse = [boolean];
+export type MakeFilePublicResponse = [unknown];
+export interface MakeFilePublicCallback {
+ (err?: Error | null, apiResponse?: unknown): void;
+}
+export type MoveResponse = [unknown];
+export interface MoveCallback {
+ (err: Error | null, destinationFile?: File | null, apiResponse?: unknown): void;
+}
+export interface MoveOptions {
+ userProject?: string;
+ preconditionOpts?: PreconditionOptions;
+}
+export type RenameOptions = MoveOptions;
+export type RenameResponse = MoveResponse;
+export type RenameCallback = MoveCallback;
+export type RotateEncryptionKeyOptions = string | Buffer | EncryptionKeyOptions;
+export interface EncryptionKeyOptions {
+ encryptionKey?: string | Buffer;
+ kmsKeyName?: string;
+ preconditionOpts?: PreconditionOptions;
+}
+export type RotateEncryptionKeyCallback = CopyCallback;
+export type RotateEncryptionKeyResponse = CopyResponse;
+export declare enum ActionToHTTPMethod {
+ read = "GET",
+ write = "PUT",
+ delete = "DELETE",
+ resumable = "POST"
+}
+/**
+ * @deprecated - no longer used
+ */
+export declare const STORAGE_POST_POLICY_BASE_URL = "https://storage.googleapis.com";
+export interface FileOptions {
+ crc32cGenerator?: CRC32CValidatorGenerator;
+ encryptionKey?: string | Buffer;
+ generation?: number | string;
+ kmsKeyName?: string;
+ preconditionOpts?: PreconditionOptions;
+ userProject?: string;
+}
+export interface CopyOptions {
+ cacheControl?: string;
+ contentEncoding?: string;
+ contentType?: string;
+ contentDisposition?: string;
+ destinationKmsKeyName?: string;
+ metadata?: FileMetadata;
+ predefinedAcl?: string;
+ token?: string;
+ userProject?: string;
+ preconditionOpts?: PreconditionOptions;
+}
+export type CopyResponse = [File, unknown];
+export interface CopyCallback {
+ (err: Error | null, file?: File | null, apiResponse?: unknown): void;
+}
+export type DownloadResponse = [Buffer];
+export type DownloadCallback = (err: RequestError | null, contents: Buffer) => void;
+export interface DownloadOptions extends CreateReadStreamOptions {
+ destination?: string;
+}
+export interface CreateReadStreamOptions {
+ userProject?: string;
+ validation?: 'md5' | 'crc32c' | false | true;
+ start?: number;
+ end?: number;
+ decompress?: boolean;
+ [GCCL_GCS_CMD_KEY]?: string;
+}
+export interface SaveOptions extends CreateWriteStreamOptions {
+ onUploadProgress?: (progressEvent: any) => void;
+}
+export interface SaveCallback {
+ (err?: Error | null): void;
+}
+export interface SetFileMetadataOptions {
+ userProject?: string;
+}
+export interface SetFileMetadataCallback {
+ (err?: Error | null, apiResponse?: unknown): void;
+}
+export type SetFileMetadataResponse = [unknown];
+export type SetStorageClassResponse = [unknown];
+export interface SetStorageClassOptions {
+ userProject?: string;
+ preconditionOpts?: PreconditionOptions;
+}
+export interface SetStorageClassCallback {
+ (err?: Error | null, apiResponse?: unknown): void;
+}
+export interface RestoreOptions extends PreconditionOptions {
+ generation: number;
+ projection?: 'full' | 'noAcl';
+}
+export interface FileMetadata extends BaseMetadata {
+ acl?: AclMetadata[] | null;
+ bucket?: string;
+ cacheControl?: string;
+ componentCount?: number;
+ contentDisposition?: string;
+ contentEncoding?: string;
+ contentLanguage?: string;
+ contentType?: string;
+ crc32c?: string;
+ customerEncryption?: {
+ encryptionAlgorithm?: string;
+ keySha256?: string;
+ };
+ customTime?: string;
+ eventBasedHold?: boolean | null;
+ readonly eventBasedHoldReleaseTime?: string;
+ generation?: string | number;
+ hardDeleteTime?: string;
+ kmsKeyName?: string;
+ md5Hash?: string;
+ mediaLink?: string;
+ metadata?: {
+ [key: string]: string;
+ };
+ metageneration?: string | number;
+ name?: string;
+ owner?: {
+ entity?: string;
+ entityId?: string;
+ };
+ retention?: {
+ retainUntilTime?: string;
+ mode?: string;
+ } | null;
+ retentionExpirationTime?: string;
+ size?: string | number;
+ softDeleteTime?: string;
+ storageClass?: string;
+ temporaryHold?: boolean | null;
+ timeCreated?: string;
+ timeDeleted?: string;
+ timeStorageClassUpdated?: string;
+ updated?: string;
+}
+export declare class RequestError extends Error {
+ code?: string;
+ errors?: Error[];
+}
+export declare enum FileExceptionMessages {
+ EXPIRATION_TIME_NA = "An expiration time is not available.",
+ DESTINATION_NO_NAME = "Destination file should have a name.",
+ INVALID_VALIDATION_FILE_RANGE = "Cannot use validation with file ranges (start/end).",
+ MD5_NOT_AVAILABLE = "MD5 verification was specified, but is not available for the requested object. MD5 is not available for composite objects.",
+ EQUALS_CONDITION_TWO_ELEMENTS = "Equals condition must be an array of 2 elements.",
+ STARTS_WITH_TWO_ELEMENTS = "StartsWith condition must be an array of 2 elements.",
+ CONTENT_LENGTH_RANGE_MIN_MAX = "ContentLengthRange must have numeric min & max fields.",
+ DOWNLOAD_MISMATCH = "The downloaded data did not match the data from the server. To be sure the content is the same, you should download the file again.",
+ UPLOAD_MISMATCH_DELETE_FAIL = "The uploaded data did not match the data from the server.\n As a precaution, we attempted to delete the file, but it was not successful.\n To be sure the content is the same, you should try removing the file manually,\n then uploading the file again.\n \n\nThe delete attempt failed with this message:\n\n ",
+ UPLOAD_MISMATCH = "The uploaded data did not match the data from the server.\n As a precaution, the file has been deleted.\n To be sure the content is the same, you should try uploading the file again.",
+ MD5_RESUMED_UPLOAD = "MD5 cannot be used with a continued resumable upload as MD5 cannot be extended from an existing value",
+ MISSING_RESUME_CRC32C_FINAL_UPLOAD = "The CRC32C is missing for the final portion of a resumed upload, which is required for validation. Please provide `resumeCRC32C` if validation is required, or disable `validation`."
+}
+/**
+ * A File object is created from your {@link Bucket} object using
+ * {@link Bucket#file}.
+ *
+ * @class
+ */
+declare class File extends ServiceObject {
+ #private;
+ acl: Acl;
+ crc32cGenerator: CRC32CValidatorGenerator;
+ bucket: Bucket;
+ storage: Storage;
+ kmsKeyName?: string;
+ userProject?: string;
+ signer?: URLSigner;
+ name: string;
+ generation?: number;
+ parent: Bucket;
+ private encryptionKey?;
+ private encryptionKeyBase64?;
+ private encryptionKeyHash?;
+ private encryptionKeyInterceptor?;
+ private instanceRetryValue?;
+ instancePreconditionOpts?: PreconditionOptions;
+ /**
+ * Cloud Storage uses access control lists (ACLs) to manage object and
+ * bucket access. ACLs are the mechanism you use to share objects with other
+ * users and allow other users to access your buckets and objects.
+ *
+ * An ACL consists of one or more entries, where each entry grants permissions
+ * to an entity. Permissions define the actions that can be performed against
+ * an object or bucket (for example, `READ` or `WRITE`); the entity defines
+ * who the permission applies to (for example, a specific user or group of
+ * users).
+ *
+ * The `acl` object on a File instance provides methods to get you a list of
+ * the ACLs defined on your bucket, as well as set, update, and delete them.
+ *
+ * See {@link http://goo.gl/6qBBPO| About Access Control lists}
+ *
+ * @name File#acl
+ * @mixes Acl
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const file = myBucket.file('my-file');
+ * //-
+ * // Make a file publicly readable.
+ * //-
+ * const options = {
+ * entity: 'allUsers',
+ * role: storage.acl.READER_ROLE
+ * };
+ *
+ * file.acl.add(options, function(err, aclObject) {});
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * file.acl.add(options).then(function(data) {
+ * const aclObject = data[0];
+ * const apiResponse = data[1];
+ * });
+ * ```
+ */
+ /**
+ * The API-formatted resource description of the file.
+ *
+ * Note: This is not guaranteed to be up-to-date when accessed. To get the
+ * latest record, call the `getMetadata()` method.
+ *
+ * @name File#metadata
+ * @type {object}
+ */
+ /**
+ * The file's name.
+ * @name File#name
+ * @type {string}
+ */
+ /**
+ * @callback Crc32cGeneratorToStringCallback
+ * A method returning the CRC32C as a base64-encoded string.
+ *
+ * @returns {string}
+ *
+ * @example
+ * Hashing the string 'data' should return 'rth90Q=='
+ *
+ * ```js
+ * const buffer = Buffer.from('data');
+ * crc32c.update(buffer);
+ * crc32c.toString(); // 'rth90Q=='
+ * ```
+ **/
+ /**
+ * @callback Crc32cGeneratorValidateCallback
+ * A method validating a base64-encoded CRC32C string.
+ *
+ * @param {string} [value] base64-encoded CRC32C string to validate
+ * @returns {boolean}
+ *
+ * @example
+ * Should return `true` if the value matches, `false` otherwise
+ *
+ * ```js
+ * const buffer = Buffer.from('data');
+ * crc32c.update(buffer);
+ * crc32c.validate('DkjKuA=='); // false
+ * crc32c.validate('rth90Q=='); // true
+ * ```
+ **/
+ /**
+ * @callback Crc32cGeneratorUpdateCallback
+ * A method for passing `Buffer`s for CRC32C generation.
+ *
+ * @param {Buffer} [data] data to update CRC32C value with
+ * @returns {undefined}
+ *
+ * @example
+ * Hashing buffers from 'some ' and 'text\n'
+ *
+ * ```js
+ * const buffer1 = Buffer.from('some ');
+ * crc32c.update(buffer1);
+ *
+ * const buffer2 = Buffer.from('text\n');
+ * crc32c.update(buffer2);
+ *
+ * crc32c.toString(); // 'DkjKuA=='
+ * ```
+ **/
+ /**
+ * @typedef {object} CRC32CValidator
+ * @property {Crc32cGeneratorToStringCallback}
+ * @property {Crc32cGeneratorValidateCallback}
+ * @property {Crc32cGeneratorUpdateCallback}
+ */
+ /**
+ * @callback Crc32cGeneratorCallback
+ * @returns {CRC32CValidator}
+ */
+ /**
+ * @typedef {object} FileOptions Options passed to the File constructor.
+ * @property {string} [encryptionKey] A custom encryption key.
+ * @property {number} [generation] Generation to scope the file to.
+ * @property {string} [kmsKeyName] Cloud KMS Key used to encrypt this
+ * object, if the object is encrypted by such a key. Limited availability;
+ * usable only by enabled projects.
+ * @property {string} [userProject] The ID of the project which will be
+ * billed for all requests made from File object.
+ * @property {Crc32cGeneratorCallback} [callback] A function that generates a CRC32C Validator. Defaults to {@link CRC32C}
+ */
+ /**
+ * Constructs a file object.
+ *
+ * @param {Bucket} bucket The Bucket instance this file is
+ * attached to.
+ * @param {string} name The name of the remote file.
+ * @param {FileOptions} [options] Configuration options.
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const file = myBucket.file('my-file');
+ * ```
+ */
+ constructor(bucket: Bucket, name: string, options?: FileOptions);
+ /**
+ * The object's Cloud Storage URI (`gs://`)
+ *
+ * @example
+ * ```ts
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('my-bucket');
+ * const file = bucket.file('image.png');
+ *
+ * // `gs://my-bucket/image.png`
+ * const href = file.cloudStorageURI.href;
+ * ```
+ */
+ get cloudStorageURI(): URL;
+ /**
+ * A helper method for determining if a request should be retried based on preconditions.
+ * This should only be used for methods where the idempotency is determined by
+ * `ifGenerationMatch`
+ * @private
+ *
+ * A request should not be retried under the following conditions:
+ * - if precondition option `ifGenerationMatch` is not set OR
+ * - if `idempotencyStrategy` is set to `RetryNever`
+ */
+ private shouldRetryBasedOnPreconditionAndIdempotencyStrat;
+ copy(destination: string | Bucket | File, options?: CopyOptions): Promise;
+ copy(destination: string | Bucket | File, callback: CopyCallback): void;
+ copy(destination: string | Bucket | File, options: CopyOptions, callback: CopyCallback): void;
+ /**
+ * @typedef {object} CreateReadStreamOptions Configuration options for File#createReadStream.
+ * @property {string} [userProject] The ID of the project which will be
+ * billed for the request.
+ * @property {string|boolean} [validation] Possible values: `"md5"`,
+ * `"crc32c"`, or `false`. By default, data integrity is validated with a
+ * CRC32c checksum. You may use MD5 if preferred, but that hash is not
+ * supported for composite objects. An error will be raised if MD5 is
+ * specified but is not available. You may also choose to skip validation
+ * completely, however this is **not recommended**.
+ * @property {number} [start] A byte offset to begin the file's download
+ * from. Default is 0. NOTE: Byte ranges are inclusive; that is,
+ * `options.start = 0` and `options.end = 999` represent the first 1000
+ * bytes in a file or object. NOTE: when specifying a byte range, data
+ * integrity is not available.
+ * @property {number} [end] A byte offset to stop reading the file at.
+ * NOTE: Byte ranges are inclusive; that is, `options.start = 0` and
+ * `options.end = 999` represent the first 1000 bytes in a file or object.
+ * NOTE: when specifying a byte range, data integrity is not available.
+ * @property {boolean} [decompress=true] Disable auto decompression of the
+ * received data. By default this option is set to `true`.
+ * Applicable in cases where the data was uploaded with
+ * `gzip: true` option. See {@link File#createWriteStream}.
+ */
+ /**
+ * Create a readable stream to read the contents of the remote file. It can be
+ * piped to a writable stream or listened to for 'data' events to read a
+ * file's contents.
+ *
+ * In the unlikely event there is a mismatch between what you downloaded and
+ * the version in your Bucket, your error handler will receive an error with
+ * code "CONTENT_DOWNLOAD_MISMATCH". If you receive this error, the best
+ * recourse is to try downloading the file again.
+ *
+ * NOTE: Readable streams will emit the `end` event when the file is fully
+ * downloaded.
+ *
+ * @param {CreateReadStreamOptions} [options] Configuration options.
+ * @returns {ReadableStream}
+ *
+ * @example
+ * ```
+ * //-
+ * // Downloading a File
+ * //
+ * // The example below demonstrates how we can reference a remote file, then
+ * // pipe its contents to a local file. This is effectively creating a local
+ * // backup of your remote data.
+ * //-
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('my-bucket');
+ *
+ * const fs = require('fs');
+ * const remoteFile = bucket.file('image.png');
+ * const localFilename = '/Users/stephen/Photos/image.png';
+ *
+ * remoteFile.createReadStream()
+ * .on('error', function(err) {})
+ * .on('response', function(response) {
+ * // Server connected and responded with the specified status and headers.
+ * })
+ * .on('end', function() {
+ * // The file is fully downloaded.
+ * })
+ * .pipe(fs.createWriteStream(localFilename));
+ *
+ * //-
+ * // To limit the downloaded data to only a byte range, pass an options
+ * // object.
+ * //-
+ * const logFile = myBucket.file('access_log');
+ * logFile.createReadStream({
+ * start: 10000,
+ * end: 20000
+ * })
+ * .on('error', function(err) {})
+ * .pipe(fs.createWriteStream('/Users/stephen/logfile.txt'));
+ *
+ * //-
+ * // To read a tail byte range, specify only `options.end` as a negative
+ * // number.
+ * //-
+ * const logFile = myBucket.file('access_log');
+ * logFile.createReadStream({
+ * end: -100
+ * })
+ * .on('error', function(err) {})
+ * .pipe(fs.createWriteStream('/Users/stephen/logfile.txt'));
+ * ```
+ */
+ createReadStream(options?: CreateReadStreamOptions): Readable;
+ createResumableUpload(options?: CreateResumableUploadOptions): Promise;
+ createResumableUpload(options: CreateResumableUploadOptions, callback: CreateResumableUploadCallback): void;
+ createResumableUpload(callback: CreateResumableUploadCallback): void;
+ /**
+ * @typedef {object} CreateWriteStreamOptions Configuration options for File#createWriteStream().
+ * @property {string} [contentType] Alias for
+ * `options.metadata.contentType`. If set to `auto`, the file name is used
+ * to determine the contentType.
+ * @property {string|boolean} [gzip] If true, automatically gzip the file.
+ * If set to `auto`, the contentType is used to determine if the file
+ * should be gzipped. This will set `options.metadata.contentEncoding` to
+ * `gzip` if necessary.
+ * @property {object} [metadata] See the examples below or
+ * {@link https://cloud.google.com/storage/docs/json_api/v1/objects/insert#request_properties_JSON| Objects: insert request body}
+ * for more details.
+ * @property {number} [offset] The starting byte of the upload stream, for
+ * resuming an interrupted upload. Defaults to 0.
+ * @property {string} [predefinedAcl] Apply a predefined set of access
+ * controls to this object.
+ *
+ * Acceptable values are:
+ * - **`authenticatedRead`** - Object owner gets `OWNER` access, and
+ * `allAuthenticatedUsers` get `READER` access.
+ *
+ * - **`bucketOwnerFullControl`** - Object owner gets `OWNER` access, and
+ * project team owners get `OWNER` access.
+ *
+ * - **`bucketOwnerRead`** - Object owner gets `OWNER` access, and project
+ * team owners get `READER` access.
+ *
+ * - **`private`** - Object owner gets `OWNER` access.
+ *
+ * - **`projectPrivate`** - Object owner gets `OWNER` access, and project
+ * team members get access according to their roles.
+ *
+ * - **`publicRead`** - Object owner gets `OWNER` access, and `allUsers`
+ * get `READER` access.
+ * @property {boolean} [private] Make the uploaded file private. (Alias for
+ * `options.predefinedAcl = 'private'`)
+ * @property {boolean} [public] Make the uploaded file public. (Alias for
+ * `options.predefinedAcl = 'publicRead'`)
+ * @property {boolean} [resumable] Force a resumable upload. NOTE: When
+ * working with streams, the file format and size is unknown until it's
+ * completely consumed. Because of this, it's best for you to be explicit
+ * for what makes sense given your input.
+ * @property {number} [timeout=60000] Set the HTTP request timeout in
+ * milliseconds. This option is not available for resumable uploads.
+ * Default: `60000`
+ * @property {string} [uri] The URI for an already-created resumable
+ * upload. See {@link File#createResumableUpload}.
+ * @property {string} [userProject] The ID of the project which will be
+ * billed for the request.
+ * @property {string|boolean} [validation] Possible values: `"md5"`,
+ * `"crc32c"`, or `false`. By default, data integrity is validated with a
+ * CRC32c checksum. You may use MD5 if preferred, but that hash is not
+ * supported for composite objects. An error will be raised if MD5 is
+ * specified but is not available. You may also choose to skip validation
+ * completely, however this is **not recommended**. In addition to specifying
+ * validation type, providing `metadata.crc32c` or `metadata.md5Hash` will
+ * cause the server to perform validation in addition to client validation.
+ * NOTE: Validation is automatically skipped for objects that were
+ * uploaded using the `gzip` option and have already compressed content.
+ */
+ /**
+ * Create a writable stream to overwrite the contents of the file in your
+ * bucket.
+ *
+ * A File object can also be used to create files for the first time.
+ *
+ * Resumable uploads are automatically enabled and must be shut off explicitly
+ * by setting `options.resumable` to `false`.
+ *
+ *
+ *
+ * There is some overhead when using a resumable upload that can cause
+ * noticeable performance degradation while uploading a series of small
+ * files. When uploading files less than 10MB, it is recommended that the
+ * resumable feature is disabled.
+ *
+ *
+ * NOTE: Writable streams will emit the `finish` event when the file is fully
+ * uploaded.
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload Upload Options (Simple or Resumable)}
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/objects/insert Objects: insert API Documentation}
+ *
+ * @param {CreateWriteStreamOptions} [options] Configuration options.
+ * @returns {WritableStream}
+ *
+ * @example
+ * ```
+ * const fs = require('fs');
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const file = myBucket.file('my-file');
+ *
+ * //-
+ * // Uploading a File
+ * //
+ * // Now, consider a case where we want to upload a file to your bucket. You
+ * // have the option of using {@link Bucket#upload}, but that is just
+ * // a convenience method which will do the following.
+ * //-
+ * fs.createReadStream('/Users/stephen/Photos/birthday-at-the-zoo/panda.jpg')
+ * .pipe(file.createWriteStream())
+ * .on('error', function(err) {})
+ * .on('finish', function() {
+ * // The file upload is complete.
+ * });
+ *
+ * //-
+ * // Uploading a File with gzip compression
+ * //-
+ * fs.createReadStream('/Users/stephen/site/index.html')
+ * .pipe(file.createWriteStream({ gzip: true }))
+ * .on('error', function(err) {})
+ * .on('finish', function() {
+ * // The file upload is complete.
+ * });
+ *
+ * //-
+ * // Downloading the file with `createReadStream` will automatically decode
+ * // the file.
+ * //-
+ *
+ * //-
+ * // Uploading a File with Metadata
+ * //
+ * // One last case you may run into is when you want to upload a file to your
+ * // bucket and set its metadata at the same time. Like above, you can use
+ * // {@link Bucket#upload} to do this, which is just a wrapper around
+ * // the following.
+ * //-
+ * fs.createReadStream('/Users/stephen/Photos/birthday-at-the-zoo/panda.jpg')
+ * .pipe(file.createWriteStream({
+ * metadata: {
+ * contentType: 'image/jpeg',
+ * metadata: {
+ * custom: 'metadata'
+ * }
+ * }
+ * }))
+ * .on('error', function(err) {})
+ * .on('finish', function() {
+ * // The file upload is complete.
+ * });
+ * ```
+ *
+ * //-
+ * // Continuing a Resumable Upload
+ * //
+ * // One can capture a `uri` from a resumable upload to reuse later.
+ * // Additionally, for validation, one can also capture and pass `crc32c`.
+ * //-
+ * let uri: string | undefined = undefined;
+ * let resumeCRC32C: string | undefined = undefined;
+ *
+ * fs.createWriteStream()
+ * .on('uri', link => {uri = link})
+ * .on('crc32', crc32c => {resumeCRC32C = crc32c});
+ *
+ * // later...
+ * fs.createWriteStream({uri, resumeCRC32C});
+ */
+ createWriteStream(options?: CreateWriteStreamOptions): Writable;
+ /**
+ * Delete the object.
+ *
+ * @param {function=} callback - The callback function.
+ * @param {?error} callback.err - An error returned while making this request.
+ * @param {object} callback.apiResponse - The full API response.
+ */
+ delete(options?: DeleteOptions): Promise<[r.Response]>;
+ delete(options: DeleteOptions, callback: DeleteCallback): void;
+ delete(callback: DeleteCallback): void;
+ download(options?: DownloadOptions): Promise;
+ download(options: DownloadOptions, callback: DownloadCallback): void;
+ download(callback: DownloadCallback): void;
+ /**
+ * The Storage API allows you to use a custom key for server-side encryption.
+ *
+ * See {@link https://cloud.google.com/storage/docs/encryption#customer-supplied| Customer-supplied Encryption Keys}
+ *
+ * @param {string|buffer} encryptionKey An AES-256 encryption key.
+ * @returns {File}
+ *
+ * @example
+ * ```
+ * const crypto = require('crypto');
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const encryptionKey = crypto.randomBytes(32);
+ *
+ * const fileWithCustomEncryption = myBucket.file('my-file');
+ * fileWithCustomEncryption.setEncryptionKey(encryptionKey);
+ *
+ * const fileWithoutCustomEncryption = myBucket.file('my-file');
+ *
+ * fileWithCustomEncryption.save('data', function(err) {
+ * // Try to download with the File object that hasn't had
+ * // `setEncryptionKey()` called:
+ * fileWithoutCustomEncryption.download(function(err) {
+ * // We will receive an error:
+ * // err.message === 'Bad Request'
+ *
+ * // Try again with the File object we called `setEncryptionKey()` on:
+ * fileWithCustomEncryption.download(function(err, contents) {
+ * // contents.toString() === 'data'
+ * });
+ * });
+ * });
+ *
+ * ```
+ * @example include:samples/encryption.js
+ * region_tag:storage_upload_encrypted_file
+ * Example of uploading an encrypted file:
+ *
+ * @example include:samples/encryption.js
+ * region_tag:storage_download_encrypted_file
+ * Example of downloading an encrypted file:
+ */
+ setEncryptionKey(encryptionKey: string | Buffer): this;
+ get(options?: GetFileOptions): Promise>;
+ get(callback: InstanceResponseCallback): void;
+ get(options: GetFileOptions, callback: InstanceResponseCallback): void;
+ getExpirationDate(): Promise;
+ getExpirationDate(callback: GetExpirationDateCallback): void;
+ generateSignedPostPolicyV2(options: GenerateSignedPostPolicyV2Options): Promise;
+ generateSignedPostPolicyV2(options: GenerateSignedPostPolicyV2Options, callback: GenerateSignedPostPolicyV2Callback): void;
+ generateSignedPostPolicyV2(callback: GenerateSignedPostPolicyV2Callback): void;
+ generateSignedPostPolicyV4(options: GenerateSignedPostPolicyV4Options): Promise;
+ generateSignedPostPolicyV4(options: GenerateSignedPostPolicyV4Options, callback: GenerateSignedPostPolicyV4Callback): void;
+ generateSignedPostPolicyV4(callback: GenerateSignedPostPolicyV4Callback): void;
+ getSignedUrl(cfg: GetSignedUrlConfig): Promise;
+ getSignedUrl(cfg: GetSignedUrlConfig, callback: GetSignedUrlCallback): void;
+ isPublic(): Promise;
+ isPublic(callback: IsPublicCallback): void;
+ makePrivate(options?: MakeFilePrivateOptions): Promise;
+ makePrivate(callback: MakeFilePrivateCallback): void;
+ makePrivate(options: MakeFilePrivateOptions, callback: MakeFilePrivateCallback): void;
+ makePublic(): Promise;
+ makePublic(callback: MakeFilePublicCallback): void;
+ /**
+ * The public URL of this File
+ * Use {@link File#makePublic} to enable anonymous access via the returned URL.
+ *
+ * @returns {string}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('albums');
+ * const file = bucket.file('my-file');
+ *
+ * // publicUrl will be "https://storage.googleapis.com/albums/my-file"
+ * const publicUrl = file.publicUrl();
+ * ```
+ */
+ publicUrl(): string;
+ move(destination: string | Bucket | File, options?: MoveOptions): Promise;
+ move(destination: string | Bucket | File, callback: MoveCallback): void;
+ move(destination: string | Bucket | File, options: MoveOptions, callback: MoveCallback): void;
+ rename(destinationFile: string | File, options?: RenameOptions): Promise;
+ rename(destinationFile: string | File, callback: RenameCallback): void;
+ rename(destinationFile: string | File, options: RenameOptions, callback: RenameCallback): void;
+ /**
+ * @typedef {object} RestoreOptions Options for File#restore(). See an
+ * {@link https://cloud.google.com/storage/docs/json_api/v1/objects#resource| Object resource}.
+ * @param {string} [userProject] The ID of the project which will be
+ * billed for the request.
+ * @param {number} [generation] If present, selects a specific revision of this object.
+ * @param {string} [projection] Specifies the set of properties to return. If used, must be 'full' or 'noAcl'.
+ * @param {string | number} [ifGenerationMatch] Request proceeds if the generation of the target resource
+ * matches the value used in the precondition.
+ * If the values don't match, the request fails with a 412 Precondition Failed response.
+ * @param {string | number} [ifGenerationNotMatch] Request proceeds if the generation of the target resource does
+ * not match the value used in the precondition. If the values match, the request fails with a 304 Not Modified response.
+ * @param {string | number} [ifMetagenerationMatch] Request proceeds if the meta-generation of the target resource
+ * matches the value used in the precondition.
+ * If the values don't match, the request fails with a 412 Precondition Failed response.
+ * @param {string | number} [ifMetagenerationNotMatch] Request proceeds if the meta-generation of the target resource does
+ * not match the value used in the precondition. If the values match, the request fails with a 304 Not Modified response.
+ */
+ /**
+ * Restores a soft-deleted file
+ * @param {RestoreOptions} options Restore options.
+ * @returns {Promise}
+ */
+ restore(options: RestoreOptions): Promise;
+ request(reqOpts: DecorateRequestOptions): Promise;
+ request(reqOpts: DecorateRequestOptions, callback: BodyResponseCallback): void;
+ rotateEncryptionKey(options?: RotateEncryptionKeyOptions): Promise;
+ rotateEncryptionKey(callback: RotateEncryptionKeyCallback): void;
+ rotateEncryptionKey(options: RotateEncryptionKeyOptions, callback: RotateEncryptionKeyCallback): void;
+ save(data: SaveData, options?: SaveOptions): Promise;
+ save(data: SaveData, callback: SaveCallback): void;
+ save(data: SaveData, options: SaveOptions, callback: SaveCallback): void;
+ setMetadata(metadata: FileMetadata, options?: SetMetadataOptions): Promise>;
+ setMetadata(metadata: FileMetadata, callback: MetadataCallback): void;
+ setMetadata(metadata: FileMetadata, options: SetMetadataOptions, callback: MetadataCallback): void;
+ setStorageClass(storageClass: string, options?: SetStorageClassOptions): Promise;
+ setStorageClass(storageClass: string, options: SetStorageClassOptions, callback: SetStorageClassCallback): void;
+ setStorageClass(storageClass: string, callback?: SetStorageClassCallback): void;
+ /**
+ * Set a user project to be billed for all requests made from this File
+ * object.
+ *
+ * @param {string} userProject The user project.
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('albums');
+ * const file = bucket.file('my-file');
+ *
+ * file.setUserProject('grape-spaceship-123');
+ * ```
+ */
+ setUserProject(userProject: string): void;
+ /**
+ * This creates a resumable-upload upload stream.
+ *
+ * @param {Duplexify} stream - Duplexify stream of data to pipe to the file.
+ * @param {object=} options - Configuration object.
+ *
+ * @private
+ */
+ startResumableUpload_(dup: Duplexify, options?: CreateResumableUploadOptions): void;
+ /**
+ * Takes a readable stream and pipes it to a remote file. Unlike
+ * `startResumableUpload_`, which uses the resumable upload technique, this
+ * method uses a simple upload (all or nothing).
+ *
+ * @param {Duplexify} dup - Duplexify stream of data to pipe to the file.
+ * @param {object=} options - Configuration object.
+ *
+ * @private
+ */
+ startSimpleUpload_(dup: Duplexify, options?: CreateWriteStreamOptions): void;
+ disableAutoRetryConditionallyIdempotent_(coreOpts: any, methodType: AvailableServiceObjectMethods, localPreconditionOptions?: PreconditionOptions): void;
+ private getBufferFromReadable;
+}
+/**
+ * Reference to the {@link File} class.
+ * @name module:@google-cloud/storage.File
+ * @see File
+ */
+export { File };
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/file.js b/node_modules/@google-cloud/storage/build/cjs/src/file.js
new file mode 100644
index 0000000..34c23a2
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/file.js
@@ -0,0 +1,3348 @@
+"use strict";
+// Copyright 2019 Google LLC
+//
+// 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.
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+var _File_instances, _File_validateIntegrity;
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.File = exports.FileExceptionMessages = exports.RequestError = exports.STORAGE_POST_POLICY_BASE_URL = exports.ActionToHTTPMethod = void 0;
+const index_js_1 = require("./nodejs-common/index.js");
+const promisify_1 = require("@google-cloud/promisify");
+const compressible_1 = __importDefault(require("compressible"));
+const crypto = __importStar(require("crypto"));
+const fs = __importStar(require("fs"));
+const mime_1 = __importDefault(require("mime"));
+const resumableUpload = __importStar(require("./resumable-upload.js"));
+const stream_1 = require("stream");
+const zlib = __importStar(require("zlib"));
+const storage_js_1 = require("./storage.js");
+const bucket_js_1 = require("./bucket.js");
+const acl_js_1 = require("./acl.js");
+const signer_js_1 = require("./signer.js");
+const util_js_1 = require("./nodejs-common/util.js");
+const duplexify_1 = __importDefault(require("duplexify"));
+const util_js_2 = require("./util.js");
+const crc32c_js_1 = require("./crc32c.js");
+const hash_stream_validator_js_1 = require("./hash-stream-validator.js");
+const async_retry_1 = __importDefault(require("async-retry"));
+var ActionToHTTPMethod;
+(function (ActionToHTTPMethod) {
+ ActionToHTTPMethod["read"] = "GET";
+ ActionToHTTPMethod["write"] = "PUT";
+ ActionToHTTPMethod["delete"] = "DELETE";
+ ActionToHTTPMethod["resumable"] = "POST";
+})(ActionToHTTPMethod || (exports.ActionToHTTPMethod = ActionToHTTPMethod = {}));
+/**
+ * @deprecated - no longer used
+ */
+exports.STORAGE_POST_POLICY_BASE_URL = 'https://storage.googleapis.com';
+/**
+ * @private
+ */
+const GS_URL_REGEXP = /^gs:\/\/([a-z0-9_.-]+)\/(.+)$/;
+class RequestError extends Error {
+}
+exports.RequestError = RequestError;
+const SEVEN_DAYS = 7 * 24 * 60 * 60;
+var FileExceptionMessages;
+(function (FileExceptionMessages) {
+ FileExceptionMessages["EXPIRATION_TIME_NA"] = "An expiration time is not available.";
+ FileExceptionMessages["DESTINATION_NO_NAME"] = "Destination file should have a name.";
+ FileExceptionMessages["INVALID_VALIDATION_FILE_RANGE"] = "Cannot use validation with file ranges (start/end).";
+ FileExceptionMessages["MD5_NOT_AVAILABLE"] = "MD5 verification was specified, but is not available for the requested object. MD5 is not available for composite objects.";
+ FileExceptionMessages["EQUALS_CONDITION_TWO_ELEMENTS"] = "Equals condition must be an array of 2 elements.";
+ FileExceptionMessages["STARTS_WITH_TWO_ELEMENTS"] = "StartsWith condition must be an array of 2 elements.";
+ FileExceptionMessages["CONTENT_LENGTH_RANGE_MIN_MAX"] = "ContentLengthRange must have numeric min & max fields.";
+ FileExceptionMessages["DOWNLOAD_MISMATCH"] = "The downloaded data did not match the data from the server. To be sure the content is the same, you should download the file again.";
+ FileExceptionMessages["UPLOAD_MISMATCH_DELETE_FAIL"] = "The uploaded data did not match the data from the server.\n As a precaution, we attempted to delete the file, but it was not successful.\n To be sure the content is the same, you should try removing the file manually,\n then uploading the file again.\n \n\nThe delete attempt failed with this message:\n\n ";
+ FileExceptionMessages["UPLOAD_MISMATCH"] = "The uploaded data did not match the data from the server.\n As a precaution, the file has been deleted.\n To be sure the content is the same, you should try uploading the file again.";
+ FileExceptionMessages["MD5_RESUMED_UPLOAD"] = "MD5 cannot be used with a continued resumable upload as MD5 cannot be extended from an existing value";
+ FileExceptionMessages["MISSING_RESUME_CRC32C_FINAL_UPLOAD"] = "The CRC32C is missing for the final portion of a resumed upload, which is required for validation. Please provide `resumeCRC32C` if validation is required, or disable `validation`.";
+})(FileExceptionMessages || (exports.FileExceptionMessages = FileExceptionMessages = {}));
+/**
+ * A File object is created from your {@link Bucket} object using
+ * {@link Bucket#file}.
+ *
+ * @class
+ */
+class File extends index_js_1.ServiceObject {
+ /**
+ * Cloud Storage uses access control lists (ACLs) to manage object and
+ * bucket access. ACLs are the mechanism you use to share objects with other
+ * users and allow other users to access your buckets and objects.
+ *
+ * An ACL consists of one or more entries, where each entry grants permissions
+ * to an entity. Permissions define the actions that can be performed against
+ * an object or bucket (for example, `READ` or `WRITE`); the entity defines
+ * who the permission applies to (for example, a specific user or group of
+ * users).
+ *
+ * The `acl` object on a File instance provides methods to get you a list of
+ * the ACLs defined on your bucket, as well as set, update, and delete them.
+ *
+ * See {@link http://goo.gl/6qBBPO| About Access Control lists}
+ *
+ * @name File#acl
+ * @mixes Acl
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const file = myBucket.file('my-file');
+ * //-
+ * // Make a file publicly readable.
+ * //-
+ * const options = {
+ * entity: 'allUsers',
+ * role: storage.acl.READER_ROLE
+ * };
+ *
+ * file.acl.add(options, function(err, aclObject) {});
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * file.acl.add(options).then(function(data) {
+ * const aclObject = data[0];
+ * const apiResponse = data[1];
+ * });
+ * ```
+ */
+ /**
+ * The API-formatted resource description of the file.
+ *
+ * Note: This is not guaranteed to be up-to-date when accessed. To get the
+ * latest record, call the `getMetadata()` method.
+ *
+ * @name File#metadata
+ * @type {object}
+ */
+ /**
+ * The file's name.
+ * @name File#name
+ * @type {string}
+ */
+ /**
+ * @callback Crc32cGeneratorToStringCallback
+ * A method returning the CRC32C as a base64-encoded string.
+ *
+ * @returns {string}
+ *
+ * @example
+ * Hashing the string 'data' should return 'rth90Q=='
+ *
+ * ```js
+ * const buffer = Buffer.from('data');
+ * crc32c.update(buffer);
+ * crc32c.toString(); // 'rth90Q=='
+ * ```
+ **/
+ /**
+ * @callback Crc32cGeneratorValidateCallback
+ * A method validating a base64-encoded CRC32C string.
+ *
+ * @param {string} [value] base64-encoded CRC32C string to validate
+ * @returns {boolean}
+ *
+ * @example
+ * Should return `true` if the value matches, `false` otherwise
+ *
+ * ```js
+ * const buffer = Buffer.from('data');
+ * crc32c.update(buffer);
+ * crc32c.validate('DkjKuA=='); // false
+ * crc32c.validate('rth90Q=='); // true
+ * ```
+ **/
+ /**
+ * @callback Crc32cGeneratorUpdateCallback
+ * A method for passing `Buffer`s for CRC32C generation.
+ *
+ * @param {Buffer} [data] data to update CRC32C value with
+ * @returns {undefined}
+ *
+ * @example
+ * Hashing buffers from 'some ' and 'text\n'
+ *
+ * ```js
+ * const buffer1 = Buffer.from('some ');
+ * crc32c.update(buffer1);
+ *
+ * const buffer2 = Buffer.from('text\n');
+ * crc32c.update(buffer2);
+ *
+ * crc32c.toString(); // 'DkjKuA=='
+ * ```
+ **/
+ /**
+ * @typedef {object} CRC32CValidator
+ * @property {Crc32cGeneratorToStringCallback}
+ * @property {Crc32cGeneratorValidateCallback}
+ * @property {Crc32cGeneratorUpdateCallback}
+ */
+ /**
+ * @callback Crc32cGeneratorCallback
+ * @returns {CRC32CValidator}
+ */
+ /**
+ * @typedef {object} FileOptions Options passed to the File constructor.
+ * @property {string} [encryptionKey] A custom encryption key.
+ * @property {number} [generation] Generation to scope the file to.
+ * @property {string} [kmsKeyName] Cloud KMS Key used to encrypt this
+ * object, if the object is encrypted by such a key. Limited availability;
+ * usable only by enabled projects.
+ * @property {string} [userProject] The ID of the project which will be
+ * billed for all requests made from File object.
+ * @property {Crc32cGeneratorCallback} [callback] A function that generates a CRC32C Validator. Defaults to {@link CRC32C}
+ */
+ /**
+ * Constructs a file object.
+ *
+ * @param {Bucket} bucket The Bucket instance this file is
+ * attached to.
+ * @param {string} name The name of the remote file.
+ * @param {FileOptions} [options] Configuration options.
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const file = myBucket.file('my-file');
+ * ```
+ */
+ constructor(bucket, name, options = {}) {
+ var _a, _b;
+ const requestQueryObject = {};
+ let generation;
+ if (options.generation !== null) {
+ if (typeof options.generation === 'string') {
+ generation = Number(options.generation);
+ }
+ else {
+ generation = options.generation;
+ }
+ if (!isNaN(generation)) {
+ requestQueryObject.generation = generation;
+ }
+ }
+ Object.assign(requestQueryObject, options.preconditionOpts);
+ const userProject = options.userProject || bucket.userProject;
+ if (typeof userProject === 'string') {
+ requestQueryObject.userProject = userProject;
+ }
+ const methods = {
+ /**
+ * @typedef {array} DeleteFileResponse
+ * @property {object} 0 The full API response.
+ */
+ /**
+ * @callback DeleteFileCallback
+ * @param {?Error} err Request error, if any.
+ * @param {object} apiResponse The full API response.
+ */
+ /**
+ * Delete the file.
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/objects/delete| Objects: delete API Documentation}
+ *
+ * @method File#delete
+ * @param {object} [options] Configuration options.
+ * @param {boolean} [options.ignoreNotFound = false] Ignore an error if
+ * the file does not exist.
+ * @param {string} [options.userProject] The ID of the project which will be
+ * billed for the request.
+ * @param {DeleteFileCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const file = myBucket.file('my-file');
+ * file.delete(function(err, apiResponse) {});
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * file.delete().then(function(data) {
+ * const apiResponse = data[0];
+ * });
+ *
+ * ```
+ * @example include:samples/files.js
+ * region_tag:storage_delete_file
+ * Another example:
+ */
+ delete: {
+ reqOpts: {
+ qs: requestQueryObject,
+ },
+ },
+ /**
+ * @typedef {array} FileExistsResponse
+ * @property {boolean} 0 Whether the {@link File} exists.
+ */
+ /**
+ * @callback FileExistsCallback
+ * @param {?Error} err Request error, if any.
+ * @param {boolean} exists Whether the {@link File} exists.
+ */
+ /**
+ * Check if the file exists.
+ *
+ * @method File#exists
+ * @param {options} [options] Configuration options.
+ * @param {string} [options.userProject] The ID of the project which will be
+ * billed for the request.
+ * @param {FileExistsCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const file = myBucket.file('my-file');
+ *
+ * file.exists(function(err, exists) {});
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * file.exists().then(function(data) {
+ * const exists = data[0];
+ * });
+ * ```
+ */
+ exists: {
+ reqOpts: {
+ qs: requestQueryObject,
+ },
+ },
+ /**
+ * @typedef {array} GetFileResponse
+ * @property {File} 0 The {@link File}.
+ * @property {object} 1 The full API response.
+ */
+ /**
+ * @callback GetFileCallback
+ * @param {?Error} err Request error, if any.
+ * @param {File} file The {@link File}.
+ * @param {object} apiResponse The full API response.
+ */
+ /**
+ * Get a file object and its metadata if it exists.
+ *
+ * @method File#get
+ * @param {options} [options] Configuration options.
+ * @param {string} [options.userProject] The ID of the project which will be
+ * billed for the request.
+ * @param {number} [options.generation] The generation number to get
+ * @param {boolean} [options.softDeleted] If true, returns the soft-deleted object.
+ Object `generation` is required if `softDeleted` is set to True.
+ * @param {GetFileCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const file = myBucket.file('my-file');
+ *
+ * file.get(function(err, file, apiResponse) {
+ * // file.metadata` has been populated.
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * file.get().then(function(data) {
+ * const file = data[0];
+ * const apiResponse = data[1];
+ * });
+ * ```
+ */
+ get: {
+ reqOpts: {
+ qs: requestQueryObject,
+ },
+ },
+ /**
+ * @typedef {array} GetFileMetadataResponse
+ * @property {object} 0 The {@link File} metadata.
+ * @property {object} 1 The full API response.
+ */
+ /**
+ * @callback GetFileMetadataCallback
+ * @param {?Error} err Request error, if any.
+ * @param {object} metadata The {@link File} metadata.
+ * @param {object} apiResponse The full API response.
+ */
+ /**
+ * Get the file's metadata.
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/objects/get| Objects: get API Documentation}
+ *
+ * @method File#getMetadata
+ * @param {object} [options] Configuration options.
+ * @param {string} [options.userProject] The ID of the project which will be
+ * billed for the request.
+ * @param {GetFileMetadataCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const file = myBucket.file('my-file');
+ *
+ * file.getMetadata(function(err, metadata, apiResponse) {});
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * file.getMetadata().then(function(data) {
+ * const metadata = data[0];
+ * const apiResponse = data[1];
+ * });
+ *
+ * ```
+ * @example include:samples/files.js
+ * region_tag:storage_get_metadata
+ * Another example:
+ */
+ getMetadata: {
+ reqOpts: {
+ qs: requestQueryObject,
+ },
+ },
+ /**
+ * @typedef {object} SetFileMetadataOptions Configuration options for File#setMetadata().
+ * @param {string} [userProject] The ID of the project which will be billed for the request.
+ */
+ /**
+ * @callback SetFileMetadataCallback
+ * @param {?Error} err Request error, if any.
+ * @param {object} apiResponse The full API response.
+ */
+ /**
+ * @typedef {array} SetFileMetadataResponse
+ * @property {object} 0 The full API response.
+ */
+ /**
+ * Merge the given metadata with the current remote file's metadata. This
+ * will set metadata if it was previously unset or update previously set
+ * metadata. To unset previously set metadata, set its value to null.
+ *
+ * You can set custom key/value pairs in the metadata key of the given
+ * object, however the other properties outside of this object must adhere
+ * to the {@link https://goo.gl/BOnnCK| official API documentation}.
+ *
+ *
+ * See the examples below for more information.
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/objects/patch| Objects: patch API Documentation}
+ *
+ * @method File#setMetadata
+ * @param {object} [metadata] The metadata you wish to update.
+ * @param {SetFileMetadataOptions} [options] Configuration options.
+ * @param {SetFileMetadataCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const file = myBucket.file('my-file');
+ *
+ * const metadata = {
+ * contentType: 'application/x-font-ttf',
+ * metadata: {
+ * my: 'custom',
+ * properties: 'go here'
+ * }
+ * };
+ *
+ * file.setMetadata(metadata, function(err, apiResponse) {});
+ *
+ * // Assuming current metadata = { hello: 'world', unsetMe: 'will do' }
+ * file.setMetadata({
+ * metadata: {
+ * abc: '123', // will be set.
+ * unsetMe: null, // will be unset (deleted).
+ * hello: 'goodbye' // will be updated from 'world' to 'goodbye'.
+ * }
+ * }, function(err, apiResponse) {
+ * // metadata should now be { abc: '123', hello: 'goodbye' }
+ * });
+ *
+ * //-
+ * // Set a temporary hold on this file from its bucket's retention period
+ * // configuration.
+ * //
+ * file.setMetadata({
+ * temporaryHold: true
+ * }, function(err, apiResponse) {});
+ *
+ * //-
+ * // Alternatively, you may set a temporary hold. This will follow the
+ * // same behavior as an event-based hold, with the exception that the
+ * // bucket's retention policy will not renew for this file from the time
+ * // the hold is released.
+ * //-
+ * file.setMetadata({
+ * eventBasedHold: true
+ * }, function(err, apiResponse) {});
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * file.setMetadata(metadata).then(function(data) {
+ * const apiResponse = data[0];
+ * });
+ * ```
+ */
+ setMetadata: {
+ reqOpts: {
+ qs: requestQueryObject,
+ },
+ },
+ };
+ super({
+ parent: bucket,
+ baseUrl: '/o',
+ id: encodeURIComponent(name),
+ methods,
+ });
+ _File_instances.add(this);
+ this.bucket = bucket;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ this.storage = bucket.parent;
+ // @TODO Can this duplicate code from above be avoided?
+ if (options.generation !== null) {
+ let generation;
+ if (typeof options.generation === 'string') {
+ generation = Number(options.generation);
+ }
+ else {
+ generation = options.generation;
+ }
+ if (!isNaN(generation)) {
+ this.generation = generation;
+ }
+ }
+ this.kmsKeyName = options.kmsKeyName;
+ this.userProject = userProject;
+ this.name = name;
+ if (options.encryptionKey) {
+ this.setEncryptionKey(options.encryptionKey);
+ }
+ this.acl = new acl_js_1.Acl({
+ request: this.request.bind(this),
+ pathPrefix: '/acl',
+ });
+ this.crc32cGenerator =
+ options.crc32cGenerator || this.bucket.crc32cGenerator;
+ this.instanceRetryValue = (_b = (_a = this.storage) === null || _a === void 0 ? void 0 : _a.retryOptions) === null || _b === void 0 ? void 0 : _b.autoRetry;
+ this.instancePreconditionOpts = options === null || options === void 0 ? void 0 : options.preconditionOpts;
+ }
+ /**
+ * The object's Cloud Storage URI (`gs://`)
+ *
+ * @example
+ * ```ts
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('my-bucket');
+ * const file = bucket.file('image.png');
+ *
+ * // `gs://my-bucket/image.png`
+ * const href = file.cloudStorageURI.href;
+ * ```
+ */
+ get cloudStorageURI() {
+ const uri = this.bucket.cloudStorageURI;
+ uri.pathname = this.name;
+ return uri;
+ }
+ /**
+ * A helper method for determining if a request should be retried based on preconditions.
+ * This should only be used for methods where the idempotency is determined by
+ * `ifGenerationMatch`
+ * @private
+ *
+ * A request should not be retried under the following conditions:
+ * - if precondition option `ifGenerationMatch` is not set OR
+ * - if `idempotencyStrategy` is set to `RetryNever`
+ */
+ shouldRetryBasedOnPreconditionAndIdempotencyStrat(options) {
+ var _a;
+ return !(((options === null || options === void 0 ? void 0 : options.ifGenerationMatch) === undefined &&
+ ((_a = this.instancePreconditionOpts) === null || _a === void 0 ? void 0 : _a.ifGenerationMatch) === undefined &&
+ this.storage.retryOptions.idempotencyStrategy ===
+ storage_js_1.IdempotencyStrategy.RetryConditional) ||
+ this.storage.retryOptions.idempotencyStrategy ===
+ storage_js_1.IdempotencyStrategy.RetryNever);
+ }
+ /**
+ * @typedef {array} CopyResponse
+ * @property {File} 0 The copied {@link File}.
+ * @property {object} 1 The full API response.
+ */
+ /**
+ * @callback CopyCallback
+ * @param {?Error} err Request error, if any.
+ * @param {File} copiedFile The copied {@link File}.
+ * @param {object} apiResponse The full API response.
+ */
+ /**
+ * @typedef {object} CopyOptions Configuration options for File#copy(). See an
+ * {@link https://cloud.google.com/storage/docs/json_api/v1/objects#resource| Object resource}.
+ * @property {string} [cacheControl] The cacheControl setting for the new file.
+ * @property {string} [contentEncoding] The contentEncoding setting for the new file.
+ * @property {string} [contentType] The contentType setting for the new file.
+ * @property {string} [destinationKmsKeyName] Resource name of the Cloud
+ * KMS key, of the form
+ * `projects/my-project/locations/location/keyRings/my-kr/cryptoKeys/my-key`,
+ * that will be used to encrypt the object. Overwrites the object
+ * metadata's `kms_key_name` value, if any.
+ * @property {Metadata} [metadata] Metadata to specify on the copied file.
+ * @property {string} [predefinedAcl] Set the ACL for the new file.
+ * @property {string} [token] A previously-returned `rewriteToken` from an
+ * unfinished rewrite request.
+ * @property {string} [userProject] The ID of the project which will be
+ * billed for the request.
+ */
+ /**
+ * Copy this file to another file. By default, this will copy the file to the
+ * same bucket, but you can choose to copy it to another Bucket by providing
+ * a Bucket or File object or a URL starting with "gs://".
+ * The generation of the file will not be preserved.
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/objects/rewrite| Objects: rewrite API Documentation}
+ *
+ * @throws {Error} If the destination file is not provided.
+ *
+ * @param {string|Bucket|File} destination Destination file.
+ * @param {CopyOptions} [options] Configuration options. See an
+ * @param {CopyCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ *
+ * //-
+ * // You can pass in a variety of types for the destination.
+ * //
+ * // For all of the below examples, assume we are working with the following
+ * // Bucket and File objects.
+ * //-
+ * const bucket = storage.bucket('my-bucket');
+ * const file = bucket.file('my-image.png');
+ *
+ * //-
+ * // If you pass in a string for the destination, the file is copied to its
+ * // current bucket, under the new name provided.
+ * //-
+ * file.copy('my-image-copy.png', function(err, copiedFile, apiResponse) {
+ * // `my-bucket` now contains:
+ * // - "my-image.png"
+ * // - "my-image-copy.png"
+ *
+ * // `copiedFile` is an instance of a File object that refers to your new
+ * // file.
+ * });
+ *
+ * //-
+ * // If you pass in a string starting with "gs://" for the destination, the
+ * // file is copied to the other bucket and under the new name provided.
+ * //-
+ * const newLocation = 'gs://another-bucket/my-image-copy.png';
+ * file.copy(newLocation, function(err, copiedFile, apiResponse) {
+ * // `my-bucket` still contains:
+ * // - "my-image.png"
+ * //
+ * // `another-bucket` now contains:
+ * // - "my-image-copy.png"
+ *
+ * // `copiedFile` is an instance of a File object that refers to your new
+ * // file.
+ * });
+ *
+ * //-
+ * // If you pass in a Bucket object, the file will be copied to that bucket
+ * // using the same name.
+ * //-
+ * const anotherBucket = storage.bucket('another-bucket');
+ * file.copy(anotherBucket, function(err, copiedFile, apiResponse) {
+ * // `my-bucket` still contains:
+ * // - "my-image.png"
+ * //
+ * // `another-bucket` now contains:
+ * // - "my-image.png"
+ *
+ * // `copiedFile` is an instance of a File object that refers to your new
+ * // file.
+ * });
+ *
+ * //-
+ * // If you pass in a File object, you have complete control over the new
+ * // bucket and filename.
+ * //-
+ * const anotherFile = anotherBucket.file('my-awesome-image.png');
+ * file.copy(anotherFile, function(err, copiedFile, apiResponse) {
+ * // `my-bucket` still contains:
+ * // - "my-image.png"
+ * //
+ * // `another-bucket` now contains:
+ * // - "my-awesome-image.png"
+ *
+ * // Note:
+ * // The `copiedFile` parameter is equal to `anotherFile`.
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * file.copy(newLocation).then(function(data) {
+ * const newFile = data[0];
+ * const apiResponse = data[1];
+ * });
+ *
+ * ```
+ * @example include:samples/files.js
+ * region_tag:storage_copy_file
+ * Another example:
+ */
+ copy(destination, optionsOrCallback, callback) {
+ var _a, _b;
+ const noDestinationError = new Error(FileExceptionMessages.DESTINATION_NO_NAME);
+ if (!destination) {
+ throw noDestinationError;
+ }
+ let options = {};
+ if (typeof optionsOrCallback === 'function') {
+ callback = optionsOrCallback;
+ }
+ else if (optionsOrCallback) {
+ options = { ...optionsOrCallback };
+ }
+ callback = callback || index_js_1.util.noop;
+ let destBucket;
+ let destName;
+ let newFile;
+ if (typeof destination === 'string') {
+ const parsedDestination = GS_URL_REGEXP.exec(destination);
+ if (parsedDestination !== null && parsedDestination.length === 3) {
+ destBucket = this.storage.bucket(parsedDestination[1]);
+ destName = parsedDestination[2];
+ }
+ else {
+ destBucket = this.bucket;
+ destName = destination;
+ }
+ }
+ else if (destination instanceof bucket_js_1.Bucket) {
+ destBucket = destination;
+ destName = this.name;
+ }
+ else if (destination instanceof File) {
+ destBucket = destination.bucket;
+ destName = destination.name;
+ newFile = destination;
+ }
+ else {
+ throw noDestinationError;
+ }
+ const query = {};
+ if (this.generation !== undefined) {
+ query.sourceGeneration = this.generation;
+ }
+ if (options.token !== undefined) {
+ query.rewriteToken = options.token;
+ }
+ if (options.userProject !== undefined) {
+ query.userProject = options.userProject;
+ delete options.userProject;
+ }
+ if (options.predefinedAcl !== undefined) {
+ query.destinationPredefinedAcl = options.predefinedAcl;
+ delete options.predefinedAcl;
+ }
+ newFile = newFile || destBucket.file(destName);
+ const headers = {};
+ if (this.encryptionKey !== undefined) {
+ headers['x-goog-copy-source-encryption-algorithm'] = 'AES256';
+ headers['x-goog-copy-source-encryption-key'] = this.encryptionKeyBase64;
+ headers['x-goog-copy-source-encryption-key-sha256'] =
+ this.encryptionKeyHash;
+ }
+ if (newFile.encryptionKey !== undefined) {
+ this.setEncryptionKey(newFile.encryptionKey);
+ }
+ else if (options.destinationKmsKeyName !== undefined) {
+ query.destinationKmsKeyName = options.destinationKmsKeyName;
+ delete options.destinationKmsKeyName;
+ }
+ else if (newFile.kmsKeyName !== undefined) {
+ query.destinationKmsKeyName = newFile.kmsKeyName;
+ }
+ if (query.destinationKmsKeyName) {
+ this.kmsKeyName = query.destinationKmsKeyName;
+ const keyIndex = this.interceptors.indexOf(this.encryptionKeyInterceptor);
+ if (keyIndex > -1) {
+ this.interceptors.splice(keyIndex, 1);
+ }
+ }
+ if (!this.shouldRetryBasedOnPreconditionAndIdempotencyStrat(options === null || options === void 0 ? void 0 : options.preconditionOpts)) {
+ this.storage.retryOptions.autoRetry = false;
+ }
+ if (((_a = options.preconditionOpts) === null || _a === void 0 ? void 0 : _a.ifGenerationMatch) !== undefined) {
+ query.ifGenerationMatch = (_b = options.preconditionOpts) === null || _b === void 0 ? void 0 : _b.ifGenerationMatch;
+ delete options.preconditionOpts;
+ }
+ this.request({
+ method: 'POST',
+ uri: `/rewriteTo/b/${destBucket.name}/o/${encodeURIComponent(newFile.name)}`,
+ qs: query,
+ json: options,
+ headers,
+ }, (err, resp) => {
+ this.storage.retryOptions.autoRetry = this.instanceRetryValue;
+ if (err) {
+ callback(err, null, resp);
+ return;
+ }
+ if (resp.rewriteToken) {
+ const options = {
+ token: resp.rewriteToken,
+ };
+ if (query.userProject) {
+ options.userProject = query.userProject;
+ }
+ if (query.destinationKmsKeyName) {
+ options.destinationKmsKeyName = query.destinationKmsKeyName;
+ }
+ this.copy(newFile, options, callback);
+ return;
+ }
+ callback(null, newFile, resp);
+ });
+ }
+ /**
+ * @typedef {object} CreateReadStreamOptions Configuration options for File#createReadStream.
+ * @property {string} [userProject] The ID of the project which will be
+ * billed for the request.
+ * @property {string|boolean} [validation] Possible values: `"md5"`,
+ * `"crc32c"`, or `false`. By default, data integrity is validated with a
+ * CRC32c checksum. You may use MD5 if preferred, but that hash is not
+ * supported for composite objects. An error will be raised if MD5 is
+ * specified but is not available. You may also choose to skip validation
+ * completely, however this is **not recommended**.
+ * @property {number} [start] A byte offset to begin the file's download
+ * from. Default is 0. NOTE: Byte ranges are inclusive; that is,
+ * `options.start = 0` and `options.end = 999` represent the first 1000
+ * bytes in a file or object. NOTE: when specifying a byte range, data
+ * integrity is not available.
+ * @property {number} [end] A byte offset to stop reading the file at.
+ * NOTE: Byte ranges are inclusive; that is, `options.start = 0` and
+ * `options.end = 999` represent the first 1000 bytes in a file or object.
+ * NOTE: when specifying a byte range, data integrity is not available.
+ * @property {boolean} [decompress=true] Disable auto decompression of the
+ * received data. By default this option is set to `true`.
+ * Applicable in cases where the data was uploaded with
+ * `gzip: true` option. See {@link File#createWriteStream}.
+ */
+ /**
+ * Create a readable stream to read the contents of the remote file. It can be
+ * piped to a writable stream or listened to for 'data' events to read a
+ * file's contents.
+ *
+ * In the unlikely event there is a mismatch between what you downloaded and
+ * the version in your Bucket, your error handler will receive an error with
+ * code "CONTENT_DOWNLOAD_MISMATCH". If you receive this error, the best
+ * recourse is to try downloading the file again.
+ *
+ * NOTE: Readable streams will emit the `end` event when the file is fully
+ * downloaded.
+ *
+ * @param {CreateReadStreamOptions} [options] Configuration options.
+ * @returns {ReadableStream}
+ *
+ * @example
+ * ```
+ * //-
+ * // Downloading a File
+ * //
+ * // The example below demonstrates how we can reference a remote file, then
+ * // pipe its contents to a local file. This is effectively creating a local
+ * // backup of your remote data.
+ * //-
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('my-bucket');
+ *
+ * const fs = require('fs');
+ * const remoteFile = bucket.file('image.png');
+ * const localFilename = '/Users/stephen/Photos/image.png';
+ *
+ * remoteFile.createReadStream()
+ * .on('error', function(err) {})
+ * .on('response', function(response) {
+ * // Server connected and responded with the specified status and headers.
+ * })
+ * .on('end', function() {
+ * // The file is fully downloaded.
+ * })
+ * .pipe(fs.createWriteStream(localFilename));
+ *
+ * //-
+ * // To limit the downloaded data to only a byte range, pass an options
+ * // object.
+ * //-
+ * const logFile = myBucket.file('access_log');
+ * logFile.createReadStream({
+ * start: 10000,
+ * end: 20000
+ * })
+ * .on('error', function(err) {})
+ * .pipe(fs.createWriteStream('/Users/stephen/logfile.txt'));
+ *
+ * //-
+ * // To read a tail byte range, specify only `options.end` as a negative
+ * // number.
+ * //-
+ * const logFile = myBucket.file('access_log');
+ * logFile.createReadStream({
+ * end: -100
+ * })
+ * .on('error', function(err) {})
+ * .pipe(fs.createWriteStream('/Users/stephen/logfile.txt'));
+ * ```
+ */
+ createReadStream(options = {}) {
+ options = Object.assign({ decompress: true }, options);
+ const rangeRequest = typeof options.start === 'number' || typeof options.end === 'number';
+ const tailRequest = options.end < 0;
+ let validateStream = undefined;
+ let request = undefined;
+ const throughStream = new util_js_2.PassThroughShim();
+ let crc32c = true;
+ let md5 = false;
+ if (typeof options.validation === 'string') {
+ const value = options.validation.toLowerCase().trim();
+ crc32c = value === 'crc32c';
+ md5 = value === 'md5';
+ }
+ else if (options.validation === false) {
+ crc32c = false;
+ }
+ const shouldRunValidation = !rangeRequest && (crc32c || md5);
+ if (rangeRequest) {
+ if (typeof options.validation === 'string' ||
+ options.validation === true) {
+ throw new Error(FileExceptionMessages.INVALID_VALIDATION_FILE_RANGE);
+ }
+ // Range requests can't receive data integrity checks.
+ crc32c = false;
+ md5 = false;
+ }
+ const onComplete = (err) => {
+ if (err) {
+ // There is an issue with node-fetch 2.x that if the stream errors the underlying socket connection is not closed.
+ // This causes a memory leak, so cleanup the sockets manually here by destroying the agent.
+ if (request === null || request === void 0 ? void 0 : request.agent) {
+ request.agent.destroy();
+ }
+ throughStream.destroy(err);
+ }
+ };
+ // We listen to the response event from the request stream so that we
+ // can...
+ //
+ // 1) Intercept any data from going to the user if an error occurred.
+ // 2) Calculate the hashes from the http.IncomingMessage response
+ // stream,
+ // which will return the bytes from the source without decompressing
+ // gzip'd content. We then send it through decompressed, if
+ // applicable, to the user.
+ const onResponse = (err, _body, rawResponseStream) => {
+ if (err) {
+ // Get error message from the body.
+ this.getBufferFromReadable(rawResponseStream).then(body => {
+ err.message = body.toString('utf8');
+ throughStream.destroy(err);
+ });
+ return;
+ }
+ request = rawResponseStream.request;
+ const headers = rawResponseStream.toJSON().headers;
+ const isCompressed = headers['content-encoding'] === 'gzip';
+ const hashes = {};
+ // The object is safe to validate if:
+ // 1. It was stored gzip and returned to us gzip OR
+ // 2. It was never stored as gzip
+ const safeToValidate = (headers['x-goog-stored-content-encoding'] === 'gzip' &&
+ isCompressed) ||
+ headers['x-goog-stored-content-encoding'] === 'identity';
+ const transformStreams = [];
+ if (shouldRunValidation) {
+ // The x-goog-hash header should be set with a crc32c and md5 hash.
+ // ex: headers['x-goog-hash'] = 'crc32c=xxxx,md5=xxxx'
+ if (typeof headers['x-goog-hash'] === 'string') {
+ headers['x-goog-hash']
+ .split(',')
+ .forEach((hashKeyValPair) => {
+ const delimiterIndex = hashKeyValPair.indexOf('=');
+ const hashType = hashKeyValPair.substring(0, delimiterIndex);
+ const hashValue = hashKeyValPair.substring(delimiterIndex + 1);
+ hashes[hashType] = hashValue;
+ });
+ }
+ validateStream = new hash_stream_validator_js_1.HashStreamValidator({
+ crc32c,
+ md5,
+ crc32cGenerator: this.crc32cGenerator,
+ crc32cExpected: hashes.crc32c,
+ md5Expected: hashes.md5,
+ });
+ }
+ if (md5 && !hashes.md5) {
+ const hashError = new RequestError(FileExceptionMessages.MD5_NOT_AVAILABLE);
+ hashError.code = 'MD5_NOT_AVAILABLE';
+ throughStream.destroy(hashError);
+ return;
+ }
+ if (safeToValidate && shouldRunValidation && validateStream) {
+ transformStreams.push(validateStream);
+ }
+ if (isCompressed && options.decompress) {
+ transformStreams.push(zlib.createGunzip());
+ }
+ (0, stream_1.pipeline)(rawResponseStream, ...transformStreams, throughStream, onComplete);
+ };
+ // Authenticate the request, then pipe the remote API request to the stream
+ // returned to the user.
+ const makeRequest = () => {
+ const query = { alt: 'media' };
+ if (this.generation) {
+ query.generation = this.generation;
+ }
+ if (options.userProject) {
+ query.userProject = options.userProject;
+ }
+ const headers = {
+ 'Accept-Encoding': 'gzip',
+ 'Cache-Control': 'no-store',
+ };
+ if (rangeRequest) {
+ const start = typeof options.start === 'number' ? options.start : '0';
+ const end = typeof options.end === 'number' ? options.end : '';
+ headers.Range = `bytes=${tailRequest ? end : `${start}-${end}`}`;
+ }
+ const reqOpts = {
+ uri: '',
+ headers,
+ qs: query,
+ };
+ if (options[util_js_1.GCCL_GCS_CMD_KEY]) {
+ reqOpts[util_js_1.GCCL_GCS_CMD_KEY] = options[util_js_1.GCCL_GCS_CMD_KEY];
+ }
+ this.requestStream(reqOpts)
+ .on('error', err => {
+ throughStream.destroy(err);
+ })
+ .on('response', res => {
+ throughStream.emit('response', res);
+ index_js_1.util.handleResp(null, res, null, onResponse);
+ })
+ .resume();
+ };
+ throughStream.on('reading', makeRequest);
+ return throughStream;
+ }
+ /**
+ * @callback CreateResumableUploadCallback
+ * @param {?Error} err Request error, if any.
+ * @param {string} uri The resumable upload's unique session URI.
+ */
+ /**
+ * @typedef {array} CreateResumableUploadResponse
+ * @property {string} 0 The resumable upload's unique session URI.
+ */
+ /**
+ * @typedef {object} CreateResumableUploadOptions
+ * @property {object} [metadata] Metadata to set on the file.
+ * @property {number} [offset] The starting byte of the upload stream for resuming an interrupted upload.
+ * @property {string} [origin] Origin header to set for the upload.
+ * @property {string} [predefinedAcl] Apply a predefined set of access
+ * controls to this object.
+ *
+ * Acceptable values are:
+ * - **`authenticatedRead`** - Object owner gets `OWNER` access, and
+ * `allAuthenticatedUsers` get `READER` access.
+ *
+ * - **`bucketOwnerFullControl`** - Object owner gets `OWNER` access, and
+ * project team owners get `OWNER` access.
+ *
+ * - **`bucketOwnerRead`** - Object owner gets `OWNER` access, and project
+ * team owners get `READER` access.
+ *
+ * - **`private`** - Object owner gets `OWNER` access.
+ *
+ * - **`projectPrivate`** - Object owner gets `OWNER` access, and project
+ * team members get access according to their roles.
+ *
+ * - **`publicRead`** - Object owner gets `OWNER` access, and `allUsers`
+ * get `READER` access.
+ * @property {boolean} [private] Make the uploaded file private. (Alias for
+ * `options.predefinedAcl = 'private'`)
+ * @property {boolean} [public] Make the uploaded file public. (Alias for
+ * `options.predefinedAcl = 'publicRead'`)
+ * @property {string} [userProject] The ID of the project which will be
+ * billed for the request.
+ * @property {string} [chunkSize] Create a separate request per chunk. This
+ * value is in bytes and should be a multiple of 256 KiB (2^18).
+ * {@link https://cloud.google.com/storage/docs/performing-resumable-uploads#chunked-upload| We recommend using at least 8 MiB for the chunk size.}
+ */
+ /**
+ * Create a unique resumable upload session URI. This is the first step when
+ * performing a resumable upload.
+ *
+ * See the {@link https://cloud.google.com/storage/docs/json_api/v1/how-tos/resumable-upload| Resumable upload guide}
+ * for more on how the entire process works.
+ *
+ * Note
+ *
+ * If you are just looking to perform a resumable upload without worrying
+ * about any of the details, see {@link File#createWriteStream}. Resumable
+ * uploads are performed by default.
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/how-tos/resumable-upload| Resumable upload guide}
+ *
+ * @param {CreateResumableUploadOptions} [options] Configuration options.
+ * @param {CreateResumableUploadCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const file = myBucket.file('my-file');
+ * file.createResumableUpload(function(err, uri) {
+ * if (!err) {
+ * // `uri` can be used to PUT data to.
+ * }
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * file.createResumableUpload().then(function(data) {
+ * const uri = data[0];
+ * });
+ * ```
+ */
+ createResumableUpload(optionsOrCallback, callback) {
+ var _a, _b;
+ const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
+ callback =
+ typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
+ const retryOptions = this.storage.retryOptions;
+ if ((((_a = options === null || options === void 0 ? void 0 : options.preconditionOpts) === null || _a === void 0 ? void 0 : _a.ifGenerationMatch) === undefined &&
+ ((_b = this.instancePreconditionOpts) === null || _b === void 0 ? void 0 : _b.ifGenerationMatch) === undefined &&
+ this.storage.retryOptions.idempotencyStrategy ===
+ storage_js_1.IdempotencyStrategy.RetryConditional) ||
+ this.storage.retryOptions.idempotencyStrategy ===
+ storage_js_1.IdempotencyStrategy.RetryNever) {
+ retryOptions.autoRetry = false;
+ }
+ resumableUpload.createURI({
+ authClient: this.storage.authClient,
+ apiEndpoint: this.storage.apiEndpoint,
+ bucket: this.bucket.name,
+ customRequestOptions: this.getRequestInterceptors().reduce((reqOpts, interceptorFn) => interceptorFn(reqOpts), {}),
+ file: this.name,
+ generation: this.generation,
+ key: this.encryptionKey,
+ kmsKeyName: this.kmsKeyName,
+ metadata: options.metadata,
+ offset: options.offset,
+ origin: options.origin,
+ predefinedAcl: options.predefinedAcl,
+ private: options.private,
+ public: options.public,
+ userProject: options.userProject || this.userProject,
+ retryOptions: retryOptions,
+ params: (options === null || options === void 0 ? void 0 : options.preconditionOpts) || this.instancePreconditionOpts,
+ universeDomain: this.bucket.storage.universeDomain,
+ [util_js_1.GCCL_GCS_CMD_KEY]: options[util_js_1.GCCL_GCS_CMD_KEY],
+ }, callback);
+ this.storage.retryOptions.autoRetry = this.instanceRetryValue;
+ }
+ /**
+ * @typedef {object} CreateWriteStreamOptions Configuration options for File#createWriteStream().
+ * @property {string} [contentType] Alias for
+ * `options.metadata.contentType`. If set to `auto`, the file name is used
+ * to determine the contentType.
+ * @property {string|boolean} [gzip] If true, automatically gzip the file.
+ * If set to `auto`, the contentType is used to determine if the file
+ * should be gzipped. This will set `options.metadata.contentEncoding` to
+ * `gzip` if necessary.
+ * @property {object} [metadata] See the examples below or
+ * {@link https://cloud.google.com/storage/docs/json_api/v1/objects/insert#request_properties_JSON| Objects: insert request body}
+ * for more details.
+ * @property {number} [offset] The starting byte of the upload stream, for
+ * resuming an interrupted upload. Defaults to 0.
+ * @property {string} [predefinedAcl] Apply a predefined set of access
+ * controls to this object.
+ *
+ * Acceptable values are:
+ * - **`authenticatedRead`** - Object owner gets `OWNER` access, and
+ * `allAuthenticatedUsers` get `READER` access.
+ *
+ * - **`bucketOwnerFullControl`** - Object owner gets `OWNER` access, and
+ * project team owners get `OWNER` access.
+ *
+ * - **`bucketOwnerRead`** - Object owner gets `OWNER` access, and project
+ * team owners get `READER` access.
+ *
+ * - **`private`** - Object owner gets `OWNER` access.
+ *
+ * - **`projectPrivate`** - Object owner gets `OWNER` access, and project
+ * team members get access according to their roles.
+ *
+ * - **`publicRead`** - Object owner gets `OWNER` access, and `allUsers`
+ * get `READER` access.
+ * @property {boolean} [private] Make the uploaded file private. (Alias for
+ * `options.predefinedAcl = 'private'`)
+ * @property {boolean} [public] Make the uploaded file public. (Alias for
+ * `options.predefinedAcl = 'publicRead'`)
+ * @property {boolean} [resumable] Force a resumable upload. NOTE: When
+ * working with streams, the file format and size is unknown until it's
+ * completely consumed. Because of this, it's best for you to be explicit
+ * for what makes sense given your input.
+ * @property {number} [timeout=60000] Set the HTTP request timeout in
+ * milliseconds. This option is not available for resumable uploads.
+ * Default: `60000`
+ * @property {string} [uri] The URI for an already-created resumable
+ * upload. See {@link File#createResumableUpload}.
+ * @property {string} [userProject] The ID of the project which will be
+ * billed for the request.
+ * @property {string|boolean} [validation] Possible values: `"md5"`,
+ * `"crc32c"`, or `false`. By default, data integrity is validated with a
+ * CRC32c checksum. You may use MD5 if preferred, but that hash is not
+ * supported for composite objects. An error will be raised if MD5 is
+ * specified but is not available. You may also choose to skip validation
+ * completely, however this is **not recommended**. In addition to specifying
+ * validation type, providing `metadata.crc32c` or `metadata.md5Hash` will
+ * cause the server to perform validation in addition to client validation.
+ * NOTE: Validation is automatically skipped for objects that were
+ * uploaded using the `gzip` option and have already compressed content.
+ */
+ /**
+ * Create a writable stream to overwrite the contents of the file in your
+ * bucket.
+ *
+ * A File object can also be used to create files for the first time.
+ *
+ * Resumable uploads are automatically enabled and must be shut off explicitly
+ * by setting `options.resumable` to `false`.
+ *
+ *
+ *
+ * There is some overhead when using a resumable upload that can cause
+ * noticeable performance degradation while uploading a series of small
+ * files. When uploading files less than 10MB, it is recommended that the
+ * resumable feature is disabled.
+ *
+ *
+ * NOTE: Writable streams will emit the `finish` event when the file is fully
+ * uploaded.
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload Upload Options (Simple or Resumable)}
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/objects/insert Objects: insert API Documentation}
+ *
+ * @param {CreateWriteStreamOptions} [options] Configuration options.
+ * @returns {WritableStream}
+ *
+ * @example
+ * ```
+ * const fs = require('fs');
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const file = myBucket.file('my-file');
+ *
+ * //-
+ * // Uploading a File
+ * //
+ * // Now, consider a case where we want to upload a file to your bucket. You
+ * // have the option of using {@link Bucket#upload}, but that is just
+ * // a convenience method which will do the following.
+ * //-
+ * fs.createReadStream('/Users/stephen/Photos/birthday-at-the-zoo/panda.jpg')
+ * .pipe(file.createWriteStream())
+ * .on('error', function(err) {})
+ * .on('finish', function() {
+ * // The file upload is complete.
+ * });
+ *
+ * //-
+ * // Uploading a File with gzip compression
+ * //-
+ * fs.createReadStream('/Users/stephen/site/index.html')
+ * .pipe(file.createWriteStream({ gzip: true }))
+ * .on('error', function(err) {})
+ * .on('finish', function() {
+ * // The file upload is complete.
+ * });
+ *
+ * //-
+ * // Downloading the file with `createReadStream` will automatically decode
+ * // the file.
+ * //-
+ *
+ * //-
+ * // Uploading a File with Metadata
+ * //
+ * // One last case you may run into is when you want to upload a file to your
+ * // bucket and set its metadata at the same time. Like above, you can use
+ * // {@link Bucket#upload} to do this, which is just a wrapper around
+ * // the following.
+ * //-
+ * fs.createReadStream('/Users/stephen/Photos/birthday-at-the-zoo/panda.jpg')
+ * .pipe(file.createWriteStream({
+ * metadata: {
+ * contentType: 'image/jpeg',
+ * metadata: {
+ * custom: 'metadata'
+ * }
+ * }
+ * }))
+ * .on('error', function(err) {})
+ * .on('finish', function() {
+ * // The file upload is complete.
+ * });
+ * ```
+ *
+ * //-
+ * // Continuing a Resumable Upload
+ * //
+ * // One can capture a `uri` from a resumable upload to reuse later.
+ * // Additionally, for validation, one can also capture and pass `crc32c`.
+ * //-
+ * let uri: string | undefined = undefined;
+ * let resumeCRC32C: string | undefined = undefined;
+ *
+ * fs.createWriteStream()
+ * .on('uri', link => {uri = link})
+ * .on('crc32', crc32c => {resumeCRC32C = crc32c});
+ *
+ * // later...
+ * fs.createWriteStream({uri, resumeCRC32C});
+ */
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ createWriteStream(options = {}) {
+ var _a;
+ (_a = options.metadata) !== null && _a !== void 0 ? _a : (options.metadata = {});
+ if (options.contentType) {
+ options.metadata.contentType = options.contentType;
+ }
+ if (!options.metadata.contentType ||
+ options.metadata.contentType === 'auto') {
+ const detectedContentType = mime_1.default.getType(this.name);
+ if (detectedContentType) {
+ options.metadata.contentType = detectedContentType;
+ }
+ }
+ let gzip = options.gzip;
+ if (gzip === 'auto') {
+ gzip = (0, compressible_1.default)(options.metadata.contentType || '');
+ }
+ if (gzip) {
+ options.metadata.contentEncoding = 'gzip';
+ }
+ let crc32c = true;
+ let md5 = false;
+ if (typeof options.validation === 'string') {
+ options.validation = options.validation.toLowerCase();
+ crc32c = options.validation === 'crc32c';
+ md5 = options.validation === 'md5';
+ }
+ else if (options.validation === false) {
+ crc32c = false;
+ md5 = false;
+ }
+ if (options.offset) {
+ if (md5) {
+ throw new RangeError(FileExceptionMessages.MD5_RESUMED_UPLOAD);
+ }
+ if (crc32c && !options.isPartialUpload && !options.resumeCRC32C) {
+ throw new RangeError(FileExceptionMessages.MISSING_RESUME_CRC32C_FINAL_UPLOAD);
+ }
+ }
+ /**
+ * A callback for determining when the underlying pipeline is complete.
+ * It's possible the pipeline callback could error before the write stream
+ * calls `final` so by default this will destroy the write stream unless the
+ * write stream sets this callback via its `final` handler.
+ * @param error An optional error
+ */
+ let pipelineCallback = error => {
+ writeStream.destroy(error || undefined);
+ };
+ // A stream for consumer to write to
+ const writeStream = new stream_1.Writable({
+ final(cb) {
+ // Set the pipeline callback to this callback so the pipeline's results
+ // can be populated to the consumer
+ pipelineCallback = cb;
+ emitStream.end();
+ },
+ write(chunk, encoding, cb) {
+ emitStream.write(chunk, encoding, cb);
+ },
+ });
+ const transformStreams = [];
+ if (gzip) {
+ transformStreams.push(zlib.createGzip());
+ }
+ const emitStream = new util_js_2.PassThroughShim();
+ let hashCalculatingStream = null;
+ if (crc32c || md5) {
+ const crc32cInstance = options.resumeCRC32C
+ ? crc32c_js_1.CRC32C.from(options.resumeCRC32C)
+ : undefined;
+ hashCalculatingStream = new hash_stream_validator_js_1.HashStreamValidator({
+ crc32c,
+ crc32cInstance,
+ md5,
+ crc32cGenerator: this.crc32cGenerator,
+ updateHashesOnly: true,
+ });
+ transformStreams.push(hashCalculatingStream);
+ }
+ const fileWriteStream = (0, duplexify_1.default)();
+ let fileWriteStreamMetadataReceived = false;
+ // Handing off emitted events to users
+ emitStream.on('reading', () => writeStream.emit('reading'));
+ emitStream.on('writing', () => writeStream.emit('writing'));
+ fileWriteStream.on('uri', evt => writeStream.emit('uri', evt));
+ fileWriteStream.on('progress', evt => writeStream.emit('progress', evt));
+ fileWriteStream.on('response', resp => writeStream.emit('response', resp));
+ fileWriteStream.once('metadata', () => {
+ fileWriteStreamMetadataReceived = true;
+ });
+ writeStream.once('writing', () => {
+ if (options.resumable === false) {
+ this.startSimpleUpload_(fileWriteStream, options);
+ }
+ else {
+ this.startResumableUpload_(fileWriteStream, options);
+ }
+ (0, stream_1.pipeline)(emitStream, ...transformStreams, fileWriteStream, async (e) => {
+ if (e) {
+ return pipelineCallback(e);
+ }
+ // We want to make sure we've received the metadata from the server in order
+ // to properly validate the object's integrity. Depending on the type of upload,
+ // the stream could close before the response is returned.
+ if (!fileWriteStreamMetadataReceived) {
+ try {
+ await new Promise((resolve, reject) => {
+ fileWriteStream.once('metadata', resolve);
+ fileWriteStream.once('error', reject);
+ });
+ }
+ catch (e) {
+ return pipelineCallback(e);
+ }
+ }
+ // Emit the local CRC32C value for future validation, if validation is enabled.
+ if (hashCalculatingStream === null || hashCalculatingStream === void 0 ? void 0 : hashCalculatingStream.crc32c) {
+ writeStream.emit('crc32c', hashCalculatingStream.crc32c);
+ }
+ try {
+ // Metadata may not be ready if the upload is a partial upload,
+ // nothing to validate yet.
+ const metadataNotReady = options.isPartialUpload && !this.metadata;
+ if (hashCalculatingStream && !metadataNotReady) {
+ await __classPrivateFieldGet(this, _File_instances, "m", _File_validateIntegrity).call(this, hashCalculatingStream, {
+ crc32c,
+ md5,
+ });
+ }
+ pipelineCallback();
+ }
+ catch (e) {
+ pipelineCallback(e);
+ }
+ });
+ });
+ return writeStream;
+ }
+ delete(optionsOrCallback, cb) {
+ const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
+ cb = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
+ this.disableAutoRetryConditionallyIdempotent_(this.methods.delete, bucket_js_1.AvailableServiceObjectMethods.delete, options);
+ super
+ .delete(options)
+ .then(resp => cb(null, ...resp))
+ .catch(cb)
+ .finally(() => {
+ this.storage.retryOptions.autoRetry = this.instanceRetryValue;
+ });
+ }
+ /**
+ * @typedef {array} DownloadResponse
+ * @property [0] The contents of a File.
+ */
+ /**
+ * @callback DownloadCallback
+ * @param err Request error, if any.
+ * @param contents The contents of a File.
+ */
+ /**
+ * Convenience method to download a file into memory or to a local
+ * destination.
+ *
+ * @param {object} [options] Configuration options. The arguments match those
+ * passed to {@link File#createReadStream}.
+ * @param {string} [options.destination] Local file path to write the file's
+ * contents to.
+ * @param {string} [options.userProject] The ID of the project which will be
+ * billed for the request.
+ * @param {DownloadCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const file = myBucket.file('my-file');
+ *
+ * //-
+ * // Download a file into memory. The contents will be available as the
+ * second
+ * // argument in the demonstration below, `contents`.
+ * //-
+ * file.download(function(err, contents) {});
+ *
+ * //-
+ * // Download a file to a local destination.
+ * //-
+ * file.download({
+ * destination: '/Users/me/Desktop/file-backup.txt'
+ * }, function(err) {});
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * file.download().then(function(data) {
+ * const contents = data[0];
+ * });
+ *
+ * ```
+ * @example include:samples/files.js
+ * region_tag:storage_download_file
+ * Another example:
+ *
+ * @example include:samples/encryption.js
+ * region_tag:storage_download_encrypted_file
+ * Example of downloading an encrypted file:
+ *
+ * @example include:samples/requesterPays.js
+ * region_tag:storage_download_file_requester_pays
+ * Example of downloading a file where the requester pays:
+ */
+ download(optionsOrCallback, cb) {
+ let options;
+ if (typeof optionsOrCallback === 'function') {
+ cb = optionsOrCallback;
+ options = {};
+ }
+ else {
+ options = optionsOrCallback;
+ }
+ let called = false;
+ const callback = ((...args) => {
+ if (!called)
+ cb(...args);
+ called = true;
+ });
+ const destination = options.destination;
+ delete options.destination;
+ const fileStream = this.createReadStream(options);
+ let receivedData = false;
+ if (destination) {
+ fileStream
+ .on('error', callback)
+ .once('data', data => {
+ // We know that the file exists the server - now we can truncate/write to a file
+ receivedData = true;
+ const writable = fs.createWriteStream(destination);
+ writable.write(data);
+ fileStream
+ .pipe(writable)
+ .on('error', callback)
+ .on('finish', callback);
+ })
+ .on('end', () => {
+ // In the case of an empty file no data will be received before the end event fires
+ if (!receivedData) {
+ const data = Buffer.alloc(0);
+ try {
+ fs.writeFileSync(destination, data);
+ callback(null, data);
+ }
+ catch (e) {
+ callback(e, data);
+ }
+ }
+ });
+ }
+ else {
+ this.getBufferFromReadable(fileStream)
+ .then(contents => callback === null || callback === void 0 ? void 0 : callback(null, contents))
+ .catch(callback);
+ }
+ }
+ /**
+ * The Storage API allows you to use a custom key for server-side encryption.
+ *
+ * See {@link https://cloud.google.com/storage/docs/encryption#customer-supplied| Customer-supplied Encryption Keys}
+ *
+ * @param {string|buffer} encryptionKey An AES-256 encryption key.
+ * @returns {File}
+ *
+ * @example
+ * ```
+ * const crypto = require('crypto');
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const encryptionKey = crypto.randomBytes(32);
+ *
+ * const fileWithCustomEncryption = myBucket.file('my-file');
+ * fileWithCustomEncryption.setEncryptionKey(encryptionKey);
+ *
+ * const fileWithoutCustomEncryption = myBucket.file('my-file');
+ *
+ * fileWithCustomEncryption.save('data', function(err) {
+ * // Try to download with the File object that hasn't had
+ * // `setEncryptionKey()` called:
+ * fileWithoutCustomEncryption.download(function(err) {
+ * // We will receive an error:
+ * // err.message === 'Bad Request'
+ *
+ * // Try again with the File object we called `setEncryptionKey()` on:
+ * fileWithCustomEncryption.download(function(err, contents) {
+ * // contents.toString() === 'data'
+ * });
+ * });
+ * });
+ *
+ * ```
+ * @example include:samples/encryption.js
+ * region_tag:storage_upload_encrypted_file
+ * Example of uploading an encrypted file:
+ *
+ * @example include:samples/encryption.js
+ * region_tag:storage_download_encrypted_file
+ * Example of downloading an encrypted file:
+ */
+ setEncryptionKey(encryptionKey) {
+ this.encryptionKey = encryptionKey;
+ this.encryptionKeyBase64 = Buffer.from(encryptionKey).toString('base64');
+ this.encryptionKeyHash = crypto
+ .createHash('sha256')
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ .update(this.encryptionKeyBase64, 'base64')
+ .digest('base64');
+ this.encryptionKeyInterceptor = {
+ request: reqOpts => {
+ reqOpts.headers = reqOpts.headers || {};
+ reqOpts.headers['x-goog-encryption-algorithm'] = 'AES256';
+ reqOpts.headers['x-goog-encryption-key'] = this.encryptionKeyBase64;
+ reqOpts.headers['x-goog-encryption-key-sha256'] =
+ this.encryptionKeyHash;
+ return reqOpts;
+ },
+ };
+ this.interceptors.push(this.encryptionKeyInterceptor);
+ return this;
+ }
+ get(optionsOrCallback, cb) {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
+ cb =
+ typeof optionsOrCallback === 'function'
+ ? optionsOrCallback
+ : cb;
+ super
+ .get(options)
+ .then(resp => cb(null, ...resp))
+ .catch(cb);
+ }
+ /**
+ * @typedef {array} GetExpirationDateResponse
+ * @property {date} 0 A Date object representing the earliest time this file's
+ * retention policy will expire.
+ */
+ /**
+ * @callback GetExpirationDateCallback
+ * @param {?Error} err Request error, if any.
+ * @param {date} expirationDate A Date object representing the earliest time
+ * this file's retention policy will expire.
+ */
+ /**
+ * If this bucket has a retention policy defined, use this method to get a
+ * Date object representing the earliest time this file will expire.
+ *
+ * @param {GetExpirationDateCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const storage = require('@google-cloud/storage')();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const file = myBucket.file('my-file');
+ *
+ * file.getExpirationDate(function(err, expirationDate) {
+ * // expirationDate is a Date object.
+ * });
+ * ```
+ */
+ getExpirationDate(callback) {
+ this.getMetadata((err, metadata, apiResponse) => {
+ if (err) {
+ callback(err, null, apiResponse);
+ return;
+ }
+ if (!metadata.retentionExpirationTime) {
+ const error = new Error(FileExceptionMessages.EXPIRATION_TIME_NA);
+ callback(error, null, apiResponse);
+ return;
+ }
+ callback(null, new Date(metadata.retentionExpirationTime), apiResponse);
+ });
+ }
+ /**
+ * @typedef {array} GenerateSignedPostPolicyV2Response
+ * @property {object} 0 The document policy.
+ */
+ /**
+ * @callback GenerateSignedPostPolicyV2Callback
+ * @param {?Error} err Request error, if any.
+ * @param {object} policy The document policy.
+ */
+ /**
+ * Get a signed policy document to allow a user to upload data with a POST
+ * request.
+ *
+ * In Google Cloud Platform environments, such as Cloud Functions and App
+ * Engine, you usually don't provide a `keyFilename` or `credentials` during
+ * instantiation. In those environments, we call the
+ * {@link https://cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/signBlob| signBlob API}
+ * to create a signed policy. That API requires either the
+ * `https://www.googleapis.com/auth/iam` or
+ * `https://www.googleapis.com/auth/cloud-platform` scope, so be sure they are
+ * enabled.
+ *
+ * See {@link https://cloud.google.com/storage/docs/xml-api/post-object-v2| POST Object with the V2 signing process}
+ *
+ * @throws {Error} If an expiration timestamp from the past is given.
+ * @throws {Error} If options.equals has an array with less or more than two
+ * members.
+ * @throws {Error} If options.startsWith has an array with less or more than two
+ * members.
+ *
+ * @param {object} options Configuration options.
+ * @param {array|array[]} [options.equals] Array of request parameters and
+ * their expected value (e.g. [['$', '']]). Values are
+ * translated into equality constraints in the conditions field of the
+ * policy document (e.g. ['eq', '$', '']). If only one
+ * equality condition is to be specified, options.equals can be a one-
+ * dimensional array (e.g. ['$', '']).
+ * @param {*} options.expires - A timestamp when this policy will expire. Any
+ * value given is passed to `new Date()`.
+ * @param {array|array[]} [options.startsWith] Array of request parameters and
+ * their expected prefixes (e.g. [['$', '']). Values are
+ * translated into starts-with constraints in the conditions field of the
+ * policy document (e.g. ['starts-with', '$', '']). If only
+ * one prefix condition is to be specified, options.startsWith can be a
+ * one- dimensional array (e.g. ['$', '']).
+ * @param {string} [options.acl] ACL for the object from possibly predefined
+ * ACLs.
+ * @param {string} [options.successRedirect] The URL to which the user client
+ * is redirected if the upload is successful.
+ * @param {string} [options.successStatus] - The status of the Google Storage
+ * response if the upload is successful (must be string).
+ * @param {object} [options.contentLengthRange]
+ * @param {number} [options.contentLengthRange.min] Minimum value for the
+ * request's content length.
+ * @param {number} [options.contentLengthRange.max] Maximum value for the
+ * request's content length.
+ * @param {GenerateSignedPostPolicyV2Callback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const file = myBucket.file('my-file');
+ * const options = {
+ * equals: ['$Content-Type', 'image/jpeg'],
+ * expires: '10-25-2022',
+ * contentLengthRange: {
+ * min: 0,
+ * max: 1024
+ * }
+ * };
+ *
+ * file.generateSignedPostPolicyV2(options, function(err, policy) {
+ * // policy.string: the policy document in plain text.
+ * // policy.base64: the policy document in base64.
+ * // policy.signature: the policy signature in base64.
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * file.generateSignedPostPolicyV2(options).then(function(data) {
+ * const policy = data[0];
+ * });
+ * ```
+ */
+ generateSignedPostPolicyV2(optionsOrCallback, cb) {
+ const args = (0, util_js_2.normalize)(optionsOrCallback, cb);
+ let options = args.options;
+ const callback = args.callback;
+ const expires = new Date(options.expires);
+ if (isNaN(expires.getTime())) {
+ throw new Error(storage_js_1.ExceptionMessages.EXPIRATION_DATE_INVALID);
+ }
+ if (expires.valueOf() < Date.now()) {
+ throw new Error(storage_js_1.ExceptionMessages.EXPIRATION_DATE_PAST);
+ }
+ options = Object.assign({}, options);
+ const conditions = [
+ ['eq', '$key', this.name],
+ {
+ bucket: this.bucket.name,
+ },
+ ];
+ if (Array.isArray(options.equals)) {
+ if (!Array.isArray(options.equals[0])) {
+ options.equals = [options.equals];
+ }
+ options.equals.forEach(condition => {
+ if (!Array.isArray(condition) || condition.length !== 2) {
+ throw new Error(FileExceptionMessages.EQUALS_CONDITION_TWO_ELEMENTS);
+ }
+ conditions.push(['eq', condition[0], condition[1]]);
+ });
+ }
+ if (Array.isArray(options.startsWith)) {
+ if (!Array.isArray(options.startsWith[0])) {
+ options.startsWith = [options.startsWith];
+ }
+ options.startsWith.forEach(condition => {
+ if (!Array.isArray(condition) || condition.length !== 2) {
+ throw new Error(FileExceptionMessages.STARTS_WITH_TWO_ELEMENTS);
+ }
+ conditions.push(['starts-with', condition[0], condition[1]]);
+ });
+ }
+ if (options.acl) {
+ conditions.push({
+ acl: options.acl,
+ });
+ }
+ if (options.successRedirect) {
+ conditions.push({
+ success_action_redirect: options.successRedirect,
+ });
+ }
+ if (options.successStatus) {
+ conditions.push({
+ success_action_status: options.successStatus,
+ });
+ }
+ if (options.contentLengthRange) {
+ const min = options.contentLengthRange.min;
+ const max = options.contentLengthRange.max;
+ if (typeof min !== 'number' || typeof max !== 'number') {
+ throw new Error(FileExceptionMessages.CONTENT_LENGTH_RANGE_MIN_MAX);
+ }
+ conditions.push(['content-length-range', min, max]);
+ }
+ const policy = {
+ expiration: expires.toISOString(),
+ conditions,
+ };
+ const policyString = JSON.stringify(policy);
+ const policyBase64 = Buffer.from(policyString).toString('base64');
+ this.storage.authClient.sign(policyBase64, options.signingEndpoint).then(signature => {
+ callback(null, {
+ string: policyString,
+ base64: policyBase64,
+ signature,
+ });
+ }, err => {
+ callback(new signer_js_1.SigningError(err.message));
+ });
+ }
+ /**
+ * @typedef {object} SignedPostPolicyV4Output
+ * @property {string} url The request URL.
+ * @property {object} fields The form fields to include in the POST request.
+ */
+ /**
+ * @typedef {array} GenerateSignedPostPolicyV4Response
+ * @property {SignedPostPolicyV4Output} 0 An object containing the request URL and form fields.
+ */
+ /**
+ * @callback GenerateSignedPostPolicyV4Callback
+ * @param {?Error} err Request error, if any.
+ * @param {SignedPostPolicyV4Output} output An object containing the request URL and form fields.
+ */
+ /**
+ * Get a v4 signed policy document to allow a user to upload data with a POST
+ * request.
+ *
+ * In Google Cloud Platform environments, such as Cloud Functions and App
+ * Engine, you usually don't provide a `keyFilename` or `credentials` during
+ * instantiation. In those environments, we call the
+ * {@link https://cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/signBlob| signBlob API}
+ * to create a signed policy. That API requires either the
+ * `https://www.googleapis.com/auth/iam` or
+ * `https://www.googleapis.com/auth/cloud-platform` scope, so be sure they are
+ * enabled.
+ *
+ * See {@link https://cloud.google.com/storage/docs/xml-api/post-object#policydocument| Policy Document Reference}
+ *
+ * @param {object} options Configuration options.
+ * @param {Date|number|string} options.expires - A timestamp when this policy will expire. Any
+ * value given is passed to `new Date()`.
+ * @param {boolean} [config.virtualHostedStyle=false] Use virtual hosted-style
+ * URLs ('https://mybucket.storage.googleapis.com/...') instead of path-style
+ * ('https://storage.googleapis.com/mybucket/...'). Virtual hosted-style URLs
+ * should generally be preferred instead of path-style URL.
+ * Currently defaults to `false` for path-style, although this may change in a
+ * future major-version release.
+ * @param {string} [config.bucketBoundHostname] The bucket-bound hostname to return in
+ * the result, e.g. "https://cdn.example.com".
+ * @param {object} [config.fields] [Form fields]{@link https://cloud.google.com/storage/docs/xml-api/post-object#policydocument}
+ * to include in the signed policy. Any fields with key beginning with 'x-ignore-'
+ * will not be included in the policy to be signed.
+ * @param {object[]} [config.conditions] [Conditions]{@link https://cloud.google.com/storage/docs/authentication/signatures#policy-document}
+ * to include in the signed policy. All fields given in `config.fields` are
+ * automatically included in the conditions array, adding the same entry
+ * in both `fields` and `conditions` will result in duplicate entries.
+ *
+ * @param {GenerateSignedPostPolicyV4Callback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const file = myBucket.file('my-file');
+ * const options = {
+ * expires: '10-25-2022',
+ * conditions: [
+ * ['eq', '$Content-Type', 'image/jpeg'],
+ * ['content-length-range', 0, 1024],
+ * ],
+ * fields: {
+ * acl: 'public-read',
+ * 'x-goog-meta-foo': 'bar',
+ * 'x-ignore-mykey': 'data'
+ * }
+ * };
+ *
+ * file.generateSignedPostPolicyV4(options, function(err, response) {
+ * // response.url The request URL
+ * // response.fields The form fields (including the signature) to include
+ * // to be used to upload objects by HTML forms.
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * file.generateSignedPostPolicyV4(options).then(function(data) {
+ * const response = data[0];
+ * // response.url The request URL
+ * // response.fields The form fields (including the signature) to include
+ * // to be used to upload objects by HTML forms.
+ * });
+ * ```
+ */
+ generateSignedPostPolicyV4(optionsOrCallback, cb) {
+ const args = (0, util_js_2.normalize)(optionsOrCallback, cb);
+ let options = args.options;
+ const callback = args.callback;
+ const expires = new Date(options.expires);
+ if (isNaN(expires.getTime())) {
+ throw new Error(storage_js_1.ExceptionMessages.EXPIRATION_DATE_INVALID);
+ }
+ if (expires.valueOf() < Date.now()) {
+ throw new Error(storage_js_1.ExceptionMessages.EXPIRATION_DATE_PAST);
+ }
+ if (expires.valueOf() - Date.now() > SEVEN_DAYS * 1000) {
+ throw new Error(`Max allowed expiration is seven days (${SEVEN_DAYS} seconds).`);
+ }
+ options = Object.assign({}, options);
+ let fields = Object.assign({}, options.fields);
+ const now = new Date();
+ const nowISO = (0, util_js_2.formatAsUTCISO)(now, true);
+ const todayISO = (0, util_js_2.formatAsUTCISO)(now);
+ const sign = async () => {
+ const { client_email } = await this.storage.authClient.getCredentials();
+ const credential = `${client_email}/${todayISO}/auto/storage/goog4_request`;
+ fields = {
+ ...fields,
+ bucket: this.bucket.name,
+ key: this.name,
+ 'x-goog-date': nowISO,
+ 'x-goog-credential': credential,
+ 'x-goog-algorithm': 'GOOG4-RSA-SHA256',
+ };
+ const conditions = options.conditions || [];
+ Object.entries(fields).forEach(([key, value]) => {
+ if (!key.startsWith('x-ignore-')) {
+ conditions.push({ [key]: value });
+ }
+ });
+ delete fields.bucket;
+ const expiration = (0, util_js_2.formatAsUTCISO)(expires, true, '-', ':');
+ const policy = {
+ conditions,
+ expiration,
+ };
+ const policyString = (0, util_js_2.unicodeJSONStringify)(policy);
+ const policyBase64 = Buffer.from(policyString).toString('base64');
+ try {
+ const signature = await this.storage.authClient.sign(policyBase64, options.signingEndpoint);
+ const signatureHex = Buffer.from(signature, 'base64').toString('hex');
+ const universe = this.parent.storage.universeDomain;
+ fields['policy'] = policyBase64;
+ fields['x-goog-signature'] = signatureHex;
+ let url;
+ if (this.storage.customEndpoint) {
+ url = this.storage.apiEndpoint;
+ }
+ else if (options.virtualHostedStyle) {
+ url = `https://${this.bucket.name}.storage.${universe}/`;
+ }
+ else if (options.bucketBoundHostname) {
+ url = `${options.bucketBoundHostname}/`;
+ }
+ else {
+ url = `https://storage.${universe}/${this.bucket.name}/`;
+ }
+ return {
+ url,
+ fields,
+ };
+ }
+ catch (err) {
+ throw new signer_js_1.SigningError(err.message);
+ }
+ };
+ sign().then(res => callback(null, res), callback);
+ }
+ /**
+ * @typedef {array} GetSignedUrlResponse
+ * @property {object} 0 The signed URL.
+ */
+ /**
+ * @callback GetSignedUrlCallback
+ * @param {?Error} err Request error, if any.
+ * @param {object} url The signed URL.
+ */
+ /**
+ * Get a signed URL to allow limited time access to the file.
+ *
+ * In Google Cloud Platform environments, such as Cloud Functions and App
+ * Engine, you usually don't provide a `keyFilename` or `credentials` during
+ * instantiation. In those environments, we call the
+ * {@link https://cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/signBlob| signBlob API}
+ * to create a signed URL. That API requires either the
+ * `https://www.googleapis.com/auth/iam` or
+ * `https://www.googleapis.com/auth/cloud-platform` scope, so be sure they are
+ * enabled.
+ *
+ * See {@link https://cloud.google.com/storage/docs/access-control/signed-urls| Signed URLs Reference}
+ *
+ * @throws {Error} if an expiration timestamp from the past is given.
+ *
+ * @param {object} config Configuration object.
+ * @param {string} config.action "read" (HTTP: GET), "write" (HTTP: PUT), or
+ * "delete" (HTTP: DELETE), "resumable" (HTTP: POST).
+ * When using "resumable", the header `X-Goog-Resumable: start` has
+ * to be sent when making a request with the signed URL.
+ * @param {*} config.expires A timestamp when this link will expire. Any value
+ * given is passed to `new Date()`.
+ * Note: 'v4' supports maximum duration of 7 days (604800 seconds) from now.
+ * See [reference]{@link https://cloud.google.com/storage/docs/access-control/signed-urls#example}
+ * @param {string} [config.version='v2'] The signing version to use, either
+ * 'v2' or 'v4'.
+ * @param {boolean} [config.virtualHostedStyle=false] Use virtual hosted-style
+ * URLs (e.g. 'https://mybucket.storage.googleapis.com/...') instead of path-style
+ * (e.g. 'https://storage.googleapis.com/mybucket/...'). Virtual hosted-style URLs
+ * should generally be preferred instaed of path-style URL.
+ * Currently defaults to `false` for path-style, although this may change in a
+ * future major-version release.
+ * @param {string} [config.cname] The cname for this bucket, i.e.,
+ * "https://cdn.example.com".
+ * @param {string} [config.contentMd5] The MD5 digest value in base64. Just like
+ * if you provide this, the client must provide this HTTP header with this same
+ * value in its request, so to if this parameter is not provided here,
+ * the client must not provide any value for this HTTP header in its request.
+ * @param {string} [config.contentType] Just like if you provide this, the client
+ * must provide this HTTP header with this same value in its request, so to if
+ * this parameter is not provided here, the client must not provide any value
+ * for this HTTP header in its request.
+ * @param {object} [config.extensionHeaders] If these headers are used, the
+ * server will check to make sure that the client provides matching
+ * values. See {@link https://cloud.google.com/storage/docs/access-control/signed-urls#about-canonical-extension-headers| Canonical extension headers}
+ * for the requirements of this feature, most notably:
+ * - The header name must be prefixed with `x-goog-`
+ * - The header name must be all lowercase
+ *
+ * Note: Multi-valued header passed as an array in the extensionHeaders
+ * object is converted into a string, delimited by `,` with
+ * no space. Requests made using the signed URL will need to
+ * delimit multi-valued headers using a single `,` as well, or
+ * else the server will report a mismatched signature.
+ * @param {object} [config.queryParams] Additional query parameters to include
+ * in the signed URL.
+ * @param {string} [config.promptSaveAs] The filename to prompt the user to
+ * save the file as when the signed url is accessed. This is ignored if
+ * `config.responseDisposition` is set.
+ * @param {string} [config.responseDisposition] The
+ * {@link http://goo.gl/yMWxQV| response-content-disposition parameter} of the
+ * signed url.
+ * @param {*} [config.accessibleAt=Date.now()] A timestamp when this link became usable. Any value
+ * given is passed to `new Date()`.
+ * Note: Use for 'v4' only.
+ * @param {string} [config.responseType] The response-content-type parameter
+ * of the signed url.
+ * @param {GetSignedUrlCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const file = myBucket.file('my-file');
+ *
+ * //-
+ * // Generate a URL that allows temporary access to download your file.
+ * //-
+ * const request = require('request');
+ *
+ * const config = {
+ * action: 'read',
+ * expires: '03-17-2025',
+ * };
+ *
+ * file.getSignedUrl(config, function(err, url) {
+ * if (err) {
+ * console.error(err);
+ * return;
+ * }
+ *
+ * // The file is now available to read from this URL.
+ * request(url, function(err, resp) {
+ * // resp.statusCode = 200
+ * });
+ * });
+ *
+ * //-
+ * // Generate a URL that allows temporary access to download your file.
+ * // Access will begin at accessibleAt and end at expires.
+ * //-
+ * const request = require('request');
+ *
+ * const config = {
+ * action: 'read',
+ * expires: '03-17-2025',
+ * accessibleAt: '03-13-2025'
+ * };
+ *
+ * file.getSignedUrl(config, function(err, url) {
+ * if (err) {
+ * console.error(err);
+ * return;
+ * }
+ *
+ * // The file will be available to read from this URL from 03-13-2025 to 03-17-2025.
+ * request(url, function(err, resp) {
+ * // resp.statusCode = 200
+ * });
+ * });
+ *
+ * //-
+ * // Generate a URL to allow write permissions. This means anyone with this
+ * URL
+ * // can send a POST request with new data that will overwrite the file.
+ * //-
+ * file.getSignedUrl({
+ * action: 'write',
+ * expires: '03-17-2025'
+ * }, function(err, url) {
+ * if (err) {
+ * console.error(err);
+ * return;
+ * }
+ *
+ * // The file is now available to be written to.
+ * const writeStream = request.put(url);
+ * writeStream.end('New data');
+ *
+ * writeStream.on('complete', function(resp) {
+ * // Confirm the new content was saved.
+ * file.download(function(err, fileContents) {
+ * console.log('Contents:', fileContents.toString());
+ * // Contents: New data
+ * });
+ * });
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * file.getSignedUrl(config).then(function(data) {
+ * const url = data[0];
+ * });
+ *
+ * ```
+ * @example include:samples/files.js
+ * region_tag:storage_generate_signed_url
+ * Another example:
+ */
+ getSignedUrl(cfg, callback) {
+ const method = ActionToHTTPMethod[cfg.action];
+ const extensionHeaders = (0, util_js_2.objectKeyToLowercase)(cfg.extensionHeaders || {});
+ if (cfg.action === 'resumable') {
+ extensionHeaders['x-goog-resumable'] = 'start';
+ }
+ const queryParams = Object.assign({}, cfg.queryParams);
+ if (typeof cfg.responseType === 'string') {
+ queryParams['response-content-type'] = cfg.responseType;
+ }
+ if (typeof cfg.promptSaveAs === 'string') {
+ queryParams['response-content-disposition'] =
+ 'attachment; filename="' + cfg.promptSaveAs + '"';
+ }
+ if (typeof cfg.responseDisposition === 'string') {
+ queryParams['response-content-disposition'] = cfg.responseDisposition;
+ }
+ if (this.generation) {
+ queryParams['generation'] = this.generation.toString();
+ }
+ const signConfig = {
+ method,
+ expires: cfg.expires,
+ accessibleAt: cfg.accessibleAt,
+ extensionHeaders,
+ queryParams,
+ contentMd5: cfg.contentMd5,
+ contentType: cfg.contentType,
+ host: cfg.host,
+ };
+ if (cfg.cname) {
+ signConfig.cname = cfg.cname;
+ }
+ if (cfg.version) {
+ signConfig.version = cfg.version;
+ }
+ if (cfg.virtualHostedStyle) {
+ signConfig.virtualHostedStyle = cfg.virtualHostedStyle;
+ }
+ if (!this.signer) {
+ this.signer = new signer_js_1.URLSigner(this.storage.authClient, this.bucket, this, this.storage);
+ }
+ this.signer
+ .getSignedUrl(signConfig)
+ .then(signedUrl => callback(null, signedUrl), callback);
+ }
+ /**
+ * @callback IsPublicCallback
+ * @param {?Error} err Request error, if any.
+ * @param {boolean} resp Whether file is public or not.
+ */
+ /**
+ * @typedef {array} IsPublicResponse
+ * @property {boolean} 0 Whether file is public or not.
+ */
+ /**
+ * Check whether this file is public or not by sending
+ * a HEAD request without credentials.
+ * No errors from the server indicates that the current
+ * file is public.
+ * A 403-Forbidden error {@link https://cloud.google.com/storage/docs/json_api/v1/status-codes#403_Forbidden}
+ * indicates that file is private.
+ * Any other non 403 error is propagated to user.
+ *
+ * @param {IsPublicCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const file = myBucket.file('my-file');
+ *
+ * //-
+ * // Check whether the file is publicly accessible.
+ * //-
+ * file.isPublic(function(err, resp) {
+ * if (err) {
+ * console.error(err);
+ * return;
+ * }
+ * console.log(`the file ${file.id} is public: ${resp}`) ;
+ * })
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * file.isPublic().then(function(data) {
+ * const resp = data[0];
+ * });
+ * ```
+ */
+ isPublic(callback) {
+ var _a;
+ // Build any custom headers based on the defined interceptors on the parent
+ // storage object and this object
+ const storageInterceptors = ((_a = this.storage) === null || _a === void 0 ? void 0 : _a.interceptors) || [];
+ const fileInterceptors = this.interceptors || [];
+ const allInterceptors = storageInterceptors.concat(fileInterceptors);
+ const headers = allInterceptors.reduce((acc, curInterceptor) => {
+ const currentHeaders = curInterceptor.request({
+ uri: `${this.storage.apiEndpoint}/${this.bucket.name}/${encodeURIComponent(this.name)}`,
+ });
+ Object.assign(acc, currentHeaders.headers);
+ return acc;
+ }, {});
+ index_js_1.util.makeRequest({
+ method: 'GET',
+ uri: `${this.storage.apiEndpoint}/${this.bucket.name}/${encodeURIComponent(this.name)}`,
+ headers,
+ }, {
+ retryOptions: this.storage.retryOptions,
+ }, (err) => {
+ if (err) {
+ const apiError = err;
+ if (apiError.code === 403) {
+ callback(null, false);
+ }
+ else {
+ callback(err);
+ }
+ }
+ else {
+ callback(null, true);
+ }
+ });
+ }
+ /**
+ * @typedef {object} MakeFilePrivateOptions Configuration options for File#makePrivate().
+ * @property {Metadata} [metadata] Define custom metadata properties to define
+ * along with the operation.
+ * @property {boolean} [strict] If true, set the file to be private to
+ * only the owner user. Otherwise, it will be private to the project.
+ * @property {string} [userProject] The ID of the project which will be
+ * billed for the request.
+ */
+ /**
+ * @callback MakeFilePrivateCallback
+ * @param {?Error} err Request error, if any.
+ * @param {object} apiResponse The full API response.
+ */
+ /**
+ * @typedef {array} MakeFilePrivateResponse
+ * @property {object} 0 The full API response.
+ */
+ /**
+ * Make a file private to the project and remove all other permissions.
+ * Set `options.strict` to true to make the file private to only the owner.
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/objects/patch| Objects: patch API Documentation}
+ *
+ * @param {MakeFilePrivateOptions} [options] Configuration options.
+ * @param {MakeFilePrivateCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const file = myBucket.file('my-file');
+ *
+ * //-
+ * // Set the file private so only project maintainers can see and modify it.
+ * //-
+ * file.makePrivate(function(err) {});
+ *
+ * //-
+ * // Set the file private so only the owner can see and modify it.
+ * //-
+ * file.makePrivate({ strict: true }, function(err) {});
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * file.makePrivate().then(function(data) {
+ * const apiResponse = data[0];
+ * });
+ * ```
+ */
+ makePrivate(optionsOrCallback, callback) {
+ var _a, _b;
+ const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
+ callback =
+ typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
+ const query = {
+ predefinedAcl: options.strict ? 'private' : 'projectPrivate',
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ };
+ if (((_a = options.preconditionOpts) === null || _a === void 0 ? void 0 : _a.ifMetagenerationMatch) !== undefined) {
+ query.ifMetagenerationMatch =
+ (_b = options.preconditionOpts) === null || _b === void 0 ? void 0 : _b.ifMetagenerationMatch;
+ delete options.preconditionOpts;
+ }
+ if (options.userProject) {
+ query.userProject = options.userProject;
+ }
+ // You aren't allowed to set both predefinedAcl & acl properties on a file,
+ // so acl must explicitly be nullified, destroying all previous acls on the
+ // file.
+ const metadata = { ...options.metadata, acl: null };
+ this.setMetadata(metadata, query, callback);
+ }
+ /**
+ * @typedef {array} MakeFilePublicResponse
+ * @property {object} 0 The full API response.
+ */
+ /**
+ * @callback MakeFilePublicCallback
+ * @param {?Error} err Request error, if any.
+ * @param {object} apiResponse The full API response.
+ */
+ /**
+ * Set a file to be publicly readable and maintain all previous permissions.
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/objectAccessControls/insert| ObjectAccessControls: insert API Documentation}
+ *
+ * @param {MakeFilePublicCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const file = myBucket.file('my-file');
+ *
+ * file.makePublic(function(err, apiResponse) {});
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * file.makePublic().then(function(data) {
+ * const apiResponse = data[0];
+ * });
+ *
+ * ```
+ * @example include:samples/files.js
+ * region_tag:storage_make_public
+ * Another example:
+ */
+ makePublic(callback) {
+ callback = callback || index_js_1.util.noop;
+ this.acl.add({
+ entity: 'allUsers',
+ role: 'READER',
+ }, (err, acl, resp) => {
+ callback(err, resp);
+ });
+ }
+ /**
+ * The public URL of this File
+ * Use {@link File#makePublic} to enable anonymous access via the returned URL.
+ *
+ * @returns {string}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('albums');
+ * const file = bucket.file('my-file');
+ *
+ * // publicUrl will be "https://storage.googleapis.com/albums/my-file"
+ * const publicUrl = file.publicUrl();
+ * ```
+ */
+ publicUrl() {
+ return `${this.storage.apiEndpoint}/${this.bucket.name}/${encodeURIComponent(this.name)}`;
+ }
+ /**
+ * @typedef {array} MoveResponse
+ * @property {File} 0 The destination File.
+ * @property {object} 1 The full API response.
+ */
+ /**
+ * @callback MoveCallback
+ * @param {?Error} err Request error, if any.
+ * @param {?File} destinationFile The destination File.
+ * @param {object} apiResponse The full API response.
+ */
+ /**
+ * @typedef {object} MoveOptions Configuration options for File#move(). See an
+ * {@link https://cloud.google.com/storage/docs/json_api/v1/objects#resource| Object resource}.
+ * @param {string} [userProject] The ID of the project which will be
+ * billed for the request.
+ */
+ /**
+ * Move this file to another location. By default, this will rename the file
+ * and keep it in the same bucket, but you can choose to move it to another
+ * Bucket by providing a Bucket or File object or a URL beginning with
+ * "gs://".
+ *
+ * **Warning**:
+ * There is currently no atomic `move` method in the Cloud Storage API,
+ * so this method is a composition of {@link File#copy} (to the new
+ * location) and {@link File#delete} (from the old location). While
+ * unlikely, it is possible that an error returned to your callback could be
+ * triggered from either one of these API calls failing, which could leave a
+ * duplicate file lingering. The error message will indicate what operation
+ * has failed.
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/objects/copy| Objects: copy API Documentation}
+ *
+ * @throws {Error} If the destination file is not provided.
+ *
+ * @param {string|Bucket|File} destination Destination file.
+ * @param {MoveCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * //-
+ * // You can pass in a variety of types for the destination.
+ * //
+ * // For all of the below examples, assume we are working with the following
+ * // Bucket and File objects.
+ * //-
+ * const bucket = storage.bucket('my-bucket');
+ * const file = bucket.file('my-image.png');
+ *
+ * //-
+ * // If you pass in a string for the destination, the file is moved to its
+ * // current bucket, under the new name provided.
+ * //-
+ * file.move('my-image-new.png', function(err, destinationFile, apiResponse) {
+ * // `my-bucket` no longer contains:
+ * // - "my-image.png"
+ * // but contains instead:
+ * // - "my-image-new.png"
+ *
+ * // `destinationFile` is an instance of a File object that refers to your
+ * // new file.
+ * });
+ *
+ * //-
+ * // If you pass in a string starting with "gs://" for the destination, the
+ * // file is copied to the other bucket and under the new name provided.
+ * //-
+ * const newLocation = 'gs://another-bucket/my-image-new.png';
+ * file.move(newLocation, function(err, destinationFile, apiResponse) {
+ * // `my-bucket` no longer contains:
+ * // - "my-image.png"
+ * //
+ * // `another-bucket` now contains:
+ * // - "my-image-new.png"
+ *
+ * // `destinationFile` is an instance of a File object that refers to your
+ * // new file.
+ * });
+ *
+ * //-
+ * // If you pass in a Bucket object, the file will be moved to that bucket
+ * // using the same name.
+ * //-
+ * const anotherBucket = gcs.bucket('another-bucket');
+ *
+ * file.move(anotherBucket, function(err, destinationFile, apiResponse) {
+ * // `my-bucket` no longer contains:
+ * // - "my-image.png"
+ * //
+ * // `another-bucket` now contains:
+ * // - "my-image.png"
+ *
+ * // `destinationFile` is an instance of a File object that refers to your
+ * // new file.
+ * });
+ *
+ * //-
+ * // If you pass in a File object, you have complete control over the new
+ * // bucket and filename.
+ * //-
+ * const anotherFile = anotherBucket.file('my-awesome-image.png');
+ *
+ * file.move(anotherFile, function(err, destinationFile, apiResponse) {
+ * // `my-bucket` no longer contains:
+ * // - "my-image.png"
+ * //
+ * // `another-bucket` now contains:
+ * // - "my-awesome-image.png"
+ *
+ * // Note:
+ * // The `destinationFile` parameter is equal to `anotherFile`.
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * file.move('my-image-new.png').then(function(data) {
+ * const destinationFile = data[0];
+ * const apiResponse = data[1];
+ * });
+ *
+ * ```
+ * @example include:samples/files.js
+ * region_tag:storage_move_file
+ * Another example:
+ */
+ move(destination, optionsOrCallback, callback) {
+ const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
+ callback =
+ typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
+ callback = callback || index_js_1.util.noop;
+ this.copy(destination, options, (err, destinationFile, copyApiResponse) => {
+ if (err) {
+ err.message = 'file#copy failed with an error - ' + err.message;
+ callback(err, null, copyApiResponse);
+ return;
+ }
+ if (this.name !== destinationFile.name ||
+ this.bucket.name !== destinationFile.bucket.name) {
+ this.delete(options, (err, apiResponse) => {
+ if (err) {
+ err.message = 'file#delete failed with an error - ' + err.message;
+ callback(err, destinationFile, apiResponse);
+ return;
+ }
+ callback(null, destinationFile, copyApiResponse);
+ });
+ }
+ else {
+ callback(null, destinationFile, copyApiResponse);
+ }
+ });
+ }
+ /**
+ * @typedef {array} RenameResponse
+ * @property {File} 0 The destination File.
+ * @property {object} 1 The full API response.
+ */
+ /**
+ * @callback RenameCallback
+ * @param {?Error} err Request error, if any.
+ * @param {?File} destinationFile The destination File.
+ * @param {object} apiResponse The full API response.
+ */
+ /**
+ * @typedef {object} RenameOptions Configuration options for File#move(). See an
+ * {@link https://cloud.google.com/storage/docs/json_api/v1/objects#resource| Object resource}.
+ * @param {string} [userProject] The ID of the project which will be
+ * billed for the request.
+ */
+ /**
+ * Rename this file.
+ *
+ * **Warning**:
+ * There is currently no atomic `rename` method in the Cloud Storage API,
+ * so this method is an alias of {@link File#move}, which in turn is a
+ * composition of {@link File#copy} (to the new location) and
+ * {@link File#delete} (from the old location). While
+ * unlikely, it is possible that an error returned to your callback could be
+ * triggered from either one of these API calls failing, which could leave a
+ * duplicate file lingering. The error message will indicate what operation
+ * has failed.
+ *
+ * @param {string|File} destinationFile Destination file.
+ * @param {RenameCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ *
+ * //-
+ * // You can pass in a string or a File object.
+ * //
+ * // For all of the below examples, assume we are working with the following
+ * // Bucket and File objects.
+ * //-
+ *
+ * const bucket = storage.bucket('my-bucket');
+ * const file = bucket.file('my-image.png');
+ *
+ * //-
+ * // You can pass in a string for the destinationFile.
+ * //-
+ * file.rename('renamed-image.png', function(err, renamedFile, apiResponse) {
+ * // `my-bucket` no longer contains:
+ * // - "my-image.png"
+ * // but contains instead:
+ * // - "renamed-image.png"
+ *
+ * // `renamedFile` is an instance of a File object that refers to your
+ * // renamed file.
+ * });
+ *
+ * //-
+ * // You can pass in a File object.
+ * //-
+ * const anotherFile = anotherBucket.file('my-awesome-image.png');
+ *
+ * file.rename(anotherFile, function(err, renamedFile, apiResponse) {
+ * // `my-bucket` no longer contains:
+ * // - "my-image.png"
+ *
+ * // Note:
+ * // The `renamedFile` parameter is equal to `anotherFile`.
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * file.rename('my-renamed-image.png').then(function(data) {
+ * const renamedFile = data[0];
+ * const apiResponse = data[1];
+ * });
+ * ```
+ */
+ rename(destinationFile, optionsOrCallback, callback) {
+ const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
+ callback =
+ typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
+ callback = callback || index_js_1.util.noop;
+ this.move(destinationFile, options, callback);
+ }
+ /**
+ * @typedef {object} RestoreOptions Options for File#restore(). See an
+ * {@link https://cloud.google.com/storage/docs/json_api/v1/objects#resource| Object resource}.
+ * @param {string} [userProject] The ID of the project which will be
+ * billed for the request.
+ * @param {number} [generation] If present, selects a specific revision of this object.
+ * @param {string} [projection] Specifies the set of properties to return. If used, must be 'full' or 'noAcl'.
+ * @param {string | number} [ifGenerationMatch] Request proceeds if the generation of the target resource
+ * matches the value used in the precondition.
+ * If the values don't match, the request fails with a 412 Precondition Failed response.
+ * @param {string | number} [ifGenerationNotMatch] Request proceeds if the generation of the target resource does
+ * not match the value used in the precondition. If the values match, the request fails with a 304 Not Modified response.
+ * @param {string | number} [ifMetagenerationMatch] Request proceeds if the meta-generation of the target resource
+ * matches the value used in the precondition.
+ * If the values don't match, the request fails with a 412 Precondition Failed response.
+ * @param {string | number} [ifMetagenerationNotMatch] Request proceeds if the meta-generation of the target resource does
+ * not match the value used in the precondition. If the values match, the request fails with a 304 Not Modified response.
+ */
+ /**
+ * Restores a soft-deleted file
+ * @param {RestoreOptions} options Restore options.
+ * @returns {Promise}
+ */
+ async restore(options) {
+ const [file] = await this.request({
+ method: 'POST',
+ uri: '/restore',
+ qs: options,
+ });
+ return file;
+ }
+ /**
+ * Makes request and applies userProject query parameter if necessary.
+ *
+ * @private
+ *
+ * @param {object} reqOpts - The request options.
+ * @param {function} callback - The callback function.
+ */
+ request(reqOpts, callback) {
+ return this.parent.request.call(this, reqOpts, callback);
+ }
+ /**
+ * @callback RotateEncryptionKeyCallback
+ * @extends CopyCallback
+ */
+ /**
+ * @typedef RotateEncryptionKeyResponse
+ * @extends CopyResponse
+ */
+ /**
+ * @param {string|buffer|object} RotateEncryptionKeyOptions Configuration options
+ * for File#rotateEncryptionKey().
+ * If a string or Buffer is provided, it is interpreted as an AES-256,
+ * customer-supplied encryption key. If you'd like to use a Cloud KMS key
+ * name, you must specify an options object with the property name:
+ * `kmsKeyName`.
+ * @param {string|buffer} [options.encryptionKey] An AES-256 encryption key.
+ * @param {string} [options.kmsKeyName] A Cloud KMS key name.
+ */
+ /**
+ * This method allows you to update the encryption key associated with this
+ * file.
+ *
+ * See {@link https://cloud.google.com/storage/docs/encryption#customer-supplied| Customer-supplied Encryption Keys}
+ *
+ * @param {RotateEncryptionKeyOptions} [options] - Configuration options.
+ * @param {RotateEncryptionKeyCallback} [callback]
+ * @returns {Promise}
+ *
+ * @example include:samples/encryption.js
+ * region_tag:storage_rotate_encryption_key
+ * Example of rotating the encryption key for this file:
+ */
+ rotateEncryptionKey(optionsOrCallback, callback) {
+ var _a;
+ callback =
+ typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
+ let options = {};
+ if (typeof optionsOrCallback === 'string' ||
+ optionsOrCallback instanceof Buffer) {
+ options = {
+ encryptionKey: optionsOrCallback,
+ };
+ }
+ else if (typeof optionsOrCallback === 'object') {
+ options = optionsOrCallback;
+ }
+ const newFile = this.bucket.file(this.id, options);
+ const copyOptions = ((_a = options.preconditionOpts) === null || _a === void 0 ? void 0 : _a.ifGenerationMatch) !== undefined
+ ? { preconditionOpts: options.preconditionOpts }
+ : {};
+ this.copy(newFile, copyOptions, callback);
+ }
+ /**
+ * @typedef {object} SaveOptions
+ * @extends CreateWriteStreamOptions
+ */
+ /**
+ * @callback SaveCallback
+ * @param {?Error} err Request error, if any.
+ */
+ /**
+ * Write strings or buffers to a file.
+ *
+ * *This is a convenience method which wraps {@link File#createWriteStream}.*
+ * To upload arbitrary data to a file, please use {@link File#createWriteStream} directly.
+ *
+ * Resumable uploads are automatically enabled and must be shut off explicitly
+ * by setting `options.resumable` to `false`.
+ *
+ * Multipart uploads with retryable error codes will be retried 3 times with exponential backoff.
+ *
+ *
+ * There is some overhead when using a resumable upload that can cause
+ * noticeable performance degradation while uploading a series of small
+ * files. When uploading files less than 10MB, it is recommended that the
+ * resumable feature is disabled.
+ *
+ *
+ * @param {SaveData} data The data to write to a file.
+ * @param {SaveOptions} [options] See {@link File#createWriteStream}'s `options`
+ * parameter.
+ * @param {SaveCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const file = myBucket.file('my-file');
+ * const contents = 'This is the contents of the file.';
+ *
+ * file.save(contents, function(err) {
+ * if (!err) {
+ * // File written successfully.
+ * }
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * file.save(contents).then(function() {});
+ * ```
+ */
+ save(data, optionsOrCallback, callback) {
+ // tslint:enable:no-any
+ callback =
+ typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
+ const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
+ let maxRetries = this.storage.retryOptions.maxRetries;
+ if (!this.shouldRetryBasedOnPreconditionAndIdempotencyStrat(options === null || options === void 0 ? void 0 : options.preconditionOpts)) {
+ maxRetries = 0;
+ }
+ const returnValue = (0, async_retry_1.default)(async (bail) => {
+ return new Promise((resolve, reject) => {
+ if (maxRetries === 0) {
+ this.storage.retryOptions.autoRetry = false;
+ }
+ const writable = this.createWriteStream(options);
+ if (options.onUploadProgress) {
+ writable.on('progress', options.onUploadProgress);
+ }
+ const handleError = (err) => {
+ if (this.storage.retryOptions.autoRetry &&
+ this.storage.retryOptions.retryableErrorFn(err)) {
+ return reject(err);
+ }
+ return bail(err);
+ };
+ if (typeof data === 'string' || Buffer.isBuffer(data)) {
+ writable
+ .on('error', handleError)
+ .on('finish', () => resolve())
+ .end(data);
+ }
+ else {
+ (0, stream_1.pipeline)(data, writable, err => {
+ if (err) {
+ if (typeof data !== 'function') {
+ // Only PipelineSourceFunction can be retried. Async-iterables
+ // and Readable streams can only be consumed once.
+ return bail(err);
+ }
+ handleError(err);
+ }
+ else {
+ resolve();
+ }
+ });
+ }
+ });
+ }, {
+ retries: maxRetries,
+ factor: this.storage.retryOptions.retryDelayMultiplier,
+ maxTimeout: this.storage.retryOptions.maxRetryDelay * 1000, //convert to milliseconds
+ maxRetryTime: this.storage.retryOptions.totalTimeout * 1000, //convert to milliseconds
+ });
+ if (!callback) {
+ return returnValue;
+ }
+ else {
+ return returnValue
+ .then(() => {
+ if (callback) {
+ return callback();
+ }
+ })
+ .catch(callback);
+ }
+ }
+ setMetadata(metadata, optionsOrCallback, cb) {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
+ cb =
+ typeof optionsOrCallback === 'function'
+ ? optionsOrCallback
+ : cb;
+ this.disableAutoRetryConditionallyIdempotent_(this.methods.setMetadata, bucket_js_1.AvailableServiceObjectMethods.setMetadata, options);
+ super
+ .setMetadata(metadata, options)
+ .then(resp => cb(null, ...resp))
+ .catch(cb)
+ .finally(() => {
+ this.storage.retryOptions.autoRetry = this.instanceRetryValue;
+ });
+ }
+ /**
+ * @typedef {array} SetStorageClassResponse
+ * @property {object} 0 The full API response.
+ */
+ /**
+ * @typedef {object} SetStorageClassOptions Configuration options for File#setStorageClass().
+ * @property {string} [userProject] The ID of the project which will be
+ * billed for the request.
+ */
+ /**
+ * @callback SetStorageClassCallback
+ * @param {?Error} err Request error, if any.
+ * @param {object} apiResponse The full API response.
+ */
+ /**
+ * Set the storage class for this file.
+ *
+ * See {@link https://cloud.google.com/storage/docs/per-object-storage-class| Per-Object Storage Class}
+ * See {@link https://cloud.google.com/storage/docs/storage-classes| Storage Classes}
+ *
+ * @param {string} storageClass The new storage class. (`standard`,
+ * `nearline`, `coldline`, or `archive`)
+ * **Note:** The storage classes `multi_regional` and `regional`
+ * are now legacy and will be deprecated in the future.
+ * @param {SetStorageClassOptions} [options] Configuration options.
+ * @param {string} [options.userProject] The ID of the project which will be
+ * billed for the request.
+ * @param {SetStorageClassCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * file.setStorageClass('nearline', function(err, apiResponse) {
+ * if (err) {
+ * // Error handling omitted.
+ * }
+ *
+ * // The storage class was updated successfully.
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * file.setStorageClass('nearline').then(function() {});
+ * ```
+ */
+ setStorageClass(storageClass, optionsOrCallback, callback) {
+ callback =
+ typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
+ const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
+ const req = {
+ ...options,
+ // In case we get input like `storageClass`, convert to `storage_class`.
+ storageClass: storageClass
+ .replace(/-/g, '_')
+ .replace(/([a-z])([A-Z])/g, (_, low, up) => {
+ return low + '_' + up;
+ })
+ .toUpperCase(),
+ };
+ this.copy(this, req, (err, file, apiResponse) => {
+ if (err) {
+ callback(err, apiResponse);
+ return;
+ }
+ this.metadata = file.metadata;
+ callback(null, apiResponse);
+ });
+ }
+ /**
+ * Set a user project to be billed for all requests made from this File
+ * object.
+ *
+ * @param {string} userProject The user project.
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('albums');
+ * const file = bucket.file('my-file');
+ *
+ * file.setUserProject('grape-spaceship-123');
+ * ```
+ */
+ setUserProject(userProject) {
+ this.bucket.setUserProject.call(this, userProject);
+ }
+ /**
+ * This creates a resumable-upload upload stream.
+ *
+ * @param {Duplexify} stream - Duplexify stream of data to pipe to the file.
+ * @param {object=} options - Configuration object.
+ *
+ * @private
+ */
+ startResumableUpload_(dup, options = {}) {
+ var _a;
+ (_a = options.metadata) !== null && _a !== void 0 ? _a : (options.metadata = {});
+ const retryOptions = this.storage.retryOptions;
+ if (!this.shouldRetryBasedOnPreconditionAndIdempotencyStrat(options.preconditionOpts)) {
+ retryOptions.autoRetry = false;
+ }
+ const uploadStream = resumableUpload.upload({
+ authClient: this.storage.authClient,
+ apiEndpoint: this.storage.apiEndpoint,
+ bucket: this.bucket.name,
+ customRequestOptions: this.getRequestInterceptors().reduce((reqOpts, interceptorFn) => interceptorFn(reqOpts), {}),
+ file: this.name,
+ generation: this.generation,
+ isPartialUpload: options.isPartialUpload,
+ key: this.encryptionKey,
+ kmsKeyName: this.kmsKeyName,
+ metadata: options.metadata,
+ offset: options.offset,
+ predefinedAcl: options.predefinedAcl,
+ private: options.private,
+ public: options.public,
+ uri: options.uri,
+ userProject: options.userProject || this.userProject,
+ retryOptions: { ...retryOptions },
+ params: (options === null || options === void 0 ? void 0 : options.preconditionOpts) || this.instancePreconditionOpts,
+ chunkSize: options === null || options === void 0 ? void 0 : options.chunkSize,
+ highWaterMark: options === null || options === void 0 ? void 0 : options.highWaterMark,
+ universeDomain: this.bucket.storage.universeDomain,
+ [util_js_1.GCCL_GCS_CMD_KEY]: options[util_js_1.GCCL_GCS_CMD_KEY],
+ });
+ uploadStream
+ .on('response', resp => {
+ dup.emit('response', resp);
+ })
+ .on('uri', uri => {
+ dup.emit('uri', uri);
+ })
+ .on('metadata', metadata => {
+ this.metadata = metadata;
+ dup.emit('metadata');
+ })
+ .on('finish', () => {
+ dup.emit('complete');
+ })
+ .on('progress', evt => dup.emit('progress', evt));
+ dup.setWritable(uploadStream);
+ this.storage.retryOptions.autoRetry = this.instanceRetryValue;
+ }
+ /**
+ * Takes a readable stream and pipes it to a remote file. Unlike
+ * `startResumableUpload_`, which uses the resumable upload technique, this
+ * method uses a simple upload (all or nothing).
+ *
+ * @param {Duplexify} dup - Duplexify stream of data to pipe to the file.
+ * @param {object=} options - Configuration object.
+ *
+ * @private
+ */
+ startSimpleUpload_(dup, options = {}) {
+ var _a;
+ (_a = options.metadata) !== null && _a !== void 0 ? _a : (options.metadata = {});
+ const apiEndpoint = this.storage.apiEndpoint;
+ const bucketName = this.bucket.name;
+ const uri = `${apiEndpoint}/upload/storage/v1/b/${bucketName}/o`;
+ const reqOpts = {
+ qs: {
+ name: this.name,
+ },
+ uri: uri,
+ [util_js_1.GCCL_GCS_CMD_KEY]: options[util_js_1.GCCL_GCS_CMD_KEY],
+ };
+ if (this.generation !== undefined) {
+ reqOpts.qs.ifGenerationMatch = this.generation;
+ }
+ if (this.kmsKeyName !== undefined) {
+ reqOpts.qs.kmsKeyName = this.kmsKeyName;
+ }
+ if (typeof options.timeout === 'number') {
+ reqOpts.timeout = options.timeout;
+ }
+ if (options.userProject || this.userProject) {
+ reqOpts.qs.userProject = options.userProject || this.userProject;
+ }
+ if (options.predefinedAcl) {
+ reqOpts.qs.predefinedAcl = options.predefinedAcl;
+ }
+ else if (options.private) {
+ reqOpts.qs.predefinedAcl = 'private';
+ }
+ else if (options.public) {
+ reqOpts.qs.predefinedAcl = 'publicRead';
+ }
+ Object.assign(reqOpts.qs, this.instancePreconditionOpts, options.preconditionOpts);
+ index_js_1.util.makeWritableStream(dup, {
+ makeAuthenticatedRequest: (reqOpts) => {
+ this.request(reqOpts, (err, body, resp) => {
+ if (err) {
+ dup.destroy(err);
+ return;
+ }
+ this.metadata = body;
+ dup.emit('metadata', body);
+ dup.emit('response', resp);
+ dup.emit('complete');
+ });
+ },
+ metadata: options.metadata,
+ request: reqOpts,
+ });
+ }
+ disableAutoRetryConditionallyIdempotent_(
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ coreOpts, methodType, localPreconditionOptions) {
+ var _a, _b, _c, _d;
+ if ((typeof coreOpts === 'object' &&
+ ((_b = (_a = coreOpts === null || coreOpts === void 0 ? void 0 : coreOpts.reqOpts) === null || _a === void 0 ? void 0 : _a.qs) === null || _b === void 0 ? void 0 : _b.ifGenerationMatch) === undefined &&
+ (localPreconditionOptions === null || localPreconditionOptions === void 0 ? void 0 : localPreconditionOptions.ifGenerationMatch) === undefined &&
+ methodType === bucket_js_1.AvailableServiceObjectMethods.delete &&
+ this.storage.retryOptions.idempotencyStrategy ===
+ storage_js_1.IdempotencyStrategy.RetryConditional) ||
+ this.storage.retryOptions.idempotencyStrategy ===
+ storage_js_1.IdempotencyStrategy.RetryNever) {
+ this.storage.retryOptions.autoRetry = false;
+ }
+ if ((typeof coreOpts === 'object' &&
+ ((_d = (_c = coreOpts === null || coreOpts === void 0 ? void 0 : coreOpts.reqOpts) === null || _c === void 0 ? void 0 : _c.qs) === null || _d === void 0 ? void 0 : _d.ifMetagenerationMatch) === undefined &&
+ (localPreconditionOptions === null || localPreconditionOptions === void 0 ? void 0 : localPreconditionOptions.ifMetagenerationMatch) === undefined &&
+ methodType === bucket_js_1.AvailableServiceObjectMethods.setMetadata &&
+ this.storage.retryOptions.idempotencyStrategy ===
+ storage_js_1.IdempotencyStrategy.RetryConditional) ||
+ this.storage.retryOptions.idempotencyStrategy ===
+ storage_js_1.IdempotencyStrategy.RetryNever) {
+ this.storage.retryOptions.autoRetry = false;
+ }
+ }
+ async getBufferFromReadable(readable) {
+ const buf = [];
+ for await (const chunk of readable) {
+ buf.push(chunk);
+ }
+ return Buffer.concat(buf);
+ }
+}
+exports.File = File;
+_File_instances = new WeakSet(), _File_validateIntegrity =
+/**
+ *
+ * @param hashCalculatingStream
+ * @param verify
+ * @returns {boolean} Returns `true` if valid, throws with error otherwise
+ */
+async function _File_validateIntegrity(hashCalculatingStream, verify = {}) {
+ const metadata = this.metadata;
+ // If we're doing validation, assume the worst
+ let dataMismatch = !!(verify.crc32c || verify.md5);
+ if (verify.crc32c && metadata.crc32c) {
+ dataMismatch = !hashCalculatingStream.test('crc32c', metadata.crc32c);
+ }
+ if (verify.md5 && metadata.md5Hash) {
+ dataMismatch = !hashCalculatingStream.test('md5', metadata.md5Hash);
+ }
+ if (dataMismatch) {
+ const errors = [];
+ let code = '';
+ let message = '';
+ try {
+ await this.delete();
+ if (verify.md5 && !metadata.md5Hash) {
+ code = 'MD5_NOT_AVAILABLE';
+ message = FileExceptionMessages.MD5_NOT_AVAILABLE;
+ }
+ else {
+ code = 'FILE_NO_UPLOAD';
+ message = FileExceptionMessages.UPLOAD_MISMATCH;
+ }
+ }
+ catch (e) {
+ const error = e;
+ code = 'FILE_NO_UPLOAD_DELETE';
+ message = `${FileExceptionMessages.UPLOAD_MISMATCH_DELETE_FAIL}${error.message}`;
+ errors.push(error);
+ }
+ const error = new RequestError(message);
+ error.code = code;
+ error.errors = errors;
+ throw error;
+ }
+ return true;
+};
+/*! Developer Documentation
+ *
+ * All async methods (except for streams) will return a Promise in the event
+ * that a callback is omitted.
+ */
+(0, promisify_1.promisifyAll)(File, {
+ exclude: [
+ 'cloudStorageURI',
+ 'publicUrl',
+ 'request',
+ 'save',
+ 'setEncryptionKey',
+ 'shouldRetryBasedOnPreconditionAndIdempotencyStrat',
+ 'getBufferFromReadable',
+ 'restore',
+ ],
+});
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/hash-stream-validator.d.ts b/node_modules/@google-cloud/storage/build/cjs/src/hash-stream-validator.d.ts
new file mode 100644
index 0000000..00d85d1
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/hash-stream-validator.d.ts
@@ -0,0 +1,37 @@
+///
+///
+import { Transform } from 'stream';
+import { CRC32CValidatorGenerator, CRC32CValidator } from './crc32c.js';
+interface HashStreamValidatorOptions {
+ /** Enables CRC32C calculation. To validate a provided value use `crc32cExpected`. */
+ crc32c: boolean;
+ /** Enables MD5 calculation. To validate a provided value use `md5Expected`. */
+ md5: boolean;
+ /** A CRC32C instance for validation. To validate a provided value use `crc32cExpected`. */
+ crc32cInstance: CRC32CValidator;
+ /** Set a custom CRC32C generator. Used if `crc32cInstance` has not been provided. */
+ crc32cGenerator: CRC32CValidatorGenerator;
+ /** Sets the expected CRC32C value to verify once all data has been consumed. Also sets the `crc32c` option to `true` */
+ crc32cExpected?: string;
+ /** Sets the expected MD5 value to verify once all data has been consumed. Also sets the `md5` option to `true` */
+ md5Expected?: string;
+ /** Indicates whether or not to run a validation check or only update the hash values */
+ updateHashesOnly?: boolean;
+}
+declare class HashStreamValidator extends Transform {
+ #private;
+ readonly crc32cEnabled: boolean;
+ readonly md5Enabled: boolean;
+ readonly crc32cExpected: string | undefined;
+ readonly md5Expected: string | undefined;
+ readonly updateHashesOnly: boolean;
+ constructor(options?: Partial);
+ /**
+ * Return the current CRC32C value, if available.
+ */
+ get crc32c(): string | undefined;
+ _flush(callback: (error?: Error | null | undefined) => void): void;
+ _transform(chunk: Buffer, encoding: BufferEncoding, callback: (e?: Error) => void): void;
+ test(hash: 'crc32c' | 'md5', sum: Buffer | string): boolean;
+}
+export { HashStreamValidator, HashStreamValidatorOptions };
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/hash-stream-validator.js b/node_modules/@google-cloud/storage/build/cjs/src/hash-stream-validator.js
new file mode 100644
index 0000000..ef61e0c
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/hash-stream-validator.js
@@ -0,0 +1,119 @@
+"use strict";
+// Copyright 2022 Google LLC
+//
+// 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.
+var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
+ if (kind === "m") throw new TypeError("Private method is not writable");
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
+};
+var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var _HashStreamValidator_crc32cHash, _HashStreamValidator_md5Hash, _HashStreamValidator_md5Digest;
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.HashStreamValidator = void 0;
+const crypto_1 = require("crypto");
+const stream_1 = require("stream");
+const crc32c_js_1 = require("./crc32c.js");
+const file_js_1 = require("./file.js");
+class HashStreamValidator extends stream_1.Transform {
+ constructor(options = {}) {
+ super();
+ this.updateHashesOnly = false;
+ _HashStreamValidator_crc32cHash.set(this, undefined);
+ _HashStreamValidator_md5Hash.set(this, undefined);
+ _HashStreamValidator_md5Digest.set(this, '');
+ this.crc32cEnabled = !!options.crc32c;
+ this.md5Enabled = !!options.md5;
+ this.updateHashesOnly = !!options.updateHashesOnly;
+ this.crc32cExpected = options.crc32cExpected;
+ this.md5Expected = options.md5Expected;
+ if (this.crc32cEnabled) {
+ if (options.crc32cInstance) {
+ __classPrivateFieldSet(this, _HashStreamValidator_crc32cHash, options.crc32cInstance, "f");
+ }
+ else {
+ const crc32cGenerator = options.crc32cGenerator || crc32c_js_1.CRC32C_DEFAULT_VALIDATOR_GENERATOR;
+ __classPrivateFieldSet(this, _HashStreamValidator_crc32cHash, crc32cGenerator(), "f");
+ }
+ }
+ if (this.md5Enabled) {
+ __classPrivateFieldSet(this, _HashStreamValidator_md5Hash, (0, crypto_1.createHash)('md5'), "f");
+ }
+ }
+ /**
+ * Return the current CRC32C value, if available.
+ */
+ get crc32c() {
+ var _a;
+ return (_a = __classPrivateFieldGet(this, _HashStreamValidator_crc32cHash, "f")) === null || _a === void 0 ? void 0 : _a.toString();
+ }
+ _flush(callback) {
+ if (__classPrivateFieldGet(this, _HashStreamValidator_md5Hash, "f")) {
+ __classPrivateFieldSet(this, _HashStreamValidator_md5Digest, __classPrivateFieldGet(this, _HashStreamValidator_md5Hash, "f").digest('base64'), "f");
+ }
+ if (this.updateHashesOnly) {
+ callback();
+ return;
+ }
+ // If we're doing validation, assume the worst-- a data integrity
+ // mismatch. If not, these tests won't be performed, and we can assume
+ // the best.
+ // We must check if the server decompressed the data on serve because hash
+ // validation is not possible in this case.
+ let failed = this.crc32cEnabled || this.md5Enabled;
+ if (this.crc32cEnabled && this.crc32cExpected) {
+ failed = !this.test('crc32c', this.crc32cExpected);
+ }
+ if (this.md5Enabled && this.md5Expected) {
+ failed = !this.test('md5', this.md5Expected);
+ }
+ if (failed) {
+ const mismatchError = new file_js_1.RequestError(file_js_1.FileExceptionMessages.DOWNLOAD_MISMATCH);
+ mismatchError.code = 'CONTENT_DOWNLOAD_MISMATCH';
+ callback(mismatchError);
+ }
+ else {
+ callback();
+ }
+ }
+ _transform(chunk, encoding, callback) {
+ this.push(chunk, encoding);
+ try {
+ if (__classPrivateFieldGet(this, _HashStreamValidator_crc32cHash, "f"))
+ __classPrivateFieldGet(this, _HashStreamValidator_crc32cHash, "f").update(chunk);
+ if (__classPrivateFieldGet(this, _HashStreamValidator_md5Hash, "f"))
+ __classPrivateFieldGet(this, _HashStreamValidator_md5Hash, "f").update(chunk);
+ callback();
+ }
+ catch (e) {
+ callback(e);
+ }
+ }
+ test(hash, sum) {
+ const check = Buffer.isBuffer(sum) ? sum.toString('base64') : sum;
+ if (hash === 'crc32c' && __classPrivateFieldGet(this, _HashStreamValidator_crc32cHash, "f")) {
+ return __classPrivateFieldGet(this, _HashStreamValidator_crc32cHash, "f").validate(check);
+ }
+ if (hash === 'md5' && __classPrivateFieldGet(this, _HashStreamValidator_md5Hash, "f")) {
+ return __classPrivateFieldGet(this, _HashStreamValidator_md5Digest, "f") === check;
+ }
+ return false;
+ }
+}
+exports.HashStreamValidator = HashStreamValidator;
+_HashStreamValidator_crc32cHash = new WeakMap(), _HashStreamValidator_md5Hash = new WeakMap(), _HashStreamValidator_md5Digest = new WeakMap();
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/hmacKey.d.ts b/node_modules/@google-cloud/storage/build/cjs/src/hmacKey.d.ts
new file mode 100644
index 0000000..4433a83
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/hmacKey.d.ts
@@ -0,0 +1,93 @@
+import { ServiceObject, MetadataCallback, SetMetadataResponse } from './nodejs-common/index.js';
+import { BaseMetadata, SetMetadataOptions } from './nodejs-common/service-object.js';
+import { Storage } from './storage.js';
+export interface HmacKeyOptions {
+ projectId?: string;
+}
+export interface HmacKeyMetadata extends BaseMetadata {
+ accessId?: string;
+ etag?: string;
+ projectId?: string;
+ serviceAccountEmail?: string;
+ state?: string;
+ timeCreated?: string;
+ updated?: string;
+}
+export interface SetHmacKeyMetadataOptions {
+ /**
+ * This parameter is currently ignored.
+ */
+ userProject?: string;
+}
+export interface SetHmacKeyMetadata {
+ state?: 'ACTIVE' | 'INACTIVE';
+ etag?: string;
+}
+export interface HmacKeyMetadataCallback {
+ (err: Error | null, metadata?: HmacKeyMetadata, apiResponse?: unknown): void;
+}
+export type HmacKeyMetadataResponse = [HmacKeyMetadata, unknown];
+/**
+ * The API-formatted resource description of the HMAC key.
+ *
+ * Note: This is not guaranteed to be up-to-date when accessed. To get the
+ * latest record, call the `getMetadata()` method.
+ *
+ * @name HmacKey#metadata
+ * @type {object}
+ */
+/**
+ * An HmacKey object contains metadata of an HMAC key created from a
+ * service account through the {@link Storage} client using
+ * {@link Storage#createHmacKey}.
+ *
+ * See {@link https://cloud.google.com/storage/docs/authentication/hmackeys| HMAC keys documentation}
+ *
+ * @class
+ */
+export declare class HmacKey extends ServiceObject {
+ /**
+ * A reference to the {@link Storage} associated with this {@link HmacKey}
+ * instance.
+ * @name HmacKey#storage
+ * @type {Storage}
+ */
+ storage: Storage;
+ private instanceRetryValue?;
+ /**
+ * @typedef {object} HmacKeyOptions
+ * @property {string} [projectId] The project ID of the project that owns
+ * the service account of the requested HMAC key. If not provided,
+ * the project ID used to instantiate the Storage client will be used.
+ */
+ /**
+ * Constructs an HmacKey object.
+ *
+ * Note: this only create a local reference to an HMAC key, to create
+ * an HMAC key, use {@link Storage#createHmacKey}.
+ *
+ * @param {Storage} storage The Storage instance this HMAC key is
+ * attached to.
+ * @param {string} accessId The unique accessId for this HMAC key.
+ * @param {HmacKeyOptions} options Constructor configurations.
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const hmacKey = storage.hmacKey('access-id');
+ * ```
+ */
+ constructor(storage: Storage, accessId: string, options?: HmacKeyOptions);
+ /**
+ * Set the metadata for this object.
+ *
+ * @param {object} metadata - The metadata to set on this object.
+ * @param {object=} options - Configuration options.
+ * @param {function=} callback - The callback function.
+ * @param {?error} callback.err - An error returned while making this request.
+ * @param {object} callback.apiResponse - The full API response.
+ */
+ setMetadata(metadata: HmacKeyMetadata, options?: SetMetadataOptions): Promise>;
+ setMetadata(metadata: HmacKeyMetadata, callback: MetadataCallback): void;
+ setMetadata(metadata: HmacKeyMetadata, options: SetMetadataOptions, callback: MetadataCallback): void;
+}
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/hmacKey.js b/node_modules/@google-cloud/storage/build/cjs/src/hmacKey.js
new file mode 100644
index 0000000..aaf654a
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/hmacKey.js
@@ -0,0 +1,336 @@
+"use strict";
+// Copyright 2019 Google LLC
+//
+// 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.HmacKey = void 0;
+const index_js_1 = require("./nodejs-common/index.js");
+const storage_js_1 = require("./storage.js");
+const promisify_1 = require("@google-cloud/promisify");
+/**
+ * The API-formatted resource description of the HMAC key.
+ *
+ * Note: This is not guaranteed to be up-to-date when accessed. To get the
+ * latest record, call the `getMetadata()` method.
+ *
+ * @name HmacKey#metadata
+ * @type {object}
+ */
+/**
+ * An HmacKey object contains metadata of an HMAC key created from a
+ * service account through the {@link Storage} client using
+ * {@link Storage#createHmacKey}.
+ *
+ * See {@link https://cloud.google.com/storage/docs/authentication/hmackeys| HMAC keys documentation}
+ *
+ * @class
+ */
+class HmacKey extends index_js_1.ServiceObject {
+ /**
+ * @typedef {object} HmacKeyOptions
+ * @property {string} [projectId] The project ID of the project that owns
+ * the service account of the requested HMAC key. If not provided,
+ * the project ID used to instantiate the Storage client will be used.
+ */
+ /**
+ * Constructs an HmacKey object.
+ *
+ * Note: this only create a local reference to an HMAC key, to create
+ * an HMAC key, use {@link Storage#createHmacKey}.
+ *
+ * @param {Storage} storage The Storage instance this HMAC key is
+ * attached to.
+ * @param {string} accessId The unique accessId for this HMAC key.
+ * @param {HmacKeyOptions} options Constructor configurations.
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const hmacKey = storage.hmacKey('access-id');
+ * ```
+ */
+ constructor(storage, accessId, options) {
+ const methods = {
+ /**
+ * @typedef {object} DeleteHmacKeyOptions
+ * @property {string} [userProject] This parameter is currently ignored.
+ */
+ /**
+ * @typedef {array} DeleteHmacKeyResponse
+ * @property {object} 0 The full API response.
+ */
+ /**
+ * @callback DeleteHmacKeyCallback
+ * @param {?Error} err Request error, if any.
+ * @param {object} apiResponse The full API response.
+ */
+ /**
+ * Deletes an HMAC key.
+ * Key state must be set to `INACTIVE` prior to deletion.
+ * Caution: HMAC keys cannot be recovered once you delete them.
+ *
+ * The authenticated user must have `storage.hmacKeys.delete` permission for the project in which the key exists.
+ *
+ * @method HmacKey#delete
+ * @param {DeleteHmacKeyOptions} [options] Configuration options.
+ * @param {DeleteHmacKeyCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ *
+ * //-
+ * // Delete HMAC key after making the key inactive.
+ * //-
+ * const hmacKey = storage.hmacKey('ACCESS_ID');
+ * hmacKey.setMetadata({state: 'INACTIVE'}, (err, hmacKeyMetadata) => {
+ * if (err) {
+ * // The request was an error.
+ * console.error(err);
+ * return;
+ * }
+ * hmacKey.delete((err) => {
+ * if (err) {
+ * console.error(err);
+ * return;
+ * }
+ * // The HMAC key is deleted.
+ * });
+ * });
+ *
+ * //-
+ * // If the callback is omitted, a promise is returned.
+ * //-
+ * const hmacKey = storage.hmacKey('ACCESS_ID');
+ * hmacKey
+ * .setMetadata({state: 'INACTIVE'})
+ * .then(() => {
+ * return hmacKey.delete();
+ * });
+ * ```
+ */
+ delete: true,
+ /**
+ * @callback GetHmacKeyCallback
+ * @param {?Error} err Request error, if any.
+ * @param {HmacKey} hmacKey this {@link HmacKey} instance.
+ * @param {object} apiResponse The full API response.
+ */
+ /**
+ * @typedef {array} GetHmacKeyResponse
+ * @property {HmacKey} 0 This {@link HmacKey} instance.
+ * @property {object} 1 The full API response.
+ */
+ /**
+ * @typedef {object} GetHmacKeyOptions
+ * @property {string} [userProject] This parameter is currently ignored.
+ */
+ /**
+ * Retrieves and populate an HMAC key's metadata, and return
+ * this {@link HmacKey} instance.
+ *
+ * HmacKey.get() does not give the HMAC key secret, as
+ * it is only returned on creation.
+ *
+ * The authenticated user must have `storage.hmacKeys.get` permission
+ * for the project in which the key exists.
+ *
+ * @method HmacKey#get
+ * @param {GetHmacKeyOptions} [options] Configuration options.
+ * @param {GetHmacKeyCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ *
+ * //-
+ * // Get the HmacKey's Metadata.
+ * //-
+ * storage.hmacKey('ACCESS_ID')
+ * .get((err, hmacKey) => {
+ * if (err) {
+ * // The request was an error.
+ * console.error(err);
+ * return;
+ * }
+ * // do something with the returned HmacKey object.
+ * });
+ *
+ * //-
+ * // If the callback is omitted, a promise is returned.
+ * //-
+ * storage.hmacKey('ACCESS_ID')
+ * .get()
+ * .then((data) => {
+ * const hmacKey = data[0];
+ * });
+ * ```
+ */
+ get: true,
+ /**
+ * @typedef {object} GetHmacKeyMetadataOptions
+ * @property {string} [userProject] This parameter is currently ignored.
+ */
+ /**
+ * Retrieves and populate an HMAC key's metadata, and return
+ * the HMAC key's metadata as an object.
+ *
+ * HmacKey.getMetadata() does not give the HMAC key secret, as
+ * it is only returned on creation.
+ *
+ * The authenticated user must have `storage.hmacKeys.get` permission
+ * for the project in which the key exists.
+ *
+ * @method HmacKey#getMetadata
+ * @param {GetHmacKeyMetadataOptions} [options] Configuration options.
+ * @param {HmacKeyMetadataCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ *
+ * //-
+ * // Get the HmacKey's metadata and populate to the metadata property.
+ * //-
+ * storage.hmacKey('ACCESS_ID')
+ * .getMetadata((err, hmacKeyMetadata) => {
+ * if (err) {
+ * // The request was an error.
+ * console.error(err);
+ * return;
+ * }
+ * console.log(hmacKeyMetadata);
+ * });
+ *
+ * //-
+ * // If the callback is omitted, a promise is returned.
+ * //-
+ * storage.hmacKey('ACCESS_ID')
+ * .getMetadata()
+ * .then((data) => {
+ * const hmacKeyMetadata = data[0];
+ * console.log(hmacKeyMetadata);
+ * });
+ * ```
+ */
+ getMetadata: true,
+ /**
+ * @typedef {object} SetHmacKeyMetadata Subset of {@link HmacKeyMetadata} to update.
+ * @property {string} state New state of the HmacKey. Either 'ACTIVE' or 'INACTIVE'.
+ * @property {string} [etag] Include an etag from a previous get HMAC key request
+ * to perform safe read-modify-write.
+ */
+ /**
+ * @typedef {object} SetHmacKeyMetadataOptions
+ * @property {string} [userProject] This parameter is currently ignored.
+ */
+ /**
+ * @callback HmacKeyMetadataCallback
+ * @param {?Error} err Request error, if any.
+ * @param {HmacKeyMetadata} metadata The updated {@link HmacKeyMetadata} object.
+ * @param {object} apiResponse The full API response.
+ */
+ /**
+ * @typedef {array} HmacKeyMetadataResponse
+ * @property {HmacKeyMetadata} 0 The updated {@link HmacKeyMetadata} object.
+ * @property {object} 1 The full API response.
+ */
+ /**
+ * Updates the state of an HMAC key. See {@link SetHmacKeyMetadata} for
+ * valid states.
+ *
+ * @method HmacKey#setMetadata
+ * @param {SetHmacKeyMetadata} metadata The new metadata.
+ * @param {SetHmacKeyMetadataOptions} [options] Configuration options.
+ * @param {HmacKeyMetadataCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ *
+ * const metadata = {
+ * state: 'INACTIVE',
+ * };
+ *
+ * storage.hmacKey('ACCESS_ID')
+ * .setMetadata(metadata, (err, hmacKeyMetadata) => {
+ * if (err) {
+ * // The request was an error.
+ * console.error(err);
+ * return;
+ * }
+ * console.log(hmacKeyMetadata);
+ * });
+ *
+ * //-
+ * // If the callback is omitted, a promise is returned.
+ * //-
+ * storage.hmacKey('ACCESS_ID')
+ * .setMetadata(metadata)
+ * .then((data) => {
+ * const hmacKeyMetadata = data[0];
+ * console.log(hmacKeyMetadata);
+ * });
+ * ```
+ */
+ setMetadata: {
+ reqOpts: {
+ method: 'PUT',
+ },
+ },
+ };
+ const projectId = (options && options.projectId) || storage.projectId;
+ super({
+ parent: storage,
+ id: accessId,
+ baseUrl: `/projects/${projectId}/hmacKeys`,
+ methods,
+ });
+ this.storage = storage;
+ this.instanceRetryValue = storage.retryOptions.autoRetry;
+ }
+ setMetadata(metadata, optionsOrCallback, cb) {
+ // ETag preconditions are not currently supported. Retries should be disabled if the idempotency strategy is not set to RetryAlways
+ if (this.storage.retryOptions.idempotencyStrategy !==
+ storage_js_1.IdempotencyStrategy.RetryAlways) {
+ this.storage.retryOptions.autoRetry = false;
+ }
+ const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
+ cb =
+ typeof optionsOrCallback === 'function'
+ ? optionsOrCallback
+ : cb;
+ super
+ .setMetadata(metadata, options)
+ .then(resp => cb(null, ...resp))
+ .catch(cb)
+ .finally(() => {
+ this.storage.retryOptions.autoRetry = this.instanceRetryValue;
+ });
+ }
+}
+exports.HmacKey = HmacKey;
+/*! Developer Documentation
+ *
+ * All async methods (except for streams) will return a Promise in the event
+ * that a callback is omitted.
+ */
+(0, promisify_1.promisifyAll)(HmacKey);
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/iam.d.ts b/node_modules/@google-cloud/storage/build/cjs/src/iam.d.ts
new file mode 100644
index 0000000..3ceb19c
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/iam.d.ts
@@ -0,0 +1,117 @@
+import { Bucket } from './bucket.js';
+export interface GetPolicyOptions {
+ userProject?: string;
+ requestedPolicyVersion?: number;
+}
+export type GetPolicyResponse = [Policy, unknown];
+/**
+ * @callback GetPolicyCallback
+ * @param {?Error} err Request error, if any.
+ * @param {object} acl The policy.
+ * @param {object} apiResponse The full API response.
+ */
+export interface GetPolicyCallback {
+ (err?: Error | null, acl?: Policy, apiResponse?: unknown): void;
+}
+/**
+ * @typedef {object} SetPolicyOptions
+ * @param {string} [userProject] The ID of the project which will be
+ * billed for the request.
+ */
+export interface SetPolicyOptions {
+ userProject?: string;
+}
+/**
+ * @typedef {array} SetPolicyResponse
+ * @property {object} 0 The policy.
+ * @property {object} 1 The full API response.
+ */
+export type SetPolicyResponse = [Policy, unknown];
+/**
+ * @callback SetPolicyCallback
+ * @param {?Error} err Request error, if any.
+ * @param {object} acl The policy.
+ * @param {object} apiResponse The full API response.
+ */
+export interface SetPolicyCallback {
+ (err?: Error | null, acl?: Policy, apiResponse?: object): void;
+}
+export interface Policy {
+ bindings: PolicyBinding[];
+ version?: number;
+ etag?: string;
+}
+export interface PolicyBinding {
+ role: string;
+ members: string[];
+ condition?: Expr;
+}
+export interface Expr {
+ title?: string;
+ description?: string;
+ expression: string;
+}
+/**
+ * @typedef {array} TestIamPermissionsResponse
+ * @property {object} 0 A subset of permissions that the caller is allowed.
+ * @property {object} 1 The full API response.
+ */
+export type TestIamPermissionsResponse = [{
+ [key: string]: boolean;
+}, unknown];
+/**
+ * @callback TestIamPermissionsCallback
+ * @param {?Error} err Request error, if any.
+ * @param {object} acl A subset of permissions that the caller is allowed.
+ * @param {object} apiResponse The full API response.
+ */
+export interface TestIamPermissionsCallback {
+ (err?: Error | null, acl?: {
+ [key: string]: boolean;
+ } | null, apiResponse?: unknown): void;
+}
+/**
+ * @typedef {object} TestIamPermissionsOptions Configuration options for Iam#testPermissions().
+ * @param {string} [userProject] The ID of the project which will be
+ * billed for the request.
+ */
+export interface TestIamPermissionsOptions {
+ userProject?: string;
+}
+export declare enum IAMExceptionMessages {
+ POLICY_OBJECT_REQUIRED = "A policy object is required.",
+ PERMISSIONS_REQUIRED = "Permissions are required."
+}
+/**
+ * Get and set IAM policies for your Cloud Storage bucket.
+ *
+ * See {@link https://cloud.google.com/storage/docs/access-control/iam#short_title_iam_management| Cloud Storage IAM Management}
+ * See {@link https://cloud.google.com/iam/docs/granting-changing-revoking-access| Granting, Changing, and Revoking Access}
+ * See {@link https://cloud.google.com/iam/docs/understanding-roles| IAM Roles}
+ *
+ * @constructor Iam
+ *
+ * @param {Bucket} bucket The parent instance.
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('my-bucket');
+ * // bucket.iam
+ * ```
+ */
+declare class Iam {
+ private request_;
+ private resourceId_;
+ constructor(bucket: Bucket);
+ getPolicy(options?: GetPolicyOptions): Promise;
+ getPolicy(options: GetPolicyOptions, callback: GetPolicyCallback): void;
+ getPolicy(callback: GetPolicyCallback): void;
+ setPolicy(policy: Policy, options?: SetPolicyOptions): Promise;
+ setPolicy(policy: Policy, callback: SetPolicyCallback): void;
+ setPolicy(policy: Policy, options: SetPolicyOptions, callback: SetPolicyCallback): void;
+ testPermissions(permissions: string | string[], options?: TestIamPermissionsOptions): Promise;
+ testPermissions(permissions: string | string[], callback: TestIamPermissionsCallback): void;
+ testPermissions(permissions: string | string[], options: TestIamPermissionsOptions, callback: TestIamPermissionsCallback): void;
+}
+export { Iam };
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/iam.js b/node_modules/@google-cloud/storage/build/cjs/src/iam.js
new file mode 100644
index 0000000..9d4ce67
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/iam.js
@@ -0,0 +1,306 @@
+"use strict";
+// Copyright 2019 Google LLC
+//
+// 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.Iam = exports.IAMExceptionMessages = void 0;
+const promisify_1 = require("@google-cloud/promisify");
+const util_js_1 = require("./util.js");
+var IAMExceptionMessages;
+(function (IAMExceptionMessages) {
+ IAMExceptionMessages["POLICY_OBJECT_REQUIRED"] = "A policy object is required.";
+ IAMExceptionMessages["PERMISSIONS_REQUIRED"] = "Permissions are required.";
+})(IAMExceptionMessages || (exports.IAMExceptionMessages = IAMExceptionMessages = {}));
+/**
+ * Get and set IAM policies for your Cloud Storage bucket.
+ *
+ * See {@link https://cloud.google.com/storage/docs/access-control/iam#short_title_iam_management| Cloud Storage IAM Management}
+ * See {@link https://cloud.google.com/iam/docs/granting-changing-revoking-access| Granting, Changing, and Revoking Access}
+ * See {@link https://cloud.google.com/iam/docs/understanding-roles| IAM Roles}
+ *
+ * @constructor Iam
+ *
+ * @param {Bucket} bucket The parent instance.
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('my-bucket');
+ * // bucket.iam
+ * ```
+ */
+class Iam {
+ constructor(bucket) {
+ this.request_ = bucket.request.bind(bucket);
+ this.resourceId_ = 'buckets/' + bucket.getId();
+ }
+ /**
+ * @typedef {object} GetPolicyOptions Requested options for IAM#getPolicy().
+ * @property {number} [requestedPolicyVersion] The version of IAM policies to
+ * request. If a policy with a condition is requested without setting
+ * this, the server will return an error. This must be set to a value
+ * of 3 to retrieve IAM policies containing conditions. This is to
+ * prevent client code that isn't aware of IAM conditions from
+ * interpreting and modifying policies incorrectly. The service might
+ * return a policy with version lower than the one that was requested,
+ * based on the feature syntax in the policy fetched.
+ * See {@link https://cloud.google.com/iam/docs/policies#versions| IAM Policy versions}
+ * @property {string} [userProject] The ID of the project which will be
+ * billed for the request.
+ */
+ /**
+ * @typedef {array} GetPolicyResponse
+ * @property {Policy} 0 The policy.
+ * @property {object} 1 The full API response.
+ */
+ /**
+ * @typedef {object} Policy
+ * @property {PolicyBinding[]} policy.bindings Bindings associate members with roles.
+ * @property {string} [policy.etag] Etags are used to perform a read-modify-write.
+ * @property {number} [policy.version] The syntax schema version of the Policy.
+ * To set an IAM policy with conditional binding, this field must be set to
+ * 3 or greater.
+ * See {@link https://cloud.google.com/iam/docs/policies#versions| IAM Policy versions}
+ */
+ /**
+ * @typedef {object} PolicyBinding
+ * @property {string} role Role that is assigned to members.
+ * @property {string[]} members Specifies the identities requesting access for the bucket.
+ * @property {Expr} [condition] The condition that is associated with this binding.
+ */
+ /**
+ * @typedef {object} Expr
+ * @property {string} [title] An optional title for the expression, i.e. a
+ * short string describing its purpose. This can be used e.g. in UIs
+ * which allow to enter the expression.
+ * @property {string} [description] An optional description of the
+ * expression. This is a longer text which describes the expression,
+ * e.g. when hovered over it in a UI.
+ * @property {string} expression Textual representation of an expression in
+ * Common Expression Language syntax. The application context of the
+ * containing message determines which well-known feature set of CEL
+ * is supported.The condition that is associated with this binding.
+ *
+ * @see [Condition] https://cloud.google.com/storage/docs/access-control/iam#conditions
+ */
+ /**
+ * Get the IAM policy.
+ *
+ * @param {GetPolicyOptions} [options] Request options.
+ * @param {GetPolicyCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/buckets/getIamPolicy| Buckets: setIamPolicy API Documentation}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('my-bucket');
+ *
+ * bucket.iam.getPolicy(
+ * {requestedPolicyVersion: 3},
+ * function(err, policy, apiResponse) {
+ *
+ * },
+ * );
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * bucket.iam.getPolicy({requestedPolicyVersion: 3})
+ * .then(function(data) {
+ * const policy = data[0];
+ * const apiResponse = data[1];
+ * });
+ *
+ * ```
+ * @example include:samples/iam.js
+ * region_tag:storage_view_bucket_iam_members
+ * Example of retrieving a bucket's IAM policy:
+ */
+ getPolicy(optionsOrCallback, callback) {
+ const { options, callback: cb } = (0, util_js_1.normalize)(optionsOrCallback, callback);
+ const qs = {};
+ if (options.userProject) {
+ qs.userProject = options.userProject;
+ }
+ if (options.requestedPolicyVersion !== null &&
+ options.requestedPolicyVersion !== undefined) {
+ qs.optionsRequestedPolicyVersion = options.requestedPolicyVersion;
+ }
+ this.request_({
+ uri: '/iam',
+ qs,
+ }, cb);
+ }
+ /**
+ * Set the IAM policy.
+ *
+ * @throws {Error} If no policy is provided.
+ *
+ * @param {Policy} policy The policy.
+ * @param {SetPolicyOptions} [options] Configuration options.
+ * @param {SetPolicyCallback} callback Callback function.
+ * @returns {Promise}
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/buckets/setIamPolicy| Buckets: setIamPolicy API Documentation}
+ * See {@link https://cloud.google.com/iam/docs/understanding-roles| IAM Roles}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('my-bucket');
+ *
+ * const myPolicy = {
+ * bindings: [
+ * {
+ * role: 'roles/storage.admin',
+ * members:
+ * ['serviceAccount:myotherproject@appspot.gserviceaccount.com']
+ * }
+ * ]
+ * };
+ *
+ * bucket.iam.setPolicy(myPolicy, function(err, policy, apiResponse) {});
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * bucket.iam.setPolicy(myPolicy).then(function(data) {
+ * const policy = data[0];
+ * const apiResponse = data[1];
+ * });
+ *
+ * ```
+ * @example include:samples/iam.js
+ * region_tag:storage_add_bucket_iam_member
+ * Example of adding to a bucket's IAM policy:
+ *
+ * @example include:samples/iam.js
+ * region_tag:storage_remove_bucket_iam_member
+ * Example of removing from a bucket's IAM policy:
+ */
+ setPolicy(policy, optionsOrCallback, callback) {
+ if (policy === null || typeof policy !== 'object') {
+ throw new Error(IAMExceptionMessages.POLICY_OBJECT_REQUIRED);
+ }
+ const { options, callback: cb } = (0, util_js_1.normalize)(optionsOrCallback, callback);
+ let maxRetries;
+ if (policy.etag === undefined) {
+ maxRetries = 0;
+ }
+ this.request_({
+ method: 'PUT',
+ uri: '/iam',
+ maxRetries,
+ json: Object.assign({
+ resourceId: this.resourceId_,
+ }, policy),
+ qs: options,
+ }, cb);
+ }
+ /**
+ * Test a set of permissions for a resource.
+ *
+ * @throws {Error} If permissions are not provided.
+ *
+ * @param {string|string[]} permissions The permission(s) to test for.
+ * @param {TestIamPermissionsOptions} [options] Configuration object.
+ * @param {TestIamPermissionsCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/buckets/testIamPermissions| Buckets: testIamPermissions API Documentation}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('my-bucket');
+ *
+ * //-
+ * // Test a single permission.
+ * //-
+ * const test = 'storage.buckets.delete';
+ *
+ * bucket.iam.testPermissions(test, function(err, permissions, apiResponse) {
+ * console.log(permissions);
+ * // {
+ * // "storage.buckets.delete": true
+ * // }
+ * });
+ *
+ * //-
+ * // Test several permissions at once.
+ * //-
+ * const tests = [
+ * 'storage.buckets.delete',
+ * 'storage.buckets.get'
+ * ];
+ *
+ * bucket.iam.testPermissions(tests, function(err, permissions) {
+ * console.log(permissions);
+ * // {
+ * // "storage.buckets.delete": false,
+ * // "storage.buckets.get": true
+ * // }
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * bucket.iam.testPermissions(test).then(function(data) {
+ * const permissions = data[0];
+ * const apiResponse = data[1];
+ * });
+ * ```
+ */
+ testPermissions(permissions, optionsOrCallback, callback) {
+ if (!Array.isArray(permissions) && typeof permissions !== 'string') {
+ throw new Error(IAMExceptionMessages.PERMISSIONS_REQUIRED);
+ }
+ const { options, callback: cb } = (0, util_js_1.normalize)(optionsOrCallback, callback);
+ const permissionsArray = Array.isArray(permissions)
+ ? permissions
+ : [permissions];
+ const req = Object.assign({
+ permissions: permissionsArray,
+ }, options);
+ this.request_({
+ uri: '/iam/testPermissions',
+ qs: req,
+ useQuerystring: true,
+ }, (err, resp) => {
+ if (err) {
+ cb(err, null, resp);
+ return;
+ }
+ const availablePermissions = Array.isArray(resp.permissions)
+ ? resp.permissions
+ : [];
+ const permissionsHash = permissionsArray.reduce((acc, permission) => {
+ acc[permission] = availablePermissions.indexOf(permission) > -1;
+ return acc;
+ }, {});
+ cb(null, permissionsHash, resp);
+ });
+ }
+}
+exports.Iam = Iam;
+/*! Developer Documentation
+ *
+ * All async methods (except for streams) will return a Promise in the event
+ * that a callback is omitted.
+ */
+(0, promisify_1.promisifyAll)(Iam);
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/index.d.ts b/node_modules/@google-cloud/storage/build/cjs/src/index.d.ts
new file mode 100644
index 0000000..6da8101
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/index.d.ts
@@ -0,0 +1,57 @@
+/**
+ * The `@google-cloud/storage` package has a single named export which is the
+ * {@link Storage} (ES6) class, which should be instantiated with `new`.
+ *
+ * See {@link Storage} and {@link ClientConfig} for client methods and
+ * configuration options.
+ *
+ * @module {Storage} @google-cloud/storage
+ * @alias nodejs-storage
+ *
+ * @example
+ * Install the client library with npm:
+ * ```
+ * npm install --save @google-cloud/storage
+ * ```
+ *
+ * @example
+ * Import the client library
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * ```
+ *
+ * @example
+ * Create a client that uses Application
+ * Default Credentials (ADC):
+ * ```
+ * const storage = new Storage();
+ * ```
+ *
+ * @example
+ * Create a client with explicit
+ * credentials:
+ * ```
+ * const storage = new Storage({ projectId:
+ * 'your-project-id', keyFilename: '/path/to/keyfile.json'
+ * });
+ * ```
+ *
+ * @example include:samples/quickstart.js
+ * region_tag:storage_quickstart
+ * Full quickstart example:
+ */
+export { ApiError } from './nodejs-common/index.js';
+export { BucketCallback, BucketOptions, CreateBucketQuery, CreateBucketRequest, CreateBucketResponse, CreateHmacKeyCallback, CreateHmacKeyOptions, CreateHmacKeyResponse, GetBucketsCallback, GetBucketsRequest, GetBucketsResponse, GetHmacKeysCallback, GetHmacKeysOptions, GetHmacKeysResponse, GetServiceAccountCallback, GetServiceAccountOptions, GetServiceAccountResponse, HmacKeyResourceResponse, IdempotencyStrategy, PreconditionOptions, ServiceAccount, Storage, StorageOptions, } from './storage.js';
+export { AclMetadata, AccessControlObject, AclOptions, AddAclCallback, AddAclOptions, AddAclResponse, GetAclCallback, GetAclOptions, GetAclResponse, RemoveAclCallback, RemoveAclOptions, RemoveAclResponse, UpdateAclCallback, UpdateAclOptions, UpdateAclResponse, } from './acl.js';
+export { Bucket, BucketExistsCallback, BucketExistsOptions, BucketExistsResponse, BucketLockCallback, BucketLockResponse, BucketMetadata, CombineCallback, CombineOptions, CombineResponse, CreateChannelCallback, CreateChannelConfig, CreateChannelOptions, CreateChannelResponse, CreateNotificationCallback, CreateNotificationOptions, CreateNotificationResponse, DeleteBucketCallback, DeleteBucketOptions, DeleteBucketResponse, DeleteFilesCallback, DeleteFilesOptions, DeleteLabelsCallback, DeleteLabelsResponse, DisableRequesterPaysCallback, DisableRequesterPaysResponse, EnableRequesterPaysCallback, EnableRequesterPaysResponse, GetBucketCallback, GetBucketMetadataCallback, GetBucketMetadataOptions, GetBucketMetadataResponse, GetBucketOptions, GetBucketResponse, GetBucketSignedUrlConfig, GetFilesCallback, GetFilesOptions, GetFilesResponse, GetLabelsCallback, GetLabelsOptions, GetLabelsResponse, GetNotificationsCallback, GetNotificationsOptions, GetNotificationsResponse, Labels, LifecycleAction, LifecycleCondition, LifecycleRule, MakeBucketPrivateCallback, MakeBucketPrivateOptions, MakeBucketPrivateResponse, MakeBucketPublicCallback, MakeBucketPublicOptions, MakeBucketPublicResponse, SetBucketMetadataCallback, SetBucketMetadataOptions, SetBucketMetadataResponse, SetBucketStorageClassCallback, SetBucketStorageClassOptions, SetLabelsCallback, SetLabelsOptions, SetLabelsResponse, UploadCallback, UploadOptions, UploadResponse, } from './bucket.js';
+export * from './crc32c.js';
+export { Channel, StopCallback } from './channel.js';
+export { CopyCallback, CopyOptions, CopyResponse, CreateReadStreamOptions, CreateResumableUploadCallback, CreateResumableUploadOptions, CreateResumableUploadResponse, CreateWriteStreamOptions, DeleteFileCallback, DeleteFileOptions, DeleteFileResponse, DownloadCallback, DownloadOptions, DownloadResponse, EncryptionKeyOptions, File, FileExistsCallback, FileExistsOptions, FileExistsResponse, FileMetadata, FileOptions, GetExpirationDateCallback, GetExpirationDateResponse, GetFileCallback, GetFileMetadataCallback, GetFileMetadataOptions, GetFileMetadataResponse, GetFileOptions, GetFileResponse, GenerateSignedPostPolicyV2Callback, GenerateSignedPostPolicyV2Options, GenerateSignedPostPolicyV2Response, GenerateSignedPostPolicyV4Callback, GenerateSignedPostPolicyV4Options, GenerateSignedPostPolicyV4Response, GetSignedUrlConfig, MakeFilePrivateCallback, MakeFilePrivateOptions, MakeFilePrivateResponse, MakeFilePublicCallback, MakeFilePublicResponse, MoveCallback, MoveOptions, MoveResponse, PolicyDocument, PolicyFields, PredefinedAcl, RotateEncryptionKeyCallback, RotateEncryptionKeyOptions, RotateEncryptionKeyResponse, SaveCallback, SaveOptions, SetFileMetadataCallback, SetFileMetadataOptions, SetFileMetadataResponse, SetStorageClassCallback, SetStorageClassOptions, SetStorageClassResponse, SignedPostPolicyV4Output, } from './file.js';
+export * from './hash-stream-validator.js';
+export { HmacKey, HmacKeyMetadata, HmacKeyMetadataCallback, HmacKeyMetadataResponse, SetHmacKeyMetadata, SetHmacKeyMetadataOptions, } from './hmacKey.js';
+export { GetPolicyCallback, GetPolicyOptions, GetPolicyResponse, Iam, Policy, SetPolicyCallback, SetPolicyOptions, SetPolicyResponse, TestIamPermissionsCallback, TestIamPermissionsOptions, TestIamPermissionsResponse, } from './iam.js';
+export { DeleteNotificationCallback, DeleteNotificationOptions, GetNotificationCallback, GetNotificationMetadataCallback, GetNotificationMetadataOptions, GetNotificationMetadataResponse, GetNotificationOptions, GetNotificationResponse, Notification, NotificationMetadata, } from './notification.js';
+export { GetSignedUrlCallback, GetSignedUrlResponse } from './signer.js';
+export * from './transfer-manager.js';
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/index.js b/node_modules/@google-cloud/storage/build/cjs/src/index.js
new file mode 100644
index 0000000..6a7818b
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/index.js
@@ -0,0 +1,94 @@
+"use strict";
+// Copyright 2019 Google LLC
+//
+// 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.
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __exportStar = (this && this.__exportStar) || function(m, exports) {
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.Notification = exports.Iam = exports.HmacKey = exports.File = exports.Channel = exports.Bucket = exports.Storage = exports.IdempotencyStrategy = exports.ApiError = void 0;
+/**
+ * The `@google-cloud/storage` package has a single named export which is the
+ * {@link Storage} (ES6) class, which should be instantiated with `new`.
+ *
+ * See {@link Storage} and {@link ClientConfig} for client methods and
+ * configuration options.
+ *
+ * @module {Storage} @google-cloud/storage
+ * @alias nodejs-storage
+ *
+ * @example
+ * Install the client library with npm:
+ * ```
+ * npm install --save @google-cloud/storage
+ * ```
+ *
+ * @example
+ * Import the client library
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * ```
+ *
+ * @example
+ * Create a client that uses Application
+ * Default Credentials (ADC):
+ * ```
+ * const storage = new Storage();
+ * ```
+ *
+ * @example
+ * Create a client with explicit
+ * credentials:
+ * ```
+ * const storage = new Storage({ projectId:
+ * 'your-project-id', keyFilename: '/path/to/keyfile.json'
+ * });
+ * ```
+ *
+ * @example include:samples/quickstart.js
+ * region_tag:storage_quickstart
+ * Full quickstart example:
+ */
+var index_js_1 = require("./nodejs-common/index.js");
+Object.defineProperty(exports, "ApiError", { enumerable: true, get: function () { return index_js_1.ApiError; } });
+var storage_js_1 = require("./storage.js");
+Object.defineProperty(exports, "IdempotencyStrategy", { enumerable: true, get: function () { return storage_js_1.IdempotencyStrategy; } });
+Object.defineProperty(exports, "Storage", { enumerable: true, get: function () { return storage_js_1.Storage; } });
+var bucket_js_1 = require("./bucket.js");
+Object.defineProperty(exports, "Bucket", { enumerable: true, get: function () { return bucket_js_1.Bucket; } });
+__exportStar(require("./crc32c.js"), exports);
+var channel_js_1 = require("./channel.js");
+Object.defineProperty(exports, "Channel", { enumerable: true, get: function () { return channel_js_1.Channel; } });
+var file_js_1 = require("./file.js");
+Object.defineProperty(exports, "File", { enumerable: true, get: function () { return file_js_1.File; } });
+__exportStar(require("./hash-stream-validator.js"), exports);
+var hmacKey_js_1 = require("./hmacKey.js");
+Object.defineProperty(exports, "HmacKey", { enumerable: true, get: function () { return hmacKey_js_1.HmacKey; } });
+var iam_js_1 = require("./iam.js");
+Object.defineProperty(exports, "Iam", { enumerable: true, get: function () { return iam_js_1.Iam; } });
+var notification_js_1 = require("./notification.js");
+Object.defineProperty(exports, "Notification", { enumerable: true, get: function () { return notification_js_1.Notification; } });
+__exportStar(require("./transfer-manager.js"), exports);
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/index.d.ts b/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/index.d.ts
new file mode 100644
index 0000000..72588c7
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/index.d.ts
@@ -0,0 +1,19 @@
+/*!
+ * Copyright 2022 Google LLC. 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.
+ */
+export { GoogleAuthOptions } from 'google-auth-library';
+export { Service, ServiceConfig, ServiceOptions, StreamRequestOptions, } from './service.js';
+export { BaseMetadata, DeleteCallback, ExistsCallback, GetConfig, InstanceResponseCallback, Interceptor, MetadataCallback, MetadataResponse, Methods, ResponseCallback, ServiceObject, ServiceObjectConfig, ServiceObjectParent, SetMetadataResponse, } from './service-object.js';
+export { Abortable, AbortableDuplex, ApiError, BodyResponseCallback, DecorateRequestOptions, ResponseBody, util, } from './util.js';
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/index.js b/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/index.js
new file mode 100644
index 0000000..bf7023c
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/index.js
@@ -0,0 +1,10 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.util = exports.ApiError = exports.ServiceObject = exports.Service = void 0;
+var service_js_1 = require("./service.js");
+Object.defineProperty(exports, "Service", { enumerable: true, get: function () { return service_js_1.Service; } });
+var service_object_js_1 = require("./service-object.js");
+Object.defineProperty(exports, "ServiceObject", { enumerable: true, get: function () { return service_object_js_1.ServiceObject; } });
+var util_js_1 = require("./util.js");
+Object.defineProperty(exports, "ApiError", { enumerable: true, get: function () { return util_js_1.ApiError; } });
+Object.defineProperty(exports, "util", { enumerable: true, get: function () { return util_js_1.util; } });
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/service-object.d.ts b/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/service-object.d.ts
new file mode 100644
index 0000000..083962b
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/service-object.d.ts
@@ -0,0 +1,218 @@
+///
+import { EventEmitter } from 'events';
+import * as r from 'teeny-request';
+import { ApiError, BodyResponseCallback, DecorateRequestOptions } from './util.js';
+export type RequestResponse = [unknown, r.Response];
+export interface ServiceObjectParent {
+ interceptors: Interceptor[];
+ getRequestInterceptors(): Function[];
+ requestStream(reqOpts: DecorateRequestOptions): r.Request;
+ request(reqOpts: DecorateRequestOptions, callback: BodyResponseCallback): void;
+}
+export interface Interceptor {
+ request(opts: r.Options): DecorateRequestOptions;
+}
+export type GetMetadataOptions = object;
+export type MetadataResponse = [K, r.Response];
+export type MetadataCallback = (err: Error | null, metadata?: K, apiResponse?: r.Response) => void;
+export type ExistsOptions = object;
+export interface ExistsCallback {
+ (err: Error | null, exists?: boolean): void;
+}
+export interface ServiceObjectConfig {
+ /**
+ * The base URL to make API requests to.
+ */
+ baseUrl?: string;
+ /**
+ * The method which creates this object.
+ */
+ createMethod?: Function;
+ /**
+ * The identifier of the object. For example, the name of a Storage bucket or
+ * Pub/Sub topic.
+ */
+ id?: string;
+ /**
+ * A map of each method name that should be inherited.
+ */
+ methods?: Methods;
+ /**
+ * The parent service instance. For example, an instance of Storage if the
+ * object is Bucket.
+ */
+ parent: ServiceObjectParent;
+ /**
+ * Override of projectId, used to allow access to resources in another project.
+ * For example, a BigQuery dataset in another project to which the user has been
+ * granted permission.
+ */
+ projectId?: string;
+}
+export interface Methods {
+ [methodName: string]: {
+ reqOpts?: r.CoreOptions;
+ } | boolean;
+}
+export interface InstanceResponseCallback {
+ (err: ApiError | null, instance?: T | null, apiResponse?: r.Response): void;
+}
+export interface CreateOptions {
+}
+export type CreateResponse = any[];
+export interface CreateCallback {
+ (err: ApiError | null, instance?: T | null, ...args: any[]): void;
+}
+export type DeleteOptions = {
+ ignoreNotFound?: boolean;
+ ifGenerationMatch?: number | string;
+ ifGenerationNotMatch?: number | string;
+ ifMetagenerationMatch?: number | string;
+ ifMetagenerationNotMatch?: number | string;
+} & object;
+export interface DeleteCallback {
+ (err: Error | null, apiResponse?: r.Response): void;
+}
+export interface GetConfig {
+ /**
+ * Create the object if it doesn't already exist.
+ */
+ autoCreate?: boolean;
+}
+export type GetOrCreateOptions = GetConfig & CreateOptions;
+export type GetResponse = [T, r.Response];
+export interface ResponseCallback {
+ (err?: Error | null, apiResponse?: r.Response): void;
+}
+export type SetMetadataResponse = [K];
+export type SetMetadataOptions = object;
+export interface BaseMetadata {
+ id?: string;
+ kind?: string;
+ etag?: string;
+ selfLink?: string;
+ [key: string]: unknown;
+}
+/**
+ * ServiceObject is a base class, meant to be inherited from by a "service
+ * object," like a BigQuery dataset or Storage bucket.
+ *
+ * Most of the time, these objects share common functionality; they can be
+ * created or deleted, and you can get or set their metadata.
+ *
+ * By inheriting from this class, a service object will be extended with these
+ * shared behaviors. Note that any method can be overridden when the service
+ * object requires specific behavior.
+ */
+declare class ServiceObject extends EventEmitter {
+ metadata: K;
+ baseUrl?: string;
+ parent: ServiceObjectParent;
+ id?: string;
+ private createMethod?;
+ protected methods: Methods;
+ interceptors: Interceptor[];
+ projectId?: string;
+ constructor(config: ServiceObjectConfig);
+ /**
+ * Create the object.
+ *
+ * @param {object=} options - Configuration object.
+ * @param {function} callback - The callback function.
+ * @param {?error} callback.err - An error returned while making this request.
+ * @param {object} callback.instance - The instance.
+ * @param {object} callback.apiResponse - The full API response.
+ */
+ create(options?: CreateOptions): Promise>;
+ create(options: CreateOptions, callback: CreateCallback): void;
+ create(callback: CreateCallback): void;
+ /**
+ * Delete the object.
+ *
+ * @param {function=} callback - The callback function.
+ * @param {?error} callback.err - An error returned while making this request.
+ * @param {object} callback.apiResponse - The full API response.
+ */
+ delete(options?: DeleteOptions): Promise<[r.Response]>;
+ delete(options: DeleteOptions, callback: DeleteCallback): void;
+ delete(callback: DeleteCallback): void;
+ /**
+ * Check if the object exists.
+ *
+ * @param {function} callback - The callback function.
+ * @param {?error} callback.err - An error returned while making this request.
+ * @param {boolean} callback.exists - Whether the object exists or not.
+ */
+ exists(options?: ExistsOptions): Promise<[boolean]>;
+ exists(options: ExistsOptions, callback: ExistsCallback): void;
+ exists(callback: ExistsCallback): void;
+ /**
+ * Get the object if it exists. Optionally have the object created if an
+ * options object is provided with `autoCreate: true`.
+ *
+ * @param {object=} options - The configuration object that will be used to
+ * create the object if necessary.
+ * @param {boolean} options.autoCreate - Create the object if it doesn't already exist.
+ * @param {function} callback - The callback function.
+ * @param {?error} callback.err - An error returned while making this request.
+ * @param {object} callback.instance - The instance.
+ * @param {object} callback.apiResponse - The full API response.
+ */
+ get(options?: GetOrCreateOptions): Promise>;
+ get(callback: InstanceResponseCallback): void;
+ get(options: GetOrCreateOptions, callback: InstanceResponseCallback): void;
+ /**
+ * Get the metadata of this object.
+ *
+ * @param {function} callback - The callback function.
+ * @param {?error} callback.err - An error returned while making this request.
+ * @param {object} callback.metadata - The metadata for this object.
+ * @param {object} callback.apiResponse - The full API response.
+ */
+ getMetadata(options?: GetMetadataOptions): Promise>;
+ getMetadata(options: GetMetadataOptions, callback: MetadataCallback): void;
+ getMetadata(callback: MetadataCallback): void;
+ /**
+ * Return the user's custom request interceptors.
+ */
+ getRequestInterceptors(): Function[];
+ /**
+ * Set the metadata for this object.
+ *
+ * @param {object} metadata - The metadata to set on this object.
+ * @param {object=} options - Configuration options.
+ * @param {function=} callback - The callback function.
+ * @param {?error} callback.err - An error returned while making this request.
+ * @param {object} callback.apiResponse - The full API response.
+ */
+ setMetadata(metadata: K, options?: SetMetadataOptions): Promise>;
+ setMetadata(metadata: K, callback: MetadataCallback): void;
+ setMetadata(metadata: K, options: SetMetadataOptions, callback: MetadataCallback): void;
+ /**
+ * Make an authenticated API request.
+ *
+ * @private
+ *
+ * @param {object} reqOpts - Request options that are passed to `request`.
+ * @param {string} reqOpts.uri - A URI relative to the baseUrl.
+ * @param {function} callback - The callback function passed to `request`.
+ */
+ private request_;
+ /**
+ * Make an authenticated API request.
+ *
+ * @param {object} reqOpts - Request options that are passed to `request`.
+ * @param {string} reqOpts.uri - A URI relative to the baseUrl.
+ * @param {function} callback - The callback function passed to `request`.
+ */
+ request(reqOpts: DecorateRequestOptions): Promise;
+ request(reqOpts: DecorateRequestOptions, callback: BodyResponseCallback): void;
+ /**
+ * Make an authenticated API request.
+ *
+ * @param {object} reqOpts - Request options that are passed to `request`.
+ * @param {string} reqOpts.uri - A URI relative to the baseUrl.
+ */
+ requestStream(reqOpts: DecorateRequestOptions): r.Request;
+}
+export { ServiceObject };
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/service-object.js b/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/service-object.js
new file mode 100644
index 0000000..7b2cdc8
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/service-object.js
@@ -0,0 +1,292 @@
+"use strict";
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.ServiceObject = void 0;
+/*!
+ * Copyright 2022 Google LLC. 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.
+ */
+const promisify_1 = require("@google-cloud/promisify");
+const events_1 = require("events");
+const util_js_1 = require("./util.js");
+/**
+ * ServiceObject is a base class, meant to be inherited from by a "service
+ * object," like a BigQuery dataset or Storage bucket.
+ *
+ * Most of the time, these objects share common functionality; they can be
+ * created or deleted, and you can get or set their metadata.
+ *
+ * By inheriting from this class, a service object will be extended with these
+ * shared behaviors. Note that any method can be overridden when the service
+ * object requires specific behavior.
+ */
+// eslint-disable-next-line @typescript-eslint/no-explicit-any
+class ServiceObject extends events_1.EventEmitter {
+ /*
+ * @constructor
+ * @alias module:common/service-object
+ *
+ * @private
+ *
+ * @param {object} config - Configuration object.
+ * @param {string} config.baseUrl - The base URL to make API requests to.
+ * @param {string} config.createMethod - The method which creates this object.
+ * @param {string=} config.id - The identifier of the object. For example, the
+ * name of a Storage bucket or Pub/Sub topic.
+ * @param {object=} config.methods - A map of each method name that should be inherited.
+ * @param {object} config.methods[].reqOpts - Default request options for this
+ * particular method. A common use case is when `setMetadata` requires a
+ * `PUT` method to override the default `PATCH`.
+ * @param {object} config.parent - The parent service instance. For example, an
+ * instance of Storage if the object is Bucket.
+ */
+ constructor(config) {
+ super();
+ this.metadata = {};
+ this.baseUrl = config.baseUrl;
+ this.parent = config.parent; // Parent class.
+ this.id = config.id; // Name or ID (e.g. dataset ID, bucket name, etc).
+ this.createMethod = config.createMethod;
+ this.methods = config.methods || {};
+ this.interceptors = [];
+ this.projectId = config.projectId;
+ if (config.methods) {
+ // This filters the ServiceObject instance (e.g. a "File") to only have
+ // the configured methods. We make a couple of exceptions for core-
+ // functionality ("request()" and "getRequestInterceptors()")
+ Object.getOwnPropertyNames(ServiceObject.prototype)
+ .filter(methodName => {
+ return (
+ // All ServiceObjects need `request` and `getRequestInterceptors`.
+ // clang-format off
+ !/^request/.test(methodName) &&
+ !/^getRequestInterceptors/.test(methodName) &&
+ // clang-format on
+ // The ServiceObject didn't redefine the method.
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ this[methodName] ===
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ ServiceObject.prototype[methodName] &&
+ // This method isn't wanted.
+ !config.methods[methodName]);
+ })
+ .forEach(methodName => {
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ this[methodName] = undefined;
+ });
+ }
+ }
+ create(optionsOrCallback, callback) {
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
+ const self = this;
+ const args = [this.id];
+ if (typeof optionsOrCallback === 'function') {
+ callback = optionsOrCallback;
+ }
+ if (typeof optionsOrCallback === 'object') {
+ args.push(optionsOrCallback);
+ }
+ // Wrap the callback to return *this* instance of the object, not the
+ // newly-created one.
+ // tslint: disable-next-line no-any
+ function onCreate(...args) {
+ const [err, instance] = args;
+ if (!err) {
+ self.metadata = instance.metadata;
+ if (self.id && instance.metadata) {
+ self.id = instance.metadata.id;
+ }
+ args[1] = self; // replace the created `instance` with this one.
+ }
+ callback(...args);
+ }
+ args.push(onCreate);
+ // eslint-disable-next-line prefer-spread
+ this.createMethod.apply(null, args);
+ }
+ delete(optionsOrCallback, cb) {
+ var _a;
+ const [options, callback] = util_js_1.util.maybeOptionsOrCallback(optionsOrCallback, cb);
+ const ignoreNotFound = options.ignoreNotFound;
+ delete options.ignoreNotFound;
+ const methodConfig = (typeof this.methods.delete === 'object' && this.methods.delete) || {};
+ const reqOpts = {
+ method: 'DELETE',
+ uri: '',
+ ...methodConfig.reqOpts,
+ qs: {
+ ...(_a = methodConfig.reqOpts) === null || _a === void 0 ? void 0 : _a.qs,
+ ...options,
+ },
+ };
+ // The `request` method may have been overridden to hold any special
+ // behavior. Ensure we call the original `request` method.
+ ServiceObject.prototype.request.call(this, reqOpts, (err, body, res) => {
+ if (err) {
+ if (err.code === 404 && ignoreNotFound) {
+ err = null;
+ }
+ }
+ callback(err, res);
+ });
+ }
+ exists(optionsOrCallback, cb) {
+ const [options, callback] = util_js_1.util.maybeOptionsOrCallback(optionsOrCallback, cb);
+ this.get(options, err => {
+ if (err) {
+ if (err.code === 404) {
+ callback(null, false);
+ }
+ else {
+ callback(err);
+ }
+ return;
+ }
+ callback(null, true);
+ });
+ }
+ get(optionsOrCallback, cb) {
+ // eslint-disable-next-line @typescript-eslint/no-this-alias
+ const self = this;
+ const [opts, callback] = util_js_1.util.maybeOptionsOrCallback(optionsOrCallback, cb);
+ const options = Object.assign({}, opts);
+ const autoCreate = options.autoCreate && typeof this.create === 'function';
+ delete options.autoCreate;
+ function onCreate(err, instance, apiResponse) {
+ if (err) {
+ if (err.code === 409) {
+ self.get(options, callback);
+ return;
+ }
+ callback(err, null, apiResponse);
+ return;
+ }
+ callback(null, instance, apiResponse);
+ }
+ this.getMetadata(options, (err, metadata) => {
+ if (err) {
+ if (err.code === 404 && autoCreate) {
+ const args = [];
+ if (Object.keys(options).length > 0) {
+ args.push(options);
+ }
+ args.push(onCreate);
+ self.create(...args);
+ return;
+ }
+ callback(err, null, metadata);
+ return;
+ }
+ callback(null, self, metadata);
+ });
+ }
+ getMetadata(optionsOrCallback, cb) {
+ var _a;
+ const [options, callback] = util_js_1.util.maybeOptionsOrCallback(optionsOrCallback, cb);
+ const methodConfig = (typeof this.methods.getMetadata === 'object' &&
+ this.methods.getMetadata) ||
+ {};
+ const reqOpts = {
+ uri: '',
+ ...methodConfig.reqOpts,
+ qs: {
+ ...(_a = methodConfig.reqOpts) === null || _a === void 0 ? void 0 : _a.qs,
+ ...options,
+ },
+ };
+ // The `request` method may have been overridden to hold any special
+ // behavior. Ensure we call the original `request` method.
+ ServiceObject.prototype.request.call(this, reqOpts, (err, body, res) => {
+ this.metadata = body;
+ callback(err, this.metadata, res);
+ });
+ }
+ /**
+ * Return the user's custom request interceptors.
+ */
+ getRequestInterceptors() {
+ // Interceptors should be returned in the order they were assigned.
+ const localInterceptors = this.interceptors
+ .filter(interceptor => typeof interceptor.request === 'function')
+ .map(interceptor => interceptor.request);
+ return this.parent.getRequestInterceptors().concat(localInterceptors);
+ }
+ setMetadata(metadata, optionsOrCallback, cb) {
+ var _a, _b;
+ const [options, callback] = util_js_1.util.maybeOptionsOrCallback(optionsOrCallback, cb);
+ const methodConfig = (typeof this.methods.setMetadata === 'object' &&
+ this.methods.setMetadata) ||
+ {};
+ const reqOpts = {
+ method: 'PATCH',
+ uri: '',
+ ...methodConfig.reqOpts,
+ json: {
+ ...(_a = methodConfig.reqOpts) === null || _a === void 0 ? void 0 : _a.json,
+ ...metadata,
+ },
+ qs: {
+ ...(_b = methodConfig.reqOpts) === null || _b === void 0 ? void 0 : _b.qs,
+ ...options,
+ },
+ };
+ // The `request` method may have been overridden to hold any special
+ // behavior. Ensure we call the original `request` method.
+ ServiceObject.prototype.request.call(this, reqOpts, (err, body, res) => {
+ this.metadata = body;
+ callback(err, this.metadata, res);
+ });
+ }
+ request_(reqOpts, callback) {
+ reqOpts = { ...reqOpts };
+ if (this.projectId) {
+ reqOpts.projectId = this.projectId;
+ }
+ const isAbsoluteUrl = reqOpts.uri.indexOf('http') === 0;
+ const uriComponents = [this.baseUrl, this.id || '', reqOpts.uri];
+ if (isAbsoluteUrl) {
+ uriComponents.splice(0, uriComponents.indexOf(reqOpts.uri));
+ }
+ reqOpts.uri = uriComponents
+ .filter(x => x.trim()) // Limit to non-empty strings.
+ .map(uriComponent => {
+ const trimSlashesRegex = /^\/*|\/*$/g;
+ return uriComponent.replace(trimSlashesRegex, '');
+ })
+ .join('/');
+ const childInterceptors = Array.isArray(reqOpts.interceptors_)
+ ? reqOpts.interceptors_
+ : [];
+ const localInterceptors = [].slice.call(this.interceptors);
+ reqOpts.interceptors_ = childInterceptors.concat(localInterceptors);
+ if (reqOpts.shouldReturnStream) {
+ return this.parent.requestStream(reqOpts);
+ }
+ this.parent.request(reqOpts, callback);
+ }
+ request(reqOpts, callback) {
+ this.request_(reqOpts, callback);
+ }
+ /**
+ * Make an authenticated API request.
+ *
+ * @param {object} reqOpts - Request options that are passed to `request`.
+ * @param {string} reqOpts.uri - A URI relative to the baseUrl.
+ */
+ requestStream(reqOpts) {
+ const opts = { ...reqOpts, shouldReturnStream: true };
+ return this.request_(opts);
+ }
+}
+exports.ServiceObject = ServiceObject;
+(0, promisify_1.promisifyAll)(ServiceObject, { exclude: ['getRequestInterceptors'] });
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/service.d.ts b/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/service.d.ts
new file mode 100644
index 0000000..e7177a2
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/service.d.ts
@@ -0,0 +1,125 @@
+/*!
+ * Copyright 2022 Google LLC. 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.
+ */
+import { AuthClient, GoogleAuth, GoogleAuthOptions } from 'google-auth-library';
+import * as r from 'teeny-request';
+import { Interceptor } from './service-object.js';
+import { BodyResponseCallback, DecorateRequestOptions, MakeAuthenticatedRequest, PackageJson } from './util.js';
+export declare const DEFAULT_PROJECT_ID_TOKEN = "{{projectId}}";
+export interface StreamRequestOptions extends DecorateRequestOptions {
+ shouldReturnStream: true;
+}
+export interface ServiceConfig {
+ /**
+ * The base URL to make API requests to.
+ */
+ baseUrl: string;
+ /**
+ * The API Endpoint to use when connecting to the service.
+ * Example: storage.googleapis.com
+ */
+ apiEndpoint: string;
+ /**
+ * The scopes required for the request.
+ */
+ scopes: string[];
+ projectIdRequired?: boolean;
+ packageJson: PackageJson;
+ /**
+ * Reuse an existing `AuthClient` or `GoogleAuth` client instead of creating a new one.
+ */
+ authClient?: AuthClient | GoogleAuth;
+ /**
+ * Set to true if the endpoint is a custom URL
+ */
+ customEndpoint?: boolean;
+}
+export interface ServiceOptions extends Omit {
+ authClient?: AuthClient | GoogleAuth;
+ interceptors_?: Interceptor[];
+ email?: string;
+ token?: string;
+ timeout?: number;
+ userAgent?: string;
+ useAuthWithCustomEndpoint?: boolean;
+}
+export declare class Service {
+ baseUrl: string;
+ private globalInterceptors;
+ interceptors: Interceptor[];
+ private packageJson;
+ projectId: string;
+ private projectIdRequired;
+ providedUserAgent?: string;
+ makeAuthenticatedRequest: MakeAuthenticatedRequest;
+ authClient: GoogleAuth;
+ apiEndpoint: string;
+ timeout?: number;
+ universeDomain: string;
+ customEndpoint: boolean;
+ /**
+ * Service is a base class, meant to be inherited from by a "service," like
+ * BigQuery or Storage.
+ *
+ * This handles making authenticated requests by exposing a `makeReq_`
+ * function.
+ *
+ * @constructor
+ * @alias module:common/service
+ *
+ * @param {object} config - Configuration object.
+ * @param {string} config.baseUrl - The base URL to make API requests to.
+ * @param {string[]} config.scopes - The scopes required for the request.
+ * @param {object=} options - [Configuration object](#/docs).
+ */
+ constructor(config: ServiceConfig, options?: ServiceOptions);
+ /**
+ * Return the user's custom request interceptors.
+ */
+ getRequestInterceptors(): Function[];
+ /**
+ * Get and update the Service's project ID.
+ *
+ * @param {function} callback - The callback function.
+ */
+ getProjectId(): Promise;
+ getProjectId(callback: (err: Error | null, projectId?: string) => void): void;
+ protected getProjectIdAsync(): Promise;
+ /**
+ * Make an authenticated API request.
+ *
+ * @private
+ *
+ * @param {object} reqOpts - Request options that are passed to `request`.
+ * @param {string} reqOpts.uri - A URI relative to the baseUrl.
+ * @param {function} callback - The callback function passed to `request`.
+ */
+ private request_;
+ /**
+ * Make an authenticated API request.
+ *
+ * @param {object} reqOpts - Request options that are passed to `request`.
+ * @param {string} reqOpts.uri - A URI relative to the baseUrl.
+ * @param {function} callback - The callback function passed to `request`.
+ */
+ request(reqOpts: DecorateRequestOptions, callback: BodyResponseCallback): void;
+ /**
+ * Make an authenticated API request.
+ *
+ * @param {object} reqOpts - Request options that are passed to `request`.
+ * @param {string} reqOpts.uri - A URI relative to the baseUrl.
+ */
+ requestStream(reqOpts: DecorateRequestOptions): r.Request;
+}
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/service.js b/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/service.js
new file mode 100644
index 0000000..21f6e53
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/service.js
@@ -0,0 +1,207 @@
+"use strict";
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.Service = exports.DEFAULT_PROJECT_ID_TOKEN = void 0;
+/*!
+ * Copyright 2022 Google LLC. 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.
+ */
+const google_auth_library_1 = require("google-auth-library");
+const uuid = __importStar(require("uuid"));
+const util_js_1 = require("./util.js");
+const util_js_2 = require("../util.js");
+exports.DEFAULT_PROJECT_ID_TOKEN = '{{projectId}}';
+class Service {
+ /**
+ * Service is a base class, meant to be inherited from by a "service," like
+ * BigQuery or Storage.
+ *
+ * This handles making authenticated requests by exposing a `makeReq_`
+ * function.
+ *
+ * @constructor
+ * @alias module:common/service
+ *
+ * @param {object} config - Configuration object.
+ * @param {string} config.baseUrl - The base URL to make API requests to.
+ * @param {string[]} config.scopes - The scopes required for the request.
+ * @param {object=} options - [Configuration object](#/docs).
+ */
+ constructor(config, options = {}) {
+ this.baseUrl = config.baseUrl;
+ this.apiEndpoint = config.apiEndpoint;
+ this.timeout = options.timeout;
+ this.globalInterceptors = Array.isArray(options.interceptors_)
+ ? options.interceptors_
+ : [];
+ this.interceptors = [];
+ this.packageJson = config.packageJson;
+ this.projectId = options.projectId || exports.DEFAULT_PROJECT_ID_TOKEN;
+ this.projectIdRequired = config.projectIdRequired !== false;
+ this.providedUserAgent = options.userAgent;
+ this.universeDomain = options.universeDomain || google_auth_library_1.DEFAULT_UNIVERSE;
+ this.customEndpoint = config.customEndpoint || false;
+ this.makeAuthenticatedRequest = util_js_1.util.makeAuthenticatedRequestFactory({
+ ...config,
+ projectIdRequired: this.projectIdRequired,
+ projectId: this.projectId,
+ authClient: options.authClient || config.authClient,
+ credentials: options.credentials,
+ keyFile: options.keyFilename,
+ email: options.email,
+ clientOptions: {
+ universeDomain: options.universeDomain,
+ ...options.clientOptions,
+ },
+ });
+ this.authClient = this.makeAuthenticatedRequest.authClient;
+ const isCloudFunctionEnv = !!process.env.FUNCTION_NAME;
+ if (isCloudFunctionEnv) {
+ this.interceptors.push({
+ request(reqOpts) {
+ reqOpts.forever = false;
+ return reqOpts;
+ },
+ });
+ }
+ }
+ /**
+ * Return the user's custom request interceptors.
+ */
+ getRequestInterceptors() {
+ // Interceptors should be returned in the order they were assigned.
+ return [].slice
+ .call(this.globalInterceptors)
+ .concat(this.interceptors)
+ .filter(interceptor => typeof interceptor.request === 'function')
+ .map(interceptor => interceptor.request);
+ }
+ getProjectId(callback) {
+ if (!callback) {
+ return this.getProjectIdAsync();
+ }
+ this.getProjectIdAsync().then(p => callback(null, p), callback);
+ }
+ async getProjectIdAsync() {
+ const projectId = await this.authClient.getProjectId();
+ if (this.projectId === exports.DEFAULT_PROJECT_ID_TOKEN && projectId) {
+ this.projectId = projectId;
+ }
+ return this.projectId;
+ }
+ request_(reqOpts, callback) {
+ reqOpts = { ...reqOpts, timeout: this.timeout };
+ const isAbsoluteUrl = reqOpts.uri.indexOf('http') === 0;
+ const uriComponents = [this.baseUrl];
+ if (this.projectIdRequired) {
+ if (reqOpts.projectId) {
+ uriComponents.push('projects');
+ uriComponents.push(reqOpts.projectId);
+ }
+ else {
+ uriComponents.push('projects');
+ uriComponents.push(this.projectId);
+ }
+ }
+ uriComponents.push(reqOpts.uri);
+ if (isAbsoluteUrl) {
+ uriComponents.splice(0, uriComponents.indexOf(reqOpts.uri));
+ }
+ reqOpts.uri = uriComponents
+ .map(uriComponent => {
+ const trimSlashesRegex = /^\/*|\/*$/g;
+ return uriComponent.replace(trimSlashesRegex, '');
+ })
+ .join('/')
+ // Some URIs have colon separators.
+ // Bad: https://.../projects/:list
+ // Good: https://.../projects:list
+ .replace(/\/:/g, ':');
+ const requestInterceptors = this.getRequestInterceptors();
+ const interceptorArray = Array.isArray(reqOpts.interceptors_)
+ ? reqOpts.interceptors_
+ : [];
+ interceptorArray.forEach(interceptor => {
+ if (typeof interceptor.request === 'function') {
+ requestInterceptors.push(interceptor.request);
+ }
+ });
+ requestInterceptors.forEach(requestInterceptor => {
+ reqOpts = requestInterceptor(reqOpts);
+ });
+ delete reqOpts.interceptors_;
+ const pkg = this.packageJson;
+ let userAgent = (0, util_js_2.getUserAgentString)();
+ if (this.providedUserAgent) {
+ userAgent = `${this.providedUserAgent} ${userAgent}`;
+ }
+ reqOpts.headers = {
+ ...reqOpts.headers,
+ 'User-Agent': userAgent,
+ 'x-goog-api-client': `${(0, util_js_2.getRuntimeTrackingString)()} gccl/${pkg.version}-${(0, util_js_2.getModuleFormat)()} gccl-invocation-id/${uuid.v4()}`,
+ };
+ if (reqOpts[util_js_1.GCCL_GCS_CMD_KEY]) {
+ reqOpts.headers['x-goog-api-client'] += ` gccl-gcs-cmd/${reqOpts[util_js_1.GCCL_GCS_CMD_KEY]}`;
+ }
+ if (reqOpts.shouldReturnStream) {
+ return this.makeAuthenticatedRequest(reqOpts);
+ }
+ else {
+ this.makeAuthenticatedRequest(reqOpts, callback);
+ }
+ }
+ /**
+ * Make an authenticated API request.
+ *
+ * @param {object} reqOpts - Request options that are passed to `request`.
+ * @param {string} reqOpts.uri - A URI relative to the baseUrl.
+ * @param {function} callback - The callback function passed to `request`.
+ */
+ request(reqOpts, callback) {
+ Service.prototype.request_.call(this, reqOpts, callback);
+ }
+ /**
+ * Make an authenticated API request.
+ *
+ * @param {object} reqOpts - Request options that are passed to `request`.
+ * @param {string} reqOpts.uri - A URI relative to the baseUrl.
+ */
+ requestStream(reqOpts) {
+ const opts = { ...reqOpts, shouldReturnStream: true };
+ return Service.prototype.request_.call(this, opts);
+ }
+}
+exports.Service = Service;
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.d.ts b/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.d.ts
new file mode 100644
index 0000000..a805858
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.d.ts
@@ -0,0 +1,334 @@
+/*!
+ * Copyright 2022 Google LLC. 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.
+ */
+///
+import { AuthClient, GoogleAuth, GoogleAuthOptions } from 'google-auth-library';
+import { CredentialBody } from 'google-auth-library';
+import * as r from 'teeny-request';
+import { Duplex, DuplexOptions, Readable, Writable } from 'stream';
+import { Interceptor } from './service-object.js';
+/**
+ * A unique symbol for providing a `gccl-gcs-cmd` value
+ * for the `X-Goog-API-Client` header.
+ *
+ * E.g. the `V` in `X-Goog-API-Client: gccl-gcs-cmd/V`
+ **/
+export declare const GCCL_GCS_CMD_KEY: unique symbol;
+export type ResponseBody = any;
+export interface DuplexifyOptions extends DuplexOptions {
+ autoDestroy?: boolean;
+ end?: boolean;
+}
+export interface Duplexify extends Duplex {
+ readonly destroyed: boolean;
+ setWritable(writable: Writable | false | null): void;
+ setReadable(readable: Readable | false | null): void;
+}
+export interface DuplexifyConstructor {
+ obj(writable?: Writable | false | null, readable?: Readable | false | null, options?: DuplexifyOptions): Duplexify;
+ new (writable?: Writable | false | null, readable?: Readable | false | null, options?: DuplexifyOptions): Duplexify;
+ (writable?: Writable | false | null, readable?: Readable | false | null, options?: DuplexifyOptions): Duplexify;
+}
+export interface ParsedHttpRespMessage {
+ resp: r.Response;
+ err?: ApiError;
+}
+export interface MakeAuthenticatedRequest {
+ (reqOpts: DecorateRequestOptions): Duplexify;
+ (reqOpts: DecorateRequestOptions, options?: MakeAuthenticatedRequestOptions): void | Abortable;
+ (reqOpts: DecorateRequestOptions, callback?: BodyResponseCallback): void | Abortable;
+ (reqOpts: DecorateRequestOptions, optionsOrCallback?: MakeAuthenticatedRequestOptions | BodyResponseCallback): void | Abortable | Duplexify;
+ getCredentials: (callback: (err?: Error | null, credentials?: CredentialBody) => void) => void;
+ authClient: GoogleAuth;
+}
+export interface Abortable {
+ abort(): void;
+}
+export type AbortableDuplex = Duplexify & Abortable;
+export interface PackageJson {
+ name: string;
+ version: string;
+}
+export interface MakeAuthenticatedRequestFactoryConfig extends Omit {
+ /**
+ * Automatically retry requests if the response is related to rate limits or
+ * certain intermittent server errors. We will exponentially backoff
+ * subsequent requests by default. (default: true)
+ */
+ autoRetry?: boolean;
+ /**
+ * If true, just return the provided request options. Default: false.
+ */
+ customEndpoint?: boolean;
+ /**
+ * If true, will authenticate when using a custom endpoint. Default: false.
+ */
+ useAuthWithCustomEndpoint?: boolean;
+ /**
+ * Account email address, required for PEM/P12 usage.
+ */
+ email?: string;
+ /**
+ * Maximum number of automatic retries attempted before returning the error.
+ * (default: 3)
+ */
+ maxRetries?: number;
+ stream?: Duplexify;
+ /**
+ * A pre-instantiated `AuthClient` or `GoogleAuth` client that should be used.
+ * A new client will be created if this is not set.
+ */
+ authClient?: AuthClient | GoogleAuth;
+ /**
+ * Determines if a projectId is required for authenticated requests. Defaults to `true`.
+ */
+ projectIdRequired?: boolean;
+}
+export interface MakeAuthenticatedRequestOptions {
+ onAuthenticated: OnAuthenticatedCallback;
+}
+export interface OnAuthenticatedCallback {
+ (err: Error | null, reqOpts?: DecorateRequestOptions): void;
+}
+export interface GoogleErrorBody {
+ code: number;
+ errors?: GoogleInnerError[];
+ response: r.Response;
+ message?: string;
+}
+export interface GoogleInnerError {
+ reason?: string;
+ message?: string;
+}
+export interface MakeWritableStreamOptions {
+ /**
+ * A connection instance used to get a token with and send the request
+ * through.
+ */
+ connection?: {};
+ /**
+ * Metadata to send at the head of the request.
+ */
+ metadata?: {
+ contentType?: string;
+ };
+ /**
+ * Request object, in the format of a standard Node.js http.request() object.
+ */
+ request?: r.Options;
+ makeAuthenticatedRequest(reqOpts: r.OptionsWithUri & {
+ [GCCL_GCS_CMD_KEY]?: string;
+ }, fnobj: {
+ onAuthenticated(err: Error | null, authenticatedReqOpts?: r.Options): void;
+ }): void;
+}
+export interface DecorateRequestOptions extends r.CoreOptions {
+ autoPaginate?: boolean;
+ autoPaginateVal?: boolean;
+ objectMode?: boolean;
+ maxRetries?: number;
+ uri: string;
+ interceptors_?: Interceptor[];
+ shouldReturnStream?: boolean;
+ projectId?: string;
+ [GCCL_GCS_CMD_KEY]?: string;
+}
+export interface ParsedHttpResponseBody {
+ body: ResponseBody;
+ err?: Error;
+}
+/**
+ * Custom error type for API errors.
+ *
+ * @param {object} errorBody - Error object.
+ */
+export declare class ApiError extends Error {
+ code?: number;
+ errors?: GoogleInnerError[];
+ response?: r.Response;
+ constructor(errorMessage: string);
+ constructor(errorBody: GoogleErrorBody);
+ /**
+ * Pieces together an error message by combining all unique error messages
+ * returned from a single GoogleError
+ *
+ * @private
+ *
+ * @param {GoogleErrorBody} err The original error.
+ * @param {GoogleInnerError[]} [errors] Inner errors, if any.
+ * @returns {string}
+ */
+ static createMultiErrorMessage(err: GoogleErrorBody, errors?: GoogleInnerError[]): string;
+}
+/**
+ * Custom error type for partial errors returned from the API.
+ *
+ * @param {object} b - Error object.
+ */
+export declare class PartialFailureError extends Error {
+ errors?: GoogleInnerError[];
+ response?: r.Response;
+ constructor(b: GoogleErrorBody);
+}
+export interface BodyResponseCallback {
+ (err: Error | ApiError | null, body?: ResponseBody, res?: r.Response): void;
+}
+export interface RetryOptions {
+ retryDelayMultiplier?: number;
+ totalTimeout?: number;
+ maxRetryDelay?: number;
+ autoRetry?: boolean;
+ maxRetries?: number;
+ retryableErrorFn?: (err: ApiError) => boolean;
+}
+export interface MakeRequestConfig {
+ /**
+ * Automatically retry requests if the response is related to rate limits or
+ * certain intermittent server errors. We will exponentially backoff
+ * subsequent requests by default. (default: true)
+ */
+ autoRetry?: boolean;
+ /**
+ * Maximum number of automatic retries attempted before returning the error.
+ * (default: 3)
+ */
+ maxRetries?: number;
+ retries?: number;
+ retryOptions?: RetryOptions;
+ stream?: Duplexify;
+ shouldRetryFn?: (response?: r.Response) => boolean;
+}
+export declare class Util {
+ ApiError: typeof ApiError;
+ PartialFailureError: typeof PartialFailureError;
+ /**
+ * No op.
+ *
+ * @example
+ * function doSomething(callback) {
+ * callback = callback || noop;
+ * }
+ */
+ noop(): void;
+ /**
+ * Uniformly process an API response.
+ *
+ * @param {*} err - Error value.
+ * @param {*} resp - Response value.
+ * @param {*} body - Body value.
+ * @param {function} callback - The callback function.
+ */
+ handleResp(err: Error | null, resp?: r.Response | null, body?: ResponseBody, callback?: BodyResponseCallback): void;
+ /**
+ * Sniff an incoming HTTP response message for errors.
+ *
+ * @param {object} httpRespMessage - An incoming HTTP response message from `request`.
+ * @return {object} parsedHttpRespMessage - The parsed response.
+ * @param {?error} parsedHttpRespMessage.err - An error detected.
+ * @param {object} parsedHttpRespMessage.resp - The original response object.
+ */
+ parseHttpRespMessage(httpRespMessage: r.Response): ParsedHttpRespMessage;
+ /**
+ * Parse the response body from an HTTP request.
+ *
+ * @param {object} body - The response body.
+ * @return {object} parsedHttpRespMessage - The parsed response.
+ * @param {?error} parsedHttpRespMessage.err - An error detected.
+ * @param {object} parsedHttpRespMessage.body - The original body value provided
+ * will try to be JSON.parse'd. If it's successful, the parsed value will
+ * be returned here, otherwise the original value and an error will be returned.
+ */
+ parseHttpRespBody(body: ResponseBody): ParsedHttpResponseBody;
+ /**
+ * Take a Duplexify stream, fetch an authenticated connection header, and
+ * create an outgoing writable stream.
+ *
+ * @param {Duplexify} dup - Duplexify stream.
+ * @param {object} options - Configuration object.
+ * @param {module:common/connection} options.connection - A connection instance used to get a token with and send the request through.
+ * @param {object} options.metadata - Metadata to send at the head of the request.
+ * @param {object} options.request - Request object, in the format of a standard Node.js http.request() object.
+ * @param {string=} options.request.method - Default: "POST".
+ * @param {string=} options.request.qs.uploadType - Default: "multipart".
+ * @param {string=} options.streamContentType - Default: "application/octet-stream".
+ * @param {function} onComplete - Callback, executed after the writable Request stream has completed.
+ */
+ makeWritableStream(dup: Duplexify, options: MakeWritableStreamOptions, onComplete?: Function): void;
+ /**
+ * Returns true if the API request should be retried, given the error that was
+ * given the first time the request was attempted. This is used for rate limit
+ * related errors as well as intermittent server errors.
+ *
+ * @param {error} err - The API error to check if it is appropriate to retry.
+ * @return {boolean} True if the API request should be retried, false otherwise.
+ */
+ shouldRetryRequest(err?: ApiError): boolean;
+ /**
+ * Get a function for making authenticated requests.
+ *
+ * @param {object} config - Configuration object.
+ * @param {boolean=} config.autoRetry - Automatically retry requests if the
+ * response is related to rate limits or certain intermittent server
+ * errors. We will exponentially backoff subsequent requests by default.
+ * (default: true)
+ * @param {object=} config.credentials - Credentials object.
+ * @param {boolean=} config.customEndpoint - If true, just return the provided request options. Default: false.
+ * @param {boolean=} config.useAuthWithCustomEndpoint - If true, will authenticate when using a custom endpoint. Default: false.
+ * @param {string=} config.email - Account email address, required for PEM/P12 usage.
+ * @param {number=} config.maxRetries - Maximum number of automatic retries attempted before returning the error. (default: 3)
+ * @param {string=} config.keyFile - Path to a .json, .pem, or .p12 keyfile.
+ * @param {array} config.scopes - Array of scopes required for the API.
+ */
+ makeAuthenticatedRequestFactory(config: MakeAuthenticatedRequestFactoryConfig): MakeAuthenticatedRequest;
+ /**
+ * Make a request through the `retryRequest` module with built-in error
+ * handling and exponential back off.
+ *
+ * @param {object} reqOpts - Request options in the format `request` expects.
+ * @param {object=} config - Configuration object.
+ * @param {boolean=} config.autoRetry - Automatically retry requests if the
+ * response is related to rate limits or certain intermittent server
+ * errors. We will exponentially backoff subsequent requests by default.
+ * (default: true)
+ * @param {number=} config.maxRetries - Maximum number of automatic retries
+ * attempted before returning the error. (default: 3)
+ * @param {object=} config.request - HTTP module for request calls.
+ * @param {function} callback - The callback function.
+ */
+ makeRequest(reqOpts: DecorateRequestOptions, config: MakeRequestConfig, callback: BodyResponseCallback): void | Abortable;
+ /**
+ * Decorate the options about to be made in a request.
+ *
+ * @param {object} reqOpts - The options to be passed to `request`.
+ * @param {string} projectId - The project ID.
+ * @return {object} reqOpts - The decorated reqOpts.
+ */
+ decorateRequest(reqOpts: DecorateRequestOptions, projectId: string): DecorateRequestOptions;
+ isCustomType(unknown: any, module: string): boolean;
+ /**
+ * Given two parameters, figure out if this is either:
+ * - Just a callback function
+ * - An options object, and then a callback function
+ * @param optionsOrCallback An options object or callback.
+ * @param cb A potentially undefined callback.
+ */
+ maybeOptionsOrCallback void>(optionsOrCallback?: T | C, cb?: C): [T, C];
+ _getDefaultHeaders(gcclGcsCmd?: string): {
+ 'User-Agent': string;
+ 'x-goog-api-client': string;
+ };
+}
+declare const util: Util;
+export { util };
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.js b/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.js
new file mode 100644
index 0000000..3a94d3f
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/nodejs-common/util.js
@@ -0,0 +1,701 @@
+"use strict";
+/*!
+ * Copyright 2022 Google LLC. 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.
+ */
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.util = exports.Util = exports.PartialFailureError = exports.ApiError = exports.GCCL_GCS_CMD_KEY = void 0;
+/*!
+ * @module common/util
+ */
+const projectify_1 = require("@google-cloud/projectify");
+const ent = __importStar(require("ent"));
+const google_auth_library_1 = require("google-auth-library");
+const retry_request_1 = __importDefault(require("retry-request"));
+const stream_1 = require("stream");
+const teeny_request_1 = require("teeny-request");
+const uuid = __importStar(require("uuid"));
+const service_js_1 = require("./service.js");
+const util_js_1 = require("../util.js");
+const duplexify_1 = __importDefault(require("duplexify"));
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+const package_json_helper_cjs_1 = require("../package-json-helper.cjs");
+const packageJson = (0, package_json_helper_cjs_1.getPackageJSON)();
+/**
+ * A unique symbol for providing a `gccl-gcs-cmd` value
+ * for the `X-Goog-API-Client` header.
+ *
+ * E.g. the `V` in `X-Goog-API-Client: gccl-gcs-cmd/V`
+ **/
+exports.GCCL_GCS_CMD_KEY = Symbol.for('GCCL_GCS_CMD');
+const requestDefaults = {
+ timeout: 60000,
+ gzip: true,
+ forever: true,
+ pool: {
+ maxSockets: Infinity,
+ },
+};
+/**
+ * Default behavior: Automatically retry retriable server errors.
+ *
+ * @const {boolean}
+ * @private
+ */
+const AUTO_RETRY_DEFAULT = true;
+/**
+ * Default behavior: Only attempt to retry retriable errors 3 times.
+ *
+ * @const {number}
+ * @private
+ */
+const MAX_RETRY_DEFAULT = 3;
+/**
+ * Custom error type for API errors.
+ *
+ * @param {object} errorBody - Error object.
+ */
+class ApiError extends Error {
+ constructor(errorBodyOrMessage) {
+ super();
+ if (typeof errorBodyOrMessage !== 'object') {
+ this.message = errorBodyOrMessage || '';
+ return;
+ }
+ const errorBody = errorBodyOrMessage;
+ this.code = errorBody.code;
+ this.errors = errorBody.errors;
+ this.response = errorBody.response;
+ try {
+ this.errors = JSON.parse(this.response.body).error.errors;
+ }
+ catch (e) {
+ this.errors = errorBody.errors;
+ }
+ this.message = ApiError.createMultiErrorMessage(errorBody, this.errors);
+ Error.captureStackTrace(this);
+ }
+ /**
+ * Pieces together an error message by combining all unique error messages
+ * returned from a single GoogleError
+ *
+ * @private
+ *
+ * @param {GoogleErrorBody} err The original error.
+ * @param {GoogleInnerError[]} [errors] Inner errors, if any.
+ * @returns {string}
+ */
+ static createMultiErrorMessage(err, errors) {
+ const messages = new Set();
+ if (err.message) {
+ messages.add(err.message);
+ }
+ if (errors && errors.length) {
+ errors.forEach(({ message }) => messages.add(message));
+ }
+ else if (err.response && err.response.body) {
+ messages.add(ent.decode(err.response.body.toString()));
+ }
+ else if (!err.message) {
+ messages.add('A failure occurred during this request.');
+ }
+ let messageArr = Array.from(messages);
+ if (messageArr.length > 1) {
+ messageArr = messageArr.map((message, i) => ` ${i + 1}. ${message}`);
+ messageArr.unshift('Multiple errors occurred during the request. Please see the `errors` array for complete details.\n');
+ messageArr.push('\n');
+ }
+ return messageArr.join('\n');
+ }
+}
+exports.ApiError = ApiError;
+/**
+ * Custom error type for partial errors returned from the API.
+ *
+ * @param {object} b - Error object.
+ */
+class PartialFailureError extends Error {
+ constructor(b) {
+ super();
+ const errorObject = b;
+ this.errors = errorObject.errors;
+ this.name = 'PartialFailureError';
+ this.response = errorObject.response;
+ this.message = ApiError.createMultiErrorMessage(errorObject, this.errors);
+ }
+}
+exports.PartialFailureError = PartialFailureError;
+class Util {
+ constructor() {
+ this.ApiError = ApiError;
+ this.PartialFailureError = PartialFailureError;
+ }
+ /**
+ * No op.
+ *
+ * @example
+ * function doSomething(callback) {
+ * callback = callback || noop;
+ * }
+ */
+ noop() { }
+ /**
+ * Uniformly process an API response.
+ *
+ * @param {*} err - Error value.
+ * @param {*} resp - Response value.
+ * @param {*} body - Body value.
+ * @param {function} callback - The callback function.
+ */
+ handleResp(err, resp, body, callback) {
+ callback = callback || util.noop;
+ const parsedResp = {
+ err: err || null,
+ ...(resp && util.parseHttpRespMessage(resp)),
+ ...(body && util.parseHttpRespBody(body)),
+ };
+ // Assign the parsed body to resp.body, even if { json: false } was passed
+ // as a request option.
+ // We assume that nobody uses the previously unparsed value of resp.body.
+ if (!parsedResp.err && resp && typeof parsedResp.body === 'object') {
+ parsedResp.resp.body = parsedResp.body;
+ }
+ if (parsedResp.err && resp) {
+ parsedResp.err.response = resp;
+ }
+ callback(parsedResp.err, parsedResp.body, parsedResp.resp);
+ }
+ /**
+ * Sniff an incoming HTTP response message for errors.
+ *
+ * @param {object} httpRespMessage - An incoming HTTP response message from `request`.
+ * @return {object} parsedHttpRespMessage - The parsed response.
+ * @param {?error} parsedHttpRespMessage.err - An error detected.
+ * @param {object} parsedHttpRespMessage.resp - The original response object.
+ */
+ parseHttpRespMessage(httpRespMessage) {
+ const parsedHttpRespMessage = {
+ resp: httpRespMessage,
+ };
+ if (httpRespMessage.statusCode < 200 || httpRespMessage.statusCode > 299) {
+ // Unknown error. Format according to ApiError standard.
+ parsedHttpRespMessage.err = new ApiError({
+ errors: new Array(),
+ code: httpRespMessage.statusCode,
+ message: httpRespMessage.statusMessage,
+ response: httpRespMessage,
+ });
+ }
+ return parsedHttpRespMessage;
+ }
+ /**
+ * Parse the response body from an HTTP request.
+ *
+ * @param {object} body - The response body.
+ * @return {object} parsedHttpRespMessage - The parsed response.
+ * @param {?error} parsedHttpRespMessage.err - An error detected.
+ * @param {object} parsedHttpRespMessage.body - The original body value provided
+ * will try to be JSON.parse'd. If it's successful, the parsed value will
+ * be returned here, otherwise the original value and an error will be returned.
+ */
+ parseHttpRespBody(body) {
+ const parsedHttpRespBody = {
+ body,
+ };
+ if (typeof body === 'string') {
+ try {
+ parsedHttpRespBody.body = JSON.parse(body);
+ }
+ catch (err) {
+ parsedHttpRespBody.body = body;
+ }
+ }
+ if (parsedHttpRespBody.body && parsedHttpRespBody.body.error) {
+ // Error from JSON API.
+ parsedHttpRespBody.err = new ApiError(parsedHttpRespBody.body.error);
+ }
+ return parsedHttpRespBody;
+ }
+ /**
+ * Take a Duplexify stream, fetch an authenticated connection header, and
+ * create an outgoing writable stream.
+ *
+ * @param {Duplexify} dup - Duplexify stream.
+ * @param {object} options - Configuration object.
+ * @param {module:common/connection} options.connection - A connection instance used to get a token with and send the request through.
+ * @param {object} options.metadata - Metadata to send at the head of the request.
+ * @param {object} options.request - Request object, in the format of a standard Node.js http.request() object.
+ * @param {string=} options.request.method - Default: "POST".
+ * @param {string=} options.request.qs.uploadType - Default: "multipart".
+ * @param {string=} options.streamContentType - Default: "application/octet-stream".
+ * @param {function} onComplete - Callback, executed after the writable Request stream has completed.
+ */
+ makeWritableStream(dup, options, onComplete) {
+ var _a;
+ onComplete = onComplete || util.noop;
+ const writeStream = new ProgressStream();
+ writeStream.on('progress', evt => dup.emit('progress', evt));
+ dup.setWritable(writeStream);
+ const defaultReqOpts = {
+ method: 'POST',
+ qs: {
+ uploadType: 'multipart',
+ },
+ timeout: 0,
+ maxRetries: 0,
+ };
+ const metadata = options.metadata || {};
+ const reqOpts = {
+ ...defaultReqOpts,
+ ...options.request,
+ qs: {
+ ...defaultReqOpts.qs,
+ ...(_a = options.request) === null || _a === void 0 ? void 0 : _a.qs,
+ },
+ multipart: [
+ {
+ 'Content-Type': 'application/json',
+ body: JSON.stringify(metadata),
+ },
+ {
+ 'Content-Type': metadata.contentType || 'application/octet-stream',
+ body: writeStream,
+ },
+ ],
+ };
+ options.makeAuthenticatedRequest(reqOpts, {
+ onAuthenticated(err, authenticatedReqOpts) {
+ if (err) {
+ dup.destroy(err);
+ return;
+ }
+ requestDefaults.headers = util._getDefaultHeaders(reqOpts[exports.GCCL_GCS_CMD_KEY]);
+ const request = teeny_request_1.teenyRequest.defaults(requestDefaults);
+ request(authenticatedReqOpts, (err, resp, body) => {
+ util.handleResp(err, resp, body, (err, data) => {
+ if (err) {
+ dup.destroy(err);
+ return;
+ }
+ dup.emit('response', resp);
+ onComplete(data);
+ });
+ });
+ },
+ });
+ }
+ /**
+ * Returns true if the API request should be retried, given the error that was
+ * given the first time the request was attempted. This is used for rate limit
+ * related errors as well as intermittent server errors.
+ *
+ * @param {error} err - The API error to check if it is appropriate to retry.
+ * @return {boolean} True if the API request should be retried, false otherwise.
+ */
+ shouldRetryRequest(err) {
+ if (err) {
+ if ([408, 429, 500, 502, 503, 504].indexOf(err.code) !== -1) {
+ return true;
+ }
+ if (err.errors) {
+ for (const e of err.errors) {
+ const reason = e.reason;
+ if (reason === 'rateLimitExceeded') {
+ return true;
+ }
+ if (reason === 'userRateLimitExceeded') {
+ return true;
+ }
+ if (reason && reason.includes('EAI_AGAIN')) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+ /**
+ * Get a function for making authenticated requests.
+ *
+ * @param {object} config - Configuration object.
+ * @param {boolean=} config.autoRetry - Automatically retry requests if the
+ * response is related to rate limits or certain intermittent server
+ * errors. We will exponentially backoff subsequent requests by default.
+ * (default: true)
+ * @param {object=} config.credentials - Credentials object.
+ * @param {boolean=} config.customEndpoint - If true, just return the provided request options. Default: false.
+ * @param {boolean=} config.useAuthWithCustomEndpoint - If true, will authenticate when using a custom endpoint. Default: false.
+ * @param {string=} config.email - Account email address, required for PEM/P12 usage.
+ * @param {number=} config.maxRetries - Maximum number of automatic retries attempted before returning the error. (default: 3)
+ * @param {string=} config.keyFile - Path to a .json, .pem, or .p12 keyfile.
+ * @param {array} config.scopes - Array of scopes required for the API.
+ */
+ makeAuthenticatedRequestFactory(config) {
+ const googleAutoAuthConfig = { ...config };
+ if (googleAutoAuthConfig.projectId === service_js_1.DEFAULT_PROJECT_ID_TOKEN) {
+ delete googleAutoAuthConfig.projectId;
+ }
+ let authClient;
+ if (googleAutoAuthConfig.authClient instanceof google_auth_library_1.GoogleAuth) {
+ // Use an existing `GoogleAuth`
+ authClient = googleAutoAuthConfig.authClient;
+ }
+ else {
+ // Pass an `AuthClient` & `clientOptions` to `GoogleAuth`, if available
+ authClient = new google_auth_library_1.GoogleAuth({
+ ...googleAutoAuthConfig,
+ authClient: googleAutoAuthConfig.authClient,
+ clientOptions: googleAutoAuthConfig.clientOptions,
+ });
+ }
+ function makeAuthenticatedRequest(reqOpts, optionsOrCallback) {
+ let stream;
+ let projectId;
+ const reqConfig = { ...config };
+ let activeRequest_;
+ if (!optionsOrCallback) {
+ stream = (0, duplexify_1.default)();
+ reqConfig.stream = stream;
+ }
+ const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : undefined;
+ const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : undefined;
+ async function setProjectId() {
+ projectId = await authClient.getProjectId();
+ }
+ const onAuthenticated = async (err, authenticatedReqOpts) => {
+ const authLibraryError = err;
+ const autoAuthFailed = err &&
+ typeof err.message === 'string' &&
+ err.message.indexOf('Could not load the default credentials') > -1;
+ if (autoAuthFailed) {
+ // Even though authentication failed, the API might not actually
+ // care.
+ authenticatedReqOpts = reqOpts;
+ }
+ if (!err || autoAuthFailed) {
+ try {
+ // Try with existing `projectId` value
+ authenticatedReqOpts = util.decorateRequest(authenticatedReqOpts, projectId);
+ err = null;
+ }
+ catch (e) {
+ if (e instanceof projectify_1.MissingProjectIdError) {
+ // A `projectId` was required, but we don't have one.
+ try {
+ // Attempt to get the `projectId`
+ await setProjectId();
+ authenticatedReqOpts = util.decorateRequest(authenticatedReqOpts, projectId);
+ err = null;
+ }
+ catch (e) {
+ // Re-use the "Could not load the default credentials error" if
+ // auto auth failed.
+ err = err || e;
+ }
+ }
+ else {
+ // Some other error unrelated to missing `projectId`
+ err = err || e;
+ }
+ }
+ }
+ if (err) {
+ if (stream) {
+ stream.destroy(err);
+ }
+ else {
+ const fn = options && options.onAuthenticated
+ ? options.onAuthenticated
+ : callback;
+ fn(err);
+ }
+ return;
+ }
+ if (options && options.onAuthenticated) {
+ options.onAuthenticated(null, authenticatedReqOpts);
+ }
+ else {
+ activeRequest_ = util.makeRequest(authenticatedReqOpts, reqConfig, (apiResponseError, ...params) => {
+ if (apiResponseError &&
+ apiResponseError.code === 401 &&
+ authLibraryError) {
+ // Re-use the "Could not load the default credentials error" if
+ // the API request failed due to missing credentials.
+ apiResponseError = authLibraryError;
+ }
+ callback(apiResponseError, ...params);
+ });
+ }
+ };
+ const prepareRequest = async () => {
+ try {
+ const getProjectId = async () => {
+ if (config.projectId &&
+ config.projectId !== service_js_1.DEFAULT_PROJECT_ID_TOKEN) {
+ // The user provided a project ID. We don't need to check with the
+ // auth client, it could be incorrect.
+ return config.projectId;
+ }
+ if (config.projectIdRequired === false) {
+ // A projectId is not required. Return the default.
+ return service_js_1.DEFAULT_PROJECT_ID_TOKEN;
+ }
+ return setProjectId();
+ };
+ const authorizeRequest = async () => {
+ if (reqConfig.customEndpoint &&
+ !reqConfig.useAuthWithCustomEndpoint) {
+ // Using a custom API override. Do not use `google-auth-library` for
+ // authentication. (ex: connecting to a local Datastore server)
+ return reqOpts;
+ }
+ else {
+ return authClient.authorizeRequest(reqOpts);
+ }
+ };
+ const [_projectId, authorizedReqOpts] = await Promise.all([
+ getProjectId(),
+ authorizeRequest(),
+ ]);
+ if (_projectId) {
+ projectId = _projectId;
+ }
+ return onAuthenticated(null, authorizedReqOpts);
+ }
+ catch (e) {
+ return onAuthenticated(e);
+ }
+ };
+ prepareRequest();
+ if (stream) {
+ return stream;
+ }
+ return {
+ abort() {
+ setImmediate(() => {
+ if (activeRequest_) {
+ activeRequest_.abort();
+ activeRequest_ = null;
+ }
+ });
+ },
+ };
+ }
+ const mar = makeAuthenticatedRequest;
+ mar.getCredentials = authClient.getCredentials.bind(authClient);
+ mar.authClient = authClient;
+ return mar;
+ }
+ /**
+ * Make a request through the `retryRequest` module with built-in error
+ * handling and exponential back off.
+ *
+ * @param {object} reqOpts - Request options in the format `request` expects.
+ * @param {object=} config - Configuration object.
+ * @param {boolean=} config.autoRetry - Automatically retry requests if the
+ * response is related to rate limits or certain intermittent server
+ * errors. We will exponentially backoff subsequent requests by default.
+ * (default: true)
+ * @param {number=} config.maxRetries - Maximum number of automatic retries
+ * attempted before returning the error. (default: 3)
+ * @param {object=} config.request - HTTP module for request calls.
+ * @param {function} callback - The callback function.
+ */
+ makeRequest(reqOpts, config, callback) {
+ var _a, _b, _c, _d, _e;
+ let autoRetryValue = AUTO_RETRY_DEFAULT;
+ if (config.autoRetry !== undefined) {
+ autoRetryValue = config.autoRetry;
+ }
+ else if (((_a = config.retryOptions) === null || _a === void 0 ? void 0 : _a.autoRetry) !== undefined) {
+ autoRetryValue = config.retryOptions.autoRetry;
+ }
+ let maxRetryValue = MAX_RETRY_DEFAULT;
+ if (config.maxRetries !== undefined) {
+ maxRetryValue = config.maxRetries;
+ }
+ else if (((_b = config.retryOptions) === null || _b === void 0 ? void 0 : _b.maxRetries) !== undefined) {
+ maxRetryValue = config.retryOptions.maxRetries;
+ }
+ requestDefaults.headers = this._getDefaultHeaders(reqOpts[exports.GCCL_GCS_CMD_KEY]);
+ const options = {
+ request: teeny_request_1.teenyRequest.defaults(requestDefaults),
+ retries: autoRetryValue !== false ? maxRetryValue : 0,
+ noResponseRetries: autoRetryValue !== false ? maxRetryValue : 0,
+ shouldRetryFn(httpRespMessage) {
+ var _a, _b;
+ const err = util.parseHttpRespMessage(httpRespMessage).err;
+ if ((_a = config.retryOptions) === null || _a === void 0 ? void 0 : _a.retryableErrorFn) {
+ return err && ((_b = config.retryOptions) === null || _b === void 0 ? void 0 : _b.retryableErrorFn(err));
+ }
+ return err && util.shouldRetryRequest(err);
+ },
+ maxRetryDelay: (_c = config.retryOptions) === null || _c === void 0 ? void 0 : _c.maxRetryDelay,
+ retryDelayMultiplier: (_d = config.retryOptions) === null || _d === void 0 ? void 0 : _d.retryDelayMultiplier,
+ totalTimeout: (_e = config.retryOptions) === null || _e === void 0 ? void 0 : _e.totalTimeout,
+ };
+ if (typeof reqOpts.maxRetries === 'number') {
+ options.retries = reqOpts.maxRetries;
+ options.noResponseRetries = reqOpts.maxRetries;
+ }
+ if (!config.stream) {
+ return (0, retry_request_1.default)(reqOpts, options,
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ (err, response, body) => {
+ util.handleResp(err, response, body, callback);
+ });
+ }
+ const dup = config.stream;
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ let requestStream;
+ const isGetRequest = (reqOpts.method || 'GET').toUpperCase() === 'GET';
+ if (isGetRequest) {
+ requestStream = (0, retry_request_1.default)(reqOpts, options);
+ dup.setReadable(requestStream);
+ }
+ else {
+ // Streaming writable HTTP requests cannot be retried.
+ requestStream = options.request(reqOpts);
+ dup.setWritable(requestStream);
+ }
+ // Replay the Request events back to the stream.
+ requestStream
+ .on('error', dup.destroy.bind(dup))
+ .on('response', dup.emit.bind(dup, 'response'))
+ .on('complete', dup.emit.bind(dup, 'complete'));
+ dup.abort = requestStream.abort;
+ return dup;
+ }
+ /**
+ * Decorate the options about to be made in a request.
+ *
+ * @param {object} reqOpts - The options to be passed to `request`.
+ * @param {string} projectId - The project ID.
+ * @return {object} reqOpts - The decorated reqOpts.
+ */
+ decorateRequest(reqOpts, projectId) {
+ delete reqOpts.autoPaginate;
+ delete reqOpts.autoPaginateVal;
+ delete reqOpts.objectMode;
+ if (reqOpts.qs !== null && typeof reqOpts.qs === 'object') {
+ delete reqOpts.qs.autoPaginate;
+ delete reqOpts.qs.autoPaginateVal;
+ reqOpts.qs = (0, projectify_1.replaceProjectIdToken)(reqOpts.qs, projectId);
+ }
+ if (Array.isArray(reqOpts.multipart)) {
+ reqOpts.multipart = reqOpts.multipart.map(part => {
+ return (0, projectify_1.replaceProjectIdToken)(part, projectId);
+ });
+ }
+ if (reqOpts.json !== null && typeof reqOpts.json === 'object') {
+ delete reqOpts.json.autoPaginate;
+ delete reqOpts.json.autoPaginateVal;
+ reqOpts.json = (0, projectify_1.replaceProjectIdToken)(reqOpts.json, projectId);
+ }
+ reqOpts.uri = (0, projectify_1.replaceProjectIdToken)(reqOpts.uri, projectId);
+ return reqOpts;
+ }
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ isCustomType(unknown, module) {
+ function getConstructorName(obj) {
+ return obj.constructor && obj.constructor.name.toLowerCase();
+ }
+ const moduleNameParts = module.split('/');
+ const parentModuleName = moduleNameParts[0] && moduleNameParts[0].toLowerCase();
+ const subModuleName = moduleNameParts[1] && moduleNameParts[1].toLowerCase();
+ if (subModuleName && getConstructorName(unknown) !== subModuleName) {
+ return false;
+ }
+ let walkingModule = unknown;
+ // eslint-disable-next-line no-constant-condition
+ while (true) {
+ if (getConstructorName(walkingModule) === parentModuleName) {
+ return true;
+ }
+ walkingModule = walkingModule.parent;
+ if (!walkingModule) {
+ return false;
+ }
+ }
+ }
+ /**
+ * Given two parameters, figure out if this is either:
+ * - Just a callback function
+ * - An options object, and then a callback function
+ * @param optionsOrCallback An options object or callback.
+ * @param cb A potentially undefined callback.
+ */
+ maybeOptionsOrCallback(optionsOrCallback, cb) {
+ return typeof optionsOrCallback === 'function'
+ ? [{}, optionsOrCallback]
+ : [optionsOrCallback, cb];
+ }
+ _getDefaultHeaders(gcclGcsCmd) {
+ const headers = {
+ 'User-Agent': (0, util_js_1.getUserAgentString)(),
+ 'x-goog-api-client': `${(0, util_js_1.getRuntimeTrackingString)()} gccl/${packageJson.version}-${(0, util_js_1.getModuleFormat)()} gccl-invocation-id/${uuid.v4()}`,
+ };
+ if (gcclGcsCmd) {
+ headers['x-goog-api-client'] += ` gccl-gcs-cmd/${gcclGcsCmd}`;
+ }
+ return headers;
+ }
+}
+exports.Util = Util;
+/**
+ * Basic Passthrough Stream that records the number of bytes read
+ * every time the cursor is moved.
+ */
+class ProgressStream extends stream_1.Transform {
+ constructor() {
+ super(...arguments);
+ this.bytesRead = 0;
+ }
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ _transform(chunk, encoding, callback) {
+ this.bytesRead += chunk.length;
+ this.emit('progress', { bytesWritten: this.bytesRead, contentLength: '*' });
+ this.push(chunk);
+ callback();
+ }
+}
+const util = new Util();
+exports.util = util;
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/notification.d.ts b/node_modules/@google-cloud/storage/build/cjs/src/notification.d.ts
new file mode 100644
index 0000000..0d3341a
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/notification.d.ts
@@ -0,0 +1,106 @@
+import { BaseMetadata, ServiceObject } from './nodejs-common/index.js';
+import { ResponseBody } from './nodejs-common/util.js';
+import { Bucket } from './bucket.js';
+export interface DeleteNotificationOptions {
+ userProject?: string;
+}
+export interface GetNotificationMetadataOptions {
+ userProject?: string;
+}
+/**
+ * @typedef {array} GetNotificationMetadataResponse
+ * @property {object} 0 The notification metadata.
+ * @property {object} 1 The full API response.
+ */
+export type GetNotificationMetadataResponse = [ResponseBody, unknown];
+/**
+ * @callback GetNotificationMetadataCallback
+ * @param {?Error} err Request error, if any.
+ * @param {object} files The notification metadata.
+ * @param {object} apiResponse The full API response.
+ */
+export interface GetNotificationMetadataCallback {
+ (err: Error | null, metadata?: ResponseBody, apiResponse?: unknown): void;
+}
+/**
+ * @typedef {array} GetNotificationResponse
+ * @property {Notification} 0 The {@link Notification}
+ * @property {object} 1 The full API response.
+ */
+export type GetNotificationResponse = [Notification, unknown];
+export interface GetNotificationOptions {
+ /**
+ * Automatically create the object if it does not exist. Default: `false`.
+ */
+ autoCreate?: boolean;
+ /**
+ * The ID of the project which will be billed for the request.
+ */
+ userProject?: string;
+}
+/**
+ * @callback GetNotificationCallback
+ * @param {?Error} err Request error, if any.
+ * @param {Notification} notification The {@link Notification}.
+ * @param {object} apiResponse The full API response.
+ */
+export interface GetNotificationCallback {
+ (err: Error | null, notification?: Notification | null, apiResponse?: unknown): void;
+}
+/**
+ * @callback DeleteNotificationCallback
+ * @param {?Error} err Request error, if any.
+ * @param {object} apiResponse The full API response.
+ */
+export interface DeleteNotificationCallback {
+ (err: Error | null, apiResponse?: unknown): void;
+}
+export interface NotificationMetadata extends BaseMetadata {
+ custom_attributes?: {
+ [key: string]: string;
+ };
+ event_types?: string[];
+ object_name_prefix?: string;
+ payload_format?: 'JSON_API_V1' | 'NONE';
+ topic?: string;
+}
+/**
+ * The API-formatted resource description of the notification.
+ *
+ * Note: This is not guaranteed to be up-to-date when accessed. To get the
+ * latest record, call the `getMetadata()` method.
+ *
+ * @name Notification#metadata
+ * @type {object}
+ */
+/**
+ * A Notification object is created from your {@link Bucket} object using
+ * {@link Bucket#notification}. Use it to interact with Cloud Pub/Sub
+ * notifications.
+ *
+ * See {@link https://cloud.google.com/storage/docs/pubsub-notifications| Cloud Pub/Sub Notifications for Google Cloud Storage}
+ *
+ * @class
+ * @hideconstructor
+ *
+ * @param {Bucket} bucket The bucket instance this notification is attached to.
+ * @param {string} id The ID of the notification.
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const notification = myBucket.notification('1');
+ * ```
+ */
+declare class Notification extends ServiceObject {
+ constructor(bucket: Bucket, id: string);
+}
+/**
+ * Reference to the {@link Notification} class.
+ * @name module:@google-cloud/storage.Notification
+ * @see Notification
+ */
+export { Notification };
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/notification.js b/node_modules/@google-cloud/storage/build/cjs/src/notification.js
new file mode 100644
index 0000000..6bf57a3
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/notification.js
@@ -0,0 +1,265 @@
+"use strict";
+// Copyright 2019 Google LLC
+//
+// 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.Notification = void 0;
+const index_js_1 = require("./nodejs-common/index.js");
+const promisify_1 = require("@google-cloud/promisify");
+/**
+ * The API-formatted resource description of the notification.
+ *
+ * Note: This is not guaranteed to be up-to-date when accessed. To get the
+ * latest record, call the `getMetadata()` method.
+ *
+ * @name Notification#metadata
+ * @type {object}
+ */
+/**
+ * A Notification object is created from your {@link Bucket} object using
+ * {@link Bucket#notification}. Use it to interact with Cloud Pub/Sub
+ * notifications.
+ *
+ * See {@link https://cloud.google.com/storage/docs/pubsub-notifications| Cloud Pub/Sub Notifications for Google Cloud Storage}
+ *
+ * @class
+ * @hideconstructor
+ *
+ * @param {Bucket} bucket The bucket instance this notification is attached to.
+ * @param {string} id The ID of the notification.
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ *
+ * const notification = myBucket.notification('1');
+ * ```
+ */
+class Notification extends index_js_1.ServiceObject {
+ constructor(bucket, id) {
+ const requestQueryObject = {};
+ const methods = {
+ /**
+ * Creates a notification subscription for the bucket.
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/notifications/insert| Notifications: insert}
+ * @method Notification#create
+ *
+ * @param {Topic|string} topic The Cloud PubSub topic to which this
+ * subscription publishes. If the project ID is omitted, the current
+ * project ID will be used.
+ *
+ * Acceptable formats are:
+ * - `projects/grape-spaceship-123/topics/my-topic`
+ *
+ * - `my-topic`
+ * @param {CreateNotificationRequest} [options] Metadata to set for
+ * the notification.
+ * @param {CreateNotificationCallback} [callback] Callback function.
+ * @returns {Promise}
+ * @throws {Error} If a valid topic is not provided.
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ * const notification = myBucket.notification('1');
+ *
+ * notification.create(function(err, notification, apiResponse) {
+ * if (!err) {
+ * // The notification was created successfully.
+ * }
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * notification.create().then(function(data) {
+ * const notification = data[0];
+ * const apiResponse = data[1];
+ * });
+ * ```
+ */
+ create: true,
+ /**
+ * @typedef {array} DeleteNotificationResponse
+ * @property {object} 0 The full API response.
+ */
+ /**
+ * Permanently deletes a notification subscription.
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/notifications/delete| Notifications: delete API Documentation}
+ *
+ * @param {object} [options] Configuration options.
+ * @param {string} [options.userProject] The ID of the project which will be
+ * billed for the request.
+ * @param {DeleteNotificationCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ * const notification = myBucket.notification('1');
+ *
+ * notification.delete(function(err, apiResponse) {});
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * notification.delete().then(function(data) {
+ * const apiResponse = data[0];
+ * });
+ *
+ * ```
+ * @example include:samples/deleteNotification.js
+ * region_tag:storage_delete_bucket_notification
+ * Another example:
+ */
+ delete: {
+ reqOpts: {
+ qs: requestQueryObject,
+ },
+ },
+ /**
+ * Get a notification and its metadata if it exists.
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/notifications/get| Notifications: get API Documentation}
+ *
+ * @param {object} [options] Configuration options.
+ * See {@link Bucket#createNotification} for create options.
+ * @param {boolean} [options.autoCreate] Automatically create the object if
+ * it does not exist. Default: `false`.
+ * @param {string} [options.userProject] The ID of the project which will be
+ * billed for the request.
+ * @param {GetNotificationCallback} [callback] Callback function.
+ * @return {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ * const notification = myBucket.notification('1');
+ *
+ * notification.get(function(err, notification, apiResponse) {
+ * // `notification.metadata` has been populated.
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * notification.get().then(function(data) {
+ * const notification = data[0];
+ * const apiResponse = data[1];
+ * });
+ * ```
+ */
+ get: {
+ reqOpts: {
+ qs: requestQueryObject,
+ },
+ },
+ /**
+ * Get the notification's metadata.
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/notifications/get| Notifications: get API Documentation}
+ *
+ * @param {object} [options] Configuration options.
+ * @param {string} [options.userProject] The ID of the project which will be
+ * billed for the request.
+ * @param {GetNotificationMetadataCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ * const notification = myBucket.notification('1');
+ *
+ * notification.getMetadata(function(err, metadata, apiResponse) {});
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * notification.getMetadata().then(function(data) {
+ * const metadata = data[0];
+ * const apiResponse = data[1];
+ * });
+ *
+ * ```
+ * @example include:samples/getMetadataNotifications.js
+ * region_tag:storage_print_pubsub_bucket_notification
+ * Another example:
+ */
+ getMetadata: {
+ reqOpts: {
+ qs: requestQueryObject,
+ },
+ },
+ /**
+ * @typedef {array} NotificationExistsResponse
+ * @property {boolean} 0 Whether the notification exists or not.
+ */
+ /**
+ * @callback NotificationExistsCallback
+ * @param {?Error} err Request error, if any.
+ * @param {boolean} exists Whether the notification exists or not.
+ */
+ /**
+ * Check if the notification exists.
+ *
+ * @method Notification#exists
+ * @param {NotificationExistsCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const myBucket = storage.bucket('my-bucket');
+ * const notification = myBucket.notification('1');
+ *
+ * notification.exists(function(err, exists) {});
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * notification.exists().then(function(data) {
+ * const exists = data[0];
+ * });
+ * ```
+ */
+ exists: true,
+ };
+ super({
+ parent: bucket,
+ baseUrl: '/notificationConfigs',
+ id: id.toString(),
+ createMethod: bucket.createNotification.bind(bucket),
+ methods,
+ });
+ }
+}
+exports.Notification = Notification;
+/*! Developer Documentation
+ *
+ * All async methods (except for streams) will return a Promise in the event
+ * that a callback is omitted.
+ */
+(0, promisify_1.promisifyAll)(Notification);
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/package-json-helper.cjs b/node_modules/@google-cloud/storage/build/cjs/src/package-json-helper.cjs
new file mode 100644
index 0000000..794923b
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/package-json-helper.cjs
@@ -0,0 +1,21 @@
+// Copyright 2023 Google LLC
+//
+// 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.
+
+/* eslint-disable node/no-missing-require */
+
+function getPackageJSON() {
+ return require('../../../package.json');
+}
+
+exports.getPackageJSON = getPackageJSON;
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/resumable-upload.d.ts b/node_modules/@google-cloud/storage/build/cjs/src/resumable-upload.d.ts
new file mode 100644
index 0000000..d88fe04
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/resumable-upload.d.ts
@@ -0,0 +1,339 @@
+///
+///
+import { GaxiosOptions, GaxiosPromise, GaxiosResponse } from 'gaxios';
+import { GoogleAuthOptions } from 'google-auth-library';
+import { Writable, WritableOptions } from 'stream';
+import { RetryOptions, PreconditionOptions } from './storage.js';
+import { GCCL_GCS_CMD_KEY } from './nodejs-common/util.js';
+import { FileMetadata } from './file.js';
+export declare const PROTOCOL_REGEX: RegExp;
+export interface ErrorWithCode extends Error {
+ code: number;
+ status?: number | string;
+}
+export type CreateUriCallback = (err: Error | null, uri?: string) => void;
+export interface Encryption {
+ key: {};
+ hash: {};
+}
+export type PredefinedAcl = 'authenticatedRead' | 'bucketOwnerFullControl' | 'bucketOwnerRead' | 'private' | 'projectPrivate' | 'publicRead';
+export interface QueryParameters extends PreconditionOptions {
+ contentEncoding?: string;
+ kmsKeyName?: string;
+ predefinedAcl?: PredefinedAcl;
+ projection?: 'full' | 'noAcl';
+ userProject?: string;
+}
+export interface UploadConfig extends Pick {
+ /**
+ * The API endpoint used for the request.
+ * Defaults to `storage.googleapis.com`.
+ *
+ * **Warning**:
+ * If this value does not match the current GCP universe an emulator context
+ * will be assumed and authentication will be bypassed.
+ */
+ apiEndpoint?: string;
+ /**
+ * The name of the destination bucket.
+ */
+ bucket: string;
+ /**
+ * The name of the destination file.
+ */
+ file: string;
+ /**
+ * The GoogleAuthOptions passed to google-auth-library
+ */
+ authConfig?: GoogleAuthOptions;
+ /**
+ * If you want to re-use an auth client from google-auto-auth, pass an
+ * instance here.
+ * Defaults to GoogleAuth and gets automatically overridden if an
+ * emulator context is detected.
+ */
+ authClient?: {
+ request: (opts: GaxiosOptions) => Promise> | GaxiosPromise;
+ };
+ /**
+ * Create a separate request per chunk.
+ *
+ * This value is in bytes and should be a multiple of 256 KiB (2^18).
+ * We recommend using at least 8 MiB for the chunk size.
+ *
+ * @link https://cloud.google.com/storage/docs/performing-resumable-uploads#chunked-upload
+ */
+ chunkSize?: number;
+ /**
+ * For each API request we send, you may specify custom request options that
+ * we'll add onto the request. The request options follow the gaxios API:
+ * https://github.com/googleapis/gaxios#request-options.
+ */
+ customRequestOptions?: GaxiosOptions;
+ /**
+ * This will cause the upload to fail if the current generation of the remote
+ * object does not match the one provided here.
+ */
+ generation?: number;
+ /**
+ * Set to `true` if the upload is only a subset of the overall object to upload.
+ * This can be used when planning to continue the upload an object in another
+ * session.
+ *
+ * **Must be used with {@link UploadConfig.chunkSize} != `0`**.
+ *
+ * If this is a continuation of a previous upload, {@link UploadConfig.offset}
+ * should be set.
+ *
+ * @see {@link checkUploadStatus} for checking the status of an existing upload.
+ */
+ isPartialUpload?: boolean;
+ /**
+ * A customer-supplied encryption key. See
+ * https://cloud.google.com/storage/docs/encryption#customer-supplied.
+ */
+ key?: string | Buffer;
+ /**
+ * Resource name of the Cloud KMS key, of the form
+ * `projects/my-project/locations/global/keyRings/my-kr/cryptoKeys/my-key`,
+ * that will be used to encrypt the object. Overrides the object metadata's
+ * `kms_key_name` value, if any.
+ */
+ kmsKeyName?: string;
+ /**
+ * Any metadata you wish to set on the object.
+ */
+ metadata?: ConfigMetadata;
+ /**
+ * The starting byte in relation to the final uploaded object.
+ * **Must be used with {@link UploadConfig.uri}**.
+ *
+ * If resuming an interrupted stream, do not supply this argument unless you
+ * know the exact number of bytes the service has AND the provided stream's
+ * first byte is a continuation from that provided offset. If resuming an
+ * interrupted stream and this option has not been provided, we will treat
+ * the provided upload stream as the object to upload - where the first byte
+ * of the upload stream is the first byte of the object to upload; skipping
+ * any bytes that are already present on the server.
+ *
+ * @see {@link checkUploadStatus} for checking the status of an existing upload.
+ * @see {@link https://cloud.google.com/storage/docs/json_api/v1/how-tos/resumable-upload#resume-upload.}
+ */
+ offset?: number;
+ /**
+ * Set an Origin header when creating the resumable upload URI.
+ */
+ origin?: string;
+ /**
+ * Specify query parameters that go along with the initial upload request. See
+ * https://cloud.google.com/storage/docs/json_api/v1/objects/insert#parameters
+ */
+ params?: QueryParameters;
+ /**
+ * Apply a predefined set of access controls to the created file.
+ */
+ predefinedAcl?: PredefinedAcl;
+ /**
+ * Make the uploaded file private. (Alias for config.predefinedAcl =
+ * 'private')
+ */
+ private?: boolean;
+ /**
+ * Make the uploaded file public. (Alias for config.predefinedAcl =
+ * 'publicRead')
+ */
+ public?: boolean;
+ /**
+ * The service domain for a given Cloud universe.
+ */
+ universeDomain?: string;
+ /**
+ * If you already have a resumable URI from a previously-created resumable
+ * upload, just pass it in here and we'll use that.
+ *
+ * If resuming an interrupted stream and the {@link UploadConfig.offset}
+ * option has not been provided, we will treat the provided upload stream as
+ * the object to upload - where the first byte of the upload stream is the
+ * first byte of the object to upload; skipping any bytes that are already
+ * present on the server.
+ *
+ * @see {@link checkUploadStatus} for checking the status of an existing upload.
+ */
+ uri?: string;
+ /**
+ * If the bucket being accessed has requesterPays functionality enabled, this
+ * can be set to control which project is billed for the access of this file.
+ */
+ userProject?: string;
+ /**
+ * Configuration options for retrying retryable errors.
+ */
+ retryOptions: RetryOptions;
+ [GCCL_GCS_CMD_KEY]?: string;
+}
+export interface ConfigMetadata {
+ [key: string]: any;
+ /**
+ * Set the length of the object being uploaded. If uploading a partial
+ * object, this is the overall size of the finalized object.
+ */
+ contentLength?: number;
+ /**
+ * Set the content type of the incoming data.
+ */
+ contentType?: string;
+}
+export interface GoogleInnerError {
+ reason?: string;
+}
+export interface ApiError extends Error {
+ code?: number;
+ errors?: GoogleInnerError[];
+}
+export interface CheckUploadStatusConfig {
+ /**
+ * Set to `false` to disable retries within this method.
+ *
+ * @defaultValue `true`
+ */
+ retry?: boolean;
+}
+export declare class Upload extends Writable {
+ #private;
+ bucket: string;
+ file: string;
+ apiEndpoint: string;
+ baseURI: string;
+ authConfig?: {
+ scopes?: string[];
+ };
+ authClient: {
+ request: (opts: GaxiosOptions) => Promise> | GaxiosPromise;
+ };
+ cacheKey: string;
+ chunkSize?: number;
+ customRequestOptions: GaxiosOptions;
+ generation?: number;
+ key?: string | Buffer;
+ kmsKeyName?: string;
+ metadata: ConfigMetadata;
+ offset?: number;
+ origin?: string;
+ params: QueryParameters;
+ predefinedAcl?: PredefinedAcl;
+ private?: boolean;
+ public?: boolean;
+ uri?: string;
+ userProject?: string;
+ encryption?: Encryption;
+ uriProvidedManually: boolean;
+ numBytesWritten: number;
+ numRetries: number;
+ contentLength: number | '*';
+ retryOptions: RetryOptions;
+ timeOfFirstRequest: number;
+ isPartialUpload: boolean;
+ private currentInvocationId;
+ /**
+ * A cache of buffers written to this instance, ready for consuming
+ */
+ private writeBuffers;
+ private numChunksReadInRequest;
+ /**
+ * An array of buffers used for caching the most recent upload chunk.
+ * We should not assume that the server received all bytes sent in the request.
+ * - https://cloud.google.com/storage/docs/performing-resumable-uploads#chunked-upload
+ */
+ private localWriteCache;
+ private localWriteCacheByteLength;
+ private upstreamEnded;
+ constructor(cfg: UploadConfig);
+ /**
+ * Prevent 'finish' event until the upload has succeeded.
+ *
+ * @param fireFinishEvent The finish callback
+ */
+ _final(fireFinishEvent?: () => void): void;
+ /**
+ * Handles incoming data from upstream
+ *
+ * @param chunk The chunk to append to the buffer
+ * @param encoding The encoding of the chunk
+ * @param readCallback A callback for when the buffer has been read downstream
+ */
+ _write(chunk: Buffer | string, encoding: BufferEncoding, readCallback?: () => void): void;
+ /**
+ * Prepends the local buffer to write buffer and resets it.
+ *
+ * @param keepLastBytes number of bytes to keep from the end of the local buffer.
+ */
+ private prependLocalBufferToUpstream;
+ /**
+ * Retrieves data from upstream's buffer.
+ *
+ * @param limit The maximum amount to return from the buffer.
+ */
+ private pullFromChunkBuffer;
+ /**
+ * A handler for determining if data is ready to be read from upstream.
+ *
+ * @returns If there will be more chunks to read in the future
+ */
+ private waitForNextChunk;
+ /**
+ * Reads data from upstream up to the provided `limit`.
+ * Ends when the limit has reached or no data is expected to be pushed from upstream.
+ *
+ * @param limit The most amount of data this iterator should return. `Infinity` by default.
+ */
+ private upstreamIterator;
+ createURI(): Promise;
+ createURI(callback: CreateUriCallback): void;
+ protected createURIAsync(): Promise;
+ private continueUploading;
+ startUploading(): Promise;
+ private responseHandler;
+ /**
+ * Check the status of an existing resumable upload.
+ *
+ * @param cfg A configuration to use. `uri` is required.
+ * @returns the current upload status
+ */
+ checkUploadStatus(config?: CheckUploadStatusConfig): Promise>;
+ private getAndSetOffset;
+ private makeRequest;
+ private makeRequestStream;
+ /**
+ * @return {bool} is the request good?
+ */
+ private onResponse;
+ /**
+ * @param resp GaxiosResponse object from previous attempt
+ */
+ private attemptDelayedRetry;
+ /**
+ * The amount of time to wait before retrying the request, in milliseconds.
+ * If negative, do not retry.
+ *
+ * @returns the amount of time to wait, in milliseconds.
+ */
+ private getRetryDelay;
+ private sanitizeEndpoint;
+ /**
+ * Check if a given status code is 2xx
+ *
+ * @param status The status code to check
+ * @returns if the status is 2xx
+ */
+ isSuccessfulResponse(status: number): boolean;
+}
+export declare function upload(cfg: UploadConfig): Upload;
+export declare function createURI(cfg: UploadConfig): Promise;
+export declare function createURI(cfg: UploadConfig, callback: CreateUriCallback): void;
+/**
+ * Check the status of an existing resumable upload.
+ *
+ * @param cfg A configuration to use. `uri` is required.
+ * @returns the current upload status
+ */
+export declare function checkUploadStatus(cfg: UploadConfig & Required>): Promise>;
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/resumable-upload.js b/node_modules/@google-cloud/storage/build/cjs/src/resumable-upload.js
new file mode 100644
index 0000000..c1aa07f
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/resumable-upload.js
@@ -0,0 +1,886 @@
+"use strict";
+// Copyright 2022 Google LLC
+//
+// 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.
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
+ if (kind === "m") throw new TypeError("Private method is not writable");
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
+};
+var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+var _Upload_instances, _Upload_gcclGcsCmd, _Upload_resetLocalBuffersCache, _Upload_addLocalBufferCache;
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.checkUploadStatus = exports.createURI = exports.upload = exports.Upload = exports.PROTOCOL_REGEX = void 0;
+const abort_controller_1 = __importDefault(require("abort-controller"));
+const crypto_1 = require("crypto");
+const gaxios = __importStar(require("gaxios"));
+const google_auth_library_1 = require("google-auth-library");
+const stream_1 = require("stream");
+const async_retry_1 = __importDefault(require("async-retry"));
+const uuid = __importStar(require("uuid"));
+const util_js_1 = require("./util.js");
+const util_js_2 = require("./nodejs-common/util.js");
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+const package_json_helper_cjs_1 = require("./package-json-helper.cjs");
+const NOT_FOUND_STATUS_CODE = 404;
+const RESUMABLE_INCOMPLETE_STATUS_CODE = 308;
+const packageJson = (0, package_json_helper_cjs_1.getPackageJSON)();
+exports.PROTOCOL_REGEX = /^(\w*):\/\//;
+class Upload extends stream_1.Writable {
+ constructor(cfg) {
+ var _a;
+ super(cfg);
+ _Upload_instances.add(this);
+ this.numBytesWritten = 0;
+ this.numRetries = 0;
+ this.currentInvocationId = {
+ checkUploadStatus: uuid.v4(),
+ chunk: uuid.v4(),
+ uri: uuid.v4(),
+ };
+ /**
+ * A cache of buffers written to this instance, ready for consuming
+ */
+ this.writeBuffers = [];
+ this.numChunksReadInRequest = 0;
+ /**
+ * An array of buffers used for caching the most recent upload chunk.
+ * We should not assume that the server received all bytes sent in the request.
+ * - https://cloud.google.com/storage/docs/performing-resumable-uploads#chunked-upload
+ */
+ this.localWriteCache = [];
+ this.localWriteCacheByteLength = 0;
+ this.upstreamEnded = false;
+ _Upload_gcclGcsCmd.set(this, void 0);
+ cfg = cfg || {};
+ if (!cfg.bucket || !cfg.file) {
+ throw new Error('A bucket and file name are required');
+ }
+ if (cfg.offset && !cfg.uri) {
+ throw new RangeError('Cannot provide an `offset` without providing a `uri`');
+ }
+ if (cfg.isPartialUpload && !cfg.chunkSize) {
+ throw new RangeError('Cannot set `isPartialUpload` without providing a `chunkSize`');
+ }
+ cfg.authConfig = cfg.authConfig || {};
+ cfg.authConfig.scopes = [
+ 'https://www.googleapis.com/auth/devstorage.full_control',
+ ];
+ this.authClient = cfg.authClient || new google_auth_library_1.GoogleAuth(cfg.authConfig);
+ const universe = cfg.universeDomain || google_auth_library_1.DEFAULT_UNIVERSE;
+ this.apiEndpoint = `https://storage.${universe}`;
+ if (cfg.apiEndpoint && cfg.apiEndpoint !== this.apiEndpoint) {
+ this.apiEndpoint = this.sanitizeEndpoint(cfg.apiEndpoint);
+ const hostname = new URL(this.apiEndpoint).hostname;
+ // check if it is a domain of a known universe
+ const isDomain = hostname === universe;
+ const isDefaultUniverseDomain = hostname === google_auth_library_1.DEFAULT_UNIVERSE;
+ // check if it is a subdomain of a known universe
+ // by checking a last (universe's length + 1) of a hostname
+ const isSubDomainOfUniverse = hostname.slice(-(universe.length + 1)) === `.${universe}`;
+ const isSubDomainOfDefaultUniverse = hostname.slice(-(google_auth_library_1.DEFAULT_UNIVERSE.length + 1)) ===
+ `.${google_auth_library_1.DEFAULT_UNIVERSE}`;
+ if (!isDomain &&
+ !isDefaultUniverseDomain &&
+ !isSubDomainOfUniverse &&
+ !isSubDomainOfDefaultUniverse) {
+ // a custom, non-universe domain,
+ // use gaxios
+ this.authClient = gaxios;
+ }
+ }
+ this.baseURI = `${this.apiEndpoint}/upload/storage/v1/b`;
+ this.bucket = cfg.bucket;
+ const cacheKeyElements = [cfg.bucket, cfg.file];
+ if (typeof cfg.generation === 'number') {
+ cacheKeyElements.push(`${cfg.generation}`);
+ }
+ this.cacheKey = cacheKeyElements.join('/');
+ this.customRequestOptions = cfg.customRequestOptions || {};
+ this.file = cfg.file;
+ this.generation = cfg.generation;
+ this.kmsKeyName = cfg.kmsKeyName;
+ this.metadata = cfg.metadata || {};
+ this.offset = cfg.offset;
+ this.origin = cfg.origin;
+ this.params = cfg.params || {};
+ this.userProject = cfg.userProject;
+ this.chunkSize = cfg.chunkSize;
+ this.retryOptions = cfg.retryOptions;
+ this.isPartialUpload = (_a = cfg.isPartialUpload) !== null && _a !== void 0 ? _a : false;
+ if (cfg.key) {
+ const base64Key = Buffer.from(cfg.key).toString('base64');
+ this.encryption = {
+ key: base64Key,
+ hash: (0, crypto_1.createHash)('sha256').update(cfg.key).digest('base64'),
+ };
+ }
+ this.predefinedAcl = cfg.predefinedAcl;
+ if (cfg.private)
+ this.predefinedAcl = 'private';
+ if (cfg.public)
+ this.predefinedAcl = 'publicRead';
+ const autoRetry = cfg.retryOptions.autoRetry;
+ this.uriProvidedManually = !!cfg.uri;
+ this.uri = cfg.uri;
+ if (this.offset) {
+ // we're resuming an incomplete upload
+ this.numBytesWritten = this.offset;
+ }
+ this.numRetries = 0; // counter for number of retries currently executed
+ if (!autoRetry) {
+ cfg.retryOptions.maxRetries = 0;
+ }
+ this.timeOfFirstRequest = Date.now();
+ const contentLength = cfg.metadata
+ ? Number(cfg.metadata.contentLength)
+ : NaN;
+ this.contentLength = isNaN(contentLength) ? '*' : contentLength;
+ __classPrivateFieldSet(this, _Upload_gcclGcsCmd, cfg[util_js_2.GCCL_GCS_CMD_KEY], "f");
+ this.once('writing', () => {
+ if (this.uri) {
+ this.continueUploading();
+ }
+ else {
+ this.createURI(err => {
+ if (err) {
+ return this.destroy(err);
+ }
+ this.startUploading();
+ return;
+ });
+ }
+ });
+ }
+ /**
+ * Prevent 'finish' event until the upload has succeeded.
+ *
+ * @param fireFinishEvent The finish callback
+ */
+ _final(fireFinishEvent = () => { }) {
+ this.upstreamEnded = true;
+ this.once('uploadFinished', fireFinishEvent);
+ process.nextTick(() => {
+ this.emit('upstreamFinished');
+ // it's possible `_write` may not be called - namely for empty object uploads
+ this.emit('writing');
+ });
+ }
+ /**
+ * Handles incoming data from upstream
+ *
+ * @param chunk The chunk to append to the buffer
+ * @param encoding The encoding of the chunk
+ * @param readCallback A callback for when the buffer has been read downstream
+ */
+ _write(chunk, encoding, readCallback = () => { }) {
+ // Backwards-compatible event
+ this.emit('writing');
+ this.writeBuffers.push(typeof chunk === 'string' ? Buffer.from(chunk, encoding) : chunk);
+ this.once('readFromChunkBuffer', readCallback);
+ process.nextTick(() => this.emit('wroteToChunkBuffer'));
+ }
+ /**
+ * Prepends the local buffer to write buffer and resets it.
+ *
+ * @param keepLastBytes number of bytes to keep from the end of the local buffer.
+ */
+ prependLocalBufferToUpstream(keepLastBytes) {
+ // Typically, the upstream write buffers should be smaller than the local
+ // cache, so we can save time by setting the local cache as the new
+ // upstream write buffer array and appending the old array to it
+ let initialBuffers = [];
+ if (keepLastBytes) {
+ // we only want the last X bytes
+ let bytesKept = 0;
+ while (keepLastBytes > bytesKept) {
+ // load backwards because we want the last X bytes
+ // note: `localWriteCacheByteLength` is reset below
+ let buf = this.localWriteCache.pop();
+ if (!buf)
+ break;
+ bytesKept += buf.byteLength;
+ if (bytesKept > keepLastBytes) {
+ // we have gone over the amount desired, let's keep the last X bytes
+ // of this buffer
+ const diff = bytesKept - keepLastBytes;
+ buf = buf.subarray(diff);
+ bytesKept -= diff;
+ }
+ initialBuffers.unshift(buf);
+ }
+ }
+ else {
+ // we're keeping all of the local cache, simply use it as the initial buffer
+ initialBuffers = this.localWriteCache;
+ }
+ // Append the old upstream to the new
+ const append = this.writeBuffers;
+ this.writeBuffers = initialBuffers;
+ for (const buf of append) {
+ this.writeBuffers.push(buf);
+ }
+ // reset last buffers sent
+ __classPrivateFieldGet(this, _Upload_instances, "m", _Upload_resetLocalBuffersCache).call(this);
+ }
+ /**
+ * Retrieves data from upstream's buffer.
+ *
+ * @param limit The maximum amount to return from the buffer.
+ */
+ *pullFromChunkBuffer(limit) {
+ while (limit) {
+ const buf = this.writeBuffers.shift();
+ if (!buf)
+ break;
+ let bufToYield = buf;
+ if (buf.byteLength > limit) {
+ bufToYield = buf.subarray(0, limit);
+ this.writeBuffers.unshift(buf.subarray(limit));
+ limit = 0;
+ }
+ else {
+ limit -= buf.byteLength;
+ }
+ yield bufToYield;
+ // Notify upstream we've read from the buffer and we're able to consume
+ // more. It can also potentially send more data down as we're currently
+ // iterating.
+ this.emit('readFromChunkBuffer');
+ }
+ }
+ /**
+ * A handler for determining if data is ready to be read from upstream.
+ *
+ * @returns If there will be more chunks to read in the future
+ */
+ async waitForNextChunk() {
+ const willBeMoreChunks = await new Promise(resolve => {
+ // There's data available - it should be digested
+ if (this.writeBuffers.length) {
+ return resolve(true);
+ }
+ // The upstream writable ended, we shouldn't expect any more data.
+ if (this.upstreamEnded) {
+ return resolve(false);
+ }
+ // Nothing immediate seems to be determined. We need to prepare some
+ // listeners to determine next steps...
+ const wroteToChunkBufferCallback = () => {
+ removeListeners();
+ return resolve(true);
+ };
+ const upstreamFinishedCallback = () => {
+ removeListeners();
+ // this should be the last chunk, if there's anything there
+ if (this.writeBuffers.length)
+ return resolve(true);
+ return resolve(false);
+ };
+ // Remove listeners when we're ready to callback.
+ const removeListeners = () => {
+ this.removeListener('wroteToChunkBuffer', wroteToChunkBufferCallback);
+ this.removeListener('upstreamFinished', upstreamFinishedCallback);
+ };
+ // If there's data recently written it should be digested
+ this.once('wroteToChunkBuffer', wroteToChunkBufferCallback);
+ // If the upstream finishes let's see if there's anything to grab
+ this.once('upstreamFinished', upstreamFinishedCallback);
+ });
+ return willBeMoreChunks;
+ }
+ /**
+ * Reads data from upstream up to the provided `limit`.
+ * Ends when the limit has reached or no data is expected to be pushed from upstream.
+ *
+ * @param limit The most amount of data this iterator should return. `Infinity` by default.
+ */
+ async *upstreamIterator(limit = Infinity) {
+ // read from upstream chunk buffer
+ while (limit && (await this.waitForNextChunk())) {
+ // read until end or limit has been reached
+ for (const chunk of this.pullFromChunkBuffer(limit)) {
+ limit -= chunk.byteLength;
+ yield chunk;
+ }
+ }
+ }
+ createURI(callback) {
+ if (!callback) {
+ return this.createURIAsync();
+ }
+ this.createURIAsync().then(r => callback(null, r), callback);
+ }
+ async createURIAsync() {
+ const metadata = { ...this.metadata };
+ const headers = {};
+ // Delete content length and content type from metadata if they exist.
+ // These are headers and should not be sent as part of the metadata.
+ if (metadata.contentLength) {
+ headers['X-Upload-Content-Length'] = metadata.contentLength.toString();
+ delete metadata.contentLength;
+ }
+ if (metadata.contentType) {
+ headers['X-Upload-Content-Type'] = metadata.contentType;
+ delete metadata.contentType;
+ }
+ let googAPIClient = `${(0, util_js_1.getRuntimeTrackingString)()} gccl/${packageJson.version}-${(0, util_js_1.getModuleFormat)()} gccl-invocation-id/${this.currentInvocationId.uri}`;
+ if (__classPrivateFieldGet(this, _Upload_gcclGcsCmd, "f")) {
+ googAPIClient += ` gccl-gcs-cmd/${__classPrivateFieldGet(this, _Upload_gcclGcsCmd, "f")}`;
+ }
+ // Check if headers already exist before creating new ones
+ const reqOpts = {
+ method: 'POST',
+ url: [this.baseURI, this.bucket, 'o'].join('/'),
+ params: Object.assign({
+ name: this.file,
+ uploadType: 'resumable',
+ }, this.params),
+ data: metadata,
+ headers: {
+ 'User-Agent': (0, util_js_1.getUserAgentString)(),
+ 'x-goog-api-client': googAPIClient,
+ ...headers,
+ },
+ };
+ if (metadata.contentLength) {
+ reqOpts.headers['X-Upload-Content-Length'] =
+ metadata.contentLength.toString();
+ }
+ if (metadata.contentType) {
+ reqOpts.headers['X-Upload-Content-Type'] = metadata.contentType;
+ }
+ if (typeof this.generation !== 'undefined') {
+ reqOpts.params.ifGenerationMatch = this.generation;
+ }
+ if (this.kmsKeyName) {
+ reqOpts.params.kmsKeyName = this.kmsKeyName;
+ }
+ if (this.predefinedAcl) {
+ reqOpts.params.predefinedAcl = this.predefinedAcl;
+ }
+ if (this.origin) {
+ reqOpts.headers.Origin = this.origin;
+ }
+ const uri = await (0, async_retry_1.default)(async (bail) => {
+ var _a, _b, _c;
+ try {
+ const res = await this.makeRequest(reqOpts);
+ // We have successfully got a URI we can now create a new invocation id
+ this.currentInvocationId.uri = uuid.v4();
+ return res.headers.location;
+ }
+ catch (err) {
+ const e = err;
+ const apiError = {
+ code: (_a = e.response) === null || _a === void 0 ? void 0 : _a.status,
+ name: (_b = e.response) === null || _b === void 0 ? void 0 : _b.statusText,
+ message: (_c = e.response) === null || _c === void 0 ? void 0 : _c.statusText,
+ errors: [
+ {
+ reason: e.code,
+ },
+ ],
+ };
+ if (this.retryOptions.maxRetries > 0 &&
+ this.retryOptions.retryableErrorFn(apiError)) {
+ throw e;
+ }
+ else {
+ return bail(e);
+ }
+ }
+ }, {
+ retries: this.retryOptions.maxRetries,
+ factor: this.retryOptions.retryDelayMultiplier,
+ maxTimeout: this.retryOptions.maxRetryDelay * 1000, //convert to milliseconds
+ maxRetryTime: this.retryOptions.totalTimeout * 1000, //convert to milliseconds
+ });
+ this.uri = uri;
+ this.offset = 0;
+ // emit the newly generated URI for future reuse, if necessary.
+ this.emit('uri', uri);
+ return uri;
+ }
+ async continueUploading() {
+ var _a;
+ (_a = this.offset) !== null && _a !== void 0 ? _a : (await this.getAndSetOffset());
+ return this.startUploading();
+ }
+ async startUploading() {
+ const multiChunkMode = !!this.chunkSize;
+ let responseReceived = false;
+ this.numChunksReadInRequest = 0;
+ if (!this.offset) {
+ this.offset = 0;
+ }
+ // Check if the offset (server) is too far behind the current stream
+ if (this.offset < this.numBytesWritten) {
+ const delta = this.numBytesWritten - this.offset;
+ const message = `The offset is lower than the number of bytes written. The server has ${this.offset} bytes and while ${this.numBytesWritten} bytes has been uploaded - thus ${delta} bytes are missing. Stopping as this could result in data loss. Initiate a new upload to continue.`;
+ this.emit('error', new RangeError(message));
+ return;
+ }
+ // Check if we should 'fast-forward' to the relevant data to upload
+ if (this.numBytesWritten < this.offset) {
+ // 'fast-forward' to the byte where we need to upload.
+ // only push data from the byte after the one we left off on
+ const fastForwardBytes = this.offset - this.numBytesWritten;
+ for await (const _chunk of this.upstreamIterator(fastForwardBytes)) {
+ _chunk; // discard the data up until the point we want
+ }
+ this.numBytesWritten = this.offset;
+ }
+ let expectedUploadSize = undefined;
+ // Set `expectedUploadSize` to `contentLength - this.numBytesWritten`, if available
+ if (typeof this.contentLength === 'number') {
+ expectedUploadSize = this.contentLength - this.numBytesWritten;
+ }
+ // `expectedUploadSize` should be no more than the `chunkSize`.
+ // It's possible this is the last chunk request for a multiple
+ // chunk upload, thus smaller than the chunk size.
+ if (this.chunkSize) {
+ expectedUploadSize = expectedUploadSize
+ ? Math.min(this.chunkSize, expectedUploadSize)
+ : this.chunkSize;
+ }
+ // A queue for the upstream data
+ const upstreamQueue = this.upstreamIterator(expectedUploadSize);
+ // The primary read stream for this request. This stream retrieves no more
+ // than the exact requested amount from upstream.
+ const requestStream = new stream_1.Readable({
+ read: async () => {
+ // Don't attempt to retrieve data upstream if we already have a response
+ if (responseReceived)
+ requestStream.push(null);
+ const result = await upstreamQueue.next();
+ if (result.value) {
+ this.numChunksReadInRequest++;
+ if (multiChunkMode) {
+ // save ever buffer used in the request in multi-chunk mode
+ __classPrivateFieldGet(this, _Upload_instances, "m", _Upload_addLocalBufferCache).call(this, result.value);
+ }
+ else {
+ __classPrivateFieldGet(this, _Upload_instances, "m", _Upload_resetLocalBuffersCache).call(this);
+ __classPrivateFieldGet(this, _Upload_instances, "m", _Upload_addLocalBufferCache).call(this, result.value);
+ }
+ this.numBytesWritten += result.value.byteLength;
+ this.emit('progress', {
+ bytesWritten: this.numBytesWritten,
+ contentLength: this.contentLength,
+ });
+ requestStream.push(result.value);
+ }
+ if (result.done) {
+ requestStream.push(null);
+ }
+ },
+ });
+ let googAPIClient = `${(0, util_js_1.getRuntimeTrackingString)()} gccl/${packageJson.version}-${(0, util_js_1.getModuleFormat)()} gccl-invocation-id/${this.currentInvocationId.chunk}`;
+ if (__classPrivateFieldGet(this, _Upload_gcclGcsCmd, "f")) {
+ googAPIClient += ` gccl-gcs-cmd/${__classPrivateFieldGet(this, _Upload_gcclGcsCmd, "f")}`;
+ }
+ const headers = {
+ 'User-Agent': (0, util_js_1.getUserAgentString)(),
+ 'x-goog-api-client': googAPIClient,
+ };
+ // If using multiple chunk upload, set appropriate header
+ if (multiChunkMode) {
+ // We need to know how much data is available upstream to set the `Content-Range` header.
+ // https://cloud.google.com/storage/docs/performing-resumable-uploads#chunked-upload
+ for await (const chunk of this.upstreamIterator(expectedUploadSize)) {
+ // This will conveniently track and keep the size of the buffers.
+ // We will reach either the expected upload size or the remainder of the stream.
+ __classPrivateFieldGet(this, _Upload_instances, "m", _Upload_addLocalBufferCache).call(this, chunk);
+ }
+ // This is the sum from the `#addLocalBufferCache` calls
+ const bytesToUpload = this.localWriteCacheByteLength;
+ // Important: we want to know if the upstream has ended and the queue is empty before
+ // unshifting data back into the queue. This way we will know if this is the last request or not.
+ const isLastChunkOfUpload = !(await this.waitForNextChunk());
+ // Important: put the data back in the queue for the actual upload
+ this.prependLocalBufferToUpstream();
+ let totalObjectSize = this.contentLength;
+ if (typeof this.contentLength !== 'number' &&
+ isLastChunkOfUpload &&
+ !this.isPartialUpload) {
+ // Let's let the server know this is the last chunk of the object since we didn't set it before.
+ totalObjectSize = bytesToUpload + this.numBytesWritten;
+ }
+ // `- 1` as the ending byte is inclusive in the request.
+ const endingByte = bytesToUpload + this.numBytesWritten - 1;
+ // `Content-Length` for multiple chunk uploads is the size of the chunk,
+ // not the overall object
+ headers['Content-Length'] = bytesToUpload;
+ headers['Content-Range'] = `bytes ${this.offset}-${endingByte}/${totalObjectSize}`;
+ }
+ else {
+ headers['Content-Range'] = `bytes ${this.offset}-*/${this.contentLength}`;
+ }
+ const reqOpts = {
+ method: 'PUT',
+ url: this.uri,
+ headers,
+ body: requestStream,
+ };
+ try {
+ const resp = await this.makeRequestStream(reqOpts);
+ if (resp) {
+ responseReceived = true;
+ await this.responseHandler(resp);
+ }
+ }
+ catch (e) {
+ const err = e;
+ if (this.retryOptions.retryableErrorFn(err)) {
+ this.attemptDelayedRetry({
+ status: NaN,
+ data: err,
+ });
+ return;
+ }
+ this.destroy(err);
+ }
+ }
+ // Process the API response to look for errors that came in
+ // the response body.
+ async responseHandler(resp) {
+ if (resp.data.error) {
+ this.destroy(resp.data.error);
+ return;
+ }
+ // At this point we can safely create a new id for the chunk
+ this.currentInvocationId.chunk = uuid.v4();
+ const moreDataToUpload = await this.waitForNextChunk();
+ const shouldContinueWithNextMultiChunkRequest = this.chunkSize &&
+ resp.status === RESUMABLE_INCOMPLETE_STATUS_CODE &&
+ resp.headers.range &&
+ moreDataToUpload;
+ /**
+ * This is true when we're expecting to upload more data in a future request,
+ * yet the upstream for the upload session has been exhausted.
+ */
+ const shouldContinueUploadInAnotherRequest = this.isPartialUpload &&
+ resp.status === RESUMABLE_INCOMPLETE_STATUS_CODE &&
+ !moreDataToUpload;
+ if (shouldContinueWithNextMultiChunkRequest) {
+ // Use the upper value in this header to determine where to start the next chunk.
+ // We should not assume that the server received all bytes sent in the request.
+ // https://cloud.google.com/storage/docs/performing-resumable-uploads#chunked-upload
+ const range = resp.headers.range;
+ this.offset = Number(range.split('-')[1]) + 1;
+ // We should not assume that the server received all bytes sent in the request.
+ // - https://cloud.google.com/storage/docs/performing-resumable-uploads#chunked-upload
+ const missingBytes = this.numBytesWritten - this.offset;
+ if (missingBytes) {
+ // As multi-chunk uploads send one chunk per request and pulls one
+ // chunk into the pipeline, prepending the missing bytes back should
+ // be fine for the next request.
+ this.prependLocalBufferToUpstream(missingBytes);
+ this.numBytesWritten -= missingBytes;
+ }
+ else {
+ // No bytes missing - no need to keep the local cache
+ __classPrivateFieldGet(this, _Upload_instances, "m", _Upload_resetLocalBuffersCache).call(this);
+ }
+ // continue uploading next chunk
+ this.continueUploading();
+ }
+ else if (!this.isSuccessfulResponse(resp.status) &&
+ !shouldContinueUploadInAnotherRequest) {
+ const err = new Error('Upload failed');
+ err.code = resp.status;
+ err.name = 'Upload failed';
+ if (resp === null || resp === void 0 ? void 0 : resp.data) {
+ err.errors = [resp === null || resp === void 0 ? void 0 : resp.data];
+ }
+ this.destroy(err);
+ }
+ else {
+ // no need to keep the cache
+ __classPrivateFieldGet(this, _Upload_instances, "m", _Upload_resetLocalBuffersCache).call(this);
+ if (resp && resp.data) {
+ resp.data.size = Number(resp.data.size);
+ }
+ this.emit('metadata', resp.data);
+ // Allow the object (Upload) to continue naturally so the user's
+ // "finish" event fires.
+ this.emit('uploadFinished');
+ }
+ }
+ /**
+ * Check the status of an existing resumable upload.
+ *
+ * @param cfg A configuration to use. `uri` is required.
+ * @returns the current upload status
+ */
+ async checkUploadStatus(config = {}) {
+ let googAPIClient = `${(0, util_js_1.getRuntimeTrackingString)()} gccl/${packageJson.version}-${(0, util_js_1.getModuleFormat)()} gccl-invocation-id/${this.currentInvocationId.checkUploadStatus}`;
+ if (__classPrivateFieldGet(this, _Upload_gcclGcsCmd, "f")) {
+ googAPIClient += ` gccl-gcs-cmd/${__classPrivateFieldGet(this, _Upload_gcclGcsCmd, "f")}`;
+ }
+ const opts = {
+ method: 'PUT',
+ url: this.uri,
+ headers: {
+ 'Content-Length': 0,
+ 'Content-Range': 'bytes */*',
+ 'User-Agent': (0, util_js_1.getUserAgentString)(),
+ 'x-goog-api-client': googAPIClient,
+ },
+ };
+ try {
+ const resp = await this.makeRequest(opts);
+ // Successfully got the offset we can now create a new offset invocation id
+ this.currentInvocationId.checkUploadStatus = uuid.v4();
+ return resp;
+ }
+ catch (e) {
+ if (config.retry === false ||
+ !(e instanceof Error) ||
+ !this.retryOptions.retryableErrorFn(e)) {
+ throw e;
+ }
+ const retryDelay = this.getRetryDelay();
+ if (retryDelay <= 0) {
+ throw e;
+ }
+ await new Promise(res => setTimeout(res, retryDelay));
+ return this.checkUploadStatus(config);
+ }
+ }
+ async getAndSetOffset() {
+ try {
+ // we want to handle retries in this method.
+ const resp = await this.checkUploadStatus({ retry: false });
+ if (resp.status === RESUMABLE_INCOMPLETE_STATUS_CODE) {
+ if (typeof resp.headers.range === 'string') {
+ this.offset = Number(resp.headers.range.split('-')[1]) + 1;
+ return;
+ }
+ }
+ this.offset = 0;
+ }
+ catch (e) {
+ const err = e;
+ if (this.retryOptions.retryableErrorFn(err)) {
+ this.attemptDelayedRetry({
+ status: NaN,
+ data: err,
+ });
+ return;
+ }
+ this.destroy(err);
+ }
+ }
+ async makeRequest(reqOpts) {
+ if (this.encryption) {
+ reqOpts.headers = reqOpts.headers || {};
+ reqOpts.headers['x-goog-encryption-algorithm'] = 'AES256';
+ reqOpts.headers['x-goog-encryption-key'] = this.encryption.key.toString();
+ reqOpts.headers['x-goog-encryption-key-sha256'] =
+ this.encryption.hash.toString();
+ }
+ if (this.userProject) {
+ reqOpts.params = reqOpts.params || {};
+ reqOpts.params.userProject = this.userProject;
+ }
+ // Let gaxios know we will handle a 308 error code ourselves.
+ reqOpts.validateStatus = (status) => {
+ return (this.isSuccessfulResponse(status) ||
+ status === RESUMABLE_INCOMPLETE_STATUS_CODE);
+ };
+ const combinedReqOpts = {
+ ...this.customRequestOptions,
+ ...reqOpts,
+ headers: {
+ ...this.customRequestOptions.headers,
+ ...reqOpts.headers,
+ },
+ };
+ const res = await this.authClient.request(combinedReqOpts);
+ if (res.data && res.data.error) {
+ throw res.data.error;
+ }
+ return res;
+ }
+ async makeRequestStream(reqOpts) {
+ const controller = new abort_controller_1.default();
+ const errorCallback = () => controller.abort();
+ this.once('error', errorCallback);
+ if (this.userProject) {
+ reqOpts.params = reqOpts.params || {};
+ reqOpts.params.userProject = this.userProject;
+ }
+ reqOpts.signal = controller.signal;
+ reqOpts.validateStatus = () => true;
+ const combinedReqOpts = {
+ ...this.customRequestOptions,
+ ...reqOpts,
+ headers: {
+ ...this.customRequestOptions.headers,
+ ...reqOpts.headers,
+ },
+ };
+ const res = await this.authClient.request(combinedReqOpts);
+ const successfulRequest = this.onResponse(res);
+ this.removeListener('error', errorCallback);
+ return successfulRequest ? res : null;
+ }
+ /**
+ * @return {bool} is the request good?
+ */
+ onResponse(resp) {
+ if (resp.status !== 200 &&
+ this.retryOptions.retryableErrorFn({
+ code: resp.status,
+ message: resp.statusText,
+ name: resp.statusText,
+ })) {
+ this.attemptDelayedRetry(resp);
+ return false;
+ }
+ this.emit('response', resp);
+ return true;
+ }
+ /**
+ * @param resp GaxiosResponse object from previous attempt
+ */
+ attemptDelayedRetry(resp) {
+ if (this.numRetries < this.retryOptions.maxRetries) {
+ if (resp.status === NOT_FOUND_STATUS_CODE &&
+ this.numChunksReadInRequest === 0) {
+ this.startUploading();
+ }
+ else {
+ const retryDelay = this.getRetryDelay();
+ if (retryDelay <= 0) {
+ this.destroy(new Error(`Retry total time limit exceeded - ${resp.data}`));
+ return;
+ }
+ // Unshift the local cache back in case it's needed for the next request.
+ this.numBytesWritten -= this.localWriteCacheByteLength;
+ this.prependLocalBufferToUpstream();
+ // We don't know how much data has been received by the server.
+ // `continueUploading` will recheck the offset via `getAndSetOffset`.
+ // If `offset` < `numberBytesReceived` then we will raise a RangeError
+ // as we've streamed too much data that has been missed - this should
+ // not be the case for multi-chunk uploads as `lastChunkSent` is the
+ // body of the entire request.
+ this.offset = undefined;
+ setTimeout(this.continueUploading.bind(this), retryDelay);
+ }
+ this.numRetries++;
+ }
+ else {
+ this.destroy(new Error('Retry limit exceeded - ' + resp.data));
+ }
+ }
+ /**
+ * The amount of time to wait before retrying the request, in milliseconds.
+ * If negative, do not retry.
+ *
+ * @returns the amount of time to wait, in milliseconds.
+ */
+ getRetryDelay() {
+ const randomMs = Math.round(Math.random() * 1000);
+ const waitTime = Math.pow(this.retryOptions.retryDelayMultiplier, this.numRetries) *
+ 1000 +
+ randomMs;
+ const maxAllowableDelayMs = this.retryOptions.totalTimeout * 1000 -
+ (Date.now() - this.timeOfFirstRequest);
+ const maxRetryDelayMs = this.retryOptions.maxRetryDelay * 1000;
+ return Math.min(waitTime, maxRetryDelayMs, maxAllowableDelayMs);
+ }
+ /*
+ * Prepare user-defined API endpoint for compatibility with our API.
+ */
+ sanitizeEndpoint(url) {
+ if (!exports.PROTOCOL_REGEX.test(url)) {
+ url = `https://${url}`;
+ }
+ return url.replace(/\/+$/, ''); // Remove trailing slashes
+ }
+ /**
+ * Check if a given status code is 2xx
+ *
+ * @param status The status code to check
+ * @returns if the status is 2xx
+ */
+ isSuccessfulResponse(status) {
+ return status >= 200 && status < 300;
+ }
+}
+exports.Upload = Upload;
+_Upload_gcclGcsCmd = new WeakMap(), _Upload_instances = new WeakSet(), _Upload_resetLocalBuffersCache = function _Upload_resetLocalBuffersCache() {
+ this.localWriteCache = [];
+ this.localWriteCacheByteLength = 0;
+}, _Upload_addLocalBufferCache = function _Upload_addLocalBufferCache(buf) {
+ this.localWriteCache.push(buf);
+ this.localWriteCacheByteLength += buf.byteLength;
+};
+function upload(cfg) {
+ return new Upload(cfg);
+}
+exports.upload = upload;
+function createURI(cfg, callback) {
+ const up = new Upload(cfg);
+ if (!callback) {
+ return up.createURI();
+ }
+ up.createURI().then(r => callback(null, r), callback);
+}
+exports.createURI = createURI;
+/**
+ * Check the status of an existing resumable upload.
+ *
+ * @param cfg A configuration to use. `uri` is required.
+ * @returns the current upload status
+ */
+function checkUploadStatus(cfg) {
+ const up = new Upload(cfg);
+ return up.checkUploadStatus();
+}
+exports.checkUploadStatus = checkUploadStatus;
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/signer.d.ts b/node_modules/@google-cloud/storage/build/cjs/src/signer.d.ts
new file mode 100644
index 0000000..b15435e
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/signer.d.ts
@@ -0,0 +1,148 @@
+///
+///
+import * as http from 'http';
+import { Storage } from './storage.js';
+import { GoogleAuth } from 'google-auth-library';
+type GoogleAuthLike = Pick;
+/**
+ * @deprecated Use {@link GoogleAuth} instead
+ */
+export interface AuthClient {
+ sign(blobToSign: string): Promise;
+ getCredentials(): Promise<{
+ client_email?: string;
+ }>;
+}
+export interface BucketI {
+ name: string;
+}
+export interface FileI {
+ name: string;
+}
+export interface Query {
+ [key: string]: string;
+}
+export interface GetSignedUrlConfigInternal {
+ expiration: number;
+ accessibleAt?: Date;
+ method: string;
+ extensionHeaders?: http.OutgoingHttpHeaders;
+ queryParams?: Query;
+ cname?: string;
+ contentMd5?: string;
+ contentType?: string;
+ bucket: string;
+ file?: string;
+ /**
+ * The host for the generated signed URL
+ *
+ * @example
+ * 'https://localhost:8080/'
+ */
+ host?: string | URL;
+ /**
+ * An endpoint for generating the signed URL
+ *
+ * @example
+ * 'https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/'
+ */
+ signingEndpoint?: string | URL;
+}
+export interface SignerGetSignedUrlConfig {
+ method: 'GET' | 'PUT' | 'DELETE' | 'POST';
+ expires: string | number | Date;
+ accessibleAt?: string | number | Date;
+ virtualHostedStyle?: boolean;
+ version?: 'v2' | 'v4';
+ cname?: string;
+ extensionHeaders?: http.OutgoingHttpHeaders;
+ queryParams?: Query;
+ contentMd5?: string;
+ contentType?: string;
+ /**
+ * The host for the generated signed URL
+ *
+ * @example
+ * 'https://localhost:8080/'
+ */
+ host?: string | URL;
+ /**
+ * An endpoint for generating the signed URL
+ *
+ * @example
+ * 'https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/'
+ */
+ signingEndpoint?: string | URL;
+}
+export type SignerGetSignedUrlResponse = string;
+export type GetSignedUrlResponse = [SignerGetSignedUrlResponse];
+export interface GetSignedUrlCallback {
+ (err: Error | null, url?: string): void;
+}
+export declare enum SignerExceptionMessages {
+ ACCESSIBLE_DATE_INVALID = "The accessible at date provided was invalid.",
+ EXPIRATION_BEFORE_ACCESSIBLE_DATE = "An expiration date cannot be before accessible date.",
+ X_GOOG_CONTENT_SHA256 = "The header X-Goog-Content-SHA256 must be a hexadecimal string."
+}
+/**
+ * @const {string}
+ * @deprecated - unused
+ */
+export declare const PATH_STYLED_HOST = "https://storage.googleapis.com";
+export declare class URLSigner {
+ private auth;
+ private bucket;
+ private file?;
+ /**
+ * A {@link Storage} object.
+ *
+ * @privateRemarks
+ *
+ * Technically this is a required field, however it would be a breaking change to
+ * move it before optional properties. In the next major we should refactor the
+ * constructor of this class to only accept a config object.
+ */
+ private storage;
+ constructor(auth: AuthClient | GoogleAuthLike, bucket: BucketI, file?: FileI | undefined,
+ /**
+ * A {@link Storage} object.
+ *
+ * @privateRemarks
+ *
+ * Technically this is a required field, however it would be a breaking change to
+ * move it before optional properties. In the next major we should refactor the
+ * constructor of this class to only accept a config object.
+ */
+ storage?: Storage);
+ getSignedUrl(cfg: SignerGetSignedUrlConfig): Promise;
+ private getSignedUrlV2;
+ private getSignedUrlV4;
+ /**
+ * Create canonical headers for signing v4 url.
+ *
+ * The canonical headers for v4-signing a request demands header names are
+ * first lowercased, followed by sorting the header names.
+ * Then, construct the canonical headers part of the request:
+ * + ":" + Trim() + "\n"
+ * ..
+ * + ":" + Trim() + "\n"
+ *
+ * @param headers
+ * @private
+ */
+ getCanonicalHeaders(headers: http.OutgoingHttpHeaders): string;
+ getCanonicalRequest(method: string, path: string, query: string, headers: string, signedHeaders: string, contentSha256?: string): string;
+ getCanonicalQueryParams(query: Query): string;
+ getResourcePath(cname: boolean, bucket: string, file?: string): string;
+ parseExpires(expires: string | number | Date, current?: Date): number;
+ parseAccessibleAt(accessibleAt?: string | number | Date): number;
+}
+/**
+ * Custom error type for errors related to getting signed errors and policies.
+ *
+ * @private
+ */
+export declare class SigningError extends Error {
+ name: string;
+}
+export {};
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/signer.js b/node_modules/@google-cloud/storage/build/cjs/src/signer.js
new file mode 100644
index 0000000..8a8f6fb
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/signer.js
@@ -0,0 +1,327 @@
+"use strict";
+// Copyright 2020 Google LLC
+//
+// 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.
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.SigningError = exports.URLSigner = exports.PATH_STYLED_HOST = exports.SignerExceptionMessages = void 0;
+const crypto = __importStar(require("crypto"));
+const url = __importStar(require("url"));
+const storage_js_1 = require("./storage.js");
+const util_js_1 = require("./util.js");
+var SignerExceptionMessages;
+(function (SignerExceptionMessages) {
+ SignerExceptionMessages["ACCESSIBLE_DATE_INVALID"] = "The accessible at date provided was invalid.";
+ SignerExceptionMessages["EXPIRATION_BEFORE_ACCESSIBLE_DATE"] = "An expiration date cannot be before accessible date.";
+ SignerExceptionMessages["X_GOOG_CONTENT_SHA256"] = "The header X-Goog-Content-SHA256 must be a hexadecimal string.";
+})(SignerExceptionMessages || (exports.SignerExceptionMessages = SignerExceptionMessages = {}));
+/*
+ * Default signing version for getSignedUrl is 'v2'.
+ */
+const DEFAULT_SIGNING_VERSION = 'v2';
+const SEVEN_DAYS = 7 * 24 * 60 * 60;
+/**
+ * @const {string}
+ * @deprecated - unused
+ */
+exports.PATH_STYLED_HOST = 'https://storage.googleapis.com';
+class URLSigner {
+ constructor(auth, bucket, file,
+ /**
+ * A {@link Storage} object.
+ *
+ * @privateRemarks
+ *
+ * Technically this is a required field, however it would be a breaking change to
+ * move it before optional properties. In the next major we should refactor the
+ * constructor of this class to only accept a config object.
+ */
+ storage = new storage_js_1.Storage()) {
+ this.auth = auth;
+ this.bucket = bucket;
+ this.file = file;
+ this.storage = storage;
+ }
+ getSignedUrl(cfg) {
+ const expiresInSeconds = this.parseExpires(cfg.expires);
+ const method = cfg.method;
+ const accessibleAtInSeconds = this.parseAccessibleAt(cfg.accessibleAt);
+ if (expiresInSeconds < accessibleAtInSeconds) {
+ throw new Error(SignerExceptionMessages.EXPIRATION_BEFORE_ACCESSIBLE_DATE);
+ }
+ let customHost;
+ // Default style is `path`.
+ const isVirtualHostedStyle = cfg.virtualHostedStyle || false;
+ if (cfg.cname) {
+ customHost = cfg.cname;
+ }
+ else if (isVirtualHostedStyle) {
+ customHost = `https://${this.bucket.name}.storage.${this.storage.universeDomain}`;
+ }
+ const secondsToMilliseconds = 1000;
+ const config = Object.assign({}, cfg, {
+ method,
+ expiration: expiresInSeconds,
+ accessibleAt: new Date(secondsToMilliseconds * accessibleAtInSeconds),
+ bucket: this.bucket.name,
+ file: this.file ? (0, util_js_1.encodeURI)(this.file.name, false) : undefined,
+ });
+ if (customHost) {
+ config.cname = customHost;
+ }
+ const version = cfg.version || DEFAULT_SIGNING_VERSION;
+ let promise;
+ if (version === 'v2') {
+ promise = this.getSignedUrlV2(config);
+ }
+ else if (version === 'v4') {
+ promise = this.getSignedUrlV4(config);
+ }
+ else {
+ throw new Error(`Invalid signed URL version: ${version}. Supported versions are 'v2' and 'v4'.`);
+ }
+ return promise.then(query => {
+ var _a;
+ query = Object.assign(query, cfg.queryParams);
+ const signedUrl = new url.URL(((_a = cfg.host) === null || _a === void 0 ? void 0 : _a.toString()) || config.cname || this.storage.apiEndpoint);
+ signedUrl.pathname = this.getResourcePath(!!config.cname, this.bucket.name, config.file);
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ signedUrl.search = (0, util_js_1.qsStringify)(query);
+ return signedUrl.href;
+ });
+ }
+ getSignedUrlV2(config) {
+ const canonicalHeadersString = this.getCanonicalHeaders(config.extensionHeaders || {});
+ const resourcePath = this.getResourcePath(false, config.bucket, config.file);
+ const blobToSign = [
+ config.method,
+ config.contentMd5 || '',
+ config.contentType || '',
+ config.expiration,
+ canonicalHeadersString + resourcePath,
+ ].join('\n');
+ const sign = async () => {
+ var _a;
+ const auth = this.auth;
+ try {
+ const signature = await auth.sign(blobToSign, (_a = config.signingEndpoint) === null || _a === void 0 ? void 0 : _a.toString());
+ const credentials = await auth.getCredentials();
+ return {
+ GoogleAccessId: credentials.client_email,
+ Expires: config.expiration,
+ Signature: signature,
+ };
+ }
+ catch (err) {
+ const error = err;
+ const signingErr = new SigningError(error.message);
+ signingErr.stack = error.stack;
+ throw signingErr;
+ }
+ };
+ return sign();
+ }
+ getSignedUrlV4(config) {
+ var _a;
+ config.accessibleAt = config.accessibleAt
+ ? config.accessibleAt
+ : new Date();
+ const millisecondsToSeconds = 1.0 / 1000.0;
+ const expiresPeriodInSeconds = config.expiration - config.accessibleAt.valueOf() * millisecondsToSeconds;
+ // v4 limit expiration to be 7 days maximum
+ if (expiresPeriodInSeconds > SEVEN_DAYS) {
+ throw new Error(`Max allowed expiration is seven days (${SEVEN_DAYS} seconds).`);
+ }
+ const extensionHeaders = Object.assign({}, config.extensionHeaders);
+ const fqdn = new url.URL(((_a = config.host) === null || _a === void 0 ? void 0 : _a.toString()) || config.cname || this.storage.apiEndpoint);
+ extensionHeaders.host = fqdn.hostname;
+ if (config.contentMd5) {
+ extensionHeaders['content-md5'] = config.contentMd5;
+ }
+ if (config.contentType) {
+ extensionHeaders['content-type'] = config.contentType;
+ }
+ let contentSha256;
+ const sha256Header = extensionHeaders['x-goog-content-sha256'];
+ if (sha256Header) {
+ if (typeof sha256Header !== 'string' ||
+ !/[A-Fa-f0-9]{40}/.test(sha256Header)) {
+ throw new Error(SignerExceptionMessages.X_GOOG_CONTENT_SHA256);
+ }
+ contentSha256 = sha256Header;
+ }
+ const signedHeaders = Object.keys(extensionHeaders)
+ .map(header => header.toLowerCase())
+ .sort()
+ .join(';');
+ const extensionHeadersString = this.getCanonicalHeaders(extensionHeaders);
+ const datestamp = (0, util_js_1.formatAsUTCISO)(config.accessibleAt);
+ const credentialScope = `${datestamp}/auto/storage/goog4_request`;
+ const sign = async () => {
+ var _a;
+ const credentials = await this.auth.getCredentials();
+ const credential = `${credentials.client_email}/${credentialScope}`;
+ const dateISO = (0, util_js_1.formatAsUTCISO)(config.accessibleAt ? config.accessibleAt : new Date(), true);
+ const queryParams = {
+ 'X-Goog-Algorithm': 'GOOG4-RSA-SHA256',
+ 'X-Goog-Credential': credential,
+ 'X-Goog-Date': dateISO,
+ 'X-Goog-Expires': expiresPeriodInSeconds.toString(10),
+ 'X-Goog-SignedHeaders': signedHeaders,
+ ...(config.queryParams || {}),
+ };
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
+ const canonicalQueryParams = this.getCanonicalQueryParams(queryParams);
+ const canonicalRequest = this.getCanonicalRequest(config.method, this.getResourcePath(!!config.cname, config.bucket, config.file), canonicalQueryParams, extensionHeadersString, signedHeaders, contentSha256);
+ const hash = crypto
+ .createHash('sha256')
+ .update(canonicalRequest)
+ .digest('hex');
+ const blobToSign = [
+ 'GOOG4-RSA-SHA256',
+ dateISO,
+ credentialScope,
+ hash,
+ ].join('\n');
+ try {
+ const signature = await this.auth.sign(blobToSign, (_a = config.signingEndpoint) === null || _a === void 0 ? void 0 : _a.toString());
+ const signatureHex = Buffer.from(signature, 'base64').toString('hex');
+ const signedQuery = Object.assign({}, queryParams, {
+ 'X-Goog-Signature': signatureHex,
+ });
+ return signedQuery;
+ }
+ catch (err) {
+ const error = err;
+ const signingErr = new SigningError(error.message);
+ signingErr.stack = error.stack;
+ throw signingErr;
+ }
+ };
+ return sign();
+ }
+ /**
+ * Create canonical headers for signing v4 url.
+ *
+ * The canonical headers for v4-signing a request demands header names are
+ * first lowercased, followed by sorting the header names.
+ * Then, construct the canonical headers part of the request:
+ * + ":" + Trim() + "\n"
+ * ..
+ * + ":" + Trim() + "\n"
+ *
+ * @param headers
+ * @private
+ */
+ getCanonicalHeaders(headers) {
+ // Sort headers by their lowercased names
+ const sortedHeaders = (0, util_js_1.objectEntries)(headers)
+ // Convert header names to lowercase
+ .map(([headerName, value]) => [
+ headerName.toLowerCase(),
+ value,
+ ])
+ .sort((a, b) => a[0].localeCompare(b[0]));
+ return sortedHeaders
+ .filter(([, value]) => value !== undefined)
+ .map(([headerName, value]) => {
+ // - Convert Array (multi-valued header) into string, delimited by
+ // ',' (no space).
+ // - Trim leading and trailing spaces.
+ // - Convert sequential (2+) spaces into a single space
+ const canonicalValue = `${value}`.trim().replace(/\s{2,}/g, ' ');
+ return `${headerName}:${canonicalValue}\n`;
+ })
+ .join('');
+ }
+ getCanonicalRequest(method, path, query, headers, signedHeaders, contentSha256) {
+ return [
+ method,
+ path,
+ query,
+ headers,
+ signedHeaders,
+ contentSha256 || 'UNSIGNED-PAYLOAD',
+ ].join('\n');
+ }
+ getCanonicalQueryParams(query) {
+ return (0, util_js_1.objectEntries)(query)
+ .map(([key, value]) => [(0, util_js_1.encodeURI)(key, true), (0, util_js_1.encodeURI)(value, true)])
+ .sort((a, b) => (a[0] < b[0] ? -1 : 1))
+ .map(([key, value]) => `${key}=${value}`)
+ .join('&');
+ }
+ getResourcePath(cname, bucket, file) {
+ if (cname) {
+ return '/' + (file || '');
+ }
+ else if (file) {
+ return `/${bucket}/${file}`;
+ }
+ else {
+ return `/${bucket}`;
+ }
+ }
+ parseExpires(expires, current = new Date()) {
+ const expiresInMSeconds = new Date(expires).valueOf();
+ if (isNaN(expiresInMSeconds)) {
+ throw new Error(storage_js_1.ExceptionMessages.EXPIRATION_DATE_INVALID);
+ }
+ if (expiresInMSeconds < current.valueOf()) {
+ throw new Error(storage_js_1.ExceptionMessages.EXPIRATION_DATE_PAST);
+ }
+ return Math.floor(expiresInMSeconds / 1000); // The API expects seconds.
+ }
+ parseAccessibleAt(accessibleAt) {
+ const accessibleAtInMSeconds = new Date(accessibleAt || new Date()).valueOf();
+ if (isNaN(accessibleAtInMSeconds)) {
+ throw new Error(SignerExceptionMessages.ACCESSIBLE_DATE_INVALID);
+ }
+ return Math.floor(accessibleAtInMSeconds / 1000); // The API expects seconds.
+ }
+}
+exports.URLSigner = URLSigner;
+/**
+ * Custom error type for errors related to getting signed errors and policies.
+ *
+ * @private
+ */
+class SigningError extends Error {
+ constructor() {
+ super(...arguments);
+ this.name = 'SigningError';
+ }
+}
+exports.SigningError = SigningError;
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/storage.d.ts b/node_modules/@google-cloud/storage/build/cjs/src/storage.d.ts
new file mode 100644
index 0000000..1a0ecb5
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/storage.d.ts
@@ -0,0 +1,723 @@
+///
+import { ApiError, Service, ServiceOptions } from './nodejs-common/index.js';
+import { Readable } from 'stream';
+import { Bucket } from './bucket.js';
+import { Channel } from './channel.js';
+import { File } from './file.js';
+import { HmacKey, HmacKeyMetadata, HmacKeyOptions } from './hmacKey.js';
+import { CRC32CValidatorGenerator } from './crc32c.js';
+export interface GetServiceAccountOptions {
+ userProject?: string;
+}
+export interface ServiceAccount {
+ emailAddress?: string;
+}
+export type GetServiceAccountResponse = [ServiceAccount, unknown];
+export interface GetServiceAccountCallback {
+ (err: Error | null, serviceAccount?: ServiceAccount, apiResponse?: unknown): void;
+}
+export interface CreateBucketQuery {
+ project: string;
+ userProject: string;
+ enableObjectRetention: boolean;
+}
+export declare enum IdempotencyStrategy {
+ RetryAlways = 0,
+ RetryConditional = 1,
+ RetryNever = 2
+}
+export interface RetryOptions {
+ retryDelayMultiplier?: number;
+ totalTimeout?: number;
+ maxRetryDelay?: number;
+ autoRetry?: boolean;
+ maxRetries?: number;
+ retryableErrorFn?: (err: ApiError) => boolean;
+ idempotencyStrategy?: IdempotencyStrategy;
+}
+export interface PreconditionOptions {
+ ifGenerationMatch?: number | string;
+ ifGenerationNotMatch?: number | string;
+ ifMetagenerationMatch?: number | string;
+ ifMetagenerationNotMatch?: number | string;
+}
+export interface StorageOptions extends ServiceOptions {
+ /**
+ * The API endpoint of the service used to make requests.
+ * Defaults to `storage.googleapis.com`.
+ */
+ apiEndpoint?: string;
+ crc32cGenerator?: CRC32CValidatorGenerator;
+ retryOptions?: RetryOptions;
+}
+export interface BucketOptions {
+ crc32cGenerator?: CRC32CValidatorGenerator;
+ kmsKeyName?: string;
+ preconditionOpts?: PreconditionOptions;
+ userProject?: string;
+}
+export interface Cors {
+ maxAgeSeconds?: number;
+ method?: string[];
+ origin?: string[];
+ responseHeader?: string[];
+}
+interface Versioning {
+ enabled: boolean;
+}
+/**
+ * Custom placement configuration.
+ * Initially used for dual-region buckets.
+ **/
+export interface CustomPlacementConfig {
+ dataLocations?: string[];
+}
+export interface AutoclassConfig {
+ enabled?: boolean;
+ terminalStorageClass?: 'NEARLINE' | 'ARCHIVE';
+}
+export interface CreateBucketRequest {
+ archive?: boolean;
+ autoclass?: AutoclassConfig;
+ coldline?: boolean;
+ cors?: Cors[];
+ customPlacementConfig?: CustomPlacementConfig;
+ dra?: boolean;
+ enableObjectRetention?: boolean;
+ location?: string;
+ multiRegional?: boolean;
+ nearline?: boolean;
+ regional?: boolean;
+ requesterPays?: boolean;
+ retentionPolicy?: object;
+ rpo?: string;
+ standard?: boolean;
+ storageClass?: string;
+ userProject?: string;
+ versioning?: Versioning;
+}
+export type CreateBucketResponse = [Bucket, unknown];
+export interface BucketCallback {
+ (err: Error | null, bucket?: Bucket | null, apiResponse?: unknown): void;
+}
+export type GetBucketsResponse = [Bucket[], {}, unknown];
+export interface GetBucketsCallback {
+ (err: Error | null, buckets: Bucket[], nextQuery?: {}, apiResponse?: unknown): void;
+}
+export interface GetBucketsRequest {
+ prefix?: string;
+ project?: string;
+ autoPaginate?: boolean;
+ maxApiCalls?: number;
+ maxResults?: number;
+ pageToken?: string;
+ userProject?: string;
+}
+export interface HmacKeyResourceResponse {
+ metadata: HmacKeyMetadata;
+ secret: string;
+}
+export type CreateHmacKeyResponse = [HmacKey, string, HmacKeyResourceResponse];
+export interface CreateHmacKeyOptions {
+ projectId?: string;
+ userProject?: string;
+}
+export interface CreateHmacKeyCallback {
+ (err: Error | null, hmacKey?: HmacKey | null, secret?: string | null, apiResponse?: HmacKeyResourceResponse): void;
+}
+export interface GetHmacKeysOptions {
+ projectId?: string;
+ serviceAccountEmail?: string;
+ showDeletedKeys?: boolean;
+ autoPaginate?: boolean;
+ maxApiCalls?: number;
+ maxResults?: number;
+ pageToken?: string;
+ userProject?: string;
+}
+export interface GetHmacKeysCallback {
+ (err: Error | null, hmacKeys: HmacKey[] | null, nextQuery?: {}, apiResponse?: unknown): void;
+}
+export declare enum ExceptionMessages {
+ EXPIRATION_DATE_INVALID = "The expiration date provided was invalid.",
+ EXPIRATION_DATE_PAST = "An expiration date cannot be in the past."
+}
+export declare enum StorageExceptionMessages {
+ BUCKET_NAME_REQUIRED = "A bucket name is needed to use Cloud Storage.",
+ BUCKET_NAME_REQUIRED_CREATE = "A name is required to create a bucket.",
+ HMAC_SERVICE_ACCOUNT = "The first argument must be a service account email to create an HMAC key.",
+ HMAC_ACCESS_ID = "An access ID is needed to create an HmacKey object."
+}
+export type GetHmacKeysResponse = [HmacKey[]];
+export declare const PROTOCOL_REGEX: RegExp;
+/**
+ * Default behavior: Automatically retry retriable server errors.
+ *
+ * @const {boolean}
+ */
+export declare const AUTO_RETRY_DEFAULT = true;
+/**
+ * Default behavior: Only attempt to retry retriable errors 3 times.
+ *
+ * @const {number}
+ */
+export declare const MAX_RETRY_DEFAULT = 3;
+/**
+ * Default behavior: Wait twice as long as previous retry before retrying.
+ *
+ * @const {number}
+ */
+export declare const RETRY_DELAY_MULTIPLIER_DEFAULT = 2;
+/**
+ * Default behavior: If the operation doesn't succeed after 600 seconds,
+ * stop retrying.
+ *
+ * @const {number}
+ */
+export declare const TOTAL_TIMEOUT_DEFAULT = 600;
+/**
+ * Default behavior: Wait no more than 64 seconds between retries.
+ *
+ * @const {number}
+ */
+export declare const MAX_RETRY_DELAY_DEFAULT = 64;
+/**
+ * Returns true if the API request should be retried, given the error that was
+ * given the first time the request was attempted.
+ * @const
+ * @param {error} err - The API error to check if it is appropriate to retry.
+ * @return {boolean} True if the API request should be retried, false otherwise.
+ */
+export declare const RETRYABLE_ERR_FN_DEFAULT: (err?: ApiError) => boolean;
+/*! Developer Documentation
+ *
+ * Invoke this method to create a new Storage object bound with pre-determined
+ * configuration options. For each object that can be created (e.g., a bucket),
+ * there is an equivalent static and instance method. While they are classes,
+ * they can be instantiated without use of the `new` keyword.
+ */
+/**
+ * Cloud Storage uses access control lists (ACLs) to manage object and
+ * bucket access. ACLs are the mechanism you use to share objects with other
+ * users and allow other users to access your buckets and objects.
+ *
+ * This object provides constants to refer to the three permission levels that
+ * can be granted to an entity:
+ *
+ * - `gcs.acl.OWNER_ROLE` - ("OWNER")
+ * - `gcs.acl.READER_ROLE` - ("READER")
+ * - `gcs.acl.WRITER_ROLE` - ("WRITER")
+ *
+ * See {@link https://cloud.google.com/storage/docs/access-control/lists| About Access Control Lists}
+ *
+ * @name Storage#acl
+ * @type {object}
+ * @property {string} OWNER_ROLE
+ * @property {string} READER_ROLE
+ * @property {string} WRITER_ROLE
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const albums = storage.bucket('albums');
+ *
+ * //-
+ * // Make all of the files currently in a bucket publicly readable.
+ * //-
+ * const options = {
+ * entity: 'allUsers',
+ * role: storage.acl.READER_ROLE
+ * };
+ *
+ * albums.acl.add(options, function(err, aclObject) {});
+ *
+ * //-
+ * // Make any new objects added to a bucket publicly readable.
+ * //-
+ * albums.acl.default.add(options, function(err, aclObject) {});
+ *
+ * //-
+ * // Grant a user ownership permissions to a bucket.
+ * //-
+ * albums.acl.add({
+ * entity: 'user-useremail@example.com',
+ * role: storage.acl.OWNER_ROLE
+ * }, function(err, aclObject) {});
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * albums.acl.add(options).then(function(data) {
+ * const aclObject = data[0];
+ * const apiResponse = data[1];
+ * });
+ * ```
+ */
+/**
+ * Get {@link Bucket} objects for all of the buckets in your project as
+ * a readable object stream.
+ *
+ * @method Storage#getBucketsStream
+ * @param {GetBucketsRequest} [query] Query object for listing buckets.
+ * @returns {ReadableStream} A readable stream that emits {@link Bucket}
+ * instances.
+ *
+ * @example
+ * ```
+ * storage.getBucketsStream()
+ * .on('error', console.error)
+ * .on('data', function(bucket) {
+ * // bucket is a Bucket object.
+ * })
+ * .on('end', function() {
+ * // All buckets retrieved.
+ * });
+ *
+ * //-
+ * // If you anticipate many results, you can end a stream early to prevent
+ * // unnecessary processing and API requests.
+ * //-
+ * storage.getBucketsStream()
+ * .on('data', function(bucket) {
+ * this.end();
+ * });
+ * ```
+ */
+/**
+ * Get {@link HmacKey} objects for all of the HMAC keys in the project in a
+ * readable object stream.
+ *
+ * @method Storage#getHmacKeysStream
+ * @param {GetHmacKeysOptions} [options] Configuration options.
+ * @returns {ReadableStream} A readable stream that emits {@link HmacKey}
+ * instances.
+ *
+ * @example
+ * ```
+ * storage.getHmacKeysStream()
+ * .on('error', console.error)
+ * .on('data', function(hmacKey) {
+ * // hmacKey is an HmacKey object.
+ * })
+ * .on('end', function() {
+ * // All HmacKey retrieved.
+ * });
+ *
+ * //-
+ * // If you anticipate many results, you can end a stream early to prevent
+ * // unnecessary processing and API requests.
+ * //-
+ * storage.getHmacKeysStream()
+ * .on('data', function(bucket) {
+ * this.end();
+ * });
+ * ```
+ */
+/**
+ * ACLs
+ * Cloud Storage uses access control lists (ACLs) to manage object and
+ * bucket access. ACLs are the mechanism you use to share files with other users
+ * and allow other users to access your buckets and files.
+ *
+ * To learn more about ACLs, read this overview on
+ * {@link https://cloud.google.com/storage/docs/access-control| Access Control}.
+ *
+ * See {@link https://cloud.google.com/storage/docs/overview| Cloud Storage overview}
+ * See {@link https://cloud.google.com/storage/docs/access-control| Access Control}
+ *
+ * @class
+ */
+export declare class Storage extends Service {
+ /**
+ * {@link Bucket} class.
+ *
+ * @name Storage.Bucket
+ * @see Bucket
+ * @type {Constructor}
+ */
+ static Bucket: typeof Bucket;
+ /**
+ * {@link Channel} class.
+ *
+ * @name Storage.Channel
+ * @see Channel
+ * @type {Constructor}
+ */
+ static Channel: typeof Channel;
+ /**
+ * {@link File} class.
+ *
+ * @name Storage.File
+ * @see File
+ * @type {Constructor}
+ */
+ static File: typeof File;
+ /**
+ * {@link HmacKey} class.
+ *
+ * @name Storage.HmacKey
+ * @see HmacKey
+ * @type {Constructor}
+ */
+ static HmacKey: typeof HmacKey;
+ static acl: {
+ OWNER_ROLE: string;
+ READER_ROLE: string;
+ WRITER_ROLE: string;
+ };
+ /**
+ * Reference to {@link Storage.acl}.
+ *
+ * @name Storage#acl
+ * @see Storage.acl
+ */
+ acl: typeof Storage.acl;
+ crc32cGenerator: CRC32CValidatorGenerator;
+ getBucketsStream(): Readable;
+ getHmacKeysStream(): Readable;
+ retryOptions: RetryOptions;
+ /**
+ * @callback Crc32cGeneratorToStringCallback
+ * A method returning the CRC32C as a base64-encoded string.
+ *
+ * @returns {string}
+ *
+ * @example
+ * Hashing the string 'data' should return 'rth90Q=='
+ *
+ * ```js
+ * const buffer = Buffer.from('data');
+ * crc32c.update(buffer);
+ * crc32c.toString(); // 'rth90Q=='
+ * ```
+ **/
+ /**
+ * @callback Crc32cGeneratorValidateCallback
+ * A method validating a base64-encoded CRC32C string.
+ *
+ * @param {string} [value] base64-encoded CRC32C string to validate
+ * @returns {boolean}
+ *
+ * @example
+ * Should return `true` if the value matches, `false` otherwise
+ *
+ * ```js
+ * const buffer = Buffer.from('data');
+ * crc32c.update(buffer);
+ * crc32c.validate('DkjKuA=='); // false
+ * crc32c.validate('rth90Q=='); // true
+ * ```
+ **/
+ /**
+ * @callback Crc32cGeneratorUpdateCallback
+ * A method for passing `Buffer`s for CRC32C generation.
+ *
+ * @param {Buffer} [data] data to update CRC32C value with
+ * @returns {undefined}
+ *
+ * @example
+ * Hashing buffers from 'some ' and 'text\n'
+ *
+ * ```js
+ * const buffer1 = Buffer.from('some ');
+ * crc32c.update(buffer1);
+ *
+ * const buffer2 = Buffer.from('text\n');
+ * crc32c.update(buffer2);
+ *
+ * crc32c.toString(); // 'DkjKuA=='
+ * ```
+ **/
+ /**
+ * @typedef {object} CRC32CValidator
+ * @property {Crc32cGeneratorToStringCallback}
+ * @property {Crc32cGeneratorValidateCallback}
+ * @property {Crc32cGeneratorUpdateCallback}
+ */
+ /**
+ * @callback Crc32cGeneratorCallback
+ * @returns {CRC32CValidator}
+ */
+ /**
+ * @typedef {object} StorageOptions
+ * @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} [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 {object} [retryOptions] Options for customizing retries. Retriable server errors
+ * will be retried with exponential delay between them dictated by the formula
+ * max(maxRetryDelay, retryDelayMultiplier*retryNumber) until maxRetries or totalTimeout
+ * has been reached. Retries will only happen if autoRetry is set to true.
+ * @property {boolean} [retryOptions.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 {number} [retryOptions.retryDelayMultiplier = 2] the multiplier by which to
+ * increase the delay time between the completion of failed requests, and the
+ * initiation of the subsequent retrying request.
+ * @property {number} [retryOptions.totalTimeout = 600] The total time, starting from
+ * when the initial request is sent, after which an error will
+ * be returned, regardless of the retrying attempts made meanwhile.
+ * @property {number} [retryOptions.maxRetryDelay = 64] The maximum delay time between requests.
+ * When this value is reached, ``retryDelayMultiplier`` will no longer be used to
+ * increase delay time.
+ * @property {number} [retryOptions.maxRetries=3] Maximum number of automatic retries
+ * attempted before returning the error.
+ * @property {function} [retryOptions.retryableErrorFn] Function that returns true if a given
+ * error should be retried and false otherwise.
+ * @property {enum} [retryOptions.idempotencyStrategy=IdempotencyStrategy.RetryConditional] Enumeration
+ * controls how conditionally idempotent operations are retried. Possible values are: RetryAlways -
+ * will respect other retry settings and attempt to retry conditionally idempotent operations. RetryConditional -
+ * will retry conditionally idempotent operations if the correct preconditions are set. RetryNever - never
+ * retry a conditionally idempotent operation.
+ * @property {string} [userAgent] The value to be prepended to the User-Agent
+ * header in API requests.
+ * @property {object} [authClient] `AuthClient` or `GoogleAuth` client to reuse instead of creating a new one.
+ * @property {number} [timeout] The amount of time in milliseconds to wait per http request before timing out.
+ * @property {object[]} [interceptors_] Array of custom request interceptors to be returned in the order they were assigned.
+ * @property {string} [apiEndpoint = storage.google.com] The API endpoint of the service used to make requests.
+ * @property {boolean} [useAuthWithCustomEndpoint = false] Controls whether or not to use authentication when using a custom endpoint.
+ * @property {Crc32cGeneratorCallback} [callback] A function that generates a CRC32C Validator. Defaults to {@link CRC32C}
+ */
+ /**
+ * Constructs the Storage client.
+ *
+ * @example
+ * Create a client that uses Application Default Credentials
+ * (ADC)
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * ```
+ *
+ * @example
+ * Create a client with explicit credentials
+ * ```
+ * const storage = new Storage({
+ * projectId: 'your-project-id',
+ * keyFilename: '/path/to/keyfile.json'
+ * });
+ * ```
+ *
+ * @example
+ * Create a client with credentials passed
+ * by value as a JavaScript object
+ * ```
+ * const storage = new Storage({
+ * projectId: 'your-project-id',
+ * credentials: {
+ * type: 'service_account',
+ * project_id: 'xxxxxxx',
+ * private_key_id: 'xxxx',
+ * private_key:'-----BEGIN PRIVATE KEY-----xxxxxxx\n-----END PRIVATE KEY-----\n',
+ * client_email: 'xxxx',
+ * client_id: 'xxx',
+ * auth_uri: 'https://accounts.google.com/o/oauth2/auth',
+ * token_uri: 'https://oauth2.googleapis.com/token',
+ * auth_provider_x509_cert_url: 'https://www.googleapis.com/oauth2/v1/certs',
+ * client_x509_cert_url: 'xxx',
+ * }
+ * });
+ * ```
+ *
+ * @example
+ * Create a client with credentials passed
+ * by loading a JSON file directly from disk
+ * ```
+ * const storage = new Storage({
+ * projectId: 'your-project-id',
+ * credentials: require('/path/to-keyfile.json')
+ * });
+ * ```
+ *
+ * @example
+ * Create a client with an `AuthClient` (e.g. `DownscopedClient`)
+ * ```
+ * const {DownscopedClient} = require('google-auth-library');
+ * const authClient = new DownscopedClient({...});
+ *
+ * const storage = new Storage({authClient});
+ * ```
+ *
+ * Additional samples:
+ * - https://github.com/googleapis/google-auth-library-nodejs#sample-usage-1
+ * - https://github.com/googleapis/google-auth-library-nodejs/blob/main/samples/downscopedclient.js
+ *
+ * @param {StorageOptions} [options] Configuration options.
+ */
+ constructor(options?: StorageOptions);
+ private static sanitizeEndpoint;
+ /**
+ * Get a reference to a Cloud Storage bucket.
+ *
+ * @param {string} name Name of the bucket.
+ * @param {object} [options] Configuration object.
+ * @param {string} [options.kmsKeyName] A Cloud KMS key that will be used to
+ * encrypt objects inserted into this bucket, if no encryption method is
+ * specified.
+ * @param {string} [options.userProject] User project to be billed for all
+ * requests made from this Bucket object.
+ * @returns {Bucket}
+ * @see Bucket
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const albums = storage.bucket('albums');
+ * const photos = storage.bucket('photos');
+ * ```
+ */
+ bucket(name: string, options?: BucketOptions): Bucket;
+ /**
+ * Reference a channel to receive notifications about changes to your bucket.
+ *
+ * @param {string} id The ID of the channel.
+ * @param {string} resourceId The resource ID of the channel.
+ * @returns {Channel}
+ * @see Channel
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const channel = storage.channel('id', 'resource-id');
+ * ```
+ */
+ channel(id: string, resourceId: string): Channel;
+ createBucket(name: string, metadata?: CreateBucketRequest): Promise;
+ createBucket(name: string, callback: BucketCallback): void;
+ createBucket(name: string, metadata: CreateBucketRequest, callback: BucketCallback): void;
+ createBucket(name: string, metadata: CreateBucketRequest, callback: BucketCallback): void;
+ createHmacKey(serviceAccountEmail: string, options?: CreateHmacKeyOptions): Promise;
+ createHmacKey(serviceAccountEmail: string, callback: CreateHmacKeyCallback): void;
+ createHmacKey(serviceAccountEmail: string, options: CreateHmacKeyOptions, callback: CreateHmacKeyCallback): void;
+ getBuckets(options?: GetBucketsRequest): Promise;
+ getBuckets(options: GetBucketsRequest, callback: GetBucketsCallback): void;
+ getBuckets(callback: GetBucketsCallback): void;
+ /**
+ * Query object for listing HMAC keys.
+ *
+ * @typedef {object} GetHmacKeysOptions
+ * @property {string} [projectId] The project ID of the project that owns
+ * the service account of the requested HMAC key. If not provided,
+ * the project ID used to instantiate the Storage client will be used.
+ * @property {string} [serviceAccountEmail] If present, only HMAC keys for the
+ * given service account are returned.
+ * @property {boolean} [showDeletedKeys=false] If true, include keys in the DELETE
+ * state. Default is false.
+ * @property {boolean} [autoPaginate=true] Have pagination handled
+ * automatically.
+ * @property {number} [maxApiCalls] Maximum number of API calls to make.
+ * @property {number} [maxResults] Maximum number of items plus prefixes to
+ * return per call.
+ * Note: By default will handle pagination automatically
+ * if more than 1 page worth of results are requested per call.
+ * When `autoPaginate` is set to `false` the smaller of `maxResults`
+ * or 1 page of results will be returned per call.
+ * @property {string} [pageToken] A previously-returned page token
+ * representing part of the larger set of results to view.
+ * @property {string} [userProject] This parameter is currently ignored.
+ */
+ /**
+ * @typedef {array} GetHmacKeysResponse
+ * @property {HmacKey[]} 0 Array of {@link HmacKey} instances.
+ * @param {object} nextQuery 1 A query object to receive more results.
+ * @param {object} apiResponse 2 The full API response.
+ */
+ /**
+ * @callback GetHmacKeysCallback
+ * @param {?Error} err Request error, if any.
+ * @param {HmacKey[]} hmacKeys Array of {@link HmacKey} instances.
+ * @param {object} nextQuery A query object to receive more results.
+ * @param {object} apiResponse The full API response.
+ */
+ /**
+ * Retrieves a list of HMAC keys matching the criteria.
+ *
+ * The authenticated user must have storage.hmacKeys.list permission for the project in which the key exists.
+ *
+ * @param {GetHmacKeysOption} options Configuration options.
+ * @param {GetHmacKeysCallback} callback Callback function.
+ * @return {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * storage.getHmacKeys(function(err, hmacKeys) {
+ * if (!err) {
+ * // hmacKeys is an array of HmacKey objects.
+ * }
+ * });
+ *
+ * //-
+ * // To control how many API requests are made and page through the results
+ * // manually, set `autoPaginate` to `false`.
+ * //-
+ * const callback = function(err, hmacKeys, nextQuery, apiResponse) {
+ * if (nextQuery) {
+ * // More results exist.
+ * storage.getHmacKeys(nextQuery, callback);
+ * }
+ *
+ * // The `metadata` property is populated for you with the metadata at the
+ * // time of fetching.
+ * hmacKeys[0].metadata;
+ * };
+ *
+ * storage.getHmacKeys({
+ * autoPaginate: false
+ * }, callback);
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * storage.getHmacKeys().then(function(data) {
+ * const hmacKeys = data[0];
+ * });
+ * ```
+ */
+ getHmacKeys(options?: GetHmacKeysOptions): Promise;
+ getHmacKeys(callback: GetHmacKeysCallback): void;
+ getHmacKeys(options: GetHmacKeysOptions, callback: GetHmacKeysCallback): void;
+ getServiceAccount(options?: GetServiceAccountOptions): Promise;
+ getServiceAccount(options?: GetServiceAccountOptions): Promise;
+ getServiceAccount(options: GetServiceAccountOptions, callback: GetServiceAccountCallback): void;
+ getServiceAccount(callback: GetServiceAccountCallback): void;
+ /**
+ * Get a reference to an HmacKey object.
+ * Note: this does not fetch the HMAC key's metadata. Use HmacKey#get() to
+ * retrieve and populate the metadata.
+ *
+ * To get a reference to an HMAC key that's not created for a service
+ * account in the same project used to instantiate the Storage client,
+ * supply the project's ID as `projectId` in the `options` argument.
+ *
+ * @param {string} accessId The HMAC key's access ID.
+ * @param {HmacKeyOptions} options HmacKey constructor options.
+ * @returns {HmacKey}
+ * @see HmacKey
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const hmacKey = storage.hmacKey('ACCESS_ID');
+ * ```
+ */
+ hmacKey(accessId: string, options?: HmacKeyOptions): HmacKey;
+}
+export {};
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/storage.js b/node_modules/@google-cloud/storage/build/cjs/src/storage.js
new file mode 100644
index 0000000..89c6145
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/storage.js
@@ -0,0 +1,1149 @@
+"use strict";
+// Copyright 2019 Google LLC
+//
+// 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.Storage = exports.RETRYABLE_ERR_FN_DEFAULT = exports.MAX_RETRY_DELAY_DEFAULT = exports.TOTAL_TIMEOUT_DEFAULT = exports.RETRY_DELAY_MULTIPLIER_DEFAULT = exports.MAX_RETRY_DEFAULT = exports.AUTO_RETRY_DEFAULT = exports.PROTOCOL_REGEX = exports.StorageExceptionMessages = exports.ExceptionMessages = exports.IdempotencyStrategy = void 0;
+const index_js_1 = require("./nodejs-common/index.js");
+const paginator_1 = require("@google-cloud/paginator");
+const promisify_1 = require("@google-cloud/promisify");
+const stream_1 = require("stream");
+const bucket_js_1 = require("./bucket.js");
+const channel_js_1 = require("./channel.js");
+const file_js_1 = require("./file.js");
+const util_js_1 = require("./util.js");
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+const package_json_helper_cjs_1 = require("./package-json-helper.cjs");
+const hmacKey_js_1 = require("./hmacKey.js");
+const crc32c_js_1 = require("./crc32c.js");
+const google_auth_library_1 = require("google-auth-library");
+var IdempotencyStrategy;
+(function (IdempotencyStrategy) {
+ IdempotencyStrategy[IdempotencyStrategy["RetryAlways"] = 0] = "RetryAlways";
+ IdempotencyStrategy[IdempotencyStrategy["RetryConditional"] = 1] = "RetryConditional";
+ IdempotencyStrategy[IdempotencyStrategy["RetryNever"] = 2] = "RetryNever";
+})(IdempotencyStrategy || (exports.IdempotencyStrategy = IdempotencyStrategy = {}));
+var ExceptionMessages;
+(function (ExceptionMessages) {
+ ExceptionMessages["EXPIRATION_DATE_INVALID"] = "The expiration date provided was invalid.";
+ ExceptionMessages["EXPIRATION_DATE_PAST"] = "An expiration date cannot be in the past.";
+})(ExceptionMessages || (exports.ExceptionMessages = ExceptionMessages = {}));
+var StorageExceptionMessages;
+(function (StorageExceptionMessages) {
+ StorageExceptionMessages["BUCKET_NAME_REQUIRED"] = "A bucket name is needed to use Cloud Storage.";
+ StorageExceptionMessages["BUCKET_NAME_REQUIRED_CREATE"] = "A name is required to create a bucket.";
+ StorageExceptionMessages["HMAC_SERVICE_ACCOUNT"] = "The first argument must be a service account email to create an HMAC key.";
+ StorageExceptionMessages["HMAC_ACCESS_ID"] = "An access ID is needed to create an HmacKey object.";
+})(StorageExceptionMessages || (exports.StorageExceptionMessages = StorageExceptionMessages = {}));
+exports.PROTOCOL_REGEX = /^(\w*):\/\//;
+/**
+ * Default behavior: Automatically retry retriable server errors.
+ *
+ * @const {boolean}
+ */
+exports.AUTO_RETRY_DEFAULT = true;
+/**
+ * Default behavior: Only attempt to retry retriable errors 3 times.
+ *
+ * @const {number}
+ */
+exports.MAX_RETRY_DEFAULT = 3;
+/**
+ * Default behavior: Wait twice as long as previous retry before retrying.
+ *
+ * @const {number}
+ */
+exports.RETRY_DELAY_MULTIPLIER_DEFAULT = 2;
+/**
+ * Default behavior: If the operation doesn't succeed after 600 seconds,
+ * stop retrying.
+ *
+ * @const {number}
+ */
+exports.TOTAL_TIMEOUT_DEFAULT = 600;
+/**
+ * Default behavior: Wait no more than 64 seconds between retries.
+ *
+ * @const {number}
+ */
+exports.MAX_RETRY_DELAY_DEFAULT = 64;
+/**
+ * Default behavior: Retry conditionally idempotent operations if correct preconditions are set.
+ *
+ * @const {enum}
+ * @private
+ */
+const IDEMPOTENCY_STRATEGY_DEFAULT = IdempotencyStrategy.RetryConditional;
+/**
+ * Returns true if the API request should be retried, given the error that was
+ * given the first time the request was attempted.
+ * @const
+ * @param {error} err - The API error to check if it is appropriate to retry.
+ * @return {boolean} True if the API request should be retried, false otherwise.
+ */
+const RETRYABLE_ERR_FN_DEFAULT = function (err) {
+ var _a;
+ const isConnectionProblem = (reason) => {
+ return (reason.includes('eai_again') || // DNS lookup error
+ reason === 'econnreset' ||
+ reason === 'unexpected connection closure' ||
+ reason === 'epipe' ||
+ reason === 'socket connection timeout');
+ };
+ if (err) {
+ if ([408, 429, 500, 502, 503, 504].indexOf(err.code) !== -1) {
+ return true;
+ }
+ if (typeof err.code === 'string') {
+ if (['408', '429', '500', '502', '503', '504'].indexOf(err.code) !== -1) {
+ return true;
+ }
+ const reason = err.code.toLowerCase();
+ if (isConnectionProblem(reason)) {
+ return true;
+ }
+ }
+ if (err.errors) {
+ for (const e of err.errors) {
+ const reason = (_a = e === null || e === void 0 ? void 0 : e.reason) === null || _a === void 0 ? void 0 : _a.toString().toLowerCase();
+ if (reason && isConnectionProblem(reason)) {
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+};
+exports.RETRYABLE_ERR_FN_DEFAULT = RETRYABLE_ERR_FN_DEFAULT;
+/*! Developer Documentation
+ *
+ * Invoke this method to create a new Storage object bound with pre-determined
+ * configuration options. For each object that can be created (e.g., a bucket),
+ * there is an equivalent static and instance method. While they are classes,
+ * they can be instantiated without use of the `new` keyword.
+ */
+/**
+ * Cloud Storage uses access control lists (ACLs) to manage object and
+ * bucket access. ACLs are the mechanism you use to share objects with other
+ * users and allow other users to access your buckets and objects.
+ *
+ * This object provides constants to refer to the three permission levels that
+ * can be granted to an entity:
+ *
+ * - `gcs.acl.OWNER_ROLE` - ("OWNER")
+ * - `gcs.acl.READER_ROLE` - ("READER")
+ * - `gcs.acl.WRITER_ROLE` - ("WRITER")
+ *
+ * See {@link https://cloud.google.com/storage/docs/access-control/lists| About Access Control Lists}
+ *
+ * @name Storage#acl
+ * @type {object}
+ * @property {string} OWNER_ROLE
+ * @property {string} READER_ROLE
+ * @property {string} WRITER_ROLE
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const albums = storage.bucket('albums');
+ *
+ * //-
+ * // Make all of the files currently in a bucket publicly readable.
+ * //-
+ * const options = {
+ * entity: 'allUsers',
+ * role: storage.acl.READER_ROLE
+ * };
+ *
+ * albums.acl.add(options, function(err, aclObject) {});
+ *
+ * //-
+ * // Make any new objects added to a bucket publicly readable.
+ * //-
+ * albums.acl.default.add(options, function(err, aclObject) {});
+ *
+ * //-
+ * // Grant a user ownership permissions to a bucket.
+ * //-
+ * albums.acl.add({
+ * entity: 'user-useremail@example.com',
+ * role: storage.acl.OWNER_ROLE
+ * }, function(err, aclObject) {});
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * albums.acl.add(options).then(function(data) {
+ * const aclObject = data[0];
+ * const apiResponse = data[1];
+ * });
+ * ```
+ */
+/**
+ * Get {@link Bucket} objects for all of the buckets in your project as
+ * a readable object stream.
+ *
+ * @method Storage#getBucketsStream
+ * @param {GetBucketsRequest} [query] Query object for listing buckets.
+ * @returns {ReadableStream} A readable stream that emits {@link Bucket}
+ * instances.
+ *
+ * @example
+ * ```
+ * storage.getBucketsStream()
+ * .on('error', console.error)
+ * .on('data', function(bucket) {
+ * // bucket is a Bucket object.
+ * })
+ * .on('end', function() {
+ * // All buckets retrieved.
+ * });
+ *
+ * //-
+ * // If you anticipate many results, you can end a stream early to prevent
+ * // unnecessary processing and API requests.
+ * //-
+ * storage.getBucketsStream()
+ * .on('data', function(bucket) {
+ * this.end();
+ * });
+ * ```
+ */
+/**
+ * Get {@link HmacKey} objects for all of the HMAC keys in the project in a
+ * readable object stream.
+ *
+ * @method Storage#getHmacKeysStream
+ * @param {GetHmacKeysOptions} [options] Configuration options.
+ * @returns {ReadableStream} A readable stream that emits {@link HmacKey}
+ * instances.
+ *
+ * @example
+ * ```
+ * storage.getHmacKeysStream()
+ * .on('error', console.error)
+ * .on('data', function(hmacKey) {
+ * // hmacKey is an HmacKey object.
+ * })
+ * .on('end', function() {
+ * // All HmacKey retrieved.
+ * });
+ *
+ * //-
+ * // If you anticipate many results, you can end a stream early to prevent
+ * // unnecessary processing and API requests.
+ * //-
+ * storage.getHmacKeysStream()
+ * .on('data', function(bucket) {
+ * this.end();
+ * });
+ * ```
+ */
+/**
+ * ACLs
+ * Cloud Storage uses access control lists (ACLs) to manage object and
+ * bucket access. ACLs are the mechanism you use to share files with other users
+ * and allow other users to access your buckets and files.
+ *
+ * To learn more about ACLs, read this overview on
+ * {@link https://cloud.google.com/storage/docs/access-control| Access Control}.
+ *
+ * See {@link https://cloud.google.com/storage/docs/overview| Cloud Storage overview}
+ * See {@link https://cloud.google.com/storage/docs/access-control| Access Control}
+ *
+ * @class
+ */
+class Storage extends index_js_1.Service {
+ getBucketsStream() {
+ // placeholder body, overwritten in constructor
+ return new stream_1.Readable();
+ }
+ getHmacKeysStream() {
+ // placeholder body, overwritten in constructor
+ return new stream_1.Readable();
+ }
+ /**
+ * @callback Crc32cGeneratorToStringCallback
+ * A method returning the CRC32C as a base64-encoded string.
+ *
+ * @returns {string}
+ *
+ * @example
+ * Hashing the string 'data' should return 'rth90Q=='
+ *
+ * ```js
+ * const buffer = Buffer.from('data');
+ * crc32c.update(buffer);
+ * crc32c.toString(); // 'rth90Q=='
+ * ```
+ **/
+ /**
+ * @callback Crc32cGeneratorValidateCallback
+ * A method validating a base64-encoded CRC32C string.
+ *
+ * @param {string} [value] base64-encoded CRC32C string to validate
+ * @returns {boolean}
+ *
+ * @example
+ * Should return `true` if the value matches, `false` otherwise
+ *
+ * ```js
+ * const buffer = Buffer.from('data');
+ * crc32c.update(buffer);
+ * crc32c.validate('DkjKuA=='); // false
+ * crc32c.validate('rth90Q=='); // true
+ * ```
+ **/
+ /**
+ * @callback Crc32cGeneratorUpdateCallback
+ * A method for passing `Buffer`s for CRC32C generation.
+ *
+ * @param {Buffer} [data] data to update CRC32C value with
+ * @returns {undefined}
+ *
+ * @example
+ * Hashing buffers from 'some ' and 'text\n'
+ *
+ * ```js
+ * const buffer1 = Buffer.from('some ');
+ * crc32c.update(buffer1);
+ *
+ * const buffer2 = Buffer.from('text\n');
+ * crc32c.update(buffer2);
+ *
+ * crc32c.toString(); // 'DkjKuA=='
+ * ```
+ **/
+ /**
+ * @typedef {object} CRC32CValidator
+ * @property {Crc32cGeneratorToStringCallback}
+ * @property {Crc32cGeneratorValidateCallback}
+ * @property {Crc32cGeneratorUpdateCallback}
+ */
+ /**
+ * @callback Crc32cGeneratorCallback
+ * @returns {CRC32CValidator}
+ */
+ /**
+ * @typedef {object} StorageOptions
+ * @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} [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 {object} [retryOptions] Options for customizing retries. Retriable server errors
+ * will be retried with exponential delay between them dictated by the formula
+ * max(maxRetryDelay, retryDelayMultiplier*retryNumber) until maxRetries or totalTimeout
+ * has been reached. Retries will only happen if autoRetry is set to true.
+ * @property {boolean} [retryOptions.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 {number} [retryOptions.retryDelayMultiplier = 2] the multiplier by which to
+ * increase the delay time between the completion of failed requests, and the
+ * initiation of the subsequent retrying request.
+ * @property {number} [retryOptions.totalTimeout = 600] The total time, starting from
+ * when the initial request is sent, after which an error will
+ * be returned, regardless of the retrying attempts made meanwhile.
+ * @property {number} [retryOptions.maxRetryDelay = 64] The maximum delay time between requests.
+ * When this value is reached, ``retryDelayMultiplier`` will no longer be used to
+ * increase delay time.
+ * @property {number} [retryOptions.maxRetries=3] Maximum number of automatic retries
+ * attempted before returning the error.
+ * @property {function} [retryOptions.retryableErrorFn] Function that returns true if a given
+ * error should be retried and false otherwise.
+ * @property {enum} [retryOptions.idempotencyStrategy=IdempotencyStrategy.RetryConditional] Enumeration
+ * controls how conditionally idempotent operations are retried. Possible values are: RetryAlways -
+ * will respect other retry settings and attempt to retry conditionally idempotent operations. RetryConditional -
+ * will retry conditionally idempotent operations if the correct preconditions are set. RetryNever - never
+ * retry a conditionally idempotent operation.
+ * @property {string} [userAgent] The value to be prepended to the User-Agent
+ * header in API requests.
+ * @property {object} [authClient] `AuthClient` or `GoogleAuth` client to reuse instead of creating a new one.
+ * @property {number} [timeout] The amount of time in milliseconds to wait per http request before timing out.
+ * @property {object[]} [interceptors_] Array of custom request interceptors to be returned in the order they were assigned.
+ * @property {string} [apiEndpoint = storage.google.com] The API endpoint of the service used to make requests.
+ * @property {boolean} [useAuthWithCustomEndpoint = false] Controls whether or not to use authentication when using a custom endpoint.
+ * @property {Crc32cGeneratorCallback} [callback] A function that generates a CRC32C Validator. Defaults to {@link CRC32C}
+ */
+ /**
+ * Constructs the Storage client.
+ *
+ * @example
+ * Create a client that uses Application Default Credentials
+ * (ADC)
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * ```
+ *
+ * @example
+ * Create a client with explicit credentials
+ * ```
+ * const storage = new Storage({
+ * projectId: 'your-project-id',
+ * keyFilename: '/path/to/keyfile.json'
+ * });
+ * ```
+ *
+ * @example
+ * Create a client with credentials passed
+ * by value as a JavaScript object
+ * ```
+ * const storage = new Storage({
+ * projectId: 'your-project-id',
+ * credentials: {
+ * type: 'service_account',
+ * project_id: 'xxxxxxx',
+ * private_key_id: 'xxxx',
+ * private_key:'-----BEGIN PRIVATE KEY-----xxxxxxx\n-----END PRIVATE KEY-----\n',
+ * client_email: 'xxxx',
+ * client_id: 'xxx',
+ * auth_uri: 'https://accounts.google.com/o/oauth2/auth',
+ * token_uri: 'https://oauth2.googleapis.com/token',
+ * auth_provider_x509_cert_url: 'https://www.googleapis.com/oauth2/v1/certs',
+ * client_x509_cert_url: 'xxx',
+ * }
+ * });
+ * ```
+ *
+ * @example
+ * Create a client with credentials passed
+ * by loading a JSON file directly from disk
+ * ```
+ * const storage = new Storage({
+ * projectId: 'your-project-id',
+ * credentials: require('/path/to-keyfile.json')
+ * });
+ * ```
+ *
+ * @example
+ * Create a client with an `AuthClient` (e.g. `DownscopedClient`)
+ * ```
+ * const {DownscopedClient} = require('google-auth-library');
+ * const authClient = new DownscopedClient({...});
+ *
+ * const storage = new Storage({authClient});
+ * ```
+ *
+ * Additional samples:
+ * - https://github.com/googleapis/google-auth-library-nodejs#sample-usage-1
+ * - https://github.com/googleapis/google-auth-library-nodejs/blob/main/samples/downscopedclient.js
+ *
+ * @param {StorageOptions} [options] Configuration options.
+ */
+ constructor(options = {}) {
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
+ const universe = options.universeDomain || google_auth_library_1.DEFAULT_UNIVERSE;
+ let apiEndpoint = `https://storage.${universe}`;
+ let customEndpoint = false;
+ // Note: EMULATOR_HOST is an experimental configuration variable. Use apiEndpoint instead.
+ const EMULATOR_HOST = process.env.STORAGE_EMULATOR_HOST;
+ if (typeof EMULATOR_HOST === 'string') {
+ apiEndpoint = Storage.sanitizeEndpoint(EMULATOR_HOST);
+ customEndpoint = true;
+ }
+ if (options.apiEndpoint) {
+ apiEndpoint = Storage.sanitizeEndpoint(options.apiEndpoint);
+ customEndpoint = true;
+ }
+ options = Object.assign({}, options, { apiEndpoint });
+ // Note: EMULATOR_HOST is an experimental configuration variable. Use apiEndpoint instead.
+ const baseUrl = EMULATOR_HOST || `${options.apiEndpoint}/storage/v1`;
+ const config = {
+ apiEndpoint: options.apiEndpoint,
+ retryOptions: {
+ autoRetry: ((_a = options.retryOptions) === null || _a === void 0 ? void 0 : _a.autoRetry) !== undefined
+ ? (_b = options.retryOptions) === null || _b === void 0 ? void 0 : _b.autoRetry
+ : exports.AUTO_RETRY_DEFAULT,
+ maxRetries: ((_c = options.retryOptions) === null || _c === void 0 ? void 0 : _c.maxRetries)
+ ? (_d = options.retryOptions) === null || _d === void 0 ? void 0 : _d.maxRetries
+ : exports.MAX_RETRY_DEFAULT,
+ retryDelayMultiplier: ((_e = options.retryOptions) === null || _e === void 0 ? void 0 : _e.retryDelayMultiplier)
+ ? (_f = options.retryOptions) === null || _f === void 0 ? void 0 : _f.retryDelayMultiplier
+ : exports.RETRY_DELAY_MULTIPLIER_DEFAULT,
+ totalTimeout: ((_g = options.retryOptions) === null || _g === void 0 ? void 0 : _g.totalTimeout)
+ ? (_h = options.retryOptions) === null || _h === void 0 ? void 0 : _h.totalTimeout
+ : exports.TOTAL_TIMEOUT_DEFAULT,
+ maxRetryDelay: ((_j = options.retryOptions) === null || _j === void 0 ? void 0 : _j.maxRetryDelay)
+ ? (_k = options.retryOptions) === null || _k === void 0 ? void 0 : _k.maxRetryDelay
+ : exports.MAX_RETRY_DELAY_DEFAULT,
+ retryableErrorFn: ((_l = options.retryOptions) === null || _l === void 0 ? void 0 : _l.retryableErrorFn)
+ ? (_m = options.retryOptions) === null || _m === void 0 ? void 0 : _m.retryableErrorFn
+ : exports.RETRYABLE_ERR_FN_DEFAULT,
+ idempotencyStrategy: ((_o = options.retryOptions) === null || _o === void 0 ? void 0 : _o.idempotencyStrategy) !== undefined
+ ? (_p = options.retryOptions) === null || _p === void 0 ? void 0 : _p.idempotencyStrategy
+ : IDEMPOTENCY_STRATEGY_DEFAULT,
+ },
+ baseUrl,
+ customEndpoint,
+ useAuthWithCustomEndpoint: options === null || options === void 0 ? void 0 : options.useAuthWithCustomEndpoint,
+ projectIdRequired: false,
+ scopes: [
+ 'https://www.googleapis.com/auth/iam',
+ 'https://www.googleapis.com/auth/cloud-platform',
+ 'https://www.googleapis.com/auth/devstorage.full_control',
+ ],
+ packageJson: (0, package_json_helper_cjs_1.getPackageJSON)(),
+ };
+ super(config, options);
+ /**
+ * Reference to {@link Storage.acl}.
+ *
+ * @name Storage#acl
+ * @see Storage.acl
+ */
+ this.acl = Storage.acl;
+ this.crc32cGenerator =
+ options.crc32cGenerator || crc32c_js_1.CRC32C_DEFAULT_VALIDATOR_GENERATOR;
+ this.retryOptions = config.retryOptions;
+ this.getBucketsStream = paginator_1.paginator.streamify('getBuckets');
+ this.getHmacKeysStream = paginator_1.paginator.streamify('getHmacKeys');
+ }
+ static sanitizeEndpoint(url) {
+ if (!exports.PROTOCOL_REGEX.test(url)) {
+ url = `https://${url}`;
+ }
+ return url.replace(/\/+$/, ''); // Remove trailing slashes
+ }
+ /**
+ * Get a reference to a Cloud Storage bucket.
+ *
+ * @param {string} name Name of the bucket.
+ * @param {object} [options] Configuration object.
+ * @param {string} [options.kmsKeyName] A Cloud KMS key that will be used to
+ * encrypt objects inserted into this bucket, if no encryption method is
+ * specified.
+ * @param {string} [options.userProject] User project to be billed for all
+ * requests made from this Bucket object.
+ * @returns {Bucket}
+ * @see Bucket
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const albums = storage.bucket('albums');
+ * const photos = storage.bucket('photos');
+ * ```
+ */
+ bucket(name, options) {
+ if (!name) {
+ throw new Error(StorageExceptionMessages.BUCKET_NAME_REQUIRED);
+ }
+ return new bucket_js_1.Bucket(this, name, options);
+ }
+ /**
+ * Reference a channel to receive notifications about changes to your bucket.
+ *
+ * @param {string} id The ID of the channel.
+ * @param {string} resourceId The resource ID of the channel.
+ * @returns {Channel}
+ * @see Channel
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const channel = storage.channel('id', 'resource-id');
+ * ```
+ */
+ channel(id, resourceId) {
+ return new channel_js_1.Channel(this, id, resourceId);
+ }
+ /**
+ * @typedef {array} CreateBucketResponse
+ * @property {Bucket} 0 The new {@link Bucket}.
+ * @property {object} 1 The full API response.
+ */
+ /**
+ * @callback CreateBucketCallback
+ * @param {?Error} err Request error, if any.
+ * @param {Bucket} bucket The new {@link Bucket}.
+ * @param {object} apiResponse The full API response.
+ */
+ /**
+ * Metadata to set for the bucket.
+ *
+ * @typedef {object} CreateBucketRequest
+ * @property {boolean} [archive=false] Specify the storage class as Archive.
+ * @property {object} [autoclass.enabled=false] Specify whether Autoclass is
+ * enabled for the bucket.
+ * @property {object} [autoclass.terminalStorageClass='NEARLINE'] The storage class that objects in an Autoclass bucket eventually transition to if
+ * they are not read for a certain length of time. Valid values are NEARLINE and ARCHIVE.
+ * @property {boolean} [coldline=false] Specify the storage class as Coldline.
+ * @property {Cors[]} [cors=[]] Specify the CORS configuration to use.
+ * @property {CustomPlacementConfig} [customPlacementConfig={}] Specify the bucket's regions for dual-region buckets.
+ * For more information, see {@link https://cloud.google.com/storage/docs/locations| Bucket Locations}.
+ * @property {boolean} [dra=false] Specify the storage class as Durable Reduced
+ * Availability.
+ * @property {boolean} [enableObjectRetention=false] Specifiy whether or not object retention should be enabled on this bucket.
+ * @property {string} [location] Specify the bucket's location. If specifying
+ * a dual-region, the `customPlacementConfig` property should be set in conjunction.
+ * For more information, see {@link https://cloud.google.com/storage/docs/locations| Bucket Locations}.
+ * @property {boolean} [multiRegional=false] Specify the storage class as
+ * Multi-Regional.
+ * @property {boolean} [nearline=false] Specify the storage class as Nearline.
+ * @property {boolean} [regional=false] Specify the storage class as Regional.
+ * @property {boolean} [requesterPays=false] **Early Access Testers Only**
+ * Force the use of the User Project metadata field to assign operational
+ * costs when an operation is made on a Bucket and its objects.
+ * @property {string} [rpo] For dual-region buckets, controls whether turbo
+ * replication is enabled (`ASYNC_TURBO`) or disabled (`DEFAULT`).
+ * @property {boolean} [standard=true] Specify the storage class as Standard.
+ * @property {string} [storageClass] The new storage class. (`standard`,
+ * `nearline`, `coldline`, or `archive`).
+ * **Note:** The storage classes `multi_regional`, `regional`, and
+ * `durable_reduced_availability` are now legacy and will be deprecated in
+ * the future.
+ * @property {Versioning} [versioning=undefined] Specify the versioning status.
+ * @property {string} [userProject] The ID of the project which will be billed
+ * for the request.
+ */
+ /**
+ * Create a bucket.
+ *
+ * Cloud Storage uses a flat namespace, so you can't create a bucket with
+ * a name that is already in use. For more information, see
+ * {@link https://cloud.google.com/storage/docs/bucketnaming.html#requirements| Bucket Naming Guidelines}.
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/buckets/insert| Buckets: insert API Documentation}
+ * See {@link https://cloud.google.com/storage/docs/storage-classes| Storage Classes}
+ *
+ * @param {string} name Name of the bucket to create.
+ * @param {CreateBucketRequest} [metadata] Metadata to set for the bucket.
+ * @param {CreateBucketCallback} [callback] Callback function.
+ * @returns {Promise}
+ * @throws {Error} If a name is not provided.
+ * @see Bucket#create
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const callback = function(err, bucket, apiResponse) {
+ * // `bucket` is a Bucket object.
+ * };
+ *
+ * storage.createBucket('new-bucket', callback);
+ *
+ * //-
+ * // Create a bucket in a specific location and region. See the
+ * // Official JSON API docs for complete details on the `location`
+ * option.
+ * //
+ * //-
+ * const metadata = {
+ * location: 'US-CENTRAL1',
+ * regional: true
+ * };
+ *
+ * storage.createBucket('new-bucket', metadata, callback);
+ *
+ * //-
+ * // Create a bucket with a retention policy of 6 months.
+ * //-
+ * const metadata = {
+ * retentionPolicy: {
+ * retentionPeriod: 15780000 // 6 months in seconds.
+ * }
+ * };
+ *
+ * storage.createBucket('new-bucket', metadata, callback);
+ *
+ * //-
+ * // Enable versioning on a new bucket.
+ * //-
+ * const metadata = {
+ * versioning: {
+ * enabled: true
+ * }
+ * };
+ *
+ * storage.createBucket('new-bucket', metadata, callback);
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * storage.createBucket('new-bucket').then(function(data) {
+ * const bucket = data[0];
+ * const apiResponse = data[1];
+ * });
+ *
+ * ```
+ * @example include:samples/buckets.js
+ * region_tag:storage_create_bucket
+ * Another example:
+ */
+ createBucket(name, metadataOrCallback, callback) {
+ if (!name) {
+ throw new Error(StorageExceptionMessages.BUCKET_NAME_REQUIRED_CREATE);
+ }
+ let metadata;
+ if (!callback) {
+ callback = metadataOrCallback;
+ metadata = {};
+ }
+ else {
+ metadata = metadataOrCallback;
+ }
+ const body = {
+ ...metadata,
+ name,
+ };
+ const storageClasses = {
+ archive: 'ARCHIVE',
+ coldline: 'COLDLINE',
+ dra: 'DURABLE_REDUCED_AVAILABILITY',
+ multiRegional: 'MULTI_REGIONAL',
+ nearline: 'NEARLINE',
+ regional: 'REGIONAL',
+ standard: 'STANDARD',
+ };
+ const storageClassKeys = Object.keys(storageClasses);
+ for (const storageClass of storageClassKeys) {
+ if (body[storageClass]) {
+ if (metadata.storageClass && metadata.storageClass !== storageClass) {
+ throw new Error(`Both \`${storageClass}\` and \`storageClass\` were provided.`);
+ }
+ body.storageClass = storageClasses[storageClass];
+ delete body[storageClass];
+ }
+ }
+ if (body.requesterPays) {
+ body.billing = {
+ requesterPays: body.requesterPays,
+ };
+ delete body.requesterPays;
+ }
+ const query = {
+ project: this.projectId,
+ };
+ if (body.userProject) {
+ query.userProject = body.userProject;
+ delete body.userProject;
+ }
+ if (body.enableObjectRetention) {
+ query.enableObjectRetention = body.enableObjectRetention;
+ delete body.enableObjectRetention;
+ }
+ this.request({
+ method: 'POST',
+ uri: '/b',
+ qs: query,
+ json: body,
+ }, (err, resp) => {
+ if (err) {
+ callback(err, null, resp);
+ return;
+ }
+ const bucket = this.bucket(name);
+ bucket.metadata = resp;
+ callback(null, bucket, resp);
+ });
+ }
+ /**
+ * @typedef {object} CreateHmacKeyOptions
+ * @property {string} [projectId] The project ID of the project that owns
+ * the service account of the requested HMAC key. If not provided,
+ * the project ID used to instantiate the Storage client will be used.
+ * @property {string} [userProject] This parameter is currently ignored.
+ */
+ /**
+ * @typedef {object} HmacKeyMetadata
+ * @property {string} accessId The access id identifies which HMAC key was
+ * used to sign a request when authenticating with HMAC.
+ * @property {string} etag Used to perform a read-modify-write of the key.
+ * @property {string} id The resource name of the HMAC key.
+ * @property {string} projectId The project ID.
+ * @property {string} serviceAccountEmail The service account's email this
+ * HMAC key is created for.
+ * @property {string} state The state of this HMAC key. One of "ACTIVE",
+ * "INACTIVE" or "DELETED".
+ * @property {string} timeCreated The creation time of the HMAC key in
+ * RFC 3339 format.
+ * @property {string} [updated] The time this HMAC key was last updated in
+ * RFC 3339 format.
+ */
+ /**
+ * @typedef {array} CreateHmacKeyResponse
+ * @property {HmacKey} 0 The HmacKey instance created from API response.
+ * @property {string} 1 The HMAC key's secret used to access the XML API.
+ * @property {object} 3 The raw API response.
+ */
+ /**
+ * @callback CreateHmacKeyCallback Callback function.
+ * @param {?Error} err Request error, if any.
+ * @param {HmacKey} hmacKey The HmacKey instance created from API response.
+ * @param {string} secret The HMAC key's secret used to access the XML API.
+ * @param {object} apiResponse The raw API response.
+ */
+ /**
+ * Create an HMAC key associated with an service account to authenticate
+ * requests to the Cloud Storage XML API.
+ *
+ * See {@link https://cloud.google.com/storage/docs/authentication/hmackeys| HMAC keys documentation}
+ *
+ * @param {string} serviceAccountEmail The service account's email address
+ * with which the HMAC key is created for.
+ * @param {CreateHmacKeyCallback} [callback] Callback function.
+ * @return {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('google-cloud/storage');
+ * const storage = new Storage();
+ *
+ * // Replace with your service account's email address
+ * const serviceAccountEmail =
+ * 'my-service-account@appspot.gserviceaccount.com';
+ *
+ * storage.createHmacKey(serviceAccountEmail, function(err, hmacKey, secret) {
+ * if (!err) {
+ * // Securely store the secret for use with the XML API.
+ * }
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * storage.createHmacKey(serviceAccountEmail)
+ * .then((response) => {
+ * const hmacKey = response[0];
+ * const secret = response[1];
+ * // Securely store the secret for use with the XML API.
+ * });
+ * ```
+ */
+ createHmacKey(serviceAccountEmail, optionsOrCb, cb) {
+ if (typeof serviceAccountEmail !== 'string') {
+ throw new Error(StorageExceptionMessages.HMAC_SERVICE_ACCOUNT);
+ }
+ const { options, callback } = (0, util_js_1.normalize)(optionsOrCb, cb);
+ const query = Object.assign({}, options, { serviceAccountEmail });
+ const projectId = query.projectId || this.projectId;
+ delete query.projectId;
+ this.request({
+ method: 'POST',
+ uri: `/projects/${projectId}/hmacKeys`,
+ qs: query,
+ maxRetries: 0, //explicitly set this value since this is a non-idempotent function
+ }, (err, resp) => {
+ if (err) {
+ callback(err, null, null, resp);
+ return;
+ }
+ const metadata = resp.metadata;
+ const hmacKey = this.hmacKey(metadata.accessId, {
+ projectId: metadata.projectId,
+ });
+ hmacKey.metadata = resp.metadata;
+ callback(null, hmacKey, resp.secret, resp);
+ });
+ }
+ /**
+ * Query object for listing buckets.
+ *
+ * @typedef {object} GetBucketsRequest
+ * @property {boolean} [autoPaginate=true] Have pagination handled
+ * automatically.
+ * @property {number} [maxApiCalls] Maximum number of API calls to make.
+ * @property {number} [maxResults] Maximum number of items plus prefixes to
+ * return per call.
+ * Note: By default will handle pagination automatically
+ * if more than 1 page worth of results are requested per call.
+ * When `autoPaginate` is set to `false` the smaller of `maxResults`
+ * or 1 page of results will be returned per call.
+ * @property {string} [pageToken] A previously-returned page token
+ * representing part of the larger set of results to view.
+ * @property {string} [userProject] The ID of the project which will be billed
+ * for the request.
+ */
+ /**
+ * @typedef {array} GetBucketsResponse
+ * @property {Bucket[]} 0 Array of {@link Bucket} instances.
+ * @property {object} 1 nextQuery A query object to receive more results.
+ * @property {object} 2 The full API response.
+ */
+ /**
+ * @callback GetBucketsCallback
+ * @param {?Error} err Request error, if any.
+ * @param {Bucket[]} buckets Array of {@link Bucket} instances.
+ * @param {object} nextQuery A query object to receive more results.
+ * @param {object} apiResponse The full API response.
+ */
+ /**
+ * Get Bucket objects for all of the buckets in your project.
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/buckets/list| Buckets: list API Documentation}
+ *
+ * @param {GetBucketsRequest} [query] Query object for listing buckets.
+ * @param {GetBucketsCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * storage.getBuckets(function(err, buckets) {
+ * if (!err) {
+ * // buckets is an array of Bucket objects.
+ * }
+ * });
+ *
+ * //-
+ * // To control how many API requests are made and page through the results
+ * // manually, set `autoPaginate` to `false`.
+ * //-
+ * const callback = function(err, buckets, nextQuery, apiResponse) {
+ * if (nextQuery) {
+ * // More results exist.
+ * storage.getBuckets(nextQuery, callback);
+ * }
+ *
+ * // The `metadata` property is populated for you with the metadata at the
+ * // time of fetching.
+ * buckets[0].metadata;
+ *
+ * // However, in cases where you are concerned the metadata could have
+ * // changed, use the `getMetadata` method.
+ * buckets[0].getMetadata(function(err, metadata, apiResponse) {});
+ * };
+ *
+ * storage.getBuckets({
+ * autoPaginate: false
+ * }, callback);
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * storage.getBuckets().then(function(data) {
+ * const buckets = data[0];
+ * });
+ *
+ * ```
+ * @example include:samples/buckets.js
+ * region_tag:storage_list_buckets
+ * Another example:
+ */
+ getBuckets(optionsOrCallback, cb) {
+ const { options, callback } = (0, util_js_1.normalize)(optionsOrCallback, cb);
+ options.project = options.project || this.projectId;
+ this.request({
+ uri: '/b',
+ qs: options,
+ }, (err, resp) => {
+ if (err) {
+ callback(err, null, null, resp);
+ return;
+ }
+ const itemsArray = resp.items ? resp.items : [];
+ const buckets = itemsArray.map((bucket) => {
+ const bucketInstance = this.bucket(bucket.id);
+ bucketInstance.metadata = bucket;
+ return bucketInstance;
+ });
+ const nextQuery = resp.nextPageToken
+ ? Object.assign({}, options, { pageToken: resp.nextPageToken })
+ : null;
+ callback(null, buckets, nextQuery, resp);
+ });
+ }
+ getHmacKeys(optionsOrCb, cb) {
+ const { options, callback } = (0, util_js_1.normalize)(optionsOrCb, cb);
+ const query = Object.assign({}, options);
+ const projectId = query.projectId || this.projectId;
+ delete query.projectId;
+ this.request({
+ uri: `/projects/${projectId}/hmacKeys`,
+ qs: query,
+ }, (err, resp) => {
+ if (err) {
+ callback(err, null, null, resp);
+ return;
+ }
+ const itemsArray = resp.items ? resp.items : [];
+ const hmacKeys = itemsArray.map((hmacKey) => {
+ const hmacKeyInstance = this.hmacKey(hmacKey.accessId, {
+ projectId: hmacKey.projectId,
+ });
+ hmacKeyInstance.metadata = hmacKey;
+ return hmacKeyInstance;
+ });
+ const nextQuery = resp.nextPageToken
+ ? Object.assign({}, options, { pageToken: resp.nextPageToken })
+ : null;
+ callback(null, hmacKeys, nextQuery, resp);
+ });
+ }
+ /**
+ * @typedef {array} GetServiceAccountResponse
+ * @property {object} 0 The service account resource.
+ * @property {object} 1 The full
+ * {@link https://cloud.google.com/storage/docs/json_api/v1/projects/serviceAccount#resource| API response}.
+ */
+ /**
+ * @callback GetServiceAccountCallback
+ * @param {?Error} err Request error, if any.
+ * @param {object} serviceAccount The serviceAccount resource.
+ * @param {string} serviceAccount.emailAddress The service account email
+ * address.
+ * @param {object} apiResponse The full
+ * {@link https://cloud.google.com/storage/docs/json_api/v1/projects/serviceAccount#resource| API response}.
+ */
+ /**
+ * Get the email address of this project's Google Cloud Storage service
+ * account.
+ *
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/projects/serviceAccount/get| Projects.serviceAccount: get API Documentation}
+ * See {@link https://cloud.google.com/storage/docs/json_api/v1/projects/serviceAccount#resource| Projects.serviceAccount Resource}
+ *
+ * @param {object} [options] Configuration object.
+ * @param {string} [options.userProject] User project to be billed for this
+ * request.
+ * @param {GetServiceAccountCallback} [callback] Callback function.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ *
+ * storage.getServiceAccount(function(err, serviceAccount, apiResponse) {
+ * if (!err) {
+ * const serviceAccountEmail = serviceAccount.emailAddress;
+ * }
+ * });
+ *
+ * //-
+ * // If the callback is omitted, we'll return a Promise.
+ * //-
+ * storage.getServiceAccount().then(function(data) {
+ * const serviceAccountEmail = data[0].emailAddress;
+ * const apiResponse = data[1];
+ * });
+ * ```
+ */
+ getServiceAccount(optionsOrCallback, cb) {
+ const { options, callback } = (0, util_js_1.normalize)(optionsOrCallback, cb);
+ this.request({
+ uri: `/projects/${this.projectId}/serviceAccount`,
+ qs: options,
+ }, (err, resp) => {
+ if (err) {
+ callback(err, null, resp);
+ return;
+ }
+ const camelCaseResponse = {};
+ for (const prop in resp) {
+ // eslint-disable-next-line no-prototype-builtins
+ if (resp.hasOwnProperty(prop)) {
+ const camelCaseProp = prop.replace(/_(\w)/g, (_, match) => match.toUpperCase());
+ camelCaseResponse[camelCaseProp] = resp[prop];
+ }
+ }
+ callback(null, camelCaseResponse, resp);
+ });
+ }
+ /**
+ * Get a reference to an HmacKey object.
+ * Note: this does not fetch the HMAC key's metadata. Use HmacKey#get() to
+ * retrieve and populate the metadata.
+ *
+ * To get a reference to an HMAC key that's not created for a service
+ * account in the same project used to instantiate the Storage client,
+ * supply the project's ID as `projectId` in the `options` argument.
+ *
+ * @param {string} accessId The HMAC key's access ID.
+ * @param {HmacKeyOptions} options HmacKey constructor options.
+ * @returns {HmacKey}
+ * @see HmacKey
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const hmacKey = storage.hmacKey('ACCESS_ID');
+ * ```
+ */
+ hmacKey(accessId, options) {
+ if (!accessId) {
+ throw new Error(StorageExceptionMessages.HMAC_ACCESS_ID);
+ }
+ return new hmacKey_js_1.HmacKey(this, accessId, options);
+ }
+}
+exports.Storage = Storage;
+/**
+ * {@link Bucket} class.
+ *
+ * @name Storage.Bucket
+ * @see Bucket
+ * @type {Constructor}
+ */
+Storage.Bucket = bucket_js_1.Bucket;
+/**
+ * {@link Channel} class.
+ *
+ * @name Storage.Channel
+ * @see Channel
+ * @type {Constructor}
+ */
+Storage.Channel = channel_js_1.Channel;
+/**
+ * {@link File} class.
+ *
+ * @name Storage.File
+ * @see File
+ * @type {Constructor}
+ */
+Storage.File = file_js_1.File;
+/**
+ * {@link HmacKey} class.
+ *
+ * @name Storage.HmacKey
+ * @see HmacKey
+ * @type {Constructor}
+ */
+Storage.HmacKey = hmacKey_js_1.HmacKey;
+Storage.acl = {
+ OWNER_ROLE: 'OWNER',
+ READER_ROLE: 'READER',
+ WRITER_ROLE: 'WRITER',
+};
+/*! Developer Documentation
+ *
+ * These methods can be auto-paginated.
+ */
+paginator_1.paginator.extend(Storage, ['getBuckets', 'getHmacKeys']);
+/*! Developer Documentation
+ *
+ * All async methods (except for streams) will return a Promise in the event
+ * that a callback is omitted.
+ */
+(0, promisify_1.promisifyAll)(Storage, {
+ exclude: ['bucket', 'channel', 'hmacKey'],
+});
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/transfer-manager.d.ts b/node_modules/@google-cloud/storage/build/cjs/src/transfer-manager.d.ts
new file mode 100644
index 0000000..9bf8fd7
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/transfer-manager.d.ts
@@ -0,0 +1,246 @@
+/*!
+ * Copyright 2022 Google LLC. 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.
+ */
+///
+import { Bucket, UploadOptions, UploadResponse } from './bucket.js';
+import { DownloadOptions, DownloadResponse, File } from './file.js';
+import { GaxiosResponse } from 'gaxios';
+export interface UploadManyFilesOptions {
+ concurrencyLimit?: number;
+ skipIfExists?: boolean;
+ prefix?: string;
+ passthroughOptions?: Omit;
+}
+export interface DownloadManyFilesOptions {
+ concurrencyLimit?: number;
+ prefix?: string;
+ stripPrefix?: string;
+ passthroughOptions?: DownloadOptions;
+}
+export interface DownloadFileInChunksOptions {
+ concurrencyLimit?: number;
+ chunkSizeBytes?: number;
+ destination?: string;
+ validation?: 'crc32c' | false;
+ noReturnData?: boolean;
+}
+export interface UploadFileInChunksOptions {
+ concurrencyLimit?: number;
+ chunkSizeBytes?: number;
+ uploadName?: string;
+ maxQueueSize?: number;
+ uploadId?: string;
+ autoAbortFailure?: boolean;
+ partsMap?: Map;
+ validation?: 'md5' | false;
+ headers?: {
+ [key: string]: string;
+ };
+}
+export interface MultiPartUploadHelper {
+ bucket: Bucket;
+ fileName: string;
+ uploadId?: string;
+ partsMap?: Map;
+ initiateUpload(headers?: {
+ [key: string]: string;
+ }): Promise;
+ uploadPart(partNumber: number, chunk: Buffer, validation?: 'md5' | false): Promise;
+ completeUpload(): Promise;
+ abortUpload(): Promise;
+}
+export type MultiPartHelperGenerator = (bucket: Bucket, fileName: string, uploadId?: string, partsMap?: Map) => MultiPartUploadHelper;
+export declare class MultiPartUploadError extends Error {
+ private uploadId;
+ private partsMap;
+ constructor(message: string, uploadId: string, partsMap: Map);
+}
+/**
+ * Create a TransferManager object to perform parallel transfer operations on a Cloud Storage bucket.
+ *
+ * @class
+ * @hideconstructor
+ *
+ * @param {Bucket} bucket A {@link Bucket} instance
+ *
+ */
+export declare class TransferManager {
+ bucket: Bucket;
+ constructor(bucket: Bucket);
+ /**
+ * @typedef {object} UploadManyFilesOptions
+ * @property {number} [concurrencyLimit] The number of concurrently executing promises
+ * to use when uploading the files.
+ * @property {boolean} [skipIfExists] Do not upload the file if it already exists in
+ * the bucket. This will set the precondition ifGenerationMatch = 0.
+ * @property {string} [prefix] A prefix to append to all of the uploaded files.
+ * @property {object} [passthroughOptions] {@link UploadOptions} Options to be passed through
+ * to each individual upload operation.
+ *
+ */
+ /**
+ * Upload multiple files in parallel to the bucket. This is a convenience method
+ * that utilizes {@link Bucket#upload} to perform the upload.
+ *
+ * @param {array | string} [filePathsOrDirectory] An array of fully qualified paths to the files or a directory name.
+ * If a directory name is provided, the directory will be recursively walked and all files will be added to the upload list.
+ * to be uploaded to the bucket
+ * @param {UploadManyFilesOptions} [options] Configuration options.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('my-bucket');
+ * const transferManager = new TransferManager(bucket);
+ *
+ * //-
+ * // Upload multiple files in parallel.
+ * //-
+ * const response = await transferManager.uploadManyFiles(['/local/path/file1.txt, 'local/path/file2.txt']);
+ * // Your bucket now contains:
+ * // - "local/path/file1.txt" (with the contents of '/local/path/file1.txt')
+ * // - "local/path/file2.txt" (with the contents of '/local/path/file2.txt')
+ * const response = await transferManager.uploadManyFiles('/local/directory');
+ * // Your bucket will now contain all files contained in '/local/directory' maintaining the subdirectory structure.
+ * ```
+ *
+ */
+ uploadManyFiles(filePathsOrDirectory: string[] | string, options?: UploadManyFilesOptions): Promise;
+ /**
+ * @typedef {object} DownloadManyFilesOptions
+ * @property {number} [concurrencyLimit] The number of concurrently executing promises
+ * to use when downloading the files.
+ * @property {string} [prefix] A prefix to append to all of the downloaded files.
+ * @property {string} [stripPrefix] A prefix to remove from all of the downloaded files.
+ * @property {object} [passthroughOptions] {@link DownloadOptions} Options to be passed through
+ * to each individual download operation.
+ *
+ */
+ /**
+ * Download multiple files in parallel to the local filesystem. This is a convenience method
+ * that utilizes {@link File#download} to perform the download.
+ *
+ * @param {array | string} [filesOrFolder] An array of file name strings or file objects to be downloaded. If
+ * a string is provided this will be treated as a GCS prefix and all files with that prefix will be downloaded.
+ * @param {DownloadManyFilesOptions} [options] Configuration options.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('my-bucket');
+ * const transferManager = new TransferManager(bucket);
+ *
+ * //-
+ * // Download multiple files in parallel.
+ * //-
+ * const response = await transferManager.downloadManyFiles(['file1.txt', 'file2.txt']);
+ * // The following files have been downloaded:
+ * // - "file1.txt" (with the contents from my-bucket.file1.txt)
+ * // - "file2.txt" (with the contents from my-bucket.file2.txt)
+ * const response = await transferManager.downloadManyFiles([bucket.File('file1.txt'), bucket.File('file2.txt')]);
+ * // The following files have been downloaded:
+ * // - "file1.txt" (with the contents from my-bucket.file1.txt)
+ * // - "file2.txt" (with the contents from my-bucket.file2.txt)
+ * const response = await transferManager.downloadManyFiles('test-folder');
+ * // All files with GCS prefix of 'test-folder' have been downloaded.
+ * ```
+ *
+ */
+ downloadManyFiles(filesOrFolder: File[] | string[] | string, options?: DownloadManyFilesOptions): Promise;
+ /**
+ * @typedef {object} DownloadFileInChunksOptions
+ * @property {number} [concurrencyLimit] The number of concurrently executing promises
+ * to use when downloading the file.
+ * @property {number} [chunkSizeBytes] The size in bytes of each chunk to be downloaded.
+ * @property {string | boolean} [validation] Whether or not to perform a CRC32C validation check when download is complete.
+ * @property {boolean} [noReturnData] Whether or not to return the downloaded data. A `true` value here would be useful for files with a size that will not fit into memory.
+ *
+ */
+ /**
+ * Download a large file in chunks utilizing parallel download operations. This is a convenience method
+ * that utilizes {@link File#download} to perform the download.
+ *
+ * @param {File | string} fileOrName {@link File} to download.
+ * @param {DownloadFileInChunksOptions} [options] Configuration options.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('my-bucket');
+ * const transferManager = new TransferManager(bucket);
+ *
+ * //-
+ * // Download a large file in chunks utilizing parallel operations.
+ * //-
+ * const response = await transferManager.downloadFileInChunks(bucket.file('large-file.txt');
+ * // Your local directory now contains:
+ * // - "large-file.txt" (with the contents from my-bucket.large-file.txt)
+ * ```
+ *
+ */
+ downloadFileInChunks(fileOrName: File | string, options?: DownloadFileInChunksOptions): Promise;
+ /**
+ * @typedef {object} UploadFileInChunksOptions
+ * @property {number} [concurrencyLimit] The number of concurrently executing promises
+ * to use when uploading the file.
+ * @property {number} [chunkSizeBytes] The size in bytes of each chunk to be uploaded.
+ * @property {string} [uploadName] Name of the file when saving to GCS. If ommitted the name is taken from the file path.
+ * @property {number} [maxQueueSize] The number of chunks to be uploaded to hold in memory concurrently. If not specified
+ * defaults to the specified concurrency limit.
+ * @property {string} [uploadId] If specified attempts to resume a previous upload.
+ * @property {Map} [partsMap] If specified alongside uploadId, attempts to resume a previous upload from the last chunk
+ * specified in partsMap
+ * @property {object} [headers] headers to be sent when initiating the multipart upload.
+ * See {@link https://cloud.google.com/storage/docs/xml-api/post-object-multipart#request_headers| Request Headers: Initiate a Multipart Upload}
+ * @property {boolean} [autoAbortFailure] boolean to indicate if an in progress upload session will be automatically aborted upon failure. If not set,
+ * failures will be automatically aborted.
+ *
+ */
+ /**
+ * Upload a large file in chunks utilizing parallel upload opertions. If the upload fails, an uploadId and
+ * map containing all the successfully uploaded parts will be returned to the caller. These arguments can be used to
+ * resume the upload.
+ *
+ * @param {string} [filePath] The path of the file to be uploaded
+ * @param {UploadFileInChunksOptions} [options] Configuration options.
+ * @param {MultiPartHelperGenerator} [generator] A function that will return a type that implements the MPU interface. Most users will not need to use this.
+ * @returns {Promise} If successful a promise resolving to void, otherwise a error containing the message, uploadid, and parts map.
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('my-bucket');
+ * const transferManager = new TransferManager(bucket);
+ *
+ * //-
+ * // Upload a large file in chunks utilizing parallel operations.
+ * //-
+ * const response = await transferManager.uploadFileInChunks('large-file.txt');
+ * // Your bucket now contains:
+ * // - "large-file.txt"
+ * ```
+ *
+ *
+ */
+ uploadFileInChunks(filePath: string, options?: UploadFileInChunksOptions, generator?: MultiPartHelperGenerator): Promise;
+ private getPathsFromDirectory;
+}
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/transfer-manager.js b/node_modules/@google-cloud/storage/build/cjs/src/transfer-manager.js
new file mode 100644
index 0000000..6d5c77c
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/transfer-manager.js
@@ -0,0 +1,664 @@
+"use strict";
+/*!
+ * Copyright 2022 Google LLC. 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.
+ */
+var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = { enumerable: true, get: function() { return m[k]; } };
+ }
+ Object.defineProperty(o, k2, desc);
+}) : (function(o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+}));
+var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
+}) : function(o, v) {
+ o["default"] = v;
+});
+var __importStar = (this && this.__importStar) || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
+};
+var __importDefault = (this && this.__importDefault) || function (mod) {
+ return (mod && mod.__esModule) ? mod : { "default": mod };
+};
+var _XMLMultiPartUploadHelper_instances, _XMLMultiPartUploadHelper_setGoogApiClientHeaders, _XMLMultiPartUploadHelper_handleErrorResponse;
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.TransferManager = exports.MultiPartUploadError = void 0;
+const file_js_1 = require("./file.js");
+const p_limit_1 = __importDefault(require("p-limit"));
+const path = __importStar(require("path"));
+const fs_1 = require("fs");
+const crc32c_js_1 = require("./crc32c.js");
+const google_auth_library_1 = require("google-auth-library");
+const fast_xml_parser_1 = require("fast-xml-parser");
+const async_retry_1 = __importDefault(require("async-retry"));
+const crypto_1 = require("crypto");
+const util_js_1 = require("./nodejs-common/util.js");
+const util_js_2 = require("./util.js");
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+const package_json_helper_cjs_1 = require("./package-json-helper.cjs");
+const packageJson = (0, package_json_helper_cjs_1.getPackageJSON)();
+/**
+ * Default number of concurrently executing promises to use when calling uploadManyFiles.
+ *
+ */
+const DEFAULT_PARALLEL_UPLOAD_LIMIT = 5;
+/**
+ * Default number of concurrently executing promises to use when calling downloadManyFiles.
+ *
+ */
+const DEFAULT_PARALLEL_DOWNLOAD_LIMIT = 5;
+/**
+ * Default number of concurrently executing promises to use when calling downloadFileInChunks.
+ *
+ */
+const DEFAULT_PARALLEL_CHUNKED_DOWNLOAD_LIMIT = 5;
+/**
+ * The minimum size threshold in bytes at which to apply a chunked download strategy when calling downloadFileInChunks.
+ *
+ */
+const DOWNLOAD_IN_CHUNKS_FILE_SIZE_THRESHOLD = 32 * 1024 * 1024;
+/**
+ * The chunk size in bytes to use when calling downloadFileInChunks.
+ *
+ */
+const DOWNLOAD_IN_CHUNKS_DEFAULT_CHUNK_SIZE = 32 * 1024 * 1024;
+/**
+ * The chunk size in bytes to use when calling uploadFileInChunks.
+ *
+ */
+const UPLOAD_IN_CHUNKS_DEFAULT_CHUNK_SIZE = 32 * 1024 * 1024;
+/**
+ * Default number of concurrently executing promises to use when calling uploadFileInChunks.
+ *
+ */
+const DEFAULT_PARALLEL_CHUNKED_UPLOAD_LIMIT = 5;
+const EMPTY_REGEX = '(?:)';
+/**
+ * The `gccl-gcs-cmd` value for the `X-Goog-API-Client` header.
+ * Example: `gccl-gcs-cmd/tm.upload_many`
+ *
+ * @see {@link GCCL_GCS_CMD}.
+ * @see {@link GCCL_GCS_CMD_KEY}.
+ */
+const GCCL_GCS_CMD_FEATURE = {
+ UPLOAD_MANY: 'tm.upload_many',
+ DOWNLOAD_MANY: 'tm.download_many',
+ UPLOAD_SHARDED: 'tm.upload_sharded',
+ DOWNLOAD_SHARDED: 'tm.download_sharded',
+};
+const defaultMultiPartGenerator = (bucket, fileName, uploadId, partsMap) => {
+ return new XMLMultiPartUploadHelper(bucket, fileName, uploadId, partsMap);
+};
+class MultiPartUploadError extends Error {
+ constructor(message, uploadId, partsMap) {
+ super(message);
+ this.uploadId = uploadId;
+ this.partsMap = partsMap;
+ }
+}
+exports.MultiPartUploadError = MultiPartUploadError;
+/**
+ * Class representing an implementation of MPU in the XML API. This class is not meant for public usage.
+ *
+ * @private
+ *
+ */
+class XMLMultiPartUploadHelper {
+ constructor(bucket, fileName, uploadId, partsMap) {
+ _XMLMultiPartUploadHelper_instances.add(this);
+ this.authClient = bucket.storage.authClient || new google_auth_library_1.GoogleAuth();
+ this.uploadId = uploadId || '';
+ this.bucket = bucket;
+ this.fileName = fileName;
+ this.baseUrl = `https://${bucket.name}.${new URL(this.bucket.storage.apiEndpoint).hostname}/${fileName}`;
+ this.xmlBuilder = new fast_xml_parser_1.XMLBuilder({ arrayNodeName: 'Part' });
+ this.xmlParser = new fast_xml_parser_1.XMLParser();
+ this.partsMap = partsMap || new Map();
+ this.retryOptions = {
+ retries: this.bucket.storage.retryOptions.maxRetries,
+ factor: this.bucket.storage.retryOptions.retryDelayMultiplier,
+ maxTimeout: this.bucket.storage.retryOptions.maxRetryDelay * 1000,
+ maxRetryTime: this.bucket.storage.retryOptions.totalTimeout * 1000,
+ };
+ }
+ /**
+ * Initiates a multipart upload (MPU) to the XML API and stores the resultant upload id.
+ *
+ * @returns {Promise}
+ */
+ async initiateUpload(headers = {}) {
+ const url = `${this.baseUrl}?uploads`;
+ return (0, async_retry_1.default)(async (bail) => {
+ try {
+ const res = await this.authClient.request({
+ headers: __classPrivateFieldGet(this, _XMLMultiPartUploadHelper_instances, "m", _XMLMultiPartUploadHelper_setGoogApiClientHeaders).call(this, headers),
+ method: 'POST',
+ url,
+ });
+ if (res.data && res.data.error) {
+ throw res.data.error;
+ }
+ const parsedXML = this.xmlParser.parse(res.data);
+ this.uploadId = parsedXML.InitiateMultipartUploadResult.UploadId;
+ }
+ catch (e) {
+ __classPrivateFieldGet(this, _XMLMultiPartUploadHelper_instances, "m", _XMLMultiPartUploadHelper_handleErrorResponse).call(this, e, bail);
+ }
+ }, this.retryOptions);
+ }
+ /**
+ * Uploads the provided chunk of data to the XML API using the previously created upload id.
+ *
+ * @param {number} partNumber the sequence number of this chunk.
+ * @param {Buffer} chunk the chunk of data to be uploaded.
+ * @param {string | false} validation whether or not to include the md5 hash in the headers to cause the server
+ * to validate the chunk was not corrupted.
+ * @returns {Promise}
+ */
+ async uploadPart(partNumber, chunk, validation) {
+ const url = `${this.baseUrl}?partNumber=${partNumber}&uploadId=${this.uploadId}`;
+ let headers = __classPrivateFieldGet(this, _XMLMultiPartUploadHelper_instances, "m", _XMLMultiPartUploadHelper_setGoogApiClientHeaders).call(this);
+ if (validation === 'md5') {
+ const hash = (0, crypto_1.createHash)('md5').update(chunk).digest('base64');
+ headers = {
+ 'Content-MD5': hash,
+ };
+ }
+ return (0, async_retry_1.default)(async (bail) => {
+ try {
+ const res = await this.authClient.request({
+ url,
+ method: 'PUT',
+ body: chunk,
+ headers,
+ });
+ if (res.data && res.data.error) {
+ throw res.data.error;
+ }
+ this.partsMap.set(partNumber, res.headers['etag']);
+ }
+ catch (e) {
+ __classPrivateFieldGet(this, _XMLMultiPartUploadHelper_instances, "m", _XMLMultiPartUploadHelper_handleErrorResponse).call(this, e, bail);
+ }
+ }, this.retryOptions);
+ }
+ /**
+ * Sends the final request of the MPU to tell GCS the upload is now complete.
+ *
+ * @returns {Promise}
+ */
+ async completeUpload() {
+ const url = `${this.baseUrl}?uploadId=${this.uploadId}`;
+ const sortedMap = new Map([...this.partsMap.entries()].sort((a, b) => a[0] - b[0]));
+ const parts = [];
+ for (const entry of sortedMap.entries()) {
+ parts.push({ PartNumber: entry[0], ETag: entry[1] });
+ }
+ const body = `${this.xmlBuilder.build(parts)}`;
+ return (0, async_retry_1.default)(async (bail) => {
+ try {
+ const res = await this.authClient.request({
+ headers: __classPrivateFieldGet(this, _XMLMultiPartUploadHelper_instances, "m", _XMLMultiPartUploadHelper_setGoogApiClientHeaders).call(this),
+ url,
+ method: 'POST',
+ body,
+ });
+ if (res.data && res.data.error) {
+ throw res.data.error;
+ }
+ return res;
+ }
+ catch (e) {
+ __classPrivateFieldGet(this, _XMLMultiPartUploadHelper_instances, "m", _XMLMultiPartUploadHelper_handleErrorResponse).call(this, e, bail);
+ return;
+ }
+ }, this.retryOptions);
+ }
+ /**
+ * Aborts an multipart upload that is in progress. Once aborted, any parts in the process of being uploaded fail,
+ * and future requests using the upload ID fail.
+ *
+ * @returns {Promise}
+ */
+ async abortUpload() {
+ const url = `${this.baseUrl}?uploadId=${this.uploadId}`;
+ return (0, async_retry_1.default)(async (bail) => {
+ try {
+ const res = await this.authClient.request({
+ url,
+ method: 'DELETE',
+ });
+ if (res.data && res.data.error) {
+ throw res.data.error;
+ }
+ }
+ catch (e) {
+ __classPrivateFieldGet(this, _XMLMultiPartUploadHelper_instances, "m", _XMLMultiPartUploadHelper_handleErrorResponse).call(this, e, bail);
+ return;
+ }
+ }, this.retryOptions);
+ }
+}
+_XMLMultiPartUploadHelper_instances = new WeakSet(), _XMLMultiPartUploadHelper_setGoogApiClientHeaders = function _XMLMultiPartUploadHelper_setGoogApiClientHeaders(headers = {}) {
+ let headerFound = false;
+ let userAgentFound = false;
+ for (const [key, value] of Object.entries(headers)) {
+ if (key.toLocaleLowerCase().trim() === 'x-goog-api-client') {
+ headerFound = true;
+ // Prepend command feature to value, if not already there
+ if (!value.includes(GCCL_GCS_CMD_FEATURE.UPLOAD_SHARDED)) {
+ headers[key] = `${value} gccl-gcs-cmd/${GCCL_GCS_CMD_FEATURE.UPLOAD_SHARDED}`;
+ }
+ }
+ else if (key.toLocaleLowerCase().trim() === 'user-agent') {
+ userAgentFound = true;
+ }
+ }
+ // If the header isn't present, add it
+ if (!headerFound) {
+ headers['x-goog-api-client'] = `${(0, util_js_2.getRuntimeTrackingString)()} gccl/${packageJson.version} gccl-gcs-cmd/${GCCL_GCS_CMD_FEATURE.UPLOAD_SHARDED}`;
+ }
+ // If the User-Agent isn't present, add it
+ if (!userAgentFound) {
+ headers['User-Agent'] = (0, util_js_2.getUserAgentString)();
+ }
+ return headers;
+}, _XMLMultiPartUploadHelper_handleErrorResponse = function _XMLMultiPartUploadHelper_handleErrorResponse(err, bail) {
+ if (this.bucket.storage.retryOptions.autoRetry &&
+ this.bucket.storage.retryOptions.retryableErrorFn(err)) {
+ throw err;
+ }
+ else {
+ bail(err);
+ }
+};
+/**
+ * Create a TransferManager object to perform parallel transfer operations on a Cloud Storage bucket.
+ *
+ * @class
+ * @hideconstructor
+ *
+ * @param {Bucket} bucket A {@link Bucket} instance
+ *
+ */
+class TransferManager {
+ constructor(bucket) {
+ this.bucket = bucket;
+ }
+ /**
+ * @typedef {object} UploadManyFilesOptions
+ * @property {number} [concurrencyLimit] The number of concurrently executing promises
+ * to use when uploading the files.
+ * @property {boolean} [skipIfExists] Do not upload the file if it already exists in
+ * the bucket. This will set the precondition ifGenerationMatch = 0.
+ * @property {string} [prefix] A prefix to append to all of the uploaded files.
+ * @property {object} [passthroughOptions] {@link UploadOptions} Options to be passed through
+ * to each individual upload operation.
+ *
+ */
+ /**
+ * Upload multiple files in parallel to the bucket. This is a convenience method
+ * that utilizes {@link Bucket#upload} to perform the upload.
+ *
+ * @param {array | string} [filePathsOrDirectory] An array of fully qualified paths to the files or a directory name.
+ * If a directory name is provided, the directory will be recursively walked and all files will be added to the upload list.
+ * to be uploaded to the bucket
+ * @param {UploadManyFilesOptions} [options] Configuration options.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('my-bucket');
+ * const transferManager = new TransferManager(bucket);
+ *
+ * //-
+ * // Upload multiple files in parallel.
+ * //-
+ * const response = await transferManager.uploadManyFiles(['/local/path/file1.txt, 'local/path/file2.txt']);
+ * // Your bucket now contains:
+ * // - "local/path/file1.txt" (with the contents of '/local/path/file1.txt')
+ * // - "local/path/file2.txt" (with the contents of '/local/path/file2.txt')
+ * const response = await transferManager.uploadManyFiles('/local/directory');
+ * // Your bucket will now contain all files contained in '/local/directory' maintaining the subdirectory structure.
+ * ```
+ *
+ */
+ async uploadManyFiles(filePathsOrDirectory, options = {}) {
+ var _a;
+ if (options.skipIfExists && ((_a = options.passthroughOptions) === null || _a === void 0 ? void 0 : _a.preconditionOpts)) {
+ options.passthroughOptions.preconditionOpts.ifGenerationMatch = 0;
+ }
+ else if (options.skipIfExists &&
+ options.passthroughOptions === undefined) {
+ options.passthroughOptions = {
+ preconditionOpts: {
+ ifGenerationMatch: 0,
+ },
+ };
+ }
+ const limit = (0, p_limit_1.default)(options.concurrencyLimit || DEFAULT_PARALLEL_UPLOAD_LIMIT);
+ const promises = [];
+ let allPaths = [];
+ if (!Array.isArray(filePathsOrDirectory)) {
+ for await (const curPath of this.getPathsFromDirectory(filePathsOrDirectory)) {
+ allPaths.push(curPath);
+ }
+ }
+ else {
+ allPaths = filePathsOrDirectory;
+ }
+ for (const filePath of allPaths) {
+ const stat = await fs_1.promises.lstat(filePath);
+ if (stat.isDirectory()) {
+ continue;
+ }
+ const passThroughOptionsCopy = {
+ ...options.passthroughOptions,
+ [util_js_1.GCCL_GCS_CMD_KEY]: GCCL_GCS_CMD_FEATURE.UPLOAD_MANY,
+ };
+ passThroughOptionsCopy.destination = filePath
+ .split(path.sep)
+ .join(path.posix.sep);
+ if (options.prefix) {
+ passThroughOptionsCopy.destination = path.posix.join(...options.prefix.split(path.sep), passThroughOptionsCopy.destination);
+ }
+ promises.push(limit(() => this.bucket.upload(filePath, passThroughOptionsCopy)));
+ }
+ return Promise.all(promises);
+ }
+ /**
+ * @typedef {object} DownloadManyFilesOptions
+ * @property {number} [concurrencyLimit] The number of concurrently executing promises
+ * to use when downloading the files.
+ * @property {string} [prefix] A prefix to append to all of the downloaded files.
+ * @property {string} [stripPrefix] A prefix to remove from all of the downloaded files.
+ * @property {object} [passthroughOptions] {@link DownloadOptions} Options to be passed through
+ * to each individual download operation.
+ *
+ */
+ /**
+ * Download multiple files in parallel to the local filesystem. This is a convenience method
+ * that utilizes {@link File#download} to perform the download.
+ *
+ * @param {array | string} [filesOrFolder] An array of file name strings or file objects to be downloaded. If
+ * a string is provided this will be treated as a GCS prefix and all files with that prefix will be downloaded.
+ * @param {DownloadManyFilesOptions} [options] Configuration options.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('my-bucket');
+ * const transferManager = new TransferManager(bucket);
+ *
+ * //-
+ * // Download multiple files in parallel.
+ * //-
+ * const response = await transferManager.downloadManyFiles(['file1.txt', 'file2.txt']);
+ * // The following files have been downloaded:
+ * // - "file1.txt" (with the contents from my-bucket.file1.txt)
+ * // - "file2.txt" (with the contents from my-bucket.file2.txt)
+ * const response = await transferManager.downloadManyFiles([bucket.File('file1.txt'), bucket.File('file2.txt')]);
+ * // The following files have been downloaded:
+ * // - "file1.txt" (with the contents from my-bucket.file1.txt)
+ * // - "file2.txt" (with the contents from my-bucket.file2.txt)
+ * const response = await transferManager.downloadManyFiles('test-folder');
+ * // All files with GCS prefix of 'test-folder' have been downloaded.
+ * ```
+ *
+ */
+ async downloadManyFiles(filesOrFolder, options = {}) {
+ const limit = (0, p_limit_1.default)(options.concurrencyLimit || DEFAULT_PARALLEL_DOWNLOAD_LIMIT);
+ const promises = [];
+ let files = [];
+ if (!Array.isArray(filesOrFolder)) {
+ const directoryFiles = await this.bucket.getFiles({
+ prefix: filesOrFolder,
+ });
+ files = directoryFiles[0];
+ }
+ else {
+ files = filesOrFolder.map(curFile => {
+ if (typeof curFile === 'string') {
+ return this.bucket.file(curFile);
+ }
+ return curFile;
+ });
+ }
+ const stripRegexString = options.stripPrefix
+ ? `^${options.stripPrefix}`
+ : EMPTY_REGEX;
+ const regex = new RegExp(stripRegexString, 'g');
+ for (const file of files) {
+ const passThroughOptionsCopy = {
+ ...options.passthroughOptions,
+ [util_js_1.GCCL_GCS_CMD_KEY]: GCCL_GCS_CMD_FEATURE.DOWNLOAD_MANY,
+ };
+ if (options.prefix) {
+ passThroughOptionsCopy.destination = path.join(options.prefix || '', passThroughOptionsCopy.destination || '', file.name);
+ }
+ if (options.stripPrefix) {
+ passThroughOptionsCopy.destination = file.name.replace(regex, '');
+ }
+ promises.push(limit(() => file.download(passThroughOptionsCopy)));
+ }
+ return Promise.all(promises);
+ }
+ /**
+ * @typedef {object} DownloadFileInChunksOptions
+ * @property {number} [concurrencyLimit] The number of concurrently executing promises
+ * to use when downloading the file.
+ * @property {number} [chunkSizeBytes] The size in bytes of each chunk to be downloaded.
+ * @property {string | boolean} [validation] Whether or not to perform a CRC32C validation check when download is complete.
+ * @property {boolean} [noReturnData] Whether or not to return the downloaded data. A `true` value here would be useful for files with a size that will not fit into memory.
+ *
+ */
+ /**
+ * Download a large file in chunks utilizing parallel download operations. This is a convenience method
+ * that utilizes {@link File#download} to perform the download.
+ *
+ * @param {File | string} fileOrName {@link File} to download.
+ * @param {DownloadFileInChunksOptions} [options] Configuration options.
+ * @returns {Promise}
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('my-bucket');
+ * const transferManager = new TransferManager(bucket);
+ *
+ * //-
+ * // Download a large file in chunks utilizing parallel operations.
+ * //-
+ * const response = await transferManager.downloadFileInChunks(bucket.file('large-file.txt');
+ * // Your local directory now contains:
+ * // - "large-file.txt" (with the contents from my-bucket.large-file.txt)
+ * ```
+ *
+ */
+ async downloadFileInChunks(fileOrName, options = {}) {
+ let chunkSize = options.chunkSizeBytes || DOWNLOAD_IN_CHUNKS_DEFAULT_CHUNK_SIZE;
+ let limit = (0, p_limit_1.default)(options.concurrencyLimit || DEFAULT_PARALLEL_CHUNKED_DOWNLOAD_LIMIT);
+ const noReturnData = Boolean(options.noReturnData);
+ const promises = [];
+ const file = typeof fileOrName === 'string'
+ ? this.bucket.file(fileOrName)
+ : fileOrName;
+ const fileInfo = await file.get();
+ const size = parseInt(fileInfo[0].metadata.size.toString());
+ // If the file size does not meet the threshold download it as a single chunk.
+ if (size < DOWNLOAD_IN_CHUNKS_FILE_SIZE_THRESHOLD) {
+ limit = (0, p_limit_1.default)(1);
+ chunkSize = size;
+ }
+ let start = 0;
+ const filePath = options.destination || path.basename(file.name);
+ const fileToWrite = await fs_1.promises.open(filePath, 'w');
+ while (start < size) {
+ const chunkStart = start;
+ let chunkEnd = start + chunkSize - 1;
+ chunkEnd = chunkEnd > size ? size : chunkEnd;
+ promises.push(limit(async () => {
+ const resp = await file.download({
+ start: chunkStart,
+ end: chunkEnd,
+ [util_js_1.GCCL_GCS_CMD_KEY]: GCCL_GCS_CMD_FEATURE.DOWNLOAD_SHARDED,
+ });
+ const result = await fileToWrite.write(resp[0], 0, resp[0].length, chunkStart);
+ if (noReturnData)
+ return;
+ return result.buffer;
+ }));
+ start += chunkSize;
+ }
+ let chunks;
+ try {
+ chunks = await Promise.all(promises);
+ }
+ finally {
+ await fileToWrite.close();
+ }
+ if (options.validation === 'crc32c' && fileInfo[0].metadata.crc32c) {
+ const downloadedCrc32C = await crc32c_js_1.CRC32C.fromFile(filePath);
+ if (!downloadedCrc32C.validate(fileInfo[0].metadata.crc32c)) {
+ const mismatchError = new file_js_1.RequestError(file_js_1.FileExceptionMessages.DOWNLOAD_MISMATCH);
+ mismatchError.code = 'CONTENT_DOWNLOAD_MISMATCH';
+ throw mismatchError;
+ }
+ }
+ if (noReturnData)
+ return;
+ return [Buffer.concat(chunks, size)];
+ }
+ /**
+ * @typedef {object} UploadFileInChunksOptions
+ * @property {number} [concurrencyLimit] The number of concurrently executing promises
+ * to use when uploading the file.
+ * @property {number} [chunkSizeBytes] The size in bytes of each chunk to be uploaded.
+ * @property {string} [uploadName] Name of the file when saving to GCS. If ommitted the name is taken from the file path.
+ * @property {number} [maxQueueSize] The number of chunks to be uploaded to hold in memory concurrently. If not specified
+ * defaults to the specified concurrency limit.
+ * @property {string} [uploadId] If specified attempts to resume a previous upload.
+ * @property {Map} [partsMap] If specified alongside uploadId, attempts to resume a previous upload from the last chunk
+ * specified in partsMap
+ * @property {object} [headers] headers to be sent when initiating the multipart upload.
+ * See {@link https://cloud.google.com/storage/docs/xml-api/post-object-multipart#request_headers| Request Headers: Initiate a Multipart Upload}
+ * @property {boolean} [autoAbortFailure] boolean to indicate if an in progress upload session will be automatically aborted upon failure. If not set,
+ * failures will be automatically aborted.
+ *
+ */
+ /**
+ * Upload a large file in chunks utilizing parallel upload opertions. If the upload fails, an uploadId and
+ * map containing all the successfully uploaded parts will be returned to the caller. These arguments can be used to
+ * resume the upload.
+ *
+ * @param {string} [filePath] The path of the file to be uploaded
+ * @param {UploadFileInChunksOptions} [options] Configuration options.
+ * @param {MultiPartHelperGenerator} [generator] A function that will return a type that implements the MPU interface. Most users will not need to use this.
+ * @returns {Promise} If successful a promise resolving to void, otherwise a error containing the message, uploadid, and parts map.
+ *
+ * @example
+ * ```
+ * const {Storage} = require('@google-cloud/storage');
+ * const storage = new Storage();
+ * const bucket = storage.bucket('my-bucket');
+ * const transferManager = new TransferManager(bucket);
+ *
+ * //-
+ * // Upload a large file in chunks utilizing parallel operations.
+ * //-
+ * const response = await transferManager.uploadFileInChunks('large-file.txt');
+ * // Your bucket now contains:
+ * // - "large-file.txt"
+ * ```
+ *
+ *
+ */
+ async uploadFileInChunks(filePath, options = {}, generator = defaultMultiPartGenerator) {
+ const chunkSize = options.chunkSizeBytes || UPLOAD_IN_CHUNKS_DEFAULT_CHUNK_SIZE;
+ const limit = (0, p_limit_1.default)(options.concurrencyLimit || DEFAULT_PARALLEL_CHUNKED_UPLOAD_LIMIT);
+ const maxQueueSize = options.maxQueueSize ||
+ options.concurrencyLimit ||
+ DEFAULT_PARALLEL_CHUNKED_UPLOAD_LIMIT;
+ const fileName = options.uploadName || path.basename(filePath);
+ const mpuHelper = generator(this.bucket, fileName, options.uploadId, options.partsMap);
+ let partNumber = 1;
+ let promises = [];
+ try {
+ if (options.uploadId === undefined) {
+ await mpuHelper.initiateUpload(options.headers);
+ }
+ const startOrResumptionByte = mpuHelper.partsMap.size * chunkSize;
+ const readStream = (0, fs_1.createReadStream)(filePath, {
+ highWaterMark: chunkSize,
+ start: startOrResumptionByte,
+ });
+ // p-limit only limits the number of running promises. We do not want to hold an entire
+ // large file in memory at once so promises acts a queue that will hold only maxQueueSize in memory.
+ for await (const curChunk of readStream) {
+ if (promises.length >= maxQueueSize) {
+ await Promise.all(promises);
+ promises = [];
+ }
+ promises.push(limit(() => mpuHelper.uploadPart(partNumber++, curChunk, options.validation)));
+ }
+ await Promise.all(promises);
+ return await mpuHelper.completeUpload();
+ }
+ catch (e) {
+ if ((options.autoAbortFailure === undefined || options.autoAbortFailure) &&
+ mpuHelper.uploadId) {
+ try {
+ await mpuHelper.abortUpload();
+ return;
+ }
+ catch (e) {
+ throw new MultiPartUploadError(e.message, mpuHelper.uploadId, mpuHelper.partsMap);
+ }
+ }
+ throw new MultiPartUploadError(e.message, mpuHelper.uploadId, mpuHelper.partsMap);
+ }
+ }
+ async *getPathsFromDirectory(directory) {
+ const filesAndSubdirectories = await fs_1.promises.readdir(directory, {
+ withFileTypes: true,
+ });
+ for (const curFileOrDirectory of filesAndSubdirectories) {
+ const fullPath = path.join(directory, curFileOrDirectory.name);
+ curFileOrDirectory.isDirectory()
+ ? yield* this.getPathsFromDirectory(fullPath)
+ : yield fullPath;
+ }
+ }
+}
+exports.TransferManager = TransferManager;
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/util.d.ts b/node_modules/@google-cloud/storage/build/cjs/src/util.d.ts
new file mode 100644
index 0000000..6f3a18b
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/util.d.ts
@@ -0,0 +1,88 @@
+///
+///
+///
+import * as querystring from 'querystring';
+import { PassThrough } from 'stream';
+export declare function normalize(optionsOrCallback?: T | U, cb?: U): {
+ options: T;
+ callback: U;
+};
+/**
+ * Flatten an object into an Array of arrays, [[key, value], ..].
+ * Implements Object.entries() for Node.js <8
+ * @internal
+ */
+export declare function objectEntries(obj: {
+ [key: string]: T;
+}): Array<[string, T]>;
+/**
+ * Encode `str` with encodeURIComponent, plus these
+ * reserved characters: `! * ' ( )`.
+ *
+ * See {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent| MDN: fixedEncodeURIComponent}
+ *
+ * @param {string} str The URI component to encode.
+ * @return {string} The encoded string.
+ */
+export declare function fixedEncodeURIComponent(str: string): string;
+/**
+ * URI encode `uri` for generating signed URLs, using fixedEncodeURIComponent.
+ *
+ * Encode every byte except `A-Z a-Z 0-9 ~ - . _`.
+ *
+ * @param {string} uri The URI to encode.
+ * @param [boolean=false] encodeSlash If `true`, the "/" character is not encoded.
+ * @return {string} The encoded string.
+ */
+export declare function encodeURI(uri: string, encodeSlash: boolean): string;
+/**
+ * Serialize an object to a URL query string using util.encodeURI(uri, true).
+ * @param {string} url The object to serialize.
+ * @return {string} Serialized string.
+ */
+export declare function qsStringify(qs: querystring.ParsedUrlQueryInput): string;
+export declare function objectKeyToLowercase(object: {
+ [key: string]: T;
+}): {
+ [key: string]: T;
+};
+/**
+ * JSON encode str, with unicode \u+ representation.
+ * @param {object} obj The object to encode.
+ * @return {string} Serialized string.
+ */
+export declare function unicodeJSONStringify(obj: object): string;
+/**
+ * Converts the given objects keys to snake_case
+ * @param {object} obj object to convert keys to snake case.
+ * @returns {object} object with keys converted to snake case.
+ */
+export declare function convertObjKeysToSnakeCase(obj: object): object;
+/**
+ * Formats the provided date object as a UTC ISO string.
+ * @param {Date} dateTimeToFormat date object to be formatted.
+ * @param {boolean} includeTime flag to include hours, minutes, seconds in output.
+ * @param {string} dateDelimiter delimiter between date components.
+ * @param {string} timeDelimiter delimiter between time components.
+ * @returns {string} UTC ISO format of provided date obect.
+ */
+export declare function formatAsUTCISO(dateTimeToFormat: Date, includeTime?: boolean, dateDelimiter?: string, timeDelimiter?: string): string;
+/**
+ * Examines the runtime environment and returns the appropriate tracking string.
+ * @returns {string} metrics tracking string based on the current runtime environment.
+ */
+export declare function getRuntimeTrackingString(): string;
+/**
+ * Looks at package.json and creates the user-agent string to be applied to request headers.
+ * @returns {string} user agent string.
+ */
+export declare function getUserAgentString(): string;
+export declare function getDirName(): string;
+export declare function getModuleFormat(): "ESM" | "CJS";
+export declare class PassThroughShim extends PassThrough {
+ private shouldEmitReading;
+ private shouldEmitWriting;
+ _read(size: number): void;
+ _write(chunk: never, encoding: BufferEncoding, callback: (error?: Error | null | undefined) => void): void;
+ _final(callback: (error?: Error | null | undefined) => void): void;
+}
diff --git a/node_modules/@google-cloud/storage/build/cjs/src/util.js b/node_modules/@google-cloud/storage/build/cjs/src/util.js
new file mode 100644
index 0000000..f0645a7
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/cjs/src/util.js
@@ -0,0 +1,270 @@
+"use strict";
+
+// Copyright 2019 Google LLC
+//
+// 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.
+var __createBinding = this && this.__createBinding || (Object.create ? function (o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ var desc = Object.getOwnPropertyDescriptor(m, k);
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
+ desc = {
+ enumerable: true,
+ get: function () {
+ return m[k];
+ }
+ };
+ }
+ Object.defineProperty(o, k2, desc);
+} : function (o, m, k, k2) {
+ if (k2 === undefined) k2 = k;
+ o[k2] = m[k];
+});
+var __setModuleDefault = this && this.__setModuleDefault || (Object.create ? function (o, v) {
+ Object.defineProperty(o, "default", {
+ enumerable: true,
+ value: v
+ });
+} : function (o, v) {
+ o["default"] = v;
+});
+var __importStar = this && this.__importStar || function (mod) {
+ if (mod && mod.__esModule) return mod;
+ var result = {};
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
+ __setModuleDefault(result, mod);
+ return result;
+};
+Object.defineProperty(exports, "__esModule", {
+ value: true
+});
+exports.PassThroughShim = exports.getModuleFormat = exports.getDirName = exports.getUserAgentString = exports.getRuntimeTrackingString = exports.formatAsUTCISO = exports.convertObjKeysToSnakeCase = exports.unicodeJSONStringify = exports.objectKeyToLowercase = exports.qsStringify = exports.encodeURI = exports.fixedEncodeURIComponent = exports.objectEntries = exports.normalize = void 0;
+const path = __importStar(require("path"));
+const querystring = __importStar(require("querystring"));
+const stream_1 = require("stream");
+const url = __importStar(require("url"));
+// eslint-disable-next-line @typescript-eslint/ban-ts-comment
+// @ts-ignore
+const package_json_helper_cjs_1 = require("./package-json-helper.cjs");
+// Done to avoid a problem with mangling of identifiers when using esModuleInterop
+const fileURLToPath = url.fileURLToPath;
+const isEsm = false;
+function normalize(optionsOrCallback, cb) {
+ const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
+ const callback = typeof optionsOrCallback === 'function' ? optionsOrCallback : cb;
+ return {
+ options,
+ callback
+ };
+}
+exports.normalize = normalize;
+/**
+ * Flatten an object into an Array of arrays, [[key, value], ..].
+ * Implements Object.entries() for Node.js <8
+ * @internal
+ */
+function objectEntries(obj) {
+ return Object.keys(obj).map(key => [key, obj[key]]);
+}
+exports.objectEntries = objectEntries;
+/**
+ * Encode `str` with encodeURIComponent, plus these
+ * reserved characters: `! * ' ( )`.
+ *
+ * See {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent| MDN: fixedEncodeURIComponent}
+ *
+ * @param {string} str The URI component to encode.
+ * @return {string} The encoded string.
+ */
+function fixedEncodeURIComponent(str) {
+ return encodeURIComponent(str).replace(/[!'()*]/g, c => '%' + c.charCodeAt(0).toString(16).toUpperCase());
+}
+exports.fixedEncodeURIComponent = fixedEncodeURIComponent;
+/**
+ * URI encode `uri` for generating signed URLs, using fixedEncodeURIComponent.
+ *
+ * Encode every byte except `A-Z a-Z 0-9 ~ - . _`.
+ *
+ * @param {string} uri The URI to encode.
+ * @param [boolean=false] encodeSlash If `true`, the "/" character is not encoded.
+ * @return {string} The encoded string.
+ */
+function encodeURI(uri, encodeSlash) {
+ // Split the string by `/`, and conditionally rejoin them with either
+ // %2F if encodeSlash is `true`, or '/' if `false`.
+ return uri.split('/').map(fixedEncodeURIComponent).join(encodeSlash ? '%2F' : '/');
+}
+exports.encodeURI = encodeURI;
+/**
+ * Serialize an object to a URL query string using util.encodeURI(uri, true).
+ * @param {string} url The object to serialize.
+ * @return {string} Serialized string.
+ */
+function qsStringify(qs) {
+ return querystring.stringify(qs, '&', '=', {
+ encodeURIComponent: component => encodeURI(component, true)
+ });
+}
+exports.qsStringify = qsStringify;
+function objectKeyToLowercase(object) {
+ const newObj = {};
+ for (let key of Object.keys(object)) {
+ const value = object[key];
+ key = key.toLowerCase();
+ newObj[key] = value;
+ }
+ return newObj;
+}
+exports.objectKeyToLowercase = objectKeyToLowercase;
+/**
+ * JSON encode str, with unicode \u+ representation.
+ * @param {object} obj The object to encode.
+ * @return {string} Serialized string.
+ */
+function unicodeJSONStringify(obj) {
+ return JSON.stringify(obj).replace(/[\u0080-\uFFFF]/g, char => '\\u' + ('0000' + char.charCodeAt(0).toString(16)).slice(-4));
+}
+exports.unicodeJSONStringify = unicodeJSONStringify;
+/**
+ * Converts the given objects keys to snake_case
+ * @param {object} obj object to convert keys to snake case.
+ * @returns {object} object with keys converted to snake case.
+ */
+function convertObjKeysToSnakeCase(obj) {
+ if (obj instanceof Date || obj instanceof RegExp) {
+ return obj;
+ }
+ if (Array.isArray(obj)) {
+ return obj.map(convertObjKeysToSnakeCase);
+ }
+ if (obj instanceof Object) {
+ return Object.keys(obj).reduce((acc, cur) => {
+ const s = cur[0].toLocaleLowerCase() + cur.slice(1).replace(/([A-Z]+)/g, (match, p1) => {
+ return `_${p1.toLowerCase()}`;
+ });
+ acc[s] = convertObjKeysToSnakeCase(obj[cur]);
+ return acc;
+ }, Object());
+ }
+ return obj;
+}
+exports.convertObjKeysToSnakeCase = convertObjKeysToSnakeCase;
+/**
+ * Formats the provided date object as a UTC ISO string.
+ * @param {Date} dateTimeToFormat date object to be formatted.
+ * @param {boolean} includeTime flag to include hours, minutes, seconds in output.
+ * @param {string} dateDelimiter delimiter between date components.
+ * @param {string} timeDelimiter delimiter between time components.
+ * @returns {string} UTC ISO format of provided date obect.
+ */
+function formatAsUTCISO(dateTimeToFormat, includeTime = false, dateDelimiter = '', timeDelimiter = '') {
+ const year = dateTimeToFormat.getUTCFullYear();
+ const month = dateTimeToFormat.getUTCMonth() + 1;
+ const day = dateTimeToFormat.getUTCDate();
+ const hour = dateTimeToFormat.getUTCHours();
+ const minute = dateTimeToFormat.getUTCMinutes();
+ const second = dateTimeToFormat.getUTCSeconds();
+ let resultString = `${year.toString().padStart(4, '0')}${dateDelimiter}${month.toString().padStart(2, '0')}${dateDelimiter}${day.toString().padStart(2, '0')}`;
+ if (includeTime) {
+ resultString = `${resultString}T${hour.toString().padStart(2, '0')}${timeDelimiter}${minute.toString().padStart(2, '0')}${timeDelimiter}${second.toString().padStart(2, '0')}Z`;
+ }
+ return resultString;
+}
+exports.formatAsUTCISO = formatAsUTCISO;
+/**
+ * Examines the runtime environment and returns the appropriate tracking string.
+ * @returns {string} metrics tracking string based on the current runtime environment.
+ */
+function getRuntimeTrackingString() {
+ if (
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ globalThis.Deno &&
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ globalThis.Deno.version &&
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ globalThis.Deno.version.deno) {
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ return `gl-deno/${globalThis.Deno.version.deno}`;
+ } else {
+ return `gl-node/${process.versions.node}`;
+ }
+}
+exports.getRuntimeTrackingString = getRuntimeTrackingString;
+/**
+ * Looks at package.json and creates the user-agent string to be applied to request headers.
+ * @returns {string} user agent string.
+ */
+function getUserAgentString() {
+ const pkg = (0, package_json_helper_cjs_1.getPackageJSON)();
+ const hyphenatedPackageName = pkg.name.replace('@google-cloud', 'gcloud-node') // For legacy purposes.
+ .replace('/', '-'); // For UA spec-compliance purposes.
+ return hyphenatedPackageName + '/' + pkg.version;
+}
+exports.getUserAgentString = getUserAgentString;
+function getDirName() {
+ let dirToUse = '';
+ try {
+ dirToUse = __dirname;
+ } catch (e) {
+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+ // @ts-ignore
+ dirToUse = __dirname;
+ }
+ return dirToUse;
+}
+exports.getDirName = getDirName;
+function getModuleFormat() {
+ return isEsm ? 'ESM' : 'CJS';
+}
+exports.getModuleFormat = getModuleFormat;
+class PassThroughShim extends stream_1.PassThrough {
+ constructor() {
+ super(...arguments);
+ this.shouldEmitReading = true;
+ this.shouldEmitWriting = true;
+ }
+ _read(size) {
+ if (this.shouldEmitReading) {
+ this.emit('reading');
+ this.shouldEmitReading = false;
+ }
+ super._read(size);
+ }
+ _write(chunk, encoding, callback) {
+ if (this.shouldEmitWriting) {
+ this.emit('writing');
+ this.shouldEmitWriting = false;
+ }
+ // Per the nodejs documention, callback must be invoked on the next tick
+ process.nextTick(() => {
+ super._write(chunk, encoding, callback);
+ });
+ }
+ _final(callback) {
+ // If the stream is empty (i.e. empty file) final will be invoked before _read / _write
+ // and we should still emit the proper events.
+ if (this.shouldEmitReading) {
+ this.emit('reading');
+ this.shouldEmitReading = false;
+ }
+ if (this.shouldEmitWriting) {
+ this.emit('writing');
+ this.shouldEmitWriting = false;
+ }
+ callback(null);
+ }
+}
+exports.PassThroughShim = PassThroughShim;
diff --git a/node_modules/@google-cloud/storage/build/esm/src/acl.d.ts b/node_modules/@google-cloud/storage/build/esm/src/acl.d.ts
new file mode 100644
index 0000000..d8f31a2
--- /dev/null
+++ b/node_modules/@google-cloud/storage/build/esm/src/acl.d.ts
@@ -0,0 +1,165 @@
+import { BodyResponseCallback, DecorateRequestOptions, BaseMetadata } from './nodejs-common/index.js';
+export interface AclOptions {
+ pathPrefix: string;
+ request: (reqOpts: DecorateRequestOptions, callback: BodyResponseCallback) => void;
+}
+export type GetAclResponse = [
+ AccessControlObject | AccessControlObject[],
+ AclMetadata
+];
+export interface GetAclCallback {
+ (err: Error | null, acl?: AccessControlObject | AccessControlObject[] | null, apiResponse?: AclMetadata): void;
+}
+export interface GetAclOptions {
+ entity: string;
+ generation?: number;
+ userProject?: string;
+}
+export interface UpdateAclOptions {
+ entity: string;
+ role: string;
+ generation?: number;
+ userProject?: string;
+}
+export type UpdateAclResponse = [AccessControlObject, AclMetadata];
+export interface UpdateAclCallback {
+ (err: Error | null, acl?: AccessControlObject | null, apiResponse?: AclMetadata): void;
+}
+export interface AddAclOptions {
+ entity: string;
+ role: string;
+ generation?: number;
+ userProject?: string;
+}
+export type AddAclResponse = [AccessControlObject, AclMetadata];
+export interface AddAclCallback {
+ (err: Error | null, acl?: AccessControlObject | null, apiResponse?: AclMetadata): void;
+}
+export type RemoveAclResponse = [AclMetadata];
+export interface RemoveAclCallback {
+ (err: Error | null, apiResponse?: AclMetadata): void;
+}
+export interface RemoveAclOptions {
+ entity: string;
+ generation?: number;
+ userProject?: string;
+}
+export interface AccessControlObject {
+ entity: string;
+ role: string;
+ projectTeam: string;
+}
+export interface AclMetadata extends BaseMetadata {
+ bucket?: string;
+ domain?: string;
+ entity?: string;
+ entityId?: string;
+ generation?: string;
+ object?: string;
+ projectTeam?: {
+ projectNumber?: string;
+ team?: 'editors' | 'owners' | 'viewers';
+ };
+ role?: 'OWNER' | 'READER' | 'WRITER' | 'FULL_CONTROL';
+ [key: string]: unknown;
+}
+/**
+ * Attach functionality to a {@link Storage.acl} instance. This will add an
+ * object for each role group (owners, readers, and writers), with each object
+ * containing methods to add or delete a type of entity.
+ *
+ * As an example, here are a few methods that are created.
+ *
+ * myBucket.acl.readers.deleteGroup('groupId', function(err) {});
+ *
+ * myBucket.acl.owners.addUser('email@example.com', function(err, acl) {});
+ *
+ * myBucket.acl.writers.addDomain('example.com', function(err, acl) {});
+ *
+ * @private
+ */
+declare class AclRoleAccessorMethods {
+ private static accessMethods;
+ private static entities;
+ private static roles;
+ owners: {};
+ readers: {};
+ writers: {};
+ constructor();
+ _assignAccessMethods(role: string): void;
+}
+/**
+ * Cloud Storage uses access control lists (ACLs) to manage object and
+ * bucket access. ACLs are the mechanism you use to share objects with other
+ * users and allow other users to access your buckets and objects.
+ *
+ * An ACL consists of one or more entries, where each entry grants permissions
+ * to an entity. Permissions define the actions that can be performed against an
+ * object or bucket (for example, `READ` or `WRITE`); the entity defines who the
+ * permission applies to (for example, a specific user or group of users).
+ *
+ * Where an `entity` value is accepted, we follow the format the Cloud Storage
+ * API expects.
+ *
+ * Refer to
+ * https://cloud.google.com/storage/docs/json_api/v1/defaultObjectAccessControls
+ * for the most up-to-date values.
+ *
+ * - `user-userId`
+ * - `user-email`
+ * - `group-groupId`
+ * - `group-email`
+ * - `domain-domain`
+ * - `project-team-projectId`
+ * - `allUsers`
+ * - `allAuthenticatedUsers`
+ *
+ * Examples:
+ *
+ * - The user "liz@example.com" would be `user-liz@example.com`.
+ * - The group "example@googlegroups.com" would be
+ * `group-example@googlegroups.com`.
+ * - To refer to all members of the Google Apps for Business domain
+ * "example.com", the entity would be `domain-example.com`.
+ *
+ * For more detailed information, see
+ * {@link http://goo.gl/6qBBPO| About Access Control Lists}.
+ *
+ * @constructor Acl
+ * @mixin
+ * @param {object} options Configuration options.
+ */
+declare class Acl extends AclRoleAccessorMethods {
+ default: Acl;
+ pathPrefix: string;
+ request_: (reqOpts: DecorateRequestOptions, callback: BodyResponseCallback) => void;
+ constructor(options: AclOptions);
+ add(options: AddAclOptions): Promise;
+ add(options: AddAclOptions, callback: AddAclCallback): void;
+ delete(options: RemoveAclOptions): Promise