@bleedingdev/modern-js-create 3.5.0-ultramodern.2 → 3.5.0-ultramodern.21

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 +22 -15
  2. package/dist/cjs/ultramodern-tooling/commands.cjs +393 -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 +7 -2
  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 +393 -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 +5 -3
  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 +393 -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 +5 -3
  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 +4 -2
  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 +9 -0
  32. package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +95 -5
@@ -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}`,
@@ -37,9 +37,10 @@ const CLOUDFLARE_COMPATIBILITY_DATE = '2026-06-02';
37
37
  const TAILWIND_VERSION = '4.3.1';
38
38
  const TAILWIND_POSTCSS_VERSION = '4.3.1';
39
39
  const POSTCSS_VERSION = '8.5.15';
40
- const EFFECT_VERSION = '4.0.0-beta.91';
41
- const EFFECT_VITEST_VERSION = '4.0.0-beta.91';
40
+ const EFFECT_VERSION = '4.0.0-beta.92';
41
+ const EFFECT_VITEST_VERSION = '4.0.0-beta.92';
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,236 @@ 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 ensureYamlScalarMapEntry(source, key, entryKey, value) {
374
+ const entryLine = ` ${entryKey}: ${value}`;
375
+ const escapedEntryKey = entryKey.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
376
+ const currentEntryPattern = new RegExp(`^ {2}${escapedEntryKey}: .+$`, 'mu');
377
+ const currentEntry = source.match(currentEntryPattern);
378
+ if (currentEntry) {
379
+ if (currentEntry[0] === entryLine) return {
380
+ source,
381
+ changed: false
382
+ };
383
+ return {
384
+ source: source.replace(currentEntryPattern, entryLine),
385
+ changed: true
386
+ };
387
+ }
388
+ const headerPattern = new RegExp(`^${key}:\\n(?:(?: .+\\n)*)`, 'mu');
389
+ const header = source.match(headerPattern);
390
+ if (header) return {
391
+ source: source.replace(headerPattern, `${header[0]}${entryLine}\n`),
392
+ changed: true
393
+ };
394
+ return {
395
+ source: `${source.trimEnd()}\n${key}:\n${entryLine}\n`,
396
+ changed: true
397
+ };
398
+ }
399
+ function removeYamlMapEntry(source, entryKey) {
400
+ const packageName = entryKey.includes('@') ? entryKey.slice(0, entryKey.lastIndexOf('@')) : entryKey;
401
+ const escapedPackageName = packageName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
402
+ const currentEntryPattern = new RegExp(`^ {2}'${escapedPackageName}@[^']+': .+\\n?`, 'mu');
403
+ if (!currentEntryPattern.test(source)) return {
404
+ source,
405
+ changed: false
406
+ };
407
+ return {
408
+ source: source.replace(currentEntryPattern, ''),
409
+ changed: true
410
+ };
411
+ }
412
+ function ensureGeneratedPatchFile(workspaceRoot, relativePatchPath, sourcePatchPath) {
413
+ const targetPath = node_path.join(workspaceRoot, relativePatchPath);
414
+ const patch = node_fs.readFileSync(sourcePatchPath, 'utf-8');
415
+ if (node_fs.existsSync(targetPath) && node_fs.readFileSync(targetPath, 'utf-8') === patch) return false;
416
+ node_fs.mkdirSync(node_path.dirname(targetPath), {
417
+ recursive: true
418
+ });
419
+ node_fs.writeFileSync(targetPath, patch, 'utf-8');
420
+ return true;
421
+ }
422
+ function removeGeneratedPatchFileIfUnchanged(workspaceRoot, relativePatchPath, sourcePatchPath) {
423
+ const targetPath = node_path.join(workspaceRoot, relativePatchPath);
424
+ if (!node_fs.existsSync(targetPath)) return false;
425
+ const patch = node_fs.readFileSync(sourcePatchPath, 'utf-8');
426
+ if (node_fs.readFileSync(targetPath, 'utf-8') !== patch) return false;
427
+ node_fs.rmSync(targetPath);
428
+ return true;
429
+ }
430
+ function workspaceUsesDependency(workspaceRoot, packageName) {
431
+ const packageJsonPaths = [
432
+ node_path.join(workspaceRoot, 'package.json')
433
+ ];
434
+ for (const workspaceDir of [
435
+ 'apps',
436
+ 'verticals',
437
+ 'packages'
438
+ ]){
439
+ const absoluteWorkspaceDir = node_path.join(workspaceRoot, workspaceDir);
440
+ if (node_fs.existsSync(absoluteWorkspaceDir)) for (const entry of node_fs.readdirSync(absoluteWorkspaceDir, {
441
+ withFileTypes: true
442
+ })){
443
+ if (!entry.isDirectory()) continue;
444
+ const packageJsonPath = node_path.join(absoluteWorkspaceDir, entry.name, 'package.json');
445
+ if (node_fs.existsSync(packageJsonPath)) packageJsonPaths.push(packageJsonPath);
446
+ }
447
+ }
448
+ for (const packageJsonPath of packageJsonPaths){
449
+ const packageJson = JSON.parse(node_fs.readFileSync(packageJsonPath, 'utf-8'));
450
+ for (const field of [
451
+ 'dependencies',
452
+ 'devDependencies',
453
+ 'peerDependencies',
454
+ 'optionalDependencies'
455
+ ]){
456
+ const dependencies = packageJson[field];
457
+ if (dependencies && 'object' == typeof dependencies) {
458
+ if (Object.prototype.hasOwnProperty.call(dependencies, packageName)) return true;
459
+ for (const specifier of Object.values(dependencies))if ('string' == typeof specifier && specifier.startsWith(`npm:${packageName}@`)) return true;
460
+ }
461
+ }
462
+ }
463
+ return false;
464
+ }
465
+ function ensureGeneratedDeclarationPatches(workspaceRoot, options) {
466
+ let changed = false;
467
+ changed = ensureGeneratedPatchFile(workspaceRoot, moduleFederationModernJsPatchPath, moduleFederationModernJsPatchSourcePath) || changed;
468
+ changed = ensureGeneratedPatchFile(workspaceRoot, moduleFederationBridgeReactPatchPath, moduleFederationBridgeReactPatchSourcePath) || changed;
469
+ changed = ensureGeneratedPatchFile(workspaceRoot, effectDeclarationPatchPath, effectDeclarationPatchSourcePath) || changed;
470
+ changed = options.includeDrizzleOrmPatch ? ensureGeneratedPatchFile(workspaceRoot, drizzleOrmDeclarationPatchPath, drizzleOrmDeclarationPatchSourcePath) || changed : removeGeneratedPatchFileIfUnchanged(workspaceRoot, drizzleOrmDeclarationPatchPath, drizzleOrmDeclarationPatchSourcePath) || changed;
471
+ return changed;
472
+ }
473
+ function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
474
+ const workspaceFile = node_path.join(workspaceRoot, 'pnpm-workspace.yaml');
475
+ if (!node_fs.existsSync(workspaceFile)) return false;
476
+ let source = node_fs.readFileSync(workspaceFile, 'utf-8');
477
+ let changed = false;
478
+ const usesDrizzleOrm = workspaceUsesDependency(workspaceRoot, 'drizzle-orm');
479
+ const replacements = [
480
+ [
481
+ /^ {4}'@effect\/vitest>effect': .+$/mu,
482
+ ` '@effect/vitest>effect': '${EFFECT_VERSION}'`
483
+ ]
484
+ ];
485
+ for (const [pattern, replacement] of replacements){
486
+ const result = replaceYamlLine(source, pattern, replacement);
487
+ source = result.source;
488
+ changed = result.changed || changed;
489
+ }
490
+ for (const [entryKey, version] of [
491
+ [
492
+ "'@effect/opentelemetry'",
493
+ EFFECT_VERSION
494
+ ],
495
+ [
496
+ "'@effect/vitest'",
497
+ EFFECT_VITEST_VERSION
498
+ ],
499
+ [
500
+ 'effect',
501
+ EFFECT_VERSION
502
+ ]
503
+ ]){
504
+ const result = ensureYamlScalarMapEntry(source, 'overrides', entryKey, version);
505
+ source = result.source;
506
+ changed = result.changed || changed;
507
+ }
508
+ for (const item of strictEffectPackageVersionPolicyExclusions){
509
+ const packageName = item.slice(0, item.lastIndexOf('@'));
510
+ const escapedPackageName = packageName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
511
+ const currentVersion = replaceYamlLine(source, new RegExp(`^ {2}- '${escapedPackageName}@[^']+'$`, 'gmu'), ` - '${item}'`);
512
+ source = currentVersion.source;
513
+ changed = currentVersion.changed || changed;
514
+ for (const policyKey of [
515
+ 'minimumReleaseAgeExclude',
516
+ 'trustPolicyExclude'
517
+ ]){
518
+ const policyExclude = ensureYamlListItem(source, policyKey, item);
519
+ source = policyExclude.source;
520
+ changed = policyExclude.changed || changed;
521
+ }
522
+ }
523
+ const effectPatch = ensureYamlMapEntry(source, 'patchedDependencies', `effect@${EFFECT_VERSION}`, effectDeclarationPatchPath);
524
+ source = effectPatch.source;
525
+ changed = effectPatch.changed || changed;
526
+ const moduleFederationModernJsPatch = ensureYamlMapEntry(source, 'patchedDependencies', `@module-federation/modern-js-v3@${MODULE_FEDERATION_VERSION}`, moduleFederationModernJsPatchPath);
527
+ source = moduleFederationModernJsPatch.source;
528
+ changed = moduleFederationModernJsPatch.changed || changed;
529
+ const moduleFederationBridgeReactPatch = ensureYamlMapEntry(source, 'patchedDependencies', `@module-federation/bridge-react@${MODULE_FEDERATION_VERSION}`, moduleFederationBridgeReactPatchPath);
530
+ source = moduleFederationBridgeReactPatch.source;
531
+ changed = moduleFederationBridgeReactPatch.changed || changed;
532
+ const drizzleOrmPatch = usesDrizzleOrm ? ensureYamlMapEntry(source, 'patchedDependencies', `drizzle-orm@${DRIZZLE_ORM_VERSION}`, drizzleOrmDeclarationPatchPath) : removeYamlMapEntry(source, `drizzle-orm@${DRIZZLE_ORM_VERSION}`);
533
+ source = drizzleOrmPatch.source;
534
+ changed = drizzleOrmPatch.changed || changed;
535
+ if (changed) node_fs.writeFileSync(workspaceFile, source, 'utf-8');
536
+ return changed;
537
+ }
219
538
  function updateUltramodernConfig(workspaceRoot, packageSource) {
220
539
  const configPath = node_path.join(workspaceRoot, '.modernjs/ultramodern.json');
221
540
  const config = readJsonFile(configPath);
@@ -235,6 +554,64 @@ function updateUltramodernConfig(workspaceRoot, packageSource) {
235
554
  for (const app of config.topology?.apps ?? [])if (app && 'object' == typeof app && !Array.isArray(app)) normalizeStrictEffectApiMetadata(app);
236
555
  writeJsonFile(configPath, config);
237
556
  }
557
+ function writeJsonIfChanged(filePath, value) {
558
+ const next = `${JSON.stringify(value, null, 2)}\n`;
559
+ if (node_fs.existsSync(filePath) && node_fs.readFileSync(filePath, 'utf-8') === next) return false;
560
+ node_fs.mkdirSync(node_path.dirname(filePath), {
561
+ recursive: true
562
+ });
563
+ node_fs.writeFileSync(filePath, next, 'utf-8');
564
+ return true;
565
+ }
566
+ function writeTextIfChanged(filePath, value) {
567
+ if (node_fs.existsSync(filePath) && node_fs.readFileSync(filePath, 'utf-8') === value) return false;
568
+ node_fs.mkdirSync(node_path.dirname(filePath), {
569
+ recursive: true
570
+ });
571
+ node_fs.writeFileSync(filePath, value, 'utf-8');
572
+ return true;
573
+ }
574
+ function ensureGeneratedIgnoreRules(workspaceRoot) {
575
+ const gitignorePath = node_path.join(workspaceRoot, '.gitignore');
576
+ const existing = node_fs.existsSync(gitignorePath) ? node_fs.readFileSync(gitignorePath, 'utf-8') : '';
577
+ const lines = 0 === existing.trimEnd().length ? [] : existing.trimEnd().split(/\r?\n/u);
578
+ let changed = false;
579
+ for (const rule of [
580
+ '.mf/',
581
+ '**/.mf/',
582
+ 'dist-cloudflare/'
583
+ ])if (!lines.includes(rule)) {
584
+ lines.push(rule);
585
+ changed = true;
586
+ }
587
+ if (!changed) return false;
588
+ const next = `${lines.join('\n')}\n`;
589
+ node_fs.writeFileSync(gitignorePath, next, 'utf-8');
590
+ return true;
591
+ }
592
+ function updateGeneratedTypeScriptSurfaces(workspaceRoot, config) {
593
+ let changed = false;
594
+ const apps = workspaceAppsFromToolingConfig(config);
595
+ const remotes = apps.filter((app)=>'shell' !== app.kind);
596
+ changed = writeJsonIfChanged(node_path.join(workspaceRoot, 'tsconfig.base.json'), createTsConfigBase()) || changed;
597
+ changed = ensureGeneratedIgnoreRules(workspaceRoot) || changed;
598
+ for (const sharedPackage of [
599
+ 'packages/shared-contracts',
600
+ 'packages/shared-design-tokens'
601
+ ])changed = writeJsonIfChanged(node_path.join(workspaceRoot, sharedPackage, 'tsconfig.json'), createSharedPackageTsConfig(sharedPackage)) || changed;
602
+ for (const app of apps){
603
+ changed = writeJsonIfChanged(node_path.join(workspaceRoot, app.directory, 'tsconfig.json'), createAppTsConfig(app, remotes)) || changed;
604
+ changed = writeJsonIfChanged(node_path.join(workspaceRoot, app.directory, 'tsconfig.mf-types.json'), createAppMfTypesTsConfig(app)) || changed;
605
+ changed = writeTextIfChanged(node_path.join(workspaceRoot, app.directory, 'src/modern-app-env.d.ts'), createAppEnvDts(app, remotes)) || changed;
606
+ }
607
+ return changed;
608
+ }
609
+ function updateGeneratedModernConfigs(workspaceRoot, config) {
610
+ let changed = false;
611
+ const apps = workspaceAppsFromToolingConfig(config);
612
+ for (const app of apps)changed = writeTextIfChanged(node_path.join(workspaceRoot, app.directory, 'modern.config.ts'), createAppModernConfig(config.workspace.packageScope, app)) || changed;
613
+ return changed;
614
+ }
238
615
  function updateReferenceTopology(workspaceRoot) {
239
616
  const topologyPath = node_path.join(workspaceRoot, 'topology/reference-topology.json');
240
617
  if (!node_fs.existsSync(topologyPath)) return false;
@@ -297,8 +674,10 @@ function runMigrateStrictEffect(args, context) {
297
674
  modern-js-create ultramodern migrate-strict-effect --version <version> [--skip-install]
298
675
 
299
676
  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.
677
+ framework-owned toolchain pins, direct Effect API topology metadata, strict
678
+ Effect pnpm overrides/trust policy, framework-owned TypeScript config
679
+ surfaces, and the pnpm lockfile. Source code still has to pass pnpm api:check
680
+ and pnpm contract:check.
302
681
  `);
303
682
  return 0;
304
683
  }
@@ -306,6 +685,9 @@ workspaces. Source code still has to pass pnpm api:check and pnpm contract:check
306
685
  const packageSource = createMigrationPackageSource(args, current);
307
686
  updateUltramodernConfig(context.workspaceRoot, packageSource);
308
687
  updateReferenceTopology(context.workspaceRoot);
688
+ const migrated = readUltramodernConfig(context.workspaceRoot);
689
+ updateGeneratedTypeScriptSurfaces(context.workspaceRoot, migrated);
690
+ updateGeneratedModernConfigs(context.workspaceRoot, migrated);
309
691
  for (const relativePackageFile of listWorkspacePackageFiles(context.workspaceRoot)){
310
692
  const packageFile = node_path.join(context.workspaceRoot, relativePackageFile);
311
693
  const packageJson = readJsonFile(packageFile);
@@ -316,9 +698,17 @@ workspaces. Source code still has to pass pnpm api:check and pnpm contract:check
316
698
  config: './.modernjs/ultramodern.json'
317
699
  };
318
700
  }
319
- if (updateModernDependencies(packageJson, packageSource)) writeJsonFile(packageFile, packageJson);
701
+ const modernDependenciesChanged = updateModernDependencies(packageJson, packageSource);
702
+ const toolingDependenciesChanged = updateGeneratedToolingDependencies(packageJson);
703
+ const generatedScriptsChanged = updateGeneratedPackageScripts(packageJson);
704
+ const changed = modernDependenciesChanged || toolingDependenciesChanged || generatedScriptsChanged;
705
+ if (changed) writeJsonFile(packageFile, packageJson);
320
706
  else if ('package.json' === relativePackageFile) writeJsonFile(packageFile, packageJson);
321
707
  }
708
+ updateGeneratedPnpmWorkspacePolicy(context.workspaceRoot);
709
+ ensureGeneratedDeclarationPatches(context.workspaceRoot, {
710
+ includeDrizzleOrmPatch: workspaceUsesDependency(context.workspaceRoot, 'drizzle-orm')
711
+ });
322
712
  if (!hasFlag(args, '--skip-install')) {
323
713
  const status = runPnpmLockfileRefresh(context);
324
714
  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: {