@jsm-mit/sultana-assets-rust-package 0.3.1 → 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 CHANGED
@@ -58,14 +58,15 @@ types are exported too, and `./declarations/*` gives the generated files.
58
58
  transcoding worker.
59
59
 
60
60
  Scripts: `build`, `typecheck`, `sync-declarations`, `test-suite`, `test-smoke`, `test-upgrade`,
61
- `test-suite-local`, `test-smoke-local`, `test-upgrade-local`, `redeploy`, `sandbox`
61
+ `redeploy`, `sandbox`
62
62
  (an interactive console: `npm run sandbox -- <canister-id>`, caller from `IDENTITY_PEM` in
63
63
  `.env.sandbox` or anonymous), `stamp-canister`, `publish-public`. See `CLAUDE.md` for who runs what.
64
64
 
65
65
  ## Integration tests
66
66
 
67
- `npm run test-suite` reinstalls the current `../sultana-assets-rust` build into the crafting
68
- table's `short-living` slot (lease 3 minutes) and runs `tests/test-suite.ts` there. No
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
69
70
  `.env`, no PEMs: every identity is generated per run. A fresh canister has no core canister,
70
71
  so the suite claims that claim-once seat for a generated identity and plays core itself.
71
72
 
@@ -74,8 +75,8 @@ read per domain (worker list, a few-byte single-shot upload read back over HTTP,
74
75
  result, a salon upload refused by the stand-in core), one replication wait, ≈ 30 s.
75
76
  `publish-public` runs it too.
76
77
 
77
- The `-local` variants (`npm run test-suite-local`, `test-smoke-local`, `test-upgrade-local`) run
78
- the same entry points on the LOCAL replica — no cycles, no lease. `scripts/local-canister.sh`
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`
79
80
  builds `../sultana-assets-rust` with cargo and reinstalls it into a canister of the dfx project
80
81
  in `local/` (its id stays under `local/.dfx`); the upgrade test upgrades that canister. The
81
82
  local replica must run (`dfx start --background`); the scripts never start or stop it.
@@ -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;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;IASpD,SAAS,CAAC,kBAAkB,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI;CAU1D"}
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"}
@@ -73,12 +73,15 @@ export class ActorBase {
73
73
  throw new Error("CriticalCanisterError", { cause: { logs: null, rawError: err } });
74
74
  }
75
75
  }
76
- // True if `error` is an IC reject caused by an inspect-stage refusal. sultana-assets-rust
77
- // has no inspect_message today; kept so the error vocabulary stays the same as in the
78
- // other wrapper packages. When the canister gets one, check the text it produces.
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".
79
79
  isInspectionRejection(error) {
80
80
  const rejectText = error?.cause?.code?.rejectMessage || error?.message || "";
81
- return rejectText.includes("canister_inspect_message explicitly refused message");
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"));
82
85
  }
83
86
  // The trap text when `error` is a trap of the canister, otherwise null. The replica
84
87
  // reports it as "... Canister called `ic0.trap` with message: '<text>'.\nConsider ...";
@@ -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. Any signed-in caller may upload; the session belongs to its starter.
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;;;;GAIG;AACH,qBAAa,sBAAuB,SAAQ,SAAS;IACjD;;;;;;;;OAQG;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;;;;;;;OAOG;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"}
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. Any signed-in caller may upload; the session belongs to its starter.
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
  */
@@ -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. */
@@ -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.1",
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,12 +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 --lease 3",
29
- "test-smoke": "bash scripts/run-tests.sh tests/test-smoke.ts --lease 3",
30
- "test-upgrade": "bash scripts/run-tests.sh tests/test-upgrade.ts --lease 6",
31
- "test-suite-local": "bash scripts/run-tests-local.sh tests/test-suite.ts",
32
- "test-smoke-local": "bash scripts/run-tests-local.sh tests/test-smoke.ts",
33
- "test-upgrade-local": "bash scripts/run-tests-local.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",
34
31
  "redeploy": "bash scripts/redeploy.sh",
35
32
  "sandbox": "npx tsx sandbox/main.ts",
36
33
  "stamp-canister": "bash scripts/stamp-canister-commit.sh"
@@ -58,6 +55,6 @@
58
55
  "sultanaAssets": {
59
56
  "repo": "sultana-assets-rust",
60
57
  "repoUrl": "https://github.com/JSM-Sultana/sultana-assets-rust",
61
- "commit": "d63f0d1ebcfa98c953ae7f68b5331e81966cec8b"
58
+ "commit": "a5db6bd52dc751a7603c5c5fdc16fb73e0486882"
62
59
  }
63
60
  }