@mountra/mountra-sdk 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +126 -0
- package/dist/index.cjs +751 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +309 -0
- package/dist/index.d.ts +309 -0
- package/dist/index.js +711 -0
- package/dist/index.js.map +1 -0
- package/package.json +39 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/upload.ts"],"sourcesContent":["export 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}\n\nexport interface UploadFileOptions extends WorkspaceSelector {\n path: string;\n /** Number of logical chunks. Defaults to 1. */\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\nexport interface UploadResumeOptions extends WorkspaceSelector {\n signal?: AbortSignal;\n onProgress?: (progress: MountraProgress) => void;\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 for (let index = 0; index < chunkCount; index += 1) {\n const offset = index * 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\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 }\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 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 return ensureFinishResponse(\n await this.requestJson(\"/upload/finish\", {\n ...getWorkspaceBody(this.clientSelector, selector),\n upload_id: uploadId,\n }),\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":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@mountra/mountra-sdk",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Browser-friendly TypeScript SDK for integrating Mountra services.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"license": "ISC",
|
|
7
|
+
"publishConfig": {
|
|
8
|
+
"access": "public"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist",
|
|
12
|
+
"README.md"
|
|
13
|
+
],
|
|
14
|
+
"main": "./dist/index.cjs",
|
|
15
|
+
"module": "./dist/index.js",
|
|
16
|
+
"types": "./dist/index.d.ts",
|
|
17
|
+
"exports": {
|
|
18
|
+
".": {
|
|
19
|
+
"types": "./dist/index.d.ts",
|
|
20
|
+
"import": "./dist/index.js",
|
|
21
|
+
"require": "./dist/index.cjs"
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"sideEffects": false,
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18"
|
|
27
|
+
},
|
|
28
|
+
"devDependencies": {
|
|
29
|
+
"@types/node": "^24.3.0",
|
|
30
|
+
"tsup": "^8.5.0",
|
|
31
|
+
"typescript": "^5.9.0",
|
|
32
|
+
"vitest": "^3.2.0"
|
|
33
|
+
},
|
|
34
|
+
"scripts": {
|
|
35
|
+
"build": "tsup",
|
|
36
|
+
"test": "vitest run",
|
|
37
|
+
"typecheck": "tsc --noEmit"
|
|
38
|
+
}
|
|
39
|
+
}
|