@e-mc/cloud 0.0.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/index.js ADDED
@@ -0,0 +1,832 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const path = require("path");
4
+ const fs = require("fs");
5
+ const types_1 = require("../types");
6
+ const core_1 = require("../core");
7
+ const util_1 = require("./util");
8
+ const SERVICE_CLIENT = {};
9
+ const SERVICE_UPLOAD = {};
10
+ const SERVICE_DOWNLOAD = {};
11
+ function setUploadFilename(upload, filename) {
12
+ filename = Cloud.toPosix(filename.replace(/^\.*[\\/]+/, ''));
13
+ const index = filename.lastIndexOf('/');
14
+ if (index !== -1) {
15
+ const directory = filename.substring(0, index + 1);
16
+ upload.pathname = upload.pathname ? Cloud.joinPath(upload.pathname, directory) : directory;
17
+ filename = filename.substring(index + 1);
18
+ }
19
+ return upload.filename = filename;
20
+ }
21
+ function hasSameBucket({ upload, service, bucket }, other) {
22
+ const endpoint = upload.endpoint;
23
+ return (service && other.service || endpoint && endpoint === other.upload.endpoint) && bucket === other.bucket;
24
+ }
25
+ function getFiles(file, data) {
26
+ const grouped = file.localUri ? [file.localUri] : [];
27
+ if (data.all) {
28
+ const individual = new Set();
29
+ if (!file.cloudUrl) {
30
+ file.transforms?.forEach(value => individual.add(value));
31
+ }
32
+ file.torrentFiles?.forEach(value => individual.add(value));
33
+ if (file.descendants) {
34
+ grouped.push(...file.descendants);
35
+ }
36
+ return [grouped, Array.from(individual)];
37
+ }
38
+ return [grouped];
39
+ }
40
+ const errorObject = (err, service, value) => err instanceof Error ? err : typeof err === 'string' ? new Error(err) : (0, util_1.formatError)(service, value);
41
+ const assignFilename = (value) => (0, types_1.generateUUID)() + (path.extname(value) || '');
42
+ class Cloud extends core_1.ClientDb {
43
+ constructor() {
44
+ super(...arguments);
45
+ this._moduleName = 'cloud';
46
+ this._threadable = true;
47
+ this.uploaded = [];
48
+ this.downloaded = [];
49
+ }
50
+ static async finalize(instance) {
51
+ var _a, _b;
52
+ if (instance.aborted) {
53
+ return Promise.reject((0, types_1.createAbortError)());
54
+ }
55
+ Cloud.sanitizeAssets(this.assets);
56
+ const localStorage = new Map();
57
+ const bucketGroup = (0, types_1.generateUUID)();
58
+ const state = { host: this, instance, bucketGroup, localStorage };
59
+ const bucketDelete = {};
60
+ const bucketPolicy = {};
61
+ const rawFiles = [];
62
+ const startTime = process.hrtime();
63
+ let tasks = [], downloadMap;
64
+ if (await instance.commit()) {
65
+ instance.writeTimeElapsed(instance.moduleName, "Transactions were committed" /* VAL_MESSAGE.COMMIT_TRANSACTION */, startTime, { type: 64 /* LOG_TYPE.CLOUD */, ...Cloud.LOG_STYLE_SUCCESS });
66
+ }
67
+ for (const { instance: document } of this.Document) {
68
+ document.cloudInit?.(state);
69
+ }
70
+ for (const item of this.assets) {
71
+ const cloudStorage = item.cloudStorage;
72
+ if ((0, types_1.isArray)(cloudStorage) && !(0, types_1.ignoreFlag)(item.flags)) {
73
+ if (item.invalid) {
74
+ cloudStorage.forEach(storage => instance.formatMessage(64 /* LOG_TYPE.CLOUD */, storage.service, ["Upload failed" /* ERR_CLOUD.UPLOAD_FAIL */, storage.bucket], (0, types_1.errorValue)("File not found" /* ERR_MESSAGE.NOTFOUND_FILE */, item.uri || item.filename || "Unknown" /* ERR_MESSAGE.UNKNOWN */), { ...Cloud.LOG_CLOUD_WARN }));
75
+ continue;
76
+ }
77
+ ignore: {
78
+ if (item.localUri || item.torrentFiles) {
79
+ for (const { instance: document } of this.Document) {
80
+ if (document.cloudObject?.(state, item)) {
81
+ break ignore;
82
+ }
83
+ }
84
+ if (item.compress) {
85
+ tasks.push(this.compressFile(item));
86
+ }
87
+ rawFiles.push(item);
88
+ }
89
+ }
90
+ for (const storage of cloudStorage) {
91
+ const { admin, bucket } = storage;
92
+ if (admin && bucket && instance.hasCredential('storage', storage)) {
93
+ const policy = admin.configBucket?.policy;
94
+ if (admin.emptyBucket) {
95
+ const service = bucketDelete[_a = storage.service] || (bucketDelete[_a] = {});
96
+ const items = service[bucket];
97
+ if (!items) {
98
+ service[bucket] = [instance.getCredential(storage), admin.recursive];
99
+ }
100
+ else if (admin.recursive === false) {
101
+ items[1] = false;
102
+ }
103
+ }
104
+ if (policy) {
105
+ const service = bucketPolicy[_b = storage.service] || (bucketPolicy[_b] = {});
106
+ service[bucket] = [storage.service, instance.getCredential(storage), bucket, policy];
107
+ }
108
+ }
109
+ }
110
+ }
111
+ }
112
+ if (tasks.length) {
113
+ await instance.allSettled(tasks, ['Compress files', instance.moduleName]);
114
+ if (instance.aborted) {
115
+ return Promise.reject((0, types_1.createAbortError)());
116
+ }
117
+ tasks = [];
118
+ }
119
+ for (const service in bucketDelete) {
120
+ const map = bucketDelete[service];
121
+ for (const bucket in map) {
122
+ const [credential, recursive] = map[bucket];
123
+ tasks.push(instance.deleteObjects(service, credential, bucket, recursive).catch(err => instance.writeFail(["Unable to empty bucket" /* ERR_CLOUD.DELETE_BUCKET */, service + ': ' + bucket], err, { type: 64 /* LOG_TYPE.CLOUD */, startTime })));
124
+ }
125
+ }
126
+ if (tasks.length) {
127
+ await instance.allSettled(tasks, ['Empty bucket', instance.moduleName]);
128
+ if (instance.aborted) {
129
+ return Promise.reject((0, types_1.createAbortError)());
130
+ }
131
+ tasks = [];
132
+ }
133
+ rawFiles.forEach(item => tasks.push(...Cloud.uploadAsset(state, item)));
134
+ if (tasks.length) {
135
+ await instance.allSettled(tasks, ['Upload raw assets', instance.moduleName]);
136
+ if (instance.aborted) {
137
+ return Promise.reject((0, types_1.createAbortError)());
138
+ }
139
+ tasks = [];
140
+ }
141
+ for (const service in bucketPolicy) {
142
+ const map = bucketPolicy[service];
143
+ for (const bucket in map) {
144
+ const params = map[bucket];
145
+ tasks.push(instance.setBucketPolicy(...params).catch(err => instance.writeFail(["Unable to update bucket policy" /* ERR_CLOUD.POLICY_BUCKET */, params[0] + ': ' + params[2]], err, { type: 64 /* LOG_TYPE.CLOUD */, startTime })));
146
+ }
147
+ }
148
+ if (tasks.length) {
149
+ await instance.allSettled(tasks, ['Configure bucket', instance.moduleName]);
150
+ if (instance.aborted) {
151
+ return Promise.reject((0, types_1.createAbortError)());
152
+ }
153
+ tasks = [];
154
+ }
155
+ for (const { instance: document } of this.Document) {
156
+ if (document.cloudFinalize) {
157
+ await document.cloudFinalize(state).catch(err => document.writeFail(["Handled rejection" /* ERR_MESSAGE.HANDLED_REJECTION */, document.moduleName], err, { type: 64 /* LOG_TYPE.CLOUD */, startTime }));
158
+ if (document.aborted) {
159
+ return Promise.reject((0, types_1.createAbortError)());
160
+ }
161
+ }
162
+ }
163
+ for (const [item, data] of localStorage) {
164
+ getFiles(item, data).forEach(group => group.forEach(value => this.deleteFile(value, { emptyDir: true })));
165
+ }
166
+ for (const item of this.assets) {
167
+ const cloudStorage = item.cloudStorage;
168
+ if ((0, types_1.isArray)(cloudStorage) && !(0, types_1.ignoreFlag)(item.flags)) {
169
+ for (const data of cloudStorage) {
170
+ if (!instance.hasStorage('download', data)) {
171
+ continue;
172
+ }
173
+ const download = data.download;
174
+ const { pathname, filename, waitStatus, overwrite } = download;
175
+ let active = download.active;
176
+ if (!filename) {
177
+ continue;
178
+ }
179
+ const localUri = item.localUri;
180
+ let downloadUri;
181
+ if (pathname && path.isAbsolute(pathname)) {
182
+ downloadUri = path.join(pathname, filename);
183
+ if (!Cloud.isPath(downloadUri) && !this.canWrite(pathname)) {
184
+ instance.writeFail(["Unable to download file" /* ERR_MESSAGE.DOWNLOAD_FILE */, filename], (0, types_1.errorValue)("Unsupported access" /* ERR_MESSAGE.UNSUPPORTED_ACCESS */, pathname), { type: 64 /* LOG_TYPE.CLOUD */, fatal: !!active, startTime });
185
+ continue;
186
+ }
187
+ }
188
+ else {
189
+ downloadUri = pathname ? path.join(this.baseDirectory, pathname.replace(/^([A-Z]:)?[\\/]+/i, ''), filename) : path.join(data.admin?.preservePath && localUri ? path.dirname(localUri) : this.baseDirectory, filename);
190
+ }
191
+ const destDir = path.dirname(downloadUri);
192
+ if (Cloud.isPath(downloadUri)) {
193
+ if (!active && !overwrite) {
194
+ continue;
195
+ }
196
+ active = true;
197
+ }
198
+ else if (!Cloud.createDir(destDir)) {
199
+ continue;
200
+ }
201
+ else if (active) {
202
+ if (localUri && path.extname(localUri) === path.extname(downloadUri)) {
203
+ downloadUri = localUri;
204
+ }
205
+ else {
206
+ active = false;
207
+ }
208
+ }
209
+ const location = data.service + data.bucket + filename;
210
+ let pending = (downloadMap || (downloadMap = {}))[location];
211
+ if (pending) {
212
+ pending.add(downloadUri);
213
+ }
214
+ else {
215
+ pending = new Set([downloadUri]);
216
+ download.admin = data.admin;
217
+ const task = instance.downloadObject(data.service, instance.getCredential(data), data.bucket, download, (value) => {
218
+ let result;
219
+ if (value && !instance.aborted) {
220
+ const items = Array.from(pending);
221
+ for (let i = 0, length = items.length, size, copy; i < length; ++i) {
222
+ const destUri = items[i];
223
+ try {
224
+ if (typeof value === 'string') {
225
+ if (!copy && i === length - 1) {
226
+ fs.renameSync(value, destUri);
227
+ }
228
+ else {
229
+ fs.copyFileSync(value, destUri);
230
+ }
231
+ size = this.addDownload(destUri);
232
+ }
233
+ else {
234
+ fs.writeFileSync(destUri, value);
235
+ this.addDownload(size = value.length);
236
+ }
237
+ this.add(destUri);
238
+ this.formatMessage(64 /* LOG_TYPE.CLOUD */, data.service, ["Download success" /* CMD_CLOUD.DOWNLOAD_FILE */, (0, types_1.formatSize)(size)], destUri, { ...Cloud.LOG_CLOUD_DOWNLOAD });
239
+ result || (result = destUri);
240
+ }
241
+ catch (err) {
242
+ if (!copy && core_1.ClientDb.isErrorCode(err, 'EXDEV')) {
243
+ copy = true;
244
+ --i;
245
+ }
246
+ else {
247
+ instance.writeFail(["Unable to write file" /* ERR_MESSAGE.WRITE_FILE */, path.basename(destUri)], err, { type: 32 /* LOG_TYPE.FILE */, fatal: !!active, startTime });
248
+ }
249
+ }
250
+ }
251
+ }
252
+ return Promise.resolve(result);
253
+ })
254
+ .catch(err => instance.writeFail(["Download failed" /* ERR_CLOUD.DOWNLOAD_FAIL */, path.basename(downloadUri)], err, { type: 64 /* LOG_TYPE.CLOUD */, startTime }));
255
+ if (active || waitStatus || this.archiving) {
256
+ tasks.push(task);
257
+ }
258
+ downloadMap[location] = pending;
259
+ }
260
+ }
261
+ }
262
+ }
263
+ if (tasks.length) {
264
+ return instance.allSettled(tasks, ['Download objects', instance.moduleName]);
265
+ }
266
+ }
267
+ static uploadAsset(state, file, contentType = file.mimeType, ignoreProcess) {
268
+ if (typeof contentType === 'boolean') {
269
+ ignoreProcess = contentType;
270
+ contentType = file.mimeType;
271
+ }
272
+ const { host, instance } = state;
273
+ if (instance.aborted) {
274
+ return [];
275
+ }
276
+ const tasks = [];
277
+ for (const storage of file.cloudStorage) {
278
+ if (!instance.hasStorage('upload', storage)) {
279
+ continue;
280
+ }
281
+ const upload = storage.upload;
282
+ const active = storage === instance.getStorage('upload', file.cloudStorage);
283
+ if (active && upload.localStorage === false) {
284
+ state.localStorage.set(file, upload);
285
+ }
286
+ const callback = async (value) => {
287
+ if (value && !ignoreProcess) {
288
+ for (const { instance: document } of host.Document) {
289
+ if (document.cloudUpload && await document.cloudUpload(state, file, value, active)) {
290
+ return;
291
+ }
292
+ }
293
+ }
294
+ };
295
+ const task = new Promise(resolve => {
296
+ const { service, bucket = state.bucketGroup, admin } = storage;
297
+ const credential = instance.getCredential(storage, true);
298
+ const uploading = [];
299
+ getFiles(file, upload).forEach((group, index) => {
300
+ let fileGroup;
301
+ if (index === 0 && group.length > 1) {
302
+ switch (service) {
303
+ case 'gcp':
304
+ case 'gcloud':
305
+ fileGroup = group.slice(1).filter(value => this.isPath(value)).map(value => [value, path.extname(value), value]);
306
+ break;
307
+ default:
308
+ fileGroup = [];
309
+ for (let i = 1; i < group.length; ++i) {
310
+ const value = group[i];
311
+ try {
312
+ if (fs.existsSync(value)) {
313
+ fileGroup.push([fs.readFileSync(value), path.extname(value), value]);
314
+ }
315
+ }
316
+ catch (err) {
317
+ instance.writeFail(["Unable to read file" /* ERR_MESSAGE.READ_FILE */, path.basename(value)], err, { type: 32 /* LOG_TYPE.FILE */, fatal: false });
318
+ }
319
+ }
320
+ break;
321
+ }
322
+ group = [group[0]];
323
+ }
324
+ for (const localUri of group) {
325
+ const exists = this.isPath(localUri);
326
+ if (!exists || !instance.canRead(localUri, { ownPermissionOnly: true })) {
327
+ instance.writeFail(["Unable to read file" /* ERR_MESSAGE.READ_FILE */, path.basename(localUri)], (0, types_1.errorValue)(exists ? "Not permitted to read file" /* ERR_MESSAGE.UNSUPPORTED_READ */ : "File not found" /* ERR_MESSAGE.NOTFOUND_FILE */, localUri), { type: 64 /* LOG_TYPE.CLOUD */, fatal: index === 0 });
328
+ continue;
329
+ }
330
+ let buffer, filename;
331
+ if (index === 0) {
332
+ if (file.cloudUrl) {
333
+ filename = path.basename(file.cloudUrl);
334
+ }
335
+ else if (upload.filename) {
336
+ filename = upload.filename;
337
+ }
338
+ else if (upload.overwrite) {
339
+ filename = path.basename(localUri);
340
+ }
341
+ buffer = file.sourceUTF8 ? Buffer.from(file.sourceUTF8, file.encoding) : host.getBuffer(file);
342
+ }
343
+ else {
344
+ contentType = this.lookupMime(path.basename(localUri)) || file.mimeType;
345
+ }
346
+ const options = { ...upload, buffer, filename, fileGroup, admin };
347
+ if (index > 0 || !options.contentType) {
348
+ options.contentType = contentType;
349
+ }
350
+ uploading.push(instance.uploadObject(service, { ...credential }, bucket, options, localUri, callback)
351
+ .catch(err => instance.writeFail(["Upload failed" /* ERR_CLOUD.UPLOAD_FAIL */, path.basename(localUri)], err, { type: 64 /* LOG_TYPE.CLOUD */, fatal: index === 0 })));
352
+ }
353
+ });
354
+ instance.allSettled(uploading, [`Upload file "${contentType || "Unknown" /* ERR_MESSAGE.UNKNOWN */}"`, storage.service + ': ' + path.basename(file.localUri)]).then(() => resolve());
355
+ });
356
+ if (active) {
357
+ tasks.push(task);
358
+ }
359
+ }
360
+ return tasks;
361
+ }
362
+ static sanitizeAssets(assets) {
363
+ const storage = [];
364
+ for (const item of assets) {
365
+ const cloudStorage = item.cloudStorage;
366
+ if ((0, types_1.isArray)(cloudStorage) && !(0, types_1.ignoreFlag)(item.flags)) {
367
+ for (const data of cloudStorage) {
368
+ const upload = data.upload;
369
+ if (upload) {
370
+ if (upload.filename) {
371
+ setUploadFilename(upload, this.toPosix(upload.filename));
372
+ }
373
+ const pathname = upload.pathname || data.admin?.preservePath && item.pathname;
374
+ if (pathname) {
375
+ upload.pathname = this.toPosix(pathname).replace(/^\/+/, '') + '/';
376
+ }
377
+ }
378
+ }
379
+ storage.push(item);
380
+ }
381
+ }
382
+ const nameIndex = {};
383
+ const length = storage.length;
384
+ for (let i = length - 1; i > 0; --i) {
385
+ const current = storage[i];
386
+ for (const data of current.cloudStorage) {
387
+ const trailing = data.upload;
388
+ if (!trailing) {
389
+ continue;
390
+ }
391
+ renamed: {
392
+ const basename = trailing.filename;
393
+ const filename = basename || current.filename;
394
+ const trailingFolder = trailing.pathname || '';
395
+ const trailingName = this.joinPath(trailingFolder, filename);
396
+ for (let j = 0; j < length - 1; ++j) {
397
+ const previous = storage[j];
398
+ if (current === previous) {
399
+ continue;
400
+ }
401
+ for (const other of previous.cloudStorage) {
402
+ const leading = other.upload;
403
+ if (leading && hasSameBucket(data, other)) {
404
+ const leadingFolder = leading.pathname || '';
405
+ const renameTrailing = (value) => {
406
+ const location = trailingFolder + value;
407
+ nameIndex[location] || (nameIndex[location] = 1);
408
+ const index = value.indexOf('.');
409
+ trailing.filename = (index !== -1 ? value.substring(0, index) : value) + '_' + nameIndex[location]++ + (index !== -1 ? value.substring(index) : '');
410
+ };
411
+ if (basename && basename === leading.filename && leadingFolder === trailingFolder) {
412
+ renameTrailing(basename);
413
+ break renamed;
414
+ }
415
+ const leadingName = this.joinPath(leadingFolder, leading.filename || previous.filename);
416
+ if (trailingName === leadingName) {
417
+ if (!trailing.overwrite || leading.overwrite) {
418
+ renameTrailing(filename);
419
+ break renamed;
420
+ }
421
+ leading.filename = assignFilename(leading.filename || previous.filename);
422
+ }
423
+ }
424
+ }
425
+ }
426
+ }
427
+ }
428
+ }
429
+ return assets;
430
+ }
431
+ setQueryResult(service, credential, queryString, result, sessionKey) {
432
+ if (!Array.isArray(result)) {
433
+ result = typeof result === 'object' ? [result] : [];
434
+ }
435
+ else if (result.includes(undefined)) {
436
+ result = result.filter(item => typeof item === 'object');
437
+ }
438
+ return super.setQueryResult(service, credential, queryString, result, sessionKey);
439
+ }
440
+ createBucket(service, credential, bucket, publicRead, options) {
441
+ if (this.aborted) {
442
+ return Promise.reject((0, types_1.createAbortError)());
443
+ }
444
+ try {
445
+ const client = this.getClient(service);
446
+ try {
447
+ if (publicRead === undefined || typeof publicRead === 'boolean') {
448
+ const handler = client.createBucket?.bind(this);
449
+ if (handler) {
450
+ return handler.call(this, credential, bucket, publicRead);
451
+ }
452
+ }
453
+ else {
454
+ const handler = client.createBucketV2?.bind(this);
455
+ if (handler) {
456
+ return handler.call(this, credential, bucket, publicRead, options);
457
+ }
458
+ }
459
+ return Promise.reject((0, util_1.formatError)(service, "Create bucket not supported" /* ERR_CLOUD.CREATE_BUCKET_SUPPORT */));
460
+ }
461
+ catch (err) {
462
+ this.formatMessage(64 /* LOG_TYPE.CLOUD */, service, ["Unable to create bucket" /* ERR_CLOUD.CREATE_BUCKET */, bucket], err, { ...Cloud.LOG_CLOUD_WARN });
463
+ return Promise.reject(err);
464
+ }
465
+ }
466
+ catch (err) {
467
+ return Promise.reject(err);
468
+ }
469
+ }
470
+ setBucketPolicy(service, credential, bucket, options) {
471
+ if (this.aborted) {
472
+ return Promise.reject((0, types_1.createAbortError)());
473
+ }
474
+ try {
475
+ const handler = this.getClient(service).setBucketPolicy?.bind(this);
476
+ if (handler) {
477
+ try {
478
+ return handler.call(this, credential, bucket, options);
479
+ }
480
+ catch (err) {
481
+ this.formatMessage(64 /* LOG_TYPE.CLOUD */, service, ["Unable to update bucket policy" /* ERR_CLOUD.POLICY_BUCKET */, bucket], err, { ...Cloud.LOG_CLOUD_WARN });
482
+ return Promise.reject(err);
483
+ }
484
+ }
485
+ return Promise.reject((0, util_1.formatError)(service, "Bucket policy not supported" /* ERR_CLOUD.BUCKET_POLICY_SUPPORT */));
486
+ }
487
+ catch (err) {
488
+ return Promise.reject(err);
489
+ }
490
+ }
491
+ setBucketWebsite(service, credential, bucket, options) {
492
+ if (this.aborted) {
493
+ return Promise.reject((0, types_1.createAbortError)());
494
+ }
495
+ try {
496
+ const handler = this.getClient(service).setBucketWebsite?.bind(this);
497
+ if (handler) {
498
+ try {
499
+ return handler.call(this, credential, bucket, options);
500
+ }
501
+ catch (err) {
502
+ this.formatMessage(64 /* LOG_TYPE.CLOUD */, service, ["Unable to configure bucket" /* ERR_CLOUD.CONFIGURE_BUCKET */, bucket], err, { ...Cloud.LOG_CLOUD_WARN });
503
+ return Promise.reject(err);
504
+ }
505
+ }
506
+ return Promise.reject((0, util_1.formatError)(service, "Set bucket website not supported" /* ERR_CLOUD.BUCKET_WEBSITE_SUPPORT */));
507
+ }
508
+ catch (err) {
509
+ return Promise.reject(err);
510
+ }
511
+ }
512
+ deleteObjects(service, credential, bucket, recursive = true) {
513
+ if (this.aborted) {
514
+ return Promise.reject((0, types_1.createAbortError)());
515
+ }
516
+ try {
517
+ const errorResponse = (err) => this.formatMessage(64 /* LOG_TYPE.CLOUD */, service, ["Unable to empty bucket" /* ERR_CLOUD.DELETE_BUCKET */, bucket], err, { ...Cloud.LOG_CLOUD_WARN });
518
+ const client = this.getClient(service);
519
+ const handlerV2 = client.deleteObjectsV2?.bind(this);
520
+ if (handlerV2) {
521
+ return handlerV2.call(this, credential, bucket, recursive, service).catch(err => errorResponse(err));
522
+ }
523
+ const handlerV1 = client.deleteObjects?.bind(this);
524
+ if (handlerV1) {
525
+ return handlerV1.call(this, credential, bucket, service, undefined, recursive).catch(err => errorResponse(err));
526
+ }
527
+ return Promise.reject((0, util_1.formatError)(service, "Delete objects not supported" /* ERR_CLOUD.DELETE_OBJECTS_SUPPORT */));
528
+ }
529
+ catch (err) {
530
+ return Promise.reject(err);
531
+ }
532
+ }
533
+ uploadObject(service, credential, bucket, upload, localUri, beforeResolve) {
534
+ if (this.aborted) {
535
+ return Promise.reject((0, types_1.createAbortError)());
536
+ }
537
+ let handler;
538
+ try {
539
+ handler = this.getUploadHandler(service, credential).bind(this);
540
+ }
541
+ catch (err) {
542
+ this.formatMessage(64 /* LOG_TYPE.CLOUD */, service, ["Upload function not supported" /* ERR_CLOUD.UPLOAD_SUPPORT */, bucket], localUri, { ...Cloud.LOG_CLOUD_WARN });
543
+ return Promise.reject(err);
544
+ }
545
+ return new Promise((resolve, reject) => {
546
+ try {
547
+ handler({ bucket, upload, buffer: upload.buffer || fs.readFileSync(localUri), localUri }, async (err, value) => {
548
+ if (err) {
549
+ reject(errorObject(err, service, "Upload failed" /* ERR_CLOUD.UPLOAD_FAIL */));
550
+ }
551
+ else if (value) {
552
+ if (beforeResolve) {
553
+ await beforeResolve(value);
554
+ }
555
+ this.addLog(types_1.STATUS_TYPE.INFO, service + ' -> upload -> ' + value);
556
+ resolve(value);
557
+ }
558
+ else {
559
+ reject((0, util_1.formatError)(service, "Upload failed" /* ERR_CLOUD.UPLOAD_FAIL */));
560
+ }
561
+ });
562
+ }
563
+ catch (err) {
564
+ reject(err);
565
+ }
566
+ });
567
+ }
568
+ downloadObject(service, credential, bucket, download, beforeResolve) {
569
+ if (this.aborted) {
570
+ return Promise.reject((0, types_1.createAbortError)());
571
+ }
572
+ if ((service === 'gcp' || service === 'gcloud') && (0, types_1.isPlainObject)(credential)) {
573
+ credential.storageBucket || (credential.storageBucket = bucket);
574
+ }
575
+ let handler;
576
+ try {
577
+ handler = this.getDownloadHandler(service, credential).bind(this);
578
+ }
579
+ catch (err) {
580
+ this.formatMessage(64 /* LOG_TYPE.CLOUD */, service, ["Download function not supported" /* ERR_CLOUD.DOWNLOAD_SUPPORT */, bucket], Cloud.joinPath(download.pathname, download.filename), { ...Cloud.LOG_CLOUD_WARN });
581
+ return Promise.reject(err);
582
+ }
583
+ return new Promise((resolve, reject) => {
584
+ try {
585
+ handler({ bucket, download }, async (err, value) => {
586
+ if (err) {
587
+ reject(errorObject(err, service, "Download failed" /* ERR_CLOUD.DOWNLOAD_FAIL */));
588
+ }
589
+ else if (value) {
590
+ if (beforeResolve) {
591
+ const output = await beforeResolve(value);
592
+ if ((0, types_1.isString)(output)) {
593
+ value = output;
594
+ }
595
+ }
596
+ if (typeof value === 'string' && path.isAbsolute(value)) {
597
+ this.addLog(types_1.STATUS_TYPE.INFO, service + ' -> download -> ' + value);
598
+ this.downloaded.push(value);
599
+ }
600
+ resolve(value);
601
+ }
602
+ else {
603
+ reject((0, util_1.formatError)(service, "Download failed" /* ERR_CLOUD.DOWNLOAD_FAIL */));
604
+ }
605
+ });
606
+ }
607
+ catch (err) {
608
+ reject(err);
609
+ }
610
+ });
611
+ }
612
+ async getDatabaseRows(item, ignoreErrors, sessionKey) {
613
+ if (this.aborted) {
614
+ return Promise.reject((0, types_1.createAbortError)());
615
+ }
616
+ if (typeof ignoreErrors === 'string') {
617
+ sessionKey = ignoreErrors;
618
+ ignoreErrors = false;
619
+ }
620
+ const service = item.service;
621
+ if (this.hasCredential('database', item)) {
622
+ const host = SERVICE_CLIENT[service];
623
+ if (host?.executeQuery) {
624
+ const credential = this.getCredential(item);
625
+ if (item.options && this.hasCoerce(service, 'options', null, credential)) {
626
+ (0, types_1.coerceObject)(item.options);
627
+ }
628
+ if (ignoreErrors) {
629
+ return host.executeQuery.call(this, credential, item, sessionKey);
630
+ }
631
+ try {
632
+ return await host.executeQuery.call(this, credential, item, sessionKey);
633
+ }
634
+ catch (err) {
635
+ this.formatFail(64 /* LOG_TYPE.CLOUD */, service, "Unable to execute query" /* ERR_DB.EXEC_QUERY */, err, { ...Cloud.LOG_CLOUD_FAIL });
636
+ return Promise.reject(err);
637
+ }
638
+ }
639
+ return Promise.reject((0, util_1.formatError)(service, "Execute query not supported" /* ERR_CLOUD.EXECUTE_QUERY_SUPPORT */));
640
+ }
641
+ return Promise.reject((0, util_1.formatError)(service, "Invalid credentials" /* ERR_DB.CREDENTIALS */));
642
+ }
643
+ async getDatabaseBatchRows(batch, ignoreErrors, sessionKey) {
644
+ if (this.aborted) {
645
+ return Promise.reject((0, types_1.createAbortError)());
646
+ }
647
+ if (typeof ignoreErrors === 'string') {
648
+ sessionKey = ignoreErrors;
649
+ ignoreErrors = false;
650
+ }
651
+ const data = batch[0];
652
+ const service = data.service;
653
+ if (this.hasCredential('database', data)) {
654
+ const host = SERVICE_CLIENT[service];
655
+ if (host?.executeBatchQuery) {
656
+ const credential = this.getCredential(data);
657
+ if (this.hasCoerce(service, 'options', null, credential)) {
658
+ batch.forEach(item => item.options && (0, types_1.coerceObject)(item.options));
659
+ }
660
+ if (ignoreErrors) {
661
+ return host.executeBatchQuery.call(this, credential, batch, sessionKey);
662
+ }
663
+ try {
664
+ return await host.executeBatchQuery.call(this, credential, batch, sessionKey);
665
+ }
666
+ catch (err) {
667
+ this.formatFail(64 /* LOG_TYPE.CLOUD */, service, "Unable to execute query" /* ERR_DB.EXEC_QUERY */, err, { ...Cloud.LOG_CLOUD_FAIL });
668
+ return Promise.reject(err);
669
+ }
670
+ }
671
+ return Promise.reject((0, util_1.formatError)(service, "Execute query not supported" /* ERR_CLOUD.EXECUTE_QUERY_SUPPORT */));
672
+ }
673
+ return Promise.reject((0, util_1.formatError)(service, "Invalid credentials" /* ERR_DB.CREDENTIALS */));
674
+ }
675
+ getCredential(item, unused) {
676
+ let credential = item.credential, stored;
677
+ if (typeof credential === 'string') {
678
+ const settings = this.getSettings(item.service);
679
+ if ((0, types_1.isPlainObject)(settings)) {
680
+ credential = settings[credential];
681
+ stored = true;
682
+ }
683
+ }
684
+ if ((0, types_1.isPlainObject)(credential)) {
685
+ item.credential = credential;
686
+ if (this.settingsOf(item.service, 'coerce', 'credential') === true) {
687
+ (0, types_1.coerceObject)(credential, stored);
688
+ }
689
+ return unused ? credential : { ...credential };
690
+ }
691
+ return {};
692
+ }
693
+ getSettings(service) {
694
+ const settings = this.module;
695
+ switch (service) {
696
+ case 'az':
697
+ return settings.az || settings.azure;
698
+ case 'azure':
699
+ return settings.azure || settings.az;
700
+ case 'gcp':
701
+ return settings.gcp || settings.gcloud;
702
+ case 'gcloud':
703
+ return settings.gcloud || settings.gcp;
704
+ default:
705
+ return settings[service];
706
+ }
707
+ }
708
+ getStorage(action, data) {
709
+ if ((0, types_1.isArray)(data)) {
710
+ for (const item of data) {
711
+ const service = this.hasStorage(action, item);
712
+ if (service && service.active) { // eslint-disable-line @typescript-eslint/prefer-optional-chain
713
+ return item;
714
+ }
715
+ }
716
+ }
717
+ }
718
+ hasStorage(action, storage) {
719
+ switch (action) {
720
+ case 'upload':
721
+ break;
722
+ case 'download':
723
+ if (!storage.bucket) {
724
+ return false;
725
+ }
726
+ break;
727
+ default:
728
+ return false;
729
+ }
730
+ const result = storage[action];
731
+ return result && this.hasCredential('storage', storage) ? result : false;
732
+ }
733
+ hasCredential(feature, data, credential = this.getCredential(data, true)) {
734
+ var _a;
735
+ try {
736
+ const client = SERVICE_CLIENT[_a = data.service] || (SERVICE_CLIENT[_a] = require(this.resolveService(data.service)));
737
+ switch (feature) {
738
+ case 'storage':
739
+ return typeof client.validateStorage === 'function' && client.validateStorage(credential, data);
740
+ case 'database':
741
+ return typeof client.validateDatabase === 'function' && client.validateDatabase(credential, data);
742
+ }
743
+ }
744
+ catch (err) {
745
+ this.formatFail(64 /* LOG_TYPE.CLOUD */, data.service, "Cloud provider not found" /* ERR_CLOUD.PROVIDER_NOTFOUND */, err, { ...Cloud.LOG_CLOUD_FAIL });
746
+ }
747
+ return false;
748
+ }
749
+ getUploadHandler(service, credential) {
750
+ return (SERVICE_UPLOAD[service] || (SERVICE_UPLOAD[service] = require(this.resolveService(service, 'upload')))).call(this, credential, service);
751
+ }
752
+ getDownloadHandler(service, credential) {
753
+ return (SERVICE_DOWNLOAD[service] || (SERVICE_DOWNLOAD[service] = require(this.resolveService(service, 'download')))).call(this, credential, service);
754
+ }
755
+ resolveService(service, folder) {
756
+ let result, sep = path.sep;
757
+ if (service[0] === '@') {
758
+ result = service;
759
+ folder || (folder = 'client');
760
+ sep = '/';
761
+ }
762
+ else {
763
+ switch (service) {
764
+ case 'az':
765
+ service = 'azure';
766
+ break;
767
+ case 'gcloud':
768
+ service = 'gcp';
769
+ break;
770
+ }
771
+ if (!Cloud.isDir(result = path.join(__dirname, service))) {
772
+ result = service;
773
+ sep = '/';
774
+ }
775
+ }
776
+ return result + (folder ? sep + folder : '');
777
+ }
778
+ settingsOf(service, name, component) {
779
+ const settings = this.settings;
780
+ let options;
781
+ switch (service) {
782
+ case 'az':
783
+ options = settings.az ?? settings.azure;
784
+ break;
785
+ case 'azure':
786
+ options = settings.azure ?? settings.az;
787
+ break;
788
+ case 'gcp':
789
+ options = settings.gcp ?? settings.gcloud;
790
+ break;
791
+ case 'gcloud':
792
+ options = settings.gcloud ?? settings.gcp;
793
+ break;
794
+ default:
795
+ options = settings[service];
796
+ break;
797
+ }
798
+ const result = options?.[name];
799
+ return component ? (0, types_1.isObject)(result) ? result[component] : undefined : result;
800
+ }
801
+ commit() {
802
+ if (this.aborted) {
803
+ return Promise.reject((0, types_1.createAbortError)());
804
+ }
805
+ const items = this.pending.filter(item => !item.document).map(data => {
806
+ data.ignoreCache ?? (data.ignoreCache = true);
807
+ return this.getDatabaseRows(data, true);
808
+ });
809
+ return items.length === 0 ? Promise.resolve(false) : this.allSettled(items, ["Execute unassigned queries" /* CMD_DB.EXEC_QUERYUNASSIGNED */, this.moduleName]).then(result => result.length > 0).catch(() => false);
810
+ }
811
+ getClient(service) {
812
+ try {
813
+ return SERVICE_CLIENT[service] || (SERVICE_CLIENT[service] = require(this.resolveService(service)));
814
+ }
815
+ catch {
816
+ throw (0, util_1.formatError)(service, "Cloud provider not found" /* ERR_CLOUD.PROVIDER_NOTFOUND */);
817
+ }
818
+ }
819
+ }
820
+ Cloud.LOG_CLOUD_FAIL = core_1.ClientDb.LOG_STYLE_FAIL;
821
+ Cloud.LOG_CLOUD_COMMAND = Object.freeze({ titleColor: 'blue' });
822
+ Cloud.LOG_CLOUD_WARN = Object.freeze({ titleColor: 'yellow' });
823
+ Cloud.LOG_CLOUD_UPLOAD = Object.freeze({ titleColor: 'green' });
824
+ Cloud.LOG_CLOUD_DOWNLOAD = Object.freeze({ titleColor: 'cyan' });
825
+ Cloud.LOG_CLOUD_DELETE = Object.freeze({ titleColor: 'grey' });
826
+ Cloud.LOG_CLOUD_DELAYED = Object.freeze({ titleColor: 'grey' });
827
+ exports.default = Cloud;
828
+
829
+ if (exports.default) {
830
+ module.exports = exports.default;
831
+ module.exports.default = exports.default;
832
+ }