@astrale-os/sdk 0.1.1 → 0.1.3

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 (198) hide show
  1. package/dist/auth/authenticate.d.ts +24 -0
  2. package/dist/auth/authenticate.d.ts.map +1 -0
  3. package/dist/auth/authenticate.js +29 -0
  4. package/dist/auth/authenticate.js.map +1 -0
  5. package/dist/auth/check.d.ts +39 -0
  6. package/dist/auth/check.d.ts.map +1 -0
  7. package/dist/auth/check.js +54 -0
  8. package/dist/auth/check.js.map +1 -0
  9. package/dist/auth/compose.d.ts +41 -0
  10. package/dist/auth/compose.d.ts.map +1 -0
  11. package/dist/auth/compose.js +45 -0
  12. package/dist/auth/compose.js.map +1 -0
  13. package/dist/auth/errors.d.ts +16 -0
  14. package/dist/auth/errors.d.ts.map +1 -0
  15. package/dist/auth/errors.js +26 -0
  16. package/dist/auth/errors.js.map +1 -0
  17. package/dist/auth/identity.d.ts +16 -0
  18. package/dist/auth/identity.d.ts.map +1 -0
  19. package/dist/auth/identity.js +2 -0
  20. package/dist/auth/identity.js.map +1 -0
  21. package/dist/auth/index.d.ts +12 -0
  22. package/dist/auth/index.d.ts.map +1 -0
  23. package/dist/auth/index.js +9 -0
  24. package/dist/auth/index.js.map +1 -0
  25. package/dist/auth/kernel-client.d.ts +43 -0
  26. package/dist/auth/kernel-client.d.ts.map +1 -0
  27. package/dist/auth/kernel-client.js +146 -0
  28. package/dist/auth/kernel-client.js.map +1 -0
  29. package/dist/auth/resolve.d.ts +19 -0
  30. package/dist/auth/resolve.d.ts.map +1 -0
  31. package/dist/auth/resolve.js +43 -0
  32. package/dist/auth/resolve.js.map +1 -0
  33. package/dist/auth/sign.d.ts +15 -0
  34. package/dist/auth/sign.d.ts.map +1 -0
  35. package/dist/auth/sign.js +24 -0
  36. package/dist/auth/sign.js.map +1 -0
  37. package/dist/auth/verify.d.ts +26 -0
  38. package/dist/auth/verify.d.ts.map +1 -0
  39. package/dist/auth/verify.js +96 -0
  40. package/dist/auth/verify.js.map +1 -0
  41. package/dist/define/index.d.ts +5 -0
  42. package/dist/define/index.d.ts.map +1 -0
  43. package/dist/define/index.js +3 -0
  44. package/dist/define/index.js.map +1 -0
  45. package/dist/define/remote-function.d.ts +96 -0
  46. package/dist/define/remote-function.d.ts.map +1 -0
  47. package/dist/define/remote-function.js +25 -0
  48. package/dist/define/remote-function.js.map +1 -0
  49. package/dist/define/view.d.ts +86 -0
  50. package/dist/define/view.d.ts.map +1 -0
  51. package/dist/define/view.js +28 -0
  52. package/dist/define/view.js.map +1 -0
  53. package/dist/deploy/check.d.ts +30 -0
  54. package/dist/deploy/check.d.ts.map +1 -0
  55. package/dist/deploy/check.js +82 -0
  56. package/dist/deploy/check.js.map +1 -0
  57. package/dist/deploy/hash-spec.d.ts +9 -0
  58. package/dist/deploy/hash-spec.d.ts.map +1 -0
  59. package/dist/deploy/hash-spec.js +29 -0
  60. package/dist/deploy/hash-spec.js.map +1 -0
  61. package/dist/deploy/index.d.ts +4 -0
  62. package/dist/deploy/index.d.ts.map +1 -0
  63. package/dist/deploy/index.js +4 -0
  64. package/dist/deploy/index.js.map +1 -0
  65. package/dist/deploy/meta.d.ts +18 -0
  66. package/dist/deploy/meta.d.ts.map +1 -0
  67. package/dist/deploy/meta.js +22 -0
  68. package/dist/deploy/meta.js.map +1 -0
  69. package/dist/dispatch/authorize.d.ts +14 -0
  70. package/dist/dispatch/authorize.d.ts.map +1 -0
  71. package/dist/dispatch/authorize.js +24 -0
  72. package/dist/dispatch/authorize.js.map +1 -0
  73. package/dist/dispatch/call-remote.d.ts +35 -0
  74. package/dist/dispatch/call-remote.d.ts.map +1 -0
  75. package/dist/dispatch/call-remote.js +37 -0
  76. package/dist/dispatch/call-remote.js.map +1 -0
  77. package/dist/dispatch/dispatcher.d.ts +60 -0
  78. package/dist/dispatch/dispatcher.d.ts.map +1 -0
  79. package/dist/dispatch/dispatcher.js +177 -0
  80. package/dist/dispatch/dispatcher.js.map +1 -0
  81. package/dist/dispatch/errors.d.ts +47 -0
  82. package/dist/dispatch/errors.d.ts.map +1 -0
  83. package/dist/dispatch/errors.js +76 -0
  84. package/dist/dispatch/errors.js.map +1 -0
  85. package/dist/dispatch/execute.d.ts +33 -0
  86. package/dist/dispatch/execute.d.ts.map +1 -0
  87. package/dist/dispatch/execute.js +24 -0
  88. package/dist/dispatch/execute.js.map +1 -0
  89. package/dist/dispatch/identity.d.ts +73 -0
  90. package/dist/dispatch/identity.d.ts.map +1 -0
  91. package/dist/dispatch/identity.js +106 -0
  92. package/dist/dispatch/identity.js.map +1 -0
  93. package/dist/dispatch/index.d.ts +8 -0
  94. package/dist/dispatch/index.d.ts.map +1 -0
  95. package/dist/dispatch/index.js +8 -0
  96. package/dist/dispatch/index.js.map +1 -0
  97. package/dist/dispatch/resolve.d.ts +27 -0
  98. package/dist/dispatch/resolve.d.ts.map +1 -0
  99. package/dist/dispatch/resolve.js +65 -0
  100. package/dist/dispatch/resolve.js.map +1 -0
  101. package/dist/dispatch/self.d.ts +27 -0
  102. package/dist/dispatch/self.d.ts.map +1 -0
  103. package/dist/dispatch/self.js +25 -0
  104. package/dist/dispatch/self.js.map +1 -0
  105. package/dist/dispatch/validate.d.ts +35 -0
  106. package/dist/dispatch/validate.d.ts.map +1 -0
  107. package/dist/dispatch/validate.js +27 -0
  108. package/dist/dispatch/validate.js.map +1 -0
  109. package/dist/domain/build-spec.d.ts +37 -0
  110. package/dist/domain/build-spec.d.ts.map +1 -0
  111. package/dist/domain/build-spec.js +95 -0
  112. package/dist/domain/build-spec.js.map +1 -0
  113. package/dist/domain/contract.d.ts +17 -0
  114. package/dist/domain/contract.d.ts.map +1 -0
  115. package/dist/domain/contract.js +26 -0
  116. package/dist/domain/contract.js.map +1 -0
  117. package/dist/domain/define.d.ts +82 -0
  118. package/dist/domain/define.d.ts.map +1 -0
  119. package/dist/domain/define.js +99 -0
  120. package/dist/domain/define.js.map +1 -0
  121. package/dist/domain/extend-core.d.ts +49 -0
  122. package/dist/domain/extend-core.d.ts.map +1 -0
  123. package/dist/domain/extend-core.js +182 -0
  124. package/dist/domain/extend-core.js.map +1 -0
  125. package/dist/domain/index.d.ts +5 -0
  126. package/dist/domain/index.d.ts.map +1 -0
  127. package/dist/domain/index.js +4 -0
  128. package/dist/domain/index.js.map +1 -0
  129. package/dist/index.d.ts +19 -0
  130. package/dist/index.d.ts.map +1 -0
  131. package/dist/index.js +32 -0
  132. package/dist/index.js.map +1 -0
  133. package/dist/method/class.d.ts +70 -0
  134. package/dist/method/class.d.ts.map +1 -0
  135. package/dist/method/class.js +26 -0
  136. package/dist/method/class.js.map +1 -0
  137. package/dist/method/context.d.ts +43 -0
  138. package/dist/method/context.d.ts.map +1 -0
  139. package/dist/method/context.js +10 -0
  140. package/dist/method/context.js.map +1 -0
  141. package/dist/method/index.d.ts +6 -0
  142. package/dist/method/index.d.ts.map +1 -0
  143. package/dist/method/index.js +3 -0
  144. package/dist/method/index.js.map +1 -0
  145. package/dist/method/single.d.ts +88 -0
  146. package/dist/method/single.d.ts.map +1 -0
  147. package/dist/method/single.js +18 -0
  148. package/dist/method/single.js.map +1 -0
  149. package/dist/server/auxiliary-routes.d.ts +44 -0
  150. package/dist/server/auxiliary-routes.d.ts.map +1 -0
  151. package/dist/server/auxiliary-routes.js +239 -0
  152. package/dist/server/auxiliary-routes.js.map +1 -0
  153. package/dist/server/config.d.ts +83 -0
  154. package/dist/server/config.d.ts.map +1 -0
  155. package/dist/server/config.js +8 -0
  156. package/dist/server/config.js.map +1 -0
  157. package/dist/server/create.d.ts +21 -0
  158. package/dist/server/create.d.ts.map +1 -0
  159. package/dist/server/create.js +210 -0
  160. package/dist/server/create.js.map +1 -0
  161. package/dist/server/handle.d.ts +35 -0
  162. package/dist/server/handle.d.ts.map +1 -0
  163. package/dist/server/handle.js +9 -0
  164. package/dist/server/handle.js.map +1 -0
  165. package/dist/server/index.d.ts +11 -0
  166. package/dist/server/index.d.ts.map +1 -0
  167. package/dist/server/index.js +8 -0
  168. package/dist/server/index.js.map +1 -0
  169. package/dist/server/jwks.d.ts +11 -0
  170. package/dist/server/jwks.d.ts.map +1 -0
  171. package/dist/server/jwks.js +15 -0
  172. package/dist/server/jwks.js.map +1 -0
  173. package/dist/server/require-env.d.ts +15 -0
  174. package/dist/server/require-env.d.ts.map +1 -0
  175. package/dist/server/require-env.js +21 -0
  176. package/dist/server/require-env.js.map +1 -0
  177. package/dist/server/serving-url.d.ts +14 -0
  178. package/dist/server/serving-url.d.ts.map +1 -0
  179. package/dist/server/serving-url.js +28 -0
  180. package/dist/server/serving-url.js.map +1 -0
  181. package/dist/server/start.d.ts +11 -0
  182. package/dist/server/start.d.ts.map +1 -0
  183. package/dist/server/start.js +34 -0
  184. package/dist/server/start.js.map +1 -0
  185. package/dist/server/worker-entry.d.ts +60 -0
  186. package/dist/server/worker-entry.d.ts.map +1 -0
  187. package/dist/server/worker-entry.js +79 -0
  188. package/dist/server/worker-entry.js.map +1 -0
  189. package/dist/server/worker-meta.d.ts +6 -0
  190. package/dist/server/worker-meta.d.ts.map +1 -0
  191. package/dist/server/worker-meta.js +10 -0
  192. package/dist/server/worker-meta.js.map +1 -0
  193. package/package.json +5 -5
  194. package/src/auth/compose.ts +27 -2
  195. package/src/auth/kernel-client.ts +103 -11
  196. package/src/define/remote-function.ts +10 -0
  197. package/src/server/auxiliary-routes.ts +3 -1
  198. package/src/server/start.ts +5 -1
@@ -0,0 +1,9 @@
1
+ /**
2
+ * `RemoteServer` and `RemoteServerHandle` — output shapes for the SDK server.
3
+ *
4
+ * `RemoteServer` is what `createRemoteServer` returns: the assembled Hono
5
+ * app plus a Node convenience helper. `RemoteServerHandle` is what `start()`
6
+ * resolves to: the bound port and a `close()` function for graceful shutdown.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=handle.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"handle.js","sourceRoot":"","sources":["../../src/server/handle.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,11 @@
1
+ export { createRemoteServer } from './create';
2
+ export type { RemoteServerConfig } from './config';
3
+ export type { RemoteServer, RemoteServerHandle } from './handle';
4
+ export { derivePublicJwk } from './jwks';
5
+ export { requireEnv } from './require-env';
6
+ export { canonicalizeServingUrl } from './serving-url';
7
+ export { createWorkerEntry } from './worker-entry';
8
+ export type { WorkerEntry, WorkerEntryConfig } from './worker-entry';
9
+ export { workerMeta } from './worker-meta';
10
+ export { startNodeServer } from './start';
11
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAC7C,YAAY,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAClD,YAAY,EAAE,YAAY,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAA;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAA;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAClD,YAAY,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA"}
@@ -0,0 +1,8 @@
1
+ export { createRemoteServer } from './create';
2
+ export { derivePublicJwk } from './jwks';
3
+ export { requireEnv } from './require-env';
4
+ export { canonicalizeServingUrl } from './serving-url';
5
+ export { createWorkerEntry } from './worker-entry';
6
+ export { workerMeta } from './worker-meta';
7
+ export { startNodeServer } from './start';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAG7C,OAAO,EAAE,eAAe,EAAE,MAAM,QAAQ,CAAA;AACxC,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAA;AACtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAA;AAElD,OAAO,EAAE,UAAU,EAAE,MAAM,eAAe,CAAA;AAC1C,OAAO,EAAE,eAAe,EAAE,MAAM,SAAS,CAAA"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Derive a public JWK from a private one.
3
+ *
4
+ * Strips the private components for both EC keys (drops `d`) and RSA keys
5
+ * (drops `d`, `p`, `q`, `dp`, `dq`, `qi`, and `oth` — the additional-primes
6
+ * array on multi-prime RSA keys). The result is safe to publish at
7
+ * `<url>/.well-known/jwks.json` so downstream verifiers can validate
8
+ * signatures the server produced.
9
+ */
10
+ export declare function derivePublicJwk(privateKey: JsonWebKey): Record<string, unknown>;
11
+ //# sourceMappingURL=jwks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwks.d.ts","sourceRoot":"","sources":["../../src/server/jwks.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,wBAAgB,eAAe,CAAC,UAAU,EAAE,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAO/E"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Derive a public JWK from a private one.
3
+ *
4
+ * Strips the private components for both EC keys (drops `d`) and RSA keys
5
+ * (drops `d`, `p`, `q`, `dp`, `dq`, `qi`, and `oth` — the additional-primes
6
+ * array on multi-prime RSA keys). The result is safe to publish at
7
+ * `<url>/.well-known/jwks.json` so downstream verifiers can validate
8
+ * signatures the server produced.
9
+ */
10
+ export function derivePublicJwk(privateKey) {
11
+ // oxlint-disable-next-line no-unused-vars
12
+ const { d, p, q, dp, dq, qi, oth, ...publicJwk } = privateKey;
13
+ return publicJwk;
14
+ }
15
+ //# sourceMappingURL=jwks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwks.js","sourceRoot":"","sources":["../../src/server/jwks.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,UAAU,eAAe,CAAC,UAAsB;IACpD,0CAA0C;IAC1C,MAAM,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,EAAE,GAAG,EAAE,GAAG,SAAS,EAAE,GAAG,UAGlD,CAAA;IACD,OAAO,SAAS,CAAA;AAClB,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * Read a string-typed env var (process.env on Node, the Worker `env` binding
3
+ * on Cloudflare) and throw a clear error if it is missing or empty.
4
+ *
5
+ * Use this for **identity-bearing** values (issuer, baseDomain, audience,
6
+ * worker URL) where a guessed default silently mints wrong JWTs or bakes
7
+ * wrong refs into persisted artifacts. The conventional `?? 'literal'`
8
+ * fallback is the anti-pattern this exists to replace.
9
+ *
10
+ * In local dev these live in each domain worker's `worker/.dev.vars` (read
11
+ * natively by `wrangler dev`), so this throw never fires in a properly-prepared
12
+ * dev environment — only when wiring is genuinely missing.
13
+ */
14
+ export declare function requireEnv(env: unknown, name: string, hint?: string): string;
15
+ //# sourceMappingURL=require-env.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"require-env.d.ts","sourceRoot":"","sources":["../../src/server/require-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,GAAG,MAAM,CAK5E"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Read a string-typed env var (process.env on Node, the Worker `env` binding
3
+ * on Cloudflare) and throw a clear error if it is missing or empty.
4
+ *
5
+ * Use this for **identity-bearing** values (issuer, baseDomain, audience,
6
+ * worker URL) where a guessed default silently mints wrong JWTs or bakes
7
+ * wrong refs into persisted artifacts. The conventional `?? 'literal'`
8
+ * fallback is the anti-pattern this exists to replace.
9
+ *
10
+ * In local dev these live in each domain worker's `worker/.dev.vars` (read
11
+ * natively by `wrangler dev`), so this throw never fires in a properly-prepared
12
+ * dev environment — only when wiring is genuinely missing.
13
+ */
14
+ export function requireEnv(env, name, hint) {
15
+ const v = env?.[name];
16
+ if (typeof v === 'string' && v.length > 0)
17
+ return v;
18
+ const help = hint ? ` (${hint})` : '';
19
+ throw new Error(`Missing required env var: ${name}${help}`);
20
+ }
21
+ //# sourceMappingURL=require-env.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"require-env.js","sourceRoot":"","sources":["../../src/server/require-env.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,UAAU,CAAC,GAAY,EAAE,IAAY,EAAE,IAAa;IAClE,MAAM,CAAC,GAAI,GAAkD,EAAE,CAAC,IAAI,CAAC,CAAA;IACrE,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,CAAC,CAAA;IACnD,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,CAAA;IACrC,MAAM,IAAI,KAAK,CAAC,6BAA6B,IAAI,GAAG,IAAI,EAAE,CAAC,CAAA;AAC7D,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Canonicalize a worker's serving URL into its `iss` identity.
3
+ *
4
+ * Returns the full URL with trailing slash(es) stripped — the base path is
5
+ * preserved (an issuer may carry a non-empty path, like `…/kernel/host`). This
6
+ * is the single canonical form used for outbound signing, the JWKS issuer,
7
+ * `/meta`, the install credential, and any `Identity.iss` a domain seeds, so the
8
+ * value a worker SIGNS always matches the value the kernel LOOKS UP (the kernel
9
+ * canonicalizes the verified `iss` the same way and does an exact-match lookup).
10
+ *
11
+ * Throws if `url` is not a parseable absolute URL.
12
+ */
13
+ export declare function canonicalizeServingUrl(url: string): string;
14
+ //# sourceMappingURL=serving-url.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serving-url.d.ts","sourceRoot":"","sources":["../../src/server/serving-url.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAS1D"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Canonicalize a worker's serving URL into its `iss` identity.
3
+ *
4
+ * Returns the full URL with trailing slash(es) stripped — the base path is
5
+ * preserved (an issuer may carry a non-empty path, like `…/kernel/host`). This
6
+ * is the single canonical form used for outbound signing, the JWKS issuer,
7
+ * `/meta`, the install credential, and any `Identity.iss` a domain seeds, so the
8
+ * value a worker SIGNS always matches the value the kernel LOOKS UP (the kernel
9
+ * canonicalizes the verified `iss` the same way and does an exact-match lookup).
10
+ *
11
+ * Throws if `url` is not a parseable absolute URL.
12
+ */
13
+ // INVARIANT (cross-repo): issuer PRODUCERS must strip trailing path slashes
14
+ // BEFORE a value becomes an iss. kernel-core's `normalizeIssuerId` only strips
15
+ // a lone trailing slash on an EMPTY path, so `https://x/base/` and
16
+ // `https://x/base` are distinct issuer identities to the kernel — this
17
+ // function and the kernel's `installSourceBase` both pre-strip with the same
18
+ // rule so the two sides can never mint diverging identities for one worker.
19
+ export function canonicalizeServingUrl(url) {
20
+ try {
21
+ return new URL(url).href.replace(/\/+$/, '');
22
+ }
23
+ catch {
24
+ throw new Error(`canonicalizeServingUrl: expected a full URL (got "${url}") — ` +
25
+ 'it is the worker serving URL and its JWT issuer identity.');
26
+ }
27
+ }
28
+ //# sourceMappingURL=serving-url.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serving-url.js","sourceRoot":"","sources":["../../src/server/serving-url.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,4EAA4E;AAC5E,+EAA+E;AAC/E,mEAAmE;AACnE,uEAAuE;AACvE,6EAA6E;AAC7E,4EAA4E;AAC5E,MAAM,UAAU,sBAAsB,CAAC,GAAW;IAChD,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAA;IAC9C,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CACb,qDAAqD,GAAG,OAAO;YAC7D,2DAA2D,CAC9D,CAAA;IACH,CAAC;AACH,CAAC"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Node HTTP convenience starter.
3
+ *
4
+ * Dynamically imports `@hono/node-server` so the SDK stays runtime-agnostic
5
+ * — only Node consumers actually pull in the dep. For Bun / Deno /
6
+ * Cloudflare, consumers go through `server.app.fetch` directly.
7
+ */
8
+ import type { Hono } from 'hono';
9
+ import type { RemoteServerHandle } from './handle';
10
+ export declare function startNodeServer(app: Hono, port?: number): Promise<RemoteServerHandle>;
11
+ //# sourceMappingURL=start.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../src/server/start.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAEhC,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAElD,wBAAsB,eAAe,CAAC,GAAG,EAAE,IAAI,EAAE,IAAI,SAAO,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA4BzF"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Node HTTP convenience starter.
3
+ *
4
+ * Dynamically imports `@hono/node-server` so the SDK stays runtime-agnostic
5
+ * — only Node consumers actually pull in the dep. For Bun / Deno /
6
+ * Cloudflare, consumers go through `server.app.fetch` directly.
7
+ */
8
+ export async function startNodeServer(app, port = 3000) {
9
+ // Opaque specifier: the `./server` barrel re-exports this module, so worker
10
+ // bundles (wrangler/esbuild) traverse it even though they never call it. A
11
+ // literal import() would make them resolve the optional peer and fail.
12
+ const nodeServerModule = '@hono/node-server';
13
+ const { serve } = (await import(nodeServerModule));
14
+ // oxlint-disable-next-line no-explicit-any
15
+ const server = serve({ fetch: app.fetch, port });
16
+ await new Promise((resolve, reject) => {
17
+ if (server.listening)
18
+ return resolve();
19
+ server.once('listening', () => resolve());
20
+ // Without this, a bind failure (e.g. EADDRINUSE on a busy port) emits
21
+ // `'error'` and never `'listening'`, leaving the Promise — and startup —
22
+ // hung forever with no diagnostic.
23
+ server.once('error', (err) => reject(err));
24
+ });
25
+ const address = server.address();
26
+ const actualPort = address?.port ?? port;
27
+ return {
28
+ port: actualPort,
29
+ close: () => new Promise((resolve, reject) => {
30
+ server.close((err) => (err ? reject(err) : resolve()));
31
+ }),
32
+ };
33
+ }
34
+ //# sourceMappingURL=start.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"start.js","sourceRoot":"","sources":["../../src/server/start.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,GAAS,EAAE,IAAI,GAAG,IAAI;IAC1D,4EAA4E;IAC5E,2EAA2E;IAC3E,uEAAuE;IACvE,MAAM,gBAAgB,GAAG,mBAAmB,CAAA;IAC5C,MAAM,EAAE,KAAK,EAAE,GAAG,CAAC,MAAM,MAAM,CAAC,gBAAgB,CAAC,CAAuC,CAAA;IACxF,2CAA2C;IAC3C,MAAM,MAAM,GAAG,KAAK,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,CAAQ,CAAA;IAEvD,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QAC1C,IAAI,MAAM,CAAC,SAAS;YAAE,OAAO,OAAO,EAAE,CAAA;QACtC,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAA;QACzC,sEAAsE;QACtE,yEAAyE;QACzE,mCAAmC;QACnC,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAA;IACnD,CAAC,CAAC,CAAA;IAEF,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,EAA8C,CAAA;IAC5E,MAAM,UAAU,GAAG,OAAO,EAAE,IAAI,IAAI,IAAI,CAAA;IAExC,OAAO;QACL,IAAI,EAAE,UAAU;QAChB,KAAK,EAAE,GAAG,EAAE,CACV,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACpC,MAAM,CAAC,KAAK,CAAC,CAAC,GAAiB,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;QACtE,CAAC,CAAC;KACL,CAAA;AACH,CAAC"}
@@ -0,0 +1,60 @@
1
+ /**
2
+ * `createWorkerEntry` — the shared worker `fetch` plumbing every Astrale domain
3
+ * worker (and the cloudflare adapter's codegen) needs, so it lives in ONE place
4
+ * instead of being copy-pasted per worker:
5
+ *
6
+ * • resolve the serving URL (== `iss`), canonicalize it (so the value matches
7
+ * what `createRemoteServer` signs with and the kernel pins), and cache the
8
+ * built app per distinct URL;
9
+ * • optional self-binding routing: when a `SELF` service binding is provided,
10
+ * route same-host subrequests (e.g. `ctx.callRemote` back into this domain)
11
+ * through it — Cloudflare forbids a Worker fetching its own hostname. This is
12
+ * the ONLY reason a `globalThis.fetch` override is installed, and only when a
13
+ * `selfBinding` is configured;
14
+ * • optional SPA hook (e.g. `/ui/*` served from an `ASSETS` binding).
15
+ *
16
+ * The worker's OWN JWKS (`<url>/.well-known/jwks.json`) is served as a normal
17
+ * route by `createRemoteServer`; the verifier resolves a self-issued credential
18
+ * from the in-memory key (see `auth/verify.ts`), so no self-fetch shim is needed.
19
+ *
20
+ * The worker file is then just schema + methods + a `build(url, env)` callback.
21
+ */
22
+ import type { RemoteServerConfig } from './config';
23
+ type Fetcher = {
24
+ fetch(request: Request): Response | Promise<Response>;
25
+ };
26
+ export interface WorkerEntryConfig<TDeps> {
27
+ /**
28
+ * Build the `createRemoteServer` config for the resolved serving `url`. Called
29
+ * once per distinct URL (the resulting app is cached), with the same `env` the
30
+ * request carries — so it can read additional bindings (e.g. a base domain).
31
+ */
32
+ build: (url: string, env: TDeps) => RemoteServerConfig<TDeps>;
33
+ /**
34
+ * Resolve the raw serving URL from `env` (+ the per-request origin, for workers
35
+ * that fall back to the request host). Defaults to the `WORKER_URL` env var.
36
+ * The result is always canonicalized before use.
37
+ */
38
+ resolveUrl?: (env: TDeps, requestOrigin: string) => string;
39
+ /** Optional: the `SELF` service binding used to route same-host subrequests. */
40
+ selfBinding?: (env: TDeps) => Fetcher | null | undefined;
41
+ /**
42
+ * Optional: handle a request before it reaches the kernel app — e.g. serve a
43
+ * SPA under `/ui/*` or a same-origin `/api/*` endpoint the view calls. Return
44
+ * a `Response` to short-circuit, or `undefined` to fall through to the domain
45
+ * dispatch.
46
+ */
47
+ before?: (env: TDeps, url: URL, request: Request) => Response | undefined | Promise<Response | undefined>;
48
+ /**
49
+ * Optional: transform the request on the fall-through path, just before it
50
+ * reaches the kernel app (e.g. rewrite the hostname for wildcard-subdomain
51
+ * routing). Not applied when `before` short-circuits.
52
+ */
53
+ rewriteRequest?: (env: TDeps, request: Request) => Request;
54
+ }
55
+ export interface WorkerEntry<TDeps> {
56
+ fetch(request: Request, env: TDeps): Response | Promise<Response>;
57
+ }
58
+ export declare function createWorkerEntry<TDeps>(config: WorkerEntryConfig<TDeps>): WorkerEntry<TDeps>;
59
+ export {};
60
+ //# sourceMappingURL=worker-entry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-entry.d.ts","sourceRoot":"","sources":["../../src/server/worker-entry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,UAAU,CAAA;AAMlD,KAAK,OAAO,GAAG;IAAE,KAAK,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;CAAE,CAAA;AAGxE,MAAM,WAAW,iBAAiB,CAAC,KAAK;IACtC;;;;OAIG;IACH,KAAK,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,KAAK,KAAK,kBAAkB,CAAC,KAAK,CAAC,CAAA;IAC7D;;;;OAIG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,aAAa,EAAE,MAAM,KAAK,MAAM,CAAA;IAC1D,gFAAgF;IAChF,WAAW,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,KAAK,OAAO,GAAG,IAAI,GAAG,SAAS,CAAA;IACxD;;;;;OAKG;IACH,MAAM,CAAC,EAAE,CACP,GAAG,EAAE,KAAK,EACV,GAAG,EAAE,GAAG,EACR,OAAO,EAAE,OAAO,KACb,QAAQ,GAAG,SAAS,GAAG,OAAO,CAAC,QAAQ,GAAG,SAAS,CAAC,CAAA;IACzD;;;;OAIG;IACH,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,KAAK,OAAO,CAAA;CAC3D;AAED,MAAM,WAAW,WAAW,CAAC,KAAK;IAChC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAAA;CAClE;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,MAAM,EAAE,iBAAiB,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC,KAAK,CAAC,CAoD7F"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * `createWorkerEntry` — the shared worker `fetch` plumbing every Astrale domain
3
+ * worker (and the cloudflare adapter's codegen) needs, so it lives in ONE place
4
+ * instead of being copy-pasted per worker:
5
+ *
6
+ * • resolve the serving URL (== `iss`), canonicalize it (so the value matches
7
+ * what `createRemoteServer` signs with and the kernel pins), and cache the
8
+ * built app per distinct URL;
9
+ * • optional self-binding routing: when a `SELF` service binding is provided,
10
+ * route same-host subrequests (e.g. `ctx.callRemote` back into this domain)
11
+ * through it — Cloudflare forbids a Worker fetching its own hostname. This is
12
+ * the ONLY reason a `globalThis.fetch` override is installed, and only when a
13
+ * `selfBinding` is configured;
14
+ * • optional SPA hook (e.g. `/ui/*` served from an `ASSETS` binding).
15
+ *
16
+ * The worker's OWN JWKS (`<url>/.well-known/jwks.json`) is served as a normal
17
+ * route by `createRemoteServer`; the verifier resolves a self-issued credential
18
+ * from the in-memory key (see `auth/verify.ts`), so no self-fetch shim is needed.
19
+ *
20
+ * The worker file is then just schema + methods + a `build(url, env)` callback.
21
+ */
22
+ import { createRemoteServer } from './create';
23
+ import { requireEnv } from './require-env';
24
+ import { canonicalizeServingUrl } from './serving-url';
25
+ export function createWorkerEntry(config) {
26
+ let cache = null;
27
+ let self = null;
28
+ function getApp(url, env) {
29
+ if (cache && cache.url === url)
30
+ return cache.app;
31
+ const { app } = createRemoteServer(config.build(url, env));
32
+ cache = { url, origin: new URL(url).origin, app };
33
+ return app;
34
+ }
35
+ // A Worker can't fetch its own hostname. When a SELF service binding is
36
+ // configured, route same-host subrequests (e.g. `ctx.callRemote` back into
37
+ // this domain) through it. This is the only reason to override
38
+ // `globalThis.fetch` — workers without a `selfBinding` get no global mutation.
39
+ // (A self-issued credential's JWKS is resolved in-memory by the verifier, not
40
+ // fetched — see `auth/verify.ts` — so no self-JWKS interception is needed.)
41
+ if (config.selfBinding) {
42
+ const originalFetch = globalThis.fetch;
43
+ globalThis.fetch = (async (input, init) => {
44
+ if (cache && self) {
45
+ const href = typeof input === 'string' ? input : input instanceof URL ? input.href : input.url;
46
+ try {
47
+ if (new URL(href).origin === cache.origin)
48
+ return self.fetch(new Request(input, init));
49
+ }
50
+ catch {
51
+ // non-absolute URL — fall through to the original fetch
52
+ }
53
+ }
54
+ return originalFetch(input, init);
55
+ });
56
+ }
57
+ return {
58
+ async fetch(request, env) {
59
+ if (config.selfBinding)
60
+ self ??= config.selfBinding(env) ?? null;
61
+ // Only parse the request URL when a hook actually needs it.
62
+ const requestUrl = config.before || config.resolveUrl ? new URL(request.url) : null;
63
+ if (config.before && requestUrl) {
64
+ // Await so an async `before` that resolves to `undefined` falls through
65
+ // (a returned Promise<undefined> would otherwise be sent as the response).
66
+ const handled = await config.before(env, requestUrl, request);
67
+ if (handled !== undefined)
68
+ return handled;
69
+ }
70
+ const raw = config.resolveUrl
71
+ ? config.resolveUrl(env, requestUrl.origin)
72
+ : requireEnv(env, 'WORKER_URL', "the worker's public serving URL (its iss identity)");
73
+ const url = canonicalizeServingUrl(raw);
74
+ const dispatched = config.rewriteRequest ? config.rewriteRequest(env, request) : request;
75
+ return getApp(url, env).fetch(dispatched);
76
+ },
77
+ };
78
+ }
79
+ //# sourceMappingURL=worker-entry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-entry.js","sourceRoot":"","sources":["../../src/server/worker-entry.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ export declare function workerMeta(domainName: string): {
2
+ sdkCommit?: string;
3
+ schemaHash?: string;
4
+ domainName: string;
5
+ };
6
+ //# sourceMappingURL=worker-meta.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-meta.d.ts","sourceRoot":"","sources":["../../src/server/worker-meta.ts"],"names":[],"mappings":"AAYA,wBAAgB,UAAU,CAAC,UAAU,EAAE,MAAM,GAAG;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,MAAM,CAAA;CACnB,CAQA"}
@@ -0,0 +1,10 @@
1
+ export function workerMeta(domainName) {
2
+ const sdkCommit = typeof SDK_COMMIT === 'string' ? SDK_COMMIT : undefined;
3
+ const schemaHash = typeof SCHEMA_HASH === 'string' ? SCHEMA_HASH : undefined;
4
+ return {
5
+ ...(sdkCommit ? { sdkCommit } : {}),
6
+ ...(schemaHash ? { schemaHash } : {}),
7
+ domainName,
8
+ };
9
+ }
10
+ //# sourceMappingURL=worker-meta.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-meta.js","sourceRoot":"","sources":["../../src/server/worker-meta.ts"],"names":[],"mappings":"AAYA,MAAM,UAAU,UAAU,CAAC,UAAkB;IAK3C,MAAM,SAAS,GAAG,OAAO,UAAU,KAAK,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAA;IACzE,MAAM,UAAU,GAAG,OAAO,WAAW,KAAK,QAAQ,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAA;IAC5E,OAAO;QACL,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACnC,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrC,UAAU;KACX,CAAA;AACH,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrale-os/sdk",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "Astrale Remote Domain SDK - Define and deploy domains as standalone Hono servers",
5
5
  "keywords": [
6
6
  "astrale",
@@ -40,10 +40,10 @@
40
40
  "registry": "https://npm.pkg.github.com"
41
41
  },
42
42
  "dependencies": {
43
- "@astrale-os/kernel-api": ">=0.4.0 <1.0.0",
44
- "@astrale-os/kernel-client": ">=0.1.0 <1.0.0",
45
- "@astrale-os/kernel-core": ">=0.3.0 <1.0.0",
46
- "@astrale-os/kernel-dsl": ">=0.1.0 <1.0.0",
43
+ "@astrale-os/kernel-api": ">=0.4.5 <1.0.0",
44
+ "@astrale-os/kernel-client": ">=0.2.2 <1.0.0",
45
+ "@astrale-os/kernel-core": ">=0.4.3 <1.0.0",
46
+ "@astrale-os/kernel-dsl": ">=0.1.2 <1.0.0",
47
47
  "@astrale-os/kernel-server": ">=0.4.0 <1.0.0",
48
48
  "hono": "^4.6.20",
49
49
  "jose": "^6.1.3",
@@ -18,6 +18,18 @@ import {
18
18
  unresolvedUnion,
19
19
  } from '@astrale-os/kernel-core'
20
20
 
21
+ /**
22
+ * The composed identity expression: union of the caller's delegated access
23
+ * (a kernel-signed credential leaf) and the function's own identity (self).
24
+ *
25
+ * Used both as the grant on outbound kernel calls AND as the delegation
26
+ * expression when minting a NEXT-HOP credential — the next worker receives
27
+ * principal = this function, authority = union(caller's delegated, own).
28
+ */
29
+ export function buildComposedExpr(delegation: Delegation) {
30
+ return unresolvedUnion(unresolvedCredential(delegation.credential), unresolvedSelf())
31
+ }
32
+
21
33
  /**
22
34
  * Build the grant expression that unions the caller's delegated access
23
35
  * with the function's own identity.
@@ -26,6 +38,19 @@ import {
26
38
  * @returns The unresolved grant object with version and expression
27
39
  */
28
40
  export function buildComposedGrant(delegation: Delegation) {
29
- const expr = unresolvedUnion(unresolvedCredential(delegation.credential), unresolvedSelf())
30
- return { grant: createUnresolvedGrant(expr) }
41
+ return { grant: createUnresolvedGrant(buildComposedExpr(delegation)) }
42
+ }
43
+
44
+ /**
45
+ * The SELF-ONLY expression: the function's own identity, nothing delegated.
46
+ * Used by `selfKernel` sessions (public/webhook handlers acting on their own
47
+ * authority) — both as the credential grant and as the next-hop delegation.
48
+ */
49
+ export function buildSelfExpr() {
50
+ return unresolvedSelf()
51
+ }
52
+
53
+ /** Self-only grant for `selfKernel` credentials. */
54
+ export function buildSelfGrant() {
55
+ return { grant: createUnresolvedGrant(buildSelfExpr()) }
31
56
  }
@@ -16,6 +16,7 @@
16
16
  */
17
17
 
18
18
  import type { Delegation } from '@astrale-os/kernel-core'
19
+ import type { UnresolvedIdentityExpr } from '@astrale-os/kernel-core'
19
20
 
20
21
  import { KernelClient, SchemaRegistry, type FnMap } from '@astrale-os/kernel-client'
21
22
  import { ClientPool } from '@astrale-os/kernel-client/pool'
@@ -23,11 +24,16 @@ import { ClientSession, type BoundClientSessionView } from '@astrale-os/kernel-c
23
24
 
24
25
  import type { RemoteIdentityConfig } from './identity'
25
26
 
26
- import { buildComposedGrant } from './compose'
27
+ import { buildComposedExpr, buildComposedGrant, buildSelfExpr, buildSelfGrant } from './compose'
27
28
  import { signCredential } from './sign'
28
29
 
29
30
  const DELEGATION_TTL_SECONDS = 3600
30
31
 
32
+ // The kernel's whoami — returns the AUTHENTICATED principal's graph node, so
33
+ // the resolved id satisfies the mint syscall's `self.id === auth.principal`
34
+ // invariant by construction (same seam the shell uses to resolve self).
35
+ const WHOAMI_PATH = '/:kernel.astrale.ai:interface.Identity:whoami'
36
+
31
37
  // Shared per kernel URL — the expensive, identity-agnostic state. Sessions are
32
38
  // NOT shared (each binds a subject-specific delegation mint), but the pool
33
39
  // (connections) and registry (learned schemas) are reused across them.
@@ -65,8 +71,36 @@ export async function bindKernel(
65
71
  kernelUrl: string,
66
72
  config: RemoteIdentityConfig,
67
73
  ): Promise<BoundClientSessionView<FnMap>> {
68
- const { grant } = buildComposedGrant(delegation)
69
- const composed = await signCredential(
74
+ return bindSession(kernelUrl, config, buildComposedGrant(delegation).grant, () =>
75
+ buildComposedExpr(delegation),
76
+ )
77
+ }
78
+
79
+ /**
80
+ * Build a `BoundClientSessionView` authenticated as the FUNCTION'S OWN
81
+ * identity — no inbound delegation, authority = the function's own grants
82
+ * only. The seam behind `selfKernel` for public/webhook handlers: an HMAC- or
83
+ * signature-verified webhook can act on the graph as itself after verifying
84
+ * the upstream. Next-hop mints delegate self only.
85
+ */
86
+ export async function bindSelfKernel(
87
+ kernelUrl: string,
88
+ config: RemoteIdentityConfig,
89
+ ): Promise<BoundClientSessionView<FnMap>> {
90
+ return bindSession(kernelUrl, config, buildSelfGrant().grant, () => buildSelfExpr())
91
+ }
92
+
93
+ /**
94
+ * Shared session construction: sign a credential as this function's identity
95
+ * carrying `grant`, bind the session to it, and wire the lazy NEXT-HOP mint.
96
+ */
97
+ async function bindSession(
98
+ kernelUrl: string,
99
+ config: RemoteIdentityConfig,
100
+ grant: unknown,
101
+ nextHopDelegation: () => UnresolvedIdentityExpr,
102
+ ): Promise<BoundClientSessionView<FnMap>> {
103
+ const credential = await signCredential(
70
104
  { grant },
71
105
  {
72
106
  issuer: config.issuer,
@@ -83,15 +117,21 @@ export async function bindKernel(
83
117
  schema: getRegistry(kernelUrl),
84
118
  pool: getPool(kernelUrl),
85
119
  delegation: {
86
- // `@<subject>::mintDelegationCredential` satisfies the syscall's
87
- // `self.id === auth.principal` invariant (composed's subject IS the
88
- // principal). `skipDelegation` keeps this mint from re-entering itself —
89
- // it targets the kernel (same origin), so no delegation is needed.
120
+ // NEXT-HOP mint: each hop mints AS ITSELF. The anchor is this function's
121
+ // identity NODE id (resolved via whoami `@` only accepts node ids, not
122
+ // paths), so `self.id === auth.principal` holds by construction. The
123
+ // minted delegation carries the session's authority expression (composed
124
+ // for delegated sessions, self-only for selfKernel): the next worker
125
+ // sees WHO called it while inheriting exactly that authority.
126
+ // `skipDelegation` keeps the whoami + mint from re-entering this
127
+ // closure — both target the kernel (same origin), so no delegation is
128
+ // needed.
90
129
  mint: async (audience) => {
130
+ const selfId = await resolveSelfId(session, credential, kernelUrl, config)
91
131
  const envelope = await session.call(
92
- `@${config.subject}::mintDelegationCredential`,
93
- { audience, delegation: { kind: 'identity', self: true }, ttl: DELEGATION_TTL_SECONDS },
94
- { credential: composed, skipDelegation: true },
132
+ `@${selfId}::mintDelegationCredential`,
133
+ { audience, delegation: nextHopDelegation(), ttl: DELEGATION_TTL_SECONDS },
134
+ { credential, skipDelegation: true },
95
135
  )
96
136
  if (typeof envelope !== 'string') {
97
137
  throw new Error(
@@ -103,5 +143,57 @@ export async function bindKernel(
103
143
  ttl: DELEGATION_TTL_SECONDS,
104
144
  },
105
145
  })
106
- return session.as(composed)
146
+ return session.as(credential)
147
+ }
148
+
149
+ /**
150
+ * Build the `selfKernel` accessor handed to remote-function handlers.
151
+ * Resolves the kernel URL from the explicit argument or `deps.KERNEL_URL`
152
+ * (a public request carries no credential, so the parent kernel cannot be
153
+ * inferred — it must be configured).
154
+ */
155
+ export function makeSelfKernel(
156
+ identity: RemoteIdentityConfig,
157
+ deps: unknown,
158
+ ): (kernelUrl?: string) => Promise<BoundClientSessionView<FnMap>> {
159
+ return async (kernelUrl?: string) => {
160
+ const url = kernelUrl ?? (deps as { KERNEL_URL?: unknown } | null | undefined)?.KERNEL_URL
161
+ if (typeof url !== 'string' || url.length === 0) {
162
+ throw new Error(
163
+ 'selfKernel: no kernel URL — pass one explicitly or set KERNEL_URL in the worker env ' +
164
+ '(managed deploys set it automatically).',
165
+ )
166
+ }
167
+ return bindSelfKernel(url, identity)
168
+ }
169
+ }
170
+
171
+ // Function-identity node ids, cached per (kernel, issuer, subject). Sessions
172
+ // are per-request, but a function's identity node is stable for the worker's
173
+ // lifetime — one whoami per function, not one per redirect.
174
+ const selfIds = new Map<string, string>()
175
+
176
+ /**
177
+ * Resolve THIS function's identity node id on the parent kernel via whoami,
178
+ * authenticated with the composed credential (whose principal IS the function).
179
+ */
180
+ async function resolveSelfId(
181
+ session: ClientSession<FnMap>,
182
+ credential: string,
183
+ kernelUrl: string,
184
+ config: RemoteIdentityConfig,
185
+ ): Promise<string> {
186
+ const key = `${kernelUrl}|${config.issuer}|${config.subject}`
187
+ const cached = selfIds.get(key)
188
+ if (cached) return cached
189
+ const me = (await session.call(WHOAMI_PATH, {}, { credential, skipDelegation: true })) as {
190
+ id?: string
191
+ } | null
192
+ if (!me?.id) {
193
+ throw new Error(
194
+ `whoami returned no identity node for ${config.subject} — cannot anchor the next-hop delegation mint`,
195
+ )
196
+ }
197
+ selfIds.set(key, me.id)
198
+ return me.id
107
199
  }