@pi-r/gcp 0.11.2 → 0.12.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 +489 -254
- package/download/index.js +21 -19
- package/package.json +5 -5
- package/types/index.d.ts +4 -3
- package/upload/index.js +29 -27
package/download/index.js
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const stream = require('node:stream');
|
|
6
|
+
const { TransferManager } = require('@google-cloud/storage');
|
|
7
|
+
const Cloud = require('@e-mc/cloud');
|
|
8
|
+
const { alignSize, errorValue, getTempDir, isObject } = require('@e-mc/types');
|
|
9
|
+
const { createErrorHandler, intoArray, readableAsBuffer } = require('@e-mc/cloud/util');
|
|
10
|
+
const { copyObject, createStorageClient, isFirebaseApp } = require('@pi-r/gcp');
|
|
10
11
|
function download(credential, service = "gcp") {
|
|
11
|
-
const storage =
|
|
12
|
+
const storage = createStorageClient.call(this, credential);
|
|
12
13
|
return (data, callback) => {
|
|
13
14
|
const { bucket: Bucket, download: target } = data;
|
|
14
15
|
const Key = target.keyname || target.filename;
|
|
15
16
|
if (!Bucket || !Key) {
|
|
16
|
-
callback(
|
|
17
|
+
callback(errorValue('Missing property', !Bucket ? 'Bucket' : 'Key'));
|
|
17
18
|
return;
|
|
18
19
|
}
|
|
19
20
|
const location = Cloud.joinPath(Bucket, Key);
|
|
@@ -21,10 +22,10 @@ function download(credential, service = "gcp") {
|
|
|
21
22
|
const deleteFailed = (err) => {
|
|
22
23
|
this.formatFail(64, service, ["Delete failed", location], err, Cloud.optionsLogMessage('FAIL', { fatal: !!target.active }));
|
|
23
24
|
};
|
|
24
|
-
if (
|
|
25
|
+
if (isFirebaseApp(credential, true, true)) {
|
|
25
26
|
const { ref, getStream, deleteObject } = require('@firebase/storage');
|
|
26
27
|
const objectRef = ref(storage, Key);
|
|
27
|
-
|
|
28
|
+
readableAsBuffer(stream.Readable.from(getStream(objectRef)))
|
|
28
29
|
.then(buffer => {
|
|
29
30
|
callback(null, buffer);
|
|
30
31
|
if (target.deleteObject) {
|
|
@@ -37,33 +38,33 @@ function download(credential, service = "gcp") {
|
|
|
37
38
|
return;
|
|
38
39
|
}
|
|
39
40
|
const { flags = 0 } = target;
|
|
40
|
-
const tempDir =
|
|
41
|
+
const tempDir = getTempDir(true, service);
|
|
41
42
|
const destination = path.join(tempDir, path.basename(target.filename || Key));
|
|
42
43
|
const bucket = storage.bucket(Bucket);
|
|
43
44
|
const file = bucket.file(Key, { generation: target.versionId });
|
|
44
|
-
const chunkSizeBytes = flags & 4 ?
|
|
45
|
+
const chunkSizeBytes = flags & 4 ? alignSize(target.chunkSize, 1024) : 0;
|
|
45
46
|
const complete = async () => {
|
|
46
47
|
callback(null, destination);
|
|
47
|
-
const copyTo =
|
|
48
|
+
const copyTo = intoArray(target.copyObject);
|
|
48
49
|
if (copyTo) {
|
|
49
50
|
const tasks = [];
|
|
50
51
|
for (const { bucket: bucketName, pathname, filename, options } of copyTo) {
|
|
51
52
|
const keyObject = filename ? Cloud.joinPath(pathname, filename, true) : Key;
|
|
52
|
-
tasks.push(
|
|
53
|
+
tasks.push(copyObject
|
|
53
54
|
.call(this, credential, Bucket, file, bucketName, keyObject, options)
|
|
54
|
-
.catch(
|
|
55
|
+
.catch(createErrorHandler(this, service, Bucket)));
|
|
55
56
|
}
|
|
56
57
|
await Promise.all(tasks);
|
|
57
58
|
}
|
|
58
59
|
const deleteObject = target.deleteObject;
|
|
59
60
|
if (deleteObject) {
|
|
60
|
-
file.delete(
|
|
61
|
+
file.delete(isObject(deleteObject) ? deleteObject : { ignoreNotFound: true })
|
|
61
62
|
.then(deleteMessage)
|
|
62
63
|
.catch(deleteFailed);
|
|
63
64
|
}
|
|
64
65
|
};
|
|
65
66
|
if (chunkSizeBytes > 0) {
|
|
66
|
-
new
|
|
67
|
+
new TransferManager(bucket).downloadFileInChunks(file, {
|
|
67
68
|
destination,
|
|
68
69
|
chunkSizeBytes,
|
|
69
70
|
concurrencyLimit: target.chunkLimit || target.options?.concurrencyLimit
|
|
@@ -84,4 +85,5 @@ function download(credential, service = "gcp") {
|
|
|
84
85
|
}
|
|
85
86
|
};
|
|
86
87
|
}
|
|
88
|
+
|
|
87
89
|
module.exports = download;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pi-r/gcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.12.0",
|
|
4
4
|
"description": "Google (GCP) cloud functions for E-mc.",
|
|
5
5
|
"main": "client/index.js",
|
|
6
6
|
"publishConfig": {
|
|
@@ -19,10 +19,10 @@
|
|
|
19
19
|
"license": "MIT",
|
|
20
20
|
"homepage": "https://github.com/anpham6/pi-r#readme",
|
|
21
21
|
"dependencies": {
|
|
22
|
-
"@e-mc/cloud": "^0.
|
|
23
|
-
"@e-mc/module": "^0.
|
|
24
|
-
"@e-mc/types": "^0.
|
|
25
|
-
"@google-cloud/firestore": "^
|
|
22
|
+
"@e-mc/cloud": "^0.14.0",
|
|
23
|
+
"@e-mc/module": "^0.14.0",
|
|
24
|
+
"@e-mc/types": "^0.14.0",
|
|
25
|
+
"@google-cloud/firestore": "^8.5.0",
|
|
26
26
|
"@google-cloud/storage": "^7.19.0"
|
|
27
27
|
}
|
|
28
28
|
}
|
package/types/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { CloudDatabase, CloudStorage } from '@e-mc/types/lib/cloud';
|
|
|
2
2
|
|
|
3
3
|
import type { StorageOptions } from '@google-cloud/storage';
|
|
4
4
|
import type { PathType } from '@google-cloud/datastore';
|
|
5
|
-
import type { AggregateSpec } from '@google-cloud/firestore';
|
|
5
|
+
import type { AggregateSpec, FieldPath } from '@google-cloud/firestore';
|
|
6
6
|
import type { entity } from '@google-cloud/datastore/build/src/entity';
|
|
7
7
|
import type { FirebaseOptions as IFirebaseOptions } from '@firebase/app';
|
|
8
8
|
import type { ServiceAccount } from 'firebase-admin/app';
|
|
@@ -18,13 +18,14 @@ export interface GCPDatabaseQuery<T = PlainObject> extends Omit<CloudDatabase<un
|
|
|
18
18
|
service: "gcp" | "gcloud";
|
|
19
19
|
product?: "firestore" | "firebase" | "bigquery" | "bigtable" | "datastore" | "spanner";
|
|
20
20
|
database?: string;
|
|
21
|
-
id?: string | string[] | number;
|
|
21
|
+
id?: string | string[] | number | boolean;
|
|
22
22
|
updateType?: 0 | 1 | 2 | 3;
|
|
23
23
|
columns?: string[];
|
|
24
24
|
keys?: ArrayOf<DatastoreKey>;
|
|
25
25
|
kind?: string | string[];
|
|
26
|
-
orderBy?: unknown[][];
|
|
26
|
+
orderBy?: (string | FieldPath | unknown[])[] | string | FieldPath;
|
|
27
27
|
aggregateSpec?: AggregateSpec;
|
|
28
|
+
pipeline?: boolean;
|
|
28
29
|
flags?: number;
|
|
29
30
|
}
|
|
30
31
|
|
package/upload/index.js
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
|
|
3
|
-
const
|
|
4
|
-
const
|
|
5
|
-
const
|
|
6
|
-
const
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
2
|
+
|
|
3
|
+
const path = require('node:path');
|
|
4
|
+
const fs = require('node:fs');
|
|
5
|
+
const stream = require('node:stream');
|
|
6
|
+
const { TransferManager } = require('@google-cloud/storage');
|
|
7
|
+
const Cloud = require('@e-mc/cloud');
|
|
8
|
+
const { alignSize, createAbortError, isArray, isObject } = require('@e-mc/types');
|
|
9
|
+
const { createErrorHandler, createKeyAndBody, generateFilename, intoArray } = require('@e-mc/cloud/util');
|
|
10
|
+
const { copyObject, createBucketV2, createStorageClient, isFirebaseApp, setPredefinedAcl } = require('@pi-r/gcp');
|
|
10
11
|
const BUCKET_SESSION = new Set();
|
|
11
12
|
const BUCKET_RESPONSE = {};
|
|
12
13
|
const getBucketKey = (credential, bucket, acl = '') => Cloud.asString(credential, true) + bucket + '_' + acl;
|
|
13
14
|
function upload(credential, service = "gcp") {
|
|
14
|
-
const storage =
|
|
15
|
+
const storage = createStorageClient.call(this, credential);
|
|
15
16
|
return async (data, callback) => {
|
|
16
|
-
const firebase =
|
|
17
|
+
const firebase = isFirebaseApp(credential, true, true);
|
|
17
18
|
const { bucket, localUri } = data;
|
|
18
|
-
const { pathname, flags = 0, fileGroup, contentType, metadata, endpoint, active, publicRead, acl, admin = {}, overwrite, options } = data.upload;
|
|
19
|
+
const { pathname, flags = 0, fileGroup, descendantsGroup, contentType, metadata, endpoint, active, publicRead, acl, admin = {}, overwrite, options } = data.upload;
|
|
19
20
|
let filename = data.upload.filename || path.basename(localUri), chunkSizeBytes = 0, bucketClient, bucketKey, listFiles;
|
|
20
21
|
const complete = (err, url) => {
|
|
21
22
|
if (!firebase) {
|
|
@@ -26,7 +27,7 @@ function upload(credential, service = "gcp") {
|
|
|
26
27
|
}
|
|
27
28
|
callback(err, url);
|
|
28
29
|
};
|
|
29
|
-
const addLog =
|
|
30
|
+
const addLog = createErrorHandler(this, bucket, service);
|
|
30
31
|
if (firebase) {
|
|
31
32
|
const { ref, listAll } = require('@firebase/storage');
|
|
32
33
|
bucketClient = ref(storage, bucket);
|
|
@@ -44,7 +45,7 @@ function upload(credential, service = "gcp") {
|
|
|
44
45
|
const configBucket = admin.configBucket;
|
|
45
46
|
if (!BUCKET_SESSION.has(bucket)) {
|
|
46
47
|
const bucketAcl = admin.publicRead ? "publicRead" : admin.acl;
|
|
47
|
-
const response = BUCKET_RESPONSE[bucketKey = getBucketKey(credential, bucket, bucketAcl)] ||=
|
|
48
|
+
const response = BUCKET_RESPONSE[bucketKey = getBucketKey(credential, bucket, bucketAcl)] ||= createBucketV2.call(this, credential, bucket, bucketAcl, configBucket?.create);
|
|
48
49
|
if (!await response) {
|
|
49
50
|
complete(null);
|
|
50
51
|
return;
|
|
@@ -64,7 +65,7 @@ function upload(credential, service = "gcp") {
|
|
|
64
65
|
})
|
|
65
66
|
.catch(addLog);
|
|
66
67
|
}
|
|
67
|
-
if (
|
|
68
|
+
if (isObject(cors)) {
|
|
68
69
|
bucketClient.setCorsConfiguration(Array.isArray(cors) ? cors : [cors])
|
|
69
70
|
.then(([response]) => {
|
|
70
71
|
const length = response.cors?.length;
|
|
@@ -72,9 +73,9 @@ function upload(credential, service = "gcp") {
|
|
|
72
73
|
})
|
|
73
74
|
.catch(addLog);
|
|
74
75
|
}
|
|
75
|
-
if (
|
|
76
|
+
if (isObject(lifecycle)) {
|
|
76
77
|
let append = false;
|
|
77
|
-
if (
|
|
78
|
+
if (isArray(lifecycle)) {
|
|
78
79
|
const arg = lifecycle.at(-1);
|
|
79
80
|
if (typeof arg === 'boolean') {
|
|
80
81
|
append = arg;
|
|
@@ -90,7 +91,7 @@ function upload(credential, service = "gcp") {
|
|
|
90
91
|
}
|
|
91
92
|
}
|
|
92
93
|
if (flags & 4) {
|
|
93
|
-
const chunkSize =
|
|
94
|
+
const chunkSize = alignSize(data.upload.chunkSize, 1024);
|
|
94
95
|
if (chunkSize > 0) {
|
|
95
96
|
chunkSizeBytes = Math.max(chunkSize, 8388608);
|
|
96
97
|
}
|
|
@@ -98,7 +99,7 @@ function upload(credential, service = "gcp") {
|
|
|
98
99
|
}
|
|
99
100
|
if (!overwrite && (!listFiles || listFiles.length)) {
|
|
100
101
|
const current = filename;
|
|
101
|
-
const next =
|
|
102
|
+
const next = generateFilename(filename);
|
|
102
103
|
let i = 0, exists = false;
|
|
103
104
|
do {
|
|
104
105
|
if (i > 0) {
|
|
@@ -156,7 +157,7 @@ function upload(credential, service = "gcp") {
|
|
|
156
157
|
}
|
|
157
158
|
}
|
|
158
159
|
if (fileGroup) {
|
|
159
|
-
const [key, body, type] =
|
|
160
|
+
const [key, body, type] = createKeyAndBody(filename, fileGroup, { errorCallback: addLog, descendantsGroup, flags, chunkSize: chunkSizeBytes });
|
|
160
161
|
Key.push(...key);
|
|
161
162
|
ContentType.push(...type);
|
|
162
163
|
for (let i = 0; i < body.length; ++i) {
|
|
@@ -177,7 +178,7 @@ function upload(credential, service = "gcp") {
|
|
|
177
178
|
try {
|
|
178
179
|
Stream.push(data.buffer.length > 0 ? stream.Readable.from(data.buffer) : fs.createReadStream(localUri, { signal: this.signal }));
|
|
179
180
|
if (fileGroup) {
|
|
180
|
-
const [key, body, type] =
|
|
181
|
+
const [key, body, type] = createKeyAndBody(filename, fileGroup, { errorCallback: addLog, descendantsGroup, flags: 2 });
|
|
181
182
|
Key.push(...key);
|
|
182
183
|
Stream.push(...body);
|
|
183
184
|
ContentType.push(...type);
|
|
@@ -189,7 +190,7 @@ function upload(credential, service = "gcp") {
|
|
|
189
190
|
}
|
|
190
191
|
}
|
|
191
192
|
else if (fileGroup) {
|
|
192
|
-
const [key, body, type] =
|
|
193
|
+
const [key, body, type] = createKeyAndBody(filename, fileGroup, { errorCallback: addLog, descendantsGroup });
|
|
193
194
|
Key.push(...key);
|
|
194
195
|
Body.push(...body);
|
|
195
196
|
ContentType.push(...type);
|
|
@@ -211,7 +212,7 @@ function upload(credential, service = "gcp") {
|
|
|
211
212
|
const first = i === 0;
|
|
212
213
|
if (this.aborted) {
|
|
213
214
|
if (first) {
|
|
214
|
-
complete(
|
|
215
|
+
complete(createAbortError());
|
|
215
216
|
}
|
|
216
217
|
return;
|
|
217
218
|
}
|
|
@@ -266,7 +267,7 @@ function upload(credential, service = "gcp") {
|
|
|
266
267
|
else {
|
|
267
268
|
predefined = true;
|
|
268
269
|
}
|
|
269
|
-
if (
|
|
270
|
+
if (isObject(metadata)) {
|
|
270
271
|
params.metadata = metadata;
|
|
271
272
|
}
|
|
272
273
|
}
|
|
@@ -293,7 +294,7 @@ function upload(credential, service = "gcp") {
|
|
|
293
294
|
const file = bucketClient.file(destination, params);
|
|
294
295
|
let uploadClient;
|
|
295
296
|
if (Path[i]) {
|
|
296
|
-
uploadClient = new
|
|
297
|
+
uploadClient = new TransferManager(bucketClient).uploadFileInChunks(Path[i], { uploadName: destination, chunkSizeBytes, headers, concurrencyLimit: data.upload.chunkLimit || concurrencyLimit, maxQueueSize });
|
|
297
298
|
}
|
|
298
299
|
else {
|
|
299
300
|
params.resumable ??= false;
|
|
@@ -316,12 +317,12 @@ function upload(credential, service = "gcp") {
|
|
|
316
317
|
const url = getURL(file.name);
|
|
317
318
|
this.formatMessage(64, service, "Upload success", url, Cloud.optionsLogMessage('UPLOAD'));
|
|
318
319
|
if (first) {
|
|
319
|
-
const copyTo =
|
|
320
|
+
const copyTo = intoArray(data.upload.copyObject);
|
|
320
321
|
if (copyTo) {
|
|
321
322
|
const tasks = [];
|
|
322
323
|
for (const { bucket: bucketName, pathname: pathObject = pathname, filename: fileObject, options: copyOptions } of copyTo) {
|
|
323
324
|
const keyObject = fileObject ? Cloud.joinPath(pathObject, fileObject, true) : file.name;
|
|
324
|
-
tasks.push(
|
|
325
|
+
tasks.push(copyObject
|
|
325
326
|
.call(this, credential, bucket, file, bucketName, keyObject, copyOptions)
|
|
326
327
|
.catch(addLog));
|
|
327
328
|
}
|
|
@@ -334,7 +335,7 @@ function upload(credential, service = "gcp") {
|
|
|
334
335
|
.catch(addLog);
|
|
335
336
|
}
|
|
336
337
|
if (ACL) {
|
|
337
|
-
void
|
|
338
|
+
void setPredefinedAcl.call(this, file.acl, ACL, file.bucket, file.name, revoke || (await file.getMetadata())[0], true);
|
|
338
339
|
}
|
|
339
340
|
})
|
|
340
341
|
.catch((err) => {
|
|
@@ -349,4 +350,5 @@ function upload(credential, service = "gcp") {
|
|
|
349
350
|
}
|
|
350
351
|
};
|
|
351
352
|
}
|
|
353
|
+
|
|
352
354
|
module.exports = upload;
|