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

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 CHANGED
@@ -193,8 +193,8 @@ For strict Effect API migrations, update generated package metadata and Modern
193
193
  package aliases through the framework command before hand-editing app code:
194
194
 
195
195
  ```bash
196
- pnpm dlx @bleedingdev/modern-js-create@3.5.0-ultramodern.2 ultramodern \
197
- migrate-strict-effect --version 3.5.0-ultramodern.2
196
+ pnpm dlx @bleedingdev/modern-js-create@3.5.0-ultramodern.3 ultramodern \
197
+ migrate-strict-effect --version 3.5.0-ultramodern.3
198
198
  pnpm api:check
199
199
  pnpm contract:check
200
200
  pnpm check
@@ -202,7 +202,8 @@ pnpm build
202
202
  ```
203
203
 
204
204
  The command updates `.modernjs/ultramodern.json`, root `modernjs.packageSource`,
205
- generated Modern package aliases, old direct topology metadata, and the pnpm
205
+ generated Modern package aliases, framework-owned toolchain pins, old direct
206
+ topology metadata, strict Effect pnpm overrides/trust policy, and the pnpm
206
207
  lockfile. It does not invent compatibility shims or move business code behind
207
208
  your back. If `pnpm api:check` still fails, migrate the source to
208
209
  `shared/api.ts`, `api/index.ts`, and `src/api/*-client.ts` and delete
@@ -210,8 +211,10 @@ your back. If `pnpm api:check` still fails, migrate the source to
210
211
 
211
212
  Generated strict Effect workspaces pin the compatible Effect cohort through
212
213
  `pnpm-workspace.yaml` overrides: `effect@4.0.0-beta.91` and
213
- `@effect/vitest@4.0.0-beta.91`. Do not override those in app packages; update
214
- the framework cohort when the runtime moves.
214
+ `@effect/vitest@4.0.0-beta.91`. The generated pnpm policy also excludes the
215
+ known `@effect/opentelemetry@4.0.0-beta.91` trusted-publisher to provenance
216
+ transition from no-downgrade checks. Do not override those in app packages;
217
+ update the framework cohort when the runtime moves.
215
218
 
216
219
  Use `--ultramodern-package-source=install` for published cohort proof and pin a
217
220
  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,54 @@ 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
+ function updateGeneratedToolingDependencies(packageJson) {
233
+ let changed = false;
234
+ for (const section of [
235
+ 'dependencies',
236
+ 'devDependencies',
237
+ 'peerDependencies',
238
+ 'optionalDependencies'
239
+ ]){
240
+ const dependencies = packageJson[section];
241
+ if (!(!dependencies || 'object' != typeof dependencies || Array.isArray(dependencies))) {
242
+ for (const [packageName, version] of generatedToolingDependencyPins)if (Object.prototype.hasOwnProperty.call(dependencies, packageName) && dependencies[packageName] !== version) {
243
+ dependencies[packageName] = version;
244
+ changed = true;
245
+ }
246
+ }
247
+ }
248
+ return changed;
249
+ }
201
250
  function normalizeStrictEffectApiMetadata(value) {
202
251
  const api = value.api;
203
252
  if (!api || 'object' != typeof api || Array.isArray(api)) return false;
@@ -263,6 +312,71 @@ function normalizeStrictEffectApiMetadata(value) {
263
312
  }
264
313
  return changed;
265
314
  }
315
+ function replaceYamlLine(source, pattern, replacement) {
316
+ const updated = source.replace(pattern, replacement);
317
+ return {
318
+ source: updated,
319
+ changed: updated !== source
320
+ };
321
+ }
322
+ function ensureYamlListItem(source, key, item) {
323
+ const itemLine = ` - '${item}'`;
324
+ const headerPattern = new RegExp(`^${key}:\\n(?:(?: - .+\\n)*)`, 'mu');
325
+ const existingItemPattern = new RegExp(`^ - '${item.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&')}'$`, 'mu');
326
+ if (existingItemPattern.test(source)) return {
327
+ source,
328
+ changed: false
329
+ };
330
+ const header = source.match(headerPattern);
331
+ if (header) return {
332
+ source: source.replace(headerPattern, `${header[0]}${itemLine}\n`),
333
+ changed: true
334
+ };
335
+ const block = `${key}:\n${itemLine}\n`;
336
+ const afterTrustPolicyIgnore = source.replace(/^(trustPolicyIgnoreAfter: .+\n)/mu, `$1${block}`);
337
+ if (afterTrustPolicyIgnore !== source) return {
338
+ source: afterTrustPolicyIgnore,
339
+ changed: true
340
+ };
341
+ return {
342
+ source: `${source.trimEnd()}\n${block}`,
343
+ changed: true
344
+ };
345
+ }
346
+ function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
347
+ const workspaceFile = external_node_path_default().join(workspaceRoot, 'pnpm-workspace.yaml');
348
+ if (!external_node_fs_default().existsSync(workspaceFile)) return false;
349
+ let source = external_node_fs_default().readFileSync(workspaceFile, 'utf-8');
350
+ let changed = false;
351
+ const replacements = [
352
+ [
353
+ /^ {4}'@effect\/vitest>effect': .+$/mu,
354
+ ` '@effect/vitest>effect': '${versions_cjs_namespaceObject.EFFECT_VERSION}'`
355
+ ],
356
+ [
357
+ /^ {2}'@effect\/vitest': .+$/mu,
358
+ ` '@effect/vitest': ${versions_cjs_namespaceObject.EFFECT_VITEST_VERSION}`
359
+ ],
360
+ [
361
+ /^ {2}effect: .+$/mu,
362
+ ` effect: ${versions_cjs_namespaceObject.EFFECT_VERSION}`
363
+ ],
364
+ [
365
+ /^ {2}- '@effect\/opentelemetry@[^']+'$/mu,
366
+ ` - '@effect/opentelemetry@${versions_cjs_namespaceObject.EFFECT_VERSION}'`
367
+ ]
368
+ ];
369
+ for (const [pattern, replacement] of replacements){
370
+ const result = replaceYamlLine(source, pattern, replacement);
371
+ source = result.source;
372
+ changed = result.changed || changed;
373
+ }
374
+ const trustPolicyExclude = ensureYamlListItem(source, 'trustPolicyExclude', `@effect/opentelemetry@${versions_cjs_namespaceObject.EFFECT_VERSION}`);
375
+ source = trustPolicyExclude.source;
376
+ changed = trustPolicyExclude.changed || changed;
377
+ if (changed) external_node_fs_default().writeFileSync(workspaceFile, source, 'utf-8');
378
+ return changed;
379
+ }
266
380
  function updateUltramodernConfig(workspaceRoot, packageSource) {
267
381
  const configPath = external_node_path_default().join(workspaceRoot, '.modernjs/ultramodern.json');
268
382
  const config = readJsonFile(configPath);
@@ -344,8 +458,9 @@ function runMigrateStrictEffect(args, context) {
344
458
  modern-js-create ultramodern migrate-strict-effect --version <version> [--skip-install]
345
459
 
346
460
  Updates generated UltraModern package-source metadata, Modern package aliases,
347
- direct Effect API topology metadata, and the pnpm lockfile for strict Effect
348
- workspaces. Source code still has to pass pnpm api:check and pnpm contract:check.
461
+ framework-owned toolchain pins, direct Effect API topology metadata, strict
462
+ Effect pnpm overrides/trust policy, and the pnpm lockfile. Source code still
463
+ has to pass pnpm api:check and pnpm contract:check.
349
464
  `);
350
465
  return 0;
351
466
  }
@@ -363,9 +478,13 @@ workspaces. Source code still has to pass pnpm api:check and pnpm contract:check
363
478
  config: './.modernjs/ultramodern.json'
364
479
  };
365
480
  }
366
- if (updateModernDependencies(packageJson, packageSource)) writeJsonFile(packageFile, packageJson);
481
+ const modernDependenciesChanged = updateModernDependencies(packageJson, packageSource);
482
+ const toolingDependenciesChanged = updateGeneratedToolingDependencies(packageJson);
483
+ const changed = modernDependenciesChanged || toolingDependenciesChanged;
484
+ if (changed) writeJsonFile(packageFile, packageJson);
367
485
  else if ('package.json' === relativePackageFile) writeJsonFile(packageFile, packageJson);
368
486
  }
487
+ updateGeneratedPnpmWorkspacePolicy(context.workspaceRoot);
369
488
  if (!hasFlag(args, '--skip-install')) {
370
489
  const status = runPnpmLockfileRefresh(context);
371
490
  if (0 !== status) return status;
@@ -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,54 @@ 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
+ function updateGeneratedToolingDependencies(packageJson) {
186
+ let changed = false;
187
+ for (const section of [
188
+ 'dependencies',
189
+ 'devDependencies',
190
+ 'peerDependencies',
191
+ 'optionalDependencies'
192
+ ]){
193
+ const dependencies = packageJson[section];
194
+ if (!(!dependencies || 'object' != typeof dependencies || Array.isArray(dependencies))) {
195
+ for (const [packageName, version] of generatedToolingDependencyPins)if (Object.prototype.hasOwnProperty.call(dependencies, packageName) && dependencies[packageName] !== version) {
196
+ dependencies[packageName] = version;
197
+ changed = true;
198
+ }
199
+ }
200
+ }
201
+ return changed;
202
+ }
154
203
  function normalizeStrictEffectApiMetadata(value) {
155
204
  const api = value.api;
156
205
  if (!api || 'object' != typeof api || Array.isArray(api)) return false;
@@ -216,6 +265,71 @@ function normalizeStrictEffectApiMetadata(value) {
216
265
  }
217
266
  return changed;
218
267
  }
268
+ function replaceYamlLine(source, pattern, replacement) {
269
+ const updated = source.replace(pattern, replacement);
270
+ return {
271
+ source: updated,
272
+ changed: updated !== source
273
+ };
274
+ }
275
+ function ensureYamlListItem(source, key, item) {
276
+ const itemLine = ` - '${item}'`;
277
+ const headerPattern = new RegExp(`^${key}:\\n(?:(?: - .+\\n)*)`, 'mu');
278
+ const existingItemPattern = new RegExp(`^ - '${item.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&')}'$`, 'mu');
279
+ if (existingItemPattern.test(source)) return {
280
+ source,
281
+ changed: false
282
+ };
283
+ const header = source.match(headerPattern);
284
+ if (header) return {
285
+ source: source.replace(headerPattern, `${header[0]}${itemLine}\n`),
286
+ changed: true
287
+ };
288
+ const block = `${key}:\n${itemLine}\n`;
289
+ const afterTrustPolicyIgnore = source.replace(/^(trustPolicyIgnoreAfter: .+\n)/mu, `$1${block}`);
290
+ if (afterTrustPolicyIgnore !== source) return {
291
+ source: afterTrustPolicyIgnore,
292
+ changed: true
293
+ };
294
+ return {
295
+ source: `${source.trimEnd()}\n${block}`,
296
+ changed: true
297
+ };
298
+ }
299
+ function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
300
+ const workspaceFile = node_path.join(workspaceRoot, 'pnpm-workspace.yaml');
301
+ if (!node_fs.existsSync(workspaceFile)) return false;
302
+ let source = node_fs.readFileSync(workspaceFile, 'utf-8');
303
+ let changed = false;
304
+ const replacements = [
305
+ [
306
+ /^ {4}'@effect\/vitest>effect': .+$/mu,
307
+ ` '@effect/vitest>effect': '${EFFECT_VERSION}'`
308
+ ],
309
+ [
310
+ /^ {2}'@effect\/vitest': .+$/mu,
311
+ ` '@effect/vitest': ${EFFECT_VITEST_VERSION}`
312
+ ],
313
+ [
314
+ /^ {2}effect: .+$/mu,
315
+ ` effect: ${EFFECT_VERSION}`
316
+ ],
317
+ [
318
+ /^ {2}- '@effect\/opentelemetry@[^']+'$/mu,
319
+ ` - '@effect/opentelemetry@${EFFECT_VERSION}'`
320
+ ]
321
+ ];
322
+ for (const [pattern, replacement] of replacements){
323
+ const result = replaceYamlLine(source, pattern, replacement);
324
+ source = result.source;
325
+ changed = result.changed || changed;
326
+ }
327
+ const trustPolicyExclude = ensureYamlListItem(source, 'trustPolicyExclude', `@effect/opentelemetry@${EFFECT_VERSION}`);
328
+ source = trustPolicyExclude.source;
329
+ changed = trustPolicyExclude.changed || changed;
330
+ if (changed) node_fs.writeFileSync(workspaceFile, source, 'utf-8');
331
+ return changed;
332
+ }
219
333
  function updateUltramodernConfig(workspaceRoot, packageSource) {
220
334
  const configPath = node_path.join(workspaceRoot, '.modernjs/ultramodern.json');
221
335
  const config = readJsonFile(configPath);
@@ -297,8 +411,9 @@ function runMigrateStrictEffect(args, context) {
297
411
  modern-js-create ultramodern migrate-strict-effect --version <version> [--skip-install]
298
412
 
299
413
  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.
414
+ framework-owned toolchain pins, direct Effect API topology metadata, strict
415
+ Effect pnpm overrides/trust policy, and the pnpm lockfile. Source code still
416
+ has to pass pnpm api:check and pnpm contract:check.
302
417
  `);
303
418
  return 0;
304
419
  }
@@ -316,9 +431,13 @@ workspaces. Source code still has to pass pnpm api:check and pnpm contract:check
316
431
  config: './.modernjs/ultramodern.json'
317
432
  };
318
433
  }
319
- if (updateModernDependencies(packageJson, packageSource)) writeJsonFile(packageFile, packageJson);
434
+ const modernDependenciesChanged = updateModernDependencies(packageJson, packageSource);
435
+ const toolingDependenciesChanged = updateGeneratedToolingDependencies(packageJson);
436
+ const changed = modernDependenciesChanged || toolingDependenciesChanged;
437
+ if (changed) writeJsonFile(packageFile, packageJson);
320
438
  else if ('package.json' === relativePackageFile) writeJsonFile(packageFile, packageJson);
321
439
  }
440
+ updateGeneratedPnpmWorkspacePolicy(context.workspaceRoot);
322
441
  if (!hasFlag(args, '--skip-install')) {
323
442
  const status = runPnpmLockfileRefresh(context);
324
443
  if (0 !== status) return status;
@@ -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,54 @@ 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
+ function updateGeneratedToolingDependencies(packageJson) {
187
+ let changed = false;
188
+ for (const section of [
189
+ 'dependencies',
190
+ 'devDependencies',
191
+ 'peerDependencies',
192
+ 'optionalDependencies'
193
+ ]){
194
+ const dependencies = packageJson[section];
195
+ if (!(!dependencies || 'object' != typeof dependencies || Array.isArray(dependencies))) {
196
+ for (const [packageName, version] of generatedToolingDependencyPins)if (Object.prototype.hasOwnProperty.call(dependencies, packageName) && dependencies[packageName] !== version) {
197
+ dependencies[packageName] = version;
198
+ changed = true;
199
+ }
200
+ }
201
+ }
202
+ return changed;
203
+ }
155
204
  function normalizeStrictEffectApiMetadata(value) {
156
205
  const api = value.api;
157
206
  if (!api || 'object' != typeof api || Array.isArray(api)) return false;
@@ -217,6 +266,71 @@ function normalizeStrictEffectApiMetadata(value) {
217
266
  }
218
267
  return changed;
219
268
  }
269
+ function replaceYamlLine(source, pattern, replacement) {
270
+ const updated = source.replace(pattern, replacement);
271
+ return {
272
+ source: updated,
273
+ changed: updated !== source
274
+ };
275
+ }
276
+ function ensureYamlListItem(source, key, item) {
277
+ const itemLine = ` - '${item}'`;
278
+ const headerPattern = new RegExp(`^${key}:\\n(?:(?: - .+\\n)*)`, 'mu');
279
+ const existingItemPattern = new RegExp(`^ - '${item.replace(/[.*+?^${}()|[\]\\]/gu, '\\$&')}'$`, 'mu');
280
+ if (existingItemPattern.test(source)) return {
281
+ source,
282
+ changed: false
283
+ };
284
+ const header = source.match(headerPattern);
285
+ if (header) return {
286
+ source: source.replace(headerPattern, `${header[0]}${itemLine}\n`),
287
+ changed: true
288
+ };
289
+ const block = `${key}:\n${itemLine}\n`;
290
+ const afterTrustPolicyIgnore = source.replace(/^(trustPolicyIgnoreAfter: .+\n)/mu, `$1${block}`);
291
+ if (afterTrustPolicyIgnore !== source) return {
292
+ source: afterTrustPolicyIgnore,
293
+ changed: true
294
+ };
295
+ return {
296
+ source: `${source.trimEnd()}\n${block}`,
297
+ changed: true
298
+ };
299
+ }
300
+ function updateGeneratedPnpmWorkspacePolicy(workspaceRoot) {
301
+ const workspaceFile = node_path.join(workspaceRoot, 'pnpm-workspace.yaml');
302
+ if (!node_fs.existsSync(workspaceFile)) return false;
303
+ let source = node_fs.readFileSync(workspaceFile, 'utf-8');
304
+ let changed = false;
305
+ const replacements = [
306
+ [
307
+ /^ {4}'@effect\/vitest>effect': .+$/mu,
308
+ ` '@effect/vitest>effect': '${EFFECT_VERSION}'`
309
+ ],
310
+ [
311
+ /^ {2}'@effect\/vitest': .+$/mu,
312
+ ` '@effect/vitest': ${EFFECT_VITEST_VERSION}`
313
+ ],
314
+ [
315
+ /^ {2}effect: .+$/mu,
316
+ ` effect: ${EFFECT_VERSION}`
317
+ ],
318
+ [
319
+ /^ {2}- '@effect\/opentelemetry@[^']+'$/mu,
320
+ ` - '@effect/opentelemetry@${EFFECT_VERSION}'`
321
+ ]
322
+ ];
323
+ for (const [pattern, replacement] of replacements){
324
+ const result = replaceYamlLine(source, pattern, replacement);
325
+ source = result.source;
326
+ changed = result.changed || changed;
327
+ }
328
+ const trustPolicyExclude = ensureYamlListItem(source, 'trustPolicyExclude', `@effect/opentelemetry@${EFFECT_VERSION}`);
329
+ source = trustPolicyExclude.source;
330
+ changed = trustPolicyExclude.changed || changed;
331
+ if (changed) node_fs.writeFileSync(workspaceFile, source, 'utf-8');
332
+ return changed;
333
+ }
220
334
  function updateUltramodernConfig(workspaceRoot, packageSource) {
221
335
  const configPath = node_path.join(workspaceRoot, '.modernjs/ultramodern.json');
222
336
  const config = readJsonFile(configPath);
@@ -298,8 +412,9 @@ function runMigrateStrictEffect(args, context) {
298
412
  modern-js-create ultramodern migrate-strict-effect --version <version> [--skip-install]
299
413
 
300
414
  Updates generated UltraModern package-source metadata, Modern package aliases,
301
- direct Effect API topology metadata, and the pnpm lockfile for strict Effect
302
- workspaces. Source code still has to pass pnpm api:check and pnpm contract:check.
415
+ framework-owned toolchain pins, direct Effect API topology metadata, strict
416
+ Effect pnpm overrides/trust policy, and the pnpm lockfile. Source code still
417
+ has to pass pnpm api:check and pnpm contract:check.
303
418
  `);
304
419
  return 0;
305
420
  }
@@ -317,9 +432,13 @@ workspaces. Source code still has to pass pnpm api:check and pnpm contract:check
317
432
  config: './.modernjs/ultramodern.json'
318
433
  };
319
434
  }
320
- if (updateModernDependencies(packageJson, packageSource)) writeJsonFile(packageFile, packageJson);
435
+ const modernDependenciesChanged = updateModernDependencies(packageJson, packageSource);
436
+ const toolingDependenciesChanged = updateGeneratedToolingDependencies(packageJson);
437
+ const changed = modernDependenciesChanged || toolingDependenciesChanged;
438
+ if (changed) writeJsonFile(packageFile, packageJson);
321
439
  else if ('package.json' === relativePackageFile) writeJsonFile(packageFile, packageJson);
322
440
  }
441
+ updateGeneratedPnpmWorkspacePolicy(context.workspaceRoot);
323
442
  if (!hasFlag(args, '--skip-install')) {
324
443
  const status = runPnpmLockfileRefresh(context);
325
444
  if (0 !== status) return status;
package/package.json CHANGED
@@ -21,7 +21,7 @@
21
21
  "engines": {
22
22
  "node": ">=20"
23
23
  },
24
- "version": "3.5.0-ultramodern.2",
24
+ "version": "3.5.0-ultramodern.3",
25
25
  "types": "./dist/types/index.d.ts",
26
26
  "main": "./dist/esm-node/index.js",
27
27
  "bin": {
@@ -77,7 +77,7 @@
77
77
  "@modern-js/codesmith": "2.6.9",
78
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.2"
80
+ "@modern-js/i18n-utils": "npm:@bleedingdev/modern-js-i18n-utils@3.5.0-ultramodern.3"
81
81
  },
82
82
  "devDependencies": {
83
83
  "@rslib/core": "0.23.1",
@@ -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.2"
102
+ "frameworkVersion": "3.5.0-ultramodern.3"
103
103
  }
104
104
  }
@@ -169,19 +169,22 @@ 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 trust policy intentionally excludes the matching
173
+ `@effect/opentelemetry` cohort package from no-downgrade checks while Effect's
174
+ beta publishes move from trusted-publisher metadata to provenance attestations.
173
175
 
174
176
  For older generated workspaces, run the framework migration command first:
175
177
 
176
178
  ```bash
177
- pnpm dlx @bleedingdev/modern-js-create@3.5.0-ultramodern.2 ultramodern \
178
- migrate-strict-effect --version 3.5.0-ultramodern.2
179
+ pnpm dlx @bleedingdev/modern-js-create@3.5.0-ultramodern.3 ultramodern \
180
+ migrate-strict-effect --version 3.5.0-ultramodern.3
179
181
  pnpm api:check
180
182
  pnpm contract:check
181
183
  ```
182
184
 
183
185
  The command updates generated package-source metadata, Modern package aliases,
184
- direct API topology metadata, and the lockfile. Remaining failures are source
186
+ framework-owned toolchain pins, direct API topology metadata, strict Effect pnpm
187
+ overrides/trust policy, and the lockfile. Remaining failures are source
185
188
  migration work; fix the owning API files instead of adding compatibility shims.
186
189
 
187
190
  ## Troubleshooting
@@ -24,6 +24,8 @@ minimumReleaseAgeExclude:
24
24
  - 'ts-checker-rspack-plugin'
25
25
  trustPolicy: no-downgrade
26
26
  trustPolicyIgnoreAfter: 1440
27
+ trustPolicyExclude:
28
+ - '@effect/opentelemetry@{{effectVersion}}'
27
29
  blockExoticSubdeps: true
28
30
  engineStrict: true
29
31
  pmOnFail: error