@naturalcycles/cloud-storage-lib 1.8.0 → 1.9.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/dist/cloudStorage.d.ts +2 -0
- package/dist/cloudStorage.js +20 -4
- package/dist/commonStorage.d.ts +17 -0
- package/dist/inMemoryCommonStorage.d.ts +4 -1
- package/dist/inMemoryCommonStorage.js +19 -1
- package/package.json +1 -1
- package/src/cloudStorage.ts +31 -4
- package/src/commonStorage.ts +25 -0
- package/src/inMemoryCommonStorage.ts +43 -3
package/dist/cloudStorage.d.ts
CHANGED
|
@@ -38,6 +38,7 @@ export declare class CloudStorage implements CommonStorage {
|
|
|
38
38
|
static createFromStorageOptions(storageOptions?: StorageOptions): CloudStorage;
|
|
39
39
|
ping(bucketName?: string): Promise<void>;
|
|
40
40
|
deletePath(bucketName: string, prefix: string): Promise<void>;
|
|
41
|
+
deletePaths(bucketName: string, prefixes: string[]): Promise<void>;
|
|
41
42
|
fileExists(bucketName: string, filePath: string): Promise<boolean>;
|
|
42
43
|
getFileNames(bucketName: string, opt?: CommonStorageGetOptions): Promise<string[]>;
|
|
43
44
|
getFileNamesStream(bucketName: string, opt?: CommonStorageGetOptions): ReadableTyped<string>;
|
|
@@ -56,6 +57,7 @@ export declare class CloudStorage implements CommonStorage {
|
|
|
56
57
|
copyFile(fromBucket: string, fromPath: string, toPath: string, toBucket?: string): Promise<void>;
|
|
57
58
|
moveFile(fromBucket: string, fromPath: string, toPath: string, toBucket?: string): Promise<void>;
|
|
58
59
|
movePath(fromBucket: string, fromPrefix: string, toPrefix: string, toBucket?: string): Promise<void>;
|
|
60
|
+
combine(bucketName: string, filePaths: string[], toPath: string, toBucket?: string): Promise<void>;
|
|
59
61
|
/**
|
|
60
62
|
* Acquires a "signed url", which allows bearer to use it to download ('read') the file.
|
|
61
63
|
*
|
package/dist/cloudStorage.js
CHANGED
|
@@ -38,10 +38,16 @@ class CloudStorage {
|
|
|
38
38
|
await this.storage.bucket(bucketName || 'non-existing-for-sure').exists();
|
|
39
39
|
}
|
|
40
40
|
async deletePath(bucketName, prefix) {
|
|
41
|
-
await this.
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
41
|
+
await this.deletePaths(bucketName, [prefix]);
|
|
42
|
+
}
|
|
43
|
+
async deletePaths(bucketName, prefixes) {
|
|
44
|
+
const bucket = this.storage.bucket(bucketName);
|
|
45
|
+
await (0, js_lib_1.pMap)(prefixes, async (prefix) => {
|
|
46
|
+
await bucket.deleteFiles({
|
|
47
|
+
prefix,
|
|
48
|
+
// to keep going in case error occurs, similar to THROW_AGGREGATED
|
|
49
|
+
force: true,
|
|
50
|
+
});
|
|
45
51
|
});
|
|
46
52
|
}
|
|
47
53
|
async fileExists(bucketName, filePath) {
|
|
@@ -149,6 +155,15 @@ class CloudStorage {
|
|
|
149
155
|
}),
|
|
150
156
|
]);
|
|
151
157
|
}
|
|
158
|
+
async combine(bucketName, filePaths, toPath, toBucket) {
|
|
159
|
+
// todo: if (filePaths.length > 32) - use recursive algorithm
|
|
160
|
+
(0, js_lib_1._assert)(filePaths.length <= 32, 'combine supports up to 32 input files');
|
|
161
|
+
await this.storage
|
|
162
|
+
.bucket(bucketName)
|
|
163
|
+
.combine(filePaths, this.storage.bucket(toBucket || bucketName).file(toPath));
|
|
164
|
+
// Delete original files
|
|
165
|
+
await this.deletePaths(bucketName, filePaths);
|
|
166
|
+
}
|
|
152
167
|
/**
|
|
153
168
|
* Acquires a "signed url", which allows bearer to use it to download ('read') the file.
|
|
154
169
|
*
|
|
@@ -162,6 +177,7 @@ class CloudStorage {
|
|
|
162
177
|
.file(filePath)
|
|
163
178
|
.getSignedUrl({
|
|
164
179
|
action: 'read',
|
|
180
|
+
version: 'v4',
|
|
165
181
|
expires: (0, js_lib_1.localTime)(expires).unixMillis(),
|
|
166
182
|
});
|
|
167
183
|
return url;
|
package/dist/commonStorage.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
import { Readable, Writable } from 'node:stream';
|
|
4
|
+
import { LocalTimeInput } from '@naturalcycles/js-lib';
|
|
4
5
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
5
6
|
export interface FileEntry {
|
|
6
7
|
filePath: string;
|
|
@@ -54,6 +55,7 @@ export interface CommonStorage {
|
|
|
54
55
|
* Should recursively delete all files in a folder, if path is a folder.
|
|
55
56
|
*/
|
|
56
57
|
deletePath: (bucketName: string, prefix: string) => Promise<void>;
|
|
58
|
+
deletePaths: (bucketName: string, prefixes: string[]) => Promise<void>;
|
|
57
59
|
/**
|
|
58
60
|
* Returns an array of strings which are file paths.
|
|
59
61
|
* Files that are not found by the path are not present in the map.
|
|
@@ -85,4 +87,19 @@ export interface CommonStorage {
|
|
|
85
87
|
* otherwise some folder that starts with the same prefix will be included.
|
|
86
88
|
*/
|
|
87
89
|
movePath: (fromBucket: string, fromPrefix: string, toPrefix: string, toBucket?: string) => Promise<void>;
|
|
90
|
+
/**
|
|
91
|
+
* Combine (compose) multiple input files into a single output file.
|
|
92
|
+
* Should support unlimited number of input files, using recursive algorithm if necessary.
|
|
93
|
+
*
|
|
94
|
+
* After the output file is created, all input files should be deleted.
|
|
95
|
+
*
|
|
96
|
+
* @experimental
|
|
97
|
+
*/
|
|
98
|
+
combine: (bucketName: string, filePaths: string[], toPath: string, toBucket?: string) => Promise<void>;
|
|
99
|
+
/**
|
|
100
|
+
* Acquire a "signed url", which allows bearer to use it to download ('read') the file.
|
|
101
|
+
*
|
|
102
|
+
* @experimental
|
|
103
|
+
*/
|
|
104
|
+
getSignedUrl: (bucketName: string, filePath: string, expires: LocalTimeInput) => Promise<string>;
|
|
88
105
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
/// <reference types="node" />
|
|
3
3
|
import { Readable, Writable } from 'node:stream';
|
|
4
|
-
import { StringMap } from '@naturalcycles/js-lib';
|
|
4
|
+
import { LocalTimeInput, StringMap } from '@naturalcycles/js-lib';
|
|
5
5
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib';
|
|
6
6
|
import { CommonStorage, CommonStorageGetOptions, FileEntry } from './commonStorage';
|
|
7
7
|
export declare class InMemoryCommonStorage implements CommonStorage {
|
|
@@ -17,6 +17,7 @@ export declare class InMemoryCommonStorage implements CommonStorage {
|
|
|
17
17
|
getFile(bucketName: string, filePath: string): Promise<Buffer | null>;
|
|
18
18
|
saveFile(bucketName: string, filePath: string, content: Buffer): Promise<void>;
|
|
19
19
|
deletePath(bucketName: string, prefix: string): Promise<void>;
|
|
20
|
+
deletePaths(bucketName: string, prefixes: string[]): Promise<void>;
|
|
20
21
|
getFileNames(bucketName: string, opt?: CommonStorageGetOptions): Promise<string[]>;
|
|
21
22
|
getFileNamesStream(bucketName: string, opt?: CommonStorageGetOptions): ReadableTyped<string>;
|
|
22
23
|
getFilesStream(bucketName: string, opt?: CommonStorageGetOptions): ReadableTyped<FileEntry>;
|
|
@@ -28,4 +29,6 @@ export declare class InMemoryCommonStorage implements CommonStorage {
|
|
|
28
29
|
copyFile(fromBucket: string, fromPath: string, toPath: string, toBucket?: string): Promise<void>;
|
|
29
30
|
moveFile(fromBucket: string, fromPath: string, toPath: string, toBucket?: string): Promise<void>;
|
|
30
31
|
movePath(fromBucket: string, fromPrefix: string, toPrefix: string, toBucket?: string): Promise<void>;
|
|
32
|
+
combine(bucketName: string, filePaths: string[], toPath: string, toBucket?: string): Promise<void>;
|
|
33
|
+
getSignedUrl(bucketName: string, filePath: string, expires: LocalTimeInput): Promise<string>;
|
|
31
34
|
}
|
|
@@ -30,8 +30,11 @@ class InMemoryCommonStorage {
|
|
|
30
30
|
this.data[bucketName][filePath] = content;
|
|
31
31
|
}
|
|
32
32
|
async deletePath(bucketName, prefix) {
|
|
33
|
+
await this.deletePaths(bucketName, [prefix]);
|
|
34
|
+
}
|
|
35
|
+
async deletePaths(bucketName, prefixes) {
|
|
33
36
|
Object.keys(this.data[bucketName] || {}).forEach(filePath => {
|
|
34
|
-
if (filePath.startsWith(prefix)) {
|
|
37
|
+
if (prefixes.some(prefix => filePath.startsWith(prefix))) {
|
|
35
38
|
delete this.data[bucketName][filePath];
|
|
36
39
|
}
|
|
37
40
|
});
|
|
@@ -101,5 +104,20 @@ class InMemoryCommonStorage {
|
|
|
101
104
|
delete this.data[fromBucket][filePath];
|
|
102
105
|
});
|
|
103
106
|
}
|
|
107
|
+
async combine(bucketName, filePaths, toPath, toBucket) {
|
|
108
|
+
if (!this.data[bucketName])
|
|
109
|
+
return;
|
|
110
|
+
const tob = toBucket || bucketName;
|
|
111
|
+
this.data[tob] ||= {};
|
|
112
|
+
this.data[tob][toPath] = Buffer.concat(filePaths.map(p => this.data[bucketName][p]).filter(js_lib_1._isTruthy));
|
|
113
|
+
// delete source files
|
|
114
|
+
filePaths.forEach(p => delete this.data[bucketName][p]);
|
|
115
|
+
}
|
|
116
|
+
async getSignedUrl(bucketName, filePath, expires) {
|
|
117
|
+
const buf = this.data[bucketName]?.[filePath];
|
|
118
|
+
(0, js_lib_1._assert)(buf, `getSignedUrl file not found: ${bucketName}/${filePath}`);
|
|
119
|
+
const signature = (0, nodejs_lib_1.md5)(buf);
|
|
120
|
+
return `https://testurl.com/${bucketName}/${filePath}?expires=${(0, js_lib_1.localTime)(expires).unix()}&signature=${signature}`;
|
|
121
|
+
}
|
|
104
122
|
}
|
|
105
123
|
exports.InMemoryCommonStorage = InMemoryCommonStorage;
|
package/package.json
CHANGED
package/src/cloudStorage.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
_substringAfterLast,
|
|
6
6
|
localTime,
|
|
7
7
|
LocalTimeInput,
|
|
8
|
+
pMap,
|
|
8
9
|
SKIP,
|
|
9
10
|
} from '@naturalcycles/js-lib'
|
|
10
11
|
import {
|
|
@@ -75,10 +76,18 @@ export class CloudStorage implements CommonStorage {
|
|
|
75
76
|
}
|
|
76
77
|
|
|
77
78
|
async deletePath(bucketName: string, prefix: string): Promise<void> {
|
|
78
|
-
await this.
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
79
|
+
await this.deletePaths(bucketName, [prefix])
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
async deletePaths(bucketName: string, prefixes: string[]): Promise<void> {
|
|
83
|
+
const bucket = this.storage.bucket(bucketName)
|
|
84
|
+
|
|
85
|
+
await pMap(prefixes, async prefix => {
|
|
86
|
+
await bucket.deleteFiles({
|
|
87
|
+
prefix,
|
|
88
|
+
// to keep going in case error occurs, similar to THROW_AGGREGATED
|
|
89
|
+
force: true,
|
|
90
|
+
})
|
|
82
91
|
})
|
|
83
92
|
}
|
|
84
93
|
|
|
@@ -227,6 +236,23 @@ export class CloudStorage implements CommonStorage {
|
|
|
227
236
|
])
|
|
228
237
|
}
|
|
229
238
|
|
|
239
|
+
async combine(
|
|
240
|
+
bucketName: string,
|
|
241
|
+
filePaths: string[],
|
|
242
|
+
toPath: string,
|
|
243
|
+
toBucket?: string,
|
|
244
|
+
): Promise<void> {
|
|
245
|
+
// todo: if (filePaths.length > 32) - use recursive algorithm
|
|
246
|
+
_assert(filePaths.length <= 32, 'combine supports up to 32 input files')
|
|
247
|
+
|
|
248
|
+
await this.storage
|
|
249
|
+
.bucket(bucketName)
|
|
250
|
+
.combine(filePaths, this.storage.bucket(toBucket || bucketName).file(toPath))
|
|
251
|
+
|
|
252
|
+
// Delete original files
|
|
253
|
+
await this.deletePaths(bucketName, filePaths)
|
|
254
|
+
}
|
|
255
|
+
|
|
230
256
|
/**
|
|
231
257
|
* Acquires a "signed url", which allows bearer to use it to download ('read') the file.
|
|
232
258
|
*
|
|
@@ -244,6 +270,7 @@ export class CloudStorage implements CommonStorage {
|
|
|
244
270
|
.file(filePath)
|
|
245
271
|
.getSignedUrl({
|
|
246
272
|
action: 'read',
|
|
273
|
+
version: 'v4',
|
|
247
274
|
expires: localTime(expires).unixMillis(),
|
|
248
275
|
})
|
|
249
276
|
|
package/src/commonStorage.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Readable, Writable } from 'node:stream'
|
|
2
|
+
import { LocalTimeInput } from '@naturalcycles/js-lib'
|
|
2
3
|
import { ReadableTyped } from '@naturalcycles/nodejs-lib'
|
|
3
4
|
|
|
4
5
|
export interface FileEntry {
|
|
@@ -66,6 +67,8 @@ export interface CommonStorage {
|
|
|
66
67
|
*/
|
|
67
68
|
deletePath: (bucketName: string, prefix: string) => Promise<void>
|
|
68
69
|
|
|
70
|
+
deletePaths: (bucketName: string, prefixes: string[]) => Promise<void>
|
|
71
|
+
|
|
69
72
|
/**
|
|
70
73
|
* Returns an array of strings which are file paths.
|
|
71
74
|
* Files that are not found by the path are not present in the map.
|
|
@@ -122,4 +125,26 @@ export interface CommonStorage {
|
|
|
122
125
|
toPrefix: string,
|
|
123
126
|
toBucket?: string,
|
|
124
127
|
) => Promise<void>
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Combine (compose) multiple input files into a single output file.
|
|
131
|
+
* Should support unlimited number of input files, using recursive algorithm if necessary.
|
|
132
|
+
*
|
|
133
|
+
* After the output file is created, all input files should be deleted.
|
|
134
|
+
*
|
|
135
|
+
* @experimental
|
|
136
|
+
*/
|
|
137
|
+
combine: (
|
|
138
|
+
bucketName: string,
|
|
139
|
+
filePaths: string[],
|
|
140
|
+
toPath: string,
|
|
141
|
+
toBucket?: string,
|
|
142
|
+
) => Promise<void>
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Acquire a "signed url", which allows bearer to use it to download ('read') the file.
|
|
146
|
+
*
|
|
147
|
+
* @experimental
|
|
148
|
+
*/
|
|
149
|
+
getSignedUrl: (bucketName: string, filePath: string, expires: LocalTimeInput) => Promise<string>
|
|
125
150
|
}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { Readable, Writable } from 'node:stream'
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
_assert,
|
|
4
|
+
_isTruthy,
|
|
5
|
+
_stringMapEntries,
|
|
6
|
+
_substringAfterLast,
|
|
7
|
+
localTime,
|
|
8
|
+
LocalTimeInput,
|
|
9
|
+
StringMap,
|
|
10
|
+
} from '@naturalcycles/js-lib'
|
|
11
|
+
import { fs2, md5, ReadableTyped } from '@naturalcycles/nodejs-lib'
|
|
4
12
|
import { CommonStorage, CommonStorageGetOptions, FileEntry } from './commonStorage'
|
|
5
13
|
|
|
6
14
|
export class InMemoryCommonStorage implements CommonStorage {
|
|
@@ -35,8 +43,12 @@ export class InMemoryCommonStorage implements CommonStorage {
|
|
|
35
43
|
}
|
|
36
44
|
|
|
37
45
|
async deletePath(bucketName: string, prefix: string): Promise<void> {
|
|
46
|
+
await this.deletePaths(bucketName, [prefix])
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async deletePaths(bucketName: string, prefixes: string[]): Promise<void> {
|
|
38
50
|
Object.keys(this.data[bucketName] || {}).forEach(filePath => {
|
|
39
|
-
if (filePath.startsWith(prefix)) {
|
|
51
|
+
if (prefixes.some(prefix => filePath.startsWith(prefix))) {
|
|
40
52
|
delete this.data[bucketName]![filePath]
|
|
41
53
|
}
|
|
42
54
|
})
|
|
@@ -142,4 +154,32 @@ export class InMemoryCommonStorage implements CommonStorage {
|
|
|
142
154
|
delete this.data[fromBucket]![filePath]
|
|
143
155
|
})
|
|
144
156
|
}
|
|
157
|
+
|
|
158
|
+
async combine(
|
|
159
|
+
bucketName: string,
|
|
160
|
+
filePaths: string[],
|
|
161
|
+
toPath: string,
|
|
162
|
+
toBucket?: string,
|
|
163
|
+
): Promise<void> {
|
|
164
|
+
if (!this.data[bucketName]) return
|
|
165
|
+
const tob = toBucket || bucketName
|
|
166
|
+
this.data[tob] ||= {}
|
|
167
|
+
this.data[tob]![toPath] = Buffer.concat(
|
|
168
|
+
filePaths.map(p => this.data[bucketName]![p]).filter(_isTruthy),
|
|
169
|
+
)
|
|
170
|
+
|
|
171
|
+
// delete source files
|
|
172
|
+
filePaths.forEach(p => delete this.data[bucketName]![p])
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async getSignedUrl(
|
|
176
|
+
bucketName: string,
|
|
177
|
+
filePath: string,
|
|
178
|
+
expires: LocalTimeInput,
|
|
179
|
+
): Promise<string> {
|
|
180
|
+
const buf = this.data[bucketName]?.[filePath]
|
|
181
|
+
_assert(buf, `getSignedUrl file not found: ${bucketName}/${filePath}`)
|
|
182
|
+
const signature = md5(buf)
|
|
183
|
+
return `https://testurl.com/${bucketName}/${filePath}?expires=${localTime(expires).unix()}&signature=${signature}`
|
|
184
|
+
}
|
|
145
185
|
}
|