@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.
Files changed (56) hide show
  1. package/dist/cjs/index.cjs +1 -1
  2. package/dist/cjs/locale/en.cjs +2 -2
  3. package/dist/cjs/locale/zh.cjs +2 -2
  4. package/dist/cjs/ultramodern-tooling/config.cjs +9 -91
  5. package/dist/cjs/ultramodern-workspace/add-vertical.cjs +13 -40
  6. package/dist/cjs/ultramodern-workspace/contracts.cjs +2 -0
  7. package/dist/cjs/ultramodern-workspace/demo-components.cjs +12 -12
  8. package/dist/cjs/ultramodern-workspace/descriptors.cjs +0 -4
  9. package/dist/cjs/ultramodern-workspace/effect-api.cjs +74 -75
  10. package/dist/cjs/ultramodern-workspace/mf-validation.cjs +1 -2
  11. package/dist/cjs/ultramodern-workspace/module-federation.cjs +3 -2
  12. package/dist/cjs/ultramodern-workspace/package-json.cjs +6 -5
  13. package/dist/cjs/ultramodern-workspace/policy.cjs +1 -1
  14. package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +7 -0
  15. package/dist/cjs/ultramodern-workspace/write-workspace.cjs +4 -4
  16. package/dist/esm/index.js +1 -1
  17. package/dist/esm/locale/en.js +2 -2
  18. package/dist/esm/locale/zh.js +2 -2
  19. package/dist/esm/ultramodern-tooling/config.js +10 -92
  20. package/dist/esm/ultramodern-workspace/add-vertical.js +14 -41
  21. package/dist/esm/ultramodern-workspace/contracts.js +2 -0
  22. package/dist/esm/ultramodern-workspace/demo-components.js +12 -12
  23. package/dist/esm/ultramodern-workspace/descriptors.js +1 -2
  24. package/dist/esm/ultramodern-workspace/effect-api.js +74 -75
  25. package/dist/esm/ultramodern-workspace/mf-validation.js +1 -2
  26. package/dist/esm/ultramodern-workspace/module-federation.js +3 -2
  27. package/dist/esm/ultramodern-workspace/package-json.js +6 -5
  28. package/dist/esm/ultramodern-workspace/policy.js +1 -1
  29. package/dist/esm/ultramodern-workspace/workspace-scripts.js +5 -1
  30. package/dist/esm/ultramodern-workspace/write-workspace.js +4 -4
  31. package/dist/esm-node/index.js +1 -1
  32. package/dist/esm-node/locale/en.js +2 -2
  33. package/dist/esm-node/locale/zh.js +2 -2
  34. package/dist/esm-node/ultramodern-tooling/config.js +10 -92
  35. package/dist/esm-node/ultramodern-workspace/add-vertical.js +14 -41
  36. package/dist/esm-node/ultramodern-workspace/contracts.js +2 -0
  37. package/dist/esm-node/ultramodern-workspace/demo-components.js +12 -12
  38. package/dist/esm-node/ultramodern-workspace/descriptors.js +1 -2
  39. package/dist/esm-node/ultramodern-workspace/effect-api.js +74 -75
  40. package/dist/esm-node/ultramodern-workspace/mf-validation.js +1 -2
  41. package/dist/esm-node/ultramodern-workspace/module-federation.js +3 -2
  42. package/dist/esm-node/ultramodern-workspace/package-json.js +6 -5
  43. package/dist/esm-node/ultramodern-workspace/policy.js +1 -1
  44. package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +5 -1
  45. package/dist/esm-node/ultramodern-workspace/write-workspace.js +4 -4
  46. package/dist/types/ultramodern-tooling/config.d.ts +1 -2
  47. package/dist/types/ultramodern-workspace/descriptors.d.ts +0 -1
  48. package/dist/types/ultramodern-workspace/workspace-scripts.d.ts +1 -0
  49. package/package.json +3 -3
  50. package/templates/workspace-scripts/assert-mf-types.mjs.handlebars +1 -11
  51. package/templates/workspace-scripts/check-ultramodern-api-boundaries.mjs +339 -0
  52. package/templates/workspace-scripts/generate-public-surface-assets.mjs +14 -12
  53. package/templates/workspace-scripts/proof-cloudflare-version.mjs +3 -13
  54. package/templates/workspace-scripts/ultramodern-cloudflare-proof.mjs +3 -3
  55. package/templates/workspace-scripts/ultramodern-performance-readiness.mjs +1 -9
  56. 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))}EffectApi`;
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))}EffectApi`;
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', '/effect/checkout/cart', {
92
+ HttpApiEndpoint.get('getCart', '/checkout/cart', {
93
93
  success: checkoutCartSchema,
94
94
  }),
95
95
  )
96
96
  .add(
97
- HttpApiEndpoint.post('addCartItem', '/effect/checkout/cart/items', {
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', '/effect/checkout/cart/remove', {
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', '/effect/checkout/cart/clear', {
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: '/effect/checkout/cart/items',
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: '/effect/checkout/cart/clear',
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: '/effect/checkout/cart',
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: '/effect/checkout/cart/remove',
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)}/effect/checkout/cart',
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.effect.${groupName}.checkout.getCart', {
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.effect.${groupName}.checkout.addCartItem', {
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.effect.${groupName}.checkout.removeCartItem', {
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.effect.${groupName}.checkout.clearCart', {
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 effectBff: 'ready';
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
- effectBff: Schema.Literal('ready'),
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', '/effect/${stem}', {
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', '/effect/${stem}/readiness', {
450
+ HttpApiEndpoint.get('readiness', '/${stem}/readiness', {
451
451
  success: ${readinessSchemaExport},
452
452
  }),
453
453
  )
454
454
  .add(
455
- HttpApiEndpoint.get('get', '/effect/${stem}/:id', {
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', '/effect/${stem}', {
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: '/effect/${stem}',
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: '/effect/${stem}/:id',
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: '/effect/${stem}',
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: '/effect/${stem}/readiness',
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}/effect/${stem}',
502
+ basePath: '${apiPrefix}/${stem}',
503
503
  ${createCheckoutCartApiContractFields(service)} ownerId: '${service.id}',
504
- readinessPath: '${apiPrefix}/effect/${stem}/readiness',
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 '../../shared/ultramodern-build.ts';
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.effect.${groupName}.list', {
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
- effectBff: 'ready' as const,
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.effect.${groupName}.readiness', {
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.effect.${groupName}.get', {
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.effect.${groupName}.create', {
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 effectBff: EffectBffDefinition<typeof ${apiExport}, EffectRuntimeLayer> &
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 effectBff;
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}EffectGroups = typeof ${apiExport} extends HttpApi.HttpApi<
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}EffectGroups, HttpApiGroup.Any>,
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)}/effect/client';`;
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: `/effect/${stem}/readiness`,
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
- 'effectBff'
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-effect-client'
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 = `/effect/${stem}`;
851
+ const basePath = `/${stem}`;
852
852
  const checkoutCartOperations = serviceHasCheckoutCartState(app) ? {
853
853
  checkoutCartAddItem: {
854
854
  client: 'addCheckoutCartItem',
855
855
  method: 'POST',
856
- path: '/effect/checkout/cart/items',
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: '/effect/checkout/cart/clear',
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: '/effect/checkout/cart',
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: '/effect/checkout/cart/remove',
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
- effect: {
911
- runtime: 'effect',
912
- bff: {
913
- prefix: app.effectApi.prefix,
914
- openapi: '/openapi.json'
915
- },
916
- contract: {
917
- export: './shared/effect/api',
918
- path: `${app.directory}/shared/effect/api.ts`
919
- },
920
- client: {
921
- export: './effect/client',
922
- path: `${app.directory}/src/effect/${app.effectApi.stem}-client.ts`
923
- },
924
- serverEntry: `${app.directory}/api/effect/index.ts`,
925
- basePath: `${app.effectApi.prefix}/effect/${app.effectApi.stem}`,
926
- consumedBy: app.effectApi.consumedBy,
927
- readiness: createEffectReadinessContract(app),
928
- requestContext: createEffectRequestContextContract(),
929
- domainOperations: createEffectDomainOperations(app)
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: '/effect/checkout/cart/items',
937
+ path: '/checkout/cart/items',
939
938
  source: 'generated-client'
940
939
  },
941
940
  clearCart: {
942
941
  method: 'POST',
943
- path: '/effect/checkout/cart/clear',
942
+ path: '/checkout/cart/clear',
944
943
  source: 'generated-client'
945
944
  },
946
945
  getCart: {
947
946
  method: 'GET',
948
- path: '/effect/checkout/cart',
947
+ path: '/checkout/cart',
949
948
  source: 'generated-client'
950
949
  },
951
950
  removeCartItem: {
952
951
  method: 'POST',
953
- path: '/effect/checkout/cart/remove',
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: `/effect/${stem}`,
963
+ path: `/${stem}`,
965
964
  source: 'generated-client'
966
965
  },
967
966
  readiness: {
968
967
  method: 'GET',
969
- path: `/effect/${stem}/readiness`,
968
+ path: `/${stem}/readiness`,
970
969
  source: 'generated-client'
971
970
  },
972
971
  get: {
973
972
  method: 'GET',
974
- path: `/effect/${stem}/:id`,
973
+ path: `/${stem}/:id`,
975
974
  source: 'generated-client'
976
975
  },
977
976
  create: {
978
977
  method: 'POST',
979
- path: `/effect/${stem}`,
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/effect/index',
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: 'effect-bff',
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-bff'
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
- './effect/client': `./src/effect/${app.effectApi.stem}-client.ts`,
394
- './shared/effect/api': './shared/effect/api.ts'
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
- './effect/clients': './src/effect/vertical-clients.ts'
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
- effectReadiness: `${effectApiPrefix(app)}/effect/${effectApiStem(app)}/readiness`
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/effect/vertical-clients.ts`, createShellEffectClient(scope, remotes));
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/effect/api.ts`, createEffectSharedApi(resolvedApp));
57
- writeFile(targetDir, `${resolvedApp.directory}/api/effect/index.ts`, createEffectServiceEntry(resolvedApp, '../../shared/effect/api.ts'));
58
- writeFile(targetDir, `${resolvedApp.directory}/src/effect/${resolvedApp.effectApi.stem}-client.ts`, createEffectClient(resolvedApp, '../../shared/effect/api'));
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));
@@ -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 an Effect BFF for every MicroVertical (supported: ${SUPPORTED_BFF_RUNTIMES.join(', ')}).`);
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,\nEffect BFF, Tailwind CSS v4, and the BleedingDev package cohort.\nThe original Modern.js setup is a dangerous opt-in path.\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
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 BFF scaffolding (every MicroVertical ships an Effect BFF)',
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、\nEffect BFF、Tailwind CSS v4,以及 BleedingDev 包版本队列。\n原始 Modern.js 初始化是危险的显式选择路径。\n!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!"
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 保留默认的 Effect BFF 脚手架(每个 MicroVertical 自带 Effect 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)',