create-forgeon 0.3.14 → 0.3.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.
- package/package.json +4 -2
- package/src/core/docs.test.mjs +79 -40
- package/src/core/scaffold.test.mjs +99 -0
- package/src/modules/db-prisma.mjs +23 -55
- package/src/modules/executor.test.mjs +2575 -2419
- package/src/modules/files-access.mjs +27 -98
- package/src/modules/files-image.mjs +26 -100
- package/src/modules/files-quotas.mjs +67 -87
- package/src/modules/files.mjs +35 -104
- package/src/modules/i18n.mjs +17 -121
- package/src/modules/idempotency.test.mjs +174 -0
- package/src/modules/jwt-auth.mjs +90 -209
- package/src/modules/logger.mjs +0 -9
- package/src/modules/probes.test.mjs +202 -0
- package/src/modules/queue.mjs +325 -412
- package/src/modules/rate-limit.mjs +22 -66
- package/src/modules/rbac.mjs +27 -67
- package/src/modules/scheduler.mjs +44 -167
- package/src/modules/shared/nest-runtime-wiring.mjs +110 -0
- package/src/modules/shared/probes.mjs +235 -0
- package/src/modules/sync-integrations.mjs +54 -21
- package/src/modules/sync-integrations.test.mjs +220 -0
- package/src/run-add-module.test.mjs +153 -0
- package/templates/base/README.md +7 -55
- package/templates/base/apps/web/src/App.tsx +70 -42
- package/templates/base/apps/web/src/probes.ts +61 -0
- package/templates/base/apps/web/src/styles.css +86 -25
- package/templates/base/package.json +21 -15
- package/templates/base/scripts/forgeon-sync-integrations.mjs +55 -11
- package/templates/module-presets/files-quotas/packages/files-quotas/src/forgeon-files-quotas.module.ts +12 -4
- package/templates/module-presets/i18n/apps/web/src/App.tsx +68 -41
- package/templates/module-presets/logger/packages/logger/src/index.ts +0 -1
- package/templates/base/docs/AI/ARCHITECTURE.md +0 -85
- package/templates/base/docs/AI/MODULE_CHECKS.md +0 -28
- package/templates/base/docs/AI/MODULE_SPEC.md +0 -77
- package/templates/base/docs/AI/PROJECT.md +0 -43
- package/templates/base/docs/AI/ROADMAP.md +0 -171
- package/templates/base/docs/AI/TASKS.md +0 -60
- package/templates/base/docs/AI/VALIDATION.md +0 -31
- package/templates/base/docs/README.md +0 -18
- package/templates/module-presets/logger/packages/logger/src/http-logging.interceptor.ts +0 -94
package/package.json
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-forgeon",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.16",
|
|
4
4
|
"description": "Forgeon project generator CLI",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Forgeon",
|
|
7
7
|
"type": "module",
|
|
8
8
|
"scripts": {
|
|
9
|
-
"test": "node --test src/cli/options.test.mjs src/cli/add-options.test.mjs src/cli/prompt-select.test.mjs src/core/docs.test.mjs src/core/validate.test.mjs src/modules/executor.test.mjs"
|
|
9
|
+
"test": "node --test --test-concurrency=1 src/cli/options.test.mjs src/cli/add-options.test.mjs src/cli/prompt-select.test.mjs src/core/docs.test.mjs src/core/validate.test.mjs src/core/scaffold.test.mjs src/modules/dependencies.test.mjs src/modules/executor.test.mjs src/modules/probes.test.mjs src/modules/idempotency.test.mjs src/modules/sync-integrations.test.mjs src/run-add-module.test.mjs",
|
|
10
|
+
"smoke:generated-project": "node scripts/generated-project-smoke.mjs",
|
|
11
|
+
"smoke:generated-project:full": "node scripts/generated-project-full-smoke.mjs"
|
|
10
12
|
},
|
|
11
13
|
"bin": {
|
|
12
14
|
"create-forgeon": "bin/create-forgeon.mjs"
|
package/src/core/docs.test.mjs
CHANGED
|
@@ -1,29 +1,30 @@
|
|
|
1
|
-
import { describe, it } from 'node:test';
|
|
2
|
-
import assert from 'node:assert/strict';
|
|
3
|
-
import fs from 'node:fs';
|
|
4
|
-
import os from 'node:os';
|
|
5
|
-
import path from 'node:path';
|
|
6
|
-
import { fileURLToPath } from 'node:url';
|
|
7
|
-
import { generateDocs } from './docs.mjs';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
const
|
|
20
|
-
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { generateDocs } from './docs.mjs';
|
|
8
|
+
import { scaffoldProject } from './scaffold.mjs';
|
|
9
|
+
|
|
10
|
+
function makeTempDir(prefix) {
|
|
11
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function readFile(filePath) {
|
|
15
|
+
return fs.readFileSync(filePath, 'utf8');
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
describe('generateDocs', () => {
|
|
19
|
+
const thisDir = path.dirname(fileURLToPath(import.meta.url));
|
|
20
|
+
const packageRoot = path.resolve(thisDir, '..', '..');
|
|
21
|
+
|
|
21
22
|
it('generates docs for proxy=none without i18n section', () => {
|
|
22
|
-
const targetRoot = makeTempDir('forgeon-docs-off-');
|
|
23
|
-
|
|
24
|
-
try {
|
|
25
|
-
generateDocs(
|
|
26
|
-
targetRoot,
|
|
23
|
+
const targetRoot = makeTempDir('forgeon-docs-off-');
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
generateDocs(
|
|
27
|
+
targetRoot,
|
|
27
28
|
{
|
|
28
29
|
frontend: 'react',
|
|
29
30
|
db: 'prisma',
|
|
@@ -31,9 +32,9 @@ describe('generateDocs', () => {
|
|
|
31
32
|
dockerEnabled: true,
|
|
32
33
|
i18nEnabled: false,
|
|
33
34
|
proxy: 'none',
|
|
34
|
-
},
|
|
35
|
-
packageRoot,
|
|
36
|
-
);
|
|
35
|
+
},
|
|
36
|
+
packageRoot,
|
|
37
|
+
);
|
|
37
38
|
|
|
38
39
|
const readme = readFile(path.join(targetRoot, 'README.md'));
|
|
39
40
|
|
|
@@ -45,18 +46,20 @@ describe('generateDocs', () => {
|
|
|
45
46
|
assert.match(readme, /Module notes index: `modules\/README\.md`/);
|
|
46
47
|
assert.doesNotMatch(readme, /i18n Configuration/);
|
|
47
48
|
assert.doesNotMatch(readme, /Prisma In Container Start/);
|
|
49
|
+
assert.doesNotMatch(readme, /docs\/README\.md/);
|
|
50
|
+
assert.doesNotMatch(readme, /docs\/Agents\.md/);
|
|
48
51
|
assert.equal(fs.existsSync(path.join(targetRoot, 'docs')), false);
|
|
49
52
|
} finally {
|
|
50
53
|
fs.rmSync(targetRoot, { recursive: true, force: true });
|
|
51
54
|
}
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
it('generates docker and caddy notes when enabled', () => {
|
|
55
|
-
const targetRoot = makeTempDir('forgeon-docs-on-');
|
|
56
|
-
|
|
57
|
-
try {
|
|
58
|
-
generateDocs(
|
|
59
|
-
targetRoot,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it('generates docker and caddy notes when enabled', () => {
|
|
58
|
+
const targetRoot = makeTempDir('forgeon-docs-on-');
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
generateDocs(
|
|
62
|
+
targetRoot,
|
|
60
63
|
{
|
|
61
64
|
frontend: 'react',
|
|
62
65
|
db: 'prisma',
|
|
@@ -64,9 +67,9 @@ describe('generateDocs', () => {
|
|
|
64
67
|
dockerEnabled: true,
|
|
65
68
|
i18nEnabled: true,
|
|
66
69
|
proxy: 'caddy',
|
|
67
|
-
},
|
|
68
|
-
packageRoot,
|
|
69
|
-
);
|
|
70
|
+
},
|
|
71
|
+
packageRoot,
|
|
72
|
+
);
|
|
70
73
|
|
|
71
74
|
const readme = readFile(path.join(targetRoot, 'README.md'));
|
|
72
75
|
|
|
@@ -77,9 +80,45 @@ describe('generateDocs', () => {
|
|
|
77
80
|
assert.match(readme, /Prisma In Container Start/);
|
|
78
81
|
assert.match(readme, /Error Handling \(`core-errors`\)/);
|
|
79
82
|
assert.match(readme, /Module-specific notes: `modules\/<module-id>\/README\.md`/);
|
|
83
|
+
assert.doesNotMatch(readme, /docs\/README\.md/);
|
|
84
|
+
assert.doesNotMatch(readme, /docs\/Agents\.md/);
|
|
80
85
|
assert.equal(fs.existsSync(path.join(targetRoot, 'docs')), false);
|
|
81
86
|
} finally {
|
|
82
87
|
fs.rmSync(targetRoot, { recursive: true, force: true });
|
|
83
88
|
}
|
|
84
|
-
});
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
it('scaffolds a generated project without copying internal docs payload', () => {
|
|
92
|
+
const tempRoot = makeTempDir('forgeon-scaffold-doc-boundary-');
|
|
93
|
+
const targetRoot = path.join(tempRoot, 'demo-doc-boundary');
|
|
94
|
+
const templateRoot = path.join(packageRoot, 'templates', 'base');
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
scaffoldProject({
|
|
98
|
+
templateRoot,
|
|
99
|
+
packageRoot,
|
|
100
|
+
targetRoot,
|
|
101
|
+
projectName: 'demo-doc-boundary',
|
|
102
|
+
frontend: 'react',
|
|
103
|
+
db: 'prisma',
|
|
104
|
+
dbPrismaEnabled: true,
|
|
105
|
+
i18nEnabled: true,
|
|
106
|
+
proxy: 'caddy',
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
const readme = readFile(path.join(targetRoot, 'README.md'));
|
|
110
|
+
const packageJson = readFile(path.join(targetRoot, 'package.json'));
|
|
111
|
+
|
|
112
|
+
assert.equal(fs.existsSync(path.join(targetRoot, 'docs')), false);
|
|
113
|
+
assert.match(readme, /Module notes index: `modules\/README\.md`/);
|
|
114
|
+
assert.doesNotMatch(readme, /temporary template placeholder/i);
|
|
115
|
+
assert.doesNotMatch(readme, /built-in docs/i);
|
|
116
|
+
assert.doesNotMatch(readme, /docs\/README\.md/);
|
|
117
|
+
assert.doesNotMatch(readme, /docs\/Agents\.md/);
|
|
118
|
+
assert.doesNotMatch(packageJson, /"create:forgeon"/);
|
|
119
|
+
assert.match(packageJson, /"forgeon:sync-integrations"/);
|
|
120
|
+
} finally {
|
|
121
|
+
fs.rmSync(tempRoot, { recursive: true, force: true });
|
|
122
|
+
}
|
|
123
|
+
});
|
|
85
124
|
});
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { describe, it } from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import fs from 'node:fs';
|
|
4
|
+
import os from 'node:os';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
import { scaffoldProject } from './scaffold.mjs';
|
|
8
|
+
|
|
9
|
+
function makeTempDir(prefix) {
|
|
10
|
+
return fs.mkdtempSync(path.join(os.tmpdir(), prefix));
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
function readFile(filePath) {
|
|
14
|
+
return fs.readFileSync(filePath, 'utf8');
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function assertProxyPreset(targetRoot, proxy) {
|
|
18
|
+
const dockerDir = path.join(targetRoot, 'infra', 'docker');
|
|
19
|
+
const compose = readFile(path.join(dockerDir, 'compose.yml'));
|
|
20
|
+
const packageJson = readFile(path.join(targetRoot, 'package.json'));
|
|
21
|
+
const appTsx = readFile(path.join(targetRoot, 'apps', 'web', 'src', 'App.tsx'));
|
|
22
|
+
const probesTs = readFile(path.join(targetRoot, 'apps', 'web', 'src', 'probes.ts'));
|
|
23
|
+
|
|
24
|
+
assert.equal(fs.existsSync(path.join(targetRoot, 'docs')), false);
|
|
25
|
+
assert.equal(fs.existsSync(path.join(dockerDir, 'compose.caddy.yml')), false);
|
|
26
|
+
assert.equal(fs.existsSync(path.join(dockerDir, 'compose.nginx.yml')), false);
|
|
27
|
+
assert.equal(fs.existsSync(path.join(dockerDir, 'compose.none.yml')), false);
|
|
28
|
+
assert.match(packageJson, /"forgeon:sync-integrations"/);
|
|
29
|
+
assert.doesNotMatch(packageJson, /"create:forgeon"/);
|
|
30
|
+
assert.match(compose, /^services:\s*$/m);
|
|
31
|
+
assert.match(compose, /^\s{2}api:\s*$/m);
|
|
32
|
+
|
|
33
|
+
if (proxy === 'caddy') {
|
|
34
|
+
assert.match(compose, /^\s{2}caddy:\s*$/m);
|
|
35
|
+
assert.doesNotMatch(compose, /^\s{2}nginx:\s*$/m);
|
|
36
|
+
assert.equal(fs.existsSync(path.join(dockerDir, 'caddy.Dockerfile')), true);
|
|
37
|
+
assert.equal(fs.existsSync(path.join(dockerDir, 'nginx.Dockerfile')), false);
|
|
38
|
+
assert.equal(fs.existsSync(path.join(targetRoot, 'infra', 'caddy')), true);
|
|
39
|
+
assert.equal(fs.existsSync(path.join(targetRoot, 'infra', 'nginx')), false);
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
if (proxy === 'nginx') {
|
|
44
|
+
assert.match(compose, /^\s{2}nginx:\s*$/m);
|
|
45
|
+
assert.doesNotMatch(compose, /^\s{2}caddy:\s*$/m);
|
|
46
|
+
assert.equal(fs.existsSync(path.join(dockerDir, 'nginx.Dockerfile')), true);
|
|
47
|
+
assert.equal(fs.existsSync(path.join(dockerDir, 'caddy.Dockerfile')), false);
|
|
48
|
+
assert.equal(fs.existsSync(path.join(targetRoot, 'infra', 'nginx')), true);
|
|
49
|
+
assert.equal(fs.existsSync(path.join(targetRoot, 'infra', 'caddy')), false);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
assert.doesNotMatch(compose, /^\s{2}caddy:\s*$/m);
|
|
54
|
+
assert.doesNotMatch(compose, /^\s{2}nginx:\s*$/m);
|
|
55
|
+
assert.match(compose, /- "3000:3000"/);
|
|
56
|
+
assert.equal(fs.existsSync(path.join(dockerDir, 'nginx.Dockerfile')), false);
|
|
57
|
+
assert.equal(fs.existsSync(path.join(dockerDir, 'caddy.Dockerfile')), false);
|
|
58
|
+
assert.equal(fs.existsSync(path.join(targetRoot, 'infra', 'nginx')), false);
|
|
59
|
+
assert.equal(fs.existsSync(path.join(targetRoot, 'infra', 'caddy')), false);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
describe('scaffoldProject', () => {
|
|
63
|
+
const thisDir = path.dirname(fileURLToPath(import.meta.url));
|
|
64
|
+
const packageRoot = path.resolve(thisDir, '..', '..');
|
|
65
|
+
const templateRoot = path.join(packageRoot, 'templates', 'base');
|
|
66
|
+
const cases = [
|
|
67
|
+
{ proxy: 'caddy', readmePattern: /Proxy Preset: Caddy/ },
|
|
68
|
+
{ proxy: 'nginx', readmePattern: /Proxy Preset: Nginx/ },
|
|
69
|
+
{ proxy: 'none', readmePattern: /Proxy Preset: none/ },
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
it('applies proxy presets without leftover reverse-proxy assets', () => {
|
|
73
|
+
for (const testCase of cases) {
|
|
74
|
+
const tempRoot = makeTempDir(`forgeon-scaffold-proxy-${testCase.proxy}-`);
|
|
75
|
+
const targetRoot = path.join(tempRoot, `demo-${testCase.proxy}`);
|
|
76
|
+
|
|
77
|
+
try {
|
|
78
|
+
scaffoldProject({
|
|
79
|
+
templateRoot,
|
|
80
|
+
packageRoot,
|
|
81
|
+
targetRoot,
|
|
82
|
+
projectName: `demo-${testCase.proxy}`,
|
|
83
|
+
frontend: 'react',
|
|
84
|
+
db: 'prisma',
|
|
85
|
+
dbPrismaEnabled: false,
|
|
86
|
+
i18nEnabled: false,
|
|
87
|
+
proxy: testCase.proxy,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const readme = readFile(path.join(targetRoot, 'README.md'));
|
|
91
|
+
assert.match(readme, testCase.readmePattern);
|
|
92
|
+
assert.match(readme, /Module notes index: `modules\/README\.md`/);
|
|
93
|
+
assertProxyPreset(targetRoot, testCase.proxy);
|
|
94
|
+
} finally {
|
|
95
|
+
fs.rmSync(tempRoot, { recursive: true, force: true });
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
});
|
|
99
|
+
});
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
ensureValidatorSchema,
|
|
16
16
|
upsertEnvLines,
|
|
17
17
|
} from './shared/patch-utils.mjs';
|
|
18
|
+
import { ensureWebProbeDefinition, resolveProbeTargets } from './shared/probes.mjs';
|
|
18
19
|
|
|
19
20
|
function copyFromPreset(packageRoot, targetRoot, relativePath) {
|
|
20
21
|
const source = path.join(packageRoot, 'templates', 'module-presets', 'db-prisma', relativePath);
|
|
@@ -110,7 +111,11 @@ function patchAppModule(targetRoot) {
|
|
|
110
111
|
fs.writeFileSync(filePath, `${content.trimEnd()}\n`, 'utf8');
|
|
111
112
|
}
|
|
112
113
|
|
|
113
|
-
function patchHealthController(targetRoot) {
|
|
114
|
+
function patchHealthController(targetRoot, probeTargets) {
|
|
115
|
+
if (!probeTargets.allowApi) {
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
114
119
|
const filePath = path.join(targetRoot, 'apps', 'api', 'src', 'health', 'health.controller.ts');
|
|
115
120
|
if (!fs.existsSync(filePath)) {
|
|
116
121
|
return;
|
|
@@ -171,58 +176,19 @@ function patchHealthController(targetRoot) {
|
|
|
171
176
|
fs.writeFileSync(filePath, `${content.trimEnd()}\n`, 'utf8');
|
|
172
177
|
}
|
|
173
178
|
|
|
174
|
-
function
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
if (!content.includes('dbProbeResult')) {
|
|
188
|
-
const stateAnchor = ' const [validationProbeResult, setValidationProbeResult] = useState<ProbeResult | null>(null);';
|
|
189
|
-
if (content.includes(stateAnchor)) {
|
|
190
|
-
content = ensureLineAfter(
|
|
191
|
-
content,
|
|
192
|
-
stateAnchor,
|
|
193
|
-
' const [dbProbeResult, setDbProbeResult] = useState<ProbeResult | null>(null);',
|
|
194
|
-
);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
if (!content.includes('Check database (create user)')) {
|
|
199
|
-
const dbButton = content.includes("runProbe(setHealthResult, '/health')")
|
|
200
|
-
? " <button onClick={() => runProbe(setDbProbeResult, '/health/db', { method: 'POST' })}>\n Check database (create user)\n </button>"
|
|
201
|
-
: " <button onClick={() => runProbe(setDbProbeResult, '/api/health/db', { method: 'POST' })}>\n Check database (create user)\n </button>";
|
|
202
|
-
|
|
203
|
-
const actionsStart = content.indexOf('<div className="actions">');
|
|
204
|
-
if (actionsStart >= 0) {
|
|
205
|
-
const actionsEnd = content.indexOf('\n </div>', actionsStart);
|
|
206
|
-
if (actionsEnd >= 0) {
|
|
207
|
-
content = `${content.slice(0, actionsEnd)}\n${dbButton}${content.slice(actionsEnd)}`;
|
|
208
|
-
}
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (!content.includes("{renderResult('DB probe response', dbProbeResult)}")) {
|
|
213
|
-
const dbResultLine = " {renderResult('DB probe response', dbProbeResult)}";
|
|
214
|
-
const networkLine = ' {networkError ? <p className="error">{networkError}</p> : null}';
|
|
215
|
-
if (content.includes(networkLine)) {
|
|
216
|
-
content = content.replace(networkLine, `${dbResultLine}\n${networkLine}`);
|
|
217
|
-
} else {
|
|
218
|
-
const resultAnchor = "{renderResult('Validation probe response', validationProbeResult)}";
|
|
219
|
-
if (content.includes(resultAnchor)) {
|
|
220
|
-
content = ensureLineAfter(content, resultAnchor, dbResultLine);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
fs.writeFileSync(filePath, `${content.trimEnd()}\n`, 'utf8');
|
|
179
|
+
function registerWebProbe(targetRoot, probeTargets) {
|
|
180
|
+
ensureWebProbeDefinition({
|
|
181
|
+
targetRoot,
|
|
182
|
+
probeTargets,
|
|
183
|
+
definition: {
|
|
184
|
+
id: 'db',
|
|
185
|
+
title: 'Database',
|
|
186
|
+
buttonLabel: 'Check database (create user)',
|
|
187
|
+
resultTitle: 'DB probe response',
|
|
188
|
+
path: '/health/db',
|
|
189
|
+
request: { method: 'POST' },
|
|
190
|
+
},
|
|
191
|
+
});
|
|
226
192
|
}
|
|
227
193
|
|
|
228
194
|
function patchApiDockerfile(targetRoot) {
|
|
@@ -349,11 +315,13 @@ export function applyDbPrismaModule({ packageRoot, targetRoot }) {
|
|
|
349
315
|
copyFromPreset(packageRoot, targetRoot, path.join('packages', 'db-prisma'));
|
|
350
316
|
copyFromPreset(packageRoot, targetRoot, path.join('apps', 'api', 'prisma'));
|
|
351
317
|
|
|
318
|
+
const probeTargets = resolveProbeTargets({ targetRoot, moduleId: 'db-prisma' });
|
|
319
|
+
|
|
352
320
|
patchApiPackage(targetRoot);
|
|
353
321
|
patchRootPackage(targetRoot);
|
|
354
322
|
patchAppModule(targetRoot);
|
|
355
|
-
patchHealthController(targetRoot);
|
|
356
|
-
|
|
323
|
+
patchHealthController(targetRoot, probeTargets);
|
|
324
|
+
registerWebProbe(targetRoot, probeTargets);
|
|
357
325
|
patchApiDockerfile(targetRoot);
|
|
358
326
|
patchCompose(targetRoot);
|
|
359
327
|
patchReadme(targetRoot);
|