create-forgeon 0.1.24 → 0.1.26
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 +1 -1
- package/src/core/docs.test.mjs +8 -6
- package/src/modules/executor.test.mjs +8 -0
- package/src/modules/i18n.mjs +19 -1
- package/src/presets/i18n.mjs +76 -34
- package/templates/base/apps/api/Dockerfile +7 -4
- package/templates/base/apps/api/package.json +3 -2
- package/templates/base/apps/api/src/app.module.ts +4 -4
- package/templates/base/apps/api/src/health/health.controller.ts +41 -8
- package/templates/base/apps/api/src/main.ts +6 -8
- package/templates/base/apps/web/src/App.tsx +76 -35
- package/templates/base/apps/web/src/styles.css +29 -17
- package/templates/base/docs/AI/ARCHITECTURE.md +48 -32
- package/templates/base/docs/AI/MODULE_CHECKS.md +25 -0
- package/templates/base/docs/AI/MODULE_SPEC.md +1 -0
- package/templates/base/docs/AI/PROJECT.md +27 -16
- package/templates/base/docs/AI/TASKS.md +8 -7
- package/templates/base/docs/AI/VALIDATION.md +6 -1
- package/templates/base/docs/README.md +1 -0
- package/templates/base/packages/core/README.md +1 -0
- package/templates/base/packages/core/src/errors/core-exception.filter.ts +11 -3
- package/templates/base/packages/core/src/index.ts +1 -0
- package/templates/base/packages/core/src/validation/core-validation.pipe.ts +56 -0
- package/templates/base/packages/core/src/validation/index.ts +1 -0
- package/templates/base/packages/db-prisma/README.md +9 -0
- package/templates/base/packages/db-prisma/package.json +20 -0
- package/templates/base/packages/db-prisma/src/db-prisma-config.loader.ts +18 -0
- package/templates/base/packages/db-prisma/src/db-prisma-config.service.ts +12 -0
- package/templates/base/packages/db-prisma/src/db-prisma-env.schema.ts +17 -0
- package/templates/base/packages/db-prisma/src/db-prisma.module.ts +13 -0
- package/templates/base/packages/db-prisma/src/index.ts +5 -0
- package/templates/base/{apps/api/src/prisma → packages/db-prisma/src}/prisma.service.ts +24 -27
- package/templates/base/packages/db-prisma/tsconfig.json +9 -0
- package/templates/base/resources/i18n/en/common.json +3 -0
- package/templates/base/resources/i18n/uk/common.json +3 -0
- package/templates/docs-fragments/AI_ARCHITECTURE/20_env_base.md +1 -1
- package/templates/docs-fragments/AI_ARCHITECTURE/30_default_db.md +9 -7
- package/templates/docs-fragments/AI_ARCHITECTURE/32_scope_freeze.md +6 -5
- package/templates/docs-fragments/AI_PROJECT/20_structure_base.md +2 -1
- package/templates/module-presets/i18n/apps/web/src/App.tsx +63 -22
- package/templates/base/apps/api/src/prisma/prisma.module.ts +0 -9
|
@@ -5,10 +5,9 @@ import * as i18nWeb from '@forgeon/i18n-web';
|
|
|
5
5
|
import type { I18nLocale } from '@forgeon/i18n-web';
|
|
6
6
|
import './styles.css';
|
|
7
7
|
|
|
8
|
-
type
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
i18n: string;
|
|
8
|
+
type ProbeResult = {
|
|
9
|
+
statusCode: number;
|
|
10
|
+
body: unknown;
|
|
12
11
|
};
|
|
13
12
|
|
|
14
13
|
function localeLabelKey(locale: I18nLocale): string {
|
|
@@ -19,8 +18,11 @@ export default function App() {
|
|
|
19
18
|
const { t } = useTranslation(['common']);
|
|
20
19
|
const { I18N_LOCALES, getInitialLocale, persistLocale, toLangQuery } = i18nWeb;
|
|
21
20
|
const [locale, setLocale] = useState<I18nLocale>(getInitialLocale);
|
|
22
|
-
const [
|
|
23
|
-
const [
|
|
21
|
+
const [healthResult, setHealthResult] = useState<ProbeResult | null>(null);
|
|
22
|
+
const [errorProbeResult, setErrorProbeResult] = useState<ProbeResult | null>(null);
|
|
23
|
+
const [validationProbeResult, setValidationProbeResult] = useState<ProbeResult | null>(null);
|
|
24
|
+
const [dbProbeResult, setDbProbeResult] = useState<ProbeResult | null>(null);
|
|
25
|
+
const [networkError, setNetworkError] = useState<string | null>(null);
|
|
24
26
|
|
|
25
27
|
const changeLocale = (nextLocale: I18nLocale) => {
|
|
26
28
|
setLocale(nextLocale);
|
|
@@ -28,24 +30,49 @@ export default function App() {
|
|
|
28
30
|
void i18n.changeLanguage(nextLocale);
|
|
29
31
|
};
|
|
30
32
|
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
+
const requestProbe = async (path: string, init?: RequestInit): Promise<ProbeResult> => {
|
|
34
|
+
const response = await fetch(`/api${path}${toLangQuery(locale)}`, {
|
|
35
|
+
...init,
|
|
36
|
+
headers: {
|
|
37
|
+
...(init?.headers ?? {}),
|
|
38
|
+
'Accept-Language': locale,
|
|
39
|
+
},
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
let body: unknown = null;
|
|
43
|
+
try {
|
|
44
|
+
body = await response.json();
|
|
45
|
+
} catch {
|
|
46
|
+
body = { message: 'Non-JSON response' };
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
statusCode: response.status,
|
|
51
|
+
body,
|
|
52
|
+
};
|
|
53
|
+
};
|
|
54
|
+
|
|
55
|
+
const runProbe = async (
|
|
56
|
+
setter: (value: ProbeResult | null) => void,
|
|
57
|
+
path: string,
|
|
58
|
+
init?: RequestInit,
|
|
59
|
+
) => {
|
|
60
|
+
setNetworkError(null);
|
|
33
61
|
try {
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
'Accept-Language': locale,
|
|
37
|
-
},
|
|
38
|
-
});
|
|
39
|
-
if (!response.ok) {
|
|
40
|
-
throw new Error(`HTTP ${response.status}`);
|
|
41
|
-
}
|
|
42
|
-
const payload = (await response.json()) as HealthResponse;
|
|
43
|
-
setData(payload);
|
|
62
|
+
const result = await requestProbe(path, init);
|
|
63
|
+
setter(result);
|
|
44
64
|
} catch (err) {
|
|
45
|
-
|
|
65
|
+
setNetworkError(err instanceof Error ? err.message : 'Unknown error');
|
|
46
66
|
}
|
|
47
67
|
};
|
|
48
68
|
|
|
69
|
+
const renderResult = (title: string, result: ProbeResult | null) => (
|
|
70
|
+
<section>
|
|
71
|
+
<h3>{title}</h3>
|
|
72
|
+
{result ? <pre>{JSON.stringify(result, null, 2)}</pre> : null}
|
|
73
|
+
</section>
|
|
74
|
+
);
|
|
75
|
+
|
|
49
76
|
return (
|
|
50
77
|
<main className="page">
|
|
51
78
|
<h1>Forgeon Fullstack Scaffold</h1>
|
|
@@ -62,9 +89,23 @@ export default function App() {
|
|
|
62
89
|
</option>
|
|
63
90
|
))}
|
|
64
91
|
</select>
|
|
65
|
-
<
|
|
66
|
-
|
|
67
|
-
|
|
92
|
+
<div className="actions">
|
|
93
|
+
<button onClick={() => runProbe(setHealthResult, '/health')}>{t('common:checkApiHealth')}</button>
|
|
94
|
+
<button onClick={() => runProbe(setErrorProbeResult, '/health/error')}>
|
|
95
|
+
{t('common:checkErrorEnvelope')}
|
|
96
|
+
</button>
|
|
97
|
+
<button onClick={() => runProbe(setValidationProbeResult, '/health/validation')}>
|
|
98
|
+
{t('common:checkValidation')}
|
|
99
|
+
</button>
|
|
100
|
+
<button onClick={() => runProbe(setDbProbeResult, '/health/db', { method: 'POST' })}>
|
|
101
|
+
{t('common:checkDatabase')}
|
|
102
|
+
</button>
|
|
103
|
+
</div>
|
|
104
|
+
{renderResult('Health response', healthResult)}
|
|
105
|
+
{renderResult('Error probe response', errorProbeResult)}
|
|
106
|
+
{renderResult('Validation probe response', validationProbeResult)}
|
|
107
|
+
{renderResult('DB probe response', dbProbeResult)}
|
|
108
|
+
{networkError ? <p className="error">{networkError}</p> : null}
|
|
68
109
|
</main>
|
|
69
110
|
);
|
|
70
111
|
}
|