@bleedingdev/modern-js-create 3.5.0-ultramodern.2 → 3.5.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 (32) hide show
  1. package/README.md +20 -14
  2. package/dist/cjs/ultramodern-tooling/commands.cjs +357 -3
  3. package/dist/cjs/ultramodern-workspace/app-files.cjs +8 -11
  4. package/dist/cjs/ultramodern-workspace/module-federation.cjs +13 -6
  5. package/dist/cjs/ultramodern-workspace/package-json.cjs +15 -8
  6. package/dist/cjs/ultramodern-workspace/versions.cjs +5 -0
  7. package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +2 -0
  8. package/dist/cjs/ultramodern-workspace/write-workspace.cjs +2 -0
  9. package/dist/esm/ultramodern-tooling/commands.js +357 -3
  10. package/dist/esm/ultramodern-workspace/app-files.js +8 -11
  11. package/dist/esm/ultramodern-workspace/module-federation.js +13 -6
  12. package/dist/esm/ultramodern-workspace/package-json.js +5 -8
  13. package/dist/esm/ultramodern-workspace/versions.js +3 -1
  14. package/dist/esm/ultramodern-workspace/workspace-scripts.js +3 -1
  15. package/dist/esm/ultramodern-workspace/write-workspace.js +3 -1
  16. package/dist/esm-node/ultramodern-tooling/commands.js +357 -3
  17. package/dist/esm-node/ultramodern-workspace/app-files.js +8 -11
  18. package/dist/esm-node/ultramodern-workspace/module-federation.js +13 -6
  19. package/dist/esm-node/ultramodern-workspace/package-json.js +5 -8
  20. package/dist/esm-node/ultramodern-workspace/versions.js +3 -1
  21. package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +3 -1
  22. package/dist/esm-node/ultramodern-workspace/write-workspace.js +3 -1
  23. package/dist/types/ultramodern-workspace/versions.d.ts +2 -0
  24. package/package.json +3 -3
  25. package/template-workspace/.gitignore.handlebars +3 -0
  26. package/template-workspace/README.md.handlebars +19 -13
  27. package/template-workspace/patches/@module-federation__bridge-react@2.6.0.patch +140 -0
  28. package/template-workspace/patches/@module-federation__modern-js-v3@2.6.0.patch +57 -0
  29. package/template-workspace/patches/drizzle-orm-ts7-strict-declarations.patch +452 -0
  30. package/template-workspace/patches/effect-schema-error-type-id.patch +18 -0
  31. package/template-workspace/pnpm-workspace.yaml.handlebars +8 -0
  32. package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +87 -5
@@ -40,6 +40,7 @@ const POSTCSS_VERSION = '8.5.15';
40
40
  const EFFECT_VERSION = '4.0.0-beta.91';
41
41
  const EFFECT_VITEST_VERSION = '4.0.0-beta.91';
42
42
  const EFFECT_TSGO_VERSION = '0.14.6';
43
+ const DRIZZLE_ORM_VERSION = '1.0.0-rc.4';
43
44
  const TYPESCRIPT_STABLE_VERSION = '6.0.3';
44
45
  const TYPESCRIPT_NATIVE_PREVIEW_VERSION = '7.0.0-dev.20260628.1';
45
46
  const TYPESCRIPT_VERSION = TYPESCRIPT_STABLE_VERSION;
@@ -64,11 +65,13 @@ const ultramodernWorkspaceVersions = {
64
65
  moduleFederation: MODULE_FEDERATION_VERSION,
65
66
  effect: EFFECT_VERSION,
66
67
  effectVitest: EFFECT_VITEST_VERSION,
68
+ drizzleOrm: DRIZZLE_ORM_VERSION,
67
69
  tailwind: TAILWIND_VERSION,
68
70
  tailwindPostcss: TAILWIND_POSTCSS_VERSION
69
71
  };
70
72
  __webpack_require__.d(__webpack_exports__, {}, {
71
73
  CLOUDFLARE_COMPATIBILITY_DATE: CLOUDFLARE_COMPATIBILITY_DATE,
74
+ DRIZZLE_ORM_VERSION: DRIZZLE_ORM_VERSION,
72
75
  EFFECT_TSGO_VERSION: EFFECT_TSGO_VERSION,
73
76
  EFFECT_VERSION: EFFECT_VERSION,
74
77
  EFFECT_VITEST_VERSION: EFFECT_VITEST_VERSION,
@@ -102,6 +105,7 @@ __webpack_require__.d(__webpack_exports__, {}, {
102
105
  ultramodernWorkspaceVersions: ultramodernWorkspaceVersions
103
106
  });
104
107
  exports.CLOUDFLARE_COMPATIBILITY_DATE = __webpack_exports__.CLOUDFLARE_COMPATIBILITY_DATE;
108
+ exports.DRIZZLE_ORM_VERSION = __webpack_exports__.DRIZZLE_ORM_VERSION;
105
109
  exports.EFFECT_TSGO_VERSION = __webpack_exports__.EFFECT_TSGO_VERSION;
106
110
  exports.EFFECT_VERSION = __webpack_exports__.EFFECT_VERSION;
107
111
  exports.EFFECT_VITEST_VERSION = __webpack_exports__.EFFECT_VITEST_VERSION;
@@ -135,6 +139,7 @@ exports.ZEPHYR_RSPACK_PLUGIN_VERSION = __webpack_exports__.ZEPHYR_RSPACK_PLUGIN_
135
139
  exports.ultramodernWorkspaceVersions = __webpack_exports__.ultramodernWorkspaceVersions;
136
140
  for(var __rspack_i in __webpack_exports__)if (-1 === [
137
141
  "CLOUDFLARE_COMPATIBILITY_DATE",
142
+ "DRIZZLE_ORM_VERSION",
138
143
  "EFFECT_TSGO_VERSION",
139
144
  "EFFECT_VERSION",
140
145
  "EFFECT_VITEST_VERSION",
@@ -174,6 +174,8 @@ function createWorkspaceValidationScript(scope, enableTailwind, remotes = []) {
174
174
  const expectedCloudflareSecurity = (0, external_policy_cjs_namespaceObject.createCloudflareSecurityContract)();
175
175
  return (0, external_fs_io_cjs_namespaceObject.renderFileTemplate)("workspace-scripts/validate-ultramodern-workspace.mjs", {
176
176
  packageScope: scope,
177
+ effectVersion: external_versions_cjs_namespaceObject.EFFECT_VERSION,
178
+ moduleFederationVersion: external_versions_cjs_namespaceObject.MODULE_FEDERATION_VERSION,
177
179
  nodeVersion: external_versions_cjs_namespaceObject.NODE_VERSION,
178
180
  pnpmVersion: external_versions_cjs_namespaceObject.PNPM_VERSION,
179
181
  tailwindEnabledJson: JSON.stringify(enableTailwind),
@@ -175,8 +175,10 @@ function generateUltramodernWorkspace(options) {
175
175
  nodeVersion: external_versions_cjs_namespaceObject.NODE_VERSION,
176
176
  pnpmVersion: external_versions_cjs_namespaceObject.PNPM_VERSION,
177
177
  nodeFetchVersion: external_versions_cjs_namespaceObject.NODE_FETCH_VERSION,
178
+ drizzleOrmVersion: external_versions_cjs_namespaceObject.DRIZZLE_ORM_VERSION,
178
179
  effectVersion: external_versions_cjs_namespaceObject.EFFECT_VERSION,
179
180
  effectVitestVersion: external_versions_cjs_namespaceObject.EFFECT_VITEST_VERSION,
181
+ moduleFederationVersion: external_versions_cjs_namespaceObject.MODULE_FEDERATION_VERSION,
180
182
  tanstackRouterCoreVersion: external_versions_cjs_namespaceObject.TANSTACK_ROUTER_CORE_VERSION,
181
183
  tanstackRouterVersion: external_versions_cjs_namespaceObject.TANSTACK_ROUTER_VERSION,
182
184
  typescriptVersion: external_versions_cjs_namespaceObject.TYPESCRIPT_VERSION,
@@ -5,7 +5,11 @@ import node_path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { resolveCreatePackageRoot } from "../create-package-root.js";
7
7
  import { BLEEDINGDEV_PACKAGE_NAME_PREFIX, BLEEDINGDEV_PACKAGE_SCOPE, ULTRAMODERN_SINGLE_APP_MODERN_PACKAGES, ULTRAMODERN_WORKSPACE_MODERN_PACKAGES, WORKSPACE_PACKAGE_VERSION, modernPackageSpecifier } from "../ultramodern-package-source.js";
8
+ import { createAppEnvDts } from "../ultramodern-workspace/app-files.js";
8
9
  import { validateModuleFederationTypes } from "../ultramodern-workspace/mf-validation.js";
10
+ import { createAppModernConfig } from "../ultramodern-workspace/module-federation.js";
11
+ import { createAppMfTypesTsConfig, createAppTsConfig, createSharedPackageTsConfig, createTsConfigBase } from "../ultramodern-workspace/package-json.js";
12
+ import { DRIZZLE_ORM_VERSION, EFFECT_TSGO_VERSION, EFFECT_VERSION, EFFECT_VITEST_VERSION, MODULE_FEDERATION_VERSION, OXFMT_VERSION, OXLINT_VERSION, TYPESCRIPT_NATIVE_PREVIEW_VERSION, WRANGLER_VERSION, ZEPHYR_AGENT_VERSION, ZEPHYR_RSPACK_PLUGIN_VERSION } from "../ultramodern-workspace/versions.js";
9
13
  import { createWorkspaceValidationScript } from "../ultramodern-workspace/workspace-scripts.js";
10
14
  import { readUltramodernConfig, workspaceAppsFromToolingConfig } from "./config.js";
11
15
  const commands_dirname = node_path.dirname(fileURLToPath(import.meta.url));
@@ -151,6 +155,91 @@ function updateModernDependencies(packageJson, packageSource) {
151
155
  }
152
156
  return changed;
153
157
  }
158
+ const generatedToolingDependencyPins = new Map([
159
+ [
160
+ '@effect/tsgo',
161
+ EFFECT_TSGO_VERSION
162
+ ],
163
+ [
164
+ "@typescript/native-preview",
165
+ TYPESCRIPT_NATIVE_PREVIEW_VERSION
166
+ ],
167
+ [
168
+ 'oxfmt',
169
+ OXFMT_VERSION
170
+ ],
171
+ [
172
+ 'oxlint',
173
+ OXLINT_VERSION
174
+ ],
175
+ [
176
+ 'wrangler',
177
+ WRANGLER_VERSION
178
+ ],
179
+ [
180
+ 'zephyr-agent',
181
+ ZEPHYR_AGENT_VERSION
182
+ ],
183
+ [
184
+ 'zephyr-rspack-plugin',
185
+ ZEPHYR_RSPACK_PLUGIN_VERSION
186
+ ]
187
+ ]);
188
+ const strictEffectPackageVersionPolicyExclusions = [
189
+ `effect@${EFFECT_VERSION}`,
190
+ `@effect/opentelemetry@${EFFECT_VERSION}`
191
+ ];
192
+ const moduleFederationModernJsPatchPath = `patches/@module-federation__modern-js-v3@${MODULE_FEDERATION_VERSION}.patch`;
193
+ const moduleFederationModernJsPatchSourcePath = node_path.join(createPackageRoot, 'template-workspace', moduleFederationModernJsPatchPath);
194
+ const moduleFederationBridgeReactPatchPath = `patches/@module-federation__bridge-react@${MODULE_FEDERATION_VERSION}.patch`;
195
+ const moduleFederationBridgeReactPatchSourcePath = node_path.join(createPackageRoot, 'template-workspace', moduleFederationBridgeReactPatchPath);
196
+ const effectDeclarationPatchPath = 'patches/effect-schema-error-type-id.patch';
197
+ const effectDeclarationPatchSourcePath = node_path.join(createPackageRoot, 'template-workspace', effectDeclarationPatchPath);
198
+ const drizzleOrmDeclarationPatchPath = 'patches/drizzle-orm-ts7-strict-declarations.patch';
199
+ const drizzleOrmDeclarationPatchSourcePath = node_path.join(createPackageRoot, 'template-workspace', drizzleOrmDeclarationPatchPath);
200
+ function updateGeneratedToolingDependencies(packageJson) {
201
+ let changed = false;
202
+ for (const section of [
203
+ 'dependencies',
204
+ 'devDependencies',
205
+ 'peerDependencies',
206
+ 'optionalDependencies'
207
+ ]){
208
+ const dependencies = packageJson[section];
209
+ if (!(!dependencies || 'object' != typeof dependencies || Array.isArray(dependencies))) {
210
+ for (const [packageName, version] of generatedToolingDependencyPins)if (Object.prototype.hasOwnProperty.call(dependencies, packageName) && dependencies[packageName] !== version) {
211
+ dependencies[packageName] = version;
212
+ changed = true;
213
+ }
214
+ }
215
+ }
216
+ return changed;
217
+ }
218
+ const cloudflareModernDeployCommand = 'ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy';
219
+ const cloudflareModernDeploySkipBuildCommand = `${cloudflareModernDeployCommand} --skip-build`;
220
+ const cloudflareWranglerDeployCommand = 'wrangler deploy --config .output/wrangler.json';
221
+ const cloudflareWranglerDeployInvalidSkipBuildCommand = `${cloudflareWranglerDeployCommand} --skip-build`;
222
+ function updateGeneratedPackageScripts(packageJson) {
223
+ const scripts = packageJson.scripts;
224
+ if (!scripts || 'object' != typeof scripts || Array.isArray(scripts)) return false;
225
+ let changed = false;
226
+ const cloudflareBuild = scripts['cloudflare:build'];
227
+ if ('string' == typeof cloudflareBuild) {
228
+ let nextCloudflareBuild = cloudflareBuild;
229
+ if (nextCloudflareBuild.includes(cloudflareModernDeployCommand) && !nextCloudflareBuild.includes(cloudflareModernDeploySkipBuildCommand)) nextCloudflareBuild = nextCloudflareBuild.replace(cloudflareModernDeployCommand, cloudflareModernDeploySkipBuildCommand);
230
+ nextCloudflareBuild = nextCloudflareBuild.replace(/ && node \S*scripts\/generate-public-surface-assets\.m[ct]s --app [^&]+ --target dist(?= && ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy --skip-build)/u, '');
231
+ if (nextCloudflareBuild !== cloudflareBuild) {
232
+ scripts['cloudflare:build'] = nextCloudflareBuild;
233
+ changed = true;
234
+ }
235
+ }
236
+ const cloudflareDeploy = scripts['cloudflare:deploy'];
237
+ if ('string' == typeof cloudflareDeploy && cloudflareDeploy.includes(cloudflareWranglerDeployInvalidSkipBuildCommand)) {
238
+ scripts['cloudflare:deploy'] = cloudflareDeploy.replace(cloudflareWranglerDeployInvalidSkipBuildCommand, cloudflareWranglerDeployCommand);
239
+ changed = true;
240
+ }
241
+ return changed;
242
+ }
154
243
  function normalizeStrictEffectApiMetadata(value) {
155
244
  const api = value.api;
156
245
  if (!api || 'object' != typeof api || Array.isArray(api)) return false;
@@ -216,6 +305,200 @@ function normalizeStrictEffectApiMetadata(value) {
216
305
  }
217
306
  return changed;
218
307
  }
308
+ function replaceYamlLine(source, pattern, replacement) {
309
+ const updated = source.replace(pattern, replacement);
310
+ return {
311
+ source: updated,
312
+ changed: updated !== source
313
+ };
314
+ }
315
+ function ensureYamlListItem(source, key, item) {
316
+ const itemLine = ` - '${item}'`;
317
+ const headerPattern = new RegExp(`^${key}:\\n(?:(?: - .+\\n)*)`, 'mu');
318
+ const header = source.match(headerPattern);
319
+ if (header) {
320
+ if (header[0].split('\n').includes(itemLine)) return {
321
+ source,
322
+ changed: false
323
+ };
324
+ return {
325
+ source: source.replace(headerPattern, `${header[0]}${itemLine}\n`),
326
+ changed: true
327
+ };
328
+ }
329
+ const block = `${key}:\n${itemLine}\n`;
330
+ const afterTrustPolicyIgnore = source.replace(/^(trustPolicyIgnoreAfter: .+\n)/mu, `$1${block}`);
331
+ if (afterTrustPolicyIgnore !== source) return {
332
+ source: afterTrustPolicyIgnore,
333
+ changed: true
334
+ };
335
+ return {
336
+ source: `${source.trimEnd()}\n${block}`,
337
+ changed: true
338
+ };
339
+ }
340
+ function ensureYamlMapEntry(source, key, entryKey, value) {
341
+ const entryLine = ` '${entryKey}': ${value}`;
342
+ const packageName = entryKey.includes('@') ? entryKey.slice(0, entryKey.lastIndexOf('@')) : entryKey;
343
+ const escapedPackageName = packageName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
344
+ const currentEntryPattern = new RegExp(`^ {2}'${escapedPackageName}@[^']+': .+$`, 'mu');
345
+ const currentEntry = source.match(currentEntryPattern);
346
+ if (currentEntry) {
347
+ if (currentEntry[0] === entryLine) return {
348
+ source,
349
+ changed: false
350
+ };
351
+ return {
352
+ source: source.replace(currentEntryPattern, entryLine),
353
+ changed: true
354
+ };
355
+ }
356
+ const headerPattern = new RegExp(`^${key}:\\n(?:(?: .+\\n)*)`, 'mu');
357
+ const header = source.match(headerPattern);
358
+ if (header) {
359
+ if (header[0].split('\n').includes(entryLine)) return {
360
+ source,
361
+ changed: false
362
+ };
363
+ return {
364
+ source: source.replace(headerPattern, `${header[0]}${entryLine}\n`),
365
+ changed: true
366
+ };
367
+ }
368
+ return {
369
+ source: `${source.trimEnd()}\n${key}:\n${entryLine}\n`,
370
+ changed: true
371
+ };
372
+ }
373
+ function removeYamlMapEntry(source, entryKey) {
374
+ const packageName = entryKey.includes('@') ? entryKey.slice(0, entryKey.lastIndexOf('@')) : entryKey;
375
+ const escapedPackageName = packageName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
376
+ const currentEntryPattern = new RegExp(`^ {2}'${escapedPackageName}@[^']+': .+\\n?`, 'mu');
377
+ if (!currentEntryPattern.test(source)) return {
378
+ source,
379
+ changed: false
380
+ };
381
+ return {
382
+ source: source.replace(currentEntryPattern, ''),
383
+ changed: true
384
+ };
385
+ }
386
+ function ensureGeneratedPatchFile(workspaceRoot, relativePatchPath, sourcePatchPath) {
387
+ const targetPath = node_path.join(workspaceRoot, relativePatchPath);
388
+ const patch = node_fs.readFileSync(sourcePatchPath, 'utf-8');
389
+ if (node_fs.existsSync(targetPath) && node_fs.readFileSync(targetPath, 'utf-8') === patch) return false;
390
+ node_fs.mkdirSync(node_path.dirname(targetPath), {
391
+ recursive: true
392
+ });
393
+ node_fs.writeFileSync(targetPath, patch, 'utf-8');
394
+ return true;
395
+ }
396
+ function removeGeneratedPatchFileIfUnchanged(workspaceRoot, relativePatchPath, sourcePatchPath) {
397
+ const targetPath = node_path.join(workspaceRoot, relativePatchPath);
398
+ if (!node_fs.existsSync(targetPath)) return false;
399
+ const patch = node_fs.readFileSync(sourcePatchPath, 'utf-8');
400
+ if (node_fs.readFileSync(targetPath, 'utf-8') !== patch) return false;
401
+ node_fs.rmSync(targetPath);
402
+ return true;
403
+ }
404
+ function workspaceUsesDependency(workspaceRoot, packageName) {
405
+ const packageJsonPaths = [
406
+ node_path.join(workspaceRoot, 'package.json')
407
+ ];
408
+ for (const workspaceDir of [
409
+ 'apps',
410
+ 'verticals',
411
+ 'packages'
412
+ ]){
413
+ const absoluteWorkspaceDir = node_path.join(workspaceRoot, workspaceDir);
414
+ if (node_fs.existsSync(absoluteWorkspaceDir)) for (const entry of node_fs.readdirSync(absoluteWorkspaceDir, {
415
+ withFileTypes: true
416
+ })){
417
+ if (!entry.isDirectory()) continue;
418
+ const packageJsonPath = node_path.join(absoluteWorkspaceDir, entry.name, 'package.json');
419
+ if (node_fs.existsSync(packageJsonPath)) packageJsonPaths.push(packageJsonPath);
420
+ }
421
+ }
422
+ for (const packageJsonPath of packageJsonPaths){
423
+ const packageJson = JSON.parse(node_fs.readFileSync(packageJsonPath, 'utf-8'));
424
+ for (const field of [
425
+ 'dependencies',
426
+ 'devDependencies',
427
+ 'peerDependencies',
428
+ 'optionalDependencies'
429
+ ]){
430
+ const dependencies = packageJson[field];
431
+ if (dependencies && 'object' == typeof dependencies) {
432
+ if (Object.prototype.hasOwnProperty.call(dependencies, packageName)) return true;
433
+ for (const specifier of Object.values(dependencies))if ('string' == typeof specifier && specifier.startsWith(`npm:${packageName}@`)) return true;
434
+ }
435
+ }
436
+ }
437
+ return false;
438
+ }
439
+ function ensureGeneratedDeclarationPatches(workspaceRoot, options) {
440
+ let changed = false;
441
+ changed = ensureGeneratedPatchFile(workspaceRoot, moduleFederationModernJsPatchPath, moduleFederationModernJsPatchSourcePath) || changed;
442
+ changed = ensureGeneratedPatchFile(workspaceRoot, moduleFederationBridgeReactPatchPath, moduleFederationBridgeReactPatchSourcePath) || changed;
443
+ changed = ensureGeneratedPatchFile(workspaceRoot, effectDeclarationPatchPath, effectDeclarationPatchSourcePath) || changed;
444
+ changed = options.includeDrizzleOrmPatch ? ensureGeneratedPatchFile(workspaceRoot, drizzleOrmDeclarationPatchPath, drizzleOrmDeclarationPatchSourcePath) || changed : removeGeneratedPatchFileIfUnchanged(workspaceRoot, drizzleOrmDeclarationPatchPath, drizzleOrmDeclarationPatchSourcePath) || changed;
445
+ return changed;
446
+ }
447
+ function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
448
+ const workspaceFile = node_path.join(workspaceRoot, 'pnpm-workspace.yaml');
449
+ if (!node_fs.existsSync(workspaceFile)) return false;
450
+ let source = node_fs.readFileSync(workspaceFile, 'utf-8');
451
+ let changed = false;
452
+ const usesDrizzleOrm = workspaceUsesDependency(workspaceRoot, 'drizzle-orm');
453
+ const replacements = [
454
+ [
455
+ /^ {4}'@effect\/vitest>effect': .+$/mu,
456
+ ` '@effect/vitest>effect': '${EFFECT_VERSION}'`
457
+ ],
458
+ [
459
+ /^ {2}'@effect\/vitest': .+$/mu,
460
+ ` '@effect/vitest': ${EFFECT_VITEST_VERSION}`
461
+ ],
462
+ [
463
+ /^ {2}effect: .+$/mu,
464
+ ` effect: ${EFFECT_VERSION}`
465
+ ]
466
+ ];
467
+ for (const [pattern, replacement] of replacements){
468
+ const result = replaceYamlLine(source, pattern, replacement);
469
+ source = result.source;
470
+ changed = result.changed || changed;
471
+ }
472
+ for (const item of strictEffectPackageVersionPolicyExclusions){
473
+ const packageName = item.slice(0, item.lastIndexOf('@'));
474
+ const escapedPackageName = packageName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
475
+ const currentVersion = replaceYamlLine(source, new RegExp(`^ {2}- '${escapedPackageName}@[^']+'$`, 'gmu'), ` - '${item}'`);
476
+ source = currentVersion.source;
477
+ changed = currentVersion.changed || changed;
478
+ for (const policyKey of [
479
+ 'minimumReleaseAgeExclude',
480
+ 'trustPolicyExclude'
481
+ ]){
482
+ const policyExclude = ensureYamlListItem(source, policyKey, item);
483
+ source = policyExclude.source;
484
+ changed = policyExclude.changed || changed;
485
+ }
486
+ }
487
+ const effectPatch = ensureYamlMapEntry(source, 'patchedDependencies', `effect@${EFFECT_VERSION}`, effectDeclarationPatchPath);
488
+ source = effectPatch.source;
489
+ changed = effectPatch.changed || changed;
490
+ const moduleFederationModernJsPatch = ensureYamlMapEntry(source, 'patchedDependencies', `@module-federation/modern-js-v3@${MODULE_FEDERATION_VERSION}`, moduleFederationModernJsPatchPath);
491
+ source = moduleFederationModernJsPatch.source;
492
+ changed = moduleFederationModernJsPatch.changed || changed;
493
+ const moduleFederationBridgeReactPatch = ensureYamlMapEntry(source, 'patchedDependencies', `@module-federation/bridge-react@${MODULE_FEDERATION_VERSION}`, moduleFederationBridgeReactPatchPath);
494
+ source = moduleFederationBridgeReactPatch.source;
495
+ changed = moduleFederationBridgeReactPatch.changed || changed;
496
+ const drizzleOrmPatch = usesDrizzleOrm ? ensureYamlMapEntry(source, 'patchedDependencies', `drizzle-orm@${DRIZZLE_ORM_VERSION}`, drizzleOrmDeclarationPatchPath) : removeYamlMapEntry(source, `drizzle-orm@${DRIZZLE_ORM_VERSION}`);
497
+ source = drizzleOrmPatch.source;
498
+ changed = drizzleOrmPatch.changed || changed;
499
+ if (changed) node_fs.writeFileSync(workspaceFile, source, 'utf-8');
500
+ return changed;
501
+ }
219
502
  function updateUltramodernConfig(workspaceRoot, packageSource) {
220
503
  const configPath = node_path.join(workspaceRoot, '.modernjs/ultramodern.json');
221
504
  const config = readJsonFile(configPath);
@@ -235,6 +518,64 @@ function updateUltramodernConfig(workspaceRoot, packageSource) {
235
518
  for (const app of config.topology?.apps ?? [])if (app && 'object' == typeof app && !Array.isArray(app)) normalizeStrictEffectApiMetadata(app);
236
519
  writeJsonFile(configPath, config);
237
520
  }
521
+ function writeJsonIfChanged(filePath, value) {
522
+ const next = `${JSON.stringify(value, null, 2)}\n`;
523
+ if (node_fs.existsSync(filePath) && node_fs.readFileSync(filePath, 'utf-8') === next) return false;
524
+ node_fs.mkdirSync(node_path.dirname(filePath), {
525
+ recursive: true
526
+ });
527
+ node_fs.writeFileSync(filePath, next, 'utf-8');
528
+ return true;
529
+ }
530
+ function writeTextIfChanged(filePath, value) {
531
+ if (node_fs.existsSync(filePath) && node_fs.readFileSync(filePath, 'utf-8') === value) return false;
532
+ node_fs.mkdirSync(node_path.dirname(filePath), {
533
+ recursive: true
534
+ });
535
+ node_fs.writeFileSync(filePath, value, 'utf-8');
536
+ return true;
537
+ }
538
+ function ensureGeneratedIgnoreRules(workspaceRoot) {
539
+ const gitignorePath = node_path.join(workspaceRoot, '.gitignore');
540
+ const existing = node_fs.existsSync(gitignorePath) ? node_fs.readFileSync(gitignorePath, 'utf-8') : '';
541
+ const lines = 0 === existing.trimEnd().length ? [] : existing.trimEnd().split(/\r?\n/u);
542
+ let changed = false;
543
+ for (const rule of [
544
+ '.mf/',
545
+ '**/.mf/',
546
+ 'dist-cloudflare/'
547
+ ])if (!lines.includes(rule)) {
548
+ lines.push(rule);
549
+ changed = true;
550
+ }
551
+ if (!changed) return false;
552
+ const next = `${lines.join('\n')}\n`;
553
+ node_fs.writeFileSync(gitignorePath, next, 'utf-8');
554
+ return true;
555
+ }
556
+ function updateGeneratedTypeScriptSurfaces(workspaceRoot, config) {
557
+ let changed = false;
558
+ const apps = workspaceAppsFromToolingConfig(config);
559
+ const remotes = apps.filter((app)=>'shell' !== app.kind);
560
+ changed = writeJsonIfChanged(node_path.join(workspaceRoot, 'tsconfig.base.json'), createTsConfigBase()) || changed;
561
+ changed = ensureGeneratedIgnoreRules(workspaceRoot) || changed;
562
+ for (const sharedPackage of [
563
+ 'packages/shared-contracts',
564
+ 'packages/shared-design-tokens'
565
+ ])changed = writeJsonIfChanged(node_path.join(workspaceRoot, sharedPackage, 'tsconfig.json'), createSharedPackageTsConfig(sharedPackage)) || changed;
566
+ for (const app of apps){
567
+ changed = writeJsonIfChanged(node_path.join(workspaceRoot, app.directory, 'tsconfig.json'), createAppTsConfig(app, remotes)) || changed;
568
+ changed = writeJsonIfChanged(node_path.join(workspaceRoot, app.directory, 'tsconfig.mf-types.json'), createAppMfTypesTsConfig(app)) || changed;
569
+ changed = writeTextIfChanged(node_path.join(workspaceRoot, app.directory, 'src/modern-app-env.d.ts'), createAppEnvDts(app, remotes)) || changed;
570
+ }
571
+ return changed;
572
+ }
573
+ function updateGeneratedModernConfigs(workspaceRoot, config) {
574
+ let changed = false;
575
+ const apps = workspaceAppsFromToolingConfig(config);
576
+ for (const app of apps)changed = writeTextIfChanged(node_path.join(workspaceRoot, app.directory, 'modern.config.ts'), createAppModernConfig(config.workspace.packageScope, app)) || changed;
577
+ return changed;
578
+ }
238
579
  function updateReferenceTopology(workspaceRoot) {
239
580
  const topologyPath = node_path.join(workspaceRoot, 'topology/reference-topology.json');
240
581
  if (!node_fs.existsSync(topologyPath)) return false;
@@ -297,8 +638,10 @@ function runMigrateStrictEffect(args, context) {
297
638
  modern-js-create ultramodern migrate-strict-effect --version <version> [--skip-install]
298
639
 
299
640
  Updates generated UltraModern package-source metadata, Modern package aliases,
300
- direct Effect API topology metadata, and the pnpm lockfile for strict Effect
301
- workspaces. Source code still has to pass pnpm api:check and pnpm contract:check.
641
+ framework-owned toolchain pins, direct Effect API topology metadata, strict
642
+ Effect pnpm overrides/trust policy, framework-owned TypeScript config
643
+ surfaces, and the pnpm lockfile. Source code still has to pass pnpm api:check
644
+ and pnpm contract:check.
302
645
  `);
303
646
  return 0;
304
647
  }
@@ -306,6 +649,9 @@ workspaces. Source code still has to pass pnpm api:check and pnpm contract:check
306
649
  const packageSource = createMigrationPackageSource(args, current);
307
650
  updateUltramodernConfig(context.workspaceRoot, packageSource);
308
651
  updateReferenceTopology(context.workspaceRoot);
652
+ const migrated = readUltramodernConfig(context.workspaceRoot);
653
+ updateGeneratedTypeScriptSurfaces(context.workspaceRoot, migrated);
654
+ updateGeneratedModernConfigs(context.workspaceRoot, migrated);
309
655
  for (const relativePackageFile of listWorkspacePackageFiles(context.workspaceRoot)){
310
656
  const packageFile = node_path.join(context.workspaceRoot, relativePackageFile);
311
657
  const packageJson = readJsonFile(packageFile);
@@ -316,9 +662,17 @@ workspaces. Source code still has to pass pnpm api:check and pnpm contract:check
316
662
  config: './.modernjs/ultramodern.json'
317
663
  };
318
664
  }
319
- if (updateModernDependencies(packageJson, packageSource)) writeJsonFile(packageFile, packageJson);
665
+ const modernDependenciesChanged = updateModernDependencies(packageJson, packageSource);
666
+ const toolingDependenciesChanged = updateGeneratedToolingDependencies(packageJson);
667
+ const generatedScriptsChanged = updateGeneratedPackageScripts(packageJson);
668
+ const changed = modernDependenciesChanged || toolingDependenciesChanged || generatedScriptsChanged;
669
+ if (changed) writeJsonFile(packageFile, packageJson);
320
670
  else if ('package.json' === relativePackageFile) writeJsonFile(packageFile, packageJson);
321
671
  }
672
+ updateGeneratedPnpmWorkspacePolicy(context.workspaceRoot);
673
+ ensureGeneratedDeclarationPatches(context.workspaceRoot, {
674
+ includeDrizzleOrmPatch: workspaceUsesDependency(context.workspaceRoot, 'drizzle-orm')
675
+ });
322
676
  if (!hasFlag(args, '--skip-install')) {
323
677
  const status = runPnpmLockfileRefresh(context);
324
678
  if (0 !== status) return status;
@@ -27,17 +27,14 @@ function createAppEnvDts(app, remotes = []) {
27
27
  }
28
28
  `;
29
29
  })).join('\n');
30
- const reactTypeReference = remoteModuleDeclarations ? "/// <reference types='react' />\n" : '';
31
- const siteUrlDeclaration = 'declare const ULTRAMODERN_SITE_URL: string;';
32
- return `${reactTypeReference}/// <reference types='@modern-js/app-tools/types' />
33
-
34
- ${siteUrlDeclaration}
35
- declare module '*.svg' {
36
- const url: string;
37
- export default url;
38
- }
39
- declare module '*.css';
40
- ${remoteModuleDeclarations ? `\n${remoteModuleDeclarations}` : ''}`;
30
+ const reactTypeImport = remoteModuleDeclarations ? "import type React from 'react';\n" : '';
31
+ return [
32
+ `import '@modern-js/app-tools/types';\n${reactTypeImport}`.trimEnd(),
33
+ `declare global {
34
+ const ULTRAMODERN_SITE_URL: string;
35
+ }`,
36
+ remoteModuleDeclarations.trimEnd()
37
+ ].filter((section)=>section.length > 0).join('\n\n').concat('\n');
41
38
  }
42
39
  function createAppRuntimeConfig(app, scope, remotes = []) {
43
40
  const pluginsConfig = 'shell' === app.kind ? ` plugins: [
@@ -25,6 +25,11 @@ function createAppModernConfig(scope, app) {
25
25
  (cloudflareDeployEnabled ? '/' : \`http://localhost:\${port}\`);
26
26
  const defaultRemoteAssetPrefix = \`\${remoteAssetOrigin.replace(/\\/+$/u, '')}/\`;
27
27
  const defaultAssetPrefix = defaultRemoteAssetPrefix;`;
28
+ const devAssetPrefixSource = 'shell' === app.kind ? ` // Keep shell dev assets origin-relative so the shell works through
29
+ // tunnels and local previews without rewriting its own chunks.
30
+ assetPrefix: '/',` : ` // Remote dev manifests must publish an absolute publicPath so host
31
+ // shells load remoteEntry.js and exposed chunks from this dev server.
32
+ assetPrefix,`;
28
33
  return `// @effect-diagnostics processEnv:off
29
34
  import {
30
35
  appTools,
@@ -93,8 +98,10 @@ ${defaultAssetPrefixSource}
93
98
  // load remoteEntry.js and exposed chunks from the remote origin, not the host.
94
99
  const assetPrefix =
95
100
  configuredModernAssetPrefix || configuredUltramodernAssetPrefix || defaultAssetPrefix;
96
- const buildCacheTarget = cloudflareDeployEnabled ? 'cloudflare' : 'web';
97
- const buildCacheDirectory = \`node_modules/.cache/rspack-\${appId}-\${buildCacheTarget}\`;
101
+ const buildTarget = cloudflareDeployEnabled ? 'cloudflare' : 'web';
102
+ const buildOutputRoot = cloudflareDeployEnabled ? 'dist-cloudflare' : 'dist';
103
+ const buildTempDirectory = \`node_modules/.modern-js-\${appId}-\${buildTarget}\`;
104
+ const buildCacheDirectory = \`node_modules/.cache/rspack-\${appId}-\${buildTarget}\`;
98
105
 
99
106
  if (
100
107
  cloudflareDeployEnabled &&
@@ -124,9 +131,7 @@ ${bffConfig} ...(cloudflareDeployEnabled
124
131
  }
125
132
  : {}),
126
133
  dev: {
127
- // Keep dev assets origin-relative too; the default absolute
128
- // http://localhost:<port> prefix breaks pages served through tunnels.
129
- assetPrefix: '/',
134
+ ${devAssetPrefixSource}
130
135
  },
131
136
  html: {
132
137
  outputStructure: 'flat',
@@ -136,13 +141,15 @@ ${bffConfig} ...(cloudflareDeployEnabled
136
141
  disableTsChecker: false,
137
142
  distPath: {
138
143
  html: './',
144
+ root: buildOutputRoot,
139
145
  },
140
146
  polyfill: 'off',
141
147
  splitRouteChunks: true,
148
+ tempDir: buildTempDirectory,
142
149
  },
143
150
  performance: {
144
151
  buildCache: {
145
- cacheDigest: [appId, buildCacheTarget],
152
+ cacheDigest: [appId, buildTarget],
146
153
  cacheDirectory: buildCacheDirectory,
147
154
  },
148
155
  rsdoctor: {
@@ -1,3 +1,4 @@
1
+ import node_path from "node:path";
1
2
  import { WORKSPACE_PACKAGE_VERSION, modernPackageSpecifier } from "../ultramodern-package-source.js";
2
3
  import { appHasApi, remoteDependencyAlias, resolveRemoteRefs, sharedPackages, shellApp, verticalApiApps, zephyrRemoteDependency } from "./descriptors.js";
3
4
  import { readFileTemplate } from "./fs-io.js";
@@ -248,7 +249,6 @@ function createTsConfigBase() {
248
249
  noFallthroughCasesInSwitch: true,
249
250
  noPropertyAccessFromIndexSignature: true,
250
251
  noImplicitReturns: true,
251
- skipLibCheck: true,
252
252
  resolveJsonModule: true,
253
253
  plugins: [
254
254
  {
@@ -280,7 +280,7 @@ function createReferences(packageDir, references) {
280
280
  return [
281
281
  ...new Set(references)
282
282
  ].filter((reference)=>reference !== packageDir).map((reference)=>({
283
- path: `${relativeRootFor(packageDir)}/${reference}`
283
+ path: node_path.relative(packageDir, reference).split(node_path.sep).join('/')
284
284
  }));
285
285
  }
286
286
  function createPackageTsConfig(packageDir, options = {}) {
@@ -290,8 +290,6 @@ function createPackageTsConfig(packageDir, options = {}) {
290
290
  const include = resolvedOptions.include ?? [
291
291
  'src',
292
292
  'locales/**/*.json',
293
- 'modern.config.ts',
294
- 'module-federation.config.ts',
295
293
  'package.json',
296
294
  'shared'
297
295
  ];
@@ -325,9 +323,9 @@ function createAppTsConfig(app, remotes = []) {
325
323
  });
326
324
  }
327
325
  function createAppMfTypesTsConfig(app) {
328
- const exposedFiles = Object.values(app.exposes ?? {}).map((exposePath)=>exposePath.replace(/^\.\//u, ''));
326
+ const exposedFiles = Object.entries(app.exposes ?? {}).sort(([left], [right])=>'./Route' === left ? -1 : './Route' === right ? 1 : 0).map(([, exposePath])=>exposePath.replace(/^\.\//u, ''));
329
327
  return {
330
- extends: './tsconfig.json',
328
+ extends: `${relativeRootFor(app.directory)}/tsconfig.base.json`,
331
329
  include: [
332
330
  ...new Set([
333
331
  ...exposedFiles,
@@ -358,7 +356,6 @@ function createRootTsConfig(apps = []) {
358
356
  }
359
357
  function createAppPackage(scope, app, packageSource, enableTailwind, remotes = [], bridge) {
360
358
  const publicSurfaceBuildCommand = createPublicSurfaceGenerationCommand(app, 'dist');
361
- const publicSurfaceCloudflareBuildCommand = createPublicSurfaceGenerationCommand(app, 'dist');
362
359
  const publicSurfaceCloudflareOutputCommand = createPublicSurfaceGenerationCommand(app, 'cloudflare');
363
360
  const packageExports = Object.fromEntries(Object.entries(app.exposes ?? {}).map(([expose, source])=>[
364
361
  expose,
@@ -371,7 +368,7 @@ function createAppPackage(scope, app, packageSource, enableTailwind, remotes = [
371
368
  scripts: {
372
369
  dev: 'modern dev',
373
370
  build: app.exposes ? `ULTRAMODERN_ZEPHYR=false modern build && ${publicSurfaceBuildCommand} && node ${relativeRootFor(app.directory)}/scripts/assert-mf-types.mts` : `ULTRAMODERN_ZEPHYR=false modern build && ${publicSurfaceBuildCommand}`,
374
- 'cloudflare:build': `ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern build && ${publicSurfaceCloudflareBuildCommand} && ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy && ${publicSurfaceCloudflareOutputCommand}`,
371
+ 'cloudflare:build': `ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern build && ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy --skip-build && ${publicSurfaceCloudflareOutputCommand}`,
375
372
  'cloudflare:deploy': 'ULTRAMODERN_CLOUDFLARE_REQUIRE_PUBLIC_URLS=true pnpm run cloudflare:build && wrangler deploy --config .output/wrangler.json',
376
373
  'cloudflare:preview': 'pnpm run cloudflare:build && wrangler dev --config .output/wrangler.json',
377
374
  'cloudflare:proof': `node ${relativeRootFor(app.directory)}/scripts/proof-cloudflare-version.mts --app ${app.id}`,
@@ -11,6 +11,7 @@ const POSTCSS_VERSION = '8.5.15';
11
11
  const EFFECT_VERSION = '4.0.0-beta.91';
12
12
  const EFFECT_VITEST_VERSION = '4.0.0-beta.91';
13
13
  const EFFECT_TSGO_VERSION = '0.14.6';
14
+ const DRIZZLE_ORM_VERSION = '1.0.0-rc.4';
14
15
  const TYPESCRIPT_STABLE_VERSION = '6.0.3';
15
16
  const TYPESCRIPT_NATIVE_PREVIEW_VERSION = '7.0.0-dev.20260628.1';
16
17
  const TYPESCRIPT_VERSION = TYPESCRIPT_STABLE_VERSION;
@@ -35,7 +36,8 @@ const ultramodernWorkspaceVersions = {
35
36
  moduleFederation: MODULE_FEDERATION_VERSION,
36
37
  effect: EFFECT_VERSION,
37
38
  effectVitest: EFFECT_VITEST_VERSION,
39
+ drizzleOrm: DRIZZLE_ORM_VERSION,
38
40
  tailwind: TAILWIND_VERSION,
39
41
  tailwindPostcss: TAILWIND_POSTCSS_VERSION
40
42
  };
41
- export { CLOUDFLARE_COMPATIBILITY_DATE, EFFECT_TSGO_VERSION, EFFECT_VERSION, EFFECT_VITEST_VERSION, I18NEXT_VERSION, LEFTHOOK_VERSION, MODULE_FEDERATION_AGENT_SKILLS_COMMIT, MODULE_FEDERATION_VERSION, NODE_FETCH_VERSION, NODE_VERSION, OXFMT_VERSION, OXLINT_VERSION, PNPM_VERSION, POSTCSS_VERSION, REACT_DOM_VERSION, REACT_ROUTER_VERSION, REACT_VERSION, RSTACK_AGENT_SKILLS_COMMIT, TAILWIND_POSTCSS_VERSION, TAILWIND_VERSION, TANSTACK_ROUTER_CORE_VERSION, TANSTACK_ROUTER_VERSION, TYPESCRIPT_NATIVE_PREVIEW_VERSION, TYPESCRIPT_STABLE_VERSION, TYPESCRIPT_VERSION, TYPES_REACT_DOM_VERSION, TYPES_REACT_VERSION, ULTRACITE_VERSION, WRANGLER_VERSION, ZEPHYR_AGENT_VERSION, ZEPHYR_RSPACK_PLUGIN_VERSION, ultramodernWorkspaceVersions };
43
+ export { CLOUDFLARE_COMPATIBILITY_DATE, DRIZZLE_ORM_VERSION, EFFECT_TSGO_VERSION, EFFECT_VERSION, EFFECT_VITEST_VERSION, I18NEXT_VERSION, LEFTHOOK_VERSION, MODULE_FEDERATION_AGENT_SKILLS_COMMIT, MODULE_FEDERATION_VERSION, NODE_FETCH_VERSION, NODE_VERSION, OXFMT_VERSION, OXLINT_VERSION, PNPM_VERSION, POSTCSS_VERSION, REACT_DOM_VERSION, REACT_ROUTER_VERSION, REACT_VERSION, RSTACK_AGENT_SKILLS_COMMIT, TAILWIND_POSTCSS_VERSION, TAILWIND_VERSION, TANSTACK_ROUTER_CORE_VERSION, TANSTACK_ROUTER_VERSION, TYPESCRIPT_NATIVE_PREVIEW_VERSION, TYPESCRIPT_STABLE_VERSION, TYPESCRIPT_VERSION, TYPES_REACT_DOM_VERSION, TYPES_REACT_VERSION, ULTRACITE_VERSION, WRANGLER_VERSION, ZEPHYR_AGENT_VERSION, ZEPHYR_RSPACK_PLUGIN_VERSION, ultramodernWorkspaceVersions };
@@ -8,7 +8,7 @@ import { packageName, tailwindPrefixForApp } from "./naming.js";
8
8
  import { createCloudflareSecurityContract } from "./policy.js";
9
9
  import { publicSurfaceManagedSourceAssetPaths } from "./public-surface.js";
10
10
  import { createLocalisedUrlsMap, createRouteMetaFilePath, createRouteOwnedI18nPaths, createRoutePageFilePath } from "./routes.js";
11
- import { CLOUDFLARE_COMPATIBILITY_DATE, NODE_VERSION, PNPM_VERSION } from "./versions.js";
11
+ import { CLOUDFLARE_COMPATIBILITY_DATE, EFFECT_VERSION, MODULE_FEDERATION_VERSION, NODE_VERSION, PNPM_VERSION } from "./versions.js";
12
12
  function createToolWrapperScript(command, extraArgs = []) {
13
13
  const commandJson = JSON.stringify(command);
14
14
  const extraArgsJson = JSON.stringify(extraArgs);
@@ -127,6 +127,8 @@ function createWorkspaceValidationScript(scope, enableTailwind, remotes = []) {
127
127
  const expectedCloudflareSecurity = createCloudflareSecurityContract();
128
128
  return renderFileTemplate("workspace-scripts/validate-ultramodern-workspace.mjs", {
129
129
  packageScope: scope,
130
+ effectVersion: EFFECT_VERSION,
131
+ moduleFederationVersion: MODULE_FEDERATION_VERSION,
130
132
  nodeVersion: NODE_VERSION,
131
133
  pnpmVersion: PNPM_VERSION,
132
134
  tailwindEnabledJson: JSON.stringify(enableTailwind),