@bleedingdev/modern-js-app-tools-extensions 3.9.3-ultramodern.1 → 3.9.3-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 (34) hide show
  1. package/dist/cjs/build-config/build-environment.js +7 -5
  2. package/dist/cjs/build-config/internal-effect-discovery.js +94 -6
  3. package/dist/cjs/native-type-checker.js +66 -20
  4. package/dist/cjs/release-identity.js +1 -1
  5. package/dist/cjs/renderer-build-identity.js +13 -3
  6. package/dist/cjs/templates/cloudflare-entry.005-worker-dispatch.mjs +18 -1
  7. package/dist/esm/build-config/build-environment.mjs +7 -5
  8. package/dist/esm/build-config/internal-effect-discovery.mjs +90 -5
  9. package/dist/esm/native-type-checker.mjs +68 -22
  10. package/dist/esm/release-identity.mjs +1 -1
  11. package/dist/esm/renderer-build-identity.mjs +13 -3
  12. package/dist/esm/templates/cloudflare-entry.005-worker-dispatch.mjs +18 -1
  13. package/dist/esm-node/build-config/build-environment.mjs +7 -5
  14. package/dist/esm-node/build-config/internal-effect-discovery.mjs +90 -5
  15. package/dist/esm-node/native-type-checker.mjs +68 -22
  16. package/dist/esm-node/release-identity.mjs +1 -1
  17. package/dist/esm-node/renderer-build-identity.mjs +13 -3
  18. package/dist/esm-node/templates/cloudflare-entry.005-worker-dispatch.mjs +18 -1
  19. package/dist/types/build-config/build-environment.d.ts +3 -1
  20. package/dist/types/build-config/internal-effect-discovery.d.ts +3 -1
  21. package/dist/types/cloudflare/worker-manifest.d.ts +3 -2
  22. package/dist/types/config.d.ts +4 -0
  23. package/dist/types/native-type-checker.d.ts +4 -2
  24. package/dist/types/release-identity.d.ts +10 -0
  25. package/dist/types/renderer-build-identity.d.ts +12 -1
  26. package/package.json +27 -27
  27. package/src/build-config/build-environment.ts +11 -9
  28. package/src/build-config/internal-effect-discovery.ts +238 -19
  29. package/src/cloudflare/worker-manifest.ts +7 -3
  30. package/src/config.ts +4 -0
  31. package/src/native-type-checker.ts +87 -43
  32. package/src/release-identity.ts +11 -2
  33. package/src/renderer-build-identity.ts +51 -11
  34. package/src/templates/cloudflare-entry.005-worker-dispatch.mjs +18 -1
@@ -8,6 +8,16 @@ export declare const createUltramodernReleaseBuildMarker: ({ generationBuildMark
8
8
  unitId: string;
9
9
  }) => string;
10
10
  export declare const resolveUltramodernSourceRevision: (workspaceRoot?: string, configuredSourceRevision?: string, environment?: Readonly<NodeJS.ProcessEnv>) => string;
11
+ /**
12
+ * The one release identity of a delivery unit, resolvable before its build.
13
+ *
14
+ * For a clean source revision the build marker is a 64-hex digest of the unit
15
+ * id, its generation marker and the revision. API bundles carry it, and a UI
16
+ * unit's renderer adopts it as its `buildId`, so contracts, release plans and
17
+ * Worker names derived from it before the build match the built
18
+ * `ultramodern-build.json`, `renderer-build.json`, chunk banners and envelope.
19
+ * A dirty or non-Git checkout yields the non-promotable `workspace` identity.
20
+ */
11
21
  export declare const resolveUltramodernReleaseIdentity: ({ generationBuildMarker, sourceRevision: configuredSourceRevision, unitId, workspaceRoot, environment, }: {
12
22
  generationBuildMarker: string;
13
23
  sourceRevision?: string;
@@ -10,7 +10,18 @@ export interface RendererBuildIdentityOptions {
10
10
  mode: 'development' | 'production';
11
11
  /** Delivery-unit app id; defaults to the application package name. */
12
12
  appId?: string;
13
- /** Externally authenticated source revision (delivery unit or CI). */
13
+ /**
14
+ * The declared delivery unit's release identity, resolved before the build
15
+ * by `resolveUltramodernReleaseIdentity`. A promotable production build
16
+ * adopts its buildMarker as the buildId, so consumers that resolve the unit
17
+ * identity before compiling see the marker the built artifacts carry.
18
+ */
19
+ deliveryUnit?: {
20
+ readonly unitId: string;
21
+ readonly buildMarker: string;
22
+ readonly sourceRevision: string;
23
+ };
24
+ /** Externally authenticated source revision (CI) for an undeclared app. */
14
25
  sourceRevision?: string;
15
26
  /** Actual final entry ownership, supplied by the selected renderer composition. */
16
27
  routerBindings: RendererRouterBindings;
package/package.json CHANGED
@@ -11,7 +11,7 @@
11
11
  "directory": "packages/solutions/app-tools-extensions"
12
12
  },
13
13
  "license": "MIT",
14
- "version": "3.9.3-ultramodern.1",
14
+ "version": "3.9.3-ultramodern.10",
15
15
  "files": [
16
16
  "dist",
17
17
  "src"
@@ -172,21 +172,21 @@
172
172
  }
173
173
  },
174
174
  "engines": {
175
- "node": ">=26.10.0"
175
+ "node": ">=26.12.0"
176
176
  },
177
177
  "dependencies": {
178
- "@babel/parser": "^8.0.6",
179
- "@babel/traverse": "^8.0.6",
180
- "@modern-js/backend-federation-contracts": "npm:@bleedingdev/modern-js-backend-federation-contracts@3.9.3-ultramodern.1",
181
- "@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.9.3-ultramodern.1",
182
- "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.9.3-ultramodern.1",
183
- "@modern-js/prod-server": "npm:@bleedingdev/modern-js-prod-server@3.9.3-ultramodern.1",
184
- "@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.9.3-ultramodern.1",
185
- "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.9.3-ultramodern.1",
186
- "@modern-js/server-runtime-extensions": "npm:@bleedingdev/modern-js-server-runtime-extensions@3.9.3-ultramodern.1",
187
- "@modern-js/surface-resolution": "npm:@bleedingdev/modern-js-surface-resolution@3.9.3-ultramodern.1",
188
- "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.3-ultramodern.1",
189
- "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.3-ultramodern.1",
178
+ "@babel/parser": "^8.0.7",
179
+ "@babel/traverse": "^8.0.7",
180
+ "@modern-js/backend-federation-contracts": "npm:@bleedingdev/modern-js-backend-federation-contracts@3.9.3-ultramodern.10",
181
+ "@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.9.3-ultramodern.10",
182
+ "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.9.3-ultramodern.10",
183
+ "@modern-js/prod-server": "npm:@bleedingdev/modern-js-prod-server@3.9.3-ultramodern.10",
184
+ "@modern-js/runtime-utils": "npm:@bleedingdev/modern-js-runtime-utils@3.9.3-ultramodern.10",
185
+ "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.9.3-ultramodern.10",
186
+ "@modern-js/server-runtime-extensions": "npm:@bleedingdev/modern-js-server-runtime-extensions@3.9.3-ultramodern.10",
187
+ "@modern-js/surface-resolution": "npm:@bleedingdev/modern-js-surface-resolution@3.9.3-ultramodern.10",
188
+ "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.9.3-ultramodern.10",
189
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.9.3-ultramodern.10",
190
190
  "@swc/helpers": "^0.5.23",
191
191
  "@vercel/nft": "^1.11.0",
192
192
  "compression-webpack-plugin": "^12.0.0",
@@ -196,9 +196,9 @@
196
196
  },
197
197
  "peerDependencies": {
198
198
  "@loadable/component": "5.16.7",
199
- "@modern-js/runtime-renderer-extensions": "3.9.3-ultramodern.1",
200
- "@rsbuild/core": "2.2.11",
201
- "react": "^19.2.8"
199
+ "@modern-js/runtime-renderer-extensions": "3.9.3-ultramodern.10",
200
+ "@rsbuild/core": "2.2.13",
201
+ "react": "^19.3.1"
202
202
  },
203
203
  "peerDependenciesMeta": {
204
204
  "@loadable/component": {
@@ -213,24 +213,24 @@
213
213
  },
214
214
  "devDependencies": {
215
215
  "@loadable/component": "5.16.7",
216
- "@modern-js/bff-effect": "npm:@bleedingdev/modern-js-bff-effect@3.9.3-ultramodern.1",
217
- "@modern-js/plugin-bff-extensions": "npm:@bleedingdev/modern-js-plugin-bff-extensions@3.9.3-ultramodern.1",
218
- "@modern-js/plugin-data-loader": "npm:@bleedingdev/modern-js-plugin-data-loader@3.9.3-ultramodern.1",
219
- "@modern-js/runtime-renderer-extensions": "npm:@bleedingdev/modern-js-runtime-renderer-extensions@3.9.3-ultramodern.1",
216
+ "@modern-js/bff-effect": "npm:@bleedingdev/modern-js-bff-effect@3.9.3-ultramodern.10",
217
+ "@modern-js/plugin-bff-extensions": "npm:@bleedingdev/modern-js-plugin-bff-extensions@3.9.3-ultramodern.10",
218
+ "@modern-js/plugin-data-loader": "npm:@bleedingdev/modern-js-plugin-data-loader@3.9.3-ultramodern.10",
219
+ "@modern-js/runtime-renderer-extensions": "npm:@bleedingdev/modern-js-runtime-renderer-extensions@3.9.3-ultramodern.10",
220
220
  "@module-federation/modern-js-v3": "2.9.2",
221
221
  "@module-federation/runtime-tools": "2.9.2",
222
- "@rsbuild/core": "2.2.11",
222
+ "@rsbuild/core": "2.2.13",
223
223
  "@rslib/core": "1.0.3",
224
224
  "@scripts/rstest-config": "2.66.0",
225
225
  "@types/babel__traverse": "7.28.0",
226
- "@types/node": "^26.6.3",
226
+ "@types/node": "^26.6.5",
227
227
  "core-js": "^3.50.0",
228
- "effect": "4.0.0",
229
- "miniflare": "5.20260930.0-alpha",
228
+ "effect": "4.0.5",
229
+ "miniflare": "5.20261012.0-beta",
230
230
  "ndepe": "^0.1.13",
231
231
  "pg": "8.23.1",
232
- "react": "^19.3.0",
233
- "react-dom": "^19.3.0"
232
+ "react": "^19.3.1",
233
+ "react-dom": "^19.3.1"
234
234
  },
235
235
  "sideEffects": false,
236
236
  "publishConfig": {
@@ -36,12 +36,13 @@ if (typeof owningName !== 'string' || owningName.length === 0) {
36
36
  const {
37
37
  effectCompilerDiscoveryFailureStage,
38
38
  resolveInstalledEffectCompiler,
39
+ validateConfiguredEffectCompiler,
39
40
  }: typeof import('./internal-effect-discovery') = createRequire(
40
41
  owningModuleUrl,
41
42
  )(`${owningName}/internal-effect-discovery`);
42
43
 
43
44
  const EFFECT_TSGO_RESOLUTION_ERROR =
44
- 'Unable to resolve the Effect TS-Go compiler. Install "@effect/tsgo" and a native TypeScript backend for this build config, or set EFFECT_TSGO_BIN.';
45
+ 'Unable to resolve the Effect TS-Go compiler. Install "@effect/tsgo" and a native TypeScript backend for this build config, or set EFFECT_TSGO_BIN. Bundled tsrs requires matching installed tsrs metadata.';
45
46
  const executableEffectTsgoCompilers = new Map<string, string>();
46
47
 
47
48
  function effectTsgoResolutionError(
@@ -58,17 +59,14 @@ function effectTsgoResolutionError(
58
59
  }
59
60
 
60
61
  function resolveExecutableEffectTsgoCompiler(compilerPath: string): string {
61
- if (process.platform === 'win32') {
62
- return compilerPath;
63
- }
64
-
65
62
  const sourcePath = realpathSync(compilerPath);
66
63
  const source = lstatSync(sourcePath);
67
- if (!source.isFile()) {
64
+ if (!source.isFile() || source.size === 0) {
68
65
  throw new Error(
69
- `Effect TS-Go compiler path is not a regular file: ${sourcePath}`,
66
+ `Effect TS-Go compiler path is not a nonempty regular file: ${sourcePath}`,
70
67
  );
71
68
  }
69
+ if (process.platform === 'win32') return compilerPath;
72
70
 
73
71
  try {
74
72
  accessSync(sourcePath, constants.X_OK);
@@ -138,7 +136,9 @@ export type ResolveEffectTsgoCompilerOptions = {
138
136
  };
139
137
 
140
138
  /**
141
- * Resolves the Effect TS-Go executable used by Module Federation DTS builds.
139
+ * Resolves the Effect-enabled native executable for checking and DTS builds.
140
+ * Use metadata-bound tsrs where both tsrs and the Effect provider support it.
141
+ * Unsupported targets use Effect-Go. Missing supported artifacts remain fatal.
142
142
  */
143
143
  export function resolveEffectTsgoCompiler(
144
144
  options: ResolveEffectTsgoCompilerOptions,
@@ -148,7 +148,9 @@ export function resolveEffectTsgoCompiler(
148
148
 
149
149
  if (configuredCompiler) {
150
150
  try {
151
- return resolveExecutableEffectTsgoCompiler(configuredCompiler);
151
+ const compiler = resolveExecutableEffectTsgoCompiler(configuredCompiler);
152
+ validateConfiguredEffectCompiler(compiler, options.from);
153
+ return compiler;
152
154
  } catch (cause) {
153
155
  throw effectTsgoResolutionError(
154
156
  cause,
@@ -1,3 +1,4 @@
1
+ import { execFileSync } from 'node:child_process';
1
2
  import { lstatSync, readFileSync, realpathSync } from 'node:fs';
2
3
  import { createRequire } from 'node:module';
3
4
  import { dirname, join, resolve } from 'node:path';
@@ -6,13 +7,28 @@ import { fileURLToPath, type URL } from 'node:url';
6
7
  const EFFECT_TSGO_PACKAGE = '@effect/tsgo';
7
8
  const EFFECT_TSGO_BIN = 'effect-tsgo';
8
9
  const NATIVE_TYPESCRIPT_PACKAGES = ['typescript', '@typescript/native'];
10
+ // @effect/tsgo@0.59.0 exports no tsrs capability API. Keep this exact contract
11
+ // aligned with its CLI's tsrsReplacementTargets / resolveTsrs, not tsrs's list.
12
+ const EFFECT_TSRS_PROVIDER_VERSION = '0.59.0';
13
+ const EFFECT_TSRS_TARGETS = new Set([
14
+ '@tsrs/darwin-arm64',
15
+ '@tsrs/linux-x64-gnu',
16
+ '@tsrs/linux-arm64-gnu',
17
+ ]);
9
18
  type PackageJson = {
10
19
  name?: string;
11
20
  bin?: Record<string, string> | string;
12
21
  version?: string;
13
22
  gitHead?: string;
23
+ tsrs?: { typescriptVersion?: string; typescriptCommit?: string };
24
+ optionalDependencies?: Record<string, string>;
25
+ };
26
+ type TsrsPackageJson = PackageJson & {
27
+ version: string;
28
+ tsrs: { typescriptVersion: string; typescriptCommit: string };
14
29
  };
15
30
  const failureStages = new WeakMap<object, string>();
31
+ const reportedUnsupportedTsrsTargets = new Set<string>();
16
32
  export function effectCompilerDiscoveryFailureStage(
17
33
  error: unknown,
18
34
  ): string | undefined {
@@ -50,7 +66,7 @@ function resolveEffectTsgoPackage(from: string | URL): {
50
66
  return { packageJsonPath, packageJson, cliPath };
51
67
  }
52
68
 
53
- function isAbsentNativeTypeScriptPackage(
69
+ function isAbsentPackage(
54
70
  projectRequire: NodeJS.Require,
55
71
  from: string | URL,
56
72
  packageName: string,
@@ -98,14 +114,7 @@ function resolveNativeTypeScriptPackage(from: string | URL): string {
98
114
  try {
99
115
  packageJsonPath = projectRequire.resolve(`${packageName}/package.json`);
100
116
  } catch (error) {
101
- if (
102
- isAbsentNativeTypeScriptPackage(
103
- projectRequire,
104
- from,
105
- packageName,
106
- error,
107
- )
108
- ) {
117
+ if (isAbsentPackage(projectRequire, from, packageName, error)) {
109
118
  continue;
110
119
  }
111
120
  throw error;
@@ -156,11 +165,215 @@ function readCompilerArtifact(filename: string): string {
156
165
  return canonicalPath;
157
166
  }
158
167
 
159
- /** Selects the exact native replacement without invoking the provider. */
168
+ function resolveTsrsManifest(from: string | URL): string | undefined {
169
+ const projectRequire = createRequire(from);
170
+ try {
171
+ return projectRequire.resolve('tsrs/package.json');
172
+ } catch (error) {
173
+ if (isAbsentPackage(projectRequire, from, 'tsrs', error)) return undefined;
174
+ throw error;
175
+ }
176
+ }
177
+
178
+ function compilerVersion(compiler: string): string {
179
+ return execFileSync(compiler, ['--version'], {
180
+ encoding: 'utf8',
181
+ env: {
182
+ ...process.env,
183
+ TSRS_CHECKER_ASSIGNMENT: process.env.TSRS_CHECKER_ASSIGNMENT || 'go',
184
+ },
185
+ timeout: 10_000,
186
+ maxBuffer: 1024 * 1024,
187
+ }).trim();
188
+ }
189
+
190
+ function tsrsPlatform(manifestPath: string): {
191
+ manifest: TsrsPackageJson;
192
+ nativeName: string;
193
+ supported: boolean;
194
+ } {
195
+ const manifest = JSON.parse(
196
+ readFileSync(manifestPath, 'utf8'),
197
+ ) as PackageJson;
198
+ const { getPlatformPackageName } = createRequire(manifestPath)(
199
+ join(dirname(manifestPath), 'lib/platform.js'),
200
+ ) as { getPlatformPackageName: () => string };
201
+ const nativeName = getPlatformPackageName();
202
+ const embedded = manifest.tsrs;
203
+ if (
204
+ typeof nativeName !== 'string' ||
205
+ !nativeName ||
206
+ !manifest.optionalDependencies ||
207
+ typeof manifest.optionalDependencies !== 'object' ||
208
+ Array.isArray(manifest.optionalDependencies) ||
209
+ Object.keys(manifest.optionalDependencies).length === 0
210
+ ) {
211
+ throw new Error(`Invalid native tsrs capability metadata: ${manifestPath}`);
212
+ }
213
+ if (
214
+ typeof manifest.name !== 'string' ||
215
+ !manifest.name ||
216
+ typeof manifest.version !== 'string' ||
217
+ !/^\d+\.\d+\.\d+-ts[\w.-]+$/u.test(manifest.version) ||
218
+ typeof embedded?.typescriptVersion !== 'string' ||
219
+ !/^7\.\d+\.\d+(?:[-+][\w.-]+)?$/u.test(embedded.typescriptVersion) ||
220
+ !manifest.version.endsWith(`-ts${embedded.typescriptVersion}`) ||
221
+ typeof embedded.typescriptCommit !== 'string' ||
222
+ !/^[a-f\d]{40}$/u.test(embedded.typescriptCommit)
223
+ ) {
224
+ throw new Error(`Invalid native tsrs metadata: ${manifestPath}`);
225
+ }
226
+ const supported = Object.hasOwn(manifest.optionalDependencies, nativeName);
227
+ if (
228
+ supported &&
229
+ manifest.optionalDependencies[nativeName] !== manifest.version
230
+ ) {
231
+ throw new Error(
232
+ `Native tsrs target version does not match its selected package: ${manifestPath}`,
233
+ );
234
+ }
235
+ return { manifest: manifest as TsrsPackageJson, nativeName, supported };
236
+ }
237
+
238
+ function resolveTsrsCompiler(
239
+ manifestPath: string,
240
+ effect: ReturnType<typeof resolveEffectTsgoPackage>,
241
+ configuredCompiler?: string,
242
+ configuredVersion?: string,
243
+ ): string {
244
+ const { manifest } = tsrsPlatform(manifestPath);
245
+ const embedded = manifest.tsrs;
246
+ const effectName = `@effect/tsgo-${process.platform}-${process.arch}`;
247
+ const effectManifest = createRequire(effect.cliPath).resolve(
248
+ `${effectName}/package.json`,
249
+ );
250
+ const platform = JSON.parse(
251
+ readFileSync(effectManifest, 'utf8'),
252
+ ) as PackageJson;
253
+ const metadataPath = join(dirname(effectManifest), 'lib/upstream.json');
254
+ const metadata = JSON.parse(readFileSync(metadataPath, 'utf8')) as {
255
+ schemaVersion?: number;
256
+ components?: {
257
+ tsrs?: Record<
258
+ string,
259
+ {
260
+ gitHead?: string;
261
+ typescript?: { version?: string; gitHead?: string };
262
+ }
263
+ >;
264
+ };
265
+ };
266
+ const component = metadata.components?.tsrs?.[manifest.version];
267
+ if (
268
+ platform.name !== effectName ||
269
+ platform.version !== effect.packageJson.version ||
270
+ metadata.schemaVersion !== 5 ||
271
+ !/^[a-f\d]{40}$/u.test(component?.gitHead ?? '') ||
272
+ component?.typescript?.version !== embedded.typescriptVersion ||
273
+ component.typescript.gitHead !== embedded.typescriptCommit
274
+ ) {
275
+ throw new Error(
276
+ `Effect replacement metadata does not match tsrs: ${metadataPath}`,
277
+ );
278
+ }
279
+ // This is the same metadata-bound artifact used by `effect-tsgo tsrs`.
280
+ // The installed @tsrs binary need not be patched or written to.
281
+ const compiler = readCompilerArtifact(
282
+ configuredCompiler ??
283
+ join(
284
+ dirname(effectManifest),
285
+ 'artifacts/tsrs',
286
+ manifest.version,
287
+ process.platform === 'win32' ? 'tsrs.exe' : 'tsrs',
288
+ ),
289
+ );
290
+ const version = configuredVersion ?? compilerVersion(compiler);
291
+ // Check the selected executable itself, including TSRS_BINARY and explicit
292
+ // EFFECT_TSGO_BIN paths. A package name alone cannot prove it was patched.
293
+ const stamp =
294
+ /\+effect-tsgo\.([\d.]+)\s+\(tsrs ([^,]+), microsoft\/TypeScript@([a-f\d]+)\)$/u.exec(
295
+ version,
296
+ );
297
+ if (
298
+ !stamp ||
299
+ stamp[1] !== effect.packageJson.version ||
300
+ stamp[2] !== manifest.version ||
301
+ stamp[3].length < 12 ||
302
+ !embedded.typescriptCommit.startsWith(stamp[3])
303
+ ) {
304
+ throw new Error(
305
+ `Effect-enabled tsrs matching ${manifest.version} and @effect/tsgo@${effect.packageJson.version} is required: ${compiler}. Install matching packages or select a matching Effect-enabled candidate with EFFECT_TSGO_BIN.`,
306
+ );
307
+ }
308
+ return compiler;
309
+ }
310
+
311
+ /** Explicit native binaries must still report Effect diagnostics support. */
312
+ export function validateConfiguredEffectCompiler(
313
+ compiler: string,
314
+ from: string | URL,
315
+ ): void {
316
+ const version = compilerVersion(compiler);
317
+ if (
318
+ !/^Version \d+\.\d+\.\d+[\w.-]*\+effect-tsgo\.\d+\.\d+\.\d+(?:\s|$)/u.test(
319
+ version,
320
+ )
321
+ ) {
322
+ throw new Error(
323
+ `EFFECT_TSGO_BIN must select an Effect-enabled native compiler: ${compiler}`,
324
+ );
325
+ }
326
+ if (version.includes('(tsrs ')) {
327
+ const manifest = resolveTsrsManifest(from);
328
+ if (!manifest)
329
+ throw new Error(
330
+ `Cannot validate tsrs without its installed package metadata for ${String(from)}`,
331
+ );
332
+ resolveTsrsCompiler(
333
+ manifest,
334
+ resolveEffectTsgoPackage(from),
335
+ compiler,
336
+ version,
337
+ );
338
+ }
339
+ }
340
+
341
+ /** Selects the exact native replacement without invoking the provider CLI. */
160
342
  export function resolveInstalledEffectCompiler(from: string | URL): string {
161
343
  let stage = 'Package CLI resolution';
162
344
  try {
163
345
  const effect = resolveEffectTsgoPackage(from);
346
+ stage = 'Native tsrs package resolution';
347
+ const tsrsManifest = resolveTsrsManifest(from);
348
+ const tsrsTarget = tsrsManifest ? tsrsPlatform(tsrsManifest) : undefined;
349
+ if (
350
+ tsrsTarget &&
351
+ effect.packageJson.version !== EFFECT_TSRS_PROVIDER_VERSION
352
+ ) {
353
+ throw new Error(
354
+ `Unreviewed Effect tsrs capability contract: ${effect.packageJson.version}`,
355
+ );
356
+ }
357
+ const configuredTsrsCompiler = process.env.TSRS_BINARY || undefined;
358
+ if (
359
+ tsrsManifest &&
360
+ tsrsTarget?.supported &&
361
+ (configuredTsrsCompiler || EFFECT_TSRS_TARGETS.has(tsrsTarget.nativeName))
362
+ ) {
363
+ stage = 'Native tsrs validation';
364
+ // TSRS_BINARY remains an explicit candidate selection. Automatic
365
+ // discovery uses the Effect provider's bundled native replacement.
366
+ return resolveTsrsCompiler(tsrsManifest, effect, configuredTsrsCompiler);
367
+ }
368
+ if (
369
+ tsrsTarget &&
370
+ !reportedUnsupportedTsrsTargets.has(tsrsTarget.nativeName)
371
+ ) {
372
+ reportedUnsupportedTsrsTargets.add(tsrsTarget.nativeName);
373
+ console.warn(
374
+ `[UltraModern] ${tsrsTarget.supported ? `@effect/tsgo@${effect.packageJson.version} does not provide a tsrs replacement for ${tsrsTarget.nativeName}` : `tsrs does not declare ${tsrsTarget.nativeName}`}; selecting the Effect-enabled TypeScript-Go compiler.`,
375
+ );
376
+ }
164
377
  stage = 'Native TypeScript package resolution';
165
378
  const typeScriptManifest = resolveNativeTypeScriptManifest(from);
166
379
  const typeScript = JSON.parse(
@@ -208,13 +421,16 @@ export function resolveInstalledEffectCompiler(from: string | URL): string {
208
421
  const metadataPath = join(dirname(effectManifest), 'lib', 'upstream.json');
209
422
  const metadata = JSON.parse(readFileSync(metadataPath, 'utf8')) as {
210
423
  schemaVersion?: number;
424
+ tags?: { typescript?: { latest?: string } };
211
425
  components?: {
212
426
  typescript?: Record<string, { gitHead?: string; provider?: string }>;
213
427
  };
214
428
  };
215
429
  const component = metadata.components?.typescript?.[native.version];
430
+ const latestTypeScript = metadata.tags?.typescript?.latest;
216
431
  if (
217
432
  metadata.schemaVersion !== 5 ||
433
+ typeof latestTypeScript !== 'string' ||
218
434
  component?.provider !== 'typescript-go' ||
219
435
  component.gitHead !== native.gitHead
220
436
  ) {
@@ -222,15 +438,18 @@ export function resolveInstalledEffectCompiler(from: string | URL): string {
222
438
  `Effect replacement metadata does not match the selected native TypeScript backend: ${metadataPath}`,
223
439
  );
224
440
  }
225
- return readCompilerArtifact(
226
- join(
227
- dirname(effectManifest),
228
- 'artifacts',
229
- 'typescript',
230
- native.version,
231
- binaryName,
232
- ),
233
- );
441
+ // Same layout rule as @effect/tsgo's getExePath: the latest TypeScript
442
+ // replacement ships in lib/, every other version under artifacts/.
443
+ const compilerDirectory =
444
+ native.version === latestTypeScript
445
+ ? join(dirname(effectManifest), 'lib')
446
+ : join(
447
+ dirname(effectManifest),
448
+ 'artifacts',
449
+ 'typescript',
450
+ native.version,
451
+ );
452
+ return readCompilerArtifact(join(compilerDirectory, binaryName));
234
453
  } catch (error) {
235
454
  if (error && typeof error === 'object' && !failureStages.has(error))
236
455
  failureStages.set(error, stage);
@@ -1,5 +1,8 @@
1
1
  import path from 'node:path';
2
- import type {} from '@modern-js/server-runtime-extensions/server-config';
2
+ import type {
3
+ BffEffectDataPlatformUserConfig,
4
+ BffEffectOpenApiUserConfig,
5
+ } from '@modern-js/server-runtime-extensions/server-config';
3
6
  import { fs as fse } from '@modern-js/utils';
4
7
  import { getCloudflareWorkerRouteDataEntryName } from '../cloudflare-output-contract';
5
8
  import { readRouteSpec } from './artifacts';
@@ -71,8 +74,9 @@ const createEffectBffWorkerManifest = (
71
74
  },
72
75
  };
73
76
 
74
- const openapi = bff?.effect?.openapi;
75
- const dataPlatform = bff?.effect?.dataPlatform;
77
+ const openapi: BffEffectOpenApiUserConfig | undefined = bff?.effect?.openapi;
78
+ const dataPlatform: BffEffectDataPlatformUserConfig | undefined =
79
+ bff?.effect?.dataPlatform;
76
80
 
77
81
  return {
78
82
  ...(openapi === undefined ? {} : { openapi }),
package/src/config.ts CHANGED
@@ -247,6 +247,10 @@ export interface CloudflareWorkerDeployConfig {
247
247
  * `env[binding].fetch(request)`.
248
248
  */
249
249
  services?: CloudflareWorkerServiceBindingConfig[];
250
+ /** Native Worker context profiles, registered before federated exposes load. */
251
+ federation?: {
252
+ contextProfiles?: readonly string[];
253
+ };
250
254
  /**
251
255
  * First-class Workers VPC service bindings to private origins reached
252
256
  * through a Cloudflare Tunnel. Modern.js writes these to `wrangler.json`