@bleedingdev/modern-js-create 3.5.0-ultramodern.27 → 3.5.0-ultramodern.29

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 (79) hide show
  1. package/dist/cjs/ultramodern-tooling/commands.cjs +497 -155
  2. package/dist/cjs/ultramodern-tooling/config.cjs +149 -8
  3. package/dist/cjs/ultramodern-workspace/add-vertical.cjs +25 -0
  4. package/dist/cjs/ultramodern-workspace/api.cjs +44 -0
  5. package/dist/cjs/ultramodern-workspace/backend-federation.cjs +282 -0
  6. package/dist/cjs/ultramodern-workspace/contracts.cjs +24 -8
  7. package/dist/cjs/ultramodern-workspace/delivery-unit-sync.cjs +157 -0
  8. package/dist/cjs/ultramodern-workspace/delivery-unit.cjs +88 -0
  9. package/dist/cjs/ultramodern-workspace/descriptors.cjs +24 -0
  10. package/dist/cjs/ultramodern-workspace/module-federation.cjs +122 -44
  11. package/dist/cjs/ultramodern-workspace/package-json.cjs +11 -34
  12. package/dist/cjs/ultramodern-workspace/pnpm-workspace-policy-plan.cjs +166 -0
  13. package/dist/cjs/ultramodern-workspace/tooling-command-catalog.cjs +153 -0
  14. package/dist/cjs/ultramodern-workspace/workspace-script-plan.cjs +175 -0
  15. package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +43 -62
  16. package/dist/cjs/ultramodern-workspace/workspace-validation-contract.cjs +97 -0
  17. package/dist/cjs/ultramodern-workspace/write-workspace.cjs +9 -3
  18. package/dist/cjs/ultramodern-workspace/zerops.cjs +100 -0
  19. package/dist/esm/ultramodern-tooling/commands.js +500 -158
  20. package/dist/esm/ultramodern-tooling/config.js +144 -9
  21. package/dist/esm/ultramodern-workspace/add-vertical.js +26 -1
  22. package/dist/esm/ultramodern-workspace/api.js +43 -2
  23. package/dist/esm/ultramodern-workspace/backend-federation.js +217 -0
  24. package/dist/esm/ultramodern-workspace/contracts.js +24 -8
  25. package/dist/esm/ultramodern-workspace/delivery-unit-sync.js +108 -0
  26. package/dist/esm/ultramodern-workspace/delivery-unit.js +31 -0
  27. package/dist/esm/ultramodern-workspace/descriptors.js +13 -1
  28. package/dist/esm/ultramodern-workspace/module-federation.js +121 -36
  29. package/dist/esm/ultramodern-workspace/package-json.js +11 -31
  30. package/dist/esm/ultramodern-workspace/pnpm-workspace-policy-plan.js +113 -0
  31. package/dist/esm/ultramodern-workspace/tooling-command-catalog.js +100 -0
  32. package/dist/esm/ultramodern-workspace/workspace-script-plan.js +110 -0
  33. package/dist/esm/ultramodern-workspace/workspace-scripts.js +35 -63
  34. package/dist/esm/ultramodern-workspace/workspace-validation-contract.js +59 -0
  35. package/dist/esm/ultramodern-workspace/write-workspace.js +11 -5
  36. package/dist/esm/ultramodern-workspace/zerops.js +62 -0
  37. package/dist/esm-node/ultramodern-tooling/commands.js +500 -158
  38. package/dist/esm-node/ultramodern-tooling/config.js +144 -9
  39. package/dist/esm-node/ultramodern-workspace/add-vertical.js +26 -1
  40. package/dist/esm-node/ultramodern-workspace/api.js +43 -2
  41. package/dist/esm-node/ultramodern-workspace/backend-federation.js +218 -0
  42. package/dist/esm-node/ultramodern-workspace/contracts.js +24 -8
  43. package/dist/esm-node/ultramodern-workspace/delivery-unit-sync.js +109 -0
  44. package/dist/esm-node/ultramodern-workspace/delivery-unit.js +32 -0
  45. package/dist/esm-node/ultramodern-workspace/descriptors.js +13 -1
  46. package/dist/esm-node/ultramodern-workspace/module-federation.js +121 -36
  47. package/dist/esm-node/ultramodern-workspace/package-json.js +11 -31
  48. package/dist/esm-node/ultramodern-workspace/pnpm-workspace-policy-plan.js +114 -0
  49. package/dist/esm-node/ultramodern-workspace/tooling-command-catalog.js +101 -0
  50. package/dist/esm-node/ultramodern-workspace/workspace-script-plan.js +111 -0
  51. package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +35 -63
  52. package/dist/esm-node/ultramodern-workspace/workspace-validation-contract.js +60 -0
  53. package/dist/esm-node/ultramodern-workspace/write-workspace.js +11 -5
  54. package/dist/esm-node/ultramodern-workspace/zerops.js +63 -0
  55. package/dist/types/ultramodern-tooling/config.d.ts +6 -0
  56. package/dist/types/ultramodern-workspace/api.d.ts +1 -0
  57. package/dist/types/ultramodern-workspace/backend-federation.d.ts +11 -0
  58. package/dist/types/ultramodern-workspace/contracts.d.ts +1 -1
  59. package/dist/types/ultramodern-workspace/delivery-unit-sync.d.ts +6 -0
  60. package/dist/types/ultramodern-workspace/delivery-unit.d.ts +27 -0
  61. package/dist/types/ultramodern-workspace/descriptors.d.ts +4 -0
  62. package/dist/types/ultramodern-workspace/module-federation.d.ts +4 -9
  63. package/dist/types/ultramodern-workspace/package-json.d.ts +0 -1
  64. package/dist/types/ultramodern-workspace/pnpm-workspace-policy-plan.d.ts +39 -0
  65. package/dist/types/ultramodern-workspace/tooling-command-catalog.d.ts +18 -0
  66. package/dist/types/ultramodern-workspace/workspace-script-plan.d.ts +72 -0
  67. package/dist/types/ultramodern-workspace/workspace-scripts.d.ts +3 -0
  68. package/dist/types/ultramodern-workspace/workspace-validation-contract.d.ts +42 -0
  69. package/dist/types/ultramodern-workspace/zerops.d.ts +2 -0
  70. package/package.json +3 -3
  71. package/template-workspace/.gitignore.handlebars +1 -0
  72. package/template-workspace/scripts/bootstrap-agent-skills.mjs +11 -3
  73. package/templates/workspace-scripts/check-ultramodern-api-boundaries.mts +40 -2
  74. package/templates/workspace-scripts/generate-node-backend-federation.mjs +270 -0
  75. package/templates/workspace-scripts/materialize-zerops-runtime.mjs +448 -0
  76. package/templates/workspace-scripts/proof-cloudflare-version.mjs +234 -8
  77. package/templates/workspace-scripts/proof-node-backend-federation.mjs +729 -0
  78. package/templates/workspace-scripts/ultramodern-cloudflare-proof.mjs +188 -2
  79. package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +322 -8
@@ -10,6 +10,10 @@ const workspaceRoot = path.resolve(
10
10
  path.join(path.dirname(fileURLToPath(import.meta.url)), '..'),
11
11
  );
12
12
  const compactConfigPath = path.join(workspaceRoot, '.modernjs/ultramodern.json');
13
+ const localOverlayPath = path.join(
14
+ workspaceRoot,
15
+ 'topology/local-overlays/development.json',
16
+ );
13
17
  const defaultOut = path.join(
14
18
  workspaceRoot,
15
19
  '.codex/reports/cloudflare-version-proof/public-url-proof.json',
@@ -19,6 +23,10 @@ function readJson(filePath) {
19
23
  return JSON.parse(fs.readFileSync(filePath, 'utf8'));
20
24
  }
21
25
 
26
+ function readOptionalJson(filePath) {
27
+ return fs.existsSync(filePath) ? readJson(filePath) : {};
28
+ }
29
+
22
30
  function toKebabCase(value) {
23
31
  return String(value)
24
32
  .trim()
@@ -50,7 +58,7 @@ function appNamespace(app) {
50
58
  return app.kind === 'shell' ? 'shell' : (app.domain ?? app.id);
51
59
  }
52
60
 
53
- function normalizeCompactApp(rawApp) {
61
+ function normalizeCompactApp(rawApp, localOverlay = {}) {
54
62
  const id = String(rawApp.id);
55
63
  const kind = rawApp.kind === 'vertical' ? 'vertical' : 'shell';
56
64
  const appPath =
@@ -86,6 +94,19 @@ function normalizeCompactApp(rawApp) {
86
94
  : `/${domain ?? id}-api`,
87
95
  }
88
96
  : undefined;
97
+ const cloudflare =
98
+ rawApp.deploy?.cloudflare && typeof rawApp.deploy.cloudflare === 'object'
99
+ ? rawApp.deploy.cloudflare
100
+ : {};
101
+ const jsonSmokeChecks = Array.isArray(cloudflare.jsonSmokeChecks)
102
+ ? cloudflare.jsonSmokeChecks
103
+ : undefined;
104
+ const port =
105
+ typeof rawApp.port === 'number'
106
+ ? rawApp.port
107
+ : typeof localOverlay.ports?.[id] === 'number'
108
+ ? localOverlay.ports[id]
109
+ : undefined;
89
110
 
90
111
  return {
91
112
  id,
@@ -93,6 +114,7 @@ function normalizeCompactApp(rawApp) {
93
114
  path: appPath,
94
115
  packageSuffix,
95
116
  domain,
117
+ port,
96
118
  mfName:
97
119
  typeof moduleFederation.name === 'string'
98
120
  ? moduleFederation.name
@@ -100,6 +122,7 @@ function normalizeCompactApp(rawApp) {
100
122
  ? 'shellSuperApp'
101
123
  : `vertical${toPascalCase(domain ?? id)}`,
102
124
  api,
125
+ jsonSmokeChecks,
103
126
  };
104
127
  }
105
128
 
@@ -111,6 +134,30 @@ function createBuildMarker(scope, app) {
111
134
  .slice(0, 16);
112
135
  }
113
136
 
137
+ function createDeliveryUnit(packageScope, app) {
138
+ const unitId = `${packageScope}/${app.domain ?? app.id}`;
139
+ const buildMarker = createBuildMarker(packageScope, app);
140
+ const identity = {
141
+ unitId,
142
+ buildMarker,
143
+ sourceRevision: 'workspace',
144
+ };
145
+
146
+ return {
147
+ schemaVersion: 1,
148
+ kind: 'microvertical-delivery-unit',
149
+ unitId,
150
+ packageName: `@${packageScope}/${app.packageSuffix}`,
151
+ version: '0.1.0',
152
+ buildMarker,
153
+ sourceRevision: 'workspace',
154
+ surfaces: {
155
+ ui: { ...identity, surface: 'ui' },
156
+ api: { ...identity, surface: 'api' },
157
+ },
158
+ };
159
+ }
160
+
114
161
  function createCloudflareSecurity() {
115
162
  return {
116
163
  enabled: true,
@@ -217,11 +264,175 @@ function createCloudflareRoutes(app) {
217
264
  ? {
218
265
  apiReadiness: `${app.api.prefix}/${app.api.stem}/readiness`,
219
266
  }
267
+ : {}),
268
+ };
269
+ }
270
+
271
+ function createApiReadinessRoute(app) {
272
+ return app.api ? `${app.api.prefix}/${app.api.stem}/readiness` : undefined;
273
+ }
274
+
275
+ function createCloudflareWorkerName(packageScope, app) {
276
+ return `${toKebabCase(packageScope)}-${app.packageSuffix}`.slice(0, 63);
277
+ }
278
+
279
+ function createWorkerBindingName(app) {
280
+ return `VERTICAL_${toEnvSegment(app.domain ?? app.id)}_WORKER`;
281
+ }
282
+
283
+ function createWorkerBindingEnv(app) {
284
+ return `VERTICAL_${toEnvSegment(app.domain ?? app.id)}_WORKER_BINDING`;
285
+ }
286
+
287
+ function createDispatchNamespaceEnv(app) {
288
+ return `VERTICAL_${toEnvSegment(app.domain ?? app.id)}_DISPATCH_NAMESPACE`;
289
+ }
290
+
291
+ function createDispatchWorkerNameEnv(app) {
292
+ return `VERTICAL_${toEnvSegment(app.domain ?? app.id)}_WORKER_NAME`;
293
+ }
294
+
295
+ function createBackendRemoteName(app) {
296
+ return `${app.mfName ?? `vertical${toPascalCase(app.id)}`}Backend`;
297
+ }
298
+
299
+ function createCloudflareExecutionSurface(packageScope, app) {
300
+ return {
301
+ kind: 'cloudflare-worker-snapshot',
302
+ workerName: createCloudflareWorkerName(packageScope, app),
303
+ publicUrlEnv: `ULTRAMODERN_PUBLIC_URL_${toEnvSegment(app.id)}`,
304
+ ssr: {
305
+ workerEntry: '.output/server/index.mjs',
306
+ workerManifest: '.output/server/modern-worker-manifest.json',
307
+ routeManifest: '.output/server/route.json',
308
+ ssrBundle: '.output/worker/index.js',
309
+ effectBffBundle: '.output/worker/__modern_bff_effect.js',
310
+ assetsBinding: 'ASSETS',
311
+ },
312
+ zephyr: {
313
+ runtime: 'ssr-worker',
314
+ integration: 'managed-cloudflare',
315
+ snapshotIdEnv: `ZEPHYR_${toEnvSegment(app.domain ?? app.id)}_SNAPSHOT_ID`,
316
+ versionIdEnv: `ZEPHYR_${toEnvSegment(app.domain ?? app.id)}_VERSION_ID`,
317
+ applicationUidEnv: `ZEPHYR_${toEnvSegment(app.domain ?? app.id)}_APPLICATION_UID`,
318
+ },
319
+ workerDispatch: {
320
+ preferred: 'service-binding',
321
+ serviceBinding: createWorkerBindingName(app),
322
+ serviceBindingEnv: createWorkerBindingEnv(app),
323
+ dispatchNamespaceEnv: createDispatchNamespaceEnv(app),
324
+ dispatchWorkerNameEnv: createDispatchWorkerNameEnv(app),
325
+ requestInterface: 'fetch',
326
+ },
327
+ };
328
+ }
329
+
330
+ function createNodeExecutionSurface(app) {
331
+ return {
332
+ kind: 'node-mf-runtime',
333
+ adapterVersion: 'backend-mf-effect-v1',
334
+ remoteName: createBackendRemoteName(app),
335
+ manifestUrl: `http://localhost:${app.port}/backend-mf-manifest.json`,
336
+ containerEntry: `http://localhost:${app.port}/backendRemoteEntry.mjs`,
337
+ remoteType: 'module',
338
+ expose: './effect-api',
339
+ runtimePackage: '@modern-js/plugin-bff/effect',
340
+ };
341
+ }
342
+
343
+ function createServerExecutionProof(packageScope, app) {
344
+ if (!app.api) {
345
+ return undefined;
346
+ }
347
+ return {
348
+ apiBaseUrl: `http://localhost:${app.port}${app.api.prefix}`,
349
+ versionBoundary: 'web-and-api-same-build',
350
+ cloudflare: {
351
+ ...createCloudflareExecutionSurface(packageScope, app),
352
+ apiReadiness: createApiReadinessRoute(app),
353
+ },
354
+ node: createNodeExecutionSurface(app),
355
+ };
356
+ }
357
+
358
+ function createBackendFederationProof(packageScope, app) {
359
+ if (!app.api) {
360
+ return undefined;
361
+ }
362
+ const apiReadiness = createApiReadinessRoute(app);
363
+ const remoteName = createBackendRemoteName(app);
364
+ return {
365
+ role: 'microvertical-server',
366
+ name: remoteName,
367
+ runtimeFramework: 'effect',
368
+ strictEffectApproach: true,
369
+ exposes: {
370
+ './effect-api': {
371
+ runtime: `${app.path}/api/index.ts`,
372
+ readiness: apiReadiness,
373
+ },
374
+ },
375
+ versionBoundary: {
376
+ invariant: 'web-and-api-same-build',
377
+ ui: {
378
+ manifestUrl: `http://localhost:${app.port}/mf-manifest.json`,
379
+ marker: createBuildMarker(packageScope, app),
380
+ },
381
+ api: {
382
+ readiness: apiReadiness,
383
+ marker: createBuildMarker(packageScope, app),
384
+ },
385
+ },
386
+ executionSurfaces: {
387
+ cloudflare: createCloudflareExecutionSurface(packageScope, app),
388
+ node: createNodeExecutionSurface(app),
389
+ },
390
+ compatibility: {
391
+ contractVersion: 'microvertical-server-effect-v1',
392
+ },
393
+ };
394
+ }
395
+
396
+ function createProofTarget(app) {
397
+ const cloudflare = app.deploy?.cloudflare;
398
+ return {
399
+ appId: app.id,
400
+ marker: app.marker,
401
+ cloudflare: {
402
+ workerName: cloudflare?.workerName,
403
+ publicUrlEnv: cloudflare?.publicUrlEnv,
404
+ routes: cloudflare?.routes,
405
+ serviceBindings: cloudflare?.serviceBindings,
406
+ jsonSmokeChecks: cloudflare?.jsonSmokeChecks,
407
+ },
408
+ ...(app.backendFederation
409
+ ? { backendFederation: app.backendFederation }
220
410
  : {}),
411
+ ...(app.serverExecution ? { serverExecution: app.serverExecution } : {}),
412
+ ...(app.deliveryUnit ? { deliveryUnit: app.deliveryUnit } : {}),
221
413
  };
222
414
  }
223
415
 
224
- function createContractApp(config, app) {
416
+ function createShellServiceBindingProof(packageScope, app, apps) {
417
+ if (app.kind !== 'shell') {
418
+ return undefined;
419
+ }
420
+
421
+ const bindings = apps
422
+ .filter(candidate => candidate.kind !== 'shell' && candidate.api)
423
+ .map(candidate => ({
424
+ appId: candidate.id,
425
+ binding: createWorkerBindingName(candidate),
426
+ route: `${candidate.api.prefix}/${candidate.api.stem}/readiness`,
427
+ service: createCloudflareWorkerName(packageScope, candidate),
428
+ expectedMarker: createBuildMarker(packageScope, candidate),
429
+ interface: 'fetch',
430
+ }));
431
+
432
+ return bindings.length > 0 ? bindings : undefined;
433
+ }
434
+
435
+ function createContractApp(config, app, apps) {
225
436
  const packageScope =
226
437
  typeof config.workspace?.packageScope === 'string'
227
438
  ? config.workspace.packageScope
@@ -230,19 +441,29 @@ function createContractApp(config, app) {
230
441
  typeof config.deploy?.worker?.compatibilityDate === 'string'
231
442
  ? config.deploy.worker.compatibilityDate
232
443
  : '2026-06-02';
444
+ const workerName = createCloudflareWorkerName(packageScope, app);
445
+ const backendFederation = createBackendFederationProof(packageScope, app);
446
+ const serverExecution = createServerExecutionProof(packageScope, app);
447
+ const deliveryUnit = app.api
448
+ ? createDeliveryUnit(packageScope, app)
449
+ : undefined;
450
+ const serviceBindings = createShellServiceBindingProof(
451
+ packageScope,
452
+ app,
453
+ apps,
454
+ );
233
455
 
234
456
  return {
235
457
  id: app.id,
236
458
  deploy: {
237
459
  cloudflare: {
238
- workerName: `${toKebabCase(packageScope)}-${app.packageSuffix}`.slice(
239
- 0,
240
- 63,
241
- ),
460
+ workerName,
242
461
  publicUrlEnv: `ULTRAMODERN_PUBLIC_URL_${toEnvSegment(app.id)}`,
243
462
  compatibilityDate,
244
463
  compatibilityFlags: ['nodejs_compat', 'global_fetch_strictly_public'],
245
464
  routes: createCloudflareRoutes(app),
465
+ ...(serviceBindings ? { serviceBindings } : {}),
466
+ ...(app.jsonSmokeChecks ? { jsonSmokeChecks: app.jsonSmokeChecks } : {}),
246
467
  security: createCloudflareSecurity(),
247
468
  qualityGates: createQualityGates(),
248
469
  },
@@ -254,6 +475,9 @@ function createContractApp(config, app) {
254
475
  appId: app.id,
255
476
  build: createBuildMarker(packageScope, app),
256
477
  },
478
+ ...(deliveryUnit ? { deliveryUnit } : {}),
479
+ ...(backendFederation ? { backendFederation } : {}),
480
+ ...(serverExecution ? { serverExecution } : {}),
257
481
  routes: {
258
482
  publicHead: createPublicHead(),
259
483
  publicSurface: createPublicSurface(),
@@ -267,13 +491,14 @@ function createContractApp(config, app) {
267
491
  }
268
492
 
269
493
  function synthesizeContractFromCompactConfig(config) {
494
+ const localOverlay = readOptionalJson(localOverlayPath);
270
495
  const apps = Array.isArray(config.topology?.apps)
271
- ? config.topology.apps.map(normalizeCompactApp)
496
+ ? config.topology.apps.map(app => normalizeCompactApp(app, localOverlay))
272
497
  : [];
273
498
 
274
499
  return {
275
500
  sourcePath: compactConfigPath,
276
- apps: apps.map(app => createContractApp(config, app)),
501
+ apps: apps.map(app => createContractApp(config, app, apps)),
277
502
  };
278
503
  }
279
504
 
@@ -372,6 +597,7 @@ async function main(argv = process.argv.slice(2)) {
372
597
  generatedAt: new Date().toISOString(),
373
598
  status: results.length > 0 ? 'pass' : 'skipped',
374
599
  contractPath: contract.sourcePath ?? compactConfigPath,
600
+ proofTargets: apps.map(createProofTarget),
375
601
  results,
376
602
  skipped,
377
603
  };