UNPKG

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