@astrale-os/cli 1.0.0-beta.3 → 1.0.0-beta.31

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 (345) hide show
  1. package/README.md +84 -6
  2. package/dist/astrale.js +57586 -60753
  3. package/dist/public/connect-core.js +2158 -30706
  4. package/dist/public/keys/index.js +1016 -29541
  5. package/dist/public/paths/index.js +370 -28654
  6. package/dist/types/admin/contract.d.ts +26 -0
  7. package/dist/types/admin/instance/client.d.ts +20 -0
  8. package/dist/types/admin/instance/index.d.ts +2 -0
  9. package/dist/types/admin/instance/model.d.ts +6 -10
  10. package/dist/types/connection/auth.d.ts +3 -0
  11. package/dist/types/connection/call.d.ts +3 -0
  12. package/dist/types/connection/command.d.ts +27 -0
  13. package/dist/types/connection/credential.d.ts +14 -0
  14. package/dist/types/connection/errors.d.ts +1 -0
  15. package/dist/types/connection/exchange.d.ts +9 -0
  16. package/dist/types/connection/failure/classify.d.ts +2 -0
  17. package/dist/types/connection/failure/index.d.ts +5 -0
  18. package/dist/types/connection/failure/model.d.ts +25 -0
  19. package/dist/types/connection/failure/render.d.ts +3 -0
  20. package/dist/types/connection/index.d.ts +8 -0
  21. package/dist/types/connection/reasons.d.ts +37 -0
  22. package/dist/types/connection/self.d.ts +37 -0
  23. package/dist/types/connection/session.d.ts +31 -0
  24. package/dist/types/connection/target.d.ts +38 -0
  25. package/dist/types/errors.d.ts +1 -1
  26. package/dist/types/lib/admin-instance.d.ts +17 -0
  27. package/dist/types/lib/admin-target.d.ts +11 -36
  28. package/dist/types/lib/config.d.ts +13 -59
  29. package/dist/types/lib/failure-debug.d.ts +1 -0
  30. package/dist/types/lib/idp.d.ts +25 -173
  31. package/dist/types/lib/instance-target.d.ts +1 -1
  32. package/dist/types/lib/instance.d.ts +30 -88
  33. package/dist/types/lib/log.d.ts +5 -3
  34. package/dist/types/lib/output.d.ts +1 -1
  35. package/dist/types/lib/proc.d.ts +43 -0
  36. package/dist/types/lib/self.d.ts +9 -0
  37. package/dist/types/lib/update.d.ts +109 -0
  38. package/dist/types/lib/validation.d.ts +4 -1
  39. package/dist/types/state/exchange-credentials.d.ts +6 -2
  40. package/dist/types/state/files.d.ts +2 -0
  41. package/dist/types/state/index.d.ts +3 -2
  42. package/dist/types/state/paths.d.ts +2 -0
  43. package/dist/types/state/session-routes.d.ts +10 -0
  44. package/package.json +16 -19
  45. package/src/__tests__/fixtures/publication.ts +20 -0
  46. package/src/admin/.spec/architecture.md +12 -5
  47. package/src/admin/__tests__/fixture.ts +25 -0
  48. package/src/admin/catalog/.spec/api.d.ts +1 -3
  49. package/src/admin/catalog/.spec/architecture.md +5 -4
  50. package/src/admin/catalog/__tests__/client.test.ts +143 -69
  51. package/src/admin/catalog/client.ts +40 -54
  52. package/src/admin/catalog/model.ts +3 -4
  53. package/src/admin/contract.ts +47 -0
  54. package/src/admin/graph/.spec/api.d.ts +4 -10
  55. package/src/admin/graph/nodes.ts +1 -1
  56. package/src/admin/instance/.spec/api.d.ts +5 -9
  57. package/src/admin/instance/.spec/architecture.md +7 -7
  58. package/src/admin/instance/__tests__/client.test.ts +157 -175
  59. package/src/admin/instance/client.ts +39 -128
  60. package/src/admin/instance/index.ts +1 -2
  61. package/src/admin/instance/model.ts +12 -18
  62. package/src/commands/__tests__/admin-instance.test.ts +11 -8
  63. package/src/commands/__tests__/call-describe.test.ts +46 -33
  64. package/src/commands/__tests__/call.test.ts +34 -0
  65. package/src/commands/__tests__/domain-install-operation.test.ts +30 -22
  66. package/src/commands/__tests__/domain-install-owned.test.ts +1 -1
  67. package/src/commands/__tests__/domain-list.test.ts +5 -25
  68. package/src/commands/__tests__/install-direct.test.ts +115 -8
  69. package/src/commands/__tests__/install-identity-override.test.ts +6 -17
  70. package/src/commands/__tests__/instance-list-rows.test.ts +1 -1
  71. package/src/commands/__tests__/instance-status.test.ts +139 -0
  72. package/src/commands/__tests__/introspect-parse.test.ts +80 -1
  73. package/src/commands/__tests__/logs.test.ts +250 -2
  74. package/src/commands/__tests__/read-commands.test.ts +119 -11
  75. package/src/commands/__tests__/token-ttl.test.ts +49 -4
  76. package/src/commands/__tests__/update.test.ts +25 -3
  77. package/src/commands/__tests__/view.test.ts +50 -2
  78. package/src/commands/auth/logout.ts +2 -1
  79. package/src/commands/browser.ts +29 -0
  80. package/src/commands/call-describe.ts +60 -68
  81. package/src/commands/call.ts +71 -59
  82. package/src/commands/domain/install.ts +73 -46
  83. package/src/commands/domain/list.ts +1 -1
  84. package/src/commands/domain/publish.ts +14 -11
  85. package/src/commands/domain/uninstall.ts +2 -2
  86. package/src/commands/get.ts +15 -16
  87. package/src/commands/identity/__tests__/register.test.ts +3 -3
  88. package/src/commands/identity/register.ts +8 -8
  89. package/src/commands/instance/create.ts +8 -16
  90. package/src/commands/instance/delete.ts +12 -9
  91. package/src/commands/instance/list.ts +2 -2
  92. package/src/commands/instance/status.ts +66 -20
  93. package/src/commands/instance/use.ts +16 -12
  94. package/src/commands/introspect.ts +53 -41
  95. package/src/commands/logs.ts +123 -36
  96. package/src/commands/mutate.ts +6 -5
  97. package/src/commands/query.ts +39 -36
  98. package/src/commands/session/analyze.ts +26 -4
  99. package/src/commands/token.ts +42 -27
  100. package/src/commands/ui/__tests__/commands.test.ts +152 -0
  101. package/src/commands/ui/add.ts +51 -0
  102. package/src/commands/ui/doctor.ts +21 -0
  103. package/src/commands/ui/init.ts +38 -0
  104. package/src/commands/ui/list.ts +26 -0
  105. package/src/commands/ui/preset-apply.ts +19 -0
  106. package/src/commands/ui/preset-list.ts +12 -0
  107. package/src/commands/ui/shared.ts +25 -0
  108. package/src/commands/update.ts +90 -48
  109. package/src/commands/view.ts +82 -37
  110. package/src/connection/.spec/api.d.ts +7 -8
  111. package/src/connection/.spec/architecture.md +14 -5
  112. package/src/connection/.spec/flows/session.ts +2 -2
  113. package/src/connection/.spec/laws/connection.ts +6 -2
  114. package/src/connection/.spec/layout.ts +1 -0
  115. package/src/connection/__tests__/auth.test.ts +1 -0
  116. package/src/connection/__tests__/credential.test.ts +21 -1
  117. package/src/connection/__tests__/errors.test.ts +27 -20
  118. package/src/connection/__tests__/exchange.test.ts +64 -11
  119. package/src/connection/__tests__/failure-fixtures.ts +39 -0
  120. package/src/connection/__tests__/failure-safety.test.ts +75 -0
  121. package/src/connection/__tests__/self.test.ts +31 -11
  122. package/src/connection/__tests__/session.test.ts +8 -4
  123. package/src/connection/__tests__/target.test.ts +2 -0
  124. package/src/connection/auth.ts +13 -0
  125. package/src/connection/call.ts +1 -1
  126. package/src/connection/credential.ts +2 -2
  127. package/src/connection/errors.ts +1 -355
  128. package/src/connection/exchange.ts +110 -61
  129. package/src/connection/failure/classify.ts +110 -0
  130. package/src/connection/failure/index.ts +18 -0
  131. package/src/connection/failure/model.ts +28 -0
  132. package/src/connection/failure/render.ts +116 -0
  133. package/src/connection/reasons.ts +16 -0
  134. package/src/connection/self.ts +39 -21
  135. package/src/connection/session.ts +27 -9
  136. package/src/errors.ts +3 -2
  137. package/src/graph/.spec/api.d.ts +13 -6
  138. package/src/graph/.spec/laws/documents.ts +7 -7
  139. package/src/graph/.spec/layout.ts +9 -1
  140. package/src/graph/__tests__/mutation.test.ts +2 -2
  141. package/src/graph/__tests__/query.test.ts +35 -9
  142. package/src/graph/class.ts +30 -0
  143. package/src/graph/index.ts +1 -0
  144. package/src/graph/query.ts +27 -40
  145. package/src/identity/.spec/api.d.ts +2 -2
  146. package/src/identity/__tests__/fixtures/registry-journey.ts +13 -1
  147. package/src/identity/__tests__/registration.test.ts +1 -1
  148. package/src/identity/__tests__/registry.test.ts +4 -0
  149. package/src/identity/registration.ts +3 -3
  150. package/src/identity/registry.ts +2 -0
  151. package/src/keys/__tests__/keys.test.ts +4 -0
  152. package/src/keys/credential.ts +1 -0
  153. package/src/lib/__tests__/admin-target.test.ts +12 -0
  154. package/src/lib/__tests__/binary.test.ts +16 -1
  155. package/src/lib/__tests__/browser-retention.test.ts +212 -0
  156. package/src/lib/__tests__/command-dx.test.ts +1 -1
  157. package/src/lib/__tests__/config.test.ts +27 -0
  158. package/src/lib/__tests__/domain-publication.test.ts +10 -16
  159. package/src/lib/__tests__/idp.test.ts +34 -4
  160. package/src/lib/__tests__/instance-candidates.test.ts +1 -3
  161. package/src/lib/__tests__/instance-target.test.ts +7 -39
  162. package/src/lib/__tests__/log-errors.test.ts +64 -0
  163. package/src/lib/__tests__/skills.test.ts +834 -0
  164. package/src/lib/__tests__/studio-server-deps.test.ts +1 -1
  165. package/src/lib/__tests__/update.test.ts +264 -11
  166. package/src/lib/__tests__/view-assets.test.ts +25 -0
  167. package/src/lib/__tests__/view-external-open-intent.test.ts +150 -0
  168. package/src/lib/__tests__/view-external-open-origins.test.ts +27 -0
  169. package/src/lib/__tests__/view-open-intent.test.ts +0 -2
  170. package/src/lib/__tests__/view-server.test.ts +26 -3
  171. package/src/lib/__tests__/view-session.test.ts +2 -1
  172. package/src/lib/admin-instance.ts +14 -8
  173. package/src/lib/admin-target.ts +21 -2
  174. package/src/lib/binary.ts +22 -5
  175. package/src/lib/browser-retention.ts +210 -0
  176. package/src/lib/command-dx.ts +9 -9
  177. package/src/lib/config.ts +12 -1
  178. package/src/lib/domain-publication.ts +9 -7
  179. package/src/lib/failure-debug.ts +26 -0
  180. package/src/lib/idp.ts +34 -3
  181. package/src/lib/instance-candidates.ts +2 -2
  182. package/src/lib/instance-target.ts +3 -14
  183. package/src/lib/instance.ts +16 -11
  184. package/src/lib/log.ts +16 -9
  185. package/src/lib/output.ts +1 -1
  186. package/src/lib/proc.ts +7 -2
  187. package/src/lib/provision-instance.ts +34 -57
  188. package/src/lib/skills/lock.ts +117 -0
  189. package/src/lib/skills/sync.ts +878 -0
  190. package/src/lib/skills.ts +1 -52
  191. package/src/lib/update.ts +298 -45
  192. package/src/lib/validation.ts +2 -2
  193. package/src/lib/view/assets.ts +11 -2
  194. package/src/lib/view/external-open-intent.ts +41 -0
  195. package/src/lib/view/external-open-origins.ts +37 -0
  196. package/src/lib/view/host-capabilities.ts +17 -0
  197. package/src/lib/view/resolve.ts +1 -1
  198. package/src/lib/view/server.ts +18 -3
  199. package/src/lib/view/session.ts +2 -0
  200. package/src/program/.spec/api.d.ts +1 -0
  201. package/src/program/__tests__/program.test.ts +201 -7
  202. package/src/program/argv.ts +14 -0
  203. package/src/program/build.ts +26 -4
  204. package/src/program/command.ts +1 -0
  205. package/src/program/index.ts +1 -0
  206. package/src/program/registry.ts +2 -1
  207. package/src/setup/__tests__/instance-step.test.ts +27 -10
  208. package/src/setup/steps/instance.ts +22 -15
  209. package/src/setup/steps/skills.ts +40 -38
  210. package/src/state/.spec/api.d.ts +21 -2
  211. package/src/state/.spec/architecture.md +18 -4
  212. package/src/state/.spec/layout.ts +1 -0
  213. package/src/state/__tests__/exchange-credentials.test.ts +88 -42
  214. package/src/state/__tests__/files.test.ts +24 -1
  215. package/src/state/__tests__/fixtures/session-route-process.ts +93 -0
  216. package/src/state/__tests__/paths.test.ts +1 -0
  217. package/src/state/__tests__/session-routes.test.ts +138 -0
  218. package/src/state/exchange-credentials.ts +22 -9
  219. package/src/state/files.ts +41 -0
  220. package/src/state/index.ts +3 -1
  221. package/src/state/paths.ts +3 -0
  222. package/src/state/session-routes.ts +34 -0
  223. package/src/telemetry/__tests__/analyze-log.test.ts +38 -0
  224. package/src/telemetry/__tests__/recorder.test.ts +1 -0
  225. package/src/telemetry/__tests__/retention.test.ts +267 -0
  226. package/src/telemetry/__tests__/settings.test.ts +102 -0
  227. package/src/telemetry/__tests__/store-scan.test.ts +128 -0
  228. package/src/telemetry/__tests__/trigger.test.ts +33 -4
  229. package/src/telemetry/analyze.ts +24 -2
  230. package/src/telemetry/recorder.ts +15 -4
  231. package/src/telemetry/retention.ts +176 -0
  232. package/src/telemetry/session.ts +18 -12
  233. package/src/telemetry/settings.ts +64 -11
  234. package/src/telemetry/store.ts +92 -9
  235. package/src/telemetry/trigger.ts +16 -28
  236. package/src/ui/.spec/api.d.ts +14 -0
  237. package/src/ui/.spec/architecture.md +14 -0
  238. package/src/ui/.spec/laws.ts +50 -0
  239. package/src/ui/.spec/layout.ts +16 -0
  240. package/src/ui/__tests__/ui.test.ts +1742 -0
  241. package/src/ui/index.ts +13 -0
  242. package/src/ui/lock.ts +89 -0
  243. package/src/ui/model.ts +83 -0
  244. package/src/ui/operations.ts +1044 -0
  245. package/src/ui/project.ts +333 -0
  246. package/src/ui/release.ts +398 -0
  247. package/src/ui/runner.ts +18 -0
  248. package/studio/client/dist/assets/elk-api-DjmKsHXc.js +1 -0
  249. package/studio/client/dist/assets/index-BFVFs_8x.js +81 -0
  250. package/studio/client/dist/assets/index-DuB9iUdu.css +2 -0
  251. package/studio/client/dist/assets/rolldown-runtime-Dd_uD5pT.js +1 -0
  252. package/studio/client/dist/assets/schema-studio--a0kX3QU.css +1 -0
  253. package/studio/client/dist/assets/schema-studio-DH6oEWME.js +8 -0
  254. package/studio/client/dist/index.html +4 -3
  255. package/studio/package.json +8 -14
  256. package/studio/server/agent/ask.test.ts +1 -1
  257. package/studio/server/agent/bridge/grant.test.ts +1 -1
  258. package/studio/server/agent/bridge/routes.test.ts +1 -1
  259. package/studio/server/agent/harness/claude/adapter.test.ts +15 -5
  260. package/studio/server/agent/harness/gateway/token.test.ts +1 -1
  261. package/studio/server/agent/harness/gateway/token.ts +3 -3
  262. package/studio/server/agent/prompts/anchors.test.ts +41 -32
  263. package/studio/server/agent/prompts/anchors.ts +23 -51
  264. package/studio/server/agent/prompts/system.test.ts +4 -4
  265. package/studio/server/agent/prompts/system.ts +5 -5
  266. package/studio/server/agent/routes.test.ts +1 -1
  267. package/studio/server/agent/run/coordinator.test.ts +1 -1
  268. package/studio/server/agent/run/preparation.ts +1 -1
  269. package/studio/server/api/canvas.ts +0 -1
  270. package/studio/server/api/context.ts +1 -1
  271. package/studio/server/api/deployment.ts +1 -1
  272. package/studio/server/api/views.ts +2 -2
  273. package/studio/server/api/workspace.ts +1 -1
  274. package/studio/server/api-agent-loadout.test.ts +1 -1
  275. package/studio/server/api.test.ts +1 -1
  276. package/studio/server/cache.test.ts +24 -18
  277. package/studio/server/cache.ts +10 -54
  278. package/studio/server/cli-consumers.test.ts +32 -4
  279. package/studio/server/cli.test.ts +2 -2
  280. package/studio/server/domain.test.ts +50 -68
  281. package/studio/server/domain.ts +82 -63
  282. package/studio/server/handoff/copy.ts +2 -2
  283. package/studio/server/index.ts +1 -1
  284. package/studio/server/instances/probe.test.ts +1 -1
  285. package/studio/server/introspect/anatomy/views/routes.ts +46 -37
  286. package/studio/server/introspect/anatomy/views.ts +10 -16
  287. package/studio/server/introspect/anatomy-extras.test.ts +29 -56
  288. package/studio/server/introspect/anatomy.test.ts +22 -14
  289. package/studio/server/introspect/anatomy.ts +6 -9
  290. package/studio/server/introspect/bundle.ts +0 -3
  291. package/studio/server/introspect/canonical-schema.test.ts +155 -424
  292. package/studio/server/introspect/canonical-schema.ts +248 -601
  293. package/studio/server/introspect/core.ts +14 -22
  294. package/studio/server/introspect/diff.test.ts +21 -9
  295. package/studio/server/introspect/diff.ts +19 -64
  296. package/studio/server/introspect/extractor.ts +23 -122
  297. package/studio/server/introspect/overlay-tsmorph.test.ts +116 -241
  298. package/studio/server/introspect/overlay-tsmorph.ts +0 -1
  299. package/studio/server/introspect/overlay.ts +3 -51
  300. package/studio/server/introspect/revision.test.ts +24 -28
  301. package/studio/server/introspect/revision.ts +11 -22
  302. package/studio/server/introspect/runtime.test.ts +77 -195
  303. package/studio/server/introspect/runtime.ts +5 -67
  304. package/studio/server/introspect/schema-ir-json.test.ts +81 -0
  305. package/studio/server/introspect/schema-ir-json.ts +39 -69
  306. package/studio/server/introspect/schema-refs.test.ts +43 -88
  307. package/studio/server/introspect/schema-refs.ts +14 -49
  308. package/studio/server/introspect/source-overlay/handlers.ts +116 -636
  309. package/studio/server/introspect/source-overlay/kernel-calls.ts +0 -3
  310. package/studio/server/introspect/source-overlay/spans.ts +15 -45
  311. package/studio/server/lifecycle.ts +4 -1
  312. package/studio/server/state/baseline.test.ts +14 -9
  313. package/studio/server/state/baseline.ts +3 -5
  314. package/studio/server/state/documents.test.ts +69 -0
  315. package/studio/server/state/documents.ts +57 -10
  316. package/studio/server/state/visibility.ts +1 -5
  317. package/studio/server/views/model.ts +3 -3
  318. package/studio/server/views/target.test.ts +18 -76
  319. package/studio/server/views/target.ts +25 -51
  320. package/studio/server/watch.test.ts +11 -11
  321. package/studio/server/watch.ts +8 -4
  322. package/studio/server/workspace/updates.ts +23 -1
  323. package/studio/server/workspace-watch.ts +2 -2
  324. package/studio/shared/contracts/runtime.ts +4 -0
  325. package/studio/shared/contracts/schema.ts +44 -131
  326. package/studio/shared/contracts/surface.test.ts +15 -17
  327. package/studio/shared/contracts/workspace.ts +5 -11
  328. package/studio/shared/schema/identity.test.ts +20 -44
  329. package/studio/shared/schema/identity.ts +9 -24
  330. package/studio/tsconfig.json +2 -1
  331. package/tsconfig.json +1 -1
  332. package/viewer/dist/index.html +21 -0
  333. package/viewer/dist/main.js +41 -62
  334. package/.check-workspace.cjs +0 -40
  335. package/src/admin/binding.ts +0 -168
  336. package/src/commands/__tests__/instance-create-hosts.test.ts +0 -29
  337. package/studio/client/dist/assets/elk-api-lwhFo7vB.js +0 -1
  338. package/studio/client/dist/assets/index-B-c-smo9.js +0 -8
  339. package/studio/client/dist/assets/index-BckHuAWk.js +0 -81
  340. package/studio/client/dist/assets/index-C4aNQ6dz.css +0 -1
  341. package/studio/client/dist/assets/index-ChOr3yP0.css +0 -1
  342. package/studio/server/introspect/anatomy/views/legacy.ts +0 -232
  343. package/studio/server/introspect/core-extractor.ts +0 -139
  344. package/studio/server/introspect/overlay.test.ts +0 -72
  345. package/studio/server/introspect/source-overlay/annotations.ts +0 -14
@@ -1,9 +1,9 @@
1
- import type { Fetch } from '@astrale-os/kernel-client'
2
1
  import type { IssuerId } from '@astrale-os/sdk/auth'
2
+ import type { Fetch } from '@astrale-os/sdk/client'
3
3
 
4
- import { call, Client } from '@astrale-os/kernel-client'
5
- import { createAuth } from '@astrale-os/kernel-client/auth'
4
+ import { createAuth } from '@astrale-os/sdk/auth'
6
5
  import { credential, exchange as exchangeProtocol } from '@astrale-os/sdk/auth'
6
+ import { call, Client } from '@astrale-os/sdk/client'
7
7
 
8
8
  import type { SourceCredentialResolver } from './credential'
9
9
  import type { ConnectionTarget } from './target'
@@ -11,7 +11,7 @@ import type { ConnectionTarget } from './target'
11
11
  import { AstraleError } from '../errors'
12
12
  import { ExchangeCredentialCache } from '../state/exchange-credentials'
13
13
 
14
- const EXCHANGE_TTL_SECONDS = 120
14
+ const EXCHANGE_TTL_SECONDS = 5 * 60
15
15
  const MAXIMUM_RESPONSE_BYTES = 256 * 1024
16
16
 
17
17
  /** Exchange exact authenticated User authority for a Domain bearer bound to this Kernel. */
@@ -27,53 +27,78 @@ export function createExchangeCredentialResolver(
27
27
  async resolve(kernelIssuer: IssuerId, signal: AbortSignal): Promise<string> {
28
28
  requireLive(signal)
29
29
  const sourceToken = await source.resolve(kernelIssuer, signal)
30
- const delegationTtlSeconds = delegationLifetime(sourceToken)
30
+ const sourceIdentity = sourceCacheIdentity(sourceToken)
31
31
  requireLive(signal)
32
32
 
33
- const client = new Client({ url: `${kernelIssuer}/invoke`, fetch, timeoutMs })
34
- try {
35
- const authenticated = client.as(sourceToken)
36
- const auth = createAuth(async (path, input, options) => {
37
- const result = await authenticated.call(call(path, input), {
38
- ...options,
39
- delegate: { ttlSeconds: delegationTtlSeconds },
40
- })
41
- return result.value
42
- })
43
- const user = await auth.whoami({ signal })
44
- const key = Object.freeze({
33
+ return await cache.getOrRefresh(
34
+ Object.freeze({
45
35
  kernelIssuer,
46
36
  domainIssuer: target.domainIssuer,
47
- user: user.id,
48
- })
49
- return await cache.getOrRefresh(key, async () => {
50
- let envelope: string | undefined
51
- for (let attempt = 0; attempt < 3; attempt += 1) {
52
- try {
53
- envelope = await auth.delegate(
54
- user.id,
55
- {
56
- audience: target.domainIssuer,
57
- ttlSeconds: delegationTtlSeconds,
58
- attenuation: { kind: 'identity', self: true },
59
- },
60
- { signal },
61
- )
62
- break
63
- } catch (cause) {
64
- if (attempt === 2 || !unknownFunctionOutcome(cause)) throw cause
37
+ sourceIssuer: sourceIdentity.issuer,
38
+ sourceSubject: sourceIdentity.subject,
39
+ }),
40
+ async () => {
41
+ const delegationTtlSeconds = delegationLifetime(sourceToken)
42
+ const client = new Client({ url: `${kernelIssuer}/invoke`, fetch, timeoutMs })
43
+ try {
44
+ const authenticated = client.as(sourceToken)
45
+ const auth = createAuth(async (path, input, options) => {
46
+ const result = await authenticated.call(call(path, input), {
47
+ ...options,
48
+ delegate: { ttlSeconds: delegationTtlSeconds },
49
+ })
50
+ return result.value
51
+ })
52
+ const user = await auth.whoami({ signal })
53
+ let envelope: string | undefined
54
+ for (let attempt = 0; attempt < 3; attempt += 1) {
55
+ try {
56
+ envelope = await auth.delegate(
57
+ user.id,
58
+ {
59
+ audience: target.domainIssuer,
60
+ ttlSeconds: delegationTtlSeconds,
61
+ attenuation: { kind: 'identity', self: true },
62
+ },
63
+ { signal },
64
+ )
65
+ break
66
+ } catch (cause) {
67
+ if (attempt === 2 || !unknownFunctionOutcome(cause)) throw cause
68
+ }
65
69
  }
70
+ if (envelope === undefined) throw new Error('Token delegation returned no credential.')
71
+ return {
72
+ ...(await exchange(target.domainIssuer, kernelIssuer, envelope, fetch, signal)),
73
+ user: user.id,
74
+ sourceIssuer: sourceIdentity.issuer,
75
+ sourceSubject: sourceIdentity.subject,
76
+ }
77
+ } finally {
78
+ client.close()
66
79
  }
67
- if (envelope === undefined) throw new Error('Token delegation returned no credential.')
68
- return exchange(target.domainIssuer, kernelIssuer, envelope, fetch, signal)
69
- })
70
- } finally {
71
- client.close()
72
- }
80
+ },
81
+ )
73
82
  },
74
83
  })
75
84
  }
76
85
 
86
+ function sourceCacheIdentity(sourceToken: string): { issuer: string; subject: string } {
87
+ const inspected = credential.inspect(sourceToken)
88
+ if (
89
+ typeof inspected.iss !== 'string' ||
90
+ inspected.iss.length === 0 ||
91
+ typeof inspected.sub !== 'string' ||
92
+ inspected.sub.length === 0
93
+ ) {
94
+ throw new AstraleError(
95
+ 'TOKEN_EXCHANGE_SOURCE_INVALID',
96
+ 'The source identity credential has no stable issuer and subject.',
97
+ )
98
+ }
99
+ return Object.freeze({ issuer: inspected.iss, subject: inspected.sub })
100
+ }
101
+
77
102
  function unknownFunctionOutcome(cause: unknown): boolean {
78
103
  if (cause === null || typeof cause !== 'object') return false
79
104
  const error = cause as { readonly code?: unknown; readonly reason?: unknown }
@@ -111,15 +136,20 @@ async function exchange(
111
136
  exchangeProtocol.paths(domainIssuer).configuration,
112
137
  domainIssuer,
113
138
  ).toString()
114
- const configurationResponse = await fetch(configurationUrl, {
115
- method: 'GET',
116
- redirect: 'error',
117
- credentials: 'omit',
118
- cache: 'no-store',
119
- referrerPolicy: 'no-referrer',
120
- headers: { accept: 'application/json' },
121
- signal,
122
- })
139
+ const configurationResponse = await fetchExchange(
140
+ fetch,
141
+ configurationUrl,
142
+ {
143
+ method: 'GET',
144
+ redirect: 'error',
145
+ credentials: 'omit',
146
+ cache: 'no-store',
147
+ referrerPolicy: 'no-referrer',
148
+ headers: { accept: 'application/json' },
149
+ signal,
150
+ },
151
+ 'Domain issuer discovery could not be reached.',
152
+ )
123
153
  if (!configurationResponse.ok) {
124
154
  throw new AstraleError(
125
155
  'TOKEN_EXCHANGE_DISCOVERY_FAILED',
@@ -139,18 +169,23 @@ async function exchange(
139
169
  )
140
170
  }
141
171
 
142
- const response = await fetch(endpoint, {
143
- method: 'POST',
144
- redirect: 'error',
145
- credentials: 'omit',
146
- cache: 'no-store',
147
- referrerPolicy: 'no-referrer',
148
- headers: {
149
- authorization: `Bearer ${envelope}`,
150
- accept: exchangeProtocol.MEDIA_TYPE,
172
+ const response = await fetchExchange(
173
+ fetch,
174
+ endpoint,
175
+ {
176
+ method: 'POST',
177
+ redirect: 'error',
178
+ credentials: 'omit',
179
+ cache: 'no-store',
180
+ referrerPolicy: 'no-referrer',
181
+ headers: {
182
+ authorization: `Bearer ${envelope}`,
183
+ accept: exchangeProtocol.MEDIA_TYPE,
184
+ },
185
+ signal,
151
186
  },
152
- signal,
153
- })
187
+ 'Domain token exchange could not be reached.',
188
+ )
154
189
  const body = await boundedJson(response, signal)
155
190
  if (!response.ok) {
156
191
  let admitted: exchangeProtocol.ErrorResponse
@@ -193,6 +228,20 @@ async function exchange(
193
228
  return Object.freeze({ credential: exchanged.token, expiresAt: exchanged.expiresAt })
194
229
  }
195
230
 
231
+ async function fetchExchange(
232
+ fetch: Fetch,
233
+ input: string,
234
+ init: RequestInit,
235
+ message: string,
236
+ ): Promise<Response> {
237
+ try {
238
+ return await fetch(input, init)
239
+ } catch (cause) {
240
+ if (init.signal?.aborted) throw cause
241
+ throw new AstraleError('TOKEN_EXCHANGE_UNAVAILABLE', message, undefined, { cause })
242
+ }
243
+ }
244
+
196
245
  function requireExchangeTransport(
197
246
  target: ConnectionTarget & { readonly domainIssuer: IssuerId },
198
247
  ): void {
@@ -0,0 +1,110 @@
1
+ import { AuthValueError } from '@astrale-os/sdk/auth'
2
+ import { ClientError, ProtocolError, ResponseError, TransportError } from '@astrale-os/sdk/client'
3
+ import { NodeUnavailableError } from '@astrale-os/sdk/client'
4
+ import { PathError } from '@astrale-os/sdk/graph/path'
5
+
6
+ import type { FailureDiagnostic, TransportDiagnosticContext } from './model'
7
+
8
+ import { AstraleError } from '../../errors'
9
+
10
+ export function classifyFailure(error: unknown): FailureDiagnostic {
11
+ if (error instanceof AstraleError) return simple(error.code, error.message, error.hint)
12
+ if (error instanceof TransportError) {
13
+ const context = transportContext(error)
14
+ if (context === undefined) return simple('TRANSPORT_ERROR', error.message)
15
+ return {
16
+ kind: 'transport',
17
+ code: lifecycleCode(error.phase),
18
+ message: error.message,
19
+ phase: error.phase,
20
+ context,
21
+ }
22
+ }
23
+ if (error instanceof ResponseError) {
24
+ return {
25
+ kind: 'response',
26
+ code: error.code,
27
+ message: error.message,
28
+ ...(error.reason === undefined ? {} : { reason: error.reason }),
29
+ }
30
+ }
31
+ if (error instanceof ClientError) {
32
+ const failure = sessionFailure(error)
33
+ if (failure !== undefined) return simple(lifecycleCode(failure), error.message)
34
+ }
35
+ if (error instanceof ProtocolError) return simple('PROTOCOL_ERROR', error.message)
36
+ if (error instanceof NodeUnavailableError)
37
+ return simple(
38
+ 'NODE_UNAVAILABLE',
39
+ error.message,
40
+ 'If this is a callable Path, use `astrale call` or `astrale introspect`.',
41
+ )
42
+ if (error instanceof PathError) return simple('PATH_INVALID', error.message)
43
+ if (error instanceof AuthValueError) return simple('AUTH_VALUE_INVALID', error.message)
44
+ if (error instanceof ClientError) return simple('CLIENT_ERROR', error.message)
45
+ return simple('UNEXPECTED_ERROR', 'The CLI encountered an unexpected internal failure.')
46
+ }
47
+
48
+ type TransportCode = Extract<FailureDiagnostic, { kind: 'transport' }>['code']
49
+ type SessionFailure = 'cancelled' | 'closed' | 'timeout'
50
+
51
+ function lifecycleCode(value: TransportError['phase']): TransportCode
52
+ function lifecycleCode(value: SessionFailure): string
53
+ function lifecycleCode(value: TransportError['phase'] | SessionFailure): string {
54
+ if (value === 'connect') return 'CONNECTION_ERROR'
55
+ if (value === 'timeout') return 'TIMEOUT'
56
+ if (value === 'closed') return 'DISCONNECTED'
57
+ return value === 'cancelled' ? 'CANCELLED' : 'TRANSPORT_ERROR'
58
+ }
59
+
60
+ function transportContext(error: TransportError): TransportDiagnosticContext | undefined {
61
+ const evidence = error as TransportError & {
62
+ readonly context?: unknown
63
+ readonly delivery?: unknown
64
+ readonly invocation?: unknown
65
+ }
66
+ if (record(evidence.context)) {
67
+ if (
68
+ evidence.context.kind === 'acquisition' &&
69
+ (evidence.context.resource === 'publication' || evidence.context.resource === 'bundle')
70
+ ) {
71
+ return { kind: 'acquisition', resource: evidence.context.resource }
72
+ }
73
+ if (
74
+ evidence.context.kind === 'invocation' &&
75
+ (evidence.context.delivery === 'not-sent' || evidence.context.delivery === 'unknown')
76
+ ) {
77
+ return {
78
+ kind: 'invocation',
79
+ delivery: evidence.context.delivery,
80
+ ...(evidence.context.invocation === undefined
81
+ ? {}
82
+ : { invocation: evidence.context.invocation }),
83
+ }
84
+ }
85
+ }
86
+ if (evidence.delivery !== 'not-sent' && evidence.delivery !== 'unknown') return undefined
87
+ return {
88
+ kind: 'invocation',
89
+ delivery: evidence.delivery,
90
+ ...(evidence.invocation === undefined ? {} : { invocation: evidence.invocation }),
91
+ }
92
+ }
93
+
94
+ function sessionFailure(error: ClientError): SessionFailure | undefined {
95
+ const failure = (error as ClientError & { readonly failure?: unknown }).failure
96
+ return failure === 'cancelled' || failure === 'closed' || failure === 'timeout'
97
+ ? failure
98
+ : undefined
99
+ }
100
+
101
+ function record(input: unknown): input is Readonly<Record<string, unknown>> {
102
+ return input !== null && typeof input === 'object' && !Array.isArray(input)
103
+ }
104
+
105
+ const simple = (code: string, message: string, hint?: string): FailureDiagnostic => ({
106
+ kind: 'simple',
107
+ code,
108
+ message,
109
+ ...(hint === undefined ? {} : { hint }),
110
+ })
@@ -0,0 +1,18 @@
1
+ import type { OperationRecovery } from '../command'
2
+
3
+ import { printFailureDebug } from '../../lib/failure-debug'
4
+ import { classifyFailure } from './classify'
5
+ import { renderFailure } from './render'
6
+
7
+ export { functionInputIssues, schemaUpgradeHint } from '../reasons'
8
+
9
+ export async function formatKernelError(
10
+ error: unknown,
11
+ machine: boolean,
12
+ urlArg = '',
13
+ debug = false,
14
+ options: { recovery?: OperationRecovery } = {},
15
+ ): Promise<void> {
16
+ renderFailure(classifyFailure(error), machine, urlArg, options.recovery)
17
+ if (debug) printFailureDebug(error, urlArg)
18
+ }
@@ -0,0 +1,28 @@
1
+ export type TransportDiagnosticContext =
2
+ | { readonly kind: 'acquisition'; readonly resource: 'publication' | 'bundle' }
3
+ | {
4
+ readonly kind: 'invocation'
5
+ readonly delivery: 'not-sent' | 'unknown'
6
+ readonly invocation?: unknown
7
+ }
8
+
9
+ export type FailureDiagnostic =
10
+ | {
11
+ readonly kind: 'simple'
12
+ readonly code: string
13
+ readonly message: string
14
+ readonly hint?: string
15
+ }
16
+ | {
17
+ readonly kind: 'response'
18
+ readonly code: number
19
+ readonly message: string
20
+ readonly reason?: unknown
21
+ }
22
+ | {
23
+ readonly kind: 'transport'
24
+ readonly code: 'CONNECTION_ERROR' | 'DISCONNECTED' | 'TIMEOUT' | 'TRANSPORT_ERROR'
25
+ readonly message: string
26
+ readonly phase: string
27
+ readonly context: TransportDiagnosticContext
28
+ }
@@ -0,0 +1,116 @@
1
+ import chalk from 'chalk'
2
+
3
+ import type { OperationRecovery } from '../command'
4
+ import type { FailureDiagnostic } from './model'
5
+
6
+ import { log } from '../../lib/log'
7
+ import {
8
+ functionInputIssues,
9
+ queryInputRepair,
10
+ reasonCode,
11
+ schemaDataRemovalHint,
12
+ schemaUpgradeDetails,
13
+ schemaUpgradeHint,
14
+ } from '../reasons'
15
+
16
+ export function renderFailure(
17
+ failure: FailureDiagnostic,
18
+ machine: boolean,
19
+ url: string,
20
+ recovery: OperationRecovery | undefined,
21
+ ): void {
22
+ if (failure.kind === 'transport') return renderTransport(failure, machine, url, recovery)
23
+ if (failure.kind === 'response') return renderResponse(failure, machine)
24
+ if (machine)
25
+ return writeRaw({ error: failure.code, message: failure.message, hint: failure.hint })
26
+ log.error(`${chalk.bold(failure.code)}: ${failure.message}`)
27
+ if (failure.hint) log.dim(` ${failure.hint}`)
28
+ }
29
+
30
+ function renderTransport(
31
+ failure: Extract<FailureDiagnostic, { kind: 'transport' }>,
32
+ machine: boolean,
33
+ url: string,
34
+ recovery: OperationRecovery | undefined,
35
+ ): void {
36
+ const invocation = failure.context.kind === 'invocation' ? failure.context : undefined
37
+ if (machine) {
38
+ writeRaw({
39
+ error: failure.code,
40
+ message: failure.message,
41
+ phase: failure.phase,
42
+ transport: failure.context,
43
+ ...(url === '' ? {} : { url }),
44
+ ...(invocation?.delivery === 'unknown' && recovery !== undefined ? recovery : {}),
45
+ })
46
+ return
47
+ }
48
+ log.error(`${chalk.bold(failure.code)}: ${failure.message}`)
49
+ if (url) log.dim(` target: ${url}`)
50
+ log.dim(` phase: ${failure.phase}`)
51
+ if (failure.phase === 'connect') log.dim(' Check the target and run `astrale status`.')
52
+ else if (failure.phase === 'timeout') log.dim(' Try increasing `--timeout`.')
53
+ else if (invocation?.delivery === 'unknown') renderRecovery(recovery)
54
+ }
55
+
56
+ function renderResponse(
57
+ failure: Extract<FailureDiagnostic, { kind: 'response' }>,
58
+ machine: boolean,
59
+ ): void {
60
+ const code = reasonCode(failure.reason)
61
+ const issues = functionInputIssues(failure.reason)
62
+ const removalHint = schemaDataRemovalHint(failure.reason)
63
+ const addressNotPublic = code === 'SCHEMA_DOMAIN_ADDRESS_NOT_PUBLIC'
64
+ const upgrade = schemaUpgradeDetails(failure.reason)
65
+ const message = addressNotPublic
66
+ ? 'Expose the Domain through a public HTTPS URL or public tunnel, then retry.'
67
+ : removalHint && !machine
68
+ ? 'Existing business data still uses schema definitions being removed.'
69
+ : failure.message
70
+ const hint =
71
+ code === 'FUNCTION_INPUT_INVALID' && (machine || issues.length === 0)
72
+ ? 'Use `astrale introspect <path>` to see the callable input.'
73
+ : (removalHint ?? (upgrade ? schemaUpgradeHint(upgrade) : undefined))
74
+ if (machine) {
75
+ writeRaw({
76
+ error: 'RESPONSE_ERROR',
77
+ code: failure.code,
78
+ message,
79
+ ...(failure.reason === undefined ? {} : { reason: failure.reason }),
80
+ ...(hint === undefined ? {} : { hint }),
81
+ })
82
+ return
83
+ }
84
+ const label = addressNotPublic
85
+ ? 'SCHEMA_DOMAIN_ADDRESS_NOT_PUBLIC'
86
+ : removalHint
87
+ ? 'DATA_MIGRATION_REQUIRED'
88
+ : `RESPONSE_ERROR(${failure.code})`
89
+ log.error(`${chalk.bold(label)}: ${message}`)
90
+ if (code && !addressNotPublic && !removalHint) log.dim(` reason: ${code}`)
91
+ for (const issue of issues)
92
+ console.log(
93
+ chalk.red(` ${issue.path || '<input>'}: ${issue.message} (${chalk.dim(issue.code)})`),
94
+ )
95
+ const repair = queryInputRepair(failure.reason)
96
+ if (repair?.phase === 'plan') log.dim(` ${repair.path ?? '/'} ${repair.issue}`)
97
+ else if (repair?.phase === 'limit')
98
+ log.dim(` ${repair.path ?? '/'} ${repair.limit} limit ${repair.actual}/${repair.maximum}`)
99
+ else if (repair) log.dim(` ${repair.path} ${repair.phase} input`)
100
+ if (upgrade?.issue === 'issuer-changed') {
101
+ log.dim(` installed issuer: ${upgrade.installedIssuer}`)
102
+ log.dim(` replacement issuer: ${upgrade.replacementIssuer}`)
103
+ }
104
+ if (hint) log.dim(` ${hint}`)
105
+ }
106
+
107
+ function renderRecovery(recovery: OperationRecovery | undefined): void {
108
+ if (!recovery)
109
+ return log.dim(' Delivery is unknown; do not automatically retry a mutating call.')
110
+ log.dim(' Delivery is unknown; retry with the same operation id:')
111
+ log.dim(` operation: ${recovery.operation}`)
112
+ log.dim(` ${recovery.retry}`)
113
+ }
114
+
115
+ const writeRaw = (payload: Record<string, unknown>): void =>
116
+ void process.stderr.write(`${JSON.stringify(payload)}\n`)
@@ -150,6 +150,22 @@ export function schemaUpgradeHint(details: SchemaUpgradeDetails): string {
150
150
  )
151
151
  }
152
152
 
153
+ export function schemaDataRemovalHint(reason: unknown): string | undefined {
154
+ if (!reasonWithCode(reason, 'DATA_MIGRATION_REQUIRED')) return undefined
155
+ const requirements = reason.details.requirements
156
+ if (
157
+ !Array.isArray(requirements) ||
158
+ requirements.length === 0 ||
159
+ !requirements.every(
160
+ (item) =>
161
+ record(item) && item.operation === 'remove-facts' && item.reason === 'destructive-change',
162
+ )
163
+ ) {
164
+ return undefined
165
+ }
166
+ return 'Delete this data explicitly, then retry. No data was deleted.'
167
+ }
168
+
153
169
  function reasonWithCode(
154
170
  input: unknown,
155
171
  code: string,
@@ -1,7 +1,9 @@
1
- import type { KernelCommandOpts } from './command'
1
+ import { NodeUnavailableError } from '@astrale-os/sdk/client'
2
2
 
3
+ import type { ConnectionContext } from './session'
4
+
5
+ import { AstraleError } from '../errors'
3
6
  import { containsSelfRef, expandSelfReferences } from '../lib/self'
4
- import { withClientSession } from './session'
5
7
 
6
8
  /** Metadata attached to errors after an authenticated caller-authored @self expansion. */
7
9
  export interface SelfExpansionMeta {
@@ -12,7 +14,7 @@ export interface SelfExpansionMeta {
12
14
  }
13
15
 
14
16
  /**
15
- * Run `action`; if it throws a node NotFoundError, retain the authenticated
17
+ * Run `action`; if it throws NodeUnavailableError, retain the authenticated
16
18
  * expansion for precise diagnostics. The error is re-thrown either way.
17
19
  */
18
20
  export async function withSelfHint<T>(
@@ -23,7 +25,7 @@ export async function withSelfHint<T>(
23
25
  try {
24
26
  return await action()
25
27
  } catch (err) {
26
- if (err instanceof Error && err.name === 'NotFoundError') {
28
+ if (err instanceof NodeUnavailableError) {
27
29
  ;(err as Error & { expandedFromSelf?: SelfExpansionMeta }).expandedFromSelf = meta
28
30
  }
29
31
  throw err
@@ -36,40 +38,39 @@ type AuthenticatedSelf = {
36
38
  }
37
39
 
38
40
  export type ResolveSelfIdDependencies = {
39
- readonly whoami?: (opts: KernelCommandOpts) => Promise<AuthenticatedSelf>
41
+ readonly whoami?: (context: ConnectionContext) => Promise<AuthenticatedSelf>
40
42
  }
41
43
 
42
44
  /** Resolve @self only from the effective principal authenticated by the selected Kernel. */
43
45
  export async function resolveSelfIdAuthenticated(
44
- opts: KernelCommandOpts,
46
+ context: ConnectionContext,
45
47
  dependencies: ResolveSelfIdDependencies = {},
46
48
  ): Promise<{ readonly id: string; readonly slug?: string }> {
47
- const resolved = await (dependencies.whoami ?? whoamiSelfId)(opts)
49
+ const resolved = await (dependencies.whoami ?? whoamiSelfId)(context)
48
50
  if (typeof resolved.id !== 'string' || resolved.id.trim().length === 0) {
49
- const error = new Error(
51
+ throw new AstraleError(
52
+ 'SELF_RESOLUTION_FAILED',
50
53
  '`@self` could not be resolved: authenticated Identity.whoami returned no NodeId.',
51
54
  )
52
- error.name = 'SelfResolutionError'
53
- throw error
54
55
  }
55
56
  return resolved.slug === undefined
56
57
  ? { id: resolved.id }
57
58
  : { id: resolved.id, slug: resolved.slug }
58
59
  }
59
60
 
60
- async function whoamiSelfId(opts: KernelCommandOpts): Promise<AuthenticatedSelf> {
61
- return withClientSession(opts, async ({ auth, target }) => ({
61
+ async function whoamiSelfId({ auth, target }: ConnectionContext): Promise<AuthenticatedSelf> {
62
+ return {
62
63
  ...(await auth.whoami()),
63
64
  ...(target.slug === undefined ? {} : { slug: target.slug }),
64
- }))
65
+ }
65
66
  }
66
67
 
67
68
  /** Expand @self in path-like commands and return metadata for NotFound diagnostics. */
68
69
  export async function expandSelfInPath(
69
70
  path: string,
70
- options: KernelCommandOpts,
71
+ context: ConnectionContext,
71
72
  ): Promise<{ readonly path: string; readonly meta?: SelfExpansionMeta }> {
72
- const expanded = await expandSelfValues(path, [], options)
73
+ const expanded = await expandSelfValues(path, [], context)
73
74
  return expanded.meta === undefined
74
75
  ? { path: expanded.path }
75
76
  : { path: expanded.path, meta: expanded.meta }
@@ -78,20 +79,37 @@ export async function expandSelfInPath(
78
79
  /** Expand @self once across one Call path and its CLI-authored string parameters. */
79
80
  export async function expandSelfInCall(
80
81
  path: string,
81
- parameters: readonly string[],
82
- options: KernelCommandOpts,
82
+ parameters: Readonly<Record<string, unknown>>,
83
+ context: ConnectionContext,
83
84
  ): Promise<{
84
85
  readonly path: string
85
- readonly parameters: readonly string[]
86
+ readonly parameters: Readonly<Record<string, unknown>>
86
87
  readonly meta?: SelfExpansionMeta
87
88
  }> {
88
- return expandSelfValues(path, parameters, options)
89
+ const values = Object.values(parameters).filter(
90
+ (value): value is string => typeof value === 'string',
91
+ )
92
+ const expanded = await expandSelfValues(path, values, context)
93
+ if (expanded.parameters === values) {
94
+ return expanded.meta === undefined
95
+ ? { path: expanded.path, parameters }
96
+ : { path: expanded.path, parameters, meta: expanded.meta }
97
+ }
98
+ let index = 0
99
+ const entries = Object.entries(parameters).map(([key, value]) => [
100
+ key,
101
+ typeof value === 'string' ? expanded.parameters[index++] : value,
102
+ ])
103
+ const resolved = Object.freeze(Object.fromEntries(entries))
104
+ return expanded.meta === undefined
105
+ ? { path: expanded.path, parameters: resolved }
106
+ : { path: expanded.path, parameters: resolved, meta: expanded.meta }
89
107
  }
90
108
 
91
109
  async function expandSelfValues(
92
110
  path: string,
93
111
  parameters: readonly string[],
94
- options: KernelCommandOpts,
112
+ context: ConnectionContext,
95
113
  ): Promise<{
96
114
  readonly path: string
97
115
  readonly parameters: readonly string[]
@@ -100,7 +118,7 @@ async function expandSelfValues(
100
118
  if (!containsSelfRef(path) && !parameters.some(containsSelfRef)) {
101
119
  return { path, parameters }
102
120
  }
103
- const self = await resolveSelfIdAuthenticated(options)
121
+ const self = await resolveSelfIdAuthenticated(context)
104
122
  const expandedPath = expandSelfReferences(path, self.id)
105
123
  const expandedParameters = parameters.map((parameter) => expandSelfReferences(parameter, self.id))
106
124
  const changed =