@ontrails/library 1.0.0-beta.42 → 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 CHANGED
@@ -1,5 +1,15 @@
1
1
  # @ontrails/library
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
+
3
13
  ## 1.0.0-beta.42
4
14
 
5
15
  ## 1.0.0-beta.41
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Render a Trails topo as an idiomatic TypeScript library.
4
4
 
5
- `@ontrails/library` is a peer surface for plain TypeScript consumers. It reads the same contract that CLI, MCP, and HTTP read, then projects that graph into function calls, package-facing errors, schema exports, and generated package files.
5
+ `@ontrails/library` is a peer surface for plain TypeScript consumers. It reads the same contract that CLI, MCP, and HTTP read, then renders that graph into function calls, package-facing errors, schema exports, and generated package files.
6
6
 
7
7
  The package is publishable as the runtime dependency for generated Trails libraries. Generated packages can depend on it while keeping their consumer-facing API idiomatic and package-local.
8
8
 
@@ -11,7 +11,7 @@ The package is publishable as the runtime dependency for generated Trails librar
11
11
  ```ts
12
12
  import { compile, deriveLibraryApi, surface } from '@ontrails/library';
13
13
 
14
- const projection = deriveLibraryApi(app);
14
+ const renderingPlan = deriveLibraryApi(app);
15
15
  const client = await surface(app);
16
16
  const files = compile(app, {
17
17
  appExportName: 'app',
@@ -20,7 +20,7 @@ const files = compile(app, {
20
20
  });
21
21
  ```
22
22
 
23
- - `deriveLibraryApi(graph, options)` is the pure projection. It decides which public trails become library exports, how export names are derived, which trails are excluded, and where export-name collisions exist.
23
+ - `deriveLibraryApi(graph, options)` is the pure derivation. It returns the rendering plan that decides which public trails become library exports, how export names are derived, which trails are excluded, and where export-name collisions exist.
24
24
  - `surface(graph, options)` returns an in-memory callable client. The root call lane unwraps `Result.ok` into a return value and maps `Result.err` into typed `LibraryError` subclasses.
25
25
  - `compile(graph, options)` returns a stable file plan for a generated package. Writing those files is intentionally a thin apply step outside the compiler.
26
26
 
@@ -35,13 +35,13 @@ Generated packages use one package with subpath exports:
35
35
  ./trails the Trails-native topo entrypoint
36
36
  ```
37
37
 
38
- Stateless trails project to root named exports. Resource-bearing trails project behind a generated `createX(options)` factory so callers can provide resource configuration once and call several related methods from the same client.
38
+ Stateless trails render to root named exports. Resource-bearing trails render behind a generated `createX(options)` factory so callers can provide resource configuration once and call several related methods from the same client.
39
39
 
40
40
  Generated root and `/result` subpaths share one internal client module, so importing both subpaths does not open separate root library surfaces.
41
41
 
42
42
  ## Typed signatures
43
43
 
44
- Topo artifacts carry durable contract facts, but they do not preserve erased source-level TypeScript generics. Generated packages therefore stay honest by defaulting method signatures to `unknown` unless the caller binds a projected trail id to the source trail export that owns its schema types:
44
+ Topo artifacts carry durable contract facts, but they do not preserve erased source-level TypeScript generics. Generated packages therefore stay honest by defaulting method signatures to `unknown` unless the caller binds a rendered trail id to the source trail export that owns its schema types:
45
45
 
46
46
  ```ts
47
47
  const files = compile(app, {
@@ -57,7 +57,7 @@ const files = compile(app, {
57
57
 
58
58
  With that binding, `/schemas` emits aliases such as `WidgetPingInput = TrailInput<typeof pingTrail>` and the root and `/result` subpaths use those aliases in their public signatures.
59
59
 
60
- Typed layer inputs are projected into the same public method input object as trail fields. When a layer field collides with a trail field or reserved surface name, the generated library input uses the same deterministic `<layerName><Field>` rename rule as other object-shaped surfaces. Runtime calls validate the projected input, strip layer-owned fields before trail validation, and route them to the layer's own input slot. When a source trail type binding is provided, generated signatures widen layer-projected inputs with `Record<string, unknown>` until layer input type exports have a source-level owner.
60
+ Typed layer inputs are rendered into the same public method input object as trail fields. When a layer field collides with a trail field or reserved surface name, the generated library input uses the same deterministic `<layerName><Field>` rename rule as other object-shaped surfaces. Runtime calls validate the rendered input, strip layer-owned fields before trail validation, and route them to the layer's own input slot. When a source trail type binding is provided, generated signatures widen layer-rendered inputs with `Record<string, unknown>` until layer input type exports have a source-level owner.
61
61
 
62
62
  ## Errors
63
63
 
@@ -75,7 +75,7 @@ The mapper is built with the shared Trails error taxonomy, so new categories mus
75
75
 
76
76
  ## Governance and dogfood
77
77
 
78
- Library projection facts are embedded in `TopoGraph.library` by Topography. Warden's `library-projection-coherence` rule checks that serialized projection facts do not drift from the graph, including missing target trails and export name collisions.
78
+ Library-derived facts are embedded in `TopoGraph.library` by Topography. Warden's `library-render-coherence` rule checks that serialized rendering facts do not drift from the graph, including missing target trails and export name collisions.
79
79
 
80
80
  Run the focused package checks while changing the surface:
81
81
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ontrails/library",
3
- "version": "1.0.0-beta.42",
3
+ "version": "1.0.0-beta.43",
4
4
  "files": [
5
5
  "src/**/*.ts",
6
6
  "!src/**/__tests__/**",
@@ -22,10 +22,10 @@
22
22
  "clean": "rm -rf dist *.tsbuildinfo"
23
23
  },
24
24
  "dependencies": {
25
- "@ontrails/core": "^1.0.0-beta.42"
25
+ "@ontrails/core": "^1.0.0-beta.43"
26
26
  },
27
27
  "devDependencies": {
28
- "@ontrails/testing": "^1.0.0-beta.42"
28
+ "@ontrails/testing": "^1.0.0-beta.43"
29
29
  },
30
30
  "peerDependencies": {
31
31
  "zod": "^4.3.5"
package/src/compile.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * `compile` — the package emitter. Consumes the `LibraryProjection` (never the
2
+ * `compile` — the package emitter. Consumes the `LibraryRenderingPlan` (never the
3
3
  * topo directly) and produces the source files of a generated TypeScript
4
4
  * package: consumer-fluent root, `/result`, `/schemas`, `/trails` subpaths.
5
5
  *
@@ -9,13 +9,13 @@
9
9
  * change consumer code — see the runtime-kernel section of the ADR.
10
10
  *
11
11
  * This slice returns the file plan (path + content); writing it to disk is a
12
- * thin apply step. Pure: derives the projection and builds strings, no I/O.
12
+ * thin apply step. Pure: derives the rendering and builds strings, no I/O.
13
13
  */
14
14
  import { deriveLibraryApi } from './derive.js';
15
15
  import type {
16
16
  DeriveLibraryApiOptions,
17
17
  LibraryExport,
18
- LibraryProjection,
18
+ LibraryRenderingPlan,
19
19
  } from './derive.js';
20
20
  import type { Topo } from './kernel.js';
21
21
 
@@ -39,7 +39,7 @@ export interface CompileOptions extends DeriveLibraryApiOptions {
39
39
  */
40
40
  readonly typeImportPath?: string;
41
41
  /**
42
- * Optional mapping from projected trail id to the source module export that
42
+ * Optional mapping from rendered trail id to the source module export that
43
43
  * owns that trail's TypeScript type. Unmapped trails intentionally keep
44
44
  * `unknown` public signatures instead of pretending topo artifacts preserve
45
45
  * erased source types.
@@ -56,8 +56,8 @@ export interface CompiledFile {
56
56
  /** The result of compiling a topo into a generated library package. */
57
57
  export interface CompileResult {
58
58
  readonly packageName: string;
59
- /** The resolved projection the files were emitted from. */
60
- readonly projection: LibraryProjection;
59
+ /** The resolved rendering the files were emitted from. */
60
+ readonly rendering: LibraryRenderingPlan;
61
61
  /** The emitted files, in stable path order. */
62
62
  readonly files: readonly CompiledFile[];
63
63
  }
@@ -73,16 +73,16 @@ const isStateless = (entry: LibraryExport): boolean =>
73
73
  entry.resources.length === 0;
74
74
 
75
75
  const statelessExports = (
76
- projection: LibraryProjection
77
- ): readonly LibraryExport[] => projection.exports.filter(isStateless);
76
+ rendering: LibraryRenderingPlan
77
+ ): readonly LibraryExport[] => rendering.exports.filter(isStateless);
78
78
 
79
79
  const resourceExports = (
80
- projection: LibraryProjection
80
+ rendering: LibraryRenderingPlan
81
81
  ): readonly LibraryExport[] =>
82
- projection.exports.filter((entry) => !isStateless(entry));
82
+ rendering.exports.filter((entry) => !isStateless(entry));
83
83
 
84
- const factoryName = (projection: LibraryProjection): string =>
85
- `create${pascalCase(projection.app)}`;
84
+ const factoryName = (rendering: LibraryRenderingPlan): string =>
85
+ `create${pascalCase(rendering.app)}`;
86
86
 
87
87
  const DEFAULT_LIBRARY_DEPENDENCY = '^1.0.0';
88
88
  const DEFAULT_ZOD_DEPENDENCY = '^4.3.5';
@@ -121,12 +121,12 @@ const typeNamesFor = (
121
121
  };
122
122
 
123
123
  const resolveTypeBindings = (
124
- projection: LibraryProjection,
124
+ rendering: LibraryRenderingPlan,
125
125
  options: CompileOptions
126
126
  ): TypeBindings => {
127
127
  const configured = options.trailTypeExports ?? {};
128
128
  const bindings = new Map<string, ExportTypeBinding>();
129
- for (const entry of projection.exports) {
129
+ for (const entry of rendering.exports) {
130
130
  const sourceExport = configured[entry.trailId];
131
131
  if (!sourceExport) {
132
132
  continue;
@@ -155,10 +155,10 @@ const outputTypeFor = (entry: LibraryExport, bindings: TypeBindings): string =>
155
155
  bindings.get(entry.trailId)?.output ?? 'unknown';
156
156
 
157
157
  const schemaTypeImport = (
158
- projection: LibraryProjection,
158
+ rendering: LibraryRenderingPlan,
159
159
  bindings: TypeBindings
160
160
  ): string | undefined => {
161
- const names = projection.exports.flatMap((entry) => {
161
+ const names = rendering.exports.flatMap((entry) => {
162
162
  const binding = bindings.get(entry.trailId);
163
163
  return binding ? [binding.input, binding.output] : [];
164
164
  });
@@ -196,7 +196,7 @@ const statelessFunction = (
196
196
  [
197
197
  jsDoc([
198
198
  exportDescription(entry),
199
- `Projects trail \`${entry.trailId}\` as a stateless library function.`,
199
+ `Renders trail \`${entry.trailId}\` as a stateless library function.`,
200
200
  ]),
201
201
  `export const ${entry.exportName} = (`,
202
202
  ` input: ${inputTypeFor(entry, bindings)}`,
@@ -210,7 +210,7 @@ const factoryMethod = (entry: LibraryExport, bindings: TypeBindings): string =>
210
210
  jsDoc(
211
211
  [
212
212
  exportDescription(entry),
213
- `Projects trail \`${entry.trailId}\` behind the resource client.`,
213
+ `Renders trail \`${entry.trailId}\` behind the resource client.`,
214
214
  ],
215
215
  ' '
216
216
  ),
@@ -222,12 +222,12 @@ const factoryMethod = (entry: LibraryExport, bindings: TypeBindings): string =>
222
222
  ].join('\n');
223
223
 
224
224
  const generateIndex = (
225
- projection: LibraryProjection,
225
+ rendering: LibraryRenderingPlan,
226
226
  bindings: TypeBindings
227
227
  ): string => {
228
- const stateless = statelessExports(projection);
229
- const resourceful = resourceExports(projection);
230
- const typedSchemas = schemaTypeImport(projection, bindings);
228
+ const stateless = statelessExports(rendering);
229
+ const resourceful = resourceExports(rendering);
230
+ const typedSchemas = schemaTypeImport(rendering, bindings);
231
231
 
232
232
  const parts: string[] = [
233
233
  "import type { SurfaceLibraryOptions } from '@ontrails/library';",
@@ -243,7 +243,7 @@ const generateIndex = (
243
243
  if (resourceful.length > 0) {
244
244
  parts.push(
245
245
  '',
246
- `export const ${factoryName(projection)} = async (`,
246
+ `export const ${factoryName(rendering)} = async (`,
247
247
  ' options: SurfaceLibraryOptions = {}',
248
248
  ') => {',
249
249
  ' const client = await createClient(options);',
@@ -271,12 +271,12 @@ const generateClient = (): string =>
271
271
  ].join('\n');
272
272
 
273
273
  const generateSchemas = (
274
- projection: LibraryProjection,
274
+ rendering: LibraryRenderingPlan,
275
275
  options: CompileOptions,
276
276
  bindings: TypeBindings
277
277
  ): string => {
278
278
  const appExport = 'app';
279
- const typedEntries = projection.exports.filter((entry) =>
279
+ const typedEntries = rendering.exports.filter((entry) =>
280
280
  bindings.has(entry.trailId)
281
281
  );
282
282
  const sourceTypeExports = [
@@ -300,22 +300,22 @@ const generateSchemas = (
300
300
  ]
301
301
  : []),
302
302
  '',
303
- '// Authored Zod schemas, keyed by export name, projected from the topo.',
304
- 'const projection = deriveLibraryApi(app);',
303
+ '// Authored Zod schemas, keyed by export name, rendered from the topo.',
304
+ 'const rendering = deriveLibraryApi(app);',
305
305
  'const byName = new Map(',
306
- ' projection.exports.map((entry) => [entry.exportName, entry])',
306
+ ' rendering.exports.map((entry) => [entry.exportName, entry])',
307
307
  ');',
308
308
  '',
309
309
  'const requireExport = (name: string) => {',
310
310
  ' const entry = byName.get(name);',
311
311
  ' if (!entry) {',
312
- " throw new Error('missing projected library export: ' + name);",
312
+ " throw new Error('missing rendered library export: ' + name);",
313
313
  ' }',
314
314
  ' return entry;',
315
315
  '};',
316
316
  '',
317
317
  ];
318
- for (const entry of projection.exports) {
318
+ for (const entry of rendering.exports) {
319
319
  const binding = bindings.get(entry.trailId);
320
320
  if (binding) {
321
321
  lines.push(
@@ -338,7 +338,7 @@ const generateSchemas = (
338
338
  );
339
339
  }
340
340
  lines.push('', 'export const schemas = {');
341
- for (const entry of projection.exports) {
341
+ for (const entry of rendering.exports) {
342
342
  lines.push(
343
343
  ` ${entry.exportName}: {`,
344
344
  ` input: ${entry.exportName}InputSchema,`,
@@ -396,12 +396,12 @@ const resultFactoryMethod = (
396
396
  ].join('\n');
397
397
 
398
398
  const generateResult = (
399
- projection: LibraryProjection,
399
+ rendering: LibraryRenderingPlan,
400
400
  bindings: TypeBindings
401
401
  ): string => {
402
- const stateless = statelessExports(projection);
403
- const resourceful = resourceExports(projection);
404
- const typedSchemas = schemaTypeImport(projection, bindings);
402
+ const stateless = statelessExports(rendering);
403
+ const resourceful = resourceExports(rendering);
404
+ const typedSchemas = schemaTypeImport(rendering, bindings);
405
405
  const parts = [
406
406
  '// No-throw API: returns the Result envelope instead of unwrapping.',
407
407
  "import { runLibraryResult } from '@ontrails/library';",
@@ -421,7 +421,7 @@ const generateResult = (
421
421
  if (resourceful.length > 0) {
422
422
  parts.push(
423
423
  '',
424
- `export const ${factoryName(projection)} = async (`,
424
+ `export const ${factoryName(rendering)} = async (`,
425
425
  ' options: SurfaceLibraryOptions = {}',
426
426
  ') => {',
427
427
  ' const client = await createClient(options);',
@@ -464,7 +464,7 @@ const generateTsconfig = (): string =>
464
464
 
465
465
  /**
466
466
  * Compile a topo into a generated library package. Returns the emitted file
467
- * plan; the resolved projection is included for inspection and governance.
467
+ * plan; the resolved rendering is included for inspection and governance.
468
468
  *
469
469
  * @example
470
470
  * const result = compile(app, {
@@ -479,8 +479,8 @@ export const compile = (
479
479
  graph: Topo,
480
480
  options: CompileOptions
481
481
  ): CompileResult => {
482
- const projection = deriveLibraryApi(graph, options);
483
- const typeBindings = resolveTypeBindings(projection, options);
482
+ const rendering = deriveLibraryApi(graph, options);
483
+ const typeBindings = resolveTypeBindings(rendering, options);
484
484
  const files: CompiledFile[] = [
485
485
  { content: generatePackageJson(options), path: 'package.json' },
486
486
  { content: generateTsconfig(), path: 'tsconfig.json' },
@@ -489,18 +489,18 @@ export const compile = (
489
489
  path: 'src/client.ts',
490
490
  },
491
491
  {
492
- content: generateIndex(projection, typeBindings),
492
+ content: generateIndex(rendering, typeBindings),
493
493
  path: 'src/index.ts',
494
494
  },
495
495
  {
496
- content: generateResult(projection, typeBindings),
496
+ content: generateResult(rendering, typeBindings),
497
497
  path: 'src/result.ts',
498
498
  },
499
499
  {
500
- content: generateSchemas(projection, options, typeBindings),
500
+ content: generateSchemas(rendering, options, typeBindings),
501
501
  path: 'src/schemas.ts',
502
502
  },
503
503
  { content: generateTrails(options), path: 'src/trails.ts' },
504
504
  ];
505
- return { files, packageName: options.packageName, projection };
505
+ return { files, packageName: options.packageName, rendering };
506
506
  };
package/src/derive.ts CHANGED
@@ -1,29 +1,29 @@
1
1
  /**
2
- * `deriveLibraryApi` — the pure projection from a topo to a `LibraryProjection`.
2
+ * `deriveLibraryApi` — the pure rendering from a topo to a `LibraryRenderingPlan`.
3
3
  *
4
4
  * This is the single semantic authority for the library surface: trail
5
5
  * selection, export naming, collision resolution, and the per-export contract
6
6
  * data the emitter renders all live here. The in-memory surface and the package
7
- * emitter both consume the projection; neither re-reads the topo nor reinvents
7
+ * emitter both consume the rendering; neither re-reads the topo nor reinvents
8
8
  * selection. Pure — no fs/network/db reads (derive* purity contract).
9
9
  */
10
10
  import { filterSurfaceTrails, isDraftId } from '@ontrails/core';
11
11
  import type { Layer, Topo, Trail } from '@ontrails/core';
12
12
  import type { ZodType } from 'zod';
13
13
 
14
- import { projectLibraryInput } from './layer-input.js';
15
- import type { LibraryLayerInputProjection } from './layer-input.js';
14
+ import { renderLibraryInput } from './layer-input.js';
15
+ import type { LibraryLayerInputRendering } from './layer-input.js';
16
16
 
17
17
  type AnyTrail = Trail<unknown, unknown, unknown>;
18
18
 
19
- /** Where a projected export name came from. */
19
+ /** Where a rendered export name came from. */
20
20
  export type LibraryExportSource = 'derived' | 'trail-hint' | 'package-config';
21
21
 
22
- /** A single projected export: one trail rendered as a library entrypoint. */
22
+ /** A single rendered export: one trail rendered as a library entrypoint. */
23
23
  export interface LibraryExport {
24
24
  /** Consumer-native export name (camelCased trail id by default). */
25
25
  readonly exportName: string;
26
- /** The trail id this export projects (the source of truth). */
26
+ /** The trail id this export renders (the source of truth). */
27
27
  readonly trailId: string;
28
28
  /** How `exportName` was chosen. v0 derives; hints/config override later. */
29
29
  readonly nameSource: LibraryExportSource;
@@ -39,27 +39,27 @@ export interface LibraryExport {
39
39
  /**
40
40
  * Input schema reference: the emitter's method-signature and `/schemas`
41
41
  * source. An in-memory Zod reference here; it serializes to JSON Schema when
42
- * the projection is persisted to the artifact family.
42
+ * the rendering is persisted to the artifact family.
43
43
  */
44
44
  readonly input: ZodType;
45
- /** Layer input routing projected onto this export's public library input. */
46
- readonly layerInputs: readonly LibraryLayerInputProjection[];
45
+ /** Layer input routing rendered onto this export's public library input. */
46
+ readonly layerInputs: readonly LibraryLayerInputRendering[];
47
47
  /** Output schema reference, when the trail declares one. */
48
48
  readonly output: ZodType | undefined;
49
49
  /**
50
50
  * Resource ids this export depends on. Empty means a stateless function
51
- * export; non-empty means the emitter projects the export behind a
51
+ * export; non-empty means the emitter renders the export behind a
52
52
  * `createX()` factory/client, grouped by shared resources. Carrying ids (not
53
53
  * just a boolean) keeps the factory-grouping decision in this authority.
54
54
  */
55
55
  readonly resources: readonly string[];
56
56
  }
57
57
 
58
- /** Why a trail did not project into the library (doctrinally-meaningful only). */
58
+ /** Why a trail did not render into the library (doctrinally-meaningful only). */
59
59
  export type LibraryExclusionReason = 'internal' | 'draft' | 'activation';
60
60
 
61
61
  /**
62
- * A trail deliberately excluded from the projection, recorded for legibility.
62
+ * A trail deliberately excluded from the rendering, recorded for legibility.
63
63
  * `reason` is the primary (first-matched) reason in precedence order
64
64
  * draft > activation > internal; a trail may technically satisfy more than one.
65
65
  */
@@ -74,11 +74,11 @@ export interface LibraryCollision {
74
74
  readonly trailIds: readonly string[];
75
75
  }
76
76
 
77
- /** The resolved library projection — the story of a topo as a TypeScript library. */
78
- export interface LibraryProjection {
77
+ /** The resolved library rendering — the story of a topo as a TypeScript library. */
78
+ export interface LibraryRenderingPlan {
79
79
  /** The topo name. */
80
80
  readonly app: string;
81
- /** Projected exports, in stable (trail-id-sorted) order. */
81
+ /** Rendered exports, in stable (trail-id-sorted) order. */
82
82
  readonly exports: readonly LibraryExport[];
83
83
  /** Trails excluded by visibility, draft state, or activation. */
84
84
  readonly excluded: readonly LibraryExclusion[];
@@ -87,7 +87,7 @@ export interface LibraryProjection {
87
87
  }
88
88
 
89
89
  /**
90
- * Options for narrowing the projection. Selectors reuse the trail-filter
90
+ * Options for narrowing the rendering. Selectors reuse the trail-filter
91
91
  * grammar (exact ids, `*`, `**`). v0 exposes include/exclude only; intent-based
92
92
  * filtering is deferred (the packet promises the filter grammar, not intent
93
93
  * narrowing, for the library surface).
@@ -97,7 +97,7 @@ export interface DeriveLibraryApiOptions {
97
97
  readonly include?: readonly string[];
98
98
  /** Exclude patterns. */
99
99
  readonly exclude?: readonly string[];
100
- /** Surface-scope layers to project alongside each trail's own input. */
100
+ /** Surface-scope layers to render alongside each trail's own input. */
101
101
  readonly layers?: readonly Layer[] | undefined;
102
102
  }
103
103
 
@@ -126,21 +126,21 @@ const isInternal = (trail: AnyTrail): boolean =>
126
126
  trail.visibility === 'internal' || trail.meta?.['internal'] === true;
127
127
 
128
128
  /**
129
- * Project a topo into a `LibraryProjection`. Selection composes
129
+ * Derive a topo into a `LibraryRenderingPlan`. Selection composes
130
130
  * `filterSurfaceTrails` (visibility, activation, intent, include/exclude) and
131
131
  * adds draft exclusion. Established public, current-version trails become
132
132
  * exports; drafts, internal, and activation-driven trails are excluded.
133
133
  *
134
134
  * @example
135
- * const projection = deriveLibraryApi(app);
136
- * for (const entry of projection.exports) {
135
+ * const rendering = deriveLibraryApi(app);
136
+ * for (const entry of rendering.exports) {
137
137
  * console.log(entry.exportName, '->', entry.trailId);
138
138
  * }
139
139
  */
140
140
  export const deriveLibraryApi = (
141
141
  graph: Topo,
142
142
  options: DeriveLibraryApiOptions = {}
143
- ): LibraryProjection => {
143
+ ): LibraryRenderingPlan => {
144
144
  const all = graph.list();
145
145
 
146
146
  const selected = filterSurfaceTrails(all, {
@@ -183,13 +183,13 @@ export const deriveLibraryApi = (
183
183
  continue;
184
184
  }
185
185
  namesToTrailIds.set(exportName, [trail.id]);
186
- const inputProjection = projectLibraryInput(graph, trail, options.layers);
186
+ const inputRendering = renderLibraryInput(graph, trail, options.layers);
187
187
  exports.push({
188
188
  description: trail.description,
189
189
  exportName,
190
- input: inputProjection.input,
190
+ input: inputRendering.input,
191
191
  intent: trail.intent,
192
- layerInputs: inputProjection.layers,
192
+ layerInputs: inputRendering.layers,
193
193
  nameSource: 'derived',
194
194
  output: trail.output,
195
195
  resources: trail.resources.map((resource) => resource.id),
package/src/index.ts CHANGED
@@ -3,11 +3,11 @@
3
3
  *
4
4
  * The library surface is a peer of CLI, MCP, and HTTP. Its public ladder:
5
5
  *
6
- * - `deriveLibraryApi(graph, options)` — pure projection → `LibraryProjection`
6
+ * - `deriveLibraryApi(graph, options)` — pure rendering → `LibraryRenderingPlan`
7
7
  * - `surface(graph, options)` — in-memory callable client
8
8
  * - `compile(graph, options)` — TypeScript package emitter
9
9
  *
10
- * Those land across the projection, surface, and emitter lanes (Linear project
10
+ * Those land across the rendering, surface, and emitter lanes (Linear project
11
11
  * "Library surface & compiler"). This scaffold establishes the package and the
12
12
  * runtime-kernel seam; see `./kernel` and the Library Surface and Compiler ADR.
13
13
  */
@@ -21,7 +21,7 @@ export type {
21
21
  LibraryExclusionReason,
22
22
  LibraryExport,
23
23
  LibraryExportSource,
24
- LibraryProjection,
24
+ LibraryRenderingPlan,
25
25
  } from './derive.js';
26
26
  export {
27
27
  LibraryAuthError,
package/src/kernel.ts CHANGED
@@ -14,7 +14,7 @@
14
14
  * Surface and Compiler ADR.
15
15
  *
16
16
  * The kernel grows only as materialization demands: today it wraps execution;
17
- * error projection and the context/compose shim join it as the surface and
17
+ * error rendering and the context/compose shim join it as the surface and
18
18
  * emitter lanes land. Keep it minimal and dependency-light on purpose.
19
19
  */
20
20
  import { run } from '@ontrails/core';
@@ -2,7 +2,7 @@ import type { AttachedTypedLayer, Layer, Topo, Trail } from '@ontrails/core';
2
2
  import {
3
3
  LAYER_FIELD_RESERVED_NAMES,
4
4
  collectAttachedTypedLayers,
5
- projectLayerFieldName,
5
+ renderLayerFieldName,
6
6
  zodToJsonSchema,
7
7
  } from '@ontrails/core';
8
8
  import { z } from 'zod';
@@ -10,20 +10,20 @@ import { z } from 'zod';
10
10
  type AnyTrail = Trail<unknown, unknown, unknown>;
11
11
  type MutableLayerShape = Record<string, z.ZodRawShape[string]>;
12
12
 
13
- export interface LibraryLayerFieldProjection {
13
+ export interface LibraryLayerFieldRendering {
14
14
  readonly claimedName: string;
15
15
  readonly routingTarget: string;
16
16
  }
17
17
 
18
- export interface LibraryLayerInputProjection {
19
- readonly fields: readonly LibraryLayerFieldProjection[];
18
+ export interface LibraryLayerInputRendering {
19
+ readonly fields: readonly LibraryLayerFieldRendering[];
20
20
  readonly input: z.ZodObject<z.ZodRawShape>;
21
21
  readonly layerName: string;
22
22
  }
23
23
 
24
- export interface LibraryInputProjection {
24
+ export interface LibraryInputRendering {
25
25
  readonly input: z.ZodType;
26
- readonly layers: readonly LibraryLayerInputProjection[];
26
+ readonly layers: readonly LibraryLayerInputRendering[];
27
27
  }
28
28
 
29
29
  const isJsonObjectSchema = (
@@ -59,19 +59,19 @@ const objectPropertiesFor = (schema: z.ZodType): readonly string[] => {
59
59
  const isJsonObjectInput = (schema: z.ZodType): boolean =>
60
60
  isJsonObjectSchema(zodToJsonSchema(schema));
61
61
 
62
- const projectLayerInputFields = (
62
+ const renderLayerInputFields = (
63
63
  attached: AttachedTypedLayer,
64
64
  claimedNames: Set<string>,
65
65
  layerShape: MutableLayerShape
66
- ): LibraryLayerInputProjection => {
66
+ ): LibraryLayerInputRendering => {
67
67
  const { layer } = attached;
68
68
  if (layer.input === undefined) {
69
69
  return { fields: [], input: z.object({}), layerName: layer.name };
70
70
  }
71
71
 
72
- const fields: LibraryLayerFieldProjection[] = [];
72
+ const fields: LibraryLayerFieldRendering[] = [];
73
73
  for (const [fieldName, fieldSchema] of Object.entries(layer.input.shape)) {
74
- const projection = projectLayerFieldName(
74
+ const rendering = renderLayerFieldName(
75
75
  layer.name,
76
76
  fieldName,
77
77
  fieldName,
@@ -80,24 +80,24 @@ const projectLayerInputFields = (
80
80
  LAYER_FIELD_RESERVED_NAMES
81
81
  );
82
82
  fields.push({
83
- claimedName: projection.claimedName,
84
- routingTarget: projection.routingTarget,
83
+ claimedName: rendering.claimedName,
84
+ routingTarget: rendering.routingTarget,
85
85
  });
86
- layerShape[projection.claimedName] = fieldSchema;
86
+ layerShape[rendering.claimedName] = fieldSchema;
87
87
  }
88
88
 
89
89
  return { fields, input: layer.input, layerName: layer.name };
90
90
  };
91
91
 
92
92
  /**
93
- * Project a trail's public library input: authored trail input plus any typed
93
+ * Render a trail's public library input: authored trail input plus any typed
94
94
  * layer input fields attached at topo, surface, or trail scope.
95
95
  */
96
- export const projectLibraryInput = (
96
+ export const renderLibraryInput = (
97
97
  graph: Topo,
98
98
  trail: AnyTrail,
99
99
  surfaceLayers?: readonly Layer[]
100
- ): LibraryInputProjection => {
100
+ ): LibraryInputRendering => {
101
101
  const attachedLayers = collectAttachedTypedLayers(
102
102
  graph,
103
103
  trail,
@@ -111,20 +111,20 @@ export const projectLibraryInput = (
111
111
  const claimedNames = new Set(trailProperties);
112
112
  if (trailProperties.length === 0 && !isJsonObjectInput(trail.input)) {
113
113
  throw new Error(
114
- `Library layer input projection requires object input for trail "${trail.id}".`
114
+ `Library layer input rendering requires object input for trail "${trail.id}".`
115
115
  );
116
116
  }
117
117
 
118
118
  const layerShape: MutableLayerShape = {};
119
- const layers: LibraryLayerInputProjection[] = [];
119
+ const layers: LibraryLayerInputRendering[] = [];
120
120
  for (const attached of attachedLayers) {
121
- const projection = projectLayerInputFields(
121
+ const rendering = renderLayerInputFields(
122
122
  attached,
123
123
  claimedNames,
124
124
  layerShape
125
125
  );
126
- if (projection.fields.length > 0) {
127
- layers.push(projection);
126
+ if (rendering.fields.length > 0) {
127
+ layers.push(rendering);
128
128
  }
129
129
  }
130
130
 
@@ -140,25 +140,25 @@ export const projectLibraryInput = (
140
140
 
141
141
  /**
142
142
  * Split a library method input back into trail input plus per-layer runtime
143
- * input slots using the projection routing table.
143
+ * input slots using the rendering routing table.
144
144
  */
145
145
  export const partitionLibraryInput = (
146
146
  input: unknown,
147
- projections: readonly LibraryLayerInputProjection[]
147
+ renderings: readonly LibraryLayerInputRendering[]
148
148
  ): {
149
149
  readonly layerInputs: Record<string, unknown>;
150
150
  readonly trailInput: unknown;
151
151
  } => {
152
- if (projections.length === 0 || !isObjectRecord(input)) {
152
+ if (renderings.length === 0 || !isObjectRecord(input)) {
153
153
  return { layerInputs: {}, trailInput: input };
154
154
  }
155
155
 
156
156
  const claimedKeys = new Set<string>();
157
157
  const layerInputs: Record<string, unknown> = {};
158
- for (const projection of projections) {
158
+ for (const rendering of renderings) {
159
159
  const layerInput: Record<string, unknown> = {};
160
160
  let received = false;
161
- for (const field of projection.fields) {
161
+ for (const field of rendering.fields) {
162
162
  claimedKeys.add(field.claimedName);
163
163
  const value = input[field.claimedName];
164
164
  if (value === undefined) {
@@ -168,13 +168,13 @@ export const partitionLibraryInput = (
168
168
  received = true;
169
169
  }
170
170
  if (received) {
171
- layerInputs[projection.layerName] = layerInput;
171
+ layerInputs[rendering.layerName] = layerInput;
172
172
  continue;
173
173
  }
174
174
 
175
- const emptyInput = projection.input.safeParse({});
175
+ const emptyInput = rendering.input.safeParse({});
176
176
  if (emptyInput.success) {
177
- layerInputs[projection.layerName] = emptyInput.data;
177
+ layerInputs[rendering.layerName] = emptyInput.data;
178
178
  }
179
179
  }
180
180
 
package/src/surface.ts CHANGED
@@ -17,7 +17,7 @@ import { deriveLibraryApi } from './derive.js';
17
17
  import type {
18
18
  DeriveLibraryApiOptions,
19
19
  LibraryExport,
20
- LibraryProjection,
20
+ LibraryRenderingPlan,
21
21
  } from './derive.js';
22
22
  import { toLibraryError } from './errors.js';
23
23
  import type { LibraryError } from './errors.js';
@@ -26,7 +26,7 @@ import { kernelRun } from './kernel.js';
26
26
  import type { KernelRunOptions, Topo } from './kernel.js';
27
27
 
28
28
  /**
29
- * Options for the in-memory library surface: projection selectors plus the
29
+ * Options for the in-memory library surface: rendering selectors plus the
30
30
  * runtime context the client owns (e.g. a permit for permitted trails).
31
31
  */
32
32
  export interface SurfaceLibraryOptions
@@ -42,14 +42,14 @@ export type LibraryResultMethod = (
42
42
  input: unknown
43
43
  ) => Promise<Result<unknown, LibraryError>>;
44
44
 
45
- /** The held in-memory client: one method per projected export, plus the projection. */
45
+ /** The held in-memory client: one method per rendered export, plus the rendering. */
46
46
  export interface LibraryClient {
47
47
  /** Invoke an exported trail by its consumer-native name. */
48
48
  readonly call: Readonly<Record<string, LibraryMethod>>;
49
49
  /** Invoke an exported trail by name without unwrapping the Result boundary. */
50
50
  readonly result: Readonly<Record<string, LibraryResultMethod>>;
51
- /** The resolved projection this client was built from (introspection). */
52
- readonly projection: LibraryProjection;
51
+ /** The resolved rendering this client was built from (introspection). */
52
+ readonly rendering: LibraryRenderingPlan;
53
53
  }
54
54
 
55
55
  const prepareLibraryInput = (
@@ -96,11 +96,9 @@ export const runLibraryResult = async (
96
96
  input: unknown,
97
97
  options: SurfaceLibraryOptions = {}
98
98
  ): Promise<Result<unknown, LibraryError>> => {
99
- const projection = deriveLibraryApi(graph, options);
99
+ const rendering = deriveLibraryApi(graph, options);
100
100
  const runOptions = runtimeOptionsFor(graph, options);
101
- const entry = projection.exports.find(
102
- (candidate) => candidate.trailId === id
103
- );
101
+ const entry = rendering.exports.find((candidate) => candidate.trailId === id);
104
102
  const prepared = entry
105
103
  ? prepareLibraryInput(entry, input)
106
104
  : { layerInputs: {}, trailInput: input };
@@ -117,7 +115,7 @@ export const runLibraryResult = async (
117
115
  };
118
116
 
119
117
  /**
120
- * Materialize a topo as an in-memory library client. Each projected export
118
+ * Materialize a topo as an in-memory library client. Each rendered export
121
119
  * becomes a method that executes its trail through the shared pipeline and
122
120
  * unwraps the Result — returning the value or throwing the error. The same
123
121
  * export names are available under `result` for callers that want the raw
@@ -132,12 +130,12 @@ export const surface = async (
132
130
  options: SurfaceLibraryOptions = {}
133
131
  // oxlint-disable-next-line require-await -- async to match peer surfaces and allow future resource init
134
132
  ): Promise<LibraryClient> => {
135
- const projection = deriveLibraryApi(graph, options);
133
+ const rendering = deriveLibraryApi(graph, options);
136
134
  const runOptions = runtimeOptionsFor(graph, options);
137
135
  const call: Record<string, LibraryMethod> = {};
138
136
  const result: Record<string, LibraryResultMethod> = {};
139
137
 
140
- for (const entry of projection.exports) {
138
+ for (const entry of rendering.exports) {
141
139
  const runExport: LibraryResultMethod = async (input: unknown) => {
142
140
  const prepared = prepareLibraryInput(entry, input);
143
141
  if (prepared instanceof ValidationError) {
@@ -169,7 +167,7 @@ export const surface = async (
169
167
 
170
168
  return {
171
169
  call: Object.freeze(call),
172
- projection,
170
+ rendering,
173
171
  result: Object.freeze(result),
174
172
  };
175
173
  };