UNPKG

@junobuild/storage

Version:

A library for interfacing with Juno's Storage features.

8 lines (7 loc) 11.2 kB
{ "version": 3, "sources": ["../../src/services/upload.services.ts"], "sourcesContent": ["import {assertNonNullish, toNullable} from '@dfinity/utils';\nimport type {ConsoleDid, SatelliteDid} from '@junobuild/ic-client/actor';\nimport {isBrowser} from '@junobuild/utils';\nimport {UPLOAD_CHUNK_SIZE} from '../constants/upload.constants';\nimport type {EncodingType} from '../types/storage';\nimport type {UploadAsset, UploadParams, UploadWithProposalParams} from '../types/upload';\n\ntype InitAssetKey = SatelliteDid.InitAssetKey | ConsoleDid.InitAssetKey;\ntype UploadChunk = SatelliteDid.UploadChunk | ConsoleDid.UploadChunk;\ntype CommitBatch = SatelliteDid.CommitBatch | ConsoleDid.CommitBatch;\n\nexport const uploadAsset = async ({\n asset: {data, headers, ...restAsset},\n actor,\n progress\n}: {\n asset: UploadAsset;\n} & UploadParams): Promise<void> => {\n const {init_asset_upload, upload_asset_chunk, commit_asset_upload} = actor;\n\n const {batch_id: batchId} = await init_asset_upload(mapInitAssetUploadParams(restAsset));\n\n progress?.onInitiatedBatch();\n\n const {chunkIds} = await uploadChunks({data, uploadFn: upload_asset_chunk, batchId});\n\n progress?.onUploadedFileChunks(restAsset.fullPath);\n\n await commitAsset({\n commitFn: commit_asset_upload,\n batchId,\n data,\n headers,\n chunkIds\n });\n\n progress?.onCommittedBatch();\n};\n\nexport const uploadAssetWithProposal = async ({\n asset: {data, headers, ...restAsset},\n proposalId,\n actor,\n progress\n}: {\n asset: UploadAsset;\n} & UploadWithProposalParams): Promise<void> => {\n const {init_proposal_asset_upload, upload_proposal_asset_chunk, commit_proposal_asset_upload} =\n actor;\n\n progress?.onInitiatedBatch();\n\n const {batch_id: batchId} = await init_proposal_asset_upload(\n mapInitAssetUploadParams(restAsset),\n proposalId\n );\n\n const {chunkIds} = await uploadChunks({data, uploadFn: upload_proposal_asset_chunk, batchId});\n\n progress?.onUploadedFileChunks(restAsset.fullPath);\n\n await commitAsset({\n commitFn: commit_proposal_asset_upload,\n batchId,\n data,\n headers,\n chunkIds\n });\n\n progress?.onCommittedBatch();\n};\n\nexport const uploadAssetsWithProposal = async ({\n assets,\n proposalId,\n actor,\n progress\n}: {\n assets: UploadAsset[];\n} & UploadWithProposalParams): Promise<void> => {\n const {\n init_proposal_many_assets_upload,\n upload_proposal_asset_chunk,\n commit_proposal_many_assets_upload\n } = actor;\n\n const batchIds = await init_proposal_many_assets_upload(\n assets.map(mapInitAssetUploadParams),\n proposalId\n );\n\n progress?.onInitiatedBatch();\n\n const uploadAssetChunk = async ({\n fullPath,\n data,\n headers\n }: UploadAsset): Promise<BatchToCommit> => {\n const initializedBatch = batchIds.find(([batchIdFullPath]) => batchIdFullPath === fullPath);\n\n assertNonNullish(initializedBatch);\n\n const [_, initUpload] = initializedBatch;\n const {batch_id: batchId} = initUpload;\n\n const {chunkIds} = await uploadChunks({data, uploadFn: upload_proposal_asset_chunk, batchId});\n\n progress?.onUploadedFileChunks(fullPath);\n\n return {\n batchId,\n headers,\n chunkIds,\n data\n };\n };\n\n const batchAndChunkIdsToCommit = await Promise.all(assets.map(uploadAssetChunk));\n\n await commit_proposal_many_assets_upload(batchAndChunkIdsToCommit.map(mapCommitBatch));\n\n progress?.onCommittedBatch();\n};\n\nconst mapInitAssetUploadParams = ({\n filename,\n collection,\n token,\n fullPath,\n encoding,\n description\n}: Omit<UploadAsset, 'headers' | 'data'>): InitAssetKey => ({\n collection,\n full_path: fullPath,\n name: filename,\n token: toNullable<string>(token),\n encoding_type: toNullable<EncodingType>(encoding),\n description: toNullable(description)\n});\n\ntype BatchToCommit = {\n batchId: bigint;\n chunkIds: UploadChunkResult[];\n} & Pick<UploadAsset, 'headers' | 'data'>;\n\nconst mapCommitBatch = ({batchId, chunkIds, headers, data}: BatchToCommit): CommitBatch => {\n const contentType: [[string, string]] | undefined =\n headers.find(([type, _]) => type.toLowerCase() === 'content-type') === undefined &&\n data.type !== undefined &&\n data.type !== ''\n ? [['Content-Type', data.type]]\n : undefined;\n\n return {\n batch_id: batchId,\n chunk_ids: chunkIds.map(({chunk_id}: UploadChunkResult) => chunk_id),\n headers: [...headers, ...(contentType ?? [])]\n };\n};\n\nconst commitAsset = async ({\n commitFn,\n ...rest\n}: {\n commitFn: (commitBatch: CommitBatch) => Promise<void>;\n batchId: bigint;\n chunkIds: UploadChunkResult[];\n} & Pick<UploadAsset, 'headers' | 'data'>) => {\n const commitBatch = mapCommitBatch(rest);\n await commitFn(commitBatch);\n};\n\nconst uploadChunks = async ({\n data,\n uploadFn,\n batchId\n}: {\n batchId: bigint;\n} & Pick<UploadAsset, 'data'> &\n Pick<UploadChunkParams, 'uploadFn'>): Promise<{chunkIds: UploadChunkResult[]}> => {\n const uploadChunks: UploadChunkParams[] = [];\n\n // Prevent transforming chunk to arrayBuffer error: The requested file could not be read, typically due to permission problems that have occurred after a reference to a file was acquired.\n const clone: Blob = isBrowser() ? new Blob([await data.arrayBuffer()]) : data;\n\n // Split data into chunks\n let orderId = 0n;\n for (let start = 0; start < clone.size; start += UPLOAD_CHUNK_SIZE) {\n const chunk: Blob = clone.slice(start, start + UPLOAD_CHUNK_SIZE);\n\n uploadChunks.push({\n batchId,\n chunk,\n uploadFn,\n orderId\n });\n\n orderId++;\n }\n\n // Upload chunks to the IC in batch - i.e. 12 chunks uploaded at a time.\n let chunkIds: UploadChunkResult[] = [];\n for await (const results of batchUploadChunks({uploadChunks})) {\n chunkIds = [...chunkIds, ...results];\n }\n\n return {chunkIds};\n};\n\nasync function* batchUploadChunks({\n uploadChunks,\n limit = 12\n}: {\n uploadChunks: UploadChunkParams[];\n limit?: number;\n}): AsyncGenerator<UploadChunkResult[], void> {\n for (let i = 0; i < uploadChunks.length; i = i + limit) {\n const batch = uploadChunks.slice(i, i + limit);\n const result = await Promise.all(batch.map((params) => uploadChunk(params)));\n yield result;\n }\n}\n\ninterface UploadChunkResult {\n chunk_id: bigint;\n}\n\ninterface UploadChunkParams {\n batchId: bigint;\n chunk: Blob;\n uploadFn: (uploadChunk: UploadChunk) => Promise<UploadChunkResult>;\n orderId: bigint;\n}\n\nconst uploadChunk = async ({\n batchId,\n chunk,\n uploadFn,\n orderId\n}: UploadChunkParams): Promise<UploadChunkResult> =>\n uploadFn({\n batch_id: batchId,\n content: new Uint8Array(await chunk.arrayBuffer()),\n order_id: toNullable(orderId)\n });\n"], "mappings": "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", "names": ["assertNonNullish", "toNullable", "isBrowser", "uploadAsset", "data", "headers", "restAsset", "actor", "progress", "init_asset_upload", "upload_asset_chunk", "commit_asset_upload", "batchId", "mapInitAssetUploadParams", "chunkIds", "uploadChunks", "commitAsset", "uploadAssetWithProposal", "proposalId", "init_proposal_asset_upload", "upload_proposal_asset_chunk", "commit_proposal_asset_upload", "uploadAssetsWithProposal", "assets", "init_proposal_many_assets_upload", "commit_proposal_many_assets_upload", "batchIds", "uploadAssetChunk", "fullPath", "initializedBatch", "batchIdFullPath", "assertNonNullish", "_", "initUpload", "batchAndChunkIdsToCommit", "mapCommitBatch", "filename", "collection", "token", "encoding", "description", "toNullable", "contentType", "type", "chunk_id", "commitFn", "rest", "commitBatch", "uploadFn", "clone", "isBrowser", "orderId", "start", "chunk", "results", "batchUploadChunks", "limit", "i", "batch", "params", "uploadChunk"] }