@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.
- package/README.md +120 -0
- package/dist/approval.d.ts +23 -0
- package/dist/approval.d.ts.map +1 -0
- package/dist/approval.js +29 -0
- package/dist/approval.js.map +1 -0
- package/dist/capabilities.d.ts +14 -0
- package/dist/capabilities.d.ts.map +1 -0
- package/dist/capabilities.js +19 -0
- package/dist/capabilities.js.map +1 -0
- package/dist/capsule.d.ts +39 -0
- package/dist/capsule.d.ts.map +1 -0
- package/dist/capsule.js +67 -0
- package/dist/capsule.js.map +1 -0
- package/dist/contracts.d.ts +1104 -0
- package/dist/contracts.d.ts.map +1 -0
- package/dist/contracts.js +4 -0
- package/dist/contracts.js.map +1 -0
- package/dist/elicit.d.ts +30 -0
- package/dist/elicit.d.ts.map +1 -0
- package/dist/elicit.js +103 -0
- package/dist/elicit.js.map +1 -0
- package/dist/env.d.ts +19 -0
- package/dist/env.d.ts.map +1 -0
- package/dist/env.js +27 -0
- package/dist/env.js.map +1 -0
- package/dist/errors.d.ts +46 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/errors.js +108 -0
- package/dist/errors.js.map +1 -0
- package/dist/fs.d.ts +135 -0
- package/dist/fs.d.ts.map +1 -0
- package/dist/fs.js +257 -0
- package/dist/fs.js.map +1 -0
- package/dist/http.d.ts +90 -0
- package/dist/http.d.ts.map +1 -0
- package/dist/http.js +276 -0
- package/dist/http.js.map +1 -0
- package/dist/identity.d.ts +46 -0
- package/dist/identity.d.ts.map +1 -0
- package/dist/identity.js +69 -0
- package/dist/identity.js.map +1 -0
- package/dist/index.d.ts +30 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +27 -0
- package/dist/index.js.map +1 -0
- package/dist/interceptors.d.ts +21 -0
- package/dist/interceptors.d.ts.map +1 -0
- package/dist/interceptors.js +22 -0
- package/dist/interceptors.js.map +1 -0
- package/dist/ipc.d.ts +143 -0
- package/dist/ipc.d.ts.map +1 -0
- package/dist/ipc.js +261 -0
- package/dist/ipc.js.map +1 -0
- package/dist/kv.d.ts +45 -0
- package/dist/kv.d.ts.map +1 -0
- package/dist/kv.js +91 -0
- package/dist/kv.js.map +1 -0
- package/dist/log.d.ts +17 -0
- package/dist/log.d.ts.map +1 -0
- package/dist/log.js +40 -0
- package/dist/log.js.map +1 -0
- package/dist/net.d.ts +154 -0
- package/dist/net.d.ts.map +1 -0
- package/dist/net.js +421 -0
- package/dist/net.js.map +1 -0
- package/dist/process.d.ts +77 -0
- package/dist/process.d.ts.map +1 -0
- package/dist/process.js +128 -0
- package/dist/process.js.map +1 -0
- package/dist/runtime/bridge.d.ts +34 -0
- package/dist/runtime/bridge.d.ts.map +1 -0
- package/dist/runtime/bridge.js +326 -0
- package/dist/runtime/bridge.js.map +1 -0
- package/dist/runtime/index.d.ts +3 -0
- package/dist/runtime/index.d.ts.map +1 -0
- package/dist/runtime/index.js +3 -0
- package/dist/runtime/index.js.map +1 -0
- package/dist/runtime/registry.d.ts +58 -0
- package/dist/runtime/registry.d.ts.map +1 -0
- package/dist/runtime/registry.js +129 -0
- package/dist/runtime/registry.js.map +1 -0
- package/dist/runtime.d.ts +36 -0
- package/dist/runtime.d.ts.map +1 -0
- package/dist/runtime.js +50 -0
- package/dist/runtime.js.map +1 -0
- package/dist/time.d.ts +29 -0
- package/dist/time.d.ts.map +1 -0
- package/dist/time.js +43 -0
- package/dist/time.js.map +1 -0
- package/dist/tool.d.ts +48 -0
- package/dist/tool.d.ts.map +1 -0
- package/dist/tool.js +86 -0
- package/dist/tool.js.map +1 -0
- package/dist/uplink.d.ts +27 -0
- package/dist/uplink.d.ts.map +1 -0
- package/dist/uplink.js +36 -0
- package/dist/uplink.js.map +1 -0
- package/package.json +38 -0
- package/src/approval.ts +38 -0
- package/src/capabilities.ts +22 -0
- package/src/capsule.ts +90 -0
- package/src/contracts.ts +1189 -0
- package/src/elicit.ts +136 -0
- package/src/env.ts +31 -0
- package/src/errors.ts +122 -0
- package/src/fs.ts +357 -0
- package/src/http.ts +345 -0
- package/src/identity.ts +101 -0
- package/src/index.ts +83 -0
- package/src/interceptors.ts +25 -0
- package/src/ipc.ts +354 -0
- package/src/kv.ts +123 -0
- package/src/log.ts +43 -0
- package/src/net.ts +545 -0
- package/src/process.ts +205 -0
- package/src/runtime/bridge.ts +374 -0
- package/src/runtime/index.ts +11 -0
- package/src/runtime/registry.ts +178 -0
- package/src/runtime.ts +70 -0
- package/src/time.ts +48 -0
- package/src/tool.ts +125 -0
- package/src/uplink.ts +49 -0
- package/src/wit-imports.d.ts +689 -0
- package/wit-contracts/astrid-contracts.wit +1266 -0
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-platform identity resolution and linking. Mirrors `astrid_sdk::identity`.
|
|
3
|
+
*
|
|
4
|
+
* Required capability in `Capsule.toml`:
|
|
5
|
+
* `["resolve"]` — resolve platform users
|
|
6
|
+
* `["link"]` — resolve, link, unlink, list-links
|
|
7
|
+
* `["admin"]` — all of the above + create new users
|
|
8
|
+
*
|
|
9
|
+
* Post per-domain WIT split, the host returns typed records directly (no
|
|
10
|
+
* `linksJson` blob, no `ok` flags). Errors surface as `SysError` with
|
|
11
|
+
* `code` set to the WIT variant (`link-not-found`, `already-linked`, etc.).
|
|
12
|
+
*
|
|
13
|
+
* The {@link resolve} helper preserves the pre-migration "absent → undefined"
|
|
14
|
+
* shape by catching `link-not-found` and returning `undefined`. Other errors
|
|
15
|
+
* propagate.
|
|
16
|
+
*/
|
|
17
|
+
export interface ResolvedUser {
|
|
18
|
+
userId: string;
|
|
19
|
+
displayName: string | undefined;
|
|
20
|
+
}
|
|
21
|
+
export interface Link {
|
|
22
|
+
platform: string;
|
|
23
|
+
platformUserId: string;
|
|
24
|
+
/** ISO 8601 timestamp the link was created. */
|
|
25
|
+
linkedAt: string;
|
|
26
|
+
/** Auth method used at link time (e.g. "passkey", "token"). */
|
|
27
|
+
method: string;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Resolve a platform identity to an Astrid user, or `undefined` if no link
|
|
31
|
+
* exists. Other identity errors (capability-denied, store-unavailable, etc.)
|
|
32
|
+
* propagate as `SysError`.
|
|
33
|
+
*/
|
|
34
|
+
export declare function resolve(platform: string, platformUserId: string): ResolvedUser | undefined;
|
|
35
|
+
/** Link a platform identity to an Astrid user. */
|
|
36
|
+
export declare function link(platform: string, platformUserId: string, astridUserId: string, method: string): void;
|
|
37
|
+
/**
|
|
38
|
+
* Unlink a platform identity. Returns `true` if a link was removed,
|
|
39
|
+
* `false` if there was nothing to remove.
|
|
40
|
+
*/
|
|
41
|
+
export declare function unlink(platform: string, platformUserId: string): boolean;
|
|
42
|
+
/** Create a new Astrid user. Returns the new user UUID. */
|
|
43
|
+
export declare function createUser(displayName?: string): string;
|
|
44
|
+
/** List all platform links for an Astrid user. */
|
|
45
|
+
export declare function listLinks(astridUserId: string): Link[];
|
|
46
|
+
//# sourceMappingURL=identity.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.d.ts","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAWH,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,GAAG,SAAS,CAAC;CACjC;AAED,MAAM,WAAW,IAAI;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAC;IACjB,+DAA+D;IAC/D,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;GAIG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAU1F;AAED,kDAAkD;AAClD,wBAAgB,IAAI,CAClB,QAAQ,EAAE,MAAM,EAChB,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,MAAM,GACb,IAAI,CAIN;AAED;;;GAGG;AACH,wBAAgB,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,GAAG,OAAO,CAQxE;AAED,2DAA2D;AAC3D,wBAAgB,UAAU,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,MAAM,CAKvD;AAED,kDAAkD;AAClD,wBAAgB,SAAS,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI,EAAE,CAQtD"}
|
package/dist/identity.js
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-platform identity resolution and linking. Mirrors `astrid_sdk::identity`.
|
|
3
|
+
*
|
|
4
|
+
* Required capability in `Capsule.toml`:
|
|
5
|
+
* `["resolve"]` — resolve platform users
|
|
6
|
+
* `["link"]` — resolve, link, unlink, list-links
|
|
7
|
+
* `["admin"]` — all of the above + create new users
|
|
8
|
+
*
|
|
9
|
+
* Post per-domain WIT split, the host returns typed records directly (no
|
|
10
|
+
* `linksJson` blob, no `ok` flags). Errors surface as `SysError` with
|
|
11
|
+
* `code` set to the WIT variant (`link-not-found`, `already-linked`, etc.).
|
|
12
|
+
*
|
|
13
|
+
* The {@link resolve} helper preserves the pre-migration "absent → undefined"
|
|
14
|
+
* shape by catching `link-not-found` and returning `undefined`. Other errors
|
|
15
|
+
* propagate.
|
|
16
|
+
*/
|
|
17
|
+
import { identityResolve as hostResolve, identityLink as hostLink, identityUnlink as hostUnlink, identityCreateUser as hostCreateUser, identityListLinks as hostListLinks, } from "astrid:identity/host@1.0.0";
|
|
18
|
+
import { SysError, callHost } from "./errors.js";
|
|
19
|
+
/**
|
|
20
|
+
* Resolve a platform identity to an Astrid user, or `undefined` if no link
|
|
21
|
+
* exists. Other identity errors (capability-denied, store-unavailable, etc.)
|
|
22
|
+
* propagate as `SysError`.
|
|
23
|
+
*/
|
|
24
|
+
export function resolve(platform, platformUserId) {
|
|
25
|
+
try {
|
|
26
|
+
const resp = callHost(`identity.resolve(${JSON.stringify(platform)})`, () => hostResolve({ platform, platformUserId }));
|
|
27
|
+
return { userId: resp.userId, displayName: resp.displayName };
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
if (err instanceof SysError && err.code === "link-not-found")
|
|
31
|
+
return undefined;
|
|
32
|
+
throw err;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
/** Link a platform identity to an Astrid user. */
|
|
36
|
+
export function link(platform, platformUserId, astridUserId, method) {
|
|
37
|
+
callHost("identity.link", () => hostLink({ platform, platformUserId, astridUserId, method }));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Unlink a platform identity. Returns `true` if a link was removed,
|
|
41
|
+
* `false` if there was nothing to remove.
|
|
42
|
+
*/
|
|
43
|
+
export function unlink(platform, platformUserId) {
|
|
44
|
+
try {
|
|
45
|
+
callHost("identity.unlink", () => hostUnlink({ platform, platformUserId }));
|
|
46
|
+
return true;
|
|
47
|
+
}
|
|
48
|
+
catch (err) {
|
|
49
|
+
if (err instanceof SysError && err.code === "link-not-found")
|
|
50
|
+
return false;
|
|
51
|
+
throw err;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/** Create a new Astrid user. Returns the new user UUID. */
|
|
55
|
+
export function createUser(displayName) {
|
|
56
|
+
const resp = callHost("identity.createUser", () => hostCreateUser({ displayName }));
|
|
57
|
+
return resp.userId;
|
|
58
|
+
}
|
|
59
|
+
/** List all platform links for an Astrid user. */
|
|
60
|
+
export function listLinks(astridUserId) {
|
|
61
|
+
const links = callHost("identity.listLinks", () => hostListLinks(astridUserId));
|
|
62
|
+
return links.map((l) => ({
|
|
63
|
+
platform: l.platform,
|
|
64
|
+
platformUserId: l.platformUserId,
|
|
65
|
+
linkedAt: l.linkedAt,
|
|
66
|
+
method: l.method,
|
|
67
|
+
}));
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=identity.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"identity.js","sourceRoot":"","sources":["../src/identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EACL,eAAe,IAAI,WAAW,EAC9B,YAAY,IAAI,QAAQ,EACxB,cAAc,IAAI,UAAU,EAC5B,kBAAkB,IAAI,cAAc,EACpC,iBAAiB,IAAI,aAAa,GACnC,MAAM,4BAA4B,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAgBjD;;;;GAIG;AACH,MAAM,UAAU,OAAO,CAAC,QAAgB,EAAE,cAAsB;IAC9D,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,QAAQ,CAAC,oBAAoB,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,EAAE,GAAG,EAAE,CAC1E,WAAW,CAAC,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,CAC1C,CAAC;QACF,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE,CAAC;IAChE,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,gBAAgB;YAAE,OAAO,SAAS,CAAC;QAC/E,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,IAAI,CAClB,QAAgB,EAChB,cAAsB,EACtB,YAAoB,EACpB,MAAc;IAEd,QAAQ,CAAC,eAAe,EAAE,GAAG,EAAE,CAC7B,QAAQ,CAAC,EAAE,QAAQ,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,EAAE,CAAC,CAC7D,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,MAAM,CAAC,QAAgB,EAAE,cAAsB;IAC7D,IAAI,CAAC;QACH,QAAQ,CAAC,iBAAiB,EAAE,GAAG,EAAE,CAAC,UAAU,CAAC,EAAE,QAAQ,EAAE,cAAc,EAAE,CAAC,CAAC,CAAC;QAC5E,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,gBAAgB;YAAE,OAAO,KAAK,CAAC;QAC3E,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,2DAA2D;AAC3D,MAAM,UAAU,UAAU,CAAC,WAAoB;IAC7C,MAAM,IAAI,GAAG,QAAQ,CAAC,qBAAqB,EAAE,GAAG,EAAE,CAChD,cAAc,CAAC,EAAE,WAAW,EAAE,CAAC,CAChC,CAAC;IACF,OAAO,IAAI,CAAC,MAAM,CAAC;AACrB,CAAC;AAED,kDAAkD;AAClD,MAAM,UAAU,SAAS,CAAC,YAAoB;IAC5C,MAAM,KAAK,GAAG,QAAQ,CAAC,oBAAoB,EAAE,GAAG,EAAE,CAAC,aAAa,CAAC,YAAY,CAAC,CAAC,CAAC;IAChF,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACvB,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,cAAc,EAAE,CAAC,CAAC,cAAc;QAChC,QAAQ,EAAE,CAAC,CAAC,QAAQ;QACpB,MAAM,EAAE,CAAC,CAAC,MAAM;KACjB,CAAC,CAAC,CAAC;AACN,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
export { SysError, type SysErrorKind } from "./errors.js";
|
|
2
|
+
export { capsule, install, upgrade, run } from "./capsule.js";
|
|
3
|
+
export { tool, interceptor, command, type ToolOptions, type InterceptorOptions, type CommandOptions, } from "./tool.js";
|
|
4
|
+
export * as log from "./log.js";
|
|
5
|
+
export * as kv from "./kv.js";
|
|
6
|
+
export * as ipc from "./ipc.js";
|
|
7
|
+
export * as fs from "./fs.js";
|
|
8
|
+
export * as http from "./http.js";
|
|
9
|
+
export * as net from "./net.js";
|
|
10
|
+
export * as process from "./process.js";
|
|
11
|
+
export * as env from "./env.js";
|
|
12
|
+
export * as time from "./time.js";
|
|
13
|
+
export * as runtime from "./runtime.js";
|
|
14
|
+
export * as capabilities from "./capabilities.js";
|
|
15
|
+
export * as elicit from "./elicit.js";
|
|
16
|
+
export * as identity from "./identity.js";
|
|
17
|
+
export * as approval from "./approval.js";
|
|
18
|
+
export * as uplink from "./uplink.js";
|
|
19
|
+
export * as interceptors from "./interceptors.js";
|
|
20
|
+
export type { IpcMessage, PollResult, Subscription, InterceptorBinding, PrincipalAttribution, } from "./ipc.js";
|
|
21
|
+
export type { Stats, Dirent, FileHandle, OpenMode, FileType } from "./fs.js";
|
|
22
|
+
export type { Request as HttpRequest, Response as HttpResponse, HttpMethod, HttpStreamHandle, StreamStart, FetchInit, FetchResponse, } from "./http.js";
|
|
23
|
+
export type { UnixListener, TcpListener, TcpStream, UdpSocket, ListenerHandle, StreamHandle, RecvError, SendError, TryRecvError, ShutdownHow, NetReadStatus, UdpDatagram, } from "./net.js";
|
|
24
|
+
export type { ProcessResult, ProcessLogs, KillResult, BackgroundProcessHandle, SpawnOptions, ProcessSignal, EnvVar, } from "./process.js";
|
|
25
|
+
export type { CallerContext } from "./runtime.js";
|
|
26
|
+
export type { ResolvedUser, Link } from "./identity.js";
|
|
27
|
+
export type { UplinkId, UplinkProfile } from "./uplink.js";
|
|
28
|
+
export type { ApprovalDecision } from "./approval.js";
|
|
29
|
+
export type { KeyPage } from "./kv.js";
|
|
30
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,QAAQ,EAAE,KAAK,YAAY,EAAE,MAAM,aAAa,CAAC;AAE1D,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EACL,IAAI,EACJ,WAAW,EACX,OAAO,EACP,KAAK,WAAW,EAChB,KAAK,kBAAkB,EACvB,KAAK,cAAc,GACpB,MAAM,WAAW,CAAC;AAKnB,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAC;AAGlD,YAAY,EACV,UAAU,EACV,UAAU,EACV,YAAY,EACZ,kBAAkB,EAClB,oBAAoB,GACrB,MAAM,UAAU,CAAC;AAClB,YAAY,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC7E,YAAY,EACV,OAAO,IAAI,WAAW,EACtB,QAAQ,IAAI,YAAY,EACxB,UAAU,EACV,gBAAgB,EAChB,WAAW,EACX,SAAS,EACT,aAAa,GACd,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,YAAY,EACZ,WAAW,EACX,SAAS,EACT,SAAS,EACT,cAAc,EACd,YAAY,EACZ,SAAS,EACT,SAAS,EACT,YAAY,EACZ,WAAW,EACX,aAAa,EACb,WAAW,GACZ,MAAM,UAAU,CAAC;AAClB,YAAY,EACV,aAAa,EACb,WAAW,EACX,UAAU,EACV,uBAAuB,EACvB,YAAY,EACZ,aAAa,EACb,MAAM,GACP,MAAM,cAAc,CAAC;AACtB,YAAY,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,YAAY,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AACxD,YAAY,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAC3D,YAAY,EAAE,gBAAgB,EAAE,MAAM,eAAe,CAAC;AACtD,YAAY,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Public API of @unicity-astrid/sdk.
|
|
2
|
+
//
|
|
3
|
+
// Module-by-module mirror of `astrid_sdk::prelude`, with idiom translated
|
|
4
|
+
// from Rust-std to Node/WHATWG conventions where appropriate.
|
|
5
|
+
export { SysError } from "./errors.js";
|
|
6
|
+
export { capsule, install, upgrade, run } from "./capsule.js";
|
|
7
|
+
export { tool, interceptor, command, } from "./tool.js";
|
|
8
|
+
// Namespaced submodules. Authors import as
|
|
9
|
+
// `import { fs, http, ipc, ... } from "@unicity-astrid/sdk"` and call
|
|
10
|
+
// `await fs.readFile(...)`, `ipc.publish(...)`, etc.
|
|
11
|
+
export * as log from "./log.js";
|
|
12
|
+
export * as kv from "./kv.js";
|
|
13
|
+
export * as ipc from "./ipc.js";
|
|
14
|
+
export * as fs from "./fs.js";
|
|
15
|
+
export * as http from "./http.js";
|
|
16
|
+
export * as net from "./net.js";
|
|
17
|
+
export * as process from "./process.js";
|
|
18
|
+
export * as env from "./env.js";
|
|
19
|
+
export * as time from "./time.js";
|
|
20
|
+
export * as runtime from "./runtime.js";
|
|
21
|
+
export * as capabilities from "./capabilities.js";
|
|
22
|
+
export * as elicit from "./elicit.js";
|
|
23
|
+
export * as identity from "./identity.js";
|
|
24
|
+
export * as approval from "./approval.js";
|
|
25
|
+
export * as uplink from "./uplink.js";
|
|
26
|
+
export * as interceptors from "./interceptors.js";
|
|
27
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAqC;AACrC,EAAE;AACF,0EAA0E;AAC1E,8DAA8D;AAE9D,OAAO,EAAE,QAAQ,EAAqB,MAAM,aAAa,CAAC;AAE1D,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAC9D,OAAO,EACL,IAAI,EACJ,WAAW,EACX,OAAO,GAIR,MAAM,WAAW,CAAC;AAEnB,2CAA2C;AAC3C,sEAAsE;AACtE,qDAAqD;AACrD,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,GAAG,MAAM,UAAU,CAAC;AAChC,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAClC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAC;AACxC,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAC1C,OAAO,KAAK,MAAM,MAAM,aAAa,CAAC;AACtC,OAAO,KAAK,YAAY,MAAM,mBAAmB,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interceptor binding registry — metadata for the kernel-managed
|
|
3
|
+
* interceptor subscriptions a capsule declared in `Capsule.toml`.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors `astrid_sdk::interceptors`. Under the per-domain ABI, interceptor
|
|
6
|
+
* events are delivered to the capsule via `astrid-hook-trigger` rather than
|
|
7
|
+
* a run-loop IPC subscription. The host fn `get-interceptor-bindings` returns
|
|
8
|
+
* metadata-only — capsules use it to enumerate the `(action, topic)` pairs
|
|
9
|
+
* they're subscribed to for debugging, introspection, and tooling. `handle`
|
|
10
|
+
* is the kernel-side registry handle (for log correlation only); it is NOT
|
|
11
|
+
* convertible into an `ipc.Subscription`.
|
|
12
|
+
*/
|
|
13
|
+
import { type InterceptorBinding } from "./ipc.js";
|
|
14
|
+
export type { InterceptorBinding } from "./ipc.js";
|
|
15
|
+
/**
|
|
16
|
+
* Query the runtime for auto-subscribed interceptor handles. Returns an
|
|
17
|
+
* empty array if this capsule has no auto-subscribed interceptors (i.e. it
|
|
18
|
+
* does not have both `@run` and `[[interceptor]]`).
|
|
19
|
+
*/
|
|
20
|
+
export declare function bindings(): InterceptorBinding[];
|
|
21
|
+
//# sourceMappingURL=interceptors.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interceptors.d.ts","sourceRoot":"","sources":["../src/interceptors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAuB,KAAK,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAExE,YAAY,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAC;AAEnD;;;;GAIG;AACH,wBAAgB,QAAQ,IAAI,kBAAkB,EAAE,CAE/C"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interceptor binding registry — metadata for the kernel-managed
|
|
3
|
+
* interceptor subscriptions a capsule declared in `Capsule.toml`.
|
|
4
|
+
*
|
|
5
|
+
* Mirrors `astrid_sdk::interceptors`. Under the per-domain ABI, interceptor
|
|
6
|
+
* events are delivered to the capsule via `astrid-hook-trigger` rather than
|
|
7
|
+
* a run-loop IPC subscription. The host fn `get-interceptor-bindings` returns
|
|
8
|
+
* metadata-only — capsules use it to enumerate the `(action, topic)` pairs
|
|
9
|
+
* they're subscribed to for debugging, introspection, and tooling. `handle`
|
|
10
|
+
* is the kernel-side registry handle (for log correlation only); it is NOT
|
|
11
|
+
* convertible into an `ipc.Subscription`.
|
|
12
|
+
*/
|
|
13
|
+
import { runtimeInterceptors } from "./ipc.js";
|
|
14
|
+
/**
|
|
15
|
+
* Query the runtime for auto-subscribed interceptor handles. Returns an
|
|
16
|
+
* empty array if this capsule has no auto-subscribed interceptors (i.e. it
|
|
17
|
+
* does not have both `@run` and `[[interceptor]]`).
|
|
18
|
+
*/
|
|
19
|
+
export function bindings() {
|
|
20
|
+
return runtimeInterceptors();
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=interceptors.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"interceptors.js","sourceRoot":"","sources":["../src/interceptors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,mBAAmB,EAA2B,MAAM,UAAU,CAAC;AAIxE;;;;GAIG;AACH,MAAM,UAAU,QAAQ;IACtB,OAAO,mBAAmB,EAAE,CAAC;AAC/B,CAAC"}
|
package/dist/ipc.d.ts
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IPC event bus. Mirrors `astrid_sdk::ipc`.
|
|
3
|
+
*
|
|
4
|
+
* Publish: {@link publish} / {@link publishJson} for the calling capsule's
|
|
5
|
+
* own principal, {@link publishAs} / {@link publishJsonAs} for uplinks
|
|
6
|
+
* asserting an end-user principal (requires `uplink = true` capability —
|
|
7
|
+
* subscribers see the principal as `claimed`, not `verified`).
|
|
8
|
+
*
|
|
9
|
+
* Subscribe: {@link subscribe} returns a {@link Subscription} resource handle.
|
|
10
|
+
* Resources are Component Model objects with a drop step; we surface
|
|
11
|
+
* `Symbol.dispose` so `using sub = ipc.subscribe(...)` cleans up automatically
|
|
12
|
+
* on scope exit, and an explicit `.close()` for codebases that haven't moved
|
|
13
|
+
* to the explicit-resource-management proposal. AsyncIterable convenience
|
|
14
|
+
* preserved from the pre-migration API.
|
|
15
|
+
*
|
|
16
|
+
* Request/response: {@link requestResponse} mirrors `astrid_sdk::ipc::request_response`.
|
|
17
|
+
* Validates the request payload, pre-subscribes to the reply topic, publishes
|
|
18
|
+
* with an auto-injected `correlation_id`, blocks up to `timeoutMs` for the
|
|
19
|
+
* single reply, always tears down the subscription.
|
|
20
|
+
*/
|
|
21
|
+
import { type PrincipalAttribution, type Subscription as WitSubscription } from "astrid:ipc/host@1.0.0";
|
|
22
|
+
/** A single IPC message dispatched to a subscriber. */
|
|
23
|
+
export interface IpcMessage {
|
|
24
|
+
topic: string;
|
|
25
|
+
payload: string;
|
|
26
|
+
/** UUID of the capsule that published this message. */
|
|
27
|
+
sourceId: string;
|
|
28
|
+
/**
|
|
29
|
+
* Principal attributed to the publisher. `verified(...)` for kernel-attributed
|
|
30
|
+
* principals, `claimed(...)` for uplink-asserted principals (NOT kernel-
|
|
31
|
+
* verified), `system` for kernel-originated events.
|
|
32
|
+
*
|
|
33
|
+
* Subscribers MUST check this variant on sensitive actions. Multi-message
|
|
34
|
+
* batches MUST be read per-message rather than relying on `runtime.caller()`
|
|
35
|
+
* (which only reflects the first message's publisher).
|
|
36
|
+
*/
|
|
37
|
+
principal: PrincipalAttribution;
|
|
38
|
+
/** Convenience: parse `payload` as JSON. Throws SysError.json on failure. */
|
|
39
|
+
json<T = unknown>(): T;
|
|
40
|
+
}
|
|
41
|
+
export type { PrincipalAttribution } from "astrid:ipc/host@1.0.0";
|
|
42
|
+
export interface PollResult {
|
|
43
|
+
messages: IpcMessage[];
|
|
44
|
+
/** Messages dropped due to buffer overflow since the previous poll. */
|
|
45
|
+
dropped: bigint;
|
|
46
|
+
/** Cumulative lag — total messages missed since subscription opened. */
|
|
47
|
+
lagged: bigint;
|
|
48
|
+
}
|
|
49
|
+
export interface InterceptorBinding {
|
|
50
|
+
/** Subscription handle ID. */
|
|
51
|
+
handle: bigint;
|
|
52
|
+
/** Hook action name the kernel dispatches when a message matches. */
|
|
53
|
+
action: string;
|
|
54
|
+
/** Topic pattern this subscription was registered for. */
|
|
55
|
+
topic: string;
|
|
56
|
+
}
|
|
57
|
+
export declare function publish(topic: string, payload: string): void;
|
|
58
|
+
export declare function publishJson<T>(topic: string, payload: T): void;
|
|
59
|
+
/**
|
|
60
|
+
* Publish on behalf of a specific principal. Requires `uplink = true` in
|
|
61
|
+
* `Capsule.toml [capabilities]`; non-uplinks see `capability-denied`.
|
|
62
|
+
* Subscribers see the principal as `claimed(...)`, NOT `verified(...)` —
|
|
63
|
+
* downstream consumers MUST treat the principal as caller-input, not
|
|
64
|
+
* authenticated context.
|
|
65
|
+
*/
|
|
66
|
+
export declare function publishAs(topic: string, payload: string, principal: string): void;
|
|
67
|
+
export declare function publishJsonAs<T>(topic: string, payload: T, principal: string): void;
|
|
68
|
+
/**
|
|
69
|
+
* Subscribe to an IPC topic pattern. Supports exact matches and trailing-suffix
|
|
70
|
+
* wildcards (`foo.bar.*`). Mid-segment wildcards are rejected by the host.
|
|
71
|
+
*
|
|
72
|
+
* The returned {@link Subscription} is a Resource handle. Use `using` for
|
|
73
|
+
* scope-bound cleanup, or call `.close()` explicitly:
|
|
74
|
+
*
|
|
75
|
+
* ```ts
|
|
76
|
+
* using sub = ipc.subscribe("foo.bar"); // disposed at scope exit
|
|
77
|
+
* for await (const msg of sub) { ... }
|
|
78
|
+
*
|
|
79
|
+
* const sub = ipc.subscribe("foo.bar"); // explicit close
|
|
80
|
+
* try { ... } finally { sub.close(); }
|
|
81
|
+
* ```
|
|
82
|
+
*
|
|
83
|
+
* Per-capsule cap: 128 subscriptions.
|
|
84
|
+
*/
|
|
85
|
+
export declare function subscribe(topicPattern: string): Subscription;
|
|
86
|
+
/**
|
|
87
|
+
* Pre-registered interceptor handles for run-loop capsules. Returns ONLY the
|
|
88
|
+
* calling capsule's own interceptors. Most authors don't call this — the
|
|
89
|
+
* `@interceptor` decorator + bridge handle dispatch.
|
|
90
|
+
*/
|
|
91
|
+
export declare function runtimeInterceptors(): InterceptorBinding[];
|
|
92
|
+
export declare class Subscription {
|
|
93
|
+
#private;
|
|
94
|
+
readonly topic: string;
|
|
95
|
+
constructor(inner: WitSubscription, topic: string);
|
|
96
|
+
/** Non-blocking poll. Returns whatever's already queued. */
|
|
97
|
+
poll(): PollResult;
|
|
98
|
+
/** Blocking receive (timeout capped at 60s by the host). */
|
|
99
|
+
recv(timeoutMs?: bigint): PollResult;
|
|
100
|
+
/**
|
|
101
|
+
* Idempotent — closing an already-closed subscription is a no-op.
|
|
102
|
+
* Equivalent to the resource Drop. Prefer `using` when the surrounding
|
|
103
|
+
* code can adopt explicit resource management.
|
|
104
|
+
*/
|
|
105
|
+
close(): void;
|
|
106
|
+
[Symbol.dispose](): void;
|
|
107
|
+
/**
|
|
108
|
+
* AsyncIterable convenience. Loops calling `.recv()` and yielding each
|
|
109
|
+
* message. Stops when the subscription is closed. Drops `lagged`/`dropped`
|
|
110
|
+
* info — use `.poll()`/`.recv()` explicitly if you need to react to lag.
|
|
111
|
+
*/
|
|
112
|
+
[Symbol.asyncIterator](): AsyncIterableIterator<IpcMessage>;
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Send a request on `requestTopic` and await a single response on a scoped
|
|
116
|
+
* reply topic. Mirrors `astrid_sdk::ipc::request_response` exactly.
|
|
117
|
+
*
|
|
118
|
+
* The helper:
|
|
119
|
+
* 1. Generates a v4 correlation ID.
|
|
120
|
+
* 2. Subscribes to `{responseNamespace}.{correlationId}` *before* publishing
|
|
121
|
+
* (so the response can never be missed in the race).
|
|
122
|
+
* 3. Injects the correlation ID into the request payload as a top-level
|
|
123
|
+
* `correlation_id` field.
|
|
124
|
+
* 4. Publishes the request.
|
|
125
|
+
* 5. Blocks up to `timeoutMs` for the response.
|
|
126
|
+
* 6. Unsubscribes (always, even on error).
|
|
127
|
+
* 7. Returns the parsed response payload as `Resp`.
|
|
128
|
+
*
|
|
129
|
+
* `request` must serialize to a JSON object. Primitives, arrays, strings,
|
|
130
|
+
* etc. are rejected synchronously with `SysError.api` because there is
|
|
131
|
+
* nowhere to put the correlation ID.
|
|
132
|
+
*
|
|
133
|
+
* `responseNamespace` should be the dotted topic prefix the responder
|
|
134
|
+
* publishes to, *without* the trailing correlation id segment. For example,
|
|
135
|
+
* if the responder publishes to
|
|
136
|
+
* `registry.v1.response.set_active_model.<corr_id>`, pass
|
|
137
|
+
* `"registry.v1.response.set_active_model"`.
|
|
138
|
+
*
|
|
139
|
+
* `timeoutMs` is capped at 60,000 ms by the host. A timeout throws
|
|
140
|
+
* `SysError.api` with `request_response: no reply within …`.
|
|
141
|
+
*/
|
|
142
|
+
export declare function requestResponse<Req, Resp = unknown>(requestTopic: string, responseNamespace: string, request: Req, timeoutMs: number | bigint): Resp;
|
|
143
|
+
//# sourceMappingURL=ipc.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ipc.d.ts","sourceRoot":"","sources":["../src/ipc.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,OAAO,EAQL,KAAK,oBAAoB,EACzB,KAAK,YAAY,IAAI,eAAe,EACrC,MAAM,uBAAuB,CAAC;AAI/B,uDAAuD;AACvD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,uDAAuD;IACvD,QAAQ,EAAE,MAAM,CAAC;IACjB;;;;;;;;OAQG;IACH,SAAS,EAAE,oBAAoB,CAAC;IAChC,6EAA6E;IAC7E,IAAI,CAAC,CAAC,GAAG,OAAO,KAAK,CAAC,CAAC;CACxB;AAED,YAAY,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAElE,MAAM,WAAW,UAAU;IACzB,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,uEAAuE;IACvE,OAAO,EAAE,MAAM,CAAC;IAChB,wEAAwE;IACxE,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,kBAAkB;IACjC,8BAA8B;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,MAAM,EAAE,MAAM,CAAC;IACf,0DAA0D;IAC1D,KAAK,EAAE,MAAM,CAAC;CACf;AAID,wBAAgB,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAE5D;AAED,wBAAgB,WAAW,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,GAAG,IAAI,CAE9D;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAIjF;AAED,wBAAgB,aAAa,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,CAAC,EAAE,SAAS,EAAE,MAAM,GAAG,IAAI,CAEnF;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,SAAS,CAAC,YAAY,EAAE,MAAM,GAAG,YAAY,CAK5D;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,IAAI,kBAAkB,EAAE,CAK1D;AAED,qBAAa,YAAY;;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;gBAGX,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,MAAM;IAKjD,4DAA4D;IAC5D,IAAI,IAAI,UAAU;IAKlB,4DAA4D;IAC5D,IAAI,CAAC,SAAS,GAAE,MAAgC,GAAG,UAAU;IAO7D;;;;OAIG;IACH,KAAK,IAAI,IAAI;IAYb,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,IAAI;IAIxB;;;;OAIG;IACI,CAAC,MAAM,CAAC,aAAa,CAAC,IAAI,qBAAqB,CAAC,UAAU,CAAC;CAenE;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2BG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,IAAI,GAAG,OAAO,EACjD,YAAY,EAAE,MAAM,EACpB,iBAAiB,EAAE,MAAM,EACzB,OAAO,EAAE,GAAG,EACZ,SAAS,EAAE,MAAM,GAAG,MAAM,GACzB,IAAI,CA0CN"}
|
package/dist/ipc.js
ADDED
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IPC event bus. Mirrors `astrid_sdk::ipc`.
|
|
3
|
+
*
|
|
4
|
+
* Publish: {@link publish} / {@link publishJson} for the calling capsule's
|
|
5
|
+
* own principal, {@link publishAs} / {@link publishJsonAs} for uplinks
|
|
6
|
+
* asserting an end-user principal (requires `uplink = true` capability —
|
|
7
|
+
* subscribers see the principal as `claimed`, not `verified`).
|
|
8
|
+
*
|
|
9
|
+
* Subscribe: {@link subscribe} returns a {@link Subscription} resource handle.
|
|
10
|
+
* Resources are Component Model objects with a drop step; we surface
|
|
11
|
+
* `Symbol.dispose` so `using sub = ipc.subscribe(...)` cleans up automatically
|
|
12
|
+
* on scope exit, and an explicit `.close()` for codebases that haven't moved
|
|
13
|
+
* to the explicit-resource-management proposal. AsyncIterable convenience
|
|
14
|
+
* preserved from the pre-migration API.
|
|
15
|
+
*
|
|
16
|
+
* Request/response: {@link requestResponse} mirrors `astrid_sdk::ipc::request_response`.
|
|
17
|
+
* Validates the request payload, pre-subscribes to the reply topic, publishes
|
|
18
|
+
* with an auto-injected `correlation_id`, blocks up to `timeoutMs` for the
|
|
19
|
+
* single reply, always tears down the subscription.
|
|
20
|
+
*/
|
|
21
|
+
import { publish as hostPublish, publishAs as hostPublishAs, subscribe as hostSubscribe, getInterceptorBindings as hostGetInterceptorBindings, } from "astrid:ipc/host@1.0.0";
|
|
22
|
+
import { randomBytes as hostRandomBytes } from "astrid:sys/host@1.0.0";
|
|
23
|
+
import { SysError, callHost } from "./errors.js";
|
|
24
|
+
const DEFAULT_RECV_TIMEOUT_MS = 5000n;
|
|
25
|
+
export function publish(topic, payload) {
|
|
26
|
+
callHost(`ipc.publish(${quote(topic)})`, () => hostPublish(topic, payload));
|
|
27
|
+
}
|
|
28
|
+
export function publishJson(topic, payload) {
|
|
29
|
+
publish(topic, jsonify(`ipc.publishJson(${quote(topic)})`, payload));
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Publish on behalf of a specific principal. Requires `uplink = true` in
|
|
33
|
+
* `Capsule.toml [capabilities]`; non-uplinks see `capability-denied`.
|
|
34
|
+
* Subscribers see the principal as `claimed(...)`, NOT `verified(...)` —
|
|
35
|
+
* downstream consumers MUST treat the principal as caller-input, not
|
|
36
|
+
* authenticated context.
|
|
37
|
+
*/
|
|
38
|
+
export function publishAs(topic, payload, principal) {
|
|
39
|
+
callHost(`ipc.publishAs(${quote(topic)})`, () => hostPublishAs(topic, payload, principal));
|
|
40
|
+
}
|
|
41
|
+
export function publishJsonAs(topic, payload, principal) {
|
|
42
|
+
publishAs(topic, jsonify(`ipc.publishJsonAs(${quote(topic)})`, payload), principal);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Subscribe to an IPC topic pattern. Supports exact matches and trailing-suffix
|
|
46
|
+
* wildcards (`foo.bar.*`). Mid-segment wildcards are rejected by the host.
|
|
47
|
+
*
|
|
48
|
+
* The returned {@link Subscription} is a Resource handle. Use `using` for
|
|
49
|
+
* scope-bound cleanup, or call `.close()` explicitly:
|
|
50
|
+
*
|
|
51
|
+
* ```ts
|
|
52
|
+
* using sub = ipc.subscribe("foo.bar"); // disposed at scope exit
|
|
53
|
+
* for await (const msg of sub) { ... }
|
|
54
|
+
*
|
|
55
|
+
* const sub = ipc.subscribe("foo.bar"); // explicit close
|
|
56
|
+
* try { ... } finally { sub.close(); }
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* Per-capsule cap: 128 subscriptions.
|
|
60
|
+
*/
|
|
61
|
+
export function subscribe(topicPattern) {
|
|
62
|
+
const inner = callHost(`ipc.subscribe(${quote(topicPattern)})`, () => hostSubscribe(topicPattern));
|
|
63
|
+
return new Subscription(inner, topicPattern);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Pre-registered interceptor handles for run-loop capsules. Returns ONLY the
|
|
67
|
+
* calling capsule's own interceptors. Most authors don't call this — the
|
|
68
|
+
* `@interceptor` decorator + bridge handle dispatch.
|
|
69
|
+
*/
|
|
70
|
+
export function runtimeInterceptors() {
|
|
71
|
+
const handles = callHost("ipc.runtimeInterceptors", () => hostGetInterceptorBindings());
|
|
72
|
+
return handles.map((h) => ({ handle: h.handleId, action: h.action, topic: h.topic }));
|
|
73
|
+
}
|
|
74
|
+
export class Subscription {
|
|
75
|
+
topic;
|
|
76
|
+
#inner;
|
|
77
|
+
constructor(inner, topic) {
|
|
78
|
+
this.#inner = inner;
|
|
79
|
+
this.topic = topic;
|
|
80
|
+
}
|
|
81
|
+
/** Non-blocking poll. Returns whatever's already queued. */
|
|
82
|
+
poll() {
|
|
83
|
+
const env = callHost(`ipc.poll(${quote(this.topic)})`, () => this.#requireInner().poll());
|
|
84
|
+
return envelopeToPollResult(env);
|
|
85
|
+
}
|
|
86
|
+
/** Blocking receive (timeout capped at 60s by the host). */
|
|
87
|
+
recv(timeoutMs = DEFAULT_RECV_TIMEOUT_MS) {
|
|
88
|
+
const env = callHost(`ipc.recv(${quote(this.topic)})`, () => this.#requireInner().recv(timeoutMs));
|
|
89
|
+
return envelopeToPollResult(env);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Idempotent — closing an already-closed subscription is a no-op.
|
|
93
|
+
* Equivalent to the resource Drop. Prefer `using` when the surrounding
|
|
94
|
+
* code can adopt explicit resource management.
|
|
95
|
+
*/
|
|
96
|
+
close() {
|
|
97
|
+
if (this.#inner === undefined)
|
|
98
|
+
return;
|
|
99
|
+
const inner = this.#inner;
|
|
100
|
+
this.#inner = undefined;
|
|
101
|
+
try {
|
|
102
|
+
inner[Symbol.dispose]();
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Resource may already be released (interceptor-owned handles, etc.).
|
|
106
|
+
// close() is meant to be safe to call from any cleanup path.
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
[Symbol.dispose]() {
|
|
110
|
+
this.close();
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* AsyncIterable convenience. Loops calling `.recv()` and yielding each
|
|
114
|
+
* message. Stops when the subscription is closed. Drops `lagged`/`dropped`
|
|
115
|
+
* info — use `.poll()`/`.recv()` explicitly if you need to react to lag.
|
|
116
|
+
*/
|
|
117
|
+
async *[Symbol.asyncIterator]() {
|
|
118
|
+
while (this.#inner !== undefined) {
|
|
119
|
+
const batch = this.recv();
|
|
120
|
+
for (const msg of batch.messages) {
|
|
121
|
+
yield msg;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
#requireInner() {
|
|
126
|
+
if (this.#inner === undefined) {
|
|
127
|
+
throw SysError.api(`subscription on ${quote(this.topic)} is closed`);
|
|
128
|
+
}
|
|
129
|
+
return this.#inner;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Send a request on `requestTopic` and await a single response on a scoped
|
|
134
|
+
* reply topic. Mirrors `astrid_sdk::ipc::request_response` exactly.
|
|
135
|
+
*
|
|
136
|
+
* The helper:
|
|
137
|
+
* 1. Generates a v4 correlation ID.
|
|
138
|
+
* 2. Subscribes to `{responseNamespace}.{correlationId}` *before* publishing
|
|
139
|
+
* (so the response can never be missed in the race).
|
|
140
|
+
* 3. Injects the correlation ID into the request payload as a top-level
|
|
141
|
+
* `correlation_id` field.
|
|
142
|
+
* 4. Publishes the request.
|
|
143
|
+
* 5. Blocks up to `timeoutMs` for the response.
|
|
144
|
+
* 6. Unsubscribes (always, even on error).
|
|
145
|
+
* 7. Returns the parsed response payload as `Resp`.
|
|
146
|
+
*
|
|
147
|
+
* `request` must serialize to a JSON object. Primitives, arrays, strings,
|
|
148
|
+
* etc. are rejected synchronously with `SysError.api` because there is
|
|
149
|
+
* nowhere to put the correlation ID.
|
|
150
|
+
*
|
|
151
|
+
* `responseNamespace` should be the dotted topic prefix the responder
|
|
152
|
+
* publishes to, *without* the trailing correlation id segment. For example,
|
|
153
|
+
* if the responder publishes to
|
|
154
|
+
* `registry.v1.response.set_active_model.<corr_id>`, pass
|
|
155
|
+
* `"registry.v1.response.set_active_model"`.
|
|
156
|
+
*
|
|
157
|
+
* `timeoutMs` is capped at 60,000 ms by the host. A timeout throws
|
|
158
|
+
* `SysError.api` with `request_response: no reply within …`.
|
|
159
|
+
*/
|
|
160
|
+
export function requestResponse(requestTopic, responseNamespace, request, timeoutMs) {
|
|
161
|
+
// Validate input before touching the host so bad calls never allocate a
|
|
162
|
+
// subscription handle.
|
|
163
|
+
if (typeof request !== "object" || request === null || Array.isArray(request)) {
|
|
164
|
+
throw SysError.api("request_response: request payload must serialize to a JSON object so the " +
|
|
165
|
+
"correlation_id can be injected");
|
|
166
|
+
}
|
|
167
|
+
const correlationId = randomUuidV4();
|
|
168
|
+
// Defensive copy + injection. Don't mutate the caller's object.
|
|
169
|
+
const augmented = {
|
|
170
|
+
...request,
|
|
171
|
+
correlation_id: correlationId,
|
|
172
|
+
};
|
|
173
|
+
const payload = jsonify("requestResponse", augmented);
|
|
174
|
+
const replyTopic = `${responseNamespace}.${correlationId}`;
|
|
175
|
+
const sub = subscribe(replyTopic);
|
|
176
|
+
try {
|
|
177
|
+
publish(requestTopic, payload);
|
|
178
|
+
const timeoutBig = typeof timeoutMs === "bigint" ? timeoutMs : BigInt(Math.max(0, Math.floor(timeoutMs)));
|
|
179
|
+
const poll = sub.recv(timeoutBig);
|
|
180
|
+
const msg = poll.messages[0];
|
|
181
|
+
if (msg === undefined) {
|
|
182
|
+
throw SysError.api(`request_response: no reply on '${replyTopic}' within ${String(timeoutMs)}ms`);
|
|
183
|
+
}
|
|
184
|
+
try {
|
|
185
|
+
return JSON.parse(msg.payload);
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
throw SysError.json(`request_response: failed to parse reply on '${replyTopic}': ${err.message}`, err);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
finally {
|
|
192
|
+
sub.close();
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
function envelopeToPollResult(env) {
|
|
196
|
+
return {
|
|
197
|
+
messages: env.messages.map(makeIpcMessage),
|
|
198
|
+
dropped: env.dropped,
|
|
199
|
+
lagged: env.lagged,
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
function makeIpcMessage(m) {
|
|
203
|
+
return {
|
|
204
|
+
topic: m.topic,
|
|
205
|
+
payload: m.payload,
|
|
206
|
+
sourceId: m.sourceId,
|
|
207
|
+
principal: m.principal,
|
|
208
|
+
json() {
|
|
209
|
+
try {
|
|
210
|
+
return JSON.parse(m.payload);
|
|
211
|
+
}
|
|
212
|
+
catch (err) {
|
|
213
|
+
throw SysError.json(`IpcMessage.json() on topic ${quote(m.topic)}: ${err.message}`, err);
|
|
214
|
+
}
|
|
215
|
+
},
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
function jsonify(label, value) {
|
|
219
|
+
try {
|
|
220
|
+
return JSON.stringify(value);
|
|
221
|
+
}
|
|
222
|
+
catch (err) {
|
|
223
|
+
throw SysError.json(`${label}: ${err.message}`, err);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
function quote(s) {
|
|
227
|
+
return `"${s.replace(/"/g, '\\"')}"`;
|
|
228
|
+
}
|
|
229
|
+
/**
|
|
230
|
+
* UUIDv4 generator. The Astrid host exposes `randomBytes`; pulling from
|
|
231
|
+
* `globalThis.crypto` would work too (StarlingMonkey exposes `crypto`), but
|
|
232
|
+
* routing through `sys::randomBytes` keeps the audit trail on the host side.
|
|
233
|
+
*
|
|
234
|
+
* Lazy-loaded to avoid a load-order cycle between ipc.ts and sys.ts.
|
|
235
|
+
*/
|
|
236
|
+
function randomUuidV4() {
|
|
237
|
+
// 16 random bytes → format as 8-4-4-4-12 hex with version (0x40) and
|
|
238
|
+
// variant (0x80) bits set. RFC 4122 §4.4.
|
|
239
|
+
const bytes = getRandomBytes();
|
|
240
|
+
bytes[6] = ((bytes[6] ?? 0) & 0x0f) | 0x40;
|
|
241
|
+
bytes[8] = ((bytes[8] ?? 0) & 0x3f) | 0x80;
|
|
242
|
+
const hex = [];
|
|
243
|
+
for (let i = 0; i < 16; i++) {
|
|
244
|
+
hex.push((bytes[i] ?? 0).toString(16).padStart(2, "0"));
|
|
245
|
+
}
|
|
246
|
+
return (hex.slice(0, 4).join("") +
|
|
247
|
+
"-" +
|
|
248
|
+
hex.slice(4, 6).join("") +
|
|
249
|
+
"-" +
|
|
250
|
+
hex.slice(6, 8).join("") +
|
|
251
|
+
"-" +
|
|
252
|
+
hex.slice(8, 10).join("") +
|
|
253
|
+
"-" +
|
|
254
|
+
hex.slice(10, 16).join(""));
|
|
255
|
+
}
|
|
256
|
+
function getRandomBytes() {
|
|
257
|
+
// Audit-traced via sys::random-bytes rather than reaching for globalThis.crypto
|
|
258
|
+
// so every UUID generation flows through the kernel's principal-scoped audit.
|
|
259
|
+
return hostRandomBytes(16n);
|
|
260
|
+
}
|
|
261
|
+
//# sourceMappingURL=ipc.js.map
|