@ontrails/config 1.0.0-beta.15 → 1.0.0-beta.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (139) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +1 -1
  3. package/package.json +10 -2
  4. package/src/define-config.ts +6 -3
  5. package/src/extensions.ts +1 -1
  6. package/src/index.ts +0 -1
  7. package/src/registry.ts +1 -1
  8. package/src/resolve.ts +4 -2
  9. package/.turbo/turbo-build.log +0 -1
  10. package/.turbo/turbo-lint.log +0 -3
  11. package/.turbo/turbo-typecheck.log +0 -1
  12. package/dist/app-config.d.ts +0 -65
  13. package/dist/app-config.d.ts.map +0 -1
  14. package/dist/app-config.js +0 -177
  15. package/dist/app-config.js.map +0 -1
  16. package/dist/collect.d.ts +0 -11
  17. package/dist/collect.d.ts.map +0 -1
  18. package/dist/collect.js +0 -81
  19. package/dist/collect.js.map +0 -1
  20. package/dist/compose.d.ts +0 -26
  21. package/dist/compose.d.ts.map +0 -1
  22. package/dist/compose.js +0 -19
  23. package/dist/compose.js.map +0 -1
  24. package/dist/config-layer.d.ts +0 -11
  25. package/dist/config-layer.d.ts.map +0 -1
  26. package/dist/config-layer.js +0 -6
  27. package/dist/config-layer.js.map +0 -1
  28. package/dist/config-resource.d.ts +0 -3
  29. package/dist/config-resource.d.ts.map +0 -1
  30. package/dist/config-resource.js +0 -26
  31. package/dist/config-resource.js.map +0 -1
  32. package/dist/define-config.d.ts +0 -61
  33. package/dist/define-config.d.ts.map +0 -1
  34. package/dist/define-config.js +0 -87
  35. package/dist/define-config.js.map +0 -1
  36. package/dist/derive/env.d.ts +0 -15
  37. package/dist/derive/env.d.ts.map +0 -1
  38. package/dist/derive/env.js +0 -65
  39. package/dist/derive/env.js.map +0 -1
  40. package/dist/derive/example.d.ts +0 -16
  41. package/dist/derive/example.d.ts.map +0 -1
  42. package/dist/derive/example.js +0 -138
  43. package/dist/derive/example.js.map +0 -1
  44. package/dist/derive/helpers.d.ts +0 -35
  45. package/dist/derive/helpers.d.ts.map +0 -1
  46. package/dist/derive/helpers.js +0 -116
  47. package/dist/derive/helpers.js.map +0 -1
  48. package/dist/derive/index.d.ts +0 -4
  49. package/dist/derive/index.d.ts.map +0 -1
  50. package/dist/derive/index.js +0 -4
  51. package/dist/derive/index.js.map +0 -1
  52. package/dist/derive/json-schema.d.ts +0 -18
  53. package/dist/derive/json-schema.d.ts.map +0 -1
  54. package/dist/derive/json-schema.js +0 -97
  55. package/dist/derive/json-schema.js.map +0 -1
  56. package/dist/derive-fields.d.ts +0 -25
  57. package/dist/derive-fields.d.ts.map +0 -1
  58. package/dist/derive-fields.js +0 -147
  59. package/dist/derive-fields.js.map +0 -1
  60. package/dist/derive-provenance.d.ts +0 -30
  61. package/dist/derive-provenance.d.ts.map +0 -1
  62. package/dist/derive-provenance.js +0 -101
  63. package/dist/derive-provenance.js.map +0 -1
  64. package/dist/doctor.d.ts +0 -27
  65. package/dist/doctor.d.ts.map +0 -1
  66. package/dist/doctor.js +0 -131
  67. package/dist/doctor.js.map +0 -1
  68. package/dist/extensions.d.ts +0 -38
  69. package/dist/extensions.d.ts.map +0 -1
  70. package/dist/extensions.js +0 -35
  71. package/dist/extensions.js.map +0 -1
  72. package/dist/index.d.ts +0 -20
  73. package/dist/index.d.ts.map +0 -1
  74. package/dist/index.js +0 -20
  75. package/dist/index.js.map +0 -1
  76. package/dist/merge.d.ts +0 -16
  77. package/dist/merge.d.ts.map +0 -1
  78. package/dist/merge.js +0 -34
  79. package/dist/merge.js.map +0 -1
  80. package/dist/ref.d.ts +0 -29
  81. package/dist/ref.d.ts.map +0 -1
  82. package/dist/ref.js +0 -30
  83. package/dist/ref.js.map +0 -1
  84. package/dist/registry.d.ts +0 -24
  85. package/dist/registry.d.ts.map +0 -1
  86. package/dist/registry.js +0 -12
  87. package/dist/registry.js.map +0 -1
  88. package/dist/resolve.d.ts +0 -21
  89. package/dist/resolve.d.ts.map +0 -1
  90. package/dist/resolve.js +0 -177
  91. package/dist/resolve.js.map +0 -1
  92. package/dist/secret-heuristics.d.ts +0 -10
  93. package/dist/secret-heuristics.d.ts.map +0 -1
  94. package/dist/secret-heuristics.js +0 -11
  95. package/dist/secret-heuristics.js.map +0 -1
  96. package/dist/trails/config-check.d.ts +0 -11
  97. package/dist/trails/config-check.d.ts.map +0 -1
  98. package/dist/trails/config-check.js +0 -53
  99. package/dist/trails/config-check.js.map +0 -1
  100. package/dist/trails/config-describe.d.ts +0 -12
  101. package/dist/trails/config-describe.d.ts.map +0 -1
  102. package/dist/trails/config-describe.js +0 -41
  103. package/dist/trails/config-describe.js.map +0 -1
  104. package/dist/trails/config-explain.d.ts +0 -8
  105. package/dist/trails/config-explain.d.ts.map +0 -1
  106. package/dist/trails/config-explain.js +0 -74
  107. package/dist/trails/config-explain.js.map +0 -1
  108. package/dist/trails/config-init.d.ts +0 -9
  109. package/dist/trails/config-init.d.ts.map +0 -1
  110. package/dist/trails/config-init.js +0 -78
  111. package/dist/trails/config-init.js.map +0 -1
  112. package/dist/workspace.d.ts +0 -9
  113. package/dist/workspace.d.ts.map +0 -1
  114. package/dist/workspace.js +0 -49
  115. package/dist/workspace.js.map +0 -1
  116. package/dist/zod-utils.d.ts +0 -14
  117. package/dist/zod-utils.d.ts.map +0 -1
  118. package/dist/zod-utils.js +0 -41
  119. package/dist/zod-utils.js.map +0 -1
  120. package/src/__tests__/app-config.test.ts +0 -342
  121. package/src/__tests__/compose.test.ts +0 -59
  122. package/src/__tests__/config-check.test.ts +0 -171
  123. package/src/__tests__/config-describe.test.ts +0 -154
  124. package/src/__tests__/config-explain.test.ts +0 -167
  125. package/src/__tests__/config-init.test.ts +0 -210
  126. package/src/__tests__/config-resource.test.ts +0 -87
  127. package/src/__tests__/define-config.test.ts +0 -269
  128. package/src/__tests__/derive-fields.test.ts +0 -158
  129. package/src/__tests__/derive-provenance.test.ts +0 -139
  130. package/src/__tests__/derive.test.ts +0 -269
  131. package/src/__tests__/doctor.test.ts +0 -172
  132. package/src/__tests__/extensions.test.ts +0 -134
  133. package/src/__tests__/ref.test.ts +0 -35
  134. package/src/__tests__/resolve.test.ts +0 -246
  135. package/src/__tests__/workspace.test.ts +0 -64
  136. package/src/workspace.ts +0 -56
  137. package/tsconfig.json +0 -9
  138. package/tsconfig.tests.json +0 -10
  139. package/tsconfig.tsbuildinfo +0 -1
@@ -1,246 +0,0 @@
1
- import { describe, expect, test } from 'bun:test';
2
- import { z } from 'zod';
3
-
4
- import { env } from '../extensions.js';
5
- import { deriveConfig } from '../resolve.js';
6
-
7
- const baseSchema = z.object({
8
- debug: z.boolean().default(false),
9
- host: z.string().default('localhost'),
10
- port: z.number().default(3000),
11
- });
12
-
13
- describe('deriveConfig', () => {
14
- describe('schema defaults', () => {
15
- test('applies schema defaults when no other source provides values', () => {
16
- const result = deriveConfig({ schema: baseSchema });
17
-
18
- expect(result.isOk()).toBe(true);
19
- expect(result.unwrap()).toEqual({
20
- debug: false,
21
- host: 'localhost',
22
- port: 3000,
23
- });
24
- });
25
- });
26
-
27
- describe('base config', () => {
28
- test('overrides schema defaults', () => {
29
- const result = deriveConfig({
30
- base: { host: 'example.com', port: 8080 },
31
- schema: baseSchema,
32
- });
33
-
34
- expect(result.isOk()).toBe(true);
35
- const value = result.unwrap();
36
- expect(value.host).toBe('example.com');
37
- expect(value.port).toBe(8080);
38
- // Schema default preserved for unspecified fields
39
- expect(value.debug).toBe(false);
40
- });
41
- });
42
-
43
- describe('profiles', () => {
44
- test('overrides base config for matching profile', () => {
45
- const result = deriveConfig({
46
- base: { host: 'example.com', port: 8080 },
47
- profile: 'production',
48
- profiles: {
49
- production: { host: 'prod.example.com', port: 443 },
50
- },
51
- schema: baseSchema,
52
- });
53
-
54
- expect(result.isOk()).toBe(true);
55
- const value = result.unwrap();
56
- expect(value.host).toBe('prod.example.com');
57
- expect(value.port).toBe(443);
58
- expect(value.debug).toBe(false);
59
- });
60
-
61
- test('silently ignores unrecognized profile (base only)', () => {
62
- const result = deriveConfig({
63
- base: { host: 'example.com' },
64
- profile: 'staging',
65
- profiles: {
66
- production: { host: 'prod.example.com' },
67
- },
68
- schema: baseSchema,
69
- });
70
-
71
- expect(result.isOk()).toBe(true);
72
- expect(result.unwrap().host).toBe('example.com');
73
- });
74
- });
75
-
76
- describe('local overrides', () => {
77
- test('deep-merge on top of profile', () => {
78
- const nestedSchema = z.object({
79
- db: z
80
- .object({
81
- host: z.string().default('localhost'),
82
- port: z.number().default(5432),
83
- })
84
- .default({}),
85
- });
86
-
87
- const result = deriveConfig({
88
- base: { db: { host: 'db.example.com', port: 5432 } },
89
- localOverrides: { db: { port: 9999 } },
90
- profile: 'production',
91
- profiles: {
92
- production: { db: { host: 'prod-db.example.com' } },
93
- },
94
- schema: nestedSchema,
95
- });
96
-
97
- expect(result.isOk()).toBe(true);
98
- const value = result.unwrap();
99
- expect(value.db.host).toBe('prod-db.example.com');
100
- expect(value.db.port).toBe(9999);
101
- });
102
- });
103
-
104
- describe('env var overrides', () => {
105
- test('overrides all other sources', () => {
106
- const schema = z.object({
107
- host: env(z.string(), 'APP_HOST').default('localhost'),
108
- port: env(z.number(), 'APP_PORT').default(3000),
109
- });
110
-
111
- const result = deriveConfig({
112
- base: { host: 'example.com', port: 8080 },
113
- env: { APP_HOST: 'env-host.example.com', APP_PORT: '9090' },
114
- schema,
115
- });
116
-
117
- expect(result.isOk()).toBe(true);
118
- const value = result.unwrap();
119
- expect(value.host).toBe('env-host.example.com');
120
- expect(value.port).toBe(9090);
121
- });
122
-
123
- test('coerces string to number', () => {
124
- const schema = z.object({
125
- port: env(z.number(), 'PORT').default(3000),
126
- });
127
-
128
- const result = deriveConfig({
129
- env: { PORT: '8080' },
130
- schema,
131
- });
132
-
133
- expect(result.isOk()).toBe(true);
134
- expect(result.unwrap().port).toBe(8080);
135
- });
136
-
137
- test('rejects non-numeric string with Zod error instead of NaN', () => {
138
- const schema = z.object({
139
- port: env(z.number(), 'PORT').default(3000),
140
- });
141
-
142
- const result = deriveConfig({
143
- env: { PORT: 'abc' },
144
- schema,
145
- });
146
-
147
- expect(result.isErr()).toBe(true);
148
- });
149
-
150
- test('coerces string to boolean', () => {
151
- const schema = z.object({
152
- debug: env(z.boolean(), 'DEBUG').default(false),
153
- verbose: env(z.boolean(), 'VERBOSE').default(false),
154
- });
155
-
156
- const trueValues = deriveConfig({
157
- env: { DEBUG: 'true', VERBOSE: '1' },
158
- schema,
159
- });
160
- expect(trueValues.isOk()).toBe(true);
161
- expect(trueValues.unwrap().debug).toBe(true);
162
- expect(trueValues.unwrap().verbose).toBe(true);
163
-
164
- const falseValues = deriveConfig({
165
- env: { DEBUG: 'false', VERBOSE: '0' },
166
- schema,
167
- });
168
- expect(falseValues.isOk()).toBe(true);
169
- expect(falseValues.unwrap().debug).toBe(false);
170
- expect(falseValues.unwrap().verbose).toBe(false);
171
- });
172
- });
173
-
174
- describe('validation', () => {
175
- test('missing required field returns Result.err', () => {
176
- const schema = z.object({
177
- required: z.string(),
178
- });
179
-
180
- const result = deriveConfig({ schema });
181
-
182
- expect(result.isErr()).toBe(true);
183
- });
184
- });
185
-
186
- describe('mutation safety', () => {
187
- test('repeated resolve() calls do not mutate the original base', () => {
188
- const schema = z.object({
189
- host: env(z.string(), 'APP_HOST').default('localhost'),
190
- });
191
- const base = { host: 'dev-host' };
192
-
193
- const first = deriveConfig({
194
- base,
195
- env: { APP_HOST: 'env-host' },
196
- schema,
197
- });
198
- expect(first.isOk()).toBe(true);
199
- expect(first.unwrap().host).toBe('env-host');
200
-
201
- const second = deriveConfig({ base, schema });
202
- expect(second.isOk()).toBe(true);
203
- expect(second.unwrap().host).toBe('dev-host');
204
- expect(base.host).toBe('dev-host');
205
- });
206
- });
207
-
208
- describe('full stack', () => {
209
- test('all 5 sources compose correctly', () => {
210
- const schema = z.object({
211
- apiUrl: env(z.string(), 'API_URL').default('http://localhost'),
212
- debug: env(z.boolean(), 'DEBUG').default(false),
213
- local: z.string().default('default-local'),
214
- name: z.string().default('app'),
215
- port: z.number().default(3000),
216
- });
217
-
218
- const result = deriveConfig({
219
- // base overrides name
220
- base: { name: 'my-app', port: 8080 },
221
- // env overrides debug and apiUrl
222
- env: { API_URL: 'https://api.prod.com', DEBUG: 'true' },
223
- // local overrides local
224
- localOverrides: { local: 'my-local-value' },
225
- // profile overrides port
226
- profile: 'production',
227
- profiles: { production: { port: 443 } },
228
- schema,
229
- });
230
-
231
- expect(result.isOk()).toBe(true);
232
- const value = result.unwrap();
233
- // Schema default
234
- // (nothing left at just default — name was overridden by base)
235
- // Base
236
- expect(value.name).toBe('my-app');
237
- // Profile overrides base port
238
- expect(value.port).toBe(443);
239
- // Local overrides
240
- expect(value.local).toBe('my-local-value');
241
- // Env overrides
242
- expect(value.apiUrl).toBe('https://api.prod.com');
243
- expect(value.debug).toBe(true);
244
- });
245
- });
246
- });
@@ -1,64 +0,0 @@
1
- import { afterEach, beforeEach, describe, expect, test } from 'bun:test';
2
- import { mkdtemp, readdir, readFile, rm } from 'node:fs/promises';
3
- import { join } from 'node:path';
4
- import { tmpdir } from 'node:os';
5
-
6
- import { ensureWorkspace } from '../workspace.js';
7
-
8
- describe('ensureWorkspace', () => {
9
- let root: string;
10
-
11
- beforeEach(async () => {
12
- root = await mkdtemp(join(tmpdir(), 'trails-ws-'));
13
- });
14
-
15
- afterEach(async () => {
16
- await rm(root, { force: true, recursive: true });
17
- });
18
-
19
- describe('directory creation', () => {
20
- test('creates .trails/ directory', async () => {
21
- await ensureWorkspace(root);
22
- const entries = await readdir(join(root, '.trails'));
23
- expect(entries).toContain('config');
24
- expect(entries).toContain('dev');
25
- expect(entries).toContain('generated');
26
- });
27
-
28
- test('creates all expected subdirectories', async () => {
29
- await ensureWorkspace(root);
30
- const config = await readdir(join(root, '.trails', 'config'));
31
- expect(config).toBeDefined();
32
- const dev = await readdir(join(root, '.trails', 'dev'));
33
- expect(dev).toBeDefined();
34
- const generated = await readdir(join(root, '.trails', 'generated'));
35
- expect(generated).toBeDefined();
36
- });
37
- });
38
-
39
- describe('.gitignore', () => {
40
- test('writes .gitignore on first run', async () => {
41
- await ensureWorkspace(root);
42
- const content = await readFile(
43
- join(root, '.trails', '.gitignore'),
44
- 'utf8'
45
- );
46
- expect(content).toContain('config/');
47
- expect(content).toContain('dev/');
48
- expect(content).toContain('generated/');
49
- });
50
-
51
- test('does not overwrite existing .gitignore', async () => {
52
- await ensureWorkspace(root);
53
- const customContent = '# custom\n*\n';
54
- await Bun.write(join(root, '.trails', '.gitignore'), customContent);
55
-
56
- await ensureWorkspace(root);
57
- const content = await readFile(
58
- join(root, '.trails', '.gitignore'),
59
- 'utf8'
60
- );
61
- expect(content).toBe(customContent);
62
- });
63
- });
64
- });
package/src/workspace.ts DELETED
@@ -1,56 +0,0 @@
1
- /**
2
- * Ensure the `.trails/` workspace directory exists with proper structure.
3
- *
4
- * Auto-creates on first framework operation. The workspace holds local
5
- * config overrides, development state, and generated artifacts that
6
- * should not be committed to source control.
7
- */
8
- import { mkdir } from 'node:fs/promises';
9
- import { join } from 'node:path';
10
-
11
- const WORKSPACE_DIRS = ['config', 'dev', 'generated'] as const;
12
-
13
- const GITIGNORE_CONTENT = [
14
- '# Local config overrides',
15
- 'config/',
16
- '',
17
- '# Development state',
18
- 'dev/',
19
- '',
20
- '# Generated artifacts',
21
- 'generated/',
22
- '',
23
- '# Shared Trails database',
24
- 'trails.db',
25
- 'trails.db-shm',
26
- 'trails.db-wal',
27
- '',
28
- ].join('\n');
29
-
30
- /**
31
- * Write `.gitignore` inside the workspace directory if it does not already exist.
32
- */
33
- const writeGitignoreIfMissing = async (trailsDir: string): Promise<void> => {
34
- const gitignorePath = join(trailsDir, '.gitignore');
35
- const file = Bun.file(gitignorePath);
36
- if (!(await file.exists())) {
37
- await Bun.write(gitignorePath, GITIGNORE_CONTENT);
38
- }
39
- };
40
-
41
- /**
42
- * Ensure the `.trails/` workspace directory exists with proper structure.
43
- *
44
- * Creates `config/`, `dev/`, and `generated/` subdirectories plus a
45
- * `.gitignore` that excludes local-only files. Safe to call repeatedly —
46
- * existing files are never overwritten.
47
- */
48
- export const ensureWorkspace = async (root: string): Promise<void> => {
49
- const trailsDir = join(root, '.trails');
50
-
51
- await Promise.all(
52
- WORKSPACE_DIRS.map((d) => mkdir(join(trailsDir, d), { recursive: true }))
53
- );
54
-
55
- await writeGitignoreIfMissing(trailsDir);
56
- };
package/tsconfig.json DELETED
@@ -1,9 +0,0 @@
1
- {
2
- "extends": "../../tsconfig.json",
3
- "compilerOptions": {
4
- "outDir": "dist",
5
- "rootDir": "src"
6
- },
7
- "include": ["src"],
8
- "exclude": ["**/__tests__/**", "**/*.test.ts", "dist"]
9
- }
@@ -1,10 +0,0 @@
1
- {
2
- "extends": "./tsconfig.json",
3
- "compilerOptions": {
4
- "noEmit": true,
5
- "rootDir": "./src",
6
- "types": ["bun"]
7
- },
8
- "include": ["src/**/*.test.ts", "src/__tests__/**/*.ts"],
9
- "exclude": []
10
- }
@@ -1 +0,0 @@
1
- {"root":["./src/app-config.ts","./src/collect.ts","./src/compose.ts","./src/config-resource.ts","./src/define-config.ts","./src/derive-fields.ts","./src/derive-provenance.ts","./src/doctor.ts","./src/extensions.ts","./src/index.ts","./src/merge.ts","./src/ref.ts","./src/registry.ts","./src/resolve.ts","./src/secret-heuristics.ts","./src/workspace.ts","./src/zod-utils.ts","./src/derive/env.ts","./src/derive/example.ts","./src/derive/helpers.ts","./src/derive/index.ts","./src/derive/json-schema.ts","./src/trails/config-check.ts","./src/trails/config-describe.ts","./src/trails/config-explain.ts","./src/trails/config-init.ts"],"version":"5.9.3"}