@pi-r/gcp 0.7.3 → 0.8.0

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/client/index.js CHANGED
@@ -1,11 +1,29 @@
1
1
  "use strict";
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;
2
+ exports.CLOUD_DOWNLOAD_CHUNK = exports.CLOUD_UPLOAD_CHUNK = exports.CLOUD_UPLOAD_STREAM = void 0;
3
+ exports.isFirebaseApp = isFirebaseApp;
4
+ exports.validateStorage = validateStorage;
5
+ exports.validateDatabase = validateDatabase;
6
+ exports.createStorageClient = createStorageClient;
7
+ exports.createDatabaseClient = createDatabaseClient;
8
+ exports.createBucket = createBucket;
9
+ exports.createBucketV2 = createBucketV2;
10
+ exports.setBucketPolicy = setBucketPolicy;
11
+ exports.setBucketTagging = setBucketTagging;
12
+ exports.setBucketWebsite = setBucketWebsite;
13
+ exports.deleteObjects = deleteObjects;
14
+ exports.deleteObjectsV2 = deleteObjectsV2;
15
+ exports.executeQuery = executeQuery;
16
+ exports.executeBatchQuery = executeBatchQuery;
17
+ exports.setPublicRead = setPublicRead;
18
+ exports.setPredefinedAcl = setPredefinedAcl;
19
+ exports.createBucketRequest = createBucketRequest;
20
+ exports.getProjectId = getProjectId;
3
21
  const path = require("path");
4
- const storage = require("@google-cloud/storage");
5
22
  const firestore_1 = require("@google-cloud/firestore");
23
+ const storage_1 = require("@google-cloud/storage");
24
+ const Cloud = require("@e-mc/cloud");
6
25
  const util_1 = require("@e-mc/cloud/util");
7
26
  const types_1 = require("@e-mc/types");
8
- const Cloud = require("@e-mc/cloud");
9
27
  const FIREBASE_DB = {};
10
28
  const FIREBASE_STORAGE = {};
11
29
  const ADMIN_DB = {};
@@ -109,15 +127,12 @@ const hasGoogleAuth = (credential) => (0, types_1.isString)(credential.keyFilena
109
127
  function isFirebaseApp(credential, store, admin) {
110
128
  return !!(credential.apiKey && credential.authDomain && (store || credential.databaseURL) || credential.product === "firebase" && process.env.GOOGLE_APPLICATION_CREDENTIALS) && (!admin || !credential.admin);
111
129
  }
112
- exports.isFirebaseApp = isFirebaseApp;
113
130
  function validateStorage(credential) {
114
131
  return hasGoogleAuth(credential) || isFirebaseApp(credential, true);
115
132
  }
116
- exports.validateStorage = validateStorage;
117
133
  function validateDatabase(credential, data) {
118
134
  return hasGoogleAuth(credential) && !!(data.product || data.database || data.table || data.query || data.id || data.keys || data.kind || data.options?.query) || isFirebaseApp(credential);
119
135
  }
120
- exports.validateDatabase = validateDatabase;
121
136
  function createStorageClient(credential, bucket) {
122
137
  if (isFirebaseApp(credential, true)) {
123
138
  let packageName = '';
@@ -134,9 +149,8 @@ function createStorageClient(credential, bucket) {
134
149
  }
135
150
  }
136
151
  getProjectId(credential, false);
137
- return new storage.Storage(credential);
152
+ return new storage_1.Storage(credential);
138
153
  }
139
- exports.createStorageClient = createStorageClient;
140
154
  function createDatabaseClient(credential, data) {
141
155
  let packageName = '';
142
156
  try {
@@ -171,11 +185,9 @@ function createDatabaseClient(credential, data) {
171
185
  }
172
186
  return new firestore_1.Firestore(credential);
173
187
  }
174
- exports.createDatabaseClient = createDatabaseClient;
175
188
  async function createBucket(credential, bucket, publicRead, service = 'gcp') {
176
189
  return createBucketV2.call(this, credential, bucket, publicRead ? 'publicRead' : undefined, createBucketRequest(credential), service);
177
190
  }
178
- exports.createBucket = createBucket;
179
191
  async function createBucketV2(credential, bucket, acl, options, service = 'gcp') {
180
192
  if (isFirebaseApp(credential, true, true)) {
181
193
  return false;
@@ -203,7 +215,6 @@ async function createBucketV2(credential, bucket, acl, options, service = 'gcp')
203
215
  return false;
204
216
  });
205
217
  }
206
- exports.createBucketV2 = createBucketV2;
207
218
  async function setBucketPolicy(credential, bucket, options, service = 'gcp') {
208
219
  if (isFirebaseApp(credential, true, true)) {
209
220
  return false;
@@ -247,17 +258,16 @@ async function setBucketPolicy(credential, bucket, options, service = 'gcp') {
247
258
  break;
248
259
  }
249
260
  }
250
- if (options.acl && (options.acl = options.acl.filter(user => (0, types_1.isString)(user.entity))).length) {
261
+ if (options.acl && (options.acl = options.acl.filter(user => (0, types_1.isString)(user.entity))).length > 0) {
251
262
  errors.push(...await updatePredefinedAcl(client.acl, options.acl, options.metadata));
252
263
  }
253
- if (errors.length) {
264
+ if (errors.length > 0) {
254
265
  this.formatFail(64, service, ["Unable to update bucket policy", bucket], errors[0], { ...Cloud.LOG_CLOUD_FAIL, fatal: false });
255
266
  return false;
256
267
  }
257
268
  this.formatMessage(64, service, ["Bucket ACL configured", bucket], (0, types_1.isString)(acl) ? acl : '', { ...Cloud.LOG_CLOUD_COMMAND });
258
269
  return true;
259
270
  }
260
- exports.setBucketPolicy = setBucketPolicy;
261
271
  async function setBucketTagging(credential, bucket, labels, service = 'gcp') {
262
272
  if (isFirebaseApp(credential, true, true) || !(0, types_1.isPlainObject)(labels)) {
263
273
  return false;
@@ -284,7 +294,6 @@ async function setBucketTagging(credential, bucket, labels, service = 'gcp') {
284
294
  return false;
285
295
  });
286
296
  }
287
- exports.setBucketTagging = setBucketTagging;
288
297
  async function setBucketWebsite(credential, bucket, options, service = 'gcp') {
289
298
  if (isFirebaseApp(credential, true, true)) {
290
299
  return false;
@@ -307,11 +316,9 @@ async function setBucketWebsite(credential, bucket, options, service = 'gcp') {
307
316
  return false;
308
317
  });
309
318
  }
310
- exports.setBucketWebsite = setBucketWebsite;
311
319
  async function deleteObjects(credential, Bucket, service) {
312
320
  return deleteObjectsV2.call(this, credential, Bucket, true, service);
313
321
  }
314
- exports.deleteObjects = deleteObjects;
315
322
  async function deleteObjectsV2(credential, bucket, recursive = true, service = 'gcp') {
316
323
  const instance = createStorageClient.call(this, credential, bucket);
317
324
  const errors = [];
@@ -322,10 +329,10 @@ async function deleteObjectsV2(credential, bucket, recursive = true, service = '
322
329
  await (async function recurse(prefix) {
323
330
  try {
324
331
  const { items, prefixes } = await listAll(ref(instance, prefix));
325
- if (items.length) {
332
+ if (items.length > 0) {
326
333
  files.push(...items.map(value => value.fullPath));
327
334
  }
328
- if (recursive && prefixes.length) {
335
+ if (recursive && prefixes.length > 0) {
329
336
  for (const { name } of prefixes) {
330
337
  await recurse(Cloud.joinPath(prefix, name));
331
338
  }
@@ -335,7 +342,7 @@ async function deleteObjectsV2(credential, bucket, recursive = true, service = '
335
342
  errors.push(err);
336
343
  }
337
344
  })('');
338
- if (files.length) {
345
+ if (files.length > 0) {
339
346
  promise = Promise.allSettled(files.map(async (value) => deleteObject(ref(instance, value))));
340
347
  }
341
348
  }
@@ -343,27 +350,31 @@ async function deleteObjectsV2(credential, bucket, recursive = true, service = '
343
350
  const client = instance.bucket(bucket);
344
351
  if (await hasBucket(client)) {
345
352
  if (recursive) {
346
- return client.deleteFiles({ force: true }).then(() => this.formatMessage(64, service, "Bucket emptied" + ' (recursive)', bucket, { ...Cloud.LOG_CLOUD_COMMAND }));
353
+ return client.deleteFiles({ force: true }).then(() => {
354
+ this.formatMessage(64, service, "Bucket emptied" + ' (recursive)', bucket, { ...Cloud.LOG_CLOUD_COMMAND });
355
+ });
347
356
  }
348
357
  const tasks = [];
349
358
  try {
350
359
  const result = await client.getFiles();
351
360
  for (const { name } of result[0]) {
352
361
  if (!name.includes('/')) {
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 })));
362
+ tasks.push(client.file(name).delete({ ignoreNotFound: true }).catch((err) => {
363
+ this.formatFail(64, service, ["Delete failed", name], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: false });
364
+ }));
354
365
  }
355
366
  }
356
367
  }
357
368
  catch (err) {
358
369
  errors.push(err);
359
370
  }
360
- if (tasks.length) {
371
+ if (tasks.length > 0) {
361
372
  promise = Promise.allSettled(tasks);
362
373
  }
363
374
  }
364
375
  }
365
376
  const checkErrors = () => {
366
- if (errors.length) {
377
+ if (errors.length > 0) {
367
378
  this.formatFail(64, service, ["Unable to empty bucket" + (recursive ? ' (recursive)' : ''), errors.length + ' errors'], errors[0], { ...Cloud.LOG_CLOUD_FAIL, fatal: false });
368
379
  return true;
369
380
  }
@@ -383,11 +394,9 @@ async function deleteObjectsV2(credential, bucket, recursive = true, service = '
383
394
  }
384
395
  checkErrors();
385
396
  }
386
- exports.deleteObjectsV2 = deleteObjectsV2;
387
397
  async function executeQuery(credential, data, sessionKey) {
388
398
  return (await executeBatchQuery.call(this, credential, [data], sessionKey))[0] || [];
389
399
  }
390
- exports.executeQuery = executeQuery;
391
400
  async function executeBatchQuery(credential, batch, sessionKey) {
392
401
  const length = batch.length;
393
402
  const result = new Array(length);
@@ -407,8 +416,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
407
416
  const closeClient = () => {
408
417
  const fs = clients[3];
409
418
  if (fs) {
410
- fs.terminate();
411
- return;
419
+ void fs.terminate();
412
420
  }
413
421
  const sp = clients[5];
414
422
  if (sp) {
@@ -438,12 +446,6 @@ async function executeBatchQuery(credential, batch, sessionKey) {
438
446
  const item = batch[i];
439
447
  const { service, product, name, database, table, id, query, limit = 0, update, ignoreCache } = item;
440
448
  const useCache = caching && ignoreCache !== true;
441
- const getCache = (value) => {
442
- if (ignoreCache !== 1) {
443
- cacheValue.renewCache = ignoreCache === 0;
444
- return this.getQueryResult(service, credential, value, cacheValue);
445
- }
446
- };
447
449
  cacheValue.exclusiveOf = Array.isArray(ignoreCache) ? ignoreCache : undefined;
448
450
  let rows, queryString = '';
449
451
  if (product === "firebase" || isFirebaseApp(credential)) {
@@ -454,7 +456,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
454
456
  const orderBy = item.orderBy;
455
457
  if (useCache) {
456
458
  queryString = query + Cloud.asString(orderBy, true);
457
- if (!update && (rows = getCache(queryString))) {
459
+ if (!update && (rows = this.getCacheResult(service, credential, queryString, cacheValue, ignoreCache))) {
458
460
  result[i] = rows;
459
461
  continue;
460
462
  }
@@ -495,7 +497,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
495
497
  if ((0, types_1.isPlainObject)(update)) {
496
498
  await updateDB(ref(db, query), update);
497
499
  }
498
- const snapshot = await (constraints.length ? get(queryDB(ref(db, query), ...constraints)) : get(child(ref(db), query)));
500
+ const snapshot = await (constraints.length > 0 ? get(queryDB(ref(db, query), ...constraints)) : get(child(ref(db), query)));
499
501
  if (snapshot.exists()) {
500
502
  const val = snapshot.val();
501
503
  const group = limiter === 1 && Object.keys(val);
@@ -514,8 +516,8 @@ async function executeBatchQuery(credential, batch, sessionKey) {
514
516
  }
515
517
  const { updateType, options = {} } = item;
516
518
  if (useCache) {
517
- queryString = name + '_' + database + (table ? '_' + table + (columns ? Cloud.asString(columns, true) : '') : '') + '_' + Cloud.asString(query, true) + (limit > 0 ? limit : '');
518
- if (!update && (rows = getCache(queryString))) {
519
+ queryString = name + '_' + database + (table ? '_' + table + (columns ? Cloud.asString(columns, true) : '') : '') + '_' + Cloud.asString(query, true) + (limit > 0 ? '_' + limit : '');
520
+ if (!update && (rows = this.getCacheResult(service, credential, queryString, cacheValue, ignoreCache))) {
519
521
  result[i] = rows;
520
522
  continue;
521
523
  }
@@ -547,10 +549,16 @@ async function executeBatchQuery(credential, batch, sessionKey) {
547
549
  transaction.runUpdate(update)
548
550
  .then(async () => {
549
551
  transaction.commit()
550
- .then(() => resolve())
551
- .catch((error) => reject(error));
552
+ .then(() => {
553
+ resolve();
554
+ })
555
+ .catch((error) => {
556
+ reject(error);
557
+ });
552
558
  })
553
- .catch((error) => reject(error));
559
+ .catch((error) => {
560
+ reject(error);
561
+ });
554
562
  }
555
563
  });
556
564
  });
@@ -577,7 +585,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
577
585
  }
578
586
  if (useCache) {
579
587
  queryString = name + '_' + table + ((0, types_1.isString)(id) ? '_' + id + ((0, types_1.isArray)(columns) ? '_' + Cloud.asString(columns, true) : '') : '') + Cloud.asString(options, true);
580
- if (!(update && id) && (rows = getCache(queryString))) {
588
+ if (!(update && id) && (rows = this.getCacheResult(service, credential, queryString, cacheValue, ignoreCache))) {
581
589
  result[i] = rows;
582
590
  continue;
583
591
  }
@@ -612,6 +620,10 @@ async function executeBatchQuery(credential, batch, sessionKey) {
612
620
  if ((0, types_1.isString)(query)) {
613
621
  options.query = query;
614
622
  }
623
+ else if (!options.query) {
624
+ closeClient();
625
+ throw (0, util_1.formatError)(item, "Missing database query");
626
+ }
615
627
  if ((0, types_1.isObject)(params)) {
616
628
  options.params = params;
617
629
  }
@@ -619,14 +631,13 @@ async function executeBatchQuery(credential, batch, sessionKey) {
619
631
  options.maxResults = limit;
620
632
  }
621
633
  if (useCache) {
622
- queryString = query + (database ? '_' + database + (table ? '_' + table : '') : '') + Cloud.asString(options, true);
623
- if (!update && (rows = getCache(queryString))) {
634
+ queryString = (database ? database + '_' + (table ? table + '_' : '') : '') + Cloud.asString(options, true);
635
+ if (!update && (rows = this.getCacheResult(service, credential, queryString, cacheValue, ignoreCache))) {
624
636
  result[i] = rows;
625
637
  continue;
626
638
  }
627
639
  }
628
640
  const instance = createClient(item, 1);
629
- let job;
630
641
  if (database) {
631
642
  const dataset = instance.dataset(database);
632
643
  let target = dataset;
@@ -639,12 +650,12 @@ async function executeBatchQuery(credential, batch, sessionKey) {
639
650
  metadata.view = update;
640
651
  await target.setMetadata(metadata);
641
652
  }
642
- [job] = await dataset.createQueryJob(options);
653
+ const job = (await dataset.createQueryJob(options))[0];
654
+ [rows] = await job.getQueryResults();
643
655
  }
644
656
  else {
645
- [job] = await instance.createQueryJob(options);
657
+ [rows] = await instance.query(options);
646
658
  }
647
- [rows] = await job.getQueryResults();
648
659
  }
649
660
  else if (product === "datastore" || !product && (item.keys || item.kind || query && !table && !id)) {
650
661
  const { keys, kind, options } = item;
@@ -654,7 +665,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
654
665
  }
655
666
  if (useCache) {
656
667
  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) : '');
657
- if (!update && (rows = getCache(queryString))) {
668
+ if (!update && (rows = this.getCacheResult(service, credential, queryString, cacheValue, ignoreCache))) {
658
669
  result[i] = rows;
659
670
  continue;
660
671
  }
@@ -702,13 +713,19 @@ async function executeBatchQuery(credential, batch, sessionKey) {
702
713
  db.runQuery(task.select('__key__'), options).then(entities => {
703
714
  if ((0, types_1.isArray)(entities)) {
704
715
  const items = entities.map((entity) => db.key(entity[db.KEY]));
705
- db.save({ key: items, data: update }).then(() => resolve()).catch((err) => reject(err));
716
+ db.save({ key: items, data: update }).then(() => {
717
+ resolve();
718
+ }).catch((err) => {
719
+ reject(err);
720
+ });
706
721
  }
707
722
  else {
708
723
  resolve();
709
724
  }
710
725
  })
711
- .catch((err) => reject(err));
726
+ .catch((err) => {
727
+ reject(err);
728
+ });
712
729
  });
713
730
  }
714
731
  [rows] = await db.runQuery(task, options);
@@ -723,7 +740,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
723
740
  const options = Array.isArray(id) ? item.options : null;
724
741
  if (useCache) {
725
742
  queryString = table + '_' + id + (options ? Cloud.asString(options, true) : '');
726
- if ((!update || Array.isArray(id)) && (rows = getCache(queryString))) {
743
+ if ((!update || Array.isArray(id)) && (rows = this.getCacheResult(service, credential, queryString, cacheValue, ignoreCache))) {
727
744
  result[i] = rows;
728
745
  continue;
729
746
  }
@@ -739,7 +756,7 @@ async function executeBatchQuery(credential, batch, sessionKey) {
739
756
  else {
740
757
  const doc = db.collection(table).doc(id);
741
758
  if ((0, types_1.isPlainObject)(update)) {
742
- const pattern = /^__(delete|serverTimestamp|increment)(?:<(.+)>)?__$/;
759
+ const pattern = /^__(delete|serverTimestamp|increment|vector|(?:array)(?:Union|Remove))(?:<(.+)>)?__$/s;
743
760
  for (const attr in update) {
744
761
  const match = pattern.exec(attr);
745
762
  if (match) {
@@ -752,6 +769,41 @@ async function executeBatchQuery(credential, batch, sessionKey) {
752
769
  case 'increment':
753
770
  update[attr] = firestore_1.FieldValue.increment(match[2] ? +match[2] : 1);
754
771
  break;
772
+ case 'vector':
773
+ if (match[2]) {
774
+ update[attr] = firestore_1.FieldValue.vector(match[2].split(',').map(unit => parseFloat(unit)));
775
+ }
776
+ break;
777
+ case 'arrayUnion':
778
+ case 'arrayRemove':
779
+ if (match[2]) {
780
+ update[attr] = firestore_1.FieldValue[method](...match[2].trim().split(/(?<!\\)\s*,\s*/).map(unit => {
781
+ switch (unit) {
782
+ case 'true':
783
+ return true;
784
+ case 'false':
785
+ return false;
786
+ case 'undefined':
787
+ return undefined;
788
+ case 'null':
789
+ return null;
790
+ }
791
+ if (isNaN(+unit)) {
792
+ return +unit;
793
+ }
794
+ const a = unit[0];
795
+ const b = unit[unit.length - 1];
796
+ if (a === '[' && b === ']' || a === '{' && b === '}') {
797
+ try {
798
+ return JSON.parse(unit.replace(/\\,/g, ','));
799
+ }
800
+ catch {
801
+ }
802
+ }
803
+ return unit;
804
+ }));
805
+ }
806
+ break;
755
807
  }
756
808
  }
757
809
  }
@@ -775,61 +827,76 @@ async function executeBatchQuery(credential, batch, sessionKey) {
775
827
  }
776
828
  }
777
829
  else if (Array.isArray(query)) {
778
- const orderBy = item.orderBy;
779
- if (useCache && (rows = getCache(queryString = table + '_' + Cloud.asString(query, true) + '_' + Cloud.asString(orderBy, true) + (limit > 0 ? '_' + limit : '')))) {
780
- result[i] = rows;
781
- continue;
782
- }
783
- let db = createClient(item, 3).collection(table);
784
- for (const args of query) {
785
- if ((0, types_1.isArray)(args)) {
786
- const method = args[0];
787
- const params = args.slice(1);
788
- switch (method) {
789
- case 'whereAnd':
790
- case 'whereOr':
791
- if (!params.every(p => (0, types_1.isArray)(p))) {
792
- throw (0, types_1.errorMessage)(method, 'Conditionals are not in array format', Cloud.asString(params));
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);
805
- break;
806
- case 'endAt':
807
- case 'endBefore':
808
- case 'limit':
809
- case 'limitToLast':
810
- case 'offset':
811
- case 'startAfter':
812
- case 'startAt':
813
- case 'withConverter':
814
- db = db[method].apply(db, params);
815
- break;
816
- }
830
+ const db = createClient(item, 3).collection(table);
831
+ if (item.params && query.every(value => typeof value === 'number')) {
832
+ const options = item.options;
833
+ if (useCache && (rows = this.getCacheResult(service, credential, queryString = table + '_' + Cloud.asString(item.params, true) + '_' + Cloud.asString(query, true) + (options ? Cloud.asString(options, true) : ''), cacheValue, ignoreCache))) {
834
+ result[i] = rows;
835
+ continue;
817
836
  }
837
+ rows = (await db.findNearest(asFieldPath(item.params), firestore_1.FieldValue.vector(query), options).get()).docs.map(doc => doc.data());
818
838
  }
819
- if (Array.isArray(orderBy)) {
820
- for (const order of orderBy) {
821
- if ((0, types_1.isArray)(order)) {
822
- db = db.orderBy(asFieldPath(order[0]), order[1]);
839
+ else {
840
+ const orderBy = item.orderBy;
841
+ if (useCache && (rows = this.getCacheResult(service, credential, queryString = table + '_' + Cloud.asString(query, true) + '_' + Cloud.asString(orderBy, true) + (limit > 0 ? '_' + limit : ''), cacheValue, ignoreCache))) {
842
+ result[i] = rows;
843
+ continue;
844
+ }
845
+ let target = db;
846
+ for (const args of query) {
847
+ if ((0, types_1.isArray)(args)) {
848
+ const method = args[0];
849
+ const params = args.slice(1);
850
+ switch (method) {
851
+ case 'whereAnd':
852
+ case 'whereOr':
853
+ if (!params.every(p => (0, types_1.isArray)(p))) {
854
+ throw (0, types_1.errorMessage)(method, 'Conditionals are not in array format', Cloud.asString(params));
855
+ }
856
+ target = target.where(firestore_1.Filter[method === 'whereAnd' ? 'and' : 'or'](...params.map((p) => firestore_1.Filter.where(p[0], p[1], p[2]))));
857
+ break;
858
+ case 'findNearest':
859
+ params[0] = asFieldPath(params[0]);
860
+ target = target.findNearest.apply(target, params).query;
861
+ break;
862
+ case 'where':
863
+ case 'orderBy':
864
+ params[0] = asFieldPath(params[0]);
865
+ target = target[method].apply(target, params);
866
+ case 'select':
867
+ params.forEach((field, index) => {
868
+ params[index] = asFieldPath(field);
869
+ });
870
+ target = target.select.apply(target, params);
871
+ break;
872
+ case 'endAt':
873
+ case 'endBefore':
874
+ case 'limit':
875
+ case 'limitToLast':
876
+ case 'offset':
877
+ case 'startAfter':
878
+ case 'startAt':
879
+ case 'withConverter':
880
+ target = target[method].apply(target, params);
881
+ break;
882
+ }
823
883
  }
824
- else if ((0, types_1.isString)(order)) {
825
- db = db.orderBy(order);
884
+ }
885
+ if (Array.isArray(orderBy)) {
886
+ for (const order of orderBy) {
887
+ if ((0, types_1.isArray)(order)) {
888
+ target = target.orderBy(asFieldPath(order[0]), order[1]);
889
+ }
890
+ else if ((0, types_1.isString)(order)) {
891
+ target = target.orderBy(order);
892
+ }
826
893
  }
827
894
  }
895
+ if (limit > 0) {
896
+ target = target.limit(limit);
897
+ }
898
+ rows = (await target.get()).docs.map(doc => doc.data());
828
899
  }
829
- if (limit > 0) {
830
- db = db.limit(limit);
831
- }
832
- rows = (await db.get()).docs.map(doc => doc.data());
833
900
  }
834
901
  else {
835
902
  closeClient();
@@ -845,7 +912,6 @@ async function executeBatchQuery(credential, batch, sessionKey) {
845
912
  closeClient();
846
913
  return result;
847
914
  }
848
- exports.executeBatchQuery = executeBatchQuery;
849
915
  function setPublicRead(acl, pathname, requested, service = 'gcp') {
850
916
  acl.add({ entity: 'allUsers', role: 'READER' })
851
917
  .then(() => {
@@ -859,7 +925,6 @@ function setPublicRead(acl, pathname, requested, service = 'gcp') {
859
925
  }
860
926
  });
861
927
  }
862
- exports.setPublicRead = setPublicRead;
863
928
  async function setPredefinedAcl(target, value, bucket, pathname = '', metadata = {}, requested = true, service = 'gcp') {
864
929
  let revoke;
865
930
  if (metadata === true) {
@@ -929,7 +994,7 @@ async function setPredefinedAcl(target, value, bucket, pathname = '', metadata =
929
994
  }
930
995
  }
931
996
  return updatePredefinedAcl(target, items, metadata).then(errors => {
932
- if (errors.length) {
997
+ if (errors.length > 0) {
933
998
  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 });
934
999
  }
935
1000
  else if (requested && (bucket || pathname)) {
@@ -937,36 +1002,58 @@ async function setPredefinedAcl(target, value, bucket, pathname = '', metadata =
937
1002
  }
938
1003
  });
939
1004
  }
940
- exports.setPredefinedAcl = setPredefinedAcl;
941
1005
  function createBucketRequest(credential) {
942
1006
  const options = {};
943
1007
  for (const attr in credential) {
944
1008
  switch (attr) {
945
1009
  case 'archive':
946
- case 'autoclass':
947
1010
  case 'coldline':
948
- case 'cors':
949
- case 'customPlacementConfig':
1011
+ case 'dataLocations':
950
1012
  case 'dra':
951
1013
  case 'enableObjectRetention':
952
- case 'location':
953
1014
  case 'multiRegional':
954
1015
  case 'nearline':
1016
+ case 'predefinedAcl':
1017
+ case 'predefinedDefaultObjectAcl':
1018
+ case 'projection':
955
1019
  case 'regional':
956
1020
  case 'requesterPays':
1021
+ case 'standard':
1022
+ case 'userProject':
1023
+ case 'acl':
1024
+ case 'autoclass':
1025
+ case 'billing':
1026
+ case 'cors':
1027
+ case 'customPlacementConfig':
1028
+ case 'defaultEventBasedHold':
1029
+ case 'defaultObjectAcl':
1030
+ case 'encryption':
1031
+ case 'hierarchicalNamespace':
1032
+ case 'iamConfiguration':
1033
+ case 'labels':
1034
+ case 'lifecycle':
1035
+ case 'location':
1036
+ case 'locationType':
1037
+ case 'logging':
1038
+ case 'metageneration':
1039
+ case 'name':
1040
+ case 'objectRetention':
1041
+ case 'owner':
1042
+ case 'projectNumber':
957
1043
  case 'retentionPolicy':
958
1044
  case 'rpo':
959
- case 'standard':
1045
+ case 'softDeletePolicy':
960
1046
  case 'storageClass':
961
- case 'userProject':
1047
+ case 'timeCreated':
1048
+ case 'updated':
962
1049
  case 'versioning':
1050
+ case 'website':
963
1051
  options[attr] = credential[attr];
964
1052
  break;
965
1053
  }
966
1054
  }
967
1055
  return options;
968
1056
  }
969
- exports.createBucketRequest = createBucketRequest;
970
1057
  function getProjectId(credential, cache) {
971
1058
  let projectId = credential.projectId;
972
1059
  if (!cache && projectId) {
@@ -994,7 +1081,6 @@ function getProjectId(credential, cache) {
994
1081
  }
995
1082
  return projectId;
996
1083
  }
997
- exports.getProjectId = getProjectId;
998
1084
  exports.CLOUD_UPLOAD_STREAM = true;
999
1085
  exports.CLOUD_UPLOAD_CHUNK = true;
1000
1086
  exports.CLOUD_DOWNLOAD_CHUNK = true;
package/download/index.js CHANGED
@@ -2,10 +2,11 @@
2
2
  const path = require("path");
3
3
  const fs = require("fs");
4
4
  const https = require("https");
5
+ const storage_1 = require("@google-cloud/storage");
5
6
  const types_1 = require("@e-mc/types");
6
7
  const Cloud = require("@e-mc/cloud");
7
8
  const client_1 = require("@pi-r/gcp");
8
- module.exports = function download(credential, service = 'gcp') {
9
+ function download(credential, service = 'gcp') {
9
10
  const storage = client_1.createStorageClient.call(this, credential);
10
11
  return (data, callback) => {
11
12
  const { bucket: Bucket, download: target } = data;
@@ -14,7 +15,9 @@ module.exports = function download(credential, service = 'gcp') {
14
15
  const downloadResponse = (err, url = null) => {
15
16
  callback(err, url);
16
17
  if (tempDir) {
17
- queueMicrotask(() => Cloud.removeDir(tempDir));
18
+ queueMicrotask(() => {
19
+ Cloud.removeDir(tempDir);
20
+ });
18
21
  }
19
22
  };
20
23
  if (!Bucket || !Key) {
@@ -27,25 +30,29 @@ module.exports = function download(credential, service = 'gcp') {
27
30
  }
28
31
  const location = Cloud.joinPath(Bucket, Key);
29
32
  const destination = path.join(tempDir, path.basename(target.filename || Key));
30
- const deleteMessage = () => this.formatMessage(64, service, "Delete success", location, { ...Cloud.LOG_CLOUD_DELETE });
33
+ const deleteMessage = () => {
34
+ this.formatMessage(64, service, "Delete success", location, { ...Cloud.LOG_CLOUD_DELETE });
35
+ };
31
36
  if ((0, client_1.isFirebaseApp)(credential, true, true)) {
32
37
  const { ref, getDownloadURL, deleteObject } = require('@firebase/storage');
33
38
  const objectRef = ref(storage, Key);
34
- getDownloadURL(objectRef).then(url => {
39
+ void getDownloadURL(objectRef).then(url => {
35
40
  https.get(url, res => {
36
41
  const statusCode = res.statusCode;
37
42
  if (statusCode >= 200 && statusCode < 300) {
38
- res.on('error', err => downloadResponse(err));
43
+ res.on('error', downloadResponse);
39
44
  res.pipe(fs.createWriteStream(destination)
40
45
  .on('finish', () => {
41
46
  downloadResponse(null, destination);
42
47
  if (target.deleteObject) {
43
48
  deleteObject(objectRef)
44
- .then(() => deleteMessage())
45
- .catch((err) => this.formatFail(64, service, ["Delete failed", location], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: !!target.active }));
49
+ .then(deleteMessage)
50
+ .catch((err) => {
51
+ this.formatFail(64, service, ["Delete failed", location], err, { ...Cloud.LOG_CLOUD_FAIL, fatal: !!target.active });
52
+ });
46
53
  }
47
54
  })
48
- .on('error', err => downloadResponse(err)));
55
+ .on('error', downloadResponse));
49
56
  }
50
57
  else {
51
58
  downloadResponse((0, types_1.errorMessage)(statusCode, 'Invalid HTTP request', location));
@@ -57,18 +64,8 @@ module.exports = function download(credential, service = 'gcp') {
57
64
  const { flags = 0 } = target;
58
65
  const bucket = storage.bucket(Bucket);
59
66
  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 });
69
- }
70
- (manager || file.download({ destination }))
71
- .then(() => {
67
+ const chunkSizeBytes = flags & 4 ? (0, types_1.alignSize)(target.chunkSize, 1024) : 0;
68
+ const fileDownload = () => {
72
69
  downloadResponse(null, destination);
73
70
  const deleteObject = target.deleteObject;
74
71
  if (deleteObject) {
@@ -81,7 +78,27 @@ module.exports = function download(credential, service = 'gcp') {
81
78
  }
82
79
  });
83
80
  }
84
- })
85
- .catch((err) => downloadResponse(err));
81
+ };
82
+ if (chunkSizeBytes > 0) {
83
+ new storage_1.TransferManager(bucket).downloadFileInChunks(file, {
84
+ destination,
85
+ chunkSizeBytes,
86
+ concurrencyLimit: target.chunkLimit || target.options?.concurrencyLimit
87
+ })
88
+ .then(fileDownload)
89
+ .catch(downloadResponse);
90
+ }
91
+ else if (target.chunkLimit === 1 && !target.chunkSize) {
92
+ file.createReadStream()
93
+ .pipe(fs.createWriteStream(destination))
94
+ .on('finish', fileDownload)
95
+ .on('error', downloadResponse);
96
+ }
97
+ else {
98
+ file.download({ destination })
99
+ .then(fileDownload)
100
+ .catch(downloadResponse);
101
+ }
86
102
  };
87
- };
103
+ }
104
+ module.exports = download;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pi-r/gcp",
3
- "version": "0.7.3",
3
+ "version": "0.8.0",
4
4
  "description": "Google (GCP) cloud functions for E-mc.",
5
5
  "main": "client/index.js",
6
6
  "publishConfig": {
@@ -20,9 +20,9 @@
20
20
  "license": "MIT",
21
21
  "homepage": "https://github.com/anpham6/pi-r#readme",
22
22
  "dependencies": {
23
- "@e-mc/cloud": "^0.9.6",
24
- "@e-mc/module": "^0.9.6",
25
- "@e-mc/types": "^0.9.6",
23
+ "@e-mc/cloud": "^0.10.0",
24
+ "@e-mc/module": "^0.10.0",
25
+ "@e-mc/types": "^0.10.0",
26
26
  "@google-cloud/firestore": "^7.9.0",
27
27
  "@google-cloud/storage": "^7.12.0"
28
28
  }
package/types/index.d.ts CHANGED
@@ -12,7 +12,7 @@ export type GCPStorage = CloudStorage<GCPStorageCredential, "gcp | gcloud">;
12
12
 
13
13
  export interface GCPStorageCredential extends StorageOptions, IFirebaseOptions {}
14
14
 
15
- export interface GCPDatabaseQuery<T = PlainObject> extends Omit<CloudDatabase<unknown, T, unknown, unknown[] | StandardMap, GCPDatabaseCredential>, "id"> {
15
+ export interface GCPDatabaseQuery<T = PlainObject> extends Omit<CloudDatabase<unknown, T, unknown, string | unknown[] | StandardMap, GCPDatabaseCredential>, "id"> {
16
16
  source: "cloud";
17
17
  service: "gcp" | "gcloud";
18
18
  product?: "firestore" | "firebase" | "bigquery" | "bigtable" | "datastore" | "spanner";
package/upload/index.js CHANGED
@@ -2,14 +2,14 @@
2
2
  const path = require("path");
3
3
  const fs = require("fs");
4
4
  const stream = require("stream");
5
+ const Cloud = require("@e-mc/cloud");
5
6
  const util_1 = require("@e-mc/cloud/util");
6
7
  const types_1 = require("@e-mc/types");
7
- const Cloud = require("@e-mc/cloud");
8
8
  const client_1 = require("@pi-r/gcp");
9
9
  const BUCKET_SESSION = new Set();
10
10
  const BUCKET_RESPONSE = {};
11
11
  const getBucketKey = (credential, bucket, acl = '') => Cloud.asString(credential, true) + bucket + '_' + acl;
12
- module.exports = function upload(credential, service = 'gcp') {
12
+ function upload(credential, service = 'gcp') {
13
13
  const storage = client_1.createStorageClient.call(this, credential);
14
14
  return async (data, callback) => {
15
15
  const firebase = (0, client_1.isFirebaseApp)(credential, true, true);
@@ -25,7 +25,11 @@ module.exports = function upload(credential, service = 'gcp') {
25
25
  }
26
26
  callback(err, url);
27
27
  };
28
- const addLog = (err) => err instanceof Error && this.addLog(this.statusType.WARN, err, service, bucket);
28
+ const addLog = (err) => {
29
+ if (err instanceof Error) {
30
+ this.addLog(this.statusType.WARN, err, service, bucket);
31
+ }
32
+ };
29
33
  if (firebase) {
30
34
  const { ref, listAll } = require('@firebase/storage');
31
35
  bucketClient = ref(storage, bucket);
@@ -53,11 +57,17 @@ module.exports = function upload(credential, service = 'gcp') {
53
57
  bucketClient = storage.bucket(bucket);
54
58
  if (configBucket) {
55
59
  let { cors, lifecycle, retentionPolicy } = configBucket;
56
- const commandMessage = (feature, message) => this.formatMessage(64, service, ["Bucket configured" + ` (${feature})`, bucket], message, { ...Cloud.LOG_CLOUD_COMMAND });
60
+ const commandMessage = (feature, message) => {
61
+ this.formatMessage(64, service, ["Bucket configured" + ` (${feature})`, bucket], message, { ...Cloud.LOG_CLOUD_COMMAND });
62
+ };
57
63
  if (typeof retentionPolicy === 'number') {
58
64
  bucketClient.setRetentionPeriod(retentionPolicy)
59
- .then(([response]) => commandMessage('Retention Policy', response.retentionPolicy?.effectiveTime))
60
- .catch((err) => addLog(err));
65
+ .then(([response]) => {
66
+ commandMessage('Retention Policy', response.retentionPolicy?.effectiveTime);
67
+ })
68
+ .catch((err) => {
69
+ addLog(err);
70
+ });
61
71
  }
62
72
  if ((0, types_1.isObject)(cors)) {
63
73
  bucketClient.setCorsConfiguration(Array.isArray(cors) ? cors : [cors])
@@ -65,7 +75,9 @@ module.exports = function upload(credential, service = 'gcp') {
65
75
  const length = response.cors?.length;
66
76
  commandMessage('CORS', length ? length + ' rules' : null);
67
77
  })
68
- .catch((err) => addLog(err));
78
+ .catch((err) => {
79
+ addLog(err);
80
+ });
69
81
  }
70
82
  if ((0, types_1.isObject)(lifecycle)) {
71
83
  let append;
@@ -86,7 +98,9 @@ module.exports = function upload(credential, service = 'gcp') {
86
98
  const length = response.lifecycle?.rule?.length;
87
99
  commandMessage('Lifecycle', length ? length + ' rules' : null);
88
100
  })
89
- .catch((err) => addLog(err));
101
+ .catch((err) => {
102
+ addLog(err);
103
+ });
90
104
  }
91
105
  }
92
106
  if (flags & 4) {
@@ -175,7 +189,7 @@ module.exports = function upload(credential, service = 'gcp') {
175
189
  }
176
190
  else if ((flags & 2) && !firebase) {
177
191
  try {
178
- Stream.push(data.buffer.length ? stream.Readable.from(data.buffer) : fs.createReadStream(localUri, { signal: this.signal }));
192
+ Stream.push(data.buffer.length > 0 ? stream.Readable.from(data.buffer) : fs.createReadStream(localUri, { signal: this.signal }));
179
193
  if (fileGroup) {
180
194
  const [key, body, type] = (0, util_1.createKeyAndBody)(filename, fileGroup, 0, addLog, 2);
181
195
  Key.push(...key);
@@ -317,10 +331,12 @@ module.exports = function upload(credential, service = 'gcp') {
317
331
  uploadResponse(null, url);
318
332
  }
319
333
  if (Path[i]) {
320
- file.setMetadata(params).catch((err) => addLog(err));
334
+ file.setMetadata(params).catch((err) => {
335
+ addLog(err);
336
+ });
321
337
  }
322
338
  if (ACL) {
323
- client_1.setPredefinedAcl.call(this, file.acl, ACL, file.bucket, file.name, revoke || (await file.getMetadata())[0], true);
339
+ void client_1.setPredefinedAcl.call(this, file.acl, ACL, file.bucket, file.name, revoke || (await file.getMetadata())[0], true);
324
340
  }
325
341
  })
326
342
  .catch((err) => {
@@ -334,4 +350,5 @@ module.exports = function upload(credential, service = 'gcp') {
334
350
  }
335
351
  }
336
352
  };
337
- };
353
+ }
354
+ module.exports = upload;