@ontrails/core 1.0.0-beta.14 → 1.0.0-beta.15

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 (280) hide show
  1. package/.turbo/turbo-lint.log +1 -1
  2. package/CHANGELOG.md +11 -0
  3. package/README.md +17 -13
  4. package/dist/branded.d.ts +1 -1
  5. package/dist/branded.d.ts.map +1 -1
  6. package/dist/branded.js +1 -1
  7. package/dist/branded.js.map +1 -1
  8. package/dist/context.d.ts +13 -1
  9. package/dist/context.d.ts.map +1 -1
  10. package/dist/context.js +19 -3
  11. package/dist/context.js.map +1 -1
  12. package/dist/contour.d.ts +81 -0
  13. package/dist/contour.d.ts.map +1 -0
  14. package/dist/contour.js +176 -0
  15. package/dist/contour.js.map +1 -0
  16. package/dist/cross-schema.d.ts +18 -0
  17. package/dist/cross-schema.d.ts.map +1 -0
  18. package/dist/cross-schema.js +29 -0
  19. package/dist/cross-schema.js.map +1 -0
  20. package/dist/draft.d.ts +5 -5
  21. package/dist/draft.d.ts.map +1 -1
  22. package/dist/draft.js +28 -27
  23. package/dist/draft.js.map +1 -1
  24. package/dist/errors.d.ts +62 -4
  25. package/dist/errors.d.ts.map +1 -1
  26. package/dist/errors.js +44 -1
  27. package/dist/errors.js.map +1 -1
  28. package/dist/execute.d.ts +26 -9
  29. package/dist/execute.d.ts.map +1 -1
  30. package/dist/execute.js +441 -20
  31. package/dist/execute.js.map +1 -1
  32. package/dist/fire.d.ts +43 -0
  33. package/dist/fire.d.ts.map +1 -0
  34. package/dist/fire.js +185 -0
  35. package/dist/fire.js.map +1 -0
  36. package/dist/index.d.ts +31 -20
  37. package/dist/index.d.ts.map +1 -1
  38. package/dist/index.js +23 -13
  39. package/dist/index.js.map +1 -1
  40. package/dist/internal/cross-batch.d.ts +44 -0
  41. package/dist/internal/cross-batch.d.ts.map +1 -0
  42. package/dist/internal/cross-batch.js +58 -0
  43. package/dist/internal/cross-batch.js.map +1 -0
  44. package/dist/internal/fork-ctx.d.ts +41 -0
  45. package/dist/internal/fork-ctx.d.ts.map +1 -0
  46. package/dist/internal/fork-ctx.js +47 -0
  47. package/dist/internal/fork-ctx.js.map +1 -0
  48. package/dist/internal/signal-ref.d.ts +15 -0
  49. package/dist/internal/signal-ref.d.ts.map +1 -0
  50. package/dist/internal/signal-ref.js +41 -0
  51. package/dist/internal/signal-ref.js.map +1 -0
  52. package/dist/internal/topo-saves.d.ts +8 -2
  53. package/dist/internal/topo-saves.d.ts.map +1 -1
  54. package/dist/internal/topo-saves.js +162 -23
  55. package/dist/internal/topo-saves.js.map +1 -1
  56. package/dist/internal/topo-snapshots.d.ts +57 -0
  57. package/dist/internal/topo-snapshots.d.ts.map +1 -0
  58. package/dist/internal/topo-snapshots.js +372 -0
  59. package/dist/internal/topo-snapshots.js.map +1 -0
  60. package/dist/internal/topo-store-read.d.ts +23 -20
  61. package/dist/internal/topo-store-read.d.ts.map +1 -1
  62. package/dist/internal/topo-store-read.js +82 -83
  63. package/dist/internal/topo-store-read.js.map +1 -1
  64. package/dist/internal/topo-store.d.ts +19 -5
  65. package/dist/internal/topo-store.d.ts.map +1 -1
  66. package/dist/internal/topo-store.js +174 -124
  67. package/dist/internal/topo-store.js.map +1 -1
  68. package/dist/internal/tracing.d.ts +98 -0
  69. package/dist/internal/tracing.d.ts.map +1 -0
  70. package/dist/internal/tracing.js +102 -0
  71. package/dist/internal/tracing.js.map +1 -0
  72. package/dist/internal/trails-db.d.ts +2 -2
  73. package/dist/internal/trails-db.d.ts.map +1 -1
  74. package/dist/internal/trails-db.js +8 -8
  75. package/dist/internal/trails-db.js.map +1 -1
  76. package/dist/internal/zod-wrappers.d.ts +40 -0
  77. package/dist/internal/zod-wrappers.d.ts.map +1 -0
  78. package/dist/internal/zod-wrappers.js +59 -0
  79. package/dist/internal/zod-wrappers.js.map +1 -0
  80. package/dist/layer.d.ts +22 -5
  81. package/dist/layer.d.ts.map +1 -1
  82. package/dist/layer.js +20 -3
  83. package/dist/layer.js.map +1 -1
  84. package/dist/path-security.d.ts +1 -1
  85. package/dist/path-security.d.ts.map +1 -1
  86. package/dist/path-security.js +1 -1
  87. package/dist/path-security.js.map +1 -1
  88. package/dist/resilience.d.ts +1 -1
  89. package/dist/resilience.d.ts.map +1 -1
  90. package/dist/resilience.js +3 -3
  91. package/dist/resilience.js.map +1 -1
  92. package/dist/resource-config.d.ts +22 -0
  93. package/dist/resource-config.d.ts.map +1 -0
  94. package/dist/resource-config.js +210 -0
  95. package/dist/resource-config.js.map +1 -0
  96. package/dist/resource.d.ts +74 -0
  97. package/dist/resource.d.ts.map +1 -0
  98. package/dist/resource.js +61 -0
  99. package/dist/resource.js.map +1 -0
  100. package/dist/run.d.ts +4 -3
  101. package/dist/run.d.ts.map +1 -1
  102. package/dist/run.js +5 -4
  103. package/dist/run.js.map +1 -1
  104. package/dist/serialization.d.ts.map +1 -1
  105. package/dist/serialization.js +2 -1
  106. package/dist/serialization.js.map +1 -1
  107. package/dist/store/accessor-protocol.d.ts +51 -0
  108. package/dist/store/accessor-protocol.d.ts.map +1 -0
  109. package/dist/store/accessor-protocol.js +2 -0
  110. package/dist/store/accessor-protocol.js.map +1 -0
  111. package/dist/store/index.d.ts +2 -0
  112. package/dist/store/index.d.ts.map +1 -0
  113. package/dist/store/index.js +2 -0
  114. package/dist/store/index.js.map +1 -0
  115. package/dist/surface-filter.d.ts +13 -0
  116. package/dist/surface-filter.d.ts.map +1 -0
  117. package/dist/surface-filter.js +76 -0
  118. package/dist/surface-filter.js.map +1 -0
  119. package/dist/topo-store.d.ts +36 -22
  120. package/dist/topo-store.d.ts.map +1 -1
  121. package/dist/topo-store.js +215 -71
  122. package/dist/topo-store.js.map +1 -1
  123. package/dist/topo.d.ts +23 -9
  124. package/dist/topo.d.ts.map +1 -1
  125. package/dist/topo.js +175 -46
  126. package/dist/topo.js.map +1 -1
  127. package/dist/trail.d.ts +86 -19
  128. package/dist/trail.d.ts.map +1 -1
  129. package/dist/trail.js +59 -4
  130. package/dist/trail.js.map +1 -1
  131. package/dist/trails/derive-trail.d.ts +66 -0
  132. package/dist/trails/derive-trail.d.ts.map +1 -0
  133. package/dist/trails/derive-trail.js +378 -0
  134. package/dist/trails/derive-trail.js.map +1 -0
  135. package/dist/trails/index.d.ts +5 -0
  136. package/dist/trails/index.d.ts.map +1 -0
  137. package/dist/trails/index.js +3 -0
  138. package/dist/trails/index.js.map +1 -0
  139. package/dist/trails/ingest.d.ts +24 -0
  140. package/dist/trails/ingest.d.ts.map +1 -0
  141. package/dist/trails/ingest.js +63 -0
  142. package/dist/trails/ingest.js.map +1 -0
  143. package/dist/transport-error-map.d.ts +106 -0
  144. package/dist/transport-error-map.d.ts.map +1 -0
  145. package/dist/transport-error-map.js +24 -0
  146. package/dist/transport-error-map.js.map +1 -0
  147. package/dist/type-checks.test-d.d.ts +71 -0
  148. package/dist/type-checks.test-d.d.ts.map +1 -0
  149. package/dist/type-checks.test-d.js +12 -0
  150. package/dist/type-checks.test-d.js.map +1 -0
  151. package/dist/type-utils.d.ts +11 -2
  152. package/dist/type-utils.d.ts.map +1 -1
  153. package/dist/type-utils.js.map +1 -1
  154. package/dist/types.d.ts +113 -7
  155. package/dist/types.d.ts.map +1 -1
  156. package/dist/types.js.map +1 -1
  157. package/dist/validate-established-topo.js +2 -2
  158. package/dist/validate-established-topo.js.map +1 -1
  159. package/dist/validate-topo.d.ts.map +1 -1
  160. package/dist/validate-topo.js +24 -7
  161. package/dist/validate-topo.js.map +1 -1
  162. package/dist/workspace.d.ts +1 -1
  163. package/dist/workspace.d.ts.map +1 -1
  164. package/dist/workspace.js +1 -1
  165. package/dist/workspace.js.map +1 -1
  166. package/package.json +8 -2
  167. package/src/__tests__/branded.test.ts +5 -5
  168. package/src/__tests__/context.test.ts +3 -3
  169. package/src/__tests__/contour.test.ts +263 -0
  170. package/src/__tests__/derive-trail.test.ts +668 -0
  171. package/src/__tests__/errors.test.ts +118 -0
  172. package/src/__tests__/execute.test.ts +1179 -141
  173. package/src/__tests__/fire.test.ts +1056 -0
  174. package/src/__tests__/fork-ctx.test.ts +83 -0
  175. package/src/__tests__/ingest.test.ts +191 -0
  176. package/src/__tests__/{gate.test.ts → layer.test.ts} +21 -21
  177. package/src/__tests__/path-security.test.ts +7 -7
  178. package/src/__tests__/resilience.test.ts +8 -8
  179. package/src/__tests__/resource.test.ts +204 -0
  180. package/src/__tests__/run.test.ts +13 -13
  181. package/src/__tests__/service-config.test.ts +28 -32
  182. package/src/__tests__/surface-filter.test.ts +196 -0
  183. package/src/__tests__/topo-store-read.test.ts +41 -36
  184. package/src/__tests__/topo-store.test.ts +493 -93
  185. package/src/__tests__/topo.test.ts +350 -54
  186. package/src/__tests__/trail.test.ts +189 -24
  187. package/src/__tests__/trails-db.test.ts +32 -25
  188. package/src/__tests__/transport-error-map.test.ts +82 -0
  189. package/src/__tests__/type-utils.test.ts +29 -1
  190. package/src/__tests__/validate-topo.test.ts +147 -25
  191. package/src/__tests__/workspace.test.ts +6 -6
  192. package/src/__tests__/zod-wrappers.test.ts +62 -0
  193. package/src/branded.ts +1 -1
  194. package/src/context.ts +24 -4
  195. package/src/contour.ts +344 -0
  196. package/src/cross-schema.ts +36 -0
  197. package/src/draft.ts +56 -52
  198. package/src/errors.ts +62 -18
  199. package/src/execute.ts +840 -29
  200. package/src/fire.ts +295 -0
  201. package/src/index.ts +116 -29
  202. package/src/internal/cross-batch.ts +77 -0
  203. package/src/internal/fork-ctx.ts +69 -0
  204. package/src/internal/signal-ref.ts +87 -0
  205. package/src/internal/topo-snapshots.ts +517 -0
  206. package/src/internal/topo-store-read.ts +140 -132
  207. package/src/internal/topo-store.ts +291 -186
  208. package/src/internal/tracing.ts +187 -0
  209. package/src/internal/trails-db.ts +9 -11
  210. package/src/internal/zod-wrappers.ts +78 -0
  211. package/src/layer.ts +50 -0
  212. package/src/path-security.ts +1 -1
  213. package/src/resilience.ts +3 -3
  214. package/src/{provision-config.ts → resource-config.ts} +109 -123
  215. package/src/resource.ts +155 -0
  216. package/src/run.ts +5 -4
  217. package/src/serialization.ts +2 -0
  218. package/src/store/accessor-protocol.ts +56 -0
  219. package/src/store/index.ts +4 -0
  220. package/src/surface-filter.ts +182 -0
  221. package/src/topo-store.ts +313 -104
  222. package/src/topo.ts +328 -57
  223. package/src/trail.ts +199 -31
  224. package/src/trails/derive-trail.ts +842 -0
  225. package/src/trails/index.ts +9 -0
  226. package/src/trails/ingest.ts +146 -0
  227. package/src/transport-error-map.ts +56 -0
  228. package/src/type-checks.test-d.ts +106 -0
  229. package/src/type-utils.ts +17 -2
  230. package/src/types.ts +148 -11
  231. package/src/validate-established-topo.ts +2 -2
  232. package/src/validate-topo.ts +32 -8
  233. package/src/workspace.ts +1 -1
  234. package/tsconfig.tests.json +10 -0
  235. package/tsconfig.tsbuildinfo +1 -1
  236. package/dist/adapters.d.ts +0 -39
  237. package/dist/adapters.d.ts.map +0 -1
  238. package/dist/adapters.js +0 -2
  239. package/dist/adapters.js.map +0 -1
  240. package/dist/dispatch.d.ts +0 -27
  241. package/dist/dispatch.d.ts.map +0 -1
  242. package/dist/dispatch.js +0 -34
  243. package/dist/dispatch.js.map +0 -1
  244. package/dist/event.d.ts +0 -8
  245. package/dist/event.d.ts.map +0 -1
  246. package/dist/event.js +0 -7
  247. package/dist/event.js.map +0 -1
  248. package/dist/gate.d.ts +0 -17
  249. package/dist/gate.d.ts.map +0 -1
  250. package/dist/gate.js +0 -21
  251. package/dist/gate.js.map +0 -1
  252. package/dist/health.d.ts +0 -18
  253. package/dist/health.d.ts.map +0 -1
  254. package/dist/health.js +0 -5
  255. package/dist/health.js.map +0 -1
  256. package/dist/job.d.ts +0 -24
  257. package/dist/job.d.ts.map +0 -1
  258. package/dist/job.js +0 -17
  259. package/dist/job.js.map +0 -1
  260. package/dist/provision-config.d.ts +0 -22
  261. package/dist/provision-config.d.ts.map +0 -1
  262. package/dist/provision-config.js +0 -210
  263. package/dist/provision-config.js.map +0 -1
  264. package/dist/provision.d.ts +0 -71
  265. package/dist/provision.d.ts.map +0 -1
  266. package/dist/provision.js +0 -56
  267. package/dist/provision.js.map +0 -1
  268. package/dist/service-config.d.ts +0 -22
  269. package/dist/service-config.d.ts.map +0 -1
  270. package/dist/service-config.js +0 -210
  271. package/dist/service-config.js.map +0 -1
  272. package/dist/service.d.ts +0 -71
  273. package/dist/service.d.ts.map +0 -1
  274. package/dist/service.js +0 -56
  275. package/dist/service.js.map +0 -1
  276. package/src/__tests__/service.test.ts +0 -197
  277. package/src/event.ts +0 -15
  278. package/src/gate.ts +0 -44
  279. package/src/internal/topo-saves.ts +0 -429
  280. package/src/provision.ts +0 -148
@@ -1,8 +1,9 @@
1
+ import { getContourReferences } from '../contour.js';
1
2
  import { deriveCliPath } from '../derive.js';
2
3
  import { Result } from '../result.js';
3
4
  import { validateEstablishedTopo } from '../validate-established-topo.js';
4
5
  import { zodToJsonSchema } from '../validation.js';
5
- import { ensureTopoHistorySchema, insertTopoSaveRecord } from './topo-saves.js';
6
+ import { ensureTopoSnapshotSchema, insertTopoSnapshotRecord, } from './topo-snapshots.js';
6
7
  const canonicalLeaf = (value) => {
7
8
  switch (typeof value) {
8
9
  case 'bigint': {
@@ -100,7 +101,7 @@ const sortKeys = (value) => {
100
101
  }
101
102
  return sorted;
102
103
  };
103
- const normalizeTrailRows = (trails, saveId) => trails.map((trail) => ({
104
+ const normalizeTrailRows = (trails, snapshotId) => trails.map((trail) => ({
104
105
  description: trail.description ?? null,
105
106
  exampleCount: trail.examples?.length ?? 0,
106
107
  hasExamples: (trail.examples?.length ?? 0) > 0 ? 1 : 0,
@@ -109,89 +110,105 @@ const normalizeTrailRows = (trails, saveId) => trails.map((trail) => ({
109
110
  idempotent: trail.idempotent === true ? 1 : 0,
110
111
  intent: trail.intent,
111
112
  meta: trail.meta === undefined ? null : stableJson(trail.meta),
112
- saveId,
113
+ pattern: trail.pattern ?? null,
114
+ snapshotId,
113
115
  }));
114
- const normalizeCrossingRows = (trails, saveId) => trails.flatMap((trail) => [...new Set(trail.crosses)].toSorted().map((targetId) => ({
115
- saveId,
116
+ const normalizeCrossingRows = (trails, snapshotId) => trails.flatMap((trail) => [...new Set(trail.crosses)].toSorted().map((targetId) => ({
117
+ snapshotId,
116
118
  sourceId: trail.id,
117
119
  targetId,
118
120
  })));
119
- const normalizeTrailProvisionRows = (trails, saveId) => trails.flatMap((trail) => [...new Set(trail.provisions.map((provision) => provision.id))]
121
+ export const normalizeFiresRows = (trails, snapshotId) => trails.flatMap((trail) => [...new Set(trail.fires)].toSorted().map((signalId) => ({
122
+ signalId,
123
+ snapshotId,
124
+ trailId: trail.id,
125
+ })));
126
+ export const normalizeOnRows = (trails, snapshotId) => trails.flatMap((trail) => [...new Set(trail.on)].toSorted().map((signalId) => ({
127
+ signalId,
128
+ snapshotId,
129
+ trailId: trail.id,
130
+ })));
131
+ const normalizeTrailResourceRows = (trails, snapshotId) => trails.flatMap((trail) => [...new Set(trail.resources.map((resource) => resource.id))]
120
132
  .toSorted()
121
- .map((provisionId) => ({
122
- provisionId,
123
- saveId,
133
+ .map((resourceId) => ({
134
+ resourceId,
135
+ snapshotId,
124
136
  trailId: trail.id,
125
137
  })));
126
- const normalizeProvisionRows = (provisions, saveId) => provisions.map((provision) => ({
127
- hasHealth: provision.health === undefined ? 0 : 1,
128
- hasMock: provision.mock === undefined ? 0 : 1,
129
- id: provision.id,
130
- saveId,
138
+ const normalizeResourceRows = (resources, snapshotId) => resources.map((resource) => ({
139
+ hasHealth: resource.health === undefined ? 0 : 1,
140
+ hasMock: resource.mock === undefined ? 0 : 1,
141
+ id: resource.id,
142
+ snapshotId,
131
143
  }));
132
- const normalizeSignalRows = (signals, saveId) => signals.map((signal) => ({
144
+ const normalizeSignalRows = (signals, snapshotId) => signals.map((signal) => ({
133
145
  description: signal.description ?? null,
134
146
  id: signal.id,
135
- saveId,
147
+ snapshotId,
136
148
  }));
137
- const normalizeTrailSignalRows = (signals, saveId) => signals.flatMap((signal) => [...new Set(signal.from)].toSorted().map((trailId) => ({
138
- saveId,
149
+ const normalizeTrailSignalRows = (signals, snapshotId) => signals.flatMap((signal) => [...new Set(signal.from)].toSorted().map((trailId) => ({
139
150
  signalId: signal.id,
151
+ snapshotId,
140
152
  trailId,
141
153
  })));
142
154
  /**
143
- * Project trailhead rows for stored topo.
155
+ * Project surface rows for stored topo.
144
156
  *
145
- * Currently records only CLI-derived rows. MCP, HTTP, and other trailhead
157
+ * Currently records only CLI-derived rows. MCP, HTTP, and other surface
146
158
  * projections are intentionally deferred until the topo-store schema supports
147
- * multi-trailhead representation. The JSON export (`trailhead_map` in
159
+ * multi-surface representation. The JSON export (`surface_map` in
148
160
  * `topo_exports`) is more faithful for now. See ADR-0015 for the target shape.
149
161
  */
150
- const normalizeTrailheadRows = (trails, saveId) => trails.map((trail) => ({
162
+ const normalizeSurfaceRows = (trails, snapshotId) => trails.map((trail) => ({
151
163
  derivedName: deriveCliPath(trail.id).join(' '),
152
164
  method: null,
153
- saveId,
165
+ snapshotId,
166
+ surface: 'cli',
154
167
  trailId: trail.id,
155
- trailhead: 'cli',
156
168
  }));
157
- const buildExampleId = (saveId, trailId, ordinal) => `${saveId}:${trailId}:${ordinal.toString().padStart(4, '0')}`;
158
- const normalizeExampleRows = (trails, saveId) => trails.flatMap((trail) => (trail.examples ?? []).map((example, index) => ({
169
+ const buildExampleId = (snapshotId, trailId, ordinal) => `${snapshotId}:${trailId}:${ordinal.toString().padStart(4, '0')}`;
170
+ const normalizeExampleRows = (trails, snapshotId) => trails.flatMap((trail) => (trail.examples ?? []).map((example, index) => ({
159
171
  description: example.description ?? null,
160
172
  error: example.error ?? null,
161
173
  expected: example.expected === undefined ? null : stableJson(example.expected),
162
- id: buildExampleId(saveId, trail.id, index),
174
+ expectedMatch: example.expectedMatch === undefined
175
+ ? null
176
+ : stableJson(example.expectedMatch),
177
+ id: buildExampleId(snapshotId, trail.id, index),
163
178
  input: stableJson(example.input),
164
179
  name: example.name,
165
180
  ordinal: index,
166
- saveId,
181
+ snapshotId,
167
182
  trailId: trail.id,
168
183
  })));
169
- const normalizeTopoProjection = (topo, saveId) => {
184
+ const normalizeTopoProjection = (topo, snapshotId) => {
170
185
  const trails = topo.list().toSorted((a, b) => a.id.localeCompare(b.id));
171
- const provisions = topo
172
- .listProvisions()
186
+ const resources = topo
187
+ .listResources()
173
188
  .toSorted((a, b) => a.id.localeCompare(b.id));
174
189
  const signals = topo
175
190
  .listSignals()
176
191
  .toSorted((a, b) => a.id.localeCompare(b.id));
177
192
  return {
178
- crossings: normalizeCrossingRows(trails, saveId),
179
- examples: normalizeExampleRows(trails, saveId),
180
- provisions: normalizeProvisionRows(provisions, saveId),
181
- signals: normalizeSignalRows(signals, saveId),
182
- trailProvisions: normalizeTrailProvisionRows(trails, saveId),
183
- trailSignals: normalizeTrailSignalRows(signals, saveId),
184
- trailheads: normalizeTrailheadRows(trails, saveId),
185
- trails: normalizeTrailRows(trails, saveId),
193
+ crossings: normalizeCrossingRows(trails, snapshotId),
194
+ examples: normalizeExampleRows(trails, snapshotId),
195
+ fires: normalizeFiresRows(trails, snapshotId),
196
+ on: normalizeOnRows(trails, snapshotId),
197
+ resources: normalizeResourceRows(resources, snapshotId),
198
+ signals: normalizeSignalRows(signals, snapshotId),
199
+ surfaces: normalizeSurfaceRows(trails, snapshotId),
200
+ trailResources: normalizeTrailResourceRows(trails, snapshotId),
201
+ trailSignals: normalizeTrailSignalRows(signals, snapshotId),
202
+ trails: normalizeTrailRows(trails, snapshotId),
186
203
  };
187
204
  };
188
205
  /**
189
206
  * Look up a cached JSON schema by content hash.
190
207
  *
191
- * The query matches on `zod_hash` without filtering by `save_id` because the
192
- * cache is intentionally cross-save: if the Zod schema definition has not
208
+ * The query matches on `zod_hash` without filtering by `snapshot_id` because the
209
+ * cache is intentionally cross-snapshot: if the Zod schema definition has not
193
210
  * changed (same hash), the serialized JSON Schema is reused regardless of
194
- * which save produced it. This is safe as long as `zodToJsonSchema` is
211
+ * which snapshot produced it. This is safe as long as `zodToJsonSchema` is
195
212
  * deterministic for a given `_def` hash — the `schemaDefinitionHash` pipeline
196
213
  * guarantees that structurally identical schemas produce the same hash.
197
214
  */
@@ -207,7 +224,7 @@ const readCachedJsonSchema = (db, ownerId, ownerKind, schemaKind, zodHash) => {
207
224
  .get(ownerId, ownerKind, schemaKind, zodHash);
208
225
  return row?.json_schema;
209
226
  };
210
- const resolveSchemaRow = (db, ownerId, ownerKind, saveId, schemaKind, schema) => {
227
+ const resolveSchemaRow = (db, ownerId, ownerKind, snapshotId, schemaKind, schema) => {
211
228
  const zodHash = schemaDefinitionHash(schema);
212
229
  const cachedJson = readCachedJsonSchema(db, ownerId, ownerKind, schemaKind, zodHash);
213
230
  if (cachedJson !== undefined) {
@@ -216,8 +233,8 @@ const resolveSchemaRow = (db, ownerId, ownerKind, saveId, schemaKind, schema) =>
216
233
  jsonSchema: cachedJson,
217
234
  ownerId,
218
235
  ownerKind,
219
- saveId,
220
236
  schemaKind,
237
+ snapshotId,
221
238
  zodHash,
222
239
  },
223
240
  value: parseJsonRecord(cachedJson),
@@ -229,15 +246,15 @@ const resolveSchemaRow = (db, ownerId, ownerKind, saveId, schemaKind, schema) =>
229
246
  jsonSchema: generated.json,
230
247
  ownerId,
231
248
  ownerKind,
232
- saveId,
233
249
  schemaKind,
250
+ snapshotId,
234
251
  zodHash,
235
252
  },
236
253
  value: generated.value,
237
254
  };
238
255
  };
239
- const materializeTrailSchema = (db, saveId, trail) => {
240
- const inputSchema = resolveSchemaRow(db, trail.id, 'trail', saveId, 'input', trail.input);
256
+ const materializeTrailSchema = (db, snapshotId, trail) => {
257
+ const inputSchema = resolveSchemaRow(db, trail.id, 'trail', snapshotId, 'input', trail.input);
241
258
  if (trail.output === undefined) {
242
259
  return {
243
260
  rows: [inputSchema.row],
@@ -246,7 +263,7 @@ const materializeTrailSchema = (db, saveId, trail) => {
246
263
  },
247
264
  };
248
265
  }
249
- const outputSchema = resolveSchemaRow(db, trail.id, 'trail', saveId, 'output', trail.output);
266
+ const outputSchema = resolveSchemaRow(db, trail.id, 'trail', snapshotId, 'output', trail.output);
250
267
  return {
251
268
  rows: [inputSchema.row, outputSchema.row],
252
269
  value: {
@@ -255,11 +272,11 @@ const materializeTrailSchema = (db, saveId, trail) => {
255
272
  },
256
273
  };
257
274
  };
258
- const materializeTrailSchemas = (db, saveId, trails) => {
275
+ const materializeTrailSchemas = (db, snapshotId, trails) => {
259
276
  const rows = [];
260
277
  const trailSchemas = new Map();
261
278
  for (const trail of trails) {
262
- const materialized = materializeTrailSchema(db, saveId, trail);
279
+ const materialized = materializeTrailSchema(db, snapshotId, trail);
263
280
  rows.push(...materialized.rows);
264
281
  trailSchemas.set(trail.id, materialized.value);
265
282
  }
@@ -268,11 +285,11 @@ const materializeTrailSchemas = (db, saveId, trails) => {
268
285
  trailSchemas,
269
286
  };
270
287
  };
271
- const materializeSignalSchemas = (db, saveId, signals) => {
288
+ const materializeSignalSchemas = (db, snapshotId, signals) => {
272
289
  const rows = [];
273
290
  const signalPayloads = new Map();
274
291
  for (const signal of signals) {
275
- const payloadSchema = resolveSchemaRow(db, signal.id, 'signal', saveId, 'payload', signal.payload);
292
+ const payloadSchema = resolveSchemaRow(db, signal.id, 'signal', snapshotId, 'payload', signal.payload);
276
293
  rows.push(payloadSchema.row);
277
294
  signalPayloads.set(signal.id, payloadSchema.value);
278
295
  }
@@ -281,9 +298,9 @@ const materializeSignalSchemas = (db, saveId, signals) => {
281
298
  signalPayloads,
282
299
  };
283
300
  };
284
- const materializeSchemas = (db, saveId, signals, trails) => {
285
- const trailMaterial = materializeTrailSchemas(db, saveId, trails);
286
- const signalMaterial = materializeSignalSchemas(db, saveId, signals);
301
+ const materializeSchemas = (db, snapshotId, signals, trails) => {
302
+ const trailMaterial = materializeTrailSchemas(db, snapshotId, trails);
303
+ const signalMaterial = materializeSignalSchemas(db, snapshotId, signals);
287
304
  return {
288
305
  rows: [...trailMaterial.rows, ...signalMaterial.rows],
289
306
  signalPayloads: signalMaterial.signalPayloads,
@@ -308,21 +325,25 @@ const addExtendedMetadata = (entry, raw, trail) => {
308
325
  if (typeof raw['replacedBy'] === 'string') {
309
326
  entry['replacedBy'] = raw['replacedBy'];
310
327
  }
311
- if (trail.detours !== undefined) {
312
- const detours = {};
313
- for (const key of Object.keys(trail.detours).toSorted()) {
314
- detours[key] = (trail.detours[key] ?? []).toSorted();
315
- }
316
- entry['detours'] = detours;
328
+ if (trail.detours.length > 0) {
329
+ entry['detours'] = trail.detours.map((d) => ({
330
+ maxAttempts: Math.max(1, Math.min(d.maxAttempts ?? 1, 5)),
331
+ on: d.on.name,
332
+ }));
317
333
  }
318
334
  };
319
335
  const addTrailRelations = (entry, trail) => {
320
336
  if (trail.crosses.length > 0) {
321
337
  entry['crosses'] = trail.crosses.toSorted();
322
338
  }
323
- if (trail.provisions.length > 0) {
324
- entry['provisions'] = trail.provisions
325
- .map((provision) => provision.id)
339
+ if (trail.contours.length > 0) {
340
+ entry['contours'] = trail.contours
341
+ .map((contour) => contour.name)
342
+ .toSorted();
343
+ }
344
+ if (trail.resources.length > 0) {
345
+ entry['resources'] = trail.resources
346
+ .map((resource) => resource.id)
326
347
  .toSorted();
327
348
  }
328
349
  };
@@ -342,6 +363,9 @@ const buildTrailEntryBase = (trail, trailSchema) => {
342
363
  if (trail.description !== undefined) {
343
364
  entry['description'] = trail.description;
344
365
  }
366
+ if (trail.pattern !== undefined) {
367
+ entry['pattern'] = trail.pattern;
368
+ }
345
369
  return {
346
370
  entry,
347
371
  raw,
@@ -374,21 +398,37 @@ const signalToEntryRecord = (signal, payloadSchema) => {
374
398
  }
375
399
  return sortKeys(entry);
376
400
  };
377
- const provisionToEntryRecord = (provision) => {
401
+ const resourceToEntryRecord = (resource) => {
378
402
  const entry = {
379
403
  exampleCount: 0,
380
- id: provision.id,
381
- kind: 'provision',
404
+ id: resource.id,
405
+ kind: 'resource',
382
406
  trailheads: [],
383
407
  };
384
- if (provision.description !== undefined) {
385
- entry['description'] = provision.description;
408
+ if (resource.description !== undefined) {
409
+ entry['description'] = resource.description;
386
410
  }
387
- if (provision.health !== undefined) {
411
+ if (resource.health !== undefined) {
388
412
  entry['healthcheck'] = true;
389
413
  }
390
414
  return sortKeys(entry);
391
415
  };
416
+ const contourToEntryRecord = (contour) => {
417
+ const schema = sortedJsonSchema(contour);
418
+ const entry = {
419
+ exampleCount: contour.examples?.length ?? 0,
420
+ id: contour.name,
421
+ identity: contour.identity,
422
+ kind: 'contour',
423
+ schema: schema.value,
424
+ trailheads: [],
425
+ };
426
+ const references = getContourReferences(contour);
427
+ if (references.length > 0) {
428
+ entry['references'] = references;
429
+ }
430
+ return sortKeys(entry);
431
+ };
392
432
  const requireTrailSchema = (trailSchemas, trailId) => {
393
433
  const schema = trailSchemas.get(trailId);
394
434
  if (schema === undefined) {
@@ -403,11 +443,12 @@ const requireSignalPayload = (signalPayloads, signalId) => {
403
443
  }
404
444
  return payload;
405
445
  };
406
- const buildTrailheadMap = (generatedAt, provisions, signalPayloads, signals, trailSchemas, trails) => {
446
+ const buildSurfaceMap = (contours, generatedAt, resources, signalPayloads, signals, trailSchemas, trails) => {
407
447
  const entries = [
448
+ ...contours.map((contour) => contourToEntryRecord(contour)),
408
449
  ...trails.map((trail) => trailToEntryRecord(trail, requireTrailSchema(trailSchemas, trail.id))),
409
450
  ...signals.map((signal) => signalToEntryRecord(signal, requireSignalPayload(signalPayloads, signal.id))),
410
- ...provisions.map((provision) => provisionToEntryRecord(provision)),
451
+ ...resources.map((resource) => resourceToEntryRecord(resource)),
411
452
  ].toSorted((a, b) => a.id.localeCompare(b.id));
412
453
  return {
413
454
  entries,
@@ -415,8 +456,8 @@ const buildTrailheadMap = (generatedAt, provisions, signalPayloads, signals, tra
415
456
  version: '1.0',
416
457
  };
417
458
  };
418
- const hashTrailheadMapRecord = (trailheadMap) => {
419
- const { generatedAt: _unused, ...rest } = trailheadMap;
459
+ const hashSurfaceMapRecord = (surfaceMap) => {
460
+ const { generatedAt: _unused, ...rest } = surfaceMap;
420
461
  return hashValue(rest);
421
462
  };
422
463
  const entryPayload = (entry) => {
@@ -426,36 +467,40 @@ const entryPayload = (entry) => {
426
467
  const entriesForKind = (entries, kind) => Object.fromEntries(entries
427
468
  .filter((entry) => entry.kind === kind)
428
469
  .map((entry) => [entry.id, entryPayload(entry)]));
429
- const buildSerializedLock = (hash, topo, trailheadMap) => sortKeys({
470
+ const buildSerializedLock = (hash, topo, surfaceMap) => sortKeys({
430
471
  apps: sortKeys({
431
472
  [topo.name]: sortKeys({
432
- provisions: entriesForKind(trailheadMap.entries, 'provision'),
433
- signals: entriesForKind(trailheadMap.entries, 'signal'),
434
- trails: entriesForKind(trailheadMap.entries, 'trail'),
473
+ contours: entriesForKind(surfaceMap.entries, 'contour'),
474
+ resources: entriesForKind(surfaceMap.entries, 'resource'),
475
+ signals: entriesForKind(surfaceMap.entries, 'signal'),
476
+ trails: entriesForKind(surfaceMap.entries, 'trail'),
435
477
  }),
436
478
  }),
437
- generatedAt: trailheadMap.generatedAt,
479
+ generatedAt: surfaceMap.generatedAt,
438
480
  hash,
439
481
  version: 1,
440
482
  });
441
- const buildStoredTopoExport = (db, save, topo) => {
483
+ const buildStoredTopoExport = (db, snapshot, topo) => {
484
+ const contours = topo
485
+ .listContours()
486
+ .toSorted((a, b) => a.name.localeCompare(b.name));
442
487
  const trails = topo.list().toSorted((a, b) => a.id.localeCompare(b.id));
443
- const provisions = topo
444
- .listProvisions()
488
+ const resources = topo
489
+ .listResources()
445
490
  .toSorted((a, b) => a.id.localeCompare(b.id));
446
491
  const signals = topo
447
492
  .listSignals()
448
493
  .toSorted((a, b) => a.id.localeCompare(b.id));
449
- const schemas = materializeSchemas(db, save.id, signals, trails);
450
- const trailheadMap = buildTrailheadMap(save.createdAt, provisions, schemas.signalPayloads, signals, schemas.trailSchemas, trails);
451
- const trailheadHash = hashTrailheadMapRecord(trailheadMap);
452
- const serializedLock = `${JSON.stringify(buildSerializedLock(trailheadHash, topo, trailheadMap), null, 2)}\n`;
494
+ const schemas = materializeSchemas(db, snapshot.id, signals, trails);
495
+ const surfaceMap = buildSurfaceMap(contours, snapshot.createdAt, resources, schemas.signalPayloads, signals, schemas.trailSchemas, trails);
496
+ const surfaceHash = hashSurfaceMapRecord(surfaceMap);
497
+ const serializedLock = `${JSON.stringify(buildSerializedLock(surfaceHash, topo, surfaceMap), null, 2)}\n`;
453
498
  return {
454
499
  exportRow: {
455
- saveId: save.id,
456
500
  serializedLock,
457
- trailheadHash,
458
- trailheadMap: `${JSON.stringify(trailheadMap, null, 2)}\n`,
501
+ snapshotId: snapshot.id,
502
+ surfaceHash,
503
+ surfaceMap: `${JSON.stringify(surfaceMap, null, 2)}\n`,
459
504
  },
460
505
  schemaRows: schemas.rows,
461
506
  };
@@ -467,8 +512,8 @@ const insertRows = (db, rows, statement, toParams) => {
467
512
  };
468
513
  const insertProjectedRows = (db, projection) => {
469
514
  insertRows(db, projection.trails, `INSERT INTO topo_trails (
470
- id, intent, idempotent, has_output, has_examples, example_count, description, meta, save_id
471
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, (row) => [
515
+ id, intent, idempotent, has_output, has_examples, example_count, description, pattern, meta, snapshot_id
516
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, (row) => [
472
517
  row.id,
473
518
  row.intent,
474
519
  row.idempotent,
@@ -476,27 +521,32 @@ const insertProjectedRows = (db, projection) => {
476
521
  row.hasExamples,
477
522
  row.exampleCount,
478
523
  row.description,
524
+ row.pattern,
479
525
  row.meta,
480
- row.saveId,
526
+ row.snapshotId,
481
527
  ]);
482
- insertRows(db, projection.crossings, 'INSERT INTO topo_crossings (source_id, target_id, save_id) VALUES (?, ?, ?)', (row) => [row.sourceId, row.targetId, row.saveId]);
483
- insertRows(db, projection.trailProvisions, `INSERT INTO topo_trail_provisions (trail_id, provision_id, save_id)
484
- VALUES (?, ?, ?)`, (row) => [row.trailId, row.provisionId, row.saveId]);
485
- insertRows(db, projection.provisions, `INSERT INTO topo_provisions (id, has_mock, has_health, save_id)
486
- VALUES (?, ?, ?, ?)`, (row) => [row.id, row.hasMock, row.hasHealth, row.saveId]);
487
- insertRows(db, projection.signals, 'INSERT INTO topo_signals (id, description, save_id) VALUES (?, ?, ?)', (row) => [row.id, row.description, row.saveId]);
488
- insertRows(db, projection.trailSignals, `INSERT INTO topo_trail_signals (trail_id, signal_id, save_id)
489
- VALUES (?, ?, ?)`, (row) => [row.trailId, row.signalId, row.saveId]);
490
- insertRows(db, projection.trailheads, `INSERT INTO topo_trailheads (trail_id, trailhead, derived_name, method, save_id)
528
+ insertRows(db, projection.crossings, 'INSERT INTO topo_crossings (source_id, target_id, snapshot_id) VALUES (?, ?, ?)', (row) => [row.sourceId, row.targetId, row.snapshotId]);
529
+ insertRows(db, projection.trailResources, `INSERT INTO topo_trail_resources (trail_id, resource_id, snapshot_id)
530
+ VALUES (?, ?, ?)`, (row) => [row.trailId, row.resourceId, row.snapshotId]);
531
+ insertRows(db, projection.resources, `INSERT INTO topo_resources (id, has_mock, has_health, snapshot_id)
532
+ VALUES (?, ?, ?, ?)`, (row) => [row.id, row.hasMock, row.hasHealth, row.snapshotId]);
533
+ insertRows(db, projection.signals, 'INSERT INTO topo_signals (id, description, snapshot_id) VALUES (?, ?, ?)', (row) => [row.id, row.description, row.snapshotId]);
534
+ insertRows(db, projection.trailSignals, `INSERT INTO topo_trail_signals (trail_id, signal_id, snapshot_id)
535
+ VALUES (?, ?, ?)`, (row) => [row.trailId, row.signalId, row.snapshotId]);
536
+ insertRows(db, projection.fires, `INSERT INTO topo_trail_fires (trail_id, signal_id, snapshot_id)
537
+ VALUES (?, ?, ?)`, (row) => [row.trailId, row.signalId, row.snapshotId]);
538
+ insertRows(db, projection.on, `INSERT INTO topo_trail_on (trail_id, signal_id, snapshot_id)
539
+ VALUES (?, ?, ?)`, (row) => [row.trailId, row.signalId, row.snapshotId]);
540
+ insertRows(db, projection.surfaces, `INSERT INTO topo_surfaces (trail_id, surface, derived_name, method, snapshot_id)
491
541
  VALUES (?, ?, ?, ?, ?)`, (row) => [
492
542
  row.trailId,
493
- row.trailhead,
543
+ row.surface,
494
544
  row.derivedName,
495
545
  row.method,
496
- row.saveId,
546
+ row.snapshotId,
497
547
  ]);
498
548
  insertRows(db, projection.examples, `INSERT INTO topo_examples (
499
- id, trail_id, ordinal, name, description, input, expected, error, save_id
549
+ id, trail_id, ordinal, name, description, input, expected, error, snapshot_id
500
550
  ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, (row) => [
501
551
  row.id,
502
552
  row.trailId,
@@ -506,66 +556,66 @@ const insertProjectedRows = (db, projection) => {
506
556
  row.input,
507
557
  row.expected,
508
558
  row.error,
509
- row.saveId,
559
+ row.snapshotId,
510
560
  ]);
511
561
  };
512
562
  const insertSchemaRows = (db, rows) => {
513
563
  insertRows(db, rows, `INSERT INTO topo_schemas (
514
- owner_id, owner_kind, schema_kind, zod_hash, json_schema, save_id
564
+ owner_id, owner_kind, schema_kind, zod_hash, json_schema, snapshot_id
515
565
  ) VALUES (?, ?, ?, ?, ?, ?)`, (row) => [
516
566
  row.ownerId,
517
567
  row.ownerKind,
518
568
  row.schemaKind,
519
569
  row.zodHash,
520
570
  row.jsonSchema,
521
- row.saveId,
571
+ row.snapshotId,
522
572
  ]);
523
573
  };
524
574
  const insertStoredExport = (db, exportRow) => {
525
575
  db.run(`INSERT INTO topo_exports (
526
- save_id, trailhead_map, trailhead_hash, serialized_lock
576
+ snapshot_id, surface_map, surface_hash, serialized_lock
527
577
  ) VALUES (?, ?, ?, ?)`, [
528
- exportRow.saveId,
529
- exportRow.trailheadMap,
530
- exportRow.trailheadHash,
578
+ exportRow.snapshotId,
579
+ exportRow.surfaceMap,
580
+ exportRow.surfaceHash,
531
581
  exportRow.serializedLock,
532
582
  ]);
533
583
  };
534
- export const getStoredTopoExport = (db, saveId) => {
584
+ export const getStoredTopoExport = (db, snapshotId) => {
535
585
  const row = db
536
- .query(`SELECT trailhead_map, trailhead_hash, serialized_lock
586
+ .query(`SELECT surface_map, surface_hash, serialized_lock
537
587
  FROM topo_exports
538
- WHERE save_id = ?`)
539
- .get(saveId);
588
+ WHERE snapshot_id = ?`)
589
+ .get(snapshotId);
540
590
  if (row === undefined || row === null) {
541
591
  return undefined;
542
592
  }
543
593
  return {
544
594
  lockContent: row.serialized_lock,
545
- trailheadHash: row.trailhead_hash,
546
- trailheadMapJson: row.trailhead_map,
595
+ surfaceHash: row.surface_hash,
596
+ surfaceMapJson: row.surface_map,
547
597
  };
548
598
  };
549
- export const persistEstablishedTopoSave = (db, topo, input) => {
599
+ export const createTopoSnapshot = (db, topo, input) => {
550
600
  const validated = validateEstablishedTopo(topo);
551
601
  if (validated.isErr()) {
552
602
  return Result.err(validated.error);
553
603
  }
554
- ensureTopoHistorySchema(db);
555
- const saveInput = {
604
+ ensureTopoSnapshotSchema(db);
605
+ const snapshotInput = {
556
606
  ...input,
557
- provisionCount: input?.provisionCount ?? topo.provisions.size,
607
+ resourceCount: input?.resourceCount ?? topo.resources.size,
558
608
  signalCount: input?.signalCount ?? topo.signals.size,
559
609
  trailCount: input?.trailCount ?? topo.trails.size,
560
610
  };
561
- const save = db.transaction(() => {
562
- const record = insertTopoSaveRecord(db, saveInput);
611
+ const snapshot = db.transaction(() => {
612
+ const record = insertTopoSnapshotRecord(db, snapshotInput);
563
613
  const artifacts = buildStoredTopoExport(db, record, topo);
564
614
  insertProjectedRows(db, normalizeTopoProjection(topo, record.id));
565
615
  insertSchemaRows(db, artifacts.schemaRows);
566
616
  insertStoredExport(db, artifacts.exportRow);
567
617
  return record;
568
618
  })();
569
- return Result.ok(save);
619
+ return Result.ok(snapshot);
570
620
  };
571
621
  //# sourceMappingURL=topo-store.js.map