@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
@@ -2,13 +2,13 @@ import "node:module";
2
2
  import { appHasEffectApi, effectApiPrefix, effectApiStem, verticalEffectApps } from "./descriptors.js";
3
3
  import { packageName, toCamelCase, toPascalCase } from "./naming.js";
4
4
  function verticalEffectApiExport(service) {
5
- return `${toCamelCase(effectApiStem(service))}EffectApi`;
5
+ return `${toCamelCase(effectApiStem(service))}Api`;
6
6
  }
7
7
  function verticalEffectGroupName(service) {
8
8
  return toCamelCase(effectApiStem(service));
9
9
  }
10
10
  function verticalEffectApiName(service) {
11
- return `${toPascalCase(effectApiStem(service))}EffectApi`;
11
+ return `${toPascalCase(effectApiStem(service))}Api`;
12
12
  }
13
13
  function verticalEffectSchemaExport(service) {
14
14
  return `${toCamelCase(effectApiStem(service))}ItemSchema`;
@@ -90,24 +90,24 @@ function createCheckoutCartEndpointDefinitions(service) {
90
90
  if (!serviceHasCheckoutCartState(service)) return '';
91
91
  return `
92
92
  .add(
93
- HttpApiEndpoint.get('getCart', '/effect/checkout/cart', {
93
+ HttpApiEndpoint.get('getCart', '/checkout/cart', {
94
94
  success: checkoutCartSchema,
95
95
  }),
96
96
  )
97
97
  .add(
98
- HttpApiEndpoint.post('addCartItem', '/effect/checkout/cart/items', {
98
+ HttpApiEndpoint.post('addCartItem', '/checkout/cart/items', {
99
99
  payload: checkoutAddCartItemPayloadSchema,
100
100
  success: checkoutCartSchema,
101
101
  }),
102
102
  )
103
103
  .add(
104
- HttpApiEndpoint.post('removeCartItem', '/effect/checkout/cart/remove', {
104
+ HttpApiEndpoint.post('removeCartItem', '/checkout/cart/remove', {
105
105
  payload: checkoutRemoveCartItemPayloadSchema,
106
106
  success: checkoutCartSchema,
107
107
  }),
108
108
  )
109
109
  .add(
110
- HttpApiEndpoint.post('clearCart', '/effect/checkout/cart/clear', {
110
+ HttpApiEndpoint.post('clearCart', '/checkout/cart/clear', {
111
111
  success: checkoutCartSchema,
112
112
  }),
113
113
  )`;
@@ -120,31 +120,31 @@ function createCheckoutCartOperationContexts(service) {
120
120
  addCartItem: {
121
121
  method: 'POST',
122
122
  operationId: '${apiName}:${groupName}:addCartItem',
123
- routePath: '/effect/checkout/cart/items',
123
+ routePath: '/checkout/cart/items',
124
124
  source: 'generated-client',
125
125
  },
126
126
  clearCart: {
127
127
  method: 'POST',
128
128
  operationId: '${apiName}:${groupName}:clearCart',
129
- routePath: '/effect/checkout/cart/clear',
129
+ routePath: '/checkout/cart/clear',
130
130
  source: 'generated-client',
131
131
  },
132
132
  getCart: {
133
133
  method: 'GET',
134
134
  operationId: '${apiName}:${groupName}:getCart',
135
- routePath: '/effect/checkout/cart',
135
+ routePath: '/checkout/cart',
136
136
  source: 'generated-client',
137
137
  },
138
138
  removeCartItem: {
139
139
  method: 'POST',
140
140
  operationId: '${apiName}:${groupName}:removeCartItem',
141
- routePath: '/effect/checkout/cart/remove',
141
+ routePath: '/checkout/cart/remove',
142
142
  source: 'generated-client',
143
143
  },`;
144
144
  }
145
145
  function createCheckoutCartApiContractFields(service) {
146
146
  if (!serviceHasCheckoutCartState(service)) return '';
147
- return ` checkoutCartPath: '${effectApiPrefix(service)}/effect/checkout/cart',
147
+ return ` checkoutCartPath: '${effectApiPrefix(service)}/checkout/cart',
148
148
  `;
149
149
  }
150
150
  function createCheckoutCartServerState(service) {
@@ -180,7 +180,7 @@ function createCheckoutCartServerHandlers(service) {
180
180
  return `
181
181
  .handle('getCart', () =>
182
182
  Effect.sync(() => createCheckoutCartSnapshot()).pipe(
183
- Effect.withSpan('ultramodern.effect.${groupName}.checkout.getCart', {
183
+ Effect.withSpan('ultramodern.api.${groupName}.checkout.getCart', {
184
184
  attributes: operationAttributes(${groupName}OperationContexts.getCart),
185
185
  kind: 'server',
186
186
  }),
@@ -198,7 +198,7 @@ function createCheckoutCartServerHandlers(service) {
198
198
  });
199
199
  return createCheckoutCartSnapshot();
200
200
  }).pipe(
201
- Effect.withSpan('ultramodern.effect.${groupName}.checkout.addCartItem', {
201
+ Effect.withSpan('ultramodern.api.${groupName}.checkout.addCartItem', {
202
202
  attributes: operationAttributes(${groupName}OperationContexts.addCartItem),
203
203
  kind: 'server',
204
204
  }),
@@ -209,7 +209,7 @@ function createCheckoutCartServerHandlers(service) {
209
209
  checkoutCartLines.delete(payload.sku);
210
210
  return createCheckoutCartSnapshot();
211
211
  }).pipe(
212
- Effect.withSpan('ultramodern.effect.${groupName}.checkout.removeCartItem', {
212
+ Effect.withSpan('ultramodern.api.${groupName}.checkout.removeCartItem', {
213
213
  attributes: operationAttributes(${groupName}OperationContexts.removeCartItem),
214
214
  kind: 'server',
215
215
  }),
@@ -220,7 +220,7 @@ function createCheckoutCartServerHandlers(service) {
220
220
  checkoutCartLines.clear();
221
221
  return createCheckoutCartSnapshot();
222
222
  }).pipe(
223
- Effect.withSpan('ultramodern.effect.${groupName}.checkout.clearCart', {
223
+ Effect.withSpan('ultramodern.api.${groupName}.checkout.clearCart', {
224
224
  attributes: operationAttributes(${groupName}OperationContexts.clearCart),
225
225
  kind: 'server',
226
226
  }),
@@ -357,7 +357,7 @@ export interface ${itemType} {
357
357
 
358
358
  export interface ${readinessType} {
359
359
  readonly checks: {
360
- readonly effectBff: 'ready';
360
+ readonly api: 'ready';
361
361
  readonly moduleFederation: 'ready';
362
362
  readonly ssr: 'ready';
363
363
  readonly translations: 'ready';
@@ -401,7 +401,7 @@ export const ${schemaExport}: Schema.Codec<${itemType}> = Schema.Struct({
401
401
 
402
402
  export const ${readinessSchemaExport}: Schema.Codec<${readinessType}> = Schema.Struct({
403
403
  checks: Schema.Struct({
404
- effectBff: Schema.Literal('ready'),
404
+ api: Schema.Literal('ready'),
405
405
  moduleFederation: Schema.Literal('ready'),
406
406
  ssr: Schema.Literal('ready'),
407
407
  translations: Schema.Literal('ready'),
@@ -438,7 +438,7 @@ export interface OperationContext {
438
438
  export const ${apiExport} = HttpApi.make('${apiName}').add(
439
439
  HttpApiGroup.make('${groupName}')
440
440
  .add(
441
- HttpApiEndpoint.get('list', '/effect/${stem}', {
441
+ HttpApiEndpoint.get('list', '/${stem}', {
442
442
  query: {
443
443
  limit: Schema.optional(Schema.FiniteFromString),
444
444
  },
@@ -448,12 +448,12 @@ export const ${apiExport} = HttpApi.make('${apiName}').add(
448
448
  }),
449
449
  )
450
450
  .add(
451
- HttpApiEndpoint.get('readiness', '/effect/${stem}/readiness', {
451
+ HttpApiEndpoint.get('readiness', '/${stem}/readiness', {
452
452
  success: ${readinessSchemaExport},
453
453
  }),
454
454
  )
455
455
  .add(
456
- HttpApiEndpoint.get('get', '/effect/${stem}/:id', {
456
+ HttpApiEndpoint.get('get', '/${stem}/:id', {
457
457
  error: ${notFoundSchemaExport},
458
458
  params: {
459
459
  id: Schema.String,
@@ -462,7 +462,7 @@ export const ${apiExport} = HttpApi.make('${apiName}').add(
462
462
  }),
463
463
  )
464
464
  .add(
465
- HttpApiEndpoint.post('create', '/effect/${stem}', {
465
+ HttpApiEndpoint.post('create', '/${stem}', {
466
466
  payload: ${createPayloadSchemaExport},
467
467
  success: Schema.Struct({
468
468
  item: ${schemaExport},
@@ -475,34 +475,34 @@ export const ${groupName}OperationContexts = {
475
475
  ${checkoutCartOperationContextEntries} create: {
476
476
  method: 'POST',
477
477
  operationId: '${apiName}:${groupName}:create',
478
- routePath: '/effect/${stem}',
478
+ routePath: '/${stem}',
479
479
  source: 'generated-client',
480
480
  },
481
481
  get: {
482
482
  method: 'GET',
483
483
  operationId: '${apiName}:${groupName}:get',
484
- routePath: '/effect/${stem}/:id',
484
+ routePath: '/${stem}/:id',
485
485
  source: 'generated-client',
486
486
  },
487
487
  list: {
488
488
  method: 'GET',
489
489
  operationId: '${apiName}:${groupName}:list',
490
- routePath: '/effect/${stem}',
490
+ routePath: '/${stem}',
491
491
  source: 'generated-client',
492
492
  },
493
493
  readiness: {
494
494
  method: 'GET',
495
495
  operationId: '${apiName}:${groupName}:readiness',
496
- routePath: '/effect/${stem}/readiness',
496
+ routePath: '/${stem}/readiness',
497
497
  source: 'generated-client',
498
498
  },
499
499
  } satisfies Record<string, OperationContext>;
500
500
 
501
501
  export const ${groupName}ApiContract = {
502
502
  apiPrefix: '${apiPrefix}',
503
- basePath: '${apiPrefix}/effect/${stem}',
503
+ basePath: '${apiPrefix}/${stem}',
504
504
  ${createCheckoutCartApiContractFields(service)} ownerId: '${service.id}',
505
- readinessPath: '${apiPrefix}/effect/${stem}/readiness',
505
+ readinessPath: '${apiPrefix}/${stem}/readiness',
506
506
  } as const;
507
507
  `;
508
508
  }
@@ -526,7 +526,7 @@ import type {
526
526
  EffectBffRuntime,
527
527
  EffectRuntimeLayer,
528
528
  } from '@modern-js/plugin-bff/effect-edge';
529
- import { ultramodernApiMarker } from '../../shared/ultramodern-build.ts';
529
+ import { ultramodernApiMarker } from '../shared/ultramodern-build.ts';
530
530
  import {
531
531
  ${apiExport},
532
532
  ${groupName}OperationContexts,
@@ -567,7 +567,7 @@ const ${groupName}Layer = HttpApiBuilder.group(
567
567
  ? ${groupName}Items.slice(0, query.limit)
568
568
  : ${groupName}Items,
569
569
  }).pipe(
570
- Effect.withSpan('ultramodern.effect.${groupName}.list', {
570
+ Effect.withSpan('ultramodern.api.${groupName}.list', {
571
571
  attributes: operationAttributes(${groupName}OperationContexts.list),
572
572
  kind: 'server',
573
573
  }),
@@ -576,7 +576,7 @@ const ${groupName}Layer = HttpApiBuilder.group(
576
576
  .handle('readiness', () =>
577
577
  Effect.succeed({
578
578
  checks: {
579
- effectBff: 'ready' as const,
579
+ api: 'ready' as const,
580
580
  moduleFederation: 'ready' as const,
581
581
  ssr: 'ready' as const,
582
582
  translations: 'ready' as const,
@@ -585,7 +585,7 @@ const ${groupName}Layer = HttpApiBuilder.group(
585
585
  status: 'ready' as const,
586
586
  versionSkew: 'none' as const,
587
587
  }).pipe(
588
- Effect.withSpan('ultramodern.effect.${groupName}.readiness', {
588
+ Effect.withSpan('ultramodern.api.${groupName}.readiness', {
589
589
  attributes: operationAttributes(${groupName}OperationContexts.readiness),
590
590
  kind: 'server',
591
591
  }),
@@ -605,7 +605,7 @@ const ${groupName}Layer = HttpApiBuilder.group(
605
605
  : Effect.succeed(matchedItem);
606
606
 
607
607
  return result.pipe(
608
- Effect.withSpan('ultramodern.effect.${groupName}.get', {
608
+ Effect.withSpan('ultramodern.api.${groupName}.get', {
609
609
  attributes: operationAttributes(${groupName}OperationContexts.get),
610
610
  kind: 'server',
611
611
  }),
@@ -622,7 +622,7 @@ const ${groupName}Layer = HttpApiBuilder.group(
622
622
  title: payload.title,
623
623
  },
624
624
  }).pipe(
625
- Effect.withSpan('ultramodern.effect.${groupName}.create', {
625
+ Effect.withSpan('ultramodern.api.${groupName}.create', {
626
626
  attributes: operationAttributes(${groupName}OperationContexts.create),
627
627
  kind: 'server',
628
628
  }),
@@ -634,13 +634,13 @@ const layer = HttpApiBuilder.layer(${apiExport}).pipe(
634
634
  Layer.provide(${groupName}Layer),
635
635
  ) satisfies EffectRuntimeLayer;
636
636
 
637
- const effectBff: EffectBffDefinition<typeof ${apiExport}, EffectRuntimeLayer> &
637
+ const apiRuntime: EffectBffDefinition<typeof ${apiExport}, EffectRuntimeLayer> &
638
638
  EffectBffRuntime<typeof ${apiExport}, EffectRuntimeLayer> = defineEffectBff({
639
639
  api: ${apiExport},
640
640
  layer,
641
641
  });
642
642
 
643
- export default effectBff;
643
+ export default apiRuntime;
644
644
  `;
645
645
  }
646
646
  function createEffectClient(service, contractImportPath) {
@@ -692,7 +692,7 @@ import type {
692
692
 
693
693
  export { Effect, runEffectRequest };
694
694
 
695
- type ${pascalStem}EffectGroups = typeof ${apiExport} extends HttpApi.HttpApi<
695
+ type ${pascalStem}ApiGroups = typeof ${apiExport} extends HttpApi.HttpApi<
696
696
  infer _ApiId,
697
697
  infer Groups
698
698
  >
@@ -700,7 +700,7 @@ type ${pascalStem}EffectGroups = typeof ${apiExport} extends HttpApi.HttpApi<
700
700
  : never;
701
701
 
702
702
  export type ${clientTypeName} = HttpApiClient.Client<
703
- Extract<${pascalStem}EffectGroups, HttpApiGroup.Any>,
703
+ Extract<${pascalStem}ApiGroups, HttpApiGroup.Any>,
704
704
  never,
705
705
  never
706
706
  >;
@@ -810,7 +810,7 @@ ${checkoutCartExports} create${pascalSingular},
810
810
  get${pascalStem}Readiness,
811
811
  list${pascalStem},
812
812
  type ${pascalStem}ClientOptions,
813
- } from '${packageName(scope, remote.packageSuffix)}/effect/client';`;
813
+ } from '${packageName(scope, remote.packageSuffix)}/api/client';`;
814
814
  }).join('\n\n');
815
815
  return exports ? `${exports}\n` : `export const ultramodernVerticalClients = [] as const;
816
816
  `;
@@ -818,7 +818,7 @@ ${checkoutCartExports} create${pascalSingular},
818
818
  function createEffectReadinessContract(app) {
819
819
  const stem = effectApiStem(app);
820
820
  return {
821
- endpoint: `/effect/${stem}/readiness`,
821
+ endpoint: `/${stem}/readiness`,
822
822
  marker: {
823
823
  ui: 'ultramodernUiMarker',
824
824
  api: 'ultramodernApiMarker',
@@ -828,7 +828,7 @@ function createEffectReadinessContract(app) {
828
828
  'moduleFederation',
829
829
  'ssr',
830
830
  'translations',
831
- 'effectBff'
831
+ 'api'
832
832
  ]
833
833
  };
834
834
  }
@@ -843,39 +843,39 @@ function createEffectRequestContextContract() {
843
843
  'x-ultramodern-env',
844
844
  'x-vertical-version-id'
845
845
  ],
846
- source: 'shell-to-vertical-effect-client'
846
+ source: 'shell-to-vertical-api-client'
847
847
  };
848
848
  }
849
849
  function createEffectDomainOperations(app) {
850
850
  const stem = effectApiStem(app);
851
851
  const group = verticalEffectGroupName(app);
852
- const basePath = `/effect/${stem}`;
852
+ const basePath = `/${stem}`;
853
853
  const checkoutCartOperations = serviceHasCheckoutCartState(app) ? {
854
854
  checkoutCartAddItem: {
855
855
  client: 'addCheckoutCartItem',
856
856
  method: 'POST',
857
- path: '/effect/checkout/cart/items',
857
+ path: '/checkout/cart/items',
858
858
  resource: 'checkout-cart',
859
859
  owner: app.id
860
860
  },
861
861
  checkoutCartClear: {
862
862
  client: 'clearCheckoutCart',
863
863
  method: 'POST',
864
- path: '/effect/checkout/cart/clear',
864
+ path: '/checkout/cart/clear',
865
865
  resource: 'checkout-cart',
866
866
  owner: app.id
867
867
  },
868
868
  checkoutCartRead: {
869
869
  client: 'getCheckoutCart',
870
870
  method: 'GET',
871
- path: '/effect/checkout/cart',
871
+ path: '/checkout/cart',
872
872
  resource: 'checkout-cart',
873
873
  owner: app.id
874
874
  },
875
875
  checkoutCartRemoveItem: {
876
876
  client: 'removeCheckoutCartItem',
877
877
  method: 'POST',
878
- path: '/effect/checkout/cart/remove',
878
+ path: '/checkout/cart/remove',
879
879
  resource: 'checkout-cart',
880
880
  owner: app.id
881
881
  }
@@ -908,27 +908,26 @@ function createEffectDomainOperations(app) {
908
908
  function effectApiTopologyMetadata(app) {
909
909
  if (!appHasEffectApi(app)) return;
910
910
  return {
911
- effect: {
912
- runtime: 'effect',
913
- bff: {
914
- prefix: app.effectApi.prefix,
915
- openapi: '/openapi.json'
916
- },
917
- contract: {
918
- export: './shared/effect/api',
919
- path: `${app.directory}/shared/effect/api.ts`
920
- },
921
- client: {
922
- export: './effect/client',
923
- path: `${app.directory}/src/effect/${app.effectApi.stem}-client.ts`
924
- },
925
- serverEntry: `${app.directory}/api/effect/index.ts`,
926
- basePath: `${app.effectApi.prefix}/effect/${app.effectApi.stem}`,
927
- consumedBy: app.effectApi.consumedBy,
928
- readiness: createEffectReadinessContract(app),
929
- requestContext: createEffectRequestContextContract(),
930
- domainOperations: createEffectDomainOperations(app)
931
- }
911
+ runtime: 'effect',
912
+ bff: {
913
+ prefix: app.effectApi.prefix,
914
+ openapi: '/openapi.json',
915
+ strictEffectApproach: true
916
+ },
917
+ contract: {
918
+ export: './api',
919
+ path: `${app.directory}/shared/api.ts`
920
+ },
921
+ client: {
922
+ export: './api/client',
923
+ path: `${app.directory}/src/api/${app.effectApi.stem}-client.ts`
924
+ },
925
+ serverEntry: `${app.directory}/api/index.ts`,
926
+ basePath: `${app.effectApi.prefix}/${app.effectApi.stem}`,
927
+ consumedBy: app.effectApi.consumedBy,
928
+ readiness: createEffectReadinessContract(app),
929
+ requestContext: createEffectRequestContextContract(),
930
+ domainOperations: createEffectDomainOperations(app)
932
931
  };
933
932
  }
934
933
  function createEffectOperationContract(target) {
@@ -936,22 +935,22 @@ function createEffectOperationContract(target) {
936
935
  const checkoutCartOperations = serviceHasCheckoutCartState(target) ? {
937
936
  addCartItem: {
938
937
  method: 'POST',
939
- path: '/effect/checkout/cart/items',
938
+ path: '/checkout/cart/items',
940
939
  source: 'generated-client'
941
940
  },
942
941
  clearCart: {
943
942
  method: 'POST',
944
- path: '/effect/checkout/cart/clear',
943
+ path: '/checkout/cart/clear',
945
944
  source: 'generated-client'
946
945
  },
947
946
  getCart: {
948
947
  method: 'GET',
949
- path: '/effect/checkout/cart',
948
+ path: '/checkout/cart',
950
949
  source: 'generated-client'
951
950
  },
952
951
  removeCartItem: {
953
952
  method: 'POST',
954
- path: '/effect/checkout/cart/remove',
953
+ path: '/checkout/cart/remove',
955
954
  source: 'generated-client'
956
955
  }
957
956
  } : {};
@@ -962,22 +961,22 @@ function createEffectOperationContract(target) {
962
961
  ...checkoutCartOperations,
963
962
  list: {
964
963
  method: 'GET',
965
- path: `/effect/${stem}`,
964
+ path: `/${stem}`,
966
965
  source: 'generated-client'
967
966
  },
968
967
  readiness: {
969
968
  method: 'GET',
970
- path: `/effect/${stem}/readiness`,
969
+ path: `/${stem}/readiness`,
971
970
  source: 'generated-client'
972
971
  },
973
972
  get: {
974
973
  method: 'GET',
975
- path: `/effect/${stem}/:id`,
974
+ path: `/${stem}/:id`,
976
975
  source: 'generated-client'
977
976
  },
978
977
  create: {
979
978
  method: 'POST',
980
- path: `/effect/${stem}`,
979
+ path: `/${stem}`,
981
980
  source: 'generated-client'
982
981
  }
983
982
  }
@@ -4,8 +4,7 @@ import node_path from "node:path";
4
4
  const moduleFederationConfigFile = 'module-federation.config.ts';
5
5
  const mfTypesArchive = 'dist/@mf-types.zip';
6
6
  const generatedMetadataPaths = [
7
- '.modernjs/ultramodern.json',
8
- '.modernjs/ultramodern-generated-contract.json'
7
+ '.modernjs/ultramodern.json'
9
8
  ];
10
9
  const defaultAppRootDirs = [
11
10
  'apps',
@@ -9,10 +9,11 @@ function createAppModernConfig(scope, app) {
9
9
  const bffImport = appHasEffectApi(app) ? "import { bffPlugin } from '@modern-js/plugin-bff';\n" : '';
10
10
  const bffConfig = appHasEffectApi(app) ? ` bff: {
11
11
  effect: {
12
- entry: './api/effect/index',
12
+ entry: './api/index',
13
13
  openapi: {
14
14
  path: '/openapi.json',
15
15
  },
16
+ strictEffectApproach: true,
16
17
  },
17
18
  prefix: '${effectApiPrefix(app)}',
18
19
  runtimeFramework: 'effect',
@@ -396,7 +397,7 @@ export const ultramodernUiMarker = {
396
397
 
397
398
  export const ultramodernApiMarker = {
398
399
  ...ultramodernVerticalIdentity,
399
- surface: 'effect-bff',
400
+ surface: 'api',
400
401
  } as const;
401
402
  `;
402
403
  }
@@ -180,10 +180,11 @@ function createRootPackageJson(scope, packageSource, remotes = [], bridge) {
180
180
  'mf:types': "node ./scripts/assert-mf-types.mjs",
181
181
  'performance:readiness': "node ./scripts/ultramodern-performance-readiness.mjs",
182
182
  'contract:check': "node ./scripts/validate-ultramodern-workspace.mjs",
183
+ 'api:check': "node ./scripts/check-ultramodern-api-boundaries.mjs",
183
184
  'i18n:boundaries': "node ./scripts/check-ultramodern-i18n-boundaries.mjs",
184
185
  ...bridgeScripts,
185
186
  postinstall: "oxfmt . '!repos/**' && node ./scripts/bootstrap-agent-skills.mjs --postinstall",
186
- check: `pnpm format:check && pnpm lint && pnpm typecheck && pnpm skills:check && pnpm i18n:boundaries && pnpm contract:check && pnpm performance:readiness${bridgeCheck}`
187
+ check: `pnpm format:check && pnpm lint && pnpm typecheck && pnpm skills:check && pnpm i18n:boundaries && pnpm api:check && pnpm contract:check && pnpm performance:readiness${bridgeCheck}`
187
188
  },
188
189
  engines: {
189
190
  node: '>=26',
@@ -383,7 +384,7 @@ function createAppPackage(scope, app, packageSource, enableTailwind, remotes = [
383
384
  appId: app.id,
384
385
  topology: `${relativeRootFor(app.directory)}/topology/reference-topology.json`,
385
386
  ...appHasEffectApi(app) ? {
386
- apiRuntime: 'effect-bff'
387
+ apiRuntime: 'effect'
387
388
  } : {}
388
389
  },
389
390
  'zephyr:dependencies': createZephyrDependencies(scope, app, remotes),
@@ -391,11 +392,11 @@ function createAppPackage(scope, app, packageSource, enableTailwind, remotes = [
391
392
  devDependencies: appDevDependencies(packageSource, enableTailwind)
392
393
  };
393
394
  if (appHasEffectApi(app)) Object.assign(packageExports, {
394
- './effect/client': `./src/effect/${app.effectApi.stem}-client.ts`,
395
- './shared/effect/api': './shared/effect/api.ts'
395
+ './api': './shared/api.ts',
396
+ './api/client': `./src/api/${app.effectApi.stem}-client.ts`
396
397
  });
397
398
  else if ('shell' === app.kind) Object.assign(packageExports, {
398
- './effect/clients': './src/effect/vertical-clients.ts'
399
+ './api/clients': './src/api/vertical-clients.ts'
399
400
  });
400
401
  if (Object.keys(packageExports).length > 0) packageJson.exports = packageExports;
401
402
  return packageJson;
@@ -17,7 +17,7 @@ function createCloudflareProofRoute(app) {
17
17
  mfManifest: '/mf-manifest.json',
18
18
  locale: `/locales/en/${appI18nNamespace(app)}.json`,
19
19
  ...appHasEffectApi(app) ? {
20
- effectReadiness: `${effectApiPrefix(app)}/effect/${effectApiStem(app)}/readiness`
20
+ apiReadiness: `${effectApiPrefix(app)}/${effectApiStem(app)}/readiness`
21
21
  } : {}
22
22
  };
23
23
  }
@@ -128,6 +128,9 @@ function createWorkspaceValidationScript(scope, enableTailwind, remotes = []) {
128
128
  function createWorkspaceI18nBoundaryValidationScript() {
129
129
  return readFileTemplate("workspace-scripts/check-ultramodern-i18n-boundaries.mjs");
130
130
  }
131
+ function createWorkspaceApiBoundaryValidationScript() {
132
+ return readFileTemplate("workspace-scripts/check-ultramodern-api-boundaries.mjs");
133
+ }
131
134
  function createPerformanceReadinessConfigScript() {
132
135
  return readFileTemplate("workspace-scripts/ultramodern-performance-readiness.config.mjs");
133
136
  }
@@ -135,6 +138,7 @@ function writeGeneratedWorkspaceScripts(targetDir, _scope, _enableTailwind, _rem
135
138
  writeFileReplacing(targetDir, "scripts/assert-mf-types.mjs", createToolWrapperScript('mf-types'));
136
139
  writeFileReplacing(targetDir, "scripts/validate-ultramodern-workspace.mjs", createToolWrapperScript('validate'));
137
140
  writeFileReplacing(targetDir, "scripts/check-ultramodern-i18n-boundaries.mjs", createWorkspaceI18nBoundaryValidationScript());
141
+ writeFileReplacing(targetDir, "scripts/check-ultramodern-api-boundaries.mjs", createWorkspaceApiBoundaryValidationScript());
138
142
  writeFileReplacing(targetDir, "scripts/generate-public-surface-assets.mjs", createToolWrapperScript('public-surface'));
139
143
  writeFileReplacing(targetDir, "scripts/proof-cloudflare-version.mjs", createToolWrapperScript('cloudflare-proof'));
140
144
  writeFileReplacing(targetDir, "scripts/ultramodern-performance-readiness.config.mjs", createPerformanceReadinessConfigScript());
@@ -142,4 +146,4 @@ function writeGeneratedWorkspaceScripts(targetDir, _scope, _enableTailwind, _rem
142
146
  writeFileReplacing(targetDir, "scripts/ultramodern-typecheck.mjs", createToolWrapperScript('typecheck'));
143
147
  writeFileReplacing(targetDir, "scripts/bootstrap-agent-skills.mjs", createSkillsToolWrapperScript());
144
148
  }
145
- export { createPerformanceReadinessConfigScript, createWorkspaceI18nBoundaryValidationScript, createWorkspaceValidationScript, writeGeneratedWorkspaceScripts };
149
+ export { createPerformanceReadinessConfigScript, createWorkspaceApiBoundaryValidationScript, createWorkspaceI18nBoundaryValidationScript, createWorkspaceValidationScript, writeGeneratedWorkspaceScripts };
@@ -51,12 +51,12 @@ function writeApp(targetDir, scope, app, packageSource, enableTailwind, remotes
51
51
  if ('shell' === resolvedApp.kind) {
52
52
  writeAppFile('src/routes/vertical-components.tsx', createShellRemoteComponents(scope, remotes));
53
53
  writeAppFile('src/routes/shell-frame.tsx', createShellFrameComponent());
54
- writeFile(targetDir, `${resolvedApp.directory}/src/effect/vertical-clients.ts`, createShellEffectClient(scope, remotes));
54
+ writeFile(targetDir, `${resolvedApp.directory}/src/api/vertical-clients.ts`, createShellEffectClient(scope, remotes));
55
55
  }
56
56
  if (appHasEffectApi(resolvedApp)) {
57
- writeFile(targetDir, `${resolvedApp.directory}/shared/effect/api.ts`, createEffectSharedApi(resolvedApp));
58
- writeFile(targetDir, `${resolvedApp.directory}/api/effect/index.ts`, createEffectServiceEntry(resolvedApp, '../../shared/effect/api.ts'));
59
- writeFile(targetDir, `${resolvedApp.directory}/src/effect/${resolvedApp.effectApi.stem}-client.ts`, createEffectClient(resolvedApp, '../../shared/effect/api'));
57
+ writeFile(targetDir, `${resolvedApp.directory}/shared/api.ts`, createEffectSharedApi(resolvedApp));
58
+ writeFile(targetDir, `${resolvedApp.directory}/api/index.ts`, createEffectServiceEntry(resolvedApp, '../shared/api.ts'));
59
+ writeFile(targetDir, `${resolvedApp.directory}/src/api/${resolvedApp.effectApi.stem}-client.ts`, createEffectClient(resolvedApp, '../../shared/api'));
60
60
  }
61
61
  if ('vertical' === resolvedApp.kind) {
62
62
  writeAppFile('src/federation-entry.tsx', createRemoteEntry(resolvedApp));
@@ -1,6 +1,6 @@
1
1
  import { type UltramodernBridgeConfig } from '../ultramodern-workspace/bridge-config';
2
2
  import type { ResolvedPackageSource, WorkspaceApp, WorkspaceEffectApi } from '../ultramodern-workspace/types';
3
- export type UltramodernToolingConfigSource = 'compact' | 'legacy';
3
+ export type UltramodernToolingConfigSource = 'compact';
4
4
  export type UltramodernToolingConfigApp = {
5
5
  id: string;
6
6
  kind: WorkspaceApp['kind'];
@@ -38,7 +38,6 @@ export type UltramodernToolingConfig = {
38
38
  topology: {
39
39
  apps: UltramodernToolingConfigApp[];
40
40
  };
41
- legacyContract?: Record<string, any>;
42
41
  };
43
42
  export declare function readUltramodernConfig(workspaceRoot?: any): UltramodernToolingConfig;
44
43
  export declare function workspaceAppsFromToolingConfig(config: UltramodernToolingConfig): WorkspaceApp[];
@@ -1,5 +1,4 @@
1
1
  import type { Ownership, WorkspaceApp, WorkspaceEffectApi } from './types';
2
- export declare const GENERATED_CONTRACT_PATH = ".modernjs/ultramodern-generated-contract.json";
3
2
  export declare const ULTRAMODERN_CONFIG_PATH = ".modernjs/ultramodern.json";
4
3
  export declare const shellApp: WorkspaceApp;
5
4
  export declare function createShellHost(remotes?: WorkspaceApp[]): WorkspaceApp;
@@ -1,5 +1,6 @@
1
1
  import type { WorkspaceApp } from './types';
2
2
  export declare function createWorkspaceValidationScript(scope: string, enableTailwind: boolean, remotes?: WorkspaceApp[]): string;
3
3
  export declare function createWorkspaceI18nBoundaryValidationScript(): string;
4
+ export declare function createWorkspaceApiBoundaryValidationScript(): string;
4
5
  export declare function createPerformanceReadinessConfigScript(): string;
5
6
  export declare function writeGeneratedWorkspaceScripts(targetDir: string, _scope: string, _enableTailwind: boolean, _remotes?: WorkspaceApp[]): void;
package/package.json CHANGED
@@ -21,7 +21,7 @@
21
21
  "engines": {
22
22
  "node": ">=20"
23
23
  },
24
- "version": "3.4.0-ultramodern.19",
24
+ "version": "3.4.0-ultramodern.20",
25
25
  "types": "./dist/types/index.d.ts",
26
26
  "main": "./dist/esm-node/index.js",
27
27
  "bin": {
@@ -77,7 +77,7 @@
77
77
  "@modern-js/codesmith": "2.6.9",
78
78
  "oxfmt": "0.55.0",
79
79
  "ultracite": "7.8.3",
80
- "@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.4.0-ultramodern.19"
80
+ "@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.4.0-ultramodern.20"
81
81
  },
82
82
  "devDependencies": {
83
83
  "@rslib/core": "0.23.0",
@@ -99,6 +99,6 @@
99
99
  "test": "rm -rf dist && rslib build -c rslibconfig.mts && rstest --passWithNoTests"
100
100
  },
101
101
  "ultramodern": {
102
- "frameworkVersion": "3.4.0-ultramodern.19"
102
+ "frameworkVersion": "3.4.0-ultramodern.20"
103
103
  }
104
104
  }