@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.
- package/CHANGELOG.md +63 -0
- package/README.md +61 -16
- package/package.json +9 -8
- package/src/activation-provenance.ts +111 -0
- package/src/activation-source-compatibility.ts +430 -0
- package/src/activation-source-projection.ts +221 -0
- package/src/activation-source.ts +91 -0
- package/src/blob-ref.ts +51 -0
- package/src/context.ts +4 -0
- package/src/{internal/cross-batch.ts → cross-batch.ts} +3 -11
- package/src/detours.ts +8 -0
- package/src/draft.ts +4 -0
- package/src/error-projection.ts +51 -0
- package/src/errors.ts +192 -39
- package/src/execute.ts +443 -44
- package/src/fire.ts +965 -91
- package/src/index.ts +285 -38
- package/src/layer-projection.ts +192 -0
- package/src/layer.ts +32 -1
- package/src/observe.ts +361 -0
- package/src/permits.ts +12 -0
- package/src/redaction/patterns.ts +6 -3
- package/src/resilience.ts +8 -8
- package/src/resource-config.ts +477 -44
- package/src/resource.ts +21 -1
- package/src/result.ts +18 -0
- package/src/run.ts +2 -2
- package/src/schedule-runtime.ts +689 -0
- package/src/schedule.ts +324 -0
- package/src/serialization.ts +90 -57
- package/src/signal-diagnostics.ts +633 -0
- package/src/{internal/signal-ref.ts → signal-ref.ts} +1 -1
- package/src/signal.ts +37 -0
- package/src/store/accessor-protocol.ts +5 -5
- package/src/structured-examples.ts +245 -0
- package/src/surface-derivation.ts +91 -0
- package/src/surface-filter.ts +7 -13
- package/src/topo.ts +386 -6
- package/src/tracing.ts +345 -0
- package/src/trail.ts +168 -22
- package/src/trails/derive-trail.ts +1 -1
- package/src/trails/ingest.ts +7 -15
- package/src/{internal/trails-db.ts → trails-db.ts} +42 -21
- package/src/transport-error-map.ts +146 -28
- package/src/types.ts +82 -28
- package/src/validate-established-topo.ts +6 -0
- package/src/validate-topo.ts +212 -5
- package/src/validation.ts +58 -1
- package/src/webhook.ts +276 -0
- package/src/{internal/zod-wrappers.ts → zod-wrappers.ts} +0 -6
- package/.turbo/turbo-build.log +0 -1
- package/.turbo/turbo-lint.log +0 -3
- package/.turbo/turbo-typecheck.log +0 -1
- package/dist/blob-ref.d.ts +0 -20
- package/dist/blob-ref.d.ts.map +0 -1
- package/dist/blob-ref.js +0 -22
- package/dist/blob-ref.js.map +0 -1
- package/dist/branded.d.ts +0 -36
- package/dist/branded.d.ts.map +0 -1
- package/dist/branded.js +0 -89
- package/dist/branded.js.map +0 -1
- package/dist/collections.d.ts +0 -31
- package/dist/collections.d.ts.map +0 -1
- package/dist/collections.js +0 -60
- package/dist/collections.js.map +0 -1
- package/dist/context.d.ts +0 -22
- package/dist/context.d.ts.map +0 -1
- package/dist/context.js +0 -37
- package/dist/context.js.map +0 -1
- package/dist/contour.d.ts +0 -81
- package/dist/contour.d.ts.map +0 -1
- package/dist/contour.js +0 -176
- package/dist/contour.js.map +0 -1
- package/dist/cross-schema.d.ts +0 -18
- package/dist/cross-schema.d.ts.map +0 -1
- package/dist/cross-schema.js +0 -29
- package/dist/cross-schema.js.map +0 -1
- package/dist/derive.d.ts +0 -44
- package/dist/derive.d.ts.map +0 -1
- package/dist/derive.js +0 -149
- package/dist/derive.js.map +0 -1
- package/dist/draft.d.ts +0 -28
- package/dist/draft.d.ts.map +0 -1
- package/dist/draft.js +0 -157
- package/dist/draft.js.map +0 -1
- package/dist/errors.d.ts +0 -141
- package/dist/errors.d.ts.map +0 -1
- package/dist/errors.js +0 -185
- package/dist/errors.js.map +0 -1
- package/dist/execute.d.ts +0 -52
- package/dist/execute.d.ts.map +0 -1
- package/dist/execute.js +0 -511
- package/dist/execute.js.map +0 -1
- package/dist/fetch.d.ts +0 -15
- package/dist/fetch.d.ts.map +0 -1
- package/dist/fetch.js +0 -102
- package/dist/fetch.js.map +0 -1
- package/dist/fire.d.ts +0 -43
- package/dist/fire.d.ts.map +0 -1
- package/dist/fire.js +0 -185
- package/dist/fire.js.map +0 -1
- package/dist/guards.d.ts +0 -17
- package/dist/guards.d.ts.map +0 -1
- package/dist/guards.js +0 -25
- package/dist/guards.js.map +0 -1
- package/dist/index.d.ts +0 -59
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -61
- package/dist/index.js.map +0 -1
- package/dist/internal/cross-batch.d.ts +0 -44
- package/dist/internal/cross-batch.d.ts.map +0 -1
- package/dist/internal/cross-batch.js +0 -58
- package/dist/internal/cross-batch.js.map +0 -1
- package/dist/internal/fork-ctx.d.ts +0 -41
- package/dist/internal/fork-ctx.d.ts.map +0 -1
- package/dist/internal/fork-ctx.js +0 -47
- package/dist/internal/fork-ctx.js.map +0 -1
- package/dist/internal/signal-ref.d.ts +0 -15
- package/dist/internal/signal-ref.d.ts.map +0 -1
- package/dist/internal/signal-ref.js +0 -41
- package/dist/internal/signal-ref.js.map +0 -1
- package/dist/internal/topo-saves.d.ts +0 -53
- package/dist/internal/topo-saves.d.ts.map +0 -1
- package/dist/internal/topo-saves.js +0 -449
- package/dist/internal/topo-saves.js.map +0 -1
- package/dist/internal/topo-snapshots.d.ts +0 -57
- package/dist/internal/topo-snapshots.d.ts.map +0 -1
- package/dist/internal/topo-snapshots.js +0 -372
- package/dist/internal/topo-snapshots.js.map +0 -1
- package/dist/internal/topo-store-read.d.ts +0 -70
- package/dist/internal/topo-store-read.d.ts.map +0 -1
- package/dist/internal/topo-store-read.js +0 -221
- package/dist/internal/topo-store-read.js.map +0 -1
- package/dist/internal/topo-store.d.ts +0 -26
- package/dist/internal/topo-store.d.ts.map +0 -1
- package/dist/internal/topo-store.js +0 -621
- package/dist/internal/topo-store.js.map +0 -1
- package/dist/internal/tracing.d.ts +0 -98
- package/dist/internal/tracing.d.ts.map +0 -1
- package/dist/internal/tracing.js +0 -102
- package/dist/internal/tracing.js.map +0 -1
- package/dist/internal/trails-db.d.ts +0 -16
- package/dist/internal/trails-db.d.ts.map +0 -1
- package/dist/internal/trails-db.js +0 -118
- package/dist/internal/trails-db.js.map +0 -1
- package/dist/internal/zod-wrappers.d.ts +0 -40
- package/dist/internal/zod-wrappers.d.ts.map +0 -1
- package/dist/internal/zod-wrappers.js +0 -59
- package/dist/internal/zod-wrappers.js.map +0 -1
- package/dist/layer.d.ts +0 -23
- package/dist/layer.d.ts.map +0 -1
- package/dist/layer.js +0 -21
- package/dist/layer.js.map +0 -1
- package/dist/path-security.d.ts +0 -28
- package/dist/path-security.d.ts.map +0 -1
- package/dist/path-security.js +0 -63
- package/dist/path-security.js.map +0 -1
- package/dist/patterns/bulk.d.ts +0 -15
- package/dist/patterns/bulk.d.ts.map +0 -1
- package/dist/patterns/bulk.js +0 -14
- package/dist/patterns/bulk.js.map +0 -1
- package/dist/patterns/change.d.ts +0 -10
- package/dist/patterns/change.d.ts.map +0 -1
- package/dist/patterns/change.js +0 -10
- package/dist/patterns/change.js.map +0 -1
- package/dist/patterns/date-range.d.ts +0 -10
- package/dist/patterns/date-range.d.ts.map +0 -1
- package/dist/patterns/date-range.js +0 -10
- package/dist/patterns/date-range.js.map +0 -1
- package/dist/patterns/index.d.ts +0 -9
- package/dist/patterns/index.d.ts.map +0 -1
- package/dist/patterns/index.js +0 -9
- package/dist/patterns/index.js.map +0 -1
- package/dist/patterns/pagination.d.ts +0 -18
- package/dist/patterns/pagination.d.ts.map +0 -1
- package/dist/patterns/pagination.js +0 -18
- package/dist/patterns/pagination.js.map +0 -1
- package/dist/patterns/progress.d.ts +0 -11
- package/dist/patterns/progress.d.ts.map +0 -1
- package/dist/patterns/progress.js +0 -11
- package/dist/patterns/progress.js.map +0 -1
- package/dist/patterns/sorting.d.ts +0 -13
- package/dist/patterns/sorting.d.ts.map +0 -1
- package/dist/patterns/sorting.js +0 -10
- package/dist/patterns/sorting.js.map +0 -1
- package/dist/patterns/status.d.ts +0 -15
- package/dist/patterns/status.d.ts.map +0 -1
- package/dist/patterns/status.js +0 -9
- package/dist/patterns/status.js.map +0 -1
- package/dist/patterns/timestamps.d.ts +0 -10
- package/dist/patterns/timestamps.d.ts.map +0 -1
- package/dist/patterns/timestamps.js +0 -10
- package/dist/patterns/timestamps.js.map +0 -1
- package/dist/redaction/index.d.ts +0 -4
- package/dist/redaction/index.d.ts.map +0 -1
- package/dist/redaction/index.js +0 -3
- package/dist/redaction/index.js.map +0 -1
- package/dist/redaction/patterns.d.ts +0 -9
- package/dist/redaction/patterns.d.ts.map +0 -1
- package/dist/redaction/patterns.js +0 -39
- package/dist/redaction/patterns.js.map +0 -1
- package/dist/redaction/redactor.d.ts +0 -27
- package/dist/redaction/redactor.d.ts.map +0 -1
- package/dist/redaction/redactor.js +0 -89
- package/dist/redaction/redactor.js.map +0 -1
- package/dist/resilience.d.ts +0 -34
- package/dist/resilience.d.ts.map +0 -1
- package/dist/resilience.js +0 -164
- package/dist/resilience.js.map +0 -1
- package/dist/resource-config.d.ts +0 -22
- package/dist/resource-config.d.ts.map +0 -1
- package/dist/resource-config.js +0 -210
- package/dist/resource-config.js.map +0 -1
- package/dist/resource.d.ts +0 -74
- package/dist/resource.d.ts.map +0 -1
- package/dist/resource.js +0 -61
- package/dist/resource.js.map +0 -1
- package/dist/result.d.ts +0 -57
- package/dist/result.d.ts.map +0 -1
- package/dist/result.js +0 -156
- package/dist/result.js.map +0 -1
- package/dist/run.d.ts +0 -28
- package/dist/run.d.ts.map +0 -1
- package/dist/run.js +0 -35
- package/dist/run.js.map +0 -1
- package/dist/serialization.d.ts +0 -27
- package/dist/serialization.d.ts.map +0 -1
- package/dist/serialization.js +0 -154
- package/dist/serialization.js.map +0 -1
- package/dist/signal.d.ts +0 -33
- package/dist/signal.d.ts.map +0 -1
- package/dist/signal.js +0 -17
- package/dist/signal.js.map +0 -1
- package/dist/store/accessor-protocol.d.ts +0 -51
- package/dist/store/accessor-protocol.d.ts.map +0 -1
- package/dist/store/accessor-protocol.js +0 -2
- package/dist/store/accessor-protocol.js.map +0 -1
- package/dist/store/index.d.ts +0 -2
- package/dist/store/index.d.ts.map +0 -1
- package/dist/store/index.js +0 -2
- package/dist/store/index.js.map +0 -1
- package/dist/surface-filter.d.ts +0 -13
- package/dist/surface-filter.d.ts.map +0 -1
- package/dist/surface-filter.js +0 -76
- package/dist/surface-filter.js.map +0 -1
- package/dist/topo-store.d.ts +0 -62
- package/dist/topo-store.d.ts.map +0 -1
- package/dist/topo-store.js +0 -319
- package/dist/topo-store.js.map +0 -1
- package/dist/topo.d.ts +0 -39
- package/dist/topo.d.ts.map +0 -1
- package/dist/topo.js +0 -241
- package/dist/topo.js.map +0 -1
- package/dist/trail.d.ts +0 -163
- package/dist/trail.d.ts.map +0 -1
- package/dist/trail.js +0 -75
- package/dist/trail.js.map +0 -1
- package/dist/trails/derive-trail.d.ts +0 -66
- package/dist/trails/derive-trail.d.ts.map +0 -1
- package/dist/trails/derive-trail.js +0 -378
- package/dist/trails/derive-trail.js.map +0 -1
- package/dist/trails/index.d.ts +0 -5
- package/dist/trails/index.d.ts.map +0 -1
- package/dist/trails/index.js +0 -3
- package/dist/trails/index.js.map +0 -1
- package/dist/trails/ingest.d.ts +0 -24
- package/dist/trails/ingest.d.ts.map +0 -1
- package/dist/trails/ingest.js +0 -63
- package/dist/trails/ingest.js.map +0 -1
- package/dist/transport-error-map.d.ts +0 -106
- package/dist/transport-error-map.d.ts.map +0 -1
- package/dist/transport-error-map.js +0 -24
- package/dist/transport-error-map.js.map +0 -1
- package/dist/type-checks.test-d.d.ts +0 -71
- package/dist/type-checks.test-d.d.ts.map +0 -1
- package/dist/type-checks.test-d.js +0 -12
- package/dist/type-checks.test-d.js.map +0 -1
- package/dist/type-utils.d.ts +0 -33
- package/dist/type-utils.d.ts.map +0 -1
- package/dist/type-utils.js +0 -12
- package/dist/type-utils.js.map +0 -1
- package/dist/types.d.ts +0 -177
- package/dist/types.d.ts.map +0 -1
- package/dist/types.js +0 -3
- package/dist/types.js.map +0 -1
- package/dist/validate-established-topo.d.ts +0 -76
- package/dist/validate-established-topo.d.ts.map +0 -1
- package/dist/validate-established-topo.js +0 -43
- package/dist/validate-established-topo.js.map +0 -1
- package/dist/validate-topo.d.ts +0 -24
- package/dist/validate-topo.d.ts.map +0 -1
- package/dist/validate-topo.js +0 -193
- package/dist/validate-topo.js.map +0 -1
- package/dist/validation.d.ts +0 -27
- package/dist/validation.d.ts.map +0 -1
- package/dist/validation.js +0 -165
- package/dist/validation.js.map +0 -1
- package/dist/workspace.d.ts +0 -25
- package/dist/workspace.d.ts.map +0 -1
- package/dist/workspace.js +0 -57
- package/dist/workspace.js.map +0 -1
- package/src/__tests__/blob-ref.test.ts +0 -103
- package/src/__tests__/branded.test.ts +0 -148
- package/src/__tests__/collections.test.ts +0 -126
- package/src/__tests__/context.test.ts +0 -77
- package/src/__tests__/contour.test.ts +0 -263
- package/src/__tests__/derive-trail.test.ts +0 -668
- package/src/__tests__/derive.test.ts +0 -260
- package/src/__tests__/errors.test.ts +0 -427
- package/src/__tests__/execute.test.ts +0 -1563
- package/src/__tests__/fetch.test.ts +0 -217
- package/src/__tests__/fire.test.ts +0 -1056
- package/src/__tests__/fork-ctx.test.ts +0 -83
- package/src/__tests__/guards.test.ts +0 -102
- package/src/__tests__/ingest.test.ts +0 -191
- package/src/__tests__/layer.test.ts +0 -125
- package/src/__tests__/path-security.test.ts +0 -114
- package/src/__tests__/patterns.test.ts +0 -273
- package/src/__tests__/redaction.test.ts +0 -244
- package/src/__tests__/resilience.test.ts +0 -246
- package/src/__tests__/resource.test.ts +0 -204
- package/src/__tests__/result.test.ts +0 -155
- package/src/__tests__/run.test.ts +0 -181
- package/src/__tests__/serialization.test.ts +0 -401
- package/src/__tests__/service-config.test.ts +0 -224
- package/src/__tests__/signal.test.ts +0 -82
- package/src/__tests__/surface-filter.test.ts +0 -196
- package/src/__tests__/topo-store-read.test.ts +0 -256
- package/src/__tests__/topo-store.test.ts +0 -869
- package/src/__tests__/topo.test.ts +0 -573
- package/src/__tests__/trail-permit.test.ts +0 -60
- package/src/__tests__/trail.test.ts +0 -426
- package/src/__tests__/trails-db.test.ts +0 -198
- package/src/__tests__/transport-error-map.test.ts +0 -82
- package/src/__tests__/type-utils.test.ts +0 -118
- package/src/__tests__/validate-topo.test.ts +0 -611
- package/src/__tests__/validation.test.ts +0 -336
- package/src/__tests__/workspace.test.ts +0 -183
- package/src/__tests__/zod-wrappers.test.ts +0 -62
- package/src/internal/topo-snapshots.ts +0 -517
- package/src/internal/topo-store-read.ts +0 -481
- package/src/internal/topo-store.ts +0 -1192
- package/src/internal/tracing.ts +0 -187
- package/src/topo-store.ts +0 -510
- package/src/type-checks.test-d.ts +0 -106
- package/tsconfig.json +0 -9
- package/tsconfig.tests.json +0 -10
- package/tsconfig.tsbuildinfo +0 -1
package/src/trails/ingest.ts
CHANGED
|
@@ -10,7 +10,6 @@ import type { Trail, TrailExample, TrailSpec } from '../trail.js';
|
|
|
10
10
|
import type { TrailContext } from '../types.js';
|
|
11
11
|
|
|
12
12
|
type SchemaValue<TSchema extends z.ZodType> = z.output<TSchema>;
|
|
13
|
-
type SignalRef<TSignal> = string | Signal<TSignal>;
|
|
14
13
|
|
|
15
14
|
type ExampleBearingSchema<TSchema extends z.ZodType> = TSchema & {
|
|
16
15
|
readonly examples?: readonly Partial<SchemaValue<TSchema>>[] | undefined;
|
|
@@ -24,8 +23,8 @@ interface IngestBaseOptions<TSchema extends z.ZodType, TSignal> extends Omit<
|
|
|
24
23
|
readonly id?: string | undefined;
|
|
25
24
|
/** Validated external payload shape. */
|
|
26
25
|
readonly schema: TSchema;
|
|
27
|
-
/** Signal to
|
|
28
|
-
readonly signal:
|
|
26
|
+
/** Signal to fire after verification and optional transformation. */
|
|
27
|
+
readonly signal: Signal<TSignal>;
|
|
29
28
|
/** Optional per-trail verification layer, e.g. HMAC signature checks. */
|
|
30
29
|
readonly verify?: Layer | undefined;
|
|
31
30
|
}
|
|
@@ -44,9 +43,6 @@ export interface IngestOptions<
|
|
|
44
43
|
| undefined;
|
|
45
44
|
}
|
|
46
45
|
|
|
47
|
-
const resolveSignalId = <TSignal>(signalRef: SignalRef<TSignal>): string =>
|
|
48
|
-
typeof signalRef === 'string' ? signalRef : signalRef.id;
|
|
49
|
-
|
|
50
46
|
const deriveExampleName = (signalId: string, index: number): string =>
|
|
51
47
|
`Ingest ${signalId} ${index + 1}`;
|
|
52
48
|
|
|
@@ -69,7 +65,7 @@ const deriveExamples = <TSchema extends z.ZodType>(
|
|
|
69
65
|
|
|
70
66
|
const createIngestBlaze =
|
|
71
67
|
<TSchema extends z.ZodType, TSignal>(
|
|
72
|
-
signalRef:
|
|
68
|
+
signalRef: Signal<TSignal>,
|
|
73
69
|
signalId: string,
|
|
74
70
|
trailId: string,
|
|
75
71
|
transform: IngestTransform<SchemaValue<TSchema>, TSignal> | undefined
|
|
@@ -81,7 +77,7 @@ const createIngestBlaze =
|
|
|
81
77
|
if (ctx.fire === undefined) {
|
|
82
78
|
return Result.err(
|
|
83
79
|
new InternalError(
|
|
84
|
-
`ingest("${trailId}") requires topo-backed execution to
|
|
80
|
+
`ingest("${trailId}") requires topo-backed execution to fire "${signalId}"`
|
|
85
81
|
)
|
|
86
82
|
);
|
|
87
83
|
}
|
|
@@ -91,12 +87,8 @@ const createIngestBlaze =
|
|
|
91
87
|
transform === undefined
|
|
92
88
|
? (input as TSignal)
|
|
93
89
|
: await transform(input, ctx);
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
? await ctx.fire(signalRef, payload as unknown)
|
|
97
|
-
: await ctx.fire(signalRef as Signal<unknown>, payload as unknown);
|
|
98
|
-
|
|
99
|
-
return fired.isErr() ? Result.err(fired.error) : Result.ok();
|
|
90
|
+
await ctx.fire(signalRef, payload);
|
|
91
|
+
return Result.ok();
|
|
100
92
|
} catch (error) {
|
|
101
93
|
const message = `ingest("${trailId}"): ${error instanceof Error ? error.message : String(error)}`;
|
|
102
94
|
return Result.err(
|
|
@@ -113,7 +105,7 @@ export const ingest = <
|
|
|
113
105
|
>(
|
|
114
106
|
options: IngestOptions<TSchema, TSignal>
|
|
115
107
|
): Trail<SchemaValue<TSchema>, void> => {
|
|
116
|
-
const signalId =
|
|
108
|
+
const signalId = options.signal.id;
|
|
117
109
|
const id = options.id ?? `${signalId}.ingest`;
|
|
118
110
|
const { id: _id, schema, signal, transform, verify, ...trailSpec } = options;
|
|
119
111
|
const baseBlaze = createIngestBlaze<TSchema, TSignal>(
|
|
@@ -2,28 +2,41 @@ import { Database } from 'bun:sqlite';
|
|
|
2
2
|
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { dirname, join, resolve } from 'node:path';
|
|
4
4
|
|
|
5
|
-
import { NotFoundError } from '
|
|
5
|
+
import { NotFoundError } from './errors.js';
|
|
6
6
|
|
|
7
7
|
const TRAILS_DIR = '.trails';
|
|
8
8
|
const TRAILS_DB_FILE = 'trails.db';
|
|
9
|
+
const TRAILS_CACHE_DIR = 'cache';
|
|
10
|
+
const TRAILS_STATE_DIR = 'state';
|
|
9
11
|
const SCHEMA_VERSION_TABLE = 'meta_schema_versions';
|
|
10
|
-
const WORKSPACE_SUBDIRS = [
|
|
11
|
-
|
|
12
|
+
const WORKSPACE_SUBDIRS = [TRAILS_CACHE_DIR, TRAILS_STATE_DIR] as const;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* The canonical lines written to a freshly-bootstrapped
|
|
16
|
+
* `.trails/.gitignore`. Kept as the source of truth for every consumer that
|
|
17
|
+
* needs to either write the file (scaffold) or audit its content (tests).
|
|
18
|
+
*
|
|
19
|
+
* @see {@link WORKSPACE_GITIGNORE_CONTENT} for the rendered string form.
|
|
20
|
+
*/
|
|
21
|
+
export const WORKSPACE_GITIGNORE_LINES = [
|
|
12
22
|
'# Local config overrides',
|
|
13
|
-
'config
|
|
23
|
+
'config.local.js',
|
|
24
|
+
'config.local.ts',
|
|
14
25
|
'',
|
|
15
|
-
'#
|
|
16
|
-
'
|
|
26
|
+
'# Rebuildable cache',
|
|
27
|
+
'cache/',
|
|
17
28
|
'',
|
|
18
|
-
'#
|
|
19
|
-
'
|
|
29
|
+
'# Mutable runtime state',
|
|
30
|
+
'state/',
|
|
20
31
|
'',
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
32
|
+
] as const;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The canonical rendered `.trails/.gitignore` content. Use this when writing
|
|
36
|
+
* the file eagerly (e.g. during `trails create` scaffolding) or when asserting
|
|
37
|
+
* on the workspace bootstrap output.
|
|
38
|
+
*/
|
|
39
|
+
export const WORKSPACE_GITIGNORE_CONTENT = `${WORKSPACE_GITIGNORE_LINES.join('\n').trimEnd()}\n`;
|
|
27
40
|
|
|
28
41
|
export interface TrailsDbLocationOptions {
|
|
29
42
|
readonly path?: string;
|
|
@@ -49,20 +62,18 @@ export const deriveTrailsDir = (options?: TrailsDbLocationOptions): string =>
|
|
|
49
62
|
export const deriveTrailsDbPath = (options?: TrailsDbLocationOptions): string =>
|
|
50
63
|
options?.path
|
|
51
64
|
? resolve(options.path)
|
|
52
|
-
: join(deriveTrailsDir(options), TRAILS_DB_FILE);
|
|
65
|
+
: join(deriveTrailsDir(options), TRAILS_STATE_DIR, TRAILS_DB_FILE);
|
|
53
66
|
|
|
54
67
|
const ensureDbParentDir = (dbPath: string): void => {
|
|
55
68
|
mkdirSync(dirname(dbPath), { recursive: true });
|
|
56
69
|
};
|
|
57
70
|
|
|
58
|
-
const GITIGNORE_TEMPLATE = `${REQUIRED_GITIGNORE_LINES.join('\n').trimEnd()}\n`;
|
|
59
|
-
|
|
60
71
|
const appendMissingGitignoreLines = (
|
|
61
72
|
gitignorePath: string,
|
|
62
73
|
content: string
|
|
63
74
|
): void => {
|
|
64
75
|
const existingLines = new Set(content.split('\n').map((l) => l.trim()));
|
|
65
|
-
const missing =
|
|
76
|
+
const missing = WORKSPACE_GITIGNORE_LINES.filter(
|
|
66
77
|
(line) => line !== '' && !existingLines.has(line)
|
|
67
78
|
);
|
|
68
79
|
|
|
@@ -78,7 +89,7 @@ const ensureWorkspaceGitignore = (trailsDir: string): void => {
|
|
|
78
89
|
const gitignorePath = join(trailsDir, '.gitignore');
|
|
79
90
|
|
|
80
91
|
if (!existsSync(gitignorePath)) {
|
|
81
|
-
writeFileSync(gitignorePath,
|
|
92
|
+
writeFileSync(gitignorePath, WORKSPACE_GITIGNORE_CONTENT);
|
|
82
93
|
return;
|
|
83
94
|
}
|
|
84
95
|
|
|
@@ -88,7 +99,17 @@ const ensureWorkspaceGitignore = (trailsDir: string): void => {
|
|
|
88
99
|
);
|
|
89
100
|
};
|
|
90
101
|
|
|
91
|
-
|
|
102
|
+
/**
|
|
103
|
+
* Bootstrap the `.trails/` workspace at `rootDir`.
|
|
104
|
+
*
|
|
105
|
+
* Creates the workspace directory plus the canonical `cache/` and `state/`
|
|
106
|
+
* subdirectories, then either writes a fresh `.gitignore` matching
|
|
107
|
+
* {@link WORKSPACE_GITIGNORE_CONTENT} or appends any missing canonical lines
|
|
108
|
+
* to an existing one. Safe to call repeatedly. This is the single canonical
|
|
109
|
+
* source of truth for workspace layout — scaffolding, configuration loading,
|
|
110
|
+
* and runtime DB initialization all flow through here.
|
|
111
|
+
*/
|
|
112
|
+
export const ensureTrailsWorkspace = (rootDir: string): void => {
|
|
92
113
|
const trailsDir = deriveTrailsDir({ rootDir });
|
|
93
114
|
mkdirSync(trailsDir, { recursive: true });
|
|
94
115
|
for (const subdir of WORKSPACE_SUBDIRS) {
|
|
@@ -144,7 +165,7 @@ export const openWriteTrailsDb = (
|
|
|
144
165
|
);
|
|
145
166
|
|
|
146
167
|
if (options?.path === undefined) {
|
|
147
|
-
|
|
168
|
+
ensureTrailsWorkspace(rootDir);
|
|
148
169
|
} else {
|
|
149
170
|
ensureDbParentDir(dbPath);
|
|
150
171
|
}
|
|
@@ -1,56 +1,174 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
|
|
1
|
+
import type {
|
|
2
|
+
ErrorCategory,
|
|
3
|
+
ErrorCategoryCodes,
|
|
4
|
+
ErrorClassRegistryEntry,
|
|
5
|
+
FixedErrorClassRegistryEntry,
|
|
6
|
+
TrailsError,
|
|
7
|
+
} from './errors.js';
|
|
8
|
+
import {
|
|
9
|
+
codesByCategory,
|
|
10
|
+
errorClasses,
|
|
11
|
+
exitCodeMap,
|
|
12
|
+
isTrailsError,
|
|
13
|
+
jsonRpcCodeMap,
|
|
14
|
+
statusCodeMap,
|
|
15
|
+
} from './errors.js';
|
|
16
|
+
import {
|
|
17
|
+
INTERNAL_ERROR_PUBLIC_MESSAGE,
|
|
18
|
+
redactErrorString,
|
|
19
|
+
} from './error-projection.js';
|
|
3
20
|
|
|
4
|
-
export const
|
|
21
|
+
export const surfaceNames = ['cli', 'http', 'jsonRpc', 'mcp'] as const;
|
|
5
22
|
|
|
6
|
-
export type
|
|
23
|
+
export type SurfaceName = (typeof surfaceNames)[number];
|
|
7
24
|
|
|
8
|
-
|
|
25
|
+
const surfaceCodeKeys = {
|
|
26
|
+
cli: 'exit',
|
|
27
|
+
http: 'http',
|
|
28
|
+
jsonRpc: 'jsonRpc',
|
|
29
|
+
mcp: 'jsonRpc',
|
|
30
|
+
} as const satisfies Record<SurfaceName, keyof ErrorCategoryCodes>;
|
|
9
31
|
|
|
10
|
-
export type
|
|
32
|
+
export type SurfaceErrorMapper<T> = (error: TrailsError) => T;
|
|
33
|
+
|
|
34
|
+
export type SurfaceErrorMappings<T> = Record<ErrorCategory, T>;
|
|
11
35
|
|
|
12
36
|
/**
|
|
13
|
-
* Union of every
|
|
37
|
+
* Union of every surface-specific error code emitted by {@link surfaceErrorMap}.
|
|
14
38
|
*
|
|
15
39
|
* @remarks
|
|
16
|
-
* Previously
|
|
40
|
+
* Previously parameterized by surface (`SurfaceErrorCode<'cli'>` etc.), but
|
|
17
41
|
* the generic collapsed to `number` because the underlying maps were typed as
|
|
18
42
|
* `Record<ErrorCategory, number>`. With `as const satisfies` on the maps the
|
|
19
|
-
* per-
|
|
20
|
-
* `
|
|
21
|
-
*
|
|
22
|
-
*
|
|
43
|
+
* per-surface literals are now observable, but TypeScript cannot narrow
|
|
44
|
+
* `surfaceErrorMap[surface][error.category]` through a generic `TSurface`
|
|
45
|
+
* without an unsound cast. The non-generic union honestly reflects what
|
|
46
|
+
* `mapSurfaceError` returns at the call site.
|
|
23
47
|
*/
|
|
24
|
-
export type
|
|
25
|
-
(typeof
|
|
48
|
+
export type SurfaceErrorCode =
|
|
49
|
+
(typeof codesByCategory)[ErrorCategory][(typeof surfaceCodeKeys)[SurfaceName]];
|
|
50
|
+
|
|
51
|
+
export interface SurfaceErrorProjection {
|
|
52
|
+
readonly category: ErrorCategory;
|
|
53
|
+
readonly code: SurfaceErrorCode;
|
|
54
|
+
readonly message: string;
|
|
55
|
+
readonly name: string;
|
|
56
|
+
readonly retryable: boolean;
|
|
57
|
+
readonly surface: SurfaceName;
|
|
58
|
+
}
|
|
26
59
|
|
|
27
|
-
export
|
|
28
|
-
|
|
60
|
+
export interface ErrorClassSurfaceProjection {
|
|
61
|
+
readonly category: ErrorCategory;
|
|
62
|
+
readonly code: SurfaceErrorCode;
|
|
63
|
+
readonly name: string;
|
|
64
|
+
readonly retryable: boolean;
|
|
65
|
+
readonly surface: SurfaceName;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export const createSurfaceErrorMapper =
|
|
69
|
+
<T>(mappings: SurfaceErrorMappings<T>): SurfaceErrorMapper<T> =>
|
|
29
70
|
(error) =>
|
|
30
71
|
mappings[error.category];
|
|
31
72
|
|
|
32
|
-
export const
|
|
73
|
+
export const surfaceErrorMap = {
|
|
33
74
|
cli: exitCodeMap,
|
|
34
75
|
http: statusCodeMap,
|
|
76
|
+
jsonRpc: jsonRpcCodeMap,
|
|
35
77
|
mcp: jsonRpcCodeMap,
|
|
36
|
-
} as const satisfies Record<
|
|
78
|
+
} as const satisfies Record<SurfaceName, SurfaceErrorMappings<number>>;
|
|
37
79
|
|
|
38
|
-
export const
|
|
80
|
+
export const surfaceErrorRegistry = {
|
|
39
81
|
cli: {
|
|
40
|
-
map:
|
|
41
|
-
values:
|
|
82
|
+
map: createSurfaceErrorMapper(surfaceErrorMap.cli),
|
|
83
|
+
values: surfaceErrorMap.cli,
|
|
42
84
|
},
|
|
43
85
|
http: {
|
|
44
|
-
map:
|
|
45
|
-
values:
|
|
86
|
+
map: createSurfaceErrorMapper(surfaceErrorMap.http),
|
|
87
|
+
values: surfaceErrorMap.http,
|
|
88
|
+
},
|
|
89
|
+
jsonRpc: {
|
|
90
|
+
map: createSurfaceErrorMapper(surfaceErrorMap.jsonRpc),
|
|
91
|
+
values: surfaceErrorMap.jsonRpc,
|
|
46
92
|
},
|
|
47
93
|
mcp: {
|
|
48
|
-
map:
|
|
49
|
-
values:
|
|
94
|
+
map: createSurfaceErrorMapper(surfaceErrorMap.mcp),
|
|
95
|
+
values: surfaceErrorMap.mcp,
|
|
50
96
|
},
|
|
51
97
|
} as const;
|
|
52
98
|
|
|
53
|
-
export const
|
|
54
|
-
|
|
99
|
+
export const mapSurfaceError = (
|
|
100
|
+
surface: SurfaceName,
|
|
55
101
|
error: TrailsError
|
|
56
|
-
):
|
|
102
|
+
): SurfaceErrorCode =>
|
|
103
|
+
codesByCategory[error.category][surfaceCodeKeys[surface]];
|
|
104
|
+
|
|
105
|
+
export const projectSurfaceError = (
|
|
106
|
+
surface: SurfaceName,
|
|
107
|
+
error: TrailsError
|
|
108
|
+
): SurfaceErrorProjection => ({
|
|
109
|
+
category: error.category,
|
|
110
|
+
code: mapSurfaceError(surface, error),
|
|
111
|
+
message: error.message,
|
|
112
|
+
name: error.name,
|
|
113
|
+
retryable: error.retryable,
|
|
114
|
+
surface,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
export const projectPublicSurfaceError = (
|
|
118
|
+
surface: SurfaceName,
|
|
119
|
+
error: Error
|
|
120
|
+
): SurfaceErrorProjection => {
|
|
121
|
+
if (isTrailsError(error)) {
|
|
122
|
+
const projection = projectSurfaceError(surface, error);
|
|
123
|
+
return {
|
|
124
|
+
...projection,
|
|
125
|
+
message:
|
|
126
|
+
projection.category === 'internal'
|
|
127
|
+
? INTERNAL_ERROR_PUBLIC_MESSAGE
|
|
128
|
+
: redactErrorString(projection.message),
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return {
|
|
133
|
+
category: 'internal',
|
|
134
|
+
code: codesByCategory.internal[surfaceCodeKeys[surface]],
|
|
135
|
+
message: INTERNAL_ERROR_PUBLIC_MESSAGE,
|
|
136
|
+
name: 'InternalError',
|
|
137
|
+
retryable: false,
|
|
138
|
+
surface,
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
const isFixedErrorClassEntry = (
|
|
143
|
+
entry: ErrorClassRegistryEntry
|
|
144
|
+
): entry is FixedErrorClassRegistryEntry => entry.category !== 'dynamic';
|
|
145
|
+
|
|
146
|
+
const fixedErrorClassByName: ReadonlyMap<string, FixedErrorClassRegistryEntry> =
|
|
147
|
+
new Map(
|
|
148
|
+
errorClasses.flatMap((entry): [string, FixedErrorClassRegistryEntry][] =>
|
|
149
|
+
isFixedErrorClassEntry(entry) ? [[entry.name, entry]] : []
|
|
150
|
+
)
|
|
151
|
+
);
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Project a known error class name onto a surface without constructing it.
|
|
155
|
+
*
|
|
156
|
+
* Dynamic-category errors such as `RetryExhaustedError` return `undefined`
|
|
157
|
+
* because their surface code depends on the wrapped runtime error.
|
|
158
|
+
*/
|
|
159
|
+
export const projectErrorClassSurface = (
|
|
160
|
+
surface: SurfaceName,
|
|
161
|
+
errorName: string
|
|
162
|
+
): ErrorClassSurfaceProjection | undefined => {
|
|
163
|
+
const entry = fixedErrorClassByName.get(errorName);
|
|
164
|
+
if (entry === undefined) {
|
|
165
|
+
return undefined;
|
|
166
|
+
}
|
|
167
|
+
return {
|
|
168
|
+
category: entry.category,
|
|
169
|
+
code: codesByCategory[entry.category][surfaceCodeKeys[surface]],
|
|
170
|
+
name: entry.name,
|
|
171
|
+
retryable: entry.retryable,
|
|
172
|
+
surface,
|
|
173
|
+
};
|
|
174
|
+
};
|
package/src/types.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import type { TrailsError } from './errors.js';
|
|
2
|
+
import type { BasePermit } from './permits.js';
|
|
2
3
|
import type { Result } from './result.js';
|
|
3
4
|
import type { Signal } from './signal.js';
|
|
4
5
|
import type { AnyTrail } from './trail.js';
|
|
5
6
|
import type { CrossInput, TrailOutput } from './type-utils.js';
|
|
7
|
+
import type { ActivationProvenance } from './activation-provenance.js';
|
|
6
8
|
|
|
7
9
|
// ---------------------------------------------------------------------------
|
|
8
10
|
// Detour
|
|
@@ -102,28 +104,17 @@ export interface CrossFn {
|
|
|
102
104
|
* Emit a signal — used for signal-driven activation.
|
|
103
105
|
*
|
|
104
106
|
* Fan-out to consumer trails (those with the signal in their `on:` array) is
|
|
105
|
-
* the framework's responsibility. Producers
|
|
106
|
-
*
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
*
|
|
111
|
-
* re-
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
* - **By id** (base shape): `ctx.fire('order.placed', { ... })`. Matches
|
|
116
|
-
* the shape of `ctx.cross`; payload is typed as `unknown` and validated
|
|
117
|
-
* against the signal's schema at the fire boundary.
|
|
118
|
-
* - **By signal value** (progressive disclosure): `ctx.fire(orderPlaced, payload)`
|
|
119
|
-
* where `orderPlaced` is a `Signal<T>`. The compiler enforces that
|
|
120
|
-
* `payload` matches the signal's declared schema type at the call site,
|
|
121
|
-
* on top of the runtime validation.
|
|
107
|
+
* the framework's responsibility. Producers call with a `Signal<T>` value and
|
|
108
|
+
* get best-effort `Promise<void>` semantics: payload validation, missing topo
|
|
109
|
+
* entries, guard suppression, and consumer failures are observable through
|
|
110
|
+
* diagnostics/logging but do not become producer-facing `Result` plumbing.
|
|
111
|
+
* Consumers fan out in parallel, each with its own derived context. Runtime
|
|
112
|
+
* cycle suppression is still signal-id-based against the current fire stack:
|
|
113
|
+
* it prevents re-entrant loops but can over-suppress legitimate diamond
|
|
114
|
+
* re-fires, with a debug breadcrumb and a warn emitted when suppression
|
|
115
|
+
* happens.
|
|
122
116
|
*/
|
|
123
|
-
export
|
|
124
|
-
<T>(signal: Signal<T>, payload: T): Promise<Result<void, Error>>;
|
|
125
|
-
(signalId: string, payload: unknown): Promise<Result<void, Error>>;
|
|
126
|
-
}
|
|
117
|
+
export type FireFn = <T>(signal: Signal<T>, payload: T) => Promise<void>;
|
|
127
118
|
|
|
128
119
|
/** Resolve a resource instance from the current trail context. */
|
|
129
120
|
export type ResourceLookup = <T = unknown>(
|
|
@@ -167,22 +158,64 @@ export interface Logger {
|
|
|
167
158
|
child(context: Record<string, unknown>): Logger;
|
|
168
159
|
}
|
|
169
160
|
|
|
170
|
-
|
|
171
|
-
|
|
161
|
+
export type LogLevel =
|
|
162
|
+
| 'debug'
|
|
163
|
+
| 'error'
|
|
164
|
+
| 'fatal'
|
|
165
|
+
| 'info'
|
|
166
|
+
| 'silent'
|
|
167
|
+
| 'trace'
|
|
168
|
+
| 'warn';
|
|
169
|
+
|
|
170
|
+
export interface LogRecord {
|
|
171
|
+
readonly category: string;
|
|
172
|
+
readonly level: LogLevel;
|
|
173
|
+
readonly message: string;
|
|
174
|
+
readonly metadata: Record<string, unknown>;
|
|
175
|
+
readonly timestamp: Date;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
export interface LogSink {
|
|
179
|
+
readonly name: string;
|
|
180
|
+
readonly write: (record: LogRecord) => void;
|
|
181
|
+
readonly flush?: (() => Promise<void>) | undefined;
|
|
182
|
+
}
|
|
172
183
|
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
readonly id: string;
|
|
176
|
-
readonly scopes: readonly string[];
|
|
184
|
+
export interface LogFormatter {
|
|
185
|
+
format(record: LogRecord): string;
|
|
177
186
|
}
|
|
178
187
|
|
|
188
|
+
/**
|
|
189
|
+
* Context extension key for the invoking surface name.
|
|
190
|
+
*/
|
|
191
|
+
export const SURFACE_KEY = '__trails_surface' as const;
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* Context extension key for the layer names attached by the invoking surface.
|
|
195
|
+
*/
|
|
196
|
+
export const SURFACE_LAYER_NAMES_KEY = '__trails_surface_layer_names' as const;
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Context extension key carrying per-layer runtime input.
|
|
200
|
+
*
|
|
201
|
+
* Surfaces (CLI, MCP, HTTP) project each typed layer's `input` schema onto
|
|
202
|
+
* their native idioms (flags, tool params, query strings). At execute time
|
|
203
|
+
* the parsed values are partitioned per layer and stored under this key as
|
|
204
|
+
* `Record<layerName, unknown>`. Layers that need runtime input read their
|
|
205
|
+
* own slot via `ctx.extensions?.[LAYER_INPUTS_KEY]?.[layer.name]`.
|
|
206
|
+
*
|
|
207
|
+
* @see TRL-473 for the CLI projection contract.
|
|
208
|
+
*/
|
|
209
|
+
export const LAYER_INPUTS_KEY = '__trails_layer_inputs' as const;
|
|
210
|
+
|
|
179
211
|
/** Runtime context threaded through every trail execution */
|
|
180
212
|
export interface TrailContext {
|
|
213
|
+
readonly activation?: ActivationProvenance | undefined;
|
|
181
214
|
readonly requestId: string;
|
|
182
215
|
readonly abortSignal: AbortSignal;
|
|
183
216
|
readonly cross?: CrossFn | undefined;
|
|
184
217
|
/**
|
|
185
|
-
* Emit a signal
|
|
218
|
+
* Emit a typed signal. Fans out to every trail with the signal in its
|
|
186
219
|
* `on:` declaration. Bound by the runner that holds the topo (typically
|
|
187
220
|
* `run()`); undefined when a context is constructed without topo access.
|
|
188
221
|
*/
|
|
@@ -195,6 +228,27 @@ export interface TrailContext {
|
|
|
195
228
|
readonly env?: Record<string, string | undefined> | undefined;
|
|
196
229
|
readonly extensions?: Readonly<Record<string, unknown>> | undefined;
|
|
197
230
|
readonly resource?: ResourceLookup | undefined;
|
|
231
|
+
/**
|
|
232
|
+
* Whether the current invocation is a dry run.
|
|
233
|
+
*
|
|
234
|
+
* Defaults to `false`. Trails that don't read this field are unaffected.
|
|
235
|
+
* Trails that do read it decide what dry-run means for their domain — for
|
|
236
|
+
* example: preview the change without committing, validate inputs without
|
|
237
|
+
* performing side effects, or return what would happen without actually
|
|
238
|
+
* doing it.
|
|
239
|
+
*
|
|
240
|
+
* The framework only carries the flag from the surface (e.g. CLI
|
|
241
|
+
* `--dry-run`) into the context. It never short-circuits trail execution
|
|
242
|
+
* on its own based on this field.
|
|
243
|
+
*
|
|
244
|
+
* Pair this runtime signal with `TrailSpec.dryRun`, which declares whether a
|
|
245
|
+
* trail supports dry-run semantics for governance, derivation, and surface
|
|
246
|
+
* tooling.
|
|
247
|
+
*
|
|
248
|
+
* @remarks Always defined on contexts produced by `executeTrail` or
|
|
249
|
+
* `createTrailContext` (normalized to `false` when not provided).
|
|
250
|
+
*/
|
|
251
|
+
readonly dryRun?: boolean | undefined;
|
|
198
252
|
/**
|
|
199
253
|
* Wrap a callback in a child trace span.
|
|
200
254
|
*
|
|
@@ -9,7 +9,13 @@ const PROJECTION_BLOCKING_RULES = new Set([
|
|
|
9
9
|
'cross-cycle',
|
|
10
10
|
'cross-exists',
|
|
11
11
|
'no-self-cross',
|
|
12
|
+
'activation-source-definition-unique',
|
|
13
|
+
'activation-source-edge-unique',
|
|
14
|
+
'activation-source-kind-known',
|
|
15
|
+
'activation-schedule-valid',
|
|
12
16
|
'resource-exists',
|
|
17
|
+
'signal-fire-exists',
|
|
18
|
+
'signal-on-exists',
|
|
13
19
|
'signal-origin-exists',
|
|
14
20
|
]);
|
|
15
21
|
|