@wener/common 2.0.3 → 2.0.5
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/lib/ai/qwen3vl/utils.js.map +1 -1
- package/lib/cn/ChineseResidentIdNo.js +1 -1
- package/lib/cn/ChineseResidentIdNo.js.map +1 -1
- package/lib/cn/Mod11.js +1 -1
- package/lib/cn/Mod11.js.map +1 -1
- package/lib/consola/formatLogObject.js +5 -5
- package/lib/consola/formatLogObject.js.map +1 -1
- package/lib/data/maybeNumber.js +1 -1
- package/lib/data/maybeNumber.js.map +1 -1
- package/lib/data/types.d.js.map +1 -1
- package/lib/dayjs/formatDuration.js.map +1 -1
- package/lib/dayjs/resolveRelativeTime.js +9 -80
- package/lib/dayjs/resolveRelativeTime.js.map +1 -1
- package/lib/drain3/Drain.js +356 -0
- package/lib/drain3/Drain.js.map +1 -0
- package/lib/drain3/LogCluster.js +38 -0
- package/lib/drain3/LogCluster.js.map +1 -0
- package/lib/drain3/Node.js +39 -0
- package/lib/drain3/Node.js.map +1 -0
- package/lib/drain3/TemplateMiner.js +204 -0
- package/lib/drain3/TemplateMiner.js.map +1 -0
- package/lib/drain3/index.js +31 -0
- package/lib/drain3/index.js.map +1 -0
- package/lib/drain3/persistence/FilePersistence.js +24 -0
- package/lib/drain3/persistence/FilePersistence.js.map +1 -0
- package/lib/drain3/persistence/MemoryPersistence.js +18 -0
- package/lib/drain3/persistence/MemoryPersistence.js.map +1 -0
- package/lib/drain3/persistence/PersistenceHandler.js +5 -0
- package/lib/drain3/persistence/PersistenceHandler.js.map +1 -0
- package/lib/drain3/types.js +7 -0
- package/lib/drain3/types.js.map +1 -0
- package/lib/fs/IFileSystem.d.js.map +1 -1
- package/lib/fs/createBrowserFileSystem.js +4 -2
- package/lib/fs/createBrowserFileSystem.js.map +1 -1
- package/lib/fs/createMemoryFileSystem.js +7 -6
- package/lib/fs/createMemoryFileSystem.js.map +1 -1
- package/lib/fs/createSandboxFileSystem.js.map +1 -1
- package/lib/fs/createWebDavFileSystem.js +22 -5
- package/lib/fs/createWebDavFileSystem.js.map +1 -1
- package/lib/fs/createWebFileSystem.js +225 -0
- package/lib/fs/createWebFileSystem.js.map +1 -0
- package/lib/fs/findMimeType.js +1 -1
- package/lib/fs/findMimeType.js.map +1 -1
- package/lib/fs/index.js +1 -1
- package/lib/fs/index.js.map +1 -1
- package/lib/fs/minio/createMinioFileSystem.js +974 -0
- package/lib/fs/minio/createMinioFileSystem.js.map +1 -0
- package/lib/fs/minio/index.js +2 -0
- package/lib/fs/minio/index.js.map +1 -0
- package/lib/fs/orpc/createContractClientFileSystem.js +3 -3
- package/lib/fs/orpc/createContractClientFileSystem.js.map +1 -1
- package/lib/fs/orpc/server/createFileSystemContractImpl.js.map +1 -1
- package/lib/fs/s3/createS3MiniFileSystem.js +116 -68
- package/lib/fs/s3/createS3MiniFileSystem.js.map +1 -1
- package/lib/fs/server/createDatabaseFileSystem.js +7 -7
- package/lib/fs/server/createDatabaseFileSystem.js.map +1 -1
- package/lib/fs/server/createNodeFileSystem.js +30 -5
- package/lib/fs/server/createNodeFileSystem.js.map +1 -1
- package/lib/fs/tests/runFileSystemTest.js +27 -26
- package/lib/fs/tests/runFileSystemTest.js.map +1 -1
- package/lib/fs/utils.js.map +1 -1
- package/lib/fs/webdav/index.js +2 -0
- package/lib/fs/webdav/index.js.map +1 -0
- package/lib/jsonschema/JsonSchema.js +5 -5
- package/lib/jsonschema/JsonSchema.js.map +1 -1
- package/lib/jsonschema/forEachJsonSchema.js +1 -1
- package/lib/jsonschema/forEachJsonSchema.js.map +1 -1
- package/lib/jsonschema/types.d.js.map +1 -1
- package/lib/meta/defineMetadata.js.map +1 -1
- package/lib/orpc/createOpenApiContractClient.js.map +1 -1
- package/lib/password/PHC.js +2 -2
- package/lib/password/PHC.js.map +1 -1
- package/lib/password/createArgon2PasswordAlgorithm.js.map +1 -1
- package/lib/password/createBase64PasswordAlgorithm.js +1 -1
- package/lib/password/createBase64PasswordAlgorithm.js.map +1 -1
- package/lib/password/createBcryptPasswordAlgorithm.js.map +1 -1
- package/lib/password/createPBKDF2PasswordAlgorithm.js +1 -1
- package/lib/password/createPBKDF2PasswordAlgorithm.js.map +1 -1
- package/lib/password/createScryptPasswordAlgorithm.js +3 -3
- package/lib/password/createScryptPasswordAlgorithm.js.map +1 -1
- package/lib/resource/ListQuery.js.map +1 -1
- package/lib/resource/index.js.map +1 -1
- package/lib/s3/formatS3Url.js +2 -2
- package/lib/s3/formatS3Url.js.map +1 -1
- package/lib/s3/parseS3Url.js +1 -1
- package/lib/s3/parseS3Url.js.map +1 -1
- package/lib/schema/SchemaRegistry.js.map +1 -1
- package/lib/schema/TypeSchema.d.js.map +1 -1
- package/lib/schema/createSchemaData.js +4 -4
- package/lib/schema/createSchemaData.js.map +1 -1
- package/lib/schema/findJsonSchemaByPath.js.map +1 -1
- package/lib/schema/formatZodError.js +42 -44
- package/lib/schema/formatZodError.js.map +1 -1
- package/lib/schema/toJsonSchema.js +4 -4
- package/lib/schema/toJsonSchema.js.map +1 -1
- package/lib/schema/validate.js +1 -1
- package/lib/schema/validate.js.map +1 -1
- package/lib/utils/buildRedactorFormSchema.js +1 -1
- package/lib/utils/buildRedactorFormSchema.js.map +1 -1
- package/package.json +32 -13
- package/src/ai/qwen3vl/utils.ts +1 -1
- package/src/cn/ChineseResidentIdNo.ts +1 -1
- package/src/cn/Mod11.ts +1 -1
- package/src/cn/__snapshots__/ChineseResidentIdNo.test.ts.snap +1 -1
- package/src/cn/__snapshots__/UnifiedSocialCreditCode.test.ts.snap +0 -23
- package/src/cn/parseChineseNumber.test.ts +4 -4
- package/src/consola/formatLogObject.ts +6 -6
- package/src/data/maybeNumber.ts +1 -1
- package/src/data/parseSort.test.ts +0 -1
- package/src/data/types.d.ts +2 -2
- package/src/dayjs/formatDuration.ts +2 -2
- package/src/dayjs/resolveRelativeTime.ts +11 -14
- package/src/drain3/Drain.test.ts +378 -0
- package/src/drain3/Drain.ts +394 -0
- package/src/drain3/LogCluster.ts +46 -0
- package/src/drain3/Node.ts +53 -0
- package/src/drain3/TemplateMiner.ts +246 -0
- package/src/drain3/index.ts +36 -0
- package/src/drain3/persistence/FilePersistence.ts +24 -0
- package/src/drain3/persistence/MemoryPersistence.ts +23 -0
- package/src/drain3/persistence/PersistenceHandler.ts +19 -0
- package/src/drain3/types.ts +75 -0
- package/src/fs/IFileSystem.d.ts +1 -2
- package/src/fs/createBrowserFileSystem.ts +7 -5
- package/src/fs/createMemoryFileSystem.ts +9 -13
- package/src/fs/createSandboxFileSystem.ts +1 -1
- package/src/fs/createWebDavFileSystem.ts +28 -10
- package/src/fs/createWebFileSystem.ts +242 -0
- package/src/fs/findMimeType.ts +1 -4
- package/src/fs/index.ts +1 -1
- package/src/fs/minio/createMinioFileSystem.ts +1148 -0
- package/src/fs/minio/index.ts +1 -0
- package/src/fs/orpc/createContractClientFileSystem.ts +5 -5
- package/src/fs/orpc/server/createFileSystemContractImpl.ts +1 -1
- package/src/fs/s3/createS3MiniFileSystem.ts +119 -78
- package/src/fs/s3/s3fs.test.ts +441 -0
- package/src/fs/s3/s3mini.test.ts +2 -2
- package/src/fs/server/createDatabaseFileSystem.ts +7 -7
- package/src/fs/server/createNodeFileSystem.ts +32 -13
- package/src/fs/server/dbfs.test.ts +2 -1
- package/src/fs/tests/runFileSystemTest.ts +29 -28
- package/src/fs/utils.ts +1 -1
- package/src/fs/webdav/index.ts +1 -0
- package/src/jsonschema/JsonSchema.ts +5 -5
- package/src/jsonschema/forEachJsonSchema.ts +1 -1
- package/src/jsonschema/types.d.ts +1 -1
- package/src/meta/defineMetadata.ts +1 -1
- package/src/orpc/createOpenApiContractClient.ts +2 -2
- package/src/password/PHC.ts +3 -3
- package/src/password/createArgon2PasswordAlgorithm.ts +1 -1
- package/src/password/createBase64PasswordAlgorithm.ts +2 -2
- package/src/password/createBcryptPasswordAlgorithm.ts +4 -2
- package/src/password/createPBKDF2PasswordAlgorithm.ts +2 -2
- package/src/password/createScryptPasswordAlgorithm.ts +4 -4
- package/src/resource/ListQuery.ts +4 -1
- package/src/resource/index.ts +2 -2
- package/src/s3/formatS3Url.test.ts +1 -1
- package/src/s3/formatS3Url.ts +2 -2
- package/src/s3/parseS3Url.ts +1 -1
- package/src/schema/SchemaRegistry.ts +1 -1
- package/src/schema/TypeSchema.d.ts +6 -6
- package/src/schema/createSchemaData.ts +4 -4
- package/src/schema/findJsonSchemaByPath.ts +4 -4
- package/src/schema/formatZodError.test.ts +2 -1
- package/src/schema/formatZodError.ts +50 -62
- package/src/schema/toJsonSchema.ts +6 -6
- package/src/schema/validate.ts +1 -1
- package/src/utils/buildRedactorFormSchema.ts +3 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { createMinioFileSystem, type CreateMinioFileSystemOptions } from './createMinioFileSystem';
|
|
@@ -16,7 +16,7 @@ import type {
|
|
|
16
16
|
WriteFileOptions,
|
|
17
17
|
} from '../IFileSystem';
|
|
18
18
|
import { resolveData } from '../utils';
|
|
19
|
-
import { FileSystemContract } from './FileSystemContract';
|
|
19
|
+
import type { FileSystemContract } from './FileSystemContract';
|
|
20
20
|
|
|
21
21
|
type FileSystemContractClient = ContractRouterClient<typeof FileSystemContract>;
|
|
22
22
|
|
|
@@ -41,7 +41,7 @@ class ContractFS implements IFileSystem {
|
|
|
41
41
|
}));
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
async stat(entry: string,
|
|
44
|
+
async stat(entry: string, _options?: StatOptions) {
|
|
45
45
|
const { data } = await this.client.stat({ path: entry });
|
|
46
46
|
return {
|
|
47
47
|
...data,
|
|
@@ -72,7 +72,7 @@ class ContractFS implements IFileSystem {
|
|
|
72
72
|
|
|
73
73
|
async writeFile(path: string, data: WritableData, options?: WriteFileOptions) {
|
|
74
74
|
let buf = resolveData(data);
|
|
75
|
-
await this.client.writeFile({ path, base64: ArrayBuffers.toBase64(buf), ...options });
|
|
75
|
+
await this.client.writeFile({ path, base64: ArrayBuffers.toBase64(buf as BufferSource), ...options });
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
async rename(oldPath: string, newPath: string, options?: RenameOptions) {
|
|
@@ -105,11 +105,11 @@ class ContractFS implements IFileSystem {
|
|
|
105
105
|
});
|
|
106
106
|
}
|
|
107
107
|
|
|
108
|
-
createReadStream(
|
|
108
|
+
createReadStream(_path: string, _options?: CreateReadStreamOptions): Readable {
|
|
109
109
|
throw new Error('createReadStream is not implemented in ContractFS');
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
createWriteStream(
|
|
112
|
+
createWriteStream(_path: string, _options?: CreateWriteStreamOptions): Writable {
|
|
113
113
|
throw new Error('createWriteStream is not implemented in ContractFS');
|
|
114
114
|
}
|
|
115
115
|
}
|
|
@@ -43,7 +43,7 @@ export function createFileSystemContractImpl(ifs: IFileSystem) {
|
|
|
43
43
|
}),
|
|
44
44
|
readFile: os.readFile.handler(async ({ input }) => {
|
|
45
45
|
return {
|
|
46
|
-
base64: ArrayBuffers.toBase64(await ifs.readFile(input.path, { encoding: 'binary' })),
|
|
46
|
+
base64: ArrayBuffers.toBase64((await ifs.readFile(input.path, { encoding: 'binary' })) as BufferSource),
|
|
47
47
|
};
|
|
48
48
|
}),
|
|
49
49
|
writeFile: os.writeFile.handler(async ({ input }) => {
|
|
@@ -14,6 +14,7 @@ import type {
|
|
|
14
14
|
RenameOptions,
|
|
15
15
|
RmOptions,
|
|
16
16
|
StatOptions,
|
|
17
|
+
WritableData,
|
|
17
18
|
WriteFileOptions,
|
|
18
19
|
} from '../IFileSystem';
|
|
19
20
|
|
|
@@ -71,7 +72,7 @@ export function createS3MiniFileSystem(options: CreateS3MiniFileSystemOptions =
|
|
|
71
72
|
class S3FS implements IFileSystem {
|
|
72
73
|
constructor(
|
|
73
74
|
readonly client: S3mini,
|
|
74
|
-
|
|
75
|
+
readonly _bucket: string,
|
|
75
76
|
private readonly prefix: string = '',
|
|
76
77
|
) {}
|
|
77
78
|
|
|
@@ -87,7 +88,7 @@ class S3FS implements IFileSystem {
|
|
|
87
88
|
|
|
88
89
|
// Prepend prefix if set
|
|
89
90
|
if (this.prefix) {
|
|
90
|
-
return this.prefix
|
|
91
|
+
return `${this.prefix}/${normalized}`;
|
|
91
92
|
}
|
|
92
93
|
return normalized;
|
|
93
94
|
}
|
|
@@ -96,9 +97,9 @@ class S3FS implements IFileSystem {
|
|
|
96
97
|
* Remove prefix from S3 key to get the file system path
|
|
97
98
|
*/
|
|
98
99
|
private stripPrefix(key: string): string {
|
|
99
|
-
if (!this.prefix || !key.startsWith(this.prefix
|
|
100
|
+
if (!this.prefix || !key.startsWith(`${this.prefix}/`)) {
|
|
100
101
|
// If key doesn't start with prefix, return as-is (shouldn't happen normally)
|
|
101
|
-
return key.startsWith('/') ? key :
|
|
102
|
+
return key.startsWith('/') ? key : `/${key}`;
|
|
102
103
|
}
|
|
103
104
|
const withoutPrefix = key.slice(this.prefix.length);
|
|
104
105
|
return withoutPrefix || '/';
|
|
@@ -122,7 +123,7 @@ class S3FS implements IFileSystem {
|
|
|
122
123
|
return '/';
|
|
123
124
|
}
|
|
124
125
|
const dir = dirname(key).replace(/\\/g, '/');
|
|
125
|
-
return dir === '.' ? '/' :
|
|
126
|
+
return dir === '.' ? '/' : `/${dir}`;
|
|
126
127
|
}
|
|
127
128
|
|
|
128
129
|
/**
|
|
@@ -164,66 +165,105 @@ class S3FS implements IFileSystem {
|
|
|
164
165
|
this.checkAborted(signal);
|
|
165
166
|
|
|
166
167
|
const dirPrefix = this.normalizeKey(dir);
|
|
167
|
-
const prefixWithSlash = dirPrefix ? (dirPrefix.endsWith('/') ? dirPrefix : dirPrefix
|
|
168
|
+
const prefixWithSlash = dirPrefix ? (dirPrefix.endsWith('/') ? dirPrefix : `${dirPrefix}/`) : '';
|
|
168
169
|
|
|
169
170
|
try {
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
//
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
171
|
+
const delimiter = recursive ? '' : '/';
|
|
172
|
+
|
|
173
|
+
// S3mini doesn't expose CommonPrefixes from delimiter-based listing.
|
|
174
|
+
// For non-recursive listing, we do two calls:
|
|
175
|
+
// 1. With delimiter to get direct files
|
|
176
|
+
// 2. Without delimiter to infer directory prefixes
|
|
177
|
+
let objects: Array<{ Key: string; Size: number | string; LastModified?: Date | string; ETag?: string }> = [];
|
|
178
|
+
let commonPrefixes: string[] = [];
|
|
179
|
+
|
|
180
|
+
if (delimiter && !recursive) {
|
|
181
|
+
const directObjects = await this.client.listObjects(delimiter, prefixWithSlash, undefined, {
|
|
182
|
+
delimiter,
|
|
183
|
+
signal,
|
|
184
|
+
});
|
|
185
|
+
if (directObjects) {
|
|
186
|
+
objects = directObjects;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// Infer CommonPrefixes by listing all objects recursively
|
|
190
|
+
const allObjectsRecursive = await this.client.listObjects('', prefixWithSlash, 1000, { signal });
|
|
191
|
+
if (allObjectsRecursive) {
|
|
192
|
+
const prefixSet = new Set<string>();
|
|
193
|
+
for (const obj of allObjectsRecursive) {
|
|
194
|
+
const key = obj.Key || '';
|
|
195
|
+
if (!key || !key.startsWith(prefixWithSlash)) continue;
|
|
196
|
+
|
|
197
|
+
const relativeKey = key.slice(prefixWithSlash.length);
|
|
198
|
+
const firstSlash = relativeKey.indexOf('/');
|
|
199
|
+
if (firstSlash > 0) {
|
|
200
|
+
prefixSet.add(prefixWithSlash + relativeKey.slice(0, firstSlash + 1));
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
commonPrefixes = Array.from(prefixSet).sort();
|
|
204
|
+
}
|
|
205
|
+
} else {
|
|
206
|
+
const listResult = await this.client.listObjects(delimiter, prefixWithSlash, undefined, { signal });
|
|
207
|
+
if (listResult) {
|
|
208
|
+
objects = listResult;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
179
211
|
|
|
180
|
-
if (!objects
|
|
212
|
+
if (!objects.length && !commonPrefixes.length) {
|
|
181
213
|
return [];
|
|
182
214
|
}
|
|
183
215
|
|
|
184
216
|
let results: IFileStat[] = [];
|
|
185
|
-
const seenPaths = new Set<string>();
|
|
186
217
|
|
|
187
|
-
|
|
218
|
+
// Process inferred CommonPrefixes (directories)
|
|
219
|
+
for (const prefix of commonPrefixes) {
|
|
188
220
|
this.checkAborted(signal);
|
|
221
|
+
if (prefixWithSlash && !prefix.startsWith(prefixWithSlash)) continue;
|
|
189
222
|
|
|
190
|
-
const
|
|
191
|
-
|
|
223
|
+
const relativePrefix = prefixWithSlash ? prefix.slice(prefixWithSlash.length) : prefix;
|
|
224
|
+
const dirName = relativePrefix.replace(/\/$/, '');
|
|
225
|
+
if (!dirName) continue;
|
|
192
226
|
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
continue;
|
|
227
|
+
if (!recursive && depth === 1) {
|
|
228
|
+
if (dirName.indexOf('/') >= 0) continue;
|
|
196
229
|
}
|
|
197
230
|
|
|
198
|
-
|
|
199
|
-
const
|
|
231
|
+
const dirKey = prefix.endsWith('/') ? prefix : `${prefix}/`;
|
|
232
|
+
const stat = this.toFileStat(dirKey, {
|
|
233
|
+
Key: dirKey,
|
|
234
|
+
Size: 0,
|
|
235
|
+
LastModified: new Date(),
|
|
236
|
+
});
|
|
200
237
|
|
|
201
|
-
|
|
202
|
-
if (
|
|
203
|
-
continue;
|
|
204
|
-
}
|
|
238
|
+
if (!hidden && stat.name.startsWith('.')) continue;
|
|
239
|
+
if (kind && stat.kind !== kind) continue;
|
|
205
240
|
|
|
206
|
-
|
|
207
|
-
|
|
241
|
+
results.push(stat);
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
// Process objects (files and explicit directory markers)
|
|
245
|
+
const seenDirs = new Set<string>();
|
|
246
|
+
for (const obj of objects) {
|
|
247
|
+
this.checkAborted(signal);
|
|
248
|
+
|
|
249
|
+
const key = obj.Key || '';
|
|
250
|
+
if (!key) continue;
|
|
251
|
+
if (prefixWithSlash && !key.startsWith(prefixWithSlash)) continue;
|
|
252
|
+
|
|
253
|
+
const relativeKey = prefixWithSlash ? key.slice(prefixWithSlash.length) : key;
|
|
254
|
+
if (!relativeKey || relativeKey === '/') continue;
|
|
208
255
|
|
|
209
|
-
// For non-recursive, only show immediate children
|
|
210
256
|
if (!recursive && depth === 1) {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
// We only want immediate children, so no more slashes in the middle
|
|
214
|
-
const keyWithoutTrailingSlash = relativeKey.replace(/\/$/, '');
|
|
215
|
-
if (keyWithoutTrailingSlash.includes('/')) {
|
|
216
|
-
// This is deeper than one level, skip
|
|
217
|
-
continue;
|
|
218
|
-
}
|
|
257
|
+
const firstSlash = relativeKey.indexOf('/');
|
|
258
|
+
if (firstSlash >= 0) continue;
|
|
219
259
|
}
|
|
220
260
|
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
continue;
|
|
261
|
+
const isDir = this.isDirectoryKey(key);
|
|
262
|
+
if (isDir) {
|
|
263
|
+
const dk = key.slice(0, -1);
|
|
264
|
+
if (seenDirs.has(dk)) continue;
|
|
265
|
+
seenDirs.add(dk);
|
|
225
266
|
}
|
|
226
|
-
seenPaths.add(pathKey);
|
|
227
267
|
|
|
228
268
|
const stat = this.toFileStat(key, {
|
|
229
269
|
Key: key,
|
|
@@ -232,15 +272,8 @@ class S3FS implements IFileSystem {
|
|
|
232
272
|
ETag: obj.ETag,
|
|
233
273
|
});
|
|
234
274
|
|
|
235
|
-
|
|
236
|
-
if (
|
|
237
|
-
continue;
|
|
238
|
-
}
|
|
239
|
-
|
|
240
|
-
// Filter by kind
|
|
241
|
-
if (kind && stat.kind !== kind) {
|
|
242
|
-
continue;
|
|
243
|
-
}
|
|
275
|
+
if (!hidden && stat.name.startsWith('.')) continue;
|
|
276
|
+
if (kind && stat.kind !== kind) continue;
|
|
244
277
|
|
|
245
278
|
results.push(stat);
|
|
246
279
|
}
|
|
@@ -316,7 +349,7 @@ class S3FS implements IFileSystem {
|
|
|
316
349
|
}
|
|
317
350
|
|
|
318
351
|
// If object not found, try checking if it's a directory (prefix listing)
|
|
319
|
-
const dirKey = key.endsWith('/') ? key : key
|
|
352
|
+
const dirKey = key.endsWith('/') ? key : `${key}/`;
|
|
320
353
|
const objects = await this.client.listObjects('/', dirKey, 1, { delimiter: '/', signal });
|
|
321
354
|
|
|
322
355
|
if (objects && objects.length > 0) {
|
|
@@ -342,7 +375,7 @@ class S3FS implements IFileSystem {
|
|
|
342
375
|
}
|
|
343
376
|
|
|
344
377
|
async mkdir(path: string, options: MkdirOptions = {}): Promise<void> {
|
|
345
|
-
const { recursive = false, signal } = options;
|
|
378
|
+
const { recursive: _recursive = false, signal } = options;
|
|
346
379
|
this.checkAborted(signal);
|
|
347
380
|
|
|
348
381
|
// In S3, directories don't actually exist - they're just prefixes
|
|
@@ -353,7 +386,7 @@ class S3FS implements IFileSystem {
|
|
|
353
386
|
}
|
|
354
387
|
|
|
355
388
|
// Ensure it ends with / to indicate directory
|
|
356
|
-
const dirKey = key.endsWith('/') ? key : key
|
|
389
|
+
const dirKey = key.endsWith('/') ? key : `${key}/`;
|
|
357
390
|
|
|
358
391
|
// Try to create a marker object (0-byte object)
|
|
359
392
|
try {
|
|
@@ -403,11 +436,7 @@ class S3FS implements IFileSystem {
|
|
|
403
436
|
}
|
|
404
437
|
}
|
|
405
438
|
|
|
406
|
-
async writeFile(
|
|
407
|
-
path: string,
|
|
408
|
-
data: string | Buffer | ArrayBuffer | Readable | ArrayBufferView,
|
|
409
|
-
options: WriteFileOptions = {},
|
|
410
|
-
): Promise<void> {
|
|
439
|
+
async writeFile(path: string, data: WritableData, options: WriteFileOptions = {}): Promise<void> {
|
|
411
440
|
const { signal, overwrite = true, onUploadProgress } = options;
|
|
412
441
|
this.checkAborted(signal);
|
|
413
442
|
|
|
@@ -426,7 +455,24 @@ class S3FS implements IFileSystem {
|
|
|
426
455
|
|
|
427
456
|
// Convert data to buffer or string
|
|
428
457
|
let body: string | Buffer;
|
|
429
|
-
if (data instanceof
|
|
458
|
+
if (data instanceof ReadableStream) {
|
|
459
|
+
// Handle web ReadableStream
|
|
460
|
+
const reader = data.getReader();
|
|
461
|
+
const chunks: Uint8Array[] = [];
|
|
462
|
+
let loaded = 0;
|
|
463
|
+
while (true) {
|
|
464
|
+
const { done, value } = await reader.read();
|
|
465
|
+
if (done) break;
|
|
466
|
+
if (value) {
|
|
467
|
+
chunks.push(value);
|
|
468
|
+
loaded += value.length;
|
|
469
|
+
if (onUploadProgress) {
|
|
470
|
+
onUploadProgress({ loaded, total: -1 });
|
|
471
|
+
}
|
|
472
|
+
}
|
|
473
|
+
}
|
|
474
|
+
body = Buffer.concat(chunks);
|
|
475
|
+
} else if (data instanceof Readable) {
|
|
430
476
|
// For streams, we need to read them into a buffer
|
|
431
477
|
const chunks: Buffer[] = [];
|
|
432
478
|
let loaded = 0;
|
|
@@ -466,12 +512,7 @@ class S3FS implements IFileSystem {
|
|
|
466
512
|
// ArrayBufferView
|
|
467
513
|
body = Buffer.from(data.buffer, data.byteOffset, data.byteLength);
|
|
468
514
|
}
|
|
469
|
-
|
|
470
|
-
try {
|
|
471
|
-
await this.client.putObject(key, body, undefined, undefined, undefined);
|
|
472
|
-
} catch (error: any) {
|
|
473
|
-
throw error;
|
|
474
|
-
}
|
|
515
|
+
await this.client.putObject(key, body, undefined, undefined, undefined);
|
|
475
516
|
}
|
|
476
517
|
|
|
477
518
|
async rm(path: string, options: RmOptions = {}): Promise<void> {
|
|
@@ -486,7 +527,7 @@ class S3FS implements IFileSystem {
|
|
|
486
527
|
try {
|
|
487
528
|
if (recursive) {
|
|
488
529
|
// List all objects with this prefix (no delimiter = recursive)
|
|
489
|
-
const prefix = key.endsWith('/') ? key : key
|
|
530
|
+
const prefix = key.endsWith('/') ? key : `${key}/`;
|
|
490
531
|
const objects = await this.client.listObjects('', prefix, undefined, { signal });
|
|
491
532
|
|
|
492
533
|
if (objects) {
|
|
@@ -538,13 +579,13 @@ class S3FS implements IFileSystem {
|
|
|
538
579
|
try {
|
|
539
580
|
// Check if it's a directory (has objects with prefix)
|
|
540
581
|
const isDir = oldKey.endsWith('/');
|
|
541
|
-
const prefix = isDir ? oldKey : oldKey
|
|
582
|
+
const prefix = isDir ? oldKey : `${oldKey}/`;
|
|
542
583
|
|
|
543
584
|
const objects = await this.client.listObjects('', prefix, undefined, { signal });
|
|
544
585
|
|
|
545
586
|
if (objects && objects.length > 0) {
|
|
546
587
|
// It's a directory or has multiple objects, move all
|
|
547
|
-
const newPrefix = newKey.endsWith('/') ? newKey : newKey
|
|
588
|
+
const newPrefix = newKey.endsWith('/') ? newKey : `${newKey}/`;
|
|
548
589
|
|
|
549
590
|
// Move all objects
|
|
550
591
|
await Promise.all(
|
|
@@ -591,7 +632,7 @@ class S3FS implements IFileSystem {
|
|
|
591
632
|
}
|
|
592
633
|
|
|
593
634
|
// Check if it's a directory
|
|
594
|
-
const dirKey = key.endsWith('/') ? key : key
|
|
635
|
+
const dirKey = key.endsWith('/') ? key : `${key}/`;
|
|
595
636
|
const objects = await this.client.listObjects('/', dirKey, 1, { delimiter: '/' });
|
|
596
637
|
return objects !== null && objects.length > 0;
|
|
597
638
|
} catch {
|
|
@@ -624,8 +665,8 @@ class S3FS implements IFileSystem {
|
|
|
624
665
|
|
|
625
666
|
if (srcStat.kind === 'directory') {
|
|
626
667
|
// Copy directory recursively
|
|
627
|
-
const srcPrefix = srcKey.endsWith('/') ? srcKey : srcKey
|
|
628
|
-
const destPrefix = destKey.endsWith('/') ? destKey : destKey
|
|
668
|
+
const srcPrefix = srcKey.endsWith('/') ? srcKey : `${srcKey}/`;
|
|
669
|
+
const destPrefix = destKey.endsWith('/') ? destKey : `${destKey}/`;
|
|
629
670
|
|
|
630
671
|
const objects = await this.client.listObjects(shallow ? '/' : '', srcPrefix, undefined, {
|
|
631
672
|
...(shallow ? { delimiter: '/' } : {}),
|
|
@@ -691,7 +732,7 @@ class S3FS implements IFileSystem {
|
|
|
691
732
|
|
|
692
733
|
// Convert ReadableStream to Node Readable
|
|
693
734
|
const reader = response.body.getReader();
|
|
694
|
-
const
|
|
735
|
+
const _decoder = new TextDecoder();
|
|
695
736
|
|
|
696
737
|
nodeStream = new Readable({
|
|
697
738
|
async read() {
|
|
@@ -781,7 +822,7 @@ class S3FS implements IFileSystem {
|
|
|
781
822
|
throw new Error('Cannot write to root directory');
|
|
782
823
|
}
|
|
783
824
|
|
|
784
|
-
const { signal, overwrite = true } = options;
|
|
825
|
+
const { signal, overwrite: _overwrite = true } = options;
|
|
785
826
|
this.checkAborted(signal);
|
|
786
827
|
|
|
787
828
|
// Create a WritableStream that buffers data and uploads when done
|
|
@@ -814,7 +855,7 @@ class S3FS implements IFileSystem {
|
|
|
814
855
|
});
|
|
815
856
|
}
|
|
816
857
|
|
|
817
|
-
getUrl(path: IFileStat | string,
|
|
858
|
+
getUrl(path: IFileStat | string, _options?: any): string | undefined {
|
|
818
859
|
if (typeof path === 'object' && path?.kind !== 'file') {
|
|
819
860
|
return;
|
|
820
861
|
}
|