@mountra/mountra-sdk 0.3.0 → 0.4.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/CHANGELOG.md +13 -0
- package/README.md +84 -1
- package/dist/index.cjs +1112 -91
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +234 -11
- package/dist/index.d.ts +234 -11
- package/dist/index.js +1110 -91
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/file.ts","../src/cache.ts","../src/download.ts","../src/upload.ts"],"sourcesContent":["export {\n DEFAULT_S3_MULTIPART_PART_SIZE_BYTES,\n InMemoryJumboChunkCheckpointStore,\n JUMBO_CHUNK_THRESHOLD_BYTES,\n LocalStorageJumboChunkCheckpointStore,\n MAX_S3_MULTIPART_PARTS,\n MIN_S3_MULTIPART_PART_SIZE_BYTES,\n MountraClient,\n MountraApiError,\n S3MultipartUploader,\n createMountraClient,\n isJumboChunk,\n sha256Hex,\n splitFileIntoChunks,\n} from \"./upload\";\nexport {\n DownloadHttpError,\n InMemoryDownloadCheckpointStore,\n IndexedDBDownloadCheckpointStore,\n MountraDownloader,\n} from \"./download\";\nexport { MountraFile } from \"./file\";\nexport { InMemoryDownloadCacheStore, IndexedDBDownloadCacheStore } from \"./cache\";\nexport type {\n DownloadCacheChunk,\n DownloadCacheFile,\n DownloadCacheMode,\n DownloadCacheOptions,\n DownloadCacheStore,\n DownloadCacheUsage,\n IndexedDBDownloadCacheStoreOptions,\n} from \"./cache\";\nexport type {\n AccessToken,\n ChunkMethod,\n FileChunk,\n FinishUploadResponse,\n JumboChunkCheckpoint,\n JumboChunkCheckpointStore,\n JumboChunkCompleteInput,\n JumboChunkCreateInput,\n JumboChunkUploadPartInput,\n JumboChunkUploader,\n MountraClientOptions,\n MountraProgress,\n PrepareUploadResponse,\n PreparedUpload,\n S3MultipartClient,\n S3MultipartPart,\n UploadResumeOptions,\n UploadSessionChunkContext,\n UploadSessionContext,\n UploadStatusChunk,\n UploadStatusResponse,\n UploadFileOptions,\n UploadResult,\n UploadTarget,\n WorkspaceId,\n WorkspaceSelector,\n} from \"./upload\";\nexport type {\n DownloadCheckpoint,\n DownloadCheckpointChunk,\n DownloadCheckpointRequest,\n DownloadCheckpointStore,\n DownloadFileOptions,\n DownloadProgress,\n DownloadResult,\n DownloadResumeOptions,\n ExportFileChunk,\n ExportFileOptions,\n ExportFileResponse,\n FileSystemFileHandleLike,\n FileSystemWritableFileStreamLike,\n} from \"./download\";\nexport type {\n MountraFileDownloadOptions,\n MountraFileExportOptions,\n MountraFileLocator,\n MountraFileResumeOptions,\n NormalizedMountraFileLocator,\n} from \"./file\";\n\nexport { MountraClient as MountraSDK } from \"./upload\";\n","import type {\n DownloadFileOptions,\n DownloadResult,\n DownloadResumeOptions,\n ExportFileOptions,\n ExportFileResponse,\n} from \"./download\";\nimport type { MountraClient, WorkspaceId, WorkspaceSelector } from \"./upload\";\n\ntype MountraFileTarget =\n | {\n path: string;\n ino?: never;\n }\n | {\n path?: never;\n ino: number | string;\n };\n\n/** A file identity accepted by `MountraClient.file()`. */\nexport type MountraFileLocator = WorkspaceSelector &\n Partial<{ wsid: WorkspaceId }> &\n MountraFileTarget;\n\nexport type NormalizedMountraFileLocator = WorkspaceSelector & MountraFileTarget;\n\n/** Options for exporting an already identified Mountra file. */\nexport type MountraFileExportOptions = Omit<\n ExportFileOptions,\n \"workspaceCuid\" | \"workspaceId\" | \"path\" | \"ino\"\n>;\n\n/** Options for downloading an already identified Mountra file. */\nexport type MountraFileDownloadOptions = Omit<\n DownloadFileOptions,\n \"workspaceCuid\" | \"workspaceId\" | \"path\" | \"ino\"\n>;\n\nexport interface MountraFileResumeOptions extends DownloadResumeOptions {\n /** Select a particular checkpoint; otherwise the newest matching one is used. */\n downloadKey?: string;\n}\n\n/**\n * Normalize a file locator and fill its workspace from the client when the\n * caller uses a client-scoped workspace.\n */\nexport function normalizeMountraFileLocator(\n locator: MountraFileLocator,\n fallbackWorkspace: WorkspaceSelector = {},\n): NormalizedMountraFileLocator {\n if (!locator || typeof locator !== \"object\") {\n throw new TypeError(\"Mountra file locator is required\");\n }\n\n const hasPath = locator.path !== undefined;\n const hasIno = locator.ino !== undefined;\n if (hasPath === hasIno) {\n throw new TypeError(\"Mountra file locator requires exactly one of path or ino\");\n }\n\n const workspaceId = locator.workspaceId ?? locator.wsid ?? fallbackWorkspace.workspaceId;\n if (\n locator.workspaceId !== undefined &&\n locator.wsid !== undefined &&\n String(locator.workspaceId) !== String(locator.wsid)\n ) {\n throw new TypeError(\"workspaceId and wsid must identify the same workspace\");\n }\n\n const workspaceCuid = locator.workspaceCuid ?? fallbackWorkspace.workspaceCuid;\n if (workspaceCuid === undefined && workspaceId === undefined) {\n throw new TypeError(\"workspaceCuid, workspaceId, or wsid is required\");\n }\n\n if (hasPath) {\n const path = normalizePath(locator.path!);\n return {\n ...(workspaceCuid !== undefined ? { workspaceCuid } : {}),\n ...(workspaceId !== undefined ? { workspaceId } : {}),\n path,\n };\n }\n\n return {\n ...(workspaceCuid !== undefined ? { workspaceCuid } : {}),\n ...(workspaceId !== undefined ? { workspaceId } : {}),\n ino: normalizeIno(locator.ino!),\n };\n}\n\n/** A stable resource object for one file in one Mountra workspace. */\nexport class MountraFile {\n readonly locator: Readonly<NormalizedMountraFileLocator>;\n\n constructor(\n private readonly client: MountraClient,\n locator: NormalizedMountraFileLocator,\n ) {\n this.locator = Object.freeze({ ...locator });\n }\n\n get workspaceCuid(): string | undefined {\n return this.locator.workspaceCuid;\n }\n\n get workspaceId(): WorkspaceId | undefined {\n return this.locator.workspaceId;\n }\n\n /** `wsid` is the short alias used by the file-object API. */\n get wsid(): WorkspaceId | undefined {\n return this.locator.workspaceId;\n }\n\n get path(): string | undefined {\n return \"path\" in this.locator ? this.locator.path : undefined;\n }\n\n get ino(): number | string | undefined {\n return \"ino\" in this.locator ? this.locator.ino : undefined;\n }\n\n export(options: MountraFileExportOptions = {}): Promise<ExportFileResponse> {\n return this.client.exportFile({ ...options, ...this.locator });\n }\n\n download(options: MountraFileDownloadOptions = {}): Promise<DownloadResult> {\n return this.client.downloadFile({ ...options, ...this.locator });\n }\n\n async resume(options: MountraFileResumeOptions = {}): Promise<DownloadResult> {\n const { downloadKey, ...resumeOptions } = options;\n const checkpoints = await this.client.listResumableDownloads();\n const candidates = checkpoints.filter(\n (checkpoint) => checkpoint.fileHandle && matchesLocator(checkpoint.request, this.locator),\n );\n const checkpoint = downloadKey\n ? candidates.find((candidate) => candidate.key === downloadKey)\n : [...candidates].sort((left, right) => right.updatedAt - left.updatedAt)[0];\n\n if (!checkpoint) {\n if (downloadKey) {\n throw new Error(\"Download checkpoint does not belong to this Mountra file\");\n }\n throw new Error(\"No resumable download was found for this Mountra file\");\n }\n\n return this.client.resumeDownload(checkpoint.key, resumeOptions);\n }\n}\n\nfunction matchesLocator(\n request: {\n workspaceCuid?: string;\n workspaceId?: number | string;\n path?: string;\n ino?: number | string;\n },\n locator: NormalizedMountraFileLocator,\n): boolean {\n if (\n locator.workspaceCuid !== undefined &&\n request.workspaceCuid !== locator.workspaceCuid\n ) {\n return false;\n }\n if (\n locator.workspaceId !== undefined &&\n String(request.workspaceId) !== String(locator.workspaceId)\n ) {\n return false;\n }\n if (\"path\" in locator) {\n if (request.path === undefined || request.ino !== undefined) {\n return false;\n }\n try {\n return normalizePath(request.path) === locator.path;\n } catch {\n return false;\n }\n }\n return String(request.ino) === String(locator.ino) && request.path === undefined;\n}\n\nexport function normalizePath(value: string): string {\n if (!value || !value.trim()) {\n throw new TypeError(\"Mountra file path cannot be empty\");\n }\n\n const raw = value.trim();\n const absolute = raw.startsWith(\"/\") ? raw : `/${raw}`;\n const segments = absolute\n .split(\"/\")\n .filter((segment) => segment.length > 0 && segment !== \".\");\n const stack: string[] = [];\n for (const segment of segments) {\n if (segment === \"..\") {\n stack.pop();\n continue;\n }\n stack.push(segment);\n }\n return stack.length === 0 ? \"/\" : `/${stack.join(\"/\")}`;\n}\n\nfunction normalizeIno(value: number | string): number | string {\n if (typeof value === \"number\") {\n if (!Number.isSafeInteger(value) || value < 0) {\n throw new TypeError(\"Mountra file ino must be a non-negative safe integer\");\n }\n return value;\n }\n if (!/^\\d+$/.test(value)) {\n throw new TypeError(\"Mountra file ino must be a non-negative integer string\");\n }\n return value;\n}\n","import { normalizePath } from \"./file\";\nimport type { WorkspaceSelector } from \"./upload\";\n\nconst DEFAULT_MAX_BYTES = 512 * 1024 * 1024;\nconst DEFAULT_MAX_CHUNK_BYTES = 128 * 1024 * 1024;\nconst DEFAULT_TTL_MS = 5 * 60 * 1000;\n\n/**\n * Per-download cache behavior, modelled on `RequestInit.cache`:\n * - `default`: serve a fresh cached file without contacting Mountra; otherwise\n * export it and reuse any cached chunks.\n * - `no-cache`: always export first, but still reuse cached chunks.\n * - `no-store`: neither read from nor write to the cache.\n */\nexport type DownloadCacheMode = \"default\" | \"no-cache\" | \"no-store\";\n\nexport interface DownloadCacheOptions {\n /** Upper bound of cached chunk bytes, shared by all workspaces. Defaults to 512 MiB. */\n maxBytes?: number;\n /**\n * Chunks larger than this are never cached, because a downloaded chunk is\n * buffered in memory before it is stored. Defaults to 128 MiB and never\n * exceeds `maxBytes`.\n */\n maxChunkBytes?: number;\n /**\n * How long a downloaded file may be served from the cache without asking\n * Mountra whether it changed. Defaults to 5 minutes; 0 always revalidates.\n */\n ttlMs?: number;\n /** Cache storage. Defaults to IndexedDB, or memory when IndexedDB is unavailable. */\n store?: DownloadCacheStore;\n}\n\nexport interface DownloadCacheChunk {\n index: number;\n offset: number;\n size: number;\n storageKey: string;\n}\n\n/** The chunk layout of one file. Signed URLs are never cached. */\nexport interface DownloadCacheFile {\n path: string;\n size: number;\n contentType?: string;\n chunks: DownloadCacheChunk[];\n /** When Mountra last confirmed this layout. */\n cachedAt: number;\n /** After this time the layout must be confirmed by Mountra again. */\n expiresAt: number;\n}\n\nexport interface DownloadCacheUsage {\n bytes: number;\n chunks: number;\n}\n\n/**\n * Storage behind the download cache. Every entry is scoped by an opaque\n * workspace key, so one workspace never observes another workspace's entries.\n */\nexport interface DownloadCacheStore {\n getFile(workspace: string, fileKey: string): Promise<DownloadCacheFile | null>;\n putFile(workspace: string, fileKey: string, file: DownloadCacheFile): Promise<void>;\n removeFile(workspace: string, fileKey: string): Promise<void>;\n /** Return the chunk bytes and mark the chunk as most recently used. */\n getChunk(workspace: string, storageKey: string): Promise<Blob | null>;\n /** Store the chunk bytes, then evict least recently used chunks until at most `maxBytes` remain. */\n putChunk(workspace: string, storageKey: string, data: Blob, maxBytes: number): Promise<void>;\n /** Remove every entry, or only the entries of one workspace. */\n clear(workspace?: string): Promise<void>;\n usage(workspace?: string): Promise<DownloadCacheUsage>;\n}\n\nfunction copyFile(file: DownloadCacheFile): DownloadCacheFile {\n return { ...file, chunks: file.chunks.map((chunk) => ({ ...chunk })) };\n}\n\nfunction memoryKey(workspace: string, key: string): string {\n return JSON.stringify([workspace, key]);\n}\n\nexport class InMemoryDownloadCacheStore implements DownloadCacheStore {\n private readonly files = new Map<string, { workspace: string; file: DownloadCacheFile }>();\n /** Map iteration order is the LRU order: the first entry is the least recently used. */\n private readonly chunks = new Map<string, { workspace: string; data: Blob }>();\n private bytes = 0;\n\n async getFile(workspace: string, fileKey: string): Promise<DownloadCacheFile | null> {\n const entry = this.files.get(memoryKey(workspace, fileKey));\n return entry ? copyFile(entry.file) : null;\n }\n\n async putFile(workspace: string, fileKey: string, file: DownloadCacheFile): Promise<void> {\n this.files.set(memoryKey(workspace, fileKey), { workspace, file: copyFile(file) });\n }\n\n async removeFile(workspace: string, fileKey: string): Promise<void> {\n this.files.delete(memoryKey(workspace, fileKey));\n }\n\n async getChunk(workspace: string, storageKey: string): Promise<Blob | null> {\n const key = memoryKey(workspace, storageKey);\n const entry = this.chunks.get(key);\n if (!entry) {\n return null;\n }\n this.chunks.delete(key);\n this.chunks.set(key, entry);\n return entry.data;\n }\n\n async putChunk(workspace: string, storageKey: string, data: Blob, maxBytes: number): Promise<void> {\n const key = memoryKey(workspace, storageKey);\n this.removeChunk(key);\n if (data.size > maxBytes) {\n return;\n }\n this.chunks.set(key, { workspace, data });\n this.bytes += data.size;\n for (const candidate of this.chunks.keys()) {\n if (this.bytes <= maxBytes) {\n break;\n }\n this.removeChunk(candidate);\n }\n }\n\n async clear(workspace?: string): Promise<void> {\n for (const [key, entry] of this.chunks) {\n if (workspace === undefined || entry.workspace === workspace) {\n this.removeChunk(key);\n }\n }\n for (const [key, entry] of this.files) {\n if (workspace === undefined || entry.workspace === workspace) {\n this.files.delete(key);\n }\n }\n }\n\n async usage(workspace?: string): Promise<DownloadCacheUsage> {\n const usage = { bytes: 0, chunks: 0 };\n for (const entry of this.chunks.values()) {\n if (workspace === undefined || entry.workspace === workspace) {\n usage.bytes += entry.data.size;\n usage.chunks += 1;\n }\n }\n return usage;\n }\n\n private removeChunk(key: string): void {\n const entry = this.chunks.get(key);\n if (entry) {\n this.chunks.delete(key);\n this.bytes -= entry.data.size;\n }\n }\n}\n\nconst CACHE_DATABASE_NAME = \"mountra-sdk-download-cache\";\nconst CACHE_DATABASE_VERSION = 1;\nconst FILES_STORE = \"files\";\n/** Small LRU records, kept apart from the bytes so touching a chunk never rewrites its Blob. */\nconst CHUNKS_STORE = \"chunks\";\nconst CHUNK_DATA_STORE = \"chunk-data\";\nconst META_STORE = \"meta\";\nconst LRU_INDEX = \"lastUsed\";\nconst USAGE_KEY = \"bytes\";\n/** A counter rather than a timestamp, so accesses within one millisecond still have an order. */\nconst CLOCK_KEY = \"clock\";\n\ninterface ChunkRecord {\n size: number;\n lastUsed: number;\n}\n\ntype CacheKey = [workspace: string, key: string];\n\nfunction getIndexedDb(): IDBFactory | null {\n return (globalThis as typeof globalThis & { indexedDB?: IDBFactory }).indexedDB ?? null;\n}\n\n/** All keys `[workspace, *]`: arrays sort after strings, so `[workspace, []]` bounds every string key. */\nfunction workspaceRange(workspace: string): IDBKeyRange {\n return IDBKeyRange.bound([workspace], [workspace, []]);\n}\n\nfunction sameKey(left: IDBValidKey, right: CacheKey): boolean {\n return Array.isArray(left) && left[0] === right[0] && left[1] === right[1];\n}\n\nasync function nextClock(meta: IDBObjectStore): Promise<number> {\n const clock = ((await requestResult<number | undefined>(meta.get(CLOCK_KEY))) ?? 0) + 1;\n await requestResult(meta.put(clock, CLOCK_KEY));\n return clock;\n}\n\nfunction requestResult<T>(request: IDBRequest<T>): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error ?? new Error(\"IndexedDB request failed\"));\n });\n}\n\n/**\n * Run `body` inside one transaction. `body` may only await IndexedDB requests\n * of this transaction; awaiting anything else lets the transaction commit early.\n */\nasync function runTransaction<T>(\n database: IDBDatabase,\n storeNames: string[],\n mode: IDBTransactionMode,\n body: (transaction: IDBTransaction) => Promise<T>,\n): Promise<T> {\n const transaction = database.transaction(storeNames, mode);\n const done = new Promise<void>((resolve, reject) => {\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => reject(transaction.error ?? new Error(\"IndexedDB transaction failed\"));\n transaction.onabort = () => reject(transaction.error ?? new Error(\"IndexedDB transaction aborted\"));\n });\n done.catch(() => undefined);\n let result: T;\n try {\n result = await body(transaction);\n } catch (error) {\n try {\n transaction.abort();\n } catch {\n // The transaction has already finished.\n }\n throw error;\n }\n await done;\n return result;\n}\n\nexport interface IndexedDBDownloadCacheStoreOptions {\n /** Use a separate database, for example one per signed-in user. */\n databaseName?: string;\n}\n\nexport class IndexedDBDownloadCacheStore implements DownloadCacheStore {\n private readonly databaseName: string;\n private readonly fallback = new InMemoryDownloadCacheStore();\n private databasePromise?: Promise<IDBDatabase | null>;\n\n constructor(options: IndexedDBDownloadCacheStoreOptions = {}) {\n this.databaseName = options.databaseName ?? CACHE_DATABASE_NAME;\n }\n\n async getFile(workspace: string, fileKey: string): Promise<DownloadCacheFile | null> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.getFile(workspace, fileKey);\n }\n return runTransaction(database, [FILES_STORE], \"readonly\", async (transaction) => {\n const file = await requestResult<DownloadCacheFile | undefined>(\n transaction.objectStore(FILES_STORE).get([workspace, fileKey]),\n );\n return file ? copyFile(file) : null;\n });\n }\n\n async putFile(workspace: string, fileKey: string, file: DownloadCacheFile): Promise<void> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.putFile(workspace, fileKey, file);\n }\n await runTransaction(database, [FILES_STORE], \"readwrite\", async (transaction) => {\n await requestResult(transaction.objectStore(FILES_STORE).put(copyFile(file), [workspace, fileKey]));\n });\n }\n\n async removeFile(workspace: string, fileKey: string): Promise<void> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.removeFile(workspace, fileKey);\n }\n await runTransaction(database, [FILES_STORE], \"readwrite\", async (transaction) => {\n await requestResult(transaction.objectStore(FILES_STORE).delete([workspace, fileKey]));\n });\n }\n\n async getChunk(workspace: string, storageKey: string): Promise<Blob | null> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.getChunk(workspace, storageKey);\n }\n const key: CacheKey = [workspace, storageKey];\n return runTransaction(\n database,\n [CHUNKS_STORE, CHUNK_DATA_STORE, META_STORE],\n \"readwrite\",\n async (transaction) => {\n const chunks = transaction.objectStore(CHUNKS_STORE);\n const record = await requestResult<ChunkRecord | undefined>(chunks.get(key));\n if (!record) {\n return null;\n }\n const data = await requestResult<Blob | undefined>(\n transaction.objectStore(CHUNK_DATA_STORE).get(key),\n );\n const meta = transaction.objectStore(META_STORE);\n if (!data) {\n // Repair a record whose bytes are gone instead of reporting a hit.\n const bytes = (await requestResult<number | undefined>(meta.get(USAGE_KEY))) ?? 0;\n await requestResult(chunks.delete(key));\n await requestResult(meta.put(Math.max(bytes - record.size, 0), USAGE_KEY));\n return null;\n }\n await requestResult(chunks.put({ size: record.size, lastUsed: await nextClock(meta) }, key));\n return data;\n },\n );\n }\n\n async putChunk(workspace: string, storageKey: string, data: Blob, maxBytes: number): Promise<void> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.putChunk(workspace, storageKey, data, maxBytes);\n }\n const key: CacheKey = [workspace, storageKey];\n await runTransaction(\n database,\n [CHUNKS_STORE, CHUNK_DATA_STORE, META_STORE],\n \"readwrite\",\n async (transaction) => {\n const chunks = transaction.objectStore(CHUNKS_STORE);\n const chunkData = transaction.objectStore(CHUNK_DATA_STORE);\n const meta = transaction.objectStore(META_STORE);\n let bytes = (await requestResult<number | undefined>(meta.get(USAGE_KEY))) ?? 0;\n const existing = await requestResult<ChunkRecord | undefined>(chunks.get(key));\n if (existing) {\n bytes -= existing.size;\n await requestResult(chunks.delete(key));\n await requestResult(chunkData.delete(key));\n }\n if (data.size <= maxBytes) {\n await requestResult(chunks.put({ size: data.size, lastUsed: await nextClock(meta) }, key));\n await requestResult(chunkData.put(data, key));\n bytes += data.size;\n }\n\n if (bytes > maxBytes) {\n const cursorRequest = chunks.index(LRU_INDEX).openCursor();\n let cursor = await requestResult(cursorRequest);\n while (cursor && bytes > maxBytes) {\n if (!sameKey(cursor.primaryKey, key)) {\n bytes -= (cursor.value as ChunkRecord).size;\n await requestResult(chunkData.delete(cursor.primaryKey));\n await requestResult(cursor.delete());\n }\n cursor.continue();\n cursor = await requestResult(cursorRequest);\n }\n }\n await requestResult(meta.put(Math.max(bytes, 0), USAGE_KEY));\n },\n );\n }\n\n async clear(workspace?: string): Promise<void> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.clear(workspace);\n }\n await runTransaction(\n database,\n [FILES_STORE, CHUNKS_STORE, CHUNK_DATA_STORE, META_STORE],\n \"readwrite\",\n async (transaction) => {\n const files = transaction.objectStore(FILES_STORE);\n const chunks = transaction.objectStore(CHUNKS_STORE);\n const chunkData = transaction.objectStore(CHUNK_DATA_STORE);\n const meta = transaction.objectStore(META_STORE);\n if (workspace === undefined) {\n await requestResult(files.clear());\n await requestResult(chunks.clear());\n await requestResult(chunkData.clear());\n await requestResult(meta.put(0, USAGE_KEY));\n return;\n }\n const range = workspaceRange(workspace);\n const removed = await requestResult<ChunkRecord[]>(chunks.getAll(range));\n const bytes = (await requestResult<number | undefined>(meta.get(USAGE_KEY))) ?? 0;\n await requestResult(files.delete(range));\n await requestResult(chunks.delete(range));\n await requestResult(chunkData.delete(range));\n await requestResult(\n meta.put(Math.max(bytes - removed.reduce((total, record) => total + record.size, 0), 0), USAGE_KEY),\n );\n },\n );\n }\n\n async usage(workspace?: string): Promise<DownloadCacheUsage> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.usage(workspace);\n }\n return runTransaction(database, [CHUNKS_STORE], \"readonly\", async (transaction) => {\n const records = await requestResult<ChunkRecord[]>(\n transaction\n .objectStore(CHUNKS_STORE)\n .getAll(workspace === undefined ? undefined : workspaceRange(workspace)),\n );\n return {\n bytes: records.reduce((total, record) => total + record.size, 0),\n chunks: records.length,\n };\n });\n }\n\n private async openDatabase(): Promise<IDBDatabase | null> {\n if (!this.databasePromise) {\n const indexedDb = getIndexedDb();\n if (!indexedDb) {\n this.databasePromise = Promise.resolve(null);\n } else {\n this.databasePromise = new Promise<IDBDatabase | null>((resolve) => {\n let request: IDBOpenDBRequest;\n try {\n request = indexedDb.open(this.databaseName, CACHE_DATABASE_VERSION);\n } catch {\n resolve(null);\n return;\n }\n request.onupgradeneeded = () => {\n const database = request.result;\n if (!database.objectStoreNames.contains(FILES_STORE)) {\n database.createObjectStore(FILES_STORE);\n }\n if (!database.objectStoreNames.contains(CHUNKS_STORE)) {\n database.createObjectStore(CHUNKS_STORE).createIndex(LRU_INDEX, \"lastUsed\");\n }\n if (!database.objectStoreNames.contains(CHUNK_DATA_STORE)) {\n database.createObjectStore(CHUNK_DATA_STORE);\n }\n if (!database.objectStoreNames.contains(META_STORE)) {\n database.createObjectStore(META_STORE);\n }\n };\n request.onsuccess = () => {\n const database = request.result;\n // Let a newer SDK in another tab upgrade the schema.\n database.onversionchange = () => {\n database.close();\n this.databasePromise = undefined;\n };\n resolve(database);\n };\n request.onerror = () => resolve(null);\n request.onblocked = () => resolve(null);\n });\n }\n }\n return this.databasePromise;\n }\n}\n\n/**\n * Only content-addressed blobs (`.../blobs/sha256/<hash>`) are cached: their\n * bytes can never change. Local-first and combined export keys can.\n */\nfunction isImmutableStorageKey(storageKey: string): boolean {\n return /(?:^|\\/)blobs\\/sha256\\/[0-9a-f]{64}$/.test(storageKey);\n}\n\n/** Mirror the server: `workspace_cuid` wins over `workspace_id` when both are sent. */\nexport function workspaceCacheKey(baseUrl: string, selector: WorkspaceSelector): string | null {\n const workspaceCuid = selector.workspaceCuid?.trim();\n const workspaceId =\n selector.workspaceId !== undefined ? String(selector.workspaceId).trim() : \"\";\n const workspace = workspaceCuid || workspaceId;\n return workspace ? JSON.stringify([baseUrl, workspace]) : null;\n}\n\n/** Mirror the server: `ino` wins over `path` when both are sent. */\nexport function fileCacheKey(target: { path?: string; ino?: number | string }): string | null {\n try {\n if (target.ino !== undefined) {\n return `ino:${BigInt(target.ino).toString()}`;\n }\n if (target.path !== undefined) {\n return `path:${normalizePath(target.path)}`;\n }\n } catch {\n // Mountra rejects this target, so there is nothing to cache.\n }\n return null;\n}\n\nfunction isValidLayout(file: DownloadCacheFile): boolean {\n let offset = 0;\n for (const [index, chunk] of file.chunks.entries()) {\n if (chunk.index !== index || chunk.offset !== offset || chunk.size < 0) {\n return false;\n }\n offset += chunk.size;\n }\n return file.chunks.length > 0 && offset === file.size;\n}\n\n/** Cache policy of one client. Cache failures degrade to misses and never fail a download. */\nexport class DownloadCache {\n readonly maxBytes: number;\n readonly maxChunkBytes: number;\n readonly ttlMs: number;\n private readonly store: DownloadCacheStore;\n\n constructor(options: DownloadCacheOptions) {\n this.maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n if (!Number.isSafeInteger(this.maxBytes) || this.maxBytes <= 0) {\n throw new RangeError(\"downloadCache.maxBytes must be a positive safe integer\");\n }\n const maxChunkBytes = options.maxChunkBytes ?? DEFAULT_MAX_CHUNK_BYTES;\n if (!Number.isSafeInteger(maxChunkBytes) || maxChunkBytes <= 0) {\n throw new RangeError(\"downloadCache.maxChunkBytes must be a positive safe integer\");\n }\n this.maxChunkBytes = Math.min(maxChunkBytes, this.maxBytes);\n this.ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;\n if (Number.isNaN(this.ttlMs) || this.ttlMs < 0) {\n throw new RangeError(\"downloadCache.ttlMs must be a non-negative number\");\n }\n this.store = options.store ?? new IndexedDBDownloadCacheStore();\n }\n\n /** Return a file that has not expired together with all of its chunk bytes. */\n async loadFile(\n workspace: string,\n fileKey: string,\n ): Promise<{ file: DownloadCacheFile; chunks: Map<number, Blob> } | null> {\n try {\n const file = await this.store.getFile(workspace, fileKey);\n if (!file) {\n return null;\n }\n if (file.expiresAt <= Date.now() || !isValidLayout(file)) {\n await this.store.removeFile(workspace, fileKey);\n return null;\n }\n const chunks = new Map<number, Blob>();\n for (const chunk of file.chunks) {\n const data = await this.readChunk(workspace, chunk);\n if (!data) {\n return null;\n }\n chunks.set(chunk.index, data);\n }\n return { file, chunks };\n } catch {\n return null;\n }\n }\n\n async readChunk(workspace: string, chunk: DownloadCacheChunk): Promise<Blob | null> {\n if (chunk.size === 0) {\n return new Blob([]);\n }\n if (!isImmutableStorageKey(chunk.storageKey)) {\n return null;\n }\n try {\n const data = await this.store.getChunk(workspace, chunk.storageKey);\n return data && data.size === chunk.size ? data : null;\n } catch {\n return null;\n }\n }\n\n canStoreChunk(chunk: DownloadCacheChunk): boolean {\n return isImmutableStorageKey(chunk.storageKey) && chunk.size <= this.maxChunkBytes;\n }\n\n /** Returns whether the chunk is now cached. */\n async storeChunk(workspace: string, chunk: DownloadCacheChunk, data: Blob): Promise<boolean> {\n if (chunk.size === 0) {\n return true;\n }\n if (!this.canStoreChunk(chunk) || data.size !== chunk.size) {\n return false;\n }\n try {\n await this.store.putChunk(workspace, chunk.storageKey, data, this.maxBytes);\n return true;\n } catch {\n return false;\n }\n }\n\n async storeFile(\n workspace: string,\n fileKey: string,\n file: Omit<DownloadCacheFile, \"cachedAt\" | \"expiresAt\">,\n ): Promise<void> {\n if (this.ttlMs <= 0) {\n return;\n }\n const cachedAt = Date.now();\n try {\n await this.store.putFile(workspace, fileKey, {\n path: file.path,\n size: file.size,\n ...(file.contentType ? { contentType: file.contentType } : {}),\n chunks: file.chunks.map(({ index, offset, size, storageKey }) => ({\n index,\n offset,\n size,\n storageKey,\n })),\n cachedAt,\n expiresAt: cachedAt + this.ttlMs,\n });\n } catch {\n // The download already succeeded; the next one simply exports again.\n }\n }\n\n async invalidateFiles(workspace: string, fileKeys: string[]): Promise<void> {\n await Promise.all(\n fileKeys.map((fileKey) => this.store.removeFile(workspace, fileKey).catch(() => undefined)),\n );\n }\n\n clear(workspace?: string): Promise<void> {\n return this.store.clear(workspace);\n }\n\n usage(workspace?: string): Promise<DownloadCacheUsage> {\n return this.store.usage(workspace);\n }\n}\n","import { fileCacheKey, workspaceCacheKey } from \"./cache\";\nimport type { DownloadCache, DownloadCacheChunk, DownloadCacheMode, DownloadCacheUsage } from \"./cache\";\nimport type { WorkspaceSelector } from \"./upload\";\n\nexport interface FileSystemWritableFileStreamLike {\n write(data: Uint8Array | Blob): Promise<void>;\n seek(position: number): Promise<void>;\n truncate(size: number): Promise<void>;\n close(): Promise<void>;\n abort?(): Promise<void>;\n}\n\nexport interface FileSystemFileHandleLike {\n readonly kind?: \"file\";\n readonly name?: string;\n createWritable(options?: { keepExistingData?: boolean }): Promise<FileSystemWritableFileStreamLike>;\n isSameEntry?(other: FileSystemFileHandleLike): Promise<boolean>;\n queryPermission?(descriptor?: { mode?: \"read\" | \"readwrite\" }): Promise<PermissionState>;\n requestPermission?(descriptor?: { mode?: \"read\" | \"readwrite\" }): Promise<PermissionState>;\n}\n\nexport interface ExportFileOptions extends WorkspaceSelector {\n path?: string;\n ino?: number | string;\n timeout?: number;\n contentDisposition?: string;\n downloadFilename?: string;\n signal?: AbortSignal;\n}\n\nexport interface ExportFileChunk {\n index: number;\n offset: number;\n size: number;\n storageKey: string;\n url: string;\n}\n\nexport interface ExportFileResponse {\n path: string;\n storageKey: string;\n url: string;\n timeout: number;\n size: number;\n contentType?: string;\n chunkMethod?: string;\n isFastPath?: boolean;\n chunks?: ExportFileChunk[];\n}\n\nexport interface DownloadProgress {\n phase: \"downloading\" | \"retrying\" | \"completed\";\n downloadedBytes: number;\n totalBytes: number;\n downloadedChunks: number;\n totalChunks: number;\n currentChunkIndex?: number;\n speedBytesPerSecond: number;\n estimatedRemainingSeconds?: number;\n elapsedMs: number;\n retryCount: number;\n}\n\nexport interface DownloadFileOptions extends ExportFileOptions {\n /** Prefer File System Access API when available. Defaults to true. */\n preferFileSystemAccess?: boolean;\n /** Continue a matching IndexedDB checkpoint when the selected file is the same entry. */\n resume?: boolean;\n maxRetries?: number;\n retryDelayMs?: number;\n onProgress?: (progress: DownloadProgress) => void;\n /** Use a previously selected file handle, primarily for resumeDownload. */\n fileHandle?: FileSystemFileHandleLike;\n /** How this download uses the client's `downloadCache`. Defaults to `default`. */\n cache?: DownloadCacheMode;\n}\n\nexport interface DownloadResumeOptions {\n signal?: AbortSignal;\n maxRetries?: number;\n retryDelayMs?: number;\n onProgress?: (progress: DownloadProgress) => void;\n}\n\nexport interface DownloadResult {\n /** Absent when the file was served from the download cache without contacting Mountra. */\n export?: ExportFileResponse;\n downloadKey: string;\n downloadedBytes: number;\n /** Bytes served from the download cache instead of the network. */\n cachedBytes: number;\n resumed: boolean;\n fileHandle?: FileSystemFileHandleLike;\n blob?: Blob;\n}\n\nexport interface DownloadCheckpointChunk {\n index: number;\n offset: number;\n size: number;\n storageKey: string;\n downloadedBytes: number;\n completed: boolean;\n}\n\nexport interface DownloadCheckpointRequest {\n workspaceCuid?: string;\n workspaceId?: number | string;\n path?: string;\n ino?: number | string;\n timeout?: number;\n contentDisposition?: string;\n downloadFilename?: string;\n}\n\nexport interface DownloadCheckpoint {\n version: 1;\n key: string;\n requestKey: string;\n request: DownloadCheckpointRequest;\n path: string;\n size: number;\n chunks: DownloadCheckpointChunk[];\n fileHandle?: FileSystemFileHandleLike;\n updatedAt: number;\n}\n\nexport interface DownloadCheckpointStore {\n load(key: string): Promise<DownloadCheckpoint | null>;\n save(key: string, checkpoint: DownloadCheckpoint): Promise<void>;\n remove(key: string): Promise<void>;\n list(): Promise<DownloadCheckpoint[]>;\n}\n\nfunction copyCheckpoint(checkpoint: DownloadCheckpoint): DownloadCheckpoint {\n return {\n ...checkpoint,\n request: { ...checkpoint.request },\n chunks: checkpoint.chunks.map((chunk) => ({ ...chunk })),\n };\n}\n\nexport class InMemoryDownloadCheckpointStore implements DownloadCheckpointStore {\n private readonly records = new Map<string, DownloadCheckpoint>();\n\n async load(key: string): Promise<DownloadCheckpoint | null> {\n const value = this.records.get(key);\n return value ? copyCheckpoint(value) : null;\n }\n\n async save(key: string, checkpoint: DownloadCheckpoint): Promise<void> {\n this.records.set(key, copyCheckpoint(checkpoint));\n }\n\n async remove(key: string): Promise<void> {\n this.records.delete(key);\n }\n\n async list(): Promise<DownloadCheckpoint[]> {\n return [...this.records.values()].map(copyCheckpoint);\n }\n}\n\nconst DOWNLOAD_DATABASE_NAME = \"mountra-sdk\";\nconst DOWNLOAD_DATABASE_VERSION = 1;\nconst DOWNLOAD_STORE_NAME = \"download-checkpoints\";\n\nfunction getIndexedDb(): IDBFactory | null {\n return (globalThis as typeof globalThis & { indexedDB?: IDBFactory }).indexedDB ?? null;\n}\n\nexport class IndexedDBDownloadCheckpointStore implements DownloadCheckpointStore {\n private readonly fallback = new InMemoryDownloadCheckpointStore();\n private databasePromise?: Promise<IDBDatabase | null>;\n\n async load(key: string): Promise<DownloadCheckpoint | null> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.load(key);\n }\n try {\n const value = await this.request<DownloadCheckpoint | undefined>(\n database,\n \"readonly\",\n (store) => store.get(key),\n );\n return value ? copyCheckpoint(value) : null;\n } catch {\n return this.fallback.load(key);\n }\n }\n\n async save(key: string, checkpoint: DownloadCheckpoint): Promise<void> {\n const value = copyCheckpoint(checkpoint);\n const database = await this.openDatabase();\n if (!database) {\n await this.fallback.save(key, value);\n return;\n }\n try {\n await this.request(database, \"readwrite\", (store) => store.put(value, key));\n } catch {\n await this.fallback.save(key, value);\n }\n }\n\n async remove(key: string): Promise<void> {\n const database = await this.openDatabase();\n if (!database) {\n await this.fallback.remove(key);\n return;\n }\n try {\n await this.request(database, \"readwrite\", (store) => store.delete(key));\n } catch {\n await this.fallback.remove(key);\n }\n }\n\n async list(): Promise<DownloadCheckpoint[]> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.list();\n }\n try {\n const values = await this.request<DownloadCheckpoint[]>(\n database,\n \"readonly\",\n (store) => store.getAll(),\n );\n return values.map(copyCheckpoint);\n } catch {\n return this.fallback.list();\n }\n }\n\n private async openDatabase(): Promise<IDBDatabase | null> {\n if (!this.databasePromise) {\n const indexedDb = getIndexedDb();\n if (!indexedDb) {\n this.databasePromise = Promise.resolve(null);\n } else {\n this.databasePromise = new Promise<IDBDatabase | null>((resolve) => {\n let request: IDBOpenDBRequest;\n try {\n request = indexedDb.open(DOWNLOAD_DATABASE_NAME, DOWNLOAD_DATABASE_VERSION);\n } catch {\n resolve(null);\n return;\n }\n request.onupgradeneeded = () => {\n if (!request.result.objectStoreNames.contains(DOWNLOAD_STORE_NAME)) {\n request.result.createObjectStore(DOWNLOAD_STORE_NAME);\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => resolve(null);\n request.onblocked = () => resolve(null);\n });\n }\n }\n return this.databasePromise;\n }\n\n private request<T = unknown>(\n database: IDBDatabase,\n mode: IDBTransactionMode,\n createRequest: (store: IDBObjectStore) => IDBRequest,\n ): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n let transaction: IDBTransaction;\n let request: IDBRequest;\n try {\n transaction = database.transaction(DOWNLOAD_STORE_NAME, mode);\n request = createRequest(transaction.objectStore(DOWNLOAD_STORE_NAME));\n } catch (error) {\n reject(error);\n return;\n }\n\n let result: T;\n request.onsuccess = () => {\n result = request.result as T;\n };\n request.onerror = () => reject(request.error ?? new Error(\"IndexedDB request failed\"));\n transaction.oncomplete = () => resolve(result);\n transaction.onerror = () => reject(transaction.error ?? new Error(\"IndexedDB transaction failed\"));\n transaction.onabort = () => reject(transaction.error ?? new Error(\"IndexedDB transaction aborted\"));\n });\n }\n}\n\nexport class DownloadHttpError extends Error {\n readonly status: number;\n\n constructor(status: number, message: string) {\n super(message);\n this.name = \"DownloadHttpError\";\n this.status = status;\n }\n}\n\ninterface DownloadTransport {\n readonly baseUrl: string;\n readonly clientSelector: WorkspaceSelector;\n readonly fetchImpl: typeof globalThis.fetch;\n readonly checkpointStore: DownloadCheckpointStore;\n readonly cache: DownloadCache | null;\n requestJson(path: string, body: unknown, signal?: AbortSignal): Promise<unknown>;\n}\n\ninterface ShowSaveFilePickerOptions {\n suggestedName?: string;\n types?: Array<{\n description?: string;\n accept: Record<string, string[]>;\n }>;\n}\n\ntype ShowSaveFilePicker = (\n options?: ShowSaveFilePickerOptions,\n) => Promise<FileSystemFileHandleLike>;\n\nfunction getShowSaveFilePicker(): ShowSaveFilePicker | null {\n return (\n (globalThis as typeof globalThis & { showSaveFilePicker?: ShowSaveFilePicker })\n .showSaveFilePicker ?? null\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction readSafeNumber(value: unknown, field: string): number {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 0) {\n throw new TypeError(`Mountra export response field ${field} is invalid`);\n }\n return value;\n}\n\nfunction readString(value: unknown, field: string): string {\n if (typeof value !== \"string\" || !value) {\n throw new TypeError(`Mountra export response field ${field} is invalid`);\n }\n return value;\n}\n\nfunction ensureExportFileResponse(value: unknown): ExportFileResponse {\n if (!isRecord(value)) {\n throw new TypeError(\"Mountra export response is invalid\");\n }\n const response: ExportFileResponse = {\n path: readString(value.path, \"path\"),\n storageKey: readString(value.storage_key, \"storage_key\"),\n url: readString(value.url, \"url\"),\n timeout: readSafeNumber(value.timeout, \"timeout\"),\n size: readSafeNumber(value.size, \"size\"),\n };\n try {\n new URL(response.url);\n } catch {\n throw new TypeError(\"Mountra export response field url is invalid\");\n }\n if (typeof value.content_type === \"string\" && value.content_type) {\n response.contentType = value.content_type;\n }\n if (typeof value.chunk_method === \"string\") {\n response.chunkMethod = value.chunk_method;\n }\n if (typeof value.is_fast_path === \"boolean\") {\n response.isFastPath = value.is_fast_path;\n }\n if (Array.isArray(value.chunks)) {\n response.chunks = value.chunks.map((rawChunk, position) => {\n if (!isRecord(rawChunk)) {\n throw new TypeError(`Mountra export response chunk ${position} is invalid`);\n }\n const chunk: ExportFileChunk = {\n index: readSafeNumber(rawChunk.index, `chunks[${position}].index`),\n offset: readSafeNumber(rawChunk.offset, `chunks[${position}].offset`),\n size: readSafeNumber(rawChunk.size, `chunks[${position}].size`),\n storageKey: readString(rawChunk.storage_key, `chunks[${position}].storage_key`),\n url: readString(rawChunk.url, `chunks[${position}].url`),\n };\n try {\n new URL(chunk.url);\n } catch {\n throw new TypeError(`Mountra export response chunk ${position} URL is invalid`);\n }\n return chunk;\n });\n response.chunks.sort((left, right) => left.index - right.index);\n response.chunks.forEach((chunk, index) => {\n if (\n chunk.index !== index ||\n chunk.offset + chunk.size > response.size ||\n (index > 0 && response.chunks![index - 1]!.offset + response.chunks![index - 1]!.size !== chunk.offset)\n ) {\n throw new TypeError(\"Mountra export response has an invalid chunk layout\");\n }\n });\n const finalChunk = response.chunks[response.chunks.length - 1];\n if (finalChunk && finalChunk.offset + finalChunk.size !== response.size) {\n throw new TypeError(\"Mountra export response chunks do not cover the complete file\");\n }\n }\n return response;\n}\n\nfunction validateRetryOption(value: number | undefined, name: string): number | undefined {\n if (value === undefined) {\n return undefined;\n }\n if (!Number.isSafeInteger(value) || value < 0) {\n throw new RangeError(`${name} must be a non-negative safe integer`);\n }\n return value;\n}\n\nfunction throwIfAborted(signal?: AbortSignal): void {\n if (signal?.aborted) {\n throw new DOMException(\"The download was aborted\", \"AbortError\");\n }\n}\n\nfunction isAbortError(error: unknown, signal?: AbortSignal): boolean {\n return signal?.aborted === true || (error instanceof DOMException && error.name === \"AbortError\");\n}\n\nfunction isRetryableError(error: unknown): boolean {\n if (error instanceof DownloadHttpError) {\n return [408, 425, 429, 500, 502, 503, 504].includes(error.status);\n }\n return true;\n}\n\nfunction waitForRetry(delayMs: number, signal?: AbortSignal): Promise<void> {\n if (delayMs <= 0) {\n throwIfAborted(signal);\n return Promise.resolve();\n }\n return new Promise<void>((resolve, reject) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const onAbort = () => {\n if (timer !== undefined) {\n clearTimeout(timer);\n }\n signal?.removeEventListener(\"abort\", onAbort);\n reject(new DOMException(\"The download was aborted\", \"AbortError\"));\n };\n timer = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, delayMs);\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n if (signal?.aborted) {\n onAbort();\n }\n });\n}\n\nclass SpeedWindow {\n private readonly samples: Array<{ at: number; bytes: number }> = [];\n\n record(bytes: number, at: number): number {\n this.samples.push({ at, bytes });\n const cutoff = at - 1_000;\n while (this.samples.length > 1 && this.samples[0]!.at < cutoff) {\n this.samples.shift();\n }\n const first = this.samples[0];\n if (!first || first.bytes === bytes) {\n return 0;\n }\n const seconds = Math.max((at - first.at) / 1_000, 0.001);\n return (bytes - first.bytes) / seconds;\n }\n}\n\nclass BlobDownloadSink {\n private readonly parts: Array<Uint8Array | Blob> = [];\n\n /** Parts arrive in file order, so the position is implied. */\n async write(bytes: Uint8Array | Blob, _position?: number): Promise<void> {\n this.parts.push(bytes instanceof Blob ? bytes : bytes.slice());\n }\n\n async flush(): Promise<void> {\n // Blob parts are already retained in memory.\n }\n\n async finalize(): Promise<void> {\n // Blob parts are finalized by blob().\n }\n\n blob(contentType?: string): Blob {\n const buffers = this.parts.map((part) => {\n if (part instanceof Blob) {\n return part;\n }\n const buffer = new ArrayBuffer(part.byteLength);\n new Uint8Array(buffer).set(part);\n return buffer;\n });\n return new Blob(buffers, contentType ? { type: contentType } : undefined);\n }\n}\n\nclass FileSystemDownloadSink {\n private writable: FileSystemWritableFileStreamLike | null = null;\n private position = 0;\n private openedOnce = false;\n\n constructor(private readonly handle: FileSystemFileHandleLike) {}\n\n async write(bytes: Uint8Array | Blob, position: number): Promise<void> {\n if (!this.writable) {\n const keepExistingData = this.openedOnce || position > 0;\n this.writable = await this.handle.createWritable({ keepExistingData });\n if (position > 0) {\n await this.writable.seek(position);\n }\n this.position = position;\n this.openedOnce = true;\n }\n if (this.position !== position) {\n throw new Error(\"File System Access writer position does not match the download checkpoint\");\n }\n await this.writable.write(bytes);\n this.position += bytes instanceof Blob ? bytes.size : bytes.byteLength;\n }\n\n async flush(): Promise<void> {\n if (this.writable) {\n const writable = this.writable;\n await writable.close();\n this.writable = null;\n }\n }\n\n async finalize(size: number): Promise<void> {\n if (!this.writable) {\n this.writable = await this.handle.createWritable({ keepExistingData: this.openedOnce });\n this.openedOnce = true;\n await this.writable.seek(size);\n }\n await this.writable.truncate(size);\n const writable = this.writable;\n this.writable = null;\n await writable.close();\n }\n\n async abort(): Promise<void> {\n if (!this.writable) {\n return;\n }\n const writable = this.writable;\n this.writable = null;\n if (writable.abort) {\n await writable.abort();\n } else {\n await writable.close();\n }\n }\n}\n\ntype DownloadSink = BlobDownloadSink | FileSystemDownloadSink;\n\nfunction downloadRequestFromOptions(options: ExportFileOptions): DownloadCheckpointRequest {\n if (options.path === undefined && options.ino === undefined) {\n throw new TypeError(\"download target requires path or ino\");\n }\n if (options.path !== undefined && !options.path.trim()) {\n throw new TypeError(\"download path cannot be empty\");\n }\n return {\n ...(options.workspaceCuid !== undefined ? { workspaceCuid: options.workspaceCuid } : {}),\n ...(options.workspaceId !== undefined ? { workspaceId: options.workspaceId } : {}),\n ...(options.path !== undefined ? { path: options.path } : {}),\n ...(options.ino !== undefined ? { ino: options.ino } : {}),\n ...(options.timeout !== undefined ? { timeout: options.timeout } : {}),\n ...(options.contentDisposition !== undefined\n ? { contentDisposition: options.contentDisposition }\n : {}),\n ...(options.downloadFilename !== undefined\n ? { downloadFilename: options.downloadFilename }\n : {}),\n };\n}\n\nfunction requestBodyFromCheckpoint(request: DownloadCheckpointRequest): Record<string, unknown> {\n return {\n ...(request.workspaceCuid !== undefined ? { workspace_cuid: request.workspaceCuid } : {}),\n ...(request.workspaceId !== undefined ? { workspace_id: request.workspaceId } : {}),\n ...(request.path !== undefined ? { path: request.path } : {}),\n ...(request.ino !== undefined ? { ino: request.ino } : {}),\n ...(request.timeout !== undefined ? { timeout: request.timeout } : {}),\n ...(request.contentDisposition !== undefined\n ? { content_disposition: request.contentDisposition }\n : {}),\n ...(request.downloadFilename !== undefined\n ? { download_filename: request.downloadFilename }\n : {}),\n };\n}\n\nfunction requestKey(request: DownloadCheckpointRequest, baseUrl: string): string {\n return encodeURIComponent(\n JSON.stringify({\n baseUrl,\n workspaceCuid: request.workspaceCuid ?? null,\n workspaceId: request.workspaceId ?? null,\n path: request.path ?? null,\n ino: request.ino ?? null,\n }),\n );\n}\n\ninterface DownloadPlanChunk {\n index: number;\n offset: number;\n size: number;\n storageKey: string;\n /** Absent only for chunks preloaded from the download cache. */\n url?: string;\n}\n\n/** What to download: an export response, or a file layout rebuilt from the download cache. */\ninterface DownloadPlan {\n path: string;\n size: number;\n contentType?: string;\n chunks: DownloadPlanChunk[];\n /** Absent when the plan comes from the download cache. */\n exported?: ExportFileResponse;\n /** Chunk bytes already read from the download cache, by chunk index. */\n cachedChunks?: Map<number, Blob>;\n}\n\nfunction buildDownloadChunks(exported: ExportFileResponse, useClientAssembly: boolean): ExportFileChunk[] {\n if (useClientAssembly && exported.chunks && exported.chunks.length > 1) {\n return exported.chunks;\n }\n return [\n {\n index: 0,\n offset: 0,\n size: exported.size,\n storageKey: exported.storageKey,\n url: exported.url,\n },\n ];\n}\n\nfunction buildDownloadKey(\n plan: DownloadPlan,\n baseUrl: string,\n request: DownloadCheckpointRequest,\n): string {\n return encodeURIComponent(\n JSON.stringify({\n request: requestKey(request, baseUrl),\n path: plan.path,\n size: plan.size,\n chunks: plan.chunks.map((chunk) => [chunk.index, chunk.offset, chunk.size, chunk.storageKey]),\n }),\n );\n}\n\nfunction checkpointMatches(checkpoint: DownloadCheckpoint, plan: DownloadPlan): boolean {\n if (checkpoint.version !== 1 || checkpoint.path !== plan.path || checkpoint.size !== plan.size) {\n return false;\n }\n if (checkpoint.chunks.length !== plan.chunks.length) {\n return false;\n }\n return checkpoint.chunks.every((saved, index) => {\n const current = plan.chunks[index];\n return Boolean(\n current &&\n saved.index === current.index &&\n saved.offset === current.offset &&\n saved.size === current.size &&\n saved.storageKey === current.storageKey &&\n saved.downloadedBytes >= 0 &&\n saved.downloadedBytes <= saved.size,\n );\n });\n}\n\nfunction createCheckpoint(\n key: string,\n baseUrl: string,\n request: DownloadCheckpointRequest,\n plan: DownloadPlan,\n fileHandle?: FileSystemFileHandleLike,\n): DownloadCheckpoint {\n return {\n version: 1,\n key,\n requestKey: requestKey(request, baseUrl),\n request: { ...request },\n path: plan.path,\n size: plan.size,\n chunks: plan.chunks.map((chunk) => ({\n index: chunk.index,\n offset: chunk.offset,\n size: chunk.size,\n storageKey: chunk.storageKey,\n downloadedBytes: 0,\n completed: chunk.size === 0,\n })),\n ...(fileHandle ? { fileHandle } : {}),\n updatedAt: Date.now(),\n };\n}\n\nfunction totalDownloadedBytes(checkpoint: DownloadCheckpoint): number {\n return checkpoint.chunks.reduce((total, chunk) => total + chunk.downloadedBytes, 0);\n}\n\nfunction completedChunkCount(checkpoint: DownloadCheckpoint): number {\n return checkpoint.chunks.filter((chunk) => chunk.completed).length;\n}\n\nfunction defaultFilename(path: string, requested?: string): string {\n const candidate = requested?.trim() || path.split(\"/\").filter(Boolean).pop() || \"download\";\n return candidate.replace(/[\\\\/\\r\\n]/g, \"_\") || \"download\";\n}\n\nfunction triggerBrowserDownload(blob: Blob, filename: string): void {\n const documentValue = (globalThis as typeof globalThis & { document?: Document }).document;\n const urlApi = (globalThis as typeof globalThis & { URL?: typeof URL }).URL;\n if (!documentValue || !urlApi?.createObjectURL) {\n return;\n }\n const url = urlApi.createObjectURL(blob);\n const anchor = documentValue.createElement(\"a\");\n anchor.href = url;\n anchor.download = filename;\n anchor.style.display = \"none\";\n documentValue.body?.appendChild(anchor);\n anchor.click();\n anchor.remove();\n setTimeout(() => urlApi.revokeObjectURL(url), 0);\n}\n\nexport class MountraDownloader {\n private readonly transport: DownloadTransport;\n\n constructor(transport: DownloadTransport) {\n this.transport = transport;\n }\n\n async exportFile(options: ExportFileOptions): Promise<ExportFileResponse> {\n return this.exportRequest(this.resolveRequest(options), options.signal);\n }\n\n async downloadFile(options: DownloadFileOptions): Promise<DownloadResult> {\n const preferFileSystemAccess = options.preferFileSystemAccess !== false;\n const fileHandle =\n options.fileHandle ??\n (preferFileSystemAccess && getShowSaveFilePicker()\n ? await this.pickSaveFile(options.downloadFilename ?? options.path?.split(\"/\").filter(Boolean).pop())\n : undefined);\n const request = this.resolveRequest(options);\n const plan =\n (await this.loadCachedPlan(request, options.cache)) ??\n this.planExport(\n await this.exportRequest(request, options.signal),\n request,\n options.cache,\n fileHandle,\n );\n return this.downloadResolved(plan, request, options, fileHandle, false);\n }\n\n async downloadExport(\n exported: ExportFileResponse,\n options: DownloadFileOptions = { path: exported.path },\n ): Promise<DownloadResult> {\n let fileHandle = options.fileHandle;\n if (\n !fileHandle &&\n options.preferFileSystemAccess !== false &&\n getShowSaveFilePicker()\n ) {\n fileHandle = await this.pickSaveFile(\n options.downloadFilename ?? defaultFilename(exported.path),\n exported.contentType,\n );\n }\n const request = this.resolveRequest(\n options.path === undefined && options.ino === undefined\n ? { ...options, path: exported.path }\n : options,\n );\n return this.downloadResolved(\n this.planExport(exported, request, options.cache, fileHandle),\n request,\n options,\n fileHandle,\n false,\n );\n }\n\n async resumeDownload(\n downloadKey: string,\n options: DownloadResumeOptions = {},\n ): Promise<DownloadResult> {\n if (!downloadKey.trim()) {\n throw new TypeError(\"downloadKey is required\");\n }\n const checkpoint = await this.transport.checkpointStore.load(downloadKey);\n if (!checkpoint || !checkpoint.fileHandle) {\n throw new Error(\"No resumable File System Access download was found\");\n }\n await this.ensureWritePermission(checkpoint.fileHandle);\n const exported = await this.exportFile({\n ...checkpoint.request,\n signal: options.signal,\n });\n return this.downloadResolved(\n this.planExport(exported, checkpoint.request, undefined, checkpoint.fileHandle),\n checkpoint.request,\n options,\n checkpoint.fileHandle,\n true,\n );\n }\n\n listResumableDownloads(): Promise<DownloadCheckpoint[]> {\n return this.transport.checkpointStore.list();\n }\n\n clearDownloadCheckpoint(downloadKey: string): Promise<void> {\n return this.transport.checkpointStore.remove(downloadKey);\n }\n\n /** Drop the cached layout of a file that was just written, so the next download sees the new content. */\n async invalidateCachedFile(\n selector: WorkspaceSelector,\n target: { path?: string; ino?: number | string },\n ): Promise<void> {\n await this.cachedFileScope(selector, target)?.invalidate();\n }\n\n /**\n * Cache a file this client just uploaded, so downloading it needs no\n * network. Falls back to invalidation when any chunk cannot be cached.\n */\n async cacheUploadedFile(\n selector: WorkspaceSelector,\n file: {\n path: string;\n ino?: number | string;\n size: number;\n contentType?: string;\n chunks: Array<DownloadCacheChunk & { data: Blob }>;\n },\n mode: Exclude<DownloadCacheMode, \"no-cache\"> = \"default\",\n ): Promise<void> {\n const scope = this.cachedFileScope(selector, file);\n if (!scope) {\n return;\n }\n await scope.invalidate();\n if (mode === \"no-store\") {\n return;\n }\n let complete = true;\n for (const chunk of file.chunks) {\n // Keep storing the rest: cached chunks still help later downloads of other layouts.\n complete = (await scope.cache.storeChunk(scope.workspace, chunk, chunk.data)) && complete;\n }\n if (complete) {\n for (const fileKey of scope.fileKeys) {\n await scope.cache.storeFile(scope.workspace, fileKey, file);\n }\n }\n }\n\n private cachedFileScope(\n selector: WorkspaceSelector,\n target: { path?: string; ino?: number | string },\n ): { cache: DownloadCache; workspace: string; fileKeys: string[]; invalidate(): Promise<void> } | null {\n const cache = this.transport.cache;\n const workspace = workspaceCacheKey(this.transport.baseUrl, selector);\n if (!cache || workspace === null) {\n return null;\n }\n const fileKeys = [\n target.path !== undefined ? fileCacheKey({ path: target.path }) : null,\n target.ino !== undefined ? fileCacheKey({ ino: target.ino }) : null,\n ].filter((fileKey): fileKey is string => fileKey !== null);\n return {\n cache,\n workspace,\n fileKeys,\n invalidate: () => cache.invalidateFiles(workspace, fileKeys),\n };\n }\n\n async clearCache(selector?: WorkspaceSelector): Promise<void> {\n const cache = this.transport.cache;\n if (!cache) {\n return;\n }\n await cache.clear(selector === undefined ? undefined : this.requireCacheWorkspace(selector));\n }\n\n async cacheUsage(selector?: WorkspaceSelector): Promise<DownloadCacheUsage> {\n const cache = this.transport.cache;\n if (!cache) {\n return { bytes: 0, chunks: 0 };\n }\n return cache.usage(selector === undefined ? undefined : this.requireCacheWorkspace(selector));\n }\n\n private requireCacheWorkspace(selector: WorkspaceSelector): string {\n const workspace = workspaceCacheKey(this.transport.baseUrl, selector);\n if (workspace === null) {\n throw new TypeError(\"workspaceCuid or workspaceId is required\");\n }\n return workspace;\n }\n\n /** Fall back to the client workspace only when the request names none, as uploads do. */\n private resolveRequest(options: ExportFileOptions): DownloadCheckpointRequest {\n const hasWorkspace = options.workspaceCuid !== undefined || options.workspaceId !== undefined;\n return downloadRequestFromOptions(\n hasWorkspace\n ? options\n : {\n ...options,\n workspaceCuid: this.transport.clientSelector.workspaceCuid,\n workspaceId: this.transport.clientSelector.workspaceId,\n },\n );\n }\n\n private async exportRequest(\n request: DownloadCheckpointRequest,\n signal?: AbortSignal,\n ): Promise<ExportFileResponse> {\n return ensureExportFileResponse(\n await this.transport.requestJson(\"/file/export\", requestBodyFromCheckpoint(request), signal),\n );\n }\n\n private cacheScope(\n request: DownloadCheckpointRequest,\n mode: DownloadCacheMode = \"default\",\n ): { cache: DownloadCache; workspace: string; fileKey: string } | null {\n const cache = this.transport.cache;\n if (!cache || mode === \"no-store\") {\n return null;\n }\n const workspace = workspaceCacheKey(this.transport.baseUrl, request);\n const fileKey = fileCacheKey(request);\n return workspace !== null && fileKey !== null ? { cache, workspace, fileKey } : null;\n }\n\n /** A plan that needs no network at all, when the cached layout is fresh and every chunk is cached. */\n private async loadCachedPlan(\n request: DownloadCheckpointRequest,\n mode: DownloadCacheMode | undefined,\n ): Promise<DownloadPlan | null> {\n const scope = this.cacheScope(request, mode);\n if (!scope || mode === \"no-cache\") {\n return null;\n }\n const cached = await scope.cache.loadFile(scope.workspace, scope.fileKey);\n if (!cached) {\n return null;\n }\n return {\n path: cached.file.path,\n size: cached.file.size,\n ...(cached.file.contentType ? { contentType: cached.file.contentType } : {}),\n chunks: cached.file.chunks,\n cachedChunks: cached.chunks,\n };\n }\n\n private planExport(\n exported: ExportFileResponse,\n request: DownloadCheckpointRequest,\n mode: DownloadCacheMode | undefined,\n fileHandle: FileSystemFileHandleLike | undefined,\n ): DownloadPlan {\n // Per-chunk downloads let each chunk be cached and reused on its own.\n const useClientAssembly =\n (exported.chunks?.length ?? 0) > 1 &&\n (Boolean(fileHandle) || this.cacheScope(request, mode) !== null);\n return {\n path: exported.path,\n size: exported.size,\n ...(exported.contentType ? { contentType: exported.contentType } : {}),\n chunks: buildDownloadChunks(exported, useClientAssembly),\n exported,\n };\n }\n\n private async pickSaveFile(\n requestedFilename?: string,\n contentType?: string,\n ): Promise<FileSystemFileHandleLike> {\n const picker = getShowSaveFilePicker();\n if (!picker) {\n throw new Error(\"File System Access API is not available\");\n }\n const types = contentType\n ? [{ description: contentType, accept: { [contentType]: [\".\" + (requestedFilename?.split(\".\").pop() || \"bin\")] } }]\n : undefined;\n return picker({\n suggestedName: requestedFilename?.trim() || \"download\",\n ...(types ? { types } : {}),\n });\n }\n\n private async ensureWritePermission(handle: FileSystemFileHandleLike): Promise<void> {\n if (!handle.queryPermission && !handle.requestPermission) {\n return;\n }\n const descriptor = { mode: \"readwrite\" as const };\n const current = await handle.queryPermission?.(descriptor);\n if (current === \"granted\") {\n return;\n }\n const requested = await handle.requestPermission?.(descriptor);\n if (requested !== undefined && requested !== \"granted\") {\n throw new DOMException(\"Write permission was not granted\", \"NotAllowedError\");\n }\n }\n\n private async downloadResolved(\n plan: DownloadPlan,\n request: DownloadCheckpointRequest,\n options: Pick<\n DownloadFileOptions,\n \"onProgress\" | \"signal\" | \"maxRetries\" | \"retryDelayMs\" | \"resume\" | \"downloadFilename\" | \"cache\"\n > | DownloadResumeOptions,\n fileHandle: FileSystemFileHandleLike | undefined,\n forceResume: boolean,\n ): Promise<DownloadResult> {\n const chunks = plan.chunks;\n const key = buildDownloadKey(plan, this.transport.baseUrl, request);\n const existing = await this.transport.checkpointStore.load(key);\n const resumeRequested = !(\"resume\" in options) || options.resume !== false;\n let checkpoint =\n existing && checkpointMatches(existing, plan) &&\n (forceResume || resumeRequested) &&\n (forceResume || (fileHandle && (await this.isSameFileHandle(existing.fileHandle, fileHandle))))\n ? existing\n : createCheckpoint(key, this.transport.baseUrl, request, plan, fileHandle);\n const cacheScope = this.cacheScope(request, \"cache\" in options ? options.cache : undefined);\n /** Indexes of chunks whose bytes are in the cache, from a hit or a store in this call. */\n const cachedChunkIndexes = new Set<number>();\n let cachedBytes = 0;\n\n if (fileHandle) {\n checkpoint.fileHandle = fileHandle;\n }\n const resumed = totalDownloadedBytes(checkpoint) > 0;\n const maxRetries = validateRetryOption(options.maxRetries, \"maxRetries\") ?? 3;\n const retryDelayMs = validateRetryOption(options.retryDelayMs, \"retryDelayMs\") ?? 500;\n const sink: DownloadSink = fileHandle\n ? new FileSystemDownloadSink(fileHandle)\n : new BlobDownloadSink();\n const speedWindow = new SpeedWindow();\n const startedAt = Date.now();\n let retryCount = 0;\n let lastCheckpointAt = 0;\n\n const emit = (\n phase: DownloadProgress[\"phase\"],\n currentChunkIndex?: number,\n ): void => {\n const downloadedBytes = totalDownloadedBytes(checkpoint);\n const speedBytesPerSecond = speedWindow.record(downloadedBytes, Date.now());\n const remainingBytes = Math.max(plan.size - downloadedBytes, 0);\n options.onProgress?.({\n phase,\n downloadedBytes,\n totalBytes: plan.size,\n downloadedChunks: completedChunkCount(checkpoint),\n totalChunks: checkpoint.chunks.length,\n ...(currentChunkIndex !== undefined ? { currentChunkIndex } : {}),\n speedBytesPerSecond,\n ...(speedBytesPerSecond > 0 && remainingBytes > 0\n ? { estimatedRemainingSeconds: remainingBytes / speedBytesPerSecond }\n : {}),\n elapsedMs: Date.now() - startedAt,\n retryCount,\n });\n };\n\n const persist = async (force: boolean): Promise<void> => {\n const now = Date.now();\n if (!force && now - lastCheckpointAt < 1_000) {\n return;\n }\n await sink.flush();\n checkpoint.updatedAt = now;\n await this.transport.checkpointStore.save(key, checkpoint);\n lastCheckpointAt = now;\n };\n\n await this.transport.checkpointStore.save(key, checkpoint);\n try {\n for (const chunk of chunks) {\n const savedChunk = checkpoint.chunks[chunk.index];\n if (!savedChunk) {\n throw new Error(`Missing download checkpoint for chunk ${chunk.index}`);\n }\n if (savedChunk.completed) {\n continue;\n }\n\n const cached =\n plan.cachedChunks?.get(chunk.index) ??\n (cacheScope ? await cacheScope.cache.readChunk(cacheScope.workspace, chunk) : null);\n if (cached) {\n throwIfAborted(options.signal);\n const remaining = cached.slice(savedChunk.downloadedBytes);\n await sink.write(remaining, chunk.offset + savedChunk.downloadedBytes);\n cachedBytes += remaining.size;\n savedChunk.downloadedBytes = chunk.size;\n savedChunk.completed = true;\n cachedChunkIndexes.add(chunk.index);\n emit(\"downloading\", chunk.index);\n await persist(false);\n continue;\n }\n const url = chunk.url;\n if (!url) {\n throw new Error(`Chunk ${chunk.index} is no longer in the download cache`);\n }\n // A chunk resumed from a checkpoint lacks its head bytes, so it cannot be cached.\n const capture: Uint8Array<ArrayBuffer>[] | null =\n cacheScope && savedChunk.downloadedBytes === 0 && cacheScope.cache.canStoreChunk(chunk)\n ? []\n : null;\n\n let attempt = 0;\n while (true) {\n throwIfAborted(options.signal);\n const rangeStart = savedChunk.downloadedBytes;\n try {\n const response = await this.transport.fetchImpl(url, {\n method: \"GET\",\n ...(rangeStart > 0 ? { headers: { Range: `bytes=${rangeStart}-` } } : {}),\n ...(options.signal ? { signal: options.signal } : {}),\n });\n if (!response.ok) {\n throw new DownloadHttpError(\n response.status,\n `Download for chunk ${chunk.index} failed with HTTP ${response.status}`,\n );\n }\n await this.consumeResponse(\n response,\n chunk,\n savedChunk,\n sink,\n plan.size,\n emit,\n persist,\n capture,\n options.signal,\n );\n if (savedChunk.downloadedBytes !== savedChunk.size) {\n throw new Error(\n `Download for chunk ${chunk.index} ended at ${savedChunk.downloadedBytes} of ${savedChunk.size} bytes`,\n );\n }\n savedChunk.completed = true;\n await persist(true);\n if (\n cacheScope &&\n capture &&\n (await cacheScope.cache.storeChunk(cacheScope.workspace, chunk, new Blob(capture)))\n ) {\n cachedChunkIndexes.add(chunk.index);\n }\n emit(\"downloading\", chunk.index);\n break;\n } catch (error) {\n await persist(true);\n if (isAbortError(error, options.signal) || !isRetryableError(error) || attempt >= maxRetries) {\n throw error;\n }\n attempt += 1;\n retryCount += 1;\n emit(\"retrying\", chunk.index);\n await waitForRetry(Math.min(retryDelayMs * 2 ** (attempt - 1), 30_000), options.signal);\n }\n }\n }\n\n if (totalDownloadedBytes(checkpoint) !== plan.size) {\n throw new Error(\"Download completed with an unexpected byte count\");\n }\n if (fileHandle) {\n await (sink as FileSystemDownloadSink).finalize(plan.size);\n } else {\n await (sink as BlobDownloadSink).finalize();\n }\n await this.transport.checkpointStore.remove(key);\n // Only a layout Mountra just confirmed may start a new freshness period.\n if (\n cacheScope &&\n plan.exported &&\n chunks.every((chunk) => chunk.size === 0 || cachedChunkIndexes.has(chunk.index))\n ) {\n await cacheScope.cache.storeFile(cacheScope.workspace, cacheScope.fileKey, plan);\n }\n emit(\"completed\");\n const blob = sink instanceof BlobDownloadSink ? sink.blob(plan.contentType) : undefined;\n if (blob) {\n const filename = \"downloadFilename\" in options ? options.downloadFilename : undefined;\n triggerBrowserDownload(blob, defaultFilename(plan.path, filename));\n }\n return {\n ...(plan.exported ? { export: plan.exported } : {}),\n downloadKey: key,\n downloadedBytes: plan.size,\n cachedBytes,\n resumed,\n ...(fileHandle ? { fileHandle } : {}),\n ...(blob ? { blob } : {}),\n };\n } catch (error) {\n await persist(true);\n throw error;\n }\n }\n\n private async consumeResponse(\n response: Response,\n chunk: DownloadPlanChunk,\n savedChunk: DownloadCheckpointChunk,\n sink: DownloadSink,\n totalSize: number,\n emit: (phase: DownloadProgress[\"phase\"], currentChunkIndex?: number) => void,\n persist: (force: boolean) => Promise<void>,\n capture: Uint8Array<ArrayBuffer>[] | null,\n signal?: AbortSignal,\n ): Promise<void> {\n const sourceOffset = savedChunk.downloadedBytes;\n let bytesToSkip = response.status === 200 && sourceOffset > 0 ? sourceOffset : 0;\n const reader = response.body?.getReader();\n if (!reader) {\n const body = new Uint8Array(await response.arrayBuffer());\n await this.consumeBytes(body, bytesToSkip, chunk, savedChunk, sink, totalSize, emit, persist, capture, signal);\n return;\n }\n\n try {\n while (true) {\n throwIfAborted(signal);\n const next = await reader.read();\n if (next.done) {\n break;\n }\n const bytes = next.value;\n if (bytesToSkip > 0) {\n const skipped = Math.min(bytesToSkip, bytes.byteLength);\n bytesToSkip -= skipped;\n if (skipped === bytes.byteLength) {\n continue;\n }\n await this.consumeBytes(\n bytes.subarray(skipped),\n 0,\n chunk,\n savedChunk,\n sink,\n totalSize,\n emit,\n persist,\n capture,\n signal,\n );\n } else {\n await this.consumeBytes(bytes, 0, chunk, savedChunk, sink, totalSize, emit, persist, capture, signal);\n }\n }\n } finally {\n reader.releaseLock();\n }\n if (bytesToSkip > 0) {\n throw new Error(`Download response did not contain the saved offset for chunk ${chunk.index}`);\n }\n }\n\n private async consumeBytes(\n bytes: Uint8Array,\n offset: number,\n chunk: DownloadPlanChunk,\n savedChunk: DownloadCheckpointChunk,\n sink: DownloadSink,\n totalSize: number,\n emit: (phase: DownloadProgress[\"phase\"], currentChunkIndex?: number) => void,\n persist: (force: boolean) => Promise<void>,\n capture: Uint8Array<ArrayBuffer>[] | null,\n signal?: AbortSignal,\n ): Promise<void> {\n const remaining = chunk.size - savedChunk.downloadedBytes;\n const writableBytes = bytes.byteLength - offset;\n if (writableBytes > remaining) {\n throw new Error(`Download response for chunk ${chunk.index} is larger than expected`);\n }\n if (writableBytes === 0) {\n return;\n }\n throwIfAborted(signal);\n const payload = bytes.subarray(offset);\n const position = chunk.offset + savedChunk.downloadedBytes;\n await sink.write(payload, position);\n capture?.push(payload.slice());\n savedChunk.downloadedBytes += payload.byteLength;\n emit(\"downloading\", chunk.index);\n await persist(false);\n if (savedChunk.downloadedBytes > totalSize) {\n throw new Error(\"Download byte count exceeded the exported file size\");\n }\n }\n\n private async isSameFileHandle(\n savedHandle: FileSystemFileHandleLike | undefined,\n selectedHandle: FileSystemFileHandleLike,\n ): Promise<boolean> {\n if (!savedHandle) {\n return false;\n }\n if (savedHandle === selectedHandle) {\n return true;\n }\n if (savedHandle.isSameEntry) {\n try {\n return await savedHandle.isSameEntry(selectedHandle);\n } catch {\n return false;\n }\n }\n return false;\n }\n}\n","import { DownloadCache } from \"./cache\";\nimport type { DownloadCacheOptions, DownloadCacheUsage } from \"./cache\";\nimport { IndexedDBDownloadCheckpointStore, MountraDownloader } from \"./download\";\nimport type {\n DownloadCheckpoint,\n DownloadCheckpointStore,\n DownloadFileOptions,\n DownloadResult,\n DownloadResumeOptions,\n ExportFileOptions,\n ExportFileResponse,\n} from \"./download\";\nimport { MountraFile, normalizeMountraFileLocator } from \"./file\";\nimport type { MountraFileLocator } from \"./file\";\n\nexport type ChunkMethod = \"none\" | \"fix\";\nexport type WorkspaceId = number | string;\n\nexport const JUMBO_CHUNK_THRESHOLD_BYTES = 128 * 1024 * 1024;\nexport const MIN_S3_MULTIPART_PART_SIZE_BYTES = 5 * 1024 * 1024;\nexport const DEFAULT_S3_MULTIPART_PART_SIZE_BYTES = 16 * 1024 * 1024;\nexport const MAX_S3_MULTIPART_PARTS = 10_000;\n\nexport interface WorkspaceSelector {\n workspaceCuid?: string;\n workspaceId?: WorkspaceId;\n}\n\nexport type AccessToken =\n | string\n | null\n | undefined\n | (() => string | null | undefined | Promise<string | null | undefined>);\n\nexport interface MountraClientOptions extends WorkspaceSelector {\n /** Mountra server origin, for example `https://mountra.example.com`. */\n baseUrl: string;\n /** API prefix. Set to an empty string when `baseUrl` already includes `/api`. */\n apiPrefix?: string;\n token?: AccessToken;\n /** Additional headers for Mountra API requests. They are never sent to signed URLs. */\n headers?: HeadersInit;\n fetch?: typeof globalThis.fetch;\n /** Adapter for S3 Multipart uploads used by chunks larger than 128 MiB. */\n jumboChunkUploader?: JumboChunkUploader;\n /** Durable local checkpoint store for jumbo Multipart uploads. */\n jumboChunkCheckpointStore?: JumboChunkCheckpointStore;\n /** S3 Multipart part size. Defaults to 16 MiB. */\n jumboPartSize?: number;\n /** IndexedDB-backed download checkpoint store. */\n downloadCheckpointStore?: DownloadCheckpointStore;\n /**\n * Cache downloaded chunks locally, per workspace, in IndexedDB. Disabled\n * unless set; pass `{}` for the defaults.\n */\n downloadCache?: DownloadCacheOptions;\n}\n\nexport interface UploadFileOptions extends WorkspaceSelector {\n path: string;\n /**\n * Maximum number of fixed-size chunks. Defaults to 1. Each chunk is\n * `ceil(size / chunkCount)` bytes except the last, so an uneven split may\n * produce fewer chunks.\n */\n chunkCount?: number;\n contentType?: string;\n nameConflictStrategy?: \"overwrite\" | \"keep_both\";\n signal?: AbortSignal;\n onProgress?: (progress: MountraProgress) => void;\n /** Persist this serializable context before the first chunk is uploaded. */\n onSessionPrepared?: (context: UploadSessionContext) => void | Promise<void>;\n /**\n * With the client's `downloadCache`, an uploaded file is cached by default so\n * downloading it needs no network. `no-store` only invalidates its old entry.\n */\n cache?: \"default\" | \"no-store\";\n}\n\nexport interface UploadResumeOptions extends WorkspaceSelector {\n signal?: AbortSignal;\n onProgress?: (progress: MountraProgress) => void;\n /** See `UploadFileOptions.cache`. */\n cache?: \"default\" | \"no-store\";\n}\n\nexport interface MountraProgress {\n phase: \"uploading\" | \"finishing\";\n uploadedBytes: number;\n totalBytes: number;\n uploadedChunks: number;\n totalChunks: number;\n uploadedParts?: number;\n totalParts?: number;\n}\n\nexport interface FileChunk {\n index: number;\n offset: number;\n size: number;\n blob: Blob;\n}\n\nexport interface UploadTarget {\n chunk_index: number;\n storage_key: string;\n put_method?: string;\n put_url?: string;\n put_headers: Record<string, string>;\n size: number;\n upload_required: boolean;\n}\n\nexport interface UploadSessionChunkContext {\n index: number;\n offset: number;\n size: number;\n sha256: string;\n}\n\nexport interface S3MultipartPart {\n partNumber: number;\n etag: string;\n size: number;\n sha256: string;\n}\n\nexport interface JumboChunkCreateInput {\n storageKey: string;\n contentType?: string;\n signal?: AbortSignal;\n}\n\nexport interface JumboChunkUploadPartInput {\n storageKey: string;\n uploadId: string;\n partNumber: number;\n body: Blob;\n signal?: AbortSignal;\n}\n\nexport interface JumboChunkCompleteInput {\n storageKey: string;\n uploadId: string;\n parts: Array<Pick<S3MultipartPart, \"partNumber\" | \"etag\">>;\n signal?: AbortSignal;\n}\n\n/**\n * Small S3 Multipart adapter. Implement these methods with the S3 SDK used by\n * the host application. Reusing a part number is intentional: S3 replaces\n * the previous part, which makes retries idempotent.\n */\nexport interface JumboChunkUploader {\n createMultipartUpload(input: JumboChunkCreateInput): Promise<{ uploadId: string }>;\n uploadPart(input: JumboChunkUploadPartInput): Promise<{ etag: string }>;\n completeMultipartUpload(input: JumboChunkCompleteInput): Promise<void>;\n abortMultipartUpload?(input: {\n storageKey: string;\n uploadId: string;\n signal?: AbortSignal;\n }): Promise<void>;\n}\n\nexport interface JumboChunkCheckpoint {\n version: 1;\n storageKey: string;\n chunkIndex: number;\n chunkSize: number;\n chunkSha256: string;\n partSize: number;\n uploadId: string;\n completed: boolean;\n completing: boolean;\n parts: S3MultipartPart[];\n}\n\nexport interface JumboChunkCheckpointStore {\n load(key: string): Promise<JumboChunkCheckpoint | null>;\n save(key: string, checkpoint: JumboChunkCheckpoint): Promise<void>;\n remove(key: string): Promise<void>;\n}\n\nexport interface S3MultipartClient {\n createMultipartUpload(input: {\n bucket: string;\n key: string;\n contentType?: string;\n signal?: AbortSignal;\n }): Promise<{ uploadId: string }>;\n uploadPart(input: {\n bucket: string;\n key: string;\n uploadId: string;\n partNumber: number;\n body: Blob;\n signal?: AbortSignal;\n }): Promise<{ etag: string }>;\n completeMultipartUpload(input: {\n bucket: string;\n key: string;\n uploadId: string;\n parts: Array<Pick<S3MultipartPart, \"partNumber\" | \"etag\">>;\n signal?: AbortSignal;\n }): Promise<void>;\n abortMultipartUpload?(input: {\n bucket: string;\n key: string;\n uploadId: string;\n signal?: AbortSignal;\n }): Promise<void>;\n}\n\n/** Serializable metadata a client must persist alongside its file/blob handle. */\nexport interface UploadSessionContext {\n uploadId: string;\n path: string;\n fileSize: number;\n contentHash: string;\n chunkMethod: \"none\" | \"fix\" | \"cdc\";\n chunks: UploadSessionChunkContext[];\n contentType?: string;\n}\n\nexport interface PrepareUploadResponse {\n upload_id: string;\n path: string;\n expires_in_seconds: number;\n chunk_method: \"none\" | \"fix\" | \"cdc\";\n session_status: \"prepared\" | \"uploaded\" | \"finished\" | \"aborted\" | \"expired\";\n upload_targets: UploadTarget[];\n}\n\nexport interface UploadStatusChunk {\n chunk_index: number;\n offset: number;\n size: number;\n sha256: string;\n storage_key: string;\n status: \"pending\" | \"uploaded\";\n upload_required: boolean;\n put_method?: string;\n put_url?: string;\n put_headers: Record<string, string>;\n}\n\nexport interface UploadStatusResponse {\n upload_id: string;\n path: string;\n storage_key: string;\n size: number;\n chunk_method: \"none\" | \"fix\" | \"cdc\";\n session_status: \"prepared\" | \"uploaded\" | \"finished\" | \"aborted\" | \"expired\";\n finish_status:\n | \"awaiting_upload\"\n | \"awaiting_finish\"\n | \"awaiting_chunks\"\n | \"completed\"\n | \"aborted\"\n | \"expired\";\n total_chunks: number;\n uploaded_chunks: number;\n uploaded_bytes: number;\n chunks: UploadStatusChunk[];\n ino?: number;\n}\n\nexport interface FinishUploadResponse {\n upload_id: string;\n path: string;\n storage_key: string;\n size: number;\n chunk_method: \"none\" | \"fix\" | \"cdc\";\n session_status: \"prepared\" | \"uploaded\" | \"finished\" | \"aborted\" | \"expired\";\n finish_status:\n | \"awaiting_upload\"\n | \"awaiting_finish\"\n | \"awaiting_chunks\"\n | \"completed\"\n | \"aborted\"\n | \"expired\";\n ino?: number;\n}\n\nexport type UploadResult = FinishUploadResponse;\n\nexport interface PreparedUpload {\n response: PrepareUploadResponse;\n chunks: FileChunk[];\n chunkHashes: string[];\n contentHash: string;\n context: UploadSessionContext;\n}\n\nexport class MountraApiError extends Error {\n readonly status: number;\n readonly code?: string;\n readonly body?: unknown;\n\n constructor(message: string, input: { status: number; code?: string; body?: unknown }) {\n super(message);\n this.name = \"MountraApiError\";\n this.status = input.status;\n this.code = input.code;\n this.body = input.body;\n }\n}\n\nconst memoryCheckpointRecords = new Map<string, string>();\n\nfunction parseJumboCheckpoint(value: unknown): JumboChunkCheckpoint | null {\n if (!isRecord(value) || value.version !== 1 || typeof value.storageKey !== \"string\") {\n return null;\n }\n if (\n typeof value.chunkIndex !== \"number\" ||\n typeof value.chunkSize !== \"number\" ||\n typeof value.chunkSha256 !== \"string\" ||\n typeof value.partSize !== \"number\" ||\n typeof value.uploadId !== \"string\" ||\n !Array.isArray(value.parts)\n ) {\n return null;\n }\n\n const parts: S3MultipartPart[] = [];\n for (const part of value.parts) {\n if (!isRecord(part)) {\n return null;\n }\n if (\n typeof part.partNumber !== \"number\" ||\n typeof part.etag !== \"string\" ||\n typeof part.size !== \"number\" ||\n typeof part.sha256 !== \"string\"\n ) {\n return null;\n }\n parts.push({\n partNumber: part.partNumber,\n etag: part.etag,\n size: part.size,\n sha256: part.sha256,\n });\n }\n\n return {\n version: 1,\n storageKey: value.storageKey,\n chunkIndex: value.chunkIndex,\n chunkSize: value.chunkSize,\n chunkSha256: value.chunkSha256,\n partSize: value.partSize,\n uploadId: value.uploadId,\n completed: value.completed === true,\n completing: value.completing === true,\n parts,\n };\n}\n\nexport class InMemoryJumboChunkCheckpointStore implements JumboChunkCheckpointStore {\n private readonly records = new Map<string, JumboChunkCheckpoint>();\n\n async load(key: string): Promise<JumboChunkCheckpoint | null> {\n return this.records.get(key) ?? null;\n }\n\n async save(key: string, checkpoint: JumboChunkCheckpoint): Promise<void> {\n this.records.set(key, {\n ...checkpoint,\n parts: checkpoint.parts.map((part) => ({ ...part })),\n });\n }\n\n async remove(key: string): Promise<void> {\n this.records.delete(key);\n }\n}\n\nexport class LocalStorageJumboChunkCheckpointStore implements JumboChunkCheckpointStore {\n private readonly prefix: string;\n\n constructor(prefix = \"mountra-sdk:jumbo:\") {\n this.prefix = prefix;\n }\n\n async load(key: string): Promise<JumboChunkCheckpoint | null> {\n const storageKey = this.storageKey(key);\n const raw = this.getStorage()?.getItem(storageKey) ?? memoryCheckpointRecords.get(storageKey);\n if (!raw) {\n return null;\n }\n try {\n return parseJumboCheckpoint(JSON.parse(raw));\n } catch {\n await this.remove(key);\n return null;\n }\n }\n\n async save(key: string, checkpoint: JumboChunkCheckpoint): Promise<void> {\n const storageKey = this.storageKey(key);\n const serialized = JSON.stringify(checkpoint);\n const storage = this.getStorage();\n if (storage) {\n storage.setItem(storageKey, serialized);\n } else {\n memoryCheckpointRecords.set(storageKey, serialized);\n }\n }\n\n async remove(key: string): Promise<void> {\n const storageKey = this.storageKey(key);\n this.getStorage()?.removeItem(storageKey);\n memoryCheckpointRecords.delete(storageKey);\n }\n\n private storageKey(key: string): string {\n return `${this.prefix}${key}`;\n }\n\n private getStorage(): Storage | null {\n try {\n return globalThis.localStorage ?? null;\n } catch {\n return null;\n }\n }\n}\n\nexport class S3MultipartUploader implements JumboChunkUploader {\n private readonly bucket: string;\n private readonly client: S3MultipartClient;\n\n constructor(input: { bucket: string; client: S3MultipartClient }) {\n const bucket = input.bucket.trim();\n if (!bucket) {\n throw new TypeError(\"S3 bucket is required\");\n }\n this.bucket = bucket;\n this.client = input.client;\n }\n\n createMultipartUpload(input: JumboChunkCreateInput): Promise<{ uploadId: string }> {\n return this.client.createMultipartUpload({\n bucket: this.bucket,\n key: input.storageKey,\n contentType: input.contentType,\n signal: input.signal,\n });\n }\n\n uploadPart(input: JumboChunkUploadPartInput): Promise<{ etag: string }> {\n return this.client.uploadPart({\n bucket: this.bucket,\n key: input.storageKey,\n uploadId: input.uploadId,\n partNumber: input.partNumber,\n body: input.body,\n signal: input.signal,\n });\n }\n\n completeMultipartUpload(input: JumboChunkCompleteInput): Promise<void> {\n return this.client.completeMultipartUpload({\n bucket: this.bucket,\n key: input.storageKey,\n uploadId: input.uploadId,\n parts: input.parts,\n signal: input.signal,\n });\n }\n\n abortMultipartUpload(input: {\n storageKey: string;\n uploadId: string;\n signal?: AbortSignal;\n }): Promise<void> {\n if (!this.client.abortMultipartUpload) {\n return Promise.resolve();\n }\n return this.client.abortMultipartUpload({\n bucket: this.bucket,\n key: input.storageKey,\n uploadId: input.uploadId,\n signal: input.signal,\n });\n }\n}\n\nfunction assertPositiveInteger(value: number, name: string): void {\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw new RangeError(`${name} must be a positive safe integer`);\n }\n}\n\nfunction assertMultipartPartSize(value: number): void {\n assertPositiveInteger(value, \"jumboPartSize\");\n if (value < MIN_S3_MULTIPART_PART_SIZE_BYTES) {\n throw new RangeError(\n `jumboPartSize must be at least ${MIN_S3_MULTIPART_PART_SIZE_BYTES} bytes for S3 Multipart uploads`,\n );\n }\n}\n\nfunction normalizeBaseUrl(value: string): string {\n const trimmed = value.trim().replace(/\\/+$/, \"\");\n if (!trimmed) {\n throw new TypeError(\"baseUrl is required\");\n }\n return trimmed;\n}\n\nfunction normalizeApiPrefix(value: string): string {\n const trimmed = value.trim();\n if (!trimmed || trimmed === \"/\") {\n return \"\";\n }\n return `/${trimmed.replace(/^\\/+|\\/+$/g, \"\")}`;\n}\n\nfunction getWorkspaceBody(\n clientSelector: WorkspaceSelector,\n requestSelector: WorkspaceSelector,\n): Record<string, string | number> {\n const workspaceCuid = requestSelector.workspaceCuid ?? clientSelector.workspaceCuid;\n const workspaceId = requestSelector.workspaceId ?? clientSelector.workspaceId;\n if (workspaceCuid === undefined && workspaceId === undefined) {\n throw new TypeError(\"workspaceCuid or workspaceId is required\");\n }\n\n return {\n ...(workspaceCuid !== undefined ? { workspace_cuid: workspaceCuid } : {}),\n ...(workspaceId !== undefined ? { workspace_id: workspaceId } : {}),\n };\n}\n\nfunction throwIfAborted(signal?: AbortSignal): void {\n if (!signal?.aborted) {\n return;\n }\n throw new DOMException(\"The upload was aborted\", \"AbortError\");\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction parseApiErrorBody(body: unknown): { message?: string; code?: string } {\n if (!isRecord(body)) {\n return {};\n }\n return {\n message: typeof body.error === \"string\" ? body.error : undefined,\n code: typeof body.code === \"string\" ? body.code : undefined,\n };\n}\n\nfunction ensurePrepareResponse(value: unknown): PrepareUploadResponse {\n if (!isRecord(value) || typeof value.upload_id !== \"string\") {\n throw new TypeError(\"Mountra prepare response is invalid\");\n }\n if (!Array.isArray(value.upload_targets)) {\n throw new TypeError(\"Mountra prepare response has no upload targets\");\n }\n return value as unknown as PrepareUploadResponse;\n}\n\nfunction ensureFinishResponse(value: unknown): FinishUploadResponse {\n if (!isRecord(value) || typeof value.upload_id !== \"string\") {\n throw new TypeError(\"Mountra finish response is invalid\");\n }\n return value as unknown as FinishUploadResponse;\n}\n\nfunction ensureUploadStatusResponse(value: unknown): UploadStatusResponse {\n if (!isRecord(value) || typeof value.upload_id !== \"string\") {\n throw new TypeError(\"Mountra upload status response is invalid\");\n }\n if (!Array.isArray(value.chunks)) {\n throw new TypeError(\"Mountra upload status response has no chunk states\");\n }\n return value as unknown as UploadStatusResponse;\n}\n\nexport function splitFileIntoChunks(file: Blob, chunkCount = 1): FileChunk[] {\n assertPositiveInteger(chunkCount, \"chunkCount\");\n\n if (file.size === 0) {\n return [{ index: 0, offset: 0, size: 0, blob: file.slice(0, 0) }];\n }\n if (chunkCount > file.size) {\n throw new RangeError(\"chunkCount cannot be greater than the file size in bytes\");\n }\n\n const chunkSize = Math.ceil(file.size / chunkCount);\n const chunks: FileChunk[] = [];\n // `fix` chunking requires every chunk but the last to be exactly chunkSize, so an\n // uneven split yields fewer chunks than requested rather than empty trailing ones.\n for (let index = 0, offset = 0; offset < file.size; index += 1, offset += chunkSize) {\n const end = Math.min(offset + chunkSize, file.size);\n chunks.push({\n index,\n offset,\n size: end - offset,\n blob: file.slice(offset, end),\n });\n }\n return chunks;\n}\n\nexport function isJumboChunk(size: number): boolean {\n return size > JUMBO_CHUNK_THRESHOLD_BYTES;\n}\n\nexport async function sha256Hex(blob: Blob): Promise<string> {\n const subtle = globalThis.crypto?.subtle;\n if (!subtle) {\n throw new Error(\"Web Crypto SHA-256 is not available in this environment\");\n }\n\n const digest = await subtle.digest(\"SHA-256\", await blob.arrayBuffer());\n return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\nexport class MountraClient {\n private readonly baseUrl: string;\n private readonly apiPrefix: string;\n private readonly clientSelector: WorkspaceSelector;\n private readonly token?: AccessToken;\n private readonly headers?: HeadersInit;\n private readonly fetchImpl: typeof globalThis.fetch;\n private readonly jumboChunkUploader?: JumboChunkUploader;\n private readonly jumboChunkCheckpointStore: JumboChunkCheckpointStore;\n private readonly jumboPartSize: number;\n private readonly downloader: MountraDownloader;\n\n constructor(options: MountraClientOptions) {\n this.baseUrl = normalizeBaseUrl(options.baseUrl);\n this.apiPrefix = normalizeApiPrefix(options.apiPrefix ?? \"/api\");\n this.clientSelector = {\n workspaceCuid: options.workspaceCuid,\n workspaceId: options.workspaceId,\n };\n this.token = options.token;\n this.headers = options.headers;\n this.jumboChunkUploader = options.jumboChunkUploader;\n this.jumboChunkCheckpointStore =\n options.jumboChunkCheckpointStore ?? new LocalStorageJumboChunkCheckpointStore();\n this.jumboPartSize = options.jumboPartSize ?? DEFAULT_S3_MULTIPART_PART_SIZE_BYTES;\n assertMultipartPartSize(this.jumboPartSize);\n\n const fetchImpl = options.fetch ?? globalThis.fetch?.bind(globalThis);\n if (!fetchImpl) {\n throw new Error(\"fetch is not available; provide fetch in MountraClientOptions\");\n }\n this.fetchImpl = fetchImpl;\n this.downloader = new MountraDownloader({\n baseUrl: this.baseUrl,\n clientSelector: this.clientSelector,\n fetchImpl: this.fetchImpl,\n checkpointStore: options.downloadCheckpointStore ?? new IndexedDBDownloadCheckpointStore(),\n cache: options.downloadCache ? new DownloadCache(options.downloadCache) : null,\n requestJson: (path, body, signal) => this.requestJson(path, body, signal),\n });\n }\n\n async exportFile(options: ExportFileOptions): Promise<ExportFileResponse> {\n return this.downloader.exportFile(options);\n }\n\n async downloadFile(options: DownloadFileOptions): Promise<DownloadResult> {\n return this.downloader.downloadFile(options);\n }\n\n async downloadExport(\n exported: ExportFileResponse,\n options?: DownloadFileOptions,\n ): Promise<DownloadResult> {\n return this.downloader.downloadExport(exported, options);\n }\n\n async resumeDownload(\n downloadKey: string,\n options?: DownloadResumeOptions,\n ): Promise<DownloadResult> {\n return this.downloader.resumeDownload(downloadKey, options);\n }\n\n listResumableDownloads(): Promise<DownloadCheckpoint[]> {\n return this.downloader.listResumableDownloads();\n }\n\n clearDownloadCheckpoint(downloadKey: string): Promise<void> {\n return this.downloader.clearDownloadCheckpoint(downloadKey);\n }\n\n /** Clear the download cache of one workspace, or of every workspace when none is given. */\n clearDownloadCache(selector?: WorkspaceSelector): Promise<void> {\n return this.downloader.clearCache(selector);\n }\n\n getDownloadCacheUsage(selector?: WorkspaceSelector): Promise<DownloadCacheUsage> {\n return this.downloader.cacheUsage(selector);\n }\n\n /** Create a stable resource object for one file in this or another workspace. */\n file(locator: MountraFileLocator): MountraFile {\n return new MountraFile(\n this,\n normalizeMountraFileLocator(locator, this.clientSelector),\n );\n }\n\n async prepareUpload(file: Blob, options: UploadFileOptions): Promise<PreparedUpload> {\n const chunks = splitFileIntoChunks(file, options.chunkCount ?? 1);\n const chunkHashes = await Promise.all(chunks.map((chunk) => sha256Hex(chunk.blob)));\n const contentHash = await sha256Hex(file);\n const chunkMethod: ChunkMethod = chunks.length === 1 ? \"none\" : \"fix\";\n const contentType = options.contentType ?? (\"type\" in file ? file.type : undefined);\n\n throwIfAborted(options.signal);\n const response = ensurePrepareResponse(\n await this.requestJson(\"/upload/prepare\", {\n ...getWorkspaceBody(this.clientSelector, options),\n path: options.path,\n size: file.size,\n content_hash: contentHash,\n chunks: chunks.map((chunk, index) => ({\n chunk_index: chunk.index,\n size: chunk.size,\n sha256: chunkHashes[index]!,\n })),\n chunk_method: chunkMethod,\n ...(contentType ? { content_type: contentType } : {}),\n ...(options.nameConflictStrategy\n ? { name_conflict_strategy: options.nameConflictStrategy }\n : {}),\n }, options.signal),\n );\n\n const context: UploadSessionContext = {\n uploadId: response.upload_id,\n path: response.path,\n fileSize: file.size,\n contentHash,\n chunkMethod: response.chunk_method,\n chunks: chunks.map((chunk, index) => ({\n index: chunk.index,\n offset: chunk.offset,\n size: chunk.size,\n sha256: chunkHashes[index]!,\n })),\n ...(contentType ? { contentType } : {}),\n };\n await options.onSessionPrepared?.(context);\n\n return { response, chunks, chunkHashes, contentHash, context };\n }\n\n async uploadFile(file: Blob, options: UploadFileOptions): Promise<UploadResult> {\n const prepared = await this.prepareUpload(file, options);\n return this.uploadPreparedChunks(file, prepared.context, prepared.chunks, prepared.response.upload_targets, options);\n }\n\n /** Generic upload entry point. It selects PUT or S3 Multipart per chunk. */\n async upload(file: Blob, options: UploadFileOptions): Promise<UploadResult> {\n return this.uploadFile(file, options);\n }\n\n async getUploadStatus(\n uploadId: string,\n selector: WorkspaceSelector = {},\n signal?: AbortSignal,\n ): Promise<UploadStatusResponse> {\n if (!uploadId.trim()) {\n throw new TypeError(\"uploadId is required\");\n }\n return ensureUploadStatusResponse(\n await this.requestJson(\"/upload/status\", {\n ...getWorkspaceBody(this.clientSelector, selector),\n upload_id: uploadId,\n }, signal),\n );\n }\n\n /**\n * Resume a previously prepared session. The caller must restore the same\n * file/blob separately; this context only describes how that file was cut.\n */\n async resumeUpload(\n file: Blob,\n context: UploadSessionContext,\n options: UploadResumeOptions = {},\n ): Promise<UploadResult> {\n this.assertUploadContext(context, file);\n const actualChunkHashes = await Promise.all(\n context.chunks.map((chunk) => sha256Hex(file.slice(chunk.offset, chunk.offset + chunk.size))),\n );\n if (\n actualChunkHashes.some(\n (hash, index) => hash !== context.chunks[index]?.sha256,\n ) ||\n (await sha256Hex(file)) !== context.contentHash\n ) {\n throw new Error(\"The restored file does not match the upload context hashes\");\n }\n const chunks = context.chunks.map((chunk) => ({\n index: chunk.index,\n offset: chunk.offset,\n size: chunk.size,\n blob: file.slice(chunk.offset, chunk.offset + chunk.size),\n }));\n const status = await this.getUploadStatus(context.uploadId, options, options.signal);\n if (status.upload_id !== context.uploadId || status.size !== context.fileSize) {\n throw new Error(\"Mountra upload status does not match the saved upload context\");\n }\n if (status.chunks.length !== context.chunks.length) {\n throw new Error(\"Mountra upload status has a different chunk layout\");\n }\n for (const [index, chunk] of status.chunks.entries()) {\n const savedChunk = context.chunks[index]!;\n if (\n chunk.chunk_index !== savedChunk.index ||\n chunk.offset !== savedChunk.offset ||\n chunk.size !== savedChunk.size ||\n chunk.sha256 !== savedChunk.sha256\n ) {\n throw new Error(\"Mountra upload status has a different chunk layout\");\n }\n }\n\n return this.uploadPreparedChunks(file, context, chunks, status.chunks, options);\n }\n\n private async uploadPreparedChunks(\n file: Blob,\n context: UploadSessionContext,\n chunks: FileChunk[],\n targets: Array<UploadTarget | UploadStatusChunk>,\n options: UploadFileOptions | UploadResumeOptions,\n ): Promise<UploadResult> {\n const orderedTargets = [...targets].sort((left, right) => left.chunk_index - right.chunk_index);\n if (orderedTargets.length !== chunks.length) {\n throw new Error(\n `Mountra returned ${orderedTargets.length} upload targets for ${chunks.length} chunks`,\n );\n }\n\n let uploadedBytes = 0;\n let uploadedChunks = 0;\n const jumboCheckpointKeys = new Set<string>();\n for (const [position, target] of orderedTargets.entries()) {\n const chunk = chunks[target.chunk_index];\n if (!chunk || target.chunk_index !== position) {\n throw new Error(\"Mountra upload targets must contain contiguous chunk indexes\");\n }\n throwIfAborted(options.signal);\n\n if (isJumboChunk(chunk.size)) {\n const checkpointKey = this.buildJumboCheckpointKey(context, target, options);\n jumboCheckpointKeys.add(checkpointKey);\n if (target.upload_required) {\n await this.uploadJumboChunk(\n chunk,\n target,\n context,\n checkpointKey,\n options,\n uploadedBytes,\n uploadedChunks,\n orderedTargets.length,\n );\n }\n } else if (target.upload_required) {\n if (!target.put_url) {\n throw new Error(`Mountra upload target ${target.chunk_index} has no signed URL`);\n }\n const response = await this.fetchImpl(target.put_url, {\n method: target.put_method ?? \"PUT\",\n headers: target.put_headers ?? {},\n body: chunk.blob,\n ...(options.signal ? { signal: options.signal } : {}),\n });\n if (!response.ok) {\n throw new MountraApiError(\n `Signed upload for chunk ${target.chunk_index} failed with HTTP ${response.status}`,\n { status: response.status },\n );\n }\n }\n\n uploadedBytes += chunk.size;\n uploadedChunks += 1;\n options.onProgress?.({\n phase: \"uploading\",\n uploadedBytes,\n totalBytes: file.size,\n uploadedChunks,\n totalChunks: orderedTargets.length,\n });\n }\n\n throwIfAborted(options.signal);\n options.onProgress?.({\n phase: \"finishing\",\n uploadedBytes: file.size,\n totalBytes: file.size,\n uploadedChunks: orderedTargets.length,\n totalChunks: orderedTargets.length,\n });\n const finished = ensureFinishResponse(\n await this.requestJson(\n \"/upload/finish\",\n {\n ...getWorkspaceBody(this.clientSelector, options),\n upload_id: context.uploadId,\n },\n options.signal,\n ),\n );\n if (finished.finish_status !== \"completed\") {\n throw new Error(`Mountra upload did not finish successfully: ${finished.finish_status}`);\n }\n await this.downloader.cacheUploadedFile(\n this.cacheWorkspace(options),\n {\n path: finished.path,\n ...(finished.ino !== undefined ? { ino: finished.ino } : {}),\n size: context.fileSize,\n ...(context.contentType ? { contentType: context.contentType } : {}),\n chunks: orderedTargets.map((target) => {\n const chunk = chunks[target.chunk_index]!;\n return {\n index: chunk.index,\n offset: chunk.offset,\n size: chunk.size,\n storageKey: target.storage_key,\n data: chunk.blob,\n };\n }),\n },\n options.cache,\n );\n await Promise.all(\n [...jumboCheckpointKeys].map((checkpointKey) =>\n this.jumboChunkCheckpointStore.remove(checkpointKey),\n ),\n );\n return finished;\n }\n\n private buildJumboCheckpointKey(\n context: UploadSessionContext,\n target: UploadTarget | UploadStatusChunk,\n selector: WorkspaceSelector,\n ): string {\n const workspaceCuid = selector.workspaceCuid ?? this.clientSelector.workspaceCuid ?? \"\";\n const workspaceId = selector.workspaceId ?? this.clientSelector.workspaceId ?? \"\";\n return encodeURIComponent(\n [\n this.baseUrl,\n workspaceCuid,\n workspaceId,\n target.storage_key,\n target.chunk_index,\n context.chunks[target.chunk_index]?.sha256 ?? \"\",\n ].join(\"|\"),\n );\n }\n\n private async uploadJumboChunk(\n chunk: FileChunk,\n target: UploadTarget | UploadStatusChunk,\n context: UploadSessionContext,\n checkpointKey: string,\n options: UploadFileOptions | UploadResumeOptions,\n baseUploadedBytes: number,\n uploadedChunks: number,\n totalChunks: number,\n ): Promise<void> {\n const uploader = this.jumboChunkUploader;\n if (!uploader) {\n throw new Error(\n `Chunk ${target.chunk_index} is larger than 128 MiB; configure jumboChunkUploader to use S3 Multipart uploads`,\n );\n }\n\n const totalParts = Math.ceil(chunk.size / this.jumboPartSize);\n if (totalParts > MAX_S3_MULTIPART_PARTS) {\n throw new RangeError(\n `Jumbo chunk requires ${totalParts} parts, exceeding S3's ${MAX_S3_MULTIPART_PARTS}-part limit`,\n );\n }\n\n let checkpoint = await this.jumboChunkCheckpointStore.load(checkpointKey);\n if (\n checkpoint &&\n !this.isCompatibleJumboCheckpoint(checkpoint, chunk, target, context)\n ) {\n await this.jumboChunkCheckpointStore.remove(checkpointKey);\n checkpoint = null;\n }\n\n if (!checkpoint) {\n const created = await uploader.createMultipartUpload({\n storageKey: target.storage_key,\n contentType: context.contentType,\n signal: options.signal,\n });\n if (!created.uploadId.trim()) {\n throw new Error(`S3 Multipart create returned no upload id for chunk ${target.chunk_index}`);\n }\n checkpoint = {\n version: 1,\n storageKey: target.storage_key,\n chunkIndex: target.chunk_index,\n chunkSize: chunk.size,\n chunkSha256: context.chunks[target.chunk_index]?.sha256 ?? \"\",\n partSize: this.jumboPartSize,\n uploadId: created.uploadId,\n completed: false,\n completing: false,\n parts: [],\n };\n await this.jumboChunkCheckpointStore.save(checkpointKey, checkpoint);\n }\n\n if (checkpoint.completed) {\n return;\n }\n\n if (checkpoint.completing) {\n const status = await this.getUploadStatus(context.uploadId, options, options.signal);\n const statusChunk = status.chunks.find(\n (candidate) => candidate.chunk_index === target.chunk_index,\n );\n if (statusChunk?.status === \"uploaded\") {\n checkpoint.completed = true;\n checkpoint.completing = false;\n await this.jumboChunkCheckpointStore.save(checkpointKey, checkpoint);\n return;\n }\n checkpoint.completing = false;\n await this.jumboChunkCheckpointStore.save(checkpointKey, checkpoint);\n }\n\n const parts = new Map(checkpoint.parts.map((part) => [part.partNumber, part]));\n let uploadedBytes = 0;\n let uploadedParts = 0;\n for (let partNumber = 1; partNumber <= totalParts; partNumber += 1) {\n throwIfAborted(options.signal);\n const start = (partNumber - 1) * this.jumboPartSize;\n const partBlob = chunk.blob.slice(start, Math.min(start + this.jumboPartSize, chunk.size));\n const partHash = await sha256Hex(partBlob);\n const savedPart = parts.get(partNumber);\n const part =\n savedPart &&\n savedPart.size === partBlob.size &&\n savedPart.sha256 === partHash &&\n savedPart.etag\n ? savedPart\n : await this.uploadJumboPart(\n uploader,\n target.storage_key,\n checkpoint.uploadId,\n partNumber,\n partBlob,\n partHash,\n options.signal,\n );\n parts.set(partNumber, part);\n checkpoint.parts = [...parts.values()].sort(\n (left, right) => left.partNumber - right.partNumber,\n );\n await this.jumboChunkCheckpointStore.save(checkpointKey, checkpoint);\n uploadedBytes += partBlob.size;\n uploadedParts += 1;\n options.onProgress?.({\n phase: \"uploading\",\n uploadedBytes: baseUploadedBytes + uploadedBytes,\n totalBytes: context.fileSize,\n uploadedChunks,\n totalChunks,\n uploadedParts,\n totalParts,\n });\n }\n\n checkpoint.completing = true;\n await this.jumboChunkCheckpointStore.save(checkpointKey, checkpoint);\n try {\n await uploader.completeMultipartUpload({\n storageKey: target.storage_key,\n uploadId: checkpoint.uploadId,\n parts: checkpoint.parts.map(({ partNumber, etag }) => ({ partNumber, etag })),\n signal: options.signal,\n });\n } catch (error) {\n checkpoint.completing = false;\n await this.jumboChunkCheckpointStore.save(checkpointKey, checkpoint);\n throw error;\n }\n checkpoint.completed = true;\n checkpoint.completing = false;\n await this.jumboChunkCheckpointStore.save(checkpointKey, checkpoint);\n }\n\n private async uploadJumboPart(\n uploader: JumboChunkUploader,\n storageKey: string,\n uploadId: string,\n partNumber: number,\n body: Blob,\n sha256: string,\n signal?: AbortSignal,\n ): Promise<S3MultipartPart> {\n const result = await uploader.uploadPart({\n storageKey,\n uploadId,\n partNumber,\n body,\n signal,\n });\n if (!result.etag.trim()) {\n throw new Error(`S3 Multipart upload returned no ETag for part ${partNumber}`);\n }\n return {\n partNumber,\n etag: result.etag,\n size: body.size,\n sha256,\n };\n }\n\n private isCompatibleJumboCheckpoint(\n checkpoint: JumboChunkCheckpoint,\n chunk: FileChunk,\n target: UploadTarget | UploadStatusChunk,\n context: UploadSessionContext,\n ): boolean {\n return (\n checkpoint.version === 1 &&\n checkpoint.storageKey === target.storage_key &&\n checkpoint.chunkIndex === target.chunk_index &&\n checkpoint.chunkSize === chunk.size &&\n checkpoint.chunkSha256 === (context.chunks[target.chunk_index]?.sha256 ?? \"\") &&\n checkpoint.partSize === this.jumboPartSize &&\n checkpoint.uploadId.trim().length > 0\n );\n }\n\n private assertUploadContext(context: UploadSessionContext, file: Blob): void {\n if (!context.uploadId.trim()) {\n throw new TypeError(\"upload context uploadId is required\");\n }\n if (context.fileSize !== file.size) {\n throw new Error(\"The restored file does not match the upload context size\");\n }\n if (!Array.isArray(context.chunks) || context.chunks.length === 0) {\n throw new TypeError(\"upload context must contain chunks\");\n }\n let expectedOffset = 0;\n for (const [index, chunk] of context.chunks.entries()) {\n if (\n chunk.index !== index ||\n chunk.offset !== expectedOffset ||\n chunk.offset < 0 ||\n chunk.size < 0 ||\n chunk.offset + chunk.size > file.size ||\n typeof chunk.sha256 !== \"string\"\n ) {\n throw new TypeError(\"upload context contains an invalid chunk layout\");\n }\n expectedOffset += chunk.size;\n }\n }\n\n async finishUpload(uploadId: string, selector: WorkspaceSelector = {}): Promise<UploadResult> {\n if (!uploadId.trim()) {\n throw new TypeError(\"uploadId is required\");\n }\n const finished = ensureFinishResponse(\n await this.requestJson(\"/upload/finish\", {\n ...getWorkspaceBody(this.clientSelector, selector),\n upload_id: uploadId,\n }),\n );\n if (finished.finish_status === \"completed\") {\n // The file's bytes are not available here, so its stale entry can only be dropped.\n await this.downloader.invalidateCachedFile(this.cacheWorkspace(selector), {\n path: finished.path,\n ...(finished.ino !== undefined ? { ino: finished.ino } : {}),\n });\n }\n return finished;\n }\n\n /** Same workspace resolution as `getWorkspaceBody`, so the cache key matches what Mountra used. */\n private cacheWorkspace(selector: WorkspaceSelector): WorkspaceSelector {\n return {\n workspaceCuid: selector.workspaceCuid ?? this.clientSelector.workspaceCuid,\n workspaceId: selector.workspaceId ?? this.clientSelector.workspaceId,\n };\n }\n\n private endpoint(path: string): string {\n return `${this.baseUrl}${this.apiPrefix}${path}`;\n }\n\n private async requestJson(path: string, body: unknown, signal?: AbortSignal): Promise<unknown> {\n const headers = new Headers(this.headers);\n headers.set(\"Content-Type\", \"application/json\");\n const token = typeof this.token === \"function\" ? await this.token() : this.token;\n if (token) {\n headers.set(\"Authorization\", `Bearer ${token}`);\n }\n\n const response = await this.fetchImpl(this.endpoint(path), {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n ...(signal ? { signal } : {}),\n });\n let responseBody: unknown;\n try {\n responseBody = await response.json();\n } catch {\n responseBody = undefined;\n }\n if (!response.ok) {\n const error = parseApiErrorBody(responseBody);\n throw new MountraApiError(\n error.message ?? `Mountra API request failed with HTTP ${response.status}`,\n { status: response.status, code: error.code, body: responseBody },\n );\n }\n return responseBody;\n }\n}\n\nexport function createMountraClient(options: MountraClientOptions): MountraClient {\n return new MountraClient(options);\n}\n"],"mappings":"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","names":["checkpoint","getIndexedDb","isRecord","throwIfAborted"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/file.ts","../src/idb.ts","../src/cache.ts","../src/download.ts","../src/errors.ts","../src/metadata.ts","../src/metadata-cache.ts","../src/upload.ts"],"sourcesContent":["export {\n DEFAULT_S3_MULTIPART_PART_SIZE_BYTES,\n InMemoryJumboChunkCheckpointStore,\n JUMBO_CHUNK_THRESHOLD_BYTES,\n LocalStorageJumboChunkCheckpointStore,\n MAX_S3_MULTIPART_PARTS,\n MIN_S3_MULTIPART_PART_SIZE_BYTES,\n MountraClient,\n S3MultipartUploader,\n createMountraClient,\n isJumboChunk,\n sha256Hex,\n splitFileIntoChunks,\n} from \"./upload\";\nexport {\n DownloadHttpError,\n InMemoryDownloadCheckpointStore,\n IndexedDBDownloadCheckpointStore,\n MountraDownloader,\n} from \"./download\";\nexport { MountraApiError } from \"./errors\";\nexport { MountraFile } from \"./file\";\nexport { InMemoryDownloadCacheStore, IndexedDBDownloadCacheStore } from \"./cache\";\nexport { InMemoryMetadataCacheStore, IndexedDBMetadataCacheStore } from \"./metadata-cache\";\nexport type {\n IndexedDBMetadataCacheStoreOptions,\n MetadataCacheBatch,\n MetadataCacheKind,\n MetadataCacheOptions,\n MetadataCacheRecord,\n MetadataCacheStore,\n MetadataListRecord,\n MetadataTreeRecord,\n} from \"./metadata-cache\";\nexport type {\n CopyOptions,\n DeleteOptions,\n FileOperationResult,\n ListOptions,\n ListResult,\n MetadataReadMode,\n MetadataReadOptions,\n MetadataSource,\n MkdirOptions,\n MountraFileEntry,\n MountraFileTreeNode,\n MoveOptions,\n RenameOptions,\n TreeOptions,\n TreeResult,\n} from \"./metadata\";\nexport type {\n DownloadCacheChunk,\n DownloadCacheFile,\n DownloadCacheMode,\n DownloadCacheOptions,\n DownloadCacheStore,\n DownloadCacheUsage,\n IndexedDBDownloadCacheStoreOptions,\n} from \"./cache\";\nexport type {\n AccessToken,\n ChunkMethod,\n FileChunk,\n FinishUploadResponse,\n JumboChunkCheckpoint,\n JumboChunkCheckpointStore,\n JumboChunkCompleteInput,\n JumboChunkCreateInput,\n JumboChunkUploadPartInput,\n JumboChunkUploader,\n MountraClientOptions,\n MountraProgress,\n PrepareUploadResponse,\n PreparedUpload,\n S3MultipartClient,\n S3MultipartPart,\n UploadResumeOptions,\n UploadSessionChunkContext,\n UploadSessionContext,\n UploadStatusChunk,\n UploadStatusResponse,\n UploadFileOptions,\n UploadResult,\n UploadTarget,\n WorkspaceId,\n WorkspaceSelector,\n} from \"./upload\";\nexport type {\n DownloadCheckpoint,\n DownloadCheckpointChunk,\n DownloadCheckpointRequest,\n DownloadCheckpointStore,\n DownloadFileOptions,\n DownloadProgress,\n DownloadResult,\n DownloadResumeOptions,\n ExportFileChunk,\n ExportFileOptions,\n ExportFileResponse,\n FileSystemFileHandleLike,\n FileSystemWritableFileStreamLike,\n} from \"./download\";\nexport type {\n MountraFileDownloadOptions,\n MountraFileExportOptions,\n MountraFileLocator,\n MountraFileResumeOptions,\n NormalizedMountraFileLocator,\n} from \"./file\";\n\nexport { MountraClient as MountraSDK } from \"./upload\";\n","import type {\n DownloadFileOptions,\n DownloadResult,\n DownloadResumeOptions,\n ExportFileOptions,\n ExportFileResponse,\n} from \"./download\";\nimport type { MountraClient, WorkspaceId, WorkspaceSelector } from \"./upload\";\n\ntype MountraFileTarget =\n | {\n path: string;\n ino?: never;\n }\n | {\n path?: never;\n ino: number | string;\n };\n\n/** A file identity accepted by `MountraClient.file()`. */\nexport type MountraFileLocator = WorkspaceSelector &\n Partial<{ wsid: WorkspaceId }> &\n MountraFileTarget;\n\nexport type NormalizedMountraFileLocator = WorkspaceSelector & MountraFileTarget;\n\n/** Options for exporting an already identified Mountra file. */\nexport type MountraFileExportOptions = Omit<\n ExportFileOptions,\n \"workspaceCuid\" | \"workspaceId\" | \"path\" | \"ino\"\n>;\n\n/** Options for downloading an already identified Mountra file. */\nexport type MountraFileDownloadOptions = Omit<\n DownloadFileOptions,\n \"workspaceCuid\" | \"workspaceId\" | \"path\" | \"ino\"\n>;\n\nexport interface MountraFileResumeOptions extends DownloadResumeOptions {\n /** Select a particular checkpoint; otherwise the newest matching one is used. */\n downloadKey?: string;\n}\n\n/**\n * Normalize a file locator and fill its workspace from the client when the\n * caller uses a client-scoped workspace.\n */\nexport function normalizeMountraFileLocator(\n locator: MountraFileLocator,\n fallbackWorkspace: WorkspaceSelector = {},\n): NormalizedMountraFileLocator {\n if (!locator || typeof locator !== \"object\") {\n throw new TypeError(\"Mountra file locator is required\");\n }\n\n const hasPath = locator.path !== undefined;\n const hasIno = locator.ino !== undefined;\n if (hasPath === hasIno) {\n throw new TypeError(\"Mountra file locator requires exactly one of path or ino\");\n }\n\n const workspaceId = locator.workspaceId ?? locator.wsid ?? fallbackWorkspace.workspaceId;\n if (\n locator.workspaceId !== undefined &&\n locator.wsid !== undefined &&\n String(locator.workspaceId) !== String(locator.wsid)\n ) {\n throw new TypeError(\"workspaceId and wsid must identify the same workspace\");\n }\n\n const workspaceCuid = locator.workspaceCuid ?? fallbackWorkspace.workspaceCuid;\n if (workspaceCuid === undefined && workspaceId === undefined) {\n throw new TypeError(\"workspaceCuid, workspaceId, or wsid is required\");\n }\n\n if (hasPath) {\n const path = normalizePath(locator.path!);\n return {\n ...(workspaceCuid !== undefined ? { workspaceCuid } : {}),\n ...(workspaceId !== undefined ? { workspaceId } : {}),\n path,\n };\n }\n\n return {\n ...(workspaceCuid !== undefined ? { workspaceCuid } : {}),\n ...(workspaceId !== undefined ? { workspaceId } : {}),\n ino: normalizeIno(locator.ino!),\n };\n}\n\n/** A stable resource object for one file in one Mountra workspace. */\nexport class MountraFile {\n readonly locator: Readonly<NormalizedMountraFileLocator>;\n\n constructor(\n private readonly client: MountraClient,\n locator: NormalizedMountraFileLocator,\n ) {\n this.locator = Object.freeze({ ...locator });\n }\n\n get workspaceCuid(): string | undefined {\n return this.locator.workspaceCuid;\n }\n\n get workspaceId(): WorkspaceId | undefined {\n return this.locator.workspaceId;\n }\n\n /** `wsid` is the short alias used by the file-object API. */\n get wsid(): WorkspaceId | undefined {\n return this.locator.workspaceId;\n }\n\n get path(): string | undefined {\n return \"path\" in this.locator ? this.locator.path : undefined;\n }\n\n get ino(): number | string | undefined {\n return \"ino\" in this.locator ? this.locator.ino : undefined;\n }\n\n export(options: MountraFileExportOptions = {}): Promise<ExportFileResponse> {\n return this.client.exportFile({ ...options, ...this.locator });\n }\n\n download(options: MountraFileDownloadOptions = {}): Promise<DownloadResult> {\n return this.client.downloadFile({ ...options, ...this.locator });\n }\n\n async resume(options: MountraFileResumeOptions = {}): Promise<DownloadResult> {\n const { downloadKey, ...resumeOptions } = options;\n const checkpoints = await this.client.listResumableDownloads();\n const candidates = checkpoints.filter(\n (checkpoint) => checkpoint.fileHandle && matchesLocator(checkpoint.request, this.locator),\n );\n const checkpoint = downloadKey\n ? candidates.find((candidate) => candidate.key === downloadKey)\n : [...candidates].sort((left, right) => right.updatedAt - left.updatedAt)[0];\n\n if (!checkpoint) {\n if (downloadKey) {\n throw new Error(\"Download checkpoint does not belong to this Mountra file\");\n }\n throw new Error(\"No resumable download was found for this Mountra file\");\n }\n\n return this.client.resumeDownload(checkpoint.key, resumeOptions);\n }\n}\n\nfunction matchesLocator(\n request: {\n workspaceCuid?: string;\n workspaceId?: number | string;\n path?: string;\n ino?: number | string;\n },\n locator: NormalizedMountraFileLocator,\n): boolean {\n if (\n locator.workspaceCuid !== undefined &&\n request.workspaceCuid !== locator.workspaceCuid\n ) {\n return false;\n }\n if (\n locator.workspaceId !== undefined &&\n String(request.workspaceId) !== String(locator.workspaceId)\n ) {\n return false;\n }\n if (\"path\" in locator) {\n if (request.path === undefined || request.ino !== undefined) {\n return false;\n }\n try {\n return normalizePath(request.path) === locator.path;\n } catch {\n return false;\n }\n }\n return String(request.ino) === String(locator.ino) && request.path === undefined;\n}\n\n/** Whether `path` is `ancestor` or below it. Both must be normalized. */\nexport function isPathWithin(path: string, ancestor: string): boolean {\n return ancestor === \"/\" || path === ancestor || path.startsWith(`${ancestor}/`);\n}\n\nexport function normalizePath(value: string): string {\n if (!value || !value.trim()) {\n throw new TypeError(\"Mountra file path cannot be empty\");\n }\n\n const raw = value.trim();\n const absolute = raw.startsWith(\"/\") ? raw : `/${raw}`;\n const segments = absolute\n .split(\"/\")\n .filter((segment) => segment.length > 0 && segment !== \".\");\n const stack: string[] = [];\n for (const segment of segments) {\n if (segment === \"..\") {\n stack.pop();\n continue;\n }\n stack.push(segment);\n }\n return stack.length === 0 ? \"/\" : `/${stack.join(\"/\")}`;\n}\n\nfunction normalizeIno(value: number | string): number | string {\n if (typeof value === \"number\") {\n if (!Number.isSafeInteger(value) || value < 0) {\n throw new TypeError(\"Mountra file ino must be a non-negative safe integer\");\n }\n return value;\n }\n if (!/^\\d+$/.test(value)) {\n throw new TypeError(\"Mountra file ino must be a non-negative integer string\");\n }\n return value;\n}\n","/** IndexedDB helpers shared by the SDK's cache stores. */\n\nexport function getIndexedDb(): IDBFactory | null {\n return (globalThis as typeof globalThis & { indexedDB?: IDBFactory }).indexedDB ?? null;\n}\n\nexport function requestResult<T>(request: IDBRequest<T>): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => reject(request.error ?? new Error(\"IndexedDB request failed\"));\n });\n}\n\n/**\n * Run `body` inside one transaction. `body` may only await IndexedDB requests\n * of this transaction; awaiting anything else lets the transaction commit early.\n */\nexport async function runTransaction<T>(\n database: IDBDatabase,\n storeNames: string[],\n mode: IDBTransactionMode,\n body: (transaction: IDBTransaction) => Promise<T>,\n): Promise<T> {\n const transaction = database.transaction(storeNames, mode);\n const done = new Promise<void>((resolve, reject) => {\n transaction.oncomplete = () => resolve();\n transaction.onerror = () => reject(transaction.error ?? new Error(\"IndexedDB transaction failed\"));\n transaction.onabort = () => reject(transaction.error ?? new Error(\"IndexedDB transaction aborted\"));\n });\n done.catch(() => undefined);\n let result: T;\n try {\n result = await body(transaction);\n } catch (error) {\n try {\n transaction.abort();\n } catch {\n // The transaction has already finished.\n }\n throw error;\n }\n await done;\n return result;\n}\n\n/** All keys `[workspace, ...]`: arrays sort after strings, so `[workspace, []]` bounds every string key. */\nexport function workspaceRange(workspace: string): IDBKeyRange {\n return IDBKeyRange.bound([workspace], [workspace, []]);\n}\n\n/** A counter rather than a timestamp, so writes within one millisecond still have an order. */\nconst CLOCK_KEY = \"clock\";\n\nexport async function nextClock(meta: IDBObjectStore): Promise<number> {\n const clock = ((await requestResult<number | undefined>(meta.get(CLOCK_KEY))) ?? 0) + 1;\n await requestResult(meta.put(clock, CLOCK_KEY));\n return clock;\n}\n\n/**\n * Open a database, or resolve `null` when IndexedDB is unavailable or blocked.\n * `onClose` runs when a newer SDK in another tab upgrades the schema, after\n * the connection is closed so that upgrade can proceed.\n */\nexport function openDatabase(\n name: string,\n version: number,\n upgrade: (database: IDBDatabase) => void,\n onClose: () => void,\n): Promise<IDBDatabase | null> {\n const indexedDb = getIndexedDb();\n if (!indexedDb) {\n return Promise.resolve(null);\n }\n return new Promise<IDBDatabase | null>((resolve) => {\n let request: IDBOpenDBRequest;\n try {\n request = indexedDb.open(name, version);\n } catch {\n resolve(null);\n return;\n }\n request.onupgradeneeded = () => upgrade(request.result);\n request.onsuccess = () => {\n const database = request.result;\n database.onversionchange = () => {\n database.close();\n onClose();\n };\n resolve(database);\n };\n request.onerror = () => resolve(null);\n request.onblocked = () => resolve(null);\n });\n}\n","import { isPathWithin, normalizePath } from \"./file\";\nimport { nextClock, openDatabase, requestResult, runTransaction, workspaceRange } from \"./idb\";\nimport type { WorkspaceSelector } from \"./upload\";\n\nconst DEFAULT_MAX_BYTES = 512 * 1024 * 1024;\nconst DEFAULT_MAX_CHUNK_BYTES = 128 * 1024 * 1024;\nconst DEFAULT_TTL_MS = 5 * 60 * 1000;\n\n/**\n * Per-download cache behavior, modelled on `RequestInit.cache`:\n * - `default`: serve a fresh cached file without contacting Mountra; otherwise\n * export it and reuse any cached chunks.\n * - `no-cache`: always export first, but still reuse cached chunks.\n * - `no-store`: neither read from nor write to the cache.\n */\nexport type DownloadCacheMode = \"default\" | \"no-cache\" | \"no-store\";\n\nexport interface DownloadCacheOptions {\n /** Upper bound of cached chunk bytes, shared by all workspaces. Defaults to 512 MiB. */\n maxBytes?: number;\n /**\n * Chunks larger than this are never cached, because a downloaded chunk is\n * buffered in memory before it is stored. Defaults to 128 MiB and never\n * exceeds `maxBytes`.\n */\n maxChunkBytes?: number;\n /**\n * How long a downloaded file may be served from the cache without asking\n * Mountra whether it changed. Defaults to 5 minutes; 0 always revalidates.\n */\n ttlMs?: number;\n /** Cache storage. Defaults to IndexedDB, or memory when IndexedDB is unavailable. */\n store?: DownloadCacheStore;\n}\n\nexport interface DownloadCacheChunk {\n index: number;\n offset: number;\n size: number;\n storageKey: string;\n}\n\n/** The chunk layout of one file. Signed URLs are never cached. */\nexport interface DownloadCacheFile {\n path: string;\n size: number;\n contentType?: string;\n chunks: DownloadCacheChunk[];\n /** When Mountra last confirmed this layout. */\n cachedAt: number;\n /** After this time the layout must be confirmed by Mountra again. */\n expiresAt: number;\n}\n\nexport interface DownloadCacheUsage {\n bytes: number;\n chunks: number;\n}\n\n/**\n * Storage behind the download cache. Every entry is scoped by an opaque\n * workspace key, so one workspace never observes another workspace's entries.\n */\nexport interface DownloadCacheStore {\n getFile(workspace: string, fileKey: string): Promise<DownloadCacheFile | null>;\n putFile(workspace: string, fileKey: string, file: DownloadCacheFile): Promise<void>;\n removeFile(workspace: string, fileKey: string): Promise<void>;\n /**\n * Remove every file whose `path` is `path` or below it, keeping the chunks.\n * Optional: without it, a move or delete through the client clears the\n * whole workspace instead.\n */\n removeFilesUnder?(workspace: string, path: string): Promise<void>;\n /** Return the chunk bytes and mark the chunk as most recently used. */\n getChunk(workspace: string, storageKey: string): Promise<Blob | null>;\n /** Store the chunk bytes, then evict least recently used chunks until at most `maxBytes` remain. */\n putChunk(workspace: string, storageKey: string, data: Blob, maxBytes: number): Promise<void>;\n /** Remove every entry, or only the entries of one workspace. */\n clear(workspace?: string): Promise<void>;\n usage(workspace?: string): Promise<DownloadCacheUsage>;\n}\n\nfunction copyFile(file: DownloadCacheFile): DownloadCacheFile {\n return { ...file, chunks: file.chunks.map((chunk) => ({ ...chunk })) };\n}\n\nfunction memoryKey(workspace: string, key: string): string {\n return JSON.stringify([workspace, key]);\n}\n\nexport class InMemoryDownloadCacheStore implements DownloadCacheStore {\n private readonly files = new Map<string, { workspace: string; file: DownloadCacheFile }>();\n /** Map iteration order is the LRU order: the first entry is the least recently used. */\n private readonly chunks = new Map<string, { workspace: string; data: Blob }>();\n private bytes = 0;\n\n async getFile(workspace: string, fileKey: string): Promise<DownloadCacheFile | null> {\n const entry = this.files.get(memoryKey(workspace, fileKey));\n return entry ? copyFile(entry.file) : null;\n }\n\n async putFile(workspace: string, fileKey: string, file: DownloadCacheFile): Promise<void> {\n this.files.set(memoryKey(workspace, fileKey), { workspace, file: copyFile(file) });\n }\n\n async removeFile(workspace: string, fileKey: string): Promise<void> {\n this.files.delete(memoryKey(workspace, fileKey));\n }\n\n async removeFilesUnder(workspace: string, path: string): Promise<void> {\n for (const [key, entry] of this.files) {\n if (entry.workspace === workspace && isPathWithin(entry.file.path, path)) {\n this.files.delete(key);\n }\n }\n }\n\n async getChunk(workspace: string, storageKey: string): Promise<Blob | null> {\n const key = memoryKey(workspace, storageKey);\n const entry = this.chunks.get(key);\n if (!entry) {\n return null;\n }\n this.chunks.delete(key);\n this.chunks.set(key, entry);\n return entry.data;\n }\n\n async putChunk(workspace: string, storageKey: string, data: Blob, maxBytes: number): Promise<void> {\n const key = memoryKey(workspace, storageKey);\n this.removeChunk(key);\n if (data.size > maxBytes) {\n return;\n }\n this.chunks.set(key, { workspace, data });\n this.bytes += data.size;\n for (const candidate of this.chunks.keys()) {\n if (this.bytes <= maxBytes) {\n break;\n }\n this.removeChunk(candidate);\n }\n }\n\n async clear(workspace?: string): Promise<void> {\n for (const [key, entry] of this.chunks) {\n if (workspace === undefined || entry.workspace === workspace) {\n this.removeChunk(key);\n }\n }\n for (const [key, entry] of this.files) {\n if (workspace === undefined || entry.workspace === workspace) {\n this.files.delete(key);\n }\n }\n }\n\n async usage(workspace?: string): Promise<DownloadCacheUsage> {\n const usage = { bytes: 0, chunks: 0 };\n for (const entry of this.chunks.values()) {\n if (workspace === undefined || entry.workspace === workspace) {\n usage.bytes += entry.data.size;\n usage.chunks += 1;\n }\n }\n return usage;\n }\n\n private removeChunk(key: string): void {\n const entry = this.chunks.get(key);\n if (entry) {\n this.chunks.delete(key);\n this.bytes -= entry.data.size;\n }\n }\n}\n\nconst CACHE_DATABASE_NAME = \"mountra-sdk-download-cache\";\nconst CACHE_DATABASE_VERSION = 1;\nconst FILES_STORE = \"files\";\n/** Small LRU records, kept apart from the bytes so touching a chunk never rewrites its Blob. */\nconst CHUNKS_STORE = \"chunks\";\nconst CHUNK_DATA_STORE = \"chunk-data\";\nconst META_STORE = \"meta\";\nconst LRU_INDEX = \"lastUsed\";\nconst USAGE_KEY = \"bytes\";\n\ninterface ChunkRecord {\n size: number;\n lastUsed: number;\n}\n\ntype CacheKey = [workspace: string, key: string];\n\nfunction sameKey(left: IDBValidKey, right: CacheKey): boolean {\n return Array.isArray(left) && left[0] === right[0] && left[1] === right[1];\n}\n\nexport interface IndexedDBDownloadCacheStoreOptions {\n /** Use a separate database, for example one per signed-in user. */\n databaseName?: string;\n}\n\nexport class IndexedDBDownloadCacheStore implements DownloadCacheStore {\n private readonly databaseName: string;\n private readonly fallback = new InMemoryDownloadCacheStore();\n private databasePromise?: Promise<IDBDatabase | null>;\n\n constructor(options: IndexedDBDownloadCacheStoreOptions = {}) {\n this.databaseName = options.databaseName ?? CACHE_DATABASE_NAME;\n }\n\n async getFile(workspace: string, fileKey: string): Promise<DownloadCacheFile | null> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.getFile(workspace, fileKey);\n }\n return runTransaction(database, [FILES_STORE], \"readonly\", async (transaction) => {\n const file = await requestResult<DownloadCacheFile | undefined>(\n transaction.objectStore(FILES_STORE).get([workspace, fileKey]),\n );\n return file ? copyFile(file) : null;\n });\n }\n\n async putFile(workspace: string, fileKey: string, file: DownloadCacheFile): Promise<void> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.putFile(workspace, fileKey, file);\n }\n await runTransaction(database, [FILES_STORE], \"readwrite\", async (transaction) => {\n await requestResult(transaction.objectStore(FILES_STORE).put(copyFile(file), [workspace, fileKey]));\n });\n }\n\n async removeFile(workspace: string, fileKey: string): Promise<void> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.removeFile(workspace, fileKey);\n }\n await runTransaction(database, [FILES_STORE], \"readwrite\", async (transaction) => {\n await requestResult(transaction.objectStore(FILES_STORE).delete([workspace, fileKey]));\n });\n }\n\n async removeFilesUnder(workspace: string, path: string): Promise<void> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.removeFilesUnder(workspace, path);\n }\n await runTransaction(database, [FILES_STORE], \"readwrite\", async (transaction) => {\n const cursorRequest = transaction.objectStore(FILES_STORE).openCursor(workspaceRange(workspace));\n let cursor = await requestResult(cursorRequest);\n while (cursor) {\n if (isPathWithin((cursor.value as DownloadCacheFile).path, path)) {\n await requestResult(cursor.delete());\n }\n cursor.continue();\n cursor = await requestResult(cursorRequest);\n }\n });\n }\n\n async getChunk(workspace: string, storageKey: string): Promise<Blob | null> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.getChunk(workspace, storageKey);\n }\n const key: CacheKey = [workspace, storageKey];\n return runTransaction(\n database,\n [CHUNKS_STORE, CHUNK_DATA_STORE, META_STORE],\n \"readwrite\",\n async (transaction) => {\n const chunks = transaction.objectStore(CHUNKS_STORE);\n const record = await requestResult<ChunkRecord | undefined>(chunks.get(key));\n if (!record) {\n return null;\n }\n const data = await requestResult<Blob | undefined>(\n transaction.objectStore(CHUNK_DATA_STORE).get(key),\n );\n const meta = transaction.objectStore(META_STORE);\n if (!data) {\n // Repair a record whose bytes are gone instead of reporting a hit.\n const bytes = (await requestResult<number | undefined>(meta.get(USAGE_KEY))) ?? 0;\n await requestResult(chunks.delete(key));\n await requestResult(meta.put(Math.max(bytes - record.size, 0), USAGE_KEY));\n return null;\n }\n await requestResult(chunks.put({ size: record.size, lastUsed: await nextClock(meta) }, key));\n return data;\n },\n );\n }\n\n async putChunk(workspace: string, storageKey: string, data: Blob, maxBytes: number): Promise<void> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.putChunk(workspace, storageKey, data, maxBytes);\n }\n const key: CacheKey = [workspace, storageKey];\n await runTransaction(\n database,\n [CHUNKS_STORE, CHUNK_DATA_STORE, META_STORE],\n \"readwrite\",\n async (transaction) => {\n const chunks = transaction.objectStore(CHUNKS_STORE);\n const chunkData = transaction.objectStore(CHUNK_DATA_STORE);\n const meta = transaction.objectStore(META_STORE);\n let bytes = (await requestResult<number | undefined>(meta.get(USAGE_KEY))) ?? 0;\n const existing = await requestResult<ChunkRecord | undefined>(chunks.get(key));\n if (existing) {\n bytes -= existing.size;\n await requestResult(chunks.delete(key));\n await requestResult(chunkData.delete(key));\n }\n if (data.size <= maxBytes) {\n await requestResult(chunks.put({ size: data.size, lastUsed: await nextClock(meta) }, key));\n await requestResult(chunkData.put(data, key));\n bytes += data.size;\n }\n\n if (bytes > maxBytes) {\n const cursorRequest = chunks.index(LRU_INDEX).openCursor();\n let cursor = await requestResult(cursorRequest);\n while (cursor && bytes > maxBytes) {\n if (!sameKey(cursor.primaryKey, key)) {\n bytes -= (cursor.value as ChunkRecord).size;\n await requestResult(chunkData.delete(cursor.primaryKey));\n await requestResult(cursor.delete());\n }\n cursor.continue();\n cursor = await requestResult(cursorRequest);\n }\n }\n await requestResult(meta.put(Math.max(bytes, 0), USAGE_KEY));\n },\n );\n }\n\n async clear(workspace?: string): Promise<void> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.clear(workspace);\n }\n await runTransaction(\n database,\n [FILES_STORE, CHUNKS_STORE, CHUNK_DATA_STORE, META_STORE],\n \"readwrite\",\n async (transaction) => {\n const files = transaction.objectStore(FILES_STORE);\n const chunks = transaction.objectStore(CHUNKS_STORE);\n const chunkData = transaction.objectStore(CHUNK_DATA_STORE);\n const meta = transaction.objectStore(META_STORE);\n if (workspace === undefined) {\n await requestResult(files.clear());\n await requestResult(chunks.clear());\n await requestResult(chunkData.clear());\n await requestResult(meta.put(0, USAGE_KEY));\n return;\n }\n const range = workspaceRange(workspace);\n const removed = await requestResult<ChunkRecord[]>(chunks.getAll(range));\n const bytes = (await requestResult<number | undefined>(meta.get(USAGE_KEY))) ?? 0;\n await requestResult(files.delete(range));\n await requestResult(chunks.delete(range));\n await requestResult(chunkData.delete(range));\n await requestResult(\n meta.put(Math.max(bytes - removed.reduce((total, record) => total + record.size, 0), 0), USAGE_KEY),\n );\n },\n );\n }\n\n async usage(workspace?: string): Promise<DownloadCacheUsage> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.usage(workspace);\n }\n return runTransaction(database, [CHUNKS_STORE], \"readonly\", async (transaction) => {\n const records = await requestResult<ChunkRecord[]>(\n transaction\n .objectStore(CHUNKS_STORE)\n .getAll(workspace === undefined ? undefined : workspaceRange(workspace)),\n );\n return {\n bytes: records.reduce((total, record) => total + record.size, 0),\n chunks: records.length,\n };\n });\n }\n\n private async openDatabase(): Promise<IDBDatabase | null> {\n this.databasePromise ??= openDatabase(\n this.databaseName,\n CACHE_DATABASE_VERSION,\n (database) => {\n if (!database.objectStoreNames.contains(FILES_STORE)) {\n database.createObjectStore(FILES_STORE);\n }\n if (!database.objectStoreNames.contains(CHUNKS_STORE)) {\n database.createObjectStore(CHUNKS_STORE).createIndex(LRU_INDEX, \"lastUsed\");\n }\n if (!database.objectStoreNames.contains(CHUNK_DATA_STORE)) {\n database.createObjectStore(CHUNK_DATA_STORE);\n }\n if (!database.objectStoreNames.contains(META_STORE)) {\n database.createObjectStore(META_STORE);\n }\n },\n () => {\n this.databasePromise = undefined;\n },\n );\n return this.databasePromise;\n }\n}\n\n/**\n * Only content-addressed blobs (`.../blobs/sha256/<hash>`) are cached: their\n * bytes can never change. Local-first and combined export keys can.\n */\nfunction isImmutableStorageKey(storageKey: string): boolean {\n return /(?:^|\\/)blobs\\/sha256\\/[0-9a-f]{64}$/.test(storageKey);\n}\n\n/** Mirror the server: `workspace_cuid` wins over `workspace_id` when both are sent. */\nexport function workspaceCacheKey(baseUrl: string, selector: WorkspaceSelector): string | null {\n const workspaceCuid = selector.workspaceCuid?.trim();\n const workspaceId =\n selector.workspaceId !== undefined ? String(selector.workspaceId).trim() : \"\";\n const workspace = workspaceCuid || workspaceId;\n return workspace ? JSON.stringify([baseUrl, workspace]) : null;\n}\n\n/** Mirror the server: `ino` wins over `path` when both are sent. */\nexport function fileCacheKey(target: { path?: string; ino?: number | string }): string | null {\n try {\n if (target.ino !== undefined) {\n return `ino:${BigInt(target.ino).toString()}`;\n }\n if (target.path !== undefined) {\n return `path:${normalizePath(target.path)}`;\n }\n } catch {\n // Mountra rejects this target, so there is nothing to cache.\n }\n return null;\n}\n\nfunction isValidLayout(file: DownloadCacheFile): boolean {\n let offset = 0;\n for (const [index, chunk] of file.chunks.entries()) {\n if (chunk.index !== index || chunk.offset !== offset || chunk.size < 0) {\n return false;\n }\n offset += chunk.size;\n }\n return file.chunks.length > 0 && offset === file.size;\n}\n\n/** Cache policy of one client. Cache failures degrade to misses and never fail a download. */\nexport class DownloadCache {\n readonly maxBytes: number;\n readonly maxChunkBytes: number;\n readonly ttlMs: number;\n private readonly store: DownloadCacheStore;\n\n constructor(options: DownloadCacheOptions) {\n this.maxBytes = options.maxBytes ?? DEFAULT_MAX_BYTES;\n if (!Number.isSafeInteger(this.maxBytes) || this.maxBytes <= 0) {\n throw new RangeError(\"downloadCache.maxBytes must be a positive safe integer\");\n }\n const maxChunkBytes = options.maxChunkBytes ?? DEFAULT_MAX_CHUNK_BYTES;\n if (!Number.isSafeInteger(maxChunkBytes) || maxChunkBytes <= 0) {\n throw new RangeError(\"downloadCache.maxChunkBytes must be a positive safe integer\");\n }\n this.maxChunkBytes = Math.min(maxChunkBytes, this.maxBytes);\n this.ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;\n if (Number.isNaN(this.ttlMs) || this.ttlMs < 0) {\n throw new RangeError(\"downloadCache.ttlMs must be a non-negative number\");\n }\n this.store = options.store ?? new IndexedDBDownloadCacheStore();\n }\n\n /** Return a file that has not expired together with all of its chunk bytes. */\n async loadFile(\n workspace: string,\n fileKey: string,\n ): Promise<{ file: DownloadCacheFile; chunks: Map<number, Blob> } | null> {\n try {\n const file = await this.store.getFile(workspace, fileKey);\n if (!file) {\n return null;\n }\n if (file.expiresAt <= Date.now() || !isValidLayout(file)) {\n await this.store.removeFile(workspace, fileKey);\n return null;\n }\n const chunks = new Map<number, Blob>();\n for (const chunk of file.chunks) {\n const data = await this.readChunk(workspace, chunk);\n if (!data) {\n return null;\n }\n chunks.set(chunk.index, data);\n }\n return { file, chunks };\n } catch {\n return null;\n }\n }\n\n async readChunk(workspace: string, chunk: DownloadCacheChunk): Promise<Blob | null> {\n if (chunk.size === 0) {\n return new Blob([]);\n }\n if (!isImmutableStorageKey(chunk.storageKey)) {\n return null;\n }\n try {\n const data = await this.store.getChunk(workspace, chunk.storageKey);\n return data && data.size === chunk.size ? data : null;\n } catch {\n return null;\n }\n }\n\n canStoreChunk(chunk: DownloadCacheChunk): boolean {\n return isImmutableStorageKey(chunk.storageKey) && chunk.size <= this.maxChunkBytes;\n }\n\n /** Returns whether the chunk is now cached. */\n async storeChunk(workspace: string, chunk: DownloadCacheChunk, data: Blob): Promise<boolean> {\n if (chunk.size === 0) {\n return true;\n }\n if (!this.canStoreChunk(chunk) || data.size !== chunk.size) {\n return false;\n }\n try {\n await this.store.putChunk(workspace, chunk.storageKey, data, this.maxBytes);\n return true;\n } catch {\n return false;\n }\n }\n\n async storeFile(\n workspace: string,\n fileKey: string,\n file: Omit<DownloadCacheFile, \"cachedAt\" | \"expiresAt\">,\n ): Promise<void> {\n if (this.ttlMs <= 0) {\n return;\n }\n const cachedAt = Date.now();\n try {\n await this.store.putFile(workspace, fileKey, {\n path: file.path,\n size: file.size,\n ...(file.contentType ? { contentType: file.contentType } : {}),\n chunks: file.chunks.map(({ index, offset, size, storageKey }) => ({\n index,\n offset,\n size,\n storageKey,\n })),\n cachedAt,\n expiresAt: cachedAt + this.ttlMs,\n });\n } catch {\n // The download already succeeded; the next one simply exports again.\n }\n }\n\n async invalidateFiles(workspace: string, fileKeys: string[]): Promise<void> {\n await Promise.all(\n fileKeys.map((fileKey) => this.store.removeFile(workspace, fileKey).catch(() => undefined)),\n );\n }\n\n /** Drop the files at or below `paths`, which a write changed; their chunks stay cached. */\n async invalidatePaths(workspace: string, paths: string[]): Promise<void> {\n try {\n if (!this.store.removeFilesUnder) {\n await this.store.clear(workspace);\n return;\n }\n for (const path of paths) {\n await this.store.removeFilesUnder(workspace, path);\n }\n } catch {\n // A file that outlives the write must not be served from the cache.\n await this.store.clear(workspace).catch(() => undefined);\n }\n }\n\n clear(workspace?: string): Promise<void> {\n return this.store.clear(workspace);\n }\n\n usage(workspace?: string): Promise<DownloadCacheUsage> {\n return this.store.usage(workspace);\n }\n}\n","import { fileCacheKey, workspaceCacheKey } from \"./cache\";\nimport type { DownloadCache, DownloadCacheChunk, DownloadCacheMode, DownloadCacheUsage } from \"./cache\";\nimport type { WorkspaceSelector } from \"./upload\";\n\nexport interface FileSystemWritableFileStreamLike {\n write(data: Uint8Array | Blob): Promise<void>;\n seek(position: number): Promise<void>;\n truncate(size: number): Promise<void>;\n close(): Promise<void>;\n abort?(): Promise<void>;\n}\n\nexport interface FileSystemFileHandleLike {\n readonly kind?: \"file\";\n readonly name?: string;\n createWritable(options?: { keepExistingData?: boolean }): Promise<FileSystemWritableFileStreamLike>;\n isSameEntry?(other: FileSystemFileHandleLike): Promise<boolean>;\n queryPermission?(descriptor?: { mode?: \"read\" | \"readwrite\" }): Promise<PermissionState>;\n requestPermission?(descriptor?: { mode?: \"read\" | \"readwrite\" }): Promise<PermissionState>;\n}\n\nexport interface ExportFileOptions extends WorkspaceSelector {\n path?: string;\n ino?: number | string;\n timeout?: number;\n contentDisposition?: string;\n downloadFilename?: string;\n signal?: AbortSignal;\n}\n\nexport interface ExportFileChunk {\n index: number;\n offset: number;\n size: number;\n storageKey: string;\n url: string;\n}\n\nexport interface ExportFileResponse {\n path: string;\n storageKey: string;\n url: string;\n timeout: number;\n size: number;\n contentType?: string;\n chunkMethod?: string;\n isFastPath?: boolean;\n chunks?: ExportFileChunk[];\n}\n\nexport interface DownloadProgress {\n phase: \"downloading\" | \"retrying\" | \"completed\";\n downloadedBytes: number;\n totalBytes: number;\n downloadedChunks: number;\n totalChunks: number;\n currentChunkIndex?: number;\n speedBytesPerSecond: number;\n estimatedRemainingSeconds?: number;\n elapsedMs: number;\n retryCount: number;\n}\n\nexport interface DownloadFileOptions extends ExportFileOptions {\n /** Prefer File System Access API when available. Defaults to true. */\n preferFileSystemAccess?: boolean;\n /** Continue a matching IndexedDB checkpoint when the selected file is the same entry. */\n resume?: boolean;\n maxRetries?: number;\n retryDelayMs?: number;\n onProgress?: (progress: DownloadProgress) => void;\n /** Use a previously selected file handle, primarily for resumeDownload. */\n fileHandle?: FileSystemFileHandleLike;\n /** How this download uses the client's `downloadCache`. Defaults to `default`. */\n cache?: DownloadCacheMode;\n}\n\nexport interface DownloadResumeOptions {\n signal?: AbortSignal;\n maxRetries?: number;\n retryDelayMs?: number;\n onProgress?: (progress: DownloadProgress) => void;\n}\n\nexport interface DownloadResult {\n /** Absent when the file was served from the download cache without contacting Mountra. */\n export?: ExportFileResponse;\n downloadKey: string;\n downloadedBytes: number;\n /** Bytes served from the download cache instead of the network. */\n cachedBytes: number;\n resumed: boolean;\n fileHandle?: FileSystemFileHandleLike;\n blob?: Blob;\n}\n\nexport interface DownloadCheckpointChunk {\n index: number;\n offset: number;\n size: number;\n storageKey: string;\n downloadedBytes: number;\n completed: boolean;\n}\n\nexport interface DownloadCheckpointRequest {\n workspaceCuid?: string;\n workspaceId?: number | string;\n path?: string;\n ino?: number | string;\n timeout?: number;\n contentDisposition?: string;\n downloadFilename?: string;\n}\n\nexport interface DownloadCheckpoint {\n version: 1;\n key: string;\n requestKey: string;\n request: DownloadCheckpointRequest;\n path: string;\n size: number;\n chunks: DownloadCheckpointChunk[];\n fileHandle?: FileSystemFileHandleLike;\n updatedAt: number;\n}\n\nexport interface DownloadCheckpointStore {\n load(key: string): Promise<DownloadCheckpoint | null>;\n save(key: string, checkpoint: DownloadCheckpoint): Promise<void>;\n remove(key: string): Promise<void>;\n list(): Promise<DownloadCheckpoint[]>;\n}\n\nfunction copyCheckpoint(checkpoint: DownloadCheckpoint): DownloadCheckpoint {\n return {\n ...checkpoint,\n request: { ...checkpoint.request },\n chunks: checkpoint.chunks.map((chunk) => ({ ...chunk })),\n };\n}\n\nexport class InMemoryDownloadCheckpointStore implements DownloadCheckpointStore {\n private readonly records = new Map<string, DownloadCheckpoint>();\n\n async load(key: string): Promise<DownloadCheckpoint | null> {\n const value = this.records.get(key);\n return value ? copyCheckpoint(value) : null;\n }\n\n async save(key: string, checkpoint: DownloadCheckpoint): Promise<void> {\n this.records.set(key, copyCheckpoint(checkpoint));\n }\n\n async remove(key: string): Promise<void> {\n this.records.delete(key);\n }\n\n async list(): Promise<DownloadCheckpoint[]> {\n return [...this.records.values()].map(copyCheckpoint);\n }\n}\n\nconst DOWNLOAD_DATABASE_NAME = \"mountra-sdk\";\nconst DOWNLOAD_DATABASE_VERSION = 1;\nconst DOWNLOAD_STORE_NAME = \"download-checkpoints\";\n\nfunction getIndexedDb(): IDBFactory | null {\n return (globalThis as typeof globalThis & { indexedDB?: IDBFactory }).indexedDB ?? null;\n}\n\nexport class IndexedDBDownloadCheckpointStore implements DownloadCheckpointStore {\n private readonly fallback = new InMemoryDownloadCheckpointStore();\n private databasePromise?: Promise<IDBDatabase | null>;\n\n async load(key: string): Promise<DownloadCheckpoint | null> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.load(key);\n }\n try {\n const value = await this.request<DownloadCheckpoint | undefined>(\n database,\n \"readonly\",\n (store) => store.get(key),\n );\n return value ? copyCheckpoint(value) : null;\n } catch {\n return this.fallback.load(key);\n }\n }\n\n async save(key: string, checkpoint: DownloadCheckpoint): Promise<void> {\n const value = copyCheckpoint(checkpoint);\n const database = await this.openDatabase();\n if (!database) {\n await this.fallback.save(key, value);\n return;\n }\n try {\n await this.request(database, \"readwrite\", (store) => store.put(value, key));\n } catch {\n await this.fallback.save(key, value);\n }\n }\n\n async remove(key: string): Promise<void> {\n const database = await this.openDatabase();\n if (!database) {\n await this.fallback.remove(key);\n return;\n }\n try {\n await this.request(database, \"readwrite\", (store) => store.delete(key));\n } catch {\n await this.fallback.remove(key);\n }\n }\n\n async list(): Promise<DownloadCheckpoint[]> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.list();\n }\n try {\n const values = await this.request<DownloadCheckpoint[]>(\n database,\n \"readonly\",\n (store) => store.getAll(),\n );\n return values.map(copyCheckpoint);\n } catch {\n return this.fallback.list();\n }\n }\n\n private async openDatabase(): Promise<IDBDatabase | null> {\n if (!this.databasePromise) {\n const indexedDb = getIndexedDb();\n if (!indexedDb) {\n this.databasePromise = Promise.resolve(null);\n } else {\n this.databasePromise = new Promise<IDBDatabase | null>((resolve) => {\n let request: IDBOpenDBRequest;\n try {\n request = indexedDb.open(DOWNLOAD_DATABASE_NAME, DOWNLOAD_DATABASE_VERSION);\n } catch {\n resolve(null);\n return;\n }\n request.onupgradeneeded = () => {\n if (!request.result.objectStoreNames.contains(DOWNLOAD_STORE_NAME)) {\n request.result.createObjectStore(DOWNLOAD_STORE_NAME);\n }\n };\n request.onsuccess = () => resolve(request.result);\n request.onerror = () => resolve(null);\n request.onblocked = () => resolve(null);\n });\n }\n }\n return this.databasePromise;\n }\n\n private request<T = unknown>(\n database: IDBDatabase,\n mode: IDBTransactionMode,\n createRequest: (store: IDBObjectStore) => IDBRequest,\n ): Promise<T> {\n return new Promise<T>((resolve, reject) => {\n let transaction: IDBTransaction;\n let request: IDBRequest;\n try {\n transaction = database.transaction(DOWNLOAD_STORE_NAME, mode);\n request = createRequest(transaction.objectStore(DOWNLOAD_STORE_NAME));\n } catch (error) {\n reject(error);\n return;\n }\n\n let result: T;\n request.onsuccess = () => {\n result = request.result as T;\n };\n request.onerror = () => reject(request.error ?? new Error(\"IndexedDB request failed\"));\n transaction.oncomplete = () => resolve(result);\n transaction.onerror = () => reject(transaction.error ?? new Error(\"IndexedDB transaction failed\"));\n transaction.onabort = () => reject(transaction.error ?? new Error(\"IndexedDB transaction aborted\"));\n });\n }\n}\n\nexport class DownloadHttpError extends Error {\n readonly status: number;\n\n constructor(status: number, message: string) {\n super(message);\n this.name = \"DownloadHttpError\";\n this.status = status;\n }\n}\n\ninterface DownloadTransport {\n readonly baseUrl: string;\n readonly clientSelector: WorkspaceSelector;\n readonly fetchImpl: typeof globalThis.fetch;\n readonly checkpointStore: DownloadCheckpointStore;\n readonly cache: DownloadCache | null;\n requestJson(path: string, body: unknown, signal?: AbortSignal): Promise<unknown>;\n}\n\ninterface ShowSaveFilePickerOptions {\n suggestedName?: string;\n types?: Array<{\n description?: string;\n accept: Record<string, string[]>;\n }>;\n}\n\ntype ShowSaveFilePicker = (\n options?: ShowSaveFilePickerOptions,\n) => Promise<FileSystemFileHandleLike>;\n\nfunction getShowSaveFilePicker(): ShowSaveFilePicker | null {\n return (\n (globalThis as typeof globalThis & { showSaveFilePicker?: ShowSaveFilePicker })\n .showSaveFilePicker ?? null\n );\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction readSafeNumber(value: unknown, field: string): number {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 0) {\n throw new TypeError(`Mountra export response field ${field} is invalid`);\n }\n return value;\n}\n\nfunction readString(value: unknown, field: string): string {\n if (typeof value !== \"string\" || !value) {\n throw new TypeError(`Mountra export response field ${field} is invalid`);\n }\n return value;\n}\n\nfunction ensureExportFileResponse(value: unknown): ExportFileResponse {\n if (!isRecord(value)) {\n throw new TypeError(\"Mountra export response is invalid\");\n }\n const response: ExportFileResponse = {\n path: readString(value.path, \"path\"),\n storageKey: readString(value.storage_key, \"storage_key\"),\n url: readString(value.url, \"url\"),\n timeout: readSafeNumber(value.timeout, \"timeout\"),\n size: readSafeNumber(value.size, \"size\"),\n };\n try {\n new URL(response.url);\n } catch {\n throw new TypeError(\"Mountra export response field url is invalid\");\n }\n if (typeof value.content_type === \"string\" && value.content_type) {\n response.contentType = value.content_type;\n }\n if (typeof value.chunk_method === \"string\") {\n response.chunkMethod = value.chunk_method;\n }\n if (typeof value.is_fast_path === \"boolean\") {\n response.isFastPath = value.is_fast_path;\n }\n if (Array.isArray(value.chunks)) {\n response.chunks = value.chunks.map((rawChunk, position) => {\n if (!isRecord(rawChunk)) {\n throw new TypeError(`Mountra export response chunk ${position} is invalid`);\n }\n const chunk: ExportFileChunk = {\n index: readSafeNumber(rawChunk.index, `chunks[${position}].index`),\n offset: readSafeNumber(rawChunk.offset, `chunks[${position}].offset`),\n size: readSafeNumber(rawChunk.size, `chunks[${position}].size`),\n storageKey: readString(rawChunk.storage_key, `chunks[${position}].storage_key`),\n url: readString(rawChunk.url, `chunks[${position}].url`),\n };\n try {\n new URL(chunk.url);\n } catch {\n throw new TypeError(`Mountra export response chunk ${position} URL is invalid`);\n }\n return chunk;\n });\n response.chunks.sort((left, right) => left.index - right.index);\n response.chunks.forEach((chunk, index) => {\n if (\n chunk.index !== index ||\n chunk.offset + chunk.size > response.size ||\n (index > 0 && response.chunks![index - 1]!.offset + response.chunks![index - 1]!.size !== chunk.offset)\n ) {\n throw new TypeError(\"Mountra export response has an invalid chunk layout\");\n }\n });\n const finalChunk = response.chunks[response.chunks.length - 1];\n if (finalChunk && finalChunk.offset + finalChunk.size !== response.size) {\n throw new TypeError(\"Mountra export response chunks do not cover the complete file\");\n }\n }\n return response;\n}\n\nfunction validateRetryOption(value: number | undefined, name: string): number | undefined {\n if (value === undefined) {\n return undefined;\n }\n if (!Number.isSafeInteger(value) || value < 0) {\n throw new RangeError(`${name} must be a non-negative safe integer`);\n }\n return value;\n}\n\nfunction throwIfAborted(signal?: AbortSignal): void {\n if (signal?.aborted) {\n throw new DOMException(\"The download was aborted\", \"AbortError\");\n }\n}\n\nfunction isAbortError(error: unknown, signal?: AbortSignal): boolean {\n return signal?.aborted === true || (error instanceof DOMException && error.name === \"AbortError\");\n}\n\nfunction isRetryableError(error: unknown): boolean {\n if (error instanceof DownloadHttpError) {\n return [408, 425, 429, 500, 502, 503, 504].includes(error.status);\n }\n return true;\n}\n\nfunction waitForRetry(delayMs: number, signal?: AbortSignal): Promise<void> {\n if (delayMs <= 0) {\n throwIfAborted(signal);\n return Promise.resolve();\n }\n return new Promise<void>((resolve, reject) => {\n let timer: ReturnType<typeof setTimeout> | undefined;\n const onAbort = () => {\n if (timer !== undefined) {\n clearTimeout(timer);\n }\n signal?.removeEventListener(\"abort\", onAbort);\n reject(new DOMException(\"The download was aborted\", \"AbortError\"));\n };\n timer = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, delayMs);\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n if (signal?.aborted) {\n onAbort();\n }\n });\n}\n\nclass SpeedWindow {\n private readonly samples: Array<{ at: number; bytes: number }> = [];\n\n record(bytes: number, at: number): number {\n this.samples.push({ at, bytes });\n const cutoff = at - 1_000;\n while (this.samples.length > 1 && this.samples[0]!.at < cutoff) {\n this.samples.shift();\n }\n const first = this.samples[0];\n if (!first || first.bytes === bytes) {\n return 0;\n }\n const seconds = Math.max((at - first.at) / 1_000, 0.001);\n return (bytes - first.bytes) / seconds;\n }\n}\n\nclass BlobDownloadSink {\n private readonly parts: Array<Uint8Array | Blob> = [];\n\n /** Parts arrive in file order, so the position is implied. */\n async write(bytes: Uint8Array | Blob, _position?: number): Promise<void> {\n this.parts.push(bytes instanceof Blob ? bytes : bytes.slice());\n }\n\n async flush(): Promise<void> {\n // Blob parts are already retained in memory.\n }\n\n async finalize(): Promise<void> {\n // Blob parts are finalized by blob().\n }\n\n blob(contentType?: string): Blob {\n const buffers = this.parts.map((part) => {\n if (part instanceof Blob) {\n return part;\n }\n const buffer = new ArrayBuffer(part.byteLength);\n new Uint8Array(buffer).set(part);\n return buffer;\n });\n return new Blob(buffers, contentType ? { type: contentType } : undefined);\n }\n}\n\nclass FileSystemDownloadSink {\n private writable: FileSystemWritableFileStreamLike | null = null;\n private position = 0;\n private openedOnce = false;\n\n constructor(private readonly handle: FileSystemFileHandleLike) {}\n\n async write(bytes: Uint8Array | Blob, position: number): Promise<void> {\n if (!this.writable) {\n const keepExistingData = this.openedOnce || position > 0;\n this.writable = await this.handle.createWritable({ keepExistingData });\n if (position > 0) {\n await this.writable.seek(position);\n }\n this.position = position;\n this.openedOnce = true;\n }\n if (this.position !== position) {\n throw new Error(\"File System Access writer position does not match the download checkpoint\");\n }\n await this.writable.write(bytes);\n this.position += bytes instanceof Blob ? bytes.size : bytes.byteLength;\n }\n\n async flush(): Promise<void> {\n if (this.writable) {\n const writable = this.writable;\n await writable.close();\n this.writable = null;\n }\n }\n\n async finalize(size: number): Promise<void> {\n if (!this.writable) {\n this.writable = await this.handle.createWritable({ keepExistingData: this.openedOnce });\n this.openedOnce = true;\n await this.writable.seek(size);\n }\n await this.writable.truncate(size);\n const writable = this.writable;\n this.writable = null;\n await writable.close();\n }\n\n async abort(): Promise<void> {\n if (!this.writable) {\n return;\n }\n const writable = this.writable;\n this.writable = null;\n if (writable.abort) {\n await writable.abort();\n } else {\n await writable.close();\n }\n }\n}\n\ntype DownloadSink = BlobDownloadSink | FileSystemDownloadSink;\n\nfunction downloadRequestFromOptions(options: ExportFileOptions): DownloadCheckpointRequest {\n if (options.path === undefined && options.ino === undefined) {\n throw new TypeError(\"download target requires path or ino\");\n }\n if (options.path !== undefined && !options.path.trim()) {\n throw new TypeError(\"download path cannot be empty\");\n }\n return {\n ...(options.workspaceCuid !== undefined ? { workspaceCuid: options.workspaceCuid } : {}),\n ...(options.workspaceId !== undefined ? { workspaceId: options.workspaceId } : {}),\n ...(options.path !== undefined ? { path: options.path } : {}),\n ...(options.ino !== undefined ? { ino: options.ino } : {}),\n ...(options.timeout !== undefined ? { timeout: options.timeout } : {}),\n ...(options.contentDisposition !== undefined\n ? { contentDisposition: options.contentDisposition }\n : {}),\n ...(options.downloadFilename !== undefined\n ? { downloadFilename: options.downloadFilename }\n : {}),\n };\n}\n\nfunction requestBodyFromCheckpoint(request: DownloadCheckpointRequest): Record<string, unknown> {\n return {\n ...(request.workspaceCuid !== undefined ? { workspace_cuid: request.workspaceCuid } : {}),\n ...(request.workspaceId !== undefined ? { workspace_id: request.workspaceId } : {}),\n ...(request.path !== undefined ? { path: request.path } : {}),\n ...(request.ino !== undefined ? { ino: request.ino } : {}),\n ...(request.timeout !== undefined ? { timeout: request.timeout } : {}),\n ...(request.contentDisposition !== undefined\n ? { content_disposition: request.contentDisposition }\n : {}),\n ...(request.downloadFilename !== undefined\n ? { download_filename: request.downloadFilename }\n : {}),\n };\n}\n\nfunction requestKey(request: DownloadCheckpointRequest, baseUrl: string): string {\n return encodeURIComponent(\n JSON.stringify({\n baseUrl,\n workspaceCuid: request.workspaceCuid ?? null,\n workspaceId: request.workspaceId ?? null,\n path: request.path ?? null,\n ino: request.ino ?? null,\n }),\n );\n}\n\ninterface DownloadPlanChunk {\n index: number;\n offset: number;\n size: number;\n storageKey: string;\n /** Absent only for chunks preloaded from the download cache. */\n url?: string;\n}\n\n/** What to download: an export response, or a file layout rebuilt from the download cache. */\ninterface DownloadPlan {\n path: string;\n size: number;\n contentType?: string;\n chunks: DownloadPlanChunk[];\n /** Absent when the plan comes from the download cache. */\n exported?: ExportFileResponse;\n /** Chunk bytes already read from the download cache, by chunk index. */\n cachedChunks?: Map<number, Blob>;\n}\n\nfunction buildDownloadChunks(exported: ExportFileResponse, useClientAssembly: boolean): ExportFileChunk[] {\n if (useClientAssembly && exported.chunks && exported.chunks.length > 1) {\n return exported.chunks;\n }\n return [\n {\n index: 0,\n offset: 0,\n size: exported.size,\n storageKey: exported.storageKey,\n url: exported.url,\n },\n ];\n}\n\nfunction buildDownloadKey(\n plan: DownloadPlan,\n baseUrl: string,\n request: DownloadCheckpointRequest,\n): string {\n return encodeURIComponent(\n JSON.stringify({\n request: requestKey(request, baseUrl),\n path: plan.path,\n size: plan.size,\n chunks: plan.chunks.map((chunk) => [chunk.index, chunk.offset, chunk.size, chunk.storageKey]),\n }),\n );\n}\n\nfunction checkpointMatches(checkpoint: DownloadCheckpoint, plan: DownloadPlan): boolean {\n if (checkpoint.version !== 1 || checkpoint.path !== plan.path || checkpoint.size !== plan.size) {\n return false;\n }\n if (checkpoint.chunks.length !== plan.chunks.length) {\n return false;\n }\n return checkpoint.chunks.every((saved, index) => {\n const current = plan.chunks[index];\n return Boolean(\n current &&\n saved.index === current.index &&\n saved.offset === current.offset &&\n saved.size === current.size &&\n saved.storageKey === current.storageKey &&\n saved.downloadedBytes >= 0 &&\n saved.downloadedBytes <= saved.size,\n );\n });\n}\n\nfunction createCheckpoint(\n key: string,\n baseUrl: string,\n request: DownloadCheckpointRequest,\n plan: DownloadPlan,\n fileHandle?: FileSystemFileHandleLike,\n): DownloadCheckpoint {\n return {\n version: 1,\n key,\n requestKey: requestKey(request, baseUrl),\n request: { ...request },\n path: plan.path,\n size: plan.size,\n chunks: plan.chunks.map((chunk) => ({\n index: chunk.index,\n offset: chunk.offset,\n size: chunk.size,\n storageKey: chunk.storageKey,\n downloadedBytes: 0,\n completed: chunk.size === 0,\n })),\n ...(fileHandle ? { fileHandle } : {}),\n updatedAt: Date.now(),\n };\n}\n\nfunction totalDownloadedBytes(checkpoint: DownloadCheckpoint): number {\n return checkpoint.chunks.reduce((total, chunk) => total + chunk.downloadedBytes, 0);\n}\n\nfunction completedChunkCount(checkpoint: DownloadCheckpoint): number {\n return checkpoint.chunks.filter((chunk) => chunk.completed).length;\n}\n\nfunction defaultFilename(path: string, requested?: string): string {\n const candidate = requested?.trim() || path.split(\"/\").filter(Boolean).pop() || \"download\";\n return candidate.replace(/[\\\\/\\r\\n]/g, \"_\") || \"download\";\n}\n\nfunction triggerBrowserDownload(blob: Blob, filename: string): void {\n const documentValue = (globalThis as typeof globalThis & { document?: Document }).document;\n const urlApi = (globalThis as typeof globalThis & { URL?: typeof URL }).URL;\n if (!documentValue || !urlApi?.createObjectURL) {\n return;\n }\n const url = urlApi.createObjectURL(blob);\n const anchor = documentValue.createElement(\"a\");\n anchor.href = url;\n anchor.download = filename;\n anchor.style.display = \"none\";\n documentValue.body?.appendChild(anchor);\n anchor.click();\n anchor.remove();\n setTimeout(() => urlApi.revokeObjectURL(url), 0);\n}\n\nexport class MountraDownloader {\n private readonly transport: DownloadTransport;\n\n constructor(transport: DownloadTransport) {\n this.transport = transport;\n }\n\n async exportFile(options: ExportFileOptions): Promise<ExportFileResponse> {\n return this.exportRequest(this.resolveRequest(options), options.signal);\n }\n\n async downloadFile(options: DownloadFileOptions): Promise<DownloadResult> {\n const preferFileSystemAccess = options.preferFileSystemAccess !== false;\n const fileHandle =\n options.fileHandle ??\n (preferFileSystemAccess && getShowSaveFilePicker()\n ? await this.pickSaveFile(options.downloadFilename ?? options.path?.split(\"/\").filter(Boolean).pop())\n : undefined);\n const request = this.resolveRequest(options);\n const plan =\n (await this.loadCachedPlan(request, options.cache)) ??\n this.planExport(\n await this.exportRequest(request, options.signal),\n request,\n options.cache,\n fileHandle,\n );\n return this.downloadResolved(plan, request, options, fileHandle, false);\n }\n\n async downloadExport(\n exported: ExportFileResponse,\n options: DownloadFileOptions = { path: exported.path },\n ): Promise<DownloadResult> {\n let fileHandle = options.fileHandle;\n if (\n !fileHandle &&\n options.preferFileSystemAccess !== false &&\n getShowSaveFilePicker()\n ) {\n fileHandle = await this.pickSaveFile(\n options.downloadFilename ?? defaultFilename(exported.path),\n exported.contentType,\n );\n }\n const request = this.resolveRequest(\n options.path === undefined && options.ino === undefined\n ? { ...options, path: exported.path }\n : options,\n );\n return this.downloadResolved(\n this.planExport(exported, request, options.cache, fileHandle),\n request,\n options,\n fileHandle,\n false,\n );\n }\n\n async resumeDownload(\n downloadKey: string,\n options: DownloadResumeOptions = {},\n ): Promise<DownloadResult> {\n if (!downloadKey.trim()) {\n throw new TypeError(\"downloadKey is required\");\n }\n const checkpoint = await this.transport.checkpointStore.load(downloadKey);\n if (!checkpoint || !checkpoint.fileHandle) {\n throw new Error(\"No resumable File System Access download was found\");\n }\n await this.ensureWritePermission(checkpoint.fileHandle);\n const exported = await this.exportFile({\n ...checkpoint.request,\n signal: options.signal,\n });\n return this.downloadResolved(\n this.planExport(exported, checkpoint.request, undefined, checkpoint.fileHandle),\n checkpoint.request,\n options,\n checkpoint.fileHandle,\n true,\n );\n }\n\n listResumableDownloads(): Promise<DownloadCheckpoint[]> {\n return this.transport.checkpointStore.list();\n }\n\n clearDownloadCheckpoint(downloadKey: string): Promise<void> {\n return this.transport.checkpointStore.remove(downloadKey);\n }\n\n /** Drop the cached layout of a file that was just written, so the next download sees the new content. */\n async invalidateCachedFile(\n selector: WorkspaceSelector,\n target: { path?: string; ino?: number | string },\n ): Promise<void> {\n await this.cachedFileScope(selector, target)?.invalidate();\n }\n\n /** Drop the cached files at or below paths that a delete, move, or copy changed. */\n async invalidateCachedPaths(selector: WorkspaceSelector, paths: string[]): Promise<void> {\n const cache = this.transport.cache;\n const workspace = workspaceCacheKey(this.transport.baseUrl, selector);\n if (cache && workspace !== null) {\n await cache.invalidatePaths(workspace, paths);\n }\n }\n\n /**\n * Cache a file this client just uploaded, so downloading it needs no\n * network. Falls back to invalidation when any chunk cannot be cached.\n */\n async cacheUploadedFile(\n selector: WorkspaceSelector,\n file: {\n path: string;\n ino?: number | string;\n size: number;\n contentType?: string;\n chunks: Array<DownloadCacheChunk & { data: Blob }>;\n },\n mode: Exclude<DownloadCacheMode, \"no-cache\"> = \"default\",\n ): Promise<void> {\n const scope = this.cachedFileScope(selector, file);\n if (!scope) {\n return;\n }\n await scope.invalidate();\n if (mode === \"no-store\") {\n return;\n }\n let complete = true;\n for (const chunk of file.chunks) {\n // Keep storing the rest: cached chunks still help later downloads of other layouts.\n complete = (await scope.cache.storeChunk(scope.workspace, chunk, chunk.data)) && complete;\n }\n if (complete) {\n for (const fileKey of scope.fileKeys) {\n await scope.cache.storeFile(scope.workspace, fileKey, file);\n }\n }\n }\n\n private cachedFileScope(\n selector: WorkspaceSelector,\n target: { path?: string; ino?: number | string },\n ): { cache: DownloadCache; workspace: string; fileKeys: string[]; invalidate(): Promise<void> } | null {\n const cache = this.transport.cache;\n const workspace = workspaceCacheKey(this.transport.baseUrl, selector);\n if (!cache || workspace === null) {\n return null;\n }\n const fileKeys = [\n target.path !== undefined ? fileCacheKey({ path: target.path }) : null,\n target.ino !== undefined ? fileCacheKey({ ino: target.ino }) : null,\n ].filter((fileKey): fileKey is string => fileKey !== null);\n return {\n cache,\n workspace,\n fileKeys,\n invalidate: () => cache.invalidateFiles(workspace, fileKeys),\n };\n }\n\n async clearCache(selector?: WorkspaceSelector): Promise<void> {\n const cache = this.transport.cache;\n if (!cache) {\n return;\n }\n await cache.clear(selector === undefined ? undefined : this.requireCacheWorkspace(selector));\n }\n\n async cacheUsage(selector?: WorkspaceSelector): Promise<DownloadCacheUsage> {\n const cache = this.transport.cache;\n if (!cache) {\n return { bytes: 0, chunks: 0 };\n }\n return cache.usage(selector === undefined ? undefined : this.requireCacheWorkspace(selector));\n }\n\n private requireCacheWorkspace(selector: WorkspaceSelector): string {\n const workspace = workspaceCacheKey(this.transport.baseUrl, selector);\n if (workspace === null) {\n throw new TypeError(\"workspaceCuid or workspaceId is required\");\n }\n return workspace;\n }\n\n /** Fall back to the client workspace only when the request names none, as uploads do. */\n private resolveRequest(options: ExportFileOptions): DownloadCheckpointRequest {\n const hasWorkspace = options.workspaceCuid !== undefined || options.workspaceId !== undefined;\n return downloadRequestFromOptions(\n hasWorkspace\n ? options\n : {\n ...options,\n workspaceCuid: this.transport.clientSelector.workspaceCuid,\n workspaceId: this.transport.clientSelector.workspaceId,\n },\n );\n }\n\n private async exportRequest(\n request: DownloadCheckpointRequest,\n signal?: AbortSignal,\n ): Promise<ExportFileResponse> {\n return ensureExportFileResponse(\n await this.transport.requestJson(\"/file/export\", requestBodyFromCheckpoint(request), signal),\n );\n }\n\n private cacheScope(\n request: DownloadCheckpointRequest,\n mode: DownloadCacheMode = \"default\",\n ): { cache: DownloadCache; workspace: string; fileKey: string } | null {\n const cache = this.transport.cache;\n if (!cache || mode === \"no-store\") {\n return null;\n }\n const workspace = workspaceCacheKey(this.transport.baseUrl, request);\n const fileKey = fileCacheKey(request);\n return workspace !== null && fileKey !== null ? { cache, workspace, fileKey } : null;\n }\n\n /** A plan that needs no network at all, when the cached layout is fresh and every chunk is cached. */\n private async loadCachedPlan(\n request: DownloadCheckpointRequest,\n mode: DownloadCacheMode | undefined,\n ): Promise<DownloadPlan | null> {\n const scope = this.cacheScope(request, mode);\n if (!scope || mode === \"no-cache\") {\n return null;\n }\n const cached = await scope.cache.loadFile(scope.workspace, scope.fileKey);\n if (!cached) {\n return null;\n }\n return {\n path: cached.file.path,\n size: cached.file.size,\n ...(cached.file.contentType ? { contentType: cached.file.contentType } : {}),\n chunks: cached.file.chunks,\n cachedChunks: cached.chunks,\n };\n }\n\n private planExport(\n exported: ExportFileResponse,\n request: DownloadCheckpointRequest,\n mode: DownloadCacheMode | undefined,\n fileHandle: FileSystemFileHandleLike | undefined,\n ): DownloadPlan {\n // Per-chunk downloads let each chunk be cached and reused on its own.\n const useClientAssembly =\n (exported.chunks?.length ?? 0) > 1 &&\n (Boolean(fileHandle) || this.cacheScope(request, mode) !== null);\n return {\n path: exported.path,\n size: exported.size,\n ...(exported.contentType ? { contentType: exported.contentType } : {}),\n chunks: buildDownloadChunks(exported, useClientAssembly),\n exported,\n };\n }\n\n private async pickSaveFile(\n requestedFilename?: string,\n contentType?: string,\n ): Promise<FileSystemFileHandleLike> {\n const picker = getShowSaveFilePicker();\n if (!picker) {\n throw new Error(\"File System Access API is not available\");\n }\n const types = contentType\n ? [{ description: contentType, accept: { [contentType]: [\".\" + (requestedFilename?.split(\".\").pop() || \"bin\")] } }]\n : undefined;\n return picker({\n suggestedName: requestedFilename?.trim() || \"download\",\n ...(types ? { types } : {}),\n });\n }\n\n private async ensureWritePermission(handle: FileSystemFileHandleLike): Promise<void> {\n if (!handle.queryPermission && !handle.requestPermission) {\n return;\n }\n const descriptor = { mode: \"readwrite\" as const };\n const current = await handle.queryPermission?.(descriptor);\n if (current === \"granted\") {\n return;\n }\n const requested = await handle.requestPermission?.(descriptor);\n if (requested !== undefined && requested !== \"granted\") {\n throw new DOMException(\"Write permission was not granted\", \"NotAllowedError\");\n }\n }\n\n private async downloadResolved(\n plan: DownloadPlan,\n request: DownloadCheckpointRequest,\n options: Pick<\n DownloadFileOptions,\n \"onProgress\" | \"signal\" | \"maxRetries\" | \"retryDelayMs\" | \"resume\" | \"downloadFilename\" | \"cache\"\n > | DownloadResumeOptions,\n fileHandle: FileSystemFileHandleLike | undefined,\n forceResume: boolean,\n ): Promise<DownloadResult> {\n const chunks = plan.chunks;\n const key = buildDownloadKey(plan, this.transport.baseUrl, request);\n const existing = await this.transport.checkpointStore.load(key);\n const resumeRequested = !(\"resume\" in options) || options.resume !== false;\n let checkpoint =\n existing && checkpointMatches(existing, plan) &&\n (forceResume || resumeRequested) &&\n (forceResume || (fileHandle && (await this.isSameFileHandle(existing.fileHandle, fileHandle))))\n ? existing\n : createCheckpoint(key, this.transport.baseUrl, request, plan, fileHandle);\n const cacheScope = this.cacheScope(request, \"cache\" in options ? options.cache : undefined);\n /** Indexes of chunks whose bytes are in the cache, from a hit or a store in this call. */\n const cachedChunkIndexes = new Set<number>();\n let cachedBytes = 0;\n\n if (fileHandle) {\n checkpoint.fileHandle = fileHandle;\n }\n const resumed = totalDownloadedBytes(checkpoint) > 0;\n const maxRetries = validateRetryOption(options.maxRetries, \"maxRetries\") ?? 3;\n const retryDelayMs = validateRetryOption(options.retryDelayMs, \"retryDelayMs\") ?? 500;\n const sink: DownloadSink = fileHandle\n ? new FileSystemDownloadSink(fileHandle)\n : new BlobDownloadSink();\n const speedWindow = new SpeedWindow();\n const startedAt = Date.now();\n let retryCount = 0;\n let lastCheckpointAt = 0;\n\n const emit = (\n phase: DownloadProgress[\"phase\"],\n currentChunkIndex?: number,\n ): void => {\n const downloadedBytes = totalDownloadedBytes(checkpoint);\n const speedBytesPerSecond = speedWindow.record(downloadedBytes, Date.now());\n const remainingBytes = Math.max(plan.size - downloadedBytes, 0);\n options.onProgress?.({\n phase,\n downloadedBytes,\n totalBytes: plan.size,\n downloadedChunks: completedChunkCount(checkpoint),\n totalChunks: checkpoint.chunks.length,\n ...(currentChunkIndex !== undefined ? { currentChunkIndex } : {}),\n speedBytesPerSecond,\n ...(speedBytesPerSecond > 0 && remainingBytes > 0\n ? { estimatedRemainingSeconds: remainingBytes / speedBytesPerSecond }\n : {}),\n elapsedMs: Date.now() - startedAt,\n retryCount,\n });\n };\n\n const persist = async (force: boolean): Promise<void> => {\n const now = Date.now();\n if (!force && now - lastCheckpointAt < 1_000) {\n return;\n }\n await sink.flush();\n checkpoint.updatedAt = now;\n await this.transport.checkpointStore.save(key, checkpoint);\n lastCheckpointAt = now;\n };\n\n await this.transport.checkpointStore.save(key, checkpoint);\n try {\n for (const chunk of chunks) {\n const savedChunk = checkpoint.chunks[chunk.index];\n if (!savedChunk) {\n throw new Error(`Missing download checkpoint for chunk ${chunk.index}`);\n }\n if (savedChunk.completed) {\n continue;\n }\n\n const cached =\n plan.cachedChunks?.get(chunk.index) ??\n (cacheScope ? await cacheScope.cache.readChunk(cacheScope.workspace, chunk) : null);\n if (cached) {\n throwIfAborted(options.signal);\n const remaining = cached.slice(savedChunk.downloadedBytes);\n await sink.write(remaining, chunk.offset + savedChunk.downloadedBytes);\n cachedBytes += remaining.size;\n savedChunk.downloadedBytes = chunk.size;\n savedChunk.completed = true;\n cachedChunkIndexes.add(chunk.index);\n emit(\"downloading\", chunk.index);\n await persist(false);\n continue;\n }\n const url = chunk.url;\n if (!url) {\n throw new Error(`Chunk ${chunk.index} is no longer in the download cache`);\n }\n // A chunk resumed from a checkpoint lacks its head bytes, so it cannot be cached.\n const capture: Uint8Array<ArrayBuffer>[] | null =\n cacheScope && savedChunk.downloadedBytes === 0 && cacheScope.cache.canStoreChunk(chunk)\n ? []\n : null;\n\n let attempt = 0;\n while (true) {\n throwIfAborted(options.signal);\n const rangeStart = savedChunk.downloadedBytes;\n try {\n const response = await this.transport.fetchImpl(url, {\n method: \"GET\",\n ...(rangeStart > 0 ? { headers: { Range: `bytes=${rangeStart}-` } } : {}),\n ...(options.signal ? { signal: options.signal } : {}),\n });\n if (!response.ok) {\n throw new DownloadHttpError(\n response.status,\n `Download for chunk ${chunk.index} failed with HTTP ${response.status}`,\n );\n }\n await this.consumeResponse(\n response,\n chunk,\n savedChunk,\n sink,\n plan.size,\n emit,\n persist,\n capture,\n options.signal,\n );\n if (savedChunk.downloadedBytes !== savedChunk.size) {\n throw new Error(\n `Download for chunk ${chunk.index} ended at ${savedChunk.downloadedBytes} of ${savedChunk.size} bytes`,\n );\n }\n savedChunk.completed = true;\n await persist(true);\n if (\n cacheScope &&\n capture &&\n (await cacheScope.cache.storeChunk(cacheScope.workspace, chunk, new Blob(capture)))\n ) {\n cachedChunkIndexes.add(chunk.index);\n }\n emit(\"downloading\", chunk.index);\n break;\n } catch (error) {\n await persist(true);\n if (isAbortError(error, options.signal) || !isRetryableError(error) || attempt >= maxRetries) {\n throw error;\n }\n attempt += 1;\n retryCount += 1;\n emit(\"retrying\", chunk.index);\n await waitForRetry(Math.min(retryDelayMs * 2 ** (attempt - 1), 30_000), options.signal);\n }\n }\n }\n\n if (totalDownloadedBytes(checkpoint) !== plan.size) {\n throw new Error(\"Download completed with an unexpected byte count\");\n }\n if (fileHandle) {\n await (sink as FileSystemDownloadSink).finalize(plan.size);\n } else {\n await (sink as BlobDownloadSink).finalize();\n }\n await this.transport.checkpointStore.remove(key);\n // Only a layout Mountra just confirmed may start a new freshness period.\n if (\n cacheScope &&\n plan.exported &&\n chunks.every((chunk) => chunk.size === 0 || cachedChunkIndexes.has(chunk.index))\n ) {\n await cacheScope.cache.storeFile(cacheScope.workspace, cacheScope.fileKey, plan);\n }\n emit(\"completed\");\n const blob = sink instanceof BlobDownloadSink ? sink.blob(plan.contentType) : undefined;\n if (blob) {\n const filename = \"downloadFilename\" in options ? options.downloadFilename : undefined;\n triggerBrowserDownload(blob, defaultFilename(plan.path, filename));\n }\n return {\n ...(plan.exported ? { export: plan.exported } : {}),\n downloadKey: key,\n downloadedBytes: plan.size,\n cachedBytes,\n resumed,\n ...(fileHandle ? { fileHandle } : {}),\n ...(blob ? { blob } : {}),\n };\n } catch (error) {\n await persist(true);\n throw error;\n }\n }\n\n private async consumeResponse(\n response: Response,\n chunk: DownloadPlanChunk,\n savedChunk: DownloadCheckpointChunk,\n sink: DownloadSink,\n totalSize: number,\n emit: (phase: DownloadProgress[\"phase\"], currentChunkIndex?: number) => void,\n persist: (force: boolean) => Promise<void>,\n capture: Uint8Array<ArrayBuffer>[] | null,\n signal?: AbortSignal,\n ): Promise<void> {\n const sourceOffset = savedChunk.downloadedBytes;\n let bytesToSkip = response.status === 200 && sourceOffset > 0 ? sourceOffset : 0;\n const reader = response.body?.getReader();\n if (!reader) {\n const body = new Uint8Array(await response.arrayBuffer());\n await this.consumeBytes(body, bytesToSkip, chunk, savedChunk, sink, totalSize, emit, persist, capture, signal);\n return;\n }\n\n try {\n while (true) {\n throwIfAborted(signal);\n const next = await reader.read();\n if (next.done) {\n break;\n }\n const bytes = next.value;\n if (bytesToSkip > 0) {\n const skipped = Math.min(bytesToSkip, bytes.byteLength);\n bytesToSkip -= skipped;\n if (skipped === bytes.byteLength) {\n continue;\n }\n await this.consumeBytes(\n bytes.subarray(skipped),\n 0,\n chunk,\n savedChunk,\n sink,\n totalSize,\n emit,\n persist,\n capture,\n signal,\n );\n } else {\n await this.consumeBytes(bytes, 0, chunk, savedChunk, sink, totalSize, emit, persist, capture, signal);\n }\n }\n } finally {\n reader.releaseLock();\n }\n if (bytesToSkip > 0) {\n throw new Error(`Download response did not contain the saved offset for chunk ${chunk.index}`);\n }\n }\n\n private async consumeBytes(\n bytes: Uint8Array,\n offset: number,\n chunk: DownloadPlanChunk,\n savedChunk: DownloadCheckpointChunk,\n sink: DownloadSink,\n totalSize: number,\n emit: (phase: DownloadProgress[\"phase\"], currentChunkIndex?: number) => void,\n persist: (force: boolean) => Promise<void>,\n capture: Uint8Array<ArrayBuffer>[] | null,\n signal?: AbortSignal,\n ): Promise<void> {\n const remaining = chunk.size - savedChunk.downloadedBytes;\n const writableBytes = bytes.byteLength - offset;\n if (writableBytes > remaining) {\n throw new Error(`Download response for chunk ${chunk.index} is larger than expected`);\n }\n if (writableBytes === 0) {\n return;\n }\n throwIfAborted(signal);\n const payload = bytes.subarray(offset);\n const position = chunk.offset + savedChunk.downloadedBytes;\n await sink.write(payload, position);\n capture?.push(payload.slice());\n savedChunk.downloadedBytes += payload.byteLength;\n emit(\"downloading\", chunk.index);\n await persist(false);\n if (savedChunk.downloadedBytes > totalSize) {\n throw new Error(\"Download byte count exceeded the exported file size\");\n }\n }\n\n private async isSameFileHandle(\n savedHandle: FileSystemFileHandleLike | undefined,\n selectedHandle: FileSystemFileHandleLike,\n ): Promise<boolean> {\n if (!savedHandle) {\n return false;\n }\n if (savedHandle === selectedHandle) {\n return true;\n }\n if (savedHandle.isSameEntry) {\n try {\n return await savedHandle.isSameEntry(selectedHandle);\n } catch {\n return false;\n }\n }\n return false;\n }\n}\n","/** An HTTP error returned by Mountra, or by a signed upload URL. */\nexport class MountraApiError extends Error {\n readonly status: number;\n readonly code?: string;\n readonly body?: unknown;\n\n constructor(message: string, input: { status: number; code?: string; body?: unknown }) {\n super(message);\n this.name = \"MountraApiError\";\n this.status = input.status;\n this.code = input.code;\n this.body = input.body;\n }\n}\n","import { workspaceCacheKey } from \"./cache\";\nimport { MountraApiError } from \"./errors\";\nimport { normalizePath } from \"./file\";\nimport type {\n MetadataCache,\n MetadataCacheKind,\n MetadataCacheRecord,\n MetadataChange,\n MetadataListRecord,\n MetadataTreeRecord,\n} from \"./metadata-cache\";\nimport type { WorkspaceSelector } from \"./upload\";\n\n/** One entry of a directory listing. */\nexport interface MountraFileEntry {\n name: string;\n /** Absolute path in the workspace. */\n path: string;\n ino: number;\n isDirectory: boolean;\n size: number;\n mtimeMs: number;\n atimeMs: number;\n uid?: number;\n gid?: number;\n uidDisplayName?: string;\n uidUsername?: string;\n uidSubjectId?: string;\n uidSubjectType?: string;\n gidDisplayName?: string;\n gidUsername?: string;\n gidSubjectId?: string;\n gidSubjectType?: string;\n}\n\n/** A node of a file tree. A directory node holds its complete subtree. */\nexport interface MountraFileTreeNode {\n name: string;\n /** Absolute path in the workspace. */\n path: string;\n ino: number;\n isDirectory: boolean;\n size: number;\n mtimeMs: number;\n uid?: number;\n gid?: number;\n uidSubjectId?: string;\n uidSubjectType?: string;\n gidSubjectId?: string;\n gidSubjectType?: string;\n children: MountraFileTreeNode[];\n}\n\n/**\n * How a metadata read uses the client's `metadataCache`:\n * - `sync`: wait for Mountra and return its result.\n * - `async`: return the cached result at once and refresh it in the\n * background. Without a cached result, wait for Mountra as `sync` does.\n *\n * Either way, a result fetched from Mountra is cached before it is returned.\n */\nexport type MetadataReadMode = \"sync\" | \"async\";\n\n/** `cache` when the result was served from the metadata cache, `remote` when Mountra just returned it. */\nexport type MetadataSource = \"cache\" | \"remote\";\n\nexport interface MetadataReadOptions<T> extends WorkspaceSelector {\n /** The directory to read. Defaults to `/`. */\n path?: string;\n /** Defaults to `sync`. */\n mode?: MetadataReadMode;\n /**\n * `async` only: receives the refreshed result of a cached result that was\n * returned, when the two differ.\n */\n onUpdate?: (result: T) => void;\n /** `async` only: receives the error of a failed background refresh. */\n onError?: (error: unknown) => void;\n /** Also cancels the background refresh; no callback runs once it has aborted. */\n signal?: AbortSignal;\n}\n\nexport interface ListResult {\n path: string;\n /** Directories first, then by name. */\n entries: MountraFileEntry[];\n source: MetadataSource;\n /**\n * When the request that returned this result was sent. A cached result\n * also reflects writes made through this client since then.\n */\n fetchedAt: number;\n}\n\nexport interface TreeResult {\n path: string;\n root: MountraFileTreeNode;\n source: MetadataSource;\n /** See `ListResult.fetchedAt`. */\n fetchedAt: number;\n}\n\nexport type ListOptions = MetadataReadOptions<ListResult>;\nexport type TreeOptions = MetadataReadOptions<TreeResult>;\n\nexport interface MkdirOptions extends WorkspaceSelector {\n /** The directory to create. Its parent must exist. */\n path: string;\n signal?: AbortSignal;\n}\n\nexport interface RenameOptions extends WorkspaceSelector {\n fromPath: string;\n /** The new name within the same directory. */\n toName: string;\n signal?: AbortSignal;\n}\n\nexport interface MoveOptions extends WorkspaceSelector {\n fromPath: string;\n /** The complete destination path, which must not exist yet. */\n toPath: string;\n signal?: AbortSignal;\n}\n\n/** Copies one file; Mountra does not copy directories. */\nexport type CopyOptions = MoveOptions;\n\nexport interface DeleteOptions extends WorkspaceSelector {\n /** A file, or an empty directory. */\n path: string;\n signal?: AbortSignal;\n}\n\nexport interface FileOperationResult {\n /** The path of the created, renamed, moved, or copied entry. */\n path: string;\n ino: number;\n}\n\ninterface MetadataTransport {\n readonly baseUrl: string;\n readonly clientSelector: WorkspaceSelector;\n readonly cache: MetadataCache | null;\n requestJson(path: string, body: unknown, signal?: AbortSignal): Promise<unknown>;\n /** Stop the download cache from serving files at or below `paths`. */\n invalidateDownloads(selector: WorkspaceSelector, paths: string[]): Promise<void>;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction invalidField(field: string): TypeError {\n return new TypeError(`Mountra metadata response field ${field} is invalid`);\n}\n\nfunction readString(value: unknown, field: string): string {\n if (typeof value !== \"string\") {\n throw invalidField(field);\n }\n return value;\n}\n\nfunction readCount(value: unknown, field: string): number {\n if (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 0) {\n throw invalidField(field);\n }\n return value;\n}\n\nfunction readBoolean(value: unknown, field: string): boolean {\n if (typeof value !== \"boolean\") {\n throw invalidField(field);\n }\n return value;\n}\n\nfunction optionalInteger(value: unknown): number | undefined {\n return typeof value === \"number\" && Number.isSafeInteger(value) ? value : undefined;\n}\n\nfunction optionalText(value: unknown): string | undefined {\n return typeof value === \"string\" && value ? value : undefined;\n}\n\n/** Drop absent optional fields, so equal results compare equal. */\nfunction withoutUndefined<T extends object>(value: T): T {\n for (const key of Object.keys(value) as Array<keyof T>) {\n if (value[key] === undefined) {\n delete value[key];\n }\n }\n return value;\n}\n\nfunction readNodeFields(raw: Record<string, unknown>, field: string) {\n return {\n name: readString(raw.name, `${field}.name`),\n path: normalizePath(readString(raw.path, `${field}.path`)),\n ino: readCount(raw.ino, `${field}.ino`),\n isDirectory: readBoolean(raw.is_directory, `${field}.is_directory`),\n size: readCount(raw.size, `${field}.size`),\n mtimeMs: readCount(raw.mtime_ms, `${field}.mtime_ms`),\n uid: optionalInteger(raw.uid),\n gid: optionalInteger(raw.gid),\n uidSubjectId: optionalText(raw.uid_subject_id),\n uidSubjectType: optionalText(raw.uid_subject_type),\n gidSubjectId: optionalText(raw.gid_subject_id),\n gidSubjectType: optionalText(raw.gid_subject_type),\n };\n}\n\nfunction readEntry(raw: unknown, field: string): MountraFileEntry {\n if (!isRecord(raw)) {\n throw invalidField(field);\n }\n return withoutUndefined({\n ...readNodeFields(raw, field),\n atimeMs: readCount(raw.atime_ms, `${field}.atime_ms`),\n uidDisplayName: optionalText(raw.uid_display_name),\n uidUsername: optionalText(raw.uid_username),\n gidDisplayName: optionalText(raw.gid_display_name),\n gidUsername: optionalText(raw.gid_username),\n });\n}\n\nfunction readTreeNode(raw: unknown, field: string): MountraFileTreeNode {\n if (!isRecord(raw) || !Array.isArray(raw.children)) {\n throw invalidField(field);\n }\n return withoutUndefined({\n ...readNodeFields(raw, field),\n children: raw.children.map((child, index) => readTreeNode(child, `${field}.children[${index}]`)),\n });\n}\n\nfunction readListResponse(value: unknown): MountraFileEntry[] {\n if (!isRecord(value) || !Array.isArray(value.entries)) {\n throw invalidField(\"entries\");\n }\n return value.entries.map((entry, index) => readEntry(entry, `entries[${index}]`));\n}\n\nfunction readOperationResponse(value: unknown): FileOperationResult {\n if (!isRecord(value)) {\n throw new TypeError(\"Mountra file operation response is invalid\");\n }\n return {\n path: normalizePath(readString(value.path, \"path\")),\n ino: readCount(value.ino, \"ino\"),\n };\n}\n\n/** Deep equality of JSON values, ignoring the order of object keys. */\nfunction sameJson(left: unknown, right: unknown): boolean {\n if (left === right) {\n return true;\n }\n if (!isRecord(left) || !isRecord(right) || Array.isArray(left) !== Array.isArray(right)) {\n return false;\n }\n const leftKeys = Object.keys(left);\n return (\n leftKeys.length === Object.keys(right).length &&\n leftKeys.every((key) => Object.hasOwn(right, key) && sameJson(left[key], right[key]))\n );\n}\n\nfunction sameContent(left: MetadataCacheRecord, right: MetadataCacheRecord): boolean {\n return left.kind === \"list\" && right.kind === \"list\"\n ? sameJson(left.entries, right.entries)\n : left.kind === \"tree\" && right.kind === \"tree\" && sameJson(left.root, right.root);\n}\n\nfunction workspaceBody(selector: WorkspaceSelector): Record<string, string | number> {\n return {\n ...(selector.workspaceCuid !== undefined ? { workspace_cuid: selector.workspaceCuid } : {}),\n ...(selector.workspaceId !== undefined ? { workspace_id: selector.workspaceId } : {}),\n };\n}\n\n/** Listing, tree, and directory operations, kept coherent with the metadata cache. */\nexport class MountraMetadata {\n private readonly transport: MetadataTransport;\n\n constructor(transport: MetadataTransport) {\n this.transport = transport;\n }\n\n list(options: ListOptions = {}): Promise<ListResult> {\n return this.read<MetadataListRecord, ListResult>(\"list\", options, (record, source) => ({\n path: record.path,\n entries: record.entries,\n source,\n fetchedAt: record.fetchedAt,\n }));\n }\n\n tree(options: TreeOptions = {}): Promise<TreeResult> {\n return this.read<MetadataTreeRecord, TreeResult>(\"tree\", options, (record, source) => ({\n path: record.path,\n root: record.root,\n source,\n fetchedAt: record.fetchedAt,\n }));\n }\n\n async mkdir(options: MkdirOptions): Promise<FileOperationResult> {\n const selector = this.resolveWorkspace(options);\n const created = await this.operate(selector, \"/file/mkdir\", { path: normalizePath(options.path) }, options.signal);\n await this.afterWrite(selector, {\n type: \"create\",\n path: created.path,\n ino: created.ino,\n isDirectory: true,\n size: 0,\n });\n return created;\n }\n\n async rename(options: RenameOptions): Promise<FileOperationResult> {\n const selector = this.resolveWorkspace(options);\n const fromPath = normalizePath(options.fromPath);\n const renamed = await this.operate(\n selector,\n \"/file/rename\",\n { from_path: fromPath, to_name: options.toName },\n options.signal,\n );\n await this.afterWrite(selector, { type: \"move\", fromPath, toPath: renamed.path, ino: renamed.ino });\n return renamed;\n }\n\n async move(options: MoveOptions): Promise<FileOperationResult> {\n const selector = this.resolveWorkspace(options);\n const fromPath = normalizePath(options.fromPath);\n const moved = await this.operate(\n selector,\n \"/file/move\",\n { from_path: fromPath, to_path: normalizePath(options.toPath) },\n options.signal,\n );\n await this.afterWrite(selector, { type: \"move\", fromPath, toPath: moved.path, ino: moved.ino });\n return moved;\n }\n\n async copy(options: CopyOptions): Promise<FileOperationResult> {\n const selector = this.resolveWorkspace(options);\n const fromPath = normalizePath(options.fromPath);\n const copied = await this.operate(\n selector,\n \"/file/copy\",\n { from_path: fromPath, to_path: normalizePath(options.toPath) },\n options.signal,\n );\n await this.afterWrite(selector, { type: \"copy\", fromPath, toPath: copied.path, ino: copied.ino });\n return copied;\n }\n\n async delete(options: DeleteOptions): Promise<void> {\n const selector = this.resolveWorkspace(options);\n const path = normalizePath(options.path);\n await this.transport.requestJson(\"/file/delete\", { ...workspaceBody(selector), path }, options.signal);\n await this.afterWrite(selector, { type: \"remove\", path });\n }\n\n /** Show a file that an upload just finished. The upload updates the download cache itself. */\n recordUpload(selector: WorkspaceSelector, file: { path: string; ino?: number; size: number }): Promise<void> {\n return this.applyChange(selector, {\n type: \"create\",\n path: normalizePath(file.path),\n ...(file.ino !== undefined ? { ino: file.ino } : {}),\n isDirectory: false,\n size: file.size,\n });\n }\n\n async clearCache(selector?: WorkspaceSelector): Promise<void> {\n const cache = this.transport.cache;\n if (!cache) {\n return;\n }\n if (selector === undefined) {\n await cache.clear();\n return;\n }\n const workspace = workspaceCacheKey(this.transport.baseUrl, selector);\n if (workspace === null) {\n throw new TypeError(\"workspaceCuid or workspaceId is required\");\n }\n await cache.clear(workspace);\n }\n\n private async read<R extends MetadataCacheRecord, T>(\n kind: R[\"kind\"],\n options: MetadataReadOptions<T>,\n present: (record: R, source: MetadataSource) => T,\n ): Promise<T> {\n const selector = this.resolveWorkspace(options);\n const path = normalizePath(options.path ?? \"/\");\n const scope = this.cacheScope(selector);\n const { signal, onUpdate, onError } = options;\n const cached =\n options.mode === \"async\" && scope ? await scope.cache.get(scope.workspace, kind, path) : null;\n if (!cached) {\n return present((await this.fetch(kind, selector, path, signal)) as R, \"remote\");\n }\n\n void this.fetch(kind, selector, path, signal).then(\n (fresh) => {\n if (!signal?.aborted && !sameContent(cached, fresh)) {\n onUpdate?.(present(fresh as R, \"remote\"));\n }\n },\n (error: unknown) => {\n if (!signal?.aborted) {\n onError?.(error);\n }\n },\n );\n return present(cached as R, \"cache\");\n }\n\n /** Fetch from Mountra, and cache the result before returning it. */\n private async fetch(\n kind: MetadataCacheKind,\n selector: WorkspaceSelector,\n path: string,\n signal?: AbortSignal,\n ): Promise<MetadataCacheRecord> {\n const scope = this.cacheScope(selector);\n const ticket = scope?.cache.beginFetch(scope.workspace);\n let body: unknown;\n try {\n body = await this.transport.requestJson(`/file/${kind}`, { ...workspaceBody(selector), path }, signal);\n } catch (error) {\n if (scope && ticket && error instanceof MountraApiError && error.status === 404) {\n await scope.cache.forgetFetched(scope.workspace, path, ticket);\n }\n throw error;\n }\n\n const fetchedAt = ticket?.startedAt ?? Date.now();\n let record: MetadataCacheRecord;\n if (kind === \"list\") {\n record = { kind, path, entries: readListResponse(body), fetchedAt };\n } else {\n if (!isRecord(body)) {\n throw invalidField(\"root\");\n }\n record = { kind, path, root: readTreeNode(body.root, \"root\"), fetchedAt };\n }\n if (scope && ticket) {\n await scope.cache.storeFetched(scope.workspace, record, ticket);\n }\n return record;\n }\n\n private async operate(\n selector: WorkspaceSelector,\n endpoint: string,\n body: Record<string, unknown>,\n signal?: AbortSignal,\n ): Promise<FileOperationResult> {\n return readOperationResponse(\n await this.transport.requestJson(endpoint, { ...workspaceBody(selector), ...body }, signal),\n );\n }\n\n /**\n * Reflect a write in both caches. Any download cached at a path the write\n * changed is stale: the file is gone, moved, or a new one now lives there.\n */\n private async afterWrite(selector: WorkspaceSelector, change: MetadataChange): Promise<void> {\n const paths =\n change.type === \"move\"\n ? [change.fromPath, change.toPath]\n : change.type === \"copy\"\n ? [change.toPath]\n : [change.path];\n await Promise.all([\n this.applyChange(selector, change),\n this.transport.invalidateDownloads(selector, paths),\n ]);\n }\n\n private async applyChange(selector: WorkspaceSelector, change: MetadataChange): Promise<void> {\n const scope = this.cacheScope(selector);\n await scope?.cache.applyChange(scope.workspace, change);\n }\n\n /** Fall back to the client workspace only when the call names none, as downloads do. */\n private resolveWorkspace(selector: WorkspaceSelector): WorkspaceSelector {\n const named = selector.workspaceCuid !== undefined || selector.workspaceId !== undefined;\n const { workspaceCuid, workspaceId } = named ? selector : this.transport.clientSelector;\n if (workspaceCuid === undefined && workspaceId === undefined) {\n throw new TypeError(\"workspaceCuid or workspaceId is required\");\n }\n return {\n ...(workspaceCuid !== undefined ? { workspaceCuid } : {}),\n ...(workspaceId !== undefined ? { workspaceId } : {}),\n };\n }\n\n private cacheScope(selector: WorkspaceSelector): { cache: MetadataCache; workspace: string } | null {\n const cache = this.transport.cache;\n const workspace = workspaceCacheKey(this.transport.baseUrl, selector);\n return cache && workspace !== null ? { cache, workspace } : null;\n }\n}\n","import { isPathWithin } from \"./file\";\nimport { nextClock, openDatabase, requestResult, runTransaction, workspaceRange } from \"./idb\";\nimport type { MountraFileEntry, MountraFileTreeNode } from \"./metadata\";\n\nconst DEFAULT_MAX_ENTRIES = 1000;\n\nexport type MetadataCacheKind = \"list\" | \"tree\";\n\n/** A cached `list` result: the entries of one directory. */\nexport interface MetadataListRecord {\n kind: \"list\";\n path: string;\n entries: MountraFileEntry[];\n /**\n * When the request that returned this result was sent. Writes through this\n * client and overlapping fetches may have updated the record since.\n */\n fetchedAt: number;\n}\n\n/** A cached `tree` result: one directory and its complete subtree. */\nexport interface MetadataTreeRecord {\n kind: \"tree\";\n path: string;\n root: MountraFileTreeNode;\n /** See `MetadataListRecord.fetchedAt`. */\n fetchedAt: number;\n}\n\nexport type MetadataCacheRecord = MetadataListRecord | MetadataTreeRecord;\n\nexport interface MetadataCacheBatch {\n put: MetadataCacheRecord[];\n remove: Array<{ kind: MetadataCacheKind; path: string }>;\n}\n\nexport interface MetadataCacheOptions {\n /**\n * Upper bound of cached `list` and `tree` results, shared by all\n * workspaces. A tree counts as one result however large it is. Defaults to\n * 1000; the least recently refreshed results are evicted first.\n */\n maxEntries?: number;\n /** Cache storage. Defaults to IndexedDB, or memory when IndexedDB is unavailable. */\n store?: MetadataCacheStore;\n}\n\n/**\n * Storage behind the metadata cache. A record is identified by an opaque\n * workspace key together with its `kind` and `path`, so one workspace never\n * observes another workspace's records.\n */\nexport interface MetadataCacheStore {\n get(workspace: string, kind: MetadataCacheKind, path: string): Promise<MetadataCacheRecord | null>;\n /** The records stored at `path` or at any path below it, of one kind or of both. */\n getSubtree(workspace: string, path: string, kind?: MetadataCacheKind): Promise<MetadataCacheRecord[]>;\n /** Apply the batch atomically, then evict the least recently written records until at most `maxEntries` remain. */\n write(workspace: string, batch: MetadataCacheBatch, maxEntries: number): Promise<void>;\n /** Remove every record, or only the records of one workspace. */\n clear(workspace?: string): Promise<void>;\n}\n\nconst KINDS: MetadataCacheKind[] = [\"list\", \"tree\"];\n\nfunction parentOf(path: string): string {\n const index = path.lastIndexOf(\"/\");\n return index <= 0 ? \"/\" : path.slice(0, index);\n}\n\nfunction baseName(path: string): string {\n return path.slice(path.lastIndexOf(\"/\") + 1) || \"/\";\n}\n\n/** `path` followed by each of its ancestors up to `/`. */\nfunction selfAndAncestors(path: string): string[] {\n const paths = [path];\n for (let current = path; current !== \"/\"; ) {\n current = parentOf(current);\n paths.push(current);\n }\n return paths;\n}\n\nfunction rebasePath(path: string, from: string, to: string): string {\n return `${to}${path.slice(from.length)}`;\n}\n\nfunction memoryKey(workspace: string, kind: MetadataCacheKind, path: string): string {\n return JSON.stringify([workspace, kind, path]);\n}\n\nexport class InMemoryMetadataCacheStore implements MetadataCacheStore {\n /** Map iteration order is the eviction order: the first entry was written least recently. */\n private readonly records = new Map<string, { workspace: string; record: MetadataCacheRecord }>();\n\n async get(workspace: string, kind: MetadataCacheKind, path: string): Promise<MetadataCacheRecord | null> {\n const entry = this.records.get(memoryKey(workspace, kind, path));\n return entry ? structuredClone(entry.record) : null;\n }\n\n async getSubtree(\n workspace: string,\n path: string,\n kind?: MetadataCacheKind,\n ): Promise<MetadataCacheRecord[]> {\n return [...this.records.values()]\n .filter(\n (entry) =>\n entry.workspace === workspace &&\n (kind === undefined || entry.record.kind === kind) &&\n isPathWithin(entry.record.path, path),\n )\n .map((entry) => structuredClone(entry.record));\n }\n\n async write(workspace: string, batch: MetadataCacheBatch, maxEntries: number): Promise<void> {\n for (const { kind, path } of batch.remove) {\n this.records.delete(memoryKey(workspace, kind, path));\n }\n for (const record of batch.put) {\n const key = memoryKey(workspace, record.kind, record.path);\n this.records.delete(key);\n this.records.set(key, { workspace, record: structuredClone(record) });\n }\n for (const key of this.records.keys()) {\n if (this.records.size <= maxEntries) {\n break;\n }\n this.records.delete(key);\n }\n }\n\n async clear(workspace?: string): Promise<void> {\n for (const [key, entry] of this.records) {\n if (workspace === undefined || entry.workspace === workspace) {\n this.records.delete(key);\n }\n }\n }\n}\n\nconst METADATA_DATABASE_NAME = \"mountra-sdk-metadata-cache\";\nconst METADATA_DATABASE_VERSION = 1;\nconst RECORDS_STORE = \"records\";\nconst META_STORE = \"meta\";\nconst WRITE_ORDER_INDEX = \"written\";\n\ninterface StoredRecord {\n record: MetadataCacheRecord;\n written: number;\n}\n\nexport interface IndexedDBMetadataCacheStoreOptions {\n /** Use a separate database, for example one per signed-in user. */\n databaseName?: string;\n}\n\n/** Records are keyed `[workspace, kind, path]`, so a subtree of one kind is one key range. */\nexport class IndexedDBMetadataCacheStore implements MetadataCacheStore {\n private readonly databaseName: string;\n private readonly fallback = new InMemoryMetadataCacheStore();\n private databasePromise?: Promise<IDBDatabase | null>;\n\n constructor(options: IndexedDBMetadataCacheStoreOptions = {}) {\n this.databaseName = options.databaseName ?? METADATA_DATABASE_NAME;\n }\n\n async get(workspace: string, kind: MetadataCacheKind, path: string): Promise<MetadataCacheRecord | null> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.get(workspace, kind, path);\n }\n return runTransaction(database, [RECORDS_STORE], \"readonly\", async (transaction) => {\n const stored = await requestResult<StoredRecord | undefined>(\n transaction.objectStore(RECORDS_STORE).get([workspace, kind, path]),\n );\n return stored?.record ?? null;\n });\n }\n\n async getSubtree(\n workspace: string,\n path: string,\n kind?: MetadataCacheKind,\n ): Promise<MetadataCacheRecord[]> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.getSubtree(workspace, path, kind);\n }\n // Every path below `path` starts with `path/` and so sorts before `path0`;\n // the range also holds siblings such as `path.txt`, which are filtered out.\n const upper = path === \"/\" ? \"0\" : `${path}0`;\n return runTransaction(database, [RECORDS_STORE], \"readonly\", async (transaction) => {\n const records: MetadataCacheRecord[] = [];\n for (const candidate of kind === undefined ? KINDS : [kind]) {\n const stored = await requestResult<StoredRecord[]>(\n transaction\n .objectStore(RECORDS_STORE)\n .getAll(IDBKeyRange.bound([workspace, candidate, path], [workspace, candidate, upper], false, true)),\n );\n records.push(\n ...stored.map(({ record }) => record).filter((record) => isPathWithin(record.path, path)),\n );\n }\n return records;\n });\n }\n\n async write(workspace: string, batch: MetadataCacheBatch, maxEntries: number): Promise<void> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.write(workspace, batch, maxEntries);\n }\n await runTransaction(database, [RECORDS_STORE, META_STORE], \"readwrite\", async (transaction) => {\n const records = transaction.objectStore(RECORDS_STORE);\n const meta = transaction.objectStore(META_STORE);\n for (const { kind, path } of batch.remove) {\n await requestResult(records.delete([workspace, kind, path]));\n }\n for (const record of batch.put) {\n const stored: StoredRecord = { record, written: await nextClock(meta) };\n await requestResult(records.put(stored, [workspace, record.kind, record.path]));\n }\n let count = await requestResult(records.count());\n if (count <= maxEntries) {\n return;\n }\n const cursorRequest = records.index(WRITE_ORDER_INDEX).openCursor();\n let cursor = await requestResult(cursorRequest);\n while (cursor && count > maxEntries) {\n await requestResult(cursor.delete());\n count -= 1;\n cursor.continue();\n cursor = await requestResult(cursorRequest);\n }\n });\n }\n\n async clear(workspace?: string): Promise<void> {\n const database = await this.openDatabase();\n if (!database) {\n return this.fallback.clear(workspace);\n }\n await runTransaction(database, [RECORDS_STORE], \"readwrite\", async (transaction) => {\n const records = transaction.objectStore(RECORDS_STORE);\n await requestResult(\n workspace === undefined ? records.clear() : records.delete(workspaceRange(workspace)),\n );\n });\n }\n\n private async openDatabase(): Promise<IDBDatabase | null> {\n this.databasePromise ??= openDatabase(\n this.databaseName,\n METADATA_DATABASE_VERSION,\n (database) => {\n if (!database.objectStoreNames.contains(RECORDS_STORE)) {\n database.createObjectStore(RECORDS_STORE).createIndex(WRITE_ORDER_INDEX, \"written\");\n }\n if (!database.objectStoreNames.contains(META_STORE)) {\n database.createObjectStore(META_STORE);\n }\n },\n () => {\n this.databasePromise = undefined;\n },\n );\n return this.databasePromise;\n }\n}\n\n/** A write that Mountra completed, described by its effect on the file tree. */\nexport type MetadataChange =\n | { type: \"create\"; path: string; ino?: number; isDirectory: boolean; size: number }\n | { type: \"remove\"; path: string }\n | { type: \"move\"; fromPath: string; toPath: string; ino: number }\n | { type: \"copy\"; fromPath: string; toPath: string; ino: number };\n\n/** Taken when a fetch starts, so its result is not cached over a write that overlapped it. */\nexport interface MetadataFetchTicket {\n readonly startedAt: number;\n readonly writeSeq: number;\n}\n\nconst NODE_FIELDS = [\n \"name\",\n \"path\",\n \"ino\",\n \"isDirectory\",\n \"size\",\n \"mtimeMs\",\n \"uid\",\n \"gid\",\n \"uidSubjectId\",\n \"uidSubjectType\",\n \"gidSubjectId\",\n \"gidSubjectType\",\n] as const;\n\nfunction pickDefined<T extends object, K extends keyof T>(source: T, keys: readonly K[]): Pick<T, K> {\n const picked = {} as Pick<T, K>;\n for (const key of keys) {\n if (source[key] !== undefined) {\n picked[key] = source[key];\n }\n }\n return picked;\n}\n\nfunction nodeFromEntry(entry: MountraFileEntry, children: MountraFileTreeNode[]): MountraFileTreeNode {\n return { ...pickDefined(entry, NODE_FIELDS), children };\n}\n\n/** Tree nodes lack the access time and owner names, so those come from the entry being refreshed. */\nfunction entryFromNode(node: MountraFileTreeNode, previous: MountraFileEntry): MountraFileEntry {\n return {\n ...pickDefined(node, NODE_FIELDS),\n atimeMs: previous.atimeMs,\n ...(node.uid === previous.uid ? pickDefined(previous, [\"uidDisplayName\", \"uidUsername\"]) : {}),\n ...(node.gid === previous.gid ? pickDefined(previous, [\"gidDisplayName\", \"gidUsername\"]) : {}),\n };\n}\n\nfunction findNode(root: MountraFileTreeNode, path: string): MountraFileTreeNode | undefined {\n let node: MountraFileTreeNode | undefined = root;\n while (node && node.path !== path) {\n node = isPathWithin(path, node.path)\n ? node.children.find((child) => isPathWithin(path, child.path))\n : undefined;\n }\n return node;\n}\n\nfunction rebaseNode(node: MountraFileTreeNode, from: string, to: string): MountraFileTreeNode {\n return {\n ...node,\n ...(node.path === from ? { name: baseName(to) } : {}),\n path: rebasePath(node.path, from, to),\n children: node.children.map((child) => rebaseNode(child, from, to)),\n };\n}\n\n/** Mountra's order: directories first, then by name. */\nfunction compareChildren(\n left: { name: string; isDirectory: boolean },\n right: { name: string; isDirectory: boolean },\n): number {\n return Number(right.isDirectory) - Number(left.isDirectory) || left.name.localeCompare(right.name);\n}\n\n/** Replace the child with the same path in place, or insert it in Mountra's order. */\nfunction withChild<T extends { name: string; path: string; isDirectory: boolean }>(children: T[], child: T): T[] {\n const result = [...children];\n const existing = result.findIndex((candidate) => candidate.path === child.path);\n if (existing >= 0) {\n result[existing] = child;\n return result;\n }\n const position = result.findIndex((candidate) => compareChildren(child, candidate) < 0);\n result.splice(position < 0 ? result.length : position, 0, child);\n return result;\n}\n\nfunction recordKey(kind: MetadataCacheKind, path: string): string {\n return `${kind}:${path}`;\n}\n\n/**\n * The records an update needs, loaded from the store. Updates mutate the\n * loaded copies in place and mark them; `batch()` collects the result.\n */\nclass MetadataDraft {\n private readonly records = new Map<string, MetadataCacheRecord>();\n private readonly changed = new Set<string>();\n private readonly removed = new Map<string, { kind: MetadataCacheKind; path: string }>();\n\n constructor(records: MetadataCacheRecord[]) {\n for (const record of records) {\n this.records.set(recordKey(record.kind, record.path), record);\n }\n }\n\n list(path: string): MetadataListRecord | undefined {\n const record = this.records.get(recordKey(\"list\", path));\n return record?.kind === \"list\" ? record : undefined;\n }\n\n tree(path: string): MetadataTreeRecord | undefined {\n const record = this.records.get(recordKey(\"tree\", path));\n return record?.kind === \"tree\" ? record : undefined;\n }\n\n /** Loaded trees that hold `path`: those rooted at `path` or at one of its ancestors. */\n treesContaining(path: string): MetadataTreeRecord[] {\n return [...this.records.values()].filter(\n (record): record is MetadataTreeRecord => record.kind === \"tree\" && isPathWithin(path, record.path),\n );\n }\n\n /** Loaded records at `path` or below it. */\n within(path: string): MetadataCacheRecord[] {\n return [...this.records.values()].filter((record) => isPathWithin(record.path, path));\n }\n\n put(record: MetadataCacheRecord): void {\n const key = recordKey(record.kind, record.path);\n this.records.set(key, record);\n this.removed.delete(key);\n this.changed.add(key);\n }\n\n /** Mark a loaded record that was changed in place. */\n touch(record: MetadataCacheRecord): void {\n this.changed.add(recordKey(record.kind, record.path));\n }\n\n remove(record: { kind: MetadataCacheKind; path: string }): void {\n const key = recordKey(record.kind, record.path);\n this.records.delete(key);\n this.changed.delete(key);\n this.removed.set(key, { kind: record.kind, path: record.path });\n }\n\n batch(): MetadataCacheBatch {\n return {\n put: [...this.changed].map((key) => this.records.get(key)!),\n remove: [...this.removed.values()],\n };\n }\n\n findEntry(path: string): MountraFileEntry | undefined {\n return this.list(parentOf(path))?.entries.find((entry) => entry.path === path);\n }\n\n /** The node of `path` with its complete subtree, from any loaded tree. */\n findNode(path: string): MountraFileTreeNode | undefined {\n for (const tree of this.treesContaining(path)) {\n const node = findNode(tree.root, path);\n if (node) {\n return node;\n }\n }\n return undefined;\n }\n\n /** Remove `path` from the listing and the trees that show it. */\n removeEntry(path: string): void {\n const parentPath = parentOf(path);\n const list = this.list(parentPath);\n if (list?.entries.some((entry) => entry.path === path)) {\n list.entries = list.entries.filter((entry) => entry.path !== path);\n this.touch(list);\n }\n for (const tree of this.treesContaining(parentPath)) {\n const parent = findNode(tree.root, parentPath);\n if (parent?.children.some((child) => child.path === path)) {\n parent.children = parent.children.filter((child) => child.path !== path);\n this.touch(tree);\n }\n }\n }\n\n /**\n * Show `path` in its parent's listing and in the trees holding its parent.\n * A record that cannot show it faithfully, because the entry or the\n * complete node is unknown, is dropped instead.\n */\n insertEntry(path: string, entry: MountraFileEntry | null, node: MountraFileTreeNode | null): void {\n const parentPath = parentOf(path);\n const list = this.list(parentPath);\n if (list && entry) {\n list.entries = withChild(list.entries, entry);\n this.touch(list);\n } else if (list) {\n this.remove(list);\n }\n for (const tree of this.treesContaining(parentPath)) {\n const parent = findNode(tree.root, parentPath);\n if (node && parent?.isDirectory) {\n parent.children = withChild(parent.children, structuredClone(node));\n this.touch(tree);\n } else {\n this.remove(tree);\n }\n }\n }\n\n removeSubtree(path: string): void {\n for (const record of this.within(path)) {\n this.remove(record);\n }\n }\n\n /** Re-key the records at or below `from` to `to`, rewriting the paths they hold. */\n moveSubtree(from: string, to: string): void {\n for (const record of this.within(from)) {\n this.remove(record);\n const path = rebasePath(record.path, from, to);\n this.put(\n record.kind === \"list\"\n ? {\n ...record,\n path,\n entries: record.entries.map((entry) => ({ ...entry, path: rebasePath(entry.path, from, to) })),\n }\n : { ...record, path, root: rebaseNode(record.root, from, to) },\n );\n }\n }\n}\n\ninterface LoadScope {\n lists?: string[];\n trees?: string[];\n /** Load every record at or below these paths. */\n subtrees?: string[];\n}\n\n/** What a change reads: the parent listings and the trees holding the parents of its paths. */\nfunction changeScope(change: MetadataChange): LoadScope {\n const paths = change.type === \"move\" || change.type === \"copy\" ? [change.fromPath, change.toPath] : [change.path];\n return {\n lists: paths.map(parentOf),\n trees: paths.flatMap((path) => selfAndAncestors(parentOf(path))),\n // A copy keeps its source; any other change makes records below its paths stale or moves them.\n subtrees: change.type === \"copy\" ? [change.toPath] : paths,\n };\n}\n\nfunction patchChange(draft: MetadataDraft, change: MetadataChange, now: number): void {\n switch (change.type) {\n case \"create\": {\n const previousEntry = draft.findEntry(change.path);\n const previousNode = draft.findNode(change.path);\n // Records below a path that did not exist, or was a file, are stale.\n draft.removeSubtree(change.path);\n if (change.ino === undefined) {\n draft.insertEntry(change.path, null, null);\n return;\n }\n const fields = {\n name: baseName(change.path),\n path: change.path,\n ino: change.ino,\n isDirectory: change.isDirectory,\n size: change.size,\n mtimeMs: now,\n };\n // Overwriting a file keeps its owner and access time until Mountra reports them.\n const sameKind = (previous?: { isDirectory: boolean }) => previous?.isDirectory === change.isDirectory;\n draft.insertEntry(\n change.path,\n { atimeMs: now, ...(sameKind(previousEntry) ? previousEntry : {}), ...fields },\n { ...(sameKind(previousNode) ? previousNode : {}), ...fields, children: [] },\n );\n return;\n }\n case \"remove\":\n draft.removeEntry(change.path);\n draft.removeSubtree(change.path);\n return;\n case \"move\": {\n const { fromPath, toPath } = change;\n if (fromPath === toPath) {\n return;\n }\n const entry = draft.findEntry(fromPath);\n const node = draft.findNode(fromPath);\n draft.removeEntry(fromPath);\n draft.removeSubtree(toPath);\n draft.moveSubtree(fromPath, toPath);\n const fields = { name: baseName(toPath), path: toPath, ino: change.ino };\n const movedEntry = entry ? { ...entry, ...fields } : null;\n draft.insertEntry(\n toPath,\n movedEntry,\n node\n ? { ...rebaseNode(node, fromPath, toPath), ino: change.ino }\n : movedEntry && !movedEntry.isDirectory\n ? nodeFromEntry(movedEntry, [])\n : null,\n );\n return;\n }\n case \"copy\": {\n const source = draft.findEntry(change.fromPath) ?? draft.findNode(change.fromPath);\n draft.removeSubtree(change.toPath);\n if (!source || source.isDirectory) {\n draft.insertEntry(change.toPath, null, null);\n return;\n }\n // The copy belongs to the caller, so the source's owner is not carried over.\n const fields = {\n name: baseName(change.toPath),\n path: change.toPath,\n ino: change.ino,\n isDirectory: false,\n size: source.size,\n mtimeMs: now,\n };\n draft.insertEntry(change.toPath, { ...fields, atimeMs: now }, { ...fields, children: [] });\n return;\n }\n }\n}\n\n/** The children of `directory` as `entries` list them, or null when a subdirectory's subtree is unknown. */\nfunction childrenFromEntries(\n directory: MountraFileTreeNode,\n entries: MountraFileEntry[],\n): MountraFileTreeNode[] | null {\n const children: MountraFileTreeNode[] = [];\n for (const entry of entries) {\n const previous = directory.children.find((child) => child.path === entry.path);\n if (!entry.isDirectory) {\n children.push(nodeFromEntry(entry, []));\n } else if (previous?.isDirectory && previous.ino === entry.ino) {\n children.push(nodeFromEntry(entry, previous.children));\n } else {\n return null;\n }\n }\n return children;\n}\n\n/** `entries` refreshed from `nodes`, or null when a node has no entry to take its listing-only fields from. */\nfunction entriesFromNodes(\n entries: MountraFileEntry[],\n nodes: MountraFileTreeNode[],\n): MountraFileEntry[] | null {\n const previous = new Map(entries.map((entry) => [entry.path, entry]));\n const fresh = new Map(nodes.map((node) => [node.path, node]));\n for (const node of nodes) {\n const entry = previous.get(node.path);\n if (!entry || entry.ino !== node.ino || entry.isDirectory !== node.isDirectory) {\n return null;\n }\n }\n return entries\n .filter((entry) => fresh.has(entry.path))\n .map((entry) => entryFromNode(fresh.get(entry.path)!, entry));\n}\n\n/** Store a fetched listing and refresh the trees that hold its directory. */\nfunction patchFetchedList(draft: MetadataDraft, record: MetadataListRecord): void {\n if ((draft.list(record.path)?.fetchedAt ?? 0) > record.fetchedAt) {\n return;\n }\n draft.put(record);\n for (const tree of draft.treesContaining(record.path)) {\n if (tree.fetchedAt > record.fetchedAt) {\n continue;\n }\n const directory = findNode(tree.root, record.path);\n const children = directory?.isDirectory ? childrenFromEntries(directory, record.entries) : null;\n if (directory && children) {\n directory.children = children;\n draft.touch(tree);\n } else {\n draft.remove(tree);\n }\n }\n}\n\n/** Store a fetched tree and refresh the listings and trees it overlaps. */\nfunction patchFetchedTree(draft: MetadataDraft, record: MetadataTreeRecord): void {\n if ((draft.tree(record.path)?.fetchedAt ?? 0) > record.fetchedAt) {\n return;\n }\n draft.put(record);\n for (const other of draft.within(record.path)) {\n if (other === record || other.fetchedAt > record.fetchedAt) {\n continue;\n }\n const node = findNode(record.root, other.path);\n if (other.kind === \"tree\") {\n if (node?.isDirectory) {\n draft.put({ ...other, root: structuredClone(node), fetchedAt: record.fetchedAt });\n } else {\n draft.remove(other);\n }\n continue;\n }\n const entries = node?.isDirectory ? entriesFromNodes(other.entries, node.children) : null;\n if (entries) {\n other.entries = entries;\n draft.touch(other);\n } else {\n draft.remove(other);\n }\n }\n if (record.path === \"/\") {\n return;\n }\n const parentPath = parentOf(record.path);\n for (const tree of draft.treesContaining(parentPath)) {\n if (tree.fetchedAt > record.fetchedAt) {\n continue;\n }\n const parent = findNode(tree.root, parentPath);\n if (parent?.isDirectory) {\n parent.children = withChild(parent.children, structuredClone(record.root));\n draft.touch(tree);\n } else {\n draft.remove(tree);\n }\n }\n}\n\n/** Cache policy of one client. Cache failures never fail a metadata call. */\nexport class MetadataCache {\n readonly maxEntries: number;\n private readonly store: MetadataCacheStore;\n /** Per workspace, how many writes this client has applied. */\n private readonly writeSeqs = new Map<string, number>();\n /** Per workspace, the tail of the queue that serializes cache updates. */\n private readonly queues = new Map<string, Promise<void>>();\n\n constructor(options: MetadataCacheOptions) {\n this.maxEntries = options.maxEntries ?? DEFAULT_MAX_ENTRIES;\n if (!Number.isSafeInteger(this.maxEntries) || this.maxEntries <= 0) {\n throw new RangeError(\"metadataCache.maxEntries must be a positive safe integer\");\n }\n this.store = options.store ?? new IndexedDBMetadataCacheStore();\n }\n\n async get(workspace: string, kind: MetadataCacheKind, path: string): Promise<MetadataCacheRecord | null> {\n try {\n const record = await this.store.get(workspace, kind, path);\n return record?.kind === kind && record.path === path ? record : null;\n } catch {\n return null;\n }\n }\n\n beginFetch(workspace: string): MetadataFetchTicket {\n return { startedAt: Date.now(), writeSeq: this.writeSeqs.get(workspace) ?? 0 };\n }\n\n /** Cache a fetched result, and bring the records it overlaps up to date with it. */\n async storeFetched(workspace: string, record: MetadataCacheRecord, ticket: MetadataFetchTicket): Promise<void> {\n await this.update(workspace, ticket, async () => {\n if (record.kind === \"list\") {\n const draft = await this.load(workspace, { lists: [record.path], trees: selfAndAncestors(record.path) });\n patchFetchedList(draft, record);\n return draft;\n }\n const draft = await this.load(workspace, { trees: selfAndAncestors(record.path), subtrees: [record.path] });\n patchFetchedTree(draft, record);\n return draft;\n }).catch(() => undefined);\n }\n\n /** Mountra reported that `path` does not exist. */\n async forgetFetched(workspace: string, path: string, ticket: MetadataFetchTicket): Promise<void> {\n const change: MetadataChange = { type: \"remove\", path };\n await this.update(workspace, ticket, async () => {\n const draft = await this.load(workspace, changeScope(change));\n patchChange(draft, change, Date.now());\n return draft;\n }).catch(() => undefined);\n }\n\n /** Reflect a write that Mountra completed. */\n async applyChange(workspace: string, change: MetadataChange): Promise<void> {\n // Counted at once, so fetches still waiting to be cached are skipped.\n this.writeSeqs.set(workspace, (this.writeSeqs.get(workspace) ?? 0) + 1);\n await this.update(workspace, null, async () => {\n const draft = await this.load(workspace, changeScope(change));\n patchChange(draft, change, Date.now());\n return draft;\n }).catch(() =>\n // A write that cannot be reflected must not leave records that contradict it.\n this.store.clear(workspace).catch(() => undefined),\n );\n }\n\n clear(workspace?: string): Promise<void> {\n return this.store.clear(workspace);\n }\n\n /**\n * Run updates of one workspace one at a time. An update for a fetch is\n * dropped when this client completed a write since the fetch started: the\n * result may predate that write.\n */\n private update(\n workspace: string,\n ticket: MetadataFetchTicket | null,\n build: () => Promise<MetadataDraft>,\n ): Promise<void> {\n const run = async () => {\n if (ticket && ticket.writeSeq !== (this.writeSeqs.get(workspace) ?? 0)) {\n return;\n }\n const batch = (await build()).batch();\n if (batch.put.length > 0 || batch.remove.length > 0) {\n await this.store.write(workspace, batch, this.maxEntries);\n }\n };\n const result = (this.queues.get(workspace) ?? Promise.resolve()).then(run);\n const tail = result.catch(() => undefined);\n this.queues.set(workspace, tail);\n void tail.then(() => {\n if (this.queues.get(workspace) === tail) {\n this.queues.delete(workspace);\n }\n });\n return result;\n }\n\n private async load(workspace: string, scope: LoadScope): Promise<MetadataDraft> {\n const [records, subtrees] = await Promise.all([\n Promise.all([\n ...[...new Set(scope.lists)].map((path) => this.store.get(workspace, \"list\", path)),\n ...[...new Set(scope.trees)].map((path) => this.store.get(workspace, \"tree\", path)),\n ]),\n Promise.all([...new Set(scope.subtrees)].map((path) => this.store.getSubtree(workspace, path))),\n ]);\n return new MetadataDraft([\n ...records.filter((record): record is MetadataCacheRecord => record !== null),\n ...subtrees.flat(),\n ]);\n }\n}\n","import { DownloadCache } from \"./cache\";\nimport type { DownloadCacheOptions, DownloadCacheUsage } from \"./cache\";\nimport { IndexedDBDownloadCheckpointStore, MountraDownloader } from \"./download\";\nimport type {\n DownloadCheckpoint,\n DownloadCheckpointStore,\n DownloadFileOptions,\n DownloadResult,\n DownloadResumeOptions,\n ExportFileOptions,\n ExportFileResponse,\n} from \"./download\";\nimport { MountraApiError } from \"./errors\";\nimport { MountraFile, normalizeMountraFileLocator } from \"./file\";\nimport type { MountraFileLocator } from \"./file\";\nimport { MountraMetadata } from \"./metadata\";\nimport type {\n CopyOptions,\n DeleteOptions,\n FileOperationResult,\n ListOptions,\n ListResult,\n MkdirOptions,\n MoveOptions,\n RenameOptions,\n TreeOptions,\n TreeResult,\n} from \"./metadata\";\nimport { MetadataCache } from \"./metadata-cache\";\nimport type { MetadataCacheOptions } from \"./metadata-cache\";\n\nexport type ChunkMethod = \"none\" | \"fix\";\nexport type WorkspaceId = number | string;\n\nexport const JUMBO_CHUNK_THRESHOLD_BYTES = 128 * 1024 * 1024;\nexport const MIN_S3_MULTIPART_PART_SIZE_BYTES = 5 * 1024 * 1024;\nexport const DEFAULT_S3_MULTIPART_PART_SIZE_BYTES = 16 * 1024 * 1024;\nexport const MAX_S3_MULTIPART_PARTS = 10_000;\n\nexport interface WorkspaceSelector {\n workspaceCuid?: string;\n workspaceId?: WorkspaceId;\n}\n\nexport type AccessToken =\n | string\n | null\n | undefined\n | (() => string | null | undefined | Promise<string | null | undefined>);\n\nexport interface MountraClientOptions extends WorkspaceSelector {\n /** Mountra server origin, for example `https://mountra.example.com`. */\n baseUrl: string;\n /** API prefix. Set to an empty string when `baseUrl` already includes `/api`. */\n apiPrefix?: string;\n token?: AccessToken;\n /** Additional headers for Mountra API requests. They are never sent to signed URLs. */\n headers?: HeadersInit;\n fetch?: typeof globalThis.fetch;\n /** Adapter for S3 Multipart uploads used by chunks larger than 128 MiB. */\n jumboChunkUploader?: JumboChunkUploader;\n /** Durable local checkpoint store for jumbo Multipart uploads. */\n jumboChunkCheckpointStore?: JumboChunkCheckpointStore;\n /** S3 Multipart part size. Defaults to 16 MiB. */\n jumboPartSize?: number;\n /** IndexedDB-backed download checkpoint store. */\n downloadCheckpointStore?: DownloadCheckpointStore;\n /**\n * Cache downloaded chunks locally, per workspace, in IndexedDB. Disabled\n * unless set; pass `{}` for the defaults.\n */\n downloadCache?: DownloadCacheOptions;\n /**\n * Cache `list` and `tree` results locally, per workspace, in IndexedDB, so\n * reads with `mode: \"async\"` return at once. Disabled unless set; pass `{}`\n * for the defaults.\n */\n metadataCache?: MetadataCacheOptions;\n}\n\nexport interface UploadFileOptions extends WorkspaceSelector {\n path: string;\n /**\n * Maximum number of fixed-size chunks. Defaults to 1. Each chunk is\n * `ceil(size / chunkCount)` bytes except the last, so an uneven split may\n * produce fewer chunks.\n */\n chunkCount?: number;\n contentType?: string;\n nameConflictStrategy?: \"overwrite\" | \"keep_both\";\n signal?: AbortSignal;\n onProgress?: (progress: MountraProgress) => void;\n /** Persist this serializable context before the first chunk is uploaded. */\n onSessionPrepared?: (context: UploadSessionContext) => void | Promise<void>;\n /**\n * With the client's `downloadCache`, an uploaded file is cached by default so\n * downloading it needs no network. `no-store` only invalidates its old entry.\n */\n cache?: \"default\" | \"no-store\";\n}\n\nexport interface UploadResumeOptions extends WorkspaceSelector {\n signal?: AbortSignal;\n onProgress?: (progress: MountraProgress) => void;\n /** See `UploadFileOptions.cache`. */\n cache?: \"default\" | \"no-store\";\n}\n\nexport interface MountraProgress {\n phase: \"uploading\" | \"finishing\";\n uploadedBytes: number;\n totalBytes: number;\n uploadedChunks: number;\n totalChunks: number;\n uploadedParts?: number;\n totalParts?: number;\n}\n\nexport interface FileChunk {\n index: number;\n offset: number;\n size: number;\n blob: Blob;\n}\n\nexport interface UploadTarget {\n chunk_index: number;\n storage_key: string;\n put_method?: string;\n put_url?: string;\n put_headers: Record<string, string>;\n size: number;\n upload_required: boolean;\n}\n\nexport interface UploadSessionChunkContext {\n index: number;\n offset: number;\n size: number;\n sha256: string;\n}\n\nexport interface S3MultipartPart {\n partNumber: number;\n etag: string;\n size: number;\n sha256: string;\n}\n\nexport interface JumboChunkCreateInput {\n storageKey: string;\n contentType?: string;\n signal?: AbortSignal;\n}\n\nexport interface JumboChunkUploadPartInput {\n storageKey: string;\n uploadId: string;\n partNumber: number;\n body: Blob;\n signal?: AbortSignal;\n}\n\nexport interface JumboChunkCompleteInput {\n storageKey: string;\n uploadId: string;\n parts: Array<Pick<S3MultipartPart, \"partNumber\" | \"etag\">>;\n signal?: AbortSignal;\n}\n\n/**\n * Small S3 Multipart adapter. Implement these methods with the S3 SDK used by\n * the host application. Reusing a part number is intentional: S3 replaces\n * the previous part, which makes retries idempotent.\n */\nexport interface JumboChunkUploader {\n createMultipartUpload(input: JumboChunkCreateInput): Promise<{ uploadId: string }>;\n uploadPart(input: JumboChunkUploadPartInput): Promise<{ etag: string }>;\n completeMultipartUpload(input: JumboChunkCompleteInput): Promise<void>;\n abortMultipartUpload?(input: {\n storageKey: string;\n uploadId: string;\n signal?: AbortSignal;\n }): Promise<void>;\n}\n\nexport interface JumboChunkCheckpoint {\n version: 1;\n storageKey: string;\n chunkIndex: number;\n chunkSize: number;\n chunkSha256: string;\n partSize: number;\n uploadId: string;\n completed: boolean;\n completing: boolean;\n parts: S3MultipartPart[];\n}\n\nexport interface JumboChunkCheckpointStore {\n load(key: string): Promise<JumboChunkCheckpoint | null>;\n save(key: string, checkpoint: JumboChunkCheckpoint): Promise<void>;\n remove(key: string): Promise<void>;\n}\n\nexport interface S3MultipartClient {\n createMultipartUpload(input: {\n bucket: string;\n key: string;\n contentType?: string;\n signal?: AbortSignal;\n }): Promise<{ uploadId: string }>;\n uploadPart(input: {\n bucket: string;\n key: string;\n uploadId: string;\n partNumber: number;\n body: Blob;\n signal?: AbortSignal;\n }): Promise<{ etag: string }>;\n completeMultipartUpload(input: {\n bucket: string;\n key: string;\n uploadId: string;\n parts: Array<Pick<S3MultipartPart, \"partNumber\" | \"etag\">>;\n signal?: AbortSignal;\n }): Promise<void>;\n abortMultipartUpload?(input: {\n bucket: string;\n key: string;\n uploadId: string;\n signal?: AbortSignal;\n }): Promise<void>;\n}\n\n/** Serializable metadata a client must persist alongside its file/blob handle. */\nexport interface UploadSessionContext {\n uploadId: string;\n path: string;\n fileSize: number;\n contentHash: string;\n chunkMethod: \"none\" | \"fix\" | \"cdc\";\n chunks: UploadSessionChunkContext[];\n contentType?: string;\n}\n\nexport interface PrepareUploadResponse {\n upload_id: string;\n path: string;\n expires_in_seconds: number;\n chunk_method: \"none\" | \"fix\" | \"cdc\";\n session_status: \"prepared\" | \"uploaded\" | \"finished\" | \"aborted\" | \"expired\";\n upload_targets: UploadTarget[];\n}\n\nexport interface UploadStatusChunk {\n chunk_index: number;\n offset: number;\n size: number;\n sha256: string;\n storage_key: string;\n status: \"pending\" | \"uploaded\";\n upload_required: boolean;\n put_method?: string;\n put_url?: string;\n put_headers: Record<string, string>;\n}\n\nexport interface UploadStatusResponse {\n upload_id: string;\n path: string;\n storage_key: string;\n size: number;\n chunk_method: \"none\" | \"fix\" | \"cdc\";\n session_status: \"prepared\" | \"uploaded\" | \"finished\" | \"aborted\" | \"expired\";\n finish_status:\n | \"awaiting_upload\"\n | \"awaiting_finish\"\n | \"awaiting_chunks\"\n | \"completed\"\n | \"aborted\"\n | \"expired\";\n total_chunks: number;\n uploaded_chunks: number;\n uploaded_bytes: number;\n chunks: UploadStatusChunk[];\n ino?: number;\n}\n\nexport interface FinishUploadResponse {\n upload_id: string;\n path: string;\n storage_key: string;\n size: number;\n chunk_method: \"none\" | \"fix\" | \"cdc\";\n session_status: \"prepared\" | \"uploaded\" | \"finished\" | \"aborted\" | \"expired\";\n finish_status:\n | \"awaiting_upload\"\n | \"awaiting_finish\"\n | \"awaiting_chunks\"\n | \"completed\"\n | \"aborted\"\n | \"expired\";\n ino?: number;\n}\n\nexport type UploadResult = FinishUploadResponse;\n\nexport interface PreparedUpload {\n response: PrepareUploadResponse;\n chunks: FileChunk[];\n chunkHashes: string[];\n contentHash: string;\n context: UploadSessionContext;\n}\n\nconst memoryCheckpointRecords = new Map<string, string>();\n\nfunction parseJumboCheckpoint(value: unknown): JumboChunkCheckpoint | null {\n if (!isRecord(value) || value.version !== 1 || typeof value.storageKey !== \"string\") {\n return null;\n }\n if (\n typeof value.chunkIndex !== \"number\" ||\n typeof value.chunkSize !== \"number\" ||\n typeof value.chunkSha256 !== \"string\" ||\n typeof value.partSize !== \"number\" ||\n typeof value.uploadId !== \"string\" ||\n !Array.isArray(value.parts)\n ) {\n return null;\n }\n\n const parts: S3MultipartPart[] = [];\n for (const part of value.parts) {\n if (!isRecord(part)) {\n return null;\n }\n if (\n typeof part.partNumber !== \"number\" ||\n typeof part.etag !== \"string\" ||\n typeof part.size !== \"number\" ||\n typeof part.sha256 !== \"string\"\n ) {\n return null;\n }\n parts.push({\n partNumber: part.partNumber,\n etag: part.etag,\n size: part.size,\n sha256: part.sha256,\n });\n }\n\n return {\n version: 1,\n storageKey: value.storageKey,\n chunkIndex: value.chunkIndex,\n chunkSize: value.chunkSize,\n chunkSha256: value.chunkSha256,\n partSize: value.partSize,\n uploadId: value.uploadId,\n completed: value.completed === true,\n completing: value.completing === true,\n parts,\n };\n}\n\nexport class InMemoryJumboChunkCheckpointStore implements JumboChunkCheckpointStore {\n private readonly records = new Map<string, JumboChunkCheckpoint>();\n\n async load(key: string): Promise<JumboChunkCheckpoint | null> {\n return this.records.get(key) ?? null;\n }\n\n async save(key: string, checkpoint: JumboChunkCheckpoint): Promise<void> {\n this.records.set(key, {\n ...checkpoint,\n parts: checkpoint.parts.map((part) => ({ ...part })),\n });\n }\n\n async remove(key: string): Promise<void> {\n this.records.delete(key);\n }\n}\n\nexport class LocalStorageJumboChunkCheckpointStore implements JumboChunkCheckpointStore {\n private readonly prefix: string;\n\n constructor(prefix = \"mountra-sdk:jumbo:\") {\n this.prefix = prefix;\n }\n\n async load(key: string): Promise<JumboChunkCheckpoint | null> {\n const storageKey = this.storageKey(key);\n const raw = this.getStorage()?.getItem(storageKey) ?? memoryCheckpointRecords.get(storageKey);\n if (!raw) {\n return null;\n }\n try {\n return parseJumboCheckpoint(JSON.parse(raw));\n } catch {\n await this.remove(key);\n return null;\n }\n }\n\n async save(key: string, checkpoint: JumboChunkCheckpoint): Promise<void> {\n const storageKey = this.storageKey(key);\n const serialized = JSON.stringify(checkpoint);\n const storage = this.getStorage();\n if (storage) {\n storage.setItem(storageKey, serialized);\n } else {\n memoryCheckpointRecords.set(storageKey, serialized);\n }\n }\n\n async remove(key: string): Promise<void> {\n const storageKey = this.storageKey(key);\n this.getStorage()?.removeItem(storageKey);\n memoryCheckpointRecords.delete(storageKey);\n }\n\n private storageKey(key: string): string {\n return `${this.prefix}${key}`;\n }\n\n private getStorage(): Storage | null {\n try {\n return globalThis.localStorage ?? null;\n } catch {\n return null;\n }\n }\n}\n\nexport class S3MultipartUploader implements JumboChunkUploader {\n private readonly bucket: string;\n private readonly client: S3MultipartClient;\n\n constructor(input: { bucket: string; client: S3MultipartClient }) {\n const bucket = input.bucket.trim();\n if (!bucket) {\n throw new TypeError(\"S3 bucket is required\");\n }\n this.bucket = bucket;\n this.client = input.client;\n }\n\n createMultipartUpload(input: JumboChunkCreateInput): Promise<{ uploadId: string }> {\n return this.client.createMultipartUpload({\n bucket: this.bucket,\n key: input.storageKey,\n contentType: input.contentType,\n signal: input.signal,\n });\n }\n\n uploadPart(input: JumboChunkUploadPartInput): Promise<{ etag: string }> {\n return this.client.uploadPart({\n bucket: this.bucket,\n key: input.storageKey,\n uploadId: input.uploadId,\n partNumber: input.partNumber,\n body: input.body,\n signal: input.signal,\n });\n }\n\n completeMultipartUpload(input: JumboChunkCompleteInput): Promise<void> {\n return this.client.completeMultipartUpload({\n bucket: this.bucket,\n key: input.storageKey,\n uploadId: input.uploadId,\n parts: input.parts,\n signal: input.signal,\n });\n }\n\n abortMultipartUpload(input: {\n storageKey: string;\n uploadId: string;\n signal?: AbortSignal;\n }): Promise<void> {\n if (!this.client.abortMultipartUpload) {\n return Promise.resolve();\n }\n return this.client.abortMultipartUpload({\n bucket: this.bucket,\n key: input.storageKey,\n uploadId: input.uploadId,\n signal: input.signal,\n });\n }\n}\n\nfunction assertPositiveInteger(value: number, name: string): void {\n if (!Number.isSafeInteger(value) || value <= 0) {\n throw new RangeError(`${name} must be a positive safe integer`);\n }\n}\n\nfunction assertMultipartPartSize(value: number): void {\n assertPositiveInteger(value, \"jumboPartSize\");\n if (value < MIN_S3_MULTIPART_PART_SIZE_BYTES) {\n throw new RangeError(\n `jumboPartSize must be at least ${MIN_S3_MULTIPART_PART_SIZE_BYTES} bytes for S3 Multipart uploads`,\n );\n }\n}\n\nfunction normalizeBaseUrl(value: string): string {\n const trimmed = value.trim().replace(/\\/+$/, \"\");\n if (!trimmed) {\n throw new TypeError(\"baseUrl is required\");\n }\n return trimmed;\n}\n\nfunction normalizeApiPrefix(value: string): string {\n const trimmed = value.trim();\n if (!trimmed || trimmed === \"/\") {\n return \"\";\n }\n return `/${trimmed.replace(/^\\/+|\\/+$/g, \"\")}`;\n}\n\nfunction getWorkspaceBody(\n clientSelector: WorkspaceSelector,\n requestSelector: WorkspaceSelector,\n): Record<string, string | number> {\n const workspaceCuid = requestSelector.workspaceCuid ?? clientSelector.workspaceCuid;\n const workspaceId = requestSelector.workspaceId ?? clientSelector.workspaceId;\n if (workspaceCuid === undefined && workspaceId === undefined) {\n throw new TypeError(\"workspaceCuid or workspaceId is required\");\n }\n\n return {\n ...(workspaceCuid !== undefined ? { workspace_cuid: workspaceCuid } : {}),\n ...(workspaceId !== undefined ? { workspace_id: workspaceId } : {}),\n };\n}\n\nfunction throwIfAborted(signal?: AbortSignal): void {\n if (!signal?.aborted) {\n return;\n }\n throw new DOMException(\"The upload was aborted\", \"AbortError\");\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === \"object\" && value !== null;\n}\n\nfunction parseApiErrorBody(body: unknown): { message?: string; code?: string } {\n if (!isRecord(body)) {\n return {};\n }\n return {\n message: typeof body.error === \"string\" ? body.error : undefined,\n code: typeof body.code === \"string\" ? body.code : undefined,\n };\n}\n\nfunction ensurePrepareResponse(value: unknown): PrepareUploadResponse {\n if (!isRecord(value) || typeof value.upload_id !== \"string\") {\n throw new TypeError(\"Mountra prepare response is invalid\");\n }\n if (!Array.isArray(value.upload_targets)) {\n throw new TypeError(\"Mountra prepare response has no upload targets\");\n }\n return value as unknown as PrepareUploadResponse;\n}\n\nfunction ensureFinishResponse(value: unknown): FinishUploadResponse {\n if (!isRecord(value) || typeof value.upload_id !== \"string\") {\n throw new TypeError(\"Mountra finish response is invalid\");\n }\n return value as unknown as FinishUploadResponse;\n}\n\nfunction ensureUploadStatusResponse(value: unknown): UploadStatusResponse {\n if (!isRecord(value) || typeof value.upload_id !== \"string\") {\n throw new TypeError(\"Mountra upload status response is invalid\");\n }\n if (!Array.isArray(value.chunks)) {\n throw new TypeError(\"Mountra upload status response has no chunk states\");\n }\n return value as unknown as UploadStatusResponse;\n}\n\nexport function splitFileIntoChunks(file: Blob, chunkCount = 1): FileChunk[] {\n assertPositiveInteger(chunkCount, \"chunkCount\");\n\n if (file.size === 0) {\n return [{ index: 0, offset: 0, size: 0, blob: file.slice(0, 0) }];\n }\n if (chunkCount > file.size) {\n throw new RangeError(\"chunkCount cannot be greater than the file size in bytes\");\n }\n\n const chunkSize = Math.ceil(file.size / chunkCount);\n const chunks: FileChunk[] = [];\n // `fix` chunking requires every chunk but the last to be exactly chunkSize, so an\n // uneven split yields fewer chunks than requested rather than empty trailing ones.\n for (let index = 0, offset = 0; offset < file.size; index += 1, offset += chunkSize) {\n const end = Math.min(offset + chunkSize, file.size);\n chunks.push({\n index,\n offset,\n size: end - offset,\n blob: file.slice(offset, end),\n });\n }\n return chunks;\n}\n\nexport function isJumboChunk(size: number): boolean {\n return size > JUMBO_CHUNK_THRESHOLD_BYTES;\n}\n\nexport async function sha256Hex(blob: Blob): Promise<string> {\n const subtle = globalThis.crypto?.subtle;\n if (!subtle) {\n throw new Error(\"Web Crypto SHA-256 is not available in this environment\");\n }\n\n const digest = await subtle.digest(\"SHA-256\", await blob.arrayBuffer());\n return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, \"0\")).join(\"\");\n}\n\nexport class MountraClient {\n private readonly baseUrl: string;\n private readonly apiPrefix: string;\n private readonly clientSelector: WorkspaceSelector;\n private readonly token?: AccessToken;\n private readonly headers?: HeadersInit;\n private readonly fetchImpl: typeof globalThis.fetch;\n private readonly jumboChunkUploader?: JumboChunkUploader;\n private readonly jumboChunkCheckpointStore: JumboChunkCheckpointStore;\n private readonly jumboPartSize: number;\n private readonly downloader: MountraDownloader;\n private readonly metadata: MountraMetadata;\n\n constructor(options: MountraClientOptions) {\n this.baseUrl = normalizeBaseUrl(options.baseUrl);\n this.apiPrefix = normalizeApiPrefix(options.apiPrefix ?? \"/api\");\n this.clientSelector = {\n workspaceCuid: options.workspaceCuid,\n workspaceId: options.workspaceId,\n };\n this.token = options.token;\n this.headers = options.headers;\n this.jumboChunkUploader = options.jumboChunkUploader;\n this.jumboChunkCheckpointStore =\n options.jumboChunkCheckpointStore ?? new LocalStorageJumboChunkCheckpointStore();\n this.jumboPartSize = options.jumboPartSize ?? DEFAULT_S3_MULTIPART_PART_SIZE_BYTES;\n assertMultipartPartSize(this.jumboPartSize);\n\n const fetchImpl = options.fetch ?? globalThis.fetch?.bind(globalThis);\n if (!fetchImpl) {\n throw new Error(\"fetch is not available; provide fetch in MountraClientOptions\");\n }\n this.fetchImpl = fetchImpl;\n this.downloader = new MountraDownloader({\n baseUrl: this.baseUrl,\n clientSelector: this.clientSelector,\n fetchImpl: this.fetchImpl,\n checkpointStore: options.downloadCheckpointStore ?? new IndexedDBDownloadCheckpointStore(),\n cache: options.downloadCache ? new DownloadCache(options.downloadCache) : null,\n requestJson: (path, body, signal) => this.requestJson(path, body, signal),\n });\n this.metadata = new MountraMetadata({\n baseUrl: this.baseUrl,\n clientSelector: this.clientSelector,\n cache: options.metadataCache ? new MetadataCache(options.metadataCache) : null,\n requestJson: (path, body, signal) => this.requestJson(path, body, signal),\n invalidateDownloads: (selector, paths) => this.downloader.invalidateCachedPaths(selector, paths),\n });\n }\n\n async exportFile(options: ExportFileOptions): Promise<ExportFileResponse> {\n return this.downloader.exportFile(options);\n }\n\n async downloadFile(options: DownloadFileOptions): Promise<DownloadResult> {\n return this.downloader.downloadFile(options);\n }\n\n async downloadExport(\n exported: ExportFileResponse,\n options?: DownloadFileOptions,\n ): Promise<DownloadResult> {\n return this.downloader.downloadExport(exported, options);\n }\n\n async resumeDownload(\n downloadKey: string,\n options?: DownloadResumeOptions,\n ): Promise<DownloadResult> {\n return this.downloader.resumeDownload(downloadKey, options);\n }\n\n listResumableDownloads(): Promise<DownloadCheckpoint[]> {\n return this.downloader.listResumableDownloads();\n }\n\n clearDownloadCheckpoint(downloadKey: string): Promise<void> {\n return this.downloader.clearDownloadCheckpoint(downloadKey);\n }\n\n /** Clear the download cache of one workspace, or of every workspace when none is given. */\n clearDownloadCache(selector?: WorkspaceSelector): Promise<void> {\n return this.downloader.clearCache(selector);\n }\n\n getDownloadCacheUsage(selector?: WorkspaceSelector): Promise<DownloadCacheUsage> {\n return this.downloader.cacheUsage(selector);\n }\n\n /** List the entries of a directory. See `MetadataReadMode` for how `mode` uses the metadata cache. */\n list(options?: ListOptions): Promise<ListResult> {\n return this.metadata.list(options);\n }\n\n /** Return a directory with its complete subtree. See `MetadataReadMode` for how `mode` uses the metadata cache. */\n tree(options?: TreeOptions): Promise<TreeResult> {\n return this.metadata.tree(options);\n }\n\n mkdir(options: MkdirOptions): Promise<FileOperationResult> {\n return this.metadata.mkdir(options);\n }\n\n rename(options: RenameOptions): Promise<FileOperationResult> {\n return this.metadata.rename(options);\n }\n\n move(options: MoveOptions): Promise<FileOperationResult> {\n return this.metadata.move(options);\n }\n\n copy(options: CopyOptions): Promise<FileOperationResult> {\n return this.metadata.copy(options);\n }\n\n delete(options: DeleteOptions): Promise<void> {\n return this.metadata.delete(options);\n }\n\n /** Clear the metadata cache of one workspace, or of every workspace when none is given. */\n clearMetadataCache(selector?: WorkspaceSelector): Promise<void> {\n return this.metadata.clearCache(selector);\n }\n\n /** Create a stable resource object for one file in this or another workspace. */\n file(locator: MountraFileLocator): MountraFile {\n return new MountraFile(\n this,\n normalizeMountraFileLocator(locator, this.clientSelector),\n );\n }\n\n async prepareUpload(file: Blob, options: UploadFileOptions): Promise<PreparedUpload> {\n const chunks = splitFileIntoChunks(file, options.chunkCount ?? 1);\n const chunkHashes = await Promise.all(chunks.map((chunk) => sha256Hex(chunk.blob)));\n const contentHash = await sha256Hex(file);\n const chunkMethod: ChunkMethod = chunks.length === 1 ? \"none\" : \"fix\";\n const contentType = options.contentType ?? (\"type\" in file ? file.type : undefined);\n\n throwIfAborted(options.signal);\n const response = ensurePrepareResponse(\n await this.requestJson(\"/upload/prepare\", {\n ...getWorkspaceBody(this.clientSelector, options),\n path: options.path,\n size: file.size,\n content_hash: contentHash,\n chunks: chunks.map((chunk, index) => ({\n chunk_index: chunk.index,\n size: chunk.size,\n sha256: chunkHashes[index]!,\n })),\n chunk_method: chunkMethod,\n ...(contentType ? { content_type: contentType } : {}),\n ...(options.nameConflictStrategy\n ? { name_conflict_strategy: options.nameConflictStrategy }\n : {}),\n }, options.signal),\n );\n\n const context: UploadSessionContext = {\n uploadId: response.upload_id,\n path: response.path,\n fileSize: file.size,\n contentHash,\n chunkMethod: response.chunk_method,\n chunks: chunks.map((chunk, index) => ({\n index: chunk.index,\n offset: chunk.offset,\n size: chunk.size,\n sha256: chunkHashes[index]!,\n })),\n ...(contentType ? { contentType } : {}),\n };\n await options.onSessionPrepared?.(context);\n\n return { response, chunks, chunkHashes, contentHash, context };\n }\n\n async uploadFile(file: Blob, options: UploadFileOptions): Promise<UploadResult> {\n const prepared = await this.prepareUpload(file, options);\n return this.uploadPreparedChunks(file, prepared.context, prepared.chunks, prepared.response.upload_targets, options);\n }\n\n /** Generic upload entry point. It selects PUT or S3 Multipart per chunk. */\n async upload(file: Blob, options: UploadFileOptions): Promise<UploadResult> {\n return this.uploadFile(file, options);\n }\n\n async getUploadStatus(\n uploadId: string,\n selector: WorkspaceSelector = {},\n signal?: AbortSignal,\n ): Promise<UploadStatusResponse> {\n if (!uploadId.trim()) {\n throw new TypeError(\"uploadId is required\");\n }\n return ensureUploadStatusResponse(\n await this.requestJson(\"/upload/status\", {\n ...getWorkspaceBody(this.clientSelector, selector),\n upload_id: uploadId,\n }, signal),\n );\n }\n\n /**\n * Resume a previously prepared session. The caller must restore the same\n * file/blob separately; this context only describes how that file was cut.\n */\n async resumeUpload(\n file: Blob,\n context: UploadSessionContext,\n options: UploadResumeOptions = {},\n ): Promise<UploadResult> {\n this.assertUploadContext(context, file);\n const actualChunkHashes = await Promise.all(\n context.chunks.map((chunk) => sha256Hex(file.slice(chunk.offset, chunk.offset + chunk.size))),\n );\n if (\n actualChunkHashes.some(\n (hash, index) => hash !== context.chunks[index]?.sha256,\n ) ||\n (await sha256Hex(file)) !== context.contentHash\n ) {\n throw new Error(\"The restored file does not match the upload context hashes\");\n }\n const chunks = context.chunks.map((chunk) => ({\n index: chunk.index,\n offset: chunk.offset,\n size: chunk.size,\n blob: file.slice(chunk.offset, chunk.offset + chunk.size),\n }));\n const status = await this.getUploadStatus(context.uploadId, options, options.signal);\n if (status.upload_id !== context.uploadId || status.size !== context.fileSize) {\n throw new Error(\"Mountra upload status does not match the saved upload context\");\n }\n if (status.chunks.length !== context.chunks.length) {\n throw new Error(\"Mountra upload status has a different chunk layout\");\n }\n for (const [index, chunk] of status.chunks.entries()) {\n const savedChunk = context.chunks[index]!;\n if (\n chunk.chunk_index !== savedChunk.index ||\n chunk.offset !== savedChunk.offset ||\n chunk.size !== savedChunk.size ||\n chunk.sha256 !== savedChunk.sha256\n ) {\n throw new Error(\"Mountra upload status has a different chunk layout\");\n }\n }\n\n return this.uploadPreparedChunks(file, context, chunks, status.chunks, options);\n }\n\n private async uploadPreparedChunks(\n file: Blob,\n context: UploadSessionContext,\n chunks: FileChunk[],\n targets: Array<UploadTarget | UploadStatusChunk>,\n options: UploadFileOptions | UploadResumeOptions,\n ): Promise<UploadResult> {\n const orderedTargets = [...targets].sort((left, right) => left.chunk_index - right.chunk_index);\n if (orderedTargets.length !== chunks.length) {\n throw new Error(\n `Mountra returned ${orderedTargets.length} upload targets for ${chunks.length} chunks`,\n );\n }\n\n let uploadedBytes = 0;\n let uploadedChunks = 0;\n const jumboCheckpointKeys = new Set<string>();\n for (const [position, target] of orderedTargets.entries()) {\n const chunk = chunks[target.chunk_index];\n if (!chunk || target.chunk_index !== position) {\n throw new Error(\"Mountra upload targets must contain contiguous chunk indexes\");\n }\n throwIfAborted(options.signal);\n\n if (isJumboChunk(chunk.size)) {\n const checkpointKey = this.buildJumboCheckpointKey(context, target, options);\n jumboCheckpointKeys.add(checkpointKey);\n if (target.upload_required) {\n await this.uploadJumboChunk(\n chunk,\n target,\n context,\n checkpointKey,\n options,\n uploadedBytes,\n uploadedChunks,\n orderedTargets.length,\n );\n }\n } else if (target.upload_required) {\n if (!target.put_url) {\n throw new Error(`Mountra upload target ${target.chunk_index} has no signed URL`);\n }\n const response = await this.fetchImpl(target.put_url, {\n method: target.put_method ?? \"PUT\",\n headers: target.put_headers ?? {},\n body: chunk.blob,\n ...(options.signal ? { signal: options.signal } : {}),\n });\n if (!response.ok) {\n throw new MountraApiError(\n `Signed upload for chunk ${target.chunk_index} failed with HTTP ${response.status}`,\n { status: response.status },\n );\n }\n }\n\n uploadedBytes += chunk.size;\n uploadedChunks += 1;\n options.onProgress?.({\n phase: \"uploading\",\n uploadedBytes,\n totalBytes: file.size,\n uploadedChunks,\n totalChunks: orderedTargets.length,\n });\n }\n\n throwIfAborted(options.signal);\n options.onProgress?.({\n phase: \"finishing\",\n uploadedBytes: file.size,\n totalBytes: file.size,\n uploadedChunks: orderedTargets.length,\n totalChunks: orderedTargets.length,\n });\n const finished = ensureFinishResponse(\n await this.requestJson(\n \"/upload/finish\",\n {\n ...getWorkspaceBody(this.clientSelector, options),\n upload_id: context.uploadId,\n },\n options.signal,\n ),\n );\n if (finished.finish_status !== \"completed\") {\n throw new Error(`Mountra upload did not finish successfully: ${finished.finish_status}`);\n }\n await this.metadata.recordUpload(this.cacheWorkspace(options), finished);\n await this.downloader.cacheUploadedFile(\n this.cacheWorkspace(options),\n {\n path: finished.path,\n ...(finished.ino !== undefined ? { ino: finished.ino } : {}),\n size: context.fileSize,\n ...(context.contentType ? { contentType: context.contentType } : {}),\n chunks: orderedTargets.map((target) => {\n const chunk = chunks[target.chunk_index]!;\n return {\n index: chunk.index,\n offset: chunk.offset,\n size: chunk.size,\n storageKey: target.storage_key,\n data: chunk.blob,\n };\n }),\n },\n options.cache,\n );\n await Promise.all(\n [...jumboCheckpointKeys].map((checkpointKey) =>\n this.jumboChunkCheckpointStore.remove(checkpointKey),\n ),\n );\n return finished;\n }\n\n private buildJumboCheckpointKey(\n context: UploadSessionContext,\n target: UploadTarget | UploadStatusChunk,\n selector: WorkspaceSelector,\n ): string {\n const workspaceCuid = selector.workspaceCuid ?? this.clientSelector.workspaceCuid ?? \"\";\n const workspaceId = selector.workspaceId ?? this.clientSelector.workspaceId ?? \"\";\n return encodeURIComponent(\n [\n this.baseUrl,\n workspaceCuid,\n workspaceId,\n target.storage_key,\n target.chunk_index,\n context.chunks[target.chunk_index]?.sha256 ?? \"\",\n ].join(\"|\"),\n );\n }\n\n private async uploadJumboChunk(\n chunk: FileChunk,\n target: UploadTarget | UploadStatusChunk,\n context: UploadSessionContext,\n checkpointKey: string,\n options: UploadFileOptions | UploadResumeOptions,\n baseUploadedBytes: number,\n uploadedChunks: number,\n totalChunks: number,\n ): Promise<void> {\n const uploader = this.jumboChunkUploader;\n if (!uploader) {\n throw new Error(\n `Chunk ${target.chunk_index} is larger than 128 MiB; configure jumboChunkUploader to use S3 Multipart uploads`,\n );\n }\n\n const totalParts = Math.ceil(chunk.size / this.jumboPartSize);\n if (totalParts > MAX_S3_MULTIPART_PARTS) {\n throw new RangeError(\n `Jumbo chunk requires ${totalParts} parts, exceeding S3's ${MAX_S3_MULTIPART_PARTS}-part limit`,\n );\n }\n\n let checkpoint = await this.jumboChunkCheckpointStore.load(checkpointKey);\n if (\n checkpoint &&\n !this.isCompatibleJumboCheckpoint(checkpoint, chunk, target, context)\n ) {\n await this.jumboChunkCheckpointStore.remove(checkpointKey);\n checkpoint = null;\n }\n\n if (!checkpoint) {\n const created = await uploader.createMultipartUpload({\n storageKey: target.storage_key,\n contentType: context.contentType,\n signal: options.signal,\n });\n if (!created.uploadId.trim()) {\n throw new Error(`S3 Multipart create returned no upload id for chunk ${target.chunk_index}`);\n }\n checkpoint = {\n version: 1,\n storageKey: target.storage_key,\n chunkIndex: target.chunk_index,\n chunkSize: chunk.size,\n chunkSha256: context.chunks[target.chunk_index]?.sha256 ?? \"\",\n partSize: this.jumboPartSize,\n uploadId: created.uploadId,\n completed: false,\n completing: false,\n parts: [],\n };\n await this.jumboChunkCheckpointStore.save(checkpointKey, checkpoint);\n }\n\n if (checkpoint.completed) {\n return;\n }\n\n if (checkpoint.completing) {\n const status = await this.getUploadStatus(context.uploadId, options, options.signal);\n const statusChunk = status.chunks.find(\n (candidate) => candidate.chunk_index === target.chunk_index,\n );\n if (statusChunk?.status === \"uploaded\") {\n checkpoint.completed = true;\n checkpoint.completing = false;\n await this.jumboChunkCheckpointStore.save(checkpointKey, checkpoint);\n return;\n }\n checkpoint.completing = false;\n await this.jumboChunkCheckpointStore.save(checkpointKey, checkpoint);\n }\n\n const parts = new Map(checkpoint.parts.map((part) => [part.partNumber, part]));\n let uploadedBytes = 0;\n let uploadedParts = 0;\n for (let partNumber = 1; partNumber <= totalParts; partNumber += 1) {\n throwIfAborted(options.signal);\n const start = (partNumber - 1) * this.jumboPartSize;\n const partBlob = chunk.blob.slice(start, Math.min(start + this.jumboPartSize, chunk.size));\n const partHash = await sha256Hex(partBlob);\n const savedPart = parts.get(partNumber);\n const part =\n savedPart &&\n savedPart.size === partBlob.size &&\n savedPart.sha256 === partHash &&\n savedPart.etag\n ? savedPart\n : await this.uploadJumboPart(\n uploader,\n target.storage_key,\n checkpoint.uploadId,\n partNumber,\n partBlob,\n partHash,\n options.signal,\n );\n parts.set(partNumber, part);\n checkpoint.parts = [...parts.values()].sort(\n (left, right) => left.partNumber - right.partNumber,\n );\n await this.jumboChunkCheckpointStore.save(checkpointKey, checkpoint);\n uploadedBytes += partBlob.size;\n uploadedParts += 1;\n options.onProgress?.({\n phase: \"uploading\",\n uploadedBytes: baseUploadedBytes + uploadedBytes,\n totalBytes: context.fileSize,\n uploadedChunks,\n totalChunks,\n uploadedParts,\n totalParts,\n });\n }\n\n checkpoint.completing = true;\n await this.jumboChunkCheckpointStore.save(checkpointKey, checkpoint);\n try {\n await uploader.completeMultipartUpload({\n storageKey: target.storage_key,\n uploadId: checkpoint.uploadId,\n parts: checkpoint.parts.map(({ partNumber, etag }) => ({ partNumber, etag })),\n signal: options.signal,\n });\n } catch (error) {\n checkpoint.completing = false;\n await this.jumboChunkCheckpointStore.save(checkpointKey, checkpoint);\n throw error;\n }\n checkpoint.completed = true;\n checkpoint.completing = false;\n await this.jumboChunkCheckpointStore.save(checkpointKey, checkpoint);\n }\n\n private async uploadJumboPart(\n uploader: JumboChunkUploader,\n storageKey: string,\n uploadId: string,\n partNumber: number,\n body: Blob,\n sha256: string,\n signal?: AbortSignal,\n ): Promise<S3MultipartPart> {\n const result = await uploader.uploadPart({\n storageKey,\n uploadId,\n partNumber,\n body,\n signal,\n });\n if (!result.etag.trim()) {\n throw new Error(`S3 Multipart upload returned no ETag for part ${partNumber}`);\n }\n return {\n partNumber,\n etag: result.etag,\n size: body.size,\n sha256,\n };\n }\n\n private isCompatibleJumboCheckpoint(\n checkpoint: JumboChunkCheckpoint,\n chunk: FileChunk,\n target: UploadTarget | UploadStatusChunk,\n context: UploadSessionContext,\n ): boolean {\n return (\n checkpoint.version === 1 &&\n checkpoint.storageKey === target.storage_key &&\n checkpoint.chunkIndex === target.chunk_index &&\n checkpoint.chunkSize === chunk.size &&\n checkpoint.chunkSha256 === (context.chunks[target.chunk_index]?.sha256 ?? \"\") &&\n checkpoint.partSize === this.jumboPartSize &&\n checkpoint.uploadId.trim().length > 0\n );\n }\n\n private assertUploadContext(context: UploadSessionContext, file: Blob): void {\n if (!context.uploadId.trim()) {\n throw new TypeError(\"upload context uploadId is required\");\n }\n if (context.fileSize !== file.size) {\n throw new Error(\"The restored file does not match the upload context size\");\n }\n if (!Array.isArray(context.chunks) || context.chunks.length === 0) {\n throw new TypeError(\"upload context must contain chunks\");\n }\n let expectedOffset = 0;\n for (const [index, chunk] of context.chunks.entries()) {\n if (\n chunk.index !== index ||\n chunk.offset !== expectedOffset ||\n chunk.offset < 0 ||\n chunk.size < 0 ||\n chunk.offset + chunk.size > file.size ||\n typeof chunk.sha256 !== \"string\"\n ) {\n throw new TypeError(\"upload context contains an invalid chunk layout\");\n }\n expectedOffset += chunk.size;\n }\n }\n\n async finishUpload(uploadId: string, selector: WorkspaceSelector = {}): Promise<UploadResult> {\n if (!uploadId.trim()) {\n throw new TypeError(\"uploadId is required\");\n }\n const finished = ensureFinishResponse(\n await this.requestJson(\"/upload/finish\", {\n ...getWorkspaceBody(this.clientSelector, selector),\n upload_id: uploadId,\n }),\n );\n if (finished.finish_status === \"completed\") {\n await this.metadata.recordUpload(this.cacheWorkspace(selector), finished);\n // The file's bytes are not available here, so its stale entry can only be dropped.\n await this.downloader.invalidateCachedFile(this.cacheWorkspace(selector), {\n path: finished.path,\n ...(finished.ino !== undefined ? { ino: finished.ino } : {}),\n });\n }\n return finished;\n }\n\n /** Same workspace resolution as `getWorkspaceBody`, so the cache key matches what Mountra used. */\n private cacheWorkspace(selector: WorkspaceSelector): WorkspaceSelector {\n return {\n workspaceCuid: selector.workspaceCuid ?? this.clientSelector.workspaceCuid,\n workspaceId: selector.workspaceId ?? this.clientSelector.workspaceId,\n };\n }\n\n private endpoint(path: string): string {\n return `${this.baseUrl}${this.apiPrefix}${path}`;\n }\n\n private async requestJson(path: string, body: unknown, signal?: AbortSignal): Promise<unknown> {\n const headers = new Headers(this.headers);\n headers.set(\"Content-Type\", \"application/json\");\n const token = typeof this.token === \"function\" ? await this.token() : this.token;\n if (token) {\n headers.set(\"Authorization\", `Bearer ${token}`);\n }\n\n const response = await this.fetchImpl(this.endpoint(path), {\n method: \"POST\",\n headers,\n body: JSON.stringify(body),\n ...(signal ? { signal } : {}),\n });\n let responseBody: unknown;\n try {\n responseBody = await response.json();\n } catch {\n responseBody = undefined;\n }\n if (!response.ok) {\n const error = parseApiErrorBody(responseBody);\n throw new MountraApiError(\n error.message ?? `Mountra API request failed with HTTP ${response.status}`,\n { status: response.status, code: error.code, body: responseBody },\n );\n }\n return responseBody;\n }\n}\n\nexport function createMountraClient(options: MountraClientOptions): MountraClient {\n return new MountraClient(options);\n}\n"],"mappings":"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","names":["checkpoint","getIndexedDb","isRecord","readString","memoryKey","META_STORE","draft","isRecord","throwIfAborted"]}
|