UNPKG

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