@mountra/mountra-sdk 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,3 +1,353 @@
1
+ /**
2
+ * Per-download cache behavior, modelled on `RequestInit.cache`:
3
+ * - `default`: serve a fresh cached file without contacting Mountra; otherwise
4
+ * export it and reuse any cached chunks.
5
+ * - `no-cache`: always export first, but still reuse cached chunks.
6
+ * - `no-store`: neither read from nor write to the cache.
7
+ */
8
+ type DownloadCacheMode = "default" | "no-cache" | "no-store";
9
+ interface DownloadCacheOptions {
10
+ /** Upper bound of cached chunk bytes, shared by all workspaces. Defaults to 512 MiB. */
11
+ maxBytes?: number;
12
+ /**
13
+ * Chunks larger than this are never cached, because a downloaded chunk is
14
+ * buffered in memory before it is stored. Defaults to 128 MiB and never
15
+ * exceeds `maxBytes`.
16
+ */
17
+ maxChunkBytes?: number;
18
+ /**
19
+ * How long a downloaded file may be served from the cache without asking
20
+ * Mountra whether it changed. Defaults to 5 minutes; 0 always revalidates.
21
+ */
22
+ ttlMs?: number;
23
+ /** Cache storage. Defaults to IndexedDB, or memory when IndexedDB is unavailable. */
24
+ store?: DownloadCacheStore;
25
+ }
26
+ interface DownloadCacheChunk {
27
+ index: number;
28
+ offset: number;
29
+ size: number;
30
+ storageKey: string;
31
+ }
32
+ /** The chunk layout of one file. Signed URLs are never cached. */
33
+ interface DownloadCacheFile {
34
+ path: string;
35
+ size: number;
36
+ contentType?: string;
37
+ chunks: DownloadCacheChunk[];
38
+ /** When Mountra last confirmed this layout. */
39
+ cachedAt: number;
40
+ /** After this time the layout must be confirmed by Mountra again. */
41
+ expiresAt: number;
42
+ }
43
+ interface DownloadCacheUsage {
44
+ bytes: number;
45
+ chunks: number;
46
+ }
47
+ /**
48
+ * Storage behind the download cache. Every entry is scoped by an opaque
49
+ * workspace key, so one workspace never observes another workspace's entries.
50
+ */
51
+ interface DownloadCacheStore {
52
+ getFile(workspace: string, fileKey: string): Promise<DownloadCacheFile | null>;
53
+ putFile(workspace: string, fileKey: string, file: DownloadCacheFile): Promise<void>;
54
+ removeFile(workspace: string, fileKey: string): Promise<void>;
55
+ /** Return the chunk bytes and mark the chunk as most recently used. */
56
+ getChunk(workspace: string, storageKey: string): Promise<Blob | null>;
57
+ /** Store the chunk bytes, then evict least recently used chunks until at most `maxBytes` remain. */
58
+ putChunk(workspace: string, storageKey: string, data: Blob, maxBytes: number): Promise<void>;
59
+ /** Remove every entry, or only the entries of one workspace. */
60
+ clear(workspace?: string): Promise<void>;
61
+ usage(workspace?: string): Promise<DownloadCacheUsage>;
62
+ }
63
+ declare class InMemoryDownloadCacheStore implements DownloadCacheStore {
64
+ private readonly files;
65
+ /** Map iteration order is the LRU order: the first entry is the least recently used. */
66
+ private readonly chunks;
67
+ private bytes;
68
+ getFile(workspace: string, fileKey: string): Promise<DownloadCacheFile | null>;
69
+ putFile(workspace: string, fileKey: string, file: DownloadCacheFile): Promise<void>;
70
+ removeFile(workspace: string, fileKey: string): Promise<void>;
71
+ getChunk(workspace: string, storageKey: string): Promise<Blob | null>;
72
+ putChunk(workspace: string, storageKey: string, data: Blob, maxBytes: number): Promise<void>;
73
+ clear(workspace?: string): Promise<void>;
74
+ usage(workspace?: string): Promise<DownloadCacheUsage>;
75
+ private removeChunk;
76
+ }
77
+ interface IndexedDBDownloadCacheStoreOptions {
78
+ /** Use a separate database, for example one per signed-in user. */
79
+ databaseName?: string;
80
+ }
81
+ declare class IndexedDBDownloadCacheStore implements DownloadCacheStore {
82
+ private readonly databaseName;
83
+ private readonly fallback;
84
+ private databasePromise?;
85
+ constructor(options?: IndexedDBDownloadCacheStoreOptions);
86
+ getFile(workspace: string, fileKey: string): Promise<DownloadCacheFile | null>;
87
+ putFile(workspace: string, fileKey: string, file: DownloadCacheFile): Promise<void>;
88
+ removeFile(workspace: string, fileKey: string): Promise<void>;
89
+ getChunk(workspace: string, storageKey: string): Promise<Blob | null>;
90
+ putChunk(workspace: string, storageKey: string, data: Blob, maxBytes: number): Promise<void>;
91
+ clear(workspace?: string): Promise<void>;
92
+ usage(workspace?: string): Promise<DownloadCacheUsage>;
93
+ private openDatabase;
94
+ }
95
+ /** Cache policy of one client. Cache failures degrade to misses and never fail a download. */
96
+ declare class DownloadCache {
97
+ readonly maxBytes: number;
98
+ readonly maxChunkBytes: number;
99
+ readonly ttlMs: number;
100
+ private readonly store;
101
+ constructor(options: DownloadCacheOptions);
102
+ /** Return a file that has not expired together with all of its chunk bytes. */
103
+ loadFile(workspace: string, fileKey: string): Promise<{
104
+ file: DownloadCacheFile;
105
+ chunks: Map<number, Blob>;
106
+ } | null>;
107
+ readChunk(workspace: string, chunk: DownloadCacheChunk): Promise<Blob | null>;
108
+ canStoreChunk(chunk: DownloadCacheChunk): boolean;
109
+ /** Returns whether the chunk is now cached. */
110
+ storeChunk(workspace: string, chunk: DownloadCacheChunk, data: Blob): Promise<boolean>;
111
+ storeFile(workspace: string, fileKey: string, file: Omit<DownloadCacheFile, "cachedAt" | "expiresAt">): Promise<void>;
112
+ invalidateFiles(workspace: string, fileKeys: string[]): Promise<void>;
113
+ clear(workspace?: string): Promise<void>;
114
+ usage(workspace?: string): Promise<DownloadCacheUsage>;
115
+ }
116
+
117
+ interface FileSystemWritableFileStreamLike {
118
+ write(data: Uint8Array | Blob): Promise<void>;
119
+ seek(position: number): Promise<void>;
120
+ truncate(size: number): Promise<void>;
121
+ close(): Promise<void>;
122
+ abort?(): Promise<void>;
123
+ }
124
+ interface FileSystemFileHandleLike {
125
+ readonly kind?: "file";
126
+ readonly name?: string;
127
+ createWritable(options?: {
128
+ keepExistingData?: boolean;
129
+ }): Promise<FileSystemWritableFileStreamLike>;
130
+ isSameEntry?(other: FileSystemFileHandleLike): Promise<boolean>;
131
+ queryPermission?(descriptor?: {
132
+ mode?: "read" | "readwrite";
133
+ }): Promise<PermissionState>;
134
+ requestPermission?(descriptor?: {
135
+ mode?: "read" | "readwrite";
136
+ }): Promise<PermissionState>;
137
+ }
138
+ interface ExportFileOptions extends WorkspaceSelector {
139
+ path?: string;
140
+ ino?: number | string;
141
+ timeout?: number;
142
+ contentDisposition?: string;
143
+ downloadFilename?: string;
144
+ signal?: AbortSignal;
145
+ }
146
+ interface ExportFileChunk {
147
+ index: number;
148
+ offset: number;
149
+ size: number;
150
+ storageKey: string;
151
+ url: string;
152
+ }
153
+ interface ExportFileResponse {
154
+ path: string;
155
+ storageKey: string;
156
+ url: string;
157
+ timeout: number;
158
+ size: number;
159
+ contentType?: string;
160
+ chunkMethod?: string;
161
+ isFastPath?: boolean;
162
+ chunks?: ExportFileChunk[];
163
+ }
164
+ interface DownloadProgress {
165
+ phase: "downloading" | "retrying" | "completed";
166
+ downloadedBytes: number;
167
+ totalBytes: number;
168
+ downloadedChunks: number;
169
+ totalChunks: number;
170
+ currentChunkIndex?: number;
171
+ speedBytesPerSecond: number;
172
+ estimatedRemainingSeconds?: number;
173
+ elapsedMs: number;
174
+ retryCount: number;
175
+ }
176
+ interface DownloadFileOptions extends ExportFileOptions {
177
+ /** Prefer File System Access API when available. Defaults to true. */
178
+ preferFileSystemAccess?: boolean;
179
+ /** Continue a matching IndexedDB checkpoint when the selected file is the same entry. */
180
+ resume?: boolean;
181
+ maxRetries?: number;
182
+ retryDelayMs?: number;
183
+ onProgress?: (progress: DownloadProgress) => void;
184
+ /** Use a previously selected file handle, primarily for resumeDownload. */
185
+ fileHandle?: FileSystemFileHandleLike;
186
+ /** How this download uses the client's `downloadCache`. Defaults to `default`. */
187
+ cache?: DownloadCacheMode;
188
+ }
189
+ interface DownloadResumeOptions {
190
+ signal?: AbortSignal;
191
+ maxRetries?: number;
192
+ retryDelayMs?: number;
193
+ onProgress?: (progress: DownloadProgress) => void;
194
+ }
195
+ interface DownloadResult {
196
+ /** Absent when the file was served from the download cache without contacting Mountra. */
197
+ export?: ExportFileResponse;
198
+ downloadKey: string;
199
+ downloadedBytes: number;
200
+ /** Bytes served from the download cache instead of the network. */
201
+ cachedBytes: number;
202
+ resumed: boolean;
203
+ fileHandle?: FileSystemFileHandleLike;
204
+ blob?: Blob;
205
+ }
206
+ interface DownloadCheckpointChunk {
207
+ index: number;
208
+ offset: number;
209
+ size: number;
210
+ storageKey: string;
211
+ downloadedBytes: number;
212
+ completed: boolean;
213
+ }
214
+ interface DownloadCheckpointRequest {
215
+ workspaceCuid?: string;
216
+ workspaceId?: number | string;
217
+ path?: string;
218
+ ino?: number | string;
219
+ timeout?: number;
220
+ contentDisposition?: string;
221
+ downloadFilename?: string;
222
+ }
223
+ interface DownloadCheckpoint {
224
+ version: 1;
225
+ key: string;
226
+ requestKey: string;
227
+ request: DownloadCheckpointRequest;
228
+ path: string;
229
+ size: number;
230
+ chunks: DownloadCheckpointChunk[];
231
+ fileHandle?: FileSystemFileHandleLike;
232
+ updatedAt: number;
233
+ }
234
+ interface DownloadCheckpointStore {
235
+ load(key: string): Promise<DownloadCheckpoint | null>;
236
+ save(key: string, checkpoint: DownloadCheckpoint): Promise<void>;
237
+ remove(key: string): Promise<void>;
238
+ list(): Promise<DownloadCheckpoint[]>;
239
+ }
240
+ declare class InMemoryDownloadCheckpointStore implements DownloadCheckpointStore {
241
+ private readonly records;
242
+ load(key: string): Promise<DownloadCheckpoint | null>;
243
+ save(key: string, checkpoint: DownloadCheckpoint): Promise<void>;
244
+ remove(key: string): Promise<void>;
245
+ list(): Promise<DownloadCheckpoint[]>;
246
+ }
247
+ declare class IndexedDBDownloadCheckpointStore implements DownloadCheckpointStore {
248
+ private readonly fallback;
249
+ private databasePromise?;
250
+ load(key: string): Promise<DownloadCheckpoint | null>;
251
+ save(key: string, checkpoint: DownloadCheckpoint): Promise<void>;
252
+ remove(key: string): Promise<void>;
253
+ list(): Promise<DownloadCheckpoint[]>;
254
+ private openDatabase;
255
+ private request;
256
+ }
257
+ declare class DownloadHttpError extends Error {
258
+ readonly status: number;
259
+ constructor(status: number, message: string);
260
+ }
261
+ interface DownloadTransport {
262
+ readonly baseUrl: string;
263
+ readonly clientSelector: WorkspaceSelector;
264
+ readonly fetchImpl: typeof globalThis.fetch;
265
+ readonly checkpointStore: DownloadCheckpointStore;
266
+ readonly cache: DownloadCache | null;
267
+ requestJson(path: string, body: unknown, signal?: AbortSignal): Promise<unknown>;
268
+ }
269
+ declare class MountraDownloader {
270
+ private readonly transport;
271
+ constructor(transport: DownloadTransport);
272
+ exportFile(options: ExportFileOptions): Promise<ExportFileResponse>;
273
+ downloadFile(options: DownloadFileOptions): Promise<DownloadResult>;
274
+ downloadExport(exported: ExportFileResponse, options?: DownloadFileOptions): Promise<DownloadResult>;
275
+ resumeDownload(downloadKey: string, options?: DownloadResumeOptions): Promise<DownloadResult>;
276
+ listResumableDownloads(): Promise<DownloadCheckpoint[]>;
277
+ clearDownloadCheckpoint(downloadKey: string): Promise<void>;
278
+ /** Drop the cached layout of a file that was just written, so the next download sees the new content. */
279
+ invalidateCachedFile(selector: WorkspaceSelector, target: {
280
+ path?: string;
281
+ ino?: number | string;
282
+ }): Promise<void>;
283
+ /**
284
+ * Cache a file this client just uploaded, so downloading it needs no
285
+ * network. Falls back to invalidation when any chunk cannot be cached.
286
+ */
287
+ cacheUploadedFile(selector: WorkspaceSelector, file: {
288
+ path: string;
289
+ ino?: number | string;
290
+ size: number;
291
+ contentType?: string;
292
+ chunks: Array<DownloadCacheChunk & {
293
+ data: Blob;
294
+ }>;
295
+ }, mode?: Exclude<DownloadCacheMode, "no-cache">): Promise<void>;
296
+ private cachedFileScope;
297
+ clearCache(selector?: WorkspaceSelector): Promise<void>;
298
+ cacheUsage(selector?: WorkspaceSelector): Promise<DownloadCacheUsage>;
299
+ private requireCacheWorkspace;
300
+ /** Fall back to the client workspace only when the request names none, as uploads do. */
301
+ private resolveRequest;
302
+ private exportRequest;
303
+ private cacheScope;
304
+ /** A plan that needs no network at all, when the cached layout is fresh and every chunk is cached. */
305
+ private loadCachedPlan;
306
+ private planExport;
307
+ private pickSaveFile;
308
+ private ensureWritePermission;
309
+ private downloadResolved;
310
+ private consumeResponse;
311
+ private consumeBytes;
312
+ private isSameFileHandle;
313
+ }
314
+
315
+ type MountraFileTarget = {
316
+ path: string;
317
+ ino?: never;
318
+ } | {
319
+ path?: never;
320
+ ino: number | string;
321
+ };
322
+ /** A file identity accepted by `MountraClient.file()`. */
323
+ type MountraFileLocator = WorkspaceSelector & Partial<{
324
+ wsid: WorkspaceId;
325
+ }> & MountraFileTarget;
326
+ type NormalizedMountraFileLocator = WorkspaceSelector & MountraFileTarget;
327
+ /** Options for exporting an already identified Mountra file. */
328
+ type MountraFileExportOptions = Omit<ExportFileOptions, "workspaceCuid" | "workspaceId" | "path" | "ino">;
329
+ /** Options for downloading an already identified Mountra file. */
330
+ type MountraFileDownloadOptions = Omit<DownloadFileOptions, "workspaceCuid" | "workspaceId" | "path" | "ino">;
331
+ interface MountraFileResumeOptions extends DownloadResumeOptions {
332
+ /** Select a particular checkpoint; otherwise the newest matching one is used. */
333
+ downloadKey?: string;
334
+ }
335
+ /** A stable resource object for one file in one Mountra workspace. */
336
+ declare class MountraFile {
337
+ private readonly client;
338
+ readonly locator: Readonly<NormalizedMountraFileLocator>;
339
+ constructor(client: MountraClient, locator: NormalizedMountraFileLocator);
340
+ get workspaceCuid(): string | undefined;
341
+ get workspaceId(): WorkspaceId | undefined;
342
+ /** `wsid` is the short alias used by the file-object API. */
343
+ get wsid(): WorkspaceId | undefined;
344
+ get path(): string | undefined;
345
+ get ino(): number | string | undefined;
346
+ export(options?: MountraFileExportOptions): Promise<ExportFileResponse>;
347
+ download(options?: MountraFileDownloadOptions): Promise<DownloadResult>;
348
+ resume(options?: MountraFileResumeOptions): Promise<DownloadResult>;
349
+ }
350
+
1
351
  type ChunkMethod = "none" | "fix";
2
352
  type WorkspaceId = number | string;
3
353
  declare const JUMBO_CHUNK_THRESHOLD_BYTES: number;
@@ -24,10 +374,21 @@ interface MountraClientOptions extends WorkspaceSelector {
24
374
  jumboChunkCheckpointStore?: JumboChunkCheckpointStore;
25
375
  /** S3 Multipart part size. Defaults to 16 MiB. */
26
376
  jumboPartSize?: number;
377
+ /** IndexedDB-backed download checkpoint store. */
378
+ downloadCheckpointStore?: DownloadCheckpointStore;
379
+ /**
380
+ * Cache downloaded chunks locally, per workspace, in IndexedDB. Disabled
381
+ * unless set; pass `{}` for the defaults.
382
+ */
383
+ downloadCache?: DownloadCacheOptions;
27
384
  }
28
385
  interface UploadFileOptions extends WorkspaceSelector {
29
386
  path: string;
30
- /** Number of logical chunks. Defaults to 1. */
387
+ /**
388
+ * Maximum number of fixed-size chunks. Defaults to 1. Each chunk is
389
+ * `ceil(size / chunkCount)` bytes except the last, so an uneven split may
390
+ * produce fewer chunks.
391
+ */
31
392
  chunkCount?: number;
32
393
  contentType?: string;
33
394
  nameConflictStrategy?: "overwrite" | "keep_both";
@@ -35,10 +396,17 @@ interface UploadFileOptions extends WorkspaceSelector {
35
396
  onProgress?: (progress: MountraProgress) => void;
36
397
  /** Persist this serializable context before the first chunk is uploaded. */
37
398
  onSessionPrepared?: (context: UploadSessionContext) => void | Promise<void>;
399
+ /**
400
+ * With the client's `downloadCache`, an uploaded file is cached by default so
401
+ * downloading it needs no network. `no-store` only invalidates its old entry.
402
+ */
403
+ cache?: "default" | "no-store";
38
404
  }
39
405
  interface UploadResumeOptions extends WorkspaceSelector {
40
406
  signal?: AbortSignal;
41
407
  onProgress?: (progress: MountraProgress) => void;
408
+ /** See `UploadFileOptions.cache`. */
409
+ cache?: "default" | "no-store";
42
410
  }
43
411
  interface MountraProgress {
44
412
  phase: "uploading" | "finishing";
@@ -283,7 +651,19 @@ declare class MountraClient {
283
651
  private readonly jumboChunkUploader?;
284
652
  private readonly jumboChunkCheckpointStore;
285
653
  private readonly jumboPartSize;
654
+ private readonly downloader;
286
655
  constructor(options: MountraClientOptions);
656
+ exportFile(options: ExportFileOptions): Promise<ExportFileResponse>;
657
+ downloadFile(options: DownloadFileOptions): Promise<DownloadResult>;
658
+ downloadExport(exported: ExportFileResponse, options?: DownloadFileOptions): Promise<DownloadResult>;
659
+ resumeDownload(downloadKey: string, options?: DownloadResumeOptions): Promise<DownloadResult>;
660
+ listResumableDownloads(): Promise<DownloadCheckpoint[]>;
661
+ clearDownloadCheckpoint(downloadKey: string): Promise<void>;
662
+ /** Clear the download cache of one workspace, or of every workspace when none is given. */
663
+ clearDownloadCache(selector?: WorkspaceSelector): Promise<void>;
664
+ getDownloadCacheUsage(selector?: WorkspaceSelector): Promise<DownloadCacheUsage>;
665
+ /** Create a stable resource object for one file in this or another workspace. */
666
+ file(locator: MountraFileLocator): MountraFile;
287
667
  prepareUpload(file: Blob, options: UploadFileOptions): Promise<PreparedUpload>;
288
668
  uploadFile(file: Blob, options: UploadFileOptions): Promise<UploadResult>;
289
669
  /** Generic upload entry point. It selects PUT or S3 Multipart per chunk. */
@@ -301,9 +681,11 @@ declare class MountraClient {
301
681
  private isCompatibleJumboCheckpoint;
302
682
  private assertUploadContext;
303
683
  finishUpload(uploadId: string, selector?: WorkspaceSelector): Promise<UploadResult>;
684
+ /** Same workspace resolution as `getWorkspaceBody`, so the cache key matches what Mountra used. */
685
+ private cacheWorkspace;
304
686
  private endpoint;
305
687
  private requestJson;
306
688
  }
307
689
  declare function createMountraClient(options: MountraClientOptions): MountraClient;
308
690
 
309
- export { type AccessToken, type ChunkMethod, DEFAULT_S3_MULTIPART_PART_SIZE_BYTES, type FileChunk, type FinishUploadResponse, InMemoryJumboChunkCheckpointStore, JUMBO_CHUNK_THRESHOLD_BYTES, type JumboChunkCheckpoint, type JumboChunkCheckpointStore, type JumboChunkCompleteInput, type JumboChunkCreateInput, type JumboChunkUploadPartInput, type JumboChunkUploader, LocalStorageJumboChunkCheckpointStore, MAX_S3_MULTIPART_PARTS, MIN_S3_MULTIPART_PART_SIZE_BYTES, MountraApiError, MountraClient, type MountraClientOptions, type MountraProgress, MountraClient as MountraSDK, type PrepareUploadResponse, type PreparedUpload, type S3MultipartClient, type S3MultipartPart, S3MultipartUploader, type UploadFileOptions, type UploadResult, type UploadResumeOptions, type UploadSessionChunkContext, type UploadSessionContext, type UploadStatusChunk, type UploadStatusResponse, type UploadTarget, type WorkspaceId, type WorkspaceSelector, createMountraClient, isJumboChunk, sha256Hex, splitFileIntoChunks };
691
+ export { type AccessToken, type ChunkMethod, DEFAULT_S3_MULTIPART_PART_SIZE_BYTES, type DownloadCacheChunk, type DownloadCacheFile, type DownloadCacheMode, type DownloadCacheOptions, type DownloadCacheStore, type DownloadCacheUsage, type DownloadCheckpoint, type DownloadCheckpointChunk, type DownloadCheckpointRequest, type DownloadCheckpointStore, type DownloadFileOptions, DownloadHttpError, type DownloadProgress, type DownloadResult, type DownloadResumeOptions, type ExportFileChunk, type ExportFileOptions, type ExportFileResponse, type FileChunk, type FileSystemFileHandleLike, type FileSystemWritableFileStreamLike, type FinishUploadResponse, InMemoryDownloadCacheStore, InMemoryDownloadCheckpointStore, InMemoryJumboChunkCheckpointStore, IndexedDBDownloadCacheStore, type IndexedDBDownloadCacheStoreOptions, IndexedDBDownloadCheckpointStore, JUMBO_CHUNK_THRESHOLD_BYTES, type JumboChunkCheckpoint, type JumboChunkCheckpointStore, type JumboChunkCompleteInput, type JumboChunkCreateInput, type JumboChunkUploadPartInput, type JumboChunkUploader, LocalStorageJumboChunkCheckpointStore, MAX_S3_MULTIPART_PARTS, MIN_S3_MULTIPART_PART_SIZE_BYTES, MountraApiError, MountraClient, type MountraClientOptions, MountraDownloader, MountraFile, type MountraFileDownloadOptions, type MountraFileExportOptions, type MountraFileLocator, type MountraFileResumeOptions, type MountraProgress, MountraClient as MountraSDK, type NormalizedMountraFileLocator, type PrepareUploadResponse, type PreparedUpload, type S3MultipartClient, type S3MultipartPart, S3MultipartUploader, type UploadFileOptions, type UploadResult, type UploadResumeOptions, type UploadSessionChunkContext, type UploadSessionContext, type UploadStatusChunk, type UploadStatusResponse, type UploadTarget, type WorkspaceId, type WorkspaceSelector, createMountraClient, isJumboChunk, sha256Hex, splitFileIntoChunks };