# Chunking library for uploading large assets ## Description The maximum size of an ingress message to the Internet Computer is currently limited to 2 MB. Larger files have to be scliced into chunks and assembled in the backend. The certified asset canister supports this via the following [interface](https://github.com/dfinity/cdk-rs/blob/main/src/ic-certified-assets/assets.did): ``` type BatchId = nat; type ChunkId = nat; type Key = text; type Time = int; type CreateAssetArguments = record { key: Key; content_type: text; max_age: opt nat64; }; // Add or change content for an asset, by content encoding type SetAssetContentArguments = record { key: Key; content_encoding: text; chunk_ids: vec ChunkId; sha256: opt blob; }; // Remove content for an asset, by content encoding type UnsetAssetContentArguments = record { key: Key; content_encoding: text; }; // Delete an asset type DeleteAssetArguments = record { key: Key; }; // Reset everything type ClearArguments = record {}; type BatchOperationKind = variant { CreateAsset: CreateAssetArguments; SetAssetContent: SetAssetContentArguments; UnsetAssetContent: UnsetAssetContentArguments; DeleteAsset: DeleteAssetArguments; Clear: ClearArguments; }; type HeaderField = record { text; text; }; type HttpRequest = record { method: text; url: text; headers: vec HeaderField; body: blob; }; type HttpResponse = record { status_code: nat16; headers: vec HeaderField; body: blob; streaming_strategy: opt StreamingStrategy; }; type StreamingCallbackHttpResponse = record { body: blob; token: opt StreamingCallbackToken; }; type StreamingCallbackToken = record { key: Key; content_encoding: text; index: nat; sha256: opt blob; }; type StreamingStrategy = variant { Callback: record { callback: func (StreamingCallbackToken) -> (opt StreamingCallbackHttpResponse) query; token: StreamingCallbackToken; }; }; service: { get: (record { key: Key; accept_encodings: vec text; }) -> (record { content: blob; // may be the entirety of the content, or just chunk index 0 content_type: text; content_encoding: text; sha256: opt blob; // sha256 of entire asset encoding, calculated by dfx and passed in SetAssetContentArguments total_length: nat; // all chunks except last have size == content.size() }) query; // if get() returned chunks > 1, call this to retrieve them. // chunks may or may not be split up at the same boundaries as presented to create_chunk(). get_chunk: (record { key: Key; content_encoding: text; index: nat; sha256: opt blob; // sha256 of entire asset encoding, calculated by dfx and passed in SetAssetContentArguments }) -> (record { content: blob }) query; list : (record {}) -> (vec record { key: Key; content_type: text; encodings: vec record { content_encoding: text; sha256: opt blob; // sha256 of entire asset encoding, calculated by dfx and passed in SetAssetContentArguments length: nat; // Size of this encoding's blob. Calculated when uploading assets. modified: Time; }; }) query; create_batch : (record {}) -> (record { batch_id: BatchId }); create_chunk: (record { batch_id: BatchId; content: blob }) -> (record { chunk_id: ChunkId }); // Perform all operations successfully, or reject commit_batch: (record { batch_id: BatchId; operations: vec BatchOperationKind }) -> (); create_asset: (CreateAssetArguments) -> (); set_asset_content: (SetAssetContentArguments) -> (); unset_asset_content: (UnsetAssetContentArguments) -> (); delete_asset: (DeleteAssetArguments) -> (); clear: (ClearArguments) -> (); // Single call to create an asset with content for a single content encoding that // fits within the message ingress limit. store: (record { key: Key; content_type: text; content_encoding: text; content: blob; sha256: opt blob }) -> (); http_request: (request: HttpRequest) -> (HttpResponse) query; http_request_streaming_callback: (token: StreamingCallbackToken) -> (opt StreamingCallbackHttpResponse) query; authorize: (principal) -> (); } ``` A client implementation [`ic-assets`](https://github.com/dfinity/agent-rs/tree/main/ic-asset) in Rust is available and used by `dfx`. However, there is no JavaScript/TypeScript library available that can be used in web applications to upload large files such as images, music and videos. The goal of this bounty is to implement such a client library. ## Acceptance Criteria - JavaScript/TypeScript client library to upload chunked files with a configurable chunk size. - Code style and API should fit to existing [`agent-js` libraries](https://github.com/dfinity/agent-js) as the goal would be to include the library as a package. - Unit test and documentation - Sample application that allows to upload arbitrary files via drag & drop interface ## More opportunities related to this bounty - Refactor `ic-certified-assets` into a proper modular library to be used in custom canisters that want to support certified assets - Implement a modular `ic-certified-assets` library in Motoko. Please get in touch if you are interested in working on one of these projects.