@ontrails/core 1.0.0-beta.5 → 1.0.0-beta.50

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 (252) hide show
  1. package/CHANGELOG.md +459 -14
  2. package/README.md +103 -28
  3. package/package.json +16 -1
  4. package/src/activation-provenance.ts +116 -0
  5. package/src/activation-source-compatibility.ts +430 -0
  6. package/src/activation-source-derivation.ts +227 -0
  7. package/src/activation-source.ts +93 -0
  8. package/src/blob-ref.ts +51 -0
  9. package/src/branded.ts +1 -1
  10. package/src/compose-batch.ts +69 -0
  11. package/src/compose-schema.ts +36 -0
  12. package/src/context.ts +59 -11
  13. package/src/derive.ts +271 -19
  14. package/src/detours.ts +8 -0
  15. package/src/diagnostics.ts +21 -0
  16. package/src/draft.ts +350 -0
  17. package/src/entity.ts +346 -0
  18. package/src/error-rendering.ts +87 -0
  19. package/src/errors.ts +335 -48
  20. package/src/execute.ts +1577 -0
  21. package/src/fire.ts +1172 -0
  22. package/src/glob.ts +81 -0
  23. package/src/index.ts +569 -33
  24. package/src/internal/fork-ctx.ts +69 -0
  25. package/src/layer-field-rendering.ts +193 -0
  26. package/src/layer.ts +43 -6
  27. package/src/observe.ts +361 -0
  28. package/src/path-scope.ts +66 -0
  29. package/src/path-security.ts +11 -3
  30. package/src/permits.ts +12 -0
  31. package/src/queue.ts +163 -0
  32. package/src/redaction/patterns.ts +6 -3
  33. package/src/resilience.ts +11 -11
  34. package/src/resource-config.ts +804 -0
  35. package/src/resource.ts +194 -0
  36. package/src/result.ts +18 -0
  37. package/src/run.ts +76 -0
  38. package/src/runtime-builtins.ts +69 -0
  39. package/src/schedule-runtime.ts +689 -0
  40. package/src/schedule.ts +326 -0
  41. package/src/serialization.ts +92 -55
  42. package/src/sha256.ts +136 -0
  43. package/src/signal-diagnostics.ts +633 -0
  44. package/src/signal-ref.ts +111 -0
  45. package/src/signal.ts +104 -0
  46. package/src/store/accessor-protocol.ts +56 -0
  47. package/src/store/index.ts +4 -0
  48. package/src/structured-examples.ts +248 -0
  49. package/src/surface-derivation.ts +91 -0
  50. package/src/surface-filter.ts +101 -0
  51. package/src/surface-overlay.ts +694 -0
  52. package/src/surface-versioning.ts +42 -0
  53. package/src/topo.ts +762 -38
  54. package/src/tracing.ts +346 -0
  55. package/src/trail-id-glob.ts +15 -0
  56. package/src/trail.ts +1244 -34
  57. package/src/trails/derive-trail.ts +835 -0
  58. package/src/trails/index.ts +9 -0
  59. package/src/trails/ingest.ts +152 -0
  60. package/src/trails-db.ts +212 -0
  61. package/src/transport-error-map.ts +163 -0
  62. package/src/type-utils.ts +63 -10
  63. package/src/types.ts +254 -12
  64. package/src/validate-established-topo.ts +73 -0
  65. package/src/validate-topo.ts +569 -55
  66. package/src/validation.ts +152 -4
  67. package/src/version-marker.ts +716 -0
  68. package/src/version-resolution.ts +308 -0
  69. package/src/version-runtime.ts +120 -0
  70. package/src/webhook.ts +461 -0
  71. package/src/workspace.ts +183 -16
  72. package/src/zod-wrappers.ts +72 -0
  73. package/.turbo/turbo-build.log +0 -1
  74. package/.turbo/turbo-lint.log +0 -3
  75. package/.turbo/turbo-typecheck.log +0 -1
  76. package/dist/adapters.d.ts +0 -39
  77. package/dist/adapters.d.ts.map +0 -1
  78. package/dist/adapters.js +0 -2
  79. package/dist/adapters.js.map +0 -1
  80. package/dist/blob-ref.d.ts +0 -20
  81. package/dist/blob-ref.d.ts.map +0 -1
  82. package/dist/blob-ref.js +0 -22
  83. package/dist/blob-ref.js.map +0 -1
  84. package/dist/branded.d.ts +0 -36
  85. package/dist/branded.d.ts.map +0 -1
  86. package/dist/branded.js +0 -89
  87. package/dist/branded.js.map +0 -1
  88. package/dist/collections.d.ts +0 -31
  89. package/dist/collections.d.ts.map +0 -1
  90. package/dist/collections.js +0 -60
  91. package/dist/collections.js.map +0 -1
  92. package/dist/context.d.ts +0 -10
  93. package/dist/context.d.ts.map +0 -1
  94. package/dist/context.js +0 -15
  95. package/dist/context.js.map +0 -1
  96. package/dist/derive.d.ts +0 -33
  97. package/dist/derive.d.ts.map +0 -1
  98. package/dist/derive.js +0 -125
  99. package/dist/derive.js.map +0 -1
  100. package/dist/errors.d.ts +0 -83
  101. package/dist/errors.d.ts.map +0 -1
  102. package/dist/errors.js +0 -142
  103. package/dist/errors.js.map +0 -1
  104. package/dist/event.d.ts +0 -45
  105. package/dist/event.d.ts.map +0 -1
  106. package/dist/event.js +0 -17
  107. package/dist/event.js.map +0 -1
  108. package/dist/fetch.d.ts +0 -15
  109. package/dist/fetch.d.ts.map +0 -1
  110. package/dist/fetch.js +0 -102
  111. package/dist/fetch.js.map +0 -1
  112. package/dist/guards.d.ts +0 -17
  113. package/dist/guards.d.ts.map +0 -1
  114. package/dist/guards.js +0 -25
  115. package/dist/guards.js.map +0 -1
  116. package/dist/health.d.ts +0 -18
  117. package/dist/health.d.ts.map +0 -1
  118. package/dist/health.js +0 -5
  119. package/dist/health.js.map +0 -1
  120. package/dist/index.d.ts +0 -36
  121. package/dist/index.d.ts.map +0 -1
  122. package/dist/index.js +0 -39
  123. package/dist/index.js.map +0 -1
  124. package/dist/job.d.ts +0 -24
  125. package/dist/job.d.ts.map +0 -1
  126. package/dist/job.js +0 -17
  127. package/dist/job.js.map +0 -1
  128. package/dist/layer.d.ts +0 -17
  129. package/dist/layer.d.ts.map +0 -1
  130. package/dist/layer.js +0 -21
  131. package/dist/layer.js.map +0 -1
  132. package/dist/path-security.d.ts +0 -28
  133. package/dist/path-security.d.ts.map +0 -1
  134. package/dist/path-security.js +0 -63
  135. package/dist/path-security.js.map +0 -1
  136. package/dist/patterns/bulk.d.ts +0 -15
  137. package/dist/patterns/bulk.d.ts.map +0 -1
  138. package/dist/patterns/bulk.js +0 -14
  139. package/dist/patterns/bulk.js.map +0 -1
  140. package/dist/patterns/change.d.ts +0 -10
  141. package/dist/patterns/change.d.ts.map +0 -1
  142. package/dist/patterns/change.js +0 -10
  143. package/dist/patterns/change.js.map +0 -1
  144. package/dist/patterns/date-range.d.ts +0 -10
  145. package/dist/patterns/date-range.d.ts.map +0 -1
  146. package/dist/patterns/date-range.js +0 -10
  147. package/dist/patterns/date-range.js.map +0 -1
  148. package/dist/patterns/index.d.ts +0 -9
  149. package/dist/patterns/index.d.ts.map +0 -1
  150. package/dist/patterns/index.js +0 -9
  151. package/dist/patterns/index.js.map +0 -1
  152. package/dist/patterns/pagination.d.ts +0 -18
  153. package/dist/patterns/pagination.d.ts.map +0 -1
  154. package/dist/patterns/pagination.js +0 -18
  155. package/dist/patterns/pagination.js.map +0 -1
  156. package/dist/patterns/progress.d.ts +0 -11
  157. package/dist/patterns/progress.d.ts.map +0 -1
  158. package/dist/patterns/progress.js +0 -11
  159. package/dist/patterns/progress.js.map +0 -1
  160. package/dist/patterns/sorting.d.ts +0 -13
  161. package/dist/patterns/sorting.d.ts.map +0 -1
  162. package/dist/patterns/sorting.js +0 -10
  163. package/dist/patterns/sorting.js.map +0 -1
  164. package/dist/patterns/status.d.ts +0 -15
  165. package/dist/patterns/status.d.ts.map +0 -1
  166. package/dist/patterns/status.js +0 -9
  167. package/dist/patterns/status.js.map +0 -1
  168. package/dist/patterns/timestamps.d.ts +0 -10
  169. package/dist/patterns/timestamps.d.ts.map +0 -1
  170. package/dist/patterns/timestamps.js +0 -10
  171. package/dist/patterns/timestamps.js.map +0 -1
  172. package/dist/redaction/index.d.ts +0 -4
  173. package/dist/redaction/index.d.ts.map +0 -1
  174. package/dist/redaction/index.js +0 -3
  175. package/dist/redaction/index.js.map +0 -1
  176. package/dist/redaction/patterns.d.ts +0 -9
  177. package/dist/redaction/patterns.d.ts.map +0 -1
  178. package/dist/redaction/patterns.js +0 -39
  179. package/dist/redaction/patterns.js.map +0 -1
  180. package/dist/redaction/redactor.d.ts +0 -27
  181. package/dist/redaction/redactor.d.ts.map +0 -1
  182. package/dist/redaction/redactor.js +0 -89
  183. package/dist/redaction/redactor.js.map +0 -1
  184. package/dist/resilience.d.ts +0 -34
  185. package/dist/resilience.d.ts.map +0 -1
  186. package/dist/resilience.js +0 -164
  187. package/dist/resilience.js.map +0 -1
  188. package/dist/result.d.ts +0 -57
  189. package/dist/result.d.ts.map +0 -1
  190. package/dist/result.js +0 -156
  191. package/dist/result.js.map +0 -1
  192. package/dist/serialization.d.ts +0 -27
  193. package/dist/serialization.d.ts.map +0 -1
  194. package/dist/serialization.js +0 -153
  195. package/dist/serialization.js.map +0 -1
  196. package/dist/topo.d.ts +0 -16
  197. package/dist/topo.d.ts.map +0 -1
  198. package/dist/topo.js +0 -66
  199. package/dist/topo.js.map +0 -1
  200. package/dist/trail.d.ts +0 -89
  201. package/dist/trail.d.ts.map +0 -1
  202. package/dist/trail.js +0 -18
  203. package/dist/trail.js.map +0 -1
  204. package/dist/type-utils.d.ts +0 -14
  205. package/dist/type-utils.d.ts.map +0 -1
  206. package/dist/type-utils.js +0 -12
  207. package/dist/type-utils.js.map +0 -1
  208. package/dist/types.d.ts +0 -46
  209. package/dist/types.d.ts.map +0 -1
  210. package/dist/types.js +0 -2
  211. package/dist/types.js.map +0 -1
  212. package/dist/validate-topo.d.ts +0 -24
  213. package/dist/validate-topo.d.ts.map +0 -1
  214. package/dist/validate-topo.js +0 -158
  215. package/dist/validate-topo.js.map +0 -1
  216. package/dist/validation.d.ts +0 -27
  217. package/dist/validation.d.ts.map +0 -1
  218. package/dist/validation.js +0 -134
  219. package/dist/validation.js.map +0 -1
  220. package/dist/workspace.d.ts +0 -25
  221. package/dist/workspace.d.ts.map +0 -1
  222. package/dist/workspace.js +0 -57
  223. package/dist/workspace.js.map +0 -1
  224. package/src/__tests__/blob-ref.test.ts +0 -103
  225. package/src/__tests__/branded.test.ts +0 -148
  226. package/src/__tests__/collections.test.ts +0 -126
  227. package/src/__tests__/context.test.ts +0 -66
  228. package/src/__tests__/derive.test.ts +0 -203
  229. package/src/__tests__/errors.test.ts +0 -309
  230. package/src/__tests__/event.test.ts +0 -82
  231. package/src/__tests__/fetch.test.ts +0 -217
  232. package/src/__tests__/guards.test.ts +0 -102
  233. package/src/__tests__/job.test.ts +0 -98
  234. package/src/__tests__/layer.test.ts +0 -212
  235. package/src/__tests__/path-security.test.ts +0 -114
  236. package/src/__tests__/patterns.test.ts +0 -273
  237. package/src/__tests__/redaction.test.ts +0 -244
  238. package/src/__tests__/resilience.test.ts +0 -246
  239. package/src/__tests__/result.test.ts +0 -155
  240. package/src/__tests__/serialization.test.ts +0 -401
  241. package/src/__tests__/topo.test.ts +0 -181
  242. package/src/__tests__/trail.test.ts +0 -217
  243. package/src/__tests__/type-utils.test.ts +0 -63
  244. package/src/__tests__/validate-topo.test.ts +0 -278
  245. package/src/__tests__/validation.test.ts +0 -283
  246. package/src/__tests__/workspace.test.ts +0 -183
  247. package/src/adapters.ts +0 -68
  248. package/src/event.ts +0 -77
  249. package/src/health.ts +0 -23
  250. package/src/job.ts +0 -20
  251. package/tsconfig.json +0 -9
  252. package/tsconfig.tsbuildinfo +0 -1
package/README.md CHANGED
@@ -15,20 +15,20 @@ const greet = trail('greet', {
15
15
  examples: [
16
16
  { name: 'Hello', input: { name: 'World' }, expected: { message: 'Hello, World!' } },
17
17
  ],
18
- run: (input) => Result.ok({ message: `Hello, ${input.name}!` }),
18
+ implementation: (input) => Result.ok({ message: `Hello, ${input.name}!` }),
19
19
  });
20
20
 
21
- const app = topo('myapp', { greet });
21
+ const graph = topo('myapp', { greet });
22
22
  ```
23
23
 
24
- Trails compose other trails through `follow` and `ctx.follow()`:
24
+ Trails compose other trails through `composes` and `ctx.compose()`:
25
25
 
26
26
  ```typescript
27
27
  const onboard = trail('entity.onboard', {
28
- follow: ['entity.add', 'entity.relate'],
28
+ composes: ['entity.add', 'entity.relate'],
29
29
  input: z.object({ name: z.string(), type: z.string() }),
30
- run: async (input, ctx) => {
31
- const added = await ctx.follow('entity.add', input);
30
+ implementation: async (input, ctx) => {
31
+ const added = await ctx.compose('entity.add', input);
32
32
  if (added.isErr()) return added;
33
33
  return Result.ok({ entity: added.value });
34
34
  },
@@ -41,10 +41,42 @@ const onboard = trail('entity.onboard', {
41
41
 
42
42
  | Export | What it does |
43
43
  | --- | --- |
44
- | `trail(id, spec)` | Define a unit of work with typed input and `Result` output; use `follow` for composition |
45
- | `event(id, spec)` | Define a server-originated push with a typed data schema |
46
- | `topo(name, ...modules)` | Collect trail modules into a queryable topology |
47
- | `validateTopo(topo)` | Structural validation: follow targets exist, no cycles, examples parse, output schemas present |
44
+ | `trail(id, spec)` | Define a unit of work with typed input and `Result` output; use `composes` for composition |
45
+ | `signal(id, spec)` | Define a server-originated notification with a typed data schema |
46
+ | `resource(id, spec)` | Define an infrastructure dependency with `create`, `dispose`, and optional `mock` |
47
+ | `drainResources(resources, ctx, configValues?)` | Evict and dispose cached resource singletons for surface/test shutdown |
48
+ | `blobRefSchema` / `createBlobRef(...)` | Declare and create binary output references with a shared descriptor contract |
49
+ | `topo(name, ...modules, options?)` | Collect trail modules into a queryable topology with optional `observe:` sinks |
50
+ | `deriveTrail(entity, operation, spec)` | Derive CRUD-shaped trail contracts from a entity on the `@ontrails/core/trails` subpath |
51
+ | `validateTopo(topo)` | Structural validation: compose targets exist, no cycles, examples parse, output schemas present |
52
+
53
+ ### Execution
54
+
55
+ | Export | What it does |
56
+ | --- | --- |
57
+ | `executeTrail(trail, rawInput, options?)` | Centralized execution pipeline: validates input, builds context, composes layers, runs the trail. Never throws -- exceptions become `Result.err(InternalError)`. |
58
+ | `run(topo, id, input, options?)` | Headless trail execution by ID. Looks up the trail in the topo, then delegates to `executeTrail`. Returns `Result.err(NotFoundError)` if the ID is not registered. |
59
+
60
+ ```typescript
61
+ // executeTrail — surfaces use this directly
62
+ const surfaceResult = await executeTrail(greet, { name: 'Alice' });
63
+
64
+ // run — headless execution by trail ID
65
+ const runResult = await run(graph, 'greet', { name: 'Alice' });
66
+ if (runResult.isOk()) console.log(runResult.value);
67
+ ```
68
+
69
+ ### Topo accessors
70
+
71
+ Beyond the `trail(id, spec)` builder, `Topo` exposes these accessors:
72
+
73
+ | Accessor | What it returns |
74
+ | --- | --- |
75
+ | `topo.ids()` | `string[]` of all registered trail IDs |
76
+ | `topo.count` | Number of registered trails |
77
+ | `topo.get(id)` | The `Trail` with that ID, or `undefined` |
78
+ | `topo.has(id)` | Whether a trail ID is registered |
79
+ | `topo.list()` | All registered trails as an array |
48
80
 
49
81
  ### Type utilities
50
82
 
@@ -52,9 +84,17 @@ const onboard = trail('entity.onboard', {
52
84
  | --- | --- |
53
85
  | `TrailInput<T>` | Extract the input type from a `Trail` |
54
86
  | `TrailOutput<T>` | Extract the output type from a `Trail` |
87
+ | `TrailResult<T>` | `Result<TrailOutput<T>, Error>` -- the Result type for a trail's output |
55
88
  | `inputOf(trail)` | Get the input Zod schema from a trail instance |
56
89
  | `outputOf(trail)` | Get the output Zod schema (or `undefined`) from a trail instance |
57
90
 
91
+ ### Execution option types
92
+
93
+ | Type | What it describes |
94
+ | --- | --- |
95
+ | `ExecuteTrailOptions` | Options for `executeTrail`: `ctx`, `abortSignal`, `layers`, `createContext` |
96
+ | `RunOptions` | Same shape as `ExecuteTrailOptions`; forwarded by `run` |
97
+
58
98
  ### Result
59
99
 
60
100
  ```typescript
@@ -75,39 +115,74 @@ result.unwrapOr(fallback); // Value or fallback
75
115
 
76
116
  ### Error taxonomy
77
117
 
78
- 13 error classes across 10 categories. Each maps deterministically to exit codes, HTTP status, and JSON-RPC codes on every surface.
79
-
80
- | Category | Classes | HTTP | Retryable |
81
- | --- | --- | --- | --- |
82
- | `validation` | `ValidationError`, `AmbiguousError`, `AssertionError` | 400 | No |
83
- | `not_found` | `NotFoundError` | 404 | No |
84
- | `conflict` | `AlreadyExistsError`, `ConflictError` | 409 | No |
85
- | `permission` | `PermissionError` | 403 | No |
86
- | `timeout` | `TimeoutError` | 504 | Yes |
87
- | `rate_limit` | `RateLimitError` | 429 | Yes |
88
- | `network` | `NetworkError` | 502 | Yes |
89
- | `internal` | `InternalError` | 500 | No |
90
- | `auth` | `AuthError` | 401 | No |
91
- | `cancelled` | `CancelledError` | 499 | No |
118
+ The current taxonomy is generated from the `errorClasses` owner registry and category code maps in `@ontrails/core`.
119
+
120
+ <!-- error-taxonomy:start -->
121
+ <!-- GENERATED: run `bun run error-taxonomy:sync`; check with `bun run error-taxonomy:check`. Variant: category. -->
122
+
123
+ | Category | CLI Exit | HTTP | JSON-RPC | Retryable | Fixed Classes |
124
+ | --- | --- | --- | --- | --- | --- |
125
+ | `validation` | 1 | 400 | -32602 | No | `ValidationError`, `AmbiguousError` |
126
+ | `not_found` | 2 | 404 | -32601 | No | `NotFoundError`, `VersionNotSupportedError` |
127
+ | `conflict` | 3 | 409 | -32603 | No | `AlreadyExistsError`, `ConflictError` |
128
+ | `permission` | 4 | 403 | -32600 | No | `PermissionError`, `PermitError` |
129
+ | `timeout` | 5 | 504 | -32603 | Yes | `TimeoutError` |
130
+ | `rate_limit` | 6 | 429 | -32603 | Yes | `RateLimitError` |
131
+ | `network` | 7 | 502 | -32603 | Yes | `NetworkError` |
132
+ | `shift` | 10 | 503 | -32603 | Yes | `WorkspaceShiftError` |
133
+ | `internal` | 8 | 500 | -32603 | No | `AssertionError`, `InternalError`, `DerivationError`, `RecoverableCompletionError` |
134
+ | `auth` | 9 | 401 | -32600 | No | `AuthError` |
135
+ | `cancelled` | 130 | 499 | -32603 | No | `CancelledError` |
136
+
137
+ Dynamic classes:
138
+
139
+ - `RetryExhaustedError` inherits category and surface codes from its wrapped `TrailsError`; retryable is always No.
140
+ <!-- error-taxonomy:end -->
141
+
142
+ Public surfaces share one redacted rendering contract before applying surface codes. Sensitive substrings are removed from non-internal `TrailsError` messages. Internal-category `TrailsError` instances and unknown native errors remain opaque: HTTP, MCP, and library boundaries use `Internal server error`, while CLI uses the transport-neutral `Internal error`. Diagnostics and serialized payloads keep their useful structure while redacting messages, context, and stack strings.
92
143
 
93
144
  The developer returns `Result.err(new NotFoundError(...))`. The framework maps it to the right code on every surface.
94
145
 
95
146
  ### Other exports
96
147
 
97
- - **Schema derivation** -- `deriveFields(schema)` extracts field metadata from Zod for prompts and forms
148
+ - **Schema derivation** -- `deriveFields(schema)` extracts faithfully
149
+ representable field metadata from Zod for prompts and forms
98
150
  - **Validation** -- `validateInput`, `formatZodIssues`, `zodToJsonSchema`
99
- - **Resilience** -- `retry`, `withTimeout`, `shouldRetry`, `getBackoffDelay`
151
+ - **Resilience** -- `retry`, `withTimeout`, `shouldRetry`, `deriveBackoffDelay`
100
152
  - **Serialization** -- `serializeError`, `deserializeError`
101
153
  - **Branded types** -- `uuid`, `email`, `nonEmptyString`, `positiveInt`
102
- - **Layers** -- cross-cutting middleware via `composeLayers`
154
+ - **Execution layers** -- low-level pipeline wrappers via `composeLayers`
103
155
  - **Guards and collections** -- `isDefined`, `chunk`, `dedupe`, `groupBy`, `sortBy`
104
156
  - **Patterns** (`@ontrails/core/patterns`) -- reusable Zod schemas for pagination, bulk ops, timestamps, sorting
157
+ - **Trail factories** (`@ontrails/core/trails`) -- derive CRUD-shaped trail contracts from entities without re-authoring IDs, schemas, examples, or intents
105
158
  - **Redaction** (`@ontrails/core/redaction`) -- strip sensitive data before logging
106
159
 
160
+ ### Public helper boundaries
161
+
162
+ The root package also exposes a few low-level contracts that other framework packages build on:
163
+
164
+ - **Intrinsic tracing** -- `TraceRecord`, `TraceSink`, `TraceContext`, and the sink registry helpers are the core-owned execution record shape shared by `@ontrails/observability` and adapters.
165
+ - **Trails DB** -- `deriveTrailsDbPath`, `deriveTrailsStateDir`, `deriveTrailsStateHome`, `deriveTrailsProjectKey`, `deriveTrailsDir`, `ensureSubsystemSchema`, `openReadTrailsDb`, and `openWriteTrailsDb` are the generic database primitive used by framework subsystems.
166
+ - **Surface rendering helpers** -- safe error rendering, layer field rendering, compose-batch validation, late-bound signal references, and Zod default-wrapper stripping are stable root exports for first-party surfaces, store helpers, and tests.
167
+
107
168
  See the [API Reference](../../docs/api-reference.md) for the full list.
108
169
 
170
+ ## Migration: topo-store moved to `@ontrails/topography`
171
+
172
+ Per [ADR-0042](../../docs/adr/0042-core-topography-boundary-doctrine.md), the topo-store public API previously exported from `@ontrails/core` now lives in `@ontrails/topography`. Generic `trails-db` helpers (`openReadTrailsDb`, `openWriteTrailsDb`, `ensureSubsystemSchema`, `deriveTrailsDbPath`, `deriveTrailsStateDir`, `deriveTrailsStateHome`, `deriveTrailsProjectKey`, `deriveTrailsDir`) stay in core because tracing and other subsystems share them.
173
+
174
+ Update consumer imports:
175
+
176
+ ```diff
177
+ - import { topoStore, createTopoStore, createMockTopoStore, createTopoSnapshot, listTopoSnapshots, pinTopoSnapshot, unpinTopoSnapshot, createStoredTopoSnapshot, getStoredTopoExport, countTopoSnapshots, countPinnedSnapshots, countPrunableSnapshots, pruneUnpinnedSnapshots } from '@ontrails/core';
178
+ + import { topoStore, createTopoStore, createMockTopoStore, createTopoSnapshot, listTopoSnapshots, pinTopoSnapshot, unpinTopoSnapshot } from '@ontrails/topography';
179
+ + import { createStoredTopoSnapshot, getStoredTopoExport, countTopoSnapshots, countPinnedSnapshots, countPrunableSnapshots, pruneUnpinnedSnapshots } from '@ontrails/topography/backend-support';
180
+ ```
181
+
182
+ Types `ReadOnlyTopoStore`, `MockTopoStoreSeed`, `TopoSnapshot`, `TopoStoreRef`, `TopoStoreExportRecord`, `TopoStoreResourceRecord`, `TopoStoreTrailRecord`, `TopoStoreTrailDetailRecord`, `CreateTopoSnapshotInput`, and `ListTopoSnapshotsOptions` move to `@ontrails/topography`. `StoredTopoExport` moves to `@ontrails/topography/backend-support`.
183
+
109
184
  ## Installation
110
185
 
111
186
  ```bash
112
- bun add @ontrails/core zod
187
+ bun add @ontrails/core@beta zod
113
188
  ```
package/package.json CHANGED
@@ -1,11 +1,26 @@
1
1
  {
2
2
  "name": "@ontrails/core",
3
- "version": "1.0.0-beta.5",
3
+ "version": "1.0.0-beta.50",
4
+ "repository": {
5
+ "type": "git",
6
+ "url": "git+https://github.com/outfitter-dev/trails.git",
7
+ "directory": "packages/core"
8
+ },
9
+ "files": [
10
+ "src/**/*.ts",
11
+ "!src/**/__tests__/**",
12
+ "!src/**/*.test.ts",
13
+ "!src/**/*.test-d.ts",
14
+ "README.md",
15
+ "CHANGELOG.md"
16
+ ],
4
17
  "type": "module",
5
18
  "exports": {
6
19
  ".": "./src/index.ts",
7
20
  "./patterns": "./src/patterns/index.ts",
8
21
  "./redaction": "./src/redaction/index.ts",
22
+ "./store": "./src/store/index.ts",
23
+ "./trails": "./src/trails/index.ts",
9
24
  "./package.json": "./package.json"
10
25
  },
11
26
  "scripts": {
@@ -0,0 +1,116 @@
1
+ import type {
2
+ ActivationSourceKind,
3
+ ActivationSourceMeta,
4
+ } from './activation-source.js';
5
+
6
+ export const ACTIVATION_PROVENANCE_KEY =
7
+ '__trails_activation_provenance' as const;
8
+
9
+ export interface ActivationProvenanceSource {
10
+ readonly cron?: string | undefined;
11
+ readonly id: string;
12
+ readonly kind: ActivationSourceKind;
13
+ readonly meta?: ActivationSourceMeta | undefined;
14
+ readonly producerTrailId?: string | undefined;
15
+ readonly queue?: string | undefined;
16
+ readonly timezone?: string | undefined;
17
+ }
18
+
19
+ export interface ActivationProvenance {
20
+ readonly fireId: string;
21
+ readonly parentFireId?: string | undefined;
22
+ readonly rootFireId: string;
23
+ readonly source: ActivationProvenanceSource;
24
+ }
25
+
26
+ export interface ActivationProvenanceCarrier {
27
+ readonly activation?: ActivationProvenance | undefined;
28
+ readonly extensions?: Readonly<Record<string, unknown>> | undefined;
29
+ }
30
+
31
+ const isObjectRecord = (value: unknown): value is Record<string, unknown> =>
32
+ typeof value === 'object' && value !== null && !Array.isArray(value);
33
+
34
+ const optionalString = (value: unknown): boolean =>
35
+ value === undefined || typeof value === 'string';
36
+
37
+ const isActivationProvenanceSource = (
38
+ value: unknown
39
+ ): value is ActivationProvenanceSource =>
40
+ isObjectRecord(value) &&
41
+ typeof value['id'] === 'string' &&
42
+ typeof value['kind'] === 'string' &&
43
+ optionalString(value['cron']) &&
44
+ optionalString(value['producerTrailId']) &&
45
+ optionalString(value['queue']) &&
46
+ optionalString(value['timezone']) &&
47
+ (value['meta'] === undefined || isObjectRecord(value['meta']));
48
+
49
+ const isActivationProvenance = (
50
+ value: unknown
51
+ ): value is ActivationProvenance =>
52
+ isObjectRecord(value) &&
53
+ typeof value['fireId'] === 'string' &&
54
+ optionalString(value['parentFireId']) &&
55
+ typeof value['rootFireId'] === 'string' &&
56
+ isActivationProvenanceSource(value['source']);
57
+
58
+ export const getActivationProvenance = (
59
+ ctx: ActivationProvenanceCarrier | undefined
60
+ ): ActivationProvenance | undefined => {
61
+ if (isActivationProvenance(ctx?.activation)) {
62
+ return ctx.activation;
63
+ }
64
+ const fromExtensions = ctx?.extensions?.[ACTIVATION_PROVENANCE_KEY];
65
+ return isActivationProvenance(fromExtensions) ? fromExtensions : undefined;
66
+ };
67
+
68
+ export const withActivationProvenance = <
69
+ TCtx extends {
70
+ readonly extensions?: Readonly<Record<string, unknown>> | undefined;
71
+ },
72
+ >(
73
+ ctx: TCtx,
74
+ activation: ActivationProvenance
75
+ ): TCtx & { readonly activation: ActivationProvenance } => ({
76
+ ...ctx,
77
+ activation,
78
+ extensions: {
79
+ ...ctx.extensions,
80
+ [ACTIVATION_PROVENANCE_KEY]: activation,
81
+ },
82
+ });
83
+
84
+ export const buildActivationProvenanceTraceAttrs = (
85
+ activation: ActivationProvenance | undefined
86
+ ): Readonly<Record<string, unknown>> => {
87
+ if (activation === undefined) {
88
+ return {};
89
+ }
90
+
91
+ const attrs: Record<string, unknown> = {
92
+ 'trails.activation.fire_id': activation.fireId,
93
+ 'trails.activation.root_fire_id': activation.rootFireId,
94
+ 'trails.activation.source.id': activation.source.id,
95
+ 'trails.activation.source.kind': activation.source.kind,
96
+ };
97
+
98
+ if (activation.parentFireId !== undefined) {
99
+ attrs['trails.activation.parent_fire_id'] = activation.parentFireId;
100
+ }
101
+ if (activation.source.producerTrailId !== undefined) {
102
+ attrs['trails.activation.source.producer_trail.id'] =
103
+ activation.source.producerTrailId;
104
+ }
105
+ if (activation.source.queue !== undefined) {
106
+ attrs['trails.activation.source.queue'] = activation.source.queue;
107
+ }
108
+ if (activation.source.cron !== undefined) {
109
+ attrs['trails.activation.source.cron'] = activation.source.cron;
110
+ }
111
+ if (activation.source.timezone !== undefined) {
112
+ attrs['trails.activation.source.timezone'] = activation.source.timezone;
113
+ }
114
+
115
+ return attrs;
116
+ };