@ontrails/core 1.0.0-beta.4 → 1.0.0-beta.41

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 (247) hide show
  1. package/CHANGELOG.md +412 -12
  2. package/README.md +112 -28
  3. package/package.json +11 -1
  4. package/src/activation-provenance.ts +116 -0
  5. package/src/activation-source-compatibility.ts +430 -0
  6. package/src/activation-source-projection.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-projection.ts +51 -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 +568 -32
  24. package/src/internal/fork-ctx.ts +69 -0
  25. package/src/layer-projection.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 +174 -0
  62. package/src/type-utils.ts +87 -0
  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 -34
  121. package/dist/index.d.ts.map +0 -1
  122. package/dist/index.js +0 -38
  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/types.d.ts +0 -46
  205. package/dist/types.d.ts.map +0 -1
  206. package/dist/types.js +0 -2
  207. package/dist/types.js.map +0 -1
  208. package/dist/validate-topo.d.ts +0 -24
  209. package/dist/validate-topo.d.ts.map +0 -1
  210. package/dist/validate-topo.js +0 -158
  211. package/dist/validate-topo.js.map +0 -1
  212. package/dist/validation.d.ts +0 -27
  213. package/dist/validation.d.ts.map +0 -1
  214. package/dist/validation.js +0 -134
  215. package/dist/validation.js.map +0 -1
  216. package/dist/workspace.d.ts +0 -25
  217. package/dist/workspace.d.ts.map +0 -1
  218. package/dist/workspace.js +0 -57
  219. package/dist/workspace.js.map +0 -1
  220. package/src/__tests__/blob-ref.test.ts +0 -103
  221. package/src/__tests__/branded.test.ts +0 -148
  222. package/src/__tests__/collections.test.ts +0 -126
  223. package/src/__tests__/context.test.ts +0 -66
  224. package/src/__tests__/derive.test.ts +0 -203
  225. package/src/__tests__/errors.test.ts +0 -309
  226. package/src/__tests__/event.test.ts +0 -82
  227. package/src/__tests__/fetch.test.ts +0 -217
  228. package/src/__tests__/guards.test.ts +0 -102
  229. package/src/__tests__/job.test.ts +0 -98
  230. package/src/__tests__/layer.test.ts +0 -212
  231. package/src/__tests__/path-security.test.ts +0 -114
  232. package/src/__tests__/patterns.test.ts +0 -273
  233. package/src/__tests__/redaction.test.ts +0 -244
  234. package/src/__tests__/resilience.test.ts +0 -246
  235. package/src/__tests__/result.test.ts +0 -155
  236. package/src/__tests__/serialization.test.ts +0 -401
  237. package/src/__tests__/topo.test.ts +0 -181
  238. package/src/__tests__/trail.test.ts +0 -217
  239. package/src/__tests__/validate-topo.test.ts +0 -278
  240. package/src/__tests__/validation.test.ts +0 -283
  241. package/src/__tests__/workspace.test.ts +0 -183
  242. package/src/adapters.ts +0 -68
  243. package/src/event.ts +0 -77
  244. package/src/health.ts +0 -23
  245. package/src/job.ts +0 -20
  246. package/tsconfig.json +0 -9
  247. 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,59 @@ 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 |
80
+
81
+ ### Type utilities
82
+
83
+ | Export | What it does |
84
+ | --- | --- |
85
+ | `TrailInput<T>` | Extract the input type from a `Trail` |
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 |
88
+ | `inputOf(trail)` | Get the input Zod schema from a trail instance |
89
+ | `outputOf(trail)` | Get the output Zod schema (or `undefined`) from a trail instance |
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` |
48
97
 
49
98
  ### Result
50
99
 
@@ -66,39 +115,74 @@ result.unwrapOr(fallback); // Value or fallback
66
115
 
67
116
  ### Error taxonomy
68
117
 
69
- 13 error classes across 10 categories. Each maps deterministically to exit codes, HTTP status, and JSON-RPC codes on every surface.
70
-
71
- | Category | Classes | HTTP | Retryable |
72
- | --- | --- | --- | --- |
73
- | `validation` | `ValidationError`, `AmbiguousError`, `AssertionError` | 400 | No |
74
- | `not_found` | `NotFoundError` | 404 | No |
75
- | `conflict` | `AlreadyExistsError`, `ConflictError` | 409 | No |
76
- | `permission` | `PermissionError` | 403 | No |
77
- | `timeout` | `TimeoutError` | 504 | Yes |
78
- | `rate_limit` | `RateLimitError` | 429 | Yes |
79
- | `network` | `NetworkError` | 502 | Yes |
80
- | `internal` | `InternalError` | 500 | No |
81
- | `auth` | `AuthError` | 401 | No |
82
- | `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 surface projections redact sensitive substrings before exposing a non-internal `TrailsError` message. Internal-category `TrailsError` instances and unknown native errors project with the generic message `Internal server error`; diagnostics and serialized payloads keep their useful structure while redacting messages, context, and stack strings.
83
143
 
84
144
  The developer returns `Result.err(new NotFoundError(...))`. The framework maps it to the right code on every surface.
85
145
 
86
146
  ### Other exports
87
147
 
88
- - **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
89
150
  - **Validation** -- `validateInput`, `formatZodIssues`, `zodToJsonSchema`
90
- - **Resilience** -- `retry`, `withTimeout`, `shouldRetry`, `getBackoffDelay`
151
+ - **Resilience** -- `retry`, `withTimeout`, `shouldRetry`, `deriveBackoffDelay`
91
152
  - **Serialization** -- `serializeError`, `deserializeError`
92
153
  - **Branded types** -- `uuid`, `email`, `nonEmptyString`, `positiveInt`
93
- - **Layers** -- cross-cutting middleware via `composeLayers`
154
+ - **Execution layers** -- low-level pipeline wrappers via `composeLayers`
94
155
  - **Guards and collections** -- `isDefined`, `chunk`, `dedupe`, `groupBy`, `sortBy`
95
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
96
158
  - **Redaction** (`@ontrails/core/redaction`) -- strip sensitive data before logging
97
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/observe`, `@ontrails/tracing`, 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 projection helpers** -- safe error projection, layer field projection, 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
+
98
168
  See the [API Reference](../../docs/api-reference.md) for the full list.
99
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
+
100
184
  ## Installation
101
185
 
102
186
  ```bash
103
- bun add @ontrails/core zod
187
+ bun add @ontrails/core@beta zod
104
188
  ```
package/package.json CHANGED
@@ -1,11 +1,21 @@
1
1
  {
2
2
  "name": "@ontrails/core",
3
- "version": "1.0.0-beta.4",
3
+ "version": "1.0.0-beta.41",
4
+ "files": [
5
+ "src/**/*.ts",
6
+ "!src/**/__tests__/**",
7
+ "!src/**/*.test.ts",
8
+ "!src/**/*.test-d.ts",
9
+ "README.md",
10
+ "CHANGELOG.md"
11
+ ],
4
12
  "type": "module",
5
13
  "exports": {
6
14
  ".": "./src/index.ts",
7
15
  "./patterns": "./src/patterns/index.ts",
8
16
  "./redaction": "./src/redaction/index.ts",
17
+ "./store": "./src/store/index.ts",
18
+ "./trails": "./src/trails/index.ts",
9
19
  "./package.json": "./package.json"
10
20
  },
11
21
  "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
+ };