@bleedingdev/modern-js-create 3.5.0-ultramodern.1 → 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.
- package/README.md +10 -6
- package/dist/cjs/ultramodern-tooling/commands.cjs +156 -3
- package/dist/cjs/ultramodern-workspace/package-json.cjs +1 -1
- package/dist/cjs/ultramodern-workspace/versions.cjs +4 -4
- package/dist/esm/ultramodern-tooling/commands.js +156 -3
- package/dist/esm/ultramodern-workspace/package-json.js +1 -1
- package/dist/esm/ultramodern-workspace/versions.js +4 -4
- package/dist/esm-node/ultramodern-tooling/commands.js +156 -3
- package/dist/esm-node/ultramodern-workspace/package-json.js +1 -1
- package/dist/esm-node/ultramodern-workspace/versions.js +4 -4
- package/dist/types/ultramodern-workspace/versions.d.ts +4 -4
- package/package.json +6 -6
- package/template-workspace/README.md.handlebars +8 -4
- package/template-workspace/pnpm-workspace.yaml.handlebars +5 -0
- package/templates/workspace-scripts/validate-ultramodern-workspace.mjs.handlebars +21 -0
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.
|
|
197
|
-
migrate-strict-effect --version 3.5.0-ultramodern.
|
|
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,16 +202,20 @@ pnpm build
|
|
|
202
202
|
```
|
|
203
203
|
|
|
204
204
|
The command updates `.modernjs/ultramodern.json`, root `modernjs.packageSource`,
|
|
205
|
-
generated Modern package aliases,
|
|
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
|
|
209
210
|
`api/effect`, `api/lambda`, `shared/effect`, and `src/effect` paths.
|
|
210
211
|
|
|
211
212
|
Generated strict Effect workspaces pin the compatible Effect cohort through
|
|
212
|
-
`pnpm-workspace.yaml` overrides: `effect@4.0.0-beta.
|
|
213
|
-
`@effect/vitest@4.0.0-beta.
|
|
214
|
-
|
|
213
|
+
`pnpm-workspace.yaml` overrides: `effect@4.0.0-beta.91` and
|
|
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
|
|
@@ -53,6 +53,7 @@ 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
55
|
const mf_validation_cjs_namespaceObject = require("../ultramodern-workspace/mf-validation.cjs");
|
|
56
|
+
const versions_cjs_namespaceObject = require("../ultramodern-workspace/versions.cjs");
|
|
56
57
|
const workspace_scripts_cjs_namespaceObject = require("../ultramodern-workspace/workspace-scripts.cjs");
|
|
57
58
|
const external_config_cjs_namespaceObject = require("./config.cjs");
|
|
58
59
|
const commands_dirname = external_node_path_default().dirname((0, external_node_url_namespaceObject.fileURLToPath)(__rslib_import_meta_url__));
|
|
@@ -198,6 +199,78 @@ function updateModernDependencies(packageJson, packageSource) {
|
|
|
198
199
|
}
|
|
199
200
|
return changed;
|
|
200
201
|
}
|
|
202
|
+
const generatedToolingDependencyPins = new Map([
|
|
203
|
+
[
|
|
204
|
+
'@effect/tsgo',
|
|
205
|
+
versions_cjs_namespaceObject.EFFECT_TSGO_VERSION
|
|
206
|
+
],
|
|
207
|
+
[
|
|
208
|
+
"@typescript/native-preview",
|
|
209
|
+
versions_cjs_namespaceObject.TYPESCRIPT_NATIVE_PREVIEW_VERSION
|
|
210
|
+
],
|
|
211
|
+
[
|
|
212
|
+
'oxfmt',
|
|
213
|
+
versions_cjs_namespaceObject.OXFMT_VERSION
|
|
214
|
+
],
|
|
215
|
+
[
|
|
216
|
+
'oxlint',
|
|
217
|
+
versions_cjs_namespaceObject.OXLINT_VERSION
|
|
218
|
+
],
|
|
219
|
+
[
|
|
220
|
+
'wrangler',
|
|
221
|
+
versions_cjs_namespaceObject.WRANGLER_VERSION
|
|
222
|
+
],
|
|
223
|
+
[
|
|
224
|
+
'zephyr-agent',
|
|
225
|
+
versions_cjs_namespaceObject.ZEPHYR_AGENT_VERSION
|
|
226
|
+
],
|
|
227
|
+
[
|
|
228
|
+
'zephyr-rspack-plugin',
|
|
229
|
+
versions_cjs_namespaceObject.ZEPHYR_RSPACK_PLUGIN_VERSION
|
|
230
|
+
]
|
|
231
|
+
]);
|
|
232
|
+
const strictEffectPackageVersionPolicyExclusions = [
|
|
233
|
+
`effect@${versions_cjs_namespaceObject.EFFECT_VERSION}`,
|
|
234
|
+
`@effect/opentelemetry@${versions_cjs_namespaceObject.EFFECT_VERSION}`
|
|
235
|
+
];
|
|
236
|
+
function updateGeneratedToolingDependencies(packageJson) {
|
|
237
|
+
let changed = false;
|
|
238
|
+
for (const section of [
|
|
239
|
+
'dependencies',
|
|
240
|
+
'devDependencies',
|
|
241
|
+
'peerDependencies',
|
|
242
|
+
'optionalDependencies'
|
|
243
|
+
]){
|
|
244
|
+
const dependencies = packageJson[section];
|
|
245
|
+
if (!(!dependencies || 'object' != typeof dependencies || Array.isArray(dependencies))) {
|
|
246
|
+
for (const [packageName, version] of generatedToolingDependencyPins)if (Object.prototype.hasOwnProperty.call(dependencies, packageName) && dependencies[packageName] !== version) {
|
|
247
|
+
dependencies[packageName] = version;
|
|
248
|
+
changed = true;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
return changed;
|
|
253
|
+
}
|
|
254
|
+
const cloudflareModernDeployCommand = 'ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy';
|
|
255
|
+
const cloudflareModernDeploySkipBuildCommand = `${cloudflareModernDeployCommand} --skip-build`;
|
|
256
|
+
const cloudflareWranglerDeployCommand = 'wrangler deploy --config .output/wrangler.json';
|
|
257
|
+
const cloudflareWranglerDeployInvalidSkipBuildCommand = `${cloudflareWranglerDeployCommand} --skip-build`;
|
|
258
|
+
function updateGeneratedPackageScripts(packageJson) {
|
|
259
|
+
const scripts = packageJson.scripts;
|
|
260
|
+
if (!scripts || 'object' != typeof scripts || Array.isArray(scripts)) return false;
|
|
261
|
+
let changed = false;
|
|
262
|
+
const cloudflareBuild = scripts['cloudflare:build'];
|
|
263
|
+
if ('string' == typeof cloudflareBuild && cloudflareBuild.includes(cloudflareModernDeployCommand) && !cloudflareBuild.includes(cloudflareModernDeploySkipBuildCommand)) {
|
|
264
|
+
scripts['cloudflare:build'] = cloudflareBuild.replace(cloudflareModernDeployCommand, cloudflareModernDeploySkipBuildCommand);
|
|
265
|
+
changed = true;
|
|
266
|
+
}
|
|
267
|
+
const cloudflareDeploy = scripts['cloudflare:deploy'];
|
|
268
|
+
if ('string' == typeof cloudflareDeploy && cloudflareDeploy.includes(cloudflareWranglerDeployInvalidSkipBuildCommand)) {
|
|
269
|
+
scripts['cloudflare:deploy'] = cloudflareDeploy.replace(cloudflareWranglerDeployInvalidSkipBuildCommand, cloudflareWranglerDeployCommand);
|
|
270
|
+
changed = true;
|
|
271
|
+
}
|
|
272
|
+
return changed;
|
|
273
|
+
}
|
|
201
274
|
function normalizeStrictEffectApiMetadata(value) {
|
|
202
275
|
const api = value.api;
|
|
203
276
|
if (!api || 'object' != typeof api || Array.isArray(api)) return false;
|
|
@@ -263,6 +336,80 @@ function normalizeStrictEffectApiMetadata(value) {
|
|
|
263
336
|
}
|
|
264
337
|
return changed;
|
|
265
338
|
}
|
|
339
|
+
function replaceYamlLine(source, pattern, replacement) {
|
|
340
|
+
const updated = source.replace(pattern, replacement);
|
|
341
|
+
return {
|
|
342
|
+
source: updated,
|
|
343
|
+
changed: updated !== source
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
function ensureYamlListItem(source, key, item) {
|
|
347
|
+
const itemLine = ` - '${item}'`;
|
|
348
|
+
const headerPattern = new RegExp(`^${key}:\\n(?:(?: - .+\\n)*)`, 'mu');
|
|
349
|
+
const header = source.match(headerPattern);
|
|
350
|
+
if (header) {
|
|
351
|
+
if (header[0].split('\n').includes(itemLine)) return {
|
|
352
|
+
source,
|
|
353
|
+
changed: false
|
|
354
|
+
};
|
|
355
|
+
return {
|
|
356
|
+
source: source.replace(headerPattern, `${header[0]}${itemLine}\n`),
|
|
357
|
+
changed: true
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
const block = `${key}:\n${itemLine}\n`;
|
|
361
|
+
const afterTrustPolicyIgnore = source.replace(/^(trustPolicyIgnoreAfter: .+\n)/mu, `$1${block}`);
|
|
362
|
+
if (afterTrustPolicyIgnore !== source) return {
|
|
363
|
+
source: afterTrustPolicyIgnore,
|
|
364
|
+
changed: true
|
|
365
|
+
};
|
|
366
|
+
return {
|
|
367
|
+
source: `${source.trimEnd()}\n${block}`,
|
|
368
|
+
changed: true
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
|
|
372
|
+
const workspaceFile = external_node_path_default().join(workspaceRoot, 'pnpm-workspace.yaml');
|
|
373
|
+
if (!external_node_fs_default().existsSync(workspaceFile)) return false;
|
|
374
|
+
let source = external_node_fs_default().readFileSync(workspaceFile, 'utf-8');
|
|
375
|
+
let changed = false;
|
|
376
|
+
const replacements = [
|
|
377
|
+
[
|
|
378
|
+
/^ {4}'@effect\/vitest>effect': .+$/mu,
|
|
379
|
+
` '@effect/vitest>effect': '${versions_cjs_namespaceObject.EFFECT_VERSION}'`
|
|
380
|
+
],
|
|
381
|
+
[
|
|
382
|
+
/^ {2}'@effect\/vitest': .+$/mu,
|
|
383
|
+
` '@effect/vitest': ${versions_cjs_namespaceObject.EFFECT_VITEST_VERSION}`
|
|
384
|
+
],
|
|
385
|
+
[
|
|
386
|
+
/^ {2}effect: .+$/mu,
|
|
387
|
+
` effect: ${versions_cjs_namespaceObject.EFFECT_VERSION}`
|
|
388
|
+
]
|
|
389
|
+
];
|
|
390
|
+
for (const [pattern, replacement] of replacements){
|
|
391
|
+
const result = replaceYamlLine(source, pattern, replacement);
|
|
392
|
+
source = result.source;
|
|
393
|
+
changed = result.changed || changed;
|
|
394
|
+
}
|
|
395
|
+
for (const item of strictEffectPackageVersionPolicyExclusions){
|
|
396
|
+
const packageName = item.slice(0, item.lastIndexOf('@'));
|
|
397
|
+
const escapedPackageName = packageName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
|
398
|
+
const currentVersion = replaceYamlLine(source, new RegExp(`^ {2}- '${escapedPackageName}@[^']+'$`, 'gmu'), ` - '${item}'`);
|
|
399
|
+
source = currentVersion.source;
|
|
400
|
+
changed = currentVersion.changed || changed;
|
|
401
|
+
for (const policyKey of [
|
|
402
|
+
'minimumReleaseAgeExclude',
|
|
403
|
+
'trustPolicyExclude'
|
|
404
|
+
]){
|
|
405
|
+
const policyExclude = ensureYamlListItem(source, policyKey, item);
|
|
406
|
+
source = policyExclude.source;
|
|
407
|
+
changed = policyExclude.changed || changed;
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
if (changed) external_node_fs_default().writeFileSync(workspaceFile, source, 'utf-8');
|
|
411
|
+
return changed;
|
|
412
|
+
}
|
|
266
413
|
function updateUltramodernConfig(workspaceRoot, packageSource) {
|
|
267
414
|
const configPath = external_node_path_default().join(workspaceRoot, '.modernjs/ultramodern.json');
|
|
268
415
|
const config = readJsonFile(configPath);
|
|
@@ -344,8 +491,9 @@ function runMigrateStrictEffect(args, context) {
|
|
|
344
491
|
modern-js-create ultramodern migrate-strict-effect --version <version> [--skip-install]
|
|
345
492
|
|
|
346
493
|
Updates generated UltraModern package-source metadata, Modern package aliases,
|
|
347
|
-
direct Effect API topology metadata,
|
|
348
|
-
|
|
494
|
+
framework-owned toolchain pins, direct Effect API topology metadata, strict
|
|
495
|
+
Effect pnpm overrides/trust policy, and the pnpm lockfile. Source code still
|
|
496
|
+
has to pass pnpm api:check and pnpm contract:check.
|
|
349
497
|
`);
|
|
350
498
|
return 0;
|
|
351
499
|
}
|
|
@@ -363,9 +511,14 @@ workspaces. Source code still has to pass pnpm api:check and pnpm contract:check
|
|
|
363
511
|
config: './.modernjs/ultramodern.json'
|
|
364
512
|
};
|
|
365
513
|
}
|
|
366
|
-
|
|
514
|
+
const modernDependenciesChanged = updateModernDependencies(packageJson, packageSource);
|
|
515
|
+
const toolingDependenciesChanged = updateGeneratedToolingDependencies(packageJson);
|
|
516
|
+
const generatedScriptsChanged = updateGeneratedPackageScripts(packageJson);
|
|
517
|
+
const changed = modernDependenciesChanged || toolingDependenciesChanged || generatedScriptsChanged;
|
|
518
|
+
if (changed) writeJsonFile(packageFile, packageJson);
|
|
367
519
|
else if ('package.json' === relativePackageFile) writeJsonFile(packageFile, packageJson);
|
|
368
520
|
}
|
|
521
|
+
updateGeneratedPnpmWorkspacePolicy(context.workspaceRoot);
|
|
369
522
|
if (!hasFlag(args, '--skip-install')) {
|
|
370
523
|
const status = runPnpmLockfileRefresh(context);
|
|
371
524
|
if (0 !== status) return status;
|
|
@@ -417,7 +417,7 @@ function createAppPackage(scope, app, packageSource, enableTailwind, remotes = [
|
|
|
417
417
|
scripts: {
|
|
418
418
|
dev: 'modern dev',
|
|
419
419
|
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}`,
|
|
420
|
+
'cloudflare:build': `ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern build && ${publicSurfaceCloudflareBuildCommand} && ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy --skip-build && ${publicSurfaceCloudflareOutputCommand}`,
|
|
421
421
|
'cloudflare:deploy': 'ULTRAMODERN_CLOUDFLARE_REQUIRE_PUBLIC_URLS=true pnpm run cloudflare:build && wrangler deploy --config .output/wrangler.json',
|
|
422
422
|
'cloudflare:preview': 'pnpm run cloudflare:build && wrangler dev --config .output/wrangler.json',
|
|
423
423
|
'cloudflare:proof': `node ${(0, external_naming_cjs_namespaceObject.relativeRootFor)(app.directory)}/scripts/proof-cloudflare-version.mts --app ${app.id}`,
|
|
@@ -37,14 +37,14 @@ 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.
|
|
41
|
-
const EFFECT_VITEST_VERSION = '4.0.0-beta.
|
|
40
|
+
const EFFECT_VERSION = '4.0.0-beta.91';
|
|
41
|
+
const EFFECT_VITEST_VERSION = '4.0.0-beta.91';
|
|
42
42
|
const EFFECT_TSGO_VERSION = '0.14.6';
|
|
43
43
|
const TYPESCRIPT_STABLE_VERSION = '6.0.3';
|
|
44
|
-
const TYPESCRIPT_NATIVE_PREVIEW_VERSION = '7.0.0-dev.
|
|
44
|
+
const TYPESCRIPT_NATIVE_PREVIEW_VERSION = '7.0.0-dev.20260628.1';
|
|
45
45
|
const TYPESCRIPT_VERSION = TYPESCRIPT_STABLE_VERSION;
|
|
46
46
|
const OXLINT_VERSION = '1.71.0';
|
|
47
|
-
const OXFMT_VERSION = '0.
|
|
47
|
+
const OXFMT_VERSION = '0.56.0';
|
|
48
48
|
const ULTRACITE_VERSION = '7.8.3';
|
|
49
49
|
const LEFTHOOK_VERSION = '^2.1.9';
|
|
50
50
|
const I18NEXT_VERSION = '26.3.1';
|
|
@@ -6,6 +6,7 @@ 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
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";
|
|
9
10
|
import { createWorkspaceValidationScript } from "../ultramodern-workspace/workspace-scripts.js";
|
|
10
11
|
import { readUltramodernConfig, workspaceAppsFromToolingConfig } from "./config.js";
|
|
11
12
|
const commands_dirname = node_path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -151,6 +152,78 @@ function updateModernDependencies(packageJson, packageSource) {
|
|
|
151
152
|
}
|
|
152
153
|
return changed;
|
|
153
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
|
+
}
|
|
154
227
|
function normalizeStrictEffectApiMetadata(value) {
|
|
155
228
|
const api = value.api;
|
|
156
229
|
if (!api || 'object' != typeof api || Array.isArray(api)) return false;
|
|
@@ -216,6 +289,80 @@ function normalizeStrictEffectApiMetadata(value) {
|
|
|
216
289
|
}
|
|
217
290
|
return changed;
|
|
218
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
|
+
}
|
|
219
366
|
function updateUltramodernConfig(workspaceRoot, packageSource) {
|
|
220
367
|
const configPath = node_path.join(workspaceRoot, '.modernjs/ultramodern.json');
|
|
221
368
|
const config = readJsonFile(configPath);
|
|
@@ -297,8 +444,9 @@ function runMigrateStrictEffect(args, context) {
|
|
|
297
444
|
modern-js-create ultramodern migrate-strict-effect --version <version> [--skip-install]
|
|
298
445
|
|
|
299
446
|
Updates generated UltraModern package-source metadata, Modern package aliases,
|
|
300
|
-
direct Effect API topology metadata,
|
|
301
|
-
|
|
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.
|
|
302
450
|
`);
|
|
303
451
|
return 0;
|
|
304
452
|
}
|
|
@@ -316,9 +464,14 @@ workspaces. Source code still has to pass pnpm api:check and pnpm contract:check
|
|
|
316
464
|
config: './.modernjs/ultramodern.json'
|
|
317
465
|
};
|
|
318
466
|
}
|
|
319
|
-
|
|
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);
|
|
320
472
|
else if ('package.json' === relativePackageFile) writeJsonFile(packageFile, packageJson);
|
|
321
473
|
}
|
|
474
|
+
updateGeneratedPnpmWorkspacePolicy(context.workspaceRoot);
|
|
322
475
|
if (!hasFlag(args, '--skip-install')) {
|
|
323
476
|
const status = runPnpmLockfileRefresh(context);
|
|
324
477
|
if (0 !== status) return status;
|
|
@@ -371,7 +371,7 @@ function createAppPackage(scope, app, packageSource, enableTailwind, remotes = [
|
|
|
371
371
|
scripts: {
|
|
372
372
|
dev: 'modern dev',
|
|
373
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}`,
|
|
374
|
-
'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}`,
|
|
375
375
|
'cloudflare:deploy': 'ULTRAMODERN_CLOUDFLARE_REQUIRE_PUBLIC_URLS=true pnpm run cloudflare:build && wrangler deploy --config .output/wrangler.json',
|
|
376
376
|
'cloudflare:preview': 'pnpm run cloudflare:build && wrangler dev --config .output/wrangler.json',
|
|
377
377
|
'cloudflare:proof': `node ${relativeRootFor(app.directory)}/scripts/proof-cloudflare-version.mts --app ${app.id}`,
|
|
@@ -8,14 +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.
|
|
12
|
-
const EFFECT_VITEST_VERSION = '4.0.0-beta.
|
|
11
|
+
const EFFECT_VERSION = '4.0.0-beta.91';
|
|
12
|
+
const EFFECT_VITEST_VERSION = '4.0.0-beta.91';
|
|
13
13
|
const EFFECT_TSGO_VERSION = '0.14.6';
|
|
14
14
|
const TYPESCRIPT_STABLE_VERSION = '6.0.3';
|
|
15
|
-
const TYPESCRIPT_NATIVE_PREVIEW_VERSION = '7.0.0-dev.
|
|
15
|
+
const TYPESCRIPT_NATIVE_PREVIEW_VERSION = '7.0.0-dev.20260628.1';
|
|
16
16
|
const TYPESCRIPT_VERSION = TYPESCRIPT_STABLE_VERSION;
|
|
17
17
|
const OXLINT_VERSION = '1.71.0';
|
|
18
|
-
const OXFMT_VERSION = '0.
|
|
18
|
+
const OXFMT_VERSION = '0.56.0';
|
|
19
19
|
const ULTRACITE_VERSION = '7.8.3';
|
|
20
20
|
const LEFTHOOK_VERSION = '^2.1.9';
|
|
21
21
|
const I18NEXT_VERSION = '26.3.1';
|
|
@@ -7,6 +7,7 @@ import { fileURLToPath } from "node:url";
|
|
|
7
7
|
import { resolveCreatePackageRoot } from "../create-package-root.js";
|
|
8
8
|
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";
|
|
9
9
|
import { validateModuleFederationTypes } from "../ultramodern-workspace/mf-validation.js";
|
|
10
|
+
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";
|
|
10
11
|
import { createWorkspaceValidationScript } from "../ultramodern-workspace/workspace-scripts.js";
|
|
11
12
|
import { readUltramodernConfig, workspaceAppsFromToolingConfig } from "./config.js";
|
|
12
13
|
const commands_dirname = node_path.dirname(fileURLToPath(import.meta.url));
|
|
@@ -152,6 +153,78 @@ function updateModernDependencies(packageJson, packageSource) {
|
|
|
152
153
|
}
|
|
153
154
|
return changed;
|
|
154
155
|
}
|
|
156
|
+
const generatedToolingDependencyPins = new Map([
|
|
157
|
+
[
|
|
158
|
+
'@effect/tsgo',
|
|
159
|
+
EFFECT_TSGO_VERSION
|
|
160
|
+
],
|
|
161
|
+
[
|
|
162
|
+
"@typescript/native-preview",
|
|
163
|
+
TYPESCRIPT_NATIVE_PREVIEW_VERSION
|
|
164
|
+
],
|
|
165
|
+
[
|
|
166
|
+
'oxfmt',
|
|
167
|
+
OXFMT_VERSION
|
|
168
|
+
],
|
|
169
|
+
[
|
|
170
|
+
'oxlint',
|
|
171
|
+
OXLINT_VERSION
|
|
172
|
+
],
|
|
173
|
+
[
|
|
174
|
+
'wrangler',
|
|
175
|
+
WRANGLER_VERSION
|
|
176
|
+
],
|
|
177
|
+
[
|
|
178
|
+
'zephyr-agent',
|
|
179
|
+
ZEPHYR_AGENT_VERSION
|
|
180
|
+
],
|
|
181
|
+
[
|
|
182
|
+
'zephyr-rspack-plugin',
|
|
183
|
+
ZEPHYR_RSPACK_PLUGIN_VERSION
|
|
184
|
+
]
|
|
185
|
+
]);
|
|
186
|
+
const strictEffectPackageVersionPolicyExclusions = [
|
|
187
|
+
`effect@${EFFECT_VERSION}`,
|
|
188
|
+
`@effect/opentelemetry@${EFFECT_VERSION}`
|
|
189
|
+
];
|
|
190
|
+
function updateGeneratedToolingDependencies(packageJson) {
|
|
191
|
+
let changed = false;
|
|
192
|
+
for (const section of [
|
|
193
|
+
'dependencies',
|
|
194
|
+
'devDependencies',
|
|
195
|
+
'peerDependencies',
|
|
196
|
+
'optionalDependencies'
|
|
197
|
+
]){
|
|
198
|
+
const dependencies = packageJson[section];
|
|
199
|
+
if (!(!dependencies || 'object' != typeof dependencies || Array.isArray(dependencies))) {
|
|
200
|
+
for (const [packageName, version] of generatedToolingDependencyPins)if (Object.prototype.hasOwnProperty.call(dependencies, packageName) && dependencies[packageName] !== version) {
|
|
201
|
+
dependencies[packageName] = version;
|
|
202
|
+
changed = true;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
return changed;
|
|
207
|
+
}
|
|
208
|
+
const cloudflareModernDeployCommand = 'ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy';
|
|
209
|
+
const cloudflareModernDeploySkipBuildCommand = `${cloudflareModernDeployCommand} --skip-build`;
|
|
210
|
+
const cloudflareWranglerDeployCommand = 'wrangler deploy --config .output/wrangler.json';
|
|
211
|
+
const cloudflareWranglerDeployInvalidSkipBuildCommand = `${cloudflareWranglerDeployCommand} --skip-build`;
|
|
212
|
+
function updateGeneratedPackageScripts(packageJson) {
|
|
213
|
+
const scripts = packageJson.scripts;
|
|
214
|
+
if (!scripts || 'object' != typeof scripts || Array.isArray(scripts)) return false;
|
|
215
|
+
let changed = false;
|
|
216
|
+
const cloudflareBuild = scripts['cloudflare:build'];
|
|
217
|
+
if ('string' == typeof cloudflareBuild && cloudflareBuild.includes(cloudflareModernDeployCommand) && !cloudflareBuild.includes(cloudflareModernDeploySkipBuildCommand)) {
|
|
218
|
+
scripts['cloudflare:build'] = cloudflareBuild.replace(cloudflareModernDeployCommand, cloudflareModernDeploySkipBuildCommand);
|
|
219
|
+
changed = true;
|
|
220
|
+
}
|
|
221
|
+
const cloudflareDeploy = scripts['cloudflare:deploy'];
|
|
222
|
+
if ('string' == typeof cloudflareDeploy && cloudflareDeploy.includes(cloudflareWranglerDeployInvalidSkipBuildCommand)) {
|
|
223
|
+
scripts['cloudflare:deploy'] = cloudflareDeploy.replace(cloudflareWranglerDeployInvalidSkipBuildCommand, cloudflareWranglerDeployCommand);
|
|
224
|
+
changed = true;
|
|
225
|
+
}
|
|
226
|
+
return changed;
|
|
227
|
+
}
|
|
155
228
|
function normalizeStrictEffectApiMetadata(value) {
|
|
156
229
|
const api = value.api;
|
|
157
230
|
if (!api || 'object' != typeof api || Array.isArray(api)) return false;
|
|
@@ -217,6 +290,80 @@ function normalizeStrictEffectApiMetadata(value) {
|
|
|
217
290
|
}
|
|
218
291
|
return changed;
|
|
219
292
|
}
|
|
293
|
+
function replaceYamlLine(source, pattern, replacement) {
|
|
294
|
+
const updated = source.replace(pattern, replacement);
|
|
295
|
+
return {
|
|
296
|
+
source: updated,
|
|
297
|
+
changed: updated !== source
|
|
298
|
+
};
|
|
299
|
+
}
|
|
300
|
+
function ensureYamlListItem(source, key, item) {
|
|
301
|
+
const itemLine = ` - '${item}'`;
|
|
302
|
+
const headerPattern = new RegExp(`^${key}:\\n(?:(?: - .+\\n)*)`, 'mu');
|
|
303
|
+
const header = source.match(headerPattern);
|
|
304
|
+
if (header) {
|
|
305
|
+
if (header[0].split('\n').includes(itemLine)) return {
|
|
306
|
+
source,
|
|
307
|
+
changed: false
|
|
308
|
+
};
|
|
309
|
+
return {
|
|
310
|
+
source: source.replace(headerPattern, `${header[0]}${itemLine}\n`),
|
|
311
|
+
changed: true
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
const block = `${key}:\n${itemLine}\n`;
|
|
315
|
+
const afterTrustPolicyIgnore = source.replace(/^(trustPolicyIgnoreAfter: .+\n)/mu, `$1${block}`);
|
|
316
|
+
if (afterTrustPolicyIgnore !== source) return {
|
|
317
|
+
source: afterTrustPolicyIgnore,
|
|
318
|
+
changed: true
|
|
319
|
+
};
|
|
320
|
+
return {
|
|
321
|
+
source: `${source.trimEnd()}\n${block}`,
|
|
322
|
+
changed: true
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
|
|
326
|
+
const workspaceFile = node_path.join(workspaceRoot, 'pnpm-workspace.yaml');
|
|
327
|
+
if (!node_fs.existsSync(workspaceFile)) return false;
|
|
328
|
+
let source = node_fs.readFileSync(workspaceFile, 'utf-8');
|
|
329
|
+
let changed = false;
|
|
330
|
+
const replacements = [
|
|
331
|
+
[
|
|
332
|
+
/^ {4}'@effect\/vitest>effect': .+$/mu,
|
|
333
|
+
` '@effect/vitest>effect': '${EFFECT_VERSION}'`
|
|
334
|
+
],
|
|
335
|
+
[
|
|
336
|
+
/^ {2}'@effect\/vitest': .+$/mu,
|
|
337
|
+
` '@effect/vitest': ${EFFECT_VITEST_VERSION}`
|
|
338
|
+
],
|
|
339
|
+
[
|
|
340
|
+
/^ {2}effect: .+$/mu,
|
|
341
|
+
` effect: ${EFFECT_VERSION}`
|
|
342
|
+
]
|
|
343
|
+
];
|
|
344
|
+
for (const [pattern, replacement] of replacements){
|
|
345
|
+
const result = replaceYamlLine(source, pattern, replacement);
|
|
346
|
+
source = result.source;
|
|
347
|
+
changed = result.changed || changed;
|
|
348
|
+
}
|
|
349
|
+
for (const item of strictEffectPackageVersionPolicyExclusions){
|
|
350
|
+
const packageName = item.slice(0, item.lastIndexOf('@'));
|
|
351
|
+
const escapedPackageName = packageName.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&');
|
|
352
|
+
const currentVersion = replaceYamlLine(source, new RegExp(`^ {2}- '${escapedPackageName}@[^']+'$`, 'gmu'), ` - '${item}'`);
|
|
353
|
+
source = currentVersion.source;
|
|
354
|
+
changed = currentVersion.changed || changed;
|
|
355
|
+
for (const policyKey of [
|
|
356
|
+
'minimumReleaseAgeExclude',
|
|
357
|
+
'trustPolicyExclude'
|
|
358
|
+
]){
|
|
359
|
+
const policyExclude = ensureYamlListItem(source, policyKey, item);
|
|
360
|
+
source = policyExclude.source;
|
|
361
|
+
changed = policyExclude.changed || changed;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
if (changed) node_fs.writeFileSync(workspaceFile, source, 'utf-8');
|
|
365
|
+
return changed;
|
|
366
|
+
}
|
|
220
367
|
function updateUltramodernConfig(workspaceRoot, packageSource) {
|
|
221
368
|
const configPath = node_path.join(workspaceRoot, '.modernjs/ultramodern.json');
|
|
222
369
|
const config = readJsonFile(configPath);
|
|
@@ -298,8 +445,9 @@ function runMigrateStrictEffect(args, context) {
|
|
|
298
445
|
modern-js-create ultramodern migrate-strict-effect --version <version> [--skip-install]
|
|
299
446
|
|
|
300
447
|
Updates generated UltraModern package-source metadata, Modern package aliases,
|
|
301
|
-
direct Effect API topology metadata,
|
|
302
|
-
|
|
448
|
+
framework-owned toolchain pins, direct Effect API topology metadata, strict
|
|
449
|
+
Effect pnpm overrides/trust policy, and the pnpm lockfile. Source code still
|
|
450
|
+
has to pass pnpm api:check and pnpm contract:check.
|
|
303
451
|
`);
|
|
304
452
|
return 0;
|
|
305
453
|
}
|
|
@@ -317,9 +465,14 @@ workspaces. Source code still has to pass pnpm api:check and pnpm contract:check
|
|
|
317
465
|
config: './.modernjs/ultramodern.json'
|
|
318
466
|
};
|
|
319
467
|
}
|
|
320
|
-
|
|
468
|
+
const modernDependenciesChanged = updateModernDependencies(packageJson, packageSource);
|
|
469
|
+
const toolingDependenciesChanged = updateGeneratedToolingDependencies(packageJson);
|
|
470
|
+
const generatedScriptsChanged = updateGeneratedPackageScripts(packageJson);
|
|
471
|
+
const changed = modernDependenciesChanged || toolingDependenciesChanged || generatedScriptsChanged;
|
|
472
|
+
if (changed) writeJsonFile(packageFile, packageJson);
|
|
321
473
|
else if ('package.json' === relativePackageFile) writeJsonFile(packageFile, packageJson);
|
|
322
474
|
}
|
|
475
|
+
updateGeneratedPnpmWorkspacePolicy(context.workspaceRoot);
|
|
323
476
|
if (!hasFlag(args, '--skip-install')) {
|
|
324
477
|
const status = runPnpmLockfileRefresh(context);
|
|
325
478
|
if (0 !== status) return status;
|
|
@@ -372,7 +372,7 @@ function createAppPackage(scope, app, packageSource, enableTailwind, remotes = [
|
|
|
372
372
|
scripts: {
|
|
373
373
|
dev: 'modern dev',
|
|
374
374
|
build: app.exposes ? `ULTRAMODERN_ZEPHYR=false modern build && ${publicSurfaceBuildCommand} && node ${relativeRootFor(app.directory)}/scripts/assert-mf-types.mts` : `ULTRAMODERN_ZEPHYR=false modern build && ${publicSurfaceBuildCommand}`,
|
|
375
|
-
'cloudflare:build': `ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern build && ${publicSurfaceCloudflareBuildCommand} && ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy && ${publicSurfaceCloudflareOutputCommand}`,
|
|
375
|
+
'cloudflare:build': `ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern build && ${publicSurfaceCloudflareBuildCommand} && ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy --skip-build && ${publicSurfaceCloudflareOutputCommand}`,
|
|
376
376
|
'cloudflare:deploy': 'ULTRAMODERN_CLOUDFLARE_REQUIRE_PUBLIC_URLS=true pnpm run cloudflare:build && wrangler deploy --config .output/wrangler.json',
|
|
377
377
|
'cloudflare:preview': 'pnpm run cloudflare:build && wrangler dev --config .output/wrangler.json',
|
|
378
378
|
'cloudflare:proof': `node ${relativeRootFor(app.directory)}/scripts/proof-cloudflare-version.mts --app ${app.id}`,
|
|
@@ -9,14 +9,14 @@ const CLOUDFLARE_COMPATIBILITY_DATE = '2026-06-02';
|
|
|
9
9
|
const TAILWIND_VERSION = '4.3.1';
|
|
10
10
|
const TAILWIND_POSTCSS_VERSION = '4.3.1';
|
|
11
11
|
const POSTCSS_VERSION = '8.5.15';
|
|
12
|
-
const EFFECT_VERSION = '4.0.0-beta.
|
|
13
|
-
const EFFECT_VITEST_VERSION = '4.0.0-beta.
|
|
12
|
+
const EFFECT_VERSION = '4.0.0-beta.91';
|
|
13
|
+
const EFFECT_VITEST_VERSION = '4.0.0-beta.91';
|
|
14
14
|
const EFFECT_TSGO_VERSION = '0.14.6';
|
|
15
15
|
const TYPESCRIPT_STABLE_VERSION = '6.0.3';
|
|
16
|
-
const TYPESCRIPT_NATIVE_PREVIEW_VERSION = '7.0.0-dev.
|
|
16
|
+
const TYPESCRIPT_NATIVE_PREVIEW_VERSION = '7.0.0-dev.20260628.1';
|
|
17
17
|
const TYPESCRIPT_VERSION = TYPESCRIPT_STABLE_VERSION;
|
|
18
18
|
const OXLINT_VERSION = '1.71.0';
|
|
19
|
-
const OXFMT_VERSION = '0.
|
|
19
|
+
const OXFMT_VERSION = '0.56.0';
|
|
20
20
|
const ULTRACITE_VERSION = '7.8.3';
|
|
21
21
|
const LEFTHOOK_VERSION = '^2.1.9';
|
|
22
22
|
const I18NEXT_VERSION = '26.3.1';
|
|
@@ -13,14 +13,14 @@ export declare const CLOUDFLARE_COMPATIBILITY_DATE = "2026-06-02";
|
|
|
13
13
|
export declare const TAILWIND_VERSION = "4.3.1";
|
|
14
14
|
export declare const TAILWIND_POSTCSS_VERSION = "4.3.1";
|
|
15
15
|
export declare const POSTCSS_VERSION = "8.5.15";
|
|
16
|
-
export declare const EFFECT_VERSION = "4.0.0-beta.
|
|
17
|
-
export declare const EFFECT_VITEST_VERSION = "4.0.0-beta.
|
|
16
|
+
export declare const EFFECT_VERSION = "4.0.0-beta.91";
|
|
17
|
+
export declare const EFFECT_VITEST_VERSION = "4.0.0-beta.91";
|
|
18
18
|
export declare const EFFECT_TSGO_VERSION = "0.14.6";
|
|
19
19
|
export declare const TYPESCRIPT_STABLE_VERSION = "6.0.3";
|
|
20
|
-
export declare const TYPESCRIPT_NATIVE_PREVIEW_VERSION = "7.0.0-dev.
|
|
20
|
+
export declare const TYPESCRIPT_NATIVE_PREVIEW_VERSION = "7.0.0-dev.20260628.1";
|
|
21
21
|
export declare const TYPESCRIPT_VERSION = "6.0.3";
|
|
22
22
|
export declare const OXLINT_VERSION = "1.71.0";
|
|
23
|
-
export declare const OXFMT_VERSION = "0.
|
|
23
|
+
export declare const OXFMT_VERSION = "0.56.0";
|
|
24
24
|
export declare const ULTRACITE_VERSION = "7.8.3";
|
|
25
25
|
export declare const LEFTHOOK_VERSION = "^2.1.9";
|
|
26
26
|
export declare const I18NEXT_VERSION = "26.3.1";
|
package/package.json
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"engines": {
|
|
22
22
|
"node": ">=20"
|
|
23
23
|
},
|
|
24
|
-
"version": "3.5.0-ultramodern.
|
|
24
|
+
"version": "3.5.0-ultramodern.10",
|
|
25
25
|
"types": "./dist/types/index.d.ts",
|
|
26
26
|
"main": "./dist/esm-node/index.js",
|
|
27
27
|
"bin": {
|
|
@@ -75,14 +75,14 @@
|
|
|
75
75
|
],
|
|
76
76
|
"dependencies": {
|
|
77
77
|
"@modern-js/codesmith": "2.6.9",
|
|
78
|
-
"oxfmt": "0.
|
|
78
|
+
"oxfmt": "0.56.0",
|
|
79
79
|
"ultracite": "7.8.3",
|
|
80
|
-
"@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.5.0-ultramodern.
|
|
80
|
+
"@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.5.0-ultramodern.10"
|
|
81
81
|
},
|
|
82
82
|
"devDependencies": {
|
|
83
|
-
"@rslib/core": "0.23.
|
|
83
|
+
"@rslib/core": "0.23.1",
|
|
84
84
|
"@types/node": "^26.0.1",
|
|
85
|
-
"@typescript/native-preview": "7.0.0-dev.
|
|
85
|
+
"@typescript/native-preview": "7.0.0-dev.20260628.1",
|
|
86
86
|
"tsx": "^4.22.4",
|
|
87
87
|
"typescript": "^6.0.3",
|
|
88
88
|
"@scripts/rstest-config": "2.66.0"
|
|
@@ -99,6 +99,6 @@
|
|
|
99
99
|
"test": "rm -rf dist && rslib build -c rslibconfig.mts && rstest --passWithNoTests"
|
|
100
100
|
},
|
|
101
101
|
"ultramodern": {
|
|
102
|
-
"frameworkVersion": "3.5.0-ultramodern.
|
|
102
|
+
"frameworkVersion": "3.5.0-ultramodern.10"
|
|
103
103
|
}
|
|
104
104
|
}
|
|
@@ -169,19 +169,23 @@ in API modules.
|
|
|
169
169
|
Generated pnpm overrides pin the framework-compatible Effect cohort. Keep
|
|
170
170
|
`effect` and `@effect/vitest` aligned with `pnpm-workspace.yaml`; do not add
|
|
171
171
|
new direct package-level Effect versions unless the whole UltraModern cohort is
|
|
172
|
-
upgraded.
|
|
172
|
+
upgraded. The generated pnpm policy intentionally excludes the matching
|
|
173
|
+
`effect` and `@effect/opentelemetry` cohort versions from the
|
|
174
|
+
minimum-release-age and no-downgrade checks while Effect's beta publishes move
|
|
175
|
+
from trusted-publisher metadata to provenance attestations.
|
|
173
176
|
|
|
174
177
|
For older generated workspaces, run the framework migration command first:
|
|
175
178
|
|
|
176
179
|
```bash
|
|
177
|
-
pnpm dlx @bleedingdev/modern-js-create@3.5.0-ultramodern.
|
|
178
|
-
migrate-strict-effect --version 3.5.0-ultramodern.
|
|
180
|
+
pnpm dlx @bleedingdev/modern-js-create@3.5.0-ultramodern.10 ultramodern \
|
|
181
|
+
migrate-strict-effect --version 3.5.0-ultramodern.10
|
|
179
182
|
pnpm api:check
|
|
180
183
|
pnpm contract:check
|
|
181
184
|
```
|
|
182
185
|
|
|
183
186
|
The command updates generated package-source metadata, Modern package aliases,
|
|
184
|
-
direct API topology metadata,
|
|
187
|
+
framework-owned toolchain pins, direct API topology metadata, strict Effect pnpm
|
|
188
|
+
overrides/trust policy, and the lockfile. Remaining failures are source
|
|
185
189
|
migration work; fix the owning API files instead of adding compatibility shims.
|
|
186
190
|
|
|
187
191
|
## Troubleshooting
|
|
@@ -8,6 +8,8 @@ minimumReleaseAgeStrict: true
|
|
|
8
8
|
minimumReleaseAgeIgnoreMissingTime: false
|
|
9
9
|
minimumReleaseAgeExclude:
|
|
10
10
|
- '@bleedingdev/modern-js-*'
|
|
11
|
+
- 'effect@{{effectVersion}}'
|
|
12
|
+
- '@effect/opentelemetry@{{effectVersion}}'
|
|
11
13
|
- '@tanstack/react-router'
|
|
12
14
|
- '@tanstack/router-core'
|
|
13
15
|
- 'typescript'
|
|
@@ -24,6 +26,9 @@ minimumReleaseAgeExclude:
|
|
|
24
26
|
- 'ts-checker-rspack-plugin'
|
|
25
27
|
trustPolicy: no-downgrade
|
|
26
28
|
trustPolicyIgnoreAfter: 1440
|
|
29
|
+
trustPolicyExclude:
|
|
30
|
+
- 'effect@{{effectVersion}}'
|
|
31
|
+
- '@effect/opentelemetry@{{effectVersion}}'
|
|
27
32
|
blockExoticSubdeps: true
|
|
28
33
|
engineStrict: true
|
|
29
34
|
pmOnFail: error
|
|
@@ -1349,6 +1349,22 @@ const extractAssetPrefixExpression = modernConfig => {
|
|
|
1349
1349
|
assert(match?.groups?.expression, 'modern.config.ts must assign assetPrefix');
|
|
1350
1350
|
return match.groups.expression;
|
|
1351
1351
|
};
|
|
1352
|
+
const assertBuildCacheBase = (appId, modernConfig) => {
|
|
1353
|
+
assert(
|
|
1354
|
+
modernConfig.includes("const buildCacheTarget = cloudflareDeployEnabled ? 'cloudflare' : 'web';") &&
|
|
1355
|
+
modernConfig.includes('const buildCacheDirectory = `node_modules/.cache/rspack-${appId}-${buildCacheTarget}`;') &&
|
|
1356
|
+
modernConfig.includes('cacheDirectory: buildCacheDirectory,'),
|
|
1357
|
+
`${appId} must provide a per-app/per-target Rspack cache base directory`,
|
|
1358
|
+
);
|
|
1359
|
+
};
|
|
1360
|
+
const assertCloudflareBuildSkipsDeployRebuild = (appId, packageJson) => {
|
|
1361
|
+
assert(
|
|
1362
|
+
packageJson.scripts?.['cloudflare:build']?.includes(
|
|
1363
|
+
'ULTRAMODERN_ZEPHYR=false MODERNJS_DEPLOY=cloudflare modern deploy --skip-build',
|
|
1364
|
+
),
|
|
1365
|
+
`${appId} cloudflare:build must deploy with --skip-build after the explicit Cloudflare build`,
|
|
1366
|
+
);
|
|
1367
|
+
};
|
|
1352
1368
|
const stripYamlInlineComment = value => {
|
|
1353
1369
|
let quote = undefined;
|
|
1354
1370
|
for (let index = 0; index < value.length; index += 1) {
|
|
@@ -1771,6 +1787,9 @@ assert(shellPackage.dependencies?.['@modern-js/plugin-bff'] === expectedModernPa
|
|
|
1771
1787
|
assert(shellPackage.dependencies?.['@modern-js/plugin-i18n'] === expectedModernPackageSpecifier('@modern-js/plugin-i18n'), 'Shell plugin-i18n dependency must match package source metadata');
|
|
1772
1788
|
assert(shellPackage.dependencies?.['@modern-js/plugin-tanstack'] === expectedModernPackageSpecifier('@modern-js/plugin-tanstack'), 'Shell plugin-tanstack dependency must match package source metadata');
|
|
1773
1789
|
assert(shellPackage.dependencies?.['@modern-js/runtime'] === expectedModernPackageSpecifier('@modern-js/runtime'), 'Shell runtime dependency must match package source metadata');
|
|
1790
|
+
assert(shellPackage.scripts?.['cloudflare:deploy'] === 'ULTRAMODERN_CLOUDFLARE_REQUIRE_PUBLIC_URLS=true pnpm run cloudflare:build && wrangler deploy --config .output/wrangler.json', 'Shell must expose cloudflare:deploy');
|
|
1791
|
+
assertBuildCacheBase('shell-super-app', shellModernConfig);
|
|
1792
|
+
assertCloudflareBuildSkipsDeployRebuild('shell-super-app', shellPackage);
|
|
1774
1793
|
const shellContract = generatedContract.apps?.find(app => app.id === 'shell-super-app');
|
|
1775
1794
|
assert(shellContract?.deploy?.cloudflare?.workerName === expectedWorkerName('shell-super-app'), 'Shell Cloudflare workerName is incorrect');
|
|
1776
1795
|
assert(shellContract?.deploy?.cloudflare?.publicUrlEnv === 'ULTRAMODERN_PUBLIC_URL_SHELL_SUPER_APP', 'Shell Cloudflare public URL env is incorrect');
|
|
@@ -1847,6 +1866,8 @@ for (const vertical of fullStackVerticals) {
|
|
|
1847
1866
|
assert(routeMetadata.includes("authoring: 'colocated-route-meta'"), `${vertical.id} route metadata manifest must advertise colocated authoring`);
|
|
1848
1867
|
assert(packageJson.name === vertical.packageName, `${vertical.id} package name is incorrect`);
|
|
1849
1868
|
assert(packageJson.scripts?.['cloudflare:deploy'] === 'ULTRAMODERN_CLOUDFLARE_REQUIRE_PUBLIC_URLS=true pnpm run cloudflare:build && wrangler deploy --config .output/wrangler.json', `${vertical.id} must expose cloudflare:deploy`);
|
|
1869
|
+
assertBuildCacheBase(vertical.id, modernConfig);
|
|
1870
|
+
assertCloudflareBuildSkipsDeployRebuild(vertical.id, packageJson);
|
|
1850
1871
|
assert(packageJson.scripts?.['cloudflare:proof']?.includes(`--app ${vertical.id}`), `${vertical.id} must expose cloudflare:proof`);
|
|
1851
1872
|
assert(packageJson.devDependencies?.['@modern-js/app-tools'] === expectedModernPackageSpecifier('@modern-js/app-tools'), `${vertical.id} app-tools dependency must match package source metadata`);
|
|
1852
1873
|
assert(packageJson.dependencies?.['@modern-js/plugin-bff'] === expectedModernPackageSpecifier('@modern-js/plugin-bff'), `${vertical.id} plugin-bff dependency must match package source metadata`);
|