@ontrails/config 1.0.0-beta.14 → 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.
Files changed (163) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/README.md +20 -28
  3. package/package.json +10 -2
  4. package/src/app-config.ts +23 -12
  5. package/src/compose.ts +16 -22
  6. package/src/{config-provision.ts → config-resource.ts} +5 -5
  7. package/src/define-config.ts +18 -18
  8. package/src/{generate → derive}/env.ts +3 -3
  9. package/src/{generate → derive}/example.ts +1 -1
  10. package/src/{generate → derive}/helpers.ts +1 -1
  11. package/src/derive/index.ts +3 -0
  12. package/src/{generate → derive}/json-schema.ts +1 -1
  13. package/src/{describe.ts → derive-fields.ts} +1 -1
  14. package/src/{explain.ts → derive-provenance.ts} +6 -6
  15. package/src/extensions.ts +1 -1
  16. package/src/index.ts +12 -19
  17. package/src/registry.ts +2 -2
  18. package/src/resolve.ts +17 -15
  19. package/src/trails/config-check.ts +3 -3
  20. package/src/trails/config-describe.ts +5 -5
  21. package/src/trails/config-explain.ts +13 -13
  22. package/src/trails/config-init.ts +10 -10
  23. package/.turbo/turbo-build.log +0 -1
  24. package/.turbo/turbo-lint.log +0 -3
  25. package/.turbo/turbo-typecheck.log +0 -1
  26. package/dist/app-config.d.ts +0 -65
  27. package/dist/app-config.d.ts.map +0 -1
  28. package/dist/app-config.js +0 -172
  29. package/dist/app-config.js.map +0 -1
  30. package/dist/collect.d.ts +0 -11
  31. package/dist/collect.d.ts.map +0 -1
  32. package/dist/collect.js +0 -81
  33. package/dist/collect.js.map +0 -1
  34. package/dist/compose.d.ts +0 -30
  35. package/dist/compose.d.ts.map +0 -1
  36. package/dist/compose.js +0 -21
  37. package/dist/compose.js.map +0 -1
  38. package/dist/config-gate.d.ts +0 -11
  39. package/dist/config-gate.d.ts.map +0 -1
  40. package/dist/config-gate.js +0 -6
  41. package/dist/config-gate.js.map +0 -1
  42. package/dist/config-layer.d.ts +0 -11
  43. package/dist/config-layer.d.ts.map +0 -1
  44. package/dist/config-layer.js +0 -6
  45. package/dist/config-layer.js.map +0 -1
  46. package/dist/config-provision.d.ts +0 -3
  47. package/dist/config-provision.d.ts.map +0 -1
  48. package/dist/config-provision.js +0 -26
  49. package/dist/config-provision.js.map +0 -1
  50. package/dist/config-service.d.ts +0 -3
  51. package/dist/config-service.d.ts.map +0 -1
  52. package/dist/config-service.js +0 -26
  53. package/dist/config-service.js.map +0 -1
  54. package/dist/define-config.d.ts +0 -61
  55. package/dist/define-config.d.ts.map +0 -1
  56. package/dist/define-config.js +0 -90
  57. package/dist/define-config.js.map +0 -1
  58. package/dist/describe.d.ts +0 -25
  59. package/dist/describe.d.ts.map +0 -1
  60. package/dist/describe.js +0 -147
  61. package/dist/describe.js.map +0 -1
  62. package/dist/doctor.d.ts +0 -27
  63. package/dist/doctor.d.ts.map +0 -1
  64. package/dist/doctor.js +0 -131
  65. package/dist/doctor.js.map +0 -1
  66. package/dist/explain.d.ts +0 -30
  67. package/dist/explain.d.ts.map +0 -1
  68. package/dist/explain.js +0 -101
  69. package/dist/explain.js.map +0 -1
  70. package/dist/extensions.d.ts +0 -38
  71. package/dist/extensions.d.ts.map +0 -1
  72. package/dist/extensions.js +0 -35
  73. package/dist/extensions.js.map +0 -1
  74. package/dist/generate/env.d.ts +0 -15
  75. package/dist/generate/env.d.ts.map +0 -1
  76. package/dist/generate/env.js +0 -65
  77. package/dist/generate/env.js.map +0 -1
  78. package/dist/generate/example.d.ts +0 -16
  79. package/dist/generate/example.d.ts.map +0 -1
  80. package/dist/generate/example.js +0 -138
  81. package/dist/generate/example.js.map +0 -1
  82. package/dist/generate/helpers.d.ts +0 -35
  83. package/dist/generate/helpers.d.ts.map +0 -1
  84. package/dist/generate/helpers.js +0 -116
  85. package/dist/generate/helpers.js.map +0 -1
  86. package/dist/generate/index.d.ts +0 -4
  87. package/dist/generate/index.d.ts.map +0 -1
  88. package/dist/generate/index.js +0 -4
  89. package/dist/generate/index.js.map +0 -1
  90. package/dist/generate/json-schema.d.ts +0 -18
  91. package/dist/generate/json-schema.d.ts.map +0 -1
  92. package/dist/generate/json-schema.js +0 -97
  93. package/dist/generate/json-schema.js.map +0 -1
  94. package/dist/index.d.ts +0 -21
  95. package/dist/index.d.ts.map +0 -1
  96. package/dist/index.js +0 -21
  97. package/dist/index.js.map +0 -1
  98. package/dist/merge.d.ts +0 -16
  99. package/dist/merge.d.ts.map +0 -1
  100. package/dist/merge.js +0 -34
  101. package/dist/merge.js.map +0 -1
  102. package/dist/ref.d.ts +0 -29
  103. package/dist/ref.d.ts.map +0 -1
  104. package/dist/ref.js +0 -30
  105. package/dist/ref.js.map +0 -1
  106. package/dist/registry.d.ts +0 -24
  107. package/dist/registry.d.ts.map +0 -1
  108. package/dist/registry.js +0 -12
  109. package/dist/registry.js.map +0 -1
  110. package/dist/resolve.d.ts +0 -21
  111. package/dist/resolve.d.ts.map +0 -1
  112. package/dist/resolve.js +0 -177
  113. package/dist/resolve.js.map +0 -1
  114. package/dist/secret-heuristics.d.ts +0 -10
  115. package/dist/secret-heuristics.d.ts.map +0 -1
  116. package/dist/secret-heuristics.js +0 -11
  117. package/dist/secret-heuristics.js.map +0 -1
  118. package/dist/trails/config-check.d.ts +0 -11
  119. package/dist/trails/config-check.d.ts.map +0 -1
  120. package/dist/trails/config-check.js +0 -53
  121. package/dist/trails/config-check.js.map +0 -1
  122. package/dist/trails/config-describe.d.ts +0 -12
  123. package/dist/trails/config-describe.d.ts.map +0 -1
  124. package/dist/trails/config-describe.js +0 -41
  125. package/dist/trails/config-describe.js.map +0 -1
  126. package/dist/trails/config-explain.d.ts +0 -8
  127. package/dist/trails/config-explain.d.ts.map +0 -1
  128. package/dist/trails/config-explain.js +0 -74
  129. package/dist/trails/config-explain.js.map +0 -1
  130. package/dist/trails/config-init.d.ts +0 -9
  131. package/dist/trails/config-init.d.ts.map +0 -1
  132. package/dist/trails/config-init.js +0 -78
  133. package/dist/trails/config-init.js.map +0 -1
  134. package/dist/workspace.d.ts +0 -9
  135. package/dist/workspace.d.ts.map +0 -1
  136. package/dist/workspace.js +0 -49
  137. package/dist/workspace.js.map +0 -1
  138. package/dist/zod-utils.d.ts +0 -14
  139. package/dist/zod-utils.d.ts.map +0 -1
  140. package/dist/zod-utils.js +0 -41
  141. package/dist/zod-utils.js.map +0 -1
  142. package/src/__tests__/app-config.test.ts +0 -329
  143. package/src/__tests__/compose.test.ts +0 -59
  144. package/src/__tests__/config-check.test.ts +0 -171
  145. package/src/__tests__/config-describe.test.ts +0 -154
  146. package/src/__tests__/config-explain.test.ts +0 -167
  147. package/src/__tests__/config-gate.test.ts +0 -53
  148. package/src/__tests__/config-init.test.ts +0 -210
  149. package/src/__tests__/config-provision.test.ts +0 -87
  150. package/src/__tests__/define-config.test.ts +0 -263
  151. package/src/__tests__/describe.test.ts +0 -158
  152. package/src/__tests__/doctor.test.ts +0 -172
  153. package/src/__tests__/explain.test.ts +0 -139
  154. package/src/__tests__/extensions.test.ts +0 -134
  155. package/src/__tests__/generate.test.ts +0 -269
  156. package/src/__tests__/ref.test.ts +0 -35
  157. package/src/__tests__/resolve.test.ts +0 -246
  158. package/src/__tests__/workspace.test.ts +0 -64
  159. package/src/config-gate.ts +0 -15
  160. package/src/generate/index.ts +0 -3
  161. package/src/workspace.ts +0 -56
  162. package/tsconfig.json +0 -9
  163. package/tsconfig.tsbuildinfo +0 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,46 @@
1
1
  # @ontrails/config
2
2
 
3
+ ## 1.0.0-beta.16
4
+
5
+ ### Major Changes
6
+
7
+ - 10eae9a: Migrate the Trails workspace to the documented `.trails/` layout: committed `.lock` files at the workspace root, ignored `cache/` for rebuildable derived data, ignored `state/` for mutable runtime state, and `.trails/config.local.{ts,js}` for local overrides. The default SQLite path is now `.trails/state/trails.db`. Workspace bootstrap creates only `cache/` and `state/` — the legacy `dev/` and `generated/` subdirectories are no longer created. Dev reset cleans both the new `.trails/state/` paths and legacy `.trails/trails.db*` and `.trails/dev/tracing.db*` paths for one cycle. Scaffold and workspace gitignores reflect the new layout.
8
+
9
+ Workspace bootstrap is now owned by a single canonical source in `@ontrails/core`. The package exposes `ensureTrailsWorkspace()`, `WORKSPACE_GITIGNORE_CONTENT`, and `WORKSPACE_GITIGNORE_LINES`. `@ontrails/config` no longer exports its own `ensureWorkspace` (consumers should import from `@ontrails/core`). `trails create` now writes `.trails/.gitignore` during scaffolding so a fresh-scaffolded project's initial commit includes the workspace gitignore (resolves TRL-703).
10
+
11
+ ### Patch Changes
12
+
13
+ - 49c2e7d: Refresh published package README taxonomy to use adapter language instead of retired connector vocabulary.
14
+ - Updated dependencies [73622ae]
15
+ - Updated dependencies [6300f70]
16
+ - Updated dependencies [d172013]
17
+ - Updated dependencies [c3fc5c3]
18
+ - Updated dependencies [20d7a5c]
19
+ - Updated dependencies [be5fb46]
20
+ - Updated dependencies [e898cc4]
21
+ - Updated dependencies [3395234]
22
+ - Updated dependencies [bcdc484]
23
+ - Updated dependencies [331e3a9]
24
+ - Updated dependencies [4399fdb]
25
+ - Updated dependencies [4b8d13b]
26
+ - Updated dependencies [112b9f2]
27
+ - Updated dependencies [893025e]
28
+ - Updated dependencies [eec5e9d]
29
+ - Updated dependencies [ebd4434]
30
+ - Updated dependencies [863d473]
31
+ - Updated dependencies [344f2f7]
32
+ - Updated dependencies [26f9ffd]
33
+ - Updated dependencies [10eae9a]
34
+ - Updated dependencies [22c6c06]
35
+ - @ontrails/core@1.0.0-beta.16
36
+
37
+ ## 1.0.0-beta.15
38
+
39
+ ### Patch Changes
40
+
41
+ - Updated dependencies [4ad6b25]
42
+ - @ontrails/core@1.0.0-beta.15
43
+
3
44
  ## 1.0.0-beta.14
4
45
 
5
46
  ### Minor Changes
package/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  Schema-derived configuration for Trails.
4
4
 
5
- The root package owns the connector-agnostic config declaration and resolution engine. Schemas define the contract; the provision and gate bind resolved values to the execution context.
5
+ The root package owns the runtime-agnostic config declaration and resolution engine. Schemas define the contract, and `configResource` exposes resolved values to trail execution.
6
6
 
7
7
  ## The core pattern
8
8
 
@@ -24,7 +24,7 @@ export const config = defineConfig({
24
24
  base: {
25
25
  host: 'example.com',
26
26
  },
27
- loadouts: {
27
+ profiles: {
28
28
  production: {
29
29
  debug: false,
30
30
  host: 'prod.example.com',
@@ -45,7 +45,7 @@ import { registerConfigState } from '@ontrails/config';
45
45
 
46
46
  const result = await config.resolve({
47
47
  cwd: process.cwd(),
48
- loadout: process.env.TRAILS_ENV,
48
+ profile: process.env.TRAILS_ENV,
49
49
  });
50
50
 
51
51
  if (!result.isOk()) {
@@ -56,7 +56,7 @@ registerConfigState({
56
56
  resolved: result.unwrap(),
57
57
  schema: config.schema,
58
58
  base: config.base,
59
- loadout: process.env.TRAILS_ENV,
59
+ profile: process.env.TRAILS_ENV,
60
60
  env: process.env,
61
61
  });
62
62
  ```
@@ -64,12 +64,12 @@ registerConfigState({
64
64
  ### 3. Access resolved config in trails
65
65
 
66
66
  ```typescript
67
- import { configProvision } from '@ontrails/config';
67
+ import { configResource } from '@ontrails/config';
68
68
 
69
69
  export const getStatus = trail('status.get', {
70
- provisions: [configProvision],
70
+ resources: [configResource],
71
71
  blaze: (_input, ctx) => {
72
- const state = configProvision.from(ctx);
72
+ const state = configResource.from(ctx);
73
73
  return Result.ok({
74
74
  port: state.resolved.port,
75
75
  debug: state.resolved.debug,
@@ -83,11 +83,14 @@ export const getStatus = trail('status.get', {
83
83
  Config resolves through a deterministic priority order:
84
84
 
85
85
  ```text
86
- defaults (schema) → base → loadout → local → env
86
+ defaults (schema) → base → profile → local → env
87
87
  ```
88
88
 
89
89
  Each layer overrides the previous. Environment variables always win.
90
90
 
91
+ `appConfig()` discovers `*.config.toml`, `*.config.json`, `*.config.jsonc`, and
92
+ `*.config.yaml` by default, plus dotfile equivalents when `dotfile: true`.
93
+
91
94
  ## Extensions
92
95
 
93
96
  ### `env()`
@@ -133,33 +136,22 @@ const schema = z.object({
133
136
  });
134
137
  ```
135
138
 
136
- ## The provision
139
+ ## The resource
137
140
 
138
- The config provision manages resolved config lifecycle:
141
+ The config resource manages resolved config lifecycle:
139
142
 
140
143
  ```typescript
141
- import { configProvision } from '@ontrails/config';
144
+ import { configResource } from '@ontrails/config';
142
145
 
143
146
  export const myTrail = trail('my.trail', {
144
- provisions: [configProvision],
147
+ resources: [configResource],
145
148
  blaze: (_input, ctx) => {
146
- const state = configProvision.from(ctx);
149
+ const state = configResource.from(ctx);
147
150
  return Result.ok(state.resolved);
148
151
  },
149
152
  });
150
153
  ```
151
154
 
152
- ## The gate
153
-
154
- The config gate reserves a slot in the execution context for per-trail config validation:
155
-
156
- ```typescript
157
- import { configGate } from '@ontrails/config';
158
-
159
- export const app = topo('my-app', configModule);
160
- // Register configGate with your trailhead
161
- ```
162
-
163
155
  ## Trail definitions
164
156
 
165
157
  ### `config.check`
@@ -172,7 +164,7 @@ Describe all fields in the schema — paths, types, defaults, env bindings, secr
172
164
 
173
165
  ### `config.explain`
174
166
 
175
- Show which source won for each config field — defaults, base, loadout, local, or env.
167
+ Show which source won for each config field — defaults, base, profile, local, or env.
176
168
 
177
169
  ### `config.init`
178
170
 
@@ -180,13 +172,13 @@ Generate example config files in TOML, JSON, JSONC, or YAML. Optionally writes `
180
172
 
181
173
  ## Testing
182
174
 
183
- Trails that depend on `configProvision` auto-resolve with a mock when registered in the topo:
175
+ Trails that depend on `configResource` auto-resolve with a mock when registered in the topo:
184
176
 
185
177
  ```typescript
186
178
  import { testAll } from '@ontrails/testing';
187
179
 
188
- const results = testAll(app);
189
- // configProvision.mock() is called automatically
180
+ const results = testAll(graph);
181
+ // configResource.mock() is called automatically
190
182
  ```
191
183
 
192
184
  For explicit test setup:
package/package.json CHANGED
@@ -1,6 +1,14 @@
1
1
  {
2
2
  "name": "@ontrails/config",
3
- "version": "1.0.0-beta.14",
3
+ "version": "1.0.0-beta.16",
4
+ "files": [
5
+ "src/**/*.ts",
6
+ "!src/**/__tests__/**",
7
+ "!src/**/*.test.ts",
8
+ "!src/**/*.test-d.ts",
9
+ "README.md",
10
+ "CHANGELOG.md"
11
+ ],
4
12
  "type": "module",
5
13
  "exports": {
6
14
  ".": "./src/index.ts",
@@ -14,7 +22,7 @@
14
22
  "clean": "rm -rf dist *.tsbuildinfo"
15
23
  },
16
24
  "peerDependencies": {
17
- "@ontrails/core": "^1.0.0-beta.13",
25
+ "@ontrails/core": "^1.0.0-beta.15",
18
26
  "zod": "^4.3.5"
19
27
  }
20
28
  }
package/src/app-config.ts CHANGED
@@ -9,10 +9,13 @@ import type { z } from 'zod';
9
9
 
10
10
  import type { CheckResult } from './doctor.js';
11
11
  import { checkConfig } from './doctor.js';
12
- import type { FieldDescription } from './describe.js';
13
- import { describeConfig } from './describe.js';
14
- import type { ExplainConfigOptions, ProvenanceEntry } from './explain.js';
15
- import { explainConfig } from './explain.js';
12
+ import type { FieldDescription } from './derive-fields.js';
13
+ import { deriveConfigFields } from './derive-fields.js';
14
+ import type {
15
+ DeriveConfigProvenanceOptions,
16
+ ProvenanceEntry,
17
+ } from './derive-provenance.js';
18
+ import { deriveConfigProvenance } from './derive-provenance.js';
16
19
  import type { ConfigRef } from './ref.js';
17
20
  import { configRef } from './ref.js';
18
21
 
@@ -39,8 +42,8 @@ export interface ResolveOptions {
39
42
  }
40
43
 
41
44
  /** Options for the `explain()` method on AppConfig, excluding schema. */
42
- export type AppConfigExplainOptions = Omit<
43
- ExplainConfigOptions<z.ZodType>,
45
+ export type AppConfigDeriveProvenanceOptions = Omit<
46
+ DeriveConfigProvenanceOptions<z.ZodType>,
44
47
  'schema'
45
48
  >;
46
49
 
@@ -62,7 +65,9 @@ export interface AppConfig<T extends z.ZodType> {
62
65
  ): CheckResult;
63
66
 
64
67
  /** Show which source won for each config field. */
65
- explain(options: AppConfigExplainOptions): readonly ProvenanceEntry[];
68
+ explain(
69
+ options: AppConfigDeriveProvenanceOptions
70
+ ): readonly ProvenanceEntry[];
66
71
 
67
72
  /** Create a lazy reference to a config field for use as a trail input default. */
68
73
  ref(fieldPath: string): ConfigRef;
@@ -72,7 +77,12 @@ export interface AppConfig<T extends z.ZodType> {
72
77
  // Default values
73
78
  // ---------------------------------------------------------------------------
74
79
 
75
- const DEFAULT_FORMATS: readonly ConfigFormat[] = ['toml', 'json', 'yaml'];
80
+ const DEFAULT_FORMATS: readonly ConfigFormat[] = [
81
+ 'toml',
82
+ 'json',
83
+ 'jsonc',
84
+ 'yaml',
85
+ ];
76
86
 
77
87
  // ---------------------------------------------------------------------------
78
88
  // Internal helpers (defined before consumers — no-use-before-define)
@@ -225,7 +235,7 @@ const discoverConfigFile = async (
225
235
  };
226
236
 
227
237
  /** Resolve a config file — either from an explicit path or via discovery. */
228
- const resolveConfig = async <T extends z.ZodType>(
238
+ const resolveAppConfigFile = async <T extends z.ZodType>(
229
239
  name: string,
230
240
  schema: T,
231
241
  formats: readonly ConfigFormat[],
@@ -292,16 +302,17 @@ export const appConfig = <T extends z.ZodType>(
292
302
  return {
293
303
  check: (values, checkOpts) => checkConfig(schema, values, checkOpts),
294
304
  describe: () =>
295
- describeConfig(
305
+ deriveConfigFields(
296
306
  schema as unknown as z.ZodObject<Record<string, z.ZodType>>
297
307
  ),
298
308
  dotfile,
299
- explain: (explainOpts) => explainConfig({ ...explainOpts, schema }),
309
+ explain: (explainOpts) =>
310
+ deriveConfigProvenance({ ...explainOpts, schema }),
300
311
  formats,
301
312
  name,
302
313
  ref: (fieldPath) => configRef(fieldPath),
303
314
  resolve: (resolveOptions?: ResolveOptions) =>
304
- resolveConfig(name, schema, formats, dotfile, resolveOptions),
315
+ resolveAppConfigFile(name, schema, formats, dotfile, resolveOptions),
305
316
  schema,
306
317
  };
307
318
  };
package/src/compose.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
- * Config composition utilities for provisions.
2
+ * Config composition utilities for resources.
3
3
  *
4
- * Collects config schemas from provision declarations so they can be
4
+ * Collects config schemas from resource declarations so they can be
5
5
  * composed into a unified config structure via `defineConfig`.
6
6
  */
7
7
 
@@ -11,17 +11,14 @@ import type { z } from 'zod';
11
11
  // Types
12
12
  // ---------------------------------------------------------------------------
13
13
 
14
- /** A provision config schema entry extracted from a provision declaration. */
15
- export interface ProvisionConfigEntry {
16
- readonly provisionId: string;
14
+ /** A resource config schema entry extracted from a resource declaration. */
15
+ export interface ResourceConfigEntry {
16
+ readonly resourceId: string;
17
17
  readonly schema: z.ZodType;
18
18
  }
19
19
 
20
- /** Backward-compatible alias while the migration is in flight. */
21
- export type ServiceConfigEntry = ProvisionConfigEntry;
22
-
23
- /** Minimal shape needed to extract config from a provision-like object. */
24
- interface ProvisionWithOptionalConfig {
20
+ /** Minimal shape needed to extract config from a resource-like object. */
21
+ interface ResourceWithOptionalConfig {
25
22
  readonly id: string;
26
23
  readonly config?: z.ZodType | undefined;
27
24
  }
@@ -31,22 +28,19 @@ interface ProvisionWithOptionalConfig {
31
28
  // ---------------------------------------------------------------------------
32
29
 
33
30
  /**
34
- * Collect config schemas from provisions that declare them.
31
+ * Collect config schemas from resources that declare them.
35
32
  *
36
- * Returns entries keyed by provision ID for composition into `defineConfig`.
37
- * Provisions without a `config` schema are excluded.
33
+ * Returns entries keyed by resource ID for composition into `defineConfig`.
34
+ * Resources without a `config` schema are excluded.
38
35
  */
39
- export const collectProvisionConfigs = (
40
- provisions: readonly ProvisionWithOptionalConfig[]
41
- ): ProvisionConfigEntry[] =>
42
- provisions
36
+ export const collectResourceConfigs = (
37
+ resources: readonly ResourceWithOptionalConfig[]
38
+ ): ResourceConfigEntry[] =>
39
+ resources
43
40
  .filter(
44
41
  (
45
42
  svc
46
- ): svc is ProvisionWithOptionalConfig & { readonly config: z.ZodType } =>
43
+ ): svc is ResourceWithOptionalConfig & { readonly config: z.ZodType } =>
47
44
  svc.config !== undefined
48
45
  )
49
- .map((svc) => ({ provisionId: svc.id, schema: svc.config }));
50
-
51
- /** Backward-compatible alias while the migration is in flight. */
52
- export const collectServiceConfigs = collectProvisionConfigs;
46
+ .map((svc) => ({ resourceId: svc.id, schema: svc.config }));
@@ -1,17 +1,17 @@
1
1
  /**
2
- * Config provision — manages resolved config lifecycle.
2
+ * Config resource — manages resolved config lifecycle.
3
3
  *
4
4
  * The config is resolved during bootstrap (two-phase init per ADR-010)
5
- * and registered via `registerConfigState`. This provision reads from the
6
- * global registry so trails can access it through `configProvision.from(ctx)`.
5
+ * and registered via `registerConfigState`. This resource reads from the
6
+ * global registry so trails can access it through `configResource.from(ctx)`.
7
7
  */
8
- import { InternalError, Result, provision } from '@ontrails/core';
8
+ import { InternalError, Result, resource } from '@ontrails/core';
9
9
  import { z } from 'zod';
10
10
 
11
11
  import type { ConfigState } from './registry.js';
12
12
  import { getConfigState } from './registry.js';
13
13
 
14
- export const configProvision = provision<ConfigState>('config', {
14
+ export const configResource = resource<ConfigState>('config', {
15
15
  create: () => {
16
16
  const state = getConfigState();
17
17
  if (state === undefined) {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Trails-specific config wrapper — `appConfig('trails', ...)` with
3
- * framework conventions for loadout selection and local overrides.
3
+ * framework conventions for profile selection and local overrides.
4
4
  */
5
5
 
6
6
  import { existsSync } from 'node:fs';
@@ -9,7 +9,7 @@ import { join } from 'node:path';
9
9
  import type { z } from 'zod';
10
10
 
11
11
  import { appConfig } from './app-config.js';
12
- import { resolveConfig } from './resolve.js';
12
+ import { deriveConfig } from './resolve.js';
13
13
 
14
14
  // ---------------------------------------------------------------------------
15
15
  // Types
@@ -19,14 +19,14 @@ import { resolveConfig } from './resolve.js';
19
19
  export interface DefineConfigOptions<T extends z.ZodType> {
20
20
  readonly schema: T;
21
21
  readonly base?: Partial<z.infer<T>>;
22
- readonly loadouts?: Record<string, Partial<z.infer<T>>>;
22
+ readonly profiles?: Record<string, Partial<z.infer<T>>>;
23
23
  /** When true, fall back to `NODE_ENV` when `TRAILS_ENV` is unset. */
24
24
  readonly envFromNodeEnv?: boolean;
25
25
  }
26
26
 
27
27
  /** Options passed to `resolve()` on a defined config. */
28
28
  interface DefineConfigResolveOptions {
29
- readonly loadout?: string;
29
+ readonly profile?: string;
30
30
  readonly env?: Record<string, string | undefined>;
31
31
  /** Working directory for local overrides discovery. Defaults to `process.cwd()`. */
32
32
  readonly cwd?: string;
@@ -36,10 +36,13 @@ interface DefineConfigResolveOptions {
36
36
  // Local overrides discovery
37
37
  // ---------------------------------------------------------------------------
38
38
 
39
- const LOCAL_OVERRIDE_CANDIDATES = ['local.ts', 'local.js'] as const;
39
+ const LOCAL_OVERRIDE_CANDIDATES = [
40
+ 'config.local.ts',
41
+ 'config.local.js',
42
+ ] as const;
40
43
 
41
44
  /**
42
- * Discover and synchronously import a `.trails/config/local.{ts,js}` file.
45
+ * Discover and synchronously import a `.trails/config.local.{ts,js}` file.
43
46
  *
44
47
  * Skipped when `TRAILS_ENV=test` for hermetic test environments.
45
48
  */
@@ -52,7 +55,7 @@ const discoverLocalOverrides = async (
52
55
  }
53
56
 
54
57
  for (const filename of LOCAL_OVERRIDE_CANDIDATES) {
55
- const candidate = join(cwd, '.trails', 'config', filename);
58
+ const candidate = join(cwd, '.trails', filename);
56
59
  if (existsSync(candidate)) {
57
60
  const mod: Record<string, unknown> = await import(candidate);
58
61
  return (mod['default'] ?? mod) as Record<string, unknown>;
@@ -70,7 +73,7 @@ const discoverLocalOverrides = async (
70
73
  * Define Trails app config.
71
74
  *
72
75
  * This is `appConfig('trails', ...)` with the framework's own conventions:
73
- * `TRAILS_ENV` selects the loadout. When `envFromNodeEnv` is true,
76
+ * `TRAILS_ENV` selects the profile. When `envFromNodeEnv` is true,
74
77
  * `NODE_ENV` is used as a fallback when `TRAILS_ENV` is unset.
75
78
  *
76
79
  * @example
@@ -81,7 +84,7 @@ const discoverLocalOverrides = async (
81
84
  * debug: z.boolean().default(false),
82
85
  * }),
83
86
  * base: { port: 8080 },
84
- * loadouts: {
87
+ * profiles: {
85
88
  * production: { debug: false },
86
89
  * test: { debug: true, port: 0 },
87
90
  * },
@@ -93,15 +96,12 @@ const discoverLocalOverrides = async (
93
96
  export const defineConfig = <T extends z.ZodType>(
94
97
  options: DefineConfigOptions<T>
95
98
  ) => {
96
- const config = appConfig('trails', {
97
- formats: ['toml', 'json'],
98
- schema: options.schema,
99
- });
99
+ const config = appConfig('trails', { schema: options.schema });
100
100
 
101
101
  return {
102
102
  ...config,
103
103
  base: options.base,
104
- loadouts: options.loadouts,
104
+ profiles: options.profiles,
105
105
  resolve: async (resolveOpts?: DefineConfigResolveOptions) => {
106
106
  const envRecord = {
107
107
  ...(resolveOpts?.env ?? process.env),
@@ -118,14 +118,14 @@ export const defineConfig = <T extends z.ZodType>(
118
118
  const cwd = resolveOpts?.cwd ?? process.cwd();
119
119
  const localOverrides = await discoverLocalOverrides(cwd, envRecord);
120
120
 
121
- return resolveConfig({
121
+ return deriveConfig({
122
122
  base: options.base as Record<string, unknown> | undefined,
123
123
  env: envRecord,
124
- loadout: resolveOpts?.loadout ?? envRecord['TRAILS_ENV'],
125
- loadouts: options.loadouts as
124
+ localOverrides,
125
+ profile: resolveOpts?.profile ?? envRecord['TRAILS_ENV'],
126
+ profiles: options.profiles as
126
127
  | Record<string, Record<string, unknown>>
127
128
  | undefined,
128
- localOverrides,
129
129
  schema: options.schema,
130
130
  });
131
131
  },
@@ -15,7 +15,7 @@ import {
15
15
  formatValue,
16
16
  getDefault,
17
17
  getDescription,
18
- resolveFieldByPath,
18
+ deriveFieldByPath,
19
19
  unwrap,
20
20
  zodTypeName,
21
21
  zodTypeToJsonSchema,
@@ -76,7 +76,7 @@ const collectEnvEntries = (
76
76
  if (!fieldMeta.env) {
77
77
  continue;
78
78
  }
79
- const fieldSchema = resolveFieldByPath(schema, path);
79
+ const fieldSchema = deriveFieldByPath(schema, path);
80
80
  if (!fieldSchema) {
81
81
  continue;
82
82
  }
@@ -96,7 +96,7 @@ const collectEnvEntries = (
96
96
  * Lists each env var with its type, default, and whether it is a secret.
97
97
  * Returns an empty string when no env bindings are present.
98
98
  */
99
- export const generateEnvExample = (
99
+ export const deriveConfigEnvExample = (
100
100
  schema: z.ZodObject<Record<string, z.ZodType>>
101
101
  ): string => {
102
102
  const entries = collectEnvEntries(schema, collectConfigMeta(schema));
@@ -216,7 +216,7 @@ const formatters: Record<
216
216
  *
217
217
  * Includes descriptions as comments, defaults shown, deprecated fields annotated.
218
218
  */
219
- export const generateExample = (
219
+ export const deriveConfigExample = (
220
220
  schema: z.ZodObject<Record<string, z.ZodType>>,
221
221
  format: ExampleFormat
222
222
  ): string => formatters[format](schema);
@@ -86,7 +86,7 @@ export const getObjectShape = (
86
86
  };
87
87
 
88
88
  /** Resolve a dot-separated path to the field schema within an object. */
89
- export const resolveFieldByPath = (
89
+ export const deriveFieldByPath = (
90
90
  schema: z.ZodObject<Record<string, z.ZodType>>,
91
91
  path: string
92
92
  ): z.ZodType | undefined => {
@@ -0,0 +1,3 @@
1
+ export { deriveConfigEnvExample } from './env.js';
2
+ export { deriveConfigExample } from './example.js';
3
+ export { deriveConfigJsonSchema } from './json-schema.js';
@@ -112,7 +112,7 @@ const buildSchemaProperties = (
112
112
  * Includes descriptions, defaults, deprecated annotations, and constraints.
113
113
  * Produces JSON Schema Draft 2020-12.
114
114
  */
115
- export const generateJsonSchema = (
115
+ export const deriveConfigJsonSchema = (
116
116
  schema: z.ZodObject<Record<string, z.ZodType>>,
117
117
  options?: { readonly description?: string; readonly title?: string }
118
118
  ): Record<string, unknown> => {
@@ -228,7 +228,7 @@ const walkShapeLevel = (
228
228
  *
229
229
  * Returns a structured catalog suitable for CLI rendering or agent inspection.
230
230
  */
231
- export const describeConfig = (
231
+ export const deriveConfigFields = (
232
232
  schema: z.ZodObject<Record<string, z.ZodType>>
233
233
  ): readonly FieldDescription[] => {
234
234
  const configMeta = collectConfigMeta(schema);
@@ -18,15 +18,15 @@ import { getAtPath, isZodObject, unwrapToBase, zodDef } from './zod-utils.js';
18
18
  export interface ProvenanceEntry {
19
19
  readonly path: string;
20
20
  readonly value: unknown;
21
- readonly source: 'default' | 'base' | 'loadout' | 'local' | 'env';
21
+ readonly source: 'default' | 'base' | 'profile' | 'local' | 'env';
22
22
  readonly redacted: boolean;
23
23
  }
24
24
 
25
25
  /** Options for explaining config provenance. */
26
- export interface ExplainConfigOptions<T extends z.ZodType> {
26
+ export interface DeriveConfigProvenanceOptions<T extends z.ZodType> {
27
27
  readonly schema: T;
28
28
  readonly base?: Record<string, unknown>;
29
- readonly loadout?: Record<string, unknown>;
29
+ readonly profile?: Record<string, unknown>;
30
30
  readonly local?: Record<string, unknown>;
31
31
  readonly env?: Record<string, string | undefined>;
32
32
  readonly resolved: Record<string, unknown>;
@@ -135,8 +135,8 @@ const collectLeafPaths = (schema: z.ZodType, prefix: string): string[] => {
135
135
  * Used for debugging — answers "where did this value come from?"
136
136
  *
137
137
  */
138
- export const explainConfig = <T extends z.ZodType>(
139
- options: ExplainConfigOptions<T>
138
+ export const deriveConfigProvenance = <T extends z.ZodType>(
139
+ options: DeriveConfigProvenanceOptions<T>
140
140
  ): readonly ProvenanceEntry[] => {
141
141
  const objSchema = options.schema as unknown as z.ZodObject<
142
142
  Record<string, z.ZodType>
@@ -146,7 +146,7 @@ export const explainConfig = <T extends z.ZodType>(
146
146
 
147
147
  const sources: readonly SourceEntry[] = [
148
148
  ['local', options.local],
149
- ['loadout', options.loadout],
149
+ ['profile', options.profile],
150
150
  ['base', options.base],
151
151
  ];
152
152
 
package/src/extensions.ts CHANGED
@@ -34,7 +34,7 @@ export const secret = <T extends z.ZodType>(schema: T): T =>
34
34
  * standard key. We set `deprecated: true` so Zod-native tooling (schema
35
35
  * serializers, OpenAPI generators) recognises the field as deprecated, and store
36
36
  * the human-readable message under `deprecationMessage` for our own
37
- * `collectConfigMeta` / survey / explain trailheads.
37
+ * `collectConfigMeta` / survey / explain surfaces.
38
38
  *
39
39
  * Must be called BEFORE `.default()`, `.optional()`, or other transforms
40
40
  * so that the metadata lives on the inner type where `collectConfigMeta`
package/src/index.ts CHANGED
@@ -1,20 +1,15 @@
1
1
  export {
2
2
  appConfig,
3
3
  type AppConfig,
4
- type AppConfigExplainOptions,
4
+ type AppConfigDeriveProvenanceOptions,
5
5
  type AppConfigOptions,
6
6
  type ConfigFormat,
7
7
  type ResolveOptions,
8
8
  } from './app-config.js';
9
9
  export { collectConfigMeta } from './collect.js';
10
- export {
11
- collectProvisionConfigs,
12
- collectServiceConfigs,
13
- type ProvisionConfigEntry,
14
- type ServiceConfigEntry,
15
- } from './compose.js';
10
+ export { collectResourceConfigs, type ResourceConfigEntry } from './compose.js';
16
11
  export { defineConfig, type DefineConfigOptions } from './define-config.js';
17
- export { describeConfig, type FieldDescription } from './describe.js';
12
+ export { deriveConfigFields, type FieldDescription } from './derive-fields.js';
18
13
  export {
19
14
  checkConfig,
20
15
  type CheckResult,
@@ -22,17 +17,16 @@ export {
22
17
  } from './doctor.js';
23
18
  export { env, secret, deprecated, type ConfigFieldMeta } from './extensions.js';
24
19
  export {
25
- explainConfig,
26
- type ExplainConfigOptions,
20
+ deriveConfigProvenance,
21
+ type DeriveConfigProvenanceOptions,
27
22
  type ProvenanceEntry,
28
- } from './explain.js';
23
+ } from './derive-provenance.js';
29
24
  export {
30
- generateEnvExample,
31
- generateExample,
32
- generateJsonSchema,
33
- } from './generate/index.js';
34
- export { configGate } from './config-gate.js';
35
- export { configProvision } from './config-provision.js';
25
+ deriveConfigEnvExample,
26
+ deriveConfigExample,
27
+ deriveConfigJsonSchema,
28
+ } from './derive/index.js';
29
+ export { configResource } from './config-resource.js';
36
30
  export {
37
31
  clearConfigState,
38
32
  type ConfigState,
@@ -41,9 +35,8 @@ export {
41
35
  } from './registry.js';
42
36
  export { deepMerge } from './merge.js';
43
37
  export { configRef, isConfigRef, type ConfigRef } from './ref.js';
44
- export { resolveConfig, type ResolveConfigOptions } from './resolve.js';
38
+ export { deriveConfig, type DeriveConfigOptions } from './resolve.js';
45
39
  export { configCheck } from './trails/config-check.js';
46
40
  export { configDescribe } from './trails/config-describe.js';
47
41
  export { configExplain } from './trails/config-explain.js';
48
42
  export { configInit } from './trails/config-init.js';
49
- export { ensureWorkspace } from './workspace.js';