@jsm-mit/sultana-assets-rust-package 0.3.0 → 0.3.1

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
@@ -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,7 +57,8 @@ 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`, `redeploy`, `sandbox`
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
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
 
@@ -73,6 +74,12 @@ read per domain (worker list, a few-byte single-shot upload read back over HTTP,
73
74
  result, a salon upload refused by the stand-in core), one replication wait, ≈ 30 s.
74
75
  `publish-public` runs it too.
75
76
 
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`
79
+ builds `../sultana-assets-rust` with cargo and reinstalls it into a canister of the dfx project
80
+ in `local/` (its id stays under `local/.dfx`); the upgrade test upgrades that canister. The
81
+ local replica must run (`dfx start --background`); the scripts never start or stop it.
82
+
76
83
  What the suite covers: the core seat and the worker list; chunked and single-shot uploads
77
84
  with every owner and size check; reads, HTTP 200/206/404, certification header and
78
85
  streaming; the worker's system upload with a poster; `delete_asset` taking the thumb along;
@@ -85,7 +92,8 @@ the suite never touches it.
85
92
 
86
93
  Bump the version by hand, commit, push, then `npm run publish-public`. It refuses unless this
87
94
  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 `short-living` (lease 2), checks that its
95
+ npm; it reinstalls the canister's master into the canister on the LOCAL replica
96
+ (`scripts/local-canister.sh`; the replica must run), checks that its
89
97
  `candid:service` equals `declarations/sultana-assets-rust/sultana-assets-rust.did` as dfx
90
98
  rewrites it (the hand-written .did is normalized by a local `dfx build --check` first), runs
91
99
  the smoke test (`tests/test-smoke.ts`) on that same deploy, stamps
@@ -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;
@@ -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;AAKD;;;;;;;;;GASG;AACH,qBAAa,SAAS;IASN,SAAS,CAAC,UAAU,EAAE,MAAM;IAAE,SAAS,CAAC,QAAQ,CAAC,EAAE,QAAQ;IAAE,SAAS,CAAC,IAAI,EAAE,MAAM;IAR/F,SAAS,CAAC,KAAK,EAAG,aAAa,CAAC,QAAQ,CAAC,CAAC;IAC1C,SAAS,CAAC,KAAK,EAAG,SAAS,CAAC;IAE5B;;;;OAIG;gBACmB,UAAU,EAAE,MAAM,EAAY,QAAQ,CAAC,EAAE,QAAQ,YAAA,EAAY,IAAI,GAAE,MAAqB;IAI9G,OAAO,CAAC,iBAAiB;IAWzB;;;;OAIG;IACI,iBAAiB,IAAI,IAAI;IAIhC,iFAAiF;cACjE,0BAA0B,CAAC,CAAC,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAqBpF,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;IASpD,SAAS,CAAC,kBAAkB,CAAC,KAAK,EAAE,GAAG,GAAG,MAAM,GAAG,IAAI;CAU1D"}
@@ -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
  }
@@ -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,4FAA4F;AAC5F,qBAAa,qBAAsB,SAAQ,SAAS;IAChD;;;;;;;OAOG;IACU,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,GAAG,IAAI,CAAC;IAKpF;;;;;;;OAOG;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
+ {"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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jsm-mit/sultana-assets-rust-package",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
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": "",
@@ -28,6 +28,9 @@
28
28
  "test-suite": "bash scripts/run-tests.sh tests/test-suite.ts --lease 3",
29
29
  "test-smoke": "bash scripts/run-tests.sh tests/test-smoke.ts --lease 3",
30
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",
31
34
  "redeploy": "bash scripts/redeploy.sh",
32
35
  "sandbox": "npx tsx sandbox/main.ts",
33
36
  "stamp-canister": "bash scripts/stamp-canister-commit.sh"
@@ -55,6 +58,6 @@
55
58
  "sultanaAssets": {
56
59
  "repo": "sultana-assets-rust",
57
60
  "repoUrl": "https://github.com/JSM-Sultana/sultana-assets-rust",
58
- "commit": "7a2c7e96a4253f0203d9694c9200189f61044c85"
61
+ "commit": "d63f0d1ebcfa98c953ae7f68b5331e81966cec8b"
59
62
  }
60
63
  }