@unicity-astrid/sdk 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.
Files changed (124) hide show
  1. package/README.md +120 -0
  2. package/dist/approval.d.ts +23 -0
  3. package/dist/approval.d.ts.map +1 -0
  4. package/dist/approval.js +29 -0
  5. package/dist/approval.js.map +1 -0
  6. package/dist/capabilities.d.ts +14 -0
  7. package/dist/capabilities.d.ts.map +1 -0
  8. package/dist/capabilities.js +19 -0
  9. package/dist/capabilities.js.map +1 -0
  10. package/dist/capsule.d.ts +39 -0
  11. package/dist/capsule.d.ts.map +1 -0
  12. package/dist/capsule.js +67 -0
  13. package/dist/capsule.js.map +1 -0
  14. package/dist/contracts.d.ts +1104 -0
  15. package/dist/contracts.d.ts.map +1 -0
  16. package/dist/contracts.js +4 -0
  17. package/dist/contracts.js.map +1 -0
  18. package/dist/elicit.d.ts +30 -0
  19. package/dist/elicit.d.ts.map +1 -0
  20. package/dist/elicit.js +103 -0
  21. package/dist/elicit.js.map +1 -0
  22. package/dist/env.d.ts +19 -0
  23. package/dist/env.d.ts.map +1 -0
  24. package/dist/env.js +27 -0
  25. package/dist/env.js.map +1 -0
  26. package/dist/errors.d.ts +46 -0
  27. package/dist/errors.d.ts.map +1 -0
  28. package/dist/errors.js +108 -0
  29. package/dist/errors.js.map +1 -0
  30. package/dist/fs.d.ts +135 -0
  31. package/dist/fs.d.ts.map +1 -0
  32. package/dist/fs.js +257 -0
  33. package/dist/fs.js.map +1 -0
  34. package/dist/http.d.ts +90 -0
  35. package/dist/http.d.ts.map +1 -0
  36. package/dist/http.js +276 -0
  37. package/dist/http.js.map +1 -0
  38. package/dist/identity.d.ts +46 -0
  39. package/dist/identity.d.ts.map +1 -0
  40. package/dist/identity.js +69 -0
  41. package/dist/identity.js.map +1 -0
  42. package/dist/index.d.ts +30 -0
  43. package/dist/index.d.ts.map +1 -0
  44. package/dist/index.js +27 -0
  45. package/dist/index.js.map +1 -0
  46. package/dist/interceptors.d.ts +21 -0
  47. package/dist/interceptors.d.ts.map +1 -0
  48. package/dist/interceptors.js +22 -0
  49. package/dist/interceptors.js.map +1 -0
  50. package/dist/ipc.d.ts +143 -0
  51. package/dist/ipc.d.ts.map +1 -0
  52. package/dist/ipc.js +261 -0
  53. package/dist/ipc.js.map +1 -0
  54. package/dist/kv.d.ts +45 -0
  55. package/dist/kv.d.ts.map +1 -0
  56. package/dist/kv.js +91 -0
  57. package/dist/kv.js.map +1 -0
  58. package/dist/log.d.ts +17 -0
  59. package/dist/log.d.ts.map +1 -0
  60. package/dist/log.js +40 -0
  61. package/dist/log.js.map +1 -0
  62. package/dist/net.d.ts +154 -0
  63. package/dist/net.d.ts.map +1 -0
  64. package/dist/net.js +421 -0
  65. package/dist/net.js.map +1 -0
  66. package/dist/process.d.ts +77 -0
  67. package/dist/process.d.ts.map +1 -0
  68. package/dist/process.js +128 -0
  69. package/dist/process.js.map +1 -0
  70. package/dist/runtime/bridge.d.ts +34 -0
  71. package/dist/runtime/bridge.d.ts.map +1 -0
  72. package/dist/runtime/bridge.js +326 -0
  73. package/dist/runtime/bridge.js.map +1 -0
  74. package/dist/runtime/index.d.ts +3 -0
  75. package/dist/runtime/index.d.ts.map +1 -0
  76. package/dist/runtime/index.js +3 -0
  77. package/dist/runtime/index.js.map +1 -0
  78. package/dist/runtime/registry.d.ts +58 -0
  79. package/dist/runtime/registry.d.ts.map +1 -0
  80. package/dist/runtime/registry.js +129 -0
  81. package/dist/runtime/registry.js.map +1 -0
  82. package/dist/runtime.d.ts +36 -0
  83. package/dist/runtime.d.ts.map +1 -0
  84. package/dist/runtime.js +50 -0
  85. package/dist/runtime.js.map +1 -0
  86. package/dist/time.d.ts +29 -0
  87. package/dist/time.d.ts.map +1 -0
  88. package/dist/time.js +43 -0
  89. package/dist/time.js.map +1 -0
  90. package/dist/tool.d.ts +48 -0
  91. package/dist/tool.d.ts.map +1 -0
  92. package/dist/tool.js +86 -0
  93. package/dist/tool.js.map +1 -0
  94. package/dist/uplink.d.ts +27 -0
  95. package/dist/uplink.d.ts.map +1 -0
  96. package/dist/uplink.js +36 -0
  97. package/dist/uplink.js.map +1 -0
  98. package/package.json +38 -0
  99. package/src/approval.ts +38 -0
  100. package/src/capabilities.ts +22 -0
  101. package/src/capsule.ts +90 -0
  102. package/src/contracts.ts +1189 -0
  103. package/src/elicit.ts +136 -0
  104. package/src/env.ts +31 -0
  105. package/src/errors.ts +122 -0
  106. package/src/fs.ts +357 -0
  107. package/src/http.ts +345 -0
  108. package/src/identity.ts +101 -0
  109. package/src/index.ts +83 -0
  110. package/src/interceptors.ts +25 -0
  111. package/src/ipc.ts +354 -0
  112. package/src/kv.ts +123 -0
  113. package/src/log.ts +43 -0
  114. package/src/net.ts +545 -0
  115. package/src/process.ts +205 -0
  116. package/src/runtime/bridge.ts +374 -0
  117. package/src/runtime/index.ts +11 -0
  118. package/src/runtime/registry.ts +178 -0
  119. package/src/runtime.ts +70 -0
  120. package/src/time.ts +48 -0
  121. package/src/tool.ts +125 -0
  122. package/src/uplink.ts +49 -0
  123. package/src/wit-imports.d.ts +689 -0
  124. package/wit-contracts/astrid-contracts.wit +1266 -0
package/README.md ADDED
@@ -0,0 +1,120 @@
1
+ # @unicity-astrid/sdk
2
+
3
+ [![License: MIT OR Apache-2.0](https://img.shields.io/badge/License-MIT%20OR%20Apache--2.0-blue.svg)](../../LICENSE-MIT)
4
+ [![Node: >=20](https://img.shields.io/badge/Node-%3E%3D20-blue)](https://nodejs.org)
5
+ [![TypeScript: 5.2+](https://img.shields.io/badge/TypeScript-5.2%2B-blue)](https://www.typescriptlang.org)
6
+
7
+ **The system library for Astrid OS user space, in JavaScript / TypeScript.**
8
+
9
+ Sibling of [`astrid-sdk`](https://github.com/unicity-astrid/sdk-rust) (Rust). Same host ABI, same WIT contract, same `.capsule` archive shape — the kernel can't tell which language built the binary. Where the Rust SDK mirrors `std`, this one mirrors Node + WHATWG. Same semantics, idiom translated.
10
+
11
+ ## Where it fits
12
+
13
+ ```text
14
+ Capsule code (TypeScript or JavaScript)
15
+ |
16
+ @unicity-astrid/sdk typed modules: fs, net, ipc, kv, http, ...
17
+ |
18
+ WIT-imported bindings "astrid:<domain>/host@1.0.0" + "astrid:io/*@1.0.0" (ComponentizeJS-generated)
19
+ |
20
+ Kernel capability checks, VFS, IPC bus, audit
21
+ ```
22
+
23
+ The SDK never reaches the network, filesystem, or any external service directly. Every operation is a WIT host call into the kernel. The kernel decides whether to allow it.
24
+
25
+ ## Module layout
26
+
27
+ | Module | Rust SDK | Node / WHATWG idiom |
28
+ |---|---|---|
29
+ | `fs` | `astrid_sdk::fs` (mirrors `std::fs`) | `node:fs/promises` shape: `readFile`/`writeFile`/`mkdir`/`stat` (returns `Stats` with `isFile()`/`isDirectory()`/`mtimeMs`)/`readdir`/`opendir` (AsyncIterable) |
30
+ | `net` | `astrid_sdk::net` (mirrors `std::sync::mpsc`) | mpsc-shaped errors (`RecvError` / `TryRecvError::{Empty,Closed}` / `SendError`) + `Symbol.asyncIterator` streams |
31
+ | `process` | `astrid_sdk::process` | `child_process.spawn`-shaped: `spawn(cmd, args) → ProcessResult`, `spawnBackground` returns `BackgroundProcessHandle` with `readLogs`/`kill` |
32
+ | `env` | `astrid_sdk::env` (mirrors `std::env`) | `env.get(key)`, `CONFIG_SOCKET_PATH` constant |
33
+ | `time` | `astrid_sdk::time` | `now() → Date`, `nowMs() → bigint` |
34
+ | `log` | `astrid_sdk::log` (mirrors `log` crate) | `log.{trace,debug,info,warn,error}`. **No** `globalThis.console` shadowing — the engine may already wire it. |
35
+ | `ipc` | `astrid_sdk::ipc` | `publish`/`publishJson`; `subscribe(topic)` returns a `Subscription` with `.poll()`/`.recv(timeoutMs)` (full parity, surfaces `lagged`/`dropped`) AND `Symbol.asyncIterator` for convenience |
36
+ | `kv` | `astrid_sdk::kv` | Map-shape async: `get<T>(key)`/`set<T>`/`has`/`del`/`listKeys`/`clearPrefix`; raw byte variants for non-JSON payloads |
37
+ | `http` | `astrid_sdk::http` (mirrors reqwest) | Builder `Request.get/post/header/json/setBody` + `send` / `streamStart`; plus a WHATWG `fetch` polyfill that routes through the same host imports for capability-gated network access |
38
+ | `runtime` | `astrid_sdk::runtime` | `signalReady()`, `caller() → CallerContext`, `socketPath()` |
39
+ | `capabilities` | `astrid_sdk::capabilities` | `check(sourceUuid, capability) → boolean` |
40
+ | `elicit` | `astrid_sdk::elicit` | `secret`/`hasSecret`/`text`/`textWithDefault`/`select`/`array` (install/upgrade only) |
41
+ | `identity` | `astrid_sdk::identity` | `resolve`/`link`/`unlink`/`createUser`/`listLinks` |
42
+ | `approval` | `astrid_sdk::approval` | `request(action, resource) → boolean` |
43
+ | `uplink` | `astrid_sdk::uplink` | `register(name, platform, profile) → UplinkId`, `send(id, userId, content) → boolean` |
44
+ | `interceptors` | `astrid_sdk::interceptors` | `bindings()` / `poll(bindings, handler)` — usually unneeded; `@interceptor` decorator handles dispatch |
45
+
46
+ ## Decorators (replaces `#[capsule]` macro)
47
+
48
+ | Rust attribute | TypeScript decorator |
49
+ |---|---|
50
+ | `#[capsule]` on impl block | `@capsule` on class |
51
+ | `#[astrid::tool("name")]` | `@tool("name", { mutable?, description?, inputSchema? })` |
52
+ | `#[astrid::interceptor("topic")]` | `@interceptor("topic", { mutable? })` |
53
+ | `#[astrid::command("name")]` | `@command("name", { mutable? })` |
54
+ | `#[astrid::install]` | `@install` |
55
+ | `#[astrid::upgrade]` | `@upgrade` |
56
+ | `#[astrid::run]` | `@run` |
57
+
58
+ TypeScript 5.2+ standard decorators (TC39 Stage 3). No `experimentalDecorators` flag — default behaviour.
59
+
60
+ ## Quick start
61
+
62
+ ```bash
63
+ npm install @unicity-astrid/sdk
64
+ npm install --save-dev @unicity-astrid/build typescript
65
+ ```
66
+
67
+ ```typescript
68
+ import { capsule, tool, install, log, kv } from "@unicity-astrid/sdk";
69
+
70
+ @capsule
71
+ export class MyCapsule {
72
+ greetings = 0;
73
+
74
+ @tool("greet", { mutable: true })
75
+ greet({ name }: { name: string }): { message: string; count: number } {
76
+ this.greetings++;
77
+ log.info(`greeting ${name} (#${this.greetings})`);
78
+ return { message: `Hello, ${name}!`, count: this.greetings };
79
+ }
80
+
81
+ @install
82
+ onInstall(): void {
83
+ log.info("my-capsule installed");
84
+ }
85
+ }
86
+ ```
87
+
88
+ `astrid build` (from the Rust kernel CLI) detects `package.json + Capsule.toml`, shells out to the `@unicity-astrid/build` Node orchestrator, and emits a `.capsule` archive packaged identically to a Rust capsule's.
89
+
90
+ ## Error model: throw, don't `Result`
91
+
92
+ The Rust SDK returns `Result<T, SysError>`. This SDK **throws** a `SysError extends Error` with a `code` discriminant (`"HostError"` / `"JsonError"` / `"ApiError"`). Fighting JS to add Rust-shaped errors would be the opposite of "feels native". Same semantics, idiom-correct.
93
+
94
+ ## Async model
95
+
96
+ The Rust SDK is synchronous because WASM exports are synchronous. The JS SDK is async (`await fs.readFile(...)`) because that's what Node developers expect. ComponentizeJS's syncify makes awaits backed by host imports settle synchronously at the WASM boundary. Use `await` freely inside `@tool` / `@interceptor` / `@run` handlers — the engine settles them before the host returns.
97
+
98
+ `@run` handlers that loop forever (`while (true) { await ipc.recv(...) }`) block the WIT `run` export until the loop exits, matching the Rust SDK's daemon-style capsules exactly.
99
+
100
+ ## `tool_describe` and `tool_execute_<name>`
101
+
102
+ The bridge auto-generates the `tool_describe` aggregated schema payload (lazy, cached) on first invocation, matching what `schemars::schema_for!` produces from Rust capsules. Tool input schemas come from the decorator's `inputSchema` option or, at build time, from `ts-json-schema-generator` walking the parameter types. Schemas may differ in subtle ways from Rust's `schemars` output (e.g. `Option<T>` vs `T | undefined` representation) — acceptable for LLM tool-calling, monitored via a conformance test.
103
+
104
+ `tool_execute_<name>` dispatch handles `mutable: true` tools by loading `__state` from KV before the call and persisting after on success, matching the Rust macro's behaviour exactly. Result is published to `tool.v1.execute.<name>.result` via IPC.
105
+
106
+ ## Subpath exports
107
+
108
+ | Import | Contents |
109
+ |---|---|
110
+ | `@unicity-astrid/sdk` | Public API barrel |
111
+ | `@unicity-astrid/sdk/runtime` | Internal registry + bridge — exposed for advanced authors only |
112
+ | `@unicity-astrid/sdk/contracts` | Auto-generated TS types from `astrid-contracts.wit` (`Message`, `ToolCall`, `GenerateRequest`, `StreamEvent`, etc.) |
113
+
114
+ ## Status
115
+
116
+ Alpha. End-to-end build + install + kernel-lifecycle execution proven. See `../../notes/phase-{0,1,2,3-install}.md`.
117
+
118
+ ## License
119
+
120
+ Dual MIT/Apache-2.0. See [LICENSE-MIT](../../LICENSE-MIT) and [LICENSE-APACHE](../../LICENSE-APACHE).
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Human-in-the-loop approval. Mirrors `astrid_sdk::approval`.
3
+ *
4
+ * The capsule declares the action and target resource. The kernel classifies
5
+ * risk, checks any pre-approved allowances, and either auto-approves or
6
+ * prompts the frontend user. The capsule sees the specific decision class
7
+ * (one-shot / session / always / allowance-hit / denied), not just
8
+ * approved/denied — UI can communicate WHY (e.g. "stored as always-approve")
9
+ * for transparency.
10
+ */
11
+ import { type ApprovalDecision } from "astrid:approval/host@1.0.0";
12
+ export type { ApprovalDecision } from "astrid:approval/host@1.0.0";
13
+ /**
14
+ * Request approval for a sensitive action. Returns `true` if approved (any
15
+ * approval variant), `false` if denied. Blocks until the user responds or
16
+ * the request times out (60s).
17
+ *
18
+ * For the specific decision class, use {@link requestDecision}.
19
+ */
20
+ export declare function request(action: string, resource: string): boolean;
21
+ /** Request approval and return the specific decision class. */
22
+ export declare function requestDecision(action: string, resource: string): ApprovalDecision;
23
+ //# sourceMappingURL=approval.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval.d.ts","sourceRoot":"","sources":["../src/approval.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAEL,KAAK,gBAAgB,EACtB,MAAM,4BAA4B,CAAC;AAGpC,YAAY,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAEnE;;;;;;GAMG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAGjE;AAED,+DAA+D;AAC/D,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAKlF"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * Human-in-the-loop approval. Mirrors `astrid_sdk::approval`.
3
+ *
4
+ * The capsule declares the action and target resource. The kernel classifies
5
+ * risk, checks any pre-approved allowances, and either auto-approves or
6
+ * prompts the frontend user. The capsule sees the specific decision class
7
+ * (one-shot / session / always / allowance-hit / denied), not just
8
+ * approved/denied — UI can communicate WHY (e.g. "stored as always-approve")
9
+ * for transparency.
10
+ */
11
+ import { requestApproval as hostRequestApproval, } from "astrid:approval/host@1.0.0";
12
+ import { callHost } from "./errors.js";
13
+ /**
14
+ * Request approval for a sensitive action. Returns `true` if approved (any
15
+ * approval variant), `false` if denied. Blocks until the user responds or
16
+ * the request times out (60s).
17
+ *
18
+ * For the specific decision class, use {@link requestDecision}.
19
+ */
20
+ export function request(action, resource) {
21
+ const decision = requestDecision(action, resource);
22
+ return decision !== "denied";
23
+ }
24
+ /** Request approval and return the specific decision class. */
25
+ export function requestDecision(action, resource) {
26
+ const resp = callHost(`approval.request(${JSON.stringify(action)})`, () => hostRequestApproval({ action, targetResource: resource }));
27
+ return resp.decision;
28
+ }
29
+ //# sourceMappingURL=approval.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approval.js","sourceRoot":"","sources":["../src/approval.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EACL,eAAe,IAAI,mBAAmB,GAEvC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAIvC;;;;;;GAMG;AACH,MAAM,UAAU,OAAO,CAAC,MAAc,EAAE,QAAgB;IACtD,MAAM,QAAQ,GAAG,eAAe,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IACnD,OAAO,QAAQ,KAAK,QAAQ,CAAC;AAC/B,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,eAAe,CAAC,MAAc,EAAE,QAAgB;IAC9D,MAAM,IAAI,GAAG,QAAQ,CAAC,oBAAoB,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,GAAG,EAAE,GAAG,EAAE,CACxE,mBAAmB,CAAC,EAAE,MAAM,EAAE,cAAc,EAAE,QAAQ,EAAE,CAAC,CAC1D,CAAC;IACF,OAAO,IAAI,CAAC,QAAQ,CAAC;AACvB,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Cross-capsule capability queries. Mirrors `astrid_sdk::capabilities`.
3
+ *
4
+ * Allows a capsule to check whether another capsule (identified by its IPC
5
+ * session UUID) has a specific manifest capability. Used by the prompt
6
+ * builder to enforce `allow_prompt_injection` gating, for example.
7
+ *
8
+ * Fail-closed: returns `false` for unknown UUIDs, unknown capabilities, or
9
+ * registry-unavailable conditions (the host returns `registry-unavailable`,
10
+ * which `callHost` raises as a SysError — capsule code that wants to swallow
11
+ * registry outages should wrap the call).
12
+ */
13
+ export declare function check(sourceUuid: string, capability: string): boolean;
14
+ //# sourceMappingURL=capabilities.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.d.ts","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAKH,wBAAgB,KAAK,CAAC,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAKrE"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Cross-capsule capability queries. Mirrors `astrid_sdk::capabilities`.
3
+ *
4
+ * Allows a capsule to check whether another capsule (identified by its IPC
5
+ * session UUID) has a specific manifest capability. Used by the prompt
6
+ * builder to enforce `allow_prompt_injection` gating, for example.
7
+ *
8
+ * Fail-closed: returns `false` for unknown UUIDs, unknown capabilities, or
9
+ * registry-unavailable conditions (the host returns `registry-unavailable`,
10
+ * which `callHost` raises as a SysError — capsule code that wants to swallow
11
+ * registry outages should wrap the call).
12
+ */
13
+ import { checkCapsuleCapability } from "astrid:sys/host@1.0.0";
14
+ import { callHost } from "./errors.js";
15
+ export function check(sourceUuid, capability) {
16
+ const resp = callHost(`capabilities.check(${JSON.stringify(capability)})`, () => checkCapsuleCapability({ sourceUuid, capability }));
17
+ return resp.allowed;
18
+ }
19
+ //# sourceMappingURL=capabilities.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capabilities.js","sourceRoot":"","sources":["../src/capabilities.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAC/D,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAEvC,MAAM,UAAU,KAAK,CAAC,UAAkB,EAAE,UAAkB;IAC1D,MAAM,IAAI,GAAG,QAAQ,CAAC,sBAAsB,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,EAAE,CAC9E,sBAAsB,CAAC,EAAE,UAAU,EAAE,UAAU,EAAE,CAAC,CACnD,CAAC;IACF,OAAO,IAAI,CAAC,OAAO,CAAC;AACtB,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * Capsule + lifecycle decorators. Mirrors `#[capsule]` / `#[astrid::install]`
3
+ * / `#[astrid::upgrade]` from the Rust SDK.
4
+ *
5
+ * TypeScript standard decorators (TC39 Stage 3 / TS 5.0+). Class-method
6
+ * decorators are the most stable subset of the spec; we deliberately use
7
+ * only that subset to minimize churn risk.
8
+ */
9
+ import { type CapsuleConstructor } from "./runtime/registry.js";
10
+ /**
11
+ * Class decorator marking the entry-point of the capsule. The decorated
12
+ * class must have a no-arg constructor (state defaults via field initializers).
13
+ *
14
+ * Exactly one `@capsule` class per compiled WASM module.
15
+ */
16
+ export declare function capsule<T extends CapsuleConstructor>(target: T, _context: ClassDecoratorContext<T>): T;
17
+ /**
18
+ * Method decorator marking the first-time install lifecycle hook. The
19
+ * method receives no arguments and may be async. It runs once before any
20
+ * tool dispatch.
21
+ */
22
+ export declare function install<This extends object>(_value: (this: This) => unknown, context: ClassMethodDecoratorContext<This, (this: This) => unknown>): void;
23
+ /**
24
+ * Method decorator marking the upgrade lifecycle hook. The method receives
25
+ * the previous version string and may be async.
26
+ */
27
+ export declare function upgrade<This extends object>(_value: (this: This, prevVersion: string) => unknown, context: ClassMethodDecoratorContext<This, (this: This, prevVersion: string) => unknown>): void;
28
+ /**
29
+ * Method decorator marking the long-running background loop. The method
30
+ * receives no arguments, may be async, and is expected NEVER to return
31
+ * (it is the capsule's daemon loop). Mirror of `#[astrid::run]`.
32
+ *
33
+ * Capsules that declare `@run` are "runnable" capsules: the kernel
34
+ * spawns them as background tasks and the WIT `run` export blocks until
35
+ * the loop exits. Capsules without `@run` are hook-driven and the `run`
36
+ * export is a no-op.
37
+ */
38
+ export declare function run<This extends object>(_value: (this: This) => unknown, context: ClassMethodDecoratorContext<This, (this: This) => unknown>): void;
39
+ //# sourceMappingURL=capsule.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capsule.d.ts","sourceRoot":"","sources":["../src/capsule.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EACL,KAAK,kBAAkB,EAMxB,MAAM,uBAAuB,CAAC;AAE/B;;;;;GAKG;AACH,wBAAgB,OAAO,CAAC,CAAC,SAAS,kBAAkB,EAClD,MAAM,EAAE,CAAC,EACT,QAAQ,EAAE,qBAAqB,CAAC,CAAC,CAAC,GACjC,CAAC,CAIH;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,IAAI,SAAS,MAAM,EACzC,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,EAC/B,OAAO,EAAE,2BAA2B,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,GAClE,IAAI,CAQN;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,IAAI,SAAS,MAAM,EACzC,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,KAAK,OAAO,EACpD,OAAO,EAAE,2BAA2B,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC,GACvF,IAAI,CAQN;AAED;;;;;;;;;GASG;AACH,wBAAgB,GAAG,CAAC,IAAI,SAAS,MAAM,EACrC,MAAM,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,EAC/B,OAAO,EAAE,2BAA2B,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,GAClE,IAAI,CAQN"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Capsule + lifecycle decorators. Mirrors `#[capsule]` / `#[astrid::install]`
3
+ * / `#[astrid::upgrade]` from the Rust SDK.
4
+ *
5
+ * TypeScript standard decorators (TC39 Stage 3 / TS 5.0+). Class-method
6
+ * decorators are the most stable subset of the spec; we deliberately use
7
+ * only that subset to minimize churn risk.
8
+ */
9
+ import { registerCapsule, recordInstall, recordUpgrade, recordRun, adoptPending, } from "./runtime/registry.js";
10
+ /**
11
+ * Class decorator marking the entry-point of the capsule. The decorated
12
+ * class must have a no-arg constructor (state defaults via field initializers).
13
+ *
14
+ * Exactly one `@capsule` class per compiled WASM module.
15
+ */
16
+ export function capsule(target, _context) {
17
+ registerCapsule(target);
18
+ adoptPending(target);
19
+ return target;
20
+ }
21
+ /**
22
+ * Method decorator marking the first-time install lifecycle hook. The
23
+ * method receives no arguments and may be async. It runs once before any
24
+ * tool dispatch.
25
+ */
26
+ export function install(_value, context) {
27
+ if (context.private || context.static) {
28
+ throw new Error("@install must be applied to a public instance method.");
29
+ }
30
+ context.addInitializer(function () {
31
+ const ctor = this.constructor;
32
+ recordInstall(ctor, String(context.name));
33
+ });
34
+ }
35
+ /**
36
+ * Method decorator marking the upgrade lifecycle hook. The method receives
37
+ * the previous version string and may be async.
38
+ */
39
+ export function upgrade(_value, context) {
40
+ if (context.private || context.static) {
41
+ throw new Error("@upgrade must be applied to a public instance method.");
42
+ }
43
+ context.addInitializer(function () {
44
+ const ctor = this.constructor;
45
+ recordUpgrade(ctor, String(context.name));
46
+ });
47
+ }
48
+ /**
49
+ * Method decorator marking the long-running background loop. The method
50
+ * receives no arguments, may be async, and is expected NEVER to return
51
+ * (it is the capsule's daemon loop). Mirror of `#[astrid::run]`.
52
+ *
53
+ * Capsules that declare `@run` are "runnable" capsules: the kernel
54
+ * spawns them as background tasks and the WIT `run` export blocks until
55
+ * the loop exits. Capsules without `@run` are hook-driven and the `run`
56
+ * export is a no-op.
57
+ */
58
+ export function run(_value, context) {
59
+ if (context.private || context.static) {
60
+ throw new Error("@run must be applied to a public instance method.");
61
+ }
62
+ context.addInitializer(function () {
63
+ const ctor = this.constructor;
64
+ recordRun(ctor, String(context.name));
65
+ });
66
+ }
67
+ //# sourceMappingURL=capsule.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"capsule.js","sourceRoot":"","sources":["../src/capsule.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAEL,eAAe,EACf,aAAa,EACb,aAAa,EACb,SAAS,EACT,YAAY,GACb,MAAM,uBAAuB,CAAC;AAE/B;;;;;GAKG;AACH,MAAM,UAAU,OAAO,CACrB,MAAS,EACT,QAAkC;IAElC,eAAe,CAAC,MAAM,CAAC,CAAC;IACxB,YAAY,CAAC,MAAM,CAAC,CAAC;IACrB,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,OAAO,CACrB,MAA+B,EAC/B,OAAmE;IAEnE,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,CAAC,cAAc,CAAC;QACrB,MAAM,IAAI,GAAI,IAAe,CAAC,WAAiC,CAAC;QAChE,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,OAAO,CACrB,MAAoD,EACpD,OAAwF;IAExF,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;IAC3E,CAAC;IACD,OAAO,CAAC,cAAc,CAAC;QACrB,MAAM,IAAI,GAAI,IAAe,CAAC,WAAiC,CAAC;QAChE,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,GAAG,CACjB,MAA+B,EAC/B,OAAmE;IAEnE,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;QACtC,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAC;IACvE,CAAC;IACD,OAAO,CAAC,cAAc,CAAC;QACrB,MAAM,IAAI,GAAI,IAAe,CAAC,WAAiC,CAAC;QAChE,SAAS,CAAC,IAAI,EAAE,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;AACL,CAAC"}