@naturalcycles/cloud-storage-lib 1.13.4 → 2.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.
@@ -1,8 +1,8 @@
1
1
  import type { Storage, StorageOptions } from '@google-cloud/storage';
2
- import { CommonLogger, LocalTimeInput } from '@naturalcycles/js-lib';
2
+ import type { CommonLogger, LocalTimeInput } from '@naturalcycles/js-lib';
3
3
  import type { ReadableBinary, ReadableTyped, WritableBinary } from '@naturalcycles/nodejs-lib';
4
- import type { CommonStorage, CommonStorageGetOptions, FileEntry } from './commonStorage';
5
- import type { GCPServiceAccount } from './model';
4
+ import type { CommonStorage, CommonStorageGetOptions, FileEntry } from './commonStorage.js';
5
+ import type { GCPServiceAccount } from './model.js';
6
6
  export type { Storage, StorageOptions, };
7
7
  /**
8
8
  * This object is intentionally made to NOT extend StorageOptions,
@@ -34,8 +34,8 @@ export declare class CloudStorage implements CommonStorage {
34
34
  cfg: CloudStorageCfg & {
35
35
  logger: CommonLogger;
36
36
  };
37
- static createFromGCPServiceAccount(credentials?: GCPServiceAccount, cfg?: CloudStorageCfg): CloudStorage;
38
- static createFromStorageOptions(storageOptions?: StorageOptions, cfg?: CloudStorageCfg): CloudStorage;
37
+ static createFromGCPServiceAccount(credentials?: GCPServiceAccount, cfg?: CloudStorageCfg): Promise<CloudStorage>;
38
+ static createFromStorageOptions(storageOptions?: StorageOptions, cfg?: CloudStorageCfg): Promise<CloudStorage>;
39
39
  /**
40
40
  * Passing the pre-created Storage allows to instantiate it from both
41
41
  * GCP Storage and FirebaseStorage.
@@ -1,7 +1,4 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CloudStorage = void 0;
4
- const js_lib_1 = require("@naturalcycles/js-lib");
1
+ import { _assert, _chunk, _since, _substringAfterLast, localTime, pMap, SKIP, } from '@naturalcycles/js-lib';
5
2
  const MAX_RECURSION_DEPTH = 10;
6
3
  const BATCH_SIZE = 32;
7
4
  /**
@@ -9,7 +6,8 @@ const BATCH_SIZE = 32;
9
6
  *
10
7
  * API: https://googleapis.dev/nodejs/storage/latest/index.html
11
8
  */
12
- class CloudStorage {
9
+ export class CloudStorage {
10
+ storage;
13
11
  constructor(storage, cfg = {}) {
14
12
  this.storage = storage;
15
13
  this.cfg = {
@@ -17,9 +15,10 @@ class CloudStorage {
17
15
  ...cfg,
18
16
  };
19
17
  }
20
- static createFromGCPServiceAccount(credentials, cfg) {
21
- const storageLib = require('@google-cloud/storage');
22
- const storage = new storageLib.Storage({
18
+ cfg;
19
+ static async createFromGCPServiceAccount(credentials, cfg) {
20
+ const { Storage } = await import('@google-cloud/storage');
21
+ const storage = new Storage({
23
22
  credentials,
24
23
  // Explicitly passing it here to fix this error:
25
24
  // Error: Unable to detect a Project Id in the current environment.
@@ -30,9 +29,9 @@ class CloudStorage {
30
29
  });
31
30
  return new CloudStorage(storage, cfg);
32
31
  }
33
- static createFromStorageOptions(storageOptions, cfg) {
34
- const storageLib = require('@google-cloud/storage');
35
- const storage = new storageLib.Storage(storageOptions);
32
+ static async createFromStorageOptions(storageOptions, cfg) {
33
+ const { Storage } = await import('@google-cloud/storage');
34
+ const storage = new Storage(storageOptions);
36
35
  return new CloudStorage(storage, cfg);
37
36
  }
38
37
  /**
@@ -50,7 +49,7 @@ class CloudStorage {
50
49
  }
51
50
  async deletePaths(bucketName, prefixes) {
52
51
  const bucket = this.storage.bucket(bucketName);
53
- await (0, js_lib_1.pMap)(prefixes, async (prefix) => {
52
+ await pMap(prefixes, async (prefix) => {
54
53
  await bucket.deleteFiles({
55
54
  prefix,
56
55
  // to keep going in case error occurs, similar to THROW_AGGREGATED
@@ -72,7 +71,7 @@ class CloudStorage {
72
71
  // It doesn't make sense to return or do anything with them
73
72
  return files.map(f => f.name).filter(s => !s.endsWith('/'));
74
73
  }
75
- return files.map(f => (0, js_lib_1._substringAfterLast)(f.name, '/')).filter(Boolean);
74
+ return files.map(f => _substringAfterLast(f.name, '/')).filter(Boolean);
76
75
  }
77
76
  getFileNamesStream(bucketName, opt = {}) {
78
77
  const { prefix, fullPaths = true } = opt;
@@ -81,7 +80,7 @@ class CloudStorage {
81
80
  maxResults: opt.limit || undefined,
82
81
  }).flatMap(f => {
83
82
  const r = this.normalizeFilename(f.name, fullPaths);
84
- if (r === js_lib_1.SKIP)
83
+ if (r === SKIP)
85
84
  return [];
86
85
  return [r];
87
86
  });
@@ -93,7 +92,7 @@ class CloudStorage {
93
92
  maxResults: opt.limit || undefined,
94
93
  }).flatMap(async (f) => {
95
94
  const filePath = this.normalizeFilename(f.name, fullPaths);
96
- if (filePath === js_lib_1.SKIP)
95
+ if (filePath === SKIP)
97
96
  return [];
98
97
  const [content] = await f.download();
99
98
  return [{ filePath, content }];
@@ -151,8 +150,8 @@ class CloudStorage {
151
150
  .move(this.storage.bucket(toBucket || fromBucket).file(toPath));
152
151
  }
153
152
  async movePath(fromBucket, fromPrefix, toPrefix, toBucket) {
154
- (0, js_lib_1._assert)(fromPrefix.endsWith('/'), 'fromPrefix should end with `/`');
155
- (0, js_lib_1._assert)(toPrefix.endsWith('/'), 'toPrefix should end with `/`');
153
+ _assert(fromPrefix.endsWith('/'), 'fromPrefix should end with `/`');
154
+ _assert(toPrefix.endsWith('/'), 'toPrefix should end with `/`');
156
155
  await this.storage
157
156
  .bucket(fromBucket)
158
157
  .getFilesStream({
@@ -165,12 +164,12 @@ class CloudStorage {
165
164
  });
166
165
  }
167
166
  async deleteFiles(bucketName, filePaths) {
168
- await (0, js_lib_1.pMap)(filePaths, async (filePath) => {
167
+ await pMap(filePaths, async (filePath) => {
169
168
  await this.storage.bucket(bucketName).file(filePath).delete();
170
169
  });
171
170
  }
172
171
  async combineFiles(bucketName, filePaths, toPath, toBucket, currentRecursionDepth = 0) {
173
- (0, js_lib_1._assert)(currentRecursionDepth <= MAX_RECURSION_DEPTH, `combineFiles reached max recursion depth of ${MAX_RECURSION_DEPTH}`);
172
+ _assert(currentRecursionDepth <= MAX_RECURSION_DEPTH, `combineFiles reached max recursion depth of ${MAX_RECURSION_DEPTH}`);
174
173
  const { logger, debug } = this.cfg;
175
174
  if (filePaths.length === 0) {
176
175
  if (debug) {
@@ -193,7 +192,7 @@ class CloudStorage {
193
192
  return;
194
193
  }
195
194
  const started = Date.now();
196
- await (0, js_lib_1.pMap)((0, js_lib_1._chunk)(filePaths, BATCH_SIZE), async (fileBatch, i) => {
195
+ await pMap(_chunk(filePaths, BATCH_SIZE), async (fileBatch, i) => {
197
196
  if (debug) {
198
197
  logger.log(`[${currentRecursionDepth}] Composing batch ${i + 1}...`);
199
198
  }
@@ -205,7 +204,7 @@ class CloudStorage {
205
204
  await this.deleteFiles(bucketName, fileBatch);
206
205
  });
207
206
  if (debug) {
208
- logger.log(`[${currentRecursionDepth}] Batch composed into ${intermediateFiles.length} files, in ${(0, js_lib_1._since)(started)}`);
207
+ logger.log(`[${currentRecursionDepth}] Batch composed into ${intermediateFiles.length} files, in ${_since(started)}`);
209
208
  }
210
209
  await this.combineFiles(toBucket || bucketName, intermediateFiles, toPath, toBucket, currentRecursionDepth + 1);
211
210
  }
@@ -227,7 +226,7 @@ class CloudStorage {
227
226
  .getSignedUrl({
228
227
  action: 'read',
229
228
  version: 'v4',
230
- expires: (0, js_lib_1.localTime)(expires).unixMillis,
229
+ expires: localTime(expires).unixMillis,
231
230
  });
232
231
  return url;
233
232
  }
@@ -238,11 +237,10 @@ class CloudStorage {
238
237
  normalizeFilename(fileName, fullPaths) {
239
238
  if (fullPaths) {
240
239
  if (fileName.endsWith('/'))
241
- return js_lib_1.SKIP; // skip folders
240
+ return SKIP; // skip folders
242
241
  return fileName;
243
242
  }
244
- fileName = (0, js_lib_1._substringAfterLast)(fileName, '/');
245
- return fileName || js_lib_1.SKIP; // skip folders
243
+ fileName = _substringAfterLast(fileName, '/');
244
+ return fileName || SKIP; // skip folders
246
245
  }
247
246
  }
248
- exports.CloudStorage = CloudStorage;
@@ -1,2 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ export {};
@@ -1,6 +1,6 @@
1
- import { Readable, Writable } from 'node:stream';
2
- import { ReadableTyped } from '@naturalcycles/nodejs-lib';
3
- import { CommonStorage, CommonStorageGetOptions, FileEntry } from './commonStorage';
1
+ import type { Readable, Writable } from 'node:stream';
2
+ import type { ReadableTyped } from '@naturalcycles/nodejs-lib';
3
+ import type { CommonStorage, CommonStorageGetOptions, FileEntry } from './commonStorage.js';
4
4
  export interface CommonStorageBucketCfg {
5
5
  storage: CommonStorage;
6
6
  bucketName: string;
@@ -1,13 +1,11 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CommonStorageBucket = void 0;
4
- const js_lib_1 = require("@naturalcycles/js-lib");
1
+ import { AppError, pMap } from '@naturalcycles/js-lib';
5
2
  /**
6
3
  * Convenience wrapper around CommonStorage for a given Bucket.
7
4
  *
8
5
  * Similar to what CommonDao is to CommonDB.
9
6
  */
10
- class CommonStorageBucket {
7
+ export class CommonStorageBucket {
8
+ cfg;
11
9
  constructor(cfg) {
12
10
  this.cfg = cfg;
13
11
  }
@@ -45,27 +43,27 @@ class CommonStorageBucket {
45
43
  return v ?? this.throwRequiredError(filePath);
46
44
  }
47
45
  throwRequiredError(filePath) {
48
- throw new js_lib_1.AppError(`File required, but not found: ${this.cfg.bucketName}/${filePath}`, {
46
+ throw new AppError(`File required, but not found: ${this.cfg.bucketName}/${filePath}`, {
49
47
  code: 'FILE_REQUIRED',
50
48
  });
51
49
  }
52
50
  async getFileContents(paths) {
53
- return (await (0, js_lib_1.pMap)(paths, async (filePath) => (await this.cfg.storage.getFile(this.cfg.bucketName, filePath)))).filter(Boolean);
51
+ return (await pMap(paths, async (filePath) => (await this.cfg.storage.getFile(this.cfg.bucketName, filePath)))).filter(Boolean);
54
52
  }
55
53
  async getFileContentsAsJson(paths) {
56
- return (await (0, js_lib_1.pMap)(paths, async (filePath) => {
54
+ return (await pMap(paths, async (filePath) => {
57
55
  const buf = await this.cfg.storage.getFile(this.cfg.bucketName, filePath);
58
56
  return buf ? JSON.parse(buf.toString()) : null;
59
57
  })).filter(Boolean);
60
58
  }
61
59
  async getFileEntries(paths) {
62
- return (await (0, js_lib_1.pMap)(paths, async (filePath) => {
60
+ return (await pMap(paths, async (filePath) => {
63
61
  const content = await this.cfg.storage.getFile(this.cfg.bucketName, filePath);
64
62
  return { filePath, content: content };
65
63
  })).filter(f => f.content);
66
64
  }
67
65
  async getFileEntriesAsJson(paths) {
68
- return (await (0, js_lib_1.pMap)(paths, async (filePath) => {
66
+ return (await pMap(paths, async (filePath) => {
69
67
  const buf = await this.cfg.storage.getFile(this.cfg.bucketName, filePath);
70
68
  return buf ? { filePath, content: JSON.parse(buf.toString()) } : null;
71
69
  })).filter(Boolean);
@@ -89,7 +87,7 @@ class CommonStorageBucket {
89
87
  await this.cfg.storage.saveFile(this.cfg.bucketName, filePath, Buffer.from(JSON.stringify(content)));
90
88
  }
91
89
  async saveFiles(entries) {
92
- await (0, js_lib_1.pMap)(entries, async (f) => {
90
+ await pMap(entries, async (f) => {
93
91
  await this.cfg.storage.saveFile(this.cfg.bucketName, f.filePath, f.content);
94
92
  });
95
93
  }
@@ -100,7 +98,7 @@ class CommonStorageBucket {
100
98
  return await this.cfg.storage.deletePath(this.cfg.bucketName, prefix);
101
99
  }
102
100
  async deletePaths(prefixes) {
103
- await (0, js_lib_1.pMap)(prefixes, async (prefix) => {
101
+ await pMap(prefixes, async (prefix) => {
104
102
  return await this.cfg.storage.deletePath(this.cfg.bucketName, prefix);
105
103
  });
106
104
  }
@@ -143,4 +141,3 @@ class CommonStorageBucket {
143
141
  await this.cfg.storage.moveFile(this.cfg.bucketName, fromPath, toPath, toBucket);
144
142
  }
145
143
  }
146
- exports.CommonStorageBucket = CommonStorageBucket;
@@ -1,7 +1,7 @@
1
- import { CommonDBCreateOptions, CommonKeyValueDB, KeyValueDBTuple } from '@naturalcycles/db-lib';
2
- import { IncrementTuple } from '@naturalcycles/db-lib/dist/kv/commonKeyValueDB';
3
- import { ReadableTyped } from '@naturalcycles/nodejs-lib';
4
- import { CommonStorage } from './commonStorage';
1
+ import type { CommonDBCreateOptions, CommonKeyValueDB, KeyValueDBTuple } from '@naturalcycles/db-lib';
2
+ import type { IncrementTuple } from '@naturalcycles/db-lib/dist/kv/commonKeyValueDB.js';
3
+ import type { ReadableTyped } from '@naturalcycles/nodejs-lib';
4
+ import type { CommonStorage } from './commonStorage.js';
5
5
  export interface CommonStorageKeyValueDBCfg {
6
6
  storage: CommonStorage;
7
7
  bucketName: string;
@@ -1,8 +1,5 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.CommonStorageKeyValueDB = void 0;
4
- const db_lib_1 = require("@naturalcycles/db-lib");
5
- const js_lib_1 = require("@naturalcycles/js-lib");
1
+ import { commonKeyValueDBFullSupport } from '@naturalcycles/db-lib';
2
+ import { AppError, pMap } from '@naturalcycles/js-lib';
6
3
  /**
7
4
  * CommonKeyValueDB, backed up by a CommonStorage implementation.
8
5
  *
@@ -11,14 +8,15 @@ const js_lib_1 = require("@naturalcycles/js-lib");
11
8
  * fileName is ${id} (without extension)
12
9
  * file contents is ${v} (Buffer)
13
10
  */
14
- class CommonStorageKeyValueDB {
11
+ export class CommonStorageKeyValueDB {
12
+ cfg;
15
13
  constructor(cfg) {
16
14
  this.cfg = cfg;
17
- this.support = {
18
- ...db_lib_1.commonKeyValueDBFullSupport,
19
- increment: false,
20
- };
21
15
  }
16
+ support = {
17
+ ...commonKeyValueDBFullSupport,
18
+ increment: false,
19
+ };
22
20
  async ping() {
23
21
  await this.cfg.storage.ping(this.cfg.bucketName);
24
22
  }
@@ -44,14 +42,14 @@ class CommonStorageKeyValueDB {
44
42
  }
45
43
  async deleteByIds(table, ids) {
46
44
  const { bucketName, prefix } = this.getBucketAndPrefix(table);
47
- await (0, js_lib_1.pMap)(ids, async (id) => {
45
+ await pMap(ids, async (id) => {
48
46
  await this.cfg.storage.deletePath(bucketName, [prefix, id].join('/'));
49
47
  });
50
48
  }
51
49
  async getByIds(table, ids) {
52
50
  const { bucketName, prefix } = this.getBucketAndPrefix(table);
53
51
  const map = {};
54
- await (0, js_lib_1.pMap)(ids, async (id) => {
52
+ await pMap(ids, async (id) => {
55
53
  const buf = await this.cfg.storage.getFile(bucketName, [prefix, id].join('/'));
56
54
  if (buf)
57
55
  map[id] = buf;
@@ -60,7 +58,7 @@ class CommonStorageKeyValueDB {
60
58
  }
61
59
  async saveBatch(table, entries) {
62
60
  const { bucketName, prefix } = this.getBucketAndPrefix(table);
63
- await (0, js_lib_1.pMap)(entries, async ([id, content]) => {
61
+ await pMap(entries, async ([id, content]) => {
64
62
  await this.cfg.storage.saveFile(bucketName, [prefix, id].join('/'), content);
65
63
  });
66
64
  }
@@ -83,7 +81,6 @@ class CommonStorageKeyValueDB {
83
81
  return (await this.cfg.storage.getFileNames(bucketName, { prefix })).length;
84
82
  }
85
83
  async incrementBatch(_table, _entries) {
86
- throw new js_lib_1.AppError('CommonStorageKeyValueDB.incrementBatch() is not implemented');
84
+ throw new AppError('CommonStorageKeyValueDB.incrementBatch() is not implemented');
87
85
  }
88
86
  }
89
- exports.CommonStorageKeyValueDB = CommonStorageKeyValueDB;
@@ -1,6 +1,6 @@
1
- import { LocalTimeInput, StringMap } from '@naturalcycles/js-lib';
2
- import { ReadableBinary, ReadableTyped, WritableBinary } from '@naturalcycles/nodejs-lib';
3
- import { CommonStorage, CommonStorageGetOptions, FileEntry } from './commonStorage';
1
+ import type { LocalTimeInput, StringMap } from '@naturalcycles/js-lib';
2
+ import type { ReadableBinary, ReadableTyped, WritableBinary } from '@naturalcycles/nodejs-lib';
3
+ import type { CommonStorage, CommonStorageGetOptions, FileEntry } from './commonStorage.js';
4
4
  export declare class InMemoryCommonStorage implements CommonStorage {
5
5
  /**
6
6
  * data[bucketName][filePath] = Buffer
@@ -1,22 +1,17 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.InMemoryCommonStorage = void 0;
4
- const js_lib_1 = require("@naturalcycles/js-lib");
5
- const nodejs_lib_1 = require("@naturalcycles/nodejs-lib");
6
- class InMemoryCommonStorage {
7
- constructor() {
8
- /**
9
- * data[bucketName][filePath] = Buffer
10
- */
11
- this.data = {};
12
- this.publicMap = {};
13
- }
1
+ import { _assert, _isTruthy, _stringMapEntries, _substringAfterLast, localTime, } from '@naturalcycles/js-lib';
2
+ import { fs2, md5, readableFrom } from '@naturalcycles/nodejs-lib';
3
+ export class InMemoryCommonStorage {
4
+ /**
5
+ * data[bucketName][filePath] = Buffer
6
+ */
7
+ data = {};
8
+ publicMap = {};
14
9
  async ping() { }
15
10
  async getBucketNames() {
16
11
  return Object.keys(this.data);
17
12
  }
18
13
  getBucketNamesStream() {
19
- return (0, nodejs_lib_1.readableFrom)(Object.keys(this.data));
14
+ return readableFrom(Object.keys(this.data));
20
15
  }
21
16
  async fileExists(bucketName, filePath) {
22
17
  return !!this.data[bucketName]?.[filePath];
@@ -47,35 +42,35 @@ class InMemoryCommonStorage {
47
42
  const { prefix = '', fullPaths = true } = opt;
48
43
  return Object.keys(this.data[bucketName] || {})
49
44
  .filter(filePath => filePath.startsWith(prefix))
50
- .map(f => (fullPaths ? f : (0, js_lib_1._substringAfterLast)(f, '/')));
45
+ .map(f => (fullPaths ? f : _substringAfterLast(f, '/')));
51
46
  }
52
47
  getFileNamesStream(bucketName, opt = {}) {
53
48
  const { prefix = '', fullPaths = true } = opt;
54
- return (0, nodejs_lib_1.readableFrom)(Object.keys(this.data[bucketName] || {})
49
+ return readableFrom(Object.keys(this.data[bucketName] || {})
55
50
  .filter(filePath => filePath.startsWith(prefix))
56
51
  .slice(0, opt.limit)
57
- .map(n => (fullPaths ? n : (0, js_lib_1._substringAfterLast)(n, '/'))));
52
+ .map(n => (fullPaths ? n : _substringAfterLast(n, '/'))));
58
53
  }
59
54
  getFilesStream(bucketName, opt = {}) {
60
55
  const { prefix = '', fullPaths = true } = opt;
61
- return (0, nodejs_lib_1.readableFrom)((0, js_lib_1._stringMapEntries)(this.data[bucketName] || {})
56
+ return readableFrom(_stringMapEntries(this.data[bucketName] || {})
62
57
  .map(([filePath, content]) => ({
63
58
  filePath,
64
59
  content,
65
60
  }))
66
61
  .filter(f => f.filePath.startsWith(prefix))
67
62
  .slice(0, opt.limit)
68
- .map(f => (fullPaths ? f : { ...f, filePath: (0, js_lib_1._substringAfterLast)(f.filePath, '/') })));
63
+ .map(f => (fullPaths ? f : { ...f, filePath: _substringAfterLast(f.filePath, '/') })));
69
64
  }
70
65
  getFileReadStream(bucketName, filePath) {
71
- return (0, nodejs_lib_1.readableFrom)(this.data[bucketName][filePath]);
66
+ return readableFrom(this.data[bucketName][filePath]);
72
67
  }
73
68
  getFileWriteStream(_bucketName, _filePath) {
74
69
  throw new Error('Method not implemented.');
75
70
  }
76
71
  async uploadFile(localFilePath, bucketName, bucketFilePath) {
77
72
  this.data[bucketName] ||= {};
78
- this.data[bucketName][bucketFilePath] = await nodejs_lib_1.fs2.readBufferAsync(localFilePath);
73
+ this.data[bucketName][bucketFilePath] = await fs2.readBufferAsync(localFilePath);
79
74
  }
80
75
  async setFileVisibility(bucketName, filePath, isPublic) {
81
76
  this.publicMap[bucketName] ||= {};
@@ -101,7 +96,7 @@ class InMemoryCommonStorage {
101
96
  const tob = toBucket || fromBucket;
102
97
  this.data[fromBucket] ||= {};
103
98
  this.data[tob] ||= {};
104
- (0, js_lib_1._stringMapEntries)(this.data[fromBucket]).forEach(([filePath, v]) => {
99
+ _stringMapEntries(this.data[fromBucket]).forEach(([filePath, v]) => {
105
100
  if (!filePath.startsWith(fromPrefix))
106
101
  return;
107
102
  this.data[tob][toPrefix + filePath.slice(fromPrefix.length)] = v;
@@ -117,15 +112,14 @@ class InMemoryCommonStorage {
117
112
  return;
118
113
  const tob = toBucket || bucketName;
119
114
  this.data[tob] ||= {};
120
- this.data[tob][toPath] = Buffer.concat(filePaths.map(p => this.data[bucketName][p]).filter(js_lib_1._isTruthy));
115
+ this.data[tob][toPath] = Buffer.concat(filePaths.map(p => this.data[bucketName][p]).filter(_isTruthy));
121
116
  // delete source files
122
117
  filePaths.forEach(p => delete this.data[bucketName][p]);
123
118
  }
124
119
  async getSignedUrl(bucketName, filePath, expires) {
125
120
  const buf = this.data[bucketName]?.[filePath];
126
- (0, js_lib_1._assert)(buf, `getSignedUrl file not found: ${bucketName}/${filePath}`);
127
- const signature = (0, nodejs_lib_1.md5)(buf);
128
- return `https://testurl.com/${bucketName}/${filePath}?expires=${(0, js_lib_1.localTime)(expires).unix}&signature=${signature}`;
121
+ _assert(buf, `getSignedUrl file not found: ${bucketName}/${filePath}`);
122
+ const signature = md5(buf);
123
+ return `https://testurl.com/${bucketName}/${filePath}?expires=${localTime(expires).unix}&signature=${signature}`;
129
124
  }
130
125
  }
131
- exports.InMemoryCommonStorage = InMemoryCommonStorage;
package/dist/index.d.ts CHANGED
@@ -1,7 +1,6 @@
1
- export * from './cloudStorage';
2
- export * from './commonStorage';
3
- export * from './commonStorageBucket';
4
- export * from './commonStorageKeyValueDB';
5
- export * from './inMemoryCommonStorage';
6
- export * from './model';
7
- export * from './testing/commonStorageTest';
1
+ export * from './cloudStorage.js';
2
+ export * from './commonStorage.js';
3
+ export * from './commonStorageBucket.js';
4
+ export * from './commonStorageKeyValueDB.js';
5
+ export * from './inMemoryCommonStorage.js';
6
+ export * from './model.js';
package/dist/index.js CHANGED
@@ -1,10 +1,6 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const tslib_1 = require("tslib");
4
- tslib_1.__exportStar(require("./cloudStorage"), exports);
5
- tslib_1.__exportStar(require("./commonStorage"), exports);
6
- tslib_1.__exportStar(require("./commonStorageBucket"), exports);
7
- tslib_1.__exportStar(require("./commonStorageKeyValueDB"), exports);
8
- tslib_1.__exportStar(require("./inMemoryCommonStorage"), exports);
9
- tslib_1.__exportStar(require("./model"), exports);
10
- tslib_1.__exportStar(require("./testing/commonStorageTest"), exports);
1
+ export * from './cloudStorage.js';
2
+ export * from './commonStorage.js';
3
+ export * from './commonStorageBucket.js';
4
+ export * from './commonStorageKeyValueDB.js';
5
+ export * from './inMemoryCommonStorage.js';
6
+ export * from './model.js';
package/dist/model.js CHANGED
@@ -1,2 +1 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
1
+ export {};
@@ -1,5 +1,5 @@
1
- import { CommonStorage } from '../commonStorage';
1
+ import type { CommonStorage } from '../commonStorage.js';
2
2
  /**
3
3
  * This test suite must be idempotent.
4
4
  */
5
- export declare function runCommonStorageTest(storage: CommonStorage, bucketName: string): void;
5
+ export declare function runCommonStorageTest(storage: CommonStorage, bucketName: string): Promise<void>;
@@ -1,20 +1,17 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.runCommonStorageTest = runCommonStorageTest;
4
- const js_lib_1 = require("@naturalcycles/js-lib");
1
+ import { _range, _substringAfterLast, pMap } from '@naturalcycles/js-lib';
5
2
  const TEST_FOLDER = 'test/subdir';
6
- const TEST_ITEMS = (0, js_lib_1._range)(10).map(n => ({
3
+ const TEST_ITEMS = _range(10).map(n => ({
7
4
  id: `id_${n + 1}`,
8
5
  n,
9
6
  even: n % 2 === 0,
10
7
  }));
11
- const TEST_ITEMS2 = (0, js_lib_1._range)(10).map(n => ({
8
+ const TEST_ITEMS2 = _range(10).map(n => ({
12
9
  fileType: 2,
13
10
  id: `id_${n + 1}`,
14
11
  n,
15
12
  even: n % 2 === 0,
16
13
  }));
17
- const TEST_ITEMS3 = (0, js_lib_1._range)(10).map(n => ({
14
+ const TEST_ITEMS3 = _range(10).map(n => ({
18
15
  fileType: 3,
19
16
  id: `id_${n + 1}`,
20
17
  n,
@@ -27,7 +24,9 @@ const TEST_FILES = [TEST_ITEMS, TEST_ITEMS2, TEST_ITEMS3].map((obj, i) => ({
27
24
  /**
28
25
  * This test suite must be idempotent.
29
26
  */
30
- function runCommonStorageTest(storage, bucketName) {
27
+ export async function runCommonStorageTest(storage, bucketName) {
28
+ // this is because vitest cannot be "required" from cjs
29
+ const { test, expect } = await import('vitest');
31
30
  // test('createBucket', async () => {
32
31
  // await storage.createBucket(bucketName)
33
32
  // })
@@ -44,7 +43,7 @@ function runCommonStorageTest(storage, bucketName) {
44
43
  // console.log(buckets)
45
44
  // })
46
45
  test('prepare: clear bucket', async () => {
47
- await (0, js_lib_1.pMap)(TEST_FILES.map(f => f.filePath), async (filePath) => await storage.deletePath(bucketName, filePath));
46
+ await pMap(TEST_FILES.map(f => f.filePath), async (filePath) => await storage.deletePath(bucketName, filePath));
48
47
  });
49
48
  // test('listFileNames on root should return empty', async () => {
50
49
  // const fileNames = await storage.getFileNames(bucketName)
@@ -61,7 +60,7 @@ function runCommonStorageTest(storage, bucketName) {
61
60
  expect(fileNames).toEqual([]);
62
61
  });
63
62
  test(`exists should return empty array`, async () => {
64
- await (0, js_lib_1.pMap)(TEST_FILES, async (f) => {
63
+ await pMap(TEST_FILES, async (f) => {
65
64
  const exists = await storage.fileExists(bucketName, f.filePath);
66
65
  expect(exists).toBe(false);
67
66
  });
@@ -69,12 +68,12 @@ function runCommonStorageTest(storage, bucketName) {
69
68
  test(`saveFiles, then listFileNames, streamFileNames and getFiles should return just saved files`, async () => {
70
69
  const testFilesMap = Object.fromEntries(TEST_FILES.map(f => [f.filePath, f.content]));
71
70
  // It's done in the same test to ensure "strong consistency"
72
- await (0, js_lib_1.pMap)(TEST_FILES, async (f) => await storage.saveFile(bucketName, f.filePath, f.content));
71
+ await pMap(TEST_FILES, async (f) => await storage.saveFile(bucketName, f.filePath, f.content));
73
72
  const fileNamesShort = await storage.getFileNames(bucketName, {
74
73
  prefix: TEST_FOLDER,
75
74
  fullPaths: false,
76
75
  });
77
- expect(fileNamesShort.sort()).toEqual(TEST_FILES.map(f => (0, js_lib_1._substringAfterLast)(f.filePath, '/')).sort());
76
+ expect(fileNamesShort.sort()).toEqual(TEST_FILES.map(f => _substringAfterLast(f.filePath, '/')).sort());
78
77
  const fileNames = await storage.getFileNames(bucketName, { prefix: TEST_FOLDER });
79
78
  expect(fileNames.sort()).toEqual(TEST_FILES.map(f => f.filePath).sort());
80
79
  const streamedFileNames = await storage
@@ -82,11 +81,11 @@ function runCommonStorageTest(storage, bucketName) {
82
81
  .toArray();
83
82
  expect(streamedFileNames.sort()).toEqual(TEST_FILES.map(f => f.filePath).sort());
84
83
  const filesMap = {};
85
- await (0, js_lib_1.pMap)(fileNames, async (filePath) => {
84
+ await pMap(fileNames, async (filePath) => {
86
85
  filesMap[filePath] = (await storage.getFile(bucketName, filePath));
87
86
  });
88
87
  expect(filesMap).toEqual(testFilesMap);
89
- await (0, js_lib_1.pMap)(fileNames, async (filePath) => {
88
+ await pMap(fileNames, async (filePath) => {
90
89
  const exists = await storage.fileExists(bucketName, filePath);
91
90
  expect(exists).toBe(true);
92
91
  });
@@ -0,0 +1 @@
1
+ export * from './commonStorageTest.js';
@@ -0,0 +1 @@
1
+ export * from './commonStorageTest.js';
package/package.json CHANGED
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "name": "@naturalcycles/cloud-storage-lib",
3
+ "type": "module",
3
4
  "scripts": {
4
5
  "prepare": "husky",
5
6
  "build": "dev-lib build",
@@ -9,16 +10,18 @@
9
10
  "lbt": "dev-lib lbt"
10
11
  },
11
12
  "dependencies": {
12
- "@google-cloud/storage": "^7.0.0",
13
- "@naturalcycles/db-lib": "^9.1.0",
14
- "@naturalcycles/js-lib": "^14.41.0",
15
- "@naturalcycles/nodejs-lib": "^13.1.0"
13
+ "@google-cloud/storage": "^7",
14
+ "@naturalcycles/db-lib": "^10",
15
+ "@naturalcycles/js-lib": "^14",
16
+ "@naturalcycles/nodejs-lib": "^13"
16
17
  },
17
18
  "devDependencies": {
18
- "@naturalcycles/dev-lib": "^15.18.0",
19
- "@types/node": "^22.7.4",
20
- "firebase-admin": "^12.0.0",
21
- "jest": "^29.1.2"
19
+ "@naturalcycles/dev-lib": "^17",
20
+ "@types/node": "^22",
21
+ "@vitest/coverage-v8": "^3",
22
+ "firebase-admin": "^13",
23
+ "tsx": "^4",
24
+ "vitest": "^3"
22
25
  },
23
26
  "files": [
24
27
  "dist",
@@ -38,9 +41,9 @@
38
41
  "url": "https://github.com/NaturalCycles/cloud-storage-lib"
39
42
  },
40
43
  "engines": {
41
- "node": ">=20.13.0"
44
+ "node": ">=22.12.0"
42
45
  },
43
- "version": "1.13.4",
46
+ "version": "2.0.1",
44
47
  "description": "CommonStorage implementation based on Google Cloud Storage",
45
48
  "author": "Natural Cycles Team",
46
49
  "license": "MIT"
@@ -1,21 +1,17 @@
1
- // eslint-disable-next-line import-x/no-duplicates
2
1
  import type { File, Storage, StorageOptions } from '@google-cloud/storage'
3
- // eslint-disable-next-line import-x/no-duplicates
4
- import type * as StorageLib from '@google-cloud/storage'
2
+ import type { CommonLogger, LocalTimeInput, UnixTimestampMillis } from '@naturalcycles/js-lib'
5
3
  import {
6
4
  _assert,
7
5
  _chunk,
8
6
  _since,
9
7
  _substringAfterLast,
10
- CommonLogger,
11
8
  localTime,
12
- LocalTimeInput,
13
9
  pMap,
14
10
  SKIP,
15
11
  } from '@naturalcycles/js-lib'
16
12
  import type { ReadableBinary, ReadableTyped, WritableBinary } from '@naturalcycles/nodejs-lib'
17
- import type { CommonStorage, CommonStorageGetOptions, FileEntry } from './commonStorage'
18
- import type { GCPServiceAccount } from './model'
13
+ import type { CommonStorage, CommonStorageGetOptions, FileEntry } from './commonStorage.js'
14
+ import type { GCPServiceAccount } from './model.js'
19
15
 
20
16
  export type {
21
17
  // This is the latest version, to be imported by consumers
@@ -67,13 +63,13 @@ export class CloudStorage implements CommonStorage {
67
63
  logger: CommonLogger
68
64
  }
69
65
 
70
- static createFromGCPServiceAccount(
66
+ static async createFromGCPServiceAccount(
71
67
  credentials?: GCPServiceAccount,
72
68
  cfg?: CloudStorageCfg,
73
- ): CloudStorage {
74
- const storageLib = require('@google-cloud/storage') as typeof StorageLib
69
+ ): Promise<CloudStorage> {
70
+ const { Storage } = await import('@google-cloud/storage')
75
71
 
76
- const storage = new storageLib.Storage({
72
+ const storage = new Storage({
77
73
  credentials,
78
74
  // Explicitly passing it here to fix this error:
79
75
  // Error: Unable to detect a Project Id in the current environment.
@@ -86,12 +82,12 @@ export class CloudStorage implements CommonStorage {
86
82
  return new CloudStorage(storage, cfg)
87
83
  }
88
84
 
89
- static createFromStorageOptions(
85
+ static async createFromStorageOptions(
90
86
  storageOptions?: StorageOptions,
91
87
  cfg?: CloudStorageCfg,
92
- ): CloudStorage {
93
- const storageLib = require('@google-cloud/storage') as typeof StorageLib
94
- const storage = new storageLib.Storage(storageOptions)
88
+ ): Promise<CloudStorage> {
89
+ const { Storage } = await import('@google-cloud/storage')
90
+ const storage = new Storage(storageOptions)
95
91
  return new CloudStorage(storage, cfg)
96
92
  }
97
93
 
@@ -319,7 +315,7 @@ export class CloudStorage implements CommonStorage {
319
315
  return
320
316
  }
321
317
 
322
- const started = Date.now()
318
+ const started = Date.now() as UnixTimestampMillis
323
319
  await pMap(_chunk(filePaths, BATCH_SIZE), async (fileBatch, i) => {
324
320
  if (debug) {
325
321
  logger.log(`[${currentRecursionDepth}] Composing batch ${i + 1}...`)
@@ -1,7 +1,7 @@
1
- import { Readable, Writable } from 'node:stream'
1
+ import type { Readable, Writable } from 'node:stream'
2
2
  import { AppError, pMap } from '@naturalcycles/js-lib'
3
- import { ReadableTyped } from '@naturalcycles/nodejs-lib'
4
- import { CommonStorage, CommonStorageGetOptions, FileEntry } from './commonStorage'
3
+ import type { ReadableTyped } from '@naturalcycles/nodejs-lib'
4
+ import type { CommonStorage, CommonStorageGetOptions, FileEntry } from './commonStorage.js'
5
5
 
6
6
  export interface CommonStorageBucketCfg {
7
7
  storage: CommonStorage
@@ -1,13 +1,14 @@
1
- import {
1
+ import type {
2
2
  CommonDBCreateOptions,
3
3
  CommonKeyValueDB,
4
- commonKeyValueDBFullSupport,
5
4
  KeyValueDBTuple,
6
5
  } from '@naturalcycles/db-lib'
7
- import { IncrementTuple } from '@naturalcycles/db-lib/dist/kv/commonKeyValueDB'
8
- import { AppError, pMap, StringMap } from '@naturalcycles/js-lib'
9
- import { ReadableTyped } from '@naturalcycles/nodejs-lib'
10
- import { CommonStorage } from './commonStorage'
6
+ import { commonKeyValueDBFullSupport } from '@naturalcycles/db-lib'
7
+ import type { IncrementTuple } from '@naturalcycles/db-lib/dist/kv/commonKeyValueDB.js'
8
+ import type { StringMap } from '@naturalcycles/js-lib'
9
+ import { AppError, pMap } from '@naturalcycles/js-lib'
10
+ import type { ReadableTyped } from '@naturalcycles/nodejs-lib'
11
+ import type { CommonStorage } from './commonStorage.js'
11
12
 
12
13
  export interface CommonStorageKeyValueDBCfg {
13
14
  storage: CommonStorage
@@ -1,21 +1,14 @@
1
+ import type { LocalTimeInput, StringMap } from '@naturalcycles/js-lib'
1
2
  import {
2
3
  _assert,
3
4
  _isTruthy,
4
5
  _stringMapEntries,
5
6
  _substringAfterLast,
6
7
  localTime,
7
- LocalTimeInput,
8
- StringMap,
9
8
  } from '@naturalcycles/js-lib'
10
- import {
11
- fs2,
12
- md5,
13
- ReadableBinary,
14
- readableFrom,
15
- ReadableTyped,
16
- WritableBinary,
17
- } from '@naturalcycles/nodejs-lib'
18
- import { CommonStorage, CommonStorageGetOptions, FileEntry } from './commonStorage'
9
+ import type { ReadableBinary, ReadableTyped, WritableBinary } from '@naturalcycles/nodejs-lib'
10
+ import { fs2, md5, readableFrom } from '@naturalcycles/nodejs-lib'
11
+ import type { CommonStorage, CommonStorageGetOptions, FileEntry } from './commonStorage.js'
19
12
 
20
13
  export class InMemoryCommonStorage implements CommonStorage {
21
14
  /**
package/src/index.ts CHANGED
@@ -1,7 +1,6 @@
1
- export * from './cloudStorage'
2
- export * from './commonStorage'
3
- export * from './commonStorageBucket'
4
- export * from './commonStorageKeyValueDB'
5
- export * from './inMemoryCommonStorage'
6
- export * from './model'
7
- export * from './testing/commonStorageTest'
1
+ export * from './cloudStorage.js'
2
+ export * from './commonStorage.js'
3
+ export * from './commonStorageBucket.js'
4
+ export * from './commonStorageKeyValueDB.js'
5
+ export * from './inMemoryCommonStorage.js'
6
+ export * from './model.js'
@@ -1,5 +1,6 @@
1
- import { _range, _substringAfterLast, pMap, StringMap } from '@naturalcycles/js-lib'
2
- import { CommonStorage, FileEntry } from '../commonStorage'
1
+ import type { StringMap } from '@naturalcycles/js-lib'
2
+ import { _range, _substringAfterLast, pMap } from '@naturalcycles/js-lib'
3
+ import type { CommonStorage, FileEntry } from '../commonStorage.js'
3
4
 
4
5
  const TEST_FOLDER = 'test/subdir'
5
6
 
@@ -31,7 +32,13 @@ const TEST_FILES: FileEntry[] = [TEST_ITEMS, TEST_ITEMS2, TEST_ITEMS3].map((obj,
31
32
  /**
32
33
  * This test suite must be idempotent.
33
34
  */
34
- export function runCommonStorageTest(storage: CommonStorage, bucketName: string): void {
35
+ export async function runCommonStorageTest(
36
+ storage: CommonStorage,
37
+ bucketName: string,
38
+ ): Promise<void> {
39
+ // this is because vitest cannot be "required" from cjs
40
+ const { test, expect } = await import('vitest')
41
+
35
42
  // test('createBucket', async () => {
36
43
  // await storage.createBucket(bucketName)
37
44
  // })
@@ -0,0 +1 @@
1
+ export * from './commonStorageTest.js'