@ontrails/core 1.0.0-beta.41 → 1.0.0-beta.43
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 +24 -0
- package/README.md +3 -3
- package/package.json +1 -1
- package/src/{activation-source-projection.ts → activation-source-derivation.ts} +9 -9
- package/src/blob-ref.ts +3 -3
- package/src/derive.ts +27 -27
- package/src/detours.ts +1 -1
- package/src/{error-projection.ts → error-rendering.ts} +3 -3
- package/src/errors.ts +1 -1
- package/src/execute.ts +3 -3
- package/src/fire.ts +1 -1
- package/src/index.ts +23 -23
- package/src/{layer-projection.ts → layer-field-rendering.ts} +30 -30
- package/src/layer.ts +6 -6
- package/src/observe.ts +6 -6
- package/src/resource.ts +1 -1
- package/src/schedule-runtime.ts +1 -1
- package/src/serialization.ts +1 -1
- package/src/structured-examples.ts +27 -27
- package/src/surface-derivation.ts +1 -1
- package/src/surface-overlay.ts +5 -5
- package/src/surface-versioning.ts +3 -3
- package/src/tracing.ts +3 -3
- package/src/trail.ts +9 -9
- package/src/trails/derive-trail.ts +1 -1
- package/src/transport-error-map.ts +14 -14
- package/src/types.ts +2 -2
- package/src/validate-established-topo.ts +6 -6
- package/src/validate-topo.ts +1 -1
- package/src/validation.ts +2 -2
- package/src/version-marker.ts +17 -17
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,29 @@
|
|
|
1
1
|
# @ontrails/core
|
|
2
2
|
|
|
3
|
+
## 1.0.0-beta.43
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [`88a6a62`](https://github.com/outfitter-dev/trails/commit/88a6a62a9e9e230ca6d368fa78dc3ece6c816204): Complete the v1 classification-first cutover from projection/project vocabulary
|
|
8
|
+
to derive/derived for contract-owned fact production and render/rendered for
|
|
9
|
+
surface presentation. Public type, helper, rule, relation, and report names move
|
|
10
|
+
without compatibility aliases; ordinary repository/project nouns remain
|
|
11
|
+
explicit preserves or structured review inventory.
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- [`113aed6`](https://github.com/outfitter-dev/trails/commit/113aed62d20041e35b0cf9d6c1b1a18df4b88f57): Rename the dependency-light observability owner from `@ontrails/observe` to
|
|
16
|
+
`@ontrails/observability` as a pre-v1 hard cut. Update dependent packages,
|
|
17
|
+
documentation, package discovery, and the governed Regrade route; no
|
|
18
|
+
compatibility package or old import route is retained.
|
|
19
|
+
- [`0938e7b`](https://github.com/outfitter-dev/trails/commit/0938e7badc0c5470d194139d642b673658d099e0): Fold the removed `@ontrails/tracing` package into the truthful existing
|
|
20
|
+
owners: intrinsic trace contracts remain in core, developer-state tooling now
|
|
21
|
+
lives at `@ontrails/observability/dev`, and the dependency-light OTel adapter
|
|
22
|
+
lives at `@ontrails/observability/otel`. There is intentionally no root-package
|
|
23
|
+
compatibility redirect because the former root had more than one owner.
|
|
24
|
+
|
|
25
|
+
## 1.0.0-beta.42
|
|
26
|
+
|
|
3
27
|
## 1.0.0-beta.41
|
|
4
28
|
|
|
5
29
|
## 1.0.0-beta.40
|
package/README.md
CHANGED
|
@@ -139,7 +139,7 @@ Dynamic classes:
|
|
|
139
139
|
- `RetryExhaustedError` inherits category and surface codes from its wrapped `TrailsError`; retryable is always No.
|
|
140
140
|
<!-- error-taxonomy:end -->
|
|
141
141
|
|
|
142
|
-
Public surface
|
|
142
|
+
Public surface renderings redact sensitive substrings before exposing a non-internal `TrailsError` message. Internal-category `TrailsError` instances and unknown native errors render with the generic message `Internal server error`; diagnostics and serialized payloads keep their useful structure while redacting messages, context, and stack strings.
|
|
143
143
|
|
|
144
144
|
The developer returns `Result.err(new NotFoundError(...))`. The framework maps it to the right code on every surface.
|
|
145
145
|
|
|
@@ -161,9 +161,9 @@ The developer returns `Result.err(new NotFoundError(...))`. The framework maps i
|
|
|
161
161
|
|
|
162
162
|
The root package also exposes a few low-level contracts that other framework packages build on:
|
|
163
163
|
|
|
164
|
-
- **Intrinsic tracing** -- `TraceRecord`, `TraceSink`, `TraceContext`, and the sink registry helpers are the core-owned execution record shape shared by `@ontrails/
|
|
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
165
|
- **Trails DB** -- `deriveTrailsDbPath`, `deriveTrailsStateDir`, `deriveTrailsStateHome`, `deriveTrailsProjectKey`, `deriveTrailsDir`, `ensureSubsystemSchema`, `openReadTrailsDb`, and `openWriteTrailsDb` are the generic database primitive used by framework subsystems.
|
|
166
|
-
- **Surface
|
|
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
167
|
|
|
168
168
|
See the [API Reference](../../docs/api-reference.md) for the full list.
|
|
169
169
|
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@ import { zodToJsonSchema } from './validation.js';
|
|
|
3
3
|
|
|
4
4
|
type ZodSchemaInput = Parameters<typeof zodToJsonSchema>[0];
|
|
5
5
|
|
|
6
|
-
export type
|
|
6
|
+
export type ActivationSourceFacts = Readonly<Record<string, unknown>> & {
|
|
7
7
|
readonly id: string;
|
|
8
8
|
readonly key: string;
|
|
9
9
|
readonly kind: string;
|
|
@@ -113,9 +113,9 @@ const normalizeWebhookMethod = (method: string | undefined): string =>
|
|
|
113
113
|
|
|
114
114
|
const normalizeWebhookPath = (path: string): string => path.trim();
|
|
115
115
|
|
|
116
|
-
export const
|
|
116
|
+
export const deriveActivationSourceFacts = (
|
|
117
117
|
source: ActivationSource
|
|
118
|
-
):
|
|
118
|
+
): ActivationSourceFacts => {
|
|
119
119
|
const record: Record<string, unknown> = {
|
|
120
120
|
id: source.id,
|
|
121
121
|
key: activationSourceKey(source),
|
|
@@ -172,7 +172,7 @@ export const projectActivationSourceDeclaration = (
|
|
|
172
172
|
record['hasVerify'] = true;
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
return sortKeys(record) as
|
|
175
|
+
return sortKeys(record) as ActivationSourceFacts;
|
|
176
176
|
};
|
|
177
177
|
|
|
178
178
|
/**
|
|
@@ -182,8 +182,8 @@ export const projectActivationSourceDeclaration = (
|
|
|
182
182
|
* returned token captures the function's reference identity so it changes when
|
|
183
183
|
* the verifier function changes.
|
|
184
184
|
*
|
|
185
|
-
* The token is intentionally kept out of {@link
|
|
186
|
-
* so that the persisted topo-store
|
|
185
|
+
* The token is intentionally kept out of {@link deriveActivationSourceFacts}
|
|
186
|
+
* so that the persisted topo-store facts remains stable and free of
|
|
187
187
|
* nondeterministic function identity. Use this only for in-memory comparisons
|
|
188
188
|
* (validation, conflict detection).
|
|
189
189
|
*/
|
|
@@ -218,10 +218,10 @@ const verifierIdentityToken = (
|
|
|
218
218
|
export const activationSourceDeclarationSignature = (
|
|
219
219
|
source: ActivationSource
|
|
220
220
|
): string => {
|
|
221
|
-
const
|
|
221
|
+
const facts = deriveActivationSourceFacts(source);
|
|
222
222
|
const verifyToken = verifierIdentityToken(source);
|
|
223
223
|
if (verifyToken === undefined) {
|
|
224
|
-
return JSON.stringify(
|
|
224
|
+
return JSON.stringify(facts);
|
|
225
225
|
}
|
|
226
|
-
return JSON.stringify({
|
|
226
|
+
return JSON.stringify({ facts, verify: verifyToken });
|
|
227
227
|
};
|
package/src/blob-ref.ts
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import { z } from 'zod';
|
|
6
6
|
|
|
7
|
-
/** Metadata key used to recognize BlobRef schemas during JSON Schema
|
|
7
|
+
/** Metadata key used to recognize BlobRef schemas during JSON Schema derivation. */
|
|
8
8
|
export const BLOB_REF_SCHEMA_META_KEY = 'ontrails/blob-ref';
|
|
9
9
|
|
|
10
10
|
/** Immutable reference to a blob of binary data. */
|
|
@@ -15,7 +15,7 @@ export interface BlobRef {
|
|
|
15
15
|
readonly data: Uint8Array | ReadableStream<Uint8Array>;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
/** Schema-
|
|
18
|
+
/** Schema-derived metadata for a BlobRef value. */
|
|
19
19
|
export interface BlobRefDescriptor {
|
|
20
20
|
readonly kind: 'blob';
|
|
21
21
|
readonly mimeType: string;
|
|
@@ -74,7 +74,7 @@ export const isBlobRef = (value: unknown): value is BlobRef => {
|
|
|
74
74
|
);
|
|
75
75
|
};
|
|
76
76
|
|
|
77
|
-
/** Zod schema for runtime BlobRef values with metadata for descriptor
|
|
77
|
+
/** Zod schema for runtime BlobRef values with metadata for descriptor derivation. */
|
|
78
78
|
export const blobRefSchema = z
|
|
79
79
|
.custom<BlobRef>(isBlobRef, { error: 'Expected BlobRef' })
|
|
80
80
|
.meta({ [BLOB_REF_SCHEMA_META_KEY]: true });
|
package/src/derive.ts
CHANGED
|
@@ -51,7 +51,7 @@ export interface FieldOverride {
|
|
|
51
51
|
}
|
|
52
52
|
|
|
53
53
|
// ---------------------------------------------------------------------------
|
|
54
|
-
// CLI command route
|
|
54
|
+
// CLI command route rendering
|
|
55
55
|
// ---------------------------------------------------------------------------
|
|
56
56
|
|
|
57
57
|
/** Authored CLI command path shape. Strings are split on whitespace. */
|
|
@@ -71,8 +71,8 @@ export type CliCommandRouteSource = 'derived' | 'trail' | 'surface';
|
|
|
71
71
|
/** Whether a resolved CLI command route is canonical or an alias. */
|
|
72
72
|
export type CliCommandRouteKind = 'alias' | 'canonical';
|
|
73
73
|
|
|
74
|
-
/** Trail-authored CLI
|
|
75
|
-
export interface
|
|
74
|
+
/** Trail-authored CLI rendering metadata. */
|
|
75
|
+
export interface TrailCliRendering {
|
|
76
76
|
readonly aliases?: readonly CliCommandAliasInput[] | undefined;
|
|
77
77
|
readonly path?: CliCommandPathInput | undefined;
|
|
78
78
|
}
|
|
@@ -85,18 +85,18 @@ export interface CliCommandRoute {
|
|
|
85
85
|
readonly target: string;
|
|
86
86
|
}
|
|
87
87
|
|
|
88
|
-
/** Resolved CLI
|
|
89
|
-
export interface
|
|
88
|
+
/** Resolved CLI rendering for one trail. */
|
|
89
|
+
export interface TrailCliCommandRendering {
|
|
90
90
|
readonly path: readonly string[];
|
|
91
91
|
readonly routes: readonly CliCommandRoute[];
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
interface
|
|
95
|
-
readonly cli?: CliCommandPathInput |
|
|
94
|
+
interface TrailCliRenderingInput {
|
|
95
|
+
readonly cli?: CliCommandPathInput | TrailCliRendering | undefined;
|
|
96
96
|
readonly id: string;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
export interface
|
|
99
|
+
export interface DeriveTrailCliCommandOptions {
|
|
100
100
|
readonly aliases?: readonly CliCommandAliasInput[] | undefined;
|
|
101
101
|
readonly aliasSource?: Extract<CliCommandRouteSource, 'surface' | 'trail'>;
|
|
102
102
|
}
|
|
@@ -306,38 +306,38 @@ export const normalizeCliCommandPath = (
|
|
|
306
306
|
? splitCliPathString(value, context)
|
|
307
307
|
: value.map((segment) => validateCliSegment(segment, context));
|
|
308
308
|
|
|
309
|
-
const
|
|
310
|
-
value: CliCommandPathInput |
|
|
311
|
-
): value is
|
|
309
|
+
const isTrailCliRendering = (
|
|
310
|
+
value: CliCommandPathInput | TrailCliRendering
|
|
311
|
+
): value is TrailCliRendering =>
|
|
312
312
|
typeof value !== 'string' &&
|
|
313
313
|
!Array.isArray(value) &&
|
|
314
314
|
value !== null &&
|
|
315
315
|
typeof value === 'object';
|
|
316
316
|
|
|
317
|
-
const
|
|
318
|
-
trail:
|
|
319
|
-
):
|
|
317
|
+
const trailCliRenderingFor = (
|
|
318
|
+
trail: TrailCliRenderingInput
|
|
319
|
+
): TrailCliRendering | undefined => {
|
|
320
320
|
if (trail.cli === undefined) {
|
|
321
321
|
return undefined;
|
|
322
322
|
}
|
|
323
|
-
return
|
|
323
|
+
return isTrailCliRendering(trail.cli) ? trail.cli : { path: trail.cli };
|
|
324
324
|
};
|
|
325
325
|
|
|
326
326
|
const deriveCanonicalCliRoute = (
|
|
327
|
-
trail:
|
|
327
|
+
trail: TrailCliRenderingInput
|
|
328
328
|
): CliCommandRoute => {
|
|
329
|
-
const
|
|
329
|
+
const rendering = trailCliRenderingFor(trail);
|
|
330
330
|
const path =
|
|
331
|
-
|
|
331
|
+
rendering?.path === undefined
|
|
332
332
|
? deriveCliPath(trail.id)
|
|
333
333
|
: normalizeCliCommandPath(
|
|
334
|
-
|
|
334
|
+
rendering.path,
|
|
335
335
|
`CLI command path for trail "${trail.id}"`
|
|
336
336
|
);
|
|
337
337
|
return {
|
|
338
338
|
kind: 'canonical',
|
|
339
339
|
path,
|
|
340
|
-
source:
|
|
340
|
+
source: rendering?.path === undefined ? 'derived' : 'trail',
|
|
341
341
|
target: trail.id,
|
|
342
342
|
};
|
|
343
343
|
};
|
|
@@ -387,7 +387,7 @@ const normalizeCliAlias = ({
|
|
|
387
387
|
*
|
|
388
388
|
* MCP tool names must be `[a-z0-9_]+`: the app name prefixes the trail id,
|
|
389
389
|
* dots and hyphens collapse to underscores, and everything lowercases. This
|
|
390
|
-
* is the one owner for the
|
|
390
|
+
* is the one owner for the rendering — the MCP surface renders tools with
|
|
391
391
|
* it and Warden checks binding-name collisions against it, so the two
|
|
392
392
|
* readers cannot drift.
|
|
393
393
|
*
|
|
@@ -404,14 +404,14 @@ export const deriveMcpToolName = (appName: string, trailId: string): string => {
|
|
|
404
404
|
};
|
|
405
405
|
|
|
406
406
|
/** Derive resolved CLI command routes for one trail. */
|
|
407
|
-
export const
|
|
408
|
-
trail:
|
|
409
|
-
options?:
|
|
410
|
-
):
|
|
407
|
+
export const deriveTrailCliCommandRendering = (
|
|
408
|
+
trail: TrailCliRenderingInput,
|
|
409
|
+
options?: DeriveTrailCliCommandOptions
|
|
410
|
+
): TrailCliCommandRendering => {
|
|
411
411
|
const canonical = deriveCanonicalCliRoute(trail);
|
|
412
|
-
const
|
|
412
|
+
const rendering = trailCliRenderingFor(trail);
|
|
413
413
|
const trailAliases =
|
|
414
|
-
|
|
414
|
+
rendering?.aliases?.map((alias) =>
|
|
415
415
|
normalizeCliAlias({
|
|
416
416
|
alias,
|
|
417
417
|
canonicalPath: canonical.path,
|
package/src/detours.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Hard upper bound for detour recovery attempts.
|
|
3
3
|
*
|
|
4
|
-
* Execution and derived surface/topo
|
|
4
|
+
* Execution and derived surface/topo facts both clamp declared detour
|
|
5
5
|
* attempts to this value so runtime behavior and inspectable contracts stay in
|
|
6
6
|
* lockstep.
|
|
7
7
|
*/
|
|
@@ -6,7 +6,7 @@ const errorRedactor = createRedactor();
|
|
|
6
6
|
|
|
7
7
|
export const INTERNAL_ERROR_PUBLIC_MESSAGE = 'Internal server error';
|
|
8
8
|
|
|
9
|
-
export interface
|
|
9
|
+
export interface ErrorDiagnosticsRendering {
|
|
10
10
|
readonly category?: ErrorCategory | undefined;
|
|
11
11
|
readonly context?: Record<string, unknown> | undefined;
|
|
12
12
|
readonly message: string;
|
|
@@ -28,9 +28,9 @@ export const redactErrorStack = (
|
|
|
28
28
|
): string | undefined =>
|
|
29
29
|
stack === undefined ? undefined : redactErrorString(stack);
|
|
30
30
|
|
|
31
|
-
export const
|
|
31
|
+
export const renderErrorDiagnostics = (
|
|
32
32
|
error: Error
|
|
33
|
-
):
|
|
33
|
+
): ErrorDiagnosticsRendering => {
|
|
34
34
|
const context = isTrailsError(error)
|
|
35
35
|
? redactErrorContext(error.context)
|
|
36
36
|
: undefined;
|
package/src/errors.ts
CHANGED
|
@@ -282,7 +282,7 @@ export type ErrorClassRegistryEntry =
|
|
|
282
282
|
/**
|
|
283
283
|
* Authored registry of concrete TrailsError classes.
|
|
284
284
|
*
|
|
285
|
-
* JavaScript cannot enumerate subclasses at runtime, so rule and
|
|
285
|
+
* JavaScript cannot enumerate subclasses at runtime, so rule and derivation
|
|
286
286
|
* tooling should walk this owner-held list instead of hardcoding parallel
|
|
287
287
|
* class-name tables. `RetryExhaustedError` is marked dynamic because it
|
|
288
288
|
* inherits its runtime category from the wrapped error rather than always
|
package/src/execute.ts
CHANGED
|
@@ -158,19 +158,19 @@ export interface ExecuteTrailOptions {
|
|
|
158
158
|
* Per-layer runtime input keyed by `Layer.name`.
|
|
159
159
|
*
|
|
160
160
|
* Surfaces (CLI, MCP, HTTP) parse their native idiom into a per-layer
|
|
161
|
-
* input object — usually
|
|
161
|
+
* input object — usually derived from each layer's `input` schema —
|
|
162
162
|
* and pass it here. The executor merges these into
|
|
163
163
|
* `ctx.extensions[LAYER_INPUTS_KEY]` so layers can read their own slot
|
|
164
164
|
* via `ctx.extensions?.[LAYER_INPUTS_KEY]?.[layer.name]`.
|
|
165
165
|
*
|
|
166
|
-
* @see TRL-473 for the CLI
|
|
166
|
+
* @see TRL-473 for the CLI rendering contract.
|
|
167
167
|
*/
|
|
168
168
|
readonly layerInputs?: Readonly<Record<string, unknown>> | undefined;
|
|
169
169
|
/**
|
|
170
170
|
* Execute a specific live trail version.
|
|
171
171
|
*
|
|
172
172
|
* Omit for the current top-level contract. Number and numeric-string
|
|
173
|
-
* references select authored versions; marker references select
|
|
173
|
+
* references select authored versions; marker references select derived
|
|
174
174
|
* content-addressed markers by unambiguous prefix.
|
|
175
175
|
*/
|
|
176
176
|
readonly version?: TrailVersionReference | undefined;
|
package/src/fire.ts
CHANGED
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
import type { ActivationProvenance } from './activation-provenance.js';
|
|
37
37
|
import type { ActivationWhereSpec } from './activation-source.js';
|
|
38
38
|
import { getActivationWherePredicate } from './activation-source.js';
|
|
39
|
-
import { activationSourceKey } from './activation-source-
|
|
39
|
+
import { activationSourceKey } from './activation-source-derivation.js';
|
|
40
40
|
import { NotFoundError, TrailsError, ValidationError } from './errors.js';
|
|
41
41
|
import { forkCtx } from './internal/fork-ctx.js';
|
|
42
42
|
import {
|
package/src/index.ts
CHANGED
|
@@ -45,29 +45,29 @@ export type {
|
|
|
45
45
|
export {
|
|
46
46
|
createSurfaceErrorMapper,
|
|
47
47
|
mapSurfaceError,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
48
|
+
renderErrorClassSurface,
|
|
49
|
+
renderPublicSurfaceError,
|
|
50
|
+
renderSurfaceError,
|
|
51
51
|
surfaceErrorMap,
|
|
52
52
|
surfaceErrorRegistry,
|
|
53
53
|
surfaceNames,
|
|
54
54
|
} from './transport-error-map.js';
|
|
55
55
|
export type {
|
|
56
|
-
|
|
56
|
+
ErrorClassSurfaceRendering,
|
|
57
57
|
SurfaceErrorCode,
|
|
58
58
|
SurfaceErrorMapper,
|
|
59
59
|
SurfaceErrorMappings,
|
|
60
|
-
|
|
60
|
+
SurfaceErrorRendering,
|
|
61
61
|
SurfaceName,
|
|
62
62
|
} from './transport-error-map.js';
|
|
63
63
|
export {
|
|
64
64
|
INTERNAL_ERROR_PUBLIC_MESSAGE,
|
|
65
|
-
|
|
65
|
+
renderErrorDiagnostics,
|
|
66
66
|
redactErrorContext,
|
|
67
67
|
redactErrorStack,
|
|
68
68
|
redactErrorString,
|
|
69
|
-
} from './error-
|
|
70
|
-
export type {
|
|
69
|
+
} from './error-rendering.js';
|
|
70
|
+
export type { ErrorDiagnosticsRendering } from './error-rendering.js';
|
|
71
71
|
export type {
|
|
72
72
|
DiagnosticBase,
|
|
73
73
|
DiagnosticSeverity,
|
|
@@ -186,9 +186,9 @@ export type {
|
|
|
186
186
|
export {
|
|
187
187
|
activationSourceDeclarationSignature,
|
|
188
188
|
activationSourceKey,
|
|
189
|
-
|
|
190
|
-
} from './activation-source-
|
|
191
|
-
export type {
|
|
189
|
+
deriveActivationSourceFacts,
|
|
190
|
+
} from './activation-source-derivation.js';
|
|
191
|
+
export type { ActivationSourceFacts } from './activation-source-derivation.js';
|
|
192
192
|
export {
|
|
193
193
|
deriveSupportedTrailVersions,
|
|
194
194
|
forkVersion,
|
|
@@ -260,8 +260,8 @@ export {
|
|
|
260
260
|
shouldIncludeTrailForSurface,
|
|
261
261
|
} from './surface-filter.js';
|
|
262
262
|
export type { SurfaceFilterOptions } from './surface-filter.js';
|
|
263
|
-
export {
|
|
264
|
-
export type {
|
|
263
|
+
export { deriveSurfaceTrailVersionRenderings } from './surface-versioning.js';
|
|
264
|
+
export type { SurfaceTrailVersionRendering } from './surface-versioning.js';
|
|
265
265
|
export {
|
|
266
266
|
shouldValidateSurfaceTopo,
|
|
267
267
|
validateSurfaceTopo,
|
|
@@ -502,23 +502,23 @@ export {
|
|
|
502
502
|
collectAttachedTypedLayers,
|
|
503
503
|
LAYER_FIELD_RESERVED_NAMES,
|
|
504
504
|
LAYER_FIELD_RESERVED_NAMES_KEBAB,
|
|
505
|
-
|
|
506
|
-
} from './layer-
|
|
505
|
+
renderLayerFieldName,
|
|
506
|
+
} from './layer-field-rendering.js';
|
|
507
507
|
export type {
|
|
508
508
|
AttachedLayerScope,
|
|
509
509
|
AttachedTypedLayer,
|
|
510
|
-
|
|
510
|
+
LayerFieldRendering,
|
|
511
511
|
LayerFieldRenameReason,
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
} from './layer-
|
|
512
|
+
RenderedLayerField,
|
|
513
|
+
RenamedLayerFieldRendering,
|
|
514
|
+
} from './layer-field-rendering.js';
|
|
515
515
|
|
|
516
516
|
// Derive
|
|
517
517
|
export {
|
|
518
518
|
deriveCliPath,
|
|
519
519
|
deriveFields,
|
|
520
520
|
deriveMcpToolName,
|
|
521
|
-
|
|
521
|
+
deriveTrailCliCommandRendering,
|
|
522
522
|
normalizeCliCommandPath,
|
|
523
523
|
} from './derive.js';
|
|
524
524
|
export type {
|
|
@@ -527,11 +527,11 @@ export type {
|
|
|
527
527
|
CliCommandRoute,
|
|
528
528
|
CliCommandRouteKind,
|
|
529
529
|
CliCommandRouteSource,
|
|
530
|
-
|
|
530
|
+
DeriveTrailCliCommandOptions,
|
|
531
531
|
Field,
|
|
532
532
|
FieldOverride,
|
|
533
|
-
|
|
534
|
-
|
|
533
|
+
TrailCliCommandRendering,
|
|
534
|
+
TrailCliRendering,
|
|
535
535
|
} from './derive.js';
|
|
536
536
|
|
|
537
537
|
// Compose schema
|
|
@@ -1,25 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared, surface-agnostic helpers for
|
|
2
|
+
* Shared, surface-agnostic helpers for rendering typed layer `input` schemas
|
|
3
3
|
* onto a surface's native idiom.
|
|
4
4
|
*
|
|
5
|
-
* Layer
|
|
5
|
+
* Layer rendering has two halves:
|
|
6
6
|
* 1. **Collection** — walk the trail's effective layers (topo → surface →
|
|
7
7
|
* trail) and keep only the ones that declare an `input` schema. These
|
|
8
|
-
* are the layers a surface needs to
|
|
9
|
-
* 2. **Naming/collision policy** — when a layer field's
|
|
8
|
+
* are the layers a surface needs to render.
|
|
9
|
+
* 2. **Naming/collision policy** — when a layer field's rendered name
|
|
10
10
|
* collides with a name already claimed by the trail, by another layer,
|
|
11
11
|
* or by a surface-reserved name, the field is renamed using the
|
|
12
12
|
* deterministic `<layerName>-<originalField>` rule. The collision-detection
|
|
13
|
-
* logic itself is surface-agnostic; the *shape* of the
|
|
13
|
+
* logic itself is surface-agnostic; the *shape* of the rendered name
|
|
14
14
|
* (kebab-case CLI flag, camelCase MCP parameter, HTTP request field)
|
|
15
15
|
* stays per-surface.
|
|
16
16
|
*
|
|
17
17
|
* This module owns the surface-agnostic half. CLI/MCP/HTTP each layer their
|
|
18
|
-
* own
|
|
18
|
+
* own rendering on top: see `@ontrails/cli/build`, `@ontrails/mcp/build`,
|
|
19
19
|
* and `@ontrails/http/build`.
|
|
20
20
|
*
|
|
21
|
-
* @see TRL-473 for the CLI
|
|
22
|
-
* @see TRL-474 for the MCP and HTTP
|
|
21
|
+
* @see TRL-473 for the CLI rendering that introduced this contract.
|
|
22
|
+
* @see TRL-474 for the MCP and HTTP renderings that lifted these helpers.
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
25
|
import type { Layer } from './layer.js';
|
|
@@ -71,10 +71,10 @@ export interface AttachedTypedLayer {
|
|
|
71
71
|
/**
|
|
72
72
|
* Collect every typed layer attached to a trail in the same composition order
|
|
73
73
|
* the executor uses (topo → surface → trail). Layers without an `input`
|
|
74
|
-
* schema are skipped — they have nothing to
|
|
74
|
+
* schema are skipped — they have nothing to render onto a surface.
|
|
75
75
|
*
|
|
76
76
|
* @param graph - The topo carrying topo-scope layers.
|
|
77
|
-
* @param trail - The trail whose effective layers we are
|
|
77
|
+
* @param trail - The trail whose effective layers we are rendering.
|
|
78
78
|
* @param surfaceLayers - Layers attached at surface scope (`options.layers`
|
|
79
79
|
* on the surface builder).
|
|
80
80
|
*/
|
|
@@ -109,15 +109,15 @@ export const collectAttachedTypedLayers = (
|
|
|
109
109
|
// ---------------------------------------------------------------------------
|
|
110
110
|
|
|
111
111
|
/**
|
|
112
|
-
* Reason a layer field was renamed during
|
|
112
|
+
* Reason a layer field was renamed during rendering.
|
|
113
113
|
*
|
|
114
114
|
* Surfaces map this onto their own warning/error idiom. CLI emits a stderr
|
|
115
|
-
* warning, while MCP/HTTP rely on the
|
|
115
|
+
* warning, while MCP/HTTP rely on the rendered schema as the source of truth.
|
|
116
116
|
*/
|
|
117
117
|
export type LayerFieldRenameReason = 'reserved-name' | 'flag-collision';
|
|
118
118
|
|
|
119
119
|
/**
|
|
120
|
-
* Outcome of
|
|
120
|
+
* Outcome of rendering a single layer field's name.
|
|
121
121
|
*
|
|
122
122
|
* `claimedName` is the name the surface will publish to consumers; it is the
|
|
123
123
|
* field name when no collision was detected, or `<layerName>-<fieldName>` (or
|
|
@@ -125,13 +125,13 @@ export type LayerFieldRenameReason = 'reserved-name' | 'flag-collision';
|
|
|
125
125
|
* a collision required a rename. `routingTarget` is the original field name
|
|
126
126
|
* the value should be assigned back to inside the layer's runtime input.
|
|
127
127
|
*/
|
|
128
|
-
export interface
|
|
128
|
+
export interface LayerFieldRendering {
|
|
129
129
|
readonly claimedName: string;
|
|
130
130
|
readonly routingTarget: string;
|
|
131
131
|
readonly renamed: false;
|
|
132
132
|
}
|
|
133
133
|
|
|
134
|
-
export interface
|
|
134
|
+
export interface RenamedLayerFieldRendering {
|
|
135
135
|
readonly claimedName: string;
|
|
136
136
|
readonly routingTarget: string;
|
|
137
137
|
readonly renamed: true;
|
|
@@ -139,40 +139,40 @@ export interface RenamedLayerFieldProjection {
|
|
|
139
139
|
readonly reason: LayerFieldRenameReason;
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
export type
|
|
143
|
-
|
|
|
144
|
-
|
|
|
142
|
+
export type RenderedLayerField =
|
|
143
|
+
| LayerFieldRendering
|
|
144
|
+
| RenamedLayerFieldRendering;
|
|
145
145
|
|
|
146
146
|
/**
|
|
147
|
-
* Apply the deterministic collision rename rule to a single
|
|
147
|
+
* Apply the deterministic collision rename rule to a single rendered layer
|
|
148
148
|
* field name.
|
|
149
149
|
*
|
|
150
150
|
* @param layerName - The layer's logical name (used as the rename prefix).
|
|
151
151
|
* @param originalName - The layer field's name as authored on its schema.
|
|
152
|
-
* @param
|
|
152
|
+
* @param renderedName - The candidate name in the surface's native idiom
|
|
153
153
|
* (e.g. kebab-case for CLI, camelCase for MCP, request field for HTTP).
|
|
154
154
|
* @param renamedName - The fallback name applied when a collision is detected.
|
|
155
155
|
* Surfaces compute this with their own casing rule.
|
|
156
156
|
* @param claimedNames - Names already taken by the trail's input or by
|
|
157
|
-
* previous layer
|
|
157
|
+
* previous layer renderings. Updated in place when a name is claimed.
|
|
158
158
|
* @param reservedNames - Framework-owned names that force a rename across
|
|
159
|
-
* surface
|
|
159
|
+
* surface renderings.
|
|
160
160
|
*/
|
|
161
|
-
export const
|
|
161
|
+
export const renderLayerFieldName = (
|
|
162
162
|
_layerName: string,
|
|
163
163
|
originalName: string,
|
|
164
|
-
|
|
164
|
+
renderedName: string,
|
|
165
165
|
renamedName: string,
|
|
166
166
|
claimedNames: Set<string>,
|
|
167
167
|
reservedNames: ReadonlySet<string>
|
|
168
|
-
):
|
|
169
|
-
const collidesWithClaimed = claimedNames.has(
|
|
170
|
-
const collidesWithReserved = reservedNames.has(
|
|
168
|
+
): RenderedLayerField => {
|
|
169
|
+
const collidesWithClaimed = claimedNames.has(renderedName);
|
|
170
|
+
const collidesWithReserved = reservedNames.has(renderedName);
|
|
171
171
|
|
|
172
172
|
if (!collidesWithClaimed && !collidesWithReserved) {
|
|
173
|
-
claimedNames.add(
|
|
173
|
+
claimedNames.add(renderedName);
|
|
174
174
|
return {
|
|
175
|
-
claimedName:
|
|
175
|
+
claimedName: renderedName,
|
|
176
176
|
renamed: false,
|
|
177
177
|
routingTarget: originalName,
|
|
178
178
|
};
|
|
@@ -185,7 +185,7 @@ export const projectLayerFieldName = (
|
|
|
185
185
|
claimedNames.add(claimedName);
|
|
186
186
|
return {
|
|
187
187
|
claimedName,
|
|
188
|
-
originalName:
|
|
188
|
+
originalName: renderedName,
|
|
189
189
|
reason: collidesWithReserved ? 'reserved-name' : 'flag-collision',
|
|
190
190
|
renamed: true,
|
|
191
191
|
routingTarget: originalName,
|
package/src/layer.ts
CHANGED
|
@@ -12,13 +12,13 @@ import type { Implementation } from './types.js';
|
|
|
12
12
|
*
|
|
13
13
|
* Layers attach at trail, surface, or topo scope and may declare an object
|
|
14
14
|
* `input` schema describing the configuration they need from the surrounding
|
|
15
|
-
* surface. Surface packages (CLI, MCP, HTTP)
|
|
15
|
+
* surface. Surface packages (CLI, MCP, HTTP) render this schema onto their
|
|
16
16
|
* native idioms — flags, tool parameters, query strings — alongside the
|
|
17
17
|
* trail's own input schema.
|
|
18
18
|
*
|
|
19
19
|
* @remarks
|
|
20
|
-
* The `input` schema is metadata for surface
|
|
21
|
-
* schema so every surface can
|
|
20
|
+
* The `input` schema is metadata for surface rendering. It must be an object
|
|
21
|
+
* schema so every surface can render named fields consistently. It is
|
|
22
22
|
* optional; layers without an `input` schema behave as plain wrappers. The
|
|
23
23
|
* layer's `wrap` function is the runtime contract.
|
|
24
24
|
*/
|
|
@@ -31,13 +31,13 @@ export interface Layer {
|
|
|
31
31
|
/**
|
|
32
32
|
* Authored configuration the layer needs from the surrounding surface.
|
|
33
33
|
*
|
|
34
|
-
* Surface packages
|
|
34
|
+
* Surface packages render this schema onto their native idioms (CLI flags,
|
|
35
35
|
* MCP tool parameters, HTTP query strings) so a layer's input fields appear
|
|
36
36
|
* alongside the trail's own input fields. Optional — layers that wrap purely
|
|
37
37
|
* by behavior, with no surface-visible inputs, may omit it.
|
|
38
38
|
*
|
|
39
|
-
* @see TRL-473 for CLI flag
|
|
40
|
-
* @see TRL-474 for MCP and HTTP
|
|
39
|
+
* @see TRL-473 for CLI flag rendering.
|
|
40
|
+
* @see TRL-474 for MCP and HTTP rendering.
|
|
41
41
|
*/
|
|
42
42
|
readonly input?: LayerInputSchema | undefined;
|
|
43
43
|
|