@bleedingdev/modern-js-create 3.4.0-ultramodern.19 → 3.4.0-ultramodern.20
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/index.cjs +1 -1
- package/dist/cjs/locale/en.cjs +2 -2
- package/dist/cjs/locale/zh.cjs +2 -2
- package/dist/cjs/ultramodern-tooling/config.cjs +9 -91
- package/dist/cjs/ultramodern-workspace/add-vertical.cjs +13 -40
- package/dist/cjs/ultramodern-workspace/contracts.cjs +2 -0
- package/dist/cjs/ultramodern-workspace/demo-components.cjs +12 -12
- package/dist/cjs/ultramodern-workspace/descriptors.cjs +0 -4
- package/dist/cjs/ultramodern-workspace/effect-api.cjs +74 -75
- package/dist/cjs/ultramodern-workspace/mf-validation.cjs +1 -2
- package/dist/cjs/ultramodern-workspace/module-federation.cjs +3 -2
- package/dist/cjs/ultramodern-workspace/package-json.cjs +6 -5
- package/dist/cjs/ultramodern-workspace/policy.cjs +1 -1
- package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +7 -0
- package/dist/cjs/ultramodern-workspace/write-workspace.cjs +4 -4
- package/dist/esm/index.js +1 -1
- package/dist/esm/locale/en.js +2 -2
- package/dist/esm/locale/zh.js +2 -2
- package/dist/esm/ultramodern-tooling/config.js +10 -92
- package/dist/esm/ultramodern-workspace/add-vertical.js +14 -41
- package/dist/esm/ultramodern-workspace/contracts.js +2 -0
- package/dist/esm/ultramodern-workspace/demo-components.js +12 -12
- package/dist/esm/ultramodern-workspace/descriptors.js +1 -2
- package/dist/esm/ultramodern-workspace/effect-api.js +74 -75
- package/dist/esm/ultramodern-workspace/mf-validation.js +1 -2
- package/dist/esm/ultramodern-workspace/module-federation.js +3 -2
- package/dist/esm/ultramodern-workspace/package-json.js +6 -5
- package/dist/esm/ultramodern-workspace/policy.js +1 -1
- package/dist/esm/ultramodern-workspace/workspace-scripts.js +5 -1
- package/dist/esm/ultramodern-workspace/write-workspace.js +4 -4
- package/dist/esm-node/index.js +1 -1
- package/dist/esm-node/locale/en.js +2 -2
- package/dist/esm-node/locale/zh.js +2 -2
- package/dist/esm-node/ultramodern-tooling/config.js +10 -92
- package/dist/esm-node/ultramodern-workspace/add-vertical.js +14 -41
- package/dist/esm-node/ultramodern-workspace/contracts.js +2 -0
- package/dist/esm-node/ultramodern-workspace/demo-components.js +12 -12
- package/dist/esm-node/ultramodern-workspace/descriptors.js +1 -2
- package/dist/esm-node/ultramodern-workspace/effect-api.js +74 -75
- package/dist/esm-node/ultramodern-workspace/mf-validation.js +1 -2
- package/dist/esm-node/ultramodern-workspace/module-federation.js +3 -2
- package/dist/esm-node/ultramodern-workspace/package-json.js +6 -5
- package/dist/esm-node/ultramodern-workspace/policy.js +1 -1
- package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +5 -1
- package/dist/esm-node/ultramodern-workspace/write-workspace.js +4 -4
- package/dist/types/ultramodern-tooling/config.d.ts +1 -2
- package/dist/types/ultramodern-workspace/descriptors.d.ts +0 -1
- package/dist/types/ultramodern-workspace/workspace-scripts.d.ts +1 -0
- package/package.json +3 -3
- package/templates/workspace-scripts/assert-mf-types.mjs.handlebars +1 -11
- package/templates/workspace-scripts/check-ultramodern-api-boundaries.mjs +339 -0
- package/templates/workspace-scripts/generate-public-surface-assets.mjs +14 -12
- package/templates/workspace-scripts/proof-cloudflare-version.mjs +3 -13
- package/templates/workspace-scripts/ultramodern-cloudflare-proof.mjs +3 -3
- package/templates/workspace-scripts/ultramodern-performance-readiness.mjs +1 -9
- package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +82 -86
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { appHasEffectApi, effectApiPrefix, effectApiStem, verticalEffectApps } from "./descriptors.js";
|
|
2
2
|
import { packageName, toCamelCase, toPascalCase } from "./naming.js";
|
|
3
3
|
function verticalEffectApiExport(service) {
|
|
4
|
-
return `${toCamelCase(effectApiStem(service))}
|
|
4
|
+
return `${toCamelCase(effectApiStem(service))}Api`;
|
|
5
5
|
}
|
|
6
6
|
function verticalEffectGroupName(service) {
|
|
7
7
|
return toCamelCase(effectApiStem(service));
|
|
8
8
|
}
|
|
9
9
|
function verticalEffectApiName(service) {
|
|
10
|
-
return `${toPascalCase(effectApiStem(service))}
|
|
10
|
+
return `${toPascalCase(effectApiStem(service))}Api`;
|
|
11
11
|
}
|
|
12
12
|
function verticalEffectSchemaExport(service) {
|
|
13
13
|
return `${toCamelCase(effectApiStem(service))}ItemSchema`;
|
|
@@ -89,24 +89,24 @@ function createCheckoutCartEndpointDefinitions(service) {
|
|
|
89
89
|
if (!serviceHasCheckoutCartState(service)) return '';
|
|
90
90
|
return `
|
|
91
91
|
.add(
|
|
92
|
-
HttpApiEndpoint.get('getCart', '/
|
|
92
|
+
HttpApiEndpoint.get('getCart', '/checkout/cart', {
|
|
93
93
|
success: checkoutCartSchema,
|
|
94
94
|
}),
|
|
95
95
|
)
|
|
96
96
|
.add(
|
|
97
|
-
HttpApiEndpoint.post('addCartItem', '/
|
|
97
|
+
HttpApiEndpoint.post('addCartItem', '/checkout/cart/items', {
|
|
98
98
|
payload: checkoutAddCartItemPayloadSchema,
|
|
99
99
|
success: checkoutCartSchema,
|
|
100
100
|
}),
|
|
101
101
|
)
|
|
102
102
|
.add(
|
|
103
|
-
HttpApiEndpoint.post('removeCartItem', '/
|
|
103
|
+
HttpApiEndpoint.post('removeCartItem', '/checkout/cart/remove', {
|
|
104
104
|
payload: checkoutRemoveCartItemPayloadSchema,
|
|
105
105
|
success: checkoutCartSchema,
|
|
106
106
|
}),
|
|
107
107
|
)
|
|
108
108
|
.add(
|
|
109
|
-
HttpApiEndpoint.post('clearCart', '/
|
|
109
|
+
HttpApiEndpoint.post('clearCart', '/checkout/cart/clear', {
|
|
110
110
|
success: checkoutCartSchema,
|
|
111
111
|
}),
|
|
112
112
|
)`;
|
|
@@ -119,31 +119,31 @@ function createCheckoutCartOperationContexts(service) {
|
|
|
119
119
|
addCartItem: {
|
|
120
120
|
method: 'POST',
|
|
121
121
|
operationId: '${apiName}:${groupName}:addCartItem',
|
|
122
|
-
routePath: '/
|
|
122
|
+
routePath: '/checkout/cart/items',
|
|
123
123
|
source: 'generated-client',
|
|
124
124
|
},
|
|
125
125
|
clearCart: {
|
|
126
126
|
method: 'POST',
|
|
127
127
|
operationId: '${apiName}:${groupName}:clearCart',
|
|
128
|
-
routePath: '/
|
|
128
|
+
routePath: '/checkout/cart/clear',
|
|
129
129
|
source: 'generated-client',
|
|
130
130
|
},
|
|
131
131
|
getCart: {
|
|
132
132
|
method: 'GET',
|
|
133
133
|
operationId: '${apiName}:${groupName}:getCart',
|
|
134
|
-
routePath: '/
|
|
134
|
+
routePath: '/checkout/cart',
|
|
135
135
|
source: 'generated-client',
|
|
136
136
|
},
|
|
137
137
|
removeCartItem: {
|
|
138
138
|
method: 'POST',
|
|
139
139
|
operationId: '${apiName}:${groupName}:removeCartItem',
|
|
140
|
-
routePath: '/
|
|
140
|
+
routePath: '/checkout/cart/remove',
|
|
141
141
|
source: 'generated-client',
|
|
142
142
|
},`;
|
|
143
143
|
}
|
|
144
144
|
function createCheckoutCartApiContractFields(service) {
|
|
145
145
|
if (!serviceHasCheckoutCartState(service)) return '';
|
|
146
|
-
return ` checkoutCartPath: '${effectApiPrefix(service)}/
|
|
146
|
+
return ` checkoutCartPath: '${effectApiPrefix(service)}/checkout/cart',
|
|
147
147
|
`;
|
|
148
148
|
}
|
|
149
149
|
function createCheckoutCartServerState(service) {
|
|
@@ -179,7 +179,7 @@ function createCheckoutCartServerHandlers(service) {
|
|
|
179
179
|
return `
|
|
180
180
|
.handle('getCart', () =>
|
|
181
181
|
Effect.sync(() => createCheckoutCartSnapshot()).pipe(
|
|
182
|
-
Effect.withSpan('ultramodern.
|
|
182
|
+
Effect.withSpan('ultramodern.api.${groupName}.checkout.getCart', {
|
|
183
183
|
attributes: operationAttributes(${groupName}OperationContexts.getCart),
|
|
184
184
|
kind: 'server',
|
|
185
185
|
}),
|
|
@@ -197,7 +197,7 @@ function createCheckoutCartServerHandlers(service) {
|
|
|
197
197
|
});
|
|
198
198
|
return createCheckoutCartSnapshot();
|
|
199
199
|
}).pipe(
|
|
200
|
-
Effect.withSpan('ultramodern.
|
|
200
|
+
Effect.withSpan('ultramodern.api.${groupName}.checkout.addCartItem', {
|
|
201
201
|
attributes: operationAttributes(${groupName}OperationContexts.addCartItem),
|
|
202
202
|
kind: 'server',
|
|
203
203
|
}),
|
|
@@ -208,7 +208,7 @@ function createCheckoutCartServerHandlers(service) {
|
|
|
208
208
|
checkoutCartLines.delete(payload.sku);
|
|
209
209
|
return createCheckoutCartSnapshot();
|
|
210
210
|
}).pipe(
|
|
211
|
-
Effect.withSpan('ultramodern.
|
|
211
|
+
Effect.withSpan('ultramodern.api.${groupName}.checkout.removeCartItem', {
|
|
212
212
|
attributes: operationAttributes(${groupName}OperationContexts.removeCartItem),
|
|
213
213
|
kind: 'server',
|
|
214
214
|
}),
|
|
@@ -219,7 +219,7 @@ function createCheckoutCartServerHandlers(service) {
|
|
|
219
219
|
checkoutCartLines.clear();
|
|
220
220
|
return createCheckoutCartSnapshot();
|
|
221
221
|
}).pipe(
|
|
222
|
-
Effect.withSpan('ultramodern.
|
|
222
|
+
Effect.withSpan('ultramodern.api.${groupName}.checkout.clearCart', {
|
|
223
223
|
attributes: operationAttributes(${groupName}OperationContexts.clearCart),
|
|
224
224
|
kind: 'server',
|
|
225
225
|
}),
|
|
@@ -356,7 +356,7 @@ export interface ${itemType} {
|
|
|
356
356
|
|
|
357
357
|
export interface ${readinessType} {
|
|
358
358
|
readonly checks: {
|
|
359
|
-
readonly
|
|
359
|
+
readonly api: 'ready';
|
|
360
360
|
readonly moduleFederation: 'ready';
|
|
361
361
|
readonly ssr: 'ready';
|
|
362
362
|
readonly translations: 'ready';
|
|
@@ -400,7 +400,7 @@ export const ${schemaExport}: Schema.Codec<${itemType}> = Schema.Struct({
|
|
|
400
400
|
|
|
401
401
|
export const ${readinessSchemaExport}: Schema.Codec<${readinessType}> = Schema.Struct({
|
|
402
402
|
checks: Schema.Struct({
|
|
403
|
-
|
|
403
|
+
api: Schema.Literal('ready'),
|
|
404
404
|
moduleFederation: Schema.Literal('ready'),
|
|
405
405
|
ssr: Schema.Literal('ready'),
|
|
406
406
|
translations: Schema.Literal('ready'),
|
|
@@ -437,7 +437,7 @@ export interface OperationContext {
|
|
|
437
437
|
export const ${apiExport} = HttpApi.make('${apiName}').add(
|
|
438
438
|
HttpApiGroup.make('${groupName}')
|
|
439
439
|
.add(
|
|
440
|
-
HttpApiEndpoint.get('list', '
|
|
440
|
+
HttpApiEndpoint.get('list', '/${stem}', {
|
|
441
441
|
query: {
|
|
442
442
|
limit: Schema.optional(Schema.FiniteFromString),
|
|
443
443
|
},
|
|
@@ -447,12 +447,12 @@ export const ${apiExport} = HttpApi.make('${apiName}').add(
|
|
|
447
447
|
}),
|
|
448
448
|
)
|
|
449
449
|
.add(
|
|
450
|
-
HttpApiEndpoint.get('readiness', '
|
|
450
|
+
HttpApiEndpoint.get('readiness', '/${stem}/readiness', {
|
|
451
451
|
success: ${readinessSchemaExport},
|
|
452
452
|
}),
|
|
453
453
|
)
|
|
454
454
|
.add(
|
|
455
|
-
HttpApiEndpoint.get('get', '
|
|
455
|
+
HttpApiEndpoint.get('get', '/${stem}/:id', {
|
|
456
456
|
error: ${notFoundSchemaExport},
|
|
457
457
|
params: {
|
|
458
458
|
id: Schema.String,
|
|
@@ -461,7 +461,7 @@ export const ${apiExport} = HttpApi.make('${apiName}').add(
|
|
|
461
461
|
}),
|
|
462
462
|
)
|
|
463
463
|
.add(
|
|
464
|
-
HttpApiEndpoint.post('create', '
|
|
464
|
+
HttpApiEndpoint.post('create', '/${stem}', {
|
|
465
465
|
payload: ${createPayloadSchemaExport},
|
|
466
466
|
success: Schema.Struct({
|
|
467
467
|
item: ${schemaExport},
|
|
@@ -474,34 +474,34 @@ export const ${groupName}OperationContexts = {
|
|
|
474
474
|
${checkoutCartOperationContextEntries} create: {
|
|
475
475
|
method: 'POST',
|
|
476
476
|
operationId: '${apiName}:${groupName}:create',
|
|
477
|
-
routePath: '
|
|
477
|
+
routePath: '/${stem}',
|
|
478
478
|
source: 'generated-client',
|
|
479
479
|
},
|
|
480
480
|
get: {
|
|
481
481
|
method: 'GET',
|
|
482
482
|
operationId: '${apiName}:${groupName}:get',
|
|
483
|
-
routePath: '
|
|
483
|
+
routePath: '/${stem}/:id',
|
|
484
484
|
source: 'generated-client',
|
|
485
485
|
},
|
|
486
486
|
list: {
|
|
487
487
|
method: 'GET',
|
|
488
488
|
operationId: '${apiName}:${groupName}:list',
|
|
489
|
-
routePath: '
|
|
489
|
+
routePath: '/${stem}',
|
|
490
490
|
source: 'generated-client',
|
|
491
491
|
},
|
|
492
492
|
readiness: {
|
|
493
493
|
method: 'GET',
|
|
494
494
|
operationId: '${apiName}:${groupName}:readiness',
|
|
495
|
-
routePath: '
|
|
495
|
+
routePath: '/${stem}/readiness',
|
|
496
496
|
source: 'generated-client',
|
|
497
497
|
},
|
|
498
498
|
} satisfies Record<string, OperationContext>;
|
|
499
499
|
|
|
500
500
|
export const ${groupName}ApiContract = {
|
|
501
501
|
apiPrefix: '${apiPrefix}',
|
|
502
|
-
basePath: '${apiPrefix}
|
|
502
|
+
basePath: '${apiPrefix}/${stem}',
|
|
503
503
|
${createCheckoutCartApiContractFields(service)} ownerId: '${service.id}',
|
|
504
|
-
readinessPath: '${apiPrefix}
|
|
504
|
+
readinessPath: '${apiPrefix}/${stem}/readiness',
|
|
505
505
|
} as const;
|
|
506
506
|
`;
|
|
507
507
|
}
|
|
@@ -525,7 +525,7 @@ import type {
|
|
|
525
525
|
EffectBffRuntime,
|
|
526
526
|
EffectRuntimeLayer,
|
|
527
527
|
} from '@modern-js/plugin-bff/effect-edge';
|
|
528
|
-
import { ultramodernApiMarker } from '
|
|
528
|
+
import { ultramodernApiMarker } from '../shared/ultramodern-build.ts';
|
|
529
529
|
import {
|
|
530
530
|
${apiExport},
|
|
531
531
|
${groupName}OperationContexts,
|
|
@@ -566,7 +566,7 @@ const ${groupName}Layer = HttpApiBuilder.group(
|
|
|
566
566
|
? ${groupName}Items.slice(0, query.limit)
|
|
567
567
|
: ${groupName}Items,
|
|
568
568
|
}).pipe(
|
|
569
|
-
Effect.withSpan('ultramodern.
|
|
569
|
+
Effect.withSpan('ultramodern.api.${groupName}.list', {
|
|
570
570
|
attributes: operationAttributes(${groupName}OperationContexts.list),
|
|
571
571
|
kind: 'server',
|
|
572
572
|
}),
|
|
@@ -575,7 +575,7 @@ const ${groupName}Layer = HttpApiBuilder.group(
|
|
|
575
575
|
.handle('readiness', () =>
|
|
576
576
|
Effect.succeed({
|
|
577
577
|
checks: {
|
|
578
|
-
|
|
578
|
+
api: 'ready' as const,
|
|
579
579
|
moduleFederation: 'ready' as const,
|
|
580
580
|
ssr: 'ready' as const,
|
|
581
581
|
translations: 'ready' as const,
|
|
@@ -584,7 +584,7 @@ const ${groupName}Layer = HttpApiBuilder.group(
|
|
|
584
584
|
status: 'ready' as const,
|
|
585
585
|
versionSkew: 'none' as const,
|
|
586
586
|
}).pipe(
|
|
587
|
-
Effect.withSpan('ultramodern.
|
|
587
|
+
Effect.withSpan('ultramodern.api.${groupName}.readiness', {
|
|
588
588
|
attributes: operationAttributes(${groupName}OperationContexts.readiness),
|
|
589
589
|
kind: 'server',
|
|
590
590
|
}),
|
|
@@ -604,7 +604,7 @@ const ${groupName}Layer = HttpApiBuilder.group(
|
|
|
604
604
|
: Effect.succeed(matchedItem);
|
|
605
605
|
|
|
606
606
|
return result.pipe(
|
|
607
|
-
Effect.withSpan('ultramodern.
|
|
607
|
+
Effect.withSpan('ultramodern.api.${groupName}.get', {
|
|
608
608
|
attributes: operationAttributes(${groupName}OperationContexts.get),
|
|
609
609
|
kind: 'server',
|
|
610
610
|
}),
|
|
@@ -621,7 +621,7 @@ const ${groupName}Layer = HttpApiBuilder.group(
|
|
|
621
621
|
title: payload.title,
|
|
622
622
|
},
|
|
623
623
|
}).pipe(
|
|
624
|
-
Effect.withSpan('ultramodern.
|
|
624
|
+
Effect.withSpan('ultramodern.api.${groupName}.create', {
|
|
625
625
|
attributes: operationAttributes(${groupName}OperationContexts.create),
|
|
626
626
|
kind: 'server',
|
|
627
627
|
}),
|
|
@@ -633,13 +633,13 @@ const layer = HttpApiBuilder.layer(${apiExport}).pipe(
|
|
|
633
633
|
Layer.provide(${groupName}Layer),
|
|
634
634
|
) satisfies EffectRuntimeLayer;
|
|
635
635
|
|
|
636
|
-
const
|
|
636
|
+
const apiRuntime: EffectBffDefinition<typeof ${apiExport}, EffectRuntimeLayer> &
|
|
637
637
|
EffectBffRuntime<typeof ${apiExport}, EffectRuntimeLayer> = defineEffectBff({
|
|
638
638
|
api: ${apiExport},
|
|
639
639
|
layer,
|
|
640
640
|
});
|
|
641
641
|
|
|
642
|
-
export default
|
|
642
|
+
export default apiRuntime;
|
|
643
643
|
`;
|
|
644
644
|
}
|
|
645
645
|
function createEffectClient(service, contractImportPath) {
|
|
@@ -691,7 +691,7 @@ import type {
|
|
|
691
691
|
|
|
692
692
|
export { Effect, runEffectRequest };
|
|
693
693
|
|
|
694
|
-
type ${pascalStem}
|
|
694
|
+
type ${pascalStem}ApiGroups = typeof ${apiExport} extends HttpApi.HttpApi<
|
|
695
695
|
infer _ApiId,
|
|
696
696
|
infer Groups
|
|
697
697
|
>
|
|
@@ -699,7 +699,7 @@ type ${pascalStem}EffectGroups = typeof ${apiExport} extends HttpApi.HttpApi<
|
|
|
699
699
|
: never;
|
|
700
700
|
|
|
701
701
|
export type ${clientTypeName} = HttpApiClient.Client<
|
|
702
|
-
Extract<${pascalStem}
|
|
702
|
+
Extract<${pascalStem}ApiGroups, HttpApiGroup.Any>,
|
|
703
703
|
never,
|
|
704
704
|
never
|
|
705
705
|
>;
|
|
@@ -809,7 +809,7 @@ ${checkoutCartExports} create${pascalSingular},
|
|
|
809
809
|
get${pascalStem}Readiness,
|
|
810
810
|
list${pascalStem},
|
|
811
811
|
type ${pascalStem}ClientOptions,
|
|
812
|
-
} from '${packageName(scope, remote.packageSuffix)}/
|
|
812
|
+
} from '${packageName(scope, remote.packageSuffix)}/api/client';`;
|
|
813
813
|
}).join('\n\n');
|
|
814
814
|
return exports ? `${exports}\n` : `export const ultramodernVerticalClients = [] as const;
|
|
815
815
|
`;
|
|
@@ -817,7 +817,7 @@ ${checkoutCartExports} create${pascalSingular},
|
|
|
817
817
|
function createEffectReadinessContract(app) {
|
|
818
818
|
const stem = effectApiStem(app);
|
|
819
819
|
return {
|
|
820
|
-
endpoint:
|
|
820
|
+
endpoint: `/${stem}/readiness`,
|
|
821
821
|
marker: {
|
|
822
822
|
ui: 'ultramodernUiMarker',
|
|
823
823
|
api: 'ultramodernApiMarker',
|
|
@@ -827,7 +827,7 @@ function createEffectReadinessContract(app) {
|
|
|
827
827
|
'moduleFederation',
|
|
828
828
|
'ssr',
|
|
829
829
|
'translations',
|
|
830
|
-
'
|
|
830
|
+
'api'
|
|
831
831
|
]
|
|
832
832
|
};
|
|
833
833
|
}
|
|
@@ -842,39 +842,39 @@ function createEffectRequestContextContract() {
|
|
|
842
842
|
'x-ultramodern-env',
|
|
843
843
|
'x-vertical-version-id'
|
|
844
844
|
],
|
|
845
|
-
source: 'shell-to-vertical-
|
|
845
|
+
source: 'shell-to-vertical-api-client'
|
|
846
846
|
};
|
|
847
847
|
}
|
|
848
848
|
function createEffectDomainOperations(app) {
|
|
849
849
|
const stem = effectApiStem(app);
|
|
850
850
|
const group = verticalEffectGroupName(app);
|
|
851
|
-
const basePath =
|
|
851
|
+
const basePath = `/${stem}`;
|
|
852
852
|
const checkoutCartOperations = serviceHasCheckoutCartState(app) ? {
|
|
853
853
|
checkoutCartAddItem: {
|
|
854
854
|
client: 'addCheckoutCartItem',
|
|
855
855
|
method: 'POST',
|
|
856
|
-
path: '/
|
|
856
|
+
path: '/checkout/cart/items',
|
|
857
857
|
resource: 'checkout-cart',
|
|
858
858
|
owner: app.id
|
|
859
859
|
},
|
|
860
860
|
checkoutCartClear: {
|
|
861
861
|
client: 'clearCheckoutCart',
|
|
862
862
|
method: 'POST',
|
|
863
|
-
path: '/
|
|
863
|
+
path: '/checkout/cart/clear',
|
|
864
864
|
resource: 'checkout-cart',
|
|
865
865
|
owner: app.id
|
|
866
866
|
},
|
|
867
867
|
checkoutCartRead: {
|
|
868
868
|
client: 'getCheckoutCart',
|
|
869
869
|
method: 'GET',
|
|
870
|
-
path: '/
|
|
870
|
+
path: '/checkout/cart',
|
|
871
871
|
resource: 'checkout-cart',
|
|
872
872
|
owner: app.id
|
|
873
873
|
},
|
|
874
874
|
checkoutCartRemoveItem: {
|
|
875
875
|
client: 'removeCheckoutCartItem',
|
|
876
876
|
method: 'POST',
|
|
877
|
-
path: '/
|
|
877
|
+
path: '/checkout/cart/remove',
|
|
878
878
|
resource: 'checkout-cart',
|
|
879
879
|
owner: app.id
|
|
880
880
|
}
|
|
@@ -907,27 +907,26 @@ function createEffectDomainOperations(app) {
|
|
|
907
907
|
function effectApiTopologyMetadata(app) {
|
|
908
908
|
if (!appHasEffectApi(app)) return;
|
|
909
909
|
return {
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
}
|
|
910
|
+
runtime: 'effect',
|
|
911
|
+
bff: {
|
|
912
|
+
prefix: app.effectApi.prefix,
|
|
913
|
+
openapi: '/openapi.json',
|
|
914
|
+
strictEffectApproach: true
|
|
915
|
+
},
|
|
916
|
+
contract: {
|
|
917
|
+
export: './api',
|
|
918
|
+
path: `${app.directory}/shared/api.ts`
|
|
919
|
+
},
|
|
920
|
+
client: {
|
|
921
|
+
export: './api/client',
|
|
922
|
+
path: `${app.directory}/src/api/${app.effectApi.stem}-client.ts`
|
|
923
|
+
},
|
|
924
|
+
serverEntry: `${app.directory}/api/index.ts`,
|
|
925
|
+
basePath: `${app.effectApi.prefix}/${app.effectApi.stem}`,
|
|
926
|
+
consumedBy: app.effectApi.consumedBy,
|
|
927
|
+
readiness: createEffectReadinessContract(app),
|
|
928
|
+
requestContext: createEffectRequestContextContract(),
|
|
929
|
+
domainOperations: createEffectDomainOperations(app)
|
|
931
930
|
};
|
|
932
931
|
}
|
|
933
932
|
function createEffectOperationContract(target) {
|
|
@@ -935,22 +934,22 @@ function createEffectOperationContract(target) {
|
|
|
935
934
|
const checkoutCartOperations = serviceHasCheckoutCartState(target) ? {
|
|
936
935
|
addCartItem: {
|
|
937
936
|
method: 'POST',
|
|
938
|
-
path: '/
|
|
937
|
+
path: '/checkout/cart/items',
|
|
939
938
|
source: 'generated-client'
|
|
940
939
|
},
|
|
941
940
|
clearCart: {
|
|
942
941
|
method: 'POST',
|
|
943
|
-
path: '/
|
|
942
|
+
path: '/checkout/cart/clear',
|
|
944
943
|
source: 'generated-client'
|
|
945
944
|
},
|
|
946
945
|
getCart: {
|
|
947
946
|
method: 'GET',
|
|
948
|
-
path: '/
|
|
947
|
+
path: '/checkout/cart',
|
|
949
948
|
source: 'generated-client'
|
|
950
949
|
},
|
|
951
950
|
removeCartItem: {
|
|
952
951
|
method: 'POST',
|
|
953
|
-
path: '/
|
|
952
|
+
path: '/checkout/cart/remove',
|
|
954
953
|
source: 'generated-client'
|
|
955
954
|
}
|
|
956
955
|
} : {};
|
|
@@ -961,22 +960,22 @@ function createEffectOperationContract(target) {
|
|
|
961
960
|
...checkoutCartOperations,
|
|
962
961
|
list: {
|
|
963
962
|
method: 'GET',
|
|
964
|
-
path:
|
|
963
|
+
path: `/${stem}`,
|
|
965
964
|
source: 'generated-client'
|
|
966
965
|
},
|
|
967
966
|
readiness: {
|
|
968
967
|
method: 'GET',
|
|
969
|
-
path:
|
|
968
|
+
path: `/${stem}/readiness`,
|
|
970
969
|
source: 'generated-client'
|
|
971
970
|
},
|
|
972
971
|
get: {
|
|
973
972
|
method: 'GET',
|
|
974
|
-
path:
|
|
973
|
+
path: `/${stem}/:id`,
|
|
975
974
|
source: 'generated-client'
|
|
976
975
|
},
|
|
977
976
|
create: {
|
|
978
977
|
method: 'POST',
|
|
979
|
-
path:
|
|
978
|
+
path: `/${stem}`,
|
|
980
979
|
source: 'generated-client'
|
|
981
980
|
}
|
|
982
981
|
}
|
|
@@ -3,8 +3,7 @@ import node_path from "node:path";
|
|
|
3
3
|
const moduleFederationConfigFile = 'module-federation.config.ts';
|
|
4
4
|
const mfTypesArchive = 'dist/@mf-types.zip';
|
|
5
5
|
const generatedMetadataPaths = [
|
|
6
|
-
'.modernjs/ultramodern.json'
|
|
7
|
-
'.modernjs/ultramodern-generated-contract.json'
|
|
6
|
+
'.modernjs/ultramodern.json'
|
|
8
7
|
];
|
|
9
8
|
const defaultAppRootDirs = [
|
|
10
9
|
'apps',
|
|
@@ -8,10 +8,11 @@ function createAppModernConfig(scope, app) {
|
|
|
8
8
|
const bffImport = appHasEffectApi(app) ? "import { bffPlugin } from '@modern-js/plugin-bff';\n" : '';
|
|
9
9
|
const bffConfig = appHasEffectApi(app) ? ` bff: {
|
|
10
10
|
effect: {
|
|
11
|
-
entry: './api/
|
|
11
|
+
entry: './api/index',
|
|
12
12
|
openapi: {
|
|
13
13
|
path: '/openapi.json',
|
|
14
14
|
},
|
|
15
|
+
strictEffectApproach: true,
|
|
15
16
|
},
|
|
16
17
|
prefix: '${effectApiPrefix(app)}',
|
|
17
18
|
runtimeFramework: 'effect',
|
|
@@ -395,7 +396,7 @@ export const ultramodernUiMarker = {
|
|
|
395
396
|
|
|
396
397
|
export const ultramodernApiMarker = {
|
|
397
398
|
...ultramodernVerticalIdentity,
|
|
398
|
-
surface: '
|
|
399
|
+
surface: 'api',
|
|
399
400
|
} as const;
|
|
400
401
|
`;
|
|
401
402
|
}
|
|
@@ -179,10 +179,11 @@ function createRootPackageJson(scope, packageSource, remotes = [], bridge) {
|
|
|
179
179
|
'mf:types': "node ./scripts/assert-mf-types.mjs",
|
|
180
180
|
'performance:readiness': "node ./scripts/ultramodern-performance-readiness.mjs",
|
|
181
181
|
'contract:check': "node ./scripts/validate-ultramodern-workspace.mjs",
|
|
182
|
+
'api:check': "node ./scripts/check-ultramodern-api-boundaries.mjs",
|
|
182
183
|
'i18n:boundaries': "node ./scripts/check-ultramodern-i18n-boundaries.mjs",
|
|
183
184
|
...bridgeScripts,
|
|
184
185
|
postinstall: "oxfmt . '!repos/**' && node ./scripts/bootstrap-agent-skills.mjs --postinstall",
|
|
185
|
-
check: `pnpm format:check && pnpm lint && pnpm typecheck && pnpm skills:check && pnpm i18n:boundaries && pnpm contract:check && pnpm performance:readiness${bridgeCheck}`
|
|
186
|
+
check: `pnpm format:check && pnpm lint && pnpm typecheck && pnpm skills:check && pnpm i18n:boundaries && pnpm api:check && pnpm contract:check && pnpm performance:readiness${bridgeCheck}`
|
|
186
187
|
},
|
|
187
188
|
engines: {
|
|
188
189
|
node: '>=26',
|
|
@@ -382,7 +383,7 @@ function createAppPackage(scope, app, packageSource, enableTailwind, remotes = [
|
|
|
382
383
|
appId: app.id,
|
|
383
384
|
topology: `${relativeRootFor(app.directory)}/topology/reference-topology.json`,
|
|
384
385
|
...appHasEffectApi(app) ? {
|
|
385
|
-
apiRuntime: 'effect
|
|
386
|
+
apiRuntime: 'effect'
|
|
386
387
|
} : {}
|
|
387
388
|
},
|
|
388
389
|
'zephyr:dependencies': createZephyrDependencies(scope, app, remotes),
|
|
@@ -390,11 +391,11 @@ function createAppPackage(scope, app, packageSource, enableTailwind, remotes = [
|
|
|
390
391
|
devDependencies: appDevDependencies(packageSource, enableTailwind)
|
|
391
392
|
};
|
|
392
393
|
if (appHasEffectApi(app)) Object.assign(packageExports, {
|
|
393
|
-
'./
|
|
394
|
-
'./
|
|
394
|
+
'./api': './shared/api.ts',
|
|
395
|
+
'./api/client': `./src/api/${app.effectApi.stem}-client.ts`
|
|
395
396
|
});
|
|
396
397
|
else if ('shell' === app.kind) Object.assign(packageExports, {
|
|
397
|
-
'./
|
|
398
|
+
'./api/clients': './src/api/vertical-clients.ts'
|
|
398
399
|
});
|
|
399
400
|
if (Object.keys(packageExports).length > 0) packageJson.exports = packageExports;
|
|
400
401
|
return packageJson;
|
|
@@ -16,7 +16,7 @@ function createCloudflareProofRoute(app) {
|
|
|
16
16
|
mfManifest: '/mf-manifest.json',
|
|
17
17
|
locale: `/locales/en/${appI18nNamespace(app)}.json`,
|
|
18
18
|
...appHasEffectApi(app) ? {
|
|
19
|
-
|
|
19
|
+
apiReadiness: `${effectApiPrefix(app)}/${effectApiStem(app)}/readiness`
|
|
20
20
|
} : {}
|
|
21
21
|
};
|
|
22
22
|
}
|
|
@@ -127,6 +127,9 @@ function createWorkspaceValidationScript(scope, enableTailwind, remotes = []) {
|
|
|
127
127
|
function createWorkspaceI18nBoundaryValidationScript() {
|
|
128
128
|
return readFileTemplate("workspace-scripts/check-ultramodern-i18n-boundaries.mjs");
|
|
129
129
|
}
|
|
130
|
+
function createWorkspaceApiBoundaryValidationScript() {
|
|
131
|
+
return readFileTemplate("workspace-scripts/check-ultramodern-api-boundaries.mjs");
|
|
132
|
+
}
|
|
130
133
|
function createPerformanceReadinessConfigScript() {
|
|
131
134
|
return readFileTemplate("workspace-scripts/ultramodern-performance-readiness.config.mjs");
|
|
132
135
|
}
|
|
@@ -134,6 +137,7 @@ function writeGeneratedWorkspaceScripts(targetDir, _scope, _enableTailwind, _rem
|
|
|
134
137
|
writeFileReplacing(targetDir, "scripts/assert-mf-types.mjs", createToolWrapperScript('mf-types'));
|
|
135
138
|
writeFileReplacing(targetDir, "scripts/validate-ultramodern-workspace.mjs", createToolWrapperScript('validate'));
|
|
136
139
|
writeFileReplacing(targetDir, "scripts/check-ultramodern-i18n-boundaries.mjs", createWorkspaceI18nBoundaryValidationScript());
|
|
140
|
+
writeFileReplacing(targetDir, "scripts/check-ultramodern-api-boundaries.mjs", createWorkspaceApiBoundaryValidationScript());
|
|
137
141
|
writeFileReplacing(targetDir, "scripts/generate-public-surface-assets.mjs", createToolWrapperScript('public-surface'));
|
|
138
142
|
writeFileReplacing(targetDir, "scripts/proof-cloudflare-version.mjs", createToolWrapperScript('cloudflare-proof'));
|
|
139
143
|
writeFileReplacing(targetDir, "scripts/ultramodern-performance-readiness.config.mjs", createPerformanceReadinessConfigScript());
|
|
@@ -141,4 +145,4 @@ function writeGeneratedWorkspaceScripts(targetDir, _scope, _enableTailwind, _rem
|
|
|
141
145
|
writeFileReplacing(targetDir, "scripts/ultramodern-typecheck.mjs", createToolWrapperScript('typecheck'));
|
|
142
146
|
writeFileReplacing(targetDir, "scripts/bootstrap-agent-skills.mjs", createSkillsToolWrapperScript());
|
|
143
147
|
}
|
|
144
|
-
export { createPerformanceReadinessConfigScript, createWorkspaceI18nBoundaryValidationScript, createWorkspaceValidationScript, writeGeneratedWorkspaceScripts };
|
|
148
|
+
export { createPerformanceReadinessConfigScript, createWorkspaceApiBoundaryValidationScript, createWorkspaceI18nBoundaryValidationScript, createWorkspaceValidationScript, writeGeneratedWorkspaceScripts };
|
|
@@ -50,12 +50,12 @@ function writeApp(targetDir, scope, app, packageSource, enableTailwind, remotes
|
|
|
50
50
|
if ('shell' === resolvedApp.kind) {
|
|
51
51
|
writeAppFile('src/routes/vertical-components.tsx', createShellRemoteComponents(scope, remotes));
|
|
52
52
|
writeAppFile('src/routes/shell-frame.tsx', createShellFrameComponent());
|
|
53
|
-
writeFile(targetDir, `${resolvedApp.directory}/src/
|
|
53
|
+
writeFile(targetDir, `${resolvedApp.directory}/src/api/vertical-clients.ts`, createShellEffectClient(scope, remotes));
|
|
54
54
|
}
|
|
55
55
|
if (appHasEffectApi(resolvedApp)) {
|
|
56
|
-
writeFile(targetDir, `${resolvedApp.directory}/shared/
|
|
57
|
-
writeFile(targetDir, `${resolvedApp.directory}/api/
|
|
58
|
-
writeFile(targetDir, `${resolvedApp.directory}/src/
|
|
56
|
+
writeFile(targetDir, `${resolvedApp.directory}/shared/api.ts`, createEffectSharedApi(resolvedApp));
|
|
57
|
+
writeFile(targetDir, `${resolvedApp.directory}/api/index.ts`, createEffectServiceEntry(resolvedApp, '../shared/api.ts'));
|
|
58
|
+
writeFile(targetDir, `${resolvedApp.directory}/src/api/${resolvedApp.effectApi.stem}-client.ts`, createEffectClient(resolvedApp, '../../shared/api'));
|
|
59
59
|
}
|
|
60
60
|
if ('vertical' === resolvedApp.kind) {
|
|
61
61
|
writeAppFile('src/federation-entry.tsx', createRemoteEntry(resolvedApp));
|
package/dist/esm-node/index.js
CHANGED
|
@@ -185,7 +185,7 @@ function detectBffRuntime(args) {
|
|
|
185
185
|
process.exit(1);
|
|
186
186
|
}
|
|
187
187
|
if (!SUPPORTED_BFF_RUNTIMES.includes(runtime)) {
|
|
188
|
-
console.error(`Unsupported BFF runtime "${runtime}". UltraModern workspaces scaffold
|
|
188
|
+
console.error(`Unsupported BFF runtime "${runtime}". UltraModern workspaces scaffold a strict Effect API runtime for every MicroVertical (supported: ${SUPPORTED_BFF_RUNTIMES.join(', ')}).`);
|
|
189
189
|
process.exit(1);
|
|
190
190
|
}
|
|
191
191
|
return runtime;
|
|
@@ -19,7 +19,7 @@ const EN_LOCALE = {
|
|
|
19
19
|
step1: 'cd {projectName}',
|
|
20
20
|
step2: 'pnpm install',
|
|
21
21
|
step3: 'pnpm dev',
|
|
22
|
-
legacyModernJsWarning: "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\nBRUTAL WARNING: YOU ARE OPTING OUT OF ULTRAMODERN.JS DEFAULTS.\nThe unattended default is the best UltraModern.js configuration:\na structured SuperApp workspace, presetUltramodern, TanStack Router,\
|
|
22
|
+
legacyModernJsWarning: "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\nBRUTAL WARNING: YOU ARE OPTING OUT OF ULTRAMODERN.JS DEFAULTS.\nThe unattended default is the best UltraModern.js configuration:\na structured SuperApp workspace, presetUltramodern, TanStack Router,\na strict Effect API runtime, Tailwind CSS v4, and the BleedingDev package cohort.\nThe original Modern.js setup is a dangerous opt-in path.\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
|
23
23
|
},
|
|
24
24
|
help: {
|
|
25
25
|
title: '🚀 UltraModern.js Project Creator',
|
|
@@ -31,7 +31,7 @@ const EN_LOCALE = {
|
|
|
31
31
|
optionVersion: ' -v, --version Display version information',
|
|
32
32
|
optionLang: ' -l, --lang Set the language (en default; zh opt-in)',
|
|
33
33
|
optionTailwind: ' --no-tailwind Disable default Tailwind CSS v4 workspace styling',
|
|
34
|
-
optionBff: ' --bff Keep the default Effect
|
|
34
|
+
optionBff: ' --bff Keep the default strict Effect API runtime (every MicroVertical ships one)',
|
|
35
35
|
optionBffRuntime: ' --bff-runtime Select the BFF runtime for scaffolded MicroVerticals (supported: effect; default: effect)',
|
|
36
36
|
optionWorkspace: ' --workspace Use workspace protocol for @modern-js dependencies (for local monorepo testing)',
|
|
37
37
|
optionUltramodernPackageSource: ' --ultramodern-package-source Select UltraModern package source (workspace or install; BleedingDev defaults to install aliases)',
|
|
@@ -19,7 +19,7 @@ const ZH_LOCALE = {
|
|
|
19
19
|
step1: 'cd {projectName}',
|
|
20
20
|
step2: 'pnpm install',
|
|
21
21
|
step3: 'pnpm dev',
|
|
22
|
-
legacyModernJsWarning: "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n严重警告:你正在退出 ULTRAMODERN.JS 默认配置。\n免交互默认值是最佳 UltraModern.js 配置:\n结构化 SuperApp 工作区、presetUltramodern、TanStack Router、\
|
|
22
|
+
legacyModernJsWarning: "!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n严重警告:你正在退出 ULTRAMODERN.JS 默认配置。\n免交互默认值是最佳 UltraModern.js 配置:\n结构化 SuperApp 工作区、presetUltramodern、TanStack Router、\n严格 Effect API 运行时、Tailwind CSS v4,以及 BleedingDev 包版本队列。\n原始 Modern.js 初始化是危险的显式选择路径。\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
|
|
23
23
|
},
|
|
24
24
|
help: {
|
|
25
25
|
title: '🚀 UltraModern.js 项目创建工具',
|
|
@@ -31,7 +31,7 @@ const ZH_LOCALE = {
|
|
|
31
31
|
optionVersion: ' -v, --version 显示版本信息',
|
|
32
32
|
optionLang: ' -l, --lang 设置语言 (默认 en;zh 需显式选择)',
|
|
33
33
|
optionTailwind: ' --no-tailwind 禁用默认 Tailwind CSS v4 工作区样式',
|
|
34
|
-
optionBff: ' --bff
|
|
34
|
+
optionBff: ' --bff 保留默认的严格 Effect API 运行时(每个 MicroVertical 自带一个)',
|
|
35
35
|
optionBffRuntime: ' --bff-runtime 选择 MicroVertical 脚手架的 BFF 运行时(支持: effect;默认: effect)',
|
|
36
36
|
optionWorkspace: ' --workspace 对 @modern-js 依赖使用 workspace 协议(用于本地 monorepo 联调)',
|
|
37
37
|
optionUltramodernPackageSource: ' --ultramodern-package-source 选择 UltraModern 依赖来源(workspace 或 install;BleedingDev 默认使用 install alias)',
|