@pi-r/gcp 0.6.7 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,10 +1,7 @@
1
- # @pi-r/gcp
1
+ ### @pi-r/gcp
2
2
 
3
- ## Documentation
3
+ https://e-mc.readthedocs.io/en/latest/cloud/gcp.html
4
4
 
5
- - [E-mc](https://e-mc.readthedocs.io/en/latest/cloud/gcp.html)
6
- - [squared](https://squared.readthedocs.io)
7
-
8
- ## LICENSE
5
+ ### LICENSE
9
6
 
10
7
  MIT
package/client/index.js CHANGED
@@ -1,18 +1,16 @@
1
1
  "use strict";
2
- exports.getProjectId = exports.createBucketRequest = exports.setPredefinedAcl = exports.setPublicRead = exports.executeBatchQuery = exports.executeQuery = exports.deleteObjectsV2 = exports.deleteObjects = exports.setBucketWebsite = exports.setBucketPolicy = exports.createBucketV2 = exports.createBucket = exports.createDatabaseClient = exports.createStorageClient = exports.validateDatabase = exports.validateStorage = exports.isFirebaseApp = void 0;
2
+ exports.CLOUD_DOWNLOAD_CHUNK = exports.CLOUD_UPLOAD_CHUNK = exports.CLOUD_UPLOAD_STREAM = exports.getProjectId = exports.createBucketRequest = exports.setPredefinedAcl = exports.setPublicRead = exports.executeBatchQuery = exports.executeQuery = exports.deleteObjectsV2 = exports.deleteObjects = exports.setBucketWebsite = exports.setBucketTagging = exports.setBucketPolicy = exports.createBucketV2 = exports.createBucket = exports.createDatabaseClient = exports.createStorageClient = exports.validateDatabase = exports.validateStorage = exports.isFirebaseApp = void 0;
3
3
  const path = require("path");
4
4
  const storage = require("@google-cloud/storage");
5
5
  const firestore_1 = require("@google-cloud/firestore");
6
6
  const util_1 = require("@e-mc/cloud/util");
7
7
  const types_1 = require("@e-mc/types");
8
- const Module = require("@e-mc/module");
9
8
  const Cloud = require("@e-mc/cloud");
10
9
  const FIREBASE_DB = {};
11
10
  const FIREBASE_STORAGE = {};
12
11
  const ADMIN_DB = {};
13
12
  const ADMIN_STORAGE = {};
14
13
  function getApp(credential, isDB) {
15
- var _a, _b;
16
14
  const { projectId, databaseURL, storageBucket, apiKey, authDomain } = credential;
17
15
  if (apiKey && authDomain) {
18
16
  const { getApps, initializeApp } = require('@firebase/app');
@@ -26,7 +24,7 @@ function getApp(credential, isDB) {
26
24
  }
27
25
  if (!app) {
28
26
  const firebaseKey = (projectId || '') + '_' + apiKey + '_' + authDomain + (isDB ? '_' + databaseURL : '');
29
- app = isDB ? FIREBASE_DB[firebaseKey] || (FIREBASE_DB[firebaseKey] = initializeApp({ ...credential, databaseURL }, firebaseKey)) : FIREBASE_STORAGE[firebaseKey] || (FIREBASE_STORAGE[firebaseKey] = initializeApp({ ...credential, storageBucket }, firebaseKey));
27
+ app = isDB ? FIREBASE_DB[firebaseKey] ||= initializeApp({ ...credential, databaseURL }, firebaseKey) : FIREBASE_STORAGE[firebaseKey] ||= initializeApp({ ...credential, storageBucket }, firebaseKey);
30
28
  }
31
29
  if (isDB) {
32
30
  const { getDatabase, goOnline } = require('@firebase/database');
@@ -47,7 +45,7 @@ function getApp(credential, isDB) {
47
45
  }
48
46
  }
49
47
  if (!app) {
50
- app = isDB ? ADMIN_DB[_a = databaseURL || '[DEFAULT]'] || (ADMIN_DB[_a] = initializeApp({ credential: applicationDefault(), databaseURL }, databaseURL)) : ADMIN_STORAGE[_b = storageBucket || '[DEFAULT]'] || (ADMIN_STORAGE[_b] = initializeApp({ credential: applicationDefault(), storageBucket }, storageBucket));
48
+ app = isDB ? ADMIN_DB[databaseURL || "[DEFAULT]"] ||= initializeApp({ credential: applicationDefault(), databaseURL }, databaseURL) : ADMIN_STORAGE[storageBucket || "[DEFAULT]"] ||= initializeApp({ credential: applicationDefault(), storageBucket }, storageBucket);
51
49
  }
52
50
  credential.admin = true;
53
51
  if (isDB) {
@@ -59,7 +57,7 @@ function getApp(credential, isDB) {
59
57
  }
60
58
  }
61
59
  async function hasBucket(client) {
62
- const [exists] = await client.exists().catch(err => isErrorConflict(err) ? [true] : [false]);
60
+ const [exists] = await client.exists().catch((err) => isErrorConflict(err) ? [true] : [false]);
63
61
  return exists;
64
62
  }
65
63
  async function updatePredefinedAcl(acl, values, metadata = {}) {
@@ -69,7 +67,7 @@ async function updatePredefinedAcl(acl, values, metadata = {}) {
69
67
  let defaultObjectAcl;
70
68
  ({ projectNumber, defaultObjectAcl } = metadata);
71
69
  if (projectNumber === undefined && (0, types_1.isArray)(defaultObjectAcl)) {
72
- const target = defaultObjectAcl.find(item => { var _a; return (_a = item.projectTeam) === null || _a === void 0 ? void 0 : _a.projectNumber; });
70
+ const target = defaultObjectAcl.find(item => item.projectTeam?.projectNumber);
73
71
  if (target !== undefined) {
74
72
  projectNumber = target.projectTeam.projectNumber;
75
73
  }
@@ -83,7 +81,7 @@ async function updatePredefinedAcl(acl, values, metadata = {}) {
83
81
  }
84
82
  if ((0, types_1.isString)(value.role)) {
85
83
  if (projectNumber !== undefined) {
86
- value.userProject || (value.userProject = projectNumber.toString());
84
+ value.userProject ||= projectNumber.toString();
87
85
  }
88
86
  return target.add(value);
89
87
  }
@@ -99,25 +97,25 @@ async function updatePredefinedAcl(acl, values, metadata = {}) {
99
97
  }
100
98
  return errors;
101
99
  })
102
- .catch(err => [err]);
100
+ .catch((err) => [err]);
103
101
  }
104
102
  async function setUniformBucketLevel(bucket, enabled) {
105
103
  return bucket.setMetadata({ iamConfiguration: { uniformBucketLevelAccess: { enabled } } });
106
104
  }
105
+ const asFieldPath = (params) => Array.isArray(params) && params.every(item => typeof item === 'string') ? new firestore_1.FieldPath(...params) : params;
107
106
  const getFirebasePackageName = (credential) => credential.apiKey && credential.authDomain ? 'firebase' : 'firebase-admin';
108
- const hasKeyFile = (credential) => (0, types_1.isString)(credential.keyFilename || credential.keyFile || process.env.GOOGLE_APPLICATION_CREDENTIALS) || (0, types_1.isObject)(credential.credentials);
109
107
  const isErrorConflict = (err) => (err instanceof Error) && err.code === 409;
108
+ const hasGoogleAuth = (credential) => (0, types_1.isString)(credential.keyFilename || credential.keyFile || process.env.GOOGLE_APPLICATION_CREDENTIALS) || (0, types_1.isObject)(credential.credentials) || !!credential.authClient;
110
109
  function isFirebaseApp(credential, store, admin) {
111
- return !!(credential.apiKey && credential.authDomain && (store || credential.databaseURL) || credential.product === 'firebase' && process.env.GOOGLE_APPLICATION_CREDENTIALS) && (!admin || !credential.admin);
110
+ return !!(credential.apiKey && credential.authDomain && (store || credential.databaseURL) || credential.product === "firebase" && process.env.GOOGLE_APPLICATION_CREDENTIALS) && (!admin || !credential.admin);
112
111
  }
113
112
  exports.isFirebaseApp = isFirebaseApp;
114
113
  function validateStorage(credential) {
115
- return hasKeyFile(credential) || !!credential.authClient || isFirebaseApp(credential, true);
114
+ return hasGoogleAuth(credential) || isFirebaseApp(credential, true);
116
115
  }
117
116
  exports.validateStorage = validateStorage;
118
117
  function validateDatabase(credential, data) {
119
- var _a;
120
- return (hasKeyFile(credential) || !!credential.authClient) && !!(data.product || data.database || data.table || data.query || data.id || data.keys || data.kind || ((_a = data.options) === null || _a === void 0 ? void 0 : _a.query)) || isFirebaseApp(credential);
118
+ return hasGoogleAuth(credential) && !!(data.product || data.database || data.table || data.query || data.id || data.keys || data.kind || data.options?.query) || isFirebaseApp(credential);
121
119
  }
122
120
  exports.validateDatabase = validateDatabase;
123
121
  function createStorageClient(credential, bucket) {
@@ -142,29 +140,26 @@ exports.createStorageClient = createStorageClient;
142
140
  function createDatabaseClient(credential, data) {
143
141
  let packageName = '';
144
142
  try {
145
- let product, name, database, table, query;
146
- if (data) {
147
- ({ product, name, table, query, database } = data);
148
- }
149
- if (product === 'firebase' || isFirebaseApp(credential)) {
143
+ if (data?.product === "firebase" || isFirebaseApp(credential)) {
150
144
  packageName = getFirebasePackageName(credential);
151
145
  return getApp(credential, true);
152
146
  }
153
147
  getProjectId(credential, true);
154
148
  if (data) {
155
- if (product === 'spanner' || !product && name && database && (query || table)) {
149
+ const { product, name, table, query, database } = data;
150
+ if (product === "spanner" || !product && name && database && (query || table)) {
156
151
  const { Spanner } = require(packageName = '@google-cloud/spanner');
157
152
  return new Spanner(credential);
158
153
  }
159
- if (product === 'bigquery' || !product && (!name && table && database || (0, types_1.isString)(query))) {
154
+ if (product === "bigquery" || !product && (!name && table && database || (0, types_1.isString)(query))) {
160
155
  const { BigQuery } = require(packageName = '@google-cloud/bigquery');
161
156
  return new BigQuery(credential);
162
157
  }
163
- if (product === 'bigtable' || !product && name && table && !database) {
158
+ if (product === "bigtable" || !product && name && table && !database) {
164
159
  const { Bigtable } = require(packageName = '@google-cloud/bigtable');
165
160
  return new Bigtable(credential);
166
161
  }
167
- if (product === 'datastore' || !product && (data.keys || data.kind || query && !table && !data.id)) {
162
+ if (product === "datastore" || !product && (data.keys || data.kind || query && !table && !data.id)) {
168
163
  const { Datastore } = require(packageName = '@google-cloud/datastore');
169
164
  return new Datastore(credential);
170
165
  }
@@ -210,7 +205,6 @@ async function createBucketV2(credential, bucket, acl, options, service = 'gcp')
210
205
  }
211
206
  exports.createBucketV2 = createBucketV2;
212
207
  async function setBucketPolicy(credential, bucket, options, service = 'gcp') {
213
- var _a;
214
208
  if (isFirebaseApp(credential, true, true)) {
215
209
  return false;
216
210
  }
@@ -224,32 +218,32 @@ async function setBucketPolicy(credential, bucket, options, service = 'gcp') {
224
218
  if (!Array.isArray(options.acl)) {
225
219
  options.acl = undefined;
226
220
  switch (acl) {
227
- case 'private':
228
- case 'projectPrivate':
229
- await client.makePrivate(options).catch(err => !isErrorConflict(err) && errors.push(err));
230
- await setPredefinedAcl.call(this, client.acl, acl, client, '', (_a = options.bucket) === null || _a === void 0 ? void 0 : _a.metadata).catch(err => errors.push(err));
221
+ case "private":
222
+ case "projectPrivate":
223
+ await client.makePrivate(options).catch((err) => !isErrorConflict(err) && errors.push(err));
224
+ await setPredefinedAcl.call(this, client.acl, acl, client, '', options.bucket?.metadata).catch((err) => errors.push(err));
231
225
  break;
232
- case 'authenticatedRead':
233
- await client.makePublic(options).catch(err => !isErrorConflict(err) && errors.push(err));
226
+ case "authenticatedRead":
227
+ await client.makePublic(options).catch((err) => !isErrorConflict(err) && errors.push(err));
234
228
  options = { ...options };
235
229
  options.acl = [{ entity: 'allUsers' }, { entity: 'allAuthenticatedUsers', role: 'READER' }];
236
230
  break;
237
- case 'publicReadWrite':
238
- await client.makePublic(options).catch(err => !isErrorConflict(err) && errors.push(err));
231
+ case "publicReadWrite":
232
+ await client.makePublic(options).catch((err) => !isErrorConflict(err) && errors.push(err));
239
233
  options = { ...options };
240
234
  options.acl = [{ entity: 'allUsers', role: 'WRITER' }];
241
235
  break;
242
- case 'publicRead':
243
- await client.makePublic(options).catch(err => !isErrorConflict(err) && errors.push(err));
236
+ case "publicRead":
237
+ await client.makePublic(options).catch((err) => !isErrorConflict(err) && errors.push(err));
244
238
  break;
245
239
  case 'bucketAccessUniform':
246
- await setUniformBucketLevel(client, true).catch(err => errors.push(err));
240
+ await setUniformBucketLevel(client, true).catch((err) => errors.push(err));
247
241
  break;
248
242
  case 'bucketAccessACL':
249
- await setUniformBucketLevel(client, false).catch(err => errors.push(err));
243
+ await setUniformBucketLevel(client, false).catch((err) => errors.push(err));
250
244
  break;
251
245
  default:
252
- errors.push((0, types_1.errorValue)('Invalid ACL', Module.asString(acl) || 'empty'));
246
+ errors.push((0, types_1.errorValue)('Invalid ACL', Cloud.asString(acl) || 'empty'));
253
247
  break;
254
248
  }
255
249
  }
@@ -264,6 +258,33 @@ async function setBucketPolicy(credential, bucket, options, service = 'gcp') {
264
258
  return true;
265
259
  }
266
260
  exports.setBucketPolicy = setBucketPolicy;
261
+ async function setBucketTagging(credential, bucket, labels, service = 'gcp') {
262
+ if (isFirebaseApp(credential, true, true) || !(0, types_1.isPlainObject)(labels)) {
263
+ return false;
264
+ }
265
+ const client = createStorageClient.call(this, credential, bucket).bucket(bucket);
266
+ const deleting = Object.keys(labels).length === 0;
267
+ if (deleting) {
268
+ const [metadata] = await client.getMetadata();
269
+ if (!(0, types_1.isPlainObject)(metadata.labels)) {
270
+ return true;
271
+ }
272
+ labels = {};
273
+ for (const key in metadata.labels) {
274
+ labels[key] = null;
275
+ }
276
+ }
277
+ return client.setMetadata({ labels })
278
+ .then(([metadata]) => {
279
+ this.formatMessage(64, service, [deleting ? "Tags deleted" : "Tags created", bucket], ((0, types_1.isPlainObject)(metadata.labels) ? Object.keys(metadata.labels).length : 0) + ' labels (current)', { ...Cloud.LOG_CLOUD_COMMAND });
280
+ return true;
281
+ })
282
+ .catch((err) => {
283
+ this.formatFail(64, service, ["Unable to update bucket tagging", bucket], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false });
284
+ return false;
285
+ });
286
+ }
287
+ exports.setBucketTagging = setBucketTagging;
267
288
  async function setBucketWebsite(credential, bucket, options, service = 'gcp') {
268
289
  if (isFirebaseApp(credential, true, true)) {
269
290
  return false;
@@ -278,11 +299,11 @@ async function setBucketWebsite(credential, bucket, options, service = 'gcp') {
278
299
  }
279
300
  return createStorageClient.call(this, credential, bucket).bucket(bucket).setMetadata({ website })
280
301
  .then(() => {
281
- this.formatMessage(64, service, ["Bucket configured", bucket], website, { ...Cloud.LOG_CLOUD_COMMAND });
302
+ this.formatMessage(64, service, ["Bucket website configured", bucket], website, { ...Cloud.LOG_CLOUD_COMMAND });
282
303
  return true;
283
304
  })
284
- .catch(err => {
285
- this.formatFail(64, service, ["Unable to configure bucket", bucket], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false });
305
+ .catch((err) => {
306
+ this.formatFail(64, service, ["Unable to set bucket website", bucket], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false });
286
307
  return false;
287
308
  });
288
309
  }
@@ -306,7 +327,7 @@ async function deleteObjectsV2(credential, bucket, recursive = true, service = '
306
327
  }
307
328
  if (recursive && prefixes.length) {
308
329
  for (const { name } of prefixes) {
309
- await recurse(Module.joinPath(prefix, name));
330
+ await recurse(Cloud.joinPath(prefix, name));
310
331
  }
311
332
  }
312
333
  }
@@ -329,7 +350,7 @@ async function deleteObjectsV2(credential, bucket, recursive = true, service = '
329
350
  const result = await client.getFiles();
330
351
  for (const { name } of result[0]) {
331
352
  if (!name.includes('/')) {
332
- tasks.push(client.file(name).delete({ ignoreNotFound: true }).catch(err => this.formatFail(64, service, ["Delete failed", name], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false })));
353
+ tasks.push(client.file(name).delete({ ignoreNotFound: true }).catch((err) => this.formatFail(64, service, ["Delete failed", name], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false })));
333
354
  }
334
355
  }
335
356
  }
@@ -356,7 +377,7 @@ async function deleteObjectsV2(credential, bucket, recursive = true, service = '
356
377
  this.formatMessage(64, service, ["Bucket emptied" + ` (${recursive ? 'recursive' : files})`, bucket], recursive ? files : '', { ...Cloud.LOG_CLOUD_COMMAND });
357
378
  }
358
379
  })
359
- .catch(err => {
380
+ .catch((err) => {
360
381
  errors.push(err);
361
382
  });
362
383
  }
@@ -368,10 +389,9 @@ async function executeQuery(credential, data, sessionKey) {
368
389
  }
369
390
  exports.executeQuery = executeQuery;
370
391
  async function executeBatchQuery(credential, batch, sessionKey) {
371
- var _a;
372
392
  const length = batch.length;
373
393
  const result = new Array(length);
374
- const clients = [];
394
+ const clients = {};
375
395
  const caching = length > 0 && this.hasCache(batch[0].service, sessionKey);
376
396
  const cacheValue = { value: this.valueOfKey(credential, 'cache'), sessionKey };
377
397
  const authItems = [];
@@ -386,7 +406,14 @@ async function executeBatchQuery(credential, batch, sessionKey) {
386
406
  };
387
407
  const closeClient = () => {
388
408
  const fs = clients[3];
389
- fs === null || fs === void 0 ? void 0 : fs.terminate();
409
+ if (fs) {
410
+ fs.terminate();
411
+ return;
412
+ }
413
+ const sp = clients[5];
414
+ if (sp) {
415
+ sp.close();
416
+ }
390
417
  };
391
418
  const getFamily = (data, row, family) => {
392
419
  const familyData = data[family];
@@ -419,14 +446,14 @@ async function executeBatchQuery(credential, batch, sessionKey) {
419
446
  };
420
447
  cacheValue.exclusiveOf = Array.isArray(ignoreCache) ? ignoreCache : undefined;
421
448
  let rows, queryString = '';
422
- if (product === 'firebase' || isFirebaseApp(credential)) {
449
+ if (product === "firebase" || isFirebaseApp(credential)) {
423
450
  if (!(0, types_1.isString)(query)) {
424
451
  closeClient();
425
452
  throw (0, util_1.formatError)(item, "Missing database query");
426
453
  }
427
454
  const orderBy = item.orderBy;
428
455
  if (useCache) {
429
- queryString = query + Module.asString(orderBy, true);
456
+ queryString = query + Cloud.asString(orderBy, true);
430
457
  if (!update && (rows = getCache(queryString))) {
431
458
  result[i] = rows;
432
459
  continue;
@@ -475,7 +502,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
475
502
  rows = [group && (0, types_1.isObject)(val) && (0, types_1.isObject)(val[group[0]]) ? val[group[0]] : val];
476
503
  }
477
504
  }
478
- else if (product === 'spanner' || !product && name && database && (query || table)) {
505
+ else if (product === "spanner" || !product && name && database && (query || table)) {
479
506
  const columns = (0, types_1.isPlainObject)(query) && query.columns || item.columns;
480
507
  if (!(query || table && columns)) {
481
508
  closeClient();
@@ -487,7 +514,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
487
514
  }
488
515
  const { updateType, options = {} } = item;
489
516
  if (useCache) {
490
- queryString = name + '_' + database + '_' + (table ? table + (columns ? Module.asString(columns, true) : '') : '') + Module.asString(query, true) + (limit > 0 ? limit : '');
517
+ queryString = name + '_' + database + (table ? '_' + table + (columns ? Cloud.asString(columns, true) : '') : '') + '_' + Cloud.asString(query, true) + (limit > 0 ? limit : '');
491
518
  if (!update && (rows = getCache(queryString))) {
492
519
  result[i] = rows;
493
520
  continue;
@@ -518,8 +545,12 @@ async function executeBatchQuery(credential, batch, sessionKey) {
518
545
  }
519
546
  else {
520
547
  transaction.runUpdate(update)
521
- .then(async () => transaction.commit().then(() => resolve()).catch(error => reject(error)))
522
- .catch(error => reject(error));
548
+ .then(async () => {
549
+ transaction.commit()
550
+ .then(() => resolve())
551
+ .catch((error) => reject(error));
552
+ })
553
+ .catch((error) => reject(error));
523
554
  }
524
555
  });
525
556
  });
@@ -527,12 +558,12 @@ async function executeBatchQuery(credential, batch, sessionKey) {
527
558
  const request = (0, types_1.isPlainObject)(query) ? query : { sql: query };
528
559
  request.json = true;
529
560
  if (limit > 0) {
530
- (request.gaxOptions || (request.gaxOptions = {})).maxResults = limit;
561
+ (request.gaxOptions ||= {}).maxResults = limit;
531
562
  }
532
563
  [rows] = await db.run(request);
533
564
  }
534
565
  }
535
- else if (product === 'bigtable' || !product && name && table && !database) {
566
+ else if (product === "bigtable" || !product && name && table && !database) {
536
567
  if (!name || !table) {
537
568
  closeClient();
538
569
  throw (0, util_1.formatError)(item, !name ? "Missing database name" : "Missing database table");
@@ -542,10 +573,10 @@ async function executeBatchQuery(credential, batch, sessionKey) {
542
573
  options.filter = query;
543
574
  }
544
575
  if (!id && limit > 0) {
545
- (options.gaxOptions || (options.gaxOptions = {})).maxResults = limit;
576
+ (options.gaxOptions ||= {}).maxResults = limit;
546
577
  }
547
578
  if (useCache) {
548
- queryString = name + '_' + table + '_' + ((0, types_1.isString)(id) ? id + ((0, types_1.isArray)(columns) ? '_' + Module.asString(columns, true) : '') : '') + Module.asString(options, true);
579
+ queryString = name + '_' + table + ((0, types_1.isString)(id) ? '_' + id + ((0, types_1.isArray)(columns) ? '_' + Cloud.asString(columns, true) : '') : '') + Cloud.asString(options, true);
549
580
  if (!(update && id) && (rows = getCache(queryString))) {
550
581
  result[i] = rows;
551
582
  continue;
@@ -576,7 +607,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
576
607
  });
577
608
  }
578
609
  }
579
- else if (product === 'bigquery' || !product && (!name && database && table || (0, types_1.isString)(query) || (0, types_1.isString)((_a = item.options) === null || _a === void 0 ? void 0 : _a.query))) {
610
+ else if (product === "bigquery" || !product && (!name && database && table || (0, types_1.isString)(query) || (0, types_1.isString)(item.options?.query))) {
580
611
  const { params, options = {} } = item;
581
612
  if ((0, types_1.isString)(query)) {
582
613
  options.query = query;
@@ -588,7 +619,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
588
619
  options.maxResults = limit;
589
620
  }
590
621
  if (useCache) {
591
- queryString = query + (database ? '_' + database + (table ? '_' + table : '') : '') + Module.asString(options, true);
622
+ queryString = query + (database ? '_' + database + (table ? '_' + table : '') : '') + Cloud.asString(options, true);
592
623
  if (!update && (rows = getCache(queryString))) {
593
624
  result[i] = rows;
594
625
  continue;
@@ -615,14 +646,14 @@ async function executeBatchQuery(credential, batch, sessionKey) {
615
646
  }
616
647
  [rows] = await job.getQueryResults();
617
648
  }
618
- else if (product === 'datastore' || !product && (item.keys || item.kind || query && !table && !id)) {
619
- const { keys, kind } = item;
649
+ else if (product === "datastore" || !product && (item.keys || item.kind || query && !table && !id)) {
650
+ const { keys, kind, options } = item;
620
651
  if (!keys && !kind && !Array.isArray(query)) {
621
652
  closeClient();
622
653
  throw (0, util_1.formatError)(item, "Missing database query");
623
654
  }
624
655
  if (useCache) {
625
- queryString = (keys ? Cloud.asString(keys, true) : (kind ? (name ? name + '_' : '') + Cloud.asString(kind, true) : '') + (limit > 0 ? '_' + limit : 0) + Cloud.asString(query, true)) + Cloud.asString(item.options, true);
656
+ queryString = (keys ? Cloud.asString(keys, true) : (kind ? (name ? '_' + name : '') + '_' + Cloud.asString(kind, true) : '') + '_' + Cloud.asString(query, true)) + (limit > 0 ? '_' + limit : 0) + (options ? Cloud.asString(options, true) : '');
626
657
  if (!update && (rows = getCache(queryString))) {
627
658
  result[i] = rows;
628
659
  continue;
@@ -634,7 +665,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
634
665
  if ((0, types_1.isPlainObject)(update)) {
635
666
  await db.save({ key: items, data: update });
636
667
  }
637
- rows = await db.get(items, item.options);
668
+ rows = await db.get(items, options);
638
669
  if (limit > 0 && rows.length > limit) {
639
670
  rows = rows.slice(0, limit);
640
671
  }
@@ -668,29 +699,30 @@ async function executeBatchQuery(credential, batch, sessionKey) {
668
699
  }
669
700
  if ((0, types_1.isPlainObject)(update)) {
670
701
  await new Promise((resolve, reject) => {
671
- db.runQuery(task.select('__key__'), item.options).then(entities => {
702
+ db.runQuery(task.select('__key__'), options).then(entities => {
672
703
  if ((0, types_1.isArray)(entities)) {
673
704
  const items = entities.map((entity) => db.key(entity[db.KEY]));
674
- db.save({ key: items, data: update }).then(() => resolve()).catch(err => reject(err));
705
+ db.save({ key: items, data: update }).then(() => resolve()).catch((err) => reject(err));
675
706
  }
676
707
  else {
677
708
  resolve();
678
709
  }
679
710
  })
680
- .catch(err => reject(err));
711
+ .catch((err) => reject(err));
681
712
  });
682
713
  }
683
- [rows] = await db.runQuery(task, item.options);
714
+ [rows] = await db.runQuery(task, options);
684
715
  }
685
716
  }
686
- else if (product === 'firestore' || !product && table) {
717
+ else if (product === "firestore" || !product && table) {
687
718
  if (!table) {
688
719
  closeClient();
689
720
  throw (0, util_1.formatError)(item, "Missing database table");
690
721
  }
691
722
  if (id) {
723
+ const options = Array.isArray(id) ? item.options : null;
692
724
  if (useCache) {
693
- queryString = table + '_' + id;
725
+ queryString = table + '_' + id + (options ? Cloud.asString(options, true) : '');
694
726
  if ((!update || Array.isArray(id)) && (rows = getCache(queryString))) {
695
727
  result[i] = rows;
696
728
  continue;
@@ -699,15 +731,42 @@ async function executeBatchQuery(credential, batch, sessionKey) {
699
731
  const db = createClient(item, 3);
700
732
  if (Array.isArray(id)) {
701
733
  const items = id.map(ref => db.doc(table + '/' + ref));
702
- if ((0, types_1.isPlainObject)(item.options)) {
703
- items.push(item.options);
734
+ if (options) {
735
+ items.push(options);
704
736
  }
705
737
  rows = (await db.getAll(...items)).filter(value => value.exists).map(value => value.data());
706
738
  }
707
739
  else {
708
740
  const doc = db.collection(table).doc(id);
709
741
  if ((0, types_1.isPlainObject)(update)) {
710
- await doc.update(update, { exists: true });
742
+ const pattern = /^__(delete|serverTimestamp|increment)(?:<(.+)>)?__$/;
743
+ for (const attr in update) {
744
+ const match = pattern.exec(attr);
745
+ if (match) {
746
+ const method = match[1];
747
+ switch (method) {
748
+ case 'delete':
749
+ case 'serverTimestamp':
750
+ update[attr] = firestore_1.FieldValue[method]();
751
+ break;
752
+ case 'increment':
753
+ update[attr] = firestore_1.FieldValue.increment(match[2] ? +match[2] : 1);
754
+ break;
755
+ }
756
+ }
757
+ }
758
+ switch (item.updateType) {
759
+ case 1:
760
+ await doc.create(update);
761
+ break;
762
+ case 2:
763
+ case 3:
764
+ await doc.set(update, { merge: item.updateType === 3 });
765
+ break;
766
+ default:
767
+ await doc.update(update);
768
+ break;
769
+ }
711
770
  }
712
771
  const data = (await doc.get()).data();
713
772
  if (data) {
@@ -717,7 +776,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
717
776
  }
718
777
  else if (Array.isArray(query)) {
719
778
  const orderBy = item.orderBy;
720
- if (useCache && (rows = getCache(queryString = table + '_' + Module.asString(query, true) + Module.asString(orderBy, true) + (limit > 0 ? limit : '')))) {
779
+ if (useCache && (rows = getCache(queryString = table + '_' + Cloud.asString(query, true) + '_' + Cloud.asString(orderBy, true) + (limit > 0 ? '_' + limit : '')))) {
721
780
  result[i] = rows;
722
781
  continue;
723
782
  }
@@ -729,33 +788,41 @@ async function executeBatchQuery(credential, batch, sessionKey) {
729
788
  switch (method) {
730
789
  case 'whereAnd':
731
790
  case 'whereOr':
732
- if (params.every(p => Array.isArray(p))) {
733
- db = db.where(firestore_1.Filter[method === 'whereAnd' ? 'and' : 'or'](...params.map((p) => firestore_1.Filter.where(p[0], p[1], p[2]))));
734
- }
735
- else {
791
+ if (!params.every(p => (0, types_1.isArray)(p))) {
736
792
  throw (0, types_1.errorMessage)(method, 'Conditionals are not in array format', Cloud.asString(params));
737
793
  }
794
+ db = db.where(firestore_1.Filter[method === 'whereAnd' ? 'and' : 'or'](...params.map((p) => firestore_1.Filter.where(p[0], p[1], p[2]))));
795
+ break;
796
+ case 'where':
797
+ case 'orderBy':
798
+ params[0] = asFieldPath(params[0]);
799
+ db = db[method].apply(db, params);
800
+ case 'select':
801
+ params.forEach((field, index) => {
802
+ params[index] = asFieldPath(field);
803
+ });
804
+ db = db.select.apply(db, params);
738
805
  break;
739
806
  case 'endAt':
740
807
  case 'endBefore':
741
808
  case 'limit':
742
809
  case 'limitToLast':
743
810
  case 'offset':
744
- case 'orderBy':
745
- case 'select':
746
811
  case 'startAfter':
747
812
  case 'startAt':
748
- case 'where':
749
813
  case 'withConverter':
750
814
  db = db[method].apply(db, params);
751
815
  break;
752
816
  }
753
817
  }
754
818
  }
755
- if ((0, types_1.isArray)(orderBy)) {
819
+ if (Array.isArray(orderBy)) {
756
820
  for (const order of orderBy) {
757
821
  if ((0, types_1.isArray)(order)) {
758
- db = db.orderBy(order[0], order[1]);
822
+ db = db.orderBy(asFieldPath(order[0]), order[1]);
823
+ }
824
+ else if ((0, types_1.isString)(order)) {
825
+ db = db.orderBy(order);
759
826
  }
760
827
  }
761
828
  }
@@ -786,7 +853,7 @@ function setPublicRead(acl, pathname, requested, service = 'gcp') {
786
853
  this.formatMessage(64, service, "Grant public-read", pathname, { ...Cloud.LOG_CLOUD_COMMAND });
787
854
  }
788
855
  })
789
- .catch(err => {
856
+ .catch((err) => {
790
857
  if (requested) {
791
858
  this.formatMessage(64, service, ["Unable to grant public-read", pathname], err, { ...Cloud.LOG_CLOUD_WARN });
792
859
  }
@@ -794,7 +861,6 @@ function setPublicRead(acl, pathname, requested, service = 'gcp') {
794
861
  }
795
862
  exports.setPublicRead = setPublicRead;
796
863
  async function setPredefinedAcl(target, value, bucket, pathname = '', metadata = {}, requested = true, service = 'gcp') {
797
- var _a;
798
864
  let revoke;
799
865
  if (metadata === true) {
800
866
  revoke = true;
@@ -809,7 +875,7 @@ async function setPredefinedAcl(target, value, bucket, pathname = '', metadata =
809
875
  items = [{ entity: 'allUsers' }, { entity: 'allAuthenticatedUsers', role: revoke ? undefined : 'READER' }];
810
876
  break;
811
877
  default: {
812
- const owner = (_a = metadata.owner) === null || _a === void 0 ? void 0 : _a.entity;
878
+ const owner = metadata.owner?.entity;
813
879
  let acl = metadata.acl;
814
880
  if ((0, types_1.isArray)(acl)) {
815
881
  items = [];
@@ -819,7 +885,7 @@ async function setPredefinedAcl(target, value, bucket, pathname = '', metadata =
819
885
  items = [{ entity: 'allUsers' }, { entity: 'allAuthenticatedUsers' }];
820
886
  }
821
887
  switch (value) {
822
- case 'private': {
888
+ case "private": {
823
889
  const owners = new Set(acl.filter(item => item.role === 'OWNER' && item.entity).map(item => item.entity));
824
890
  if (owner) {
825
891
  owners.add(owner);
@@ -834,7 +900,7 @@ async function setPredefinedAcl(target, value, bucket, pathname = '', metadata =
834
900
  }
835
901
  break;
836
902
  }
837
- case 'projectPrivate':
903
+ case "projectPrivate":
838
904
  for (const user of acl) {
839
905
  const entity = user.entity;
840
906
  if (entity) {
@@ -843,7 +909,7 @@ async function setPredefinedAcl(target, value, bucket, pathname = '', metadata =
843
909
  }
844
910
  }
845
911
  break;
846
- case 'bucketOwnerRead':
912
+ case "bucketOwnerRead":
847
913
  if (bucket && owner) {
848
914
  for (const user of acl) {
849
915
  const entity = user.entity;
@@ -852,7 +918,7 @@ async function setPredefinedAcl(target, value, bucket, pathname = '', metadata =
852
918
  }
853
919
  }
854
920
  }
855
- case 'bucketOwnerFullControl':
921
+ case "bucketOwnerFullControl":
856
922
  if (bucket && owner) {
857
923
  items.push({ entity: owner, role: 'OWNER' });
858
924
  }
@@ -867,7 +933,7 @@ async function setPredefinedAcl(target, value, bucket, pathname = '', metadata =
867
933
  this.formatMessage(64, service, [`Unable to ${revoke ? 'revoke' : 'grant'} ` + value, bucket && pathname ? bucket.name + '/' + pathname : bucket ? bucket.name : pathname], errors[0], { ...Cloud.LOG_CLOUD_WARN });
868
934
  }
869
935
  else if (requested && (bucket || pathname)) {
870
- this.formatMessage(64, service, [(revoke ? 'Revoke' : 'Grant') + ' ' + value, bucket === null || bucket === void 0 ? void 0 : bucket.name], pathname, { ...Cloud.LOG_CLOUD_COMMAND });
936
+ this.formatMessage(64, service, [(revoke ? 'Revoke' : 'Grant') + ' ' + value, bucket?.name], pathname, { ...Cloud.LOG_CLOUD_COMMAND });
871
937
  }
872
938
  });
873
939
  }
@@ -919,13 +985,16 @@ function getProjectId(credential, cache) {
919
985
  const id = require(pathname).project_id;
920
986
  if ((0, types_1.isString)(id)) {
921
987
  projectId = id;
922
- credential.projectId = projectId;
923
988
  }
924
989
  }
925
990
  catch {
926
991
  }
992
+ credential.projectId = projectId || (projectId = process.env.GCLOUD_PROJECT);
927
993
  }
928
994
  }
929
995
  return projectId;
930
996
  }
931
997
  exports.getProjectId = getProjectId;
998
+ exports.CLOUD_UPLOAD_STREAM = true;
999
+ exports.CLOUD_UPLOAD_CHUNK = true;
1000
+ exports.CLOUD_DOWNLOAD_CHUNK = true;
package/download/index.js CHANGED
@@ -3,20 +3,18 @@ const path = require("path");
3
3
  const fs = require("fs");
4
4
  const https = require("https");
5
5
  const types_1 = require("@e-mc/types");
6
- const Module = require("@e-mc/module");
7
6
  const Cloud = require("@e-mc/cloud");
8
7
  const client_1 = require("@pi-r/gcp");
9
8
  module.exports = function download(credential, service = 'gcp') {
10
9
  const storage = client_1.createStorageClient.call(this, credential);
11
10
  return (data, callback) => {
12
11
  const { bucket: Bucket, download: target } = data;
13
- const Key = target.filename;
14
- const firebase = (0, client_1.isFirebaseApp)(credential, true, true);
12
+ const Key = target.keyname || target.filename;
15
13
  let tempDir;
16
- const downloadResponse = (err, url) => {
14
+ const downloadResponse = (err, url = null) => {
17
15
  callback(err, url);
18
16
  if (tempDir) {
19
- queueMicrotask(() => Module.removeDir(tempDir));
17
+ queueMicrotask(() => Cloud.removeDir(tempDir));
20
18
  }
21
19
  };
22
20
  if (!Bucket || !Key) {
@@ -24,13 +22,13 @@ module.exports = function download(credential, service = 'gcp') {
24
22
  return;
25
23
  }
26
24
  if (!(tempDir = this.getTempDir({ uuidDir: true }))) {
27
- downloadResponse(new Error("Unable to create temp directory"));
25
+ downloadResponse((0, types_1.errorValue)("Unable to create temp directory", service));
28
26
  return;
29
27
  }
30
- const location = Module.joinPath(Bucket, Key);
31
- const destination = path.join(tempDir, path.basename(Key));
28
+ const location = Cloud.joinPath(Bucket, Key);
29
+ const destination = path.join(tempDir, path.basename(target.filename || Key));
32
30
  const deleteMessage = () => this.formatMessage(64, service, "Delete success", location, { ...Cloud.LOG_CLOUD_DELETE });
33
- if (firebase) {
31
+ if ((0, client_1.isFirebaseApp)(credential, true, true)) {
34
32
  const { ref, getDownloadURL, deleteObject } = require('@firebase/storage');
35
33
  const objectRef = ref(storage, Key);
36
34
  getDownloadURL(objectRef).then(url => {
@@ -44,7 +42,7 @@ module.exports = function download(credential, service = 'gcp') {
44
42
  if (target.deleteObject) {
45
43
  deleteObject(objectRef)
46
44
  .then(() => deleteMessage())
47
- .catch(err => this.formatFail(64, service, ["Delete failed", location], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: !!target.active }));
45
+ .catch((err) => this.formatFail(64, service, ["Delete failed", location], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: !!target.active }));
48
46
  }
49
47
  })
50
48
  .on('error', err => downloadResponse(err)));
@@ -54,26 +52,36 @@ module.exports = function download(credential, service = 'gcp') {
54
52
  }
55
53
  });
56
54
  });
55
+ return;
57
56
  }
58
- else {
59
- const bucket = storage.bucket(Bucket);
60
- const file = bucket.file(Key, { generation: target.versionId });
61
- file.download({ destination })
62
- .then(() => {
63
- downloadResponse(null, destination);
64
- const deleteObject = target.deleteObject;
65
- if (deleteObject) {
66
- file.delete((0, types_1.isPlainObject)(deleteObject) ? deleteObject : { ignoreNotFound: true }, err => {
67
- if (!err) {
68
- deleteMessage();
69
- }
70
- else {
71
- this.formatFail(64, service, ["Delete failed", location], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: !!target.active });
72
- }
73
- });
74
- }
75
- })
76
- .catch(err => downloadResponse(err));
57
+ const { flags = 0 } = target;
58
+ const bucket = storage.bucket(Bucket);
59
+ const file = bucket.file(Key, { generation: target.versionId });
60
+ const chunkSize = flags & 4 ? (0, types_1.alignSize)(target.chunkSize, 1024) : 0;
61
+ let manager;
62
+ if (chunkSize > 0) {
63
+ const { TransferManager } = require('@google-cloud/storage');
64
+ let concurrencyLimit = target.chunkLimit;
65
+ if (!concurrencyLimit && target.options) {
66
+ ({ concurrencyLimit } = target.options);
67
+ }
68
+ manager = new TransferManager(bucket).downloadFileInChunks(file, { destination, chunkSizeBytes: chunkSize, concurrencyLimit });
77
69
  }
70
+ (manager || file.download({ destination }))
71
+ .then(() => {
72
+ downloadResponse(null, destination);
73
+ const deleteObject = target.deleteObject;
74
+ if (deleteObject) {
75
+ file.delete((0, types_1.isObject)(deleteObject) ? deleteObject : { ignoreNotFound: true }, err => {
76
+ if (!err) {
77
+ deleteMessage();
78
+ }
79
+ else {
80
+ this.formatFail(64, service, ["Delete failed", location], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: !!target.active });
81
+ }
82
+ });
83
+ }
84
+ })
85
+ .catch((err) => downloadResponse(err));
78
86
  };
79
87
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-r/gcp",
3
- "version": "0.6.7",
3
+ "version": "0.7.1",
4
4
  "description": "Google (GCP) cloud functions for E-mc.",
5
5
  "main": "client/index.js",
6
6
  "publishConfig": {
@@ -20,10 +20,10 @@
20
20
  "license": "MIT",
21
21
  "homepage": "https://github.com/anpham6/pi-r#readme",
22
22
  "dependencies": {
23
- "@e-mc/cloud": "^0.8.8",
24
- "@e-mc/module": "^0.8.8",
25
- "@e-mc/types": "^0.8.8",
26
- "@google-cloud/firestore": "^7.6.0",
27
- "@google-cloud/storage": "^7.9.0"
23
+ "@e-mc/cloud": "^0.9.2",
24
+ "@e-mc/module": "^0.9.2",
25
+ "@e-mc/types": "^0.9.2",
26
+ "@google-cloud/firestore": "^7.7.0",
27
+ "@google-cloud/storage": "^7.11.1"
28
28
  }
29
29
  }
@@ -0,0 +1,36 @@
1
+ import type { CloudDatabase, CloudStorage } from '@e-mc/types/lib/cloud';
2
+
3
+ import type { StorageOptions } from '@google-cloud/storage';
4
+ import type { PathType } from '@google-cloud/datastore';
5
+ import type { entity } from '@google-cloud/datastore/build/src/entity';
6
+ import type { FirebaseOptions as IFirebaseOptions } from '@firebase/app';
7
+
8
+ // @ts-ignore
9
+ import type { GoogleAuthOptions } from 'google-auth-library';
10
+
11
+ export type GCPStorage = CloudStorage<GCPStorageCredential, "gcp | gcloud">;
12
+
13
+ export interface GCPStorageCredential extends StorageOptions, IFirebaseOptions {}
14
+
15
+ export interface GCPDatabaseQuery<T = PlainObject> extends Omit<CloudDatabase<unknown, T, unknown, unknown[] | StandardMap, GCPDatabaseCredential>, "id"> {
16
+ source: "cloud";
17
+ service: "gcp" | "gcloud";
18
+ product?: "firestore" | "firebase" | "bigquery" | "bigtable" | "datastore" | "spanner";
19
+ database?: string;
20
+ id?: ArrayOf<string>;
21
+ updateType?: 0 | 1 | 2 | 3;
22
+ columns?: string[];
23
+ keys?: ArrayOf<DatastoreKey>;
24
+ kind?: ArrayOf<string>;
25
+ orderBy?: unknown[][];
26
+ }
27
+
28
+ export type GCPDatabaseCredential = GoogleAuthOptions;
29
+
30
+ export interface FirebaseOptions extends IFirebaseOptions {
31
+ product?: "firebase";
32
+ admin?: boolean;
33
+ }
34
+
35
+ export type DatastoreKey = string | PathType[] | entity.KeyOptions;
36
+ export type BucketAcl = "authenticatedRead" | "private" | "projectPrivate" | "publicRead" | "publicReadWrite" | "bucketAccessUniform" | "bucketAccessACL";
package/upload/index.js CHANGED
@@ -1,22 +1,21 @@
1
1
  "use strict";
2
2
  const path = require("path");
3
+ const fs = require("fs");
4
+ const stream = require("stream");
3
5
  const util_1 = require("@e-mc/cloud/util");
4
6
  const types_1 = require("@e-mc/types");
5
- const Module = require("@e-mc/module");
6
7
  const Cloud = require("@e-mc/cloud");
7
8
  const client_1 = require("@pi-r/gcp");
8
9
  const BUCKET_SESSION = new Set();
9
10
  const BUCKET_RESPONSE = {};
10
- const getBucketKey = (credential, bucket, acl = '') => Module.asString(credential, true) + bucket + '_' + acl;
11
+ const getBucketKey = (credential, bucket, acl = '') => Cloud.asString(credential, true) + bucket + '_' + acl;
11
12
  module.exports = function upload(credential, service = 'gcp') {
12
13
  const storage = client_1.createStorageClient.call(this, credential);
13
14
  return async (data, callback) => {
14
- var _a;
15
- var _b;
16
15
  const firebase = (0, client_1.isFirebaseApp)(credential, true, true);
17
16
  const { bucket, localUri } = data;
18
- const { pathname = '', fileGroup, contentType, metadata, endpoint, active, publicRead, acl, admin = {}, overwrite, options } = data.upload;
19
- let filename = data.upload.filename || path.basename(localUri), bucketClient, bucketKey, listFiles;
17
+ const { pathname = '', flags = 0, fileGroup, contentType, metadata, endpoint, active, publicRead, acl, admin = {}, overwrite, options } = data.upload;
18
+ let filename = data.upload.filename || path.basename(localUri), chunkSizeBytes = 0, bucketClient, bucketKey, listFiles;
20
19
  const uploadResponse = (err, url) => {
21
20
  if (!firebase) {
22
21
  BUCKET_SESSION.delete(bucket);
@@ -43,8 +42,8 @@ module.exports = function upload(credential, service = 'gcp') {
43
42
  else {
44
43
  const configBucket = admin.configBucket;
45
44
  if (!BUCKET_SESSION.has(bucket)) {
46
- const bucketAcl = admin.publicRead ? 'publicRead' : admin.acl;
47
- const response = BUCKET_RESPONSE[_b = bucketKey = getBucketKey(credential, bucket, bucketAcl)] || (BUCKET_RESPONSE[_b] = client_1.createBucketV2.call(this, credential, bucket, bucketAcl, (configBucket === null || configBucket === void 0 ? void 0 : configBucket.create) || (0, client_1.createBucketRequest)(credential)));
45
+ const bucketAcl = admin.publicRead ? "publicRead" : admin.acl;
46
+ const response = BUCKET_RESPONSE[bucketKey = getBucketKey(credential, bucket, bucketAcl)] ||= client_1.createBucketV2.call(this, credential, bucket, bucketAcl, configBucket?.create);
48
47
  if (!await response) {
49
48
  uploadResponse(null);
50
49
  return;
@@ -52,14 +51,49 @@ module.exports = function upload(credential, service = 'gcp') {
52
51
  BUCKET_SESSION.add(bucket);
53
52
  }
54
53
  bucketClient = storage.bucket(bucket);
55
- const retentionPolicy = configBucket === null || configBucket === void 0 ? void 0 : configBucket.retentionPolicy;
56
- if (typeof retentionPolicy === 'number') {
57
- bucketClient.setRetentionPeriod(retentionPolicy)
58
- .then(([response]) => {
59
- var _a;
60
- this.formatMessage(64, service, ["Bucket configured" + ' (retention policy)', bucket], (_a = response.retentionPolicy) === null || _a === void 0 ? void 0 : _a.effectiveTime, { ...Cloud.LOG_CLOUD_COMMAND });
61
- })
62
- .catch(err => addLog(err));
54
+ if (configBucket) {
55
+ let { cors, lifecycle, retentionPolicy } = configBucket;
56
+ const commandMessage = (feature, message) => this.formatMessage(64, service, ["Bucket configured" + ` (${feature})`, bucket], message, { ...Cloud.LOG_CLOUD_COMMAND });
57
+ if (typeof retentionPolicy === 'number') {
58
+ bucketClient.setRetentionPeriod(retentionPolicy)
59
+ .then(([response]) => commandMessage('Retention Policy', response.retentionPolicy?.effectiveTime))
60
+ .catch((err) => addLog(err));
61
+ }
62
+ if ((0, types_1.isObject)(cors)) {
63
+ bucketClient.setCorsConfiguration(Array.isArray(cors) ? cors : [cors])
64
+ .then(([response]) => {
65
+ const length = response.cors?.length;
66
+ commandMessage('CORS', length ? length + ' rules' : null);
67
+ })
68
+ .catch((err) => addLog(err));
69
+ }
70
+ if ((0, types_1.isObject)(lifecycle)) {
71
+ let append;
72
+ if (Array.isArray(lifecycle)) {
73
+ if (lifecycle.length === 0) {
74
+ append = false;
75
+ }
76
+ else {
77
+ const arg = lifecycle[lifecycle.length - 1];
78
+ if (typeof arg === 'boolean') {
79
+ append = arg;
80
+ lifecycle = lifecycle.slice(0, lifecycle.length - 1);
81
+ }
82
+ }
83
+ }
84
+ bucketClient.addLifecycleRule(lifecycle, { append })
85
+ .then(([response]) => {
86
+ const length = response.lifecycle?.rule?.length;
87
+ commandMessage('Lifecycle', length ? length + ' rules' : null);
88
+ })
89
+ .catch((err) => addLog(err));
90
+ }
91
+ }
92
+ if (flags & 4) {
93
+ const chunkSize = (0, types_1.alignSize)(data.upload.chunkSize, 1024);
94
+ if (chunkSize > 0) {
95
+ chunkSizeBytes = Math.max(chunkSize, 8388608);
96
+ }
63
97
  }
64
98
  }
65
99
  if (!overwrite && (!listFiles || listFiles.length)) {
@@ -73,7 +107,7 @@ module.exports = function upload(credential, service = 'gcp') {
73
107
  break;
74
108
  }
75
109
  }
76
- const name = pathname ? Module.joinPath(pathname, filename) : filename;
110
+ const name = pathname ? Cloud.joinPath(pathname, filename) : filename;
77
111
  if (firebase) {
78
112
  exists = listFiles.includes(name);
79
113
  }
@@ -85,16 +119,94 @@ module.exports = function upload(credential, service = 'gcp') {
85
119
  this.formatMessage(64, service, ["File renamed", current], filename, { ...Cloud.LOG_CLOUD_WARN });
86
120
  }
87
121
  }
88
- const getURL = (value) => endpoint ? Module.joinPath(endpoint, value) : Module.joinPath("https://storage.googleapis.com", bucket, value);
122
+ const getURL = (value) => endpoint ? Cloud.joinPath(endpoint, value) : Cloud.joinPath("https://storage.googleapis.com", bucket, value);
89
123
  const Key = [filename];
90
124
  const Body = [data.buffer];
125
+ const Path = [];
126
+ const Stream = [];
91
127
  const ContentType = [contentType];
92
- if (fileGroup) {
93
- const [key, body, type] = (0, util_1.createKeyAndBody)(filename, fileGroup, addLog);
128
+ if (chunkSizeBytes > 0) {
129
+ const main = Body[0];
130
+ if (main.length > chunkSizeBytes) {
131
+ try {
132
+ fs.writeFileSync(localUri, main);
133
+ Path[0] = localUri;
134
+ }
135
+ catch {
136
+ if (flags & 2) {
137
+ Stream[0] = stream.Readable.from(main, { highWaterMark: chunkSizeBytes });
138
+ }
139
+ }
140
+ }
141
+ else if (main.length === 0) {
142
+ try {
143
+ if (fs.statSync(localUri).size > chunkSizeBytes) {
144
+ Path[0] = localUri;
145
+ }
146
+ else if (flags & 2) {
147
+ Stream[0] = fs.createReadStream(localUri, { highWaterMark: chunkSizeBytes, signal: this.signal });
148
+ }
149
+ else {
150
+ Body[0] = fs.readFileSync(localUri);
151
+ }
152
+ }
153
+ catch (err) {
154
+ uploadResponse(err);
155
+ return;
156
+ }
157
+ }
158
+ if (fileGroup) {
159
+ const [key, body, type] = (0, util_1.createKeyAndBody)(filename, fileGroup, chunkSizeBytes, addLog, flags);
160
+ Key.push(...key);
161
+ ContentType.push(...type);
162
+ for (let i = 0; i < body.length; ++i) {
163
+ const item = body[i];
164
+ if (typeof item === 'string') {
165
+ Path[i + 1] = item;
166
+ }
167
+ else if (Buffer.isBuffer(item)) {
168
+ Body[i + 1] = item;
169
+ }
170
+ else {
171
+ Stream[i + 1] = item;
172
+ }
173
+ }
174
+ }
175
+ }
176
+ else if ((flags & 2) && !firebase) {
177
+ try {
178
+ Stream.push(data.buffer.length ? stream.Readable.from(data.buffer) : fs.createReadStream(localUri, { signal: this.signal }));
179
+ if (fileGroup) {
180
+ const [key, body, type] = (0, util_1.createKeyAndBody)(filename, fileGroup, 0, addLog, 2);
181
+ Key.push(...key);
182
+ Stream.push(...body);
183
+ ContentType.push(...type);
184
+ }
185
+ }
186
+ catch (err) {
187
+ uploadResponse(err);
188
+ return;
189
+ }
190
+ }
191
+ else if (fileGroup) {
192
+ const [key, body, type] = (0, util_1.createKeyAndBody)(filename, fileGroup, 0, addLog);
94
193
  Key.push(...key);
95
194
  Body.push(...body);
96
195
  ContentType.push(...type);
97
196
  }
197
+ let headers, concurrencyLimit, maxQueueSize;
198
+ if (options) {
199
+ ({ headers, concurrencyLimit, maxQueueSize } = options);
200
+ if (headers !== undefined) {
201
+ delete options.headers;
202
+ }
203
+ if (concurrencyLimit !== undefined) {
204
+ delete options.concurrencyLimit;
205
+ }
206
+ if (maxQueueSize !== undefined) {
207
+ delete options.maxQueueSize;
208
+ }
209
+ }
98
210
  for (let i = 0; i < Key.length; ++i) {
99
211
  const first = i === 0;
100
212
  if (this.aborted) {
@@ -103,12 +215,21 @@ module.exports = function upload(credential, service = 'gcp') {
103
215
  }
104
216
  return;
105
217
  }
106
- const destination = pathname ? Module.joinPath(pathname, Key[i]) : Key[i];
218
+ const destination = pathname ? Cloud.joinPath(pathname, Key[i]) : Key[i];
107
219
  if (firebase) {
108
220
  const { ref, uploadBytes } = require('@firebase/storage');
109
221
  const params = { ...options };
110
222
  if (first) {
111
- params.contentType || (params.contentType = ContentType[i]);
223
+ if (Body[0].length === 0) {
224
+ try {
225
+ Body[0] = fs.readFileSync(localUri);
226
+ }
227
+ catch (err) {
228
+ uploadResponse(err);
229
+ return;
230
+ }
231
+ }
232
+ params.contentType ||= ContentType[i];
112
233
  if (metadata) {
113
234
  params.customMetadata = metadata;
114
235
  }
@@ -124,7 +245,7 @@ module.exports = function upload(credential, service = 'gcp') {
124
245
  uploadResponse(null, url);
125
246
  }
126
247
  })
127
- .catch(err => {
248
+ .catch((err) => {
128
249
  if (first) {
129
250
  uploadResponse(err);
130
251
  }
@@ -138,14 +259,14 @@ module.exports = function upload(credential, service = 'gcp') {
138
259
  const readable = publicRead || active && publicRead !== false && publicRead !== 0 && !acl;
139
260
  let ACL, revoke, predefined;
140
261
  if (first) {
141
- params.contentType || (params.contentType = ContentType[i]);
262
+ params.contentType ||= ContentType[i];
142
263
  if (readable) {
143
- ACL = 'publicRead';
264
+ ACL = "publicRead";
144
265
  }
145
266
  else {
146
267
  predefined = true;
147
268
  }
148
- if (typeof metadata === 'object') {
269
+ if ((0, types_1.isObject)(metadata)) {
149
270
  params.metadata = metadata;
150
271
  }
151
272
  }
@@ -153,7 +274,7 @@ module.exports = function upload(credential, service = 'gcp') {
153
274
  params.contentType = ContentType[i];
154
275
  if (!params.predefinedAcl) {
155
276
  if (readable) {
156
- ACL = 'publicRead';
277
+ ACL = "publicRead";
157
278
  }
158
279
  else {
159
280
  predefined = true;
@@ -162,26 +283,47 @@ module.exports = function upload(credential, service = 'gcp') {
162
283
  }
163
284
  if (predefined) {
164
285
  if (publicRead === 0) {
165
- ACL = 'publicRead';
286
+ ACL = "publicRead";
166
287
  revoke = true;
167
288
  }
168
289
  if (acl && (!revoke || acl !== ACL)) {
169
290
  params.predefinedAcl = acl;
170
291
  }
171
292
  }
172
- (_a = params.resumable) !== null && _a !== void 0 ? _a : (params.resumable = false);
173
293
  const file = bucketClient.file(destination);
174
- file.save(Body[i], params).then(async () => {
294
+ let uploadClient;
295
+ if (Path[i]) {
296
+ const { TransferManager } = require('@google-cloud/storage');
297
+ uploadClient = new TransferManager(bucketClient).uploadFileInChunks(Path[i], { uploadName: destination, chunkSizeBytes, headers, concurrencyLimit: data.upload.chunkLimit || concurrencyLimit, maxQueueSize });
298
+ }
299
+ else {
300
+ params.resumable ??= false;
301
+ if (Stream[i]) {
302
+ if (chunkSizeBytes > 0) {
303
+ params.chunkSize = chunkSizeBytes;
304
+ }
305
+ uploadClient = new Promise((resolve, reject) => {
306
+ Stream[i].pipe(file.createWriteStream(params))
307
+ .on('finish', resolve)
308
+ .on('error', reject);
309
+ });
310
+ }
311
+ }
312
+ (uploadClient || file.save(Body[i], params))
313
+ .then(async () => {
175
314
  const url = getURL(file.name);
176
315
  this.formatMessage(64, service, "Upload success", url, { ...Cloud.LOG_CLOUD_UPLOAD });
177
316
  if (first) {
178
317
  uploadResponse(null, url);
179
318
  }
319
+ if (Path[i]) {
320
+ file.setMetadata(params).catch((err) => addLog(err));
321
+ }
180
322
  if (ACL) {
181
323
  client_1.setPredefinedAcl.call(this, file.acl, ACL, file.bucket, file.name, revoke || (await file.getMetadata())[0], true);
182
324
  }
183
325
  })
184
- .catch(err => {
326
+ .catch((err) => {
185
327
  if (first) {
186
328
  uploadResponse(err);
187
329
  }