create-forgeon 0.2.1 → 0.2.2
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
CHANGED
|
@@ -324,6 +324,11 @@ function patchWebApp(targetRoot) {
|
|
|
324
324
|
}
|
|
325
325
|
|
|
326
326
|
let content = fs.readFileSync(filePath, 'utf8').replace(/\r\n/g, '\n');
|
|
327
|
+
content = content
|
|
328
|
+
.replace(/^\s*\{\/\* forgeon:probes:actions:start \*\/\}\r?\n?/gm, '')
|
|
329
|
+
.replace(/^\s*\{\/\* forgeon:probes:actions:end \*\/\}\r?\n?/gm, '')
|
|
330
|
+
.replace(/^\s*\{\/\* forgeon:probes:results:start \*\/\}\r?\n?/gm, '')
|
|
331
|
+
.replace(/^\s*\{\/\* forgeon:probes:results:end \*\/\}\r?\n?/gm, '');
|
|
327
332
|
|
|
328
333
|
if (!content.includes('dbProbeResult')) {
|
|
329
334
|
const stateAnchor = ' const [validationProbeResult, setValidationProbeResult] = useState<ProbeResult | null>(null);';
|
|
@@ -337,23 +342,29 @@ function patchWebApp(targetRoot) {
|
|
|
337
342
|
}
|
|
338
343
|
|
|
339
344
|
if (!content.includes('Check database (create user)')) {
|
|
340
|
-
const
|
|
341
|
-
const buttonAnchorI18n = " <button onClick={() => runProbe(setValidationProbeResult, '/health/validation')>";
|
|
342
|
-
const dbButton = content.includes(buttonAnchorI18n)
|
|
345
|
+
const dbButton = content.includes("runProbe(setHealthResult, '/health')")
|
|
343
346
|
? " <button onClick={() => runProbe(setDbProbeResult, '/health/db', { method: 'POST' })}>\n Check database (create user)\n </button>"
|
|
344
347
|
: " <button onClick={() => runProbe(setDbProbeResult, '/api/health/db', { method: 'POST' })}>\n Check database (create user)\n </button>";
|
|
345
348
|
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
349
|
+
const actionsStart = content.indexOf('<div className="actions">');
|
|
350
|
+
if (actionsStart >= 0) {
|
|
351
|
+
const actionsEnd = content.indexOf('\n </div>', actionsStart);
|
|
352
|
+
if (actionsEnd >= 0) {
|
|
353
|
+
content = `${content.slice(0, actionsEnd)}\n${dbButton}${content.slice(actionsEnd)}`;
|
|
354
|
+
}
|
|
350
355
|
}
|
|
351
356
|
}
|
|
352
357
|
|
|
353
358
|
if (!content.includes("{renderResult('DB probe response', dbProbeResult)}")) {
|
|
354
|
-
const
|
|
355
|
-
|
|
356
|
-
|
|
359
|
+
const dbResultLine = " {renderResult('DB probe response', dbProbeResult)}";
|
|
360
|
+
const networkLine = ' {networkError ? <p className="error">{networkError}</p> : null}';
|
|
361
|
+
if (content.includes(networkLine)) {
|
|
362
|
+
content = content.replace(networkLine, `${dbResultLine}\n${networkLine}`);
|
|
363
|
+
} else {
|
|
364
|
+
const resultAnchor = "{renderResult('Validation probe response', validationProbeResult)}";
|
|
365
|
+
if (content.includes(resultAnchor)) {
|
|
366
|
+
content = ensureLineAfter(content, resultAnchor, dbResultLine);
|
|
367
|
+
}
|
|
357
368
|
}
|
|
358
369
|
}
|
|
359
370
|
|
package/src/modules/jwt-auth.mjs
CHANGED
|
@@ -2,9 +2,6 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { copyRecursive, writeJson } from '../utils/fs.mjs';
|
|
4
4
|
|
|
5
|
-
const JWT_README_START = '<!-- forgeon:jwt-auth:start -->';
|
|
6
|
-
const JWT_README_END = '<!-- forgeon:jwt-auth:end -->';
|
|
7
|
-
|
|
8
5
|
function copyFromPreset(packageRoot, targetRoot, relativePath) {
|
|
9
6
|
const source = path.join(packageRoot, 'templates', 'module-presets', 'jwt-auth', relativePath);
|
|
10
7
|
if (!fs.existsSync(source)) {
|
|
@@ -356,30 +353,58 @@ function patchWebApp(targetRoot) {
|
|
|
356
353
|
}
|
|
357
354
|
|
|
358
355
|
let content = fs.readFileSync(filePath, 'utf8').replace(/\r\n/g, '\n');
|
|
356
|
+
content = content
|
|
357
|
+
.replace(/^\s*\{\/\* forgeon:probes:actions:start \*\/\}\r?\n?/gm, '')
|
|
358
|
+
.replace(/^\s*\{\/\* forgeon:probes:actions:end \*\/\}\r?\n?/gm, '')
|
|
359
|
+
.replace(/^\s*\{\/\* forgeon:probes:results:start \*\/\}\r?\n?/gm, '')
|
|
360
|
+
.replace(/^\s*\{\/\* forgeon:probes:results:end \*\/\}\r?\n?/gm, '');
|
|
361
|
+
|
|
359
362
|
if (!content.includes('authProbeResult')) {
|
|
360
|
-
content =
|
|
361
|
-
|
|
362
|
-
|
|
363
|
+
if (content.includes(' const [dbProbeResult, setDbProbeResult] = useState<ProbeResult | null>(null);')) {
|
|
364
|
+
content = content.replace(
|
|
365
|
+
' const [dbProbeResult, setDbProbeResult] = useState<ProbeResult | null>(null);',
|
|
366
|
+
` const [dbProbeResult, setDbProbeResult] = useState<ProbeResult | null>(null);
|
|
363
367
|
const [authProbeResult, setAuthProbeResult] = useState<ProbeResult | null>(null);`,
|
|
364
|
-
|
|
368
|
+
);
|
|
369
|
+
} else if (content.includes(' const [validationProbeResult, setValidationProbeResult] = useState<ProbeResult | null>(null);')) {
|
|
370
|
+
content = content.replace(
|
|
371
|
+
' const [validationProbeResult, setValidationProbeResult] = useState<ProbeResult | null>(null);',
|
|
372
|
+
` const [validationProbeResult, setValidationProbeResult] = useState<ProbeResult | null>(null);
|
|
373
|
+
const [authProbeResult, setAuthProbeResult] = useState<ProbeResult | null>(null);`,
|
|
374
|
+
);
|
|
375
|
+
}
|
|
365
376
|
}
|
|
366
377
|
|
|
367
378
|
if (!content.includes('Check JWT auth probe')) {
|
|
368
379
|
const path = content.includes("runProbe(setHealthResult, '/health')") ? '/health/auth' : '/api/health/auth';
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
380
|
+
const authButton = ` <button onClick={() => runProbe(setAuthProbeResult, '${path}')}>Check JWT auth probe</button>`;
|
|
381
|
+
const actionsStart = content.indexOf('<div className="actions">');
|
|
382
|
+
if (actionsStart >= 0) {
|
|
383
|
+
const actionsEnd = content.indexOf('\n </div>', actionsStart);
|
|
384
|
+
if (actionsEnd >= 0) {
|
|
385
|
+
content = `${content.slice(0, actionsEnd)}\n${authButton}${content.slice(actionsEnd)}`;
|
|
386
|
+
}
|
|
387
|
+
}
|
|
375
388
|
}
|
|
376
389
|
|
|
377
390
|
if (!content.includes("renderResult('Auth probe response', authProbeResult)")) {
|
|
378
|
-
|
|
379
|
-
"{
|
|
380
|
-
|
|
391
|
+
const authResultLine = " {renderResult('Auth probe response', authProbeResult)}";
|
|
392
|
+
const networkLine = ' {networkError ? <p className="error">{networkError}</p> : null}';
|
|
393
|
+
if (content.includes(networkLine)) {
|
|
394
|
+
content = content.replace(networkLine, `${authResultLine}\n${networkLine}`);
|
|
395
|
+
} else if (content.includes("{renderResult('DB probe response', dbProbeResult)}")) {
|
|
396
|
+
content = content.replace(
|
|
397
|
+
"{renderResult('DB probe response', dbProbeResult)}",
|
|
398
|
+
`{renderResult('DB probe response', dbProbeResult)}
|
|
381
399
|
{renderResult('Auth probe response', authProbeResult)}`,
|
|
382
|
-
|
|
400
|
+
);
|
|
401
|
+
} else if (content.includes("{renderResult('Validation probe response', validationProbeResult)}")) {
|
|
402
|
+
content = content.replace(
|
|
403
|
+
"{renderResult('Validation probe response', validationProbeResult)}",
|
|
404
|
+
`{renderResult('Validation probe response', validationProbeResult)}
|
|
405
|
+
{renderResult('Auth probe response', authProbeResult)}`,
|
|
406
|
+
);
|
|
407
|
+
}
|
|
383
408
|
}
|
|
384
409
|
|
|
385
410
|
fs.writeFileSync(filePath, `${content.trimEnd()}\n`, 'utf8');
|
|
@@ -480,8 +505,7 @@ function patchReadme(targetRoot, dbAdapter) {
|
|
|
480
505
|
1. install a DB module first (for now: \`create-forgeon add db-prisma --project .\`);
|
|
481
506
|
2. run \`create-forgeon add jwt-auth --project .\` again to auto-wire the adapter.`;
|
|
482
507
|
|
|
483
|
-
const section =
|
|
484
|
-
## JWT Auth Module
|
|
508
|
+
const section = `## JWT Auth Module
|
|
485
509
|
|
|
486
510
|
The jwt-auth add-module provides:
|
|
487
511
|
- \`@forgeon/auth-contracts\` shared auth routes/types/error codes
|
|
@@ -501,13 +525,19 @@ Default routes:
|
|
|
501
525
|
- \`POST /api/auth/login\`
|
|
502
526
|
- \`POST /api/auth/refresh\`
|
|
503
527
|
- \`POST /api/auth/logout\`
|
|
504
|
-
- \`GET /api/auth/me
|
|
505
|
-
${JWT_README_END}`;
|
|
528
|
+
- \`GET /api/auth/me\``;
|
|
506
529
|
|
|
507
530
|
let content = fs.readFileSync(readmePath, 'utf8').replace(/\r\n/g, '\n');
|
|
508
|
-
const
|
|
509
|
-
if (
|
|
510
|
-
|
|
531
|
+
const sectionHeading = '## JWT Auth Module';
|
|
532
|
+
if (content.includes(sectionHeading)) {
|
|
533
|
+
const start = content.indexOf(sectionHeading);
|
|
534
|
+
const tail = content.slice(start + sectionHeading.length);
|
|
535
|
+
const nextHeadingMatch = tail.match(/\n##\s+/);
|
|
536
|
+
const end =
|
|
537
|
+
nextHeadingMatch && nextHeadingMatch.index !== undefined
|
|
538
|
+
? start + sectionHeading.length + nextHeadingMatch.index + 1
|
|
539
|
+
: content.length;
|
|
540
|
+
content = `${content.slice(0, start)}${section}\n\n${content.slice(end).replace(/^\n+/, '')}`;
|
|
511
541
|
} else if (content.includes('## Prisma In Docker Start')) {
|
|
512
542
|
content = content.replace('## Prisma In Docker Start', `${section}\n\n## Prisma In Docker Start`);
|
|
513
543
|
} else {
|
|
@@ -566,6 +596,14 @@ export function applyJwtAuthModule({ packageRoot, targetRoot }) {
|
|
|
566
596
|
copyFromPreset(packageRoot, targetRoot, path.join('packages', 'auth-contracts'));
|
|
567
597
|
copyFromPreset(packageRoot, targetRoot, path.join('packages', 'auth-api'));
|
|
568
598
|
|
|
599
|
+
const swaggerPackagePath = path.join(targetRoot, 'packages', 'swagger', 'package.json');
|
|
600
|
+
const authApiPackagePath = path.join(targetRoot, 'packages', 'auth-api', 'package.json');
|
|
601
|
+
if (fs.existsSync(swaggerPackagePath) && fs.existsSync(authApiPackagePath)) {
|
|
602
|
+
const authApiPackage = JSON.parse(fs.readFileSync(authApiPackagePath, 'utf8'));
|
|
603
|
+
ensureDependency(authApiPackage, '@nestjs/swagger', '^11.2.0');
|
|
604
|
+
writeJson(authApiPackagePath, authApiPackage);
|
|
605
|
+
}
|
|
606
|
+
|
|
569
607
|
if (supportsPrismaStore) {
|
|
570
608
|
copyFromPreset(
|
|
571
609
|
packageRoot,
|
|
@@ -23,3 +23,6 @@ If a module can be validated through a safe API call, it must provide:
|
|
|
23
23
|
- If probe writes data, it must use clearly marked probe/test records.
|
|
24
24
|
- Probe should not require hidden setup beyond documented env/dependencies.
|
|
25
25
|
- `create-forgeon add <module>` must wire both API probe and web probe UI when feasible.
|
|
26
|
+
- Web probes should be appended to the existing probe UI structure in `apps/web/src/App.tsx`:
|
|
27
|
+
- add new action button at the end of `<div className="actions">`
|
|
28
|
+
- add new result block before the `networkError` render block
|
|
@@ -54,8 +54,14 @@ function syncJwtSwagger({ rootDir, changedFiles }) {
|
|
|
54
54
|
);
|
|
55
55
|
const loginDtoPath = path.join(rootDir, 'packages', 'auth-api', 'src', 'dto', 'login.dto.ts');
|
|
56
56
|
const refreshDtoPath = path.join(rootDir, 'packages', 'auth-api', 'src', 'dto', 'refresh.dto.ts');
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
const authApiPackagePath = path.join(rootDir, 'packages', 'auth-api', 'package.json');
|
|
58
|
+
|
|
59
|
+
if (
|
|
60
|
+
!fs.existsSync(controllerPath) ||
|
|
61
|
+
!fs.existsSync(loginDtoPath) ||
|
|
62
|
+
!fs.existsSync(refreshDtoPath) ||
|
|
63
|
+
!fs.existsSync(authApiPackagePath)
|
|
64
|
+
) {
|
|
59
65
|
return { applied: false, reason: 'jwt-auth source files are missing' };
|
|
60
66
|
}
|
|
61
67
|
|
|
@@ -153,6 +159,16 @@ function syncJwtSwagger({ rootDir, changedFiles }) {
|
|
|
153
159
|
changedFiles.add(loginDtoPath);
|
|
154
160
|
changedFiles.add(refreshDtoPath);
|
|
155
161
|
|
|
162
|
+
const authApiPackage = JSON.parse(fs.readFileSync(authApiPackagePath, 'utf8'));
|
|
163
|
+
if (!authApiPackage.dependencies) {
|
|
164
|
+
authApiPackage.dependencies = {};
|
|
165
|
+
}
|
|
166
|
+
if (!authApiPackage.dependencies['@nestjs/swagger']) {
|
|
167
|
+
authApiPackage.dependencies['@nestjs/swagger'] = '^11.2.0';
|
|
168
|
+
fs.writeFileSync(authApiPackagePath, `${JSON.stringify(authApiPackage, null, 2)}\n`, 'utf8');
|
|
169
|
+
changedFiles.add(authApiPackagePath);
|
|
170
|
+
}
|
|
171
|
+
|
|
156
172
|
return { applied: true };
|
|
157
173
|
}
|
|
158
174
|
|