@ontrails/config 1.0.0-beta.12 → 1.0.0-beta.14
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/.turbo/turbo-lint.log +1 -1
- package/CHANGELOG.md +44 -5
- package/README.md +212 -0
- package/dist/compose.d.ts +15 -11
- package/dist/compose.d.ts.map +1 -1
- package/dist/compose.js +9 -7
- package/dist/compose.js.map +1 -1
- package/dist/config-gate.d.ts +11 -0
- package/dist/config-gate.d.ts.map +1 -0
- package/dist/config-gate.js +6 -0
- package/dist/config-gate.js.map +1 -0
- package/dist/config-provision.d.ts +3 -0
- package/dist/config-provision.d.ts.map +1 -0
- package/dist/config-provision.js +26 -0
- package/dist/config-provision.js.map +1 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +1 -37
- package/dist/doctor.js.map +1 -1
- package/dist/explain.d.ts.map +1 -1
- package/dist/explain.js +5 -18
- package/dist/explain.js.map +1 -1
- package/dist/extensions.d.ts +1 -1
- package/dist/extensions.js +1 -1
- package/dist/generate/example.d.ts.map +1 -1
- package/dist/generate/example.js +20 -18
- package/dist/generate/example.js.map +1 -1
- package/dist/generate/helpers.js +1 -1
- package/dist/generate/helpers.js.map +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -3
- package/dist/index.js.map +1 -1
- package/dist/ref.d.ts +8 -3
- package/dist/ref.d.ts.map +1 -1
- package/dist/ref.js +8 -3
- package/dist/ref.js.map +1 -1
- package/dist/registry.d.ts +1 -1
- package/dist/resolve.d.ts.map +1 -1
- package/dist/resolve.js +4 -1
- package/dist/resolve.js.map +1 -1
- package/dist/trails/config-check.js +12 -12
- package/dist/trails/config-check.js.map +1 -1
- package/dist/trails/config-describe.js +8 -8
- package/dist/trails/config-describe.js.map +1 -1
- package/dist/trails/config-explain.js +12 -12
- package/dist/trails/config-explain.js.map +1 -1
- package/dist/trails/config-init.js +13 -13
- package/dist/trails/config-init.js.map +1 -1
- package/dist/workspace.d.ts.map +1 -1
- package/dist/workspace.js +5 -0
- package/dist/workspace.js.map +1 -1
- package/package.json +2 -2
- package/src/__tests__/compose.test.ts +15 -15
- package/src/__tests__/config-check.test.ts +15 -15
- package/src/__tests__/config-describe.test.ts +15 -15
- package/src/__tests__/config-explain.test.ts +15 -15
- package/src/__tests__/{config-layer.test.ts → config-gate.test.ts} +9 -9
- package/src/__tests__/config-init.test.ts +19 -19
- package/src/__tests__/{config-service.test.ts → config-provision.test.ts} +13 -13
- package/src/compose.ts +22 -16
- package/src/config-gate.ts +15 -0
- package/src/{config-service.ts → config-provision.ts} +6 -6
- package/src/explain.ts +6 -6
- package/src/extensions.ts +1 -1
- package/src/index.ts +8 -3
- package/src/registry.ts +1 -1
- package/src/trails/config-check.ts +12 -12
- package/src/trails/config-describe.ts +8 -8
- package/src/trails/config-explain.ts +12 -12
- package/src/trails/config-init.ts +15 -15
- package/src/workspace.ts +5 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/src/config-layer.ts +0 -15
|
@@ -2,57 +2,57 @@ import { describe, expect, test } from 'bun:test';
|
|
|
2
2
|
|
|
3
3
|
import { z } from 'zod';
|
|
4
4
|
|
|
5
|
-
import {
|
|
5
|
+
import { collectProvisionConfigs } from '../compose.js';
|
|
6
6
|
|
|
7
7
|
// ---------------------------------------------------------------------------
|
|
8
8
|
// Tests
|
|
9
9
|
// ---------------------------------------------------------------------------
|
|
10
10
|
|
|
11
|
-
describe('
|
|
12
|
-
test('extracts config schemas from
|
|
11
|
+
describe('collectProvisionConfigs', () => {
|
|
12
|
+
test('extracts config schemas from provisions that declare them', () => {
|
|
13
13
|
const dbSchema = z.object({ url: z.string().url() });
|
|
14
14
|
const cacheSchema = z.object({ ttl: z.number() });
|
|
15
15
|
|
|
16
|
-
const
|
|
16
|
+
const provisions = [
|
|
17
17
|
{ config: dbSchema, id: 'db.main' },
|
|
18
18
|
{ config: cacheSchema, id: 'cache.main' },
|
|
19
19
|
];
|
|
20
20
|
|
|
21
|
-
const entries =
|
|
21
|
+
const entries = collectProvisionConfigs(provisions);
|
|
22
22
|
|
|
23
23
|
expect(entries).toHaveLength(2);
|
|
24
|
-
expect(entries[0]).toEqual({
|
|
24
|
+
expect(entries[0]).toEqual({ provisionId: 'db.main', schema: dbSchema });
|
|
25
25
|
expect(entries[1]).toEqual({
|
|
26
|
+
provisionId: 'cache.main',
|
|
26
27
|
schema: cacheSchema,
|
|
27
|
-
serviceId: 'cache.main',
|
|
28
28
|
});
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
-
test('excludes
|
|
31
|
+
test('excludes provisions without config', () => {
|
|
32
32
|
const schema = z.object({ url: z.string() });
|
|
33
33
|
|
|
34
|
-
const
|
|
34
|
+
const provisions = [
|
|
35
35
|
{ config: schema, id: 'db.main' },
|
|
36
36
|
{ id: 'counter.main' },
|
|
37
37
|
{ config: undefined, id: 'logger.main' },
|
|
38
38
|
];
|
|
39
39
|
|
|
40
|
-
const entries =
|
|
40
|
+
const entries = collectProvisionConfigs(provisions);
|
|
41
41
|
|
|
42
42
|
expect(entries).toHaveLength(1);
|
|
43
|
-
expect(entries[0]?.
|
|
43
|
+
expect(entries[0]?.provisionId).toBe('db.main');
|
|
44
44
|
});
|
|
45
45
|
|
|
46
|
-
test('returns empty array when no
|
|
47
|
-
const
|
|
46
|
+
test('returns empty array when no provisions have config', () => {
|
|
47
|
+
const provisions = [{ id: 'counter.main' }, { id: 'logger.main' }];
|
|
48
48
|
|
|
49
|
-
const entries =
|
|
49
|
+
const entries = collectProvisionConfigs(provisions);
|
|
50
50
|
|
|
51
51
|
expect(entries).toEqual([]);
|
|
52
52
|
});
|
|
53
53
|
|
|
54
54
|
test('returns empty array for empty input', () => {
|
|
55
|
-
const entries =
|
|
55
|
+
const entries = collectProvisionConfigs([]);
|
|
56
56
|
|
|
57
57
|
expect(entries).toEqual([]);
|
|
58
58
|
});
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, test } from 'bun:test';
|
|
2
|
-
import {
|
|
2
|
+
import { createProvisionLookup } from '@ontrails/core';
|
|
3
3
|
import type { TrailContext } from '@ontrails/core';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
|
|
@@ -7,22 +7,22 @@ import { configCheck } from '../trails/config-check.js';
|
|
|
7
7
|
import type { ConfigState } from '../registry.js';
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
|
-
* Build a TrailContext with
|
|
10
|
+
* Build a TrailContext with configProvision resolved in extensions.
|
|
11
11
|
*/
|
|
12
12
|
const buildCtx = (state: ConfigState): TrailContext => {
|
|
13
13
|
const extensions = { config: state };
|
|
14
14
|
const ctx: TrailContext = {
|
|
15
|
+
abortSignal: AbortSignal.timeout(5000),
|
|
15
16
|
cwd: '/tmp',
|
|
16
17
|
env: {},
|
|
17
18
|
extensions,
|
|
19
|
+
provision: undefined as unknown as TrailContext['provision'],
|
|
18
20
|
requestId: 'test',
|
|
19
|
-
service: undefined as unknown as TrailContext['service'],
|
|
20
|
-
signal: AbortSignal.timeout(5000),
|
|
21
21
|
workspaceRoot: '/tmp',
|
|
22
22
|
};
|
|
23
23
|
const withLookup = {
|
|
24
24
|
...ctx,
|
|
25
|
-
|
|
25
|
+
provision: createProvisionLookup(() => withLookup),
|
|
26
26
|
};
|
|
27
27
|
return withLookup;
|
|
28
28
|
};
|
|
@@ -41,17 +41,17 @@ describe('config.check trail', () => {
|
|
|
41
41
|
expect(configCheck.intent).toBe('read');
|
|
42
42
|
});
|
|
43
43
|
|
|
44
|
-
test('has infrastructure
|
|
45
|
-
expect(configCheck.
|
|
44
|
+
test('has infrastructure meta', () => {
|
|
45
|
+
expect(configCheck.meta).toEqual({ category: 'infrastructure' });
|
|
46
46
|
});
|
|
47
47
|
|
|
48
48
|
test('has output schema', () => {
|
|
49
49
|
expect(configCheck.output).toBeDefined();
|
|
50
50
|
});
|
|
51
51
|
|
|
52
|
-
test('declares
|
|
53
|
-
expect(configCheck.
|
|
54
|
-
expect(configCheck.
|
|
52
|
+
test('declares configProvision dependency', () => {
|
|
53
|
+
expect(configCheck.provisions).toBeDefined();
|
|
54
|
+
expect(configCheck.provisions?.length).toBe(1);
|
|
55
55
|
});
|
|
56
56
|
});
|
|
57
57
|
|
|
@@ -72,7 +72,7 @@ describe('config.check trail', () => {
|
|
|
72
72
|
schema,
|
|
73
73
|
};
|
|
74
74
|
const ctx = buildCtx(state);
|
|
75
|
-
const result = await configCheck.
|
|
75
|
+
const result = await configCheck.blaze({ values: {} }, ctx);
|
|
76
76
|
|
|
77
77
|
expect(result.isOk()).toBe(true);
|
|
78
78
|
const value = result.unwrap();
|
|
@@ -90,7 +90,7 @@ describe('config.check trail', () => {
|
|
|
90
90
|
schema,
|
|
91
91
|
};
|
|
92
92
|
const ctx = buildCtx(state);
|
|
93
|
-
const result = await configCheck.
|
|
93
|
+
const result = await configCheck.blaze({ values: {} }, ctx);
|
|
94
94
|
|
|
95
95
|
expect(result.isOk()).toBe(true);
|
|
96
96
|
const value = result.unwrap();
|
|
@@ -108,7 +108,7 @@ describe('config.check trail', () => {
|
|
|
108
108
|
schema,
|
|
109
109
|
};
|
|
110
110
|
const ctx = buildCtx(state);
|
|
111
|
-
const result = await configCheck.
|
|
111
|
+
const result = await configCheck.blaze({ values: { port: 8080 } }, ctx);
|
|
112
112
|
|
|
113
113
|
expect(result.isOk()).toBe(true);
|
|
114
114
|
const value = result.unwrap();
|
|
@@ -129,7 +129,7 @@ describe('config.check trail', () => {
|
|
|
129
129
|
schema,
|
|
130
130
|
};
|
|
131
131
|
const ctx = buildCtx(state);
|
|
132
|
-
const result = await configCheck.
|
|
132
|
+
const result = await configCheck.blaze(
|
|
133
133
|
{ values: { db: { port: 6543 } } },
|
|
134
134
|
ctx
|
|
135
135
|
);
|
|
@@ -159,7 +159,7 @@ describe('config.check trail', () => {
|
|
|
159
159
|
schema,
|
|
160
160
|
};
|
|
161
161
|
const ctx = buildCtx(state);
|
|
162
|
-
const result = await configCheck.
|
|
162
|
+
const result = await configCheck.blaze({ values: {} }, ctx);
|
|
163
163
|
|
|
164
164
|
expect(result.isOk()).toBe(true);
|
|
165
165
|
const defaults = result
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, test } from 'bun:test';
|
|
2
|
-
import {
|
|
2
|
+
import { createProvisionLookup } from '@ontrails/core';
|
|
3
3
|
import type { TrailContext } from '@ontrails/core';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
|
|
@@ -8,22 +8,22 @@ import { env, secret } from '../extensions.js';
|
|
|
8
8
|
import type { ConfigState } from '../registry.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* Build a TrailContext with
|
|
11
|
+
* Build a TrailContext with configProvision resolved in extensions.
|
|
12
12
|
*/
|
|
13
13
|
const buildCtx = (state: ConfigState): TrailContext => {
|
|
14
14
|
const extensions = { config: state };
|
|
15
15
|
const ctx: TrailContext = {
|
|
16
|
+
abortSignal: AbortSignal.timeout(5000),
|
|
16
17
|
cwd: '/tmp',
|
|
17
18
|
env: {},
|
|
18
19
|
extensions,
|
|
20
|
+
provision: undefined as unknown as TrailContext['provision'],
|
|
19
21
|
requestId: 'test',
|
|
20
|
-
service: undefined as unknown as TrailContext['service'],
|
|
21
|
-
signal: AbortSignal.timeout(5000),
|
|
22
22
|
workspaceRoot: '/tmp',
|
|
23
23
|
};
|
|
24
24
|
const withLookup = {
|
|
25
25
|
...ctx,
|
|
26
|
-
|
|
26
|
+
provision: createProvisionLookup(() => withLookup),
|
|
27
27
|
};
|
|
28
28
|
return withLookup;
|
|
29
29
|
};
|
|
@@ -42,17 +42,17 @@ describe('config.describe trail', () => {
|
|
|
42
42
|
expect(configDescribe.intent).toBe('read');
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
-
test('has infrastructure
|
|
46
|
-
expect(configDescribe.
|
|
45
|
+
test('has infrastructure meta', () => {
|
|
46
|
+
expect(configDescribe.meta).toEqual({ category: 'infrastructure' });
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
test('has output schema', () => {
|
|
50
50
|
expect(configDescribe.output).toBeDefined();
|
|
51
51
|
});
|
|
52
52
|
|
|
53
|
-
test('declares
|
|
54
|
-
expect(configDescribe.
|
|
55
|
-
expect(configDescribe.
|
|
53
|
+
test('declares configProvision dependency', () => {
|
|
54
|
+
expect(configDescribe.provisions).toBeDefined();
|
|
55
|
+
expect(configDescribe.provisions?.length).toBe(1);
|
|
56
56
|
});
|
|
57
57
|
});
|
|
58
58
|
|
|
@@ -73,7 +73,7 @@ describe('config.describe trail', () => {
|
|
|
73
73
|
schema,
|
|
74
74
|
};
|
|
75
75
|
const ctx = buildCtx(state);
|
|
76
|
-
const result = await configDescribe.
|
|
76
|
+
const result = await configDescribe.blaze({}, ctx);
|
|
77
77
|
|
|
78
78
|
expect(result.isOk()).toBe(true);
|
|
79
79
|
expect(result.unwrap().fields.length).toBe(2);
|
|
@@ -89,7 +89,7 @@ describe('config.describe trail', () => {
|
|
|
89
89
|
schema,
|
|
90
90
|
};
|
|
91
91
|
const ctx = buildCtx(state);
|
|
92
|
-
const result = await configDescribe.
|
|
92
|
+
const result = await configDescribe.blaze({}, ctx);
|
|
93
93
|
const { fields } = result.unwrap();
|
|
94
94
|
|
|
95
95
|
expect(fields[0]?.path).toBe('host');
|
|
@@ -107,7 +107,7 @@ describe('config.describe trail', () => {
|
|
|
107
107
|
schema,
|
|
108
108
|
};
|
|
109
109
|
const ctx = buildCtx(state);
|
|
110
|
-
const result = await configDescribe.
|
|
110
|
+
const result = await configDescribe.blaze({}, ctx);
|
|
111
111
|
|
|
112
112
|
expect(result.isOk()).toBe(true);
|
|
113
113
|
const [field] = result.unwrap().fields;
|
|
@@ -123,7 +123,7 @@ describe('config.describe trail', () => {
|
|
|
123
123
|
schema,
|
|
124
124
|
};
|
|
125
125
|
const ctx = buildCtx(state);
|
|
126
|
-
const result = await configDescribe.
|
|
126
|
+
const result = await configDescribe.blaze({}, ctx);
|
|
127
127
|
|
|
128
128
|
expect(result.isOk()).toBe(true);
|
|
129
129
|
const [field] = result.unwrap().fields;
|
|
@@ -141,7 +141,7 @@ describe('config.describe trail', () => {
|
|
|
141
141
|
schema,
|
|
142
142
|
};
|
|
143
143
|
const ctx = buildCtx(state);
|
|
144
|
-
const result = await configDescribe.
|
|
144
|
+
const result = await configDescribe.blaze({}, ctx);
|
|
145
145
|
|
|
146
146
|
expect(result.isOk()).toBe(true);
|
|
147
147
|
const { fields } = result.unwrap();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { describe, expect, test } from 'bun:test';
|
|
2
|
-
import {
|
|
2
|
+
import { createProvisionLookup } from '@ontrails/core';
|
|
3
3
|
import type { TrailContext } from '@ontrails/core';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
|
|
@@ -8,22 +8,22 @@ import { env } from '../extensions.js';
|
|
|
8
8
|
import type { ConfigState } from '../registry.js';
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
|
-
* Build a TrailContext with
|
|
11
|
+
* Build a TrailContext with configProvision resolved in extensions.
|
|
12
12
|
*/
|
|
13
13
|
const buildCtx = (state: ConfigState): TrailContext => {
|
|
14
14
|
const extensions = { config: state };
|
|
15
15
|
const ctx: TrailContext = {
|
|
16
|
+
abortSignal: AbortSignal.timeout(5000),
|
|
16
17
|
cwd: '/tmp',
|
|
17
18
|
env: {},
|
|
18
19
|
extensions,
|
|
20
|
+
provision: undefined as unknown as TrailContext['provision'],
|
|
19
21
|
requestId: 'test',
|
|
20
|
-
service: undefined as unknown as TrailContext['service'],
|
|
21
|
-
signal: AbortSignal.timeout(5000),
|
|
22
22
|
workspaceRoot: '/tmp',
|
|
23
23
|
};
|
|
24
24
|
const withLookup = {
|
|
25
25
|
...ctx,
|
|
26
|
-
|
|
26
|
+
provision: createProvisionLookup(() => withLookup),
|
|
27
27
|
};
|
|
28
28
|
return withLookup;
|
|
29
29
|
};
|
|
@@ -42,17 +42,17 @@ describe('config.explain trail', () => {
|
|
|
42
42
|
expect(configExplain.intent).toBe('read');
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
-
test('has infrastructure
|
|
46
|
-
expect(configExplain.
|
|
45
|
+
test('has infrastructure meta', () => {
|
|
46
|
+
expect(configExplain.meta).toEqual({ category: 'infrastructure' });
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
test('has output schema', () => {
|
|
50
50
|
expect(configExplain.output).toBeDefined();
|
|
51
51
|
});
|
|
52
52
|
|
|
53
|
-
test('declares
|
|
54
|
-
expect(configExplain.
|
|
55
|
-
expect(configExplain.
|
|
53
|
+
test('declares configProvision dependency', () => {
|
|
54
|
+
expect(configExplain.provisions).toBeDefined();
|
|
55
|
+
expect(configExplain.provisions?.length).toBe(1);
|
|
56
56
|
});
|
|
57
57
|
});
|
|
58
58
|
|
|
@@ -73,7 +73,7 @@ describe('config.explain trail', () => {
|
|
|
73
73
|
schema,
|
|
74
74
|
};
|
|
75
75
|
const ctx = buildCtx(state);
|
|
76
|
-
const result = await configExplain.
|
|
76
|
+
const result = await configExplain.blaze({ path: '' }, ctx);
|
|
77
77
|
|
|
78
78
|
expect(result.isOk()).toBe(true);
|
|
79
79
|
const value = result.unwrap();
|
|
@@ -96,7 +96,7 @@ describe('config.explain trail', () => {
|
|
|
96
96
|
schema,
|
|
97
97
|
};
|
|
98
98
|
const ctx = buildCtx(state);
|
|
99
|
-
const result = await configExplain.
|
|
99
|
+
const result = await configExplain.blaze({ path: 'db' }, ctx);
|
|
100
100
|
|
|
101
101
|
expect(result.isOk()).toBe(true);
|
|
102
102
|
const value = result.unwrap();
|
|
@@ -121,7 +121,7 @@ describe('config.explain trail', () => {
|
|
|
121
121
|
schema,
|
|
122
122
|
};
|
|
123
123
|
const ctx = buildCtx(state);
|
|
124
|
-
const result = await configExplain.
|
|
124
|
+
const result = await configExplain.blaze({ path: 'db' }, ctx);
|
|
125
125
|
|
|
126
126
|
expect(result.isOk()).toBe(true);
|
|
127
127
|
expect(result.unwrap().entries).toEqual([
|
|
@@ -139,7 +139,7 @@ describe('config.explain trail', () => {
|
|
|
139
139
|
schema,
|
|
140
140
|
};
|
|
141
141
|
const ctx = buildCtx(state);
|
|
142
|
-
const result = await configExplain.
|
|
142
|
+
const result = await configExplain.blaze({ path: '' }, ctx);
|
|
143
143
|
|
|
144
144
|
expect(result.isOk()).toBe(true);
|
|
145
145
|
const [entry] = result.unwrap().entries;
|
|
@@ -157,7 +157,7 @@ describe('config.explain trail', () => {
|
|
|
157
157
|
schema,
|
|
158
158
|
};
|
|
159
159
|
const ctx = buildCtx(state);
|
|
160
|
-
const result = await configExplain.
|
|
160
|
+
const result = await configExplain.blaze({ path: '' }, ctx);
|
|
161
161
|
|
|
162
162
|
expect(result.isOk()).toBe(true);
|
|
163
163
|
const [entry] = result.unwrap().entries;
|
|
@@ -3,33 +3,33 @@ import { Result } from '@ontrails/core';
|
|
|
3
3
|
import type { TrailContext } from '@ontrails/core';
|
|
4
4
|
import { z } from 'zod';
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { configGate } from '../config-gate.js';
|
|
7
7
|
|
|
8
8
|
const stubTrail = {
|
|
9
|
+
blaze: (_input: unknown, _ctx: TrailContext) => Result.ok({}),
|
|
10
|
+
crosses: [],
|
|
9
11
|
description: undefined,
|
|
10
12
|
detours: undefined,
|
|
11
13
|
examples: undefined,
|
|
12
14
|
fields: undefined,
|
|
13
|
-
follow: [],
|
|
14
15
|
id: 'test.stub',
|
|
15
16
|
idempotent: undefined,
|
|
16
17
|
input: z.object({}),
|
|
17
18
|
intent: 'read' as const,
|
|
18
19
|
kind: 'trail' as const,
|
|
19
|
-
|
|
20
|
+
meta: undefined,
|
|
20
21
|
output: undefined,
|
|
21
|
-
|
|
22
|
-
services: [],
|
|
22
|
+
provisions: [],
|
|
23
23
|
};
|
|
24
24
|
|
|
25
|
-
describe('
|
|
25
|
+
describe('configGate', () => {
|
|
26
26
|
describe('identity', () => {
|
|
27
27
|
test('has name "config"', () => {
|
|
28
|
-
expect(
|
|
28
|
+
expect(configGate.name).toBe('config');
|
|
29
29
|
});
|
|
30
30
|
|
|
31
31
|
test('has a description', () => {
|
|
32
|
-
expect(
|
|
32
|
+
expect(configGate.description).toBeDefined();
|
|
33
33
|
});
|
|
34
34
|
});
|
|
35
35
|
|
|
@@ -38,7 +38,7 @@ describe('configLayer', () => {
|
|
|
38
38
|
const impl = (_input: unknown, _ctx: TrailContext) =>
|
|
39
39
|
Result.ok({ called: true });
|
|
40
40
|
|
|
41
|
-
const wrapped =
|
|
41
|
+
const wrapped = configGate.wrap(stubTrail, impl);
|
|
42
42
|
const ctx = {
|
|
43
43
|
cwd: '/tmp',
|
|
44
44
|
env: {},
|
|
@@ -2,7 +2,7 @@ import { afterEach, beforeEach, describe, expect, test } from 'bun:test';
|
|
|
2
2
|
import { mkdtemp, readFile, rm } from 'node:fs/promises';
|
|
3
3
|
import { tmpdir } from 'node:os';
|
|
4
4
|
import { join } from 'node:path';
|
|
5
|
-
import {
|
|
5
|
+
import { createProvisionLookup } from '@ontrails/core';
|
|
6
6
|
import type { TrailContext } from '@ontrails/core';
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
|
|
@@ -11,22 +11,22 @@ import type { ConfigState } from '../registry.js';
|
|
|
11
11
|
import { configInit } from '../trails/config-init.js';
|
|
12
12
|
|
|
13
13
|
/**
|
|
14
|
-
* Build a TrailContext with
|
|
14
|
+
* Build a TrailContext with configProvision resolved in extensions.
|
|
15
15
|
*/
|
|
16
16
|
const buildCtx = (state: ConfigState): TrailContext => {
|
|
17
17
|
const extensions = { config: state };
|
|
18
18
|
const ctx: TrailContext = {
|
|
19
|
+
abortSignal: AbortSignal.timeout(5000),
|
|
19
20
|
cwd: '/tmp',
|
|
20
21
|
env: {},
|
|
21
22
|
extensions,
|
|
23
|
+
provision: undefined as unknown as TrailContext['provision'],
|
|
22
24
|
requestId: 'test',
|
|
23
|
-
service: undefined as unknown as TrailContext['service'],
|
|
24
|
-
signal: AbortSignal.timeout(5000),
|
|
25
25
|
workspaceRoot: '/tmp',
|
|
26
26
|
};
|
|
27
27
|
const withLookup = {
|
|
28
28
|
...ctx,
|
|
29
|
-
|
|
29
|
+
provision: createProvisionLookup(() => withLookup),
|
|
30
30
|
};
|
|
31
31
|
return withLookup;
|
|
32
32
|
};
|
|
@@ -55,17 +55,17 @@ describe('config.init trail', () => {
|
|
|
55
55
|
expect(configInit.intent).toBe('write');
|
|
56
56
|
});
|
|
57
57
|
|
|
58
|
-
test('has infrastructure
|
|
59
|
-
expect(configInit.
|
|
58
|
+
test('has infrastructure meta', () => {
|
|
59
|
+
expect(configInit.meta).toEqual({ category: 'infrastructure' });
|
|
60
60
|
});
|
|
61
61
|
|
|
62
62
|
test('has output schema', () => {
|
|
63
63
|
expect(configInit.output).toBeDefined();
|
|
64
64
|
});
|
|
65
65
|
|
|
66
|
-
test('declares
|
|
67
|
-
expect(configInit.
|
|
68
|
-
expect(configInit.
|
|
66
|
+
test('declares configProvision dependency', () => {
|
|
67
|
+
expect(configInit.provisions).toBeDefined();
|
|
68
|
+
expect(configInit.provisions?.length).toBe(1);
|
|
69
69
|
});
|
|
70
70
|
});
|
|
71
71
|
|
|
@@ -78,7 +78,7 @@ describe('config.init trail', () => {
|
|
|
78
78
|
describe('wired behavior', () => {
|
|
79
79
|
test('generates TOML output by default', async () => {
|
|
80
80
|
const ctx = buildCtx(testState);
|
|
81
|
-
const result = await configInit.
|
|
81
|
+
const result = await configInit.blaze({ format: 'toml' }, ctx);
|
|
82
82
|
|
|
83
83
|
expect(result.isOk()).toBe(true);
|
|
84
84
|
const value = result.unwrap();
|
|
@@ -90,7 +90,7 @@ describe('config.init trail', () => {
|
|
|
90
90
|
|
|
91
91
|
test('generates JSON output when requested', async () => {
|
|
92
92
|
const ctx = buildCtx(testState);
|
|
93
|
-
const result = await configInit.
|
|
93
|
+
const result = await configInit.blaze({ format: 'json' }, ctx);
|
|
94
94
|
|
|
95
95
|
expect(result.isOk()).toBe(true);
|
|
96
96
|
const value = result.unwrap();
|
|
@@ -101,7 +101,7 @@ describe('config.init trail', () => {
|
|
|
101
101
|
|
|
102
102
|
test('generates YAML output when requested', async () => {
|
|
103
103
|
const ctx = buildCtx(testState);
|
|
104
|
-
const result = await configInit.
|
|
104
|
+
const result = await configInit.blaze({ format: 'yaml' }, ctx);
|
|
105
105
|
|
|
106
106
|
expect(result.isOk()).toBe(true);
|
|
107
107
|
const value = result.unwrap();
|
|
@@ -111,7 +111,7 @@ describe('config.init trail', () => {
|
|
|
111
111
|
|
|
112
112
|
test('generates JSONC output when requested', async () => {
|
|
113
113
|
const ctx = buildCtx(testState);
|
|
114
|
-
const result = await configInit.
|
|
114
|
+
const result = await configInit.blaze({ format: 'jsonc' }, ctx);
|
|
115
115
|
|
|
116
116
|
expect(result.isOk()).toBe(true);
|
|
117
117
|
const value = result.unwrap();
|
|
@@ -121,7 +121,7 @@ describe('config.init trail', () => {
|
|
|
121
121
|
|
|
122
122
|
test('output content is non-empty for schema with fields', async () => {
|
|
123
123
|
const ctx = buildCtx(testState);
|
|
124
|
-
const result = await configInit.
|
|
124
|
+
const result = await configInit.blaze({ format: 'toml' }, ctx);
|
|
125
125
|
|
|
126
126
|
expect(result.isOk()).toBe(true);
|
|
127
127
|
expect(result.unwrap().content.trim().length).toBeGreaterThan(0);
|
|
@@ -129,7 +129,7 @@ describe('config.init trail', () => {
|
|
|
129
129
|
|
|
130
130
|
test('returns content without writtenFiles when dir is not provided', async () => {
|
|
131
131
|
const ctx = buildCtx(testState);
|
|
132
|
-
const result = await configInit.
|
|
132
|
+
const result = await configInit.blaze({ format: 'toml' }, ctx);
|
|
133
133
|
|
|
134
134
|
expect(result.isOk()).toBe(true);
|
|
135
135
|
expect(result.unwrap().writtenFiles).toBeUndefined();
|
|
@@ -159,7 +159,7 @@ describe('config.init trail', () => {
|
|
|
159
159
|
|
|
160
160
|
test('writes .schema.json when dir is provided', async () => {
|
|
161
161
|
const ctx = buildCtx(envState);
|
|
162
|
-
const result = await configInit.
|
|
162
|
+
const result = await configInit.blaze(
|
|
163
163
|
{ dir: tempDir, format: 'toml' },
|
|
164
164
|
ctx
|
|
165
165
|
);
|
|
@@ -181,7 +181,7 @@ describe('config.init trail', () => {
|
|
|
181
181
|
|
|
182
182
|
test('writes .env.example when schema has env bindings', async () => {
|
|
183
183
|
const ctx = buildCtx(envState);
|
|
184
|
-
const result = await configInit.
|
|
184
|
+
const result = await configInit.blaze(
|
|
185
185
|
{ dir: tempDir, format: 'toml' },
|
|
186
186
|
ctx
|
|
187
187
|
);
|
|
@@ -196,7 +196,7 @@ describe('config.init trail', () => {
|
|
|
196
196
|
|
|
197
197
|
test('still returns content alongside written files', async () => {
|
|
198
198
|
const ctx = buildCtx(envState);
|
|
199
|
-
const result = await configInit.
|
|
199
|
+
const result = await configInit.blaze(
|
|
200
200
|
{ dir: tempDir, format: 'json' },
|
|
201
201
|
ctx
|
|
202
202
|
);
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { afterEach, describe, expect, test } from 'bun:test';
|
|
2
2
|
import { z } from 'zod';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { configProvision } from '../config-provision.js';
|
|
5
5
|
import type { ConfigState } from '../registry.js';
|
|
6
6
|
import { clearConfigState, registerConfigState } from '../registry.js';
|
|
7
7
|
|
|
8
|
-
/** Stub
|
|
8
|
+
/** Stub ProvisionContext for create calls. */
|
|
9
9
|
const stubSvcCtx = {
|
|
10
10
|
config: undefined,
|
|
11
11
|
cwd: '/tmp',
|
|
@@ -13,32 +13,32 @@ const stubSvcCtx = {
|
|
|
13
13
|
workspaceRoot: '/tmp',
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
describe('
|
|
16
|
+
describe('configProvision', () => {
|
|
17
17
|
afterEach(() => {
|
|
18
18
|
clearConfigState();
|
|
19
19
|
});
|
|
20
20
|
|
|
21
21
|
describe('identity', () => {
|
|
22
22
|
test('has id "config"', () => {
|
|
23
|
-
expect(
|
|
23
|
+
expect(configProvision.id).toBe('config');
|
|
24
24
|
});
|
|
25
25
|
|
|
26
|
-
test('has kind "
|
|
27
|
-
expect(
|
|
26
|
+
test('has kind "provision"', () => {
|
|
27
|
+
expect(configProvision.kind).toBe('provision');
|
|
28
28
|
});
|
|
29
29
|
|
|
30
|
-
test('has infrastructure
|
|
31
|
-
expect(
|
|
30
|
+
test('has infrastructure meta', () => {
|
|
31
|
+
expect(configProvision.meta).toEqual({ category: 'infrastructure' });
|
|
32
32
|
});
|
|
33
33
|
|
|
34
34
|
test('has description', () => {
|
|
35
|
-
expect(
|
|
35
|
+
expect(configProvision.description).toBeDefined();
|
|
36
36
|
});
|
|
37
37
|
});
|
|
38
38
|
|
|
39
39
|
describe('mock', () => {
|
|
40
40
|
test('returns a ConfigState with empty schema and resolved', () => {
|
|
41
|
-
const value =
|
|
41
|
+
const value = configProvision.mock?.() as ConfigState;
|
|
42
42
|
expect(value).toBeDefined();
|
|
43
43
|
expect(value.resolved).toEqual({});
|
|
44
44
|
expect(value.schema).toBeDefined();
|
|
@@ -51,7 +51,7 @@ describe('configService', () => {
|
|
|
51
51
|
const state: ConfigState = { resolved: { port: 3000 }, schema };
|
|
52
52
|
registerConfigState(state);
|
|
53
53
|
|
|
54
|
-
const result = await
|
|
54
|
+
const result = await configProvision.create(stubSvcCtx);
|
|
55
55
|
|
|
56
56
|
expect(result.isOk()).toBe(true);
|
|
57
57
|
const value = result.unwrap() as ConfigState;
|
|
@@ -69,7 +69,7 @@ describe('configService', () => {
|
|
|
69
69
|
};
|
|
70
70
|
registerConfigState(state);
|
|
71
71
|
|
|
72
|
-
const result = await
|
|
72
|
+
const result = await configProvision.create(stubSvcCtx);
|
|
73
73
|
|
|
74
74
|
expect(result.isOk()).toBe(true);
|
|
75
75
|
const value = result.unwrap() as ConfigState;
|
|
@@ -78,7 +78,7 @@ describe('configService', () => {
|
|
|
78
78
|
});
|
|
79
79
|
|
|
80
80
|
test('returns Result.err when no state is registered', async () => {
|
|
81
|
-
const result = await
|
|
81
|
+
const result = await configProvision.create(stubSvcCtx);
|
|
82
82
|
|
|
83
83
|
expect(result.isErr()).toBe(true);
|
|
84
84
|
expect(result.error.message).toContain('Config state not registered');
|