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

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 (348) hide show
  1. package/CHANGELOG.md +63 -0
  2. package/README.md +61 -16
  3. package/package.json +9 -8
  4. package/src/activation-provenance.ts +111 -0
  5. package/src/activation-source-compatibility.ts +430 -0
  6. package/src/activation-source-projection.ts +221 -0
  7. package/src/activation-source.ts +91 -0
  8. package/src/blob-ref.ts +51 -0
  9. package/src/context.ts +4 -0
  10. package/src/{internal/cross-batch.ts → cross-batch.ts} +3 -11
  11. package/src/detours.ts +8 -0
  12. package/src/draft.ts +4 -0
  13. package/src/error-projection.ts +51 -0
  14. package/src/errors.ts +192 -39
  15. package/src/execute.ts +443 -44
  16. package/src/fire.ts +965 -91
  17. package/src/index.ts +285 -38
  18. package/src/layer-projection.ts +192 -0
  19. package/src/layer.ts +32 -1
  20. package/src/observe.ts +361 -0
  21. package/src/permits.ts +12 -0
  22. package/src/redaction/patterns.ts +6 -3
  23. package/src/resilience.ts +8 -8
  24. package/src/resource-config.ts +477 -44
  25. package/src/resource.ts +21 -1
  26. package/src/result.ts +18 -0
  27. package/src/run.ts +2 -2
  28. package/src/schedule-runtime.ts +689 -0
  29. package/src/schedule.ts +324 -0
  30. package/src/serialization.ts +90 -57
  31. package/src/signal-diagnostics.ts +633 -0
  32. package/src/{internal/signal-ref.ts → signal-ref.ts} +1 -1
  33. package/src/signal.ts +37 -0
  34. package/src/store/accessor-protocol.ts +5 -5
  35. package/src/structured-examples.ts +245 -0
  36. package/src/surface-derivation.ts +91 -0
  37. package/src/surface-filter.ts +7 -13
  38. package/src/topo.ts +386 -6
  39. package/src/tracing.ts +345 -0
  40. package/src/trail.ts +168 -22
  41. package/src/trails/derive-trail.ts +1 -1
  42. package/src/trails/ingest.ts +7 -15
  43. package/src/{internal/trails-db.ts → trails-db.ts} +42 -21
  44. package/src/transport-error-map.ts +146 -28
  45. package/src/types.ts +82 -28
  46. package/src/validate-established-topo.ts +6 -0
  47. package/src/validate-topo.ts +212 -5
  48. package/src/validation.ts +58 -1
  49. package/src/webhook.ts +276 -0
  50. package/src/{internal/zod-wrappers.ts → zod-wrappers.ts} +0 -6
  51. package/.turbo/turbo-build.log +0 -1
  52. package/.turbo/turbo-lint.log +0 -3
  53. package/.turbo/turbo-typecheck.log +0 -1
  54. package/dist/blob-ref.d.ts +0 -20
  55. package/dist/blob-ref.d.ts.map +0 -1
  56. package/dist/blob-ref.js +0 -22
  57. package/dist/blob-ref.js.map +0 -1
  58. package/dist/branded.d.ts +0 -36
  59. package/dist/branded.d.ts.map +0 -1
  60. package/dist/branded.js +0 -89
  61. package/dist/branded.js.map +0 -1
  62. package/dist/collections.d.ts +0 -31
  63. package/dist/collections.d.ts.map +0 -1
  64. package/dist/collections.js +0 -60
  65. package/dist/collections.js.map +0 -1
  66. package/dist/context.d.ts +0 -22
  67. package/dist/context.d.ts.map +0 -1
  68. package/dist/context.js +0 -37
  69. package/dist/context.js.map +0 -1
  70. package/dist/contour.d.ts +0 -81
  71. package/dist/contour.d.ts.map +0 -1
  72. package/dist/contour.js +0 -176
  73. package/dist/contour.js.map +0 -1
  74. package/dist/cross-schema.d.ts +0 -18
  75. package/dist/cross-schema.d.ts.map +0 -1
  76. package/dist/cross-schema.js +0 -29
  77. package/dist/cross-schema.js.map +0 -1
  78. package/dist/derive.d.ts +0 -44
  79. package/dist/derive.d.ts.map +0 -1
  80. package/dist/derive.js +0 -149
  81. package/dist/derive.js.map +0 -1
  82. package/dist/draft.d.ts +0 -28
  83. package/dist/draft.d.ts.map +0 -1
  84. package/dist/draft.js +0 -157
  85. package/dist/draft.js.map +0 -1
  86. package/dist/errors.d.ts +0 -141
  87. package/dist/errors.d.ts.map +0 -1
  88. package/dist/errors.js +0 -185
  89. package/dist/errors.js.map +0 -1
  90. package/dist/execute.d.ts +0 -52
  91. package/dist/execute.d.ts.map +0 -1
  92. package/dist/execute.js +0 -511
  93. package/dist/execute.js.map +0 -1
  94. package/dist/fetch.d.ts +0 -15
  95. package/dist/fetch.d.ts.map +0 -1
  96. package/dist/fetch.js +0 -102
  97. package/dist/fetch.js.map +0 -1
  98. package/dist/fire.d.ts +0 -43
  99. package/dist/fire.d.ts.map +0 -1
  100. package/dist/fire.js +0 -185
  101. package/dist/fire.js.map +0 -1
  102. package/dist/guards.d.ts +0 -17
  103. package/dist/guards.d.ts.map +0 -1
  104. package/dist/guards.js +0 -25
  105. package/dist/guards.js.map +0 -1
  106. package/dist/index.d.ts +0 -59
  107. package/dist/index.d.ts.map +0 -1
  108. package/dist/index.js +0 -61
  109. package/dist/index.js.map +0 -1
  110. package/dist/internal/cross-batch.d.ts +0 -44
  111. package/dist/internal/cross-batch.d.ts.map +0 -1
  112. package/dist/internal/cross-batch.js +0 -58
  113. package/dist/internal/cross-batch.js.map +0 -1
  114. package/dist/internal/fork-ctx.d.ts +0 -41
  115. package/dist/internal/fork-ctx.d.ts.map +0 -1
  116. package/dist/internal/fork-ctx.js +0 -47
  117. package/dist/internal/fork-ctx.js.map +0 -1
  118. package/dist/internal/signal-ref.d.ts +0 -15
  119. package/dist/internal/signal-ref.d.ts.map +0 -1
  120. package/dist/internal/signal-ref.js +0 -41
  121. package/dist/internal/signal-ref.js.map +0 -1
  122. package/dist/internal/topo-saves.d.ts +0 -53
  123. package/dist/internal/topo-saves.d.ts.map +0 -1
  124. package/dist/internal/topo-saves.js +0 -449
  125. package/dist/internal/topo-saves.js.map +0 -1
  126. package/dist/internal/topo-snapshots.d.ts +0 -57
  127. package/dist/internal/topo-snapshots.d.ts.map +0 -1
  128. package/dist/internal/topo-snapshots.js +0 -372
  129. package/dist/internal/topo-snapshots.js.map +0 -1
  130. package/dist/internal/topo-store-read.d.ts +0 -70
  131. package/dist/internal/topo-store-read.d.ts.map +0 -1
  132. package/dist/internal/topo-store-read.js +0 -221
  133. package/dist/internal/topo-store-read.js.map +0 -1
  134. package/dist/internal/topo-store.d.ts +0 -26
  135. package/dist/internal/topo-store.d.ts.map +0 -1
  136. package/dist/internal/topo-store.js +0 -621
  137. package/dist/internal/topo-store.js.map +0 -1
  138. package/dist/internal/tracing.d.ts +0 -98
  139. package/dist/internal/tracing.d.ts.map +0 -1
  140. package/dist/internal/tracing.js +0 -102
  141. package/dist/internal/tracing.js.map +0 -1
  142. package/dist/internal/trails-db.d.ts +0 -16
  143. package/dist/internal/trails-db.d.ts.map +0 -1
  144. package/dist/internal/trails-db.js +0 -118
  145. package/dist/internal/trails-db.js.map +0 -1
  146. package/dist/internal/zod-wrappers.d.ts +0 -40
  147. package/dist/internal/zod-wrappers.d.ts.map +0 -1
  148. package/dist/internal/zod-wrappers.js +0 -59
  149. package/dist/internal/zod-wrappers.js.map +0 -1
  150. package/dist/layer.d.ts +0 -23
  151. package/dist/layer.d.ts.map +0 -1
  152. package/dist/layer.js +0 -21
  153. package/dist/layer.js.map +0 -1
  154. package/dist/path-security.d.ts +0 -28
  155. package/dist/path-security.d.ts.map +0 -1
  156. package/dist/path-security.js +0 -63
  157. package/dist/path-security.js.map +0 -1
  158. package/dist/patterns/bulk.d.ts +0 -15
  159. package/dist/patterns/bulk.d.ts.map +0 -1
  160. package/dist/patterns/bulk.js +0 -14
  161. package/dist/patterns/bulk.js.map +0 -1
  162. package/dist/patterns/change.d.ts +0 -10
  163. package/dist/patterns/change.d.ts.map +0 -1
  164. package/dist/patterns/change.js +0 -10
  165. package/dist/patterns/change.js.map +0 -1
  166. package/dist/patterns/date-range.d.ts +0 -10
  167. package/dist/patterns/date-range.d.ts.map +0 -1
  168. package/dist/patterns/date-range.js +0 -10
  169. package/dist/patterns/date-range.js.map +0 -1
  170. package/dist/patterns/index.d.ts +0 -9
  171. package/dist/patterns/index.d.ts.map +0 -1
  172. package/dist/patterns/index.js +0 -9
  173. package/dist/patterns/index.js.map +0 -1
  174. package/dist/patterns/pagination.d.ts +0 -18
  175. package/dist/patterns/pagination.d.ts.map +0 -1
  176. package/dist/patterns/pagination.js +0 -18
  177. package/dist/patterns/pagination.js.map +0 -1
  178. package/dist/patterns/progress.d.ts +0 -11
  179. package/dist/patterns/progress.d.ts.map +0 -1
  180. package/dist/patterns/progress.js +0 -11
  181. package/dist/patterns/progress.js.map +0 -1
  182. package/dist/patterns/sorting.d.ts +0 -13
  183. package/dist/patterns/sorting.d.ts.map +0 -1
  184. package/dist/patterns/sorting.js +0 -10
  185. package/dist/patterns/sorting.js.map +0 -1
  186. package/dist/patterns/status.d.ts +0 -15
  187. package/dist/patterns/status.d.ts.map +0 -1
  188. package/dist/patterns/status.js +0 -9
  189. package/dist/patterns/status.js.map +0 -1
  190. package/dist/patterns/timestamps.d.ts +0 -10
  191. package/dist/patterns/timestamps.d.ts.map +0 -1
  192. package/dist/patterns/timestamps.js +0 -10
  193. package/dist/patterns/timestamps.js.map +0 -1
  194. package/dist/redaction/index.d.ts +0 -4
  195. package/dist/redaction/index.d.ts.map +0 -1
  196. package/dist/redaction/index.js +0 -3
  197. package/dist/redaction/index.js.map +0 -1
  198. package/dist/redaction/patterns.d.ts +0 -9
  199. package/dist/redaction/patterns.d.ts.map +0 -1
  200. package/dist/redaction/patterns.js +0 -39
  201. package/dist/redaction/patterns.js.map +0 -1
  202. package/dist/redaction/redactor.d.ts +0 -27
  203. package/dist/redaction/redactor.d.ts.map +0 -1
  204. package/dist/redaction/redactor.js +0 -89
  205. package/dist/redaction/redactor.js.map +0 -1
  206. package/dist/resilience.d.ts +0 -34
  207. package/dist/resilience.d.ts.map +0 -1
  208. package/dist/resilience.js +0 -164
  209. package/dist/resilience.js.map +0 -1
  210. package/dist/resource-config.d.ts +0 -22
  211. package/dist/resource-config.d.ts.map +0 -1
  212. package/dist/resource-config.js +0 -210
  213. package/dist/resource-config.js.map +0 -1
  214. package/dist/resource.d.ts +0 -74
  215. package/dist/resource.d.ts.map +0 -1
  216. package/dist/resource.js +0 -61
  217. package/dist/resource.js.map +0 -1
  218. package/dist/result.d.ts +0 -57
  219. package/dist/result.d.ts.map +0 -1
  220. package/dist/result.js +0 -156
  221. package/dist/result.js.map +0 -1
  222. package/dist/run.d.ts +0 -28
  223. package/dist/run.d.ts.map +0 -1
  224. package/dist/run.js +0 -35
  225. package/dist/run.js.map +0 -1
  226. package/dist/serialization.d.ts +0 -27
  227. package/dist/serialization.d.ts.map +0 -1
  228. package/dist/serialization.js +0 -154
  229. package/dist/serialization.js.map +0 -1
  230. package/dist/signal.d.ts +0 -33
  231. package/dist/signal.d.ts.map +0 -1
  232. package/dist/signal.js +0 -17
  233. package/dist/signal.js.map +0 -1
  234. package/dist/store/accessor-protocol.d.ts +0 -51
  235. package/dist/store/accessor-protocol.d.ts.map +0 -1
  236. package/dist/store/accessor-protocol.js +0 -2
  237. package/dist/store/accessor-protocol.js.map +0 -1
  238. package/dist/store/index.d.ts +0 -2
  239. package/dist/store/index.d.ts.map +0 -1
  240. package/dist/store/index.js +0 -2
  241. package/dist/store/index.js.map +0 -1
  242. package/dist/surface-filter.d.ts +0 -13
  243. package/dist/surface-filter.d.ts.map +0 -1
  244. package/dist/surface-filter.js +0 -76
  245. package/dist/surface-filter.js.map +0 -1
  246. package/dist/topo-store.d.ts +0 -62
  247. package/dist/topo-store.d.ts.map +0 -1
  248. package/dist/topo-store.js +0 -319
  249. package/dist/topo-store.js.map +0 -1
  250. package/dist/topo.d.ts +0 -39
  251. package/dist/topo.d.ts.map +0 -1
  252. package/dist/topo.js +0 -241
  253. package/dist/topo.js.map +0 -1
  254. package/dist/trail.d.ts +0 -163
  255. package/dist/trail.d.ts.map +0 -1
  256. package/dist/trail.js +0 -75
  257. package/dist/trail.js.map +0 -1
  258. package/dist/trails/derive-trail.d.ts +0 -66
  259. package/dist/trails/derive-trail.d.ts.map +0 -1
  260. package/dist/trails/derive-trail.js +0 -378
  261. package/dist/trails/derive-trail.js.map +0 -1
  262. package/dist/trails/index.d.ts +0 -5
  263. package/dist/trails/index.d.ts.map +0 -1
  264. package/dist/trails/index.js +0 -3
  265. package/dist/trails/index.js.map +0 -1
  266. package/dist/trails/ingest.d.ts +0 -24
  267. package/dist/trails/ingest.d.ts.map +0 -1
  268. package/dist/trails/ingest.js +0 -63
  269. package/dist/trails/ingest.js.map +0 -1
  270. package/dist/transport-error-map.d.ts +0 -106
  271. package/dist/transport-error-map.d.ts.map +0 -1
  272. package/dist/transport-error-map.js +0 -24
  273. package/dist/transport-error-map.js.map +0 -1
  274. package/dist/type-checks.test-d.d.ts +0 -71
  275. package/dist/type-checks.test-d.d.ts.map +0 -1
  276. package/dist/type-checks.test-d.js +0 -12
  277. package/dist/type-checks.test-d.js.map +0 -1
  278. package/dist/type-utils.d.ts +0 -33
  279. package/dist/type-utils.d.ts.map +0 -1
  280. package/dist/type-utils.js +0 -12
  281. package/dist/type-utils.js.map +0 -1
  282. package/dist/types.d.ts +0 -177
  283. package/dist/types.d.ts.map +0 -1
  284. package/dist/types.js +0 -3
  285. package/dist/types.js.map +0 -1
  286. package/dist/validate-established-topo.d.ts +0 -76
  287. package/dist/validate-established-topo.d.ts.map +0 -1
  288. package/dist/validate-established-topo.js +0 -43
  289. package/dist/validate-established-topo.js.map +0 -1
  290. package/dist/validate-topo.d.ts +0 -24
  291. package/dist/validate-topo.d.ts.map +0 -1
  292. package/dist/validate-topo.js +0 -193
  293. package/dist/validate-topo.js.map +0 -1
  294. package/dist/validation.d.ts +0 -27
  295. package/dist/validation.d.ts.map +0 -1
  296. package/dist/validation.js +0 -165
  297. package/dist/validation.js.map +0 -1
  298. package/dist/workspace.d.ts +0 -25
  299. package/dist/workspace.d.ts.map +0 -1
  300. package/dist/workspace.js +0 -57
  301. package/dist/workspace.js.map +0 -1
  302. package/src/__tests__/blob-ref.test.ts +0 -103
  303. package/src/__tests__/branded.test.ts +0 -148
  304. package/src/__tests__/collections.test.ts +0 -126
  305. package/src/__tests__/context.test.ts +0 -77
  306. package/src/__tests__/contour.test.ts +0 -263
  307. package/src/__tests__/derive-trail.test.ts +0 -668
  308. package/src/__tests__/derive.test.ts +0 -260
  309. package/src/__tests__/errors.test.ts +0 -427
  310. package/src/__tests__/execute.test.ts +0 -1563
  311. package/src/__tests__/fetch.test.ts +0 -217
  312. package/src/__tests__/fire.test.ts +0 -1056
  313. package/src/__tests__/fork-ctx.test.ts +0 -83
  314. package/src/__tests__/guards.test.ts +0 -102
  315. package/src/__tests__/ingest.test.ts +0 -191
  316. package/src/__tests__/layer.test.ts +0 -125
  317. package/src/__tests__/path-security.test.ts +0 -114
  318. package/src/__tests__/patterns.test.ts +0 -273
  319. package/src/__tests__/redaction.test.ts +0 -244
  320. package/src/__tests__/resilience.test.ts +0 -246
  321. package/src/__tests__/resource.test.ts +0 -204
  322. package/src/__tests__/result.test.ts +0 -155
  323. package/src/__tests__/run.test.ts +0 -181
  324. package/src/__tests__/serialization.test.ts +0 -401
  325. package/src/__tests__/service-config.test.ts +0 -224
  326. package/src/__tests__/signal.test.ts +0 -82
  327. package/src/__tests__/surface-filter.test.ts +0 -196
  328. package/src/__tests__/topo-store-read.test.ts +0 -256
  329. package/src/__tests__/topo-store.test.ts +0 -869
  330. package/src/__tests__/topo.test.ts +0 -573
  331. package/src/__tests__/trail-permit.test.ts +0 -60
  332. package/src/__tests__/trail.test.ts +0 -426
  333. package/src/__tests__/trails-db.test.ts +0 -198
  334. package/src/__tests__/transport-error-map.test.ts +0 -82
  335. package/src/__tests__/type-utils.test.ts +0 -118
  336. package/src/__tests__/validate-topo.test.ts +0 -611
  337. package/src/__tests__/validation.test.ts +0 -336
  338. package/src/__tests__/workspace.test.ts +0 -183
  339. package/src/__tests__/zod-wrappers.test.ts +0 -62
  340. package/src/internal/topo-snapshots.ts +0 -517
  341. package/src/internal/topo-store-read.ts +0 -481
  342. package/src/internal/topo-store.ts +0 -1192
  343. package/src/internal/tracing.ts +0 -187
  344. package/src/topo-store.ts +0 -510
  345. package/src/type-checks.test-d.ts +0 -106
  346. package/tsconfig.json +0 -9
  347. package/tsconfig.tests.json +0 -10
  348. package/tsconfig.tsbuildinfo +0 -1
@@ -1,187 +0,0 @@
1
- /**
2
- * Intrinsic tracing primitives.
3
- *
4
- * This module is the home for the trace record type, the sink interface,
5
- * the sink registry, and the helpers `executeTrail` uses to create root
6
- * trace records and child spans. It is intentionally framework-internal —
7
- * the `@ontrails/tracing` package re-exports the public surface so callers
8
- * can continue to import from there.
9
- *
10
- * Tracing is intrinsic: every `executeTrail` call automatically produces a
11
- * root `TraceRecord`, and `ctx.trace(label, fn)` creates nested child spans
12
- * underneath it. A default no-op sink is installed at module load so core
13
- * never crashes when no real sink has been registered.
14
- */
15
-
16
- /** Evidence of a single trail execution or manual span. */
17
- export interface TraceRecord {
18
- readonly id: string;
19
- readonly traceId: string;
20
- readonly rootId: string;
21
- readonly parentId?: string | undefined;
22
- readonly kind: 'trail' | 'span';
23
- readonly name: string;
24
- readonly trailId?: string | undefined;
25
- readonly trailhead?: 'cli' | 'mcp' | 'http' | 'ws' | undefined;
26
- readonly intent?: 'read' | 'write' | 'destroy' | undefined;
27
- readonly startedAt: number;
28
- readonly endedAt?: number | undefined;
29
- readonly status: 'ok' | 'err' | 'cancelled';
30
- readonly errorCategory?: string | undefined;
31
- readonly permit?:
32
- | { readonly id: string; readonly tenantId?: string }
33
- | undefined;
34
- readonly attrs: Readonly<Record<string, unknown>>;
35
- }
36
-
37
- /**
38
- * Minimal shape a tracing sink must satisfy.
39
- *
40
- * Kept intentionally tiny so adapters in `@ontrails/tracing`,
41
- * `@ontrails/observe`, and user code can all satisfy it without
42
- * additional dependencies.
43
- */
44
- export interface TraceSink {
45
- readonly write: (record: TraceRecord) => void | Promise<void>;
46
- }
47
-
48
- /** Trace context carried through trail execution via `ctx.extensions`. */
49
- export interface TraceContext {
50
- readonly traceId: string;
51
- readonly spanId: string;
52
- readonly rootId: string;
53
- readonly sampled: boolean;
54
- }
55
-
56
- /** Key used to store trace context in `ctx.extensions`. */
57
- export const TRACE_CONTEXT_KEY = '__trace_context';
58
-
59
- /** Read trace context from trail context extensions. */
60
- export const getTraceContext = (ctx: {
61
- readonly extensions?: Readonly<Record<string, unknown>> | undefined;
62
- }): TraceContext | undefined =>
63
- ctx.extensions?.[TRACE_CONTEXT_KEY] as TraceContext | undefined;
64
-
65
- // ---------------------------------------------------------------------------
66
- // Default no-op sink + sink registry
67
- // ---------------------------------------------------------------------------
68
-
69
- /** No-op sink installed by default so core never crashes without configuration. */
70
- export const NOOP_SINK: TraceSink = {
71
- // oxlint-disable-next-line no-empty-function -- intentional no-op
72
- write: () => {},
73
- };
74
-
75
- // oxlint-disable-next-line eslint-plugin-jest/require-hook -- module-level sink registry, not test setup
76
- let currentSink: TraceSink = NOOP_SINK;
77
-
78
- /**
79
- * Register a trace sink globally.
80
- *
81
- * All trails executed via `executeTrail` will write their completed trace
82
- * records to this sink, as will every `ctx.trace(label, fn)` child span.
83
- * Registering `undefined` or calling {@link clearTraceSink} resets back to
84
- * the default no-op sink.
85
- */
86
- export const registerTraceSink = (sink: TraceSink | undefined): void => {
87
- currentSink = sink ?? NOOP_SINK;
88
- };
89
-
90
- /** Retrieve the currently registered sink (never undefined). */
91
- export const getTraceSink = (): TraceSink => currentSink;
92
-
93
- /** True when tracing is effectively disabled and executeTrail should skip allocation. */
94
- export const isTracingDisabled = (sink: TraceSink = currentSink): boolean =>
95
- sink === NOOP_SINK;
96
-
97
- /** Reset the sink registry back to the default no-op sink. */
98
- export const clearTraceSink = (): void => {
99
- currentSink = NOOP_SINK;
100
- };
101
-
102
- // ---------------------------------------------------------------------------
103
- // Record + span helpers
104
- // ---------------------------------------------------------------------------
105
-
106
- /** Options for creating a trail-scoped {@link TraceRecord}. */
107
- interface CreateTraceRecordOptions {
108
- readonly trailId: string;
109
- readonly traceId?: string | undefined;
110
- readonly parentId?: string | undefined;
111
- readonly rootId?: string | undefined;
112
- readonly trailhead?: TraceRecord['trailhead'];
113
- readonly intent?: TraceRecord['intent'];
114
- readonly permit?:
115
- | { readonly id: string; readonly tenantId?: string }
116
- | undefined;
117
- }
118
-
119
- /** Create a fresh trail-kind {@link TraceRecord}. */
120
- export const createTraceRecord = (
121
- options: CreateTraceRecordOptions
122
- ): TraceRecord => {
123
- const id = Bun.randomUUIDv7();
124
- const traceId = options.traceId ?? Bun.randomUUIDv7();
125
-
126
- return {
127
- attrs: {},
128
- endedAt: undefined,
129
- id,
130
- intent: options.intent,
131
- kind: 'trail',
132
- name: options.trailId,
133
- parentId: options.parentId,
134
- permit: options.permit,
135
- rootId: options.rootId ?? id,
136
- startedAt: Date.now(),
137
- status: 'ok',
138
- traceId,
139
- trailId: options.trailId,
140
- trailhead: options.trailhead,
141
- };
142
- };
143
-
144
- /** Build a span record from a parent trace context. */
145
- export const createSpanRecord = (
146
- parent: TraceContext,
147
- label: string
148
- ): TraceRecord => ({
149
- attrs: {},
150
- endedAt: undefined,
151
- errorCategory: undefined,
152
- id: Bun.randomUUIDv7(),
153
- intent: undefined,
154
- kind: 'span',
155
- name: label,
156
- parentId: parent.spanId,
157
- rootId: parent.rootId,
158
- startedAt: Date.now(),
159
- status: 'ok',
160
- traceId: parent.traceId,
161
- trailId: undefined,
162
- trailhead: undefined,
163
- });
164
-
165
- /** Mark a record as completed with timing and status. */
166
- export const completeRecord = (
167
- record: TraceRecord,
168
- status: TraceRecord['status'],
169
- errorCategory?: string | undefined
170
- ): TraceRecord => ({
171
- ...record,
172
- endedAt: Date.now(),
173
- errorCategory,
174
- status,
175
- });
176
-
177
- /** Best-effort sink write that never throws. */
178
- export const writeToSink = async (
179
- sink: TraceSink,
180
- record: TraceRecord
181
- ): Promise<void> => {
182
- try {
183
- await Promise.resolve(sink.write(record));
184
- } catch {
185
- // Sink failures must never affect trail result delivery.
186
- }
187
- };
package/src/topo-store.ts DELETED
@@ -1,510 +0,0 @@
1
- import type { SQLQueryBindings } from 'bun:sqlite';
2
- import { existsSync, statSync } from 'node:fs';
3
-
4
- import { NotFoundError } from './errors.js';
5
- import type { Topo } from './topo.js';
6
- import { resource } from './resource.js';
7
- import { Result } from './result.js';
8
- import {
9
- TOPO_SCHEMA_VERSION,
10
- ensureTopoSnapshotSchema,
11
- listTopoSnapshots as listStoredTopoSnapshots,
12
- pinTopoSnapshot as pinStoredTopoSnapshot,
13
- unpinTopoSnapshot as unpinStoredTopoSnapshot,
14
- } from './internal/topo-snapshots.js';
15
- import type {
16
- CreateTopoSnapshotInput,
17
- ListTopoSnapshotsOptions,
18
- TopoSnapshot,
19
- } from './internal/topo-snapshots.js';
20
- import type {
21
- TopoStoreExportRecord,
22
- TopoStoreResourceRecord,
23
- TopoStoreRef,
24
- TopoStoreTrailDetailRecord,
25
- TopoStoreTrailRecord,
26
- } from './internal/topo-store-read.js';
27
- import {
28
- getTopoStoreExport,
29
- getTopoStoreResource,
30
- getTopoStoreTrail,
31
- listTopoStoreResources,
32
- listTopoStoreSnapshots,
33
- listTopoStoreTrails,
34
- queryTopoStore,
35
- readTopoStoreSnapshot,
36
- } from './internal/topo-store-read.js';
37
- import { createTopoSnapshot as storeTopoSnapshot } from './internal/topo-store.js';
38
- import {
39
- openReadTrailsDb,
40
- openWriteTrailsDb,
41
- deriveTrailsDbPath,
42
- } from './internal/trails-db.js';
43
- import type { TrailsDbLocationOptions } from './internal/trails-db.js';
44
-
45
- interface MigratedDbIdentity {
46
- readonly mtimeMs: number;
47
- readonly size: number;
48
- }
49
-
50
- const migratedTopoDbPaths = new Map<string, MigratedDbIdentity>();
51
-
52
- /**
53
- * Test-only instrumentation counters. Incremented by the read-path migration
54
- * check to let tests assert that a current-schema store does not escalate to
55
- * a write-mode open, and that cache invalidation re-runs the check when the
56
- * underlying file is replaced.
57
- *
58
- * @internal
59
- */
60
- export const __topoStoreMigrationStats = {
61
- peekCalls: 0,
62
- writeEscalations: 0,
63
- };
64
-
65
- const peekTopoSchemaVersion = (
66
- options: TrailsDbLocationOptions | undefined
67
- ): number | undefined => {
68
- let db: ReturnType<typeof openReadTrailsDb> | undefined;
69
- try {
70
- db = openReadTrailsDb(options);
71
- const row = db
72
- .query<{ version: number }, [string]>(
73
- 'SELECT version FROM meta_schema_versions WHERE subsystem = ?'
74
- )
75
- .get('topo');
76
- return row?.version ?? 0;
77
- } catch {
78
- // Table missing or unexpected shape: caller will escalate to a write-mode
79
- // open and run the migration, which rebuilds the schema.
80
- return undefined;
81
- } finally {
82
- db?.close();
83
- }
84
- };
85
-
86
- const statIdentity = (dbPath: string): MigratedDbIdentity | undefined => {
87
- try {
88
- const info = statSync(dbPath);
89
- return { mtimeMs: info.mtimeMs, size: info.size };
90
- } catch {
91
- return undefined;
92
- }
93
- };
94
-
95
- const identitiesEqual = (
96
- a: MigratedDbIdentity,
97
- b: MigratedDbIdentity
98
- ): boolean => a.mtimeMs === b.mtimeMs && a.size === b.size;
99
-
100
- const runTopoMigrationEscalation = (
101
- options: TrailsDbLocationOptions | undefined,
102
- dbPath: string,
103
- fallbackIdentity: MigratedDbIdentity
104
- ): void => {
105
- __topoStoreMigrationStats.writeEscalations += 1;
106
- const db = openWriteTrailsDb(options);
107
- try {
108
- ensureTopoSnapshotSchema(db);
109
- } finally {
110
- db.close();
111
- }
112
- // Re-stat after the migration so the cached identity matches the file we
113
- // just touched, avoiding a spurious second escalation on the next read.
114
- const postIdentity = statIdentity(dbPath) ?? fallbackIdentity;
115
- migratedTopoDbPaths.set(dbPath, postIdentity);
116
- };
117
-
118
- const resolveIdentityIfFresh = (
119
- dbPath: string
120
- ): MigratedDbIdentity | undefined => {
121
- if (!existsSync(dbPath)) {
122
- return undefined;
123
- }
124
- const identity = statIdentity(dbPath);
125
- if (identity === undefined) {
126
- return undefined;
127
- }
128
- const cached = migratedTopoDbPaths.get(dbPath);
129
- if (cached !== undefined && identitiesEqual(cached, identity)) {
130
- return undefined;
131
- }
132
- return identity;
133
- };
134
-
135
- /**
136
- * Ensure the topo snapshot schema is at the current version before any
137
- * read-only access. Peeks the version through a read-only handle first and
138
- * only escalates to a write-mode open + migration when the store is stale.
139
- *
140
- * Memoized per resolved DB path keyed on file identity (mtime + size) so a
141
- * long-running process that deletes and recreates `trails.db` re-runs the
142
- * migration check against the fresh file.
143
- *
144
- * If the DB file does not yet exist, this is a no-op — the downstream read
145
- * path will surface its own NotFoundError.
146
- */
147
- const ensureTopoMigratedIfExists = (
148
- options?: TrailsDbLocationOptions
149
- ): void => {
150
- const dbPath = deriveTrailsDbPath(options);
151
- const identity = resolveIdentityIfFresh(dbPath);
152
- if (identity === undefined) {
153
- return;
154
- }
155
-
156
- __topoStoreMigrationStats.peekCalls += 1;
157
- const version = peekTopoSchemaVersion(options);
158
- if (version !== undefined && version >= TOPO_SCHEMA_VERSION) {
159
- // Already current — record identity and skip the write-mode open entirely,
160
- // preserving the read-only contract for callers whose filesystem mounts
161
- // `trails.db` read-only.
162
- migratedTopoDbPaths.set(dbPath, identity);
163
- return;
164
- }
165
-
166
- runTopoMigrationEscalation(options, dbPath, identity);
167
- };
168
-
169
- export type {
170
- TopoStoreExportRecord,
171
- TopoStoreResourceRecord,
172
- TopoStoreRef,
173
- TopoStoreTrailDetailRecord,
174
- TopoStoreTrailRecord,
175
- } from './internal/topo-store-read.js';
176
- export type {
177
- CreateTopoSnapshotInput,
178
- ListTopoSnapshotsOptions,
179
- TopoSnapshot,
180
- } from './internal/topo-snapshots.js';
181
-
182
- export interface ReadOnlyTopoStore {
183
- readonly exports: {
184
- get(ref?: TopoStoreRef): TopoStoreExportRecord | undefined;
185
- };
186
- query<TRow extends Record<string, unknown>>(
187
- sql: string,
188
- bindings?: readonly SQLQueryBindings[]
189
- ): readonly TRow[];
190
- readonly resources: {
191
- get(
192
- id: string,
193
- options?: { readonly snapshot?: TopoStoreRef }
194
- ): TopoStoreResourceRecord | undefined;
195
- list(options?: {
196
- readonly snapshot?: TopoStoreRef;
197
- }): readonly TopoStoreResourceRecord[];
198
- };
199
- readonly snapshots: {
200
- get(ref?: TopoStoreRef): TopoSnapshot | undefined;
201
- latest(): TopoSnapshot | undefined;
202
- list(options?: ListTopoSnapshotsOptions): readonly TopoSnapshot[];
203
- };
204
- readonly trails: {
205
- get(
206
- id: string,
207
- options?: { readonly snapshot?: TopoStoreRef }
208
- ): TopoStoreTrailDetailRecord | undefined;
209
- list(options?: {
210
- readonly intent?: TopoStoreTrailRecord['intent'];
211
- readonly snapshot?: TopoStoreRef;
212
- }): readonly TopoStoreTrailRecord[];
213
- };
214
- }
215
-
216
- export interface MockTopoStoreSeed {
217
- readonly exports?: readonly TopoStoreExportRecord[];
218
- readonly resources?: readonly TopoStoreResourceRecord[];
219
- readonly snapshots?: readonly TopoSnapshot[];
220
- readonly trails?: readonly TopoStoreTrailDetailRecord[];
221
- }
222
-
223
- const missingStoreMessage =
224
- 'No saved topo state found. Populate trails.db first or run a topo-backed surface.';
225
-
226
- const resolveStoreRootDir = (options?: TrailsDbLocationOptions): string =>
227
- options?.rootDir ?? process.cwd();
228
-
229
- const requireReadDb = (
230
- options?: TrailsDbLocationOptions
231
- ): ReturnType<typeof openReadTrailsDb> => {
232
- const dbPath = deriveTrailsDbPath(options);
233
- if (!existsSync(dbPath)) {
234
- throw new NotFoundError(missingStoreMessage);
235
- }
236
- ensureTopoMigratedIfExists(options);
237
- return openReadTrailsDb(options);
238
- };
239
-
240
- const requireSavedTopoState = (
241
- db: ReturnType<typeof openReadTrailsDb>
242
- ): void => {
243
- if (readTopoStoreSnapshot(db) === undefined) {
244
- throw new NotFoundError(missingStoreMessage);
245
- }
246
- };
247
-
248
- const withStoredTopoState = <T>(
249
- options: TrailsDbLocationOptions | undefined,
250
- run: (db: ReturnType<typeof openReadTrailsDb>) => T
251
- ): T => {
252
- const db = requireReadDb(options);
253
- try {
254
- requireSavedTopoState(db);
255
- return run(db);
256
- } finally {
257
- db.close();
258
- }
259
- };
260
-
261
- const createSeedResolver = (seed?: MockTopoStoreSeed) => {
262
- const snapshots = [...(seed?.snapshots ?? [])];
263
- const trails = [...(seed?.trails ?? [])];
264
- const resources = [...(seed?.resources ?? [])];
265
- const exports = [...(seed?.exports ?? [])];
266
-
267
- const resolveSnapshot = (ref?: TopoStoreRef): TopoSnapshot | undefined => {
268
- if (ref?.snapshotId !== undefined) {
269
- return snapshots.find((snapshot) => snapshot.id === ref.snapshotId);
270
- }
271
- if (ref?.pin !== undefined) {
272
- return snapshots.find((snapshot) => snapshot.pinnedAs === ref.pin);
273
- }
274
- return snapshots[0];
275
- };
276
-
277
- return {
278
- exports,
279
- resolveSnapshot,
280
- resources,
281
- snapshots,
282
- trails,
283
- };
284
- };
285
-
286
- export const createMockTopoStore = (
287
- seed?: MockTopoStoreSeed
288
- ): ReadOnlyTopoStore => {
289
- const resolved = createSeedResolver(seed);
290
-
291
- return {
292
- exports: {
293
- get(ref?: TopoStoreRef) {
294
- const snapshot = resolved.resolveSnapshot(ref);
295
- return snapshot === undefined
296
- ? undefined
297
- : resolved.exports.find((entry) => entry.snapshot.id === snapshot.id);
298
- },
299
- },
300
- query() {
301
- throw new NotFoundError(
302
- 'Mock topoStore.query() is unsupported. Seed typed accessors instead.'
303
- );
304
- },
305
- resources: {
306
- get(id, options) {
307
- const snapshot = resolved.resolveSnapshot(options?.snapshot);
308
- return resolved.resources.find(
309
- (item) =>
310
- item.id === id &&
311
- (snapshot === undefined || item.snapshotId === snapshot.id)
312
- );
313
- },
314
- list(options) {
315
- const snapshot = resolved.resolveSnapshot(options?.snapshot);
316
- return snapshot === undefined
317
- ? []
318
- : resolved.resources.filter(
319
- (item) => item.snapshotId === snapshot.id
320
- );
321
- },
322
- },
323
- snapshots: {
324
- get(ref?: TopoStoreRef) {
325
- return resolved.resolveSnapshot(ref);
326
- },
327
- latest() {
328
- return resolved.snapshots[0];
329
- },
330
- list(options) {
331
- let snapshots =
332
- options?.pinned === undefined
333
- ? resolved.snapshots
334
- : resolved.snapshots.filter((snapshot) =>
335
- options.pinned
336
- ? snapshot.pinnedAs !== undefined
337
- : snapshot.pinnedAs === undefined
338
- );
339
- if (options?.before !== undefined) {
340
- const target = snapshots.find((s) => s.id === options.before);
341
- if (target !== undefined) {
342
- snapshots = snapshots.filter(
343
- (s) =>
344
- s.createdAt < target.createdAt ||
345
- (s.createdAt === target.createdAt && s.id < target.id)
346
- );
347
- }
348
- }
349
- if (options?.limit !== undefined) {
350
- snapshots = snapshots.slice(0, options.limit);
351
- }
352
- return snapshots;
353
- },
354
- },
355
- trails: {
356
- get(id, options) {
357
- const snapshot = resolved.resolveSnapshot(options?.snapshot);
358
- if (snapshot === undefined) {
359
- return;
360
- }
361
- return resolved.trails.find(
362
- (trail) => trail.id === id && trail.snapshotId === snapshot.id
363
- );
364
- },
365
- list(options) {
366
- const snapshot = resolved.resolveSnapshot(options?.snapshot);
367
- if (snapshot === undefined) {
368
- return [];
369
- }
370
- return resolved.trails.filter(
371
- (trail) =>
372
- trail.snapshotId === snapshot.id &&
373
- (options?.intent === undefined || trail.intent === options.intent)
374
- );
375
- },
376
- },
377
- };
378
- };
379
-
380
- export const createTopoStore = (
381
- options?: TrailsDbLocationOptions
382
- ): ReadOnlyTopoStore => ({
383
- exports: {
384
- get(ref?: TopoStoreRef) {
385
- return withStoredTopoState(options, (db) => getTopoStoreExport(db, ref));
386
- },
387
- },
388
- query<TRow extends Record<string, unknown>>(
389
- sql: string,
390
- bindings?: readonly SQLQueryBindings[]
391
- ) {
392
- return withStoredTopoState(options, (db) =>
393
- queryTopoStore<TRow>(db, sql, bindings)
394
- );
395
- },
396
- resources: {
397
- get(id, queryOptions) {
398
- return withStoredTopoState(options, (db) =>
399
- getTopoStoreResource(db, id, queryOptions)
400
- );
401
- },
402
- list(queryOptions) {
403
- return withStoredTopoState(options, (db) =>
404
- listTopoStoreResources(db, queryOptions)
405
- );
406
- },
407
- },
408
- snapshots: {
409
- get(ref?: TopoStoreRef) {
410
- return withStoredTopoState(options, (db) =>
411
- readTopoStoreSnapshot(db, ref)
412
- );
413
- },
414
- latest() {
415
- return withStoredTopoState(options, (db) => readTopoStoreSnapshot(db));
416
- },
417
- list(snapshotOptions) {
418
- return withStoredTopoState(options, (db) =>
419
- listTopoStoreSnapshots(db, snapshotOptions)
420
- );
421
- },
422
- },
423
- trails: {
424
- get(id, queryOptions) {
425
- return withStoredTopoState(options, (db) =>
426
- getTopoStoreTrail(db, id, queryOptions)
427
- );
428
- },
429
- list(queryOptions) {
430
- return withStoredTopoState(options, (db) =>
431
- listTopoStoreTrails(db, queryOptions)
432
- );
433
- },
434
- },
435
- });
436
-
437
- export const createTopoSnapshot = (
438
- topo: Topo,
439
- options?: TrailsDbLocationOptions & CreateTopoSnapshotInput
440
- ): Result<TopoSnapshot, Error> => {
441
- const db = openWriteTrailsDb(options);
442
- try {
443
- return storeTopoSnapshot(db, topo, options);
444
- } finally {
445
- db.close();
446
- }
447
- };
448
-
449
- export const listTopoSnapshots = (
450
- options?: TrailsDbLocationOptions & ListTopoSnapshotsOptions
451
- ): readonly TopoSnapshot[] => {
452
- const dbPath = deriveTrailsDbPath(options);
453
- if (!existsSync(dbPath)) {
454
- return [];
455
- }
456
-
457
- ensureTopoMigratedIfExists(options);
458
- const db = openReadTrailsDb(options);
459
- try {
460
- return listStoredTopoSnapshots(db, options);
461
- } finally {
462
- db.close();
463
- }
464
- };
465
-
466
- export const pinTopoSnapshot = (
467
- id: string,
468
- name: string,
469
- options?: TrailsDbLocationOptions
470
- ): TopoSnapshot | undefined => {
471
- const dbPath = deriveTrailsDbPath(options);
472
- if (!existsSync(dbPath)) {
473
- return undefined;
474
- }
475
-
476
- const db = openWriteTrailsDb(options);
477
- try {
478
- return pinStoredTopoSnapshot(db, { id, name });
479
- } finally {
480
- db.close();
481
- }
482
- };
483
-
484
- export const unpinTopoSnapshot = (
485
- nameOrId: string,
486
- options?: TrailsDbLocationOptions
487
- ): TopoSnapshot | undefined => {
488
- const dbPath = deriveTrailsDbPath(options);
489
- if (!existsSync(dbPath)) {
490
- return undefined;
491
- }
492
-
493
- const db = openWriteTrailsDb(options);
494
- try {
495
- return unpinStoredTopoSnapshot(db, nameOrId);
496
- } finally {
497
- db.close();
498
- }
499
- };
500
-
501
- export const topoStore = resource('topo.store', {
502
- create: (svc) =>
503
- Result.ok(
504
- createTopoStore({
505
- rootDir: svc.workspaceRoot ?? svc.cwd ?? resolveStoreRootDir(),
506
- })
507
- ),
508
- description: 'Read-only query access to saved topo state in trails.db',
509
- mock: () => createMockTopoStore(),
510
- });