@jsm-mit/sultana-assets-rust-package 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 +86 -0
- package/declarations/sultana-assets-rust/sultana-assets-rust.did +98 -0
- package/declarations/sultana-assets-rust/sultana-assets-rust.did.d.ts +129 -0
- package/declarations/sultana-assets-rust/sultana-assets-rust.did.js +143 -0
- package/dist/actor-base.d.ts +46 -0
- package/dist/actor-base.d.ts.map +1 -0
- package/dist/actor-base.js +87 -0
- package/dist/actors/admin-actor.d.ts +72 -0
- package/dist/actors/admin-actor.d.ts.map +1 -0
- package/dist/actors/admin-actor.js +86 -0
- package/dist/actors/assets-actor.d.ts +38 -0
- package/dist/actors/assets-actor.d.ts.map +1 -0
- package/dist/actors/assets-actor.js +54 -0
- package/dist/actors/salon-actor.d.ts +64 -0
- package/dist/actors/salon-actor.d.ts.map +1 -0
- package/dist/actors/salon-actor.js +92 -0
- package/dist/actors/uploads-actor.d.ts +74 -0
- package/dist/actors/uploads-actor.d.ts.map +1 -0
- package/dist/actors/uploads-actor.js +97 -0
- package/dist/actors/worker-actor.d.ts +72 -0
- package/dist/actors/worker-actor.d.ts.map +1 -0
- package/dist/actors/worker-actor.js +86 -0
- package/dist/constants.d.ts +33 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +45 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/interfaces.d.ts +97 -0
- package/dist/interfaces.d.ts.map +1 -0
- package/dist/interfaces.js +1 -0
- package/dist/mappers.d.ts +11 -0
- package/dist/mappers.d.ts.map +1 -0
- package/dist/mappers.js +38 -0
- package/package.json +58 -0
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { ActorBase } from "../actor-base.js";
|
|
2
|
+
import { splitIntoChunks } from "../constants.js";
|
|
3
|
+
/**
|
|
4
|
+
* The transcoding worker's side: it stores a finished result under the id the salon
|
|
5
|
+
* reserved. Every method traps unless the caller's principal is on the canister's worker list
|
|
6
|
+
* (`set_workers`, driven by core's superadmin).
|
|
7
|
+
*/
|
|
8
|
+
export class AssetsRustWorkerActor extends ActorBase {
|
|
9
|
+
/**
|
|
10
|
+
* Opens a chunked upload session under a reserved id.
|
|
11
|
+
* @param input - The reserved id, name, content type and number of chunks.
|
|
12
|
+
* @returns A Promise that resolves to the id.
|
|
13
|
+
* @throws CanisterError - The canister trapped: "caller is not a transcoding worker",
|
|
14
|
+
* totalChunks 0, "asset already exists".
|
|
15
|
+
* @throws CallRefusedAtInspectionStage - The call was refused at the inspect stage.
|
|
16
|
+
* @throws CriticalCanisterError - Transport failure or an unreachable canister.
|
|
17
|
+
*/
|
|
18
|
+
async systemStartUploadAsyncUnsafe(input) {
|
|
19
|
+
return this.executeFunctionAsyncUnsafe(() => this.actor.system_start_upload({ id: input.id, name: input.name, contentType: input.contentType, totalChunks: input.totalChunks }));
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Stores one chunk of a session this worker started.
|
|
23
|
+
* @param assetId - The session id.
|
|
24
|
+
* @param index - 0-based chunk index.
|
|
25
|
+
* @param data - At most ASSETS_RUST_LIMITS.chunkSizeBytes.
|
|
26
|
+
* @throws CanisterError - The canister trapped: chunk too big, unknown session, not the
|
|
27
|
+
* session owner, index out of range.
|
|
28
|
+
* @throws CallRefusedAtInspectionStage - The call was refused at the inspect stage.
|
|
29
|
+
* @throws CriticalCanisterError - Transport failure or an unreachable canister.
|
|
30
|
+
*/
|
|
31
|
+
async uploadChunkAsyncUnsafe(assetId, index, data) {
|
|
32
|
+
await this.executeFunctionAsyncUnsafe(() => this.actor.upload_chunk(assetId, index, data));
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Opens a system session under `assetId` and sends every chunk of `bytes` — everything but
|
|
36
|
+
* the finish, because a video and its poster are finished together
|
|
37
|
+
* ({@link finishSystemUploadAsyncUnsafe}).
|
|
38
|
+
* @param assetId - The reserved id (or the poster's own id).
|
|
39
|
+
* @param name - The stored name.
|
|
40
|
+
* @param contentType - The stored content type.
|
|
41
|
+
* @param bytes - The file.
|
|
42
|
+
* @param options - Chunk size and a progress callback.
|
|
43
|
+
* @throws CanisterError - The canister trapped in start or in a chunk.
|
|
44
|
+
* @throws CallRefusedAtInspectionStage - The call was refused at the inspect stage.
|
|
45
|
+
* @throws CriticalCanisterError - Transport failure or an unreachable canister.
|
|
46
|
+
*/
|
|
47
|
+
async systemUploadBytesAsyncUnsafe(assetId, name, contentType, bytes, options = {}) {
|
|
48
|
+
const chunks = splitIntoChunks(bytes, options.chunkSizeBytes);
|
|
49
|
+
await this.systemStartUploadAsyncUnsafe({ id: assetId, name, contentType, totalChunks: chunks.length });
|
|
50
|
+
for (let index = 0; index < chunks.length; index++) {
|
|
51
|
+
await this.uploadChunkAsyncUnsafe(assetId, index, chunks[index]);
|
|
52
|
+
options.onProgress?.({ uploadedChunks: index + 1, totalChunks: chunks.length });
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Finishes the result (and its poster session, when given) and — when the id was
|
|
57
|
+
* reserved by a salon — registers it in that salon's core library with the poster as its
|
|
58
|
+
* thumb. Safe to retry after a failed registration: stored bytes are not stored again.
|
|
59
|
+
* @param assetId - The reserved id.
|
|
60
|
+
* @param posterId - The poster frame's session id, uploaded alongside.
|
|
61
|
+
* @returns A Promise that resolves to the asset id.
|
|
62
|
+
* @throws CanisterError - The canister trapped: "caller is not a transcoding worker",
|
|
63
|
+
* "posterId must differ from the video id", an incomplete session, "asset register
|
|
64
|
+
* failed: …" (core refused or unreachable; the reservation is kept for a retry).
|
|
65
|
+
* @throws CallRefusedAtInspectionStage - The call was refused at the inspect stage.
|
|
66
|
+
* @throws CriticalCanisterError - Transport failure or an unreachable canister.
|
|
67
|
+
*/
|
|
68
|
+
async finishSystemUploadAsyncUnsafe(assetId, posterId) {
|
|
69
|
+
return this.executeFunctionAsyncUnsafe(() => this.actor.finish_system_upload({ id: assetId, posterId: posterId === undefined ? [] : [posterId] }));
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Reports a failed transcode: the salon's #Pending library entry becomes #Failed(reason)
|
|
73
|
+
* and the reservation is dropped.
|
|
74
|
+
* @param assetId - The reserved id.
|
|
75
|
+
* @param reason - What went wrong (a JSON error payload the front translates).
|
|
76
|
+
* @returns A Promise that resolves to `true` when reported, `false` when there is no such
|
|
77
|
+
* reservation (finished, deleted or swept).
|
|
78
|
+
* @throws CanisterError - The canister trapped: "caller is not a transcoding worker",
|
|
79
|
+
* "markAssetFailed rejected: …" (the reservation is kept; the sweep retries).
|
|
80
|
+
* @throws CallRefusedAtInspectionStage - The call was refused at the inspect stage.
|
|
81
|
+
* @throws CriticalCanisterError - Transport failure or an unreachable canister.
|
|
82
|
+
*/
|
|
83
|
+
async failSystemUploadAsyncUnsafe(assetId, reason) {
|
|
84
|
+
return this.executeFunctionAsyncUnsafe(() => this.actor.fail_system_upload({ id: assetId, reason }));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/** The IC API host every actor uses unless the constructor gets another one. */
|
|
2
|
+
export declare const DEFAULT_HOST = "https://icp0.io";
|
|
3
|
+
/**
|
|
4
|
+
* Limits of sultana-assets-rust (`src/lib.rs` constants), for client-side checks before a
|
|
5
|
+
* call the canister would trap on anyway.
|
|
6
|
+
*/
|
|
7
|
+
export declare const ASSETS_RUST_LIMITS: {
|
|
8
|
+
/** Largest chunk `upload_chunk` accepts, and largest single-shot payload
|
|
9
|
+
* (`upload_asset`, `upload_image`) — kept under the ~2 MB ingress limit. */
|
|
10
|
+
readonly chunkSizeBytes: 1900000;
|
|
11
|
+
/** Largest slice one Range request returns over HTTP. */
|
|
12
|
+
readonly maxRangeBytes: 1800000;
|
|
13
|
+
/** Width of the thumbnail `upload_image` generates (never upscaled). */
|
|
14
|
+
readonly thumbnailWidth: 128;
|
|
15
|
+
/** An unfinished upload session is purged after this long (30 min). */
|
|
16
|
+
readonly sessionTtlMs: number;
|
|
17
|
+
/** The only audio content type `reserve_render` takes as the music track. */
|
|
18
|
+
readonly audioContentType: "audio/mpeg";
|
|
19
|
+
/** `reserve_render`: musicVolumePct 0..100, musicStartSec 0..600, slideDurationSec 5..60. */
|
|
20
|
+
readonly maxMusicVolumePct: 100;
|
|
21
|
+
readonly maxMusicStartSec: 600;
|
|
22
|
+
readonly minSlideDurationSec: 5;
|
|
23
|
+
readonly maxSlideDurationSec: 60;
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* The public URL of a stored asset. Served from the raw host (`<id>.raw.icp0.io`), which
|
|
27
|
+
* also answers Range requests (206, uncertified) that a `<video>` needs to seek.
|
|
28
|
+
*/
|
|
29
|
+
export declare function assetUrl(canisterId: string, assetId: string): string;
|
|
30
|
+
/** Splits `bytes` into chunks the canister accepts. An empty input is one empty chunk —
|
|
31
|
+
* a session needs at least one. */
|
|
32
|
+
export declare function splitIntoChunks(bytes: Uint8Array, chunkSizeBytes?: number): Uint8Array[];
|
|
33
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,eAAO,MAAM,YAAY,oBAAoB,CAAC;AAE9C;;;GAGG;AACH,eAAO,MAAM,kBAAkB;IAC3B;iFAC6E;;IAE7E,yDAAyD;;IAEzD,wEAAwE;;IAExE,uEAAuE;;IAEvE,6EAA6E;;IAE7E,6FAA6F;;;;;CAKvF,CAAC;AAEX;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED;oCACoC;AACpC,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,EAAE,cAAc,GAAE,MAA0C,GAAG,UAAU,EAAE,CAY3H"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/** The IC API host every actor uses unless the constructor gets another one. */
|
|
2
|
+
export const DEFAULT_HOST = "https://icp0.io";
|
|
3
|
+
/**
|
|
4
|
+
* Limits of sultana-assets-rust (`src/lib.rs` constants), for client-side checks before a
|
|
5
|
+
* call the canister would trap on anyway.
|
|
6
|
+
*/
|
|
7
|
+
export const ASSETS_RUST_LIMITS = {
|
|
8
|
+
/** Largest chunk `upload_chunk` accepts, and largest single-shot payload
|
|
9
|
+
* (`upload_asset`, `upload_image`) — kept under the ~2 MB ingress limit. */
|
|
10
|
+
chunkSizeBytes: 1_900_000,
|
|
11
|
+
/** Largest slice one Range request returns over HTTP. */
|
|
12
|
+
maxRangeBytes: 1_800_000,
|
|
13
|
+
/** Width of the thumbnail `upload_image` generates (never upscaled). */
|
|
14
|
+
thumbnailWidth: 128,
|
|
15
|
+
/** An unfinished upload session is purged after this long (30 min). */
|
|
16
|
+
sessionTtlMs: 30 * 60 * 1000,
|
|
17
|
+
/** The only audio content type `reserve_render` takes as the music track. */
|
|
18
|
+
audioContentType: "audio/mpeg",
|
|
19
|
+
/** `reserve_render`: musicVolumePct 0..100, musicStartSec 0..600, slideDurationSec 5..60. */
|
|
20
|
+
maxMusicVolumePct: 100,
|
|
21
|
+
maxMusicStartSec: 600,
|
|
22
|
+
minSlideDurationSec: 5,
|
|
23
|
+
maxSlideDurationSec: 60,
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* The public URL of a stored asset. Served from the raw host (`<id>.raw.icp0.io`), which
|
|
27
|
+
* also answers Range requests (206, uncertified) that a `<video>` needs to seek.
|
|
28
|
+
*/
|
|
29
|
+
export function assetUrl(canisterId, assetId) {
|
|
30
|
+
return `https://${canisterId}.raw.icp0.io/asset/${assetId}`;
|
|
31
|
+
}
|
|
32
|
+
/** Splits `bytes` into chunks the canister accepts. An empty input is one empty chunk —
|
|
33
|
+
* a session needs at least one. */
|
|
34
|
+
export function splitIntoChunks(bytes, chunkSizeBytes = ASSETS_RUST_LIMITS.chunkSizeBytes) {
|
|
35
|
+
if (chunkSizeBytes <= 0 || chunkSizeBytes > ASSETS_RUST_LIMITS.chunkSizeBytes) {
|
|
36
|
+
throw new Error(`chunkSizeBytes must be 1..${ASSETS_RUST_LIMITS.chunkSizeBytes}`);
|
|
37
|
+
}
|
|
38
|
+
if (bytes.length === 0)
|
|
39
|
+
return [bytes];
|
|
40
|
+
const chunks = [];
|
|
41
|
+
for (let offset = 0; offset < bytes.length; offset += chunkSizeBytes) {
|
|
42
|
+
chunks.push(bytes.subarray(offset, offset + chunkSizeBytes));
|
|
43
|
+
}
|
|
44
|
+
return chunks;
|
|
45
|
+
}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export { ActorBase, type TrapCause } from "./actor-base.js";
|
|
2
|
+
export { AssetsRustAdminActor } from "./actors/admin-actor.js";
|
|
3
|
+
export { AssetsRustUploadsActor } from "./actors/uploads-actor.js";
|
|
4
|
+
export { AssetsRustSalonActor } from "./actors/salon-actor.js";
|
|
5
|
+
export { AssetsRustWorkerActor } from "./actors/worker-actor.js";
|
|
6
|
+
export { AssetsRustAssetsActor } from "./actors/assets-actor.js";
|
|
7
|
+
export { ASSETS_RUST_LIMITS, DEFAULT_HOST, assetUrl, splitIntoChunks } from "./constants.js";
|
|
8
|
+
export type { AssetInfoView, WorkerView, ReservationView, TranscodingKindView, RenderModeView, StartUploadInput, UploadAssetInput, UploadImageInput, ReserveTranscodingUploadInput, ReserveRenderInput, SystemStartUploadInput, HttpGetInput, HttpResponseView, UploadProgress, ChunkedUploadOptions, } from "./interfaces.js";
|
|
9
|
+
export { mapAssetInfoView, mapWorkerView, mapReservationView, mapHttpResponseView, toCandidTranscodingKind, toCandidRenderMode, toCandidOpt, } from "./mappers.js";
|
|
10
|
+
export type { AssetInfo, WorkerEntry, ReserveTranscodingUpload, TranscodingKind, RenderMode, HttpRequest, HttpResponse, StreamingCallbackToken, StreamingCallbackHttpResponse, StreamingStrategy, } from "../declarations/sultana-assets-rust/sultana-assets-rust.did.js";
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,EAAE,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAC/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AACjE,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AAC7F,YAAY,EACR,aAAa,EACb,UAAU,EACV,eAAe,EACf,mBAAmB,EACnB,cAAc,EACd,gBAAgB,EAChB,gBAAgB,EAChB,gBAAgB,EAChB,6BAA6B,EAC7B,kBAAkB,EAClB,sBAAsB,EACtB,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,oBAAoB,GACvB,MAAM,iBAAiB,CAAC;AACzB,OAAO,EACH,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EAClB,mBAAmB,EACnB,uBAAuB,EACvB,kBAAkB,EAClB,WAAW,GACd,MAAM,cAAc,CAAC;AACtB,YAAY,EACR,SAAS,EACT,WAAW,EACX,wBAAwB,EACxB,eAAe,EACf,UAAU,EACV,WAAW,EACX,YAAY,EACZ,sBAAsB,EACtB,6BAA6B,EAC7B,iBAAiB,GACpB,MAAM,gEAAgE,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export { ActorBase } from "./actor-base.js";
|
|
2
|
+
export { AssetsRustAdminActor } from "./actors/admin-actor.js";
|
|
3
|
+
export { AssetsRustUploadsActor } from "./actors/uploads-actor.js";
|
|
4
|
+
export { AssetsRustSalonActor } from "./actors/salon-actor.js";
|
|
5
|
+
export { AssetsRustWorkerActor } from "./actors/worker-actor.js";
|
|
6
|
+
export { AssetsRustAssetsActor } from "./actors/assets-actor.js";
|
|
7
|
+
export { ASSETS_RUST_LIMITS, DEFAULT_HOST, assetUrl, splitIntoChunks } from "./constants.js";
|
|
8
|
+
export { mapAssetInfoView, mapWorkerView, mapReservationView, mapHttpResponseView, toCandidTranscodingKind, toCandidRenderMode, toCandidOpt, } from "./mappers.js";
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/** One stored asset as the canister describes it (`get_asset_info`, `list_assets`). */
|
|
2
|
+
export interface AssetInfoView {
|
|
3
|
+
id: string;
|
|
4
|
+
name: string;
|
|
5
|
+
contentType: string;
|
|
6
|
+
/** Size in bytes. */
|
|
7
|
+
totalSize: number;
|
|
8
|
+
chunkCount: number;
|
|
9
|
+
/** Nanoseconds since the epoch. */
|
|
10
|
+
uploadedAt: bigint;
|
|
11
|
+
}
|
|
12
|
+
/** A transcoding worker: its identity and the FULL upload-endpoint URL, used verbatim. */
|
|
13
|
+
export interface WorkerView {
|
|
14
|
+
principal: string;
|
|
15
|
+
url: string;
|
|
16
|
+
}
|
|
17
|
+
/** What the salon-job reservations return: the reserved asset id and the worker upload
|
|
18
|
+
* URLs, rotated per reservation — the client tries them in order. */
|
|
19
|
+
export interface ReservationView {
|
|
20
|
+
id: string;
|
|
21
|
+
uploadUrls: string[];
|
|
22
|
+
}
|
|
23
|
+
export type TranscodingKindView = "video" | "audio";
|
|
24
|
+
export type RenderModeView = "replace" | "mix";
|
|
25
|
+
export interface StartUploadInput {
|
|
26
|
+
name: string;
|
|
27
|
+
contentType: string;
|
|
28
|
+
totalChunks: number;
|
|
29
|
+
}
|
|
30
|
+
export interface UploadAssetInput {
|
|
31
|
+
name: string;
|
|
32
|
+
contentType: string;
|
|
33
|
+
/** At most ASSETS_RUST_LIMITS.chunkSizeBytes. */
|
|
34
|
+
data: Uint8Array;
|
|
35
|
+
}
|
|
36
|
+
export interface UploadImageInput {
|
|
37
|
+
salonId: string;
|
|
38
|
+
name: string;
|
|
39
|
+
contentType: string;
|
|
40
|
+
/** At most ASSETS_RUST_LIMITS.chunkSizeBytes — downscale first. */
|
|
41
|
+
data: Uint8Array;
|
|
42
|
+
/** Attach the image to this salon service as well. */
|
|
43
|
+
targetSalonServiceId?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface ReserveTranscodingUploadInput {
|
|
46
|
+
salonId: string;
|
|
47
|
+
/** Default "video". "audio" reserves a music track (the worker stores an MP3). */
|
|
48
|
+
kind?: TranscodingKindView;
|
|
49
|
+
/** The library name core shows for the entry. */
|
|
50
|
+
name?: string;
|
|
51
|
+
}
|
|
52
|
+
export interface ReserveRenderInput {
|
|
53
|
+
salonId: string;
|
|
54
|
+
/** A stored picture (image/*) or video (video/*). */
|
|
55
|
+
sourceAssetId: string;
|
|
56
|
+
/** A stored music track (audio/mpeg). */
|
|
57
|
+
audioAssetId: string;
|
|
58
|
+
mode: RenderModeView;
|
|
59
|
+
/** 0..100. */
|
|
60
|
+
musicVolumePct: number;
|
|
61
|
+
/** 0..600; left out = 0. */
|
|
62
|
+
musicStartSec?: number;
|
|
63
|
+
/** 5..60, for a picture source only (and required there). */
|
|
64
|
+
slideDurationSec?: number;
|
|
65
|
+
/** The library name core shows for the result. */
|
|
66
|
+
name?: string;
|
|
67
|
+
}
|
|
68
|
+
export interface SystemStartUploadInput {
|
|
69
|
+
/** The reserved asset id the result is stored under. */
|
|
70
|
+
id: string;
|
|
71
|
+
name: string;
|
|
72
|
+
contentType: string;
|
|
73
|
+
totalChunks: number;
|
|
74
|
+
}
|
|
75
|
+
export interface HttpGetInput {
|
|
76
|
+
/** Request headers, e.g. `{ Range: "bytes=0-99" }`. */
|
|
77
|
+
headers?: Record<string, string>;
|
|
78
|
+
}
|
|
79
|
+
/** `http_request` answered as a plain object. Header names are lower-cased. */
|
|
80
|
+
export interface HttpResponseView {
|
|
81
|
+
statusCode: number;
|
|
82
|
+
headers: Record<string, string>;
|
|
83
|
+
body: Uint8Array;
|
|
84
|
+
/** True when the body is only the first chunk and the rest streams through callbacks. */
|
|
85
|
+
streaming: boolean;
|
|
86
|
+
}
|
|
87
|
+
export interface UploadProgress {
|
|
88
|
+
/** Chunks confirmed by the canister so far. */
|
|
89
|
+
uploadedChunks: number;
|
|
90
|
+
totalChunks: number;
|
|
91
|
+
}
|
|
92
|
+
export interface ChunkedUploadOptions {
|
|
93
|
+
/** Default ASSETS_RUST_LIMITS.chunkSizeBytes. */
|
|
94
|
+
chunkSizeBytes?: number;
|
|
95
|
+
onProgress?: (progress: UploadProgress) => void;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=interfaces.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../src/interfaces.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AssetInfo, HttpResponse, RenderMode, ReserveTranscodingUpload, TranscodingKind, WorkerEntry } from "../declarations/sultana-assets-rust/sultana-assets-rust.did.js";
|
|
2
|
+
import type { AssetInfoView, HttpResponseView, RenderModeView, ReservationView, TranscodingKindView, WorkerView } from "./interfaces.js";
|
|
3
|
+
export declare function mapAssetInfoView(info: AssetInfo): AssetInfoView;
|
|
4
|
+
export declare function mapWorkerView(entry: WorkerEntry): WorkerView;
|
|
5
|
+
export declare function mapReservationView(reservation: ReserveTranscodingUpload): ReservationView;
|
|
6
|
+
export declare function mapHttpResponseView(response: HttpResponse): HttpResponseView;
|
|
7
|
+
export declare function toCandidTranscodingKind(kind: TranscodingKindView): TranscodingKind;
|
|
8
|
+
export declare function toCandidRenderMode(mode: RenderModeView): RenderMode;
|
|
9
|
+
/** `undefined` → candid `opt` none, anything else → `[value]`. */
|
|
10
|
+
export declare function toCandidOpt<T>(value: T | undefined): [] | [T];
|
|
11
|
+
//# sourceMappingURL=mappers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mappers.d.ts","sourceRoot":"","sources":["../src/mappers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,UAAU,EAAE,wBAAwB,EAAE,eAAe,EAAE,WAAW,EAAE,MAAM,gEAAgE,CAAC;AAClL,OAAO,KAAK,EAAE,aAAa,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,mBAAmB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAEzI,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,SAAS,GAAG,aAAa,CAS/D;AAED,wBAAgB,aAAa,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,CAE5D;AAED,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,wBAAwB,GAAG,eAAe,CAEzF;AAED,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,YAAY,GAAG,gBAAgB,CAY5E;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,mBAAmB,GAAG,eAAe,CAElF;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,cAAc,GAAG,UAAU,CAEnE;AAED,kEAAkE;AAClE,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,GAAG,SAAS,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC,CAE7D"}
|
package/dist/mappers.js
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
export function mapAssetInfoView(info) {
|
|
2
|
+
return {
|
|
3
|
+
id: info.id,
|
|
4
|
+
name: info.name,
|
|
5
|
+
contentType: info.contentType,
|
|
6
|
+
totalSize: Number(info.totalSize),
|
|
7
|
+
chunkCount: info.chunkCount,
|
|
8
|
+
uploadedAt: info.uploadedAt,
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
export function mapWorkerView(entry) {
|
|
12
|
+
return { principal: entry.principal.toText(), url: entry.url };
|
|
13
|
+
}
|
|
14
|
+
export function mapReservationView(reservation) {
|
|
15
|
+
return { id: reservation.id, uploadUrls: [...reservation.uploadUrls] };
|
|
16
|
+
}
|
|
17
|
+
export function mapHttpResponseView(response) {
|
|
18
|
+
const headers = {};
|
|
19
|
+
for (const [name, value] of response.headers) {
|
|
20
|
+
headers[name.toLowerCase()] = value;
|
|
21
|
+
}
|
|
22
|
+
return {
|
|
23
|
+
statusCode: response.status_code,
|
|
24
|
+
headers,
|
|
25
|
+
body: response.body instanceof Uint8Array ? response.body : Uint8Array.from(response.body),
|
|
26
|
+
streaming: response.streaming_strategy.length > 0,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export function toCandidTranscodingKind(kind) {
|
|
30
|
+
return kind === "audio" ? { Audio: null } : { Video: null };
|
|
31
|
+
}
|
|
32
|
+
export function toCandidRenderMode(mode) {
|
|
33
|
+
return mode === "mix" ? { Mix: null } : { Replace: null };
|
|
34
|
+
}
|
|
35
|
+
/** `undefined` → candid `opt` none, anything else → `[value]`. */
|
|
36
|
+
export function toCandidOpt(value) {
|
|
37
|
+
return value === undefined ? [] : [value];
|
|
38
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jsm-mit/sultana-assets-rust-package",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Wrapper TypeScript package for the sultana-assets-rust canister: chunked and single-shot uploads, salon images and transcoding reservations, the worker upload path, reads and asset URLs.",
|
|
5
|
+
"license": "ISC",
|
|
6
|
+
"author": "",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"import": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"./declarations/*": "./declarations/*"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist/",
|
|
19
|
+
"declarations/"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "tsc",
|
|
23
|
+
"clean": "rm -rf dist",
|
|
24
|
+
"prepare": "npm run build",
|
|
25
|
+
"publish-public": "bash scripts/publish-public.sh",
|
|
26
|
+
"typecheck": "tsc --noEmit -p tsconfig.tests.json",
|
|
27
|
+
"sync-declarations": "bash scripts/sync-declarations.sh",
|
|
28
|
+
"test-suite": "bash scripts/run-tests.sh tests/test-suite.ts --lease 3",
|
|
29
|
+
"redeploy": "bash scripts/redeploy.sh",
|
|
30
|
+
"sandbox": "npx tsx sandbox/main.ts",
|
|
31
|
+
"stamp-canister": "bash scripts/stamp-canister-commit.sh"
|
|
32
|
+
},
|
|
33
|
+
"peerDependencies": {
|
|
34
|
+
"@icp-sdk/core": "^6.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@icp-sdk/core": "^6.1.0",
|
|
38
|
+
"@jsm-mit/cli-game-helpers": "^0.1.3",
|
|
39
|
+
"@jsm-mit/utils-package": "^0.5.0",
|
|
40
|
+
"@types/node": "^25.5.2",
|
|
41
|
+
"dotenv": "^16.3.1",
|
|
42
|
+
"tsx": "^4.18.0",
|
|
43
|
+
"typescript": "^5.9.3"
|
|
44
|
+
},
|
|
45
|
+
"homepage": "https://github.com/JSM-Sultana/sultana-assets-rust-package#readme",
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/JSM-Sultana/sultana-assets-rust-package/issues"
|
|
48
|
+
},
|
|
49
|
+
"repository": {
|
|
50
|
+
"type": "git",
|
|
51
|
+
"url": "git+https://github.com/JSM-Sultana/sultana-assets-rust-package.git"
|
|
52
|
+
},
|
|
53
|
+
"sultanaAssets": {
|
|
54
|
+
"repo": "sultana-assets-rust",
|
|
55
|
+
"repoUrl": "https://github.com/JSM-Sultana/sultana-assets-rust",
|
|
56
|
+
"commit": "a2fcfea02282aa858d683bddb26297f2091c431c"
|
|
57
|
+
}
|
|
58
|
+
}
|