@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
package/README.md CHANGED
@@ -193,8 +193,8 @@ For strict Effect API migrations, update generated package metadata and Modern
193
193
  package aliases through the framework command before hand-editing app code:
194
194
 
195
195
  ```bash
196
- pnpm dlx @bleedingdev/modern-js-create@3.5.0-ultramodern.2 ultramodern \
197
- migrate-strict-effect --version 3.5.0-ultramodern.2
196
+ pnpm dlx @bleedingdev/modern-js-create@3.5.0-ultramodern.10 ultramodern \
197
+ migrate-strict-effect --version 3.5.0-ultramodern.10
198
198
  pnpm api:check
199
199
  pnpm contract:check
200
200
  pnpm check
@@ -202,7 +202,8 @@ pnpm build
202
202
  ```
203
203
 
204
204
  The command updates `.modernjs/ultramodern.json`, root `modernjs.packageSource`,
205
- generated Modern package aliases, old direct topology metadata, and the pnpm
205
+ generated Modern package aliases, framework-owned toolchain pins, old direct
206
+ topology metadata, strict Effect pnpm overrides/trust policy, and the pnpm
206
207
  lockfile. It does not invent compatibility shims or move business code behind
207
208
  your back. If `pnpm api:check` still fails, migrate the source to
208
209
  `shared/api.ts`, `api/index.ts`, and `src/api/*-client.ts` and delete
@@ -210,8 +211,11 @@ your back. If `pnpm api:check` still fails, migrate the source to
210
211
 
211
212
  Generated strict Effect workspaces pin the compatible Effect cohort through
212
213
  `pnpm-workspace.yaml` overrides: `effect@4.0.0-beta.91` and
213
- `@effect/vitest@4.0.0-beta.91`. Do not override those in app packages; update
214
- the framework cohort when the runtime moves.
214
+ `@effect/vitest@4.0.0-beta.91`. The generated pnpm policy also excludes the
215
+ known `effect@4.0.0-beta.91` and `@effect/opentelemetry@4.0.0-beta.91`
216
+ versions from the 24-hour minimum-release-age gate and their trusted-publisher
217
+ to provenance transitions from no-downgrade checks. Do not override those in
218
+ app packages; update the framework cohort when the runtime moves.
215
219
 
216
220
  Use `--ultramodern-package-source=install` for published cohort proof and pin a
217
221
  specific release with `--ultramodern-package-version` when CI must prove an
@@ -376,19 +380,21 @@ updating workspaces.
376
380
  | `ULTRAMODERN_ASSET_PREFIX` | UltraModern asset prefix fallback | Modern/Rspack-emitted asset URLs when `MODERN_ASSET_PREFIX` is unset |
377
381
  | `ULTRAMODERN_PUBLIC_URL_<APP_ID>` | Per-app deployment/proof URL | Cloudflare proof inputs and Module Federation remote URLs |
378
382
 
379
- Asset URLs use this precedence: `MODERN_ASSET_PREFIX` →
380
- `ULTRAMODERN_ASSET_PREFIX` → origin-relative `/`. `MODERN_PUBLIC_SITE_URL` is
381
- canonical/SEO-only and must not be used as an asset-prefix fallback.
383
+ Shell asset URLs use this precedence: `MODERN_ASSET_PREFIX` →
384
+ `ULTRAMODERN_ASSET_PREFIX` → origin-relative `/`. Module Federation remotes use
385
+ the same env precedence, then fall back to their per-app public origin:
386
+ configured public URL, inferred workers.dev URL, or local dev port.
387
+ `MODERN_PUBLIC_SITE_URL` is canonical/SEO-only and must not be used as an
388
+ asset-prefix fallback.
382
389
  SEO output uses `MODERN_PUBLIC_SITE_URL`; if it is unset, generated local and
383
390
  preview outputs remain non-public until deployment proof provides explicit
384
391
  public URLs.
385
392
 
386
- Without public URLs configured, asset paths are origin-relative (`/`), and the
387
- dev server uses `dev.assetPrefix: '/'` so apps work through tunnels and
388
- reverse proxies (ngrok, cloudflared) without triggering Chrome's Local Network
389
- Access prompt or mixed-content errors. Shell-only workspaces can set
390
- `MODERN_PUBLIC_SITE_URL` for SEO output without changing where assets load
391
- from.
393
+ Without public URLs configured, shell asset paths are origin-relative (`/`).
394
+ Remote dev manifests publish their own local origin so host shells load
395
+ `remoteEntry.js` and exposed chunks from the remote dev server. Shell-only
396
+ workspaces can set `MODERN_PUBLIC_SITE_URL` for SEO output without changing
397
+ where assets load from.
392
398
 
393
399
  ## Cloudflare And Zephyr Proof
394
400
 
@@ -52,7 +52,11 @@ var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_no
52
52
  const external_node_url_namespaceObject = require("node:url");
53
53
  const external_create_package_root_cjs_namespaceObject = require("../create-package-root.cjs");
54
54
  const external_ultramodern_package_source_cjs_namespaceObject = require("../ultramodern-package-source.cjs");
55
+ const app_files_cjs_namespaceObject = require("../ultramodern-workspace/app-files.cjs");
55
56
  const mf_validation_cjs_namespaceObject = require("../ultramodern-workspace/mf-validation.cjs");
57
+ const module_federation_cjs_namespaceObject = require("../ultramodern-workspace/module-federation.cjs");
58
+ const package_json_cjs_namespaceObject = require("../ultramodern-workspace/package-json.cjs");
59
+ const versions_cjs_namespaceObject = require("../ultramodern-workspace/versions.cjs");
56
60
  const workspace_scripts_cjs_namespaceObject = require("../ultramodern-workspace/workspace-scripts.cjs");
57
61
  const external_config_cjs_namespaceObject = require("./config.cjs");
58
62
  const commands_dirname = external_node_path_default().dirname((0, external_node_url_namespaceObject.fileURLToPath)(__rslib_import_meta_url__));
@@ -198,6 +202,91 @@ function updateModernDependencies(packageJson, packageSource) {
198
202
  }
199
203
  return changed;
200
204
  }
205
+ const generatedToolingDependencyPins = new Map([
206
+ [
207
+ '@effect/tsgo',
208
+ versions_cjs_namespaceObject.EFFECT_TSGO_VERSION
209
+ ],
210
+ [
211
+ "@typescript/native-preview",
212
+ versions_cjs_namespaceObject.TYPESCRIPT_NATIVE_PREVIEW_VERSION
213
+ ],
214
+ [
215
+ 'oxfmt',
216
+ versions_cjs_namespaceObject.OXFMT_VERSION
217
+ ],
218
+ [
219
+ 'oxlint',
220
+ versions_cjs_namespaceObject.OXLINT_VERSION
221
+ ],
222
+ [
223
+ 'wrangler',
224
+ versions_cjs_namespaceObject.WRANGLER_VERSION
225
+ ],
226
+ [
227
+ 'zephyr-agent',
228
+ versions_cjs_namespaceObject.ZEPHYR_AGENT_VERSION
229
+ ],
230
+ [
231
+ 'zephyr-rspack-plugin',
232
+ versions_cjs_namespaceObject.ZEPHYR_RSPACK_PLUGIN_VERSION
233
+ ]
234
+ ]);
235
+ const strictEffectPackageVersionPolicyExclusions = [
236
+ `effect@${versions_cjs_namespaceObject.EFFECT_VERSION}`,
237
+ `@effect/opentelemetry@${versions_cjs_namespaceObject.EFFECT_VERSION}`
238
+ ];
239
+ const moduleFederationModernJsPatchPath = `patches/@module-federation__modern-js-v3@${versions_cjs_namespaceObject.MODULE_FEDERATION_VERSION}.patch`;
240
+ const moduleFederationModernJsPatchSourcePath = external_node_path_default().join(createPackageRoot, 'template-workspace', moduleFederationModernJsPatchPath);
241
+ const moduleFederationBridgeReactPatchPath = `patches/@module-federation__bridge-react@${versions_cjs_namespaceObject.MODULE_FEDERATION_VERSION}.patch`;
242
+ const moduleFederationBridgeReactPatchSourcePath = external_node_path_default().join(createPackageRoot, 'template-workspace', moduleFederationBridgeReactPatchPath);
243
+ const effectDeclarationPatchPath = 'patches/effect-schema-error-type-id.patch';
244
+ const effectDeclarationPatchSourcePath = external_node_path_default().join(createPackageRoot, 'template-workspace', effectDeclarationPatchPath);
245
+ const drizzleOrmDeclarationPatchPath = 'patches/drizzle-orm-ts7-strict-declarations.patch';
246
+ const drizzleOrmDeclarationPatchSourcePath = external_node_path_default().join(createPackageRoot, 'template-workspace', drizzleOrmDeclarationPatchPath);
247
+ function updateGeneratedToolingDependencies(packageJson) {
248
+ let changed = false;
249
+ for (const section of [
250
+ 'dependencies',
251
+ 'devDependencies',
252
+ 'peerDependencies',
253
+ 'optionalDependencies'
254
+ ]){
255
+ const dependencies = packageJson[section];
256
+ if (!(!dependencies || 'object' != typeof dependencies || Array.isArray(dependencies))) {
257
+ for (const [packageName, version] of generatedToolingDependencyPins)if (Object.prototype.hasOwnProperty.call(dependencies, packageName) && dependencies[packageName] !== version) {
258
+ dependencies[packageName] = version;
259
+ changed = true;
260
+ }
261
+ }
262
+ }
263
+ return changed;
264
+ }
265
+ const cloudflareModernDeployCommand = 'ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy';
266
+ const cloudflareModernDeploySkipBuildCommand = `${cloudflareModernDeployCommand} --skip-build`;
267
+ const cloudflareWranglerDeployCommand = 'wrangler deploy --config .output/wrangler.json';
268
+ const cloudflareWranglerDeployInvalidSkipBuildCommand = `${cloudflareWranglerDeployCommand} --skip-build`;
269
+ function updateGeneratedPackageScripts(packageJson) {
270
+ const scripts = packageJson.scripts;
271
+ if (!scripts || 'object' != typeof scripts || Array.isArray(scripts)) return false;
272
+ let changed = false;
273
+ const cloudflareBuild = scripts['cloudflare:build'];
274
+ if ('string' == typeof cloudflareBuild) {
275
+ let nextCloudflareBuild = cloudflareBuild;
276
+ if (nextCloudflareBuild.includes(cloudflareModernDeployCommand) && !nextCloudflareBuild.includes(cloudflareModernDeploySkipBuildCommand)) nextCloudflareBuild = nextCloudflareBuild.replace(cloudflareModernDeployCommand, cloudflareModernDeploySkipBuildCommand);
277
+ 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, '');
278
+ if (nextCloudflareBuild !== cloudflareBuild) {
279
+ scripts['cloudflare:build'] = nextCloudflareBuild;
280
+ changed = true;
281
+ }
282
+ }
283
+ const cloudflareDeploy = scripts['cloudflare:deploy'];
284
+ if ('string' == typeof cloudflareDeploy && cloudflareDeploy.includes(cloudflareWranglerDeployInvalidSkipBuildCommand)) {
285
+ scripts['cloudflare:deploy'] = cloudflareDeploy.replace(cloudflareWranglerDeployInvalidSkipBuildCommand, cloudflareWranglerDeployCommand);
286
+ changed = true;
287
+ }
288
+ return changed;
289
+ }
201
290
  function normalizeStrictEffectApiMetadata(value) {
202
291
  const api = value.api;
203
292
  if (!api || 'object' != typeof api || Array.isArray(api)) return false;
@@ -263,6 +352,200 @@ function normalizeStrictEffectApiMetadata(value) {
263
352
  }
264
353
  return changed;
265
354
  }
355
+ function replaceYamlLine(source, pattern, replacement) {
356
+ const updated = source.replace(pattern, replacement);
357
+ return {
358
+ source: updated,
359
+ changed: updated !== source
360
+ };
361
+ }
362
+ function ensureYamlListItem(source, key, item) {
363
+ const itemLine = ` - '${item}'`;
364
+ const headerPattern = new RegExp(`^${key}:\\n(?:(?: - .+\\n)*)`, 'mu');
365
+ const header = source.match(headerPattern);
366
+ if (header) {
367
+ if (header[0].split('\n').includes(itemLine)) return {
368
+ source,
369
+ changed: false
370
+ };
371
+ return {
372
+ source: source.replace(headerPattern, `${header[0]}${itemLine}\n`),
373
+ changed: true
374
+ };
375
+ }
376
+ const block = `${key}:\n${itemLine}\n`;
377
+ const afterTrustPolicyIgnore = source.replace(/^(trustPolicyIgnoreAfter: .+\n)/mu, `$1${block}`);
378
+ if (afterTrustPolicyIgnore !== source) return {
379
+ source: afterTrustPolicyIgnore,
380
+ changed: true
381
+ };
382
+ return {
383
+ source: `${source.trimEnd()}\n${block}`,
384
+ changed: true
385
+ };
386
+ }
387
+ function ensureYamlMapEntry(source, key, entryKey, value) {
388
+ const entryLine = ` '${entryKey}': ${value}`;
389
+ const packageName = entryKey.includes('@') ? entryKey.slice(0, entryKey.lastIndexOf('@')) : entryKey;
390
+ const escapedPackageName = packageName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
391
+ const currentEntryPattern = new RegExp(`^ {2}'${escapedPackageName}@[^']+': .+$`, 'mu');
392
+ const currentEntry = source.match(currentEntryPattern);
393
+ if (currentEntry) {
394
+ if (currentEntry[0] === entryLine) return {
395
+ source,
396
+ changed: false
397
+ };
398
+ return {
399
+ source: source.replace(currentEntryPattern, entryLine),
400
+ changed: true
401
+ };
402
+ }
403
+ const headerPattern = new RegExp(`^${key}:\\n(?:(?: .+\\n)*)`, 'mu');
404
+ const header = source.match(headerPattern);
405
+ if (header) {
406
+ if (header[0].split('\n').includes(entryLine)) return {
407
+ source,
408
+ changed: false
409
+ };
410
+ return {
411
+ source: source.replace(headerPattern, `${header[0]}${entryLine}\n`),
412
+ changed: true
413
+ };
414
+ }
415
+ return {
416
+ source: `${source.trimEnd()}\n${key}:\n${entryLine}\n`,
417
+ changed: true
418
+ };
419
+ }
420
+ function removeYamlMapEntry(source, entryKey) {
421
+ const packageName = entryKey.includes('@') ? entryKey.slice(0, entryKey.lastIndexOf('@')) : entryKey;
422
+ const escapedPackageName = packageName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
423
+ const currentEntryPattern = new RegExp(`^ {2}'${escapedPackageName}@[^']+': .+\\n?`, 'mu');
424
+ if (!currentEntryPattern.test(source)) return {
425
+ source,
426
+ changed: false
427
+ };
428
+ return {
429
+ source: source.replace(currentEntryPattern, ''),
430
+ changed: true
431
+ };
432
+ }
433
+ function ensureGeneratedPatchFile(workspaceRoot, relativePatchPath, sourcePatchPath) {
434
+ const targetPath = external_node_path_default().join(workspaceRoot, relativePatchPath);
435
+ const patch = external_node_fs_default().readFileSync(sourcePatchPath, 'utf-8');
436
+ if (external_node_fs_default().existsSync(targetPath) && external_node_fs_default().readFileSync(targetPath, 'utf-8') === patch) return false;
437
+ external_node_fs_default().mkdirSync(external_node_path_default().dirname(targetPath), {
438
+ recursive: true
439
+ });
440
+ external_node_fs_default().writeFileSync(targetPath, patch, 'utf-8');
441
+ return true;
442
+ }
443
+ function removeGeneratedPatchFileIfUnchanged(workspaceRoot, relativePatchPath, sourcePatchPath) {
444
+ const targetPath = external_node_path_default().join(workspaceRoot, relativePatchPath);
445
+ if (!external_node_fs_default().existsSync(targetPath)) return false;
446
+ const patch = external_node_fs_default().readFileSync(sourcePatchPath, 'utf-8');
447
+ if (external_node_fs_default().readFileSync(targetPath, 'utf-8') !== patch) return false;
448
+ external_node_fs_default().rmSync(targetPath);
449
+ return true;
450
+ }
451
+ function workspaceUsesDependency(workspaceRoot, packageName) {
452
+ const packageJsonPaths = [
453
+ external_node_path_default().join(workspaceRoot, 'package.json')
454
+ ];
455
+ for (const workspaceDir of [
456
+ 'apps',
457
+ 'verticals',
458
+ 'packages'
459
+ ]){
460
+ const absoluteWorkspaceDir = external_node_path_default().join(workspaceRoot, workspaceDir);
461
+ if (external_node_fs_default().existsSync(absoluteWorkspaceDir)) for (const entry of external_node_fs_default().readdirSync(absoluteWorkspaceDir, {
462
+ withFileTypes: true
463
+ })){
464
+ if (!entry.isDirectory()) continue;
465
+ const packageJsonPath = external_node_path_default().join(absoluteWorkspaceDir, entry.name, 'package.json');
466
+ if (external_node_fs_default().existsSync(packageJsonPath)) packageJsonPaths.push(packageJsonPath);
467
+ }
468
+ }
469
+ for (const packageJsonPath of packageJsonPaths){
470
+ const packageJson = JSON.parse(external_node_fs_default().readFileSync(packageJsonPath, 'utf-8'));
471
+ for (const field of [
472
+ 'dependencies',
473
+ 'devDependencies',
474
+ 'peerDependencies',
475
+ 'optionalDependencies'
476
+ ]){
477
+ const dependencies = packageJson[field];
478
+ if (dependencies && 'object' == typeof dependencies) {
479
+ if (Object.prototype.hasOwnProperty.call(dependencies, packageName)) return true;
480
+ for (const specifier of Object.values(dependencies))if ('string' == typeof specifier && specifier.startsWith(`npm:${packageName}@`)) return true;
481
+ }
482
+ }
483
+ }
484
+ return false;
485
+ }
486
+ function ensureGeneratedDeclarationPatches(workspaceRoot, options) {
487
+ let changed = false;
488
+ changed = ensureGeneratedPatchFile(workspaceRoot, moduleFederationModernJsPatchPath, moduleFederationModernJsPatchSourcePath) || changed;
489
+ changed = ensureGeneratedPatchFile(workspaceRoot, moduleFederationBridgeReactPatchPath, moduleFederationBridgeReactPatchSourcePath) || changed;
490
+ changed = ensureGeneratedPatchFile(workspaceRoot, effectDeclarationPatchPath, effectDeclarationPatchSourcePath) || changed;
491
+ changed = options.includeDrizzleOrmPatch ? ensureGeneratedPatchFile(workspaceRoot, drizzleOrmDeclarationPatchPath, drizzleOrmDeclarationPatchSourcePath) || changed : removeGeneratedPatchFileIfUnchanged(workspaceRoot, drizzleOrmDeclarationPatchPath, drizzleOrmDeclarationPatchSourcePath) || changed;
492
+ return changed;
493
+ }
494
+ function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
495
+ const workspaceFile = external_node_path_default().join(workspaceRoot, 'pnpm-workspace.yaml');
496
+ if (!external_node_fs_default().existsSync(workspaceFile)) return false;
497
+ let source = external_node_fs_default().readFileSync(workspaceFile, 'utf-8');
498
+ let changed = false;
499
+ const usesDrizzleOrm = workspaceUsesDependency(workspaceRoot, 'drizzle-orm');
500
+ const replacements = [
501
+ [
502
+ /^ {4}'@effect\/vitest>effect': .+$/mu,
503
+ ` '@effect/vitest>effect': '${versions_cjs_namespaceObject.EFFECT_VERSION}'`
504
+ ],
505
+ [
506
+ /^ {2}'@effect\/vitest': .+$/mu,
507
+ ` '@effect/vitest': ${versions_cjs_namespaceObject.EFFECT_VITEST_VERSION}`
508
+ ],
509
+ [
510
+ /^ {2}effect: .+$/mu,
511
+ ` effect: ${versions_cjs_namespaceObject.EFFECT_VERSION}`
512
+ ]
513
+ ];
514
+ for (const [pattern, replacement] of replacements){
515
+ const result = replaceYamlLine(source, pattern, replacement);
516
+ source = result.source;
517
+ changed = result.changed || changed;
518
+ }
519
+ for (const item of strictEffectPackageVersionPolicyExclusions){
520
+ const packageName = item.slice(0, item.lastIndexOf('@'));
521
+ const escapedPackageName = packageName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
522
+ const currentVersion = replaceYamlLine(source, new RegExp(`^ {2}- '${escapedPackageName}@[^']+'$`, 'gmu'), ` - '${item}'`);
523
+ source = currentVersion.source;
524
+ changed = currentVersion.changed || changed;
525
+ for (const policyKey of [
526
+ 'minimumReleaseAgeExclude',
527
+ 'trustPolicyExclude'
528
+ ]){
529
+ const policyExclude = ensureYamlListItem(source, policyKey, item);
530
+ source = policyExclude.source;
531
+ changed = policyExclude.changed || changed;
532
+ }
533
+ }
534
+ const effectPatch = ensureYamlMapEntry(source, 'patchedDependencies', `effect@${versions_cjs_namespaceObject.EFFECT_VERSION}`, effectDeclarationPatchPath);
535
+ source = effectPatch.source;
536
+ changed = effectPatch.changed || changed;
537
+ const moduleFederationModernJsPatch = ensureYamlMapEntry(source, 'patchedDependencies', `@module-federation/modern-js-v3@${versions_cjs_namespaceObject.MODULE_FEDERATION_VERSION}`, moduleFederationModernJsPatchPath);
538
+ source = moduleFederationModernJsPatch.source;
539
+ changed = moduleFederationModernJsPatch.changed || changed;
540
+ const moduleFederationBridgeReactPatch = ensureYamlMapEntry(source, 'patchedDependencies', `@module-federation/bridge-react@${versions_cjs_namespaceObject.MODULE_FEDERATION_VERSION}`, moduleFederationBridgeReactPatchPath);
541
+ source = moduleFederationBridgeReactPatch.source;
542
+ changed = moduleFederationBridgeReactPatch.changed || changed;
543
+ const drizzleOrmPatch = usesDrizzleOrm ? ensureYamlMapEntry(source, 'patchedDependencies', `drizzle-orm@${versions_cjs_namespaceObject.DRIZZLE_ORM_VERSION}`, drizzleOrmDeclarationPatchPath) : removeYamlMapEntry(source, `drizzle-orm@${versions_cjs_namespaceObject.DRIZZLE_ORM_VERSION}`);
544
+ source = drizzleOrmPatch.source;
545
+ changed = drizzleOrmPatch.changed || changed;
546
+ if (changed) external_node_fs_default().writeFileSync(workspaceFile, source, 'utf-8');
547
+ return changed;
548
+ }
266
549
  function updateUltramodernConfig(workspaceRoot, packageSource) {
267
550
  const configPath = external_node_path_default().join(workspaceRoot, '.modernjs/ultramodern.json');
268
551
  const config = readJsonFile(configPath);
@@ -282,6 +565,64 @@ function updateUltramodernConfig(workspaceRoot, packageSource) {
282
565
  for (const app of config.topology?.apps ?? [])if (app && 'object' == typeof app && !Array.isArray(app)) normalizeStrictEffectApiMetadata(app);
283
566
  writeJsonFile(configPath, config);
284
567
  }
568
+ function writeJsonIfChanged(filePath, value) {
569
+ const next = `${JSON.stringify(value, null, 2)}\n`;
570
+ if (external_node_fs_default().existsSync(filePath) && external_node_fs_default().readFileSync(filePath, 'utf-8') === next) return false;
571
+ external_node_fs_default().mkdirSync(external_node_path_default().dirname(filePath), {
572
+ recursive: true
573
+ });
574
+ external_node_fs_default().writeFileSync(filePath, next, 'utf-8');
575
+ return true;
576
+ }
577
+ function writeTextIfChanged(filePath, value) {
578
+ if (external_node_fs_default().existsSync(filePath) && external_node_fs_default().readFileSync(filePath, 'utf-8') === value) return false;
579
+ external_node_fs_default().mkdirSync(external_node_path_default().dirname(filePath), {
580
+ recursive: true
581
+ });
582
+ external_node_fs_default().writeFileSync(filePath, value, 'utf-8');
583
+ return true;
584
+ }
585
+ function ensureGeneratedIgnoreRules(workspaceRoot) {
586
+ const gitignorePath = external_node_path_default().join(workspaceRoot, '.gitignore');
587
+ const existing = external_node_fs_default().existsSync(gitignorePath) ? external_node_fs_default().readFileSync(gitignorePath, 'utf-8') : '';
588
+ const lines = 0 === existing.trimEnd().length ? [] : existing.trimEnd().split(/\r?\n/u);
589
+ let changed = false;
590
+ for (const rule of [
591
+ '.mf/',
592
+ '**/.mf/',
593
+ 'dist-cloudflare/'
594
+ ])if (!lines.includes(rule)) {
595
+ lines.push(rule);
596
+ changed = true;
597
+ }
598
+ if (!changed) return false;
599
+ const next = `${lines.join('\n')}\n`;
600
+ external_node_fs_default().writeFileSync(gitignorePath, next, 'utf-8');
601
+ return true;
602
+ }
603
+ function updateGeneratedTypeScriptSurfaces(workspaceRoot, config) {
604
+ let changed = false;
605
+ const apps = (0, external_config_cjs_namespaceObject.workspaceAppsFromToolingConfig)(config);
606
+ const remotes = apps.filter((app)=>'shell' !== app.kind);
607
+ changed = writeJsonIfChanged(external_node_path_default().join(workspaceRoot, 'tsconfig.base.json'), (0, package_json_cjs_namespaceObject.createTsConfigBase)()) || changed;
608
+ changed = ensureGeneratedIgnoreRules(workspaceRoot) || changed;
609
+ for (const sharedPackage of [
610
+ 'packages/shared-contracts',
611
+ 'packages/shared-design-tokens'
612
+ ])changed = writeJsonIfChanged(external_node_path_default().join(workspaceRoot, sharedPackage, 'tsconfig.json'), (0, package_json_cjs_namespaceObject.createSharedPackageTsConfig)(sharedPackage)) || changed;
613
+ for (const app of apps){
614
+ changed = writeJsonIfChanged(external_node_path_default().join(workspaceRoot, app.directory, 'tsconfig.json'), (0, package_json_cjs_namespaceObject.createAppTsConfig)(app, remotes)) || changed;
615
+ changed = writeJsonIfChanged(external_node_path_default().join(workspaceRoot, app.directory, 'tsconfig.mf-types.json'), (0, package_json_cjs_namespaceObject.createAppMfTypesTsConfig)(app)) || changed;
616
+ changed = writeTextIfChanged(external_node_path_default().join(workspaceRoot, app.directory, 'src/modern-app-env.d.ts'), (0, app_files_cjs_namespaceObject.createAppEnvDts)(app, remotes)) || changed;
617
+ }
618
+ return changed;
619
+ }
620
+ function updateGeneratedModernConfigs(workspaceRoot, config) {
621
+ let changed = false;
622
+ const apps = (0, external_config_cjs_namespaceObject.workspaceAppsFromToolingConfig)(config);
623
+ for (const app of apps)changed = writeTextIfChanged(external_node_path_default().join(workspaceRoot, app.directory, 'modern.config.ts'), (0, module_federation_cjs_namespaceObject.createAppModernConfig)(config.workspace.packageScope, app)) || changed;
624
+ return changed;
625
+ }
285
626
  function updateReferenceTopology(workspaceRoot) {
286
627
  const topologyPath = external_node_path_default().join(workspaceRoot, 'topology/reference-topology.json');
287
628
  if (!external_node_fs_default().existsSync(topologyPath)) return false;
@@ -344,8 +685,10 @@ function runMigrateStrictEffect(args, context) {
344
685
  modern-js-create ultramodern migrate-strict-effect --version <version> [--skip-install]
345
686
 
346
687
  Updates generated UltraModern package-source metadata, Modern package aliases,
347
- direct Effect API topology metadata, and the pnpm lockfile for strict Effect
348
- workspaces. Source code still has to pass pnpm api:check and pnpm contract:check.
688
+ framework-owned toolchain pins, direct Effect API topology metadata, strict
689
+ Effect pnpm overrides/trust policy, framework-owned TypeScript config
690
+ surfaces, and the pnpm lockfile. Source code still has to pass pnpm api:check
691
+ and pnpm contract:check.
349
692
  `);
350
693
  return 0;
351
694
  }
@@ -353,6 +696,9 @@ workspaces. Source code still has to pass pnpm api:check and pnpm contract:check
353
696
  const packageSource = createMigrationPackageSource(args, current);
354
697
  updateUltramodernConfig(context.workspaceRoot, packageSource);
355
698
  updateReferenceTopology(context.workspaceRoot);
699
+ const migrated = (0, external_config_cjs_namespaceObject.readUltramodernConfig)(context.workspaceRoot);
700
+ updateGeneratedTypeScriptSurfaces(context.workspaceRoot, migrated);
701
+ updateGeneratedModernConfigs(context.workspaceRoot, migrated);
356
702
  for (const relativePackageFile of listWorkspacePackageFiles(context.workspaceRoot)){
357
703
  const packageFile = external_node_path_default().join(context.workspaceRoot, relativePackageFile);
358
704
  const packageJson = readJsonFile(packageFile);
@@ -363,9 +709,17 @@ workspaces. Source code still has to pass pnpm api:check and pnpm contract:check
363
709
  config: './.modernjs/ultramodern.json'
364
710
  };
365
711
  }
366
- if (updateModernDependencies(packageJson, packageSource)) writeJsonFile(packageFile, packageJson);
712
+ const modernDependenciesChanged = updateModernDependencies(packageJson, packageSource);
713
+ const toolingDependenciesChanged = updateGeneratedToolingDependencies(packageJson);
714
+ const generatedScriptsChanged = updateGeneratedPackageScripts(packageJson);
715
+ const changed = modernDependenciesChanged || toolingDependenciesChanged || generatedScriptsChanged;
716
+ if (changed) writeJsonFile(packageFile, packageJson);
367
717
  else if ('package.json' === relativePackageFile) writeJsonFile(packageFile, packageJson);
368
718
  }
719
+ updateGeneratedPnpmWorkspacePolicy(context.workspaceRoot);
720
+ ensureGeneratedDeclarationPatches(context.workspaceRoot, {
721
+ includeDrizzleOrmPatch: workspaceUsesDependency(context.workspaceRoot, 'drizzle-orm')
722
+ });
369
723
  if (!hasFlag(args, '--skip-install')) {
370
724
  const status = runPnpmLockfileRefresh(context);
371
725
  if (0 !== status) return status;
@@ -71,17 +71,14 @@ function createAppEnvDts(app, remotes = []) {
71
71
  }
72
72
  `;
73
73
  })).join('\n');
74
- const reactTypeReference = remoteModuleDeclarations ? "/// <reference types='react' />\n" : '';
75
- const siteUrlDeclaration = 'declare const ULTRAMODERN_SITE_URL: string;';
76
- return `${reactTypeReference}/// <reference types='@modern-js/app-tools/types' />
77
-
78
- ${siteUrlDeclaration}
79
- declare module '*.svg' {
80
- const url: string;
81
- export default url;
82
- }
83
- declare module '*.css';
84
- ${remoteModuleDeclarations ? `\n${remoteModuleDeclarations}` : ''}`;
74
+ const reactTypeImport = remoteModuleDeclarations ? "import type React from 'react';\n" : '';
75
+ return [
76
+ `import '@modern-js/app-tools/types';\n${reactTypeImport}`.trimEnd(),
77
+ `declare global {
78
+ const ULTRAMODERN_SITE_URL: string;
79
+ }`,
80
+ remoteModuleDeclarations.trimEnd()
81
+ ].filter((section)=>section.length > 0).join('\n\n').concat('\n');
85
82
  }
86
83
  function createAppRuntimeConfig(app, scope, remotes = []) {
87
84
  const pluginsConfig = 'shell' === app.kind ? ` plugins: [
@@ -76,6 +76,11 @@ function createAppModernConfig(scope, app) {
76
76
  (cloudflareDeployEnabled ? '/' : \`http://localhost:\${port}\`);
77
77
  const defaultRemoteAssetPrefix = \`\${remoteAssetOrigin.replace(/\\/+$/u, '')}/\`;
78
78
  const defaultAssetPrefix = defaultRemoteAssetPrefix;`;
79
+ const devAssetPrefixSource = 'shell' === app.kind ? ` // Keep shell dev assets origin-relative so the shell works through
80
+ // tunnels and local previews without rewriting its own chunks.
81
+ assetPrefix: '/',` : ` // Remote dev manifests must publish an absolute publicPath so host
82
+ // shells load remoteEntry.js and exposed chunks from this dev server.
83
+ assetPrefix,`;
79
84
  return `// @effect-diagnostics processEnv:off
80
85
  import {
81
86
  appTools,
@@ -144,8 +149,10 @@ ${defaultAssetPrefixSource}
144
149
  // load remoteEntry.js and exposed chunks from the remote origin, not the host.
145
150
  const assetPrefix =
146
151
  configuredModernAssetPrefix || configuredUltramodernAssetPrefix || defaultAssetPrefix;
147
- const buildCacheTarget = cloudflareDeployEnabled ? 'cloudflare' : 'web';
148
- const buildCacheDirectory = \`node_modules/.cache/rspack-\${appId}-\${buildCacheTarget}\`;
152
+ const buildTarget = cloudflareDeployEnabled ? 'cloudflare' : 'web';
153
+ const buildOutputRoot = cloudflareDeployEnabled ? 'dist-cloudflare' : 'dist';
154
+ const buildTempDirectory = \`node_modules/.modern-js-\${appId}-\${buildTarget}\`;
155
+ const buildCacheDirectory = \`node_modules/.cache/rspack-\${appId}-\${buildTarget}\`;
149
156
 
150
157
  if (
151
158
  cloudflareDeployEnabled &&
@@ -175,9 +182,7 @@ ${bffConfig} ...(cloudflareDeployEnabled
175
182
  }
176
183
  : {}),
177
184
  dev: {
178
- // Keep dev assets origin-relative too; the default absolute
179
- // http://localhost:<port> prefix breaks pages served through tunnels.
180
- assetPrefix: '/',
185
+ ${devAssetPrefixSource}
181
186
  },
182
187
  html: {
183
188
  outputStructure: 'flat',
@@ -187,13 +192,15 @@ ${bffConfig} ...(cloudflareDeployEnabled
187
192
  disableTsChecker: false,
188
193
  distPath: {
189
194
  html: './',
195
+ root: buildOutputRoot,
190
196
  },
191
197
  polyfill: 'off',
192
198
  splitRouteChunks: true,
199
+ tempDir: buildTempDirectory,
193
200
  },
194
201
  performance: {
195
202
  buildCache: {
196
- cacheDigest: [appId, buildCacheTarget],
203
+ cacheDigest: [appId, buildTarget],
197
204
  cacheDirectory: buildCacheDirectory,
198
205
  },
199
206
  rsdoctor: {
@@ -1,5 +1,14 @@
1
1
  "use strict";
2
2
  var __webpack_require__ = {};
3
+ (()=>{
4
+ __webpack_require__.n = (module)=>{
5
+ var getter = module && module.__esModule ? ()=>module['default'] : ()=>module;
6
+ __webpack_require__.d(getter, {
7
+ a: getter
8
+ });
9
+ return getter;
10
+ };
11
+ })();
3
12
  (()=>{
4
13
  __webpack_require__.d = (exports1, getters, values)=>{
5
14
  var define = (defs, kind)=>{
@@ -44,6 +53,8 @@ __webpack_require__.d(__webpack_exports__, {
44
53
  createZephyrDependencies: ()=>createZephyrDependencies,
45
54
  effectDiagnostics: ()=>effectDiagnostics
46
55
  });
56
+ const external_node_path_namespaceObject = require("node:path");
57
+ var external_node_path_default = /*#__PURE__*/ __webpack_require__.n(external_node_path_namespaceObject);
47
58
  const external_ultramodern_package_source_cjs_namespaceObject = require("../ultramodern-package-source.cjs");
48
59
  const external_descriptors_cjs_namespaceObject = require("./descriptors.cjs");
49
60
  const external_fs_io_cjs_namespaceObject = require("./fs-io.cjs");
@@ -294,7 +305,6 @@ function createTsConfigBase() {
294
305
  noFallthroughCasesInSwitch: true,
295
306
  noPropertyAccessFromIndexSignature: true,
296
307
  noImplicitReturns: true,
297
- skipLibCheck: true,
298
308
  resolveJsonModule: true,
299
309
  plugins: [
300
310
  {
@@ -326,7 +336,7 @@ function createReferences(packageDir, references) {
326
336
  return [
327
337
  ...new Set(references)
328
338
  ].filter((reference)=>reference !== packageDir).map((reference)=>({
329
- path: `${(0, external_naming_cjs_namespaceObject.relativeRootFor)(packageDir)}/${reference}`
339
+ path: external_node_path_default().relative(packageDir, reference).split(external_node_path_default().sep).join('/')
330
340
  }));
331
341
  }
332
342
  function createPackageTsConfig(packageDir, options = {}) {
@@ -336,8 +346,6 @@ function createPackageTsConfig(packageDir, options = {}) {
336
346
  const include = resolvedOptions.include ?? [
337
347
  'src',
338
348
  'locales/**/*.json',
339
- 'modern.config.ts',
340
- 'module-federation.config.ts',
341
349
  'package.json',
342
350
  'shared'
343
351
  ];
@@ -371,9 +379,9 @@ function createAppTsConfig(app, remotes = []) {
371
379
  });
372
380
  }
373
381
  function createAppMfTypesTsConfig(app) {
374
- const exposedFiles = Object.values(app.exposes ?? {}).map((exposePath)=>exposePath.replace(/^\.\//u, ''));
382
+ const exposedFiles = Object.entries(app.exposes ?? {}).sort(([left], [right])=>'./Route' === left ? -1 : './Route' === right ? 1 : 0).map(([, exposePath])=>exposePath.replace(/^\.\//u, ''));
375
383
  return {
376
- extends: './tsconfig.json',
384
+ extends: `${(0, external_naming_cjs_namespaceObject.relativeRootFor)(app.directory)}/tsconfig.base.json`,
377
385
  include: [
378
386
  ...new Set([
379
387
  ...exposedFiles,
@@ -404,7 +412,6 @@ function createRootTsConfig(apps = []) {
404
412
  }
405
413
  function createAppPackage(scope, app, packageSource, enableTailwind, remotes = [], bridge) {
406
414
  const publicSurfaceBuildCommand = (0, external_public_surface_cjs_namespaceObject.createPublicSurfaceGenerationCommand)(app, 'dist');
407
- const publicSurfaceCloudflareBuildCommand = (0, external_public_surface_cjs_namespaceObject.createPublicSurfaceGenerationCommand)(app, 'dist');
408
415
  const publicSurfaceCloudflareOutputCommand = (0, external_public_surface_cjs_namespaceObject.createPublicSurfaceGenerationCommand)(app, 'cloudflare');
409
416
  const packageExports = Object.fromEntries(Object.entries(app.exposes ?? {}).map(([expose, source])=>[
410
417
  expose,
@@ -417,7 +424,7 @@ function createAppPackage(scope, app, packageSource, enableTailwind, remotes = [
417
424
  scripts: {
418
425
  dev: 'modern dev',
419
426
  build: app.exposes ? `ULTRAMODERN_ZEPHYR=false modern build && ${publicSurfaceBuildCommand} && node ${(0, external_naming_cjs_namespaceObject.relativeRootFor)(app.directory)}/scripts/assert-mf-types.mts` : `ULTRAMODERN_ZEPHYR=false modern build && ${publicSurfaceBuildCommand}`,
420
- 'cloudflare:build': `ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern build && ${publicSurfaceCloudflareBuildCommand} && ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy && ${publicSurfaceCloudflareOutputCommand}`,
427
+ 'cloudflare:build': `ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern build && ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy --skip-build && ${publicSurfaceCloudflareOutputCommand}`,
421
428
  'cloudflare:deploy': 'ULTRAMODERN_CLOUDFLARE_REQUIRE_PUBLIC_URLS=true pnpm run cloudflare:build && wrangler deploy --config .output/wrangler.json',
422
429
  'cloudflare:preview': 'pnpm run cloudflare:build && wrangler dev --config .output/wrangler.json',
423
430
  'cloudflare:proof': `node ${(0, external_naming_cjs_namespaceObject.relativeRootFor)(app.directory)}/scripts/proof-cloudflare-version.mts --app ${app.id}`,