@ontrails/core 1.0.0-beta.39 → 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.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,63 @@
1
1
  # @ontrails/core
2
2
 
3
+ ## 1.0.0-beta.41
4
+
5
+ ## 1.0.0-beta.40
6
+
7
+ ### Minor Changes
8
+
9
+ - [`1e64ee7`](https://github.com/outfitter-dev/trails/commit/1e64ee7bc270901486c5bb51ac38bf045c924adc): Add first-class queue activation sources with `queue()` in `@ontrails/core`.
10
+ Queue sources validate their runtime queue name and parse contract, project the
11
+ queue name into durable topo facts, participate in activation input
12
+ compatibility, and block established outputs when malformed.
13
+
14
+ Add `@ontrails/cloudflare/queues` with `cloudflareQueue`, `createMemoryQueue`,
15
+ and `createQueueHandler`. Cloudflare Workers now expose both `fetch` and
16
+ `queue` entrypoints from `createWorkersHandler`, resolve env-bound resources for
17
+ queue-activated trails, acknowledge successful/skipped/cancelled messages, and
18
+ acknowledge traced non-retryable Trails errors so permanently invalid messages
19
+ do not churn through the queue. Failures explicitly marked retryable enter
20
+ Cloudflare's retry and DLQ flow, with rate-limit delays preserved.
21
+
22
+ `@ontrails/warden` now treats queue activation sources as materialized and
23
+ requires `cloudflareQueue` public export example coverage.
24
+
25
+ - [`5adb995`](https://github.com/outfitter-dev/trails/commit/5adb99551c2dda6190d46cce7f60bb08d63c99aa): Complete the v1 hard cutover from the authored `blaze` field to
26
+ `implementation` across trail contracts, surface projections, tests, examples,
27
+ and public source-analysis helpers. Existing applications must rename authored
28
+ trail behavior fields and direct trail-object access before upgrading.
29
+ - [`6712075`](https://github.com/outfitter-dev/trails/commit/67120754df3f614c7f4dd98be1fa0ba9d69b7765): Complete the v1 hard cutover from the `contour` domain-object declaration
30
+ vocabulary to `entity` across contracts, topo facts, store helpers, Warden,
31
+ Wayfinder, operator surfaces, examples, and generated locks. Existing
32
+ applications must rename contour APIs, run `trails dev reset --yes` to discard
33
+ pre-cutover local Topographer snapshots, and then recompile committed
34
+ `trails.lock` artifacts before upgrading. Those derived snapshots are
35
+ intentionally not read through a compatibility layer.
36
+ The entity-shaped wire contract advances `TopoGraph` and split lock manifests
37
+ from schema version 3 to 4; old split artifacts fail with regeneration guidance,
38
+ while the canonical root `trails.lock` remains schema version 5.
39
+ Wayfinder reports those stale rows as topo-store drift while keeping current
40
+ committed lock facts available for inspection.
41
+
42
+ ### Patch Changes
43
+
44
+ - [`9874e0b`](https://github.com/outfitter-dev/trails/commit/9874e0bb034c0f98edeb19833d9d3519c2a07a4c): Add `@ontrails/cloudflare/d1`, an env-bound Cloudflare D1 store resource for `@ontrails/store` definitions. The new subpath exports `cloudflareD1` and `connectD1`, supports the backend-agnostic store accessor contract (`get`, `list`, `upsert`, `remove`), versioned-table optimistic concurrency, fixture/mock seeding, store-derived write signals, Miniflare-backed conformance tests, and Worker env-bridge integration.
45
+
46
+ `@ontrails/core` and `@ontrails/store` no longer require the Bun global for signal fire ids or late-bound store signal tokens, so store definitions and store-derived signal emission work inside Worker modules. `@ontrails/warden` now treats `cloudflareD1` as a required Cloudflare public export with `@example` coverage.
47
+
48
+ - [`3a65ae3`](https://github.com/outfitter-dev/trails/commit/3a65ae363e05b7589f4a9876da4346886353b48c): Rename the durable graph substrate package from `@ontrails/topographer` to
49
+ `@ontrails/topography` after folding Wayfind graph queries into that owner.
50
+
51
+ Update imports to `@ontrails/topography` or
52
+ `@ontrails/topography/backend-support`. The pre-1.0 cutover does not ship a
53
+ compatibility package. TopoGraph, lock, topo-store, semantic diff, and Wayfind
54
+ APIs keep their existing contracts, and the `trails wayfind` CLI and MCP names
55
+ remain unchanged.
56
+
57
+ The governed package-route transition moves legacy `@ontrails/wayfinder`
58
+ imports directly to `@ontrails/topography`; it does not emit the retired
59
+ intermediate `@ontrails/topographer` route.
60
+
3
61
  ## 1.0.0-beta.39
4
62
 
5
63
  ### Patch Changes
package/README.md CHANGED
@@ -15,7 +15,7 @@ const greet = trail('greet', {
15
15
  examples: [
16
16
  { name: 'Hello', input: { name: 'World' }, expected: { message: 'Hello, World!' } },
17
17
  ],
18
- blaze: (input) => Result.ok({ message: `Hello, ${input.name}!` }),
18
+ implementation: (input) => Result.ok({ message: `Hello, ${input.name}!` }),
19
19
  });
20
20
 
21
21
  const graph = topo('myapp', { greet });
@@ -27,7 +27,7 @@ Trails compose other trails through `composes` and `ctx.compose()`:
27
27
  const onboard = trail('entity.onboard', {
28
28
  composes: ['entity.add', 'entity.relate'],
29
29
  input: z.object({ name: z.string(), type: z.string() }),
30
- blaze: async (input, ctx) => {
30
+ implementation: async (input, ctx) => {
31
31
  const added = await ctx.compose('entity.add', input);
32
32
  if (added.isErr()) return added;
33
33
  return Result.ok({ entity: added.value });
@@ -47,14 +47,14 @@ const onboard = trail('entity.onboard', {
47
47
  | `drainResources(resources, ctx, configValues?)` | Evict and dispose cached resource singletons for surface/test shutdown |
48
48
  | `blobRefSchema` / `createBlobRef(...)` | Declare and create binary output references with a shared descriptor contract |
49
49
  | `topo(name, ...modules, options?)` | Collect trail modules into a queryable topology with optional `observe:` sinks |
50
- | `deriveTrail(contour, operation, spec)` | Derive CRUD-shaped trail contracts from a contour on the `@ontrails/core/trails` subpath |
50
+ | `deriveTrail(entity, operation, spec)` | Derive CRUD-shaped trail contracts from a entity on the `@ontrails/core/trails` subpath |
51
51
  | `validateTopo(topo)` | Structural validation: compose targets exist, no cycles, examples parse, output schemas present |
52
52
 
53
53
  ### Execution
54
54
 
55
55
  | Export | What it does |
56
56
  | --- | --- |
57
- | `executeTrail(trail, rawInput, options?)` | Centralized execution pipeline: validates input, builds context, composes layers, runs the blazed trail. Never throws -- exceptions become `Result.err(InternalError)`. |
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
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
59
 
60
60
  ```typescript
@@ -154,7 +154,7 @@ The developer returns `Result.err(new NotFoundError(...))`. The framework maps i
154
154
  - **Execution layers** -- low-level pipeline wrappers via `composeLayers`
155
155
  - **Guards and collections** -- `isDefined`, `chunk`, `dedupe`, `groupBy`, `sortBy`
156
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 contours without re-authoring IDs, schemas, examples, or intents
157
+ - **Trail factories** (`@ontrails/core/trails`) -- derive CRUD-shaped trail contracts from entities without re-authoring IDs, schemas, examples, or intents
158
158
  - **Redaction** (`@ontrails/core/redaction`) -- strip sensitive data before logging
159
159
 
160
160
  ### Public helper boundaries
@@ -167,19 +167,19 @@ The root package also exposes a few low-level contracts that other framework pac
167
167
 
168
168
  See the [API Reference](../../docs/api-reference.md) for the full list.
169
169
 
170
- ## Migration: topo-store moved to `@ontrails/topographer`
170
+ ## Migration: topo-store moved to `@ontrails/topography`
171
171
 
172
- Per [ADR-0042](../../docs/adr/0042-core-topographer-boundary-doctrine.md), the topo-store public API previously exported from `@ontrails/core` now lives in `@ontrails/topographer`. Generic `trails-db` helpers (`openReadTrailsDb`, `openWriteTrailsDb`, `ensureSubsystemSchema`, `deriveTrailsDbPath`, `deriveTrailsStateDir`, `deriveTrailsStateHome`, `deriveTrailsProjectKey`, `deriveTrailsDir`) stay in core because tracing and other subsystems share them.
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
173
 
174
174
  Update consumer imports:
175
175
 
176
176
  ```diff
177
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/topographer';
179
- + import { createStoredTopoSnapshot, getStoredTopoExport, countTopoSnapshots, countPinnedSnapshots, countPrunableSnapshots, pruneUnpinnedSnapshots } from '@ontrails/topographer/backend-support';
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
180
  ```
181
181
 
182
- Types `ReadOnlyTopoStore`, `MockTopoStoreSeed`, `TopoSnapshot`, `TopoStoreRef`, `TopoStoreExportRecord`, `TopoStoreResourceRecord`, `TopoStoreTrailRecord`, `TopoStoreTrailDetailRecord`, `CreateTopoSnapshotInput`, and `ListTopoSnapshotsOptions` move to `@ontrails/topographer`. `StoredTopoExport` moves to `@ontrails/topographer/backend-support`.
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
183
 
184
184
  ## Installation
185
185
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ontrails/core",
3
- "version": "1.0.0-beta.39",
3
+ "version": "1.0.0-beta.41",
4
4
  "files": [
5
5
  "src/**/*.ts",
6
6
  "!src/**/__tests__/**",
@@ -12,6 +12,7 @@ export interface ActivationProvenanceSource {
12
12
  readonly kind: ActivationSourceKind;
13
13
  readonly meta?: ActivationSourceMeta | undefined;
14
14
  readonly producerTrailId?: string | undefined;
15
+ readonly queue?: string | undefined;
15
16
  readonly timezone?: string | undefined;
16
17
  }
17
18
 
@@ -41,6 +42,7 @@ const isActivationProvenanceSource = (
41
42
  typeof value['kind'] === 'string' &&
42
43
  optionalString(value['cron']) &&
43
44
  optionalString(value['producerTrailId']) &&
45
+ optionalString(value['queue']) &&
44
46
  optionalString(value['timezone']) &&
45
47
  (value['meta'] === undefined || isObjectRecord(value['meta']));
46
48
 
@@ -100,6 +102,9 @@ export const buildActivationProvenanceTraceAttrs = (
100
102
  attrs['trails.activation.source.producer_trail.id'] =
101
103
  activation.source.producerTrailId;
102
104
  }
105
+ if (activation.source.queue !== undefined) {
106
+ attrs['trails.activation.source.queue'] = activation.source.queue;
107
+ }
103
108
  if (activation.source.cron !== undefined) {
104
109
  attrs['trails.activation.source.cron'] = activation.source.cron;
105
110
  }
@@ -159,6 +159,12 @@ export const projectActivationSourceDeclaration = (
159
159
  record['payloadSchema'] = toSortedJsonSchema(source.payload);
160
160
  }
161
161
  }
162
+ if (source.queue !== undefined) {
163
+ record['queue'] =
164
+ typeof source.queue === 'string'
165
+ ? source.queue.trim()
166
+ : canonicalize(source.queue);
167
+ }
162
168
  if (source.timezone !== undefined) {
163
169
  record['timezone'] = source.timezone;
164
170
  }
@@ -3,6 +3,7 @@ import type { z } from 'zod';
3
3
  import type { AnySignal } from './signal.js';
4
4
 
5
5
  export const activationSourceKinds = Object.freeze([
6
+ 'queue',
6
7
  'signal',
7
8
  'schedule',
8
9
  'webhook',
@@ -31,6 +32,7 @@ export interface ActivationSource {
31
32
  readonly parse?: ActivationSourceParse | undefined;
32
33
  readonly path?: string | undefined;
33
34
  readonly payload?: z.ZodType<unknown> | undefined;
35
+ readonly queue?: string | undefined;
34
36
  readonly timezone?: string | undefined;
35
37
  readonly verify?: unknown;
36
38
  }
@@ -43,7 +43,7 @@ export const normalizeComposeBatchConcurrency = (
43
43
  /**
44
44
  * Produce one validation-error result per call, preserving the original
45
45
  * call order. Used when `normalizeComposeBatchConcurrency` fails so the caller
46
- * can surface a uniform batch shape to the blaze.
46
+ * can surface a uniform batch shape to the implementation.
47
47
  */
48
48
  export const createComposeBatchValidationResults = <TCall>(
49
49
  calls: readonly TCall[],
package/src/draft.ts CHANGED
@@ -1,5 +1,5 @@
1
- import type { AnyContour } from './contour.js';
2
- import { getContourReferences } from './contour.js';
1
+ import type { AnyEntity } from './entity.js';
2
+ import { getEntityReferences } from './entity.js';
3
3
  import { ValidationError } from './errors.js';
4
4
  import type { AnySignal } from './signal.js';
5
5
  import type { AnyResource } from './resource.js';
@@ -11,7 +11,7 @@ export const DRAFT_ID_PREFIX = '_draft.';
11
11
 
12
12
  export type DraftDependencyKind =
13
13
  | 'compose'
14
- | 'contour'
14
+ | 'entity'
15
15
  | 'resource'
16
16
  | 'replaced-by'
17
17
  | 'schema-reference'
@@ -27,7 +27,7 @@ export interface DraftDependency {
27
27
 
28
28
  export interface DraftDiagnostic {
29
29
  readonly id: string;
30
- readonly kind: 'contour' | 'resource' | 'signal' | 'trail' | 'unknown';
30
+ readonly kind: 'entity' | 'resource' | 'signal' | 'trail' | 'unknown';
31
31
  readonly message: string;
32
32
  readonly rule: 'draft-contamination' | 'draft-id';
33
33
  readonly via?: DraftDependencyKind | undefined;
@@ -54,7 +54,7 @@ interface DraftReason {
54
54
  readonly via: DraftDependencyKind;
55
55
  }
56
56
 
57
- type TopoNode = AnyContour | AnyResource | AnySignal | AnyTrail;
57
+ type TopoNode = AnyEntity | AnyResource | AnySignal | AnyTrail;
58
58
 
59
59
  const replacedByTarget = (value: TopoNode): string | undefined => {
60
60
  const raw = value as unknown as { replacedBy?: unknown };
@@ -93,8 +93,8 @@ const dependencyFromTarget = (
93
93
  const trailDependencies = (trail: AnyTrail): DraftDependency[] => [
94
94
  ...dependenciesFromIds(
95
95
  trail.id,
96
- (trail.contours ?? []).map((contour) => contour.name),
97
- 'contour'
96
+ (trail.entities ?? []).map((entity) => entity.name),
97
+ 'entity'
98
98
  ),
99
99
  ...dependenciesFromIds(trail.id, trail.composes, 'compose'),
100
100
  ...dependenciesFromIds(
@@ -107,10 +107,10 @@ const trailDependencies = (trail: AnyTrail): DraftDependency[] => [
107
107
  ...dependencyFromTarget(trail.id, replacedByTarget(trail), 'replaced-by'),
108
108
  ];
109
109
 
110
- const contourDependencies = (contour: AnyContour): DraftDependency[] =>
110
+ const entityDependencies = (entity: AnyEntity): DraftDependency[] =>
111
111
  dependenciesFromIds(
112
- contour.name,
113
- getContourReferences(contour).map((reference) => reference.contour),
112
+ entity.name,
113
+ getEntityReferences(entity).map((reference) => reference.entity),
114
114
  'schema-reference'
115
115
  );
116
116
 
@@ -124,13 +124,13 @@ const resourceDependencies = (resource: AnyResource): DraftDependency[] =>
124
124
 
125
125
  const nodeKind = (
126
126
  id: string,
127
- contours: ReadonlyMap<string, AnyContour>,
127
+ entities: ReadonlyMap<string, AnyEntity>,
128
128
  trails: ReadonlyMap<string, AnyTrail>,
129
129
  signals: ReadonlyMap<string, AnySignal>,
130
130
  resources: ReadonlyMap<string, AnyResource>
131
131
  ): DraftDiagnostic['kind'] => {
132
- if (contours.has(id)) {
133
- return 'contour';
132
+ if (entities.has(id)) {
133
+ return 'entity';
134
134
  }
135
135
  if (trails.has(id)) {
136
136
  return 'trail';
@@ -152,7 +152,7 @@ const draftIdsFromKeys = (keys: Iterable<string>): string[] =>
152
152
 
153
153
  const collectDeclaredDraftIds = (topo: Topo): ReadonlySet<string> =>
154
154
  new Set([
155
- ...draftIdsFromKeys(topo.contours.keys()),
155
+ ...draftIdsFromKeys(topo.entities.keys()),
156
156
  ...draftIdsFromKeys(topo.trails.keys()),
157
157
  ...draftIdsFromKeys(topo.signals.keys()),
158
158
  ...draftIdsFromKeys(topo.resources.keys()),
@@ -248,7 +248,7 @@ const contaminationFindingForId = (
248
248
  id: string,
249
249
  declaredDraftIds: ReadonlySet<string>,
250
250
  reasons: ReadonlyMap<string, DraftReason>,
251
- contours: ReadonlyMap<string, AnyContour>,
251
+ entities: ReadonlyMap<string, AnyEntity>,
252
252
  trails: ReadonlyMap<string, AnyTrail>,
253
253
  signals: ReadonlyMap<string, AnySignal>,
254
254
  resources: ReadonlyMap<string, AnyResource>
@@ -264,7 +264,7 @@ const contaminationFindingForId = (
264
264
 
265
265
  return findingForContamination(
266
266
  id,
267
- nodeKind(id, contours, trails, signals, resources),
267
+ nodeKind(id, entities, trails, signals, resources),
268
268
  reason
269
269
  );
270
270
  };
@@ -273,7 +273,7 @@ const collectFindings = (
273
273
  declaredDraftIds: ReadonlySet<string>,
274
274
  contaminatedIds: ReadonlySet<string>,
275
275
  reasons: ReadonlyMap<string, DraftReason>,
276
- contours: ReadonlyMap<string, AnyContour>,
276
+ entities: ReadonlyMap<string, AnyEntity>,
277
277
  trails: ReadonlyMap<string, AnyTrail>,
278
278
  signals: ReadonlyMap<string, AnySignal>,
279
279
  resources: ReadonlyMap<string, AnyResource>
@@ -281,14 +281,14 @@ const collectFindings = (
281
281
  ...[...declaredDraftIds]
282
282
  .toSorted()
283
283
  .map((id) =>
284
- findingForDraftId(id, nodeKind(id, contours, trails, signals, resources))
284
+ findingForDraftId(id, nodeKind(id, entities, trails, signals, resources))
285
285
  ),
286
286
  ...[...contaminatedIds].toSorted().flatMap((id) => {
287
287
  const finding = contaminationFindingForId(
288
288
  id,
289
289
  declaredDraftIds,
290
290
  reasons,
291
- contours,
291
+ entities,
292
292
  trails,
293
293
  signals,
294
294
  resources
@@ -299,7 +299,7 @@ const collectFindings = (
299
299
  ];
300
300
 
301
301
  const collectDependencies = (topo: Topo): DraftDependency[] => [
302
- ...[...topo.contours.values()].flatMap(contourDependencies),
302
+ ...[...topo.entities.values()].flatMap(entityDependencies),
303
303
  ...[...topo.trails.values()].flatMap(trailDependencies),
304
304
  ...[...topo.signals.values()].flatMap(signalDependencies),
305
305
  ...[...topo.resources.values()].flatMap(resourceDependencies),
@@ -316,7 +316,7 @@ export const deriveDraftReport = (topo: Topo): DraftReport => {
316
316
  declaredDraftIds,
317
317
  contaminatedIds,
318
318
  reasons,
319
- topo.contours,
319
+ topo.entities,
320
320
  topo.trails,
321
321
  topo.signals,
322
322
  topo.resources