@bleedingdev/modern-js-create 3.5.0-ultramodern.0 → 3.5.0-ultramodern.10

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 (28) hide show
  1. package/README.md +28 -0
  2. package/dist/cjs/ultramodern-tooling/commands.cjs +399 -0
  3. package/dist/cjs/ultramodern-workspace/contracts.cjs +1 -0
  4. package/dist/cjs/ultramodern-workspace/module-federation.cjs +6 -0
  5. package/dist/cjs/ultramodern-workspace/package-json.cjs +2 -1
  6. package/dist/cjs/ultramodern-workspace/versions.cjs +12 -2
  7. package/dist/cjs/ultramodern-workspace/workspace-scripts.cjs +1 -0
  8. package/dist/cjs/ultramodern-workspace/write-workspace.cjs +2 -0
  9. package/dist/esm/ultramodern-tooling/commands.js +399 -0
  10. package/dist/esm/ultramodern-workspace/contracts.js +1 -0
  11. package/dist/esm/ultramodern-workspace/module-federation.js +6 -0
  12. package/dist/esm/ultramodern-workspace/package-json.js +2 -1
  13. package/dist/esm/ultramodern-workspace/versions.js +7 -3
  14. package/dist/esm/ultramodern-workspace/workspace-scripts.js +1 -0
  15. package/dist/esm/ultramodern-workspace/write-workspace.js +3 -1
  16. package/dist/esm-node/ultramodern-tooling/commands.js +399 -0
  17. package/dist/esm-node/ultramodern-workspace/contracts.js +1 -0
  18. package/dist/esm-node/ultramodern-workspace/module-federation.js +6 -0
  19. package/dist/esm-node/ultramodern-workspace/package-json.js +2 -1
  20. package/dist/esm-node/ultramodern-workspace/versions.js +7 -3
  21. package/dist/esm-node/ultramodern-workspace/workspace-scripts.js +1 -0
  22. package/dist/esm-node/ultramodern-workspace/write-workspace.js +3 -1
  23. package/dist/types/ultramodern-workspace/versions.d.ts +6 -2
  24. package/package.json +6 -6
  25. package/template-workspace/README.md.handlebars +44 -1
  26. package/template-workspace/pnpm-workspace.yaml.handlebars +8 -0
  27. package/templates/workspace-scripts/check-ultramodern-api-boundaries.mts +30 -8
  28. package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +23 -0
@@ -4,7 +4,9 @@ import node_os from "node:os";
4
4
  import node_path from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  import { resolveCreatePackageRoot } from "../create-package-root.js";
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";
7
8
  import { validateModuleFederationTypes } from "../ultramodern-workspace/mf-validation.js";
9
+ import { EFFECT_TSGO_VERSION, EFFECT_VERSION, EFFECT_VITEST_VERSION, OXFMT_VERSION, OXLINT_VERSION, TYPESCRIPT_NATIVE_PREVIEW_VERSION, WRANGLER_VERSION, ZEPHYR_AGENT_VERSION, ZEPHYR_RSPACK_PLUGIN_VERSION } from "../ultramodern-workspace/versions.js";
8
10
  import { createWorkspaceValidationScript } from "../ultramodern-workspace/workspace-scripts.js";
9
11
  import { readUltramodernConfig, workspaceAppsFromToolingConfig } from "./config.js";
10
12
  const commands_dirname = node_path.dirname(fileURLToPath(import.meta.url));
@@ -17,6 +19,7 @@ Commands:
17
19
  validate
18
20
  typecheck
19
21
  mf-types
22
+ migrate-strict-effect
20
23
  public-surface
21
24
  cloudflare-proof
22
25
  performance-readiness
@@ -82,6 +85,400 @@ Checks real Module Federation config files and DTS archives for exposed apps.
82
85
  });
83
86
  return 0;
84
87
  }
88
+ const modernPackageNames = new Set([
89
+ ...ULTRAMODERN_SINGLE_APP_MODERN_PACKAGES,
90
+ ...ULTRAMODERN_WORKSPACE_MODERN_PACKAGES
91
+ ]);
92
+ function readJsonFile(filePath) {
93
+ return JSON.parse(node_fs.readFileSync(filePath, 'utf-8'));
94
+ }
95
+ function writeJsonFile(filePath, value) {
96
+ node_fs.writeFileSync(filePath, `${JSON.stringify(value, null, 2)}\n`, 'utf-8');
97
+ }
98
+ function readOption(args, name) {
99
+ const prefix = `${name}=`;
100
+ const inline = args.find((arg)=>arg.startsWith(prefix));
101
+ if (inline) {
102
+ const value = inline.slice(prefix.length);
103
+ if (!value) throw new Error(`${name} needs a value.`);
104
+ return value;
105
+ }
106
+ const index = args.indexOf(name);
107
+ if (-1 === index) return;
108
+ const value = args[index + 1];
109
+ if (!value || value.startsWith('--')) throw new Error(`${name} needs a value.`);
110
+ return value;
111
+ }
112
+ function hasFlag(args, name) {
113
+ return args.includes(name);
114
+ }
115
+ function listWorkspacePackageFiles(workspaceRoot) {
116
+ const packageFiles = [
117
+ 'package.json'
118
+ ];
119
+ for (const directory of [
120
+ 'apps',
121
+ 'verticals',
122
+ 'packages'
123
+ ]){
124
+ const absoluteDirectory = node_path.join(workspaceRoot, directory);
125
+ if (node_fs.existsSync(absoluteDirectory)) for (const entry of node_fs.readdirSync(absoluteDirectory, {
126
+ withFileTypes: true
127
+ })){
128
+ if (!entry.isDirectory()) continue;
129
+ const packageFile = node_path.join(directory, entry.name, 'package.json');
130
+ if (node_fs.existsSync(node_path.join(workspaceRoot, packageFile))) packageFiles.push(packageFile);
131
+ }
132
+ }
133
+ return packageFiles;
134
+ }
135
+ function updateModernDependencies(packageJson, packageSource) {
136
+ let changed = false;
137
+ for (const section of [
138
+ 'dependencies',
139
+ 'devDependencies',
140
+ 'peerDependencies',
141
+ 'optionalDependencies'
142
+ ]){
143
+ const dependencies = packageJson[section];
144
+ if (!(!dependencies || 'object' != typeof dependencies || Array.isArray(dependencies))) for (const packageName of Object.keys(dependencies)){
145
+ if (!modernPackageNames.has(packageName)) continue;
146
+ const nextSpecifier = modernPackageSpecifier(packageName, packageSource);
147
+ if (dependencies[packageName] !== nextSpecifier) {
148
+ dependencies[packageName] = nextSpecifier;
149
+ changed = true;
150
+ }
151
+ }
152
+ }
153
+ return changed;
154
+ }
155
+ const generatedToolingDependencyPins = new Map([
156
+ [
157
+ '@effect/tsgo',
158
+ EFFECT_TSGO_VERSION
159
+ ],
160
+ [
161
+ "@typescript/native-preview",
162
+ TYPESCRIPT_NATIVE_PREVIEW_VERSION
163
+ ],
164
+ [
165
+ 'oxfmt',
166
+ OXFMT_VERSION
167
+ ],
168
+ [
169
+ 'oxlint',
170
+ OXLINT_VERSION
171
+ ],
172
+ [
173
+ 'wrangler',
174
+ WRANGLER_VERSION
175
+ ],
176
+ [
177
+ 'zephyr-agent',
178
+ ZEPHYR_AGENT_VERSION
179
+ ],
180
+ [
181
+ 'zephyr-rspack-plugin',
182
+ ZEPHYR_RSPACK_PLUGIN_VERSION
183
+ ]
184
+ ]);
185
+ const strictEffectPackageVersionPolicyExclusions = [
186
+ `effect@${EFFECT_VERSION}`,
187
+ `@effect/opentelemetry@${EFFECT_VERSION}`
188
+ ];
189
+ function updateGeneratedToolingDependencies(packageJson) {
190
+ let changed = false;
191
+ for (const section of [
192
+ 'dependencies',
193
+ 'devDependencies',
194
+ 'peerDependencies',
195
+ 'optionalDependencies'
196
+ ]){
197
+ const dependencies = packageJson[section];
198
+ if (!(!dependencies || 'object' != typeof dependencies || Array.isArray(dependencies))) {
199
+ for (const [packageName, version] of generatedToolingDependencyPins)if (Object.prototype.hasOwnProperty.call(dependencies, packageName) && dependencies[packageName] !== version) {
200
+ dependencies[packageName] = version;
201
+ changed = true;
202
+ }
203
+ }
204
+ }
205
+ return changed;
206
+ }
207
+ const cloudflareModernDeployCommand = 'ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy';
208
+ const cloudflareModernDeploySkipBuildCommand = `${cloudflareModernDeployCommand} --skip-build`;
209
+ const cloudflareWranglerDeployCommand = 'wrangler deploy --config .output/wrangler.json';
210
+ const cloudflareWranglerDeployInvalidSkipBuildCommand = `${cloudflareWranglerDeployCommand} --skip-build`;
211
+ function updateGeneratedPackageScripts(packageJson) {
212
+ const scripts = packageJson.scripts;
213
+ if (!scripts || 'object' != typeof scripts || Array.isArray(scripts)) return false;
214
+ let changed = false;
215
+ const cloudflareBuild = scripts['cloudflare:build'];
216
+ if ('string' == typeof cloudflareBuild && cloudflareBuild.includes(cloudflareModernDeployCommand) && !cloudflareBuild.includes(cloudflareModernDeploySkipBuildCommand)) {
217
+ scripts['cloudflare:build'] = cloudflareBuild.replace(cloudflareModernDeployCommand, cloudflareModernDeploySkipBuildCommand);
218
+ changed = true;
219
+ }
220
+ const cloudflareDeploy = scripts['cloudflare:deploy'];
221
+ if ('string' == typeof cloudflareDeploy && cloudflareDeploy.includes(cloudflareWranglerDeployInvalidSkipBuildCommand)) {
222
+ scripts['cloudflare:deploy'] = cloudflareDeploy.replace(cloudflareWranglerDeployInvalidSkipBuildCommand, cloudflareWranglerDeployCommand);
223
+ changed = true;
224
+ }
225
+ return changed;
226
+ }
227
+ function normalizeStrictEffectApiMetadata(value) {
228
+ const api = value.api;
229
+ if (!api || 'object' != typeof api || Array.isArray(api)) return false;
230
+ let changed = false;
231
+ const oldEffect = api.effect;
232
+ if (oldEffect && 'object' == typeof oldEffect && !Array.isArray(oldEffect)) {
233
+ if (void 0 === api.stem && 'string' == typeof oldEffect.stem) {
234
+ api.stem = oldEffect.stem;
235
+ changed = true;
236
+ }
237
+ if (void 0 === api.prefix && 'string' == typeof oldEffect.prefix) {
238
+ api.prefix = oldEffect.prefix;
239
+ changed = true;
240
+ }
241
+ if (void 0 === api.consumedBy && Array.isArray(oldEffect.consumedBy)) {
242
+ api.consumedBy = oldEffect.consumedBy;
243
+ changed = true;
244
+ }
245
+ delete api.effect;
246
+ changed = true;
247
+ }
248
+ if (void 0 !== api.runtime && 'effect' !== api.runtime) {
249
+ api.runtime = 'effect';
250
+ changed = true;
251
+ }
252
+ if (api.bff && 'object' == typeof api.bff && !Array.isArray(api.bff)) {
253
+ if (true !== api.bff.strictEffectApproach) {
254
+ api.bff.strictEffectApproach = true;
255
+ changed = true;
256
+ }
257
+ }
258
+ if ('string' == typeof value.path) {
259
+ const directServerEntry = `${value.path}/api/index.ts`;
260
+ if ('string' == typeof api.serverEntry && /\/api\/effect\/index\.[cm]?[jt]sx?$/u.test(api.serverEntry)) {
261
+ api.serverEntry = directServerEntry;
262
+ changed = true;
263
+ }
264
+ if (api.contract && 'object' == typeof api.contract && !Array.isArray(api.contract)) {
265
+ if ('./shared/effect/api' === api.contract.export) {
266
+ api.contract.export = './api';
267
+ changed = true;
268
+ }
269
+ if ('string' == typeof api.contract.path && /\/shared\/effect\/api\.[cm]?[jt]sx?$/u.test(api.contract.path)) {
270
+ api.contract.path = `${value.path}/shared/api.ts`;
271
+ changed = true;
272
+ }
273
+ }
274
+ if (api.client && 'object' == typeof api.client && !Array.isArray(api.client)) {
275
+ if ('./effect/client' === api.client.export) {
276
+ api.client.export = './api/client';
277
+ changed = true;
278
+ }
279
+ if ('string' == typeof api.client.path && /\/src\/effect\/[^/]+-client\.[cm]?ts$/u.test(api.client.path)) {
280
+ const basename = node_path.basename(api.client.path);
281
+ api.client.path = `${value.path}/src/api/${basename}`;
282
+ changed = true;
283
+ }
284
+ }
285
+ if (void 0 === api.serverEntry && 'effect' === api.runtime) {
286
+ api.serverEntry = directServerEntry;
287
+ changed = true;
288
+ }
289
+ }
290
+ return changed;
291
+ }
292
+ function replaceYamlLine(source, pattern, replacement) {
293
+ const updated = source.replace(pattern, replacement);
294
+ return {
295
+ source: updated,
296
+ changed: updated !== source
297
+ };
298
+ }
299
+ function ensureYamlListItem(source, key, item) {
300
+ const itemLine = ` - '${item}'`;
301
+ const headerPattern = new RegExp(`^${key}:\\n(?:(?: - .+\\n)*)`, 'mu');
302
+ const header = source.match(headerPattern);
303
+ if (header) {
304
+ if (header[0].split('\n').includes(itemLine)) return {
305
+ source,
306
+ changed: false
307
+ };
308
+ return {
309
+ source: source.replace(headerPattern, `${header[0]}${itemLine}\n`),
310
+ changed: true
311
+ };
312
+ }
313
+ const block = `${key}:\n${itemLine}\n`;
314
+ const afterTrustPolicyIgnore = source.replace(/^(trustPolicyIgnoreAfter: .+\n)/mu, `$1${block}`);
315
+ if (afterTrustPolicyIgnore !== source) return {
316
+ source: afterTrustPolicyIgnore,
317
+ changed: true
318
+ };
319
+ return {
320
+ source: `${source.trimEnd()}\n${block}`,
321
+ changed: true
322
+ };
323
+ }
324
+ function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
325
+ const workspaceFile = node_path.join(workspaceRoot, 'pnpm-workspace.yaml');
326
+ if (!node_fs.existsSync(workspaceFile)) return false;
327
+ let source = node_fs.readFileSync(workspaceFile, 'utf-8');
328
+ let changed = false;
329
+ const replacements = [
330
+ [
331
+ /^ {4}'@effect\/vitest>effect': .+$/mu,
332
+ ` '@effect/vitest>effect': '${EFFECT_VERSION}'`
333
+ ],
334
+ [
335
+ /^ {2}'@effect\/vitest': .+$/mu,
336
+ ` '@effect/vitest': ${EFFECT_VITEST_VERSION}`
337
+ ],
338
+ [
339
+ /^ {2}effect: .+$/mu,
340
+ ` effect: ${EFFECT_VERSION}`
341
+ ]
342
+ ];
343
+ for (const [pattern, replacement] of replacements){
344
+ const result = replaceYamlLine(source, pattern, replacement);
345
+ source = result.source;
346
+ changed = result.changed || changed;
347
+ }
348
+ for (const item of strictEffectPackageVersionPolicyExclusions){
349
+ const packageName = item.slice(0, item.lastIndexOf('@'));
350
+ const escapedPackageName = packageName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
351
+ const currentVersion = replaceYamlLine(source, new RegExp(`^ {2}- '${escapedPackageName}@[^']+'$`, 'gmu'), ` - '${item}'`);
352
+ source = currentVersion.source;
353
+ changed = currentVersion.changed || changed;
354
+ for (const policyKey of [
355
+ 'minimumReleaseAgeExclude',
356
+ 'trustPolicyExclude'
357
+ ]){
358
+ const policyExclude = ensureYamlListItem(source, policyKey, item);
359
+ source = policyExclude.source;
360
+ changed = policyExclude.changed || changed;
361
+ }
362
+ }
363
+ if (changed) node_fs.writeFileSync(workspaceFile, source, 'utf-8');
364
+ return changed;
365
+ }
366
+ function updateUltramodernConfig(workspaceRoot, packageSource) {
367
+ const configPath = node_path.join(workspaceRoot, '.modernjs/ultramodern.json');
368
+ const config = readJsonFile(configPath);
369
+ config.packageSource = {
370
+ strategy: packageSource.strategy,
371
+ modernPackageVersion: packageSource.modernPackageVersion,
372
+ ...packageSource.registry ? {
373
+ registry: packageSource.registry
374
+ } : {},
375
+ ...packageSource.aliasScope ? {
376
+ aliasScope: packageSource.aliasScope
377
+ } : {},
378
+ ...packageSource.aliasPackageNamePrefix ? {
379
+ aliasPackageNamePrefix: packageSource.aliasPackageNamePrefix
380
+ } : {}
381
+ };
382
+ for (const app of config.topology?.apps ?? [])if (app && 'object' == typeof app && !Array.isArray(app)) normalizeStrictEffectApiMetadata(app);
383
+ writeJsonFile(configPath, config);
384
+ }
385
+ function updateReferenceTopology(workspaceRoot) {
386
+ const topologyPath = node_path.join(workspaceRoot, 'topology/reference-topology.json');
387
+ if (!node_fs.existsSync(topologyPath)) return false;
388
+ const topology = readJsonFile(topologyPath);
389
+ let changed = false;
390
+ for (const vertical of topology.verticals ?? [])if (vertical && 'object' == typeof vertical && !Array.isArray(vertical)) changed = normalizeStrictEffectApiMetadata(vertical) || changed;
391
+ if (changed) writeJsonFile(topologyPath, topology);
392
+ return changed;
393
+ }
394
+ function createMigrationPackageSource(args, current) {
395
+ const strategy = hasFlag(args, '--workspace') ? 'workspace' : 'install';
396
+ const registry = readOption(args, '--registry') ?? readOption(args, '--ultramodern-package-registry');
397
+ const explicitAliasScope = readOption(args, '--alias-scope') ?? readOption(args, '--ultramodern-package-scope');
398
+ const aliasScope = explicitAliasScope ?? ('install' === strategy && void 0 === registry ? current.packageSource?.aliasScope ?? BLEEDINGDEV_PACKAGE_SCOPE : current.packageSource?.aliasScope);
399
+ const aliasPackageNamePrefix = readOption(args, '--alias-package-name-prefix') ?? readOption(args, '--ultramodern-package-name-prefix') ?? current.packageSource?.aliasPackageNamePrefix ?? (aliasScope ? BLEEDINGDEV_PACKAGE_NAME_PREFIX : void 0);
400
+ if ('workspace' === strategy) return {
401
+ strategy,
402
+ modernPackageVersion: WORKSPACE_PACKAGE_VERSION,
403
+ ...registry ? {
404
+ registry
405
+ } : {},
406
+ ...aliasScope ? {
407
+ aliasScope
408
+ } : {},
409
+ ...aliasPackageNamePrefix ? {
410
+ aliasPackageNamePrefix
411
+ } : {}
412
+ };
413
+ const version = readOption(args, '--version') ?? readOption(args, '--ultramodern-package-version') ?? current.packageSource?.modernPackageVersion;
414
+ if (!version || version === WORKSPACE_PACKAGE_VERSION) throw new Error('migrate-strict-effect needs --version <published-ultramodern-version> for install package source.');
415
+ return {
416
+ strategy,
417
+ modernPackageVersion: version,
418
+ ...registry ? {
419
+ registry
420
+ } : {},
421
+ ...aliasScope ? {
422
+ aliasScope
423
+ } : {},
424
+ ...aliasPackageNamePrefix ? {
425
+ aliasPackageNamePrefix
426
+ } : {}
427
+ };
428
+ }
429
+ function runPnpmLockfileRefresh(context) {
430
+ const result = spawnSync('pnpm', [
431
+ 'install',
432
+ '--lockfile-only',
433
+ "--ignore-scripts"
434
+ ], {
435
+ cwd: context.workspaceRoot,
436
+ stdio: 'inherit'
437
+ });
438
+ if (result.error) throw result.error;
439
+ return result.status ?? 1;
440
+ }
441
+ function runMigrateStrictEffect(args, context) {
442
+ if (args.includes('--help') || args.includes('-h')) {
443
+ process.stdout.write(`Usage:
444
+ modern-js-create ultramodern migrate-strict-effect --version <version> [--skip-install]
445
+
446
+ Updates generated UltraModern package-source metadata, Modern package aliases,
447
+ framework-owned toolchain pins, direct Effect API topology metadata, strict
448
+ Effect pnpm overrides/trust policy, and the pnpm lockfile. Source code still
449
+ has to pass pnpm api:check and pnpm contract:check.
450
+ `);
451
+ return 0;
452
+ }
453
+ const current = readUltramodernConfig(context.workspaceRoot);
454
+ const packageSource = createMigrationPackageSource(args, current);
455
+ updateUltramodernConfig(context.workspaceRoot, packageSource);
456
+ updateReferenceTopology(context.workspaceRoot);
457
+ for (const relativePackageFile of listWorkspacePackageFiles(context.workspaceRoot)){
458
+ const packageFile = node_path.join(context.workspaceRoot, relativePackageFile);
459
+ const packageJson = readJsonFile(packageFile);
460
+ if ('package.json' === relativePackageFile) {
461
+ packageJson.modernjs ??= {};
462
+ packageJson.modernjs.packageSource = {
463
+ strategy: packageSource.strategy,
464
+ config: './.modernjs/ultramodern.json'
465
+ };
466
+ }
467
+ const modernDependenciesChanged = updateModernDependencies(packageJson, packageSource);
468
+ const toolingDependenciesChanged = updateGeneratedToolingDependencies(packageJson);
469
+ const generatedScriptsChanged = updateGeneratedPackageScripts(packageJson);
470
+ const changed = modernDependenciesChanged || toolingDependenciesChanged || generatedScriptsChanged;
471
+ if (changed) writeJsonFile(packageFile, packageJson);
472
+ else if ('package.json' === relativePackageFile) writeJsonFile(packageFile, packageJson);
473
+ }
474
+ updateGeneratedPnpmWorkspacePolicy(context.workspaceRoot);
475
+ if (!hasFlag(args, '--skip-install')) {
476
+ const status = runPnpmLockfileRefresh(context);
477
+ if (0 !== status) return status;
478
+ }
479
+ process.stdout.write(`UltraModern strict Effect metadata migrated to ${packageSource.modernPackageVersion}. Run pnpm api:check && pnpm contract:check next.\n`);
480
+ return 0;
481
+ }
85
482
  function runSkills(args, context) {
86
483
  const [subcommand, ...rest] = args;
87
484
  if ('install' === subcommand) return spawnNodeScript("template-workspace/scripts/bootstrap-agent-skills.mjs", rest, context);
@@ -112,6 +509,8 @@ async function runUltramodernToolingCli(args, workspaceRoot = process.env.ULTRAM
112
509
  });
113
510
  case 'mf-types':
114
511
  return runMfTypes(rest, context);
512
+ case 'migrate-strict-effect':
513
+ return runMigrateStrictEffect(rest, context);
115
514
  case 'public-surface':
116
515
  return spawnNodeScript("templates/workspace-scripts/generate-public-surface-assets.mjs", rest, context);
117
516
  case 'cloudflare-proof':
@@ -254,6 +254,7 @@ function createUltramodernConfig(scope, modernVersion, packageSource, apps = [
254
254
  publicSurface: "scripts/generate-public-surface-assets.mts",
255
255
  cloudflareProof: "scripts/proof-cloudflare-version.mts",
256
256
  performanceReadiness: "scripts/ultramodern-performance-readiness.mts",
257
+ migrateStrictEffect: "scripts/migrate-strict-effect.mts",
257
258
  apiBoundaries: "scripts/check-ultramodern-api-boundaries.mts",
258
259
  skills: "scripts/bootstrap-agent-skills.mts"
259
260
  }
@@ -93,6 +93,8 @@ ${defaultAssetPrefixSource}
93
93
  // load remoteEntry.js and exposed chunks from the remote origin, not the host.
94
94
  const assetPrefix =
95
95
  configuredModernAssetPrefix || configuredUltramodernAssetPrefix || defaultAssetPrefix;
96
+ const buildCacheTarget = cloudflareDeployEnabled ? 'cloudflare' : 'web';
97
+ const buildCacheDirectory = \`node_modules/.cache/rspack-\${appId}-\${buildCacheTarget}\`;
96
98
 
97
99
  if (
98
100
  cloudflareDeployEnabled &&
@@ -139,6 +141,10 @@ ${bffConfig} ...(cloudflareDeployEnabled
139
141
  splitRouteChunks: true,
140
142
  },
141
143
  performance: {
144
+ buildCache: {
145
+ cacheDigest: [appId, buildCacheTarget],
146
+ cacheDirectory: buildCacheDirectory,
147
+ },
142
148
  rsdoctor: {
143
149
  disableClientServer: true,
144
150
  enabled: process.env['ULTRAMODERN_RSDOCTOR'] === 'true',
@@ -178,6 +178,7 @@ function createRootPackageJson(scope, packageSource, remotes = [], bridge) {
178
178
  'agents:refs:check': "node ./scripts/setup-agent-reference-repos.mts --check",
179
179
  'mf:types': "node ./scripts/assert-mf-types.mts",
180
180
  'performance:readiness': "node ./scripts/ultramodern-performance-readiness.mts",
181
+ 'migrate:strict-effect': "node ./scripts/migrate-strict-effect.mts",
181
182
  'contract:check': "node ./scripts/validate-ultramodern-workspace.mts",
182
183
  'api:check': "node ./scripts/check-ultramodern-api-boundaries.mts",
183
184
  'i18n:boundaries': "node ./scripts/check-ultramodern-i18n-boundaries.mts",
@@ -370,7 +371,7 @@ function createAppPackage(scope, app, packageSource, enableTailwind, remotes = [
370
371
  scripts: {
371
372
  dev: 'modern dev',
372
373
  build: app.exposes ? `ULTRAMODERN_ZEPHYR=false modern build && ${publicSurfaceBuildCommand} && node ${relativeRootFor(app.directory)}/scripts/assert-mf-types.mts` : `ULTRAMODERN_ZEPHYR=false modern build && ${publicSurfaceBuildCommand}`,
373
- 'cloudflare:build': `ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern build && ${publicSurfaceCloudflareBuildCommand} && ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy && ${publicSurfaceCloudflareOutputCommand}`,
374
+ 'cloudflare:build': `ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern build && ${publicSurfaceCloudflareBuildCommand} && ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy --skip-build && ${publicSurfaceCloudflareOutputCommand}`,
374
375
  'cloudflare:deploy': 'ULTRAMODERN_CLOUDFLARE_REQUIRE_PUBLIC_URLS=true pnpm run cloudflare:build && wrangler deploy --config .output/wrangler.json',
375
376
  'cloudflare:preview': 'pnpm run cloudflare:build && wrangler dev --config .output/wrangler.json',
376
377
  'cloudflare:proof': `node ${relativeRootFor(app.directory)}/scripts/proof-cloudflare-version.mts --app ${app.id}`,
@@ -8,12 +8,14 @@ const CLOUDFLARE_COMPATIBILITY_DATE = '2026-06-02';
8
8
  const TAILWIND_VERSION = '4.3.1';
9
9
  const TAILWIND_POSTCSS_VERSION = '4.3.1';
10
10
  const POSTCSS_VERSION = '8.5.15';
11
+ const EFFECT_VERSION = '4.0.0-beta.91';
12
+ const EFFECT_VITEST_VERSION = '4.0.0-beta.91';
11
13
  const EFFECT_TSGO_VERSION = '0.14.6';
12
14
  const TYPESCRIPT_STABLE_VERSION = '6.0.3';
13
- const TYPESCRIPT_NATIVE_PREVIEW_VERSION = '7.0.0-dev.20260624.1';
15
+ const TYPESCRIPT_NATIVE_PREVIEW_VERSION = '7.0.0-dev.20260628.1';
14
16
  const TYPESCRIPT_VERSION = TYPESCRIPT_STABLE_VERSION;
15
17
  const OXLINT_VERSION = '1.71.0';
16
- const OXFMT_VERSION = '0.55.0';
18
+ const OXFMT_VERSION = '0.56.0';
17
19
  const ULTRACITE_VERSION = '7.8.3';
18
20
  const LEFTHOOK_VERSION = '^2.1.9';
19
21
  const I18NEXT_VERSION = '26.3.1';
@@ -31,7 +33,9 @@ const ultramodernWorkspaceVersions = {
31
33
  tanstackRouter: TANSTACK_ROUTER_VERSION,
32
34
  tanstackRouterCore: TANSTACK_ROUTER_CORE_VERSION,
33
35
  moduleFederation: MODULE_FEDERATION_VERSION,
36
+ effect: EFFECT_VERSION,
37
+ effectVitest: EFFECT_VITEST_VERSION,
34
38
  tailwind: TAILWIND_VERSION,
35
39
  tailwindPostcss: TAILWIND_POSTCSS_VERSION
36
40
  };
37
- export { CLOUDFLARE_COMPATIBILITY_DATE, EFFECT_TSGO_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 };
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 };
@@ -162,6 +162,7 @@ function writeGeneratedWorkspaceScripts(targetDir, _scope, _enableTailwind, _rem
162
162
  writeWorkspaceOwnedMtsScript(targetDir, 'proof-cloudflare-version', createToolWrapperScript('cloudflare-proof'));
163
163
  writeFileReplacing(targetDir, "scripts/ultramodern-performance-readiness.config.mjs", createPerformanceReadinessConfigScript());
164
164
  writeWorkspaceOwnedMtsScript(targetDir, 'ultramodern-performance-readiness', createToolWrapperScript('performance-readiness'));
165
+ writeWorkspaceOwnedMtsScript(targetDir, 'migrate-strict-effect', createToolWrapperScript('migrate-strict-effect'));
165
166
  writeWorkspaceOwnedMtsScript(targetDir, 'ultramodern-typecheck', createToolWrapperScript('typecheck'));
166
167
  writeWorkspaceOwnedMtsScript(targetDir, 'bootstrap-agent-skills', createSkillsToolWrapperScript());
167
168
  migrateCopiedWorkspaceScriptToMts(targetDir, 'setup-agent-reference-repos');
@@ -14,7 +14,7 @@ import { runCodeSmithOverlays } from "./overlays.js";
14
14
  import { createAppMfTypesTsConfig, createAppPackage, createAppTsConfig, createRootPackageJson, createRootTsConfig, createSharedContractsIndex, createSharedPackage, createSharedPackageTsConfig, createTsConfigBase } from "./package-json.js";
15
15
  import { resolvePackageSource } from "./package-source.js";
16
16
  import { createPublicWebAppArtifacts } from "./public-surface.js";
17
- import { NODE_FETCH_VERSION, NODE_VERSION, PNPM_VERSION, TANSTACK_ROUTER_CORE_VERSION, TANSTACK_ROUTER_VERSION, TYPESCRIPT_VERSION } from "./versions.js";
17
+ import { EFFECT_VERSION, EFFECT_VITEST_VERSION, NODE_FETCH_VERSION, NODE_VERSION, PNPM_VERSION, TANSTACK_ROUTER_CORE_VERSION, TANSTACK_ROUTER_VERSION, TYPESCRIPT_VERSION } from "./versions.js";
18
18
  import { writeGeneratedWorkspaceScripts } from "./workspace-scripts.js";
19
19
  function writeApp(targetDir, scope, app, packageSource, enableTailwind, remotes = [], bridge) {
20
20
  const resolvedApp = 'shell' === app.kind ? createShellHost(remotes) : app;
@@ -130,6 +130,8 @@ function generateUltramodernWorkspace(options) {
130
130
  nodeVersion: NODE_VERSION,
131
131
  pnpmVersion: PNPM_VERSION,
132
132
  nodeFetchVersion: NODE_FETCH_VERSION,
133
+ effectVersion: EFFECT_VERSION,
134
+ effectVitestVersion: EFFECT_VITEST_VERSION,
133
135
  tanstackRouterCoreVersion: TANSTACK_ROUTER_CORE_VERSION,
134
136
  tanstackRouterVersion: TANSTACK_ROUTER_VERSION,
135
137
  typescriptVersion: TYPESCRIPT_VERSION,