@mettlecast/domain-cli 0.2.54 → 0.2.56
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/dist/commands/create-project.js +4 -4
- package/dist/commands/doctor.js +1 -1
- package/dist/commands/upgrade.js +1 -1
- package/dist/utils/header-inject.d.ts +1 -1
- package/dist/utils/header-inject.js +1 -1
- package/dist/utils/scaffold-config.d.ts +2 -2
- package/dist/utils/scaffold-config.js +1 -1
- package/package.json +1 -1
- package/src/__tests__/commands/add-module.test.ts +13 -13
- package/src/__tests__/commands/create-project.test.ts +19 -19
- package/src/__tests__/commands/why.test.ts +2 -2
- package/src/__tests__/doctor.test.ts +19 -19
- package/src/__tests__/scaffold-src/part-a-layout.test.ts +4 -4
- package/src/__tests__/smoke/scaffold.test.ts +6 -6
- package/src/__tests__/utils/header-inject.test.ts +6 -6
- package/src/commands/create-project.ts +4 -4
- package/src/commands/doctor.ts +1 -1
- package/src/commands/upgrade.ts +1 -1
- package/src/utils/header-inject.ts +1 -1
- package/src/utils/scaffold-config.ts +12 -5
|
@@ -46,8 +46,8 @@ function topoSort(modules, selected) {
|
|
|
46
46
|
}
|
|
47
47
|
result.push(mod);
|
|
48
48
|
}
|
|
49
|
-
// Always core first, then
|
|
50
|
-
const priorityOrder = ['core', '
|
|
49
|
+
// Always core first, then domain, then rest
|
|
50
|
+
const priorityOrder = ['core', 'domain'];
|
|
51
51
|
for (const id of priorityOrder) {
|
|
52
52
|
if (selected.has(id))
|
|
53
53
|
visit(id);
|
|
@@ -131,11 +131,11 @@ export async function runCreateProject(opts) {
|
|
|
131
131
|
console.log(`\nFetching modules for scaffold@${scaffoldVersion}...`);
|
|
132
132
|
const modulesJson = await fetchModulesJson(SCAFFOLD_BUCKET, scaffoldVersion);
|
|
133
133
|
// 4. Resolve module selection
|
|
134
|
-
const selectedIds = new Set(['core', '
|
|
134
|
+
const selectedIds = new Set(['core', 'domain']);
|
|
135
135
|
if (includeDatabase)
|
|
136
136
|
selectedIds.add('db-aurora');
|
|
137
137
|
if (includeAuth)
|
|
138
|
-
selectedIds.add('auth
|
|
138
|
+
selectedIds.add('auth');
|
|
139
139
|
if (includeFrontend)
|
|
140
140
|
selectedIds.add('frontend');
|
|
141
141
|
if (includeFlows)
|
package/dist/commands/doctor.js
CHANGED
|
@@ -1594,7 +1594,7 @@ async function runRelocate(projectRoot) {
|
|
|
1594
1594
|
const sha256 = manifestEntry?.sha256 ?? computeChecksumString(content);
|
|
1595
1595
|
upsertManifestFile(manifest, {
|
|
1596
1596
|
path: newPath,
|
|
1597
|
-
module: manifestEntry?.module ?? '
|
|
1597
|
+
module: manifestEntry?.module ?? 'domain',
|
|
1598
1598
|
moduleVersion: manifestEntry?.moduleVersion ?? '1.0.0',
|
|
1599
1599
|
sha256,
|
|
1600
1600
|
wasTemplate: manifestEntry?.wasTemplate ?? false,
|
package/dist/commands/upgrade.js
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* @param content The file content (post-token-substitution)
|
|
7
7
|
* @param filename The destination filename (used to determine type)
|
|
8
|
-
* @param moduleId The scaffold module id (e.g. '
|
|
8
|
+
* @param moduleId The scaffold module id (e.g. 'domain')
|
|
9
9
|
* @param version The scaffold module version (e.g. '1.0.0')
|
|
10
10
|
*/
|
|
11
11
|
export declare function injectHeader(content: string, filename: string, moduleId: string, version: string): string;
|
|
@@ -12,7 +12,7 @@ const JSON_SKIP_LIST = new Set([
|
|
|
12
12
|
*
|
|
13
13
|
* @param content The file content (post-token-substitution)
|
|
14
14
|
* @param filename The destination filename (used to determine type)
|
|
15
|
-
* @param moduleId The scaffold module id (e.g. '
|
|
15
|
+
* @param moduleId The scaffold module id (e.g. 'domain')
|
|
16
16
|
* @param version The scaffold module version (e.g. '1.0.0')
|
|
17
17
|
*/
|
|
18
18
|
export function injectHeader(content, filename, moduleId, version) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ModuleId = 'core' | '
|
|
1
|
+
export type ModuleId = 'core' | 'domain' | 'db-aurora' | 'auth' | 'frontend' | 'flows' | 'data-management' | 'tenants' | 'users' | 'shared' | 'data-storage' | 'monitoring' | 'orgs' | 'test-executor';
|
|
2
2
|
export type LogRetentionDays = 30 | 90 | 365 | 2557;
|
|
3
3
|
export interface SecurityOptions {
|
|
4
4
|
/** Enable CMK (KMS customer-managed keys) for DynamoDB, S3, SQS. ~$10–20/month */
|
|
@@ -65,7 +65,7 @@ export interface ScaffoldConfig {
|
|
|
65
65
|
projectName: string;
|
|
66
66
|
awsRegion: string;
|
|
67
67
|
awsAccountId: string;
|
|
68
|
-
/** Admin email collected at scaffold time (Cognito seed user). Present only when auth
|
|
68
|
+
/** Admin email collected at scaffold time (Cognito seed user). Present only when auth module is enabled. */
|
|
69
69
|
adminEmail?: string;
|
|
70
70
|
/** Domain IDs added via `tib add-domain` — NOT scaffold-owned, user-managed */
|
|
71
71
|
domainIds: string[];
|
|
@@ -2,7 +2,7 @@ import { readFile, writeFile } from 'fs/promises';
|
|
|
2
2
|
import path from 'path';
|
|
3
3
|
const DEFAULT_SCAFFOLD_CONFIG = {
|
|
4
4
|
scaffoldVersion: '0.0.0',
|
|
5
|
-
enabledModules: ['core', '
|
|
5
|
+
enabledModules: ['core', 'domain'],
|
|
6
6
|
projectName: 'unknown',
|
|
7
7
|
awsRegion: 'eu-north-1',
|
|
8
8
|
awsAccountId: '',
|
package/package.json
CHANGED
|
@@ -15,18 +15,18 @@ vi.mock('../../utils/s3-fetch.js', () => ({
|
|
|
15
15
|
sha256: 'abc123',
|
|
16
16
|
},
|
|
17
17
|
{
|
|
18
|
-
id: '
|
|
18
|
+
id: 'domain',
|
|
19
19
|
version: '1.0.0',
|
|
20
20
|
description: 'Backend Lambda support',
|
|
21
21
|
dependencies: ['core'],
|
|
22
|
-
tarball: '
|
|
22
|
+
tarball: 'domain-1.0.0.tar.gz',
|
|
23
23
|
sha256: 'def456',
|
|
24
24
|
},
|
|
25
25
|
{
|
|
26
26
|
id: 'db-aurora',
|
|
27
27
|
version: '1.0.0',
|
|
28
28
|
description: 'Aurora database support',
|
|
29
|
-
dependencies: ['
|
|
29
|
+
dependencies: ['domain'],
|
|
30
30
|
tarball: 'db-aurora-1.0.0.tar.gz',
|
|
31
31
|
sha256: 'ghi789',
|
|
32
32
|
},
|
|
@@ -34,7 +34,7 @@ vi.mock('../../utils/s3-fetch.js', () => ({
|
|
|
34
34
|
id: 'data-management',
|
|
35
35
|
version: '1.0.0',
|
|
36
36
|
description: 'Data management module',
|
|
37
|
-
dependencies: ['
|
|
37
|
+
dependencies: ['domain', 'db-aurora'],
|
|
38
38
|
tarball: 'data-management-1.0.0.tar.gz',
|
|
39
39
|
sha256: 'jkl012',
|
|
40
40
|
},
|
|
@@ -55,7 +55,7 @@ vi.mock('../../utils/s3-fetch.js', () => ({
|
|
|
55
55
|
vi.mock('../../utils/scaffold-config.js', () => ({
|
|
56
56
|
readScaffoldConfig: vi.fn().mockResolvedValue({
|
|
57
57
|
scaffoldVersion: '1.0.0',
|
|
58
|
-
enabledModules: ['core', '
|
|
58
|
+
enabledModules: ['core', 'domain'],
|
|
59
59
|
projectName: 'test-project',
|
|
60
60
|
awsRegion: 'eu-north-1',
|
|
61
61
|
awsAccountId: '123456789012',
|
|
@@ -70,7 +70,7 @@ vi.mock('../../utils/manifest.js', () => ({
|
|
|
70
70
|
readManifest: vi.fn().mockResolvedValue({
|
|
71
71
|
scaffoldVersion: '1.0.0',
|
|
72
72
|
files: [],
|
|
73
|
-
enabledModules: ['core', '
|
|
73
|
+
enabledModules: ['core', 'domain'],
|
|
74
74
|
projectName: 'test',
|
|
75
75
|
awsRegion: 'eu-north-1',
|
|
76
76
|
createdAt: '',
|
|
@@ -96,7 +96,7 @@ describe('add-module command', () => {
|
|
|
96
96
|
// Reset to default mock state
|
|
97
97
|
mockReadScaffoldConfig.mockResolvedValue({
|
|
98
98
|
scaffoldVersion: '1.0.0',
|
|
99
|
-
enabledModules: ['core', '
|
|
99
|
+
enabledModules: ['core', 'domain'],
|
|
100
100
|
projectName: 'test-project',
|
|
101
101
|
awsRegion: 'eu-north-1',
|
|
102
102
|
awsAccountId: '123456789012',
|
|
@@ -118,18 +118,18 @@ describe('add-module command', () => {
|
|
|
118
118
|
sha256: 'abc123',
|
|
119
119
|
},
|
|
120
120
|
{
|
|
121
|
-
id: '
|
|
121
|
+
id: 'domain',
|
|
122
122
|
version: '1.0.0',
|
|
123
123
|
description: 'Backend Lambda support',
|
|
124
124
|
dependencies: ['core'],
|
|
125
|
-
tarball: '
|
|
125
|
+
tarball: 'domain-1.0.0.tar.gz',
|
|
126
126
|
sha256: 'def456',
|
|
127
127
|
},
|
|
128
128
|
{
|
|
129
129
|
id: 'db-aurora',
|
|
130
130
|
version: '1.0.0',
|
|
131
131
|
description: 'Aurora database support',
|
|
132
|
-
dependencies: ['
|
|
132
|
+
dependencies: ['domain'],
|
|
133
133
|
tarball: 'db-aurora-1.0.0.tar.gz',
|
|
134
134
|
sha256: 'ghi789',
|
|
135
135
|
},
|
|
@@ -137,7 +137,7 @@ describe('add-module command', () => {
|
|
|
137
137
|
id: 'data-management',
|
|
138
138
|
version: '1.0.0',
|
|
139
139
|
description: 'Data management module',
|
|
140
|
-
dependencies: ['
|
|
140
|
+
dependencies: ['domain', 'db-aurora'],
|
|
141
141
|
tarball: 'data-management-1.0.0.tar.gz',
|
|
142
142
|
sha256: 'jkl012',
|
|
143
143
|
},
|
|
@@ -157,7 +157,7 @@ describe('add-module command', () => {
|
|
|
157
157
|
it('rejects already-installed module', async () => {
|
|
158
158
|
mockReadScaffoldConfig.mockResolvedValue({
|
|
159
159
|
scaffoldVersion: '1.0.0',
|
|
160
|
-
enabledModules: ['core', '
|
|
160
|
+
enabledModules: ['core', 'domain'],
|
|
161
161
|
projectName: 'test-project',
|
|
162
162
|
awsRegion: 'eu-north-1',
|
|
163
163
|
awsAccountId: '123456789012',
|
|
@@ -177,7 +177,7 @@ describe('add-module command', () => {
|
|
|
177
177
|
it('rejects missing dependency', async () => {
|
|
178
178
|
mockReadScaffoldConfig.mockResolvedValue({
|
|
179
179
|
scaffoldVersion: '1.0.0',
|
|
180
|
-
enabledModules: ['core', '
|
|
180
|
+
enabledModules: ['core', 'domain'],
|
|
181
181
|
projectName: 'test-project',
|
|
182
182
|
awsRegion: 'eu-north-1',
|
|
183
183
|
awsAccountId: '123456789012',
|
|
@@ -140,11 +140,11 @@ describe('runCreateProject', () => {
|
|
|
140
140
|
sha256: 'abc123',
|
|
141
141
|
},
|
|
142
142
|
{
|
|
143
|
-
id: '
|
|
143
|
+
id: 'domain',
|
|
144
144
|
version: '1.0.0',
|
|
145
145
|
description: 'Backend Lambda',
|
|
146
146
|
dependencies: ['core'],
|
|
147
|
-
tarball: '
|
|
147
|
+
tarball: 'domain.tar.gz',
|
|
148
148
|
sha256: 'def456',
|
|
149
149
|
},
|
|
150
150
|
],
|
|
@@ -241,19 +241,19 @@ describe('runCreateProject', () => {
|
|
|
241
241
|
sha256: 'abc123',
|
|
242
242
|
},
|
|
243
243
|
{
|
|
244
|
-
id: '
|
|
244
|
+
id: 'domain',
|
|
245
245
|
version: '1.0.0',
|
|
246
246
|
description: 'Backend Lambda',
|
|
247
247
|
dependencies: ['core'],
|
|
248
|
-
tarball: '
|
|
248
|
+
tarball: 'domain.tar.gz',
|
|
249
249
|
sha256: 'def456',
|
|
250
250
|
},
|
|
251
251
|
{
|
|
252
|
-
id: 'auth
|
|
252
|
+
id: 'auth',
|
|
253
253
|
version: '1.0.0',
|
|
254
254
|
description: 'Auth Cognito',
|
|
255
|
-
dependencies: ['core', '
|
|
256
|
-
tarball: 'auth
|
|
255
|
+
dependencies: ['core', 'domain'],
|
|
256
|
+
tarball: 'auth.tar.gz',
|
|
257
257
|
sha256: 'ghi789',
|
|
258
258
|
},
|
|
259
259
|
],
|
|
@@ -326,7 +326,7 @@ describe('runCreateProject', () => {
|
|
|
326
326
|
expect(authContent).not.toContain('@mettlecast/domain-runtime');
|
|
327
327
|
});
|
|
328
328
|
|
|
329
|
-
it('Core module files are written before
|
|
329
|
+
it('Core module files are written before domain files (topological order)', async () => {
|
|
330
330
|
const outputDir = join(tempDir, 'project3');
|
|
331
331
|
const writeCallOrder: string[] = [];
|
|
332
332
|
|
|
@@ -348,11 +348,11 @@ describe('runCreateProject', () => {
|
|
|
348
348
|
sha256: 'abc123',
|
|
349
349
|
},
|
|
350
350
|
{
|
|
351
|
-
id: '
|
|
351
|
+
id: 'domain',
|
|
352
352
|
version: '1.0.0',
|
|
353
353
|
description: 'Backend Lambda',
|
|
354
354
|
dependencies: ['core'],
|
|
355
|
-
tarball: '
|
|
355
|
+
tarball: 'domain.tar.gz',
|
|
356
356
|
sha256: 'def456',
|
|
357
357
|
},
|
|
358
358
|
],
|
|
@@ -447,11 +447,11 @@ describe('runCreateProject', () => {
|
|
|
447
447
|
sha256: 'abc123',
|
|
448
448
|
},
|
|
449
449
|
{
|
|
450
|
-
id: '
|
|
450
|
+
id: 'domain',
|
|
451
451
|
version: '1.0.0',
|
|
452
452
|
description: 'Backend Lambda',
|
|
453
453
|
dependencies: ['core'],
|
|
454
|
-
tarball: '
|
|
454
|
+
tarball: 'domain.tar.gz',
|
|
455
455
|
sha256: 'def456',
|
|
456
456
|
},
|
|
457
457
|
],
|
|
@@ -537,11 +537,11 @@ describe('runCreateProject', () => {
|
|
|
537
537
|
sha256: 'abc123',
|
|
538
538
|
},
|
|
539
539
|
{
|
|
540
|
-
id: '
|
|
540
|
+
id: 'domain',
|
|
541
541
|
version: '1.0.0',
|
|
542
542
|
description: 'Backend Lambda',
|
|
543
543
|
dependencies: ['core'],
|
|
544
|
-
tarball: '
|
|
544
|
+
tarball: 'domain.tar.gz',
|
|
545
545
|
sha256: 'def456',
|
|
546
546
|
},
|
|
547
547
|
],
|
|
@@ -609,7 +609,7 @@ describe('runCreateProject', () => {
|
|
|
609
609
|
expect(manifest.createdAt).toBeDefined();
|
|
610
610
|
expect(manifest.updatedAt).toBeDefined();
|
|
611
611
|
expect(manifest.enabledModules).toContain('core');
|
|
612
|
-
expect(manifest.enabledModules).toContain('
|
|
612
|
+
expect(manifest.enabledModules).toContain('domain');
|
|
613
613
|
|
|
614
614
|
// Verify file entries
|
|
615
615
|
expect(manifest.files).toBeInstanceOf(Array);
|
|
@@ -625,7 +625,7 @@ describe('runCreateProject', () => {
|
|
|
625
625
|
|
|
626
626
|
const backendFile = manifest.files.find((f: any) => f.path === 'backend-config.json');
|
|
627
627
|
expect(backendFile).toBeDefined();
|
|
628
|
-
expect(backendFile.module).toBe('
|
|
628
|
+
expect(backendFile.module).toBe('domain');
|
|
629
629
|
expect(backendFile.moduleVersion).toBe('1.0.0');
|
|
630
630
|
});
|
|
631
631
|
|
|
@@ -650,11 +650,11 @@ describe('runCreateProject', () => {
|
|
|
650
650
|
sha256: 'abc123',
|
|
651
651
|
},
|
|
652
652
|
{
|
|
653
|
-
id: '
|
|
653
|
+
id: 'domain',
|
|
654
654
|
version: '1.0.0',
|
|
655
655
|
description: 'Backend Lambda',
|
|
656
656
|
dependencies: ['core'],
|
|
657
|
-
tarball: '
|
|
657
|
+
tarball: 'domain.tar.gz',
|
|
658
658
|
sha256: 'def456',
|
|
659
659
|
},
|
|
660
660
|
{
|
|
@@ -704,7 +704,7 @@ describe('runCreateProject', () => {
|
|
|
704
704
|
expect(config.awsRegion).toBe('eu-north-1');
|
|
705
705
|
expect(config.awsAccountId).toBe('123456789012');
|
|
706
706
|
expect(config.enabledModules).toContain('core');
|
|
707
|
-
expect(config.enabledModules).toContain('
|
|
707
|
+
expect(config.enabledModules).toContain('domain');
|
|
708
708
|
expect(config.enabledModules).toContain('db-aurora');
|
|
709
709
|
expect(config.domainIds).toEqual([]);
|
|
710
710
|
expect(config.flowIds).toEqual([]);
|
|
@@ -29,7 +29,7 @@ describe('why command', () => {
|
|
|
29
29
|
join(tmpDir, '.mc', 'manifest.json'),
|
|
30
30
|
JSON.stringify({
|
|
31
31
|
scaffoldVersion: '2.5.0',
|
|
32
|
-
enabledModules: ['core', '
|
|
32
|
+
enabledModules: ['core', 'domain', 'frontend'],
|
|
33
33
|
})
|
|
34
34
|
);
|
|
35
35
|
fetchVersionsJsonSpy.mockResolvedValue({
|
|
@@ -43,7 +43,7 @@ describe('why command', () => {
|
|
|
43
43
|
expect(report.latestVersion).toBe('2.5.0');
|
|
44
44
|
expect(report.upgradeAvailable).toBe(false);
|
|
45
45
|
expect(report.versionsBehind).toBe(0);
|
|
46
|
-
expect(report.enabledModules).toEqual(['core', '
|
|
46
|
+
expect(report.enabledModules).toEqual(['core', 'domain', 'frontend']);
|
|
47
47
|
});
|
|
48
48
|
|
|
49
49
|
it('reports upgrade available when current is behind latest', async () => {
|
|
@@ -119,7 +119,7 @@ describe('runDoctor', () => {
|
|
|
119
119
|
await mkdir(join(tempDir, '.husky'), { recursive: true });
|
|
120
120
|
await mkdir(join(tempDir, '.tib', 'infra', 'modules'), { recursive: true });
|
|
121
121
|
|
|
122
|
-
await writeFile(join(tempDir, '.tib', 'infra', 'modules', 'app.ts'), '// @mc-scaffold:
|
|
122
|
+
await writeFile(join(tempDir, '.tib', 'infra', 'modules', 'app.ts'), '// @mc-scaffold: domain@1.0.0\n');
|
|
123
123
|
await writeFile(join(tempDir, '.husky', 'pre-commit'), '#!/bin/sh');
|
|
124
124
|
await writeFile(join(tempDir, '.tib', 'scaffold-config.json'), JSON.stringify({ domainIds: [] }));
|
|
125
125
|
|
|
@@ -130,9 +130,9 @@ describe('runDoctor', () => {
|
|
|
130
130
|
updatedAt: '2026-01-01T00:00:00Z',
|
|
131
131
|
projectName: 'test',
|
|
132
132
|
awsRegion: 'eu-north-1',
|
|
133
|
-
enabledModules: ['
|
|
133
|
+
enabledModules: ['domain'],
|
|
134
134
|
files: [
|
|
135
|
-
{ path: '.mc/infra/modules/app.ts', module: '
|
|
135
|
+
{ path: '.mc/infra/modules/app.ts', module: 'domain', moduleVersion: '1.0.0',
|
|
136
136
|
sha256: 'abc', wasTemplate: true, installedAt: '2026-01-01T00:00:00Z', policy: 'managed' as const }
|
|
137
137
|
]
|
|
138
138
|
};
|
|
@@ -150,7 +150,7 @@ describe('runDoctor', () => {
|
|
|
150
150
|
await mkdir(join(tempDir, '.husky'), { recursive: true });
|
|
151
151
|
await mkdir(join(tempDir, 'infra', 'modules'), { recursive: true });
|
|
152
152
|
|
|
153
|
-
await writeFile(join(tempDir, 'infra', 'modules', 'app.ts'), '// @mc-scaffold:
|
|
153
|
+
await writeFile(join(tempDir, 'infra', 'modules', 'app.ts'), '// @mc-scaffold: domain@1.0.0\n');
|
|
154
154
|
await writeFile(join(tempDir, '.husky', 'pre-commit'), '#!/bin/sh');
|
|
155
155
|
await writeFile(join(tempDir, '.tib', 'scaffold-config.json'), JSON.stringify({ domainIds: [] }));
|
|
156
156
|
|
|
@@ -161,9 +161,9 @@ describe('runDoctor', () => {
|
|
|
161
161
|
updatedAt: '2026-01-01T00:00:00Z',
|
|
162
162
|
projectName: 'test',
|
|
163
163
|
awsRegion: 'eu-north-1',
|
|
164
|
-
enabledModules: ['
|
|
164
|
+
enabledModules: ['domain'],
|
|
165
165
|
files: [
|
|
166
|
-
{ path: 'infra/modules/app.ts', module: '
|
|
166
|
+
{ path: 'infra/modules/app.ts', module: 'domain', moduleVersion: '1.0.0',
|
|
167
167
|
sha256: 'abc', wasTemplate: true, installedAt: '2026-01-01T00:00:00Z', policy: 'managed' as const }
|
|
168
168
|
]
|
|
169
169
|
};
|
|
@@ -190,9 +190,9 @@ describe('runDoctor', () => {
|
|
|
190
190
|
updatedAt: '2026-01-01T00:00:00Z',
|
|
191
191
|
projectName: 'test',
|
|
192
192
|
awsRegion: 'eu-north-1',
|
|
193
|
-
enabledModules: ['
|
|
193
|
+
enabledModules: ['domain'],
|
|
194
194
|
files: [
|
|
195
|
-
{ path: '.mc/infra/missing-file.ts', module: '
|
|
195
|
+
{ path: '.mc/infra/missing-file.ts', module: 'domain', moduleVersion: '1.0.0',
|
|
196
196
|
sha256: 'abc', wasTemplate: false, installedAt: '2026-01-01T00:00:00Z', policy: 'managed' as const }
|
|
197
197
|
]
|
|
198
198
|
};
|
|
@@ -212,7 +212,7 @@ describe('runDoctor', () => {
|
|
|
212
212
|
await mkdir(join(tempDir, 'domains'), { recursive: true });
|
|
213
213
|
await mkdir(join(tempDir, '.husky'), { recursive: true });
|
|
214
214
|
|
|
215
|
-
const appContent = '// @mc-scaffold:
|
|
215
|
+
const appContent = '// @mc-scaffold: domain@1.0.0\nimport * as cdk from "aws-cdk-lib";\n';
|
|
216
216
|
await writeFile(join(tempDir, 'infra', 'modules', 'app.ts'), appContent);
|
|
217
217
|
await writeFile(join(tempDir, '.husky', 'pre-commit'), '#!/bin/sh');
|
|
218
218
|
await writeFile(join(tempDir, '.tib', 'scaffold-config.json'), JSON.stringify({ domainIds: [] }));
|
|
@@ -227,9 +227,9 @@ describe('runDoctor', () => {
|
|
|
227
227
|
updatedAt: '2026-01-01T00:00:00Z',
|
|
228
228
|
projectName: 'test',
|
|
229
229
|
awsRegion: 'eu-north-1',
|
|
230
|
-
enabledModules: ['
|
|
230
|
+
enabledModules: ['domain'],
|
|
231
231
|
files: [
|
|
232
|
-
{ path: 'infra/modules/app.ts', module: '
|
|
232
|
+
{ path: 'infra/modules/app.ts', module: 'domain', moduleVersion: '1.0.0',
|
|
233
233
|
sha256, wasTemplate: true, installedAt: '2026-01-01T00:00:00Z', policy: 'managed' as const }
|
|
234
234
|
]
|
|
235
235
|
};
|
|
@@ -252,8 +252,8 @@ describe('runDoctor', () => {
|
|
|
252
252
|
await mkdir(join(tempDir, '.mc'), { recursive: true });
|
|
253
253
|
await mkdir(join(tempDir, 'infra', 'modules'), { recursive: true });
|
|
254
254
|
|
|
255
|
-
const originalContent = '// @mc-scaffold:
|
|
256
|
-
const modifiedContent = '// @mc-scaffold:
|
|
255
|
+
const originalContent = '// @mc-scaffold: domain@1.0.0\noriginal\n';
|
|
256
|
+
const modifiedContent = '// @mc-scaffold: domain@1.0.0\nmodified by user\n';
|
|
257
257
|
await writeFile(join(tempDir, 'infra', 'modules', 'app.ts'), modifiedContent);
|
|
258
258
|
await writeFile(join(tempDir, '.tib', 'scaffold-config.json'), JSON.stringify({ domainIds: [] }));
|
|
259
259
|
|
|
@@ -267,9 +267,9 @@ describe('runDoctor', () => {
|
|
|
267
267
|
updatedAt: '2026-01-01T00:00:00Z',
|
|
268
268
|
projectName: 'test',
|
|
269
269
|
awsRegion: 'eu-north-1',
|
|
270
|
-
enabledModules: ['
|
|
270
|
+
enabledModules: ['domain'],
|
|
271
271
|
files: [
|
|
272
|
-
{ path: 'infra/modules/app.ts', module: '
|
|
272
|
+
{ path: 'infra/modules/app.ts', module: 'domain', moduleVersion: '1.0.0',
|
|
273
273
|
sha256: originalSha, wasTemplate: true, installedAt: '2026-01-01T00:00:00Z', policy: 'managed' as const }
|
|
274
274
|
]
|
|
275
275
|
};
|
|
@@ -306,7 +306,7 @@ describe('runDoctor', () => {
|
|
|
306
306
|
await mkdir(join(tempDir, 'domains'), { recursive: true });
|
|
307
307
|
await mkdir(join(tempDir, '.husky'), { recursive: true });
|
|
308
308
|
|
|
309
|
-
const appContent = '// @mc-scaffold:
|
|
309
|
+
const appContent = '// @mc-scaffold: domain@1.0.0\nimport * as cdk from "aws-cdk-lib";\n';
|
|
310
310
|
await writeFile(join(tempDir, 'infra', 'modules', 'app.ts'), appContent);
|
|
311
311
|
await writeFile(join(tempDir, '.husky', 'pre-commit'), '#!/bin/sh');
|
|
312
312
|
await writeFile(join(tempDir, '.tib', 'scaffold-config.json'), JSON.stringify({ domainIds: [] }));
|
|
@@ -321,9 +321,9 @@ describe('runDoctor', () => {
|
|
|
321
321
|
updatedAt: '2026-01-01T00:00:00Z',
|
|
322
322
|
projectName: 'test',
|
|
323
323
|
awsRegion: 'eu-north-1',
|
|
324
|
-
enabledModules: ['
|
|
324
|
+
enabledModules: ['domain'],
|
|
325
325
|
files: [
|
|
326
|
-
{ path: 'infra/modules/app.ts', module: '
|
|
326
|
+
{ path: 'infra/modules/app.ts', module: 'domain', moduleVersion: '1.0.0',
|
|
327
327
|
sha256, wasTemplate: true, installedAt: '2026-01-01T00:00:00Z', policy: 'managed' as const }
|
|
328
328
|
]
|
|
329
329
|
};
|
|
@@ -375,7 +375,7 @@ describe('runDoctor', () => {
|
|
|
375
375
|
updatedAt: '2026-01-01T00:00:00Z',
|
|
376
376
|
projectName: 'test',
|
|
377
377
|
awsRegion: 'eu-north-1',
|
|
378
|
-
enabledModules: ['
|
|
378
|
+
enabledModules: ['domain'],
|
|
379
379
|
files: []
|
|
380
380
|
};
|
|
381
381
|
await writeFile(join(tempDir, '.mc', 'manifest.json'), JSON.stringify(manifest));
|
|
@@ -6,19 +6,19 @@ import { fileURLToPath } from 'url';
|
|
|
6
6
|
const __filename = fileURLToPath(import.meta.url);
|
|
7
7
|
const __dirname = dirname(__filename);
|
|
8
8
|
const repoRoot = resolve(__dirname, '../../../../..');
|
|
9
|
-
const backendLambdaDir = join(repoRoot, 'scaffold-src', 'modules', '
|
|
9
|
+
const backendLambdaDir = join(repoRoot, 'scaffold-src', 'modules', 'domain');
|
|
10
10
|
const coreDir = join(repoRoot, 'scaffold-src', 'modules', 'core');
|
|
11
11
|
|
|
12
12
|
describe('scaffold-src layout (Part A)', () => {
|
|
13
|
-
it('
|
|
13
|
+
it('domain has app.ts.tpl under .mc/infra/modules/', () => {
|
|
14
14
|
expect(existsSync(join(backendLambdaDir, '.mc/infra/modules/app.ts.tpl'))).toBe(true);
|
|
15
15
|
});
|
|
16
16
|
|
|
17
|
-
it('
|
|
17
|
+
it('domain infra/ directory is removed', () => {
|
|
18
18
|
expect(existsSync(join(backendLambdaDir, 'infra'))).toBe(false);
|
|
19
19
|
});
|
|
20
20
|
|
|
21
|
-
it('
|
|
21
|
+
it('domain has root cdk.json.tpl seed', () => {
|
|
22
22
|
expect(existsSync(join(backendLambdaDir, 'cdk.json.tpl'))).toBe(true);
|
|
23
23
|
const content = readFileSync(join(backendLambdaDir, 'cdk.json.tpl'), 'utf-8');
|
|
24
24
|
const parsed = JSON.parse(content);
|
|
@@ -285,9 +285,9 @@ function logFailure(label: string, result: CmdResult): void {
|
|
|
285
285
|
/** Modules runCreateProject selects when the user says "yes" to all. */
|
|
286
286
|
const DEFAULT_MODULE_IDS = [
|
|
287
287
|
'core',
|
|
288
|
-
'
|
|
288
|
+
'domain',
|
|
289
289
|
'db-aurora',
|
|
290
|
-
'auth
|
|
290
|
+
'auth',
|
|
291
291
|
'frontend',
|
|
292
292
|
] as const;
|
|
293
293
|
const SMOKE_VERSION = '99.0.0-smoke';
|
|
@@ -400,7 +400,7 @@ describe('scaffold smoke test (issue #3831)', () => {
|
|
|
400
400
|
'frontend/package.json',
|
|
401
401
|
'frontend/vite.config.ts',
|
|
402
402
|
'frontend/tsconfig.json',
|
|
403
|
-
'domains/.gitkeep', //
|
|
403
|
+
'domains/.gitkeep', // domain seeds this
|
|
404
404
|
];
|
|
405
405
|
for (const p of requiredPaths) {
|
|
406
406
|
const full = join(projectDir, p);
|
|
@@ -448,8 +448,8 @@ describe('scaffold smoke test (issue #3831)', () => {
|
|
|
448
448
|
expect(tsconfig.compilerOptions.strict).toBe(true);
|
|
449
449
|
});
|
|
450
450
|
|
|
451
|
-
it('seeds api handlers from auth
|
|
452
|
-
// The auth
|
|
451
|
+
it('seeds api handlers from auth that import defineApi from @mettlecast/domain-runtime', async () => {
|
|
452
|
+
// The auth module ships a hand-written seed api/me.ts. We
|
|
453
453
|
// confirm it parses (no obvious syntax errors) and uses the runtime
|
|
454
454
|
// primitive. This is a structural check; the wave-2 "import ky + call
|
|
455
455
|
// initOtel()" expectation is documented below as a separate soft gate.
|
|
@@ -487,7 +487,7 @@ describe('scaffold smoke test (issue #3831)', () => {
|
|
|
487
487
|
`seed handler gap: ${apiFile} does not call initOtel()\n` +
|
|
488
488
|
` hasInitOtel=${hasInitOtel}\n` +
|
|
489
489
|
` expected: initOtel() at module scope\n` +
|
|
490
|
-
` Fix: update scaffold-src/modules/auth
|
|
490
|
+
` Fix: update scaffold-src/modules/auth/domains/auth/api/*.ts\n` +
|
|
491
491
|
` to include \`import { initOtel } from '@mettlecast/domain-runtime';\n` +
|
|
492
492
|
` initOtel();\` at module scope`,
|
|
493
493
|
);
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { describe, it, expect } from 'vitest';
|
|
2
2
|
import { injectHeader } from '../../utils/header-inject.js';
|
|
3
3
|
|
|
4
|
-
const MODULE = '
|
|
4
|
+
const MODULE = 'domain';
|
|
5
5
|
const VERSION = '1.0.0';
|
|
6
6
|
|
|
7
7
|
describe('injectHeader — TypeScript files', () => {
|
|
8
8
|
it('prepends // @mc-scaffold header to .ts file', () => {
|
|
9
9
|
const result = injectHeader('const x = 1;\n', 'app.ts', MODULE, VERSION);
|
|
10
|
-
expect(result).toMatch(/^\/\/ @mc-scaffold:
|
|
10
|
+
expect(result).toMatch(/^\/\/ @mc-scaffold: domain@1\.0\.0\n/);
|
|
11
11
|
expect(result).toContain('const x = 1;');
|
|
12
12
|
});
|
|
13
13
|
|
|
@@ -27,7 +27,7 @@ describe('injectHeader — TypeScript files', () => {
|
|
|
27
27
|
describe('injectHeader — YAML files', () => {
|
|
28
28
|
it('prepends # @mc-scaffold header to .yml file', () => {
|
|
29
29
|
const result = injectHeader('name: CI\n', 'ci.yml', MODULE, VERSION);
|
|
30
|
-
expect(result).toMatch(/^# @mc-scaffold:
|
|
30
|
+
expect(result).toMatch(/^# @mc-scaffold: domain@1\.0\.0\n/);
|
|
31
31
|
expect(result).toContain('name: CI');
|
|
32
32
|
});
|
|
33
33
|
|
|
@@ -42,7 +42,7 @@ describe('injectHeader — JSON files', () => {
|
|
|
42
42
|
const result = injectHeader('{"name": "test", "version": "1.0.0"}', 'config.json', MODULE, VERSION);
|
|
43
43
|
const parsed = JSON.parse(result) as Record<string, unknown>;
|
|
44
44
|
expect(Object.keys(parsed)[0]).toBe('_tibScaffold');
|
|
45
|
-
expect(parsed._tibScaffold).toBe('
|
|
45
|
+
expect(parsed._tibScaffold).toBe('domain@1.0.0');
|
|
46
46
|
expect(parsed.name).toBe('test');
|
|
47
47
|
});
|
|
48
48
|
|
|
@@ -68,7 +68,7 @@ describe('injectHeader — JSON files', () => {
|
|
|
68
68
|
describe('injectHeader — CSS files', () => {
|
|
69
69
|
it('prepends /* @mc-scaffold */ header to .css file', () => {
|
|
70
70
|
const result = injectHeader('@tailwind base;\n', 'index.css', MODULE, VERSION);
|
|
71
|
-
expect(result).toMatch(/^\/\* @mc-scaffold:
|
|
71
|
+
expect(result).toMatch(/^\/\* @mc-scaffold: domain@1\.0\.0 \*\//);
|
|
72
72
|
expect(result).toContain('@tailwind base;');
|
|
73
73
|
});
|
|
74
74
|
});
|
|
@@ -76,7 +76,7 @@ describe('injectHeader — CSS files', () => {
|
|
|
76
76
|
describe('injectHeader — HTML files', () => {
|
|
77
77
|
it('prepends <!-- @mc-scaffold --> header to .html file', () => {
|
|
78
78
|
const result = injectHeader('<!doctype html>\n', 'index.html', MODULE, VERSION);
|
|
79
|
-
expect(result).toMatch(/^<!-- @mc-scaffold:
|
|
79
|
+
expect(result).toMatch(/^<!-- @mc-scaffold: domain@1\.0\.0 -->/);
|
|
80
80
|
});
|
|
81
81
|
});
|
|
82
82
|
|
|
@@ -74,8 +74,8 @@ function topoSort(modules: S3ModuleEntry[], selected: Set<string>): S3ModuleEntr
|
|
|
74
74
|
result.push(mod);
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
// Always core first, then
|
|
78
|
-
const priorityOrder = ['core', '
|
|
77
|
+
// Always core first, then domain, then rest
|
|
78
|
+
const priorityOrder = ['core', 'domain'];
|
|
79
79
|
for (const id of priorityOrder) {
|
|
80
80
|
if (selected.has(id)) visit(id);
|
|
81
81
|
}
|
|
@@ -190,9 +190,9 @@ export async function runCreateProject(opts: CreateProjectOptions): Promise<void
|
|
|
190
190
|
const modulesJson = await fetchModulesJson(SCAFFOLD_BUCKET, scaffoldVersion);
|
|
191
191
|
|
|
192
192
|
// 4. Resolve module selection
|
|
193
|
-
const selectedIds = new Set<string>(['core', '
|
|
193
|
+
const selectedIds = new Set<string>(['core', 'domain']);
|
|
194
194
|
if (includeDatabase) selectedIds.add('db-aurora');
|
|
195
|
-
if (includeAuth) selectedIds.add('auth
|
|
195
|
+
if (includeAuth) selectedIds.add('auth');
|
|
196
196
|
if (includeFrontend) selectedIds.add('frontend');
|
|
197
197
|
if (includeFlows) selectedIds.add('flows');
|
|
198
198
|
|
package/src/commands/doctor.ts
CHANGED
|
@@ -1683,7 +1683,7 @@ async function runRelocate(projectRoot: string): Promise<DoctorReport> {
|
|
|
1683
1683
|
const sha256 = manifestEntry?.sha256 ?? computeChecksumString(content);
|
|
1684
1684
|
upsertManifestFile(manifest, {
|
|
1685
1685
|
path: newPath,
|
|
1686
|
-
module: manifestEntry?.module ?? '
|
|
1686
|
+
module: manifestEntry?.module ?? 'domain',
|
|
1687
1687
|
moduleVersion: manifestEntry?.moduleVersion ?? '1.0.0',
|
|
1688
1688
|
sha256,
|
|
1689
1689
|
wasTemplate: manifestEntry?.wasTemplate ?? false,
|
package/src/commands/upgrade.ts
CHANGED
|
@@ -139,7 +139,7 @@ function topoSort(modules: S3ModuleEntry[], selected: Set<string>): S3ModuleEntr
|
|
|
139
139
|
result.push(mod);
|
|
140
140
|
}
|
|
141
141
|
|
|
142
|
-
for (const id of ['core', '
|
|
142
|
+
for (const id of ['core', 'domain']) {
|
|
143
143
|
if (selected.has(id)) visit(id);
|
|
144
144
|
}
|
|
145
145
|
for (const id of selected) visit(id);
|
|
@@ -14,7 +14,7 @@ const JSON_SKIP_LIST = new Set([
|
|
|
14
14
|
*
|
|
15
15
|
* @param content The file content (post-token-substitution)
|
|
16
16
|
* @param filename The destination filename (used to determine type)
|
|
17
|
-
* @param moduleId The scaffold module id (e.g. '
|
|
17
|
+
* @param moduleId The scaffold module id (e.g. 'domain')
|
|
18
18
|
* @param version The scaffold module version (e.g. '1.0.0')
|
|
19
19
|
*/
|
|
20
20
|
export function injectHeader(
|
|
@@ -3,12 +3,19 @@ import path from 'path';
|
|
|
3
3
|
|
|
4
4
|
export type ModuleId =
|
|
5
5
|
| 'core'
|
|
6
|
-
| '
|
|
6
|
+
| 'domain'
|
|
7
7
|
| 'db-aurora'
|
|
8
|
-
| 'auth
|
|
8
|
+
| 'auth'
|
|
9
9
|
| 'frontend'
|
|
10
10
|
| 'flows'
|
|
11
|
-
| 'data-management'
|
|
11
|
+
| 'data-management'
|
|
12
|
+
| 'tenants'
|
|
13
|
+
| 'users'
|
|
14
|
+
| 'shared'
|
|
15
|
+
| 'data-storage'
|
|
16
|
+
| 'monitoring'
|
|
17
|
+
| 'orgs'
|
|
18
|
+
| 'test-executor';
|
|
12
19
|
|
|
13
20
|
export type LogRetentionDays = 30 | 90 | 365 | 2557;
|
|
14
21
|
|
|
@@ -83,7 +90,7 @@ export interface ScaffoldConfig {
|
|
|
83
90
|
projectName: string;
|
|
84
91
|
awsRegion: string;
|
|
85
92
|
awsAccountId: string;
|
|
86
|
-
/** Admin email collected at scaffold time (Cognito seed user). Present only when auth
|
|
93
|
+
/** Admin email collected at scaffold time (Cognito seed user). Present only when auth module is enabled. */
|
|
87
94
|
adminEmail?: string;
|
|
88
95
|
/** Domain IDs added via `tib add-domain` — NOT scaffold-owned, user-managed */
|
|
89
96
|
domainIds: string[];
|
|
@@ -111,7 +118,7 @@ export interface ScaffoldConfig {
|
|
|
111
118
|
|
|
112
119
|
const DEFAULT_SCAFFOLD_CONFIG: Omit<ScaffoldConfig, 'domainIds' | 'flowIds'> = {
|
|
113
120
|
scaffoldVersion: '0.0.0',
|
|
114
|
-
enabledModules: ['core', '
|
|
121
|
+
enabledModules: ['core', 'domain'],
|
|
115
122
|
projectName: 'unknown',
|
|
116
123
|
awsRegion: 'eu-north-1',
|
|
117
124
|
awsAccountId: '',
|