UNPKG

45.7 kBJavaScriptView Raw
1// Copyright 2019 Google LLC
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14import { Service } from './nodejs-common/index.js';
15import { paginator } from '@google-cloud/paginator';
16import { promisifyAll } from '@google-cloud/promisify';
17import { Readable } from 'stream';
18import { Bucket } from './bucket.js';
19import { Channel } from './channel.js';
20import { File } from './file.js';
21import { normalize } from './util.js';
22// eslint-disable-next-line @typescript-eslint/ban-ts-comment
23// @ts-ignore
24import { getPackageJSON } from './package-json-helper.cjs';
25import { HmacKey } from './hmacKey.js';
26import { CRC32C_DEFAULT_VALIDATOR_GENERATOR, } from './crc32c.js';
27import { DEFAULT_UNIVERSE } from 'google-auth-library';
28export var IdempotencyStrategy;
29(function (IdempotencyStrategy) {
30 IdempotencyStrategy[IdempotencyStrategy["RetryAlways"] = 0] = "RetryAlways";
31 IdempotencyStrategy[IdempotencyStrategy["RetryConditional"] = 1] = "RetryConditional";
32 IdempotencyStrategy[IdempotencyStrategy["RetryNever"] = 2] = "RetryNever";
33})(IdempotencyStrategy || (IdempotencyStrategy = {}));
34export var ExceptionMessages;
35(function (ExceptionMessages) {
36 ExceptionMessages["EXPIRATION_DATE_INVALID"] = "The expiration date provided was invalid.";
37 ExceptionMessages["EXPIRATION_DATE_PAST"] = "An expiration date cannot be in the past.";
38})(ExceptionMessages || (ExceptionMessages = {}));
39export var StorageExceptionMessages;
40(function (StorageExceptionMessages) {
41 StorageExceptionMessages["BUCKET_NAME_REQUIRED"] = "A bucket name is needed to use Cloud Storage.";
42 StorageExceptionMessages["BUCKET_NAME_REQUIRED_CREATE"] = "A name is required to create a bucket.";
43 StorageExceptionMessages["HMAC_SERVICE_ACCOUNT"] = "The first argument must be a service account email to create an HMAC key.";
44 StorageExceptionMessages["HMAC_ACCESS_ID"] = "An access ID is needed to create an HmacKey object.";
45})(StorageExceptionMessages || (StorageExceptionMessages = {}));
46export const PROTOCOL_REGEX = /^(\w*):\/\//;
47/**
48 * Default behavior: Automatically retry retriable server errors.
49 *
50 * @const {boolean}
51 */
52export const AUTO_RETRY_DEFAULT = true;
53/**
54 * Default behavior: Only attempt to retry retriable errors 3 times.
55 *
56 * @const {number}
57 */
58export const MAX_RETRY_DEFAULT = 3;
59/**
60 * Default behavior: Wait twice as long as previous retry before retrying.
61 *
62 * @const {number}
63 */
64export const RETRY_DELAY_MULTIPLIER_DEFAULT = 2;
65/**
66 * Default behavior: If the operation doesn't succeed after 600 seconds,
67 * stop retrying.
68 *
69 * @const {number}
70 */
71export const TOTAL_TIMEOUT_DEFAULT = 600;
72/**
73 * Default behavior: Wait no more than 64 seconds between retries.
74 *
75 * @const {number}
76 */
77export const MAX_RETRY_DELAY_DEFAULT = 64;
78/**
79 * Default behavior: Retry conditionally idempotent operations if correct preconditions are set.
80 *
81 * @const {enum}
82 * @private
83 */
84const IDEMPOTENCY_STRATEGY_DEFAULT = IdempotencyStrategy.RetryConditional;
85/**
86 * Returns true if the API request should be retried, given the error that was
87 * given the first time the request was attempted.
88 * @const
89 * @param {error} err - The API error to check if it is appropriate to retry.
90 * @return {boolean} True if the API request should be retried, false otherwise.
91 */
92export const RETRYABLE_ERR_FN_DEFAULT = function (err) {
93 var _a;
94 const isConnectionProblem = (reason) => {
95 return (reason.includes('eai_again') || // DNS lookup error
96 reason === 'econnreset' ||
97 reason === 'unexpected connection closure' ||
98 reason === 'epipe' ||
99 reason === 'socket connection timeout');
100 };
101 if (err) {
102 if ([408, 429, 500, 502, 503, 504].indexOf(err.code) !== -1) {
103 return true;
104 }
105 if (typeof err.code === 'string') {
106 if (['408', '429', '500', '502', '503', '504'].indexOf(err.code) !== -1) {
107 return true;
108 }
109 const reason = err.code.toLowerCase();
110 if (isConnectionProblem(reason)) {
111 return true;
112 }
113 }
114 if (err.errors) {
115 for (const e of err.errors) {
116 const reason = (_a = e === null || e === void 0 ? void 0 : e.reason) === null || _a === void 0 ? void 0 : _a.toString().toLowerCase();
117 if (reason && isConnectionProblem(reason)) {
118 return true;
119 }
120 }
121 }
122 }
123 return false;
124};
125/*! Developer Documentation
126 *
127 * Invoke this method to create a new Storage object bound with pre-determined
128 * configuration options. For each object that can be created (e.g., a bucket),
129 * there is an equivalent static and instance method. While they are classes,
130 * they can be instantiated without use of the `new` keyword.
131 */
132/**
133 * Cloud Storage uses access control lists (ACLs) to manage object and
134 * bucket access. ACLs are the mechanism you use to share objects with other
135 * users and allow other users to access your buckets and objects.
136 *
137 * This object provides constants to refer to the three permission levels that
138 * can be granted to an entity:
139 *
140 * - `gcs.acl.OWNER_ROLE` - ("OWNER")
141 * - `gcs.acl.READER_ROLE` - ("READER")
142 * - `gcs.acl.WRITER_ROLE` - ("WRITER")
143 *
144 * See {@link https://cloud.google.com/storage/docs/access-control/lists| About Access Control Lists}
145 *
146 * @name Storage#acl
147 * @type {object}
148 * @property {string} OWNER_ROLE
149 * @property {string} READER_ROLE
150 * @property {string} WRITER_ROLE
151 *
152 * @example
153 * ```
154 * const {Storage} = require('@google-cloud/storage');
155 * const storage = new Storage();
156 * const albums = storage.bucket('albums');
157 *
158 * //-
159 * // Make all of the files currently in a bucket publicly readable.
160 * //-
161 * const options = {
162 * entity: 'allUsers',
163 * role: storage.acl.READER_ROLE
164 * };
165 *
166 * albums.acl.add(options, function(err, aclObject) {});
167 *
168 * //-
169 * // Make any new objects added to a bucket publicly readable.
170 * //-
171 * albums.acl.default.add(options, function(err, aclObject) {});
172 *
173 * //-
174 * // Grant a user ownership permissions to a bucket.
175 * //-
176 * albums.acl.add({
177 * entity: 'user-useremail@example.com',
178 * role: storage.acl.OWNER_ROLE
179 * }, function(err, aclObject) {});
180 *
181 * //-
182 * // If the callback is omitted, we'll return a Promise.
183 * //-
184 * albums.acl.add(options).then(function(data) {
185 * const aclObject = data[0];
186 * const apiResponse = data[1];
187 * });
188 * ```
189 */
190/**
191 * Get {@link Bucket} objects for all of the buckets in your project as
192 * a readable object stream.
193 *
194 * @method Storage#getBucketsStream
195 * @param {GetBucketsRequest} [query] Query object for listing buckets.
196 * @returns {ReadableStream} A readable stream that emits {@link Bucket}
197 * instances.
198 *
199 * @example
200 * ```
201 * storage.getBucketsStream()
202 * .on('error', console.error)
203 * .on('data', function(bucket) {
204 * // bucket is a Bucket object.
205 * })
206 * .on('end', function() {
207 * // All buckets retrieved.
208 * });
209 *
210 * //-
211 * // If you anticipate many results, you can end a stream early to prevent
212 * // unnecessary processing and API requests.
213 * //-
214 * storage.getBucketsStream()
215 * .on('data', function(bucket) {
216 * this.end();
217 * });
218 * ```
219 */
220/**
221 * Get {@link HmacKey} objects for all of the HMAC keys in the project in a
222 * readable object stream.
223 *
224 * @method Storage#getHmacKeysStream
225 * @param {GetHmacKeysOptions} [options] Configuration options.
226 * @returns {ReadableStream} A readable stream that emits {@link HmacKey}
227 * instances.
228 *
229 * @example
230 * ```
231 * storage.getHmacKeysStream()
232 * .on('error', console.error)
233 * .on('data', function(hmacKey) {
234 * // hmacKey is an HmacKey object.
235 * })
236 * .on('end', function() {
237 * // All HmacKey retrieved.
238 * });
239 *
240 * //-
241 * // If you anticipate many results, you can end a stream early to prevent
242 * // unnecessary processing and API requests.
243 * //-
244 * storage.getHmacKeysStream()
245 * .on('data', function(bucket) {
246 * this.end();
247 * });
248 * ```
249 */
250/**
251 * <h4>ACLs</h4>
252 * Cloud Storage uses access control lists (ACLs) to manage object and
253 * bucket access. ACLs are the mechanism you use to share files with other users
254 * and allow other users to access your buckets and files.
255 *
256 * To learn more about ACLs, read this overview on
257 * {@link https://cloud.google.com/storage/docs/access-control| Access Control}.
258 *
259 * See {@link https://cloud.google.com/storage/docs/overview| Cloud Storage overview}
260 * See {@link https://cloud.google.com/storage/docs/access-control| Access Control}
261 *
262 * @class
263 */
264export class Storage extends Service {
265 getBucketsStream() {
266 // placeholder body, overwritten in constructor
267 return new Readable();
268 }
269 getHmacKeysStream() {
270 // placeholder body, overwritten in constructor
271 return new Readable();
272 }
273 /**
274 * @callback Crc32cGeneratorToStringCallback
275 * A method returning the CRC32C as a base64-encoded string.
276 *
277 * @returns {string}
278 *
279 * @example
280 * Hashing the string 'data' should return 'rth90Q=='
281 *
282 * ```js
283 * const buffer = Buffer.from('data');
284 * crc32c.update(buffer);
285 * crc32c.toString(); // 'rth90Q=='
286 * ```
287 **/
288 /**
289 * @callback Crc32cGeneratorValidateCallback
290 * A method validating a base64-encoded CRC32C string.
291 *
292 * @param {string} [value] base64-encoded CRC32C string to validate
293 * @returns {boolean}
294 *
295 * @example
296 * Should return `true` if the value matches, `false` otherwise
297 *
298 * ```js
299 * const buffer = Buffer.from('data');
300 * crc32c.update(buffer);
301 * crc32c.validate('DkjKuA=='); // false
302 * crc32c.validate('rth90Q=='); // true
303 * ```
304 **/
305 /**
306 * @callback Crc32cGeneratorUpdateCallback
307 * A method for passing `Buffer`s for CRC32C generation.
308 *
309 * @param {Buffer} [data] data to update CRC32C value with
310 * @returns {undefined}
311 *
312 * @example
313 * Hashing buffers from 'some ' and 'text\n'
314 *
315 * ```js
316 * const buffer1 = Buffer.from('some ');
317 * crc32c.update(buffer1);
318 *
319 * const buffer2 = Buffer.from('text\n');
320 * crc32c.update(buffer2);
321 *
322 * crc32c.toString(); // 'DkjKuA=='
323 * ```
324 **/
325 /**
326 * @typedef {object} CRC32CValidator
327 * @property {Crc32cGeneratorToStringCallback}
328 * @property {Crc32cGeneratorValidateCallback}
329 * @property {Crc32cGeneratorUpdateCallback}
330 */
331 /**
332 * @callback Crc32cGeneratorCallback
333 * @returns {CRC32CValidator}
334 */
335 /**
336 * @typedef {object} StorageOptions
337 * @property {string} [projectId] The project ID from the Google Developer's
338 * Console, e.g. 'grape-spaceship-123'. We will also check the environment
339 * variable `GCLOUD_PROJECT` for your project ID. If your app is running
340 * in an environment which supports {@link
341 * https://cloud.google.com/docs/authentication/production#providing_credentials_to_your_application
342 * Application Default Credentials}, your project ID will be detected
343 * automatically.
344 * @property {string} [keyFilename] Full path to the a .json, .pem, or .p12 key
345 * downloaded from the Google Developers Console. If you provide a path to
346 * a JSON file, the `projectId` option above is not necessary. NOTE: .pem and
347 * .p12 require you to specify the `email` option as well.
348 * @property {string} [email] Account email address. Required when using a .pem
349 * or .p12 keyFilename.
350 * @property {object} [credentials] Credentials object.
351 * @property {string} [credentials.client_email]
352 * @property {string} [credentials.private_key]
353 * @property {object} [retryOptions] Options for customizing retries. Retriable server errors
354 * will be retried with exponential delay between them dictated by the formula
355 * max(maxRetryDelay, retryDelayMultiplier*retryNumber) until maxRetries or totalTimeout
356 * has been reached. Retries will only happen if autoRetry is set to true.
357 * @property {boolean} [retryOptions.autoRetry=true] Automatically retry requests if the
358 * response is related to rate limits or certain intermittent server
359 * errors. We will exponentially backoff subsequent requests by default.
360 * @property {number} [retryOptions.retryDelayMultiplier = 2] the multiplier by which to
361 * increase the delay time between the completion of failed requests, and the
362 * initiation of the subsequent retrying request.
363 * @property {number} [retryOptions.totalTimeout = 600] The total time, starting from
364 * when the initial request is sent, after which an error will
365 * be returned, regardless of the retrying attempts made meanwhile.
366 * @property {number} [retryOptions.maxRetryDelay = 64] The maximum delay time between requests.
367 * When this value is reached, ``retryDelayMultiplier`` will no longer be used to
368 * increase delay time.
369 * @property {number} [retryOptions.maxRetries=3] Maximum number of automatic retries
370 * attempted before returning the error.
371 * @property {function} [retryOptions.retryableErrorFn] Function that returns true if a given
372 * error should be retried and false otherwise.
373 * @property {enum} [retryOptions.idempotencyStrategy=IdempotencyStrategy.RetryConditional] Enumeration
374 * controls how conditionally idempotent operations are retried. Possible values are: RetryAlways -
375 * will respect other retry settings and attempt to retry conditionally idempotent operations. RetryConditional -
376 * will retry conditionally idempotent operations if the correct preconditions are set. RetryNever - never
377 * retry a conditionally idempotent operation.
378 * @property {string} [userAgent] The value to be prepended to the User-Agent
379 * header in API requests.
380 * @property {object} [authClient] `AuthClient` or `GoogleAuth` client to reuse instead of creating a new one.
381 * @property {number} [timeout] The amount of time in milliseconds to wait per http request before timing out.
382 * @property {object[]} [interceptors_] Array of custom request interceptors to be returned in the order they were assigned.
383 * @property {string} [apiEndpoint = storage.google.com] The API endpoint of the service used to make requests.
384 * @property {boolean} [useAuthWithCustomEndpoint = false] Controls whether or not to use authentication when using a custom endpoint.
385 * @property {Crc32cGeneratorCallback} [callback] A function that generates a CRC32C Validator. Defaults to {@link CRC32C}
386 */
387 /**
388 * Constructs the Storage client.
389 *
390 * @example
391 * Create a client that uses Application Default Credentials
392 * (ADC)
393 * ```
394 * const {Storage} = require('@google-cloud/storage');
395 * const storage = new Storage();
396 * ```
397 *
398 * @example
399 * Create a client with explicit credentials
400 * ```
401 * const storage = new Storage({
402 * projectId: 'your-project-id',
403 * keyFilename: '/path/to/keyfile.json'
404 * });
405 * ```
406 *
407 * @example
408 * Create a client with credentials passed
409 * by value as a JavaScript object
410 * ```
411 * const storage = new Storage({
412 * projectId: 'your-project-id',
413 * credentials: {
414 * type: 'service_account',
415 * project_id: 'xxxxxxx',
416 * private_key_id: 'xxxx',
417 * private_key:'-----BEGIN PRIVATE KEY-----xxxxxxx\n-----END PRIVATE KEY-----\n',
418 * client_email: 'xxxx',
419 * client_id: 'xxx',
420 * auth_uri: 'https://accounts.google.com/o/oauth2/auth',
421 * token_uri: 'https://oauth2.googleapis.com/token',
422 * auth_provider_x509_cert_url: 'https://www.googleapis.com/oauth2/v1/certs',
423 * client_x509_cert_url: 'xxx',
424 * }
425 * });
426 * ```
427 *
428 * @example
429 * Create a client with credentials passed
430 * by loading a JSON file directly from disk
431 * ```
432 * const storage = new Storage({
433 * projectId: 'your-project-id',
434 * credentials: require('/path/to-keyfile.json')
435 * });
436 * ```
437 *
438 * @example
439 * Create a client with an `AuthClient` (e.g. `DownscopedClient`)
440 * ```
441 * const {DownscopedClient} = require('google-auth-library');
442 * const authClient = new DownscopedClient({...});
443 *
444 * const storage = new Storage({authClient});
445 * ```
446 *
447 * Additional samples:
448 * - https://github.com/googleapis/google-auth-library-nodejs#sample-usage-1
449 * - https://github.com/googleapis/google-auth-library-nodejs/blob/main/samples/downscopedclient.js
450 *
451 * @param {StorageOptions} [options] Configuration options.
452 */
453 constructor(options = {}) {
454 var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p;
455 const universe = options.universeDomain || DEFAULT_UNIVERSE;
456 let apiEndpoint = `https://storage.${universe}`;
457 let customEndpoint = false;
458 // Note: EMULATOR_HOST is an experimental configuration variable. Use apiEndpoint instead.
459 const EMULATOR_HOST = process.env.STORAGE_EMULATOR_HOST;
460 if (typeof EMULATOR_HOST === 'string') {
461 apiEndpoint = Storage.sanitizeEndpoint(EMULATOR_HOST);
462 customEndpoint = true;
463 }
464 if (options.apiEndpoint && options.apiEndpoint !== apiEndpoint) {
465 apiEndpoint = Storage.sanitizeEndpoint(options.apiEndpoint);
466 customEndpoint = true;
467 }
468 options = Object.assign({}, options, { apiEndpoint });
469 // Note: EMULATOR_HOST is an experimental configuration variable. Use apiEndpoint instead.
470 const baseUrl = EMULATOR_HOST || `${options.apiEndpoint}/storage/v1`;
471 const config = {
472 apiEndpoint: options.apiEndpoint,
473 retryOptions: {
474 autoRetry: ((_a = options.retryOptions) === null || _a === void 0 ? void 0 : _a.autoRetry) !== undefined
475 ? (_b = options.retryOptions) === null || _b === void 0 ? void 0 : _b.autoRetry
476 : AUTO_RETRY_DEFAULT,
477 maxRetries: ((_c = options.retryOptions) === null || _c === void 0 ? void 0 : _c.maxRetries)
478 ? (_d = options.retryOptions) === null || _d === void 0 ? void 0 : _d.maxRetries
479 : MAX_RETRY_DEFAULT,
480 retryDelayMultiplier: ((_e = options.retryOptions) === null || _e === void 0 ? void 0 : _e.retryDelayMultiplier)
481 ? (_f = options.retryOptions) === null || _f === void 0 ? void 0 : _f.retryDelayMultiplier
482 : RETRY_DELAY_MULTIPLIER_DEFAULT,
483 totalTimeout: ((_g = options.retryOptions) === null || _g === void 0 ? void 0 : _g.totalTimeout)
484 ? (_h = options.retryOptions) === null || _h === void 0 ? void 0 : _h.totalTimeout
485 : TOTAL_TIMEOUT_DEFAULT,
486 maxRetryDelay: ((_j = options.retryOptions) === null || _j === void 0 ? void 0 : _j.maxRetryDelay)
487 ? (_k = options.retryOptions) === null || _k === void 0 ? void 0 : _k.maxRetryDelay
488 : MAX_RETRY_DELAY_DEFAULT,
489 retryableErrorFn: ((_l = options.retryOptions) === null || _l === void 0 ? void 0 : _l.retryableErrorFn)
490 ? (_m = options.retryOptions) === null || _m === void 0 ? void 0 : _m.retryableErrorFn
491 : RETRYABLE_ERR_FN_DEFAULT,
492 idempotencyStrategy: ((_o = options.retryOptions) === null || _o === void 0 ? void 0 : _o.idempotencyStrategy) !== undefined
493 ? (_p = options.retryOptions) === null || _p === void 0 ? void 0 : _p.idempotencyStrategy
494 : IDEMPOTENCY_STRATEGY_DEFAULT,
495 },
496 baseUrl,
497 customEndpoint,
498 useAuthWithCustomEndpoint: options === null || options === void 0 ? void 0 : options.useAuthWithCustomEndpoint,
499 projectIdRequired: false,
500 scopes: [
501 'https://www.googleapis.com/auth/iam',
502 'https://www.googleapis.com/auth/cloud-platform',
503 'https://www.googleapis.com/auth/devstorage.full_control',
504 ],
505 packageJson: getPackageJSON(),
506 };
507 super(config, options);
508 /**
509 * Reference to {@link Storage.acl}.
510 *
511 * @name Storage#acl
512 * @see Storage.acl
513 */
514 this.acl = Storage.acl;
515 this.crc32cGenerator =
516 options.crc32cGenerator || CRC32C_DEFAULT_VALIDATOR_GENERATOR;
517 this.retryOptions = config.retryOptions;
518 this.getBucketsStream = paginator.streamify('getBuckets');
519 this.getHmacKeysStream = paginator.streamify('getHmacKeys');
520 }
521 static sanitizeEndpoint(url) {
522 if (!PROTOCOL_REGEX.test(url)) {
523 url = `https://${url}`;
524 }
525 return url.replace(/\/+$/, ''); // Remove trailing slashes
526 }
527 /**
528 * Get a reference to a Cloud Storage bucket.
529 *
530 * @param {string} name Name of the bucket.
531 * @param {object} [options] Configuration object.
532 * @param {string} [options.kmsKeyName] A Cloud KMS key that will be used to
533 * encrypt objects inserted into this bucket, if no encryption method is
534 * specified.
535 * @param {string} [options.userProject] User project to be billed for all
536 * requests made from this Bucket object.
537 * @returns {Bucket}
538 * @see Bucket
539 *
540 * @example
541 * ```
542 * const {Storage} = require('@google-cloud/storage');
543 * const storage = new Storage();
544 * const albums = storage.bucket('albums');
545 * const photos = storage.bucket('photos');
546 * ```
547 */
548 bucket(name, options) {
549 if (!name) {
550 throw new Error(StorageExceptionMessages.BUCKET_NAME_REQUIRED);
551 }
552 return new Bucket(this, name, options);
553 }
554 /**
555 * Reference a channel to receive notifications about changes to your bucket.
556 *
557 * @param {string} id The ID of the channel.
558 * @param {string} resourceId The resource ID of the channel.
559 * @returns {Channel}
560 * @see Channel
561 *
562 * @example
563 * ```
564 * const {Storage} = require('@google-cloud/storage');
565 * const storage = new Storage();
566 * const channel = storage.channel('id', 'resource-id');
567 * ```
568 */
569 channel(id, resourceId) {
570 return new Channel(this, id, resourceId);
571 }
572 /**
573 * @typedef {array} CreateBucketResponse
574 * @property {Bucket} 0 The new {@link Bucket}.
575 * @property {object} 1 The full API response.
576 */
577 /**
578 * @callback CreateBucketCallback
579 * @param {?Error} err Request error, if any.
580 * @param {Bucket} bucket The new {@link Bucket}.
581 * @param {object} apiResponse The full API response.
582 */
583 /**
584 * Metadata to set for the bucket.
585 *
586 * @typedef {object} CreateBucketRequest
587 * @property {boolean} [archive=false] Specify the storage class as Archive.
588 * @property {object} [autoclass.enabled=false] Specify whether Autoclass is
589 * enabled for the bucket.
590 * @property {object} [autoclass.terminalStorageClass='NEARLINE'] The storage class that objects in an Autoclass bucket eventually transition to if
591 * they are not read for a certain length of time. Valid values are NEARLINE and ARCHIVE.
592 * @property {boolean} [coldline=false] Specify the storage class as Coldline.
593 * @property {Cors[]} [cors=[]] Specify the CORS configuration to use.
594 * @property {CustomPlacementConfig} [customPlacementConfig={}] Specify the bucket's regions for dual-region buckets.
595 * For more information, see {@link https://cloud.google.com/storage/docs/locations| Bucket Locations}.
596 * @property {boolean} [dra=false] Specify the storage class as Durable Reduced
597 * Availability.
598 * @property {boolean} [enableObjectRetention=false] Specifiy whether or not object retention should be enabled on this bucket.
599 * @property {object} [hierarchicalNamespace.enabled=false] Specify whether or not to enable hierarchical namespace on this bucket.
600 * @property {string} [location] Specify the bucket's location. If specifying
601 * a dual-region, the `customPlacementConfig` property should be set in conjunction.
602 * For more information, see {@link https://cloud.google.com/storage/docs/locations| Bucket Locations}.
603 * @property {boolean} [multiRegional=false] Specify the storage class as
604 * Multi-Regional.
605 * @property {boolean} [nearline=false] Specify the storage class as Nearline.
606 * @property {boolean} [regional=false] Specify the storage class as Regional.
607 * @property {boolean} [requesterPays=false] Force the use of the User Project metadata field to assign operational
608 * costs when an operation is made on a Bucket and its objects.
609 * @property {string} [rpo] For dual-region buckets, controls whether turbo
610 * replication is enabled (`ASYNC_TURBO`) or disabled (`DEFAULT`).
611 * @property {boolean} [standard=true] Specify the storage class as Standard.
612 * @property {string} [storageClass] The new storage class. (`standard`,
613 * `nearline`, `coldline`, or `archive`).
614 * **Note:** The storage classes `multi_regional`, `regional`, and
615 * `durable_reduced_availability` are now legacy and will be deprecated in
616 * the future.
617 * @property {Versioning} [versioning=undefined] Specify the versioning status.
618 * @property {string} [userProject] The ID of the project which will be billed
619 * for the request.
620 */
621 /**
622 * Create a bucket.
623 *
624 * Cloud Storage uses a flat namespace, so you can't create a bucket with
625 * a name that is already in use. For more information, see
626 * {@link https://cloud.google.com/storage/docs/bucketnaming.html#requirements| Bucket Naming Guidelines}.
627 *
628 * See {@link https://cloud.google.com/storage/docs/json_api/v1/buckets/insert| Buckets: insert API Documentation}
629 * See {@link https://cloud.google.com/storage/docs/storage-classes| Storage Classes}
630 *
631 * @param {string} name Name of the bucket to create.
632 * @param {CreateBucketRequest} [metadata] Metadata to set for the bucket.
633 * @param {CreateBucketCallback} [callback] Callback function.
634 * @returns {Promise<CreateBucketResponse>}
635 * @throws {Error} If a name is not provided.
636 * @see Bucket#create
637 *
638 * @example
639 * ```
640 * const {Storage} = require('@google-cloud/storage');
641 * const storage = new Storage();
642 * const callback = function(err, bucket, apiResponse) {
643 * // `bucket` is a Bucket object.
644 * };
645 *
646 * storage.createBucket('new-bucket', callback);
647 *
648 * //-
649 * // Create a bucket in a specific location and region. <em>See the <a
650 * // href="https://cloud.google.com/storage/docs/json_api/v1/buckets/insert">
651 * // Official JSON API docs</a> for complete details on the `location`
652 * option.
653 * // </em>
654 * //-
655 * const metadata = {
656 * location: 'US-CENTRAL1',
657 * regional: true
658 * };
659 *
660 * storage.createBucket('new-bucket', metadata, callback);
661 *
662 * //-
663 * // Create a bucket with a retention policy of 6 months.
664 * //-
665 * const metadata = {
666 * retentionPolicy: {
667 * retentionPeriod: 15780000 // 6 months in seconds.
668 * }
669 * };
670 *
671 * storage.createBucket('new-bucket', metadata, callback);
672 *
673 * //-
674 * // Enable versioning on a new bucket.
675 * //-
676 * const metadata = {
677 * versioning: {
678 * enabled: true
679 * }
680 * };
681 *
682 * storage.createBucket('new-bucket', metadata, callback);
683 *
684 * //-
685 * // If the callback is omitted, we'll return a Promise.
686 * //-
687 * storage.createBucket('new-bucket').then(function(data) {
688 * const bucket = data[0];
689 * const apiResponse = data[1];
690 * });
691 *
692 * ```
693 * @example <caption>include:samples/buckets.js</caption>
694 * region_tag:storage_create_bucket
695 * Another example:
696 */
697 createBucket(name, metadataOrCallback, callback) {
698 if (!name) {
699 throw new Error(StorageExceptionMessages.BUCKET_NAME_REQUIRED_CREATE);
700 }
701 let metadata;
702 if (!callback) {
703 callback = metadataOrCallback;
704 metadata = {};
705 }
706 else {
707 metadata = metadataOrCallback;
708 }
709 const body = {
710 ...metadata,
711 name,
712 };
713 const storageClasses = {
714 archive: 'ARCHIVE',
715 coldline: 'COLDLINE',
716 dra: 'DURABLE_REDUCED_AVAILABILITY',
717 multiRegional: 'MULTI_REGIONAL',
718 nearline: 'NEARLINE',
719 regional: 'REGIONAL',
720 standard: 'STANDARD',
721 };
722 const storageClassKeys = Object.keys(storageClasses);
723 for (const storageClass of storageClassKeys) {
724 if (body[storageClass]) {
725 if (metadata.storageClass && metadata.storageClass !== storageClass) {
726 throw new Error(`Both \`${storageClass}\` and \`storageClass\` were provided.`);
727 }
728 body.storageClass = storageClasses[storageClass];
729 delete body[storageClass];
730 }
731 }
732 if (body.requesterPays) {
733 body.billing = {
734 requesterPays: body.requesterPays,
735 };
736 delete body.requesterPays;
737 }
738 const query = {
739 project: this.projectId,
740 };
741 if (body.userProject) {
742 query.userProject = body.userProject;
743 delete body.userProject;
744 }
745 if (body.enableObjectRetention) {
746 query.enableObjectRetention = body.enableObjectRetention;
747 delete body.enableObjectRetention;
748 }
749 if (body.predefinedAcl) {
750 query.predefinedAcl = body.predefinedAcl;
751 delete body.predefinedAcl;
752 }
753 if (body.predefinedDefaultObjectAcl) {
754 query.predefinedDefaultObjectAcl = body.predefinedDefaultObjectAcl;
755 delete body.predefinedDefaultObjectAcl;
756 }
757 if (body.projection) {
758 query.projection = body.projection;
759 delete body.projection;
760 }
761 this.request({
762 method: 'POST',
763 uri: '/b',
764 qs: query,
765 json: body,
766 }, (err, resp) => {
767 if (err) {
768 callback(err, null, resp);
769 return;
770 }
771 const bucket = this.bucket(name);
772 bucket.metadata = resp;
773 callback(null, bucket, resp);
774 });
775 }
776 /**
777 * @typedef {object} CreateHmacKeyOptions
778 * @property {string} [projectId] The project ID of the project that owns
779 * the service account of the requested HMAC key. If not provided,
780 * the project ID used to instantiate the Storage client will be used.
781 * @property {string} [userProject] This parameter is currently ignored.
782 */
783 /**
784 * @typedef {object} HmacKeyMetadata
785 * @property {string} accessId The access id identifies which HMAC key was
786 * used to sign a request when authenticating with HMAC.
787 * @property {string} etag Used to perform a read-modify-write of the key.
788 * @property {string} id The resource name of the HMAC key.
789 * @property {string} projectId The project ID.
790 * @property {string} serviceAccountEmail The service account's email this
791 * HMAC key is created for.
792 * @property {string} state The state of this HMAC key. One of "ACTIVE",
793 * "INACTIVE" or "DELETED".
794 * @property {string} timeCreated The creation time of the HMAC key in
795 * RFC 3339 format.
796 * @property {string} [updated] The time this HMAC key was last updated in
797 * RFC 3339 format.
798 */
799 /**
800 * @typedef {array} CreateHmacKeyResponse
801 * @property {HmacKey} 0 The HmacKey instance created from API response.
802 * @property {string} 1 The HMAC key's secret used to access the XML API.
803 * @property {object} 3 The raw API response.
804 */
805 /**
806 * @callback CreateHmacKeyCallback Callback function.
807 * @param {?Error} err Request error, if any.
808 * @param {HmacKey} hmacKey The HmacKey instance created from API response.
809 * @param {string} secret The HMAC key's secret used to access the XML API.
810 * @param {object} apiResponse The raw API response.
811 */
812 /**
813 * Create an HMAC key associated with an service account to authenticate
814 * requests to the Cloud Storage XML API.
815 *
816 * See {@link https://cloud.google.com/storage/docs/authentication/hmackeys| HMAC keys documentation}
817 *
818 * @param {string} serviceAccountEmail The service account's email address
819 * with which the HMAC key is created for.
820 * @param {CreateHmacKeyCallback} [callback] Callback function.
821 * @return {Promise<CreateHmacKeyResponse>}
822 *
823 * @example
824 * ```
825 * const {Storage} = require('google-cloud/storage');
826 * const storage = new Storage();
827 *
828 * // Replace with your service account's email address
829 * const serviceAccountEmail =
830 * 'my-service-account@appspot.gserviceaccount.com';
831 *
832 * storage.createHmacKey(serviceAccountEmail, function(err, hmacKey, secret) {
833 * if (!err) {
834 * // Securely store the secret for use with the XML API.
835 * }
836 * });
837 *
838 * //-
839 * // If the callback is omitted, we'll return a Promise.
840 * //-
841 * storage.createHmacKey(serviceAccountEmail)
842 * .then((response) => {
843 * const hmacKey = response[0];
844 * const secret = response[1];
845 * // Securely store the secret for use with the XML API.
846 * });
847 * ```
848 */
849 createHmacKey(serviceAccountEmail, optionsOrCb, cb) {
850 if (typeof serviceAccountEmail !== 'string') {
851 throw new Error(StorageExceptionMessages.HMAC_SERVICE_ACCOUNT);
852 }
853 const { options, callback } = normalize(optionsOrCb, cb);
854 const query = Object.assign({}, options, { serviceAccountEmail });
855 const projectId = query.projectId || this.projectId;
856 delete query.projectId;
857 this.request({
858 method: 'POST',
859 uri: `/projects/${projectId}/hmacKeys`,
860 qs: query,
861 maxRetries: 0, //explicitly set this value since this is a non-idempotent function
862 }, (err, resp) => {
863 if (err) {
864 callback(err, null, null, resp);
865 return;
866 }
867 const metadata = resp.metadata;
868 const hmacKey = this.hmacKey(metadata.accessId, {
869 projectId: metadata.projectId,
870 });
871 hmacKey.metadata = resp.metadata;
872 callback(null, hmacKey, resp.secret, resp);
873 });
874 }
875 /**
876 * Query object for listing buckets.
877 *
878 * @typedef {object} GetBucketsRequest
879 * @property {boolean} [autoPaginate=true] Have pagination handled
880 * automatically.
881 * @property {number} [maxApiCalls] Maximum number of API calls to make.
882 * @property {number} [maxResults] Maximum number of items plus prefixes to
883 * return per call.
884 * Note: By default will handle pagination automatically
885 * if more than 1 page worth of results are requested per call.
886 * When `autoPaginate` is set to `false` the smaller of `maxResults`
887 * or 1 page of results will be returned per call.
888 * @property {string} [pageToken] A previously-returned page token
889 * representing part of the larger set of results to view.
890 * @property {string} [userProject] The ID of the project which will be billed
891 * for the request.
892 */
893 /**
894 * @typedef {array} GetBucketsResponse
895 * @property {Bucket[]} 0 Array of {@link Bucket} instances.
896 * @property {object} 1 nextQuery A query object to receive more results.
897 * @property {object} 2 The full API response.
898 */
899 /**
900 * @callback GetBucketsCallback
901 * @param {?Error} err Request error, if any.
902 * @param {Bucket[]} buckets Array of {@link Bucket} instances.
903 * @param {object} nextQuery A query object to receive more results.
904 * @param {object} apiResponse The full API response.
905 */
906 /**
907 * Get Bucket objects for all of the buckets in your project.
908 *
909 * See {@link https://cloud.google.com/storage/docs/json_api/v1/buckets/list| Buckets: list API Documentation}
910 *
911 * @param {GetBucketsRequest} [query] Query object for listing buckets.
912 * @param {GetBucketsCallback} [callback] Callback function.
913 * @returns {Promise<GetBucketsResponse>}
914 *
915 * @example
916 * ```
917 * const {Storage} = require('@google-cloud/storage');
918 * const storage = new Storage();
919 * storage.getBuckets(function(err, buckets) {
920 * if (!err) {
921 * // buckets is an array of Bucket objects.
922 * }
923 * });
924 *
925 * //-
926 * // To control how many API requests are made and page through the results
927 * // manually, set `autoPaginate` to `false`.
928 * //-
929 * const callback = function(err, buckets, nextQuery, apiResponse) {
930 * if (nextQuery) {
931 * // More results exist.
932 * storage.getBuckets(nextQuery, callback);
933 * }
934 *
935 * // The `metadata` property is populated for you with the metadata at the
936 * // time of fetching.
937 * buckets[0].metadata;
938 *
939 * // However, in cases where you are concerned the metadata could have
940 * // changed, use the `getMetadata` method.
941 * buckets[0].getMetadata(function(err, metadata, apiResponse) {});
942 * };
943 *
944 * storage.getBuckets({
945 * autoPaginate: false
946 * }, callback);
947 *
948 * //-
949 * // If the callback is omitted, we'll return a Promise.
950 * //-
951 * storage.getBuckets().then(function(data) {
952 * const buckets = data[0];
953 * });
954 *
955 * ```
956 * @example <caption>include:samples/buckets.js</caption>
957 * region_tag:storage_list_buckets
958 * Another example:
959 */
960 getBuckets(optionsOrCallback, cb) {
961 const { options, callback } = normalize(optionsOrCallback, cb);
962 options.project = options.project || this.projectId;
963 this.request({
964 uri: '/b',
965 qs: options,
966 }, (err, resp) => {
967 if (err) {
968 callback(err, null, null, resp);
969 return;
970 }
971 const itemsArray = resp.items ? resp.items : [];
972 const buckets = itemsArray.map((bucket) => {
973 const bucketInstance = this.bucket(bucket.id);
974 bucketInstance.metadata = bucket;
975 return bucketInstance;
976 });
977 const nextQuery = resp.nextPageToken
978 ? Object.assign({}, options, { pageToken: resp.nextPageToken })
979 : null;
980 callback(null, buckets, nextQuery, resp);
981 });
982 }
983 getHmacKeys(optionsOrCb, cb) {
984 const { options, callback } = normalize(optionsOrCb, cb);
985 const query = Object.assign({}, options);
986 const projectId = query.projectId || this.projectId;
987 delete query.projectId;
988 this.request({
989 uri: `/projects/${projectId}/hmacKeys`,
990 qs: query,
991 }, (err, resp) => {
992 if (err) {
993 callback(err, null, null, resp);
994 return;
995 }
996 const itemsArray = resp.items ? resp.items : [];
997 const hmacKeys = itemsArray.map((hmacKey) => {
998 const hmacKeyInstance = this.hmacKey(hmacKey.accessId, {
999 projectId: hmacKey.projectId,
1000 });
1001 hmacKeyInstance.metadata = hmacKey;
1002 return hmacKeyInstance;
1003 });
1004 const nextQuery = resp.nextPageToken
1005 ? Object.assign({}, options, { pageToken: resp.nextPageToken })
1006 : null;
1007 callback(null, hmacKeys, nextQuery, resp);
1008 });
1009 }
1010 /**
1011 * @typedef {array} GetServiceAccountResponse
1012 * @property {object} 0 The service account resource.
1013 * @property {object} 1 The full
1014 * {@link https://cloud.google.com/storage/docs/json_api/v1/projects/serviceAccount#resource| API response}.
1015 */
1016 /**
1017 * @callback GetServiceAccountCallback
1018 * @param {?Error} err Request error, if any.
1019 * @param {object} serviceAccount The serviceAccount resource.
1020 * @param {string} serviceAccount.emailAddress The service account email
1021 * address.
1022 * @param {object} apiResponse The full
1023 * {@link https://cloud.google.com/storage/docs/json_api/v1/projects/serviceAccount#resource| API response}.
1024 */
1025 /**
1026 * Get the email address of this project's Google Cloud Storage service
1027 * account.
1028 *
1029 * See {@link https://cloud.google.com/storage/docs/json_api/v1/projects/serviceAccount/get| Projects.serviceAccount: get API Documentation}
1030 * See {@link https://cloud.google.com/storage/docs/json_api/v1/projects/serviceAccount#resource| Projects.serviceAccount Resource}
1031 *
1032 * @param {object} [options] Configuration object.
1033 * @param {string} [options.userProject] User project to be billed for this
1034 * request.
1035 * @param {GetServiceAccountCallback} [callback] Callback function.
1036 * @returns {Promise<GetServiceAccountResponse>}
1037 *
1038 * @example
1039 * ```
1040 * const {Storage} = require('@google-cloud/storage');
1041 * const storage = new Storage();
1042 *
1043 * storage.getServiceAccount(function(err, serviceAccount, apiResponse) {
1044 * if (!err) {
1045 * const serviceAccountEmail = serviceAccount.emailAddress;
1046 * }
1047 * });
1048 *
1049 * //-
1050 * // If the callback is omitted, we'll return a Promise.
1051 * //-
1052 * storage.getServiceAccount().then(function(data) {
1053 * const serviceAccountEmail = data[0].emailAddress;
1054 * const apiResponse = data[1];
1055 * });
1056 * ```
1057 */
1058 getServiceAccount(optionsOrCallback, cb) {
1059 const { options, callback } = normalize(optionsOrCallback, cb);
1060 this.request({
1061 uri: `/projects/${this.projectId}/serviceAccount`,
1062 qs: options,
1063 }, (err, resp) => {
1064 if (err) {
1065 callback(err, null, resp);
1066 return;
1067 }
1068 const camelCaseResponse = {};
1069 for (const prop in resp) {
1070 // eslint-disable-next-line no-prototype-builtins
1071 if (resp.hasOwnProperty(prop)) {
1072 const camelCaseProp = prop.replace(/_(\w)/g, (_, match) => match.toUpperCase());
1073 camelCaseResponse[camelCaseProp] = resp[prop];
1074 }
1075 }
1076 callback(null, camelCaseResponse, resp);
1077 });
1078 }
1079 /**
1080 * Get a reference to an HmacKey object.
1081 * Note: this does not fetch the HMAC key's metadata. Use HmacKey#get() to
1082 * retrieve and populate the metadata.
1083 *
1084 * To get a reference to an HMAC key that's not created for a service
1085 * account in the same project used to instantiate the Storage client,
1086 * supply the project's ID as `projectId` in the `options` argument.
1087 *
1088 * @param {string} accessId The HMAC key's access ID.
1089 * @param {HmacKeyOptions} options HmacKey constructor options.
1090 * @returns {HmacKey}
1091 * @see HmacKey
1092 *
1093 * @example
1094 * ```
1095 * const {Storage} = require('@google-cloud/storage');
1096 * const storage = new Storage();
1097 * const hmacKey = storage.hmacKey('ACCESS_ID');
1098 * ```
1099 */
1100 hmacKey(accessId, options) {
1101 if (!accessId) {
1102 throw new Error(StorageExceptionMessages.HMAC_ACCESS_ID);
1103 }
1104 return new HmacKey(this, accessId, options);
1105 }
1106}
1107/**
1108 * {@link Bucket} class.
1109 *
1110 * @name Storage.Bucket
1111 * @see Bucket
1112 * @type {Constructor}
1113 */
1114Storage.Bucket = Bucket;
1115/**
1116 * {@link Channel} class.
1117 *
1118 * @name Storage.Channel
1119 * @see Channel
1120 * @type {Constructor}
1121 */
1122Storage.Channel = Channel;
1123/**
1124 * {@link File} class.
1125 *
1126 * @name Storage.File
1127 * @see File
1128 * @type {Constructor}
1129 */
1130Storage.File = File;
1131/**
1132 * {@link HmacKey} class.
1133 *
1134 * @name Storage.HmacKey
1135 * @see HmacKey
1136 * @type {Constructor}
1137 */
1138Storage.HmacKey = HmacKey;
1139Storage.acl = {
1140 OWNER_ROLE: 'OWNER',
1141 READER_ROLE: 'READER',
1142 WRITER_ROLE: 'WRITER',
1143};
1144/*! Developer Documentation
1145 *
1146 * These methods can be auto-paginated.
1147 */
1148paginator.extend(Storage, ['getBuckets', 'getHmacKeys']);
1149/*! Developer Documentation
1150 *
1151 * All async methods (except for streams) will return a Promise in the event
1152 * that a callback is omitted.
1153 */
1154promisifyAll(Storage, {
1155 exclude: ['bucket', 'channel', 'hmacKey'],
1156});