@bleedingdev/modern-js-create 3.4.0-ultramodern.2 → 3.4.0-ultramodern.4
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/cjs/ultramodern-workspace/contracts.cjs +2 -0
- package/dist/cjs/ultramodern-workspace/demo-components.cjs +10 -19
- package/dist/cjs/ultramodern-workspace/effect-api.cjs +161 -30
- package/dist/cjs/ultramodern-workspace/module-federation.cjs +12 -4
- package/dist/cjs/ultramodern-workspace/package-json.cjs +12 -1
- package/dist/esm/ultramodern-workspace/contracts.js +2 -0
- package/dist/esm/ultramodern-workspace/demo-components.js +10 -19
- package/dist/esm/ultramodern-workspace/effect-api.js +161 -30
- package/dist/esm/ultramodern-workspace/module-federation.js +12 -4
- package/dist/esm/ultramodern-workspace/package-json.js +12 -1
- package/dist/esm-node/ultramodern-workspace/contracts.js +2 -0
- package/dist/esm-node/ultramodern-workspace/demo-components.js +10 -19
- package/dist/esm-node/ultramodern-workspace/effect-api.js +161 -30
- package/dist/esm-node/ultramodern-workspace/module-federation.js +12 -4
- package/dist/esm-node/ultramodern-workspace/package-json.js +12 -1
- package/package.json +3 -3
- package/template-workspace/pnpm-workspace.yaml.handlebars +8 -0
- package/template-workspace/scripts/bootstrap-agent-skills.mjs +19 -2
- package/templates/app/shell-frame.tsx +1 -2
- package/templates/app/ultramodern-route-head.tsx.handlebars +5 -6
- package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +91 -0
|
@@ -10,8 +10,7 @@ import { VerticalShowcase } from '../vertical-components';
|
|
|
10
10
|
import { ultramodernUiMarker } from '../../ultramodern-build';
|
|
11
11
|
|
|
12
12
|
export default function ShellHome() {
|
|
13
|
-
const {
|
|
14
|
-
const t = i18nInstance['t'].bind(i18nInstance);
|
|
13
|
+
const { t } = useModernI18n();
|
|
15
14
|
|
|
16
15
|
return (
|
|
17
16
|
<ShellFrame>
|
|
@@ -84,8 +83,7 @@ const loadRemoteComponent = (specifier: string) =>
|
|
|
84
83
|
|
|
85
84
|
const createRemoteFallback = (specifier: string) =>
|
|
86
85
|
({ error }: { error: Error }) => {
|
|
87
|
-
const {
|
|
88
|
-
const t = i18nInstance['t'].bind(i18nInstance);
|
|
86
|
+
const { t } = useModernI18n();
|
|
89
87
|
const classification = classifyModuleFederationFallback(error);
|
|
90
88
|
const telemetry = createModuleFederationFallbackTelemetry({
|
|
91
89
|
appName: '${shellApp.id}',
|
|
@@ -112,7 +110,7 @@ const createRemoteFallback = (specifier: string) =>
|
|
|
112
110
|
remote: specifier,
|
|
113
111
|
status: 'degraded',
|
|
114
112
|
});
|
|
115
|
-
}, [classification, error,
|
|
113
|
+
}, [classification, error, telemetry]);
|
|
116
114
|
|
|
117
115
|
return <div className="${tw('rounded-xl border border-red-900/20 bg-red-50 px-4 py-3 text-sm font-semibold text-red-900')}" data-remote-error={error.name} {...toModuleFederationFallbackAttributes(telemetry)}>{t('shell.remoteUnavailable')}</div>;
|
|
118
116
|
};
|
|
@@ -167,8 +165,7 @@ const createHydratedRemote =
|
|
|
167
165
|
${hydratedExports}
|
|
168
166
|
|
|
169
167
|
export const Header = () => {
|
|
170
|
-
const {
|
|
171
|
-
const t = i18nInstance['t'].bind(i18nInstance);
|
|
168
|
+
const { t } = useModernI18n();
|
|
172
169
|
|
|
173
170
|
return (
|
|
174
171
|
<header className="${tw('flex min-w-0 flex-wrap items-center gap-x-8 gap-y-2 md:flex-1')}" data-modern-boundary-id="${shellApp.mfName}" data-modern-mf-expose="shell/Header">
|
|
@@ -178,8 +175,7 @@ const createHydratedRemote =
|
|
|
178
175
|
};
|
|
179
176
|
|
|
180
177
|
export const StatusBadge = () => {
|
|
181
|
-
const {
|
|
182
|
-
const t = i18nInstance['t'].bind(i18nInstance);
|
|
178
|
+
const { t } = useModernI18n();
|
|
183
179
|
|
|
184
180
|
return (
|
|
185
181
|
<span className="${tw('inline-flex h-10 shrink-0 items-center justify-center rounded-full border border-stone-900/15 bg-white px-4 text-sm font-extrabold text-stone-950 shadow-lg shadow-stone-900/5')}">
|
|
@@ -189,8 +185,7 @@ export const StatusBadge = () => {
|
|
|
189
185
|
};
|
|
190
186
|
|
|
191
187
|
export const VerticalShowcase = () => {
|
|
192
|
-
const {
|
|
193
|
-
const t = i18nInstance['t'].bind(i18nInstance);
|
|
188
|
+
const { t } = useModernI18n();
|
|
194
189
|
|
|
195
190
|
if (widgetCount === 0) {
|
|
196
191
|
return (
|
|
@@ -257,8 +252,7 @@ import { ultramodernUiMarker } from '../../ultramodern-build';
|
|
|
257
252
|
` : '';
|
|
258
253
|
return `${effectBffImport}
|
|
259
254
|
export default function ${toPascalCase(app.id)}Home() {
|
|
260
|
-
const {
|
|
261
|
-
const t = i18nInstance['t'].bind(i18nInstance);
|
|
255
|
+
const { language, supportedLanguages, t } = useModernI18n();
|
|
262
256
|
${effectBffState} return (
|
|
263
257
|
<main className="${tw('min-h-screen bg-um-canvas px-4 py-6 text-um-foreground sm:px-8')}">
|
|
264
258
|
<UltramodernRouteHead />
|
|
@@ -304,8 +298,7 @@ function createRemoteEntry(app) {
|
|
|
304
298
|
return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
|
|
305
299
|
|
|
306
300
|
export default function ${toPascalCase(domain)}Route() {
|
|
307
|
-
const {
|
|
308
|
-
const t = i18nInstance['t'].bind(i18nInstance);
|
|
301
|
+
const { t } = useModernI18n();
|
|
309
302
|
|
|
310
303
|
return (
|
|
311
304
|
<section className="${tw('rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10')}" data-modern-boundary-id="${app.mfName}" data-modern-mf-expose="./Route">
|
|
@@ -323,8 +316,7 @@ function createRemoteWidget(app) {
|
|
|
323
316
|
return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
|
|
324
317
|
|
|
325
318
|
export default function ${componentName}() {
|
|
326
|
-
const {
|
|
327
|
-
const t = i18nInstance['t'].bind(i18nInstance);
|
|
319
|
+
const { t } = useModernI18n();
|
|
328
320
|
|
|
329
321
|
return (
|
|
330
322
|
<section className="${tw('rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10')}" data-modern-boundary-id="${app.mfName}" data-modern-mf-expose="./Widget">
|
|
@@ -343,8 +335,7 @@ function createRemoteExposeComponent(app, expose) {
|
|
|
343
335
|
return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
|
|
344
336
|
|
|
345
337
|
export default function ${componentName}() {
|
|
346
|
-
const {
|
|
347
|
-
const t = i18nInstance['t'].bind(i18nInstance);
|
|
338
|
+
const { t } = useModernI18n();
|
|
348
339
|
|
|
349
340
|
return (
|
|
350
341
|
<section className="${tw('rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10')}" data-modern-boundary-id="${app.mfName}" data-modern-mf-expose="${expose}">
|
|
@@ -36,27 +36,51 @@ function serviceHasCheckoutCartState(service) {
|
|
|
36
36
|
function createCheckoutCartSharedSchemas(service) {
|
|
37
37
|
if (!serviceHasCheckoutCartState(service)) return '';
|
|
38
38
|
return `
|
|
39
|
-
export
|
|
39
|
+
export interface CheckoutCartLine {
|
|
40
|
+
readonly sku: string;
|
|
41
|
+
readonly name: string;
|
|
42
|
+
readonly quantity: number;
|
|
43
|
+
readonly unitPriceCents: number;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface CheckoutCart {
|
|
47
|
+
readonly lines: ReadonlyArray<CheckoutCartLine>;
|
|
48
|
+
readonly subtotalCents: number;
|
|
49
|
+
readonly totalQuantity: number;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export interface CheckoutAddCartItemPayload {
|
|
53
|
+
readonly sku: string;
|
|
54
|
+
readonly name?: string;
|
|
55
|
+
readonly quantity: number;
|
|
56
|
+
readonly unitPriceCents?: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface CheckoutRemoveCartItemPayload {
|
|
60
|
+
readonly sku: string;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export const checkoutCartLineSchema: Schema.Schema<CheckoutCartLine> = Schema.Struct({
|
|
40
64
|
sku: Schema.String,
|
|
41
65
|
name: Schema.String,
|
|
42
66
|
quantity: Schema.Finite,
|
|
43
67
|
unitPriceCents: Schema.Finite,
|
|
44
68
|
});
|
|
45
69
|
|
|
46
|
-
export const checkoutCartSchema = Schema.Struct({
|
|
70
|
+
export const checkoutCartSchema: Schema.Schema<CheckoutCart> = Schema.Struct({
|
|
47
71
|
lines: Schema.Array(checkoutCartLineSchema),
|
|
48
72
|
subtotalCents: Schema.Finite,
|
|
49
73
|
totalQuantity: Schema.Finite,
|
|
50
74
|
});
|
|
51
75
|
|
|
52
|
-
export const checkoutAddCartItemPayloadSchema = Schema.Struct({
|
|
76
|
+
export const checkoutAddCartItemPayloadSchema: Schema.Schema<CheckoutAddCartItemPayload> = Schema.Struct({
|
|
53
77
|
sku: Schema.String,
|
|
54
78
|
name: Schema.optional(Schema.String),
|
|
55
79
|
quantity: Schema.Finite,
|
|
56
80
|
unitPriceCents: Schema.optional(Schema.Finite),
|
|
57
81
|
});
|
|
58
82
|
|
|
59
|
-
export const checkoutRemoveCartItemPayloadSchema = Schema.Struct({
|
|
83
|
+
export const checkoutRemoveCartItemPayloadSchema: Schema.Schema<CheckoutRemoveCartItemPayload> = Schema.Struct({
|
|
60
84
|
sku: Schema.String,
|
|
61
85
|
});
|
|
62
86
|
`;
|
|
@@ -209,6 +233,7 @@ function createCheckoutCartClientExports(service) {
|
|
|
209
233
|
const pascalStem = toPascalCase(stem);
|
|
210
234
|
const clientOptionsName = `${pascalStem}ClientOptions`;
|
|
211
235
|
const createClientName = `create${pascalStem}Client`;
|
|
236
|
+
const clientEffectTypeName = `${pascalStem}ClientEffect`;
|
|
212
237
|
return `
|
|
213
238
|
export interface CheckoutCartLine {
|
|
214
239
|
sku: string;
|
|
@@ -232,7 +257,7 @@ export interface CheckoutAddCartItemInput {
|
|
|
232
257
|
|
|
233
258
|
export const getCheckoutCart = (
|
|
234
259
|
options: ${clientOptionsName} = {},
|
|
235
|
-
) =>
|
|
260
|
+
): ${clientEffectTypeName}<CheckoutCart> =>
|
|
236
261
|
${createClientName}({
|
|
237
262
|
...options,
|
|
238
263
|
operationContext:
|
|
@@ -244,7 +269,7 @@ export const getCheckoutCart = (
|
|
|
244
269
|
export const addCheckoutCartItem = (
|
|
245
270
|
payload: CheckoutAddCartItemInput,
|
|
246
271
|
options: ${clientOptionsName} = {},
|
|
247
|
-
) =>
|
|
272
|
+
): ${clientEffectTypeName}<CheckoutCart> =>
|
|
248
273
|
${createClientName}({
|
|
249
274
|
...options,
|
|
250
275
|
operationContext:
|
|
@@ -258,7 +283,7 @@ export const addCheckoutCartItem = (
|
|
|
258
283
|
export const removeCheckoutCartItem = (
|
|
259
284
|
sku: string,
|
|
260
285
|
options: ${clientOptionsName} = {},
|
|
261
|
-
) =>
|
|
286
|
+
): ${clientEffectTypeName}<CheckoutCart> =>
|
|
262
287
|
${createClientName}({
|
|
263
288
|
...options,
|
|
264
289
|
operationContext:
|
|
@@ -271,7 +296,7 @@ export const removeCheckoutCartItem = (
|
|
|
271
296
|
|
|
272
297
|
export const clearCheckoutCart = (
|
|
273
298
|
options: ${clientOptionsName} = {},
|
|
274
|
-
) =>
|
|
299
|
+
): ${clientEffectTypeName}<CheckoutCart> =>
|
|
275
300
|
${createClientName}({
|
|
276
301
|
...options,
|
|
277
302
|
operationContext:
|
|
@@ -302,12 +327,63 @@ function createEffectSharedApiContract(service) {
|
|
|
302
327
|
const apiName = verticalEffectApiName(service);
|
|
303
328
|
const groupName = verticalEffectGroupName(service);
|
|
304
329
|
const stem = effectApiStem(service);
|
|
330
|
+
const pascalStem = toPascalCase(stem);
|
|
331
|
+
const markerType = `${pascalStem}Marker`;
|
|
332
|
+
const itemType = `${pascalStem}Item`;
|
|
333
|
+
const readinessType = `${pascalStem}Readiness`;
|
|
334
|
+
const createPayloadType = `${pascalStem}CreatePayload`;
|
|
335
|
+
const createResponseType = `${pascalStem}CreateResponse`;
|
|
336
|
+
const listResponseType = `${pascalStem}ListResponse`;
|
|
305
337
|
const apiPrefix = effectApiPrefix(service);
|
|
306
338
|
const checkoutCartSharedSchemas = createCheckoutCartSharedSchemas(service);
|
|
307
339
|
const checkoutCartSharedSchemaSection = '' === checkoutCartSharedSchemas ? '' : `${checkoutCartSharedSchemas}\n`;
|
|
308
340
|
const checkoutCartOperationContexts = createCheckoutCartOperationContexts(service).trimStart();
|
|
309
341
|
const checkoutCartOperationContextEntries = '' === checkoutCartOperationContexts ? '' : `${checkoutCartOperationContexts}\n`;
|
|
310
|
-
return `export
|
|
342
|
+
return `export interface ${markerType} {
|
|
343
|
+
readonly appId: string;
|
|
344
|
+
readonly build: string;
|
|
345
|
+
readonly deployProfile: string;
|
|
346
|
+
readonly packageName: string;
|
|
347
|
+
readonly surface: string;
|
|
348
|
+
readonly version: string;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
export interface ${itemType} {
|
|
352
|
+
readonly id: string;
|
|
353
|
+
readonly marker: ${markerType};
|
|
354
|
+
readonly title: string;
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
export interface ${readinessType} {
|
|
358
|
+
readonly checks: {
|
|
359
|
+
readonly effectBff: 'ready';
|
|
360
|
+
readonly moduleFederation: 'ready';
|
|
361
|
+
readonly ssr: 'ready';
|
|
362
|
+
readonly translations: 'ready';
|
|
363
|
+
};
|
|
364
|
+
readonly marker: ${markerType};
|
|
365
|
+
readonly status: 'ready';
|
|
366
|
+
readonly versionSkew: 'none';
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
export interface ${createPayloadType} {
|
|
370
|
+
readonly title: string;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
export interface ${listResponseType} {
|
|
374
|
+
readonly items: ReadonlyArray<${itemType}>;
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
export interface ${createResponseType} {
|
|
378
|
+
readonly item: ${itemType};
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
export interface ${notFoundErrorExport} {
|
|
382
|
+
readonly _tag: '${notFoundErrorExport}';
|
|
383
|
+
readonly id: string;
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
export const ${markerSchemaExport}: Schema.Schema<${markerType}> = Schema.Struct({
|
|
311
387
|
appId: Schema.String,
|
|
312
388
|
build: Schema.String,
|
|
313
389
|
deployProfile: Schema.String,
|
|
@@ -316,13 +392,13 @@ function createEffectSharedApiContract(service) {
|
|
|
316
392
|
version: Schema.String,
|
|
317
393
|
});
|
|
318
394
|
|
|
319
|
-
export const ${schemaExport} = Schema.Struct({
|
|
395
|
+
export const ${schemaExport}: Schema.Schema<${itemType}> = Schema.Struct({
|
|
320
396
|
id: Schema.String,
|
|
321
397
|
marker: ${markerSchemaExport},
|
|
322
398
|
title: Schema.String,
|
|
323
399
|
});
|
|
324
400
|
|
|
325
|
-
export const ${readinessSchemaExport} = Schema.Struct({
|
|
401
|
+
export const ${readinessSchemaExport}: Schema.Schema<${readinessType}> = Schema.Struct({
|
|
326
402
|
checks: Schema.Struct({
|
|
327
403
|
effectBff: Schema.Literal('ready'),
|
|
328
404
|
moduleFederation: Schema.Literal('ready'),
|
|
@@ -334,18 +410,13 @@ export const ${readinessSchemaExport} = Schema.Struct({
|
|
|
334
410
|
versionSkew: Schema.Literal('none'),
|
|
335
411
|
});
|
|
336
412
|
|
|
337
|
-
export const ${createPayloadSchemaExport} = Schema.Struct({
|
|
413
|
+
export const ${createPayloadSchemaExport}: Schema.Schema<${createPayloadType}> = Schema.Struct({
|
|
338
414
|
title: Schema.String,
|
|
339
415
|
});
|
|
340
416
|
|
|
341
|
-
${checkoutCartSharedSchemaSection}export
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
id: Schema.String,
|
|
345
|
-
},
|
|
346
|
-
) {}
|
|
347
|
-
|
|
348
|
-
export const ${notFoundSchemaExport} = ${notFoundErrorExport}.pipe(
|
|
417
|
+
${checkoutCartSharedSchemaSection}export const ${notFoundSchemaExport}: Schema.Schema<${notFoundErrorExport}> = Schema.TaggedStruct('${notFoundErrorExport}', {
|
|
418
|
+
id: Schema.String,
|
|
419
|
+
}).pipe(
|
|
349
420
|
HttpApiSchema.status(404),
|
|
350
421
|
);
|
|
351
422
|
|
|
@@ -449,13 +520,20 @@ function createEffectServiceEntry(service, contractImportPath) {
|
|
|
449
520
|
HttpApiBuilder,
|
|
450
521
|
Layer,
|
|
451
522
|
} from '@modern-js/plugin-bff/effect-edge';
|
|
523
|
+
import type {
|
|
524
|
+
EffectBffDefinition,
|
|
525
|
+
EffectBffRuntime,
|
|
526
|
+
EffectRuntimeLayer,
|
|
527
|
+
} from '@modern-js/plugin-bff/effect-edge';
|
|
452
528
|
import { ultramodernApiMarker } from '../../src/ultramodern-build.ts';
|
|
453
529
|
import {
|
|
454
530
|
${apiExport},
|
|
455
531
|
${groupName}OperationContexts,
|
|
532
|
+
} from '${contractImportPath}';
|
|
533
|
+
import type {
|
|
456
534
|
${notFoundErrorExport},
|
|
535
|
+
OperationContext,
|
|
457
536
|
} from '${contractImportPath}';
|
|
458
|
-
import type { OperationContext } from '${contractImportPath}';
|
|
459
537
|
|
|
460
538
|
const ${groupName}Items = [
|
|
461
539
|
{
|
|
@@ -516,9 +594,13 @@ const ${groupName}Layer = HttpApiBuilder.group(
|
|
|
516
594
|
const matchedItem = ${groupName}Items.find(
|
|
517
595
|
candidate => candidate.id === params.id,
|
|
518
596
|
);
|
|
597
|
+
const notFound: ${notFoundErrorExport} = {
|
|
598
|
+
_tag: '${notFoundErrorExport}',
|
|
599
|
+
id: params.id,
|
|
600
|
+
};
|
|
519
601
|
const result =
|
|
520
602
|
matchedItem === undefined
|
|
521
|
-
? Effect.fail(
|
|
603
|
+
? Effect.fail(notFound)
|
|
522
604
|
: Effect.succeed(matchedItem);
|
|
523
605
|
|
|
524
606
|
return result.pipe(
|
|
@@ -549,12 +631,15 @@ const ${groupName}Layer = HttpApiBuilder.group(
|
|
|
549
631
|
|
|
550
632
|
const layer = HttpApiBuilder.layer(${apiExport}).pipe(
|
|
551
633
|
Layer.provide(${groupName}Layer),
|
|
552
|
-
);
|
|
634
|
+
) satisfies EffectRuntimeLayer;
|
|
553
635
|
|
|
554
|
-
|
|
636
|
+
const effectBff: EffectBffDefinition<typeof ${apiExport}, EffectRuntimeLayer> &
|
|
637
|
+
EffectBffRuntime<typeof ${apiExport}, EffectRuntimeLayer> = defineEffectBff({
|
|
555
638
|
api: ${apiExport},
|
|
556
639
|
layer,
|
|
557
640
|
});
|
|
641
|
+
|
|
642
|
+
export default effectBff;
|
|
558
643
|
`;
|
|
559
644
|
}
|
|
560
645
|
function createEffectClient(service, contractImportPath) {
|
|
@@ -565,25 +650,71 @@ function createEffectClient(service, contractImportPath) {
|
|
|
565
650
|
const singular = verticalEffectErrorStem(service);
|
|
566
651
|
const clientOptionsName = `${toPascalCase(stem)}ClientOptions`;
|
|
567
652
|
const createClientName = `create${toPascalCase(stem)}Client`;
|
|
653
|
+
const clientTypeName = `${toPascalCase(stem)}Client`;
|
|
654
|
+
const clientEffectTypeName = `${toPascalCase(stem)}ClientEffect`;
|
|
568
655
|
const listName = `list${toPascalCase(stem)}`;
|
|
569
656
|
const readinessName = `get${toPascalCase(stem)}Readiness`;
|
|
570
657
|
const getName = `get${toPascalCase(singular)}`;
|
|
571
658
|
const createName = `create${toPascalCase(singular)}`;
|
|
659
|
+
const notFoundErrorExport = verticalEffectNotFoundErrorExport(service);
|
|
660
|
+
const pascalStem = toPascalCase(stem);
|
|
661
|
+
const itemType = `${pascalStem}Item`;
|
|
662
|
+
const readinessType = `${pascalStem}Readiness`;
|
|
663
|
+
const createResponseType = `${pascalStem}CreateResponse`;
|
|
664
|
+
const listResponseType = `${pascalStem}ListResponse`;
|
|
572
665
|
const checkoutCartClientExports = createCheckoutCartClientExports(service);
|
|
573
666
|
return `import {
|
|
574
667
|
Effect,
|
|
575
668
|
makeEffectHttpApiClient,
|
|
576
669
|
runEffectRequest,
|
|
577
670
|
} from '@modern-js/plugin-bff/effect-client';
|
|
671
|
+
import type {
|
|
672
|
+
HttpClientError,
|
|
673
|
+
HttpApi,
|
|
674
|
+
HttpApiClient,
|
|
675
|
+
HttpApiGroup,
|
|
676
|
+
Schema,
|
|
677
|
+
} from '@modern-js/plugin-bff/effect-client';
|
|
578
678
|
import {
|
|
579
679
|
${contractExport}ApiContract,
|
|
580
680
|
${apiExport},
|
|
581
681
|
${groupName}OperationContexts,
|
|
582
682
|
} from '${contractImportPath}';
|
|
583
|
-
import type {
|
|
683
|
+
import type {
|
|
684
|
+
${createResponseType},
|
|
685
|
+
${itemType},
|
|
686
|
+
${listResponseType},
|
|
687
|
+
${notFoundErrorExport},
|
|
688
|
+
OperationContext,
|
|
689
|
+
${readinessType},
|
|
690
|
+
} from '${contractImportPath}';
|
|
584
691
|
|
|
585
692
|
export { Effect, runEffectRequest };
|
|
586
693
|
|
|
694
|
+
type ${pascalStem}EffectGroups = typeof ${apiExport} extends HttpApi.HttpApi<
|
|
695
|
+
infer _ApiId,
|
|
696
|
+
infer Groups
|
|
697
|
+
>
|
|
698
|
+
? Groups
|
|
699
|
+
: never;
|
|
700
|
+
|
|
701
|
+
export type ${clientTypeName} = HttpApiClient.Client<
|
|
702
|
+
Extract<${pascalStem}EffectGroups, HttpApiGroup.Any>,
|
|
703
|
+
never,
|
|
704
|
+
never
|
|
705
|
+
>;
|
|
706
|
+
|
|
707
|
+
export type ${pascalStem}ClientError =
|
|
708
|
+
| ${notFoundErrorExport}
|
|
709
|
+
| HttpClientError.HttpClientError
|
|
710
|
+
| Schema.SchemaError;
|
|
711
|
+
|
|
712
|
+
export type ${clientEffectTypeName}<Success> = Effect.Effect<
|
|
713
|
+
Success,
|
|
714
|
+
${pascalStem}ClientError,
|
|
715
|
+
never
|
|
716
|
+
>;
|
|
717
|
+
|
|
587
718
|
export interface ${clientOptionsName} {
|
|
588
719
|
baseUrl?: string | URL;
|
|
589
720
|
locale?: string;
|
|
@@ -593,7 +724,7 @@ export interface ${clientOptionsName} {
|
|
|
593
724
|
|
|
594
725
|
export const ${createClientName} = (
|
|
595
726
|
options: ${clientOptionsName} = {},
|
|
596
|
-
) =>
|
|
727
|
+
): ${clientEffectTypeName}<${clientTypeName}> =>
|
|
597
728
|
makeEffectHttpApiClient(${apiExport}, {
|
|
598
729
|
baseUrl: options.baseUrl ?? ${contractExport}ApiContract.apiPrefix,
|
|
599
730
|
requestContext: {
|
|
@@ -609,7 +740,7 @@ export const ${createClientName} = (
|
|
|
609
740
|
|
|
610
741
|
export const ${listName} = (
|
|
611
742
|
options: ${clientOptionsName} & { limit?: number } = {},
|
|
612
|
-
) =>
|
|
743
|
+
): ${clientEffectTypeName}<${listResponseType}> =>
|
|
613
744
|
${createClientName}({
|
|
614
745
|
...options,
|
|
615
746
|
operationContext:
|
|
@@ -622,7 +753,7 @@ export const ${listName} = (
|
|
|
622
753
|
|
|
623
754
|
export const ${readinessName} = (
|
|
624
755
|
options: ${clientOptionsName} = {},
|
|
625
|
-
) =>
|
|
756
|
+
): ${clientEffectTypeName}<${readinessType}> =>
|
|
626
757
|
${createClientName}({
|
|
627
758
|
...options,
|
|
628
759
|
operationContext:
|
|
@@ -634,7 +765,7 @@ export const ${readinessName} = (
|
|
|
634
765
|
export const ${getName} = (
|
|
635
766
|
id: string,
|
|
636
767
|
options: ${clientOptionsName} = {},
|
|
637
|
-
) =>
|
|
768
|
+
): ${clientEffectTypeName}<${itemType}> =>
|
|
638
769
|
${createClientName}({
|
|
639
770
|
...options,
|
|
640
771
|
operationContext:
|
|
@@ -646,7 +777,7 @@ export const ${getName} = (
|
|
|
646
777
|
export const ${createName} = (
|
|
647
778
|
title: string,
|
|
648
779
|
options: ${clientOptionsName} = {},
|
|
649
|
-
) =>
|
|
780
|
+
): ${clientEffectTypeName}<${createResponseType}> =>
|
|
650
781
|
${createClientName}({
|
|
651
782
|
...options,
|
|
652
783
|
operationContext:
|
|
@@ -217,12 +217,12 @@ ${bffPluginEntry} moduleFederationPlugin(),
|
|
|
217
217
|
}
|
|
218
218
|
function createSharedModuleFederationConfig() {
|
|
219
219
|
return ` shared: {
|
|
220
|
-
'@modern-js/plugin-i18n/runtime
|
|
220
|
+
'@modern-js/plugin-i18n/runtime': {
|
|
221
221
|
requiredVersion: pluginI18nVersion,
|
|
222
222
|
singleton: true,
|
|
223
223
|
treeShaking: false,
|
|
224
224
|
},
|
|
225
|
-
'@modern-js/plugin-i18n/runtime': {
|
|
225
|
+
'@modern-js/plugin-i18n/runtime/no-react-i18next': {
|
|
226
226
|
requiredVersion: pluginI18nVersion,
|
|
227
227
|
singleton: true,
|
|
228
228
|
treeShaking: false,
|
|
@@ -342,7 +342,9 @@ const reactVersion = (require('react/package.json') as { version: string }).vers
|
|
|
342
342
|
const reactDomVersion = (require('react-dom/package.json') as { version: string }).version;
|
|
343
343
|
|
|
344
344
|
${createModuleFederationRemoteUrlHelpers(shellHost, remotes)}
|
|
345
|
-
|
|
345
|
+
const moduleFederationConfig: Parameters<
|
|
346
|
+
typeof createModuleFederationConfig
|
|
347
|
+
>[0] = createModuleFederationConfig({
|
|
346
348
|
bridge: {
|
|
347
349
|
enableBridgeRouter: false,
|
|
348
350
|
},
|
|
@@ -360,6 +362,8 @@ export default createModuleFederationConfig({
|
|
|
360
362
|
${createModuleFederationRemotesConfig(scope, shellHost, remotes)}${createSharedModuleFederationConfig()},
|
|
361
363
|
treeShakingSharedExcludePlugins: ['RspackModuleFederationPlugin'],
|
|
362
364
|
});
|
|
365
|
+
|
|
366
|
+
export default moduleFederationConfig;
|
|
363
367
|
`;
|
|
364
368
|
}
|
|
365
369
|
function createBuildMarker(scope, app) {
|
|
@@ -400,7 +404,9 @@ const reactVersion = (require('react/package.json') as { version: string }).vers
|
|
|
400
404
|
const reactDomVersion = (require('react-dom/package.json') as { version: string }).version;
|
|
401
405
|
|
|
402
406
|
${createModuleFederationRemoteUrlHelpers(app, remotes)}
|
|
403
|
-
|
|
407
|
+
const moduleFederationConfig: Parameters<
|
|
408
|
+
typeof createModuleFederationConfig
|
|
409
|
+
>[0] = createModuleFederationConfig({
|
|
404
410
|
bridge: {
|
|
405
411
|
enableBridgeRouter: false,
|
|
406
412
|
},
|
|
@@ -419,6 +425,8 @@ export default createModuleFederationConfig({
|
|
|
419
425
|
${createModuleFederationRemotesConfig(scope, app, remotes)}${createSharedModuleFederationConfig()},
|
|
420
426
|
treeShakingSharedExcludePlugins: ['RspackModuleFederationPlugin'],
|
|
421
427
|
});
|
|
428
|
+
|
|
429
|
+
export default moduleFederationConfig;
|
|
422
430
|
`;
|
|
423
431
|
}
|
|
424
432
|
export { createAppModernConfig, createBuildMarker, createModuleFederationRemoteUrlHelpers, createModuleFederationRemotesConfig, createRemoteModuleFederationConfig, createSharedModuleFederationConfig, createShellModuleFederationConfig, createUltramodernBuildModule, formatTsObjectLiteral };
|
|
@@ -255,6 +255,10 @@ function createTsBuildInfoFile(packageDir) {
|
|
|
255
255
|
const cacheKey = packageDir.replace(/[^a-zA-Z0-9._-]+/gu, '__');
|
|
256
256
|
return `${relativeRootFor(packageDir)}/node_modules/.cache/tsgo/${cacheKey}.tsbuildinfo`;
|
|
257
257
|
}
|
|
258
|
+
function createTsDeclarationOutDir(packageDir) {
|
|
259
|
+
const cacheKey = packageDir.replace(/[^a-zA-Z0-9._-]+/gu, '__');
|
|
260
|
+
return `${relativeRootFor(packageDir)}/node_modules/.cache/tsgo/declarations/${cacheKey}`;
|
|
261
|
+
}
|
|
258
262
|
function createReferences(packageDir, references) {
|
|
259
263
|
return [
|
|
260
264
|
...new Set(references)
|
|
@@ -268,8 +272,10 @@ function createPackageTsConfig(packageDir, options = {}) {
|
|
|
268
272
|
} : options;
|
|
269
273
|
const include = resolvedOptions.include ?? [
|
|
270
274
|
'src',
|
|
275
|
+
'locales/**/*.json',
|
|
271
276
|
'modern.config.ts',
|
|
272
|
-
'module-federation.config.ts'
|
|
277
|
+
'module-federation.config.ts',
|
|
278
|
+
'package.json'
|
|
273
279
|
];
|
|
274
280
|
if (resolvedOptions.includeApi) include.push('api', 'shared');
|
|
275
281
|
const references = createReferences(packageDir, resolvedOptions.references ?? []);
|
|
@@ -277,7 +283,12 @@ function createPackageTsConfig(packageDir, options = {}) {
|
|
|
277
283
|
extends: `${relativeRootFor(packageDir)}/tsconfig.base.json`,
|
|
278
284
|
compilerOptions: {
|
|
279
285
|
composite: true,
|
|
286
|
+
declaration: true,
|
|
287
|
+
declarationMap: false,
|
|
288
|
+
emitDeclarationOnly: true,
|
|
280
289
|
incremental: true,
|
|
290
|
+
noEmit: false,
|
|
291
|
+
outDir: createTsDeclarationOutDir(packageDir),
|
|
281
292
|
tsBuildInfoFile: createTsBuildInfoFile(packageDir)
|
|
282
293
|
},
|
|
283
294
|
include
|
|
@@ -669,6 +669,7 @@ function createTemplateManifest(modernVersion, packageSource) {
|
|
|
669
669
|
'pnpm-workspace.yaml',
|
|
670
670
|
"scripts/**",
|
|
671
671
|
'topology/**',
|
|
672
|
+
'tsconfig.json',
|
|
672
673
|
'tsconfig.base.json'
|
|
673
674
|
],
|
|
674
675
|
deniedPaths: [
|
|
@@ -733,6 +734,7 @@ function createTemplateManifest(modernVersion, packageSource) {
|
|
|
733
734
|
expectedCommands: [
|
|
734
735
|
'mise install',
|
|
735
736
|
'pnpm install',
|
|
737
|
+
'pnpm run typecheck',
|
|
736
738
|
'pnpm run i18n:boundaries',
|
|
737
739
|
'pnpm run contract:check',
|
|
738
740
|
'pnpm run performance:readiness'
|
|
@@ -11,8 +11,7 @@ import { VerticalShowcase } from '../vertical-components';
|
|
|
11
11
|
import { ultramodernUiMarker } from '../../ultramodern-build';
|
|
12
12
|
|
|
13
13
|
export default function ShellHome() {
|
|
14
|
-
const {
|
|
15
|
-
const t = i18nInstance['t'].bind(i18nInstance);
|
|
14
|
+
const { t } = useModernI18n();
|
|
16
15
|
|
|
17
16
|
return (
|
|
18
17
|
<ShellFrame>
|
|
@@ -85,8 +84,7 @@ const loadRemoteComponent = (specifier: string) =>
|
|
|
85
84
|
|
|
86
85
|
const createRemoteFallback = (specifier: string) =>
|
|
87
86
|
({ error }: { error: Error }) => {
|
|
88
|
-
const {
|
|
89
|
-
const t = i18nInstance['t'].bind(i18nInstance);
|
|
87
|
+
const { t } = useModernI18n();
|
|
90
88
|
const classification = classifyModuleFederationFallback(error);
|
|
91
89
|
const telemetry = createModuleFederationFallbackTelemetry({
|
|
92
90
|
appName: '${shellApp.id}',
|
|
@@ -113,7 +111,7 @@ const createRemoteFallback = (specifier: string) =>
|
|
|
113
111
|
remote: specifier,
|
|
114
112
|
status: 'degraded',
|
|
115
113
|
});
|
|
116
|
-
}, [classification, error,
|
|
114
|
+
}, [classification, error, telemetry]);
|
|
117
115
|
|
|
118
116
|
return <div className="${tw('rounded-xl border border-red-900/20 bg-red-50 px-4 py-3 text-sm font-semibold text-red-900')}" data-remote-error={error.name} {...toModuleFederationFallbackAttributes(telemetry)}>{t('shell.remoteUnavailable')}</div>;
|
|
119
117
|
};
|
|
@@ -168,8 +166,7 @@ const createHydratedRemote =
|
|
|
168
166
|
${hydratedExports}
|
|
169
167
|
|
|
170
168
|
export const Header = () => {
|
|
171
|
-
const {
|
|
172
|
-
const t = i18nInstance['t'].bind(i18nInstance);
|
|
169
|
+
const { t } = useModernI18n();
|
|
173
170
|
|
|
174
171
|
return (
|
|
175
172
|
<header className="${tw('flex min-w-0 flex-wrap items-center gap-x-8 gap-y-2 md:flex-1')}" data-modern-boundary-id="${shellApp.mfName}" data-modern-mf-expose="shell/Header">
|
|
@@ -179,8 +176,7 @@ const createHydratedRemote =
|
|
|
179
176
|
};
|
|
180
177
|
|
|
181
178
|
export const StatusBadge = () => {
|
|
182
|
-
const {
|
|
183
|
-
const t = i18nInstance['t'].bind(i18nInstance);
|
|
179
|
+
const { t } = useModernI18n();
|
|
184
180
|
|
|
185
181
|
return (
|
|
186
182
|
<span className="${tw('inline-flex h-10 shrink-0 items-center justify-center rounded-full border border-stone-900/15 bg-white px-4 text-sm font-extrabold text-stone-950 shadow-lg shadow-stone-900/5')}">
|
|
@@ -190,8 +186,7 @@ export const StatusBadge = () => {
|
|
|
190
186
|
};
|
|
191
187
|
|
|
192
188
|
export const VerticalShowcase = () => {
|
|
193
|
-
const {
|
|
194
|
-
const t = i18nInstance['t'].bind(i18nInstance);
|
|
189
|
+
const { t } = useModernI18n();
|
|
195
190
|
|
|
196
191
|
if (widgetCount === 0) {
|
|
197
192
|
return (
|
|
@@ -258,8 +253,7 @@ import { ultramodernUiMarker } from '../../ultramodern-build';
|
|
|
258
253
|
` : '';
|
|
259
254
|
return `${effectBffImport}
|
|
260
255
|
export default function ${toPascalCase(app.id)}Home() {
|
|
261
|
-
const {
|
|
262
|
-
const t = i18nInstance['t'].bind(i18nInstance);
|
|
256
|
+
const { language, supportedLanguages, t } = useModernI18n();
|
|
263
257
|
${effectBffState} return (
|
|
264
258
|
<main className="${tw('min-h-screen bg-um-canvas px-4 py-6 text-um-foreground sm:px-8')}">
|
|
265
259
|
<UltramodernRouteHead />
|
|
@@ -305,8 +299,7 @@ function createRemoteEntry(app) {
|
|
|
305
299
|
return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
|
|
306
300
|
|
|
307
301
|
export default function ${toPascalCase(domain)}Route() {
|
|
308
|
-
const {
|
|
309
|
-
const t = i18nInstance['t'].bind(i18nInstance);
|
|
302
|
+
const { t } = useModernI18n();
|
|
310
303
|
|
|
311
304
|
return (
|
|
312
305
|
<section className="${tw('rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10')}" data-modern-boundary-id="${app.mfName}" data-modern-mf-expose="./Route">
|
|
@@ -324,8 +317,7 @@ function createRemoteWidget(app) {
|
|
|
324
317
|
return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
|
|
325
318
|
|
|
326
319
|
export default function ${componentName}() {
|
|
327
|
-
const {
|
|
328
|
-
const t = i18nInstance['t'].bind(i18nInstance);
|
|
320
|
+
const { t } = useModernI18n();
|
|
329
321
|
|
|
330
322
|
return (
|
|
331
323
|
<section className="${tw('rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10')}" data-modern-boundary-id="${app.mfName}" data-modern-mf-expose="./Widget">
|
|
@@ -344,8 +336,7 @@ function createRemoteExposeComponent(app, expose) {
|
|
|
344
336
|
return `import { useModernI18n } from '@modern-js/plugin-i18n/runtime';
|
|
345
337
|
|
|
346
338
|
export default function ${componentName}() {
|
|
347
|
-
const {
|
|
348
|
-
const t = i18nInstance['t'].bind(i18nInstance);
|
|
339
|
+
const { t } = useModernI18n();
|
|
349
340
|
|
|
350
341
|
return (
|
|
351
342
|
<section className="${tw('rounded-2xl bg-white/90 p-5 shadow-xl shadow-stone-900/10')}" data-modern-boundary-id="${app.mfName}" data-modern-mf-expose="${expose}">
|