# 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.