@bleedingdev/modern-js-create 3.5.0-ultramodern.3 → 3.5.0-ultramodern.30

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 (93) hide show
  1. package/README.md +21 -17
  2. package/dist/cjs/ultramodern-tooling/commands.cjs +772 -75
  3. package/dist/cjs/ultramodern-tooling/config.cjs +149 -8
  4. package/dist/cjs/ultramodern-workspace/add-vertical.cjs +25 -0
  5. package/dist/cjs/ultramodern-workspace/api.cjs +44 -0
  6. package/dist/cjs/ultramodern-workspace/app-files.cjs +8 -11
  7. package/dist/cjs/ultramodern-workspace/backend-federation.cjs +282 -0
  8. package/dist/cjs/ultramodern-workspace/contracts.cjs +24 -8
  9. package/dist/cjs/ultramodern-workspace/delivery-unit-sync.cjs +157 -0
  10. package/dist/cjs/ultramodern-workspace/delivery-unit.cjs +88 -0
  11. package/dist/cjs/ultramodern-workspace/descriptors.cjs +24 -0
  12. package/dist/cjs/ultramodern-workspace/module-federation.cjs +161 -50
  13. package/dist/cjs/ultramodern-workspace/package-json.cjs +26 -43
  14. package/dist/cjs/ultramodern-workspace/pnpm-workspace-policy-plan.cjs +166 -0
  15. package/dist/cjs/ultramodern-workspace/tooling-command-catalog.cjs +153 -0
  16. package/dist/cjs/ultramodern-workspace/versions.cjs +8 -3
  17. package/dist/cjs/ultramodern-workspace/workspace-script-plan.cjs +175 -0
  18. package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +104 -63
  19. package/dist/cjs/ultramodern-workspace/workspace-validation-contract.cjs +97 -0
  20. package/dist/cjs/ultramodern-workspace/write-workspace.cjs +11 -3
  21. package/dist/cjs/ultramodern-workspace/zerops.cjs +100 -0
  22. package/dist/esm/ultramodern-tooling/commands.js +775 -78
  23. package/dist/esm/ultramodern-tooling/config.js +144 -9
  24. package/dist/esm/ultramodern-workspace/add-vertical.js +26 -1
  25. package/dist/esm/ultramodern-workspace/api.js +43 -2
  26. package/dist/esm/ultramodern-workspace/app-files.js +8 -11
  27. package/dist/esm/ultramodern-workspace/backend-federation.js +217 -0
  28. package/dist/esm/ultramodern-workspace/contracts.js +24 -8
  29. package/dist/esm/ultramodern-workspace/delivery-unit-sync.js +108 -0
  30. package/dist/esm/ultramodern-workspace/delivery-unit.js +31 -0
  31. package/dist/esm/ultramodern-workspace/descriptors.js +13 -1
  32. package/dist/esm/ultramodern-workspace/module-federation.js +160 -42
  33. package/dist/esm/ultramodern-workspace/package-json.js +16 -40
  34. package/dist/esm/ultramodern-workspace/pnpm-workspace-policy-plan.js +113 -0
  35. package/dist/esm/ultramodern-workspace/tooling-command-catalog.js +100 -0
  36. package/dist/esm/ultramodern-workspace/versions.js +6 -4
  37. package/dist/esm/ultramodern-workspace/workspace-script-plan.js +110 -0
  38. package/dist/esm/ultramodern-workspace/workspace-scripts.js +88 -65
  39. package/dist/esm/ultramodern-workspace/workspace-validation-contract.js +59 -0
  40. package/dist/esm/ultramodern-workspace/write-workspace.js +14 -6
  41. package/dist/esm/ultramodern-workspace/zerops.js +62 -0
  42. package/dist/esm-node/ultramodern-tooling/commands.js +775 -78
  43. package/dist/esm-node/ultramodern-tooling/config.js +144 -9
  44. package/dist/esm-node/ultramodern-workspace/add-vertical.js +26 -1
  45. package/dist/esm-node/ultramodern-workspace/api.js +43 -2
  46. package/dist/esm-node/ultramodern-workspace/app-files.js +8 -11
  47. package/dist/esm-node/ultramodern-workspace/backend-federation.js +218 -0
  48. package/dist/esm-node/ultramodern-workspace/contracts.js +24 -8
  49. package/dist/esm-node/ultramodern-workspace/delivery-unit-sync.js +109 -0
  50. package/dist/esm-node/ultramodern-workspace/delivery-unit.js +32 -0
  51. package/dist/esm-node/ultramodern-workspace/descriptors.js +13 -1
  52. package/dist/esm-node/ultramodern-workspace/module-federation.js +160 -42
  53. package/dist/esm-node/ultramodern-workspace/package-json.js +16 -40
  54. package/dist/esm-node/ultramodern-workspace/pnpm-workspace-policy-plan.js +114 -0
  55. package/dist/esm-node/ultramodern-workspace/tooling-command-catalog.js +101 -0
  56. package/dist/esm-node/ultramodern-workspace/versions.js +6 -4
  57. package/dist/esm-node/ultramodern-workspace/workspace-script-plan.js +111 -0
  58. package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +88 -65
  59. package/dist/esm-node/ultramodern-workspace/workspace-validation-contract.js +60 -0
  60. package/dist/esm-node/ultramodern-workspace/write-workspace.js +14 -6
  61. package/dist/esm-node/ultramodern-workspace/zerops.js +63 -0
  62. package/dist/types/ultramodern-tooling/config.d.ts +6 -0
  63. package/dist/types/ultramodern-workspace/api.d.ts +1 -0
  64. package/dist/types/ultramodern-workspace/backend-federation.d.ts +11 -0
  65. package/dist/types/ultramodern-workspace/contracts.d.ts +1 -1
  66. package/dist/types/ultramodern-workspace/delivery-unit-sync.d.ts +6 -0
  67. package/dist/types/ultramodern-workspace/delivery-unit.d.ts +27 -0
  68. package/dist/types/ultramodern-workspace/descriptors.d.ts +4 -0
  69. package/dist/types/ultramodern-workspace/module-federation.d.ts +4 -9
  70. package/dist/types/ultramodern-workspace/package-json.d.ts +0 -1
  71. package/dist/types/ultramodern-workspace/pnpm-workspace-policy-plan.d.ts +39 -0
  72. package/dist/types/ultramodern-workspace/tooling-command-catalog.d.ts +18 -0
  73. package/dist/types/ultramodern-workspace/versions.d.ts +5 -3
  74. package/dist/types/ultramodern-workspace/workspace-script-plan.d.ts +72 -0
  75. package/dist/types/ultramodern-workspace/workspace-scripts.d.ts +13 -0
  76. package/dist/types/ultramodern-workspace/workspace-validation-contract.d.ts +42 -0
  77. package/dist/types/ultramodern-workspace/zerops.d.ts +2 -0
  78. package/package.json +3 -3
  79. package/template-workspace/.gitignore.handlebars +4 -0
  80. package/template-workspace/README.md.handlebars +18 -15
  81. package/template-workspace/patches/@module-federation__bridge-react@2.6.0.patch +140 -0
  82. package/template-workspace/patches/@module-federation__modern-js-v3@2.6.0.patch +57 -0
  83. package/template-workspace/patches/drizzle-orm-ts7-strict-declarations.patch +452 -0
  84. package/template-workspace/patches/effect-schema-error-type-id.patch +18 -0
  85. package/template-workspace/pnpm-workspace.yaml.handlebars +8 -0
  86. package/template-workspace/scripts/bootstrap-agent-skills.mjs +11 -3
  87. package/templates/workspace-scripts/check-ultramodern-api-boundaries.mts +40 -2
  88. package/templates/workspace-scripts/generate-node-backend-federation.mjs +270 -0
  89. package/templates/workspace-scripts/materialize-zerops-runtime.mjs +448 -0
  90. package/templates/workspace-scripts/proof-cloudflare-version.mjs +237 -9
  91. package/templates/workspace-scripts/proof-node-backend-federation.mjs +729 -0
  92. package/templates/workspace-scripts/ultramodern-cloudflare-proof.mjs +188 -2
  93. package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +434 -18
@@ -20,8 +20,8 @@ function resolveModuleFederationPublicPath(publicPath, manifestUrl) {
20
20
  }
21
21
  }
22
22
 
23
- async function fetchText(url) {
24
- const response = await fetch(url);
23
+ async function fetchText(url, init) {
24
+ const response = await fetch(url, init);
25
25
  return {
26
26
  ok: response.ok,
27
27
  status: response.status,
@@ -48,6 +48,52 @@ function parseMaybeJson(body) {
48
48
  }
49
49
  }
50
50
 
51
+ function jsonPathValue(value, path) {
52
+ const segments = String(path ?? '')
53
+ .split('.')
54
+ .filter(Boolean);
55
+ let current = value;
56
+
57
+ for (const segment of segments) {
58
+ if (current === null || current === undefined) {
59
+ return undefined;
60
+ }
61
+
62
+ if (Array.isArray(current) && /^\d+$/u.test(segment)) {
63
+ current = current[Number(segment)];
64
+ continue;
65
+ }
66
+
67
+ if (typeof current === 'object' && Object.hasOwn(current, segment)) {
68
+ current = current[segment];
69
+ continue;
70
+ }
71
+
72
+ return undefined;
73
+ }
74
+
75
+ return current;
76
+ }
77
+
78
+ function jsonValuesEqual(left, right) {
79
+ return JSON.stringify(left) === JSON.stringify(right);
80
+ }
81
+
82
+ function normalizeJsonSmokeExpectations(check) {
83
+ if (Array.isArray(check.expectations)) {
84
+ return check.expectations;
85
+ }
86
+
87
+ if (check.expect && typeof check.expect === 'object') {
88
+ return Object.entries(check.expect).map(([path, equals]) => ({
89
+ path,
90
+ equals,
91
+ }));
92
+ }
93
+
94
+ return [];
95
+ }
96
+
51
97
  function markerFromJson(value) {
52
98
  if (!value || typeof value !== 'object') {
53
99
  return undefined;
@@ -687,6 +733,27 @@ function validateUiMarkerEvidence(evidence, app, ssr) {
687
733
  status: uiMarker === app.marker?.build ? 'pass' : 'fail',
688
734
  });
689
735
  assert(uiMarker === app.marker?.build, `${app.id} UI marker mismatch`);
736
+
737
+ if (app.deliveryUnit) {
738
+ evidence.assertions.push({
739
+ type: 'delivery-unit-ui-marker',
740
+ unitId: app.deliveryUnit.unitId,
741
+ expected: app.deliveryUnit.surfaces?.ui?.buildMarker ?? app.deliveryUnit.buildMarker,
742
+ actual: uiMarker,
743
+ status:
744
+ uiMarker === (app.deliveryUnit.surfaces?.ui?.buildMarker ?? app.deliveryUnit.buildMarker)
745
+ ? 'pass'
746
+ : 'fail',
747
+ });
748
+ assert(
749
+ uiMarker !== undefined,
750
+ `${app.id} delivery unit ${app.deliveryUnit.unitId} is declared but SSR response is missing its build marker`,
751
+ );
752
+ assert(
753
+ uiMarker === (app.deliveryUnit.surfaces?.ui?.buildMarker ?? app.deliveryUnit.buildMarker),
754
+ `${app.id} delivery unit ${app.deliveryUnit.unitId} UI surface build marker mismatch`,
755
+ );
756
+ }
690
757
  }
691
758
 
692
759
  function validateCssRootMarkerEvidence(evidence, app, ssr) {
@@ -857,6 +924,123 @@ async function validateReadinessEvidence(evidence, app, publicUrl, routes) {
857
924
  `${app.id} Effect readiness returned HTTP ${readiness.status}`,
858
925
  );
859
926
  assert(apiMarker === app.marker?.build, `${app.id} API marker mismatch`);
927
+
928
+ if (app.deliveryUnit) {
929
+ evidence.assertions.push({
930
+ type: 'delivery-unit-api-marker',
931
+ route: routes.apiReadiness,
932
+ unitId: app.deliveryUnit.unitId,
933
+ expected: app.deliveryUnit.buildMarker,
934
+ actual: apiMarker,
935
+ status: apiMarker === app.deliveryUnit.buildMarker ? 'pass' : 'fail',
936
+ });
937
+ assert(
938
+ apiMarker !== undefined,
939
+ `${app.id} delivery unit ${app.deliveryUnit.unitId} is declared but readiness response is missing its build marker`,
940
+ );
941
+ assert(
942
+ apiMarker === app.deliveryUnit.buildMarker,
943
+ `${app.id} delivery unit ${app.deliveryUnit.unitId} API surface build marker mismatch`,
944
+ );
945
+ }
946
+ }
947
+ }
948
+
949
+ async function validateServiceBindingEvidence(evidence, app, publicUrl) {
950
+ const serviceBindings = app.deploy?.cloudflare?.serviceBindings ?? [];
951
+
952
+ for (const binding of serviceBindings) {
953
+ const response = await fetchText(joinUrl(publicUrl, binding.route));
954
+ const responseJson = parseMaybeJson(response.body);
955
+ const apiMarker = markerFromJson(responseJson);
956
+ const passed = response.ok && apiMarker === binding.expectedMarker;
957
+
958
+ evidence.assertions.push({
959
+ type: 'service-binding-api-marker',
960
+ appId: binding.appId,
961
+ binding: binding.binding,
962
+ route: binding.route,
963
+ expected: binding.expectedMarker,
964
+ actual: apiMarker,
965
+ status: passed ? 'pass' : 'fail',
966
+ statusCode: response.status,
967
+ });
968
+ assert(
969
+ response.ok,
970
+ `${app.id} service binding ${binding.binding} returned HTTP ${response.status}`,
971
+ );
972
+ assert(
973
+ apiMarker === binding.expectedMarker,
974
+ `${app.id} service binding ${binding.binding} API marker mismatch`,
975
+ );
976
+ }
977
+ }
978
+
979
+ async function validateJsonSmokeEvidence(evidence, app, publicUrl) {
980
+ const checks = app.deploy?.cloudflare?.jsonSmokeChecks ?? [];
981
+
982
+ for (const check of checks) {
983
+ const route = check.route;
984
+ assert(
985
+ typeof route === 'string' && route.length > 0,
986
+ `${app.id} JSON smoke check is missing a route`,
987
+ );
988
+
989
+ const method = String(check.method ?? 'GET').toUpperCase();
990
+ const requestBody =
991
+ check.body ?? check.payload ?? check.requestBody ?? undefined;
992
+ const response = await fetchText(joinUrl(publicUrl, route), {
993
+ method,
994
+ headers: {
995
+ accept: 'application/json',
996
+ ...(requestBody === undefined
997
+ ? {}
998
+ : { 'content-type': 'application/json' }),
999
+ },
1000
+ ...(requestBody === undefined
1001
+ ? {}
1002
+ : { body: JSON.stringify(requestBody) }),
1003
+ });
1004
+ const responseJson = parseMaybeJson(response.body);
1005
+ const checkId = check.id ?? route;
1006
+
1007
+ evidence.assertions.push({
1008
+ type: 'json-smoke-http',
1009
+ id: checkId,
1010
+ method,
1011
+ route,
1012
+ status: response.ok && responseJson !== undefined ? 'pass' : 'fail',
1013
+ statusCode: response.status,
1014
+ });
1015
+ assert(
1016
+ response.ok,
1017
+ `${app.id} JSON smoke ${checkId} returned HTTP ${response.status}`,
1018
+ );
1019
+ assert(
1020
+ responseJson !== undefined,
1021
+ `${app.id} JSON smoke ${checkId} did not return JSON`,
1022
+ );
1023
+
1024
+ for (const expectation of normalizeJsonSmokeExpectations(check)) {
1025
+ const actual = jsonPathValue(responseJson, expectation.path);
1026
+ const passed = jsonValuesEqual(actual, expectation.equals);
1027
+
1028
+ evidence.assertions.push({
1029
+ type: 'json-smoke-value',
1030
+ id: checkId,
1031
+ route,
1032
+ path: expectation.path,
1033
+ expected: expectation.equals,
1034
+ actual,
1035
+ status: passed ? 'pass' : 'fail',
1036
+ });
1037
+ assert(
1038
+ passed,
1039
+ `${app.id} JSON smoke ${checkId} expected ${expectation.path} to equal ${JSON.stringify(
1040
+ expectation.equals,
1041
+ )}`,
1042
+ );
1043
+ }
860
1044
  }
861
1045
  }
862
1046
 
@@ -869,6 +1053,8 @@ async function validateApp(app, publicUrl) {
869
1053
  await validateModuleFederationManifestEvidence(evidence, app, publicUrl, routes);
870
1054
  await validateI18nEvidence(evidence, app, publicUrl, routes);
871
1055
  await validateReadinessEvidence(evidence, app, publicUrl, routes);
1056
+ await validateServiceBindingEvidence(evidence, app, publicUrl);
1057
+ await validateJsonSmokeEvidence(evidence, app, publicUrl);
872
1058
 
873
1059
  return evidence;
874
1060
  }