@jsm-mit/sultana-assets-rust-package 0.3.0 → 0.4.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 +14 -5
- package/dist/actor-base.d.ts +4 -1
- package/dist/actor-base.d.ts.map +1 -1
- package/dist/actor-base.js +16 -5
- package/dist/actors/assets-actor.d.ts +4 -2
- package/dist/actors/assets-actor.d.ts.map +1 -1
- package/dist/actors/assets-actor.js +4 -2
- package/dist/actors/uploads-actor.d.ts +7 -3
- package/dist/actors/uploads-actor.d.ts.map +1 -1
- package/dist/actors/uploads-actor.js +7 -3
- package/dist/constants.d.ts +4 -0
- package/dist/constants.d.ts.map +1 -1
- package/dist/constants.js +4 -0
- package/package.json +5 -5
package/README.md
CHANGED
|
@@ -34,7 +34,7 @@ One class per part of the canister:
|
|
|
34
34
|
| `AssetsRustUploadsActor` | chunked session, single-shot upload, `uploadBytesAsyncUnsafe` | any signed-in caller |
|
|
35
35
|
| `AssetsRustSalonActor` | `upload_image`, `delete_salon_asset`, transcoding and render reservations | the salon's owner — core decides |
|
|
36
36
|
| `AssetsRustWorkerActor` | system upload of a transcoded result under a reserved id | listed transcoding workers |
|
|
37
|
-
| `AssetsRustAssetsActor` | `get_asset_info`, `list_assets`, `http_request`, `assetUrl` | anybody |
|
|
37
|
+
| `AssetsRustAssetsActor` | `get_asset_info`, `list_assets`, `http_request`, `assetUrl` | anybody; `list_assets` only the canister's controllers and the core seat |
|
|
38
38
|
| `AssetsRustAvatarActor` | `upload_my_avatar`, `delete_my_avatar` (own avatar only, profile required — core `isUser` —, no quota; 64 KB / 512 px, re-encoded as JPEG), `get_avatar`, `/avatar/<principal>`, `avatarUrl` | writes: the caller for themselves; reads: anybody |
|
|
39
39
|
|
|
40
40
|
Every method is `…AsyncUnsafe` and throws one of three errors, like the other wrapper
|
|
@@ -57,14 +57,16 @@ types are exported too, and `./declarations/*` gives the generated files.
|
|
|
57
57
|
`src/` is browser-safe — the same package serves the biz panel, the playground and the
|
|
58
58
|
transcoding worker.
|
|
59
59
|
|
|
60
|
-
Scripts: `build`, `typecheck`, `sync-declarations`, `test-suite`, `test-smoke`, `test-upgrade`,
|
|
60
|
+
Scripts: `build`, `typecheck`, `sync-declarations`, `test-suite`, `test-smoke`, `test-upgrade`,
|
|
61
|
+
`redeploy`, `sandbox`
|
|
61
62
|
(an interactive console: `npm run sandbox -- <canister-id>`, caller from `IDENTITY_PEM` in
|
|
62
63
|
`.env.sandbox` or anonymous), `stamp-canister`, `publish-public`. See `CLAUDE.md` for who runs what.
|
|
63
64
|
|
|
64
65
|
## Integration tests
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
All tests run on the LOCAL replica — no cycles, no shared slot. `npm run test-suite`
|
|
68
|
+
reinstalls the current `../sultana-assets-rust` build into a local canister and runs
|
|
69
|
+
`tests/test-suite.ts` there. No
|
|
68
70
|
`.env`, no PEMs: every identity is generated per run. A fresh canister has no core canister,
|
|
69
71
|
so the suite claims that claim-once seat for a generated identity and plays core itself.
|
|
70
72
|
|
|
@@ -73,6 +75,12 @@ read per domain (worker list, a few-byte single-shot upload read back over HTTP,
|
|
|
73
75
|
result, a salon upload refused by the stand-in core), one replication wait, ≈ 30 s.
|
|
74
76
|
`publish-public` runs it too.
|
|
75
77
|
|
|
78
|
+
`npm run test-upgrade` seeds the canister, upgrades it in the middle of the run and checks
|
|
79
|
+
that the stored data reads back identical. `scripts/local-canister.sh`
|
|
80
|
+
builds `../sultana-assets-rust` with cargo and reinstalls it into a canister of the dfx project
|
|
81
|
+
in `local/` (its id stays under `local/.dfx`); the upgrade test upgrades that canister. The
|
|
82
|
+
local replica must run (`dfx start --background`); the scripts never start or stop it.
|
|
83
|
+
|
|
76
84
|
What the suite covers: the core seat and the worker list; chunked and single-shot uploads
|
|
77
85
|
with every owner and size check; reads, HTTP 200/206/404, certification header and
|
|
78
86
|
streaming; the worker's system upload with a poster; `delete_asset` taking the thumb along;
|
|
@@ -85,7 +93,8 @@ the suite never touches it.
|
|
|
85
93
|
|
|
86
94
|
Bump the version by hand, commit, push, then `npm run publish-public`. It refuses unless this
|
|
87
95
|
repo and `../sultana-assets-rust` are on a clean, pushed `master` and the version is new on
|
|
88
|
-
npm; it reinstalls the canister's master into
|
|
96
|
+
npm; it reinstalls the canister's master into the canister on the LOCAL replica
|
|
97
|
+
(`scripts/local-canister.sh`; the replica must run), checks that its
|
|
89
98
|
`candid:service` equals `declarations/sultana-assets-rust/sultana-assets-rust.did` as dfx
|
|
90
99
|
rewrites it (the hand-written .did is normalized by a local `dfx build --check` first), runs
|
|
91
100
|
the smoke test (`tests/test-smoke.ts`) on that same deploy, stamps
|
package/dist/actor-base.d.ts
CHANGED
|
@@ -25,10 +25,13 @@ export declare class ActorBase {
|
|
|
25
25
|
protected host: string;
|
|
26
26
|
protected actor: ActorSubclass<_SERVICE>;
|
|
27
27
|
protected agent: HttpAgent;
|
|
28
|
+
private ready;
|
|
28
29
|
/**
|
|
29
30
|
* @param canisterId - The sultana-assets-rust canister to talk to.
|
|
30
31
|
* @param identity - The caller; left out = anonymous (enough for the reads).
|
|
31
|
-
* @param host - The IC API host; default https://icp0.io.
|
|
32
|
+
* @param host - The IC API host; default https://icp0.io. A local replica
|
|
33
|
+
* (`http://127.0.0.1:4943`) works too: for a local host — and only then — the agent
|
|
34
|
+
* fetches the replica's root key before the first call.
|
|
32
35
|
*/
|
|
33
36
|
constructor(canisterId: string, identity?: Identity | undefined, host?: string);
|
|
34
37
|
private initAgentAndActor;
|
package/dist/actor-base.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"actor-base.d.ts","sourceRoot":"","sources":["../src/actor-base.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAS,MAAM,qBAAqB,CAAC;AAE1F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gEAAgE,CAAC;AAG/F,sFAAsF;AACtF,MAAM,WAAW,SAAS;IACtB,yFAAyF;IACzF,QAAQ,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,YAAY,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,QAAQ,EAAE,OAAO,CAAC;CACrB;
|
|
1
|
+
{"version":3,"file":"actor-base.d.ts","sourceRoot":"","sources":["../src/actor-base.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,aAAa,EAAE,SAAS,EAAE,KAAK,QAAQ,EAAS,MAAM,qBAAqB,CAAC;AAE1F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,gEAAgE,CAAC;AAG/F,sFAAsF;AACtF,MAAM,WAAW,SAAS;IACtB,yFAAyF;IACzF,QAAQ,EAAE,MAAM,CAAC;IACjB,iFAAiF;IACjF,YAAY,EAAE,MAAM,CAAC;IACrB,oCAAoC;IACpC,QAAQ,EAAE,OAAO,CAAC;CACrB;AASD;;;;;;;;;GASG;AACH,qBAAa,SAAS;IAYN,SAAS,CAAC,UAAU,EAAE,MAAM;IAAE,SAAS,CAAC,QAAQ,CAAC,EAAE,QAAQ;IAAE,SAAS,CAAC,IAAI,EAAE,MAAM;IAX/F,SAAS,CAAC,KAAK,EAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC1C,SAAS,CAAC,KAAK,EAAG,SAAS,CAAC;IAC5B,OAAO,CAAC,KAAK,CAAoC;IAEjD;;;;;;OAMG;gBACmB,UAAU,EAAE,MAAM,EAAY,QAAQ,CAAC,EAAE,QAAQ,YAAA,EAAY,IAAI,GAAE,MAAqB;IAI9G,OAAO,CAAC,iBAAiB;IAYzB;;;;OAIG;IACI,iBAAiB,IAAI,IAAI;IAIhC,iFAAiF;cACjE,0BAA0B,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAuBpF,SAAS,CAAC,qBAAqB,CAAC,KAAK,EAAE,GAAG,GAAG,OAAO;IAcpD,SAAS,CAAC,kBAAkB,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI;CAU1D"}
|
package/dist/actor-base.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { HttpAgent, Actor } from "@icp-sdk/core/agent";
|
|
2
2
|
import { idlFactory } from "../declarations/sultana-assets-rust/sultana-assets-rust.did.js";
|
|
3
3
|
import { DEFAULT_HOST } from "./constants.js";
|
|
4
|
+
function isLocalHost(host) {
|
|
5
|
+
return /^https?:\/\/(127\.0\.0\.1|localhost|\[::1\])(:\d+)?\/?$/.test(host);
|
|
6
|
+
}
|
|
4
7
|
// IC error code of an explicit trap (ic0.trap — every ic_cdk::trap and every Rust panic).
|
|
5
8
|
const TRAP_ERROR_CODE = "IC0503";
|
|
6
9
|
/**
|
|
@@ -19,10 +22,13 @@ export class ActorBase {
|
|
|
19
22
|
host;
|
|
20
23
|
actor;
|
|
21
24
|
agent;
|
|
25
|
+
ready = Promise.resolve();
|
|
22
26
|
/**
|
|
23
27
|
* @param canisterId - The sultana-assets-rust canister to talk to.
|
|
24
28
|
* @param identity - The caller; left out = anonymous (enough for the reads).
|
|
25
|
-
* @param host - The IC API host; default https://icp0.io.
|
|
29
|
+
* @param host - The IC API host; default https://icp0.io. A local replica
|
|
30
|
+
* (`http://127.0.0.1:4943`) works too: for a local host — and only then — the agent
|
|
31
|
+
* fetches the replica's root key before the first call.
|
|
26
32
|
*/
|
|
27
33
|
constructor(canisterId, identity, host = DEFAULT_HOST) {
|
|
28
34
|
this.canisterId = canisterId;
|
|
@@ -35,6 +41,7 @@ export class ActorBase {
|
|
|
35
41
|
host: this.host,
|
|
36
42
|
identity: this.identity,
|
|
37
43
|
});
|
|
44
|
+
this.ready = isLocalHost(this.host) ? this.agent.fetchRootKey().then(() => undefined) : Promise.resolve();
|
|
38
45
|
this.actor = Actor.createActor(idlFactory, {
|
|
39
46
|
agent: this.agent,
|
|
40
47
|
canisterId: this.canisterId,
|
|
@@ -50,6 +57,7 @@ export class ActorBase {
|
|
|
50
57
|
}
|
|
51
58
|
/** Runs one canister call and translates its failure (see the class comment). */
|
|
52
59
|
async executeFunctionAsyncUnsafe(fnAsync) {
|
|
60
|
+
await this.ready;
|
|
53
61
|
try {
|
|
54
62
|
return await fnAsync();
|
|
55
63
|
}
|
|
@@ -65,12 +73,15 @@ export class ActorBase {
|
|
|
65
73
|
throw new Error("CriticalCanisterError", { cause: { logs: null, rawError: err } });
|
|
66
74
|
}
|
|
67
75
|
}
|
|
68
|
-
// True if `error` is an IC reject caused by an inspect-stage refusal.
|
|
69
|
-
//
|
|
70
|
-
//
|
|
76
|
+
// True if `error` is an IC reject caused by an inspect-stage refusal. The canister's
|
|
77
|
+
// inspect_message (since 2026-10-25) refuses by not accepting, which the replica reports as
|
|
78
|
+
// "Canister rejected the message" (IC0406); older replicas said "... refused message".
|
|
71
79
|
isInspectionRejection(error) {
|
|
72
80
|
const rejectText = error?.cause?.code?.rejectMessage || error?.message || "";
|
|
73
|
-
return rejectText.includes("
|
|
81
|
+
return (rejectText.includes("Canister rejected the message") ||
|
|
82
|
+
rejectText.includes("IC0406") ||
|
|
83
|
+
rejectText.includes("canister_inspect_message explicitly refused message") ||
|
|
84
|
+
rejectText.includes("canister_inspect_message implicitly refused message"));
|
|
74
85
|
}
|
|
75
86
|
// The trap text when `error` is a trap of the canister, otherwise null. The replica
|
|
76
87
|
// reports it as "... Canister called `ic0.trap` with message: '<text>'.\nConsider ...";
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ActorBase } from "../actor-base.js";
|
|
2
2
|
import type { AssetInfoView, HttpGetInput, HttpResponseView } from "../interfaces.js";
|
|
3
|
-
/** Reads: what is stored and how it is served. All queries — anonymous callers are fine
|
|
3
|
+
/** Reads: what is stored and how it is served. All queries — anonymous callers are fine,
|
|
4
|
+
* except `listAssetsAsyncUnsafe`: the canister's controllers and the core seat only. */
|
|
4
5
|
export declare class AssetsRustAssetsActor extends ActorBase {
|
|
5
6
|
/**
|
|
6
7
|
* @param assetId - The asset.
|
|
@@ -13,7 +14,8 @@ export declare class AssetsRustAssetsActor extends ActorBase {
|
|
|
13
14
|
getAssetInfoAsyncUnsafe(assetId: string): Promise<AssetInfoView | null>;
|
|
14
15
|
/**
|
|
15
16
|
* Every asset physically stored — the raw storage view, independent of any salon library:
|
|
16
|
-
* thumbnails, posters and orphans included.
|
|
17
|
+
* thumbnails, posters and orphans included. The canister's controllers and the core seat
|
|
18
|
+
* only; anybody else gets a CanisterError ("list_assets refused: controllers only").
|
|
17
19
|
* @returns A Promise that resolves to every stored asset.
|
|
18
20
|
* @throws CanisterError - The canister trapped.
|
|
19
21
|
* @throws CallRefusedAtInspectionStage - The call was refused at the inspect stage.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"assets-actor.d.ts","sourceRoot":"","sources":["../../src/actors/assets-actor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGtF
|
|
1
|
+
{"version":3,"file":"assets-actor.d.ts","sourceRoot":"","sources":["../../src/actors/assets-actor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAGtF;wFACwF;AACxF,qBAAa,qBAAsB,SAAQ,SAAS;IAChD;;;;;;;OAOG;IACU,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAKpF;;;;;;;;OAQG;IACU,qBAAqB,IAAI,OAAO,CAAC,aAAa,EAAE,CAAC;IAK9D;;;;;;;;;;OAUG;IACU,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,GAAE,YAAiB,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAYzG,0EAA0E;IACnE,QAAQ,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;CAG3C"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ActorBase } from "../actor-base.js";
|
|
2
2
|
import { assetUrl } from "../constants.js";
|
|
3
3
|
import { mapAssetInfoView, mapHttpResponseView } from "../mappers.js";
|
|
4
|
-
/** Reads: what is stored and how it is served. All queries — anonymous callers are fine
|
|
4
|
+
/** Reads: what is stored and how it is served. All queries — anonymous callers are fine,
|
|
5
|
+
* except `listAssetsAsyncUnsafe`: the canister's controllers and the core seat only. */
|
|
5
6
|
export class AssetsRustAssetsActor extends ActorBase {
|
|
6
7
|
/**
|
|
7
8
|
* @param assetId - The asset.
|
|
@@ -17,7 +18,8 @@ export class AssetsRustAssetsActor extends ActorBase {
|
|
|
17
18
|
}
|
|
18
19
|
/**
|
|
19
20
|
* Every asset physically stored — the raw storage view, independent of any salon library:
|
|
20
|
-
* thumbnails, posters and orphans included.
|
|
21
|
+
* thumbnails, posters and orphans included. The canister's controllers and the core seat
|
|
22
|
+
* only; anybody else gets a CanisterError ("list_assets refused: controllers only").
|
|
21
23
|
* @returns A Promise that resolves to every stored asset.
|
|
22
24
|
* @throws CanisterError - The canister trapped.
|
|
23
25
|
* @throws CallRefusedAtInspectionStage - The call was refused at the inspect stage.
|
|
@@ -2,7 +2,9 @@ import { ActorBase } from "../actor-base.js";
|
|
|
2
2
|
import type { ChunkedUploadOptions, StartUploadInput, UploadAssetInput } from "../interfaces.js";
|
|
3
3
|
/**
|
|
4
4
|
* Generic uploads, not tied to a salon: a chunked session (start → chunks → finish) or a
|
|
5
|
-
* single-shot upload.
|
|
5
|
+
* single-shot upload. Only an admin of the group may upload (the canister asks core's
|
|
6
|
+
* `isAdmin`; today the cockpit's APK), at most 64 MiB per session and three open sessions per
|
|
7
|
+
* uploader (ASSETS_RUST_LIMITS); the session belongs to its starter.
|
|
6
8
|
* Salon-library uploads go through {@link AssetsRustSalonActor} instead.
|
|
7
9
|
*/
|
|
8
10
|
export declare class AssetsRustUploadsActor extends ActorBase {
|
|
@@ -11,7 +13,8 @@ export declare class AssetsRustUploadsActor extends ActorBase {
|
|
|
11
13
|
* after 30 minutes.
|
|
12
14
|
* @param input - Name, content type and the number of chunks that will follow.
|
|
13
15
|
* @returns A Promise that resolves to the new asset id (the session id).
|
|
14
|
-
* @throws CanisterError - The canister trapped: anonymous caller, totalChunks 0
|
|
16
|
+
* @throws CanisterError - The canister trapped: anonymous caller, totalChunks 0, upload
|
|
17
|
+
* too large, not an admin of the group (`upload refused`), too many open sessions.
|
|
15
18
|
* @throws CallRefusedAtInspectionStage - The call was refused at the inspect stage.
|
|
16
19
|
* @throws CriticalCanisterError - Transport failure or an unreachable canister.
|
|
17
20
|
*/
|
|
@@ -52,7 +55,8 @@ export declare class AssetsRustUploadsActor extends ActorBase {
|
|
|
52
55
|
* Single-shot upload of a small file.
|
|
53
56
|
* @param input - Name, content type and at most ASSETS_RUST_LIMITS.chunkSizeBytes of data.
|
|
54
57
|
* @returns A Promise that resolves to the new asset id.
|
|
55
|
-
* @throws CanisterError - The canister trapped: anonymous caller, file too large
|
|
58
|
+
* @throws CanisterError - The canister trapped: anonymous caller, file too large, not an
|
|
59
|
+
* admin of the group (`upload refused`).
|
|
56
60
|
* @throws CallRefusedAtInspectionStage - The call was refused at the inspect stage.
|
|
57
61
|
* @throws CriticalCanisterError - Transport failure or an unreachable canister.
|
|
58
62
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"uploads-actor.d.ts","sourceRoot":"","sources":["../../src/actors/uploads-actor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEjG
|
|
1
|
+
{"version":3,"file":"uploads-actor.d.ts","sourceRoot":"","sources":["../../src/actors/uploads-actor.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAE7C,OAAO,KAAK,EAAE,oBAAoB,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEjG;;;;;;GAMG;AACH,qBAAa,sBAAuB,SAAQ,SAAS;IACjD;;;;;;;;;OASG;IACU,sBAAsB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC;IAI7E;;;;;;;;;;OAUG;IACU,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpG;;;;;;;;OAQG;IACU,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAItE;;;;;;;;OAQG;IACU,sBAAsB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAItE;;;;;;;;OAQG;IACU,sBAAsB,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC;IAI7E;;;;;;;;;;;OAWG;IACU,sBAAsB,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,GAAE,oBAAyB,GAAG,OAAO,CAAC,MAAM,CAAC;CAgBjJ"}
|
|
@@ -2,7 +2,9 @@ import { ActorBase } from "../actor-base.js";
|
|
|
2
2
|
import { splitIntoChunks } from "../constants.js";
|
|
3
3
|
/**
|
|
4
4
|
* Generic uploads, not tied to a salon: a chunked session (start → chunks → finish) or a
|
|
5
|
-
* single-shot upload.
|
|
5
|
+
* single-shot upload. Only an admin of the group may upload (the canister asks core's
|
|
6
|
+
* `isAdmin`; today the cockpit's APK), at most 64 MiB per session and three open sessions per
|
|
7
|
+
* uploader (ASSETS_RUST_LIMITS); the session belongs to its starter.
|
|
6
8
|
* Salon-library uploads go through {@link AssetsRustSalonActor} instead.
|
|
7
9
|
*/
|
|
8
10
|
export class AssetsRustUploadsActor extends ActorBase {
|
|
@@ -11,7 +13,8 @@ export class AssetsRustUploadsActor extends ActorBase {
|
|
|
11
13
|
* after 30 minutes.
|
|
12
14
|
* @param input - Name, content type and the number of chunks that will follow.
|
|
13
15
|
* @returns A Promise that resolves to the new asset id (the session id).
|
|
14
|
-
* @throws CanisterError - The canister trapped: anonymous caller, totalChunks 0
|
|
16
|
+
* @throws CanisterError - The canister trapped: anonymous caller, totalChunks 0, upload
|
|
17
|
+
* too large, not an admin of the group (`upload refused`), too many open sessions.
|
|
15
18
|
* @throws CallRefusedAtInspectionStage - The call was refused at the inspect stage.
|
|
16
19
|
* @throws CriticalCanisterError - Transport failure or an unreachable canister.
|
|
17
20
|
*/
|
|
@@ -60,7 +63,8 @@ export class AssetsRustUploadsActor extends ActorBase {
|
|
|
60
63
|
* Single-shot upload of a small file.
|
|
61
64
|
* @param input - Name, content type and at most ASSETS_RUST_LIMITS.chunkSizeBytes of data.
|
|
62
65
|
* @returns A Promise that resolves to the new asset id.
|
|
63
|
-
* @throws CanisterError - The canister trapped: anonymous caller, file too large
|
|
66
|
+
* @throws CanisterError - The canister trapped: anonymous caller, file too large, not an
|
|
67
|
+
* admin of the group (`upload refused`).
|
|
64
68
|
* @throws CallRefusedAtInspectionStage - The call was refused at the inspect stage.
|
|
65
69
|
* @throws CriticalCanisterError - Transport failure or an unreachable canister.
|
|
66
70
|
*/
|
package/dist/constants.d.ts
CHANGED
|
@@ -12,6 +12,10 @@ export declare const ASSETS_RUST_LIMITS: {
|
|
|
12
12
|
readonly maxRangeBytes: 1800000;
|
|
13
13
|
/** Width of the thumbnail `upload_image` generates (never upscaled). */
|
|
14
14
|
readonly thumbnailWidth: 128;
|
|
15
|
+
/** Generic uploads (`start_upload`, `upload_asset`; admins of the group only): the most
|
|
16
|
+
* bytes one session may announce, and the open sessions one uploader may hold. */
|
|
17
|
+
readonly maxGenericUploadBytes: number;
|
|
18
|
+
readonly maxOpenSessionsPerOwner: 3;
|
|
15
19
|
/** An unfinished upload session is purged after this long (30 min). */
|
|
16
20
|
readonly sessionTtlMs: number;
|
|
17
21
|
/** The only audio content type `reserve_render` takes as the music track. */
|
package/dist/constants.d.ts.map
CHANGED
|
@@ -1 +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;;;;;IAK7F;uDACmD;;;CAG7C,CAAC;AAEX;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED;oCACoC;AACpC,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,EAAE,cAAc,GAAE,MAA0C,GAAG,UAAU,EAAE,CAY3H"}
|
|
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;uFACmF;;;IAGnF,uEAAuE;;IAEvE,6EAA6E;;IAE7E,6FAA6F;;;;;IAK7F;uDACmD;;;CAG7C,CAAC;AAEX;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEpE;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnE;AAED;oCACoC;AACpC,wBAAgB,eAAe,CAAC,KAAK,EAAE,UAAU,EAAE,cAAc,GAAE,MAA0C,GAAG,UAAU,EAAE,CAY3H"}
|
package/dist/constants.js
CHANGED
|
@@ -12,6 +12,10 @@ export const ASSETS_RUST_LIMITS = {
|
|
|
12
12
|
maxRangeBytes: 1_800_000,
|
|
13
13
|
/** Width of the thumbnail `upload_image` generates (never upscaled). */
|
|
14
14
|
thumbnailWidth: 128,
|
|
15
|
+
/** Generic uploads (`start_upload`, `upload_asset`; admins of the group only): the most
|
|
16
|
+
* bytes one session may announce, and the open sessions one uploader may hold. */
|
|
17
|
+
maxGenericUploadBytes: 64 * 1024 * 1024,
|
|
18
|
+
maxOpenSessionsPerOwner: 3,
|
|
15
19
|
/** An unfinished upload session is purged after this long (30 min). */
|
|
16
20
|
sessionTtlMs: 30 * 60 * 1000,
|
|
17
21
|
/** The only audio content type `reserve_render` takes as the music track. */
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jsm-mit/sultana-assets-rust-package",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
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
5
|
"license": "ISC",
|
|
6
6
|
"author": "",
|
|
@@ -25,9 +25,9 @@
|
|
|
25
25
|
"publish-public": "bash scripts/publish-public.sh",
|
|
26
26
|
"typecheck": "tsc --noEmit -p tsconfig.tests.json",
|
|
27
27
|
"sync-declarations": "bash scripts/sync-declarations.sh",
|
|
28
|
-
"test-suite": "bash scripts/run-tests.sh tests/test-suite.ts
|
|
29
|
-
"test-smoke": "bash scripts/run-tests.sh tests/test-smoke.ts
|
|
30
|
-
"test-upgrade": "bash scripts/run-tests.sh tests/test-upgrade.ts
|
|
28
|
+
"test-suite": "bash scripts/run-tests-local.sh tests/test-suite.ts",
|
|
29
|
+
"test-smoke": "bash scripts/run-tests-local.sh tests/test-smoke.ts",
|
|
30
|
+
"test-upgrade": "bash scripts/run-tests-local.sh tests/test-upgrade.ts",
|
|
31
31
|
"redeploy": "bash scripts/redeploy.sh",
|
|
32
32
|
"sandbox": "npx tsx sandbox/main.ts",
|
|
33
33
|
"stamp-canister": "bash scripts/stamp-canister-commit.sh"
|
|
@@ -55,6 +55,6 @@
|
|
|
55
55
|
"sultanaAssets": {
|
|
56
56
|
"repo": "sultana-assets-rust",
|
|
57
57
|
"repoUrl": "https://github.com/JSM-Sultana/sultana-assets-rust",
|
|
58
|
-
"commit": "
|
|
58
|
+
"commit": "a5db6bd52dc751a7603c5c5fdc16fb73e0486882"
|
|
59
59
|
}
|
|
60
60
|
}
|