@astrale-os/cli 0.8.0-alpha.0 → 0.8.1-alpha.2

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 (317) hide show
  1. package/README.md +4 -1
  2. package/dist/astrale.js +62968 -41240
  3. package/dist/public/connect-core.js +55030 -0
  4. package/dist/public/keys/index.js +45631 -0
  5. package/dist/public/paths/index.js +43990 -0
  6. package/dist/types/admin/instance/model.d.ts +40 -0
  7. package/dist/types/connect-core.d.ts +22 -0
  8. package/dist/types/connection/auth.d.ts +33 -0
  9. package/dist/types/errors.d.ts +23 -0
  10. package/dist/types/identity/registry.d.ts +25 -0
  11. package/dist/types/keys/algorithm.d.ts +6 -0
  12. package/dist/types/keys/credential.d.ts +21 -0
  13. package/dist/types/keys/index.d.ts +4 -0
  14. package/dist/types/keys/pair.d.ts +34 -0
  15. package/dist/types/lib/admin-target.d.ts +74 -0
  16. package/dist/types/lib/ca-fetch.d.ts +2 -0
  17. package/dist/types/lib/config.d.ts +71 -0
  18. package/dist/types/lib/format.d.ts +1 -0
  19. package/dist/types/lib/idp-session.d.ts +33 -0
  20. package/dist/types/lib/idp.d.ts +397 -0
  21. package/dist/types/lib/instance-target.d.ts +36 -0
  22. package/dist/types/lib/instance.d.ts +186 -0
  23. package/dist/types/lib/log.d.ts +30 -0
  24. package/dist/types/lib/login-flow.d.ts +49 -0
  25. package/dist/types/lib/meta.d.ts +36 -0
  26. package/dist/types/lib/output.d.ts +83 -0
  27. package/dist/types/lib/table.d.ts +18 -0
  28. package/dist/types/lib/validation.d.ts +11 -0
  29. package/dist/types/paths/index.d.ts +2 -0
  30. package/dist/types/state/exchange-credentials.d.ts +25 -0
  31. package/dist/types/state/files.d.ts +9 -0
  32. package/dist/types/state/identities.d.ts +42 -0
  33. package/dist/types/state/index.d.ts +8 -0
  34. package/dist/types/state/paths.d.ts +32 -0
  35. package/package.json +30 -8
  36. package/src/admin/.spec/api.d.ts +3 -0
  37. package/src/admin/.spec/architecture.md +15 -0
  38. package/src/admin/.spec/icon.svg +3 -0
  39. package/src/admin/.spec/layout.ts +6 -0
  40. package/src/admin/catalog/.spec/api.d.ts +65 -0
  41. package/src/admin/catalog/.spec/architecture.md +6 -0
  42. package/src/admin/catalog/.spec/icon.svg +3 -0
  43. package/src/admin/catalog/.spec/layout.ts +6 -0
  44. package/src/admin/catalog/__tests__/client.test.ts +171 -0
  45. package/src/admin/catalog/client.ts +214 -0
  46. package/src/admin/catalog/index.ts +13 -0
  47. package/src/admin/catalog/model.ts +42 -0
  48. package/src/admin/catalog/tsconfig.json +8 -0
  49. package/src/admin/graph/.spec/api.d.ts +28 -0
  50. package/src/admin/graph/.spec/architecture.md +5 -0
  51. package/src/admin/graph/.spec/icon.svg +3 -0
  52. package/src/admin/graph/.spec/layout.ts +3 -0
  53. package/src/admin/graph/index.ts +6 -0
  54. package/src/admin/graph/nodes.ts +56 -0
  55. package/src/admin/index.ts +2 -0
  56. package/src/admin/instance/.spec/api.d.ts +66 -0
  57. package/src/admin/instance/.spec/architecture.md +10 -0
  58. package/src/admin/instance/.spec/icon.svg +3 -0
  59. package/src/admin/instance/.spec/layout.ts +6 -0
  60. package/src/admin/instance/__tests__/client.test.ts +289 -0
  61. package/src/admin/instance/client.ts +298 -0
  62. package/src/admin/instance/index.ts +16 -0
  63. package/src/admin/instance/model.ts +65 -0
  64. package/src/admin/instance/tsconfig.json +8 -0
  65. package/src/commands/__tests__/admin-instance.test.ts +3 -36
  66. package/src/commands/__tests__/call.test.ts +21 -68
  67. package/src/commands/__tests__/domain-install-owned.test.ts +26 -27
  68. package/src/commands/__tests__/domain-list.test.ts +2 -6
  69. package/src/commands/__tests__/logs.test.ts +50 -98
  70. package/src/commands/__tests__/ls.test.ts +21 -17
  71. package/src/commands/__tests__/read-commands.test.ts +171 -101
  72. package/src/commands/__tests__/view.test.ts +100 -51
  73. package/src/commands/admin/status.ts +3 -3
  74. package/src/commands/admin/use.ts +29 -6
  75. package/src/commands/auth/login.ts +1 -1
  76. package/src/commands/auth/logout.ts +4 -2
  77. package/src/commands/auth/status.ts +2 -2
  78. package/src/commands/auth/token.ts +2 -2
  79. package/src/commands/browser.ts +1 -1
  80. package/src/commands/call.ts +55 -91
  81. package/src/commands/describe.ts +52 -147
  82. package/src/commands/domain/install.ts +81 -50
  83. package/src/commands/domain/list.ts +4 -8
  84. package/src/commands/domain/publish.ts +9 -31
  85. package/src/commands/get.ts +32 -65
  86. package/src/commands/identity/__tests__/register.test.ts +93 -0
  87. package/src/commands/identity/create.ts +2 -2
  88. package/src/commands/identity/delete.ts +2 -2
  89. package/src/commands/identity/export.ts +7 -33
  90. package/src/commands/identity/import.ts +21 -70
  91. package/src/commands/identity/list.ts +2 -2
  92. package/src/commands/identity/register.ts +148 -117
  93. package/src/commands/identity/sync.ts +2 -2
  94. package/src/commands/identity/unsync.ts +2 -2
  95. package/src/commands/identity/use.ts +2 -2
  96. package/src/commands/identity/whoami.ts +2 -2
  97. package/src/commands/idp/add.ts +1 -1
  98. package/src/commands/idp/list.ts +1 -1
  99. package/src/commands/idp/refresh.ts +1 -1
  100. package/src/commands/idp/remove.ts +2 -2
  101. package/src/commands/idp/show.ts +1 -1
  102. package/src/commands/instance/active.ts +2 -2
  103. package/src/commands/instance/bookmark.ts +8 -2
  104. package/src/commands/instance/create.ts +1 -1
  105. package/src/commands/instance/delete.ts +4 -10
  106. package/src/commands/instance/forget.ts +1 -1
  107. package/src/commands/instance/list.ts +3 -3
  108. package/src/commands/instance/status.ts +5 -7
  109. package/src/commands/instance/use.ts +3 -3
  110. package/src/commands/logs.ts +152 -279
  111. package/src/commands/ls.ts +78 -204
  112. package/src/commands/mutate.ts +70 -139
  113. package/src/commands/query.ts +100 -278
  114. package/src/commands/session/analyze.ts +1 -1
  115. package/src/commands/session/list.ts +1 -1
  116. package/src/commands/setup.ts +1 -1
  117. package/src/commands/status.ts +1 -1
  118. package/src/commands/studio.ts +1 -1
  119. package/src/commands/token.ts +26 -21
  120. package/src/commands/update.ts +1 -1
  121. package/src/commands/use.ts +2 -3
  122. package/src/commands/view-serve.ts +1 -1
  123. package/src/commands/view.ts +67 -109
  124. package/src/connect-core.test.ts +38 -0
  125. package/src/connect-core.ts +42 -0
  126. package/src/connection/.spec/api.d.ts +111 -0
  127. package/src/connection/.spec/architecture.md +41 -0
  128. package/src/connection/.spec/capabilities/connection.ts +13 -0
  129. package/src/connection/.spec/examples/call.ts +7 -0
  130. package/src/connection/.spec/flows/command.ts +20 -0
  131. package/src/connection/.spec/flows/session.ts +61 -0
  132. package/src/connection/.spec/laws/connection.ts +181 -0
  133. package/src/connection/.spec/layout.ts +19 -0
  134. package/src/{kernel → connection}/__tests__/auth.test.ts +26 -2
  135. package/src/connection/__tests__/ca-fetch.test.ts +53 -0
  136. package/src/connection/__tests__/call.test.ts +17 -0
  137. package/src/connection/__tests__/credential.test.ts +109 -0
  138. package/src/connection/__tests__/errors.test.ts +96 -0
  139. package/src/connection/__tests__/exchange.test.ts +224 -0
  140. package/src/connection/__tests__/fixtures/localhost-cert.pem +19 -0
  141. package/src/connection/__tests__/fixtures/localhost-key.base64 +1 -0
  142. package/src/connection/__tests__/managed.test.ts +39 -0
  143. package/src/connection/__tests__/self.test.ts +51 -0
  144. package/src/connection/__tests__/session.test.ts +140 -0
  145. package/src/connection/__tests__/target.test.ts +93 -0
  146. package/src/{kernel → connection}/auth.ts +8 -8
  147. package/src/connection/call.ts +7 -0
  148. package/src/{kernel/run.ts → connection/command.ts} +22 -13
  149. package/src/connection/credential.ts +114 -0
  150. package/src/{kernel → connection}/errors.ts +32 -9
  151. package/src/connection/exchange.ts +274 -0
  152. package/src/connection/index.ts +8 -0
  153. package/src/connection/self.ts +120 -0
  154. package/src/connection/session.ts +176 -0
  155. package/src/connection/target.ts +111 -0
  156. package/src/connection/tsconfig.json +6 -0
  157. package/src/graph/.spec/api.d.ts +34 -0
  158. package/src/graph/.spec/laws/documents.ts +24 -0
  159. package/src/graph/.spec/laws/projection.ts +13 -0
  160. package/src/graph/.spec/layout.ts +6 -0
  161. package/src/graph/__tests__/mutation.test.ts +43 -0
  162. package/src/graph/__tests__/projection.test.ts +22 -0
  163. package/src/graph/__tests__/query.test.ts +154 -0
  164. package/src/graph/index.ts +3 -0
  165. package/src/graph/mutation.ts +18 -0
  166. package/src/graph/projection.ts +21 -0
  167. package/src/graph/query.ts +108 -0
  168. package/src/graph/tsconfig.json +6 -0
  169. package/src/identity/.history/ard/bootstrap-root-transfer.md +57 -0
  170. package/src/identity/.history/ard/domain-mediated-registration.md +36 -0
  171. package/src/identity/.spec/api.d.ts +124 -0
  172. package/src/identity/.spec/architecture.md +33 -0
  173. package/src/identity/.spec/capabilities/identity.ts +7 -0
  174. package/src/identity/.spec/flows/bootstrap-root.ts +79 -0
  175. package/src/identity/.spec/flows/domain-mediated-registration.ts +51 -0
  176. package/src/identity/.spec/flows/import.ts +29 -0
  177. package/src/identity/.spec/laws/identity.ts +56 -0
  178. package/src/identity/.spec/layout.ts +13 -0
  179. package/src/identity/.spec/schemas/identity-export-v1.schema.json +25 -0
  180. package/src/identity/__tests__/fixtures/registry-journey.ts +53 -0
  181. package/src/identity/__tests__/registration.test.ts +64 -0
  182. package/src/identity/__tests__/registry.test.ts +70 -0
  183. package/src/identity/__tests__/transfer.test.ts +198 -0
  184. package/src/identity/index.ts +23 -0
  185. package/src/identity/registration.ts +72 -0
  186. package/src/identity/registry.ts +172 -0
  187. package/src/identity/transfer.ts +187 -0
  188. package/src/identity/tsconfig.json +6 -0
  189. package/src/index.ts +1 -0
  190. package/src/keys/.spec/api.d.ts +74 -0
  191. package/src/keys/.spec/architecture.md +13 -0
  192. package/src/keys/.spec/laws/keys.ts +43 -0
  193. package/src/keys/.spec/layout.ts +6 -0
  194. package/src/keys/__tests__/algorithm.test.ts +39 -0
  195. package/src/keys/__tests__/keys.test.ts +168 -0
  196. package/src/keys/algorithm.ts +33 -0
  197. package/src/keys/credential.ts +112 -0
  198. package/src/keys/index.ts +14 -0
  199. package/src/keys/pair.ts +219 -0
  200. package/src/keys/tsconfig.json +6 -0
  201. package/src/lib/__tests__/admin-target.test.ts +67 -7
  202. package/src/lib/__tests__/binary.test.ts +2 -3
  203. package/src/lib/__tests__/command-dx.test.ts +2 -2
  204. package/src/lib/__tests__/config.test.ts +3 -2
  205. package/src/lib/__tests__/idp.test.ts +4 -6
  206. package/src/lib/__tests__/instance-target.test.ts +7 -4
  207. package/src/lib/__tests__/local-status.test.ts +1 -1
  208. package/src/lib/__tests__/log.test.ts +31 -0
  209. package/src/lib/__tests__/meta.test.ts +55 -0
  210. package/src/lib/__tests__/sdk-deps.test.ts +1 -1
  211. package/src/lib/__tests__/self.test.ts +8 -230
  212. package/src/lib/__tests__/use-target.test.ts +1 -1
  213. package/src/lib/__tests__/view-open-intent.test.ts +78 -104
  214. package/src/lib/__tests__/view-session.test.ts +99 -0
  215. package/src/lib/admin-domain.ts +39 -25
  216. package/src/lib/admin-instance.ts +38 -43
  217. package/src/lib/admin-target.ts +67 -13
  218. package/src/lib/binary.ts +13 -34
  219. package/src/lib/browser.ts +1 -1
  220. package/src/{kernel → lib}/ca-fetch.ts +35 -27
  221. package/src/lib/config.ts +1 -1
  222. package/src/lib/idp-session.ts +1 -1
  223. package/src/lib/idp.ts +3 -8
  224. package/src/lib/instance-target.ts +12 -8
  225. package/src/lib/instance.ts +34 -2
  226. package/src/lib/local-status.ts +2 -2
  227. package/src/lib/log.ts +3 -1
  228. package/src/lib/login-flow.ts +32 -5
  229. package/src/lib/meta.ts +15 -11
  230. package/src/lib/provision-instance.ts +4 -12
  231. package/src/lib/self.ts +5 -147
  232. package/src/lib/update.ts +1 -1
  233. package/src/lib/use-target.ts +1 -1
  234. package/src/lib/validation.ts +2 -2
  235. package/src/lib/view/open-intent.ts +7 -37
  236. package/src/lib/view/port-allocation.ts +1 -1
  237. package/src/lib/view/resolve.ts +52 -45
  238. package/src/lib/view/server.ts +16 -33
  239. package/src/lib/view/session.ts +51 -22
  240. package/src/paths/.spec/api.d.ts +13 -0
  241. package/src/paths/.spec/architecture.md +5 -0
  242. package/src/paths/.spec/layout.ts +3 -0
  243. package/src/paths/index.ts +13 -0
  244. package/src/program/.spec/api.d.ts +42 -0
  245. package/src/program/.spec/architecture.md +18 -0
  246. package/src/program/.spec/laws/program.ts +29 -0
  247. package/src/program/.spec/layout.ts +14 -0
  248. package/src/program/__tests__/program.test.ts +359 -0
  249. package/src/program/build.ts +190 -0
  250. package/src/program/command.ts +42 -0
  251. package/src/program/index.ts +2 -0
  252. package/src/program/options.ts +40 -0
  253. package/src/{registry.ts → program/registry.ts} +5 -1
  254. package/src/program/tsconfig.json +6 -0
  255. package/src/setup/steps/admin.ts +18 -3
  256. package/src/setup/steps/instance.ts +1 -1
  257. package/src/state/.spec/api.d.ts +133 -0
  258. package/src/state/.spec/architecture.md +31 -0
  259. package/src/state/.spec/capabilities/state.ts +7 -0
  260. package/src/state/.spec/flows/identity-update.ts +22 -0
  261. package/src/state/.spec/laws/state.ts +73 -0
  262. package/src/state/.spec/layout.ts +14 -0
  263. package/src/state/__tests__/exchange-credentials.test.ts +188 -0
  264. package/src/state/__tests__/files.test.ts +113 -0
  265. package/src/state/__tests__/fixtures/identity-transition.ts +37 -0
  266. package/src/state/__tests__/identities.test.ts +142 -0
  267. package/src/state/__tests__/paths.test.ts +27 -0
  268. package/src/state/exchange-credentials.ts +219 -0
  269. package/src/state/files.ts +129 -0
  270. package/src/state/identities.ts +236 -0
  271. package/src/state/index.ts +29 -0
  272. package/src/state/paths.ts +61 -0
  273. package/src/state/tsconfig.json +6 -0
  274. package/src/telemetry/__tests__/redact.test.ts +3 -3
  275. package/src/telemetry/__tests__/trigger.test.ts +1 -1
  276. package/src/telemetry/settings.ts +1 -1
  277. package/src/telemetry/store.ts +1 -1
  278. package/src/test-utils.ts +1 -1
  279. package/studio/client/dist/assets/elk-api-D0cBetPW.js +1 -0
  280. package/studio/client/dist/assets/elk-worker.min-C9JGDOE-.js +6312 -0
  281. package/studio/client/dist/assets/index-BQnJ5sgd.css +1 -0
  282. package/studio/client/dist/assets/index-ChOr3yP0.css +1 -0
  283. package/studio/client/dist/assets/index-Dspir4w7.js +81 -0
  284. package/studio/client/dist/assets/index-bVD2KJgz.js +8 -0
  285. package/studio/client/dist/index.html +2 -2
  286. package/studio/package.json +10 -1
  287. package/studio/server/introspect/extractor.ts +1 -1
  288. package/studio/server/state/views.test.ts +3 -7
  289. package/studio/server/state/views.ts +23 -30
  290. package/studio/tsconfig.json +23 -0
  291. package/tsconfig.json +1 -1
  292. package/viewer/dist/main.js +65 -39
  293. package/viewer/tsconfig.json +13 -0
  294. package/src/command.ts +0 -42
  295. package/src/commands/__tests__/help-contract.test.ts +0 -164
  296. package/src/kernel/__tests__/client-owned-lookup.test.ts +0 -51
  297. package/src/kernel/__tests__/errors.test.ts +0 -43
  298. package/src/kernel/__tests__/expand.test.ts +0 -123
  299. package/src/kernel/client.ts +0 -214
  300. package/src/kernel/expand.ts +0 -192
  301. package/src/kernel/graph.ts +0 -96
  302. package/src/kernel/index.ts +0 -29
  303. package/src/kernel/options.ts +0 -22
  304. package/src/kernel/types.ts +0 -14
  305. package/src/lib/__tests__/domain-identity.test.ts +0 -60
  306. package/src/lib/__tests__/fs-atomic.test.ts +0 -104
  307. package/src/lib/__tests__/identity.test.ts +0 -79
  308. package/src/lib/__tests__/keys.test.ts +0 -129
  309. package/src/lib/domain-identity.ts +0 -49
  310. package/src/lib/env.ts +0 -49
  311. package/src/lib/fs-atomic.ts +0 -126
  312. package/src/lib/identity.ts +0 -256
  313. package/src/lib/keys.ts +0 -294
  314. package/src/lib/paths.ts +0 -11
  315. package/src/program.ts +0 -213
  316. package/studio/client/dist/assets/index-BaqEuIQJ.js +0 -109
  317. package/studio/client/dist/assets/index-jRdExahh.css +0 -1
@@ -1,29 +1,43 @@
1
- /**
2
- * The admin `DomainEntry` surface used by `astrale domain publish`. The merged
3
- * admin domain models the installable-domain REGISTRY as the `DomainEntry`
4
- * class (named `DomainEntry`, not `Domain`, because `Domain` is a reserved
5
- * kernel node-kind); `publish` upserts a `name → url` catalog entry the child
6
- * kernel later installs from. Publishing only makes a domain INSTALLABLE —
7
- * mounting it on an instance is the separate `domain install` step (or the
8
- * admin's install-by-default policy).
9
- */
10
- export const ADMIN_DOMAIN = '/:admin.astrale.ai:class.DomainEntry'
1
+ import type { AdminConnectionOptions, ConnectionContext } from '../connection'
11
2
 
12
- export function adminDomainMethod(method: 'info' | 'install' | 'list' | 'publish'): string {
13
- return `${ADMIN_DOMAIN}:${method}`
3
+ import { connectAdminCatalog, type DomainInfo, type PublishDomainInput } from '../admin/catalog'
4
+ import { connectAdminInstances, type OwnedInstanceInfo } from '../admin/instance'
5
+ import { withAdminClientSession } from '../connection'
6
+
7
+ export type { DomainInfo, InstallDomainResult, PublishDomainInput } from '../admin/catalog'
8
+
9
+ /** Read the caller-visible V2 Admin Domain catalog. */
10
+ export function listAdminDomains(options: AdminConnectionOptions): Promise<DomainInfo[]> {
11
+ return withAdminClientSession(options, async (context) =>
12
+ (await connectAdminCatalog(context)).list(),
13
+ )
14
+ }
15
+
16
+ /** Reuse one open Admin session for catalog reads. */
17
+ export async function listAdminDomainsInContext(context: ConnectionContext): Promise<DomainInfo[]> {
18
+ return (await connectAdminCatalog(context)).list()
19
+ }
20
+
21
+ /** Publish and optionally configure default installation through V2 receiver Methods. */
22
+ export function publishAdminDomain(options: AdminConnectionOptions, input: PublishDomainInput) {
23
+ return withAdminClientSession(options, async (context) =>
24
+ (await connectAdminCatalog(context)).publish(input),
25
+ )
14
26
  }
15
27
 
16
- /** Read shape returned by `DomainEntry.publish` / `info` / `list` (domain `DomainInfoSchema`). */
17
- export type DomainInfo = {
18
- id: string
19
- /** shell.astrale.ai — the authority origin (== JWT aud + kernel path prefix). */
20
- origin: string
21
- /** 'shell' — the node slug + the id used in install plans / the CLI. */
22
- name: string
23
- /** https://shell.astrale.ai — the published worker URL the kernel installs from. */
24
- url?: string
25
- description?: string
26
- installByDefault?: boolean
27
- createdAt: string
28
- updatedAt: string
28
+ /** Install one resolved catalog Domain on one caller-visible Instance. */
29
+ export async function installAdminDomainInContext(
30
+ context: ConnectionContext,
31
+ instance: OwnedInstanceInfo,
32
+ domain: DomainInfo,
33
+ ) {
34
+ const receipt = await (await connectAdminInstances(context)).installDomain(instance.id, domain.id)
35
+ return Object.freeze({
36
+ name: domain.name,
37
+ origin: receipt.origin,
38
+ instanceId: instance.slug,
39
+ url: domain.url ?? '',
40
+ ok: receipt.ok,
41
+ ...(receipt.error === undefined ? {} : { error: receipt.error }),
42
+ })
29
43
  }
@@ -1,55 +1,50 @@
1
- /**
2
- * The admin `Instance` surface used by `astrale instance
3
- * list/status/create/delete`. The merged admin domain models instances as the
4
- * `Instance` class (provisioned via `Instance.init`); these commands target it.
5
- */
6
- export const ADMIN_INSTANCE = '/:admin.astrale.ai:class.Instance'
1
+ import type { AdminConnectionOptions, ConnectionContext } from '../connection'
7
2
 
8
- export function adminInstanceMethod(
9
- method: 'alphaCreate' | 'delete' | 'info' | 'list' | 'listMine',
10
- ): string {
11
- return `${ADMIN_INSTANCE}:${method}`
12
- }
3
+ import { connectAdminInstances } from '../admin/instance'
4
+ import { withAdminClientSession } from '../connection'
13
5
 
14
- export type InstanceState = 'provisioning' | 'ready' | 'failed'
6
+ export {
7
+ AdminInstanceNotFoundError,
8
+ findOwnedInstance,
9
+ formatInstanceLocation,
10
+ type InstanceInfo,
11
+ type InstanceState,
12
+ type OwnedInstanceInfo,
13
+ } from '../admin/instance'
15
14
 
16
- /** Read shape returned by `Instance.list` / `info` / `delete` (domain `InstanceInfoSchema`). */
17
- export type InstanceInfo = {
18
- id: string
19
- slug: string
20
- url: string
21
- hostId?: string
22
- region?: string
23
- state?: InstanceState
24
- phase?: string
25
- error?: string | null
26
- createdAt?: string
27
- organizationId?: string
15
+ /** Resolve the Admin target and read only the caller-visible Instance inventory. */
16
+ export function listOwnedInstances(options: AdminConnectionOptions) {
17
+ return withAdminClientSession(options, async (context) =>
18
+ (await connectAdminInstances(context)).list(),
19
+ )
28
20
  }
29
21
 
30
- /** Owner-scoped read shape returned by `Instance.listMine`. */
31
- export type OwnedInstanceInfo = InstanceInfo & {
32
- state: InstanceState
22
+ /** Reuse an already-open Admin session for a caller-visible Instance inventory. */
23
+ export async function listOwnedInstancesInContext(context: ConnectionContext) {
24
+ return (await connectAdminInstances(context)).list()
33
25
  }
34
26
 
35
- /** Call the owner-scoped list contract through any admin client-shaped object. */
36
- export async function callOwnedInstances(client: {
37
- call: (path: string, params: Record<string, never>) => Promise<unknown>
38
- }): Promise<OwnedInstanceInfo[]> {
39
- return (await client.call(adminInstanceMethod('listMine'), {})) as OwnedInstanceInfo[]
27
+ /** Provision through Fleet placement or one explicitly resolved Host receiver. */
28
+ export function createOwnedInstance(
29
+ options: AdminConnectionOptions,
30
+ slug: string,
31
+ hostId?: string,
32
+ ) {
33
+ return withAdminClientSession(options, async (context) =>
34
+ (await connectAdminInstances(context)).create(slug, hostId),
35
+ )
40
36
  }
41
37
 
42
- /** Match an owner-scoped instance by its stable node id or human slug. */
43
- export function findOwnedInstance(
44
- instances: readonly OwnedInstanceInfo[],
45
- identifier: string,
46
- ): OwnedInstanceInfo | undefined {
47
- return instances.find((instance) => instance.id === identifier || instance.slug === identifier)
38
+ /** Refresh one exact caller-visible Instance through its V2 receiver Method. */
39
+ export function statusOwnedInstance(options: AdminConnectionOptions, identifier: string) {
40
+ return withAdminClientSession(options, async (context) =>
41
+ (await connectAdminInstances(context)).status(identifier),
42
+ )
48
43
  }
49
44
 
50
- /** Human-readable location of a managed instance ("region · hostId"). */
51
- export function formatInstanceLocation(info: InstanceInfo): string {
52
- return [info.state && info.state !== 'ready' ? info.state : undefined, info.region, info.hostId]
53
- .filter(Boolean)
54
- .join(' · ')
45
+ /** Delete one exact caller-visible Instance through its V2 receiver Method. */
46
+ export function deleteOwnedInstance(options: AdminConnectionOptions, identifier: string) {
47
+ return withAdminClientSession(options, async (context) =>
48
+ (await connectAdminInstances(context)).delete(identifier),
49
+ )
55
50
  }
@@ -9,11 +9,13 @@ import { isHttpUrl } from './validation'
9
9
 
10
10
  export const DEFAULT_ADMIN_TARGET_NAME = 'admin'
11
11
  export const DEFAULT_ADMIN_TARGET_URL = 'https://admin.eu.astrale.ai/api'
12
+ export const DEFAULT_ADMIN_DOMAIN_ISSUER = 'https://admin.beta.astrale.ai'
12
13
 
13
14
  export const DEFAULT_ADMIN_TARGET_CONFIG = {
14
15
  name: DEFAULT_ADMIN_TARGET_NAME,
15
16
  url: DEFAULT_ADMIN_TARGET_URL,
16
- issuer: DEFAULT_ADMIN_TARGET_URL,
17
+ kernelIssuer: DEFAULT_ADMIN_TARGET_URL,
18
+ domainIssuer: DEFAULT_ADMIN_DOMAIN_ISSUER,
17
19
  } satisfies AdminTargetConfig
18
20
 
19
21
  const HttpUrlSchema = z.string().refine(isHttpUrl, {
@@ -27,7 +29,9 @@ export const AdminTargetConfigSchema = z
27
29
  /** Direct admin kernel URL. */
28
30
  url: HttpUrlSchema.optional(),
29
31
  /** Kernel issuer / JWT audience when different from url. */
30
- issuer: HttpUrlSchema.optional(),
32
+ kernelIssuer: HttpUrlSchema.optional(),
33
+ /** Exact native Admin Domain issuer used by the standard token exchange. */
34
+ domainIssuer: HttpUrlSchema.optional(),
31
35
  /** Bookmark name for the admin kernel. */
32
36
  instance: z.string().min(1).optional(),
33
37
  })
@@ -45,11 +49,18 @@ export const AdminTargetConfigSchema = z
45
49
  message: 'admin target requires url or instance',
46
50
  })
47
51
  }
48
- if (value.issuer && !value.url) {
52
+ if (value.kernelIssuer && !value.url) {
49
53
  ctx.addIssue({
50
54
  code: 'custom',
51
- path: ['issuer'],
52
- message: 'admin issuer is only valid with a direct url target',
55
+ path: ['kernelIssuer'],
56
+ message: 'admin kernel issuer is only valid with a direct url target',
57
+ })
58
+ }
59
+ if (value.domainIssuer && !value.url) {
60
+ ctx.addIssue({
61
+ code: 'custom',
62
+ path: ['domainIssuer'],
63
+ message: 'admin domain issuer is only valid with a direct url target',
53
64
  })
54
65
  }
55
66
  })
@@ -59,6 +70,7 @@ export type AdminTargetConfig = z.infer<typeof AdminTargetConfigSchema>
59
70
  export type AdminTargetCommandOpts = {
60
71
  admin?: string
61
72
  adminUrl?: string
73
+ domainIssuer?: string
62
74
  instance?: string
63
75
  url?: string
64
76
  }
@@ -68,7 +80,8 @@ export type AdminTargetSource = 'admin-url' | 'admin' | 'config-instance' | 'con
68
80
  export type ResolvedAdminTarget = {
69
81
  name: string
70
82
  url: string
71
- issuer: string
83
+ kernelIssuer: string
84
+ domainIssuer: string
72
85
  defaultIdentity?: string
73
86
  caFile?: string
74
87
  source: AdminTargetSource
@@ -85,6 +98,10 @@ export const ADMIN_TARGET_OPTIONS = [
85
98
  flags: '--admin-url <url>',
86
99
  description: 'Admin kernel URL to use for this admin operation',
87
100
  },
101
+ {
102
+ flags: '--domain-issuer <url>',
103
+ description: 'Admin Domain issuer used for token exchange with an explicit URL',
104
+ },
88
105
  ]
89
106
 
90
107
  export async function resolveAdminTarget(
@@ -102,29 +119,50 @@ export function resolveAdminTargetFromStore(
102
119
  ): ResolvedAdminTarget {
103
120
  const override = readOverride(opts)
104
121
  if (override) {
122
+ if (override.kind === 'instance' && opts.domainIssuer !== undefined) {
123
+ throw new AstraleError(
124
+ 'INVALID_FLAG',
125
+ '--domain-issuer is only valid with --admin-url or --url.',
126
+ )
127
+ }
105
128
  return override.kind === 'url'
106
129
  ? directTarget({
107
130
  url: override.url,
108
131
  name: DEFAULT_ADMIN_TARGET_NAME,
109
132
  source: override.source,
110
133
  configured: false,
134
+ domainIssuer: opts.domainIssuer ?? config.admin.domainIssuer,
111
135
  })
112
- : bookmarkTarget(store, override.instance, override.source, false)
136
+ : bookmarkTarget(
137
+ store,
138
+ override.instance,
139
+ override.source,
140
+ false,
141
+ config.admin.domainIssuer ?? DEFAULT_ADMIN_DOMAIN_ISSUER,
142
+ )
113
143
  }
114
144
 
115
145
  const admin = config.admin
116
146
  if (admin.instance) {
117
- return bookmarkTarget(store, admin.instance, 'config-instance', true)
147
+ return bookmarkTarget(
148
+ store,
149
+ admin.instance,
150
+ 'config-instance',
151
+ true,
152
+ admin.domainIssuer ?? DEFAULT_ADMIN_DOMAIN_ISSUER,
153
+ )
118
154
  }
119
155
 
120
156
  const isDefaultDirectTarget =
121
157
  admin.url === DEFAULT_ADMIN_TARGET_URL &&
122
- admin.issuer === DEFAULT_ADMIN_TARGET_URL &&
158
+ admin.kernelIssuer === DEFAULT_ADMIN_TARGET_URL &&
159
+ (admin.domainIssuer ?? DEFAULT_ADMIN_DOMAIN_ISSUER) === DEFAULT_ADMIN_DOMAIN_ISSUER &&
123
160
  admin.name === DEFAULT_ADMIN_TARGET_NAME
124
161
 
125
162
  return directTarget({
126
163
  url: admin.url ?? DEFAULT_ADMIN_TARGET_URL,
127
- issuer: admin.issuer,
164
+ kernelIssuer: admin.kernelIssuer,
165
+ domainIssuer: admin.domainIssuer ?? DEFAULT_ADMIN_DOMAIN_ISSUER,
128
166
  name: admin.name ?? DEFAULT_ADMIN_TARGET_NAME,
129
167
  source: isDefaultDirectTarget ? 'default' : 'config-url',
130
168
  configured: !isDefaultDirectTarget,
@@ -177,6 +215,7 @@ function bookmarkTarget(
177
215
  identifier: string,
178
216
  source: AdminTargetSource,
179
217
  configured: boolean,
218
+ domainIssuer: string,
180
219
  ): ResolvedAdminTarget {
181
220
  const key = resolveInstanceKey(store, identifier)
182
221
  const entry = key ? store.instances[key] : undefined
@@ -191,7 +230,11 @@ function bookmarkTarget(
191
230
  name: key,
192
231
  registrationSlug: key,
193
232
  url: entry.url,
194
- issuer: entry.issuer ?? entry.url,
233
+ kernelIssuer: entry.issuer ?? entry.url,
234
+ domainIssuer: requireDomainIssuer(
235
+ entry.domainIssuer ?? (configured ? domainIssuer : undefined),
236
+ `Admin bookmark "${key}"`,
237
+ ),
195
238
  defaultIdentity: entry.defaultIdentity,
196
239
  ...(entry.caFile ? { caFile: entry.caFile } : {}),
197
240
  source,
@@ -201,7 +244,8 @@ function bookmarkTarget(
201
244
 
202
245
  function directTarget(input: {
203
246
  url: string
204
- issuer?: string
247
+ kernelIssuer?: string
248
+ domainIssuer?: string
205
249
  name: string
206
250
  source: AdminTargetSource
207
251
  configured: boolean
@@ -210,8 +254,18 @@ function directTarget(input: {
210
254
  name: input.name,
211
255
  registrationSlug: input.name,
212
256
  url: input.url,
213
- issuer: input.issuer ?? input.url,
257
+ kernelIssuer: input.kernelIssuer ?? input.url,
258
+ domainIssuer: requireDomainIssuer(input.domainIssuer, 'Direct Admin target'),
214
259
  source: input.source,
215
260
  configured: input.configured,
216
261
  }
217
262
  }
263
+
264
+ function requireDomainIssuer(value: string | undefined, label: string): string {
265
+ if (value !== undefined) return value
266
+ throw new AstraleError(
267
+ 'ADMIN_DOMAIN_ISSUER_MISSING',
268
+ `${label} has no Domain issuer for token exchange.`,
269
+ 'Configure domainIssuer or pass --domain-issuer <url>; there is no legacy token fallback.',
270
+ )
271
+ }
package/src/lib/binary.ts CHANGED
@@ -7,35 +7,14 @@ import { output } from './output'
7
7
 
8
8
  /** A binary kernel result: bytes (or a stream of them) plus its content-type. */
9
9
  export type BinaryLike = {
10
- status: number
11
- contentType: string
12
- body: Uint8Array | ReadableStream<Uint8Array>
10
+ readonly body: Uint8Array
11
+ readonly mediaType: string
12
+ readonly headers?: Readonly<Record<string, string>>
13
13
  }
14
14
 
15
15
  /** Collapse a (possibly streamed) binary body into a single byte array. */
16
- export async function readBinaryBody(
17
- body: Uint8Array | ReadableStream<Uint8Array>,
18
- ): Promise<Uint8Array> {
19
- if (body instanceof Uint8Array) return body
20
-
21
- const chunks: Uint8Array[] = []
22
- const reader = body.getReader()
23
- let total = 0
24
- while (true) {
25
- const { done, value } = await reader.read()
26
- if (done) break
27
- if (!value) continue
28
- chunks.push(value)
29
- total += value.byteLength
30
- }
31
-
32
- const out = new Uint8Array(total)
33
- let offset = 0
34
- for (const chunk of chunks) {
35
- out.set(chunk, offset)
36
- offset += chunk.byteLength
37
- }
38
- return out
16
+ export async function readBinaryBody(body: Uint8Array): Promise<Uint8Array> {
17
+ return body
39
18
  }
40
19
 
41
20
  function isTextLike(contentType: string): boolean {
@@ -62,16 +41,16 @@ function humanSize(bytes: number): string {
62
41
 
63
42
  /** The `--json` envelope: text-like inlines decoded text, otherwise base64. */
64
43
  function jsonEnvelope(resp: BinaryLike, bytes: Uint8Array): Record<string, unknown> {
65
- if (isTextLike(resp.contentType)) {
44
+ if (isTextLike(resp.mediaType)) {
66
45
  return {
67
- status: resp.status,
68
- contentType: resp.contentType,
46
+ status: 200,
47
+ contentType: resp.mediaType,
69
48
  body: new TextDecoder().decode(bytes),
70
49
  }
71
50
  }
72
51
  return {
73
- status: resp.status,
74
- contentType: resp.contentType,
52
+ status: 200,
53
+ contentType: resp.mediaType,
75
54
  bodyBase64: Buffer.from(bytes).toString('base64'),
76
55
  }
77
56
  }
@@ -97,7 +76,7 @@ export async function presentBinary(
97
76
  if (io?.outFile) {
98
77
  await writeFile(io.outFile, bytes)
99
78
  process.stderr.write(
100
- chalk.dim(` wrote ${humanSize(bytes.length)} (${resp.contentType}) → ${io.outFile}\n`),
79
+ chalk.dim(` wrote ${humanSize(bytes.length)} (${resp.mediaType}) → ${io.outFile}\n`),
101
80
  )
102
81
  return
103
82
  }
@@ -117,7 +96,7 @@ export async function presentBinary(
117
96
  return
118
97
  }
119
98
 
120
- if (isTextLike(resp.contentType)) {
99
+ if (isTextLike(resp.mediaType)) {
121
100
  const text = new TextDecoder().decode(bytes)
122
101
  process.stdout.write(text.endsWith('\n') ? text : text + '\n')
123
102
  return
@@ -125,7 +104,7 @@ export async function presentBinary(
125
104
 
126
105
  process.stdout.write(
127
106
  chalk.dim(
128
- ` <binary · ${resp.contentType} · ${humanSize(bytes.length)}> — pipe or use -o <file> to save\n`,
107
+ ` <binary · ${resp.mediaType} · ${humanSize(bytes.length)}> — pipe or use -o <file> to save\n`,
129
108
  ),
130
109
  )
131
110
  }
@@ -1,7 +1,7 @@
1
1
  import { mkdir, readFile, writeFile } from 'node:fs/promises'
2
2
  import { join } from 'node:path'
3
3
 
4
- import { paths } from './env'
4
+ import { paths } from '../state/index'
5
5
  import { run } from './proc'
6
6
 
7
7
  /**
@@ -4,18 +4,19 @@ import { Buffer } from 'node:buffer'
4
4
  import { readFileSync } from 'node:fs'
5
5
  import { request as httpsRequest } from 'node:https'
6
6
 
7
+ /** Create a Fetch capability whose HTTPS requests trust one CLI-selected CA file. */
7
8
  export function fetchWithCaFile(
8
9
  caFile: string,
9
- fallback: typeof fetch = globalThis.fetch,
10
- ): typeof fetch {
10
+ fallback: (input: RequestInfo | URL, init?: RequestInit) => Promise<Response> = globalThis.fetch,
11
+ ): (input: RequestInfo | URL, init?: RequestInit) => Promise<Response> {
11
12
  const ca = readFileSync(caFile)
12
13
  const fallbackFetch = fallback.bind(globalThis)
13
14
 
14
- return (async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {
15
+ return async (input: RequestInfo | URL, init?: RequestInit): Promise<Response> => {
15
16
  const url = requestUrl(input)
16
17
  if (url.protocol !== 'https:') return fallbackFetch(input, init)
17
18
  return fetchWithNode(url, init, ca)
18
- }) as typeof fetch
19
+ }
19
20
  }
20
21
 
21
22
  function requestUrl(input: RequestInfo | URL): URL {
@@ -26,12 +27,11 @@ function requestUrl(input: RequestInfo | URL): URL {
26
27
 
27
28
  function fetchWithNode(url: URL, init: RequestInit | undefined, ca: Buffer): Promise<Response> {
28
29
  return new Promise((resolve, reject) => {
29
- const headers = headersInitToRecord(init?.headers)
30
30
  const request = httpsRequest(
31
31
  url,
32
32
  {
33
33
  method: init?.method ?? 'GET',
34
- headers,
34
+ headers: headersInitToRecord(init?.headers),
35
35
  ca,
36
36
  },
37
37
  (response) => {
@@ -40,26 +40,32 @@ function fetchWithNode(url: URL, init: RequestInit | undefined, ca: Buffer): Pro
40
40
  chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk)),
41
41
  )
42
42
  response.on('end', () => {
43
- resolve(
44
- new Response(Buffer.concat(chunks), {
45
- status: response.statusCode ?? 0,
46
- statusText: response.statusMessage,
47
- headers: responseHeaders(response.headers),
48
- }),
49
- )
43
+ const result = new Response(Buffer.concat(chunks), {
44
+ status: response.statusCode ?? 0,
45
+ statusText: response.statusMessage,
46
+ headers: responseHeaders(response.headers),
47
+ })
48
+ // Synthetic Responses have no URL list. This transport does not follow
49
+ // redirects, so the exact request URL is also the final response URL.
50
+ Object.defineProperty(result, 'url', { value: url.toString() })
51
+ resolve(result)
50
52
  })
51
53
  },
52
54
  )
53
55
 
54
56
  request.on('error', reject)
55
57
  if (init?.signal) {
56
- if (init.signal.aborted)
57
- request.destroy(new DOMException('The operation was aborted.', 'AbortError'))
58
- init.signal.addEventListener(
59
- 'abort',
60
- () => request.destroy(new DOMException('The operation was aborted.', 'AbortError')),
61
- { once: true },
62
- )
58
+ if (init.signal.aborted) {
59
+ request.destroy(abortError(init.signal.reason))
60
+ } else {
61
+ init.signal.addEventListener(
62
+ 'abort',
63
+ () => request.destroy(abortError(init.signal?.reason)),
64
+ {
65
+ once: true,
66
+ },
67
+ )
68
+ }
63
69
  }
64
70
 
65
71
  writeBody(request, init?.body)
@@ -68,16 +74,18 @@ function fetchWithNode(url: URL, init: RequestInit | undefined, ca: Buffer): Pro
68
74
  })
69
75
  }
70
76
 
77
+ function abortError(reason: unknown): Error {
78
+ return reason instanceof Error
79
+ ? reason
80
+ : new DOMException('The operation was aborted.', 'AbortError')
81
+ }
82
+
71
83
  async function writeBody(
72
84
  request: ReturnType<typeof httpRequest>,
73
85
  body: BodyInit | null | undefined,
74
86
  ): Promise<void> {
75
87
  if (body === undefined || body === null) return
76
- if (typeof body === 'string') {
77
- request.write(body)
78
- return
79
- }
80
- if (body instanceof Uint8Array) {
88
+ if (typeof body === 'string' || body instanceof Uint8Array) {
81
89
  request.write(body)
82
90
  return
83
91
  }
@@ -89,7 +97,7 @@ async function writeBody(
89
97
  request.write(Buffer.from(await body.arrayBuffer()))
90
98
  return
91
99
  }
92
- throw new Error(`Unsupported request body type for CA-backed fetch`)
100
+ throw new Error('Unsupported request body type for CA-backed fetch')
93
101
  }
94
102
 
95
103
  function headersInitToRecord(headers: HeadersInit | undefined): Record<string, string> {
@@ -101,7 +109,7 @@ function headersInitToRecord(headers: HeadersInit | undefined): Record<string, s
101
109
  })
102
110
  return out
103
111
  }
104
- if (Array.isArray(headers)) return Object.fromEntries(headers.map(([key, value]) => [key, value]))
112
+ if (Array.isArray(headers)) return Object.fromEntries(headers)
105
113
  return Object.fromEntries(Object.entries(headers).map(([key, value]) => [key, String(value)]))
106
114
  }
107
115
 
package/src/lib/config.ts CHANGED
@@ -2,9 +2,9 @@ import { readFile, writeFile, mkdir } from 'node:fs/promises'
2
2
  import { dirname } from 'node:path'
3
3
  import { z } from 'zod'
4
4
 
5
+ import { CONFIG_PATH } from '../state/index'
5
6
  import { AdminTargetConfigSchema, DEFAULT_ADMIN_TARGET_CONFIG } from './admin-target'
6
7
  import { log } from './log'
7
- import { CONFIG_PATH } from './paths'
8
8
 
9
9
  export const AstraleConfigSchema = z.object({
10
10
  issuer: z.string().url().default('https://unregistered.invalid'),
@@ -1,4 +1,4 @@
1
- import { withFileLock } from './fs-atomic'
1
+ import { withFileLock } from '../state/index'
2
2
  import {
3
3
  accessTokenForAudience,
4
4
  classifyRefreshFailure,
package/src/lib/idp.ts CHANGED
@@ -3,10 +3,8 @@ import { mkdir, readFile, readdir, unlink } from 'node:fs/promises'
3
3
  import { dirname, join } from 'node:path'
4
4
  import { z } from 'zod'
5
5
 
6
- import { paths } from './env'
7
- import { atomicWrite } from './fs-atomic'
6
+ import { atomicWrite, IDPS_PATH, IDP_SESSIONS_DIR, paths } from '../state/index'
8
7
  import { log } from './log'
9
- import { IDPS_PATH, IDP_SESSIONS_DIR } from './paths'
10
8
  import { validateName, validateUrl } from './validation'
11
9
 
12
10
  /**
@@ -214,7 +212,6 @@ export type IdpConfig = {
214
212
 
215
213
  export const BUILTIN_WORKOS_IDP_NAME = 'workos'
216
214
  const DEFAULT_WORKOS_API_HOST = 'https://api.workos.com'
217
- const DEFAULT_WORKOS_CLIENT_ID = 'client_01KC29HEGD7B40TV2C4QZ436BG'
218
215
  const WORKOS_CLIENT_ID_ENV_NAMES = ['WORKOS_CLIENT_ID', 'VITE_WORKOS_CLIENT_ID'] as const
219
216
 
220
217
  export function idpDir(name: string): string {
@@ -414,10 +411,8 @@ export function builtinIdpConfig(
414
411
  }
415
412
 
416
413
  export function workosClientIdFromEnv(env: NodeJS.ProcessEnv = process.env): string | undefined {
417
- return (
418
- WORKOS_CLIENT_ID_ENV_NAMES.map((name) => env[name]).find(
419
- (value): value is string => typeof value === 'string' && value.length > 0,
420
- ) ?? DEFAULT_WORKOS_CLIENT_ID
414
+ return WORKOS_CLIENT_ID_ENV_NAMES.map((name) => env[name]?.trim()).find(
415
+ (value): value is string => typeof value === 'string' && value.length > 0,
421
416
  )
422
417
  }
423
418