@astrale-os/cli 1.0.0-beta.2 → 1.0.0-beta.20

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 (282) hide show
  1. package/README.md +16 -1
  2. package/dist/astrale.js +51105 -58057
  3. package/dist/public/connect-core.js +2085 -30702
  4. package/dist/public/keys/index.js +884 -29476
  5. package/dist/public/paths/index.js +13101 -41452
  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 +7 -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/package.json +15 -20
  40. package/src/__tests__/fixtures/publication.ts +20 -0
  41. package/src/admin/.spec/architecture.md +12 -5
  42. package/src/admin/__tests__/fixture.ts +25 -0
  43. package/src/admin/catalog/.spec/api.d.ts +1 -3
  44. package/src/admin/catalog/.spec/architecture.md +5 -4
  45. package/src/admin/catalog/__tests__/client.test.ts +143 -69
  46. package/src/admin/catalog/client.ts +40 -54
  47. package/src/admin/catalog/model.ts +3 -4
  48. package/src/admin/contract.ts +46 -0
  49. package/src/admin/graph/.spec/api.d.ts +4 -10
  50. package/src/admin/graph/nodes.ts +1 -1
  51. package/src/admin/instance/.spec/api.d.ts +5 -9
  52. package/src/admin/instance/.spec/architecture.md +7 -7
  53. package/src/admin/instance/__tests__/client.test.ts +157 -175
  54. package/src/admin/instance/client.ts +39 -128
  55. package/src/admin/instance/index.ts +1 -2
  56. package/src/admin/instance/model.ts +12 -18
  57. package/src/commands/__tests__/admin-instance.test.ts +11 -8
  58. package/src/commands/__tests__/call-describe.test.ts +46 -33
  59. package/src/commands/__tests__/call.test.ts +34 -0
  60. package/src/commands/__tests__/domain-install-operation.test.ts +7 -22
  61. package/src/commands/__tests__/domain-install-owned.test.ts +1 -1
  62. package/src/commands/__tests__/domain-list.test.ts +5 -25
  63. package/src/commands/__tests__/install-direct.test.ts +115 -8
  64. package/src/commands/__tests__/install-identity-override.test.ts +3 -14
  65. package/src/commands/__tests__/instance-list-rows.test.ts +1 -1
  66. package/src/commands/__tests__/instance-status.test.ts +139 -0
  67. package/src/commands/__tests__/introspect-parse.test.ts +80 -1
  68. package/src/commands/__tests__/logs.test.ts +250 -2
  69. package/src/commands/__tests__/read-commands.test.ts +62 -10
  70. package/src/commands/__tests__/token-ttl.test.ts +49 -4
  71. package/src/commands/__tests__/update.test.ts +25 -3
  72. package/src/commands/__tests__/view.test.ts +49 -0
  73. package/src/commands/call-describe.ts +60 -68
  74. package/src/commands/call.ts +71 -59
  75. package/src/commands/domain/install.ts +54 -35
  76. package/src/commands/domain/list.ts +1 -1
  77. package/src/commands/domain/publish.ts +14 -11
  78. package/src/commands/domain/uninstall.ts +2 -2
  79. package/src/commands/get.ts +14 -15
  80. package/src/commands/identity/__tests__/register.test.ts +3 -3
  81. package/src/commands/identity/register.ts +5 -4
  82. package/src/commands/instance/create.ts +8 -16
  83. package/src/commands/instance/delete.ts +12 -9
  84. package/src/commands/instance/list.ts +2 -2
  85. package/src/commands/instance/status.ts +66 -20
  86. package/src/commands/instance/use.ts +16 -12
  87. package/src/commands/introspect.ts +48 -35
  88. package/src/commands/logs.ts +123 -33
  89. package/src/commands/mutate.ts +6 -5
  90. package/src/commands/query.ts +35 -32
  91. package/src/commands/token.ts +42 -27
  92. package/src/commands/ui/__tests__/commands.test.ts +152 -0
  93. package/src/commands/ui/add.ts +51 -0
  94. package/src/commands/ui/doctor.ts +13 -0
  95. package/src/commands/ui/init.ts +38 -0
  96. package/src/commands/ui/list.ts +26 -0
  97. package/src/commands/ui/preset-apply.ts +19 -0
  98. package/src/commands/ui/preset-list.ts +12 -0
  99. package/src/commands/ui/shared.ts +25 -0
  100. package/src/commands/update.ts +31 -11
  101. package/src/commands/view.ts +82 -37
  102. package/src/connection/.spec/api.d.ts +7 -8
  103. package/src/connection/.spec/architecture.md +5 -4
  104. package/src/connection/.spec/flows/session.ts +2 -2
  105. package/src/connection/.spec/laws/connection.ts +6 -2
  106. package/src/connection/.spec/layout.ts +1 -0
  107. package/src/connection/__tests__/credential.test.ts +20 -1
  108. package/src/connection/__tests__/errors.test.ts +27 -20
  109. package/src/connection/__tests__/exchange.test.ts +30 -1
  110. package/src/connection/__tests__/failure-fixtures.ts +39 -0
  111. package/src/connection/__tests__/failure-safety.test.ts +75 -0
  112. package/src/connection/__tests__/self.test.ts +31 -11
  113. package/src/connection/__tests__/session.test.ts +3 -3
  114. package/src/connection/__tests__/target.test.ts +1 -0
  115. package/src/connection/auth.ts +13 -0
  116. package/src/connection/call.ts +1 -1
  117. package/src/connection/credential.ts +2 -2
  118. package/src/connection/errors.ts +1 -355
  119. package/src/connection/exchange.ts +47 -23
  120. package/src/connection/failure/classify.ts +110 -0
  121. package/src/connection/failure/index.ts +18 -0
  122. package/src/connection/failure/model.ts +28 -0
  123. package/src/connection/failure/render.ts +116 -0
  124. package/src/connection/reasons.ts +16 -0
  125. package/src/connection/self.ts +39 -21
  126. package/src/connection/session.ts +19 -8
  127. package/src/errors.ts +3 -2
  128. package/src/graph/.spec/api.d.ts +12 -5
  129. package/src/graph/.spec/layout.ts +9 -1
  130. package/src/graph/__tests__/mutation.test.ts +2 -2
  131. package/src/graph/__tests__/query.test.ts +25 -6
  132. package/src/graph/class.ts +30 -0
  133. package/src/graph/index.ts +1 -0
  134. package/src/graph/query.ts +21 -32
  135. package/src/identity/.spec/api.d.ts +2 -2
  136. package/src/identity/__tests__/registration.test.ts +1 -1
  137. package/src/identity/registration.ts +3 -3
  138. package/src/keys/__tests__/keys.test.ts +4 -0
  139. package/src/keys/credential.ts +1 -0
  140. package/src/lib/__tests__/admin-target.test.ts +12 -0
  141. package/src/lib/__tests__/binary.test.ts +16 -1
  142. package/src/lib/__tests__/command-dx.test.ts +1 -1
  143. package/src/lib/__tests__/domain-publication.test.ts +10 -16
  144. package/src/lib/__tests__/idp.test.ts +34 -4
  145. package/src/lib/__tests__/instance-candidates.test.ts +1 -3
  146. package/src/lib/__tests__/instance-target.test.ts +7 -39
  147. package/src/lib/__tests__/log-errors.test.ts +64 -0
  148. package/src/lib/__tests__/studio-server-deps.test.ts +1 -1
  149. package/src/lib/__tests__/update.test.ts +264 -11
  150. package/src/lib/__tests__/view-assets.test.ts +14 -0
  151. package/src/lib/__tests__/view-external-open-intent.test.ts +150 -0
  152. package/src/lib/__tests__/view-external-open-origins.test.ts +27 -0
  153. package/src/lib/__tests__/view-open-intent.test.ts +0 -2
  154. package/src/lib/__tests__/view-server.test.ts +26 -3
  155. package/src/lib/__tests__/view-session.test.ts +2 -1
  156. package/src/lib/admin-instance.ts +14 -8
  157. package/src/lib/admin-target.ts +21 -2
  158. package/src/lib/binary.ts +22 -5
  159. package/src/lib/command-dx.ts +9 -9
  160. package/src/lib/domain-publication.ts +9 -7
  161. package/src/lib/failure-debug.ts +26 -0
  162. package/src/lib/idp.ts +34 -3
  163. package/src/lib/instance-candidates.ts +2 -2
  164. package/src/lib/instance-target.ts +3 -14
  165. package/src/lib/instance.ts +16 -11
  166. package/src/lib/log.ts +16 -9
  167. package/src/lib/output.ts +1 -1
  168. package/src/lib/proc.ts +7 -2
  169. package/src/lib/provision-instance.ts +34 -57
  170. package/src/lib/update.ts +298 -45
  171. package/src/lib/validation.ts +2 -2
  172. package/src/lib/view/assets.ts +11 -2
  173. package/src/lib/view/external-open-intent.ts +41 -0
  174. package/src/lib/view/external-open-origins.ts +37 -0
  175. package/src/lib/view/host-capabilities.ts +17 -0
  176. package/src/lib/view/resolve.ts +1 -1
  177. package/src/lib/view/server.ts +18 -3
  178. package/src/lib/view/session.ts +2 -0
  179. package/src/program/.spec/api.d.ts +1 -0
  180. package/src/program/__tests__/program.test.ts +163 -6
  181. package/src/program/argv.ts +14 -0
  182. package/src/program/build.ts +26 -4
  183. package/src/program/command.ts +1 -0
  184. package/src/program/index.ts +1 -0
  185. package/src/program/registry.ts +2 -1
  186. package/src/setup/__tests__/instance-step.test.ts +27 -10
  187. package/src/setup/steps/instance.ts +22 -15
  188. package/src/telemetry/__tests__/recorder.test.ts +1 -0
  189. package/src/telemetry/recorder.ts +9 -1
  190. package/src/ui/.spec/api.d.ts +14 -0
  191. package/src/ui/.spec/architecture.md +10 -0
  192. package/src/ui/.spec/laws.ts +36 -0
  193. package/src/ui/.spec/layout.ts +16 -0
  194. package/src/ui/__tests__/ui.test.ts +981 -0
  195. package/src/ui/index.ts +13 -0
  196. package/src/ui/lock.ts +87 -0
  197. package/src/ui/model.ts +83 -0
  198. package/src/ui/operations.ts +710 -0
  199. package/src/ui/project.ts +219 -0
  200. package/src/ui/release.ts +321 -0
  201. package/src/ui/runner.ts +18 -0
  202. package/studio/client/dist/assets/elk-api-DjmKsHXc.js +1 -0
  203. package/studio/client/dist/assets/index-7YHdeCxp.js +81 -0
  204. package/studio/client/dist/assets/index-C0FAnwNw.css +2 -0
  205. package/studio/client/dist/assets/rolldown-runtime-Dd_uD5pT.js +1 -0
  206. package/studio/client/dist/assets/schema-studio-BilUNb6Z.css +1 -0
  207. package/studio/client/dist/assets/schema-studio-CABpTfvH.js +8 -0
  208. package/studio/client/dist/index.html +3 -2
  209. package/studio/package.json +7 -13
  210. package/studio/server/agent/ask.test.ts +1 -1
  211. package/studio/server/agent/bridge/grant.test.ts +1 -1
  212. package/studio/server/agent/bridge/routes.test.ts +1 -1
  213. package/studio/server/agent/harness/claude/adapter.test.ts +15 -5
  214. package/studio/server/agent/harness/gateway/token.test.ts +1 -1
  215. package/studio/server/agent/harness/gateway/token.ts +3 -3
  216. package/studio/server/agent/prompts/anchors.test.ts +32 -36
  217. package/studio/server/agent/prompts/anchors.ts +20 -49
  218. package/studio/server/agent/prompts/system.test.ts +3 -2
  219. package/studio/server/agent/prompts/system.ts +3 -3
  220. package/studio/server/agent/routes.test.ts +1 -1
  221. package/studio/server/agent/run/coordinator.test.ts +1 -1
  222. package/studio/server/api/canvas.ts +0 -1
  223. package/studio/server/api-agent-loadout.test.ts +1 -1
  224. package/studio/server/api.test.ts +1 -1
  225. package/studio/server/cache.test.ts +23 -12
  226. package/studio/server/cache.ts +12 -15
  227. package/studio/server/domain.test.ts +50 -68
  228. package/studio/server/domain.ts +82 -63
  229. package/studio/server/handoff/copy.ts +1 -1
  230. package/studio/server/index.ts +1 -1
  231. package/studio/server/instances/probe.test.ts +1 -1
  232. package/studio/server/introspect/anatomy/views/routes.ts +46 -37
  233. package/studio/server/introspect/anatomy/views.ts +9 -14
  234. package/studio/server/introspect/anatomy-extras.test.ts +26 -42
  235. package/studio/server/introspect/anatomy.test.ts +22 -14
  236. package/studio/server/introspect/anatomy.ts +6 -9
  237. package/studio/server/introspect/bundle.ts +0 -3
  238. package/studio/server/introspect/canonical-schema.test.ts +94 -389
  239. package/studio/server/introspect/canonical-schema.ts +227 -457
  240. package/studio/server/introspect/core-extractor.ts +18 -127
  241. package/studio/server/introspect/core.ts +1 -2
  242. package/studio/server/introspect/diff.test.ts +11 -7
  243. package/studio/server/introspect/diff.ts +18 -55
  244. package/studio/server/introspect/extractor.ts +22 -117
  245. package/studio/server/introspect/overlay-tsmorph.test.ts +119 -240
  246. package/studio/server/introspect/overlay.test.ts +26 -54
  247. package/studio/server/introspect/overlay.ts +10 -37
  248. package/studio/server/introspect/revision.test.ts +1 -1
  249. package/studio/server/introspect/revision.ts +1 -1
  250. package/studio/server/introspect/runtime.test.ts +65 -183
  251. package/studio/server/introspect/runtime.ts +8 -25
  252. package/studio/server/introspect/schema-ir-json.test.ts +70 -0
  253. package/studio/server/introspect/schema-ir-json.ts +38 -68
  254. package/studio/server/introspect/schema-refs.test.ts +43 -88
  255. package/studio/server/introspect/schema-refs.ts +14 -49
  256. package/studio/server/introspect/source-overlay/handlers.ts +116 -636
  257. package/studio/server/introspect/source-overlay/kernel-calls.ts +0 -3
  258. package/studio/server/introspect/source-overlay/spans.ts +15 -45
  259. package/studio/server/state/baseline.test.ts +14 -9
  260. package/studio/server/state/baseline.ts +3 -5
  261. package/studio/server/state/visibility.ts +1 -5
  262. package/studio/server/views/model.ts +3 -3
  263. package/studio/server/views/target.test.ts +17 -74
  264. package/studio/server/views/target.ts +24 -50
  265. package/studio/server/watch.test.ts +11 -11
  266. package/studio/server/watch.ts +8 -4
  267. package/studio/server/workspace-watch.ts +2 -2
  268. package/studio/shared/contracts/schema.ts +38 -107
  269. package/studio/shared/contracts/surface.test.ts +13 -15
  270. package/studio/shared/contracts/workspace.ts +2 -11
  271. package/studio/shared/schema/identity.test.ts +20 -44
  272. package/studio/shared/schema/identity.ts +9 -23
  273. package/viewer/dist/main.js +30 -51
  274. package/.check-workspace.cjs +0 -40
  275. package/src/admin/binding.ts +0 -168
  276. package/src/commands/__tests__/instance-create-hosts.test.ts +0 -29
  277. package/studio/client/dist/assets/elk-api-lwhFo7vB.js +0 -1
  278. package/studio/client/dist/assets/index-B-c-smo9.js +0 -8
  279. package/studio/client/dist/assets/index-BckHuAWk.js +0 -81
  280. package/studio/client/dist/assets/index-C4aNQ6dz.css +0 -1
  281. package/studio/client/dist/assets/index-ChOr3yP0.css +0 -1
  282. package/studio/server/introspect/anatomy/views/legacy.ts +0 -232
@@ -1,474 +1,179 @@
1
1
  import { describe, expect, test } from 'bun:test'
2
2
 
3
- import type { CanonicalDomainSchemaV1 } from './canonical-schema'
4
-
5
3
  import {
4
+ admitCanonicalSchemaFromSdk,
6
5
  closureFromSdk,
7
6
  findCanonicalDomainSchemaExport,
8
- normalizeLegacySchemaIR,
7
+ isCanonicalDomainSchemaV1,
9
8
  projectCanonicalCore,
10
9
  projectCanonicalSchema,
10
+ type CanonicalDomainSchemaV1,
11
11
  } from './canonical-schema'
12
12
 
13
- const emptyProperties = {
14
- type: 'object',
15
- properties: {},
16
- required: [],
17
- additionalProperties: false,
18
- }
13
+ const localRef = { origin: 'docs.example.dev', kind: 'class', name: 'Document' } as const
14
+ const baseRef = { origin: 'shared.example.dev', kind: 'class', name: 'Named' } as const
15
+ const edgeRef = { origin: 'docs.example.dev', kind: 'class', name: 'links' } as const
19
16
 
20
17
  const dependency = {
21
18
  format: 'astrale.dsl',
22
19
  version: 'v1',
23
- origin: 'directory.example.dev',
24
- dependencies: [],
25
- types: {},
26
- interfaces: {
20
+ origin: 'shared.example.dev',
21
+ classes: {
27
22
  Named: {
28
- family: 'node',
29
- extends: [],
30
- properties: {
31
- ...emptyProperties,
32
- properties: { name: { type: 'string' } },
33
- required: ['name'],
34
- },
35
- propertyMetadata: {},
23
+ kind: 'node',
24
+ properties: { title: { schema: { type: 'string' }, required: true } },
36
25
  methods: {},
37
26
  },
38
27
  },
39
- classes: {},
40
- functions: {},
41
- policies: {},
42
- views: {},
43
- core: { nodes: {}, edges: [] },
44
28
  } satisfies CanonicalDomainSchemaV1
45
29
 
46
- const namedRef = {
47
- origin: dependency.origin,
48
- kind: 'interface',
49
- name: 'Named',
50
- } as const
51
- const namedKey = `${dependency.origin}:interface.Named` as const
52
- const documentRef = {
53
- origin: 'documents.example.dev',
54
- kind: 'class',
55
- name: 'Document',
56
- } as const
57
-
58
30
  const root = {
59
31
  format: 'astrale.dsl',
60
32
  version: 'v1',
61
- origin: 'documents.example.dev',
33
+ origin: 'docs.example.dev',
62
34
  dependencies: [{ origin: dependency.origin, revision: `sha256:${'1'.repeat(64)}` }],
63
- types: { State: { type: 'string', enum: ['draft', 'published'] } },
64
- interfaces: {
65
- Publishable: {
66
- family: 'node',
67
- extends: [namedRef],
68
- properties: emptyProperties,
69
- propertyMetadata: {},
70
- methods: {},
71
- },
72
- },
73
35
  classes: {
74
36
  Document: {
75
- family: 'node',
76
- implements: [{ origin: 'documents.example.dev', kind: 'interface', name: 'Publishable' }],
37
+ kind: 'node',
38
+ extends: [baseRef],
77
39
  properties: {
78
- ...emptyProperties,
79
- properties: {
80
- title: { type: 'string' },
81
- summary: { type: 'string' },
82
- note: { type: ['string', 'null'] },
83
- },
84
- required: ['title', 'note'],
40
+ slug: { schema: { type: 'string', minLength: 1 }, required: true },
85
41
  },
86
- propertyMetadata: {},
87
- data: { mediaType: 'application/json', indexed: true },
88
42
  methods: {
89
- watch: {
43
+ rename: {
90
44
  input: {
91
- ...emptyProperties,
92
- properties: { cursor: { type: 'string' }, limit: { type: 'integer' } },
93
- required: ['cursor'],
45
+ type: 'object',
46
+ properties: { title: { type: 'string' } },
47
+ required: ['title'],
94
48
  },
95
- output: { mode: 'stream', item: { type: 'string' } },
49
+ output: { mode: 'value', schema: { type: 'boolean' } },
96
50
  auth: 'authorized',
97
51
  static: false,
98
52
  inheritance: 'default',
99
53
  },
100
54
  },
101
- policies: {},
102
55
  },
103
- references: {
104
- family: 'edge',
105
- implements: [],
106
- properties: emptyProperties,
107
- propertyMetadata: {},
56
+ links: {
57
+ kind: 'edge',
108
58
  orientation: 'directed',
109
59
  endpoints: {
110
- source: { role: 'document', accepts: [documentRef], outgoing: '1..*' },
111
- target: { role: 'named', accepts: [namedRef], incoming: '0..1' },
60
+ source: { role: 'source', accepts: [localRef], outgoing: '1' },
61
+ target: { role: 'target', accepts: [baseRef], incoming: '0..*' },
112
62
  },
113
- policies: {},
114
- constraints: { noSelf: true },
63
+ properties: {},
64
+ methods: {},
115
65
  },
116
66
  },
117
67
  functions: {
118
- exportAll: {
119
- description: 'Export every document.',
120
- input: emptyProperties,
121
- output: { mode: 'binary' },
68
+ search: {
69
+ input: { type: 'object', properties: { text: { type: 'string' } }, required: ['text'] },
70
+ output: { mode: 'stream', item: { type: 'string' } },
122
71
  auth: 'authenticated',
123
72
  },
124
73
  },
125
- policies: {},
126
74
  views: {
127
- editor: {
128
- description: 'Document editor',
129
- target: { kind: 'definition', definitions: [documentRef, namedRef] },
75
+ documents: {
76
+ target: { kind: 'definition', definitions: [localRef] },
130
77
  auth: 'optional',
131
78
  },
132
79
  },
133
80
  core: {
134
81
  nodes: {
135
- welcome: {
136
- class: documentRef,
137
- properties: {
138
- 'documents.example.dev:class.Document.property.title': 'Welcome',
139
- },
140
- },
82
+ primary: { class: localRef, properties: { slug: 'primary' } },
141
83
  },
142
84
  edges: [
143
85
  {
144
- class: { origin: 'documents.example.dev', kind: 'class', name: 'references' },
145
- source: { origin: 'documents.example.dev', kind: 'core', name: 'welcome' },
146
- target: { kind: 'domain' },
147
- properties: { weight: 1 },
86
+ class: edgeRef,
87
+ source: { origin: 'docs.example.dev', kind: 'core', name: 'primary' },
88
+ target: { kind: 'domain', origin: 'docs.example.dev' },
148
89
  },
149
90
  ],
150
91
  },
151
92
  } satisfies CanonicalDomainSchemaV1
152
93
 
153
- describe('canonical DomainSchema V1 projection', () => {
154
- test('admits only an SDK-verified, exact dependency closure', () => {
155
- expect(
156
- closureFromSdk({ bundle: { create: () => ({ root, closure: [dependency] }) } }, root),
157
- ).toEqual([dependency])
158
-
159
- expect(
160
- closureFromSdk(
161
- {
162
- bundle: { create: () => ({ root: dependency, closure: [dependency] }) },
163
- schema: { resolve: () => ({ $: { schema: root, closure: [dependency] } }) },
164
- },
165
- root,
166
- ),
167
- ).toEqual([dependency])
168
-
169
- expect(
170
- closureFromSdk({ bundle: { create: () => ({ root, closure: [root, dependency] }) } }, root),
171
- ).toEqual([])
172
- })
173
-
174
- test('finds any directly exported V1 root while preferring `schema`', () => {
175
- expect(findCanonicalDomainSchemaExport({ Other: dependency, schema: root })).toBe(root)
176
- expect(findCanonicalDomainSchemaExport({ Current: root })).toBe(root)
177
- expect(findCanonicalDomainSchemaExport({ schema: { kind: 'legacy' } })).toBeNull()
178
- })
179
-
180
- test('keeps legacy fields and enriches refs, callables, views, and imported interfaces', () => {
181
- const projected = projectCanonicalSchema(root, [dependency])
182
- const ir = projected.ir
183
-
184
- expect(ir).toMatchObject({
185
- format: 'astrale.dsl',
186
- version: 'v1',
187
- domain: root.origin,
188
- dependencies: root.dependencies,
189
- })
190
- expect(ir.interfaces.Publishable.extends).toEqual(['Named'])
191
- expect(ir.interfaces.Publishable.extendsRefs).toEqual([namedRef])
192
- expect(ir.imports.Named).toEqual({
193
- origin: dependency.origin,
194
- definition: 'interface',
195
- ref: namedRef,
196
- key: namedKey,
197
- })
198
- expect(ir.importsByKey?.[namedKey]).toEqual(ir.imports.Named)
199
- expect(ir.importedInterfacesByKey?.[namedKey]).toMatchObject({
200
- name: 'Named',
201
- origin: dependency.origin,
202
- })
203
- expect(projected.importedInterfaces.Named).toMatchObject({
204
- name: 'Named',
205
- origin: dependency.origin,
206
- family: 'node',
207
- properties: { name: { type: 'string' } },
208
- required: ['name'],
209
- })
210
-
211
- expect(ir.classes.Document.properties).toEqual({
212
- title: { type: 'string' },
213
- summary: { type: 'string' },
214
- note: { type: ['string', 'null'] },
215
- })
216
- expect(ir.classes.Document.required).toEqual(['title', 'note'])
217
- expect(ir.classes.Document.data).toEqual({ mediaType: 'application/json', indexed: true })
218
- expect(ir.classes.Document.methods.watch).toMatchObject({
219
- name: 'watch',
220
- auth: 'authorized',
221
- static: false,
222
- inheritance: 'default',
223
- params: {
224
- cursor: { type: 'string' },
225
- limit: { type: 'integer' },
226
- },
227
- requiredParams: ['cursor'],
228
- output: { mode: 'stream', item: { type: 'string' } },
229
- returns: { type: 'string' },
230
- })
231
- expect(ir.classes.references.endpoints).toEqual([
232
- {
233
- name: 'document',
234
- types: ['Document'],
235
- refs: [documentRef],
236
- cardinality: { min: 1, max: null },
237
- },
238
- {
239
- name: 'named',
240
- types: ['Named'],
241
- refs: [namedRef],
242
- cardinality: { min: 0, max: 1 },
243
- },
244
- ])
245
- expect(ir.functions.exportAll).toMatchObject({
246
- name: 'exportAll',
247
- auth: 'authenticated',
248
- static: true,
249
- inheritance: 'default',
250
- params: {},
251
- requiredParams: [],
252
- output: { mode: 'binary' },
253
- returns: {},
254
- })
255
- expect(ir.views?.editor).toEqual({
256
- name: 'editor',
257
- description: 'Document editor',
258
- target: { kind: 'definition', definitions: [documentRef, namedRef] },
259
- auth: 'optional',
260
- })
261
- expect(ir.core).toEqual(root.core)
94
+ describe('canonical Schema projection', () => {
95
+ test('recognizes and selects only portable V1 schema roots', () => {
96
+ expect(isCanonicalDomainSchemaV1(root)).toBe(true)
97
+ expect(isCanonicalDomainSchemaV1({ ...root, version: 'v0' })).toBe(false)
98
+ expect(findCanonicalDomainSchemaExport({ other: dependency, schema: root })).toBe(root)
262
99
  })
263
100
 
264
- test('keeps colliding imported definitions under exact DSL Keys only', () => {
265
- const alternate = {
266
- ...dependency,
267
- origin: 'people.example.dev',
268
- } satisfies CanonicalDomainSchemaV1
269
- const classOwner = {
270
- ...dependency,
271
- origin: 'catalog.example.dev',
272
- interfaces: {},
273
- classes: {
274
- Named: {
275
- family: 'node',
276
- implements: [],
277
- properties: emptyProperties,
278
- propertyMetadata: {},
279
- methods: {},
280
- policies: {},
281
- },
282
- },
283
- } satisfies CanonicalDomainSchemaV1
284
- const alternateRef = {
285
- origin: alternate.origin,
286
- kind: 'interface',
287
- name: 'Named',
288
- } as const
289
- const classRef = {
290
- origin: classOwner.origin,
291
- kind: 'class',
292
- name: 'Named',
293
- } as const
294
- const collisionRoot = {
295
- format: 'astrale.dsl',
296
- version: 'v1',
297
- origin: 'collisions.example.dev',
298
- dependencies: [],
299
- types: {},
300
- interfaces: {
301
- Local: {
302
- family: 'node',
303
- extends: [namedRef, alternateRef],
304
- properties: emptyProperties,
305
- propertyMetadata: {},
306
- methods: {},
307
- },
308
- },
309
- classes: {},
310
- functions: {},
311
- policies: {},
312
- views: {
313
- everything: {
314
- target: { kind: 'definition', definitions: [namedRef, alternateRef, classRef] },
315
- auth: 'required',
101
+ test('projects Classes, exact inheritance/imports, callables, Views, and edges', () => {
102
+ const { ir } = projectCanonicalSchema(root, [dependency])
103
+ expect(ir.classes.Document).toMatchObject({
104
+ extendsRefs: [baseRef],
105
+ properties: { slug: { type: 'string', minLength: 1 } },
106
+ required: ['slug'],
107
+ methods: {
108
+ rename: {
109
+ input: { required: ['title'] },
110
+ auth: 'authorized',
111
+ output: { mode: 'value', schema: { type: 'boolean' } },
316
112
  },
317
113
  },
318
- core: { nodes: {}, edges: [] },
319
- } satisfies CanonicalDomainSchemaV1
320
-
321
- const projected = projectCanonicalSchema(collisionRoot, [dependency, alternate, classOwner])
322
- const keys = [
323
- 'directory.example.dev:interface.Named',
324
- 'people.example.dev:interface.Named',
325
- 'catalog.example.dev:class.Named',
326
- ]
327
-
328
- expect(Object.keys(projected.ir.importsByKey ?? {}).sort()).toEqual(keys.sort())
329
- expect(Object.keys(projected.ir.importedInterfacesByKey ?? {}).sort()).toEqual(
330
- keys.filter((key) => key.includes(':interface.')).sort(),
331
- )
332
- expect(
333
- projected.ir.importedInterfacesByKey?.['directory.example.dev:interface.Named']?.origin,
334
- ).toBe('directory.example.dev')
335
- expect(
336
- projected.ir.importedInterfacesByKey?.['people.example.dev:interface.Named']?.origin,
337
- ).toBe('people.example.dev')
338
- expect(projected.ir.importsByKey?.['catalog.example.dev:class.Named']).toMatchObject({
339
- definition: 'class',
340
- key: 'catalog.example.dev:class.Named',
341
- ref: classRef,
342
114
  })
343
- expect(projected.ir.imports.Named).toBeUndefined()
344
- expect(projected.importedInterfaces.Named).toBeUndefined()
345
- })
346
-
347
- test('collects an exact external Definition referenced only by a top-level Policy', () => {
348
- const policyOrigin = 'authorization.example.dev'
349
- const subjectRef = { origin: policyOrigin, kind: 'class', name: 'Subject' } as const
350
- const objectRef = { origin: policyOrigin, kind: 'class', name: 'Object' } as const
351
- const policyOnlyRef = { origin: policyOrigin, kind: 'class', name: 'may_access' } as const
352
- const policyDependency = {
353
- format: 'astrale.dsl',
354
- version: 'v1',
355
- origin: policyOrigin,
356
- dependencies: [],
357
- types: {},
358
- interfaces: {},
359
- classes: {
360
- Subject: {
361
- family: 'node',
362
- implements: [],
363
- properties: emptyProperties,
364
- propertyMetadata: {},
365
- methods: {},
366
- policies: {},
367
- },
368
- Object: {
369
- family: 'node',
370
- implements: [],
371
- properties: emptyProperties,
372
- propertyMetadata: {},
373
- methods: {},
374
- policies: {},
375
- },
376
- may_access: {
377
- family: 'edge',
378
- implements: [],
379
- properties: emptyProperties,
380
- propertyMetadata: {},
381
- orientation: 'directed',
382
- endpoints: {
383
- source: { role: 'subject', accepts: [subjectRef], outgoing: '0..*' },
384
- target: { role: 'object', accepts: [objectRef], incoming: '0..*' },
385
- },
386
- policies: {},
387
- constraints: {},
388
- },
389
- },
390
- functions: {},
391
- policies: {},
392
- views: {},
393
- core: { nodes: {}, edges: [] },
394
- } satisfies CanonicalDomainSchemaV1
395
- const policyOnlyRoot = {
396
- format: 'astrale.dsl',
397
- version: 'v1',
398
- origin: 'policy-consumer.example.dev',
399
- dependencies: [{ origin: policyDependency.origin, revision: `sha256:${'2'.repeat(64)}` }],
400
- types: {},
401
- interfaces: {},
402
- classes: {},
403
- functions: {},
404
- policies: {
405
- canRead: {
406
- match: {
407
- source: { kind: 'subject' },
408
- class: policyOnlyRef,
409
- target: { kind: 'object' },
410
- },
411
- },
412
- },
413
- views: {},
414
- core: { nodes: {}, edges: [] },
415
- } satisfies CanonicalDomainSchemaV1
416
-
417
- const projected = projectCanonicalSchema(policyOnlyRoot, [policyDependency])
418
- expect(projected.ir.importsByKey?.['authorization.example.dev:class.may_access']).toEqual({
419
- origin: policyDependency.origin,
420
- definition: 'class',
421
- ref: policyOnlyRef,
422
- key: 'authorization.example.dev:class.may_access',
115
+ expect(ir.importsByKey['shared.example.dev:class.Named']).toEqual({
116
+ origin: baseRef.origin,
117
+ ref: baseRef,
118
+ key: 'shared.example.dev:class.Named',
423
119
  })
120
+ expect(ir.importedClassesByKey['shared.example.dev:class.Named']?.properties.title).toEqual({
121
+ type: 'string',
122
+ })
123
+ expect(ir.classes.links.endpoints).toEqual([
124
+ { name: 'source', types: ['Document'], refs: [localRef], cardinality: { min: 1, max: 1 } },
125
+ { name: 'target', types: ['Named'], refs: [baseRef], cardinality: { min: 0, max: null } },
126
+ ])
127
+ expect(ir.functions.search).toMatchObject({ auth: 'authenticated', output: { mode: 'stream' } })
128
+ expect(ir.views?.documents.target).toEqual({ kind: 'definition', definitions: [localRef] })
424
129
  })
425
130
 
426
- test('projects canonical core paths and the owning Domain endpoint', () => {
131
+ test('projects canonical Core coordinates without importing Application or Runtime', () => {
427
132
  expect(projectCanonicalCore(root)).toEqual({
428
133
  domain: root.origin,
429
134
  nodes: [
430
135
  {
431
- path: '/:documents.example.dev:core.welcome',
136
+ path: '/:docs.example.dev:core.primary',
432
137
  className: 'Document',
433
- data: { 'documents.example.dev:class.Document.property.title': 'Welcome' },
138
+ data: { slug: 'primary' },
434
139
  },
435
140
  ],
436
141
  edges: [
437
142
  {
438
- from: '/:documents.example.dev:core.welcome',
439
- to: '/:documents.example.dev',
440
- edgeName: 'references',
441
- data: { weight: 1 },
143
+ from: '/:docs.example.dev:core.primary',
144
+ to: '/:docs.example.dev',
145
+ edgeName: 'links',
442
146
  },
443
147
  ],
444
148
  })
445
149
  })
446
150
 
447
- test('normalizes a legacy IR to the required standalone-function shape', () => {
448
- const ir = normalizeLegacySchemaIR({
449
- version: '1.0',
450
- domain: 'legacy.example.dev',
451
- types: {},
452
- interfaces: {},
453
- classes: {},
454
- imports: {},
455
- functions: {
456
- legacy: {
457
- params: {
458
- required: { type: 'string' },
459
- maybe: { type: ['string', 'null'] },
460
- },
461
- returns: { type: 'boolean' },
462
- },
463
- },
151
+ test('uses the authored SDK for closure, admission, revision, and resolved-source proof', () => {
152
+ const accepted = { ...root }
153
+ const revision = `sha256:${'a'.repeat(64)}` as const
154
+ const sdk = {
155
+ bundle: { create: () => ({ root: accepted, closure: [dependency] }) },
156
+ schema: {
157
+ accept: (candidate: unknown) => candidate,
158
+ revision: () => revision,
159
+ resolve: (candidate: unknown) => ({ source: candidate, origin: root.origin }),
160
+ },
161
+ }
162
+ expect(closureFromSdk(sdk, accepted)).toEqual([dependency])
163
+ expect(admitCanonicalSchemaFromSdk(sdk, accepted)).toEqual({
164
+ status: 'admitted',
165
+ root: accepted,
166
+ closure: [dependency],
167
+ revision,
464
168
  })
465
- expect(ir.functions.legacy).toMatchObject({
466
- params: {
467
- required: { type: 'string' },
468
- maybe: { type: ['string', 'null'] },
469
- },
470
- requiredParams: ['required'],
471
- input: { required: ['required'] },
169
+ })
170
+
171
+ test('fails to preview when the SDK cannot prove admission', () => {
172
+ expect(admitCanonicalSchemaFromSdk({}, root)).toEqual({
173
+ status: 'preview',
174
+ root,
175
+ closure: [],
176
+ revision: null,
472
177
  })
473
178
  })
474
179
  })