UNPKG

134 kBJavaScriptView Raw
1"use strict";
2// Copyright 2019 Google LLC
3//
4// Licensed under the Apache License, Version 2.0 (the "License");
5// you may not use this file except in compliance with the License.
6// You may obtain a copy of the License at
7//
8// http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing, software
11// distributed under the License is distributed on an "AS IS" BASIS,
12// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13// See the License for the specific language governing permissions and
14// limitations under the License.
15Object.defineProperty(exports, "__esModule", { value: true });
16exports.Bucket = exports.BucketExceptionMessages = exports.AvailableServiceObjectMethods = exports.BucketActionToHTTPMethod = void 0;
17const nodejs_common_1 = require("./nodejs-common");
18const paginator_1 = require("@google-cloud/paginator");
19const promisify_1 = require("@google-cloud/promisify");
20const arrify = require("arrify");
21const extend = require("extend");
22const fs = require("fs");
23const mime = require("mime-types");
24const path = require("path");
25const pLimit = require("p-limit");
26const util_1 = require("util");
27const retry = require("async-retry");
28// eslint-disable-next-line @typescript-eslint/no-var-requires
29const snakeize = require('snakeize');
30const acl_1 = require("./acl");
31const file_1 = require("./file");
32const iam_1 = require("./iam");
33const notification_1 = require("./notification");
34const storage_1 = require("./storage");
35const signer_1 = require("./signer");
36const stream_1 = require("stream");
37var BucketActionToHTTPMethod;
38(function (BucketActionToHTTPMethod) {
39 BucketActionToHTTPMethod["list"] = "GET";
40})(BucketActionToHTTPMethod = exports.BucketActionToHTTPMethod || (exports.BucketActionToHTTPMethod = {}));
41var AvailableServiceObjectMethods;
42(function (AvailableServiceObjectMethods) {
43 AvailableServiceObjectMethods[AvailableServiceObjectMethods["setMetadata"] = 0] = "setMetadata";
44 AvailableServiceObjectMethods[AvailableServiceObjectMethods["delete"] = 1] = "delete";
45})(AvailableServiceObjectMethods = exports.AvailableServiceObjectMethods || (exports.AvailableServiceObjectMethods = {}));
46var BucketExceptionMessages;
47(function (BucketExceptionMessages) {
48 BucketExceptionMessages["PROVIDE_SOURCE_FILE"] = "You must provide at least one source file.";
49 BucketExceptionMessages["DESTINATION_FILE_NOT_SPECIFIED"] = "A destination file must be specified.";
50 BucketExceptionMessages["CHANNEL_ID_REQUIRED"] = "An ID is required to create a channel.";
51 BucketExceptionMessages["CHANNEL_ADDRESS_REQUIRED"] = "An address is required to create a channel.";
52 BucketExceptionMessages["TOPIC_NAME_REQUIRED"] = "A valid topic name is required.";
53 BucketExceptionMessages["CONFIGURATION_OBJECT_PREFIX_REQUIRED"] = "A configuration object with a prefix is required.";
54 BucketExceptionMessages["SPECIFY_FILE_NAME"] = "A file name must be specified.";
55 BucketExceptionMessages["METAGENERATION_NOT_PROVIDED"] = "A metageneration must be provided.";
56 BucketExceptionMessages["SUPPLY_NOTIFICATION_ID"] = "You must supply a notification ID.";
57})(BucketExceptionMessages = exports.BucketExceptionMessages || (exports.BucketExceptionMessages = {}));
58/**
59 * The size of a file (in bytes) must be greater than this number to
60 * automatically trigger a resumable upload.
61 *
62 * @const {number}
63 * @private
64 */
65const RESUMABLE_THRESHOLD = 5000000;
66/**
67 * Get and set IAM policies for your bucket.
68 *
69 * @name Bucket#iam
70 * @mixes Iam
71 *
72 * See {@link https://cloud.google.com/storage/docs/access-control/iam#short_title_iam_management| Cloud Storage IAM Management}
73 * See {@link https://cloud.google.com/iam/docs/granting-changing-revoking-access| Granting, Changing, and Revoking Access}
74 * See {@link https://cloud.google.com/iam/docs/understanding-roles| IAM Roles}
75 *
76 * @example
77 * ```
78 * const {Storage} = require('@google-cloud/storage');
79 * const storage = new Storage();
80 * const bucket = storage.bucket('albums');
81 *
82 * //-
83 * // Get the IAM policy for your bucket.
84 * //-
85 * bucket.iam.getPolicy(function(err, policy) {
86 * console.log(policy);
87 * });
88 *
89 * //-
90 * // If the callback is omitted, we'll return a Promise.
91 * //-
92 * bucket.iam.getPolicy().then(function(data) {
93 * const policy = data[0];
94 * const apiResponse = data[1];
95 * });
96 *
97 * ```
98 * @example <caption>include:samples/iam.js</caption>
99 * region_tag:storage_view_bucket_iam_members
100 * Example of retrieving a bucket's IAM policy:
101 *
102 * @example <caption>include:samples/iam.js</caption>
103 * region_tag:storage_add_bucket_iam_member
104 * Example of adding to a bucket's IAM policy:
105 *
106 * @example <caption>include:samples/iam.js</caption>
107 * region_tag:storage_remove_bucket_iam_member
108 * Example of removing from a bucket's IAM policy:
109 */
110/**
111 * Cloud Storage uses access control lists (ACLs) to manage object and
112 * bucket access. ACLs are the mechanism you use to share objects with other
113 * users and allow other users to access your buckets and objects.
114 *
115 * An ACL consists of one or more entries, where each entry grants permissions
116 * to an entity. Permissions define the actions that can be performed against
117 * an object or bucket (for example, `READ` or `WRITE`); the entity defines
118 * who the permission applies to (for example, a specific user or group of
119 * users).
120 *
121 * The `acl` object on a Bucket instance provides methods to get you a list of
122 * the ACLs defined on your bucket, as well as set, update, and delete them.
123 *
124 * Buckets also have
125 * {@link https://cloud.google.com/storage/docs/access-control/lists#default| default ACLs}
126 * for all created files. Default ACLs specify permissions that all new
127 * objects added to the bucket will inherit by default. You can add, delete,
128 * get, and update entities and permissions for these as well with
129 * {@link Bucket#acl.default}.
130 *
131 * See {@link http://goo.gl/6qBBPO| About Access Control Lists}
132 * See {@link https://cloud.google.com/storage/docs/access-control/lists#default| Default ACLs}
133 *
134 * @name Bucket#acl
135 * @mixes Acl
136 * @property {Acl} default Cloud Storage Buckets have
137 * {@link https://cloud.google.com/storage/docs/access-control/lists#default| default ACLs}
138 * for all created files. You can add, delete, get, and update entities and
139 * permissions for these as well. The method signatures and examples are all
140 * the same, after only prefixing the method call with `default`.
141 *
142 * @example
143 * ```
144 * const {Storage} = require('@google-cloud/storage');
145 * const storage = new Storage();
146 *
147 * //-
148 * // Make a bucket's contents publicly readable.
149 * //-
150 * const myBucket = storage.bucket('my-bucket');
151 *
152 * const options = {
153 * entity: 'allUsers',
154 * role: storage.acl.READER_ROLE
155 * };
156 *
157 * myBucket.acl.add(options, function(err, aclObject) {});
158 *
159 * //-
160 * // If the callback is omitted, we'll return a Promise.
161 * //-
162 * myBucket.acl.add(options).then(function(data) {
163 * const aclObject = data[0];
164 * const apiResponse = data[1];
165 * });
166 *
167 * ```
168 * @example <caption>include:samples/acl.js</caption>
169 * region_tag:storage_print_bucket_acl
170 * Example of printing a bucket's ACL:
171 *
172 * @example <caption>include:samples/acl.js</caption>
173 * region_tag:storage_print_bucket_acl_for_user
174 * Example of printing a bucket's ACL for a specific user:
175 *
176 * @example <caption>include:samples/acl.js</caption>
177 * region_tag:storage_add_bucket_owner
178 * Example of adding an owner to a bucket:
179 *
180 * @example <caption>include:samples/acl.js</caption>
181 * region_tag:storage_remove_bucket_owner
182 * Example of removing an owner from a bucket:
183 *
184 * @example <caption>include:samples/acl.js</caption>
185 * region_tag:storage_add_bucket_default_owner
186 * Example of adding a default owner to a bucket:
187 *
188 * @example <caption>include:samples/acl.js</caption>
189 * region_tag:storage_remove_bucket_default_owner
190 * Example of removing a default owner from a bucket:
191 */
192/**
193 * The API-formatted resource description of the bucket.
194 *
195 * Note: This is not guaranteed to be up-to-date when accessed. To get the
196 * latest record, call the `getMetadata()` method.
197 *
198 * @name Bucket#metadata
199 * @type {object}
200 */
201/**
202 * The bucket's name.
203 * @name Bucket#name
204 * @type {string}
205 */
206/**
207 * Get {@link File} objects for the files currently in the bucket as a
208 * readable object stream.
209 *
210 * @method Bucket#getFilesStream
211 * @param {GetFilesOptions} [query] Query object for listing files.
212 * @returns {ReadableStream} A readable stream that emits {@link File} instances.
213 *
214 * @example
215 * ```
216 * const {Storage} = require('@google-cloud/storage');
217 * const storage = new Storage();
218 * const bucket = storage.bucket('albums');
219 *
220 * bucket.getFilesStream()
221 * .on('error', console.error)
222 * .on('data', function(file) {
223 * // file is a File object.
224 * })
225 * .on('end', function() {
226 * // All files retrieved.
227 * });
228 *
229 * //-
230 * // If you anticipate many results, you can end a stream early to prevent
231 * // unnecessary processing and API requests.
232 * //-
233 * bucket.getFilesStream()
234 * .on('data', function(file) {
235 * this.end();
236 * });
237 *
238 * //-
239 * // If you're filtering files with a delimiter, you should use
240 * // {@link Bucket#getFiles} and set `autoPaginate: false` in order to
241 * // preserve the `apiResponse` argument.
242 * //-
243 * const prefixes = [];
244 *
245 * function callback(err, files, nextQuery, apiResponse) {
246 * prefixes = prefixes.concat(apiResponse.prefixes);
247 *
248 * if (nextQuery) {
249 * bucket.getFiles(nextQuery, callback);
250 * } else {
251 * // prefixes = The finished array of prefixes.
252 * }
253 * }
254 *
255 * bucket.getFiles({
256 * autoPaginate: false,
257 * delimiter: '/'
258 * }, callback);
259 * ```
260 */
261/**
262 * Create a Bucket object to interact with a Cloud Storage bucket.
263 *
264 * @class
265 * @hideconstructor
266 *
267 * @param {Storage} storage A {@link Storage} instance.
268 * @param {string} name The name of the bucket.
269 * @param {object} [options] Configuration object.
270 * @param {string} [options.userProject] User project.
271 *
272 * @example
273 * ```
274 * const {Storage} = require('@google-cloud/storage');
275 * const storage = new Storage();
276 * const bucket = storage.bucket('albums');
277 * ```
278 */
279class Bucket extends nodejs_common_1.ServiceObject {
280 constructor(storage, name, options) {
281 var _a, _b, _c, _d;
282 options = options || {};
283 // Allow for "gs://"-style input, and strip any trailing slashes.
284 name = name.replace(/^gs:\/\//, '').replace(/\/+$/, '');
285 const requestQueryObject = {};
286 if ((_a = options === null || options === void 0 ? void 0 : options.preconditionOpts) === null || _a === void 0 ? void 0 : _a.ifGenerationMatch) {
287 requestQueryObject.ifGenerationMatch =
288 options.preconditionOpts.ifGenerationMatch;
289 }
290 if ((_b = options === null || options === void 0 ? void 0 : options.preconditionOpts) === null || _b === void 0 ? void 0 : _b.ifGenerationNotMatch) {
291 requestQueryObject.ifGenerationNotMatch =
292 options.preconditionOpts.ifGenerationNotMatch;
293 }
294 if ((_c = options === null || options === void 0 ? void 0 : options.preconditionOpts) === null || _c === void 0 ? void 0 : _c.ifMetagenerationMatch) {
295 requestQueryObject.ifMetagenerationMatch =
296 options.preconditionOpts.ifMetagenerationMatch;
297 }
298 if ((_d = options === null || options === void 0 ? void 0 : options.preconditionOpts) === null || _d === void 0 ? void 0 : _d.ifMetagenerationNotMatch) {
299 requestQueryObject.ifMetagenerationNotMatch =
300 options.preconditionOpts.ifMetagenerationNotMatch;
301 }
302 const userProject = options.userProject;
303 if (typeof userProject === 'string') {
304 requestQueryObject.userProject = userProject;
305 }
306 const methods = {
307 /**
308 * Create a bucket.
309 *
310 * @method Bucket#create
311 * @param {CreateBucketRequest} [metadata] Metadata to set for the bucket.
312 * @param {CreateBucketCallback} [callback] Callback function.
313 * @returns {Promise<CreateBucketResponse>}
314 *
315 * @example
316 * ```
317 * const {Storage} = require('@google-cloud/storage');
318 * const storage = new Storage();
319 * const bucket = storage.bucket('albums');
320 * bucket.create(function(err, bucket, apiResponse) {
321 * if (!err) {
322 * // The bucket was created successfully.
323 * }
324 * });
325 *
326 * //-
327 * // If the callback is omitted, we'll return a Promise.
328 * //-
329 * bucket.create().then(function(data) {
330 * const bucket = data[0];
331 * const apiResponse = data[1];
332 * });
333 * ```
334 */
335 create: {
336 reqOpts: {
337 qs: requestQueryObject,
338 },
339 },
340 /**
341 * @typedef {object} DeleteBucketOptions Configuration options.
342 * @property {boolean} [ignoreNotFound = false] Ignore an error if
343 * the bucket does not exist.
344 * @property {string} [userProject] The ID of the project which will be
345 * billed for the request.
346 */
347 /**
348 * @typedef {array} DeleteBucketResponse
349 * @property {object} 0 The full API response.
350 */
351 /**
352 * @callback DeleteBucketCallback
353 * @param {?Error} err Request error, if any.
354 * @param {object} apiResponse The full API response.
355 */
356 /**
357 * Delete the bucket.
358 *
359 * See {@link https://cloud.google.com/storage/docs/json_api/v1/buckets/delete| Buckets: delete API Documentation}
360 *
361 * @method Bucket#delete
362 * @param {DeleteBucketOptions} [options] Configuration options.
363 * @param {boolean} [options.ignoreNotFound = false] Ignore an error if
364 * the bucket does not exist.
365 * @param {string} [options.userProject] The ID of the project which will be
366 * billed for the request.
367 * @param {DeleteBucketCallback} [callback] Callback function.
368 * @returns {Promise<DeleteBucketResponse>}
369 *
370 * @example
371 * ```
372 * const {Storage} = require('@google-cloud/storage');
373 * const storage = new Storage();
374 * const bucket = storage.bucket('albums');
375 * bucket.delete(function(err, apiResponse) {});
376 *
377 * //-
378 * // If the callback is omitted, we'll return a Promise.
379 * //-
380 * bucket.delete().then(function(data) {
381 * const apiResponse = data[0];
382 * });
383 *
384 * ```
385 * @example <caption>include:samples/buckets.js</caption>
386 * region_tag:storage_delete_bucket
387 * Another example:
388 */
389 delete: {
390 reqOpts: {
391 qs: requestQueryObject,
392 },
393 },
394 /**
395 * @typedef {object} BucketExistsOptions Configuration options for Bucket#exists().
396 * @property {string} [userProject] The ID of the project which will be
397 * billed for the request.
398 */
399 /**
400 * @typedef {array} BucketExistsResponse
401 * @property {boolean} 0 Whether the {@link Bucket} exists.
402 */
403 /**
404 * @callback BucketExistsCallback
405 * @param {?Error} err Request error, if any.
406 * @param {boolean} exists Whether the {@link Bucket} exists.
407 */
408 /**
409 * Check if the bucket exists.
410 *
411 * @method Bucket#exists
412 * @param {BucketExistsOptions} [options] Configuration options.
413 * @param {string} [options.userProject] The ID of the project which will be
414 * billed for the request.
415 * @param {BucketExistsCallback} [callback] Callback function.
416 * @returns {Promise<BucketExistsResponse>}
417 *
418 * @example
419 * ```
420 * const {Storage} = require('@google-cloud/storage');
421 * const storage = new Storage();
422 * const bucket = storage.bucket('albums');
423 *
424 * bucket.exists(function(err, exists) {});
425 *
426 * //-
427 * // If the callback is omitted, we'll return a Promise.
428 * //-
429 * bucket.exists().then(function(data) {
430 * const exists = data[0];
431 * });
432 * ```
433 */
434 exists: {
435 reqOpts: {
436 qs: requestQueryObject,
437 },
438 },
439 /**
440 * @typedef {object} [GetBucketOptions] Configuration options for Bucket#get()
441 * @property {boolean} [autoCreate] Automatically create the object if
442 * it does not exist. Default: `false`
443 * @property {string} [userProject] The ID of the project which will be
444 * billed for the request.
445 */
446 /**
447 * @typedef {array} GetBucketResponse
448 * @property {Bucket} 0 The {@link Bucket}.
449 * @property {object} 1 The full API response.
450 */
451 /**
452 * @callback GetBucketCallback
453 * @param {?Error} err Request error, if any.
454 * @param {Bucket} bucket The {@link Bucket}.
455 * @param {object} apiResponse The full API response.
456 */
457 /**
458 * Get a bucket if it exists.
459 *
460 * You may optionally use this to "get or create" an object by providing
461 * an object with `autoCreate` set to `true`. Any extra configuration that
462 * is normally required for the `create` method must be contained within
463 * this object as well.
464 *
465 * @method Bucket#get
466 * @param {GetBucketOptions} [options] Configuration options.
467 * @param {boolean} [options.autoCreate] Automatically create the object if
468 * it does not exist. Default: `false`
469 * @param {string} [options.userProject] The ID of the project which will be
470 * billed for the request.
471 * @param {GetBucketCallback} [callback] Callback function.
472 * @returns {Promise<GetBucketResponse>}
473 *
474 * @example
475 * ```
476 * const {Storage} = require('@google-cloud/storage');
477 * const storage = new Storage();
478 * const bucket = storage.bucket('albums');
479 *
480 * bucket.get(function(err, bucket, apiResponse) {
481 * // `bucket.metadata` has been populated.
482 * });
483 *
484 * //-
485 * // If the callback is omitted, we'll return a Promise.
486 * //-
487 * bucket.get().then(function(data) {
488 * const bucket = data[0];
489 * const apiResponse = data[1];
490 * });
491 * ```
492 */
493 get: {
494 reqOpts: {
495 qs: requestQueryObject,
496 },
497 },
498 /**
499 * @typedef {array} GetBucketMetadataResponse
500 * @property {object} 0 The bucket metadata.
501 * @property {object} 1 The full API response.
502 */
503 /**
504 * @callback GetBucketMetadataCallback
505 * @param {?Error} err Request error, if any.
506 * @param {object} metadata The bucket metadata.
507 * @param {object} apiResponse The full API response.
508 */
509 /**
510 * @typedef {object} GetBucketMetadataOptions Configuration options for Bucket#getMetadata().
511 * @property {string} [userProject] The ID of the project which will be
512 * billed for the request.
513 */
514 /**
515 * Get the bucket's metadata.
516 *
517 * To set metadata, see {@link Bucket#setMetadata}.
518 *
519 * See {@link https://cloud.google.com/storage/docs/json_api/v1/buckets/get| Buckets: get API Documentation}
520 *
521 * @method Bucket#getMetadata
522 * @param {GetBucketMetadataOptions} [options] Configuration options.
523 * @param {string} [options.userProject] The ID of the project which will be
524 * billed for the request.
525 * @param {GetBucketMetadataCallback} [callback] Callback function.
526 * @returns {Promise<GetBucketMetadataResponse>}
527 *
528 * @example
529 * ```
530 * const {Storage} = require('@google-cloud/storage');
531 * const storage = new Storage();
532 * const bucket = storage.bucket('albums');
533 *
534 * bucket.getMetadata(function(err, metadata, apiResponse) {});
535 *
536 * //-
537 * // If the callback is omitted, we'll return a Promise.
538 * //-
539 * bucket.getMetadata().then(function(data) {
540 * const metadata = data[0];
541 * const apiResponse = data[1];
542 * });
543 *
544 * ```
545 * @example <caption>include:samples/requesterPays.js</caption>
546 * region_tag:storage_get_requester_pays_status
547 * Example of retrieving the requester pays status of a bucket:
548 */
549 getMetadata: {
550 reqOpts: {
551 qs: requestQueryObject,
552 },
553 },
554 /**
555 * @typedef {object} SetBucketMetadataOptions Configuration options for Bucket#setMetadata().
556 * @property {string} [userProject] The ID of the project which will be
557 * billed for the request.
558 */
559 /**
560 * @typedef {array} SetBucketMetadataResponse
561 * @property {object} apiResponse The full API response.
562 */
563 /**
564 * @callback SetBucketMetadataCallback
565 * @param {?Error} err Request error, if any.
566 * @param {object} metadata The bucket metadata.
567 */
568 /**
569 * Set the bucket's metadata.
570 *
571 * See {@link https://cloud.google.com/storage/docs/json_api/v1/buckets/patch| Buckets: patch API Documentation}
572 *
573 * @method Bucket#setMetadata
574 * @param {object<string, *>} metadata The metadata you wish to set.
575 * @param {SetBucketMetadataOptions} [options] Configuration options.
576 * @param {string} [options.userProject] The ID of the project which will be
577 * billed for the request.
578 * @param {SetBucketMetadataCallback} [callback] Callback function.
579 * @returns {Promise<SetBucketMetadataResponse>}
580 *
581 * @example
582 * ```
583 * const {Storage} = require('@google-cloud/storage');
584 * const storage = new Storage();
585 * const bucket = storage.bucket('albums');
586 *
587 * //-
588 * // Set website metadata field on the bucket.
589 * //-
590 * const metadata = {
591 * website: {
592 * mainPageSuffix: 'http://example.com',
593 * notFoundPage: 'http://example.com/404.html'
594 * }
595 * };
596 *
597 * bucket.setMetadata(metadata, function(err, apiResponse) {});
598 *
599 * //-
600 * // Enable versioning for your bucket.
601 * //-
602 * bucket.setMetadata({
603 * versioning: {
604 * enabled: true
605 * }
606 * }, function(err, apiResponse) {});
607 *
608 * //-
609 * // Enable KMS encryption for objects within this bucket.
610 * //-
611 * bucket.setMetadata({
612 * encryption: {
613 * defaultKmsKeyName: 'projects/grape-spaceship-123/...'
614 * }
615 * }, function(err, apiResponse) {});
616 *
617 * //-
618 * // Set the default event-based hold value for new objects in this
619 * // bucket.
620 * //-
621 * bucket.setMetadata({
622 * defaultEventBasedHold: true
623 * }, function(err, apiResponse) {});
624 *
625 * //-
626 * // Remove object lifecycle rules.
627 * //-
628 * bucket.setMetadata({
629 * lifecycle: null
630 * }, function(err, apiResponse) {});
631 *
632 * //-
633 * // If the callback is omitted, we'll return a Promise.
634 * //-
635 * bucket.setMetadata(metadata).then(function(data) {
636 * const apiResponse = data[0];
637 * });
638 * ```
639 */
640 setMetadata: {
641 reqOpts: {
642 qs: requestQueryObject,
643 },
644 },
645 };
646 super({
647 parent: storage,
648 baseUrl: '/b',
649 id: name,
650 createMethod: storage.createBucket.bind(storage),
651 methods,
652 });
653 this.name = name;
654 this.storage = storage;
655 this.userProject = options.userProject;
656 this.acl = new acl_1.Acl({
657 request: this.request.bind(this),
658 pathPrefix: '/acl',
659 });
660 this.acl.default = new acl_1.Acl({
661 request: this.request.bind(this),
662 pathPrefix: '/defaultObjectAcl',
663 });
664 this.iam = new iam_1.Iam(this);
665 this.getFilesStream = paginator_1.paginator.streamify('getFiles');
666 this.instanceRetryValue = storage.retryOptions.autoRetry;
667 this.instancePreconditionOpts = options === null || options === void 0 ? void 0 : options.preconditionOpts;
668 }
669 // eslint-disable-next-line @typescript-eslint/no-unused-vars
670 getFilesStream(query) {
671 // placeholder body, overwritten in constructor
672 return new stream_1.Readable();
673 }
674 /**
675 * @typedef {object} AddLifecycleRuleOptions Configuration options for Bucket#addLifecycleRule().
676 * @property {boolean} [append=true] The new rules will be appended to any
677 * pre-existing rules.
678 */
679 /**
680 *
681 * @typedef {object} LifecycleRule The new lifecycle rule to be added to objects
682 * in this bucket.
683 * @property {string|object} action The action to be taken upon matching of
684 * all the conditions 'delete' or 'setStorageClass'.
685 * **Note**: For configuring a raw-formatted rule object to be passed as `action`
686 * please refer to the [examples]{@link https://cloud.google.com/storage/docs/managing-lifecycles#configexamples}.
687 * @property {object} condition Condition a bucket must meet before the
688 * action occurs on the bucket. Refer to following supported [conditions]{@link https://cloud.google.com/storage/docs/lifecycle#conditions}.
689 * @property {string} [storageClass] When using the `setStorageClass`
690 * action, provide this option to dictate which storage class the object
691 * should update to. Please see
692 * [SetStorageClass option documentation]{@link https://cloud.google.com/storage/docs/lifecycle#setstorageclass} for supported transitions.
693 */
694 /**
695 * Add an object lifecycle management rule to the bucket.
696 *
697 * By default, an Object Lifecycle Management rule provided to this method
698 * will be included to the existing policy. To replace all existing rules,
699 * supply the `options` argument, setting `append` to `false`.
700 *
701 * See {@link https://cloud.google.com/storage/docs/lifecycle| Object Lifecycle Management}
702 * See {@link https://cloud.google.com/storage/docs/json_api/v1/buckets/patch| Buckets: patch API Documentation}
703 *
704 * @param {LifecycleRule} rule The new lifecycle rule to be added to objects
705 * in this bucket.
706 * @param {string|object} rule.action The action to be taken upon matching of
707 * all the conditions 'delete' or 'setStorageClass'.
708 * **Note**: For configuring a raw-formatted rule object to be passed as `action`
709 * please refer to the [examples]{@link https://cloud.google.com/storage/docs/managing-lifecycles#configexamples}.
710 * @param {object} rule.condition Condition a bucket must meet before the
711 * action occurson the bucket. Refer to followitn supported [conditions]{@link https://cloud.google.com/storage/docs/lifecycle#conditions}.
712 * @param {string} [rule.storageClass] When using the `setStorageClass`
713 * action, provide this option to dictate which storage class the object
714 * should update to.
715 * @param {AddLifecycleRuleOptions} [options] Configuration object.
716 * @param {boolean} [options.append=true] Append the new rule to the existing
717 * policy.
718 * @param {SetBucketMetadataCallback} [callback] Callback function.
719 * @returns {Promise<SetBucketMetadataResponse>}
720 *
721 * @example
722 * ```
723 * const {Storage} = require('@google-cloud/storage');
724 * const storage = new Storage();
725 * const bucket = storage.bucket('albums');
726 *
727 * //-
728 * // Automatically have an object deleted from this bucket once it is 3 years
729 * // of age.
730 * //-
731 * bucket.addLifecycleRule({
732 * action: 'delete',
733 * condition: {
734 * age: 365 * 3 // Specified in days.
735 * }
736 * }, function(err, apiResponse) {
737 * if (err) {
738 * // Error handling omitted.
739 * }
740 *
741 * const lifecycleRules = bucket.metadata.lifecycle.rule;
742 *
743 * // Iterate over the Object Lifecycle Management rules on this bucket.
744 * lifecycleRules.forEach(lifecycleRule => {});
745 * });
746 *
747 * //-
748 * // By default, the rule you provide will be added to the existing policy.
749 * // Optionally, you can disable this behavior to replace all of the
750 * // pre-existing rules.
751 * //-
752 * const options = {
753 * append: false
754 * };
755 *
756 * bucket.addLifecycleRule({
757 * action: 'delete',
758 * condition: {
759 * age: 365 * 3 // Specified in days.
760 * }
761 * }, options, function(err, apiResponse) {
762 * if (err) {
763 * // Error handling omitted.
764 * }
765 *
766 * // All rules have been replaced with the new "delete" rule.
767 *
768 * // Iterate over the Object Lifecycle Management rules on this bucket.
769 * lifecycleRules.forEach(lifecycleRule => {});
770 * });
771 *
772 * //-
773 * // For objects created before 2018, "downgrade" the storage class.
774 * //-
775 * bucket.addLifecycleRule({
776 * action: 'setStorageClass',
777 * storageClass: 'COLDLINE',
778 * condition: {
779 * createdBefore: new Date('2018')
780 * }
781 * }, function(err, apiResponse) {});
782 *
783 * //-
784 * // Delete objects created before 2016 which have the Coldline storage
785 * // class.
786 * //-
787 * bucket.addLifecycleRule({
788 * action: 'delete',
789 * condition: {
790 * matchesStorageClass: [
791 * 'COLDLINE'
792 * ],
793 * createdBefore: new Date('2016')
794 * }
795 * }, function(err, apiResponse) {});
796 *
797 * //-
798 * // Delete object that has a noncurrent timestamp that is at least 100 days.
799 * //-
800 * bucket.addLifecycleRule({
801 * action: 'delete',
802 * condition: {
803 * daysSinceNoncurrentTime: 100
804 * }
805 * }, function(err, apiResponse) {});
806 *
807 * //-
808 * // Delete object that has a noncurrent timestamp before 2020-01-01.
809 * //-
810 * bucket.addLifecycleRule({
811 * action: 'delete',
812 * condition: {
813 * noncurrentTimeBefore: new Date('2020-01-01')
814 * }
815 * }, function(err, apiResponse) {});
816 *
817 * //-
818 * // Delete object that has a customTime that is at least 100 days.
819 * //-
820 * bucket.addLifecycleRule({
821 * action: 'delete',
822 * condition: {
823 * daysSinceCustomTime: 100
824 * }
825 * }, function(err, apiResponse) ());
826 *
827 * //-
828 * // Delete object that has a customTime before 2020-01-01.
829 * //-
830 * bucket.addLifecycleRule({
831 * action: 'delete',
832 * condition: {
833 * customTimeBefore: new Date('2020-01-01')
834 * }
835 * }, function(err, apiResponse) {});
836 * ```
837 */
838 addLifecycleRule(rule, optionsOrCallback, callback) {
839 let options;
840 if (typeof optionsOrCallback === 'function') {
841 callback = optionsOrCallback;
842 }
843 else if (optionsOrCallback) {
844 options = optionsOrCallback;
845 }
846 options = options || {};
847 const newLifecycleRules = arrify(rule).map(rule => {
848 if (typeof rule.action === 'object') {
849 // This is a raw-formatted rule object, the way the API expects.
850 // Just pass it through as-is.
851 return rule;
852 }
853 const apiFormattedRule = {};
854 apiFormattedRule.condition = {};
855 apiFormattedRule.action = {
856 type: rule.action.charAt(0).toUpperCase() + rule.action.slice(1),
857 };
858 if (rule.storageClass) {
859 apiFormattedRule.action.storageClass = rule.storageClass;
860 }
861 for (const condition in rule.condition) {
862 if (rule.condition[condition] instanceof Date) {
863 apiFormattedRule.condition[condition] = rule.condition[condition]
864 .toISOString()
865 .replace(/T.+$/, '');
866 }
867 else {
868 apiFormattedRule.condition[condition] = rule.condition[condition];
869 }
870 }
871 return apiFormattedRule;
872 });
873 this.disableAutoRetryConditionallyIdempotent_(this.methods.setMetadata, AvailableServiceObjectMethods.setMetadata);
874 if (options.append === false) {
875 this.setMetadata({ lifecycle: { rule: newLifecycleRules } }, callback);
876 this.storage.retryOptions.autoRetry = this.instanceRetryValue;
877 return;
878 }
879 // The default behavior appends the previously-defined lifecycle rules with
880 // the new ones just passed in by the user.
881 this.getMetadata((err, metadata) => {
882 if (err) {
883 callback(err);
884 return;
885 }
886 const currentLifecycleRules = arrify(metadata.lifecycle && metadata.lifecycle.rule);
887 this.setMetadata({
888 lifecycle: {
889 rule: currentLifecycleRules.concat(newLifecycleRules),
890 },
891 }, callback);
892 });
893 this.storage.retryOptions.autoRetry = this.instanceRetryValue;
894 }
895 /**
896 * @typedef {object} CombineOptions
897 * @property {string} [kmsKeyName] Resource name of the Cloud KMS key, of
898 * the form
899 * `projects/my-project/locations/location/keyRings/my-kr/cryptoKeys/my-key`,
900 * that will be used to encrypt the object. Overwrites the object
901 * metadata's `kms_key_name` value, if any.
902 * @property {string} [userProject] The ID of the project which will be
903 * billed for the request.
904 */
905 /**
906 * @callback CombineCallback
907 * @param {?Error} err Request error, if any.
908 * @param {File} newFile The new {@link File}.
909 * @param {object} apiResponse The full API response.
910 */
911 /**
912 * @typedef {array} CombineResponse
913 * @property {File} 0 The new {@link File}.
914 * @property {object} 1 The full API response.
915 */
916 /**
917 * Combine multiple files into one new file.
918 *
919 * See {@link https://cloud.google.com/storage/docs/json_api/v1/objects/compose| Objects: compose API Documentation}
920 *
921 * @throws {Error} if a non-array is provided as sources argument.
922 * @throws {Error} if no sources are provided.
923 * @throws {Error} if no destination is provided.
924 *
925 * @param {string[]|File[]} sources The source files that will be
926 * combined.
927 * @param {string|File} destination The file you would like the
928 * source files combined into.
929 * @param {CombineOptions} [options] Configuration options.
930 * @param {string} [options.kmsKeyName] Resource name of the Cloud KMS key, of
931 * the form
932 * `projects/my-project/locations/location/keyRings/my-kr/cryptoKeys/my-key`,
933 * that will be used to encrypt the object. Overwrites the object
934 * metadata's `kms_key_name` value, if any.
935 * @param {string} [options.userProject] The ID of the project which will be
936 * billed for the request.
937
938 * @param {CombineCallback} [callback] Callback function.
939 * @returns {Promise<CombineResponse>}
940 *
941 * @example
942 * ```
943 * const logBucket = storage.bucket('log-bucket');
944 *
945 * const sources = [
946 * logBucket.file('2013-logs.txt'),
947 * logBucket.file('2014-logs.txt')
948 * ];
949 *
950 * const allLogs = logBucket.file('all-logs.txt');
951 *
952 * logBucket.combine(sources, allLogs, function(err, newFile, apiResponse) {
953 * // newFile === allLogs
954 * });
955 *
956 * //-
957 * // If the callback is omitted, we'll return a Promise.
958 * //-
959 * logBucket.combine(sources, allLogs).then(function(data) {
960 * const newFile = data[0];
961 * const apiResponse = data[1];
962 * });
963 * ```
964 */
965 combine(sources, destination, optionsOrCallback, callback) {
966 if (!Array.isArray(sources) || sources.length === 0) {
967 throw new Error(BucketExceptionMessages.PROVIDE_SOURCE_FILE);
968 }
969 if (!destination) {
970 throw new Error(BucketExceptionMessages.DESTINATION_FILE_NOT_SPECIFIED);
971 }
972 let options = {};
973 if (typeof optionsOrCallback === 'function') {
974 callback = optionsOrCallback;
975 }
976 else if (optionsOrCallback) {
977 options = optionsOrCallback;
978 }
979 const convertToFile = (file) => {
980 if (file instanceof file_1.File) {
981 return file;
982 }
983 return this.file(file);
984 };
985 // eslint-disable-next-line @typescript-eslint/no-explicit-any
986 sources = sources.map(convertToFile);
987 const destinationFile = convertToFile(destination);
988 callback = callback || nodejs_common_1.util.noop;
989 if (!destinationFile.metadata.contentType) {
990 const destinationContentType = mime.contentType(destinationFile.name);
991 if (destinationContentType) {
992 destinationFile.metadata.contentType = destinationContentType;
993 }
994 }
995 let maxRetries = this.storage.retryOptions.maxRetries;
996 sources.forEach(source => {
997 var _a;
998 if ((((_a = source === null || source === void 0 ? void 0 : source.instancePreconditionOpts) === null || _a === void 0 ? void 0 : _a.ifGenerationMatch) === undefined &&
999 this.storage.retryOptions.idempotencyStrategy ===
1000 storage_1.IdempotencyStrategy.RetryConditional) ||
1001 this.storage.retryOptions.idempotencyStrategy ===
1002 storage_1.IdempotencyStrategy.RetryNever) {
1003 maxRetries = 0;
1004 }
1005 });
1006 Object.assign(options, this.instancePreconditionOpts, options);
1007 // Make the request from the destination File object.
1008 destinationFile.request({
1009 method: 'POST',
1010 uri: '/compose',
1011 maxRetries,
1012 json: {
1013 destination: {
1014 contentType: destinationFile.metadata.contentType,
1015 },
1016 sourceObjects: sources.map(source => {
1017 var _a, _b, _c, _d;
1018 const sourceObject = {
1019 name: source.name,
1020 };
1021 if (((_a = source === null || source === void 0 ? void 0 : source.metadata) === null || _a === void 0 ? void 0 : _a.generation) || ((_b = source === null || source === void 0 ? void 0 : source.instancePreconditionOpts) === null || _b === void 0 ? void 0 : _b.ifGenerationMatch)) {
1022 sourceObject.generation =
1023 ((_c = source === null || source === void 0 ? void 0 : source.metadata) === null || _c === void 0 ? void 0 : _c.generation) || ((_d = source === null || source === void 0 ? void 0 : source.instancePreconditionOpts) === null || _d === void 0 ? void 0 : _d.ifGenerationMatch);
1024 }
1025 return sourceObject;
1026 }),
1027 },
1028 qs: options,
1029 }, (err, resp) => {
1030 if (err) {
1031 callback(err, null, resp);
1032 return;
1033 }
1034 callback(null, destinationFile, resp);
1035 });
1036 }
1037 /**
1038 * See a {@link https://cloud.google.com/storage/docs/json_api/v1/objects/watchAll| Objects: watchAll request body}.
1039 *
1040 * @typedef {object} CreateChannelConfig
1041 * @property {string} address The address where notifications are
1042 * delivered for this channel.
1043 * @property {string} [delimiter] Returns results in a directory-like mode.
1044 * @property {number} [maxResults] Maximum number of `items` plus `prefixes`
1045 * to return in a single page of responses.
1046 * @property {string} [pageToken] A previously-returned page token
1047 * representing part of the larger set of results to view.
1048 * @property {string} [prefix] Filter results to objects whose names begin
1049 * with this prefix.
1050 * @property {string} [projection=noAcl] Set of properties to return.
1051 * @property {string} [userProject] The ID of the project which will be
1052 * billed for the request.
1053 * @property {boolean} [versions=false] If `true`, lists all versions of an object
1054 * as distinct results.
1055 */
1056 /**
1057 * @typedef {object} CreateChannelOptions
1058 * @property {string} [userProject] The ID of the project which will be
1059 * billed for the request.
1060 */
1061 /**
1062 * @typedef {array} CreateChannelResponse
1063 * @property {Channel} 0 The new {@link Channel}.
1064 * @property {object} 1 The full API response.
1065 */
1066 /**
1067 * @callback CreateChannelCallback
1068 * @param {?Error} err Request error, if any.
1069 * @param {Channel} channel The new {@link Channel}.
1070 * @param {object} apiResponse The full API response.
1071 */
1072 /**
1073 * Create a channel that will be notified when objects in this bucket changes.
1074 *
1075 * @throws {Error} If an ID is not provided.
1076 * @throws {Error} If an address is not provided.
1077 *
1078 * See {@link https://cloud.google.com/storage/docs/json_api/v1/objects/watchAll| Objects: watchAll API Documentation}
1079 *
1080 * @param {string} id The ID of the channel to create.
1081 * @param {CreateChannelConfig} config Configuration for creating channel.
1082 * @param {string} config.address The address where notifications are
1083 * delivered for this channel.
1084 * @param {string} [config.delimiter] Returns results in a directory-like mode.
1085 * @param {number} [config.maxResults] Maximum number of `items` plus `prefixes`
1086 * to return in a single page of responses.
1087 * @param {string} [config.pageToken] A previously-returned page token
1088 * representing part of the larger set of results to view.
1089 * @param {string} [config.prefix] Filter results to objects whose names begin
1090 * with this prefix.
1091 * @param {string} [config.projection=noAcl] Set of properties to return.
1092 * @param {string} [config.userProject] The ID of the project which will be
1093 * billed for the request.
1094 * @param {boolean} [config.versions=false] If `true`, lists all versions of an object
1095 * as distinct results.
1096 * @param {CreateChannelOptions} [options] Configuration options.
1097 * @param {string} [options.userProject] The ID of the project which will be
1098 * billed for the request.
1099 * @param {CreateChannelCallback} [callback] Callback function.
1100 * @returns {Promise<CreateChannelResponse>}
1101 *
1102 * @example
1103 * ```
1104 * const {Storage} = require('@google-cloud/storage');
1105 * const storage = new Storage();
1106 * const bucket = storage.bucket('albums');
1107 * const id = 'new-channel-id';
1108 *
1109 * const config = {
1110 * address: 'https://...'
1111 * };
1112 *
1113 * bucket.createChannel(id, config, function(err, channel, apiResponse) {
1114 * if (!err) {
1115 * // Channel created successfully.
1116 * }
1117 * });
1118 *
1119 * //-
1120 * // If the callback is omitted, we'll return a Promise.
1121 * //-
1122 * bucket.createChannel(id, config).then(function(data) {
1123 * const channel = data[0];
1124 * const apiResponse = data[1];
1125 * });
1126 * ```
1127 */
1128 createChannel(id, config, optionsOrCallback, callback) {
1129 if (typeof id !== 'string') {
1130 throw new Error(BucketExceptionMessages.CHANNEL_ID_REQUIRED);
1131 }
1132 if (typeof config.address !== 'string') {
1133 throw new Error(BucketExceptionMessages.CHANNEL_ADDRESS_REQUIRED);
1134 }
1135 let options = {};
1136 if (typeof optionsOrCallback === 'function') {
1137 callback = optionsOrCallback;
1138 }
1139 else if (optionsOrCallback) {
1140 options = optionsOrCallback;
1141 }
1142 this.request({
1143 method: 'POST',
1144 uri: '/o/watch',
1145 json: Object.assign({
1146 id,
1147 type: 'web_hook',
1148 }, config),
1149 qs: options,
1150 }, (err, apiResponse) => {
1151 if (err) {
1152 callback(err, null, apiResponse);
1153 return;
1154 }
1155 const resourceId = apiResponse.resourceId;
1156 const channel = this.storage.channel(id, resourceId);
1157 channel.metadata = apiResponse;
1158 callback(null, channel, apiResponse);
1159 });
1160 }
1161 /**
1162 * Metadata to set for the Notification.
1163 *
1164 * @typedef {object} CreateNotificationOptions
1165 * @property {object} [customAttributes] An optional list of additional
1166 * attributes to attach to each Cloud PubSub message published for this
1167 * notification subscription.
1168 * @property {string[]} [eventTypes] If present, only send notifications about
1169 * listed event types. If empty, sent notifications for all event types.
1170 * @property {string} [objectNamePrefix] If present, only apply this
1171 * notification configuration to object names that begin with this prefix.
1172 * @property {string} [payloadFormat] The desired content of the Payload.
1173 * Defaults to `JSON_API_V1`.
1174 *
1175 * Acceptable values are:
1176 * - `JSON_API_V1`
1177 *
1178 * - `NONE`
1179 * @property {string} [userProject] The ID of the project which will be
1180 * billed for the request.
1181 */
1182 /**
1183 * @callback CreateNotificationCallback
1184 * @param {?Error} err Request error, if any.
1185 * @param {Notification} notification The new {@link Notification}.
1186 * @param {object} apiResponse The full API response.
1187 */
1188 /**
1189 * @typedef {array} CreateNotificationResponse
1190 * @property {Notification} 0 The new {@link Notification}.
1191 * @property {object} 1 The full API response.
1192 */
1193 /**
1194 * Creates a notification subscription for the bucket.
1195 *
1196 * See {@link https://cloud.google.com/storage/docs/json_api/v1/notifications/insert| Notifications: insert}
1197 *
1198 * @param {Topic|string} topic The Cloud PubSub topic to which this
1199 * subscription publishes. If the project ID is omitted, the current
1200 * project ID will be used.
1201 *
1202 * Acceptable formats are:
1203 * - `projects/grape-spaceship-123/topics/my-topic`
1204 *
1205 * - `my-topic`
1206 * @param {CreateNotificationOptions} [options] Metadata to set for the
1207 * notification.
1208 * @param {object} [options.customAttributes] An optional list of additional
1209 * attributes to attach to each Cloud PubSub message published for this
1210 * notification subscription.
1211 * @param {string[]} [options.eventTypes] If present, only send notifications about
1212 * listed event types. If empty, sent notifications for all event types.
1213 * @param {string} [options.objectNamePrefix] If present, only apply this
1214 * notification configuration to object names that begin with this prefix.
1215 * @param {string} [options.payloadFormat] The desired content of the Payload.
1216 * Defaults to `JSON_API_V1`.
1217 *
1218 * Acceptable values are:
1219 * - `JSON_API_V1`
1220 *
1221 * - `NONE`
1222 * @param {string} [options.userProject] The ID of the project which will be
1223 * billed for the request.
1224 * @param {CreateNotificationCallback} [callback] Callback function.
1225 * @returns {Promise<CreateNotificationResponse>}
1226 * @throws {Error} If a valid topic is not provided.
1227 * @see Notification#create
1228 *
1229 * @example
1230 * ```
1231 * const {Storage} = require('@google-cloud/storage');
1232 * const storage = new Storage();
1233 * const myBucket = storage.bucket('my-bucket');
1234 *
1235 * const callback = function(err, notification, apiResponse) {
1236 * if (!err) {
1237 * // The notification was created successfully.
1238 * }
1239 * };
1240 *
1241 * myBucket.createNotification('my-topic', callback);
1242 *
1243 * //-
1244 * // Configure the nofiication by providing Notification metadata.
1245 * //-
1246 * const metadata = {
1247 * objectNamePrefix: 'prefix-'
1248 * };
1249 *
1250 * myBucket.createNotification('my-topic', metadata, callback);
1251 *
1252 * //-
1253 * // If the callback is omitted, we'll return a Promise.
1254 * //-
1255 * myBucket.createNotification('my-topic').then(function(data) {
1256 * const notification = data[0];
1257 * const apiResponse = data[1];
1258 * });
1259 *
1260 * ```
1261 * @example <caption>include:samples/createNotification.js</caption>
1262 * region_tag:storage_create_bucket_notifications
1263 * Another example:
1264 */
1265 createNotification(topic, optionsOrCallback, callback) {
1266 let options = {};
1267 if (typeof optionsOrCallback === 'function') {
1268 callback = optionsOrCallback;
1269 }
1270 else if (optionsOrCallback) {
1271 options = optionsOrCallback;
1272 }
1273 const topicIsObject = topic !== null && typeof topic === 'object';
1274 if (topicIsObject && nodejs_common_1.util.isCustomType(topic, 'pubsub/topic')) {
1275 // eslint-disable-next-line @typescript-eslint/no-explicit-any
1276 topic = topic.name;
1277 }
1278 if (typeof topic !== 'string') {
1279 throw new Error(BucketExceptionMessages.TOPIC_NAME_REQUIRED);
1280 }
1281 const body = Object.assign({ topic }, options);
1282 if (body.topic.indexOf('projects') !== 0) {
1283 body.topic = 'projects/{{projectId}}/topics/' + body.topic;
1284 }
1285 body.topic = '//pubsub.googleapis.com/' + body.topic;
1286 if (!body.payloadFormat) {
1287 body.payloadFormat = 'JSON_API_V1';
1288 }
1289 const query = {};
1290 if (body.userProject) {
1291 query.userProject = body.userProject;
1292 delete body.userProject;
1293 }
1294 this.request({
1295 method: 'POST',
1296 uri: '/notificationConfigs',
1297 json: snakeize(body),
1298 qs: query,
1299 maxRetries: 0,
1300 }, (err, apiResponse) => {
1301 if (err) {
1302 callback(err, null, apiResponse);
1303 return;
1304 }
1305 const notification = this.notification(apiResponse.id);
1306 notification.metadata = apiResponse;
1307 callback(null, notification, apiResponse);
1308 });
1309 }
1310 /**
1311 * @typedef {object} DeleteFilesOptions Query object. See {@link Bucket#getFiles}
1312 * for all of the supported properties.
1313 * @property {boolean} [force] Suppress errors until all files have been
1314 * processed.
1315 */
1316 /**
1317 * @callback DeleteFilesCallback
1318 * @param {?Error|?Error[]} err Request error, if any, or array of errors from
1319 * files that were not able to be deleted.
1320 * @param {object} [apiResponse] The full API response.
1321 */
1322 /**
1323 * Iterate over the bucket's files, calling `file.delete()` on each.
1324 *
1325 * <strong>This is not an atomic request.</strong> A delete attempt will be
1326 * made for each file individually. Any one can fail, in which case only a
1327 * portion of the files you intended to be deleted would have.
1328 *
1329 * Operations are performed in parallel, up to 10 at once. The first error
1330 * breaks the loop and will execute the provided callback with it. Specify
1331 * `{ force: true }` to suppress the errors until all files have had a chance
1332 * to be processed.
1333 *
1334 * The `query` object passed as the first argument will also be passed to
1335 * {@link Bucket#getFiles}.
1336 *
1337 * See {@link https://cloud.google.com/storage/docs/json_api/v1/objects/delete| Objects: delete API Documentation}
1338 *
1339 * @param {DeleteFilesOptions} [query] Query object. See {@link Bucket#getFiles}
1340 * @param {boolean} [query.force] Suppress errors until all files have been
1341 * processed.
1342 * @param {DeleteFilesCallback} [callback] Callback function.
1343 * @returns {Promise}
1344 *
1345 * @example
1346 * ```
1347 * const {Storage} = require('@google-cloud/storage');
1348 * const storage = new Storage();
1349 * const bucket = storage.bucket('albums');
1350 *
1351 * //-
1352 * // Delete all of the files in the bucket.
1353 * //-
1354 * bucket.deleteFiles(function(err) {});
1355 *
1356 * //-
1357 * // By default, if a file cannot be deleted, this method will stop deleting
1358 * // files from your bucket. You can override this setting with `force:
1359 * // true`.
1360 * //-
1361 * bucket.deleteFiles({
1362 * force: true
1363 * }, function(errors) {
1364 * // `errors`:
1365 * // Array of errors if any occurred, otherwise null.
1366 * });
1367 *
1368 * //-
1369 * // The first argument to this method acts as a query to
1370 * // {@link Bucket#getFiles}. As an example, you can delete files
1371 * // which match a prefix.
1372 * //-
1373 * bucket.deleteFiles({
1374 * prefix: 'images/'
1375 * }, function(err) {
1376 * if (!err) {
1377 * // All files in the `images` directory have been deleted.
1378 * }
1379 * });
1380 *
1381 * //-
1382 * // If the callback is omitted, we'll return a Promise.
1383 * //-
1384 * bucket.deleteFiles().then(function() {});
1385 * ```
1386 */
1387 deleteFiles(queryOrCallback, callback) {
1388 let query = {};
1389 if (typeof queryOrCallback === 'function') {
1390 callback = queryOrCallback;
1391 }
1392 else if (queryOrCallback) {
1393 query = queryOrCallback;
1394 }
1395 const MAX_PARALLEL_LIMIT = 10;
1396 const errors = [];
1397 const deleteFile = (file) => {
1398 return file.delete(query).catch(err => {
1399 if (!query.force) {
1400 throw err;
1401 }
1402 errors.push(err);
1403 });
1404 };
1405 this.getFiles(query)
1406 .then(([files]) => {
1407 const limit = pLimit(MAX_PARALLEL_LIMIT);
1408 const promises = files.map(file => {
1409 return limit(() => deleteFile(file));
1410 });
1411 return Promise.all(promises);
1412 })
1413 .then(() => callback(errors.length > 0 ? errors : null), callback);
1414 }
1415 /**
1416 * @typedef {array} DeleteLabelsResponse
1417 * @property {object} 0 The full API response.
1418 */
1419 /**
1420 * @callback DeleteLabelsCallback
1421 * @param {?Error} err Request error, if any.
1422 * @param {object} metadata Bucket's metadata.
1423 */
1424 /**
1425 * Delete one or more labels from this bucket.
1426 *
1427 * @param {string|string[]} [labels] The labels to delete. If no labels are
1428 * provided, all of the labels are removed.
1429 * @param {DeleteLabelsCallback} [callback] Callback function.
1430 * @returns {Promise<DeleteLabelsResponse>}
1431 *
1432 * @example
1433 * ```
1434 * const {Storage} = require('@google-cloud/storage');
1435 * const storage = new Storage();
1436 * const bucket = storage.bucket('albums');
1437 *
1438 * //-
1439 * // Delete all of the labels from this bucket.
1440 * //-
1441 * bucket.deleteLabels(function(err, apiResponse) {});
1442 *
1443 * //-
1444 * // Delete a single label.
1445 * //-
1446 * bucket.deleteLabels('labelone', function(err, apiResponse) {});
1447 *
1448 * //-
1449 * // Delete a specific set of labels.
1450 * //-
1451 * bucket.deleteLabels([
1452 * 'labelone',
1453 * 'labeltwo'
1454 * ], function(err, apiResponse) {});
1455 *
1456 * //-
1457 * // If the callback is omitted, we'll return a Promise.
1458 * //-
1459 * bucket.deleteLabels().then(function(data) {
1460 * const apiResponse = data[0];
1461 * });
1462 * ```
1463 */
1464 deleteLabels(labelsOrCallback, callback) {
1465 let labels = new Array();
1466 if (typeof labelsOrCallback === 'function') {
1467 callback = labelsOrCallback;
1468 }
1469 else if (labelsOrCallback) {
1470 labels = arrify(labelsOrCallback);
1471 }
1472 const deleteLabels = (labels) => {
1473 const nullLabelMap = labels.reduce((nullLabelMap, labelKey) => {
1474 nullLabelMap[labelKey] = null;
1475 return nullLabelMap;
1476 }, {});
1477 this.setLabels(nullLabelMap, callback);
1478 };
1479 if (labels.length === 0) {
1480 this.getLabels((err, labels) => {
1481 if (err) {
1482 callback(err);
1483 return;
1484 }
1485 deleteLabels(Object.keys(labels));
1486 });
1487 }
1488 else {
1489 deleteLabels(labels);
1490 }
1491 }
1492 /**
1493 * @typedef {array} DisableRequesterPaysResponse
1494 * @property {object} 0 The full API response.
1495 */
1496 /**
1497 * @callback DisableRequesterPaysCallback
1498 * @param {?Error} err Request error, if any.
1499 * @param {object} apiResponse The full API response.
1500 */
1501 /**
1502 * <div class="notice">
1503 * <strong>Early Access Testers Only</strong>
1504 * <p>
1505 * This feature is not yet widely-available.
1506 * </p>
1507 * </div>
1508 *
1509 * Disable `requesterPays` functionality from this bucket.
1510 *
1511 * @param {DisableRequesterPaysCallback} [callback] Callback function.
1512 * @returns {Promise<DisableRequesterPaysCallback>}
1513 *
1514 * @example
1515 * ```
1516 * const {Storage} = require('@google-cloud/storage');
1517 * const storage = new Storage();
1518 * const bucket = storage.bucket('albums');
1519 *
1520 * bucket.disableRequesterPays(function(err, apiResponse) {
1521 * if (!err) {
1522 * // requesterPays functionality disabled successfully.
1523 * }
1524 * });
1525 *
1526 * //-
1527 * // If the callback is omitted, we'll return a Promise.
1528 * //-
1529 * bucket.disableRequesterPays().then(function(data) {
1530 * const apiResponse = data[0];
1531 * });
1532 *
1533 * ```
1534 * @example <caption>include:samples/requesterPays.js</caption>
1535 * region_tag:storage_disable_requester_pays
1536 * Example of disabling requester pays:
1537 */
1538 disableRequesterPays(callback) {
1539 this.disableAutoRetryConditionallyIdempotent_(this.methods.setMetadata, AvailableServiceObjectMethods.setMetadata);
1540 this.setMetadata({
1541 billing: {
1542 requesterPays: false,
1543 },
1544 }, callback || nodejs_common_1.util.noop);
1545 this.storage.retryOptions.autoRetry = this.instanceRetryValue;
1546 }
1547 /**
1548 * Configuration object for enabling logging.
1549 *
1550 * @typedef {object} EnableLoggingOptions
1551 * @property {string|Bucket} [bucket] The bucket for the log entries. By
1552 * default, the current bucket is used.
1553 * @property {string} prefix A unique prefix for log object names.
1554 */
1555 /**
1556 * Enable logging functionality for this bucket. This will make two API
1557 * requests, first to grant Cloud Storage WRITE permission to the bucket, then
1558 * to set the appropriate configuration on the Bucket's metadata.
1559 *
1560 * @param {EnableLoggingOptions} config Configuration options.
1561 * @param {string|Bucket} [config.bucket] The bucket for the log entries. By
1562 * default, the current bucket is used.
1563 * @param {string} config.prefix A unique prefix for log object names.
1564 * @param {SetBucketMetadataCallback} [callback] Callback function.
1565 * @returns {Promise<SetBucketMetadataResponse>}
1566 *
1567 * @example
1568 * ```
1569 * const {Storage} = require('@google-cloud/storage');
1570 * const storage = new Storage();
1571 * const bucket = storage.bucket('albums');
1572 *
1573 * const config = {
1574 * prefix: 'log'
1575 * };
1576 *
1577 * bucket.enableLogging(config, function(err, apiResponse) {
1578 * if (!err) {
1579 * // Logging functionality enabled successfully.
1580 * }
1581 * });
1582 *
1583 * ```
1584 * @example
1585 * Optionally, provide a destination bucket.
1586 * ```
1587 * const config = {
1588 * prefix: 'log',
1589 * bucket: 'destination-bucket'
1590 * };
1591 *
1592 * bucket.enableLogging(config, function(err, apiResponse) {});
1593 * ```
1594 *
1595 * @example
1596 * If the callback is omitted, we'll return a Promise.
1597 * ```
1598 * bucket.enableLogging(config).then(function(data) {
1599 * const apiResponse = data[0];
1600 * });
1601 * ```
1602 */
1603 enableLogging(config, callback) {
1604 if (!config ||
1605 typeof config === 'function' ||
1606 typeof config.prefix === 'undefined') {
1607 throw new Error(BucketExceptionMessages.CONFIGURATION_OBJECT_PREFIX_REQUIRED);
1608 }
1609 const logBucket = config.bucket
1610 ? config.bucket.id || config.bucket
1611 : this.id;
1612 (async () => {
1613 let setMetadataResponse;
1614 try {
1615 const [policy] = await this.iam.getPolicy();
1616 policy.bindings.push({
1617 members: ['group:cloud-storage-analytics@google.com'],
1618 role: 'roles/storage.objectCreator',
1619 });
1620 await this.iam.setPolicy(policy);
1621 this.disableAutoRetryConditionallyIdempotent_(this.methods.setMetadata, AvailableServiceObjectMethods.setMetadata);
1622 [setMetadataResponse] = await this.setMetadata({
1623 logging: {
1624 logBucket,
1625 logObjectPrefix: config.prefix,
1626 },
1627 });
1628 }
1629 catch (e) {
1630 callback(e);
1631 return;
1632 }
1633 finally {
1634 this.storage.retryOptions.autoRetry = this.instanceRetryValue;
1635 }
1636 callback(null, setMetadataResponse);
1637 })();
1638 }
1639 /**
1640 * @typedef {array} EnableRequesterPaysResponse
1641 * @property {object} 0 The full API response.
1642 */
1643 /**
1644 * @callback EnableRequesterPaysCallback
1645 * @param {?Error} err Request error, if any.
1646 * @param {object} apiResponse The full API response.
1647 */
1648 /**
1649 * <div class="notice">
1650 * <strong>Early Access Testers Only</strong>
1651 * <p>
1652 * This feature is not yet widely-available.
1653 * </p>
1654 * </div>
1655 *
1656 * Enable `requesterPays` functionality for this bucket. This enables you, the
1657 * bucket owner, to have the requesting user assume the charges for the access
1658 * to your bucket and its contents.
1659 *
1660 * @param {EnableRequesterPaysCallback} [callback] Callback function.
1661 * @returns {Promise<EnableRequesterPaysResponse>}
1662 *
1663 * @example
1664 * ```
1665 * const {Storage} = require('@google-cloud/storage');
1666 * const storage = new Storage();
1667 * const bucket = storage.bucket('albums');
1668 *
1669 * bucket.enableRequesterPays(function(err, apiResponse) {
1670 * if (!err) {
1671 * // requesterPays functionality enabled successfully.
1672 * }
1673 * });
1674 *
1675 * //-
1676 * // If the callback is omitted, we'll return a Promise.
1677 * //-
1678 * bucket.enableRequesterPays().then(function(data) {
1679 * const apiResponse = data[0];
1680 * });
1681 *
1682 * ```
1683 * @example <caption>include:samples/requesterPays.js</caption>
1684 * region_tag:storage_enable_requester_pays
1685 * Example of enabling requester pays:
1686 */
1687 enableRequesterPays(callback) {
1688 this.disableAutoRetryConditionallyIdempotent_(this.methods.setMetadata, AvailableServiceObjectMethods.setMetadata);
1689 this.setMetadata({
1690 billing: {
1691 requesterPays: true,
1692 },
1693 }, callback || nodejs_common_1.util.noop);
1694 this.storage.retryOptions.autoRetry = this.instanceRetryValue;
1695 }
1696 /**
1697 * Create a {@link File} object. See {@link File} to see how to handle
1698 * the different use cases you may have.
1699 *
1700 * @param {string} name The name of the file in this bucket.
1701 * @param {FileOptions} [options] Configuration options.
1702 * @param {string|number} [options.generation] Only use a specific revision of
1703 * this file.
1704 * @param {string} [options.encryptionKey] A custom encryption key. See
1705 * {@link https://cloud.google.com/storage/docs/encryption#customer-supplied| Customer-supplied Encryption Keys}.
1706 * @param {string} [options.kmsKeyName] The name of the Cloud KMS key that will
1707 * be used to encrypt the object. Must be in the format:
1708 * `projects/my-project/locations/location/keyRings/my-kr/cryptoKeys/my-key`.
1709 * KMS key ring must use the same location as the bucket.
1710 * @param {string} [options.userProject] The ID of the project which will be
1711 * billed for all requests made from File object.
1712 * @returns {File}
1713 *
1714 * @example
1715 * ```
1716 * const {Storage} = require('@google-cloud/storage');
1717 * const storage = new Storage();
1718 * const bucket = storage.bucket('albums');
1719 * const file = bucket.file('my-existing-file.png');
1720 * ```
1721 */
1722 file(name, options) {
1723 if (!name) {
1724 throw Error(BucketExceptionMessages.SPECIFY_FILE_NAME);
1725 }
1726 return new file_1.File(this, name, options);
1727 }
1728 /**
1729 * @typedef {array} GetFilesResponse
1730 * @property {File[]} 0 Array of {@link File} instances.
1731 * @param {object} nextQuery 1 A query object to receive more results.
1732 * @param {object} apiResponse 2 The full API response.
1733 */
1734 /**
1735 * @callback GetFilesCallback
1736 * @param {?Error} err Request error, if any.
1737 * @param {File[]} files Array of {@link File} instances.
1738 * @param {object} nextQuery A query object to receive more results.
1739 * @param {object} apiResponse The full API response.
1740 */
1741 /**
1742 * Query object for listing files.
1743 *
1744 * @typedef {object} GetFilesOptions
1745 * @property {boolean} [autoPaginate=true] Have pagination handled
1746 * automatically.
1747 * @property {string} [delimiter] Results will contain only objects whose
1748 * names, aside from the prefix, do not contain delimiter. Objects whose
1749 * names, aside from the prefix, contain delimiter will have their name
1750 * truncated after the delimiter, returned in `apiResponse.prefixes`.
1751 * Duplicate prefixes are omitted.
1752 * @deprecated @property {string} [directory] Filter results based on a directory name, or
1753 * more technically, a "prefix". Assumes delimeter to be '/'. Deprecated. Use prefix instead.
1754 * @property {string} [endOffset] Filter results to objects whose names are
1755 * lexicographically before endOffset. If startOffset is also set, the objects
1756 * listed have names between startOffset (inclusive) and endOffset (exclusive).
1757 * @property {boolean} [includeTrailingDelimiter] If true, objects that end in
1758 * exactly one instance of delimiter have their metadata included in items[]
1759 * in addition to the relevant part of the object name appearing in prefixes[].
1760 * @property {string} [prefix] Filter results to objects whose names begin
1761 * with this prefix.
1762 * @property {number} [maxApiCalls] Maximum number of API calls to make.
1763 * @property {number} [maxResults] Maximum number of items plus prefixes to
1764 * return per call.
1765 * Note: By default will handle pagination automatically
1766 * if more than 1 page worth of results are requested per call.
1767 * When `autoPaginate` is set to `false` the smaller of `maxResults`
1768 * or 1 page of results will be returned per call.
1769 * @property {string} [pageToken] A previously-returned page token
1770 * representing part of the larger set of results to view.
1771 * @property {string} [startOffset] Filter results to objects whose names are
1772 * lexicographically equal to or after startOffset. If endOffset is also set,
1773 * the objects listed have names between startOffset (inclusive) and endOffset (exclusive).
1774 * @property {string} [userProject] The ID of the project which will be
1775 * billed for the request.
1776 * @property {boolean} [versions] If true, returns File objects scoped to
1777 * their versions.
1778 */
1779 /**
1780 * Get {@link File} objects for the files currently in the bucket.
1781 *
1782 * See {@link https://cloud.google.com/storage/docs/json_api/v1/objects/list| Objects: list API Documentation}
1783 *
1784 * @param {GetFilesOptions} [query] Query object for listing files.
1785 * @param {boolean} [query.autoPaginate=true] Have pagination handled
1786 * automatically.
1787 * @param {string} [query.delimiter] Results will contain only objects whose
1788 * names, aside from the prefix, do not contain delimiter. Objects whose
1789 * names, aside from the prefix, contain delimiter will have their name
1790 * truncated after the delimiter, returned in `apiResponse.prefixes`.
1791 * Duplicate prefixes are omitted.
1792 * @deprecated @param {string} [query.directory] Filter results based on a directory name, or
1793 * more technically, a "prefix". Assumes delimeter to be '/'. Deprecated. Use query.prefix instead.
1794 * @param {string} [query.endOffset] Filter results to objects whose names are
1795 * lexicographically before endOffset. If startOffset is also set, the objects
1796 * listed have names between startOffset (inclusive) and endOffset (exclusive).
1797 * @param {boolean} [query.includeTrailingDelimiter] If true, objects that end in
1798 * exactly one instance of delimiter have their metadata included in items[]
1799 * in addition to the relevant part of the object name appearing in prefixes[].
1800 * @param {string} [query.prefix] Filter results to objects whose names begin
1801 * with this prefix.
1802 * @param {number} [query.maxApiCalls] Maximum number of API calls to make.
1803 * @param {number} [query.maxResults] Maximum number of items plus prefixes to
1804 * return per call.
1805 * Note: By default will handle pagination automatically
1806 * if more than 1 page worth of results are requested per call.
1807 * When `autoPaginate` is set to `false` the smaller of `maxResults`
1808 * or 1 page of results will be returned per call.
1809 * @param {string} [query.pageToken] A previously-returned page token
1810 * representing part of the larger set of results to view.
1811 * @param {string} [query.startOffset] Filter results to objects whose names are
1812 * lexicographically equal to or after startOffset. If endOffset is also set,
1813 * the objects listed have names between startOffset (inclusive) and endOffset (exclusive).
1814 * @param {string} [query.userProject] The ID of the project which will be
1815 * billed for the request.
1816 * @param {boolean} [query.versions] If true, returns File objects scoped to
1817 * their versions.
1818 * @param {GetFilesCallback} [callback] Callback function.
1819 * @returns {Promise<GetFilesResponse>}
1820 *
1821 * @example
1822 * ```
1823 * const {Storage} = require('@google-cloud/storage');
1824 * const storage = new Storage();
1825 * const bucket = storage.bucket('albums');
1826 *
1827 * bucket.getFiles(function(err, files) {
1828 * if (!err) {
1829 * // files is an array of File objects.
1830 * }
1831 * });
1832 *
1833 * //-
1834 * // If your bucket has versioning enabled, you can get all of your files
1835 * // scoped to their generation.
1836 * //-
1837 * bucket.getFiles({
1838 * versions: true
1839 * }, function(err, files) {
1840 * // Each file is scoped to its generation.
1841 * });
1842 *
1843 * //-
1844 * // To control how many API requests are made and page through the results
1845 * // manually, set `autoPaginate` to `false`.
1846 * //-
1847 * const callback = function(err, files, nextQuery, apiResponse) {
1848 * if (nextQuery) {
1849 * // More results exist.
1850 * bucket.getFiles(nextQuery, callback);
1851 * }
1852 *
1853 * // The `metadata` property is populated for you with the metadata at the
1854 * // time of fetching.
1855 * files[0].metadata;
1856 *
1857 * // However, in cases where you are concerned the metadata could have
1858 * // changed, use the `getMetadata` method.
1859 * files[0].getMetadata(function(err, metadata) {});
1860 * };
1861 *
1862 * bucket.getFiles({
1863 * autoPaginate: false
1864 * }, callback);
1865 *
1866 * //-
1867 * // If the callback is omitted, we'll return a Promise.
1868 * //-
1869 * bucket.getFiles().then(function(data) {
1870 * const files = data[0];
1871 * });
1872 *
1873 * ```
1874 * @example
1875 * <h6>Simulating a File System</h6><p>With `autoPaginate: false`, it's possible to iterate over files which incorporate a common structure using a delimiter.</p><p>Consider the following remote objects:</p><ol><li>"a"</li><li>"a/b/c/d"</li><li>"b/d/e"</li></ol><p>Using a delimiter of `/` will return a single file, "a".</p><p>`apiResponse.prefixes` will return the "sub-directories" that were found:</p><ol><li>"a/"</li><li>"b/"</li></ol>
1876 * ```
1877 * bucket.getFiles({
1878 * autoPaginate: false,
1879 * delimiter: '/'
1880 * }, function(err, files, nextQuery, apiResponse) {
1881 * // files = [
1882 * // {File} // File object for file "a"
1883 * // ]
1884 *
1885 * // apiResponse.prefixes = [
1886 * // 'a/',
1887 * // 'b/'
1888 * // ]
1889 * });
1890 * ```
1891 *
1892 * @example
1893 * Using prefixes, it's now possible to simulate a file system with follow-up requests.
1894 * ```
1895 * bucket.getFiles({
1896 * autoPaginate: false,
1897 * delimiter: '/',
1898 * prefix: 'a/'
1899 * }, function(err, files, nextQuery, apiResponse) {
1900 * // No files found within "directory" a.
1901 * // files = []
1902 *
1903 * // However, a "sub-directory" was found.
1904 * // This prefix can be used to continue traversing the "file system".
1905 * // apiResponse.prefixes = [
1906 * // 'a/b/'
1907 * // ]
1908 * });
1909 * ```
1910 *
1911 * @example <caption>include:samples/files.js</caption>
1912 * region_tag:storage_list_files
1913 * Another example:
1914 *
1915 * @example <caption>include:samples/files.js</caption>
1916 * region_tag:storage_list_files_with_prefix
1917 * Example of listing files, filtered by a prefix:
1918 */
1919 getFiles(queryOrCallback, callback) {
1920 let query = typeof queryOrCallback === 'object' ? queryOrCallback : {};
1921 if (!callback) {
1922 callback = queryOrCallback;
1923 }
1924 query = Object.assign({}, query);
1925 if (query.directory) {
1926 query.prefix = `${query.directory}/`.replace(/\/*$/, '/');
1927 delete query.directory;
1928 }
1929 this.request({
1930 uri: '/o',
1931 qs: query,
1932 }, (err, resp) => {
1933 if (err) {
1934 // eslint-disable-next-line @typescript-eslint/no-explicit-any
1935 callback(err, null, null, resp);
1936 return;
1937 }
1938 const files = arrify(resp.items).map((file) => {
1939 const options = {};
1940 if (query.versions) {
1941 options.generation = file.generation;
1942 }
1943 if (file.kmsKeyName) {
1944 options.kmsKeyName = file.kmsKeyName;
1945 }
1946 const fileInstance = this.file(file.name, options);
1947 fileInstance.metadata = file;
1948 return fileInstance;
1949 });
1950 let nextQuery = null;
1951 if (resp.nextPageToken) {
1952 nextQuery = Object.assign({}, query, {
1953 pageToken: resp.nextPageToken,
1954 });
1955 }
1956 // eslint-disable-next-line @typescript-eslint/no-explicit-any
1957 callback(null, files, nextQuery, resp);
1958 });
1959 }
1960 /**
1961 * @typedef {object} GetLabelsOptions Configuration options for Bucket#getLabels().
1962 * @param {string} [userProject] The ID of the project which will be
1963 * billed for the request.
1964 */
1965 /**
1966 * @typedef {array} GetLabelsResponse
1967 * @property {object} 0 Object of labels currently set on this bucket.
1968 */
1969 /**
1970 * @callback GetLabelsCallback
1971 * @param {?Error} err Request error, if any.
1972 * @param {object} labels Object of labels currently set on this bucket.
1973 */
1974 /**
1975 * Get the labels currently set on this bucket.
1976 *
1977 * @param {object} [options] Configuration options.
1978 * @param {string} [options.userProject] The ID of the project which will be
1979 * billed for the request.
1980 * @param {GetLabelsCallback} [callback] Callback function.
1981 * @returns {Promise<GetLabelsCallback>}
1982 *
1983 * @example
1984 * ```
1985 * const {Storage} = require('@google-cloud/storage');
1986 * const storage = new Storage();
1987 * const bucket = storage.bucket('albums');
1988 *
1989 * bucket.getLabels(function(err, labels) {
1990 * if (err) {
1991 * // Error handling omitted.
1992 * }
1993 *
1994 * // labels = {
1995 * // label: 'labelValue',
1996 * // ...
1997 * // }
1998 * });
1999 *
2000 * //-
2001 * // If the callback is omitted, we'll return a Promise.
2002 * //-
2003 * bucket.getLabels().then(function(data) {
2004 * const labels = data[0];
2005 * });
2006 * ```
2007 */
2008 getLabels(optionsOrCallback, callback) {
2009 let options = {};
2010 if (typeof optionsOrCallback === 'function') {
2011 callback = optionsOrCallback;
2012 }
2013 else if (optionsOrCallback) {
2014 options = optionsOrCallback;
2015 }
2016 this.getMetadata(options, (err, metadata) => {
2017 if (err) {
2018 callback(err, null);
2019 return;
2020 }
2021 callback(null, metadata.labels || {});
2022 });
2023 }
2024 /**
2025 * @typedef {object} GetNotificationsOptions Configuration options for Bucket#getNotification().
2026 * @property {string} [userProject] The ID of the project which will be
2027 * billed for the request.
2028 */
2029 /**
2030 * @callback GetNotificationsCallback
2031 * @param {?Error} err Request error, if any.
2032 * @param {Notification[]} notifications Array of {@link Notification}
2033 * instances.
2034 * @param {object} apiResponse The full API response.
2035 */
2036 /**
2037 * @typedef {array} GetNotificationsResponse
2038 * @property {Notification[]} 0 Array of {@link Notification} instances.
2039 * @property {object} 1 The full API response.
2040 */
2041 /**
2042 * Retrieves a list of notification subscriptions for a given bucket.
2043 *
2044 * See {@link https://cloud.google.com/storage/docs/json_api/v1/notifications/list| Notifications: list}
2045 *
2046 * @param {GetNotificationsOptions} [options] Configuration options.
2047 * @param {string} [options.userProject] The ID of the project which will be
2048 * billed for the request.
2049 * @param {GetNotificationsCallback} [callback] Callback function.
2050 * @returns {Promise<GetNotificationsResponse>}
2051 *
2052 * @example
2053 * ```
2054 * const {Storage} = require('@google-cloud/storage');
2055 * const storage = new Storage();
2056 * const bucket = storage.bucket('my-bucket');
2057 *
2058 * bucket.getNotifications(function(err, notifications, apiResponse) {
2059 * if (!err) {
2060 * // notifications is an array of Notification objects.
2061 * }
2062 * });
2063 *
2064 * //-
2065 * // If the callback is omitted, we'll return a Promise.
2066 * //-
2067 * bucket.getNotifications().then(function(data) {
2068 * const notifications = data[0];
2069 * const apiResponse = data[1];
2070 * });
2071 *
2072 * ```
2073 * @example <caption>include:samples/listNotifications.js</caption>
2074 * region_tag:storage_list_bucket_notifications
2075 * Another example:
2076 */
2077 getNotifications(optionsOrCallback, callback) {
2078 let options = {};
2079 if (typeof optionsOrCallback === 'function') {
2080 callback = optionsOrCallback;
2081 }
2082 else if (optionsOrCallback) {
2083 options = optionsOrCallback;
2084 }
2085 this.request({
2086 uri: '/notificationConfigs',
2087 qs: options,
2088 }, (err, resp) => {
2089 if (err) {
2090 callback(err, null, resp);
2091 return;
2092 }
2093 const notifications = arrify(resp.items).map((notification) => {
2094 const notificationInstance = this.notification(notification.id);
2095 notificationInstance.metadata = notification;
2096 return notificationInstance;
2097 });
2098 callback(null, notifications, resp);
2099 });
2100 }
2101 /**
2102 * @typedef {array} GetSignedUrlResponse
2103 * @property {object} 0 The signed URL.
2104 */
2105 /**
2106 * @callback GetSignedUrlCallback
2107 * @param {?Error} err Request error, if any.
2108 * @param {object} url The signed URL.
2109 */
2110 /**
2111 * @typedef {object} GetBucketSignedUrlConfig
2112 * @property {string} action Currently only supports "list" (HTTP: GET).
2113 * @property {*} expires A timestamp when this link will expire. Any value
2114 * given is passed to `new Date()`.
2115 * Note: 'v4' supports maximum duration of 7 days (604800 seconds) from now.
2116 * @property {string} [version='v2'] The signing version to use, either
2117 * 'v2' or 'v4'.
2118 * @property {boolean} [virtualHostedStyle=false] Use virtual hosted-style
2119 * URLs ('https://mybucket.storage.googleapis.com/...') instead of path-style
2120 * ('https://storage.googleapis.com/mybucket/...'). Virtual hosted-style URLs
2121 * should generally be preferred instaed of path-style URL.
2122 * Currently defaults to `false` for path-style, although this may change in a
2123 * future major-version release.
2124 * @property {string} [cname] The cname for this bucket, i.e.,
2125 * "https://cdn.example.com".
2126 * See [reference]{@link https://cloud.google.com/storage/docs/access-control/signed-urls#example}
2127 * @property {object} [extensionHeaders] If these headers are used, the
2128 * server will check to make sure that the client provides matching
2129 * values. See {@link https://cloud.google.com/storage/docs/access-control/signed-urls#about-canonical-extension-headers| Canonical extension headers}
2130 * for the requirements of this feature, most notably:
2131 * - The header name must be prefixed with `x-goog-`
2132 * - The header name must be all lowercase
2133 *
2134 * Note: Multi-valued header passed as an array in the extensionHeaders
2135 * object is converted into a string, delimited by `,` with
2136 * no space. Requests made using the signed URL will need to
2137 * delimit multi-valued headers using a single `,` as well, or
2138 * else the server will report a mismatched signature.
2139 * @property {object} [queryParams] Additional query parameters to include
2140 * in the signed URL.
2141 */
2142 /**
2143 * Get a signed URL to allow limited time access to a bucket.
2144 *
2145 * In Google Cloud Platform environments, such as Cloud Functions and App
2146 * Engine, you usually don't provide a `keyFilename` or `credentials` during
2147 * instantiation. In those environments, we call the
2148 * {@link https://cloud.google.com/iam/docs/reference/credentials/rest/v1/projects.serviceAccounts/signBlob| signBlob API}
2149 * to create a signed URL. That API requires either the
2150 * `https://www.googleapis.com/auth/iam` or
2151 * `https://www.googleapis.com/auth/cloud-platform` scope, so be sure they are
2152 * enabled.
2153 *
2154 * See {@link https://cloud.google.com/storage/docs/access-control/signed-urls| Signed URLs Reference}
2155 *
2156 * @throws {Error} if an expiration timestamp from the past is given.
2157 *
2158 * @param {GetBucketSignedUrlConfig} config Configuration object.
2159 * @param {string} config.action Currently only supports "list" (HTTP: GET).
2160 * @param {*} config.expires A timestamp when this link will expire. Any value
2161 * given is passed to `new Date()`.
2162 * Note: 'v4' supports maximum duration of 7 days (604800 seconds) from now.
2163 * @param {string} [config.version='v2'] The signing version to use, either
2164 * 'v2' or 'v4'.
2165 * @param {boolean} [config.virtualHostedStyle=false] Use virtual hosted-style
2166 * URLs ('https://mybucket.storage.googleapis.com/...') instead of path-style
2167 * ('https://storage.googleapis.com/mybucket/...'). Virtual hosted-style URLs
2168 * should generally be preferred instaed of path-style URL.
2169 * Currently defaults to `false` for path-style, although this may change in a
2170 * future major-version release.
2171 * @param {string} [config.cname] The cname for this bucket, i.e.,
2172 * "https://cdn.example.com".
2173 * See [reference]{@link https://cloud.google.com/storage/docs/access-control/signed-urls#example}
2174 * @param {object} [config.extensionHeaders] If these headers are used, the
2175 * server will check to make sure that the client provides matching
2176 * values. See {@link https://cloud.google.com/storage/docs/access-control/signed-urls#about-canonical-extension-headers| Canonical extension headers}
2177 * for the requirements of this feature, most notably:
2178 * - The header name must be prefixed with `x-goog-`
2179 * - The header name must be all lowercase
2180 *
2181 * Note: Multi-valued header passed as an array in the extensionHeaders
2182 * object is converted into a string, delimited by `,` with
2183 * no space. Requests made using the signed URL will need to
2184 * delimit multi-valued headers using a single `,` as well, or
2185 * else the server will report a mismatched signature.
2186 * @property {object} [config.queryParams] Additional query parameters to include
2187 * in the signed URL.
2188 * @param {GetSignedUrlCallback} [callback] Callback function.
2189 * @returns {Promise<GetSignedUrlResponse>}
2190 *
2191 * @example
2192 * ```
2193 * const {Storage} = require('@google-cloud/storage');
2194 * const storage = new Storage();
2195 * const myBucket = storage.bucket('my-bucket');
2196 *
2197 * //-
2198 * // Generate a URL that allows temporary access to list files in a bucket.
2199 * //-
2200 * const request = require('request');
2201 *
2202 * const config = {
2203 * action: 'list',
2204 * expires: '03-17-2025'
2205 * };
2206 *
2207 * bucket.getSignedUrl(config, function(err, url) {
2208 * if (err) {
2209 * console.error(err);
2210 * return;
2211 * }
2212 *
2213 * // The bucket is now available to be listed from this URL.
2214 * request(url, function(err, resp) {
2215 * // resp.statusCode = 200
2216 * });
2217 * });
2218 *
2219 * //-
2220 * // If the callback is omitted, we'll return a Promise.
2221 * //-
2222 * bucket.getSignedUrl(config).then(function(data) {
2223 * const url = data[0];
2224 * });
2225 * ```
2226 */
2227 getSignedUrl(cfg, callback) {
2228 const method = BucketActionToHTTPMethod[cfg.action];
2229 if (!method) {
2230 throw new Error(storage_1.ExceptionMessages.INVALID_ACTION);
2231 }
2232 const signConfig = {
2233 method,
2234 expires: cfg.expires,
2235 version: cfg.version,
2236 cname: cfg.cname,
2237 extensionHeaders: cfg.extensionHeaders || {},
2238 queryParams: cfg.queryParams || {},
2239 };
2240 if (!this.signer) {
2241 this.signer = new signer_1.URLSigner(this.storage.authClient, this);
2242 }
2243 this.signer
2244 .getSignedUrl(signConfig)
2245 .then(signedUrl => callback(null, signedUrl), callback);
2246 }
2247 /**
2248 * @callback BucketLockCallback
2249 * @param {?Error} err Request error, if any.
2250 * @param {object} apiResponse The full API response.
2251 */
2252 /**
2253 * Lock a previously-defined retention policy. This will prevent changes to
2254 * the policy.
2255 *
2256 * @throws {Error} if a metageneration is not provided.
2257 *
2258 * @param {number|string} metageneration The bucket's metageneration. This is
2259 * accesssible from calling {@link File#getMetadata}.
2260 * @param {BucketLockCallback} [callback] Callback function.
2261 * @returns {Promise<BucketLockResponse>}
2262 *
2263 * @example
2264 * ```
2265 * const storage = require('@google-cloud/storage')();
2266 * const bucket = storage.bucket('albums');
2267 *
2268 * const metageneration = 2;
2269 *
2270 * bucket.lock(metageneration, function(err, apiResponse) {});
2271 *
2272 * //-
2273 * // If the callback is omitted, we'll return a Promise.
2274 * //-
2275 * bucket.lock(metageneration).then(function(data) {
2276 * const apiResponse = data[0];
2277 * });
2278 * ```
2279 */
2280 lock(metageneration, callback) {
2281 const metatype = typeof metageneration;
2282 if (metatype !== 'number' && metatype !== 'string') {
2283 throw new Error(BucketExceptionMessages.METAGENERATION_NOT_PROVIDED);
2284 }
2285 this.request({
2286 method: 'POST',
2287 uri: '/lockRetentionPolicy',
2288 qs: {
2289 ifMetagenerationMatch: metageneration,
2290 },
2291 }, callback);
2292 }
2293 /**
2294 * @typedef {array} MakeBucketPrivateResponse
2295 * @property {File[]} 0 List of files made private.
2296 */
2297 /**
2298 * @callback MakeBucketPrivateCallback
2299 * @param {?Error} err Request error, if any.
2300 * @param {File[]} files List of files made private.
2301 */
2302 /**
2303 * @typedef {object} MakeBucketPrivateOptions
2304 * @property {boolean} [includeFiles=false] Make each file in the bucket
2305 * private.
2306 * @property {Metadata} [metadata] Define custom metadata properties to define
2307 * along with the operation.
2308 * @property {boolean} [force] Queue errors occurred while making files
2309 * private until all files have been processed.
2310 * @property {string} [userProject] The ID of the project which will be
2311 * billed for the request.
2312 */
2313 /**
2314 * Make the bucket listing private.
2315 *
2316 * You may also choose to make the contents of the bucket private by
2317 * specifying `includeFiles: true`. This will automatically run
2318 * {@link File#makePrivate} for every file in the bucket.
2319 *
2320 * When specifying `includeFiles: true`, use `force: true` to delay execution
2321 * of your callback until all files have been processed. By default, the
2322 * callback is executed after the first error. Use `force` to queue such
2323 * errors until all files have been processed, after which they will be
2324 * returned as an array as the first argument to your callback.
2325 *
2326 * NOTE: This may cause the process to be long-running and use a high number
2327 * of requests. Use with caution.
2328 *
2329 * See {@link https://cloud.google.com/storage/docs/json_api/v1/buckets/patch| Buckets: patch API Documentation}
2330 *
2331 * @param {MakeBucketPrivateOptions} [options] Configuration options.
2332 * @param {boolean} [options.includeFiles=false] Make each file in the bucket
2333 * private.
2334 * @param {Metadata} [options.metadata] Define custom metadata properties to define
2335 * along with the operation.
2336 * @param {boolean} [options.force] Queue errors occurred while making files
2337 * private until all files have been processed.
2338 * @param {string} [options.userProject] The ID of the project which will be
2339 * billed for the request.
2340 * @param {MakeBucketPrivateCallback} [callback] Callback function.
2341 * @returns {Promise<MakeBucketPrivateResponse>}
2342 *
2343 * @example
2344 * ```
2345 * const {Storage} = require('@google-cloud/storage');
2346 * const storage = new Storage();
2347 * const bucket = storage.bucket('albums');
2348 *
2349 * //-
2350 * // Make the bucket private.
2351 * //-
2352 * bucket.makePrivate(function(err) {});
2353 *
2354 * //-
2355 * // Make the bucket and its contents private.
2356 * //-
2357 * const opts = {
2358 * includeFiles: true
2359 * };
2360 *
2361 * bucket.makePrivate(opts, function(err, files) {
2362 * // `err`:
2363 * // The first error to occur, otherwise null.
2364 * //
2365 * // `files`:
2366 * // Array of files successfully made private in the bucket.
2367 * });
2368 *
2369 * //-
2370 * // Make the bucket and its contents private, using force to suppress errors
2371 * // until all files have been processed.
2372 * //-
2373 * const opts = {
2374 * includeFiles: true,
2375 * force: true
2376 * };
2377 *
2378 * bucket.makePrivate(opts, function(errors, files) {
2379 * // `errors`:
2380 * // Array of errors if any occurred, otherwise null.
2381 * //
2382 * // `files`:
2383 * // Array of files successfully made private in the bucket.
2384 * });
2385 *
2386 * //-
2387 * // If the callback is omitted, we'll return a Promise.
2388 * //-
2389 * bucket.makePrivate(opts).then(function(data) {
2390 * const files = data[0];
2391 * });
2392 * ```
2393 */
2394 makePrivate(optionsOrCallback, callback) {
2395 const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
2396 callback =
2397 typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
2398 options.private = true;
2399 const query = {
2400 predefinedAcl: 'projectPrivate',
2401 };
2402 if (options.userProject) {
2403 query.userProject = options.userProject;
2404 }
2405 this.disableAutoRetryConditionallyIdempotent_(this.methods.setMetadata, AvailableServiceObjectMethods.setMetadata);
2406 // You aren't allowed to set both predefinedAcl & acl properties on a bucket
2407 // so acl must explicitly be nullified.
2408 const metadata = extend({}, options.metadata, { acl: null });
2409 this.setMetadata(metadata, query)
2410 .then(() => {
2411 if (options.includeFiles) {
2412 return util_1.promisify(this.makeAllFilesPublicPrivate_).call(this, options);
2413 }
2414 return [];
2415 })
2416 .then(files => callback(null, files), callback)
2417 .finally(() => {
2418 this.storage.retryOptions.autoRetry = this.instanceRetryValue;
2419 });
2420 }
2421 /**
2422 * @typedef {object} MakeBucketPublicOptions
2423 * @property {boolean} [includeFiles=false] Make each file in the bucket
2424 * private.
2425 * @property {boolean} [force] Queue errors occurred while making files
2426 * private until all files have been processed.
2427 */
2428 /**
2429 * @callback MakeBucketPublicCallback
2430 * @param {?Error} err Request error, if any.
2431 * @param {File[]} files List of files made public.
2432 */
2433 /**
2434 * @typedef {array} MakeBucketPublicResponse
2435 * @property {File[]} 0 List of files made public.
2436 */
2437 /**
2438 * Make the bucket publicly readable.
2439 *
2440 * You may also choose to make the contents of the bucket publicly readable by
2441 * specifying `includeFiles: true`. This will automatically run
2442 * {@link File#makePublic} for every file in the bucket.
2443 *
2444 * When specifying `includeFiles: true`, use `force: true` to delay execution
2445 * of your callback until all files have been processed. By default, the
2446 * callback is executed after the first error. Use `force` to queue such
2447 * errors until all files have been processed, after which they will be
2448 * returned as an array as the first argument to your callback.
2449 *
2450 * NOTE: This may cause the process to be long-running and use a high number
2451 * of requests. Use with caution.
2452 *
2453 * See {@link https://cloud.google.com/storage/docs/json_api/v1/buckets/patch| Buckets: patch API Documentation}
2454 *
2455 * @param {MakeBucketPublicOptions} [options] Configuration options.
2456 * @param {boolean} [options.includeFiles=false] Make each file in the bucket
2457 * private.
2458 * @param {boolean} [options.force] Queue errors occurred while making files
2459 * private until all files have been processed.
2460 * @param {MakeBucketPublicCallback} [callback] Callback function.
2461 * @returns {Promise<MakeBucketPublicResponse>}
2462 *
2463 * @example
2464 * ```
2465 * const {Storage} = require('@google-cloud/storage');
2466 * const storage = new Storage();
2467 * const bucket = storage.bucket('albums');
2468 *
2469 * //-
2470 * // Make the bucket publicly readable.
2471 * //-
2472 * bucket.makePublic(function(err) {});
2473 *
2474 * //-
2475 * // Make the bucket and its contents publicly readable.
2476 * //-
2477 * const opts = {
2478 * includeFiles: true
2479 * };
2480 *
2481 * bucket.makePublic(opts, function(err, files) {
2482 * // `err`:
2483 * // The first error to occur, otherwise null.
2484 * //
2485 * // `files`:
2486 * // Array of files successfully made public in the bucket.
2487 * });
2488 *
2489 * //-
2490 * // Make the bucket and its contents publicly readable, using force to
2491 * // suppress errors until all files have been processed.
2492 * //-
2493 * const opts = {
2494 * includeFiles: true,
2495 * force: true
2496 * };
2497 *
2498 * bucket.makePublic(opts, function(errors, files) {
2499 * // `errors`:
2500 * // Array of errors if any occurred, otherwise null.
2501 * //
2502 * // `files`:
2503 * // Array of files successfully made public in the bucket.
2504 * });
2505 *
2506 * //-
2507 * // If the callback is omitted, we'll return a Promise.
2508 * //-
2509 * bucket.makePublic(opts).then(function(data) {
2510 * const files = data[0];
2511 * });
2512 * ```
2513 */
2514 makePublic(optionsOrCallback, callback) {
2515 const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
2516 callback =
2517 typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
2518 const req = extend(true, { public: true }, options);
2519 this.acl
2520 .add({
2521 entity: 'allUsers',
2522 role: 'READER',
2523 })
2524 .then(() => {
2525 return this.acl.default.add({
2526 entity: 'allUsers',
2527 role: 'READER',
2528 });
2529 })
2530 .then(() => {
2531 if (req.includeFiles) {
2532 return util_1.promisify(this.makeAllFilesPublicPrivate_).call(this, req);
2533 }
2534 return [];
2535 })
2536 .then(files => callback(null, files), callback);
2537 }
2538 /**
2539 * Get a reference to a Cloud Pub/Sub Notification.
2540 *
2541 * @param {string} id ID of notification.
2542 * @returns {Notification}
2543 * @see Notification
2544 *
2545 * @example
2546 * ```
2547 * const {Storage} = require('@google-cloud/storage');
2548 * const storage = new Storage();
2549 * const bucket = storage.bucket('my-bucket');
2550 * const notification = bucket.notification('1');
2551 * ```
2552 */
2553 notification(id) {
2554 if (!id) {
2555 throw new Error(BucketExceptionMessages.SUPPLY_NOTIFICATION_ID);
2556 }
2557 return new notification_1.Notification(this, id);
2558 }
2559 /**
2560 * Remove an already-existing retention policy from this bucket, if it is not
2561 * locked.
2562 *
2563 * @param {SetBucketMetadataCallback} [callback] Callback function.
2564 * @returns {Promise<SetBucketMetadataResponse>}
2565 *
2566 * @example
2567 * ```
2568 * const storage = require('@google-cloud/storage')();
2569 * const bucket = storage.bucket('albums');
2570 *
2571 * bucket.removeRetentionPeriod(function(err, apiResponse) {});
2572 *
2573 * //-
2574 * // If the callback is omitted, we'll return a Promise.
2575 * //-
2576 * bucket.removeRetentionPeriod().then(function(data) {
2577 * const apiResponse = data[0];
2578 * });
2579 * ```
2580 */
2581 removeRetentionPeriod(callback) {
2582 this.disableAutoRetryConditionallyIdempotent_(this.methods.setMetadata, AvailableServiceObjectMethods.setMetadata);
2583 this.setMetadata({
2584 retentionPolicy: null,
2585 }, callback);
2586 this.storage.retryOptions.autoRetry = this.instanceRetryValue;
2587 }
2588 /**
2589 * Makes request and applies userProject query parameter if necessary.
2590 *
2591 * @private
2592 *
2593 * @param {object} reqOpts - The request options.
2594 * @param {function} callback - The callback function.
2595 */
2596 request(reqOpts, callback) {
2597 if (this.userProject && (!reqOpts.qs || !reqOpts.qs.userProject)) {
2598 reqOpts.qs = extend(reqOpts.qs, { userProject: this.userProject });
2599 }
2600 return super.request(reqOpts, callback);
2601 }
2602 /**
2603 * @typedef {array} SetLabelsResponse
2604 * @property {object} 0 The bucket metadata.
2605 */
2606 /**
2607 * @callback SetLabelsCallback
2608 * @param {?Error} err Request error, if any.
2609 * @param {object} metadata The bucket metadata.
2610 */
2611 /**
2612 * @typedef {object} SetLabelsOptions Configuration options for Bucket#setLabels().
2613 * @property {string} [userProject] The ID of the project which will be
2614 * billed for the request.
2615 */
2616 /**
2617 * Set labels on the bucket.
2618 *
2619 * This makes an underlying call to {@link Bucket#setMetadata}, which
2620 * is a PATCH request. This means an individual label can be overwritten, but
2621 * unmentioned labels will not be touched.
2622 *
2623 * @param {object<string, string>} labels Labels to set on the bucket.
2624 * @param {SetLabelsOptions} [options] Configuration options.
2625 * @param {string} [options.userProject] The ID of the project which will be
2626 * billed for the request.
2627 * @param {SetLabelsCallback} [callback] Callback function.
2628 * @returns {Promise<SetLabelsResponse>}
2629 *
2630 * @example
2631 * ```
2632 * const {Storage} = require('@google-cloud/storage');
2633 * const storage = new Storage();
2634 * const bucket = storage.bucket('albums');
2635 *
2636 * const labels = {
2637 * labelone: 'labelonevalue',
2638 * labeltwo: 'labeltwovalue'
2639 * };
2640 *
2641 * bucket.setLabels(labels, function(err, metadata) {
2642 * if (!err) {
2643 * // Labels set successfully.
2644 * }
2645 * });
2646 *
2647 * //-
2648 * // If the callback is omitted, we'll return a Promise.
2649 * //-
2650 * bucket.setLabels(labels).then(function(data) {
2651 * const metadata = data[0];
2652 * });
2653 * ```
2654 */
2655 setLabels(labels, optionsOrCallback, callback) {
2656 const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
2657 callback =
2658 typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
2659 callback = callback || nodejs_common_1.util.noop;
2660 this.disableAutoRetryConditionallyIdempotent_(this.methods.setMetadata, AvailableServiceObjectMethods.setMetadata);
2661 this.setMetadata({ labels }, options, callback);
2662 this.storage.retryOptions.autoRetry = this.instanceRetryValue;
2663 }
2664 /**
2665 * Lock all objects contained in the bucket, based on their creation time. Any
2666 * attempt to overwrite or delete objects younger than the retention period
2667 * will result in a `PERMISSION_DENIED` error.
2668 *
2669 * An unlocked retention policy can be modified or removed from the bucket via
2670 * {@link File#removeRetentionPeriod} and {@link File#setRetentionPeriod}. A
2671 * locked retention policy cannot be removed or shortened in duration for the
2672 * lifetime of the bucket. Attempting to remove or decrease period of a locked
2673 * retention policy will result in a `PERMISSION_DENIED` error. You can still
2674 * increase the policy.
2675 *
2676 * @param {*} duration In seconds, the minimum retention time for all objects
2677 * contained in this bucket.
2678 * @param {SetBucketMetadataCallback} [callback] Callback function.
2679 * @returns {Promise<SetBucketMetadataResponse>}
2680 *
2681 * @example
2682 * ```
2683 * const storage = require('@google-cloud/storage')();
2684 * const bucket = storage.bucket('albums');
2685 *
2686 * const DURATION_SECONDS = 15780000; // 6 months.
2687 *
2688 * //-
2689 * // Lock the objects in this bucket for 6 months.
2690 * //-
2691 * bucket.setRetentionPeriod(DURATION_SECONDS, function(err, apiResponse) {});
2692 *
2693 * //-
2694 * // If the callback is omitted, we'll return a Promise.
2695 * //-
2696 * bucket.setRetentionPeriod(DURATION_SECONDS).then(function(data) {
2697 * const apiResponse = data[0];
2698 * });
2699 * ```
2700 */
2701 setRetentionPeriod(duration, callback) {
2702 this.disableAutoRetryConditionallyIdempotent_(this.methods.setMetadata, AvailableServiceObjectMethods.setMetadata);
2703 this.setMetadata({
2704 retentionPolicy: {
2705 retentionPeriod: duration,
2706 },
2707 }, callback);
2708 this.storage.retryOptions.autoRetry = this.instanceRetryValue;
2709 }
2710 /**
2711 *
2712 * @typedef {object} Cors
2713 * @property {number} [maxAgeSeconds] The number of seconds the browser is
2714 * allowed to make requests before it must repeat the preflight request.
2715 * @property {string[]} [method] HTTP method allowed for cross origin resource
2716 * sharing with this bucket.
2717 * @property {string[]} [origin] an origin allowed for cross origin resource
2718 * sharing with this bucket.
2719 * @property {string[]} [responseHeader] A header allowed for cross origin
2720 * resource sharing with this bucket.
2721 */
2722 /**
2723 * This can be used to set the CORS configuration on the bucket.
2724 *
2725 * The configuration will be overwritten with the value passed into this.
2726 *
2727 * @param {Cors[]} corsConfiguration The new CORS configuration to set
2728 * @param {number} [corsConfiguration.maxAgeSeconds] The number of seconds the browser is
2729 * allowed to make requests before it must repeat the preflight request.
2730 * @param {string[]} [corsConfiguration.method] HTTP method allowed for cross origin resource
2731 * sharing with this bucket.
2732 * @param {string[]} [corsConfiguration.origin] an origin allowed for cross origin resource
2733 * sharing with this bucket.
2734 * @param {string[]} [corsConfiguration.responseHeader] A header allowed for cross origin
2735 * resource sharing with this bucket.
2736 * @param {SetBucketMetadataCallback} [callback] Callback function.
2737 * @returns {Promise<SetBucketMetadataResponse>}
2738 *
2739 * @example
2740 * ```
2741 * const storage = require('@google-cloud/storage')();
2742 * const bucket = storage.bucket('albums');
2743 *
2744 * const corsConfiguration = [{maxAgeSeconds: 3600}]; // 1 hour
2745 * bucket.setCorsConfiguration(corsConfiguration);
2746 *
2747 * //-
2748 * // If the callback is omitted, we'll return a Promise.
2749 * //-
2750 * bucket.setCorsConfiguration(corsConfiguration).then(function(data) {
2751 * const apiResponse = data[0];
2752 * });
2753 * ```
2754 */
2755 setCorsConfiguration(corsConfiguration, callback) {
2756 this.disableAutoRetryConditionallyIdempotent_(this.methods.setMetadata, AvailableServiceObjectMethods.setMetadata);
2757 this.setMetadata({
2758 cors: corsConfiguration,
2759 }, callback);
2760 this.storage.retryOptions.autoRetry = this.instanceRetryValue;
2761 }
2762 /**
2763 * @typedef {object} SetBucketStorageClassOptions
2764 * @property {string} [userProject] - The ID of the project which will be
2765 * billed for the request.
2766 */
2767 /**
2768 * @callback SetBucketStorageClassCallback
2769 * @param {?Error} err Request error, if any.
2770 */
2771 /**
2772 * Set the default storage class for new files in this bucket.
2773 *
2774 * See {@link https://cloud.google.com/storage/docs/storage-classes| Storage Classes}
2775 *
2776 * @param {string} storageClass The new storage class. (`standard`,
2777 * `nearline`, `coldline`, or `archive`).
2778 * **Note:** The storage classes `multi_regional`, `regional`, and
2779 * `durable_reduced_availability` are now legacy and will be deprecated in
2780 * the future.
2781 * @param {object} [options] Configuration options.
2782 * @param {string} [options.userProject] - The ID of the project which will be
2783 * billed for the request.
2784 * @param {SetStorageClassCallback} [callback] Callback function.
2785 * @returns {Promise}
2786 *
2787 * @example
2788 * ```
2789 * const {Storage} = require('@google-cloud/storage');
2790 * const storage = new Storage();
2791 * const bucket = storage.bucket('albums');
2792 *
2793 * bucket.setStorageClass('nearline', function(err, apiResponse) {
2794 * if (err) {
2795 * // Error handling omitted.
2796 * }
2797 *
2798 * // The storage class was updated successfully.
2799 * });
2800 *
2801 * //-
2802 * // If the callback is omitted, we'll return a Promise.
2803 * //-
2804 * bucket.setStorageClass('nearline').then(function() {});
2805 * ```
2806 */
2807 setStorageClass(storageClass, optionsOrCallback, callback) {
2808 const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
2809 callback =
2810 typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
2811 this.disableAutoRetryConditionallyIdempotent_(this.methods.setMetadata, AvailableServiceObjectMethods.setMetadata);
2812 // In case we get input like `storageClass`, convert to `storage_class`.
2813 storageClass = storageClass
2814 .replace(/-/g, '_')
2815 .replace(/([a-z])([A-Z])/g, (_, low, up) => {
2816 return low + '_' + up;
2817 })
2818 .toUpperCase();
2819 this.setMetadata({ storageClass }, options, callback);
2820 this.storage.retryOptions.autoRetry = this.instanceRetryValue;
2821 }
2822 /**
2823 * Set a user project to be billed for all requests made from this Bucket
2824 * object and any files referenced from this Bucket object.
2825 *
2826 * @param {string} userProject The user project.
2827 *
2828 * @example
2829 * ```
2830 * const {Storage} = require('@google-cloud/storage');
2831 * const storage = new Storage();
2832 * const bucket = storage.bucket('albums');
2833 *
2834 * bucket.setUserProject('grape-spaceship-123');
2835 * ```
2836 */
2837 setUserProject(userProject) {
2838 this.userProject = userProject;
2839 const methods = [
2840 'create',
2841 'delete',
2842 'exists',
2843 'get',
2844 'getMetadata',
2845 'setMetadata',
2846 ];
2847 methods.forEach(method => {
2848 const methodConfig = this.methods[method];
2849 if (typeof methodConfig === 'object') {
2850 if (typeof methodConfig.reqOpts === 'object') {
2851 extend(methodConfig.reqOpts.qs, { userProject });
2852 }
2853 else {
2854 methodConfig.reqOpts = {
2855 qs: { userProject },
2856 };
2857 }
2858 }
2859 });
2860 }
2861 /**
2862 * @typedef {object} UploadOptions Configuration options for Bucket#upload().
2863 * @property {string|File} [destination] The place to save
2864 * your file. If given a string, the file will be uploaded to the bucket
2865 * using the string as a filename. When given a File object, your local
2866 * file will be uploaded to the File object's bucket and under the File
2867 * object's name. Lastly, when this argument is omitted, the file is uploaded
2868 * to your bucket using the name of the local file.
2869 * @property {string} [encryptionKey] A custom encryption key. See
2870 * {@link https://cloud.google.com/storage/docs/encryption#customer-supplied| Customer-supplied Encryption Keys}.
2871 * @property {boolean} [gzip] Automatically gzip the file. This will set
2872 * `options.metadata.contentEncoding` to `gzip`.
2873 * @property {string} [kmsKeyName] The name of the Cloud KMS key that will
2874 * be used to encrypt the object. Must be in the format:
2875 * `projects/my-project/locations/location/keyRings/my-kr/cryptoKeys/my-key`.
2876 * @property {object} [metadata] See an
2877 * {@link https://cloud.google.com/storage/docs/json_api/v1/objects/insert#request_properties_JSON| Objects: insert request body}.
2878 * @property {string} [offset] The starting byte of the upload stream, for
2879 * resuming an interrupted upload. Defaults to 0.
2880 * @property {string} [predefinedAcl] Apply a predefined set of access
2881 * controls to this object.
2882 *
2883 * Acceptable values are:
2884 * - **`authenticatedRead`** - Object owner gets `OWNER` access, and
2885 * `allAuthenticatedUsers` get `READER` access.
2886 *
2887 * - **`bucketOwnerFullControl`** - Object owner gets `OWNER` access, and
2888 * project team owners get `OWNER` access.
2889 *
2890 * - **`bucketOwnerRead`** - Object owner gets `OWNER` access, and project
2891 * team owners get `READER` access.
2892 *
2893 * - **`private`** - Object owner gets `OWNER` access.
2894 *
2895 * - **`projectPrivate`** - Object owner gets `OWNER` access, and project
2896 * team members get access according to their roles.
2897 *
2898 * - **`publicRead`** - Object owner gets `OWNER` access, and `allUsers`
2899 * get `READER` access.
2900 * @property {boolean} [private] Make the uploaded file private. (Alias for
2901 * `options.predefinedAcl = 'private'`)
2902 * @property {boolean} [public] Make the uploaded file public. (Alias for
2903 * `options.predefinedAcl = 'publicRead'`)
2904 * @property {boolean} [resumable] Force a resumable upload. (default:
2905 * true for files larger than 5 MB).
2906 * @property {number} [timeout=60000] Set the HTTP request timeout in
2907 * milliseconds. This option is not available for resumable uploads.
2908 * Default: `60000`
2909 * @property {string} [uri] The URI for an already-created resumable
2910 * upload. See {@link File#createResumableUpload}.
2911 * @property {string} [userProject] The ID of the project which will be
2912 * billed for the request.
2913 * @property {string|boolean} [validation] Possible values: `"md5"`,
2914 * `"crc32c"`, or `false`. By default, data integrity is validated with an
2915 * MD5 checksum for maximum reliability. CRC32c will provide better
2916 * performance with less reliability. You may also choose to skip
2917 * validation completely, however this is **not recommended**.
2918 */
2919 /**
2920 * @typedef {array} UploadResponse
2921 * @property {object} 0 The uploaded {@link File}.
2922 * @property {object} 1 The full API response.
2923 */
2924 /**
2925 * @callback UploadCallback
2926 * @param {?Error} err Request error, if any.
2927 * @param {object} file The uploaded {@link File}.
2928 * @param {object} apiResponse The full API response.
2929 */
2930 /**
2931 * Upload a file to the bucket. This is a convenience method that wraps
2932 * {@link File#createWriteStream}.
2933 *
2934 * You can specify whether or not an upload is resumable by setting
2935 * `options.resumable`. *Resumable uploads are enabled by default if your
2936 * input file is larger than 5 MB.*
2937 *
2938 * For faster crc32c computation, you must manually install
2939 * {@link https://www.npmjs.com/package/fast-crc32c| `fast-crc32c`}:
2940 *
2941 * $ npm install --save fast-crc32c
2942 *
2943 * See {@link https://cloud.google.com/storage/docs/json_api/v1/how-tos/upload#uploads| Upload Options (Simple or Resumable)}
2944 * See {@link https://cloud.google.com/storage/docs/json_api/v1/objects/insert| Objects: insert API Documentation}
2945 *
2946 * @param {string} pathString The fully qualified path to the file you
2947 * wish to upload to your bucket.
2948 * @param {UploadOptions} [options] Configuration options.
2949 * @param {string|File} [options.destination] The place to save
2950 * your file. If given a string, the file will be uploaded to the bucket
2951 * using the string as a filename. When given a File object, your local
2952 * file will be uploaded to the File object's bucket and under the File
2953 * object's name. Lastly, when this argument is omitted, the file is uploaded
2954 * to your bucket using the name of the local file.
2955 * @param {string} [options.encryptionKey] A custom encryption key. See
2956 * {@link https://cloud.google.com/storage/docs/encryption#customer-supplied| Customer-supplied Encryption Keys}.
2957 * @param {boolean} [options.gzip] Automatically gzip the file. This will set
2958 * `options.metadata.contentEncoding` to `gzip`.
2959 * @param {string} [options.kmsKeyName] The name of the Cloud KMS key that will
2960 * be used to encrypt the object. Must be in the format:
2961 * `projects/my-project/locations/location/keyRings/my-kr/cryptoKeys/my-key`.
2962 * @param {object} [options.metadata] See an
2963 * {@link https://cloud.google.com/storage/docs/json_api/v1/objects/insert#request_properties_JSON| Objects: insert request body}.
2964 * @param {string} [options.offset] The starting byte of the upload stream, for
2965 * resuming an interrupted upload. Defaults to 0.
2966 * @param {string} [options.predefinedAcl] Apply a predefined set of access
2967 * controls to this object.
2968 * Acceptable values are:
2969 * - **`authenticatedRead`** - Object owner gets `OWNER` access, and
2970 * `allAuthenticatedUsers` get `READER` access.
2971 *
2972 * - **`bucketOwnerFullControl`** - Object owner gets `OWNER` access, and
2973 * project team owners get `OWNER` access.
2974 *
2975 * - **`bucketOwnerRead`** - Object owner gets `OWNER` access, and project
2976 * team owners get `READER` access.
2977 *
2978 * - **`private`** - Object owner gets `OWNER` access.
2979 *
2980 * - **`projectPrivate`** - Object owner gets `OWNER` access, and project
2981 * team members get access according to their roles.
2982 *
2983 * - **`publicRead`** - Object owner gets `OWNER` access, and `allUsers`
2984 * get `READER` access.
2985 * @param {boolean} [options.private] Make the uploaded file private. (Alias for
2986 * `options.predefinedAcl = 'private'`)
2987 * @param {boolean} [options.public] Make the uploaded file public. (Alias for
2988 * `options.predefinedAcl = 'publicRead'`)
2989 * @param {boolean} [options.resumable] Force a resumable upload. (default:
2990 * true for files larger than 5 MB).
2991 * @param {number} [options.timeout=60000] Set the HTTP request timeout in
2992 * milliseconds. This option is not available for resumable uploads.
2993 * Default: `60000`
2994 * @param {string} [options.uri] The URI for an already-created resumable
2995 * upload. See {@link File#createResumableUpload}.
2996 * @param {string} [options.userProject] The ID of the project which will be
2997 * billed for the request.
2998 * @param {string|boolean} [options.validation] Possible values: `"md5"`,
2999 * `"crc32c"`, or `false`. By default, data integrity is validated with an
3000 * MD5 checksum for maximum reliability. CRC32c will provide better
3001 * performance with less reliability. You may also choose to skip
3002 * validation completely, however this is **not recommended**.
3003 * @param {UploadCallback} [callback] Callback function.
3004 * @returns {Promise<UploadResponse>}
3005 *
3006 * @example
3007 * ```
3008 * const {Storage} = require('@google-cloud/storage');
3009 * const storage = new Storage();
3010 * const bucket = storage.bucket('albums');
3011 *
3012 * //-
3013 * // Upload a file from a local path.
3014 * //-
3015 * bucket.upload('/local/path/image.png', function(err, file, apiResponse) {
3016 * // Your bucket now contains:
3017 * // - "image.png" (with the contents of `/local/path/image.png')
3018 *
3019 * // `file` is an instance of a File object that refers to your new file.
3020 * });
3021 *
3022 *
3023 * //-
3024 * // It's not always that easy. You will likely want to specify the filename
3025 * // used when your new file lands in your bucket.
3026 * //
3027 * // You may also want to set metadata or customize other options.
3028 * //-
3029 * const options = {
3030 * destination: 'new-image.png',
3031 * resumable: true,
3032 * validation: 'crc32c',
3033 * metadata: {
3034 * metadata: {
3035 * event: 'Fall trip to the zoo'
3036 * }
3037 * }
3038 * };
3039 *
3040 * bucket.upload('local-image.png', options, function(err, file) {
3041 * // Your bucket now contains:
3042 * // - "new-image.png" (with the contents of `local-image.png')
3043 *
3044 * // `file` is an instance of a File object that refers to your new file.
3045 * });
3046 *
3047 * //-
3048 * // You can also have a file gzip'd on the fly.
3049 * //-
3050 * bucket.upload('index.html', { gzip: true }, function(err, file) {
3051 * // Your bucket now contains:
3052 * // - "index.html" (automatically compressed with gzip)
3053 *
3054 * // Downloading the file with `file.download` will automatically decode
3055 * the
3056 * // file.
3057 * });
3058 *
3059 * //-
3060 * // You may also re-use a File object, {File}, that references
3061 * // the file you wish to create or overwrite.
3062 * //-
3063 * const options = {
3064 * destination: bucket.file('existing-file.png'),
3065 * resumable: false
3066 * };
3067 *
3068 * bucket.upload('local-img.png', options, function(err, newFile) {
3069 * // Your bucket now contains:
3070 * // - "existing-file.png" (with the contents of `local-img.png')
3071 *
3072 * // Note:
3073 * // The `newFile` parameter is equal to `file`.
3074 * });
3075 *
3076 * //-
3077 * // To use
3078 * // <a
3079 * href="https://cloud.google.com/storage/docs/encryption#customer-supplied">
3080 * // Customer-supplied Encryption Keys</a>, provide the `encryptionKey`
3081 * option.
3082 * //-
3083 * const crypto = require('crypto');
3084 * const encryptionKey = crypto.randomBytes(32);
3085 *
3086 * bucket.upload('img.png', {
3087 * encryptionKey: encryptionKey
3088 * }, function(err, newFile) {
3089 * // `img.png` was uploaded with your custom encryption key.
3090 *
3091 * // `newFile` is already configured to use the encryption key when making
3092 * // operations on the remote object.
3093 *
3094 * // However, to use your encryption key later, you must create a `File`
3095 * // instance with the `key` supplied:
3096 * const file = bucket.file('img.png', {
3097 * encryptionKey: encryptionKey
3098 * });
3099 *
3100 * // Or with `file#setEncryptionKey`:
3101 * const file = bucket.file('img.png');
3102 * file.setEncryptionKey(encryptionKey);
3103 * });
3104 *
3105 * //-
3106 * // If the callback is omitted, we'll return a Promise.
3107 * //-
3108 * bucket.upload('local-image.png').then(function(data) {
3109 * const file = data[0];
3110 * });
3111 *
3112 * To upload a file from a URL, use {@link File#createWriteStream}.
3113 *
3114 * ```
3115 * @example <caption>include:samples/files.js</caption>
3116 * region_tag:storage_upload_file
3117 * Another example:
3118 *
3119 * @example <caption>include:samples/encryption.js</caption>
3120 * region_tag:storage_upload_encrypted_file
3121 * Example of uploading an encrypted file:
3122 */
3123 upload(pathString, optionsOrCallback, callback) {
3124 var _a, _b;
3125 const upload = (numberOfRetries) => {
3126 const returnValue = retry(async (bail) => {
3127 await new Promise((resolve, reject) => {
3128 var _a, _b;
3129 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)) {
3130 newFile.storage.retryOptions.autoRetry = false;
3131 }
3132 const writable = newFile.createWriteStream(options);
3133 if (options.onUploadProgress) {
3134 writable.on('progress', options.onUploadProgress);
3135 }
3136 fs.createReadStream(pathString)
3137 .pipe(writable)
3138 .on('error', err => {
3139 if (this.storage.retryOptions.autoRetry &&
3140 this.storage.retryOptions.retryableErrorFn(err)) {
3141 return reject(err);
3142 }
3143 else {
3144 return bail(err);
3145 }
3146 })
3147 .on('finish', () => {
3148 return resolve();
3149 });
3150 });
3151 }, {
3152 retries: numberOfRetries,
3153 factor: this.storage.retryOptions.retryDelayMultiplier,
3154 maxTimeout: this.storage.retryOptions.maxRetryDelay * 1000,
3155 maxRetryTime: this.storage.retryOptions.totalTimeout * 1000,
3156 });
3157 if (!callback) {
3158 return returnValue;
3159 }
3160 else {
3161 return returnValue
3162 .then(() => {
3163 if (callback) {
3164 return callback(null, newFile, newFile.metadata);
3165 }
3166 })
3167 .catch(callback);
3168 }
3169 };
3170 // eslint-disable-next-line @typescript-eslint/no-explicit-any
3171 if (global['GCLOUD_SANDBOX_ENV']) {
3172 return;
3173 }
3174 let options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
3175 callback =
3176 typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
3177 options = Object.assign({
3178 metadata: {},
3179 }, options);
3180 // Do not retry if precondition option ifGenerationMatch is not set
3181 // because this is a file operation
3182 let maxRetries = this.storage.retryOptions.maxRetries;
3183 if ((((_a = options === null || options === void 0 ? void 0 : options.preconditionOpts) === null || _a === void 0 ? void 0 : _a.ifGenerationMatch) === undefined &&
3184 ((_b = this.instancePreconditionOpts) === null || _b === void 0 ? void 0 : _b.ifGenerationMatch) === undefined &&
3185 this.storage.retryOptions.idempotencyStrategy ===
3186 storage_1.IdempotencyStrategy.RetryConditional) ||
3187 this.storage.retryOptions.idempotencyStrategy ===
3188 storage_1.IdempotencyStrategy.RetryNever) {
3189 maxRetries = 0;
3190 }
3191 let newFile;
3192 if (options.destination instanceof file_1.File) {
3193 newFile = options.destination;
3194 }
3195 else if (options.destination !== null &&
3196 typeof options.destination === 'string') {
3197 // Use the string as the name of the file.
3198 newFile = this.file(options.destination, {
3199 encryptionKey: options.encryptionKey,
3200 kmsKeyName: options.kmsKeyName,
3201 preconditionOpts: this.instancePreconditionOpts,
3202 });
3203 }
3204 else {
3205 // Resort to using the name of the incoming file.
3206 const destination = path.basename(pathString);
3207 newFile = this.file(destination, {
3208 encryptionKey: options.encryptionKey,
3209 kmsKeyName: options.kmsKeyName,
3210 preconditionOpts: this.instancePreconditionOpts,
3211 });
3212 }
3213 if (options.resumable !== null && typeof options.resumable === 'boolean') {
3214 upload(maxRetries);
3215 }
3216 else {
3217 // Determine if the upload should be resumable if it's over the threshold.
3218 fs.stat(pathString, (err, fd) => {
3219 if (err) {
3220 callback(err);
3221 return;
3222 }
3223 if (fd.size <= RESUMABLE_THRESHOLD) {
3224 // Only disable resumable uploads so createWriteStream still attempts them and falls back to simple upload.
3225 options.resumable = false;
3226 }
3227 upload(maxRetries);
3228 });
3229 }
3230 }
3231 /**
3232 * @private
3233 *
3234 * @typedef {object} MakeAllFilesPublicPrivateOptions
3235 * @property {boolean} [force] Suppress errors until all files have been
3236 * processed.
3237 * @property {boolean} [private] Make files private.
3238 * @property {boolean} [public] Make files public.
3239 * @property {string} [userProject] The ID of the project which will be
3240 * billed for the request.
3241 */
3242 /**
3243 * @private
3244 *
3245 * @callback SetBucketMetadataCallback
3246 * @param {?Error} err Request error, if any.
3247 * @param {File[]} files Files that were updated.
3248 */
3249 /**
3250 * @typedef {array} MakeAllFilesPublicPrivateResponse
3251 * @property {File[]} 0 List of files affected.
3252 */
3253 /**
3254 * Iterate over all of a bucket's files, calling `file.makePublic()` (public)
3255 * or `file.makePrivate()` (private) on each.
3256 *
3257 * Operations are performed in parallel, up to 10 at once. The first error
3258 * breaks the loop, and will execute the provided callback with it. Specify
3259 * `{ force: true }` to suppress the errors.
3260 *
3261 * @private
3262 *
3263 * @param {MakeAllFilesPublicPrivateOptions} [options] Configuration options.
3264 * @param {boolean} [options.force] Suppress errors until all files have been
3265 * processed.
3266 * @param {boolean} [options.private] Make files private.
3267 * @param {boolean} [options.public] Make files public.
3268 * @param {string} [options.userProject] The ID of the project which will be
3269 * billed for the request.
3270
3271 * @param {MakeAllFilesPublicPrivateCallback} callback Callback function.
3272 *
3273 * @return {Promise<MakeAllFilesPublicPrivateResponse>}
3274 */
3275 makeAllFilesPublicPrivate_(optionsOrCallback, callback) {
3276 const MAX_PARALLEL_LIMIT = 10;
3277 const errors = [];
3278 const updatedFiles = [];
3279 const options = typeof optionsOrCallback === 'object' ? optionsOrCallback : {};
3280 callback =
3281 typeof optionsOrCallback === 'function' ? optionsOrCallback : callback;
3282 const processFile = async (file) => {
3283 try {
3284 await (options.public ? file.makePublic() : file.makePrivate(options));
3285 updatedFiles.push(file);
3286 }
3287 catch (e) {
3288 if (!options.force) {
3289 throw e;
3290 }
3291 errors.push(e);
3292 }
3293 };
3294 this.getFiles(options)
3295 .then(([files]) => {
3296 const limit = pLimit(MAX_PARALLEL_LIMIT);
3297 const promises = files.map(file => {
3298 return limit(() => processFile(file));
3299 });
3300 return Promise.all(promises);
3301 })
3302 .then(() => callback(errors.length > 0 ? errors : null, updatedFiles), err => callback(err, updatedFiles));
3303 }
3304 getId() {
3305 return this.id;
3306 }
3307 disableAutoRetryConditionallyIdempotent_(
3308 // eslint-disable-next-line @typescript-eslint/no-explicit-any
3309 coreOpts, methodType) {
3310 var _a, _b;
3311 if (typeof coreOpts === 'object' &&
3312 ((_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 &&
3313 (methodType === AvailableServiceObjectMethods.setMetadata ||
3314 methodType === AvailableServiceObjectMethods.delete) &&
3315 this.storage.retryOptions.idempotencyStrategy ===
3316 storage_1.IdempotencyStrategy.RetryConditional) {
3317 this.storage.retryOptions.autoRetry = false;
3318 }
3319 else if (this.storage.retryOptions.idempotencyStrategy ===
3320 storage_1.IdempotencyStrategy.RetryNever) {
3321 this.storage.retryOptions.autoRetry = false;
3322 }
3323 }
3324}
3325exports.Bucket = Bucket;
3326/*! Developer Documentation
3327 *
3328 * These methods can be auto-paginated.
3329 */
3330paginator_1.paginator.extend(Bucket, 'getFiles');
3331/*! Developer Documentation
3332 *
3333 * All async methods (except for streams) will return a Promise in the event
3334 * that a callback is omitted.
3335 */
3336promisify_1.promisifyAll(Bucket, {
3337 exclude: ['request', 'file', 'notification'],
3338});
3339//# sourceMappingURL=bucket.js.map
\No newline at end of file