@harryy/react-file-browser 1.0.0 → 1.1.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/README.md +91 -5
- package/dist/adapters/cloud-adapter-base.d.ts +17 -17
- package/dist/adapters/cloud-adapter-base.d.ts.map +1 -1
- package/dist/adapters/in-memory/in-memory-file-browser-adapter.d.ts +18 -17
- package/dist/adapters/in-memory/in-memory-file-browser-adapter.d.ts.map +1 -1
- package/dist/adapters/in-memory/index.js +10 -2
- package/dist/adapters/in-memory/index.js.map +1 -1
- package/dist/adapters/r2/index.d.ts +3 -3
- package/dist/adapters/r2/index.d.ts.map +1 -1
- package/dist/adapters/r2/index.js.map +1 -1
- package/dist/adapters/s3/index.d.ts +3 -3
- package/dist/adapters/s3/index.d.ts.map +1 -1
- package/dist/adapters/s3/index.js.map +1 -1
- package/dist/adapters/s3-compatible-adapter.d.ts +16 -16
- package/dist/adapters/s3-compatible-adapter.d.ts.map +1 -1
- package/dist/adapters/supabase/index.d.ts +2 -2
- package/dist/adapters/supabase/index.d.ts.map +1 -1
- package/dist/adapters/supabase/index.js.map +1 -1
- package/dist/adapters/supabase/supabase-file-browser-adapter.d.ts +16 -16
- package/dist/adapters/supabase/supabase-file-browser-adapter.d.ts.map +1 -1
- package/dist/chunks/cloud-adapter-base-CBUoZYLS.js.map +1 -1
- package/dist/chunks/path-CPm7s9NF.js.map +1 -1
- package/dist/chunks/s3-compatible-adapter-D9agsn9e.js.map +1 -1
- package/dist/components/file-browser.d.ts +24 -4
- package/dist/components/file-browser.d.ts.map +1 -1
- package/dist/core/types.d.ts +12 -10
- package/dist/core/types.d.ts.map +1 -1
- package/dist/core/use-file-browser.d.ts +25 -13
- package/dist/core/use-file-browser.d.ts.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1238 -1058
- package/dist/index.js.map +1 -1
- package/dist/transfers/file-browser-provider.d.ts.map +1 -1
- package/dist/transfers/transfer-manager.d.ts +7 -3
- package/dist/transfers/transfer-manager.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -27,6 +27,8 @@ S3, Cloudflare R2, Supabase Storage, an in-memory store, or any backend you impl
|
|
|
27
27
|
zip from signed URLs.
|
|
28
28
|
- **Upload policies** — reject files by MIME type, size, remaining quota, or a custom validator before
|
|
29
29
|
they enqueue.
|
|
30
|
+
- **Host extension points** — controlled path and search state, opaque item ids, typed metadata,
|
|
31
|
+
custom item/details rendering, conflict policy, and custom empty states.
|
|
30
32
|
- **Themeable** with CSS variables that inherit your Tailwind v4 / design-system tokens. No global CSS
|
|
31
33
|
shipped.
|
|
32
34
|
- **Read-only mode**, comfortable/compact density, ESM-only, fully typed.
|
|
@@ -62,6 +64,56 @@ export function App() {
|
|
|
62
64
|
floating transfer widget, and the refresh guard. `FileBrowser` can mount on any page or modal and can
|
|
63
65
|
unmount while transfers keep running.
|
|
64
66
|
|
|
67
|
+
### Host integration
|
|
68
|
+
|
|
69
|
+
`FileNode.path` remains the immutable storage key used by browser operations. Hosts can additionally
|
|
70
|
+
provide an opaque `id` and typed, sanitized metadata for domain-specific routes and rendering:
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
import type { FileBrowserAdapter } from "@harryy/react-file-browser";
|
|
74
|
+
import { FileBrowser } from "@harryy/react-file-browser";
|
|
75
|
+
|
|
76
|
+
type IndexingMetadata = {
|
|
77
|
+
indexingStatus: "pending" | "ready" | "failed";
|
|
78
|
+
indexingError?: string;
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
declare const adapter: FileBrowserAdapter<IndexingMetadata>;
|
|
82
|
+
|
|
83
|
+
<FileBrowser<IndexingMetadata>
|
|
84
|
+
adapter={adapter}
|
|
85
|
+
rootLabel="Knowledge base"
|
|
86
|
+
path={path}
|
|
87
|
+
onPathChange={(nextPath, context) => {
|
|
88
|
+
if (context.source === "item" && context.item.id) {
|
|
89
|
+
navigateToFolder(context.item.id);
|
|
90
|
+
}
|
|
91
|
+
setPath(nextPath);
|
|
92
|
+
}}
|
|
93
|
+
searchQuery={searchQuery}
|
|
94
|
+
onSearchQueryChange={setSearchQuery}
|
|
95
|
+
renderItemMeta={(item) =>
|
|
96
|
+
item.metadata ? <IndexingStatus status={item.metadata.indexingStatus} /> : null
|
|
97
|
+
}
|
|
98
|
+
renderDetailsContent={(item, defaultContent) => (
|
|
99
|
+
<>
|
|
100
|
+
{defaultContent}
|
|
101
|
+
{item.metadata ? <IndexingDetails metadata={item.metadata} /> : null}
|
|
102
|
+
</>
|
|
103
|
+
)}
|
|
104
|
+
uploadConflictResolutions={["keep-both", "skip"]}
|
|
105
|
+
allowClientZipFallback={false}
|
|
106
|
+
/>;
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
`onPathChange` receives the target `FileNode` for item-originated folder navigation. Breadcrumb and
|
|
110
|
+
programmatic navigation may not have a node. Externally changing controlled `path` or `searchQuery`
|
|
111
|
+
updates the browser without firing the corresponding change callback again.
|
|
112
|
+
|
|
113
|
+
Controlled search does not require putting the query in the URL. Hosts handling sensitive filenames or
|
|
114
|
+
search terms should keep that state out of URLs, analytics, and other durable history surfaces unless
|
|
115
|
+
their data policy explicitly permits it.
|
|
116
|
+
|
|
65
117
|
## Mount points
|
|
66
118
|
|
|
67
119
|
After a hard refresh, browsers cannot restore the original `File` object automatically. Use
|
|
@@ -151,18 +203,30 @@ or `bulkDownloadUrl`, those controls are hidden. Recursive folder drops are reje
|
|
|
151
203
|
| --- | --- | --- | --- |
|
|
152
204
|
| `adapter` | `FileBrowserAdapter` | — (required) | Storage backend. |
|
|
153
205
|
| `initialPath` | `string` | `"/"` | Directory to open on mount. |
|
|
206
|
+
| `path` | `string` | None | Controlled current directory. |
|
|
207
|
+
| `onPathChange` | `(path, context) => void` | None | Receives item, breadcrumb, and programmatic navigation. |
|
|
208
|
+
| `searchQuery` | `string` | None | Controlled local search query. |
|
|
209
|
+
| `initialSearchQuery` | `string` | `""` | Initial uncontrolled search query. |
|
|
210
|
+
| `onSearchQueryChange` | `(query) => void` | None | Receives user-driven search changes. |
|
|
154
211
|
| `density` | `"comfortable" \| "compact"` | `"comfortable"` | Row/tile density. |
|
|
155
212
|
| `readOnly` | `boolean` | `false` | Hides all mutating affordances. |
|
|
156
213
|
| `showDetailsPanel` | `boolean` | `true` | Toggles the right-hand details panel. |
|
|
157
|
-
| `uploadPolicy` | `FileBrowserUploadPolicy` |
|
|
158
|
-
| `
|
|
214
|
+
| `uploadPolicy` | `FileBrowserUploadPolicy` | None | Reject files before they enqueue. |
|
|
215
|
+
| `uploadConflictResolutions` | `FileBrowserUploadConflictResolution[]` | all | Allowed conflict-dialog actions. |
|
|
216
|
+
| `allowClientZipFallback` | `boolean` | `true` | Allows browser-built ZIPs when no server ZIP exists. |
|
|
217
|
+
| `warnZipSizeBytes` | `number` | None | Warn before building a large client-side zip. |
|
|
218
|
+
| `rootLabel` | `string` | `"Files"` | Root breadcrumb and navigation label. |
|
|
219
|
+
| `emptyState` | `{ title: ReactNode; description?: ReactNode }` | built in | Empty-folder content. |
|
|
220
|
+
| `renderItemMeta` | `(item, { view }) => ReactNode` | None | Host metadata below grid/list item names. |
|
|
221
|
+
| `renderDetailsContent` | `(item, defaultContent) => ReactNode` | None | Extends single-item details. |
|
|
222
|
+
| `className` | `string` | None | Class name merged onto the root browser surface. |
|
|
159
223
|
|
|
160
224
|
### `<FileBrowserProvider>` props
|
|
161
225
|
|
|
162
226
|
| Prop | Type | Default | Description |
|
|
163
227
|
| --- | --- | --- | --- |
|
|
164
228
|
| `manager` | `TransferManager` | auto-created | Bring your own transfer manager. |
|
|
165
|
-
| `options` | `TransferManagerOptions` | — | Storage, storage key, id factory, clock. |
|
|
229
|
+
| `options` | `TransferManagerOptions` | — | Storage, concurrency, storage key, id factory, clock. |
|
|
166
230
|
| `resolveRestoredUpload` | `(upload) => ... \| undefined` | — | Reattach a `File` when resuming after reload. |
|
|
167
231
|
| `showFloatingWidget` | `boolean` | `true` | Toggles the floating transfer widget. |
|
|
168
232
|
|
|
@@ -183,6 +247,9 @@ bulk failures so successful paths stay applied and failed paths roll back.
|
|
|
183
247
|
`useFileBrowser({ adapter, initialPath })` exposes the full state and actions if you want to build your
|
|
184
248
|
own UI. The `FileBrowser` component is a consumer of this hook.
|
|
185
249
|
|
|
250
|
+
It also accepts controlled `path`, `searchQuery`, and their change callbacks. `navigate(path)` emits a
|
|
251
|
+
`programmatic` path-change source, while `open(folder)` emits the complete target item.
|
|
252
|
+
|
|
186
253
|
### Entry points
|
|
187
254
|
|
|
188
255
|
| Import | Contents |
|
|
@@ -216,17 +283,36 @@ documents every token and its default.
|
|
|
216
283
|
- `readOnly` hides upload, create, rename, move, copy, and delete affordances while keeping browsing,
|
|
217
284
|
preview, details, and download available.
|
|
218
285
|
- `uploadPolicy` can reject files before enqueueing transfers by MIME type, extension, max file size,
|
|
219
|
-
remaining quota, or a custom validator.
|
|
220
|
-
|
|
286
|
+
remaining quota, maximum files per batch, or a custom validator. A batch over `maxFilesPerBatch` is
|
|
287
|
+
rejected before folders are created or transfers enqueue. Other rejections render as an alert and
|
|
288
|
+
valid files in the same batch still upload.
|
|
221
289
|
- Upload conflicts surface a replace / keep both / skip dialog with apply-to-all support.
|
|
222
290
|
- Partial bulk failures can be reported with `FileBrowserBulkActionError`; successful paths stay
|
|
223
291
|
applied and failed paths are surfaced in a dialog.
|
|
224
292
|
- Single-file download uses `signedUrl`. Folder and multi-select bulk download uses `bulkDownloadUrl`
|
|
225
293
|
when present, otherwise it builds a client zip from signed URLs after the configured size warning.
|
|
294
|
+
Set `allowClientZipFallback={false}` to require server ZIP support for folder and multi-file download.
|
|
226
295
|
- Move-capable adapters enable the destination tree picker, Cut/Paste, and drag onto folders.
|
|
227
296
|
- Keyboard shortcuts include Enter preview/open, F2 rename, Delete confirm, Cmd/Ctrl+A selection, and
|
|
228
297
|
Cmd/Ctrl+C/X/V for adapter-gated copy, cut, and paste.
|
|
229
298
|
|
|
299
|
+
### Transfer persistence and concurrency
|
|
300
|
+
|
|
301
|
+
Provider-owned managers use `window.localStorage` by default so resumable state can survive a refresh.
|
|
302
|
+
Set `options={{ storage: null }}` to keep transfer state in memory only. This preserves transfers across
|
|
303
|
+
SPA navigation and browser unmounts but writes no filenames, paths, results, or metadata to durable web
|
|
304
|
+
storage. Transfer persistence serializes only the fields needed to restore transfer status and resume
|
|
305
|
+
multipart work; arbitrary `FileNode.metadata` is never persisted.
|
|
306
|
+
|
|
307
|
+
Set `maxConcurrentUploads` in provider options to bound active uploads across every browser using that
|
|
308
|
+
provider. Queued, resumed, and restored uploads share the same limit:
|
|
309
|
+
|
|
310
|
+
```tsx
|
|
311
|
+
<FileBrowserProvider options={{ maxConcurrentUploads: MAX_CONCURRENT_UPLOADS, storage: null }}>
|
|
312
|
+
<App />
|
|
313
|
+
</FileBrowserProvider>
|
|
314
|
+
```
|
|
315
|
+
|
|
230
316
|
## Required backend lifecycle
|
|
231
317
|
|
|
232
318
|
The package never creates server routes or lifecycle rules. Hosts must configure:
|
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
import type { FileBrowserAdapter, FileBrowserListOptions, FileBrowserListResult, FileBrowserUploadOptions, FileNode } from '../core/types';
|
|
2
2
|
export type CloudAdapterName = 'S3' | 'R2' | 'Supabase';
|
|
3
|
-
export type CloudFileBrowserAdapterOptions = {
|
|
4
|
-
implementation?: FileBrowserAdapter
|
|
3
|
+
export type CloudFileBrowserAdapterOptions<TMetadata = unknown> = {
|
|
4
|
+
implementation?: FileBrowserAdapter<TMetadata>;
|
|
5
5
|
};
|
|
6
|
-
export declare class UnsupportedCloudFileBrowserAdapter implements FileBrowserAdapter {
|
|
6
|
+
export declare class UnsupportedCloudFileBrowserAdapter<TMetadata = unknown> implements FileBrowserAdapter<TMetadata> {
|
|
7
7
|
private readonly adapterName;
|
|
8
|
-
readonly rename?: NonNullable<FileBrowserAdapter['rename']>;
|
|
9
|
-
readonly createFolder?: NonNullable<FileBrowserAdapter['createFolder']>;
|
|
10
|
-
readonly move?: NonNullable<FileBrowserAdapter['move']>;
|
|
11
|
-
readonly copy?: NonNullable<FileBrowserAdapter['copy']>;
|
|
12
|
-
readonly stat?: NonNullable<FileBrowserAdapter['stat']>;
|
|
13
|
-
readonly exists?: NonNullable<FileBrowserAdapter['exists']>;
|
|
14
|
-
readonly createMultipartUpload?: NonNullable<FileBrowserAdapter['createMultipartUpload']>;
|
|
15
|
-
readonly uploadPart?: NonNullable<FileBrowserAdapter['uploadPart']>;
|
|
16
|
-
readonly completeMultipartUpload?: NonNullable<FileBrowserAdapter['completeMultipartUpload']>;
|
|
17
|
-
readonly abortMultipartUpload?: NonNullable<FileBrowserAdapter['abortMultipartUpload']>;
|
|
18
|
-
readonly bulkDownloadUrl?: NonNullable<FileBrowserAdapter['bulkDownloadUrl']>;
|
|
8
|
+
readonly rename?: NonNullable<FileBrowserAdapter<TMetadata>['rename']>;
|
|
9
|
+
readonly createFolder?: NonNullable<FileBrowserAdapter<TMetadata>['createFolder']>;
|
|
10
|
+
readonly move?: NonNullable<FileBrowserAdapter<TMetadata>['move']>;
|
|
11
|
+
readonly copy?: NonNullable<FileBrowserAdapter<TMetadata>['copy']>;
|
|
12
|
+
readonly stat?: NonNullable<FileBrowserAdapter<TMetadata>['stat']>;
|
|
13
|
+
readonly exists?: NonNullable<FileBrowserAdapter<TMetadata>['exists']>;
|
|
14
|
+
readonly createMultipartUpload?: NonNullable<FileBrowserAdapter<TMetadata>['createMultipartUpload']>;
|
|
15
|
+
readonly uploadPart?: NonNullable<FileBrowserAdapter<TMetadata>['uploadPart']>;
|
|
16
|
+
readonly completeMultipartUpload?: NonNullable<FileBrowserAdapter<TMetadata>['completeMultipartUpload']>;
|
|
17
|
+
readonly abortMultipartUpload?: NonNullable<FileBrowserAdapter<TMetadata>['abortMultipartUpload']>;
|
|
18
|
+
readonly bulkDownloadUrl?: NonNullable<FileBrowserAdapter<TMetadata>['bulkDownloadUrl']>;
|
|
19
19
|
private readonly implementation?;
|
|
20
|
-
constructor(adapterName: CloudAdapterName, options?: CloudFileBrowserAdapterOptions);
|
|
21
|
-
list(path: string, opts?: FileBrowserListOptions): Promise<FileBrowserListResult
|
|
20
|
+
constructor(adapterName: CloudAdapterName, options?: CloudFileBrowserAdapterOptions<TMetadata>);
|
|
21
|
+
list(path: string, opts?: FileBrowserListOptions): Promise<FileBrowserListResult<TMetadata>>;
|
|
22
22
|
delete(paths: string[]): Promise<void>;
|
|
23
23
|
signedUrl(path: string): Promise<string>;
|
|
24
|
-
upload(path: string, file: File, opts?: FileBrowserUploadOptions): Promise<FileNode
|
|
24
|
+
upload(path: string, file: File, opts?: FileBrowserUploadOptions): Promise<FileNode<TMetadata>>;
|
|
25
25
|
private error;
|
|
26
26
|
}
|
|
27
27
|
//# sourceMappingURL=cloud-adapter-base.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloud-adapter-base.d.ts","sourceRoot":"","sources":["../../src/adapters/cloud-adapter-base.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,QAAQ,EACR,MAAM,eAAe,CAAA;AAEtB,MAAM,MAAM,gBAAgB,GAAG,IAAI,GAAG,IAAI,GAAG,UAAU,CAAA;AAEvD,MAAM,MAAM,8BAA8B,GAAG;
|
|
1
|
+
{"version":3,"file":"cloud-adapter-base.d.ts","sourceRoot":"","sources":["../../src/adapters/cloud-adapter-base.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,QAAQ,EACR,MAAM,eAAe,CAAA;AAEtB,MAAM,MAAM,gBAAgB,GAAG,IAAI,GAAG,IAAI,GAAG,UAAU,CAAA;AAEvD,MAAM,MAAM,8BAA8B,CAAC,SAAS,GAAG,OAAO,IAAI;IACjE,cAAc,CAAC,EAAE,kBAAkB,CAAC,SAAS,CAAC,CAAA;CAC9C,CAAA;AAED,qBAAa,kCAAkC,CAAC,SAAS,GAAG,OAAO,CAAE,YAAW,kBAAkB,CAAC,SAAS,CAAC;IAgB3G,OAAO,CAAC,QAAQ,CAAC,WAAW;IAf7B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;IACtE,QAAQ,CAAC,YAAY,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,cAAc,CAAC,CAAC,CAAA;IAClF,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;IAClE,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;IAClE,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;IAClE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;IACtE,QAAQ,CAAC,qBAAqB,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAA;IACpG,QAAQ,CAAC,UAAU,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC,CAAA;IAC9E,QAAQ,CAAC,uBAAuB,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAA;IACxG,QAAQ,CAAC,oBAAoB,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAA;IAClG,QAAQ,CAAC,eAAe,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAA;IAExF,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,CAA+B;gBAG7C,WAAW,EAAE,gBAAgB,EAC9C,OAAO,GAAE,8BAA8B,CAAC,SAAS,CAAM;IAuCxD,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAS5F,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAQtC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAQxC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,wBAAwB,GAAG,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAU/F,OAAO,CAAC,KAAK;CAMb"}
|
|
@@ -1,23 +1,24 @@
|
|
|
1
1
|
import type { FileBrowserAdapter, FileBrowserListOptions, FileBrowserListResult, FileBrowserUploadOptions, FileNode } from '../../core/types';
|
|
2
2
|
export type InMemoryFileBrowserCapability = 'createFolder' | 'rename' | 'move' | 'copy' | 'stat' | 'exists' | 'bulkDownloadUrl' | 'multipart';
|
|
3
|
-
export type InMemoryFileBrowserAdapterOptions = {
|
|
3
|
+
export type InMemoryFileBrowserAdapterOptions<TMetadata = unknown> = {
|
|
4
4
|
capabilities?: Partial<Record<InMemoryFileBrowserCapability, boolean>>;
|
|
5
|
+
initialEntries?: readonly FileNode<TMetadata>[];
|
|
5
6
|
multipartPartSize?: number;
|
|
6
7
|
pageSize?: number;
|
|
7
8
|
now?: () => Date;
|
|
8
9
|
};
|
|
9
|
-
export declare class InMemoryFileBrowserAdapter implements FileBrowserAdapter {
|
|
10
|
-
readonly createFolder?: NonNullable<FileBrowserAdapter['createFolder']>;
|
|
11
|
-
readonly rename?: NonNullable<FileBrowserAdapter['rename']>;
|
|
12
|
-
readonly move?: NonNullable<FileBrowserAdapter['move']>;
|
|
13
|
-
readonly copy?: NonNullable<FileBrowserAdapter['copy']>;
|
|
14
|
-
readonly stat?: NonNullable<FileBrowserAdapter['stat']>;
|
|
15
|
-
readonly exists?: NonNullable<FileBrowserAdapter['exists']>;
|
|
16
|
-
readonly bulkDownloadUrl?: NonNullable<FileBrowserAdapter['bulkDownloadUrl']>;
|
|
17
|
-
readonly createMultipartUpload?: NonNullable<FileBrowserAdapter['createMultipartUpload']>;
|
|
18
|
-
readonly uploadPart?: NonNullable<FileBrowserAdapter['uploadPart']>;
|
|
19
|
-
readonly completeMultipartUpload?: NonNullable<FileBrowserAdapter['completeMultipartUpload']>;
|
|
20
|
-
readonly abortMultipartUpload?: NonNullable<FileBrowserAdapter['abortMultipartUpload']>;
|
|
10
|
+
export declare class InMemoryFileBrowserAdapter<TMetadata = unknown> implements FileBrowserAdapter<TMetadata> {
|
|
11
|
+
readonly createFolder?: NonNullable<FileBrowserAdapter<TMetadata>['createFolder']>;
|
|
12
|
+
readonly rename?: NonNullable<FileBrowserAdapter<TMetadata>['rename']>;
|
|
13
|
+
readonly move?: NonNullable<FileBrowserAdapter<TMetadata>['move']>;
|
|
14
|
+
readonly copy?: NonNullable<FileBrowserAdapter<TMetadata>['copy']>;
|
|
15
|
+
readonly stat?: NonNullable<FileBrowserAdapter<TMetadata>['stat']>;
|
|
16
|
+
readonly exists?: NonNullable<FileBrowserAdapter<TMetadata>['exists']>;
|
|
17
|
+
readonly bulkDownloadUrl?: NonNullable<FileBrowserAdapter<TMetadata>['bulkDownloadUrl']>;
|
|
18
|
+
readonly createMultipartUpload?: NonNullable<FileBrowserAdapter<TMetadata>['createMultipartUpload']>;
|
|
19
|
+
readonly uploadPart?: NonNullable<FileBrowserAdapter<TMetadata>['uploadPart']>;
|
|
20
|
+
readonly completeMultipartUpload?: NonNullable<FileBrowserAdapter<TMetadata>['completeMultipartUpload']>;
|
|
21
|
+
readonly abortMultipartUpload?: NonNullable<FileBrowserAdapter<TMetadata>['abortMultipartUpload']>;
|
|
21
22
|
private readonly entries;
|
|
22
23
|
private readonly multipartUploads;
|
|
23
24
|
private readonly multipartPartSize;
|
|
@@ -25,12 +26,12 @@ export declare class InMemoryFileBrowserAdapter implements FileBrowserAdapter {
|
|
|
25
26
|
private readonly now;
|
|
26
27
|
private etagSequence;
|
|
27
28
|
private multipartSequence;
|
|
28
|
-
constructor(options?: InMemoryFileBrowserAdapterOptions);
|
|
29
|
-
list(path: string, opts?: FileBrowserListOptions): Promise<FileBrowserListResult
|
|
29
|
+
constructor(options?: InMemoryFileBrowserAdapterOptions<TMetadata>);
|
|
30
|
+
list(path: string, opts?: FileBrowserListOptions): Promise<FileBrowserListResult<TMetadata>>;
|
|
30
31
|
private createFolderEntry;
|
|
31
32
|
delete(paths: string[]): Promise<void>;
|
|
32
33
|
signedUrl(path: string): Promise<string>;
|
|
33
|
-
upload(path: string, file: File, opts?: FileBrowserUploadOptions): Promise<FileNode
|
|
34
|
+
upload(path: string, file: File, opts?: FileBrowserUploadOptions): Promise<FileNode<TMetadata>>;
|
|
34
35
|
private nextAvailablePath;
|
|
35
36
|
private renameEntry;
|
|
36
37
|
private moveEntries;
|
|
@@ -49,5 +50,5 @@ export declare class InMemoryFileBrowserAdapter implements FileBrowserAdapter {
|
|
|
49
50
|
private timestamp;
|
|
50
51
|
private nextEtag;
|
|
51
52
|
}
|
|
52
|
-
export declare function createInMemoryFileBrowserAdapter(options?: InMemoryFileBrowserAdapterOptions): InMemoryFileBrowserAdapter
|
|
53
|
+
export declare function createInMemoryFileBrowserAdapter<TMetadata = unknown>(options?: InMemoryFileBrowserAdapterOptions<TMetadata>): InMemoryFileBrowserAdapter<TMetadata>;
|
|
53
54
|
//# sourceMappingURL=in-memory-file-browser-adapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"in-memory-file-browser-adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/in-memory/in-memory-file-browser-adapter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACX,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,QAAQ,EACR,MAAM,kBAAkB,CAAA;AAWzB,MAAM,MAAM,6BAA6B,GACtC,cAAc,GACd,QAAQ,GACR,MAAM,GACN,MAAM,GACN,MAAM,GACN,QAAQ,GACR,iBAAiB,GACjB,WAAW,CAAA;AAEd,MAAM,MAAM,iCAAiC,GAAG;
|
|
1
|
+
{"version":3,"file":"in-memory-file-browser-adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/in-memory/in-memory-file-browser-adapter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACX,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,QAAQ,EACR,MAAM,kBAAkB,CAAA;AAWzB,MAAM,MAAM,6BAA6B,GACtC,cAAc,GACd,QAAQ,GACR,MAAM,GACN,MAAM,GACN,MAAM,GACN,QAAQ,GACR,iBAAiB,GACjB,WAAW,CAAA;AAEd,MAAM,MAAM,iCAAiC,CAAC,SAAS,GAAG,OAAO,IAAI;IACpE,YAAY,CAAC,EAAE,OAAO,CAAC,MAAM,CAAC,6BAA6B,EAAE,OAAO,CAAC,CAAC,CAAA;IACtE,cAAc,CAAC,EAAE,SAAS,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAA;IAC/C,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;CAChB,CAAA;AAwBD,qBAAa,0BAA0B,CAAC,SAAS,GAAG,OAAO,CAAE,YAAW,kBAAkB,CAAC,SAAS,CAAC;IACpG,QAAQ,CAAC,YAAY,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,cAAc,CAAC,CAAC,CAAA;IAClF,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;IACtE,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;IAClE,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;IAClE,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;IAClE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;IACtE,QAAQ,CAAC,eAAe,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,iBAAiB,CAAC,CAAC,CAAA;IACxF,QAAQ,CAAC,qBAAqB,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,uBAAuB,CAAC,CAAC,CAAA;IACpG,QAAQ,CAAC,UAAU,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC,CAAA;IAC9E,QAAQ,CAAC,uBAAuB,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,yBAAyB,CAAC,CAAC,CAAA;IACxG,QAAQ,CAAC,oBAAoB,CAAC,EAAE,WAAW,CAAC,kBAAkB,CAAC,SAAS,CAAC,CAAC,sBAAsB,CAAC,CAAC,CAAA;IAElG,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA8C;IACtE,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA6C;IAC9E,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAQ;IAC1C,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAQ;IAClC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAY;IAChC,OAAO,CAAC,YAAY,CAAI;IACxB,OAAO,CAAC,iBAAiB,CAAI;gBAEjB,OAAO,GAAE,iCAAiC,CAAC,SAAS,CAAM;IAwDtE,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,GAAE,sBAA2B,GAAG,OAAO,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;IA8BhG,OAAO,CAAC,iBAAiB;IAyBzB,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAkBtC,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAUxC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,GAAE,wBAA6B,GAAG,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAiCnG,OAAO,CAAC,iBAAiB;IAkBzB,OAAO,CAAC,WAAW;YAoBL,WAAW;IAQzB,OAAO,CAAC,WAAW;IAkCnB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,aAAa;YAWP,qBAAqB;IAwBnC,OAAO,CAAC,0BAA0B;IAqBlC,OAAO,CAAC,mBAAmB;IAqB3B,OAAO,CAAC,4BAA4B;IAuCpC,OAAO,CAAC,yBAAyB;IAOjC,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,WAAW;IAOnB,OAAO,CAAC,kBAAkB;IAQ1B,OAAO,CAAC,QAAQ;IAWhB,OAAO,CAAC,SAAS;IAIjB,OAAO,CAAC,QAAQ;CAIhB;AAED,wBAAgB,gCAAgC,CAAC,SAAS,GAAG,OAAO,EACnE,OAAO,CAAC,EAAE,iCAAiC,CAAC,SAAS,CAAC,GACpD,0BAA0B,CAAC,SAAS,CAAC,CAEvC"}
|
|
@@ -39,7 +39,15 @@ var c = {
|
|
|
39
39
|
name: "",
|
|
40
40
|
kind: "folder",
|
|
41
41
|
modifiedAt: this.timestamp()
|
|
42
|
-
})
|
|
42
|
+
});
|
|
43
|
+
for (let t of e.initialEntries ?? []) {
|
|
44
|
+
let e = i(t.path);
|
|
45
|
+
this.entries.set(e, {
|
|
46
|
+
...t,
|
|
47
|
+
path: e
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
t.createFolder && (this.createFolder = this.createFolderEntry.bind(this)), t.rename && (this.rename = this.renameEntry.bind(this)), t.move && (this.move = this.moveEntries.bind(this)), t.copy && (this.copy = this.copyEntries.bind(this)), t.stat && (this.stat = this.statEntry.bind(this)), t.exists && (this.exists = this.existsEntries.bind(this)), t.bulkDownloadUrl && (this.bulkDownloadUrl = this.createBulkDownloadUrl.bind(this)), t.multipart && (this.createMultipartUpload = this.createMultipartUploadEntry.bind(this), this.uploadPart = this.uploadMultipartPart.bind(this), this.completeMultipartUpload = this.completeMultipartUploadEntry.bind(this), this.abortMultipartUpload = this.abortMultipartUploadEntry.bind(this));
|
|
43
51
|
}
|
|
44
52
|
list(e, n = {}) {
|
|
45
53
|
p(n.signal);
|
|
@@ -250,7 +258,7 @@ function d(e) {
|
|
|
250
258
|
name: e.name,
|
|
251
259
|
kind: e.kind
|
|
252
260
|
};
|
|
253
|
-
return e.size !== void 0 && (t.size = e.size), e.mimeType !== void 0 && (t.mimeType = e.mimeType), e.modifiedAt !== void 0 && (t.modifiedAt = e.modifiedAt), e.etag !== void 0 && (t.etag = e.etag), e.thumbnailUrl !== void 0 && (t.thumbnailUrl = e.thumbnailUrl), t;
|
|
261
|
+
return e.id !== void 0 && (t.id = e.id), e.size !== void 0 && (t.size = e.size), e.mimeType !== void 0 && (t.mimeType = e.mimeType), e.modifiedAt !== void 0 && (t.modifiedAt = e.modifiedAt), e.etag !== void 0 && (t.etag = e.etag), e.thumbnailUrl !== void 0 && (t.thumbnailUrl = e.thumbnailUrl), e.metadata !== void 0 && (t.metadata = e.metadata), t;
|
|
254
262
|
}
|
|
255
263
|
function f(e, t) {
|
|
256
264
|
return e.kind === t.kind ? e.name.localeCompare(t.name, void 0, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/adapters/in-memory/in-memory-file-browser-adapter.ts"],"sourcesContent":["import { zipSync } from 'fflate'\nimport type { Zippable } from 'fflate'\nimport { FileBrowserAdapterError } from '../../core/types'\nimport type {\n\tFileBrowserAdapter,\n\tFileBrowserListOptions,\n\tFileBrowserListResult,\n\tFileBrowserUploadOptions,\n\tFileNode\n} from '../../core/types'\nimport {\n\tROOT_PATH,\n\tgetFileBrowserBasename,\n\tgetFileBrowserDirname,\n\tisFileBrowserDescendantOrSelf,\n\tjoinFileBrowserPath,\n\tnormalizeFileBrowserPath,\n\treplaceFileBrowserPathPrefix\n} from '../../core/path'\n\nexport type InMemoryFileBrowserCapability =\n\t| 'createFolder'\n\t| 'rename'\n\t| 'move'\n\t| 'copy'\n\t| 'stat'\n\t| 'exists'\n\t| 'bulkDownloadUrl'\n\t| 'multipart'\n\nexport type InMemoryFileBrowserAdapterOptions = {\n\tcapabilities?: Partial<Record<InMemoryFileBrowserCapability, boolean>>\n\tmultipartPartSize?: number\n\tpageSize?: number\n\tnow?: () => Date\n}\n\ntype InMemoryEntry = FileNode & {\n\tblob?: Blob\n}\n\ntype InMemoryMultipartUpload = {\n\tpath: string\n\tsize: number\n\tpartSize: number\n\tparts: Map<number, { blob: Blob; etag: string }>\n}\n\nconst DEFAULT_CAPABILITIES: Record<InMemoryFileBrowserCapability, boolean> = {\n\tcreateFolder: true,\n\trename: true,\n\tmove: true,\n\tcopy: true,\n\tstat: true,\n\texists: true,\n\tbulkDownloadUrl: true,\n\tmultipart: false\n}\n\nexport class InMemoryFileBrowserAdapter implements FileBrowserAdapter {\n\treadonly createFolder?: NonNullable<FileBrowserAdapter['createFolder']>\n\treadonly rename?: NonNullable<FileBrowserAdapter['rename']>\n\treadonly move?: NonNullable<FileBrowserAdapter['move']>\n\treadonly copy?: NonNullable<FileBrowserAdapter['copy']>\n\treadonly stat?: NonNullable<FileBrowserAdapter['stat']>\n\treadonly exists?: NonNullable<FileBrowserAdapter['exists']>\n\treadonly bulkDownloadUrl?: NonNullable<FileBrowserAdapter['bulkDownloadUrl']>\n\treadonly createMultipartUpload?: NonNullable<FileBrowserAdapter['createMultipartUpload']>\n\treadonly uploadPart?: NonNullable<FileBrowserAdapter['uploadPart']>\n\treadonly completeMultipartUpload?: NonNullable<FileBrowserAdapter['completeMultipartUpload']>\n\treadonly abortMultipartUpload?: NonNullable<FileBrowserAdapter['abortMultipartUpload']>\n\n\tprivate readonly entries = new Map<string, InMemoryEntry>()\n\tprivate readonly multipartUploads = new Map<string, InMemoryMultipartUpload>()\n\tprivate readonly multipartPartSize: number\n\tprivate readonly pageSize?: number\n\tprivate readonly now: () => Date\n\tprivate etagSequence = 0\n\tprivate multipartSequence = 0\n\n\tconstructor(options: InMemoryFileBrowserAdapterOptions = {}) {\n\t\tconst capabilities = {\n\t\t\t...DEFAULT_CAPABILITIES,\n\t\t\t...options.capabilities\n\t\t}\n\n\t\tthis.pageSize = options.pageSize\n\t\tthis.multipartPartSize = Math.max(1, options.multipartPartSize ?? 5 * 1024 * 1024)\n\t\tthis.now = options.now ?? (() => new Date())\n\t\tthis.entries.set(ROOT_PATH, {\n\t\t\tpath: ROOT_PATH,\n\t\t\tname: '',\n\t\t\tkind: 'folder',\n\t\t\tmodifiedAt: this.timestamp()\n\t\t})\n\n\t\tif (capabilities.createFolder) {\n\t\t\tthis.createFolder = this.createFolderEntry.bind(this)\n\t\t}\n\n\t\tif (capabilities.rename) {\n\t\t\tthis.rename = this.renameEntry.bind(this)\n\t\t}\n\n\t\tif (capabilities.move) {\n\t\t\tthis.move = this.moveEntries.bind(this)\n\t\t}\n\n\t\tif (capabilities.copy) {\n\t\t\tthis.copy = this.copyEntries.bind(this)\n\t\t}\n\n\t\tif (capabilities.stat) {\n\t\t\tthis.stat = this.statEntry.bind(this)\n\t\t}\n\n\t\tif (capabilities.exists) {\n\t\t\tthis.exists = this.existsEntries.bind(this)\n\t\t}\n\n\t\tif (capabilities.bulkDownloadUrl) {\n\t\t\tthis.bulkDownloadUrl = this.createBulkDownloadUrl.bind(this)\n\t\t}\n\n\t\tif (capabilities.multipart) {\n\t\t\tthis.createMultipartUpload = this.createMultipartUploadEntry.bind(this)\n\t\t\tthis.uploadPart = this.uploadMultipartPart.bind(this)\n\t\t\tthis.completeMultipartUpload = this.completeMultipartUploadEntry.bind(this)\n\t\t\tthis.abortMultipartUpload = this.abortMultipartUploadEntry.bind(this)\n\t\t}\n\t}\n\n\tlist(path: string, opts: FileBrowserListOptions = {}): Promise<FileBrowserListResult> {\n\t\tthrowIfAborted(opts.signal)\n\t\tconst normalized = normalizeFileBrowserPath(path)\n\t\tconst folder = this.getEntry(normalized)\n\n\t\tif (folder.kind !== 'folder') {\n\t\t\tthrow new FileBrowserAdapterError('invalid_path', `Cannot list a file path: ${normalized}`)\n\t\t}\n\n\t\tconst allItems = Array.from(this.entries.values())\n\t\t\t.filter((entry) => entry.path !== ROOT_PATH)\n\t\t\t.filter((entry) => getFileBrowserDirname(entry.path) === normalized)\n\t\t\t.sort(compareEntries)\n\t\t\t.map(cloneNode)\n\n\t\tif (!this.pageSize) {\n\t\t\treturn Promise.resolve({ items: allItems })\n\t\t}\n\n\t\tconst start = opts.cursor ? Number.parseInt(opts.cursor, 10) : 0\n\t\tconst safeStart = Number.isFinite(start) && start > 0 ? start : 0\n\t\tconst items = allItems.slice(safeStart, safeStart + this.pageSize)\n\t\tconst next = safeStart + items.length\n\n\t\treturn Promise.resolve({\n\t\t\titems,\n\t\t\tcursor: next < allItems.length ? String(next) : undefined\n\t\t})\n\t}\n\n\tprivate createFolderEntry(path: string): Promise<FileNode> {\n\t\tconst normalized = normalizeFileBrowserPath(path)\n\n\t\tif (normalized === ROOT_PATH) {\n\t\t\treturn Promise.resolve(cloneNode(this.getEntry(ROOT_PATH)))\n\t\t}\n\n\t\tif (this.entries.has(normalized)) {\n\t\t\tthrow new FileBrowserAdapterError('conflict', `A file browser entry already exists at ${normalized}`)\n\t\t}\n\n\t\tthis.assertFolderExists(getFileBrowserDirname(normalized))\n\n\t\tconst entry: InMemoryEntry = {\n\t\t\tpath: normalized,\n\t\t\tname: getFileBrowserBasename(normalized),\n\t\t\tkind: 'folder',\n\t\t\tmodifiedAt: this.timestamp(),\n\t\t\tetag: this.nextEtag()\n\t\t}\n\n\t\tthis.entries.set(normalized, entry)\n\t\treturn Promise.resolve(cloneNode(entry))\n\t}\n\n\tdelete(paths: string[]): Promise<void> {\n\t\tfor (const path of paths.map(normalizeFileBrowserPath)) {\n\t\t\tif (path === ROOT_PATH) {\n\t\t\t\tthrow new FileBrowserAdapterError('invalid_path', 'Cannot delete the root folder')\n\t\t\t}\n\n\t\t\tthis.getEntry(path)\n\n\t\t\tfor (const candidate of Array.from(this.entries.keys())) {\n\t\t\t\tif (isFileBrowserDescendantOrSelf(path, candidate)) {\n\t\t\t\t\tthis.entries.delete(candidate)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn Promise.resolve()\n\t}\n\n\tsignedUrl(path: string): Promise<string> {\n\t\tconst entry = this.getEntry(path)\n\n\t\tif (entry.kind !== 'file' || !entry.blob) {\n\t\t\tthrow new FileBrowserAdapterError('invalid_path', `Cannot create a signed URL for a folder: ${entry.path}`)\n\t\t}\n\n\t\treturn Promise.resolve(URL.createObjectURL(entry.blob))\n\t}\n\n\tupload(path: string, file: File, opts: FileBrowserUploadOptions = {}): Promise<FileNode> {\n\t\tthrowIfAborted(opts.signal)\n\t\tlet normalized = normalizeFileBrowserPath(path)\n\t\tthis.assertFolderExists(getFileBrowserDirname(normalized))\n\n\t\tif (this.entries.has(normalized) && opts.onConflict !== 'replace') {\n\t\t\tif (opts.onConflict === 'keep-both') {\n\t\t\t\tnormalized = this.nextAvailablePath(normalized)\n\t\t\t} else {\n\t\t\t\tthrow new FileBrowserAdapterError('conflict', `A file browser entry already exists at ${normalized}`)\n\t\t\t}\n\t\t}\n\n\t\topts.onProgress?.(0, file.size)\n\t\tthrowIfAborted(opts.signal)\n\n\t\tconst entry: InMemoryEntry = {\n\t\t\tpath: normalized,\n\t\t\tname: getFileBrowserBasename(normalized) || file.name,\n\t\t\tkind: 'file',\n\t\t\tsize: file.size,\n\t\t\tmimeType: file.type || undefined,\n\t\t\tmodifiedAt: this.timestamp(),\n\t\t\tetag: this.nextEtag(),\n\t\t\tblob: file\n\t\t}\n\n\t\tthis.entries.set(normalized, entry)\n\t\topts.onProgress?.(file.size, file.size)\n\n\t\treturn Promise.resolve(cloneNode(entry))\n\t}\n\n\tprivate nextAvailablePath(path: string): string {\n\t\tconst dir = getFileBrowserDirname(path)\n\t\tconst basename = getFileBrowserBasename(path)\n\t\tconst dotIndex = basename.lastIndexOf('.')\n\t\tconst hasExtension = dotIndex > 0\n\t\tconst stem = hasExtension ? basename.slice(0, dotIndex) : basename\n\t\tconst extension = hasExtension ? basename.slice(dotIndex) : ''\n\n\t\tfor (let index = 1; index < Number.MAX_SAFE_INTEGER; index += 1) {\n\t\t\tconst candidate = joinFileBrowserPath(dir, `${stem} (${index})${extension}`)\n\t\t\tif (!this.entries.has(candidate)) {\n\t\t\t\treturn candidate\n\t\t\t}\n\t\t}\n\n\t\tthrow new FileBrowserAdapterError('conflict', `Could not allocate a unique file browser path for ${path}`)\n\t}\n\n\tprivate renameEntry(path: string, newName: string): Promise<FileNode> {\n\t\tconst normalized = normalizeFileBrowserPath(path)\n\t\tconst entry = this.getEntry(normalized)\n\t\tconst trimmedName = newName.trim()\n\n\t\tif (!trimmedName || trimmedName.includes('/') || trimmedName.includes('\\\\')) {\n\t\t\tthrow new FileBrowserAdapterError('invalid_path', `Invalid file browser name: ${newName}`)\n\t\t}\n\n\t\tconst updated: InMemoryEntry = {\n\t\t\t...entry,\n\t\t\tname: trimmedName,\n\t\t\tmodifiedAt: this.timestamp(),\n\t\t\tetag: this.nextEtag()\n\t\t}\n\n\t\tthis.entries.set(normalized, updated)\n\t\treturn Promise.resolve(cloneNode(updated))\n\t}\n\n\tprivate async moveEntries(from: string[], toDir: string): Promise<void> {\n\t\tawait this.copyEntries(from, toDir)\n\n\t\tfor (const path of from) {\n\t\t\tawait this.delete([path])\n\t\t}\n\t}\n\n\tprivate copyEntries(from: string[], toDir: string): Promise<void> {\n\t\tconst normalizedToDir = normalizeFileBrowserPath(toDir)\n\t\tthis.assertFolderExists(normalizedToDir)\n\n\t\tconst copies = new Map<string, InMemoryEntry>()\n\n\t\tfor (const sourcePath of from.map(normalizeFileBrowserPath)) {\n\t\t\tconst source = this.getEntry(sourcePath)\n\t\t\tconst destinationRoot = joinFileBrowserPath(normalizedToDir, getFileBrowserBasename(source.path))\n\n\t\t\tfor (const entry of this.collectTree(source.path)) {\n\t\t\t\tconst destinationPath = replaceFileBrowserPathPrefix(entry.path, source.path, destinationRoot)\n\n\t\t\t\tif (this.entries.has(destinationPath) || copies.has(destinationPath)) {\n\t\t\t\t\tthrow new FileBrowserAdapterError('conflict', `A file browser entry already exists at ${destinationPath}`)\n\t\t\t\t}\n\n\t\t\t\tcopies.set(destinationPath, {\n\t\t\t\t\t...entry,\n\t\t\t\t\tpath: destinationPath,\n\t\t\t\t\tname: entry.path === source.path ? getFileBrowserBasename(destinationPath) : entry.name,\n\t\t\t\t\tmodifiedAt: this.timestamp(),\n\t\t\t\t\tetag: this.nextEtag()\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tfor (const [path, entry] of copies) {\n\t\t\tthis.entries.set(path, entry)\n\t\t}\n\n\t\treturn Promise.resolve()\n\t}\n\n\tprivate statEntry(path: string): Promise<FileNode> {\n\t\treturn Promise.resolve(cloneNode(this.getEntry(path)))\n\t}\n\n\tprivate existsEntries(paths: string[]): Promise<Record<string, boolean>> {\n\t\treturn Promise.resolve(\n\t\t\tObject.fromEntries(\n\t\t\t\tpaths.map((path) => {\n\t\t\t\t\tconst normalized = normalizeFileBrowserPath(path)\n\t\t\t\t\treturn [normalized, this.entries.has(normalized)]\n\t\t\t\t})\n\t\t\t)\n\t\t)\n\t}\n\n\tprivate async createBulkDownloadUrl(paths: string[]): Promise<{ url: string; expiresAt: string }> {\n\t\tconst zippable: Zippable = {}\n\n\t\tfor (const path of paths) {\n\t\t\tthis.getEntry(path)\n\t\t\tconst tree = this.collectTree(path)\n\t\t\tfor (const entry of tree) {\n\t\t\t\tif (entry.kind === 'folder' || !entry.blob) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tzippable[toArchivePath(entry.path)] = new Uint8Array(await entry.blob.arrayBuffer())\n\t\t\t}\n\t\t}\n\n\t\tconst archive = new Blob([zipSync(zippable)], {\n\t\t\ttype: 'application/zip'\n\t\t})\n\n\t\treturn {\n\t\t\turl: URL.createObjectURL(archive),\n\t\t\texpiresAt: new Date(this.now().getTime() + 4 * 60 * 60 * 1000).toISOString()\n\t\t}\n\t}\n\n\tprivate createMultipartUploadEntry(path: string, size: number): Promise<{ uploadId: string; partSize: number }> {\n\t\tconst normalized = normalizeFileBrowserPath(path)\n\t\tthis.assertFolderExists(getFileBrowserDirname(normalized))\n\n\t\tconst existing = this.entries.get(normalized)\n\t\tif (existing?.kind === 'folder') {\n\t\t\tthrow new FileBrowserAdapterError('conflict', `A file browser entry already exists at ${normalized}`)\n\t\t}\n\n\t\tthis.multipartSequence += 1\n\t\tconst uploadId = `memory-multipart-${this.multipartSequence}`\n\t\tthis.multipartUploads.set(uploadId, {\n\t\t\tpath: normalized,\n\t\t\tsize,\n\t\t\tpartSize: this.multipartPartSize,\n\t\t\tparts: new Map()\n\t\t})\n\n\t\treturn Promise.resolve({ uploadId, partSize: this.multipartPartSize })\n\t}\n\n\tprivate uploadMultipartPart({\n\t\tchunk,\n\t\tonProgress,\n\t\tpartNumber,\n\t\tsignal,\n\t\tuploadId\n\t}: Parameters<NonNullable<FileBrowserAdapter['uploadPart']>>[0]): Promise<{\n\t\tetag: string\n\t}> {\n\t\treturn Promise.resolve().then(() => {\n\t\t\tthrowIfAborted(signal)\n\t\t\tconst upload = this.getMultipartUpload(uploadId)\n\t\t\tconst etag = `memory-part-${partNumber}`\n\t\t\tupload.parts.set(partNumber, { blob: chunk, etag })\n\t\t\tonProgress?.(chunk.size)\n\t\t\tthrowIfAborted(signal)\n\n\t\t\treturn { etag }\n\t\t})\n\t}\n\n\tprivate completeMultipartUploadEntry({\n\t\tparts,\n\t\tuploadId\n\t}: Parameters<NonNullable<FileBrowserAdapter['completeMultipartUpload']>>[0]): Promise<FileNode> {\n\t\treturn Promise.resolve().then(() => {\n\t\t\tconst upload = this.getMultipartUpload(uploadId)\n\t\t\tconst blobs: Blob[] = []\n\n\t\t\tfor (const part of parts.sort((left, right) => left.partNumber - right.partNumber)) {\n\t\t\t\tconst uploaded = upload.parts.get(part.partNumber)\n\t\t\t\tif (!uploaded || uploaded.etag !== part.etag) {\n\t\t\t\t\tthrow new FileBrowserAdapterError('not_found', `No uploaded part ${part.partNumber} exists for ${uploadId}`)\n\t\t\t\t}\n\t\t\t\tblobs.push(uploaded.blob)\n\t\t\t}\n\n\t\t\tconst blob = new Blob(blobs)\n\t\t\tif (blob.size !== upload.size) {\n\t\t\t\tthrow new FileBrowserAdapterError('invalid_path', `Multipart upload ${uploadId} size mismatch`)\n\t\t\t}\n\n\t\t\tconst entry: InMemoryEntry = {\n\t\t\t\tpath: upload.path,\n\t\t\t\tname: getFileBrowserBasename(upload.path),\n\t\t\t\tkind: 'file',\n\t\t\t\tsize: blob.size,\n\t\t\t\tmodifiedAt: this.timestamp(),\n\t\t\t\tetag: this.nextEtag(),\n\t\t\t\tblob\n\t\t\t}\n\t\t\tthis.entries.set(upload.path, entry)\n\t\t\tthis.multipartUploads.delete(uploadId)\n\n\t\t\treturn cloneNode(entry)\n\t\t})\n\t}\n\n\tprivate abortMultipartUploadEntry(uploadId: string): Promise<void> {\n\t\treturn Promise.resolve().then(() => {\n\t\t\tthis.getMultipartUpload(uploadId)\n\t\t\tthis.multipartUploads.delete(uploadId)\n\t\t})\n\t}\n\n\tprivate getMultipartUpload(uploadId: string): InMemoryMultipartUpload {\n\t\tconst upload = this.multipartUploads.get(uploadId)\n\t\tif (!upload) {\n\t\t\tthrow new FileBrowserAdapterError('not_found', `No multipart upload exists for ${uploadId}`)\n\t\t}\n\t\treturn upload\n\t}\n\n\tprivate collectTree(path: string): InMemoryEntry[] {\n\t\tconst normalized = normalizeFileBrowserPath(path)\n\t\treturn Array.from(this.entries.values())\n\t\t\t.filter((entry) => isFileBrowserDescendantOrSelf(normalized, entry.path))\n\t\t\t.sort((left, right) => left.path.localeCompare(right.path))\n\t}\n\n\tprivate assertFolderExists(path: string): void {\n\t\tconst entry = this.getEntry(path)\n\n\t\tif (entry.kind !== 'folder') {\n\t\t\tthrow new FileBrowserAdapterError('invalid_path', `Expected a folder at ${entry.path}`)\n\t\t}\n\t}\n\n\tprivate getEntry(path: string): InMemoryEntry {\n\t\tconst normalized = normalizeFileBrowserPath(path)\n\t\tconst entry = this.entries.get(normalized)\n\n\t\tif (!entry) {\n\t\t\tthrow new FileBrowserAdapterError('not_found', `No file browser entry exists at ${normalized}`)\n\t\t}\n\n\t\treturn entry\n\t}\n\n\tprivate timestamp(): string {\n\t\treturn this.now().toISOString()\n\t}\n\n\tprivate nextEtag(): string {\n\t\tthis.etagSequence += 1\n\t\treturn `memory-${this.etagSequence}`\n\t}\n}\n\nexport function createInMemoryFileBrowserAdapter(\n\toptions?: InMemoryFileBrowserAdapterOptions\n): InMemoryFileBrowserAdapter {\n\treturn new InMemoryFileBrowserAdapter(options)\n}\n\nfunction cloneNode(entry: InMemoryEntry): FileNode {\n\tconst node: FileNode = {\n\t\tpath: entry.path,\n\t\tname: entry.name,\n\t\tkind: entry.kind\n\t}\n\n\tif (entry.size !== undefined) {\n\t\tnode.size = entry.size\n\t}\n\n\tif (entry.mimeType !== undefined) {\n\t\tnode.mimeType = entry.mimeType\n\t}\n\n\tif (entry.modifiedAt !== undefined) {\n\t\tnode.modifiedAt = entry.modifiedAt\n\t}\n\n\tif (entry.etag !== undefined) {\n\t\tnode.etag = entry.etag\n\t}\n\n\tif (entry.thumbnailUrl !== undefined) {\n\t\tnode.thumbnailUrl = entry.thumbnailUrl\n\t}\n\n\treturn node\n}\n\nfunction compareEntries(left: InMemoryEntry, right: InMemoryEntry): number {\n\tif (left.kind !== right.kind) {\n\t\treturn left.kind === 'folder' ? -1 : 1\n\t}\n\n\treturn left.name.localeCompare(right.name, undefined, {\n\t\tnumeric: true,\n\t\tsensitivity: 'base'\n\t})\n}\n\nfunction throwIfAborted(signal?: AbortSignal): void {\n\tif (signal?.aborted) {\n\t\tthrow new FileBrowserAdapterError('aborted', 'Operation was aborted')\n\t}\n}\n\nfunction toArchivePath(path: string): string {\n\treturn path.replace(/^\\/+/, '') || 'download'\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/adapters/in-memory/in-memory-file-browser-adapter.ts"],"sourcesContent":["import { zipSync } from 'fflate'\nimport type { Zippable } from 'fflate'\nimport { FileBrowserAdapterError } from '../../core/types'\nimport type {\n\tFileBrowserAdapter,\n\tFileBrowserListOptions,\n\tFileBrowserListResult,\n\tFileBrowserUploadOptions,\n\tFileNode\n} from '../../core/types'\nimport {\n\tROOT_PATH,\n\tgetFileBrowserBasename,\n\tgetFileBrowserDirname,\n\tisFileBrowserDescendantOrSelf,\n\tjoinFileBrowserPath,\n\tnormalizeFileBrowserPath,\n\treplaceFileBrowserPathPrefix\n} from '../../core/path'\n\nexport type InMemoryFileBrowserCapability =\n\t| 'createFolder'\n\t| 'rename'\n\t| 'move'\n\t| 'copy'\n\t| 'stat'\n\t| 'exists'\n\t| 'bulkDownloadUrl'\n\t| 'multipart'\n\nexport type InMemoryFileBrowserAdapterOptions<TMetadata = unknown> = {\n\tcapabilities?: Partial<Record<InMemoryFileBrowserCapability, boolean>>\n\tinitialEntries?: readonly FileNode<TMetadata>[]\n\tmultipartPartSize?: number\n\tpageSize?: number\n\tnow?: () => Date\n}\n\ntype InMemoryEntry<TMetadata> = FileNode<TMetadata> & {\n\tblob?: Blob\n}\n\ntype InMemoryMultipartUpload = {\n\tpath: string\n\tsize: number\n\tpartSize: number\n\tparts: Map<number, { blob: Blob; etag: string }>\n}\n\nconst DEFAULT_CAPABILITIES: Record<InMemoryFileBrowserCapability, boolean> = {\n\tcreateFolder: true,\n\trename: true,\n\tmove: true,\n\tcopy: true,\n\tstat: true,\n\texists: true,\n\tbulkDownloadUrl: true,\n\tmultipart: false\n}\n\nexport class InMemoryFileBrowserAdapter<TMetadata = unknown> implements FileBrowserAdapter<TMetadata> {\n\treadonly createFolder?: NonNullable<FileBrowserAdapter<TMetadata>['createFolder']>\n\treadonly rename?: NonNullable<FileBrowserAdapter<TMetadata>['rename']>\n\treadonly move?: NonNullable<FileBrowserAdapter<TMetadata>['move']>\n\treadonly copy?: NonNullable<FileBrowserAdapter<TMetadata>['copy']>\n\treadonly stat?: NonNullable<FileBrowserAdapter<TMetadata>['stat']>\n\treadonly exists?: NonNullable<FileBrowserAdapter<TMetadata>['exists']>\n\treadonly bulkDownloadUrl?: NonNullable<FileBrowserAdapter<TMetadata>['bulkDownloadUrl']>\n\treadonly createMultipartUpload?: NonNullable<FileBrowserAdapter<TMetadata>['createMultipartUpload']>\n\treadonly uploadPart?: NonNullable<FileBrowserAdapter<TMetadata>['uploadPart']>\n\treadonly completeMultipartUpload?: NonNullable<FileBrowserAdapter<TMetadata>['completeMultipartUpload']>\n\treadonly abortMultipartUpload?: NonNullable<FileBrowserAdapter<TMetadata>['abortMultipartUpload']>\n\n\tprivate readonly entries = new Map<string, InMemoryEntry<TMetadata>>()\n\tprivate readonly multipartUploads = new Map<string, InMemoryMultipartUpload>()\n\tprivate readonly multipartPartSize: number\n\tprivate readonly pageSize?: number\n\tprivate readonly now: () => Date\n\tprivate etagSequence = 0\n\tprivate multipartSequence = 0\n\n\tconstructor(options: InMemoryFileBrowserAdapterOptions<TMetadata> = {}) {\n\t\tconst capabilities = {\n\t\t\t...DEFAULT_CAPABILITIES,\n\t\t\t...options.capabilities\n\t\t}\n\n\t\tthis.pageSize = options.pageSize\n\t\tthis.multipartPartSize = Math.max(1, options.multipartPartSize ?? 5 * 1024 * 1024)\n\t\tthis.now = options.now ?? (() => new Date())\n\t\tthis.entries.set(ROOT_PATH, {\n\t\t\tpath: ROOT_PATH,\n\t\t\tname: '',\n\t\t\tkind: 'folder',\n\t\t\tmodifiedAt: this.timestamp()\n\t\t})\n\t\tfor (const node of options.initialEntries ?? []) {\n\t\t\tconst normalized = normalizeFileBrowserPath(node.path)\n\t\t\tthis.entries.set(normalized, { ...node, path: normalized })\n\t\t}\n\n\t\tif (capabilities.createFolder) {\n\t\t\tthis.createFolder = this.createFolderEntry.bind(this)\n\t\t}\n\n\t\tif (capabilities.rename) {\n\t\t\tthis.rename = this.renameEntry.bind(this)\n\t\t}\n\n\t\tif (capabilities.move) {\n\t\t\tthis.move = this.moveEntries.bind(this)\n\t\t}\n\n\t\tif (capabilities.copy) {\n\t\t\tthis.copy = this.copyEntries.bind(this)\n\t\t}\n\n\t\tif (capabilities.stat) {\n\t\t\tthis.stat = this.statEntry.bind(this)\n\t\t}\n\n\t\tif (capabilities.exists) {\n\t\t\tthis.exists = this.existsEntries.bind(this)\n\t\t}\n\n\t\tif (capabilities.bulkDownloadUrl) {\n\t\t\tthis.bulkDownloadUrl = this.createBulkDownloadUrl.bind(this)\n\t\t}\n\n\t\tif (capabilities.multipart) {\n\t\t\tthis.createMultipartUpload = this.createMultipartUploadEntry.bind(this)\n\t\t\tthis.uploadPart = this.uploadMultipartPart.bind(this)\n\t\t\tthis.completeMultipartUpload = this.completeMultipartUploadEntry.bind(this)\n\t\t\tthis.abortMultipartUpload = this.abortMultipartUploadEntry.bind(this)\n\t\t}\n\t}\n\n\tlist(path: string, opts: FileBrowserListOptions = {}): Promise<FileBrowserListResult<TMetadata>> {\n\t\tthrowIfAborted(opts.signal)\n\t\tconst normalized = normalizeFileBrowserPath(path)\n\t\tconst folder = this.getEntry(normalized)\n\n\t\tif (folder.kind !== 'folder') {\n\t\t\tthrow new FileBrowserAdapterError('invalid_path', `Cannot list a file path: ${normalized}`)\n\t\t}\n\n\t\tconst allItems = Array.from(this.entries.values())\n\t\t\t.filter((entry) => entry.path !== ROOT_PATH)\n\t\t\t.filter((entry) => getFileBrowserDirname(entry.path) === normalized)\n\t\t\t.sort(compareEntries)\n\t\t\t.map(cloneNode)\n\n\t\tif (!this.pageSize) {\n\t\t\treturn Promise.resolve({ items: allItems })\n\t\t}\n\n\t\tconst start = opts.cursor ? Number.parseInt(opts.cursor, 10) : 0\n\t\tconst safeStart = Number.isFinite(start) && start > 0 ? start : 0\n\t\tconst items = allItems.slice(safeStart, safeStart + this.pageSize)\n\t\tconst next = safeStart + items.length\n\n\t\treturn Promise.resolve({\n\t\t\titems,\n\t\t\tcursor: next < allItems.length ? String(next) : undefined\n\t\t})\n\t}\n\n\tprivate createFolderEntry(path: string): Promise<FileNode<TMetadata>> {\n\t\tconst normalized = normalizeFileBrowserPath(path)\n\n\t\tif (normalized === ROOT_PATH) {\n\t\t\treturn Promise.resolve(cloneNode(this.getEntry(ROOT_PATH)))\n\t\t}\n\n\t\tif (this.entries.has(normalized)) {\n\t\t\tthrow new FileBrowserAdapterError('conflict', `A file browser entry already exists at ${normalized}`)\n\t\t}\n\n\t\tthis.assertFolderExists(getFileBrowserDirname(normalized))\n\n\t\tconst entry: InMemoryEntry<TMetadata> = {\n\t\t\tpath: normalized,\n\t\t\tname: getFileBrowserBasename(normalized),\n\t\t\tkind: 'folder',\n\t\t\tmodifiedAt: this.timestamp(),\n\t\t\tetag: this.nextEtag()\n\t\t}\n\n\t\tthis.entries.set(normalized, entry)\n\t\treturn Promise.resolve(cloneNode(entry))\n\t}\n\n\tdelete(paths: string[]): Promise<void> {\n\t\tfor (const path of paths.map(normalizeFileBrowserPath)) {\n\t\t\tif (path === ROOT_PATH) {\n\t\t\t\tthrow new FileBrowserAdapterError('invalid_path', 'Cannot delete the root folder')\n\t\t\t}\n\n\t\t\tthis.getEntry(path)\n\n\t\t\tfor (const candidate of Array.from(this.entries.keys())) {\n\t\t\t\tif (isFileBrowserDescendantOrSelf(path, candidate)) {\n\t\t\t\t\tthis.entries.delete(candidate)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn Promise.resolve()\n\t}\n\n\tsignedUrl(path: string): Promise<string> {\n\t\tconst entry = this.getEntry(path)\n\n\t\tif (entry.kind !== 'file' || !entry.blob) {\n\t\t\tthrow new FileBrowserAdapterError('invalid_path', `Cannot create a signed URL for a folder: ${entry.path}`)\n\t\t}\n\n\t\treturn Promise.resolve(URL.createObjectURL(entry.blob))\n\t}\n\n\tupload(path: string, file: File, opts: FileBrowserUploadOptions = {}): Promise<FileNode<TMetadata>> {\n\t\tthrowIfAborted(opts.signal)\n\t\tlet normalized = normalizeFileBrowserPath(path)\n\t\tthis.assertFolderExists(getFileBrowserDirname(normalized))\n\n\t\tif (this.entries.has(normalized) && opts.onConflict !== 'replace') {\n\t\t\tif (opts.onConflict === 'keep-both') {\n\t\t\t\tnormalized = this.nextAvailablePath(normalized)\n\t\t\t} else {\n\t\t\t\tthrow new FileBrowserAdapterError('conflict', `A file browser entry already exists at ${normalized}`)\n\t\t\t}\n\t\t}\n\n\t\topts.onProgress?.(0, file.size)\n\t\tthrowIfAborted(opts.signal)\n\n\t\tconst entry: InMemoryEntry<TMetadata> = {\n\t\t\tpath: normalized,\n\t\t\tname: getFileBrowserBasename(normalized) || file.name,\n\t\t\tkind: 'file',\n\t\t\tsize: file.size,\n\t\t\tmimeType: file.type || undefined,\n\t\t\tmodifiedAt: this.timestamp(),\n\t\t\tetag: this.nextEtag(),\n\t\t\tblob: file\n\t\t}\n\n\t\tthis.entries.set(normalized, entry)\n\t\topts.onProgress?.(file.size, file.size)\n\n\t\treturn Promise.resolve(cloneNode(entry))\n\t}\n\n\tprivate nextAvailablePath(path: string): string {\n\t\tconst dir = getFileBrowserDirname(path)\n\t\tconst basename = getFileBrowserBasename(path)\n\t\tconst dotIndex = basename.lastIndexOf('.')\n\t\tconst hasExtension = dotIndex > 0\n\t\tconst stem = hasExtension ? basename.slice(0, dotIndex) : basename\n\t\tconst extension = hasExtension ? basename.slice(dotIndex) : ''\n\n\t\tfor (let index = 1; index < Number.MAX_SAFE_INTEGER; index += 1) {\n\t\t\tconst candidate = joinFileBrowserPath(dir, `${stem} (${index})${extension}`)\n\t\t\tif (!this.entries.has(candidate)) {\n\t\t\t\treturn candidate\n\t\t\t}\n\t\t}\n\n\t\tthrow new FileBrowserAdapterError('conflict', `Could not allocate a unique file browser path for ${path}`)\n\t}\n\n\tprivate renameEntry(path: string, newName: string): Promise<FileNode<TMetadata>> {\n\t\tconst normalized = normalizeFileBrowserPath(path)\n\t\tconst entry = this.getEntry(normalized)\n\t\tconst trimmedName = newName.trim()\n\n\t\tif (!trimmedName || trimmedName.includes('/') || trimmedName.includes('\\\\')) {\n\t\t\tthrow new FileBrowserAdapterError('invalid_path', `Invalid file browser name: ${newName}`)\n\t\t}\n\n\t\tconst updated: InMemoryEntry<TMetadata> = {\n\t\t\t...entry,\n\t\t\tname: trimmedName,\n\t\t\tmodifiedAt: this.timestamp(),\n\t\t\tetag: this.nextEtag()\n\t\t}\n\n\t\tthis.entries.set(normalized, updated)\n\t\treturn Promise.resolve(cloneNode(updated))\n\t}\n\n\tprivate async moveEntries(from: string[], toDir: string): Promise<void> {\n\t\tawait this.copyEntries(from, toDir)\n\n\t\tfor (const path of from) {\n\t\t\tawait this.delete([path])\n\t\t}\n\t}\n\n\tprivate copyEntries(from: string[], toDir: string): Promise<void> {\n\t\tconst normalizedToDir = normalizeFileBrowserPath(toDir)\n\t\tthis.assertFolderExists(normalizedToDir)\n\n\t\tconst copies = new Map<string, InMemoryEntry<TMetadata>>()\n\n\t\tfor (const sourcePath of from.map(normalizeFileBrowserPath)) {\n\t\t\tconst source = this.getEntry(sourcePath)\n\t\t\tconst destinationRoot = joinFileBrowserPath(normalizedToDir, getFileBrowserBasename(source.path))\n\n\t\t\tfor (const entry of this.collectTree(source.path)) {\n\t\t\t\tconst destinationPath = replaceFileBrowserPathPrefix(entry.path, source.path, destinationRoot)\n\n\t\t\t\tif (this.entries.has(destinationPath) || copies.has(destinationPath)) {\n\t\t\t\t\tthrow new FileBrowserAdapterError('conflict', `A file browser entry already exists at ${destinationPath}`)\n\t\t\t\t}\n\n\t\t\t\tcopies.set(destinationPath, {\n\t\t\t\t\t...entry,\n\t\t\t\t\tpath: destinationPath,\n\t\t\t\t\tname: entry.path === source.path ? getFileBrowserBasename(destinationPath) : entry.name,\n\t\t\t\t\tmodifiedAt: this.timestamp(),\n\t\t\t\t\tetag: this.nextEtag()\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tfor (const [path, entry] of copies) {\n\t\t\tthis.entries.set(path, entry)\n\t\t}\n\n\t\treturn Promise.resolve()\n\t}\n\n\tprivate statEntry(path: string): Promise<FileNode<TMetadata>> {\n\t\treturn Promise.resolve(cloneNode(this.getEntry(path)))\n\t}\n\n\tprivate existsEntries(paths: string[]): Promise<Record<string, boolean>> {\n\t\treturn Promise.resolve(\n\t\t\tObject.fromEntries(\n\t\t\t\tpaths.map((path) => {\n\t\t\t\t\tconst normalized = normalizeFileBrowserPath(path)\n\t\t\t\t\treturn [normalized, this.entries.has(normalized)]\n\t\t\t\t})\n\t\t\t)\n\t\t)\n\t}\n\n\tprivate async createBulkDownloadUrl(paths: string[]): Promise<{ url: string; expiresAt: string }> {\n\t\tconst zippable: Zippable = {}\n\n\t\tfor (const path of paths) {\n\t\t\tthis.getEntry(path)\n\t\t\tconst tree = this.collectTree(path)\n\t\t\tfor (const entry of tree) {\n\t\t\t\tif (entry.kind === 'folder' || !entry.blob) {\n\t\t\t\t\tcontinue\n\t\t\t\t}\n\t\t\t\tzippable[toArchivePath(entry.path)] = new Uint8Array(await entry.blob.arrayBuffer())\n\t\t\t}\n\t\t}\n\n\t\tconst archive = new Blob([zipSync(zippable)], {\n\t\t\ttype: 'application/zip'\n\t\t})\n\n\t\treturn {\n\t\t\turl: URL.createObjectURL(archive),\n\t\t\texpiresAt: new Date(this.now().getTime() + 4 * 60 * 60 * 1000).toISOString()\n\t\t}\n\t}\n\n\tprivate createMultipartUploadEntry(path: string, size: number): Promise<{ uploadId: string; partSize: number }> {\n\t\tconst normalized = normalizeFileBrowserPath(path)\n\t\tthis.assertFolderExists(getFileBrowserDirname(normalized))\n\n\t\tconst existing = this.entries.get(normalized)\n\t\tif (existing?.kind === 'folder') {\n\t\t\tthrow new FileBrowserAdapterError('conflict', `A file browser entry already exists at ${normalized}`)\n\t\t}\n\n\t\tthis.multipartSequence += 1\n\t\tconst uploadId = `memory-multipart-${this.multipartSequence}`\n\t\tthis.multipartUploads.set(uploadId, {\n\t\t\tpath: normalized,\n\t\t\tsize,\n\t\t\tpartSize: this.multipartPartSize,\n\t\t\tparts: new Map()\n\t\t})\n\n\t\treturn Promise.resolve({ uploadId, partSize: this.multipartPartSize })\n\t}\n\n\tprivate uploadMultipartPart({\n\t\tchunk,\n\t\tonProgress,\n\t\tpartNumber,\n\t\tsignal,\n\t\tuploadId\n\t}: Parameters<NonNullable<FileBrowserAdapter<TMetadata>['uploadPart']>>[0]): Promise<{\n\t\tetag: string\n\t}> {\n\t\treturn Promise.resolve().then(() => {\n\t\t\tthrowIfAborted(signal)\n\t\t\tconst upload = this.getMultipartUpload(uploadId)\n\t\t\tconst etag = `memory-part-${partNumber}`\n\t\t\tupload.parts.set(partNumber, { blob: chunk, etag })\n\t\t\tonProgress?.(chunk.size)\n\t\t\tthrowIfAborted(signal)\n\n\t\t\treturn { etag }\n\t\t})\n\t}\n\n\tprivate completeMultipartUploadEntry({\n\t\tparts,\n\t\tuploadId\n\t}: Parameters<NonNullable<FileBrowserAdapter<TMetadata>['completeMultipartUpload']>>[0]): Promise<\n\t\tFileNode<TMetadata>\n\t> {\n\t\treturn Promise.resolve().then(() => {\n\t\t\tconst upload = this.getMultipartUpload(uploadId)\n\t\t\tconst blobs: Blob[] = []\n\n\t\t\tfor (const part of parts.sort((left, right) => left.partNumber - right.partNumber)) {\n\t\t\t\tconst uploaded = upload.parts.get(part.partNumber)\n\t\t\t\tif (!uploaded || uploaded.etag !== part.etag) {\n\t\t\t\t\tthrow new FileBrowserAdapterError('not_found', `No uploaded part ${part.partNumber} exists for ${uploadId}`)\n\t\t\t\t}\n\t\t\t\tblobs.push(uploaded.blob)\n\t\t\t}\n\n\t\t\tconst blob = new Blob(blobs)\n\t\t\tif (blob.size !== upload.size) {\n\t\t\t\tthrow new FileBrowserAdapterError('invalid_path', `Multipart upload ${uploadId} size mismatch`)\n\t\t\t}\n\n\t\t\tconst entry: InMemoryEntry<TMetadata> = {\n\t\t\t\tpath: upload.path,\n\t\t\t\tname: getFileBrowserBasename(upload.path),\n\t\t\t\tkind: 'file',\n\t\t\t\tsize: blob.size,\n\t\t\t\tmodifiedAt: this.timestamp(),\n\t\t\t\tetag: this.nextEtag(),\n\t\t\t\tblob\n\t\t\t}\n\t\t\tthis.entries.set(upload.path, entry)\n\t\t\tthis.multipartUploads.delete(uploadId)\n\n\t\t\treturn cloneNode(entry)\n\t\t})\n\t}\n\n\tprivate abortMultipartUploadEntry(uploadId: string): Promise<void> {\n\t\treturn Promise.resolve().then(() => {\n\t\t\tthis.getMultipartUpload(uploadId)\n\t\t\tthis.multipartUploads.delete(uploadId)\n\t\t})\n\t}\n\n\tprivate getMultipartUpload(uploadId: string): InMemoryMultipartUpload {\n\t\tconst upload = this.multipartUploads.get(uploadId)\n\t\tif (!upload) {\n\t\t\tthrow new FileBrowserAdapterError('not_found', `No multipart upload exists for ${uploadId}`)\n\t\t}\n\t\treturn upload\n\t}\n\n\tprivate collectTree(path: string): InMemoryEntry<TMetadata>[] {\n\t\tconst normalized = normalizeFileBrowserPath(path)\n\t\treturn Array.from(this.entries.values())\n\t\t\t.filter((entry) => isFileBrowserDescendantOrSelf(normalized, entry.path))\n\t\t\t.sort((left, right) => left.path.localeCompare(right.path))\n\t}\n\n\tprivate assertFolderExists(path: string): void {\n\t\tconst entry = this.getEntry(path)\n\n\t\tif (entry.kind !== 'folder') {\n\t\t\tthrow new FileBrowserAdapterError('invalid_path', `Expected a folder at ${entry.path}`)\n\t\t}\n\t}\n\n\tprivate getEntry(path: string): InMemoryEntry<TMetadata> {\n\t\tconst normalized = normalizeFileBrowserPath(path)\n\t\tconst entry = this.entries.get(normalized)\n\n\t\tif (!entry) {\n\t\t\tthrow new FileBrowserAdapterError('not_found', `No file browser entry exists at ${normalized}`)\n\t\t}\n\n\t\treturn entry\n\t}\n\n\tprivate timestamp(): string {\n\t\treturn this.now().toISOString()\n\t}\n\n\tprivate nextEtag(): string {\n\t\tthis.etagSequence += 1\n\t\treturn `memory-${this.etagSequence}`\n\t}\n}\n\nexport function createInMemoryFileBrowserAdapter<TMetadata = unknown>(\n\toptions?: InMemoryFileBrowserAdapterOptions<TMetadata>\n): InMemoryFileBrowserAdapter<TMetadata> {\n\treturn new InMemoryFileBrowserAdapter<TMetadata>(options)\n}\n\nfunction cloneNode<TMetadata>(entry: InMemoryEntry<TMetadata>): FileNode<TMetadata> {\n\tconst node: FileNode<TMetadata> = {\n\t\tpath: entry.path,\n\t\tname: entry.name,\n\t\tkind: entry.kind\n\t}\n\n\tif (entry.id !== undefined) {\n\t\tnode.id = entry.id\n\t}\n\n\tif (entry.size !== undefined) {\n\t\tnode.size = entry.size\n\t}\n\n\tif (entry.mimeType !== undefined) {\n\t\tnode.mimeType = entry.mimeType\n\t}\n\n\tif (entry.modifiedAt !== undefined) {\n\t\tnode.modifiedAt = entry.modifiedAt\n\t}\n\n\tif (entry.etag !== undefined) {\n\t\tnode.etag = entry.etag\n\t}\n\n\tif (entry.thumbnailUrl !== undefined) {\n\t\tnode.thumbnailUrl = entry.thumbnailUrl\n\t}\n\n\tif (entry.metadata !== undefined) {\n\t\tnode.metadata = entry.metadata\n\t}\n\n\treturn node\n}\n\nfunction compareEntries<TMetadata>(left: InMemoryEntry<TMetadata>, right: InMemoryEntry<TMetadata>): number {\n\tif (left.kind !== right.kind) {\n\t\treturn left.kind === 'folder' ? -1 : 1\n\t}\n\n\treturn left.name.localeCompare(right.name, undefined, {\n\t\tnumeric: true,\n\t\tsensitivity: 'base'\n\t})\n}\n\nfunction throwIfAborted(signal?: AbortSignal): void {\n\tif (signal?.aborted) {\n\t\tthrow new FileBrowserAdapterError('aborted', 'Operation was aborted')\n\t}\n}\n\nfunction toArchivePath(path: string): string {\n\treturn path.replace(/^\\/+/, '') || 'download'\n}\n"],"mappings":";;;AAiDA,IAAM,IAAuE;CAC5E,cAAc;CACd,QAAQ;CACR,MAAM;CACN,MAAM;CACN,MAAM;CACN,QAAQ;CACR,iBAAiB;CACjB,WAAW;AACZ,GAEa,IAAb,MAAsG;CACrG;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CAEA,0BAA2B,IAAI,IAAsC;CACrE,mCAAoC,IAAI,IAAqC;CAC7E;CACA;CACA;CACA,eAAuB;CACvB,oBAA4B;CAE5B,YAAY,IAAwD,CAAC,GAAG;EACvE,IAAM,IAAe;GACpB,GAAG;GACH,GAAG,EAAQ;EACZ;EAKA,AAHA,KAAK,WAAW,EAAQ,UACxB,KAAK,oBAAoB,KAAK,IAAI,GAAG,EAAQ,qBAAqB,IAAI,OAAO,IAAI,GACjF,KAAK,MAAM,EAAQ,8BAAc,IAAI,KAAK,IAC1C,KAAK,QAAQ,IAAA,KAAe;GAC3B,MAAA;GACA,MAAM;GACN,MAAM;GACN,YAAY,KAAK,UAAU;EAC5B,CAAC;EACD,KAAK,IAAM,KAAQ,EAAQ,kBAAkB,CAAC,GAAG;GAChD,IAAM,IAAa,EAAyB,EAAK,IAAI;GACrD,KAAK,QAAQ,IAAI,GAAY;IAAE,GAAG;IAAM,MAAM;GAAW,CAAC;EAC3D;EA8BA,AA5BI,EAAa,iBAChB,KAAK,eAAe,KAAK,kBAAkB,KAAK,IAAI,IAGjD,EAAa,WAChB,KAAK,SAAS,KAAK,YAAY,KAAK,IAAI,IAGrC,EAAa,SAChB,KAAK,OAAO,KAAK,YAAY,KAAK,IAAI,IAGnC,EAAa,SAChB,KAAK,OAAO,KAAK,YAAY,KAAK,IAAI,IAGnC,EAAa,SAChB,KAAK,OAAO,KAAK,UAAU,KAAK,IAAI,IAGjC,EAAa,WAChB,KAAK,SAAS,KAAK,cAAc,KAAK,IAAI,IAGvC,EAAa,oBAChB,KAAK,kBAAkB,KAAK,sBAAsB,KAAK,IAAI,IAGxD,EAAa,cAChB,KAAK,wBAAwB,KAAK,2BAA2B,KAAK,IAAI,GACtE,KAAK,aAAa,KAAK,oBAAoB,KAAK,IAAI,GACpD,KAAK,0BAA0B,KAAK,6BAA6B,KAAK,IAAI,GAC1E,KAAK,uBAAuB,KAAK,0BAA0B,KAAK,IAAI;CAEtE;CAEA,KAAK,GAAc,IAA+B,CAAC,GAA8C;EAChG,EAAe,EAAK,MAAM;EAC1B,IAAM,IAAa,EAAyB,CAAI;EAGhD,IAFe,KAAK,SAAS,CAEzB,CAAA,CAAO,SAAS,UACnB,MAAM,IAAI,EAAwB,gBAAgB,4BAA4B,GAAY;EAG3F,IAAM,IAAW,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC,CAAC,CAChD,QAAQ,MAAU,EAAM,SAAA,GAAkB,CAAC,CAC3C,QAAQ,MAAU,EAAsB,EAAM,IAAI,MAAM,CAAU,CAAC,CACnE,KAAK,CAAc,CAAC,CACpB,IAAI,CAAS;EAEf,IAAI,CAAC,KAAK,UACT,OAAO,QAAQ,QAAQ,EAAE,OAAO,EAAS,CAAC;EAG3C,IAAM,IAAQ,EAAK,SAAS,OAAO,SAAS,EAAK,QAAQ,EAAE,IAAI,GACzD,IAAY,OAAO,SAAS,CAAK,KAAK,IAAQ,IAAI,IAAQ,GAC1D,IAAQ,EAAS,MAAM,GAAW,IAAY,KAAK,QAAQ,GAC3D,IAAO,IAAY,EAAM;EAE/B,OAAO,QAAQ,QAAQ;GACtB;GACA,QAAQ,IAAO,EAAS,SAAS,OAAO,CAAI,IAAI,KAAA;EACjD,CAAC;CACF;CAEA,kBAA0B,GAA4C;EACrE,IAAM,IAAa,EAAyB,CAAI;EAEhD,IAAI,MAAA,KACH,OAAO,QAAQ,QAAQ,EAAU,KAAK,SAAA,GAAkB,CAAC,CAAC;EAG3D,IAAI,KAAK,QAAQ,IAAI,CAAU,GAC9B,MAAM,IAAI,EAAwB,YAAY,0CAA0C,GAAY;EAGrG,KAAK,mBAAmB,EAAsB,CAAU,CAAC;EAEzD,IAAM,IAAkC;GACvC,MAAM;GACN,MAAM,EAAuB,CAAU;GACvC,MAAM;GACN,YAAY,KAAK,UAAU;GAC3B,MAAM,KAAK,SAAS;EACrB;EAGA,OADA,KAAK,QAAQ,IAAI,GAAY,CAAK,GAC3B,QAAQ,QAAQ,EAAU,CAAK,CAAC;CACxC;CAEA,OAAO,GAAgC;EACtC,KAAK,IAAM,KAAQ,EAAM,IAAI,CAAwB,GAAG;GACvD,IAAI,MAAA,KACH,MAAM,IAAI,EAAwB,gBAAgB,+BAA+B;GAGlF,KAAK,SAAS,CAAI;GAElB,KAAK,IAAM,KAAa,MAAM,KAAK,KAAK,QAAQ,KAAK,CAAC,GACrD,AAAI,EAA8B,GAAM,CAAS,KAChD,KAAK,QAAQ,OAAO,CAAS;EAGhC;EAEA,OAAO,QAAQ,QAAQ;CACxB;CAEA,UAAU,GAA+B;EACxC,IAAM,IAAQ,KAAK,SAAS,CAAI;EAEhC,IAAI,EAAM,SAAS,UAAU,CAAC,EAAM,MACnC,MAAM,IAAI,EAAwB,gBAAgB,4CAA4C,EAAM,MAAM;EAG3G,OAAO,QAAQ,QAAQ,IAAI,gBAAgB,EAAM,IAAI,CAAC;CACvD;CAEA,OAAO,GAAc,GAAY,IAAiC,CAAC,GAAiC;EACnG,EAAe,EAAK,MAAM;EAC1B,IAAI,IAAa,EAAyB,CAAI;EAG9C,IAFA,KAAK,mBAAmB,EAAsB,CAAU,CAAC,GAErD,KAAK,QAAQ,IAAI,CAAU,KAAK,EAAK,eAAe,WACvD,IAAI,EAAK,eAAe,aACvB,IAAa,KAAK,kBAAkB,CAAU;OAE9C,MAAM,IAAI,EAAwB,YAAY,0CAA0C,GAAY;EAKtG,AADA,EAAK,aAAa,GAAG,EAAK,IAAI,GAC9B,EAAe,EAAK,MAAM;EAE1B,IAAM,IAAkC;GACvC,MAAM;GACN,MAAM,EAAuB,CAAU,KAAK,EAAK;GACjD,MAAM;GACN,MAAM,EAAK;GACX,UAAU,EAAK,QAAQ,KAAA;GACvB,YAAY,KAAK,UAAU;GAC3B,MAAM,KAAK,SAAS;GACpB,MAAM;EACP;EAKA,OAHA,KAAK,QAAQ,IAAI,GAAY,CAAK,GAClC,EAAK,aAAa,EAAK,MAAM,EAAK,IAAI,GAE/B,QAAQ,QAAQ,EAAU,CAAK,CAAC;CACxC;CAEA,kBAA0B,GAAsB;EAC/C,IAAM,IAAM,EAAsB,CAAI,GAChC,IAAW,EAAuB,CAAI,GACtC,IAAW,EAAS,YAAY,GAAG,GACnC,IAAe,IAAW,GAC1B,IAAO,IAAe,EAAS,MAAM,GAAG,CAAQ,IAAI,GACpD,IAAY,IAAe,EAAS,MAAM,CAAQ,IAAI;EAE5D,KAAK,IAAI,IAAQ,GAAG,iBAAiC,KAAS,GAAG;GAChE,IAAM,IAAY,EAAoB,GAAK,GAAG,EAAK,IAAI,EAAM,GAAG,GAAW;GAC3E,IAAI,CAAC,KAAK,QAAQ,IAAI,CAAS,GAC9B,OAAO;EAET;EAEA,MAAM,IAAI,EAAwB,YAAY,qDAAqD,GAAM;CAC1G;CAEA,YAAoB,GAAc,GAA+C;EAChF,IAAM,IAAa,EAAyB,CAAI,GAC1C,IAAQ,KAAK,SAAS,CAAU,GAChC,IAAc,EAAQ,KAAK;EAEjC,IAAI,CAAC,KAAe,EAAY,SAAS,GAAG,KAAK,EAAY,SAAS,IAAI,GACzE,MAAM,IAAI,EAAwB,gBAAgB,8BAA8B,GAAS;EAG1F,IAAM,IAAoC;GACzC,GAAG;GACH,MAAM;GACN,YAAY,KAAK,UAAU;GAC3B,MAAM,KAAK,SAAS;EACrB;EAGA,OADA,KAAK,QAAQ,IAAI,GAAY,CAAO,GAC7B,QAAQ,QAAQ,EAAU,CAAO,CAAC;CAC1C;CAEA,MAAc,YAAY,GAAgB,GAA8B;EACvE,MAAM,KAAK,YAAY,GAAM,CAAK;EAElC,KAAK,IAAM,KAAQ,GAClB,MAAM,KAAK,OAAO,CAAC,CAAI,CAAC;CAE1B;CAEA,YAAoB,GAAgB,GAA8B;EACjE,IAAM,IAAkB,EAAyB,CAAK;EACtD,KAAK,mBAAmB,CAAe;EAEvC,IAAM,oBAAS,IAAI,IAAsC;EAEzD,KAAK,IAAM,KAAc,EAAK,IAAI,CAAwB,GAAG;GAC5D,IAAM,IAAS,KAAK,SAAS,CAAU,GACjC,IAAkB,EAAoB,GAAiB,EAAuB,EAAO,IAAI,CAAC;GAEhG,KAAK,IAAM,KAAS,KAAK,YAAY,EAAO,IAAI,GAAG;IAClD,IAAM,IAAkB,EAA6B,EAAM,MAAM,EAAO,MAAM,CAAe;IAE7F,IAAI,KAAK,QAAQ,IAAI,CAAe,KAAK,EAAO,IAAI,CAAe,GAClE,MAAM,IAAI,EAAwB,YAAY,0CAA0C,GAAiB;IAG1G,EAAO,IAAI,GAAiB;KAC3B,GAAG;KACH,MAAM;KACN,MAAM,EAAM,SAAS,EAAO,OAAO,EAAuB,CAAe,IAAI,EAAM;KACnF,YAAY,KAAK,UAAU;KAC3B,MAAM,KAAK,SAAS;IACrB,CAAC;GACF;EACD;EAEA,KAAK,IAAM,CAAC,GAAM,MAAU,GAC3B,KAAK,QAAQ,IAAI,GAAM,CAAK;EAG7B,OAAO,QAAQ,QAAQ;CACxB;CAEA,UAAkB,GAA4C;EAC7D,OAAO,QAAQ,QAAQ,EAAU,KAAK,SAAS,CAAI,CAAC,CAAC;CACtD;CAEA,cAAsB,GAAmD;EACxE,OAAO,QAAQ,QACd,OAAO,YACN,EAAM,KAAK,MAAS;GACnB,IAAM,IAAa,EAAyB,CAAI;GAChD,OAAO,CAAC,GAAY,KAAK,QAAQ,IAAI,CAAU,CAAC;EACjD,CAAC,CACF,CACD;CACD;CAEA,MAAc,sBAAsB,GAA8D;EACjG,IAAM,IAAqB,CAAC;EAE5B,KAAK,IAAM,KAAQ,GAAO;GACzB,KAAK,SAAS,CAAI;GAClB,IAAM,IAAO,KAAK,YAAY,CAAI;GAClC,KAAK,IAAM,KAAS,GACf,EAAM,SAAS,YAAY,CAAC,EAAM,SAGtC,EAAS,EAAc,EAAM,IAAI,KAAK,IAAI,WAAW,MAAM,EAAM,KAAK,YAAY,CAAC;EAErF;EAEA,IAAM,IAAU,IAAI,KAAK,CAAC,EAAQ,CAAQ,CAAC,GAAG,EAC7C,MAAM,kBACP,CAAC;EAED,OAAO;GACN,KAAK,IAAI,gBAAgB,CAAO;GAChC,WAAW,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,QAAQ,IAAI,QAAc,GAAI,CAAC,CAAC,YAAY;EAC5E;CACD;CAEA,2BAAmC,GAAc,GAA+D;EAC/G,IAAM,IAAa,EAAyB,CAAI;EAIhD,IAHA,KAAK,mBAAmB,EAAsB,CAAU,CAAC,GAExC,KAAK,QAAQ,IAAI,CAC9B,CAAA,EAAU,SAAS,UACtB,MAAM,IAAI,EAAwB,YAAY,0CAA0C,GAAY;EAGrG,KAAK,qBAAqB;EAC1B,IAAM,IAAW,oBAAoB,KAAK;EAQ1C,OAPA,KAAK,iBAAiB,IAAI,GAAU;GACnC,MAAM;GACN;GACA,UAAU,KAAK;GACf,uBAAO,IAAI,IAAI;EAChB,CAAC,GAEM,QAAQ,QAAQ;GAAE;GAAU,UAAU,KAAK;EAAkB,CAAC;CACtE;CAEA,oBAA4B,EAC3B,UACA,eACA,eACA,WACA,eAGE;EACF,OAAO,QAAQ,QAAQ,CAAC,CAAC,WAAW;GACnC,EAAe,CAAM;GACrB,IAAM,IAAS,KAAK,mBAAmB,CAAQ,GACzC,IAAO,eAAe;GAK5B,OAJA,EAAO,MAAM,IAAI,GAAY;IAAE,MAAM;IAAO;GAAK,CAAC,GAClD,IAAa,EAAM,IAAI,GACvB,EAAe,CAAM,GAEd,EAAE,QAAK;EACf,CAAC;CACF;CAEA,6BAAqC,EACpC,UACA,eAGC;EACD,OAAO,QAAQ,QAAQ,CAAC,CAAC,WAAW;GACnC,IAAM,IAAS,KAAK,mBAAmB,CAAQ,GACzC,IAAgB,CAAC;GAEvB,KAAK,IAAM,KAAQ,EAAM,MAAM,GAAM,MAAU,EAAK,aAAa,EAAM,UAAU,GAAG;IACnF,IAAM,IAAW,EAAO,MAAM,IAAI,EAAK,UAAU;IACjD,IAAI,CAAC,KAAY,EAAS,SAAS,EAAK,MACvC,MAAM,IAAI,EAAwB,aAAa,oBAAoB,EAAK,WAAW,cAAc,GAAU;IAE5G,EAAM,KAAK,EAAS,IAAI;GACzB;GAEA,IAAM,IAAO,IAAI,KAAK,CAAK;GAC3B,IAAI,EAAK,SAAS,EAAO,MACxB,MAAM,IAAI,EAAwB,gBAAgB,oBAAoB,EAAS,eAAe;GAG/F,IAAM,IAAkC;IACvC,MAAM,EAAO;IACb,MAAM,EAAuB,EAAO,IAAI;IACxC,MAAM;IACN,MAAM,EAAK;IACX,YAAY,KAAK,UAAU;IAC3B,MAAM,KAAK,SAAS;IACpB;GACD;GAIA,OAHA,KAAK,QAAQ,IAAI,EAAO,MAAM,CAAK,GACnC,KAAK,iBAAiB,OAAO,CAAQ,GAE9B,EAAU,CAAK;EACvB,CAAC;CACF;CAEA,0BAAkC,GAAiC;EAClE,OAAO,QAAQ,QAAQ,CAAC,CAAC,WAAW;GAEnC,AADA,KAAK,mBAAmB,CAAQ,GAChC,KAAK,iBAAiB,OAAO,CAAQ;EACtC,CAAC;CACF;CAEA,mBAA2B,GAA2C;EACrE,IAAM,IAAS,KAAK,iBAAiB,IAAI,CAAQ;EACjD,IAAI,CAAC,GACJ,MAAM,IAAI,EAAwB,aAAa,kCAAkC,GAAU;EAE5F,OAAO;CACR;CAEA,YAAoB,GAA0C;EAC7D,IAAM,IAAa,EAAyB,CAAI;EAChD,OAAO,MAAM,KAAK,KAAK,QAAQ,OAAO,CAAC,CAAC,CACtC,QAAQ,MAAU,EAA8B,GAAY,EAAM,IAAI,CAAC,CAAC,CACxE,MAAM,GAAM,MAAU,EAAK,KAAK,cAAc,EAAM,IAAI,CAAC;CAC5D;CAEA,mBAA2B,GAAoB;EAC9C,IAAM,IAAQ,KAAK,SAAS,CAAI;EAEhC,IAAI,EAAM,SAAS,UAClB,MAAM,IAAI,EAAwB,gBAAgB,wBAAwB,EAAM,MAAM;CAExF;CAEA,SAAiB,GAAwC;EACxD,IAAM,IAAa,EAAyB,CAAI,GAC1C,IAAQ,KAAK,QAAQ,IAAI,CAAU;EAEzC,IAAI,CAAC,GACJ,MAAM,IAAI,EAAwB,aAAa,mCAAmC,GAAY;EAG/F,OAAO;CACR;CAEA,YAA4B;EAC3B,OAAO,KAAK,IAAI,CAAC,CAAC,YAAY;CAC/B;CAEA,WAA2B;EAE1B,OADA,KAAK,gBAAgB,GACd,UAAU,KAAK;CACvB;AACD;AAEA,SAAgB,EACf,GACwC;CACxC,OAAO,IAAI,EAAsC,CAAO;AACzD;AAEA,SAAS,EAAqB,GAAsD;CACnF,IAAM,IAA4B;EACjC,MAAM,EAAM;EACZ,MAAM,EAAM;EACZ,MAAM,EAAM;CACb;CA8BA,OA5BI,EAAM,OAAO,KAAA,MAChB,EAAK,KAAK,EAAM,KAGb,EAAM,SAAS,KAAA,MAClB,EAAK,OAAO,EAAM,OAGf,EAAM,aAAa,KAAA,MACtB,EAAK,WAAW,EAAM,WAGnB,EAAM,eAAe,KAAA,MACxB,EAAK,aAAa,EAAM,aAGrB,EAAM,SAAS,KAAA,MAClB,EAAK,OAAO,EAAM,OAGf,EAAM,iBAAiB,KAAA,MAC1B,EAAK,eAAe,EAAM,eAGvB,EAAM,aAAa,KAAA,MACtB,EAAK,WAAW,EAAM,WAGhB;AACR;AAEA,SAAS,EAA0B,GAAgC,GAAyC;CAK3G,OAJI,EAAK,SAAS,EAAM,OAIjB,EAAK,KAAK,cAAc,EAAM,MAAM,KAAA,GAAW;EACrD,SAAS;EACT,aAAa;CACd,CAAC,IANO,EAAK,SAAS,WAAW,KAAK;AAOvC;AAEA,SAAS,EAAe,GAA4B;CACnD,IAAI,GAAQ,SACX,MAAM,IAAI,EAAwB,WAAW,uBAAuB;AAEtE;AAEA,SAAS,EAAc,GAAsB;CAC5C,OAAO,EAAK,QAAQ,QAAQ,EAAE,KAAK;AACpC"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { S3CompatibleFileBrowserAdapter } from '../s3-compatible-adapter';
|
|
2
2
|
import type { S3CompatibleFileBrowserAdapterOptions } from '../s3-compatible-adapter';
|
|
3
|
-
export type R2FileBrowserAdapterOptions = S3CompatibleFileBrowserAdapterOptions
|
|
4
|
-
export declare class R2FileBrowserAdapter extends S3CompatibleFileBrowserAdapter {
|
|
5
|
-
constructor(options?: R2FileBrowserAdapterOptions);
|
|
3
|
+
export type R2FileBrowserAdapterOptions<TMetadata = unknown> = S3CompatibleFileBrowserAdapterOptions<TMetadata>;
|
|
4
|
+
export declare class R2FileBrowserAdapter<TMetadata = unknown> extends S3CompatibleFileBrowserAdapter<TMetadata> {
|
|
5
|
+
constructor(options?: R2FileBrowserAdapterOptions<TMetadata>);
|
|
6
6
|
}
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/r2/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,0BAA0B,CAAA;AACzE,OAAO,KAAK,EAAE,qCAAqC,EAAE,MAAM,0BAA0B,CAAA;AAErF,MAAM,MAAM,2BAA2B,GAAG,qCAAqC,CAAA;AAE/
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/r2/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,0BAA0B,CAAA;AACzE,OAAO,KAAK,EAAE,qCAAqC,EAAE,MAAM,0BAA0B,CAAA;AAErF,MAAM,MAAM,2BAA2B,CAAC,SAAS,GAAG,OAAO,IAAI,qCAAqC,CAAC,SAAS,CAAC,CAAA;AAE/G,qBAAa,oBAAoB,CAAC,SAAS,GAAG,OAAO,CAAE,SAAQ,8BAA8B,CAAC,SAAS,CAAC;gBAC3F,OAAO,CAAC,EAAE,2BAA2B,CAAC,SAAS,CAAC;CAG5D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/adapters/r2/index.ts"],"sourcesContent":["import { S3CompatibleFileBrowserAdapter } from '../s3-compatible-adapter'\nimport type { S3CompatibleFileBrowserAdapterOptions } from '../s3-compatible-adapter'\n\nexport type R2FileBrowserAdapterOptions = S3CompatibleFileBrowserAdapterOptions
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/adapters/r2/index.ts"],"sourcesContent":["import { S3CompatibleFileBrowserAdapter } from '../s3-compatible-adapter'\nimport type { S3CompatibleFileBrowserAdapterOptions } from '../s3-compatible-adapter'\n\nexport type R2FileBrowserAdapterOptions<TMetadata = unknown> = S3CompatibleFileBrowserAdapterOptions<TMetadata>\n\nexport class R2FileBrowserAdapter<TMetadata = unknown> extends S3CompatibleFileBrowserAdapter<TMetadata> {\n\tconstructor(options?: R2FileBrowserAdapterOptions<TMetadata>) {\n\t\tsuper('R2', options)\n\t}\n}\n"],"mappings":";;AAKA,IAAa,IAAb,cAA+D,EAA0C;CACxG,YAAY,GAAkD;EAC7D,MAAM,MAAM,CAAO;CACpB;AACD"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { S3CompatibleFileBrowserAdapter } from '../s3-compatible-adapter';
|
|
2
2
|
import type { S3CompatibleFileBrowserAdapterOptions } from '../s3-compatible-adapter';
|
|
3
|
-
export type S3FileBrowserAdapterOptions = S3CompatibleFileBrowserAdapterOptions
|
|
4
|
-
export declare class S3FileBrowserAdapter extends S3CompatibleFileBrowserAdapter {
|
|
5
|
-
constructor(options?: S3FileBrowserAdapterOptions);
|
|
3
|
+
export type S3FileBrowserAdapterOptions<TMetadata = unknown> = S3CompatibleFileBrowserAdapterOptions<TMetadata>;
|
|
4
|
+
export declare class S3FileBrowserAdapter<TMetadata = unknown> extends S3CompatibleFileBrowserAdapter<TMetadata> {
|
|
5
|
+
constructor(options?: S3FileBrowserAdapterOptions<TMetadata>);
|
|
6
6
|
}
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/s3/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,0BAA0B,CAAA;AACzE,OAAO,KAAK,EAAE,qCAAqC,EAAE,MAAM,0BAA0B,CAAA;AAErF,MAAM,MAAM,2BAA2B,GAAG,qCAAqC,CAAA;AAE/
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/s3/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,0BAA0B,CAAA;AACzE,OAAO,KAAK,EAAE,qCAAqC,EAAE,MAAM,0BAA0B,CAAA;AAErF,MAAM,MAAM,2BAA2B,CAAC,SAAS,GAAG,OAAO,IAAI,qCAAqC,CAAC,SAAS,CAAC,CAAA;AAE/G,qBAAa,oBAAoB,CAAC,SAAS,GAAG,OAAO,CAAE,SAAQ,8BAA8B,CAAC,SAAS,CAAC;gBAC3F,OAAO,CAAC,EAAE,2BAA2B,CAAC,SAAS,CAAC;CAG5D"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../../../src/adapters/s3/index.ts"],"sourcesContent":["import { S3CompatibleFileBrowserAdapter } from '../s3-compatible-adapter'\nimport type { S3CompatibleFileBrowserAdapterOptions } from '../s3-compatible-adapter'\n\nexport type S3FileBrowserAdapterOptions = S3CompatibleFileBrowserAdapterOptions
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../../../src/adapters/s3/index.ts"],"sourcesContent":["import { S3CompatibleFileBrowserAdapter } from '../s3-compatible-adapter'\nimport type { S3CompatibleFileBrowserAdapterOptions } from '../s3-compatible-adapter'\n\nexport type S3FileBrowserAdapterOptions<TMetadata = unknown> = S3CompatibleFileBrowserAdapterOptions<TMetadata>\n\nexport class S3FileBrowserAdapter<TMetadata = unknown> extends S3CompatibleFileBrowserAdapter<TMetadata> {\n\tconstructor(options?: S3FileBrowserAdapterOptions<TMetadata>) {\n\t\tsuper('S3', options)\n\t}\n}\n"],"mappings":";;AAKA,IAAa,IAAb,cAA+D,EAA0C;CACxG,YAAY,GAAkD;EAC7D,MAAM,MAAM,CAAO;CACpB;AACD"}
|
|
@@ -3,34 +3,34 @@ import type { CloudAdapterName, CloudFileBrowserAdapterOptions } from './cloud-a
|
|
|
3
3
|
export type S3CompatibleClient = {
|
|
4
4
|
send(command: object): Promise<unknown>;
|
|
5
5
|
};
|
|
6
|
-
export type S3CompatibleFileBrowserAdapterOptions = CloudFileBrowserAdapterOptions & {
|
|
6
|
+
export type S3CompatibleFileBrowserAdapterOptions<TMetadata = unknown> = CloudFileBrowserAdapterOptions<TMetadata> & {
|
|
7
7
|
bucket?: string;
|
|
8
8
|
client?: S3CompatibleClient;
|
|
9
9
|
multipartPartSize?: number;
|
|
10
10
|
prefix?: string;
|
|
11
11
|
signedUrlExpiresIn?: number;
|
|
12
12
|
};
|
|
13
|
-
export declare class S3CompatibleFileBrowserAdapter implements FileBrowserAdapter {
|
|
14
|
-
createFolder?: NonNullable<FileBrowserAdapter['createFolder']>;
|
|
15
|
-
rename?: NonNullable<FileBrowserAdapter['rename']>;
|
|
16
|
-
move?: NonNullable<FileBrowserAdapter['move']>;
|
|
17
|
-
copy?: NonNullable<FileBrowserAdapter['copy']>;
|
|
18
|
-
stat?: NonNullable<FileBrowserAdapter['stat']>;
|
|
19
|
-
exists?: NonNullable<FileBrowserAdapter['exists']>;
|
|
20
|
-
createMultipartUpload?: NonNullable<FileBrowserAdapter['createMultipartUpload']>;
|
|
21
|
-
uploadPart?: NonNullable<FileBrowserAdapter['uploadPart']>;
|
|
22
|
-
completeMultipartUpload?: NonNullable<FileBrowserAdapter['completeMultipartUpload']>;
|
|
23
|
-
abortMultipartUpload?: NonNullable<FileBrowserAdapter['abortMultipartUpload']>;
|
|
24
|
-
bulkDownloadUrl?: NonNullable<FileBrowserAdapter['bulkDownloadUrl']>;
|
|
13
|
+
export declare class S3CompatibleFileBrowserAdapter<TMetadata = unknown> implements FileBrowserAdapter<TMetadata> {
|
|
14
|
+
createFolder?: NonNullable<FileBrowserAdapter<TMetadata>['createFolder']>;
|
|
15
|
+
rename?: NonNullable<FileBrowserAdapter<TMetadata>['rename']>;
|
|
16
|
+
move?: NonNullable<FileBrowserAdapter<TMetadata>['move']>;
|
|
17
|
+
copy?: NonNullable<FileBrowserAdapter<TMetadata>['copy']>;
|
|
18
|
+
stat?: NonNullable<FileBrowserAdapter<TMetadata>['stat']>;
|
|
19
|
+
exists?: NonNullable<FileBrowserAdapter<TMetadata>['exists']>;
|
|
20
|
+
createMultipartUpload?: NonNullable<FileBrowserAdapter<TMetadata>['createMultipartUpload']>;
|
|
21
|
+
uploadPart?: NonNullable<FileBrowserAdapter<TMetadata>['uploadPart']>;
|
|
22
|
+
completeMultipartUpload?: NonNullable<FileBrowserAdapter<TMetadata>['completeMultipartUpload']>;
|
|
23
|
+
abortMultipartUpload?: NonNullable<FileBrowserAdapter<TMetadata>['abortMultipartUpload']>;
|
|
24
|
+
bulkDownloadUrl?: NonNullable<FileBrowserAdapter<TMetadata>['bulkDownloadUrl']>;
|
|
25
25
|
private readonly delegate?;
|
|
26
26
|
private readonly multipartSessions;
|
|
27
27
|
private readonly sdk?;
|
|
28
|
-
constructor(adapterName: CloudAdapterName, options?: S3CompatibleFileBrowserAdapterOptions);
|
|
29
|
-
list(path: string, opts?: FileBrowserListOptions): Promise<FileBrowserListResult
|
|
28
|
+
constructor(adapterName: CloudAdapterName, options?: S3CompatibleFileBrowserAdapterOptions<TMetadata>);
|
|
29
|
+
list(path: string, opts?: FileBrowserListOptions): Promise<FileBrowserListResult<TMetadata>>;
|
|
30
30
|
private createFolderEntry;
|
|
31
31
|
delete(paths: string[]): Promise<void>;
|
|
32
32
|
signedUrl(path: string): Promise<string>;
|
|
33
|
-
upload(path: string, file: File, opts?: FileBrowserUploadOptions): Promise<FileNode
|
|
33
|
+
upload(path: string, file: File, opts?: FileBrowserUploadOptions): Promise<FileNode<TMetadata>>;
|
|
34
34
|
private statEntry;
|
|
35
35
|
private existsEntries;
|
|
36
36
|
private copyEntries;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"s3-compatible-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/s3-compatible-adapter.ts"],"names":[],"mappings":"AAcA,OAAO,KAAK,EACX,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,QAAQ,EAER,MAAM,eAAe,CAAA;AAGtB,OAAO,KAAK,EAAE,gBAAgB,EAAE,8BAA8B,EAAE,MAAM,sBAAsB,CAAA;AAE5F,MAAM,MAAM,kBAAkB,GAAG;IAChC,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;CACvC,CAAA;AAED,MAAM,MAAM,qCAAqC,GAAG,8BAA8B,GAAG;
|
|
1
|
+
{"version":3,"file":"s3-compatible-adapter.d.ts","sourceRoot":"","sources":["../../src/adapters/s3-compatible-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { SupabaseStorageFileBrowserAdapter } from './supabase-file-browser-adapter';
|
|
2
2
|
import type { SupabaseFileBrowserAdapterOptions } from './supabase-file-browser-adapter';
|
|
3
3
|
export type { SupabaseFileBrowserAdapterOptions };
|
|
4
|
-
export declare class SupabaseFileBrowserAdapter extends SupabaseStorageFileBrowserAdapter {
|
|
5
|
-
constructor(options?: SupabaseFileBrowserAdapterOptions);
|
|
4
|
+
export declare class SupabaseFileBrowserAdapter<TMetadata = unknown> extends SupabaseStorageFileBrowserAdapter<TMetadata> {
|
|
5
|
+
constructor(options?: SupabaseFileBrowserAdapterOptions<TMetadata>);
|
|
6
6
|
}
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/supabase/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iCAAiC,EAAE,MAAM,iCAAiC,CAAA;AACnF,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,iCAAiC,CAAA;AAExF,YAAY,EAAE,iCAAiC,EAAE,CAAA;AAEjD,qBAAa,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/supabase/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iCAAiC,EAAE,MAAM,iCAAiC,CAAA;AACnF,OAAO,KAAK,EAAE,iCAAiC,EAAE,MAAM,iCAAiC,CAAA;AAExF,YAAY,EAAE,iCAAiC,EAAE,CAAA;AAEjD,qBAAa,0BAA0B,CAAC,SAAS,GAAG,OAAO,CAAE,SAAQ,iCAAiC,CAAC,SAAS,CAAC;gBACpG,OAAO,CAAC,EAAE,iCAAiC,CAAC,SAAS,CAAC;CAGlE"}
|