create-forgeon 0.3.23 → 0.3.24
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/README.md +14 -12
- package/package.json +1 -1
- package/src/modules/accounts.mjs +3 -1
- package/src/modules/communications.mjs +232 -0
- package/src/modules/dependencies.test.mjs +16 -2
- package/src/modules/executor.mjs +4 -0
- package/src/modules/executor.test.mjs +5 -2
- package/src/modules/registry.mjs +18 -2
- package/src/modules/shared/probes.mjs +3 -1
- package/src/run-add-module.test.mjs +4 -0
- package/templates/base/apps/web/src/App.tsx +75 -11
- package/templates/base/apps/web/src/probes.ts +11 -1
- package/templates/base/apps/web/src/styles.css +25 -0
- package/templates/module-fragments/accounts/20_scope.md +3 -2
- package/templates/module-fragments/accounts/90_status_implemented.md +2 -2
- package/templates/module-fragments/accounts/90_status_planned.md +1 -1
- package/templates/module-fragments/communications/00_title.md +1 -0
- package/templates/module-fragments/communications/10_overview.md +6 -0
- package/templates/module-fragments/communications/20_scope.md +20 -0
- package/templates/module-fragments/communications/90_status_implemented.md +8 -0
- package/templates/module-presets/accounts/packages/accounts-api/package.json +1 -0
- package/templates/module-presets/accounts/packages/accounts-api/src/auth-core.service.ts +60 -20
- package/templates/module-presets/accounts/packages/accounts-api/src/forgeon-accounts.module.ts +2 -6
- package/templates/module-presets/accounts/packages/accounts-api/src/index.ts +1 -1
- package/templates/module-presets/communications/packages/communications/package.json +23 -0
- package/templates/module-presets/communications/packages/communications/src/communications-config.loader.ts +58 -0
- package/templates/module-presets/communications/packages/communications/src/communications-config.module.ts +11 -0
- package/templates/module-presets/communications/packages/communications/src/communications-config.service.ts +60 -0
- package/templates/module-presets/communications/packages/communications/src/communications-env.schema.ts +24 -0
- package/templates/module-presets/communications/packages/communications/src/communications.constants.ts +3 -0
- package/templates/module-presets/communications/packages/communications/src/communications.probe.controller.ts +18 -0
- package/templates/module-presets/communications/packages/communications/src/communications.service.ts +104 -0
- package/templates/module-presets/communications/packages/communications/src/communications.types.ts +55 -0
- package/templates/module-presets/communications/packages/communications/src/dto/send-communications-probe.dto.ts +6 -0
- package/templates/module-presets/communications/packages/communications/src/email/email-channel.service.ts +90 -0
- package/templates/module-presets/communications/packages/communications/src/email/email-provider.port.ts +16 -0
- package/templates/module-presets/communications/packages/communications/src/email/providers/gmail-smtp-email.provider.ts +64 -0
- package/templates/module-presets/communications/packages/communications/src/forgeon-communications.module.ts +64 -0
- package/templates/module-presets/communications/packages/communications/src/index.ts +21 -0
- package/templates/module-presets/communications/packages/communications/src/push/providers/stub-push.provider.ts +16 -0
- package/templates/module-presets/communications/packages/communications/src/push/push-channel.service.ts +56 -0
- package/templates/module-presets/communications/packages/communications/src/push/push-provider.port.ts +14 -0
- package/templates/module-presets/communications/packages/communications/src/sms/providers/stub-sms.provider.ts +16 -0
- package/templates/module-presets/communications/packages/communications/src/sms/sms-channel.service.ts +56 -0
- package/templates/module-presets/communications/packages/communications/src/sms/sms-provider.port.ts +14 -0
- package/templates/module-presets/communications/packages/communications/src/template-loader.service.ts +98 -0
- package/templates/module-presets/communications/packages/communications/src/template-renderer.service.ts +30 -0
- package/templates/module-presets/communications/packages/communications/tsconfig.json +9 -0
- package/templates/module-presets/communications/resources/communications/email/communications_probe.html +9 -0
- package/templates/module-presets/communications/resources/communications/email/communications_probe.subject.txt +1 -0
- package/templates/module-presets/communications/resources/communications/email/email_verification_code.html +8 -0
- package/templates/module-presets/communications/resources/communications/email/email_verification_code.subject.txt +1 -0
- package/templates/module-presets/communications/resources/communications/email/password_reset.html +8 -0
- package/templates/module-presets/communications/resources/communications/email/password_reset.subject.txt +1 -0
- package/templates/module-presets/communications/resources/communications/email/welcome_email.html +8 -0
- package/templates/module-presets/communications/resources/communications/email/welcome_email.subject.txt +1 -0
- package/templates/module-presets/communications/resources/communications/push/login_alert.json +4 -0
- package/templates/module-presets/communications/resources/communications/sms/phone_verification.txt +1 -0
- package/templates/module-presets/i18n/apps/web/src/App.tsx +72 -8
- package/templates/module-presets/accounts/packages/accounts-api/src/accounts-email.port.ts +0 -13
|
@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next';
|
|
|
3
3
|
import i18n from './i18n';
|
|
4
4
|
import * as i18nWeb from '@forgeon/i18n-web';
|
|
5
5
|
import type { I18nLocale } from '@forgeon/i18n-web';
|
|
6
|
-
import { probeDefinitions, type ProbeDefinition, type ProbeResult } from './probes';
|
|
6
|
+
import { probeDefinitions, type ProbeDefinition, type ProbeInputDefinition, type ProbeResult } from './probes';
|
|
7
7
|
import './styles.css';
|
|
8
8
|
|
|
9
9
|
type ProbeState = {
|
|
@@ -12,17 +12,42 @@ type ProbeState = {
|
|
|
12
12
|
loading: boolean;
|
|
13
13
|
};
|
|
14
14
|
|
|
15
|
+
type ProbeInputState = Record<string, string>;
|
|
16
|
+
|
|
15
17
|
const emptyProbeState: ProbeState = {
|
|
16
18
|
result: null,
|
|
17
19
|
error: null,
|
|
18
20
|
loading: false,
|
|
19
21
|
};
|
|
20
22
|
|
|
23
|
+
function resolveBodyTemplate(value: unknown, inputs: ProbeInputState): unknown {
|
|
24
|
+
if (typeof value === 'string') {
|
|
25
|
+
const match = value.match(/^\$INPUT\.([a-zA-Z0-9_-]+)\$$/);
|
|
26
|
+
if (match) {
|
|
27
|
+
return inputs[match[1]] ?? '';
|
|
28
|
+
}
|
|
29
|
+
return value;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (Array.isArray(value)) {
|
|
33
|
+
return value.map((item) => resolveBodyTemplate(item, inputs));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (value && typeof value === 'object') {
|
|
37
|
+
return Object.fromEntries(
|
|
38
|
+
Object.entries(value).map(([key, nestedValue]) => [key, resolveBodyTemplate(nestedValue, inputs)]),
|
|
39
|
+
);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
44
|
+
|
|
21
45
|
export default function App() {
|
|
22
46
|
const { t } = useTranslation(['ui']);
|
|
23
47
|
const { I18N_LOCALES, getInitialLocale, persistLocale, toLangQuery } = i18nWeb;
|
|
24
48
|
const [locale, setLocale] = useState<I18nLocale>(getInitialLocale);
|
|
25
49
|
const [probeState, setProbeState] = useState<Record<string, ProbeState>>({});
|
|
50
|
+
const [probeInputs, setProbeInputs] = useState<Record<string, ProbeInputState>>({});
|
|
26
51
|
|
|
27
52
|
const changeLocale = (nextLocale: I18nLocale) => {
|
|
28
53
|
setLocale(nextLocale);
|
|
@@ -30,15 +55,39 @@ export default function App() {
|
|
|
30
55
|
void i18n.changeLanguage(nextLocale);
|
|
31
56
|
};
|
|
32
57
|
|
|
58
|
+
const getProbeInputValue = (probeId: string, input: ProbeInputDefinition): string => {
|
|
59
|
+
return probeInputs[probeId]?.[input.id] ?? input.defaultValue ?? '';
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
const updateProbeInput = (probeId: string, inputId: string, value: string) => {
|
|
63
|
+
setProbeInputs((current) => ({
|
|
64
|
+
...current,
|
|
65
|
+
[probeId]: {
|
|
66
|
+
...(current[probeId] ?? {}),
|
|
67
|
+
[inputId]: value,
|
|
68
|
+
},
|
|
69
|
+
}));
|
|
70
|
+
};
|
|
71
|
+
|
|
33
72
|
const requestProbe = async (probe: ProbeDefinition): Promise<ProbeResult> => {
|
|
34
|
-
const
|
|
35
|
-
|
|
73
|
+
const method = probe.request?.method ?? 'GET';
|
|
74
|
+
const headers: Record<string, string> = {
|
|
75
|
+
...(probe.request?.headers ?? {}),
|
|
76
|
+
'Accept-Language': locale,
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
const requestInit: RequestInit = {
|
|
80
|
+
method,
|
|
36
81
|
cache: 'no-store',
|
|
37
|
-
headers
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
82
|
+
headers,
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
if (method !== 'GET' && probe.request?.body !== undefined) {
|
|
86
|
+
headers['Content-Type'] = 'application/json';
|
|
87
|
+
requestInit.body = JSON.stringify(resolveBodyTemplate(probe.request.body, probeInputs[probe.id] ?? {}));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const response = await fetch(`/api${probe.path}${toLangQuery(locale)}`, requestInit);
|
|
42
91
|
|
|
43
92
|
let body: unknown = null;
|
|
44
93
|
try {
|
|
@@ -113,6 +162,21 @@ export default function App() {
|
|
|
113
162
|
{current.loading ? 'Running...' : probe.buttonLabel}
|
|
114
163
|
</button>
|
|
115
164
|
</div>
|
|
165
|
+
{probe.inputs?.length ? (
|
|
166
|
+
<div className="probe-inputs">
|
|
167
|
+
{probe.inputs.map((input) => (
|
|
168
|
+
<label key={`${probe.id}-${input.id}`} className="probe-input">
|
|
169
|
+
<span>{input.label}</span>
|
|
170
|
+
<input
|
|
171
|
+
type={input.type ?? 'text'}
|
|
172
|
+
value={getProbeInputValue(probe.id, input)}
|
|
173
|
+
placeholder={input.placeholder}
|
|
174
|
+
onChange={(event) => updateProbeInput(probe.id, input.id, event.target.value)}
|
|
175
|
+
/>
|
|
176
|
+
</label>
|
|
177
|
+
))}
|
|
178
|
+
</div>
|
|
179
|
+
) : null}
|
|
116
180
|
<div className="probe-output">
|
|
117
181
|
<h3>{probe.resultTitle}</h3>
|
|
118
182
|
{current.error ? <p className="error">{current.error}</p> : null}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
export const ACCOUNTS_EMAIL_PORT = 'FORGEON_ACCOUNTS_EMAIL_PORT';
|
|
2
|
-
|
|
3
|
-
export interface AccountsEmailPort {
|
|
4
|
-
sendVerificationEmail(input: { email: string; token: string; userId: string }): Promise<void>;
|
|
5
|
-
sendPasswordResetEmail(input: { email: string; token: string; userId: string }): Promise<void>;
|
|
6
|
-
sendWelcomeEmail(input: { email: string; userId: string }): Promise<void>;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
export class StubAccountsEmailAdapter implements AccountsEmailPort {
|
|
10
|
-
async sendVerificationEmail(): Promise<void> {}
|
|
11
|
-
async sendPasswordResetEmail(): Promise<void> {}
|
|
12
|
-
async sendWelcomeEmail(): Promise<void> {}
|
|
13
|
-
}
|