@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
@@ -1,29 +1,59 @@
1
- import { execFile } from "node:child_process";
1
+ import { execFile, execFileSync } from "node:child_process";
2
2
  import { randomUUID } from "node:crypto";
3
- import { existsSync, readFileSync, realpathSync, statSync, unlinkSync, writeFileSync } from "node:fs";
3
+ import { existsSync, readFileSync, realpathSync, unlinkSync, writeFileSync } from "node:fs";
4
+ import { createRequire } from "node:module";
4
5
  import node_path from "node:path";
5
6
  import { promisify } from "node:util";
6
7
  import { refreshTsgoCheckerConfig } from "@modern-js/builder";
7
8
  import { parse, printParseErrorCode } from "jsonc-parser";
9
+ import { resolveEffectTsgoCompiler } from "./build-config/build-environment.mjs";
8
10
  const execute = promisify(execFile);
9
11
  const native_type_checker_name = 'UltramodernNativeTypeChecker';
10
- function resolveNativeTypeCheckerCommand(packageJsonPath) {
11
- const manifestFile = realpathSync(packageJsonPath);
12
- const directory = node_path.dirname(manifestFile);
13
- const manifest = JSON.parse(readFileSync(manifestFile, 'utf8'));
14
- if ("typescript" !== manifest.name || '7.0.2' !== manifest.version) throw new Error(`${native_type_checker_name} requires typescript@7.0.2; found ${String(manifest.name)}@${String(manifest.version)} at ${manifestFile}.`);
15
- const bin = manifest.bin?.tsc;
16
- if ('string' != typeof bin || !bin || node_path.isAbsolute(bin)) throw new Error(`${native_type_checker_name} requires the selected package's public tsc bin.`);
17
- const launcher = realpathSync(node_path.resolve(directory, bin));
18
- const relative = node_path.relative(directory, launcher);
19
- if (!relative || node_path.isAbsolute(relative) || '..' === relative || relative.startsWith(`..${node_path.sep}`) || !statSync(launcher).isFile()) throw new Error(`${native_type_checker_name} public tsc bin must belong to its selected package.`);
12
+ function resolveNativeTypeCheckerCommand(from) {
13
+ const executable = resolveEffectTsgoCompiler({
14
+ from
15
+ });
16
+ const version = execFileSync(executable, [
17
+ '--version'
18
+ ], {
19
+ encoding: 'utf8',
20
+ env: {
21
+ ...process.env,
22
+ TSRS_CHECKER_ASSIGNMENT: process.env.TSRS_CHECKER_ASSIGNMENT || 'go'
23
+ },
24
+ timeout: 10000
25
+ });
26
+ if (version.includes('(tsrs ')) return {
27
+ executable,
28
+ args: [],
29
+ configApi: createRequire(from).resolve('tsrs/sync')
30
+ };
20
31
  return {
21
- executable: process.execPath,
22
- args: [
23
- launcher
24
- ]
32
+ executable,
33
+ args: []
25
34
  };
26
35
  }
36
+ const inspectNativeConfig = `
37
+ import { pathToFileURL } from 'node:url';
38
+ const [modulePath, compiler, configFile] = process.argv.slice(1);
39
+ const { API, formatDiagnostics } = await import(pathToFileURL(modulePath).href);
40
+ const api = new API({ tsserverPath: compiler });
41
+ try {
42
+ const config = api.parseConfigFile(configFile);
43
+ if (config.errors.length) {
44
+ process.stdout.write(formatDiagnostics(config.errors, api));
45
+ process.exitCode = 1;
46
+ } else {
47
+ process.stdout.write(JSON.stringify({
48
+ compilerOptions: config.options,
49
+ files: config.fileNames,
50
+ references: config.projectReferences,
51
+ }));
52
+ }
53
+ } finally {
54
+ api.close();
55
+ }
56
+ `;
27
57
  const watchDependencyPath = (file)=>{
28
58
  if ('win32' !== process.platform) return file;
29
59
  try {
@@ -135,19 +165,37 @@ class UltramodernNativeTypeChecker {
135
165
  executable: selected,
136
166
  args: []
137
167
  } : selected;
138
- const result = await execute(command.executable, [
168
+ const inspect = '--showConfig' === args[0] && command.configApi;
169
+ const result = await execute(inspect ? process.execPath : command.executable, inspect ? [
170
+ '--input-type=module',
171
+ '--eval',
172
+ inspectNativeConfig,
173
+ command.configApi,
174
+ command.executable,
175
+ args[args.indexOf('--project') + 1]
176
+ ] : [
139
177
  ...command.args,
140
178
  ...args
141
179
  ], {
142
180
  cwd: node_path.dirname(this.options.configFile),
143
- maxBuffer: 16777216
181
+ env: {
182
+ ...process.env,
183
+ TSRS_CHECKER_ASSIGNMENT: process.env.TSRS_CHECKER_ASSIGNMENT || 'go'
184
+ },
185
+ maxBuffer: 16777216,
186
+ ...inspect ? {
187
+ timeout: 10000
188
+ } : {}
144
189
  });
145
190
  return result.stdout;
146
191
  } catch (cause) {
147
192
  const output = cause;
148
193
  const diagnostics = `${output.stdout ?? ''}${output.stderr ?? ''}`;
149
- throw new Error(`${native_type_checker_name} failed:\n${diagnostics || (cause instanceof Error ? cause.message : String(cause))}${missingJsxRuntimeHint(diagnostics)}`, {
194
+ throw Object.assign(new Error(`${native_type_checker_name} failed:\n${diagnostics || (cause instanceof Error ? cause.message : String(cause))}${missingJsxRuntimeHint(diagnostics)}`, {
150
195
  cause
196
+ }), {
197
+ code: output.code,
198
+ signal: output.signal
151
199
  });
152
200
  }
153
201
  }
@@ -209,9 +257,7 @@ class UltramodernNativeTypeChecker {
209
257
  this.removeProjection(configFile);
210
258
  }
211
259
  } catch (cause) {
212
- compilation.errors.push(new Error(cause instanceof Error ? cause.message : String(cause), {
213
- cause
214
- }));
260
+ compilation.errors.push(cause instanceof Error ? cause : new Error(String(cause)));
215
261
  }
216
262
  });
217
263
  });
@@ -20,7 +20,7 @@ const gitOutput = (workspaceRoot, args)=>{
20
20
  return;
21
21
  }
22
22
  };
23
- const createUltramodernReleaseBuildMarker = ({ generationBuildMarker, sourceRevision, unitId })=>createHash('sha256').update(`${BUILD_MARKER_NAMESPACE}:${unitId}:${generationBuildMarker}:${sourceRevision}`).digest('hex').slice(0, 16);
23
+ const createUltramodernReleaseBuildMarker = ({ generationBuildMarker, sourceRevision, unitId })=>createHash('sha256').update(`${BUILD_MARKER_NAMESPACE}:${unitId}:${generationBuildMarker}:${sourceRevision}`).digest('hex');
24
24
  const resolveUltramodernSourceRevision = (workspaceRoot = process.cwd(), configuredSourceRevision, environment = process.env)=>{
25
25
  const configuredArgumentValue = configuredSourceRevision?.trim();
26
26
  const configuredEnvironmentValue = environment.ULTRAMODERN_SOURCE_REVISION?.trim();
@@ -10,6 +10,7 @@ const LOCKFILES = [
10
10
  'bun.lock',
11
11
  'bun.lockb'
12
12
  ];
13
+ const RELEASE_BUILD_MARKER_PATTERN = /^[a-f0-9]{64}$/u;
13
14
  const processNonce = randomUUID();
14
15
  const sha256 = (value)=>createHash('sha256').update(value).digest('hex');
15
16
  function rendererProfileKey(profile) {
@@ -54,12 +55,21 @@ function resolveRendererBuildIdentities(options) {
54
55
  const projectRoot = node_path.resolve(options.projectRoot);
55
56
  const appId = options.appId ?? JSON.parse(node_fs.readFileSync(node_path.join(projectRoot, 'package.json'), 'utf8')).name;
56
57
  if ('string' != typeof appId || !appId || appId.trim() !== appId) throw new Error('Renderer application identity requires a delivery artifact appId or a package name.');
58
+ const { deliveryUnit } = options;
59
+ if (void 0 !== deliveryUnit && ('string' != typeof deliveryUnit.unitId || !deliveryUnit.unitId || deliveryUnit.unitId.trim() !== deliveryUnit.unitId)) throw new Error('Renderer delivery-unit identity requires a nonempty trimmed unitId.');
57
60
  const profileKey = rendererProfileKey(options.profile);
58
- const sourceRevision = resolveUltramodernSourceRevision(projectRoot, options.sourceRevision);
59
- const buildId = sha256(JSON.stringify([
61
+ const sourceRevision = resolveUltramodernSourceRevision(projectRoot, deliveryUnit ? deliveryUnit.sourceRevision : options.sourceRevision);
62
+ const promotable = 'production' === options.mode && 'workspace' !== sourceRevision;
63
+ let buildId;
64
+ if (promotable && deliveryUnit) {
65
+ if (deliveryUnit.sourceRevision !== sourceRevision || !RELEASE_BUILD_MARKER_PATTERN.test(deliveryUnit.buildMarker)) throw new Error(`Renderer delivery unit ${deliveryUnit.unitId} must carry the release identity of source revision ${sourceRevision}.`);
66
+ buildId = deliveryUnit.buildMarker;
67
+ } else buildId = sha256(JSON.stringify([
68
+ appId,
69
+ deliveryUnit?.unitId ?? null,
60
70
  profileKey,
61
71
  lockfileHash(projectRoot),
62
- 'development' === options.mode || 'workspace' === sourceRevision ? processNonce : sourceRevision
72
+ promotable ? sourceRevision : processNonce
63
73
  ]));
64
74
  const identities = Object.fromEntries(entries.map((entryName)=>[
65
75
  entryName,
@@ -306,7 +306,24 @@ async function invokeNativeRouteWorker(route, identity, request, env, ctx) {
306
306
  const resources =
307
307
  nativeRenderer?.renderer === identity.renderer &&
308
308
  Object.hasOwn(nativeRenderer.entries, route.entryName)
309
- ? nativeRenderer.entries[route.entryName]
309
+ ? {
310
+ ...nativeRenderer.entries[route.entryName],
311
+ ...(Object.hasOwn(nativeRenderer, 'workerFederation')
312
+ ? { workerFederation: nativeRenderer.workerFederation }
313
+ : {}),
314
+ ...(Object.hasOwn(nativeRenderer, 'workerFederationManifestUrl')
315
+ ? {
316
+ workerFederationManifestUrl:
317
+ nativeRenderer.workerFederationManifestUrl,
318
+ }
319
+ : {}),
320
+ ...(Object.hasOwn(nativeRenderer, 'workerFederationServices')
321
+ ? {
322
+ workerFederationServices:
323
+ nativeRenderer.workerFederationServices,
324
+ }
325
+ : {}),
326
+ }
310
327
  : undefined;
311
328
  // Native renderers have no Flight transport. Reject before the bundle loads.
312
329
  if (
@@ -10,8 +10,8 @@ const owningManifest = findPackageJSON(owningModuleUrl, owningModuleUrl);
10
10
  if (!owningManifest) throw new Error('Cannot find owning build-config package manifest');
11
11
  const owningName = JSON.parse(readFileSync(owningManifest, 'utf8')).name;
12
12
  if ('string' != typeof owningName || 0 === owningName.length) throw new Error(`Invalid owning build-config package name: ${owningManifest}`);
13
- const { effectCompilerDiscoveryFailureStage: effectCompilerDiscoveryFailureStage, resolveInstalledEffectCompiler: resolveInstalledEffectCompiler } = createRequire(owningModuleUrl)(`${owningName}/internal-effect-discovery`);
14
- const EFFECT_TSGO_RESOLUTION_ERROR = '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.';
13
+ const { effectCompilerDiscoveryFailureStage: effectCompilerDiscoveryFailureStage, resolveInstalledEffectCompiler: resolveInstalledEffectCompiler, validateConfiguredEffectCompiler: validateConfiguredEffectCompiler } = createRequire(owningModuleUrl)(`${owningName}/internal-effect-discovery`);
14
+ const EFFECT_TSGO_RESOLUTION_ERROR = '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.';
15
15
  const executableEffectTsgoCompilers = new Map();
16
16
  function effectTsgoResolutionError(cause, stage, from) {
17
17
  const detail = cause instanceof Error ? `${cause.name}: ${cause.message}` : String(cause);
@@ -20,10 +20,10 @@ function effectTsgoResolutionError(cause, stage, from) {
20
20
  });
21
21
  }
22
22
  function resolveExecutableEffectTsgoCompiler(compilerPath) {
23
- if ('win32' === process.platform) return compilerPath;
24
23
  const sourcePath = realpathSync(compilerPath);
25
24
  const source = lstatSync(sourcePath);
26
- if (!source.isFile()) throw new Error(`Effect TS-Go compiler path is not a regular file: ${sourcePath}`);
25
+ if (!source.isFile() || 0 === source.size) throw new Error(`Effect TS-Go compiler path is not a nonempty regular file: ${sourcePath}`);
26
+ if ('win32' === process.platform) return compilerPath;
27
27
  try {
28
28
  accessSync(sourcePath, constants.X_OK);
29
29
  return compilerPath;
@@ -73,7 +73,9 @@ function getBuildConfigEnvironment(name) {
73
73
  function resolveEffectTsgoCompiler(options) {
74
74
  const configuredCompiler = getBuildConfigEnvironment('EFFECT_TSGO_BIN')?.trim();
75
75
  if (configuredCompiler) try {
76
- return resolveExecutableEffectTsgoCompiler(configuredCompiler);
76
+ const compiler = resolveExecutableEffectTsgoCompiler(configuredCompiler);
77
+ validateConfiguredEffectCompiler(compiler, options.from);
78
+ return compiler;
77
79
  } catch (cause) {
78
80
  throw effectTsgoResolutionError(cause, 'Configured compiler validation', options.from);
79
81
  }
@@ -1,4 +1,5 @@
1
1
  import "node:module";
2
+ import { execFileSync } from "node:child_process";
2
3
  import { lstatSync, readFileSync, realpathSync } from "node:fs";
3
4
  import { createRequire } from "node:module";
4
5
  import { dirname, join, resolve } from "node:path";
@@ -9,7 +10,14 @@ const NATIVE_TYPESCRIPT_PACKAGES = [
9
10
  "typescript",
10
11
  "@typescript/native"
11
12
  ];
13
+ const EFFECT_TSRS_PROVIDER_VERSION = '0.59.0';
14
+ const EFFECT_TSRS_TARGETS = new Set([
15
+ '@tsrs/darwin-arm64',
16
+ '@tsrs/linux-x64-gnu',
17
+ '@tsrs/linux-arm64-gnu'
18
+ ]);
12
19
  const failureStages = new WeakMap();
20
+ const reportedUnsupportedTsrsTargets = new Set();
13
21
  function effectCompilerDiscoveryFailureStage(error) {
14
22
  return error && 'object' == typeof error ? failureStages.get(error) : void 0;
15
23
  }
@@ -27,7 +35,7 @@ function resolveEffectTsgoPackage(from) {
27
35
  cliPath
28
36
  };
29
37
  }
30
- function isAbsentNativeTypeScriptPackage(projectRequire, from, packageName, error) {
38
+ function isAbsentPackage(projectRequire, from, packageName, error) {
31
39
  const filename = 'string' != typeof from || from.startsWith('file:') ? fileURLToPath(from) : from;
32
40
  if (!(error instanceof Error) || !('code' in error) || 'MODULE_NOT_FOUND' !== error.code || 'path' in error && void 0 !== error.path || error.message.split('\n')[0] !== `Cannot find module '${packageName}/package.json'` || !('requireStack' in error) || !Array.isArray(error.requireStack) || error.requireStack[0] !== filename) return false;
33
41
  for (const searchDirectory of projectRequire.resolve.paths(packageName) ?? [])try {
@@ -48,7 +56,7 @@ function resolveNativeTypeScriptPackage(from) {
48
56
  try {
49
57
  packageJsonPath = projectRequire.resolve(`${packageName}/package.json`);
50
58
  } catch (error) {
51
- if (isAbsentNativeTypeScriptPackage(projectRequire, from, packageName, error)) continue;
59
+ if (isAbsentPackage(projectRequire, from, packageName, error)) continue;
52
60
  throw error;
53
61
  }
54
62
  const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
@@ -72,10 +80,85 @@ function readCompilerArtifact(filename) {
72
80
  if (0 === stats.size) throw new Error(`Compiler artifact is empty: ${filename}`);
73
81
  return canonicalPath;
74
82
  }
83
+ function resolveTsrsManifest(from) {
84
+ const projectRequire = createRequire(from);
85
+ try {
86
+ return projectRequire.resolve('tsrs/package.json');
87
+ } catch (error) {
88
+ if (isAbsentPackage(projectRequire, from, 'tsrs', error)) return;
89
+ throw error;
90
+ }
91
+ }
92
+ function compilerVersion(compiler) {
93
+ return execFileSync(compiler, [
94
+ '--version'
95
+ ], {
96
+ encoding: 'utf8',
97
+ env: {
98
+ ...process.env,
99
+ TSRS_CHECKER_ASSIGNMENT: process.env.TSRS_CHECKER_ASSIGNMENT || 'go'
100
+ },
101
+ timeout: 10000,
102
+ maxBuffer: 1048576
103
+ }).trim();
104
+ }
105
+ function tsrsPlatform(manifestPath) {
106
+ const manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
107
+ const { getPlatformPackageName } = createRequire(manifestPath)(join(dirname(manifestPath), 'lib/platform.js'));
108
+ const nativeName = getPlatformPackageName();
109
+ const embedded = manifest.tsrs;
110
+ if ('string' != typeof nativeName || !nativeName || !manifest.optionalDependencies || 'object' != typeof manifest.optionalDependencies || Array.isArray(manifest.optionalDependencies) || 0 === Object.keys(manifest.optionalDependencies).length) throw new Error(`Invalid native tsrs capability metadata: ${manifestPath}`);
111
+ if ('string' != typeof manifest.name || !manifest.name || 'string' != typeof manifest.version || !/^\d+\.\d+\.\d+-ts[\w.-]+$/u.test(manifest.version) || 'string' != typeof embedded?.typescriptVersion || !/^7\.\d+\.\d+(?:[-+][\w.-]+)?$/u.test(embedded.typescriptVersion) || !manifest.version.endsWith(`-ts${embedded.typescriptVersion}`) || 'string' != typeof embedded.typescriptCommit || !/^[a-f\d]{40}$/u.test(embedded.typescriptCommit)) throw new Error(`Invalid native tsrs metadata: ${manifestPath}`);
112
+ const supported = Object.hasOwn(manifest.optionalDependencies, nativeName);
113
+ if (supported && manifest.optionalDependencies[nativeName] !== manifest.version) throw new Error(`Native tsrs target version does not match its selected package: ${manifestPath}`);
114
+ return {
115
+ manifest: manifest,
116
+ nativeName,
117
+ supported
118
+ };
119
+ }
120
+ function resolveTsrsCompiler(manifestPath, effect, configuredCompiler, configuredVersion) {
121
+ const { manifest } = tsrsPlatform(manifestPath);
122
+ const embedded = manifest.tsrs;
123
+ const effectName = `@effect/tsgo-${process.platform}-${process.arch}`;
124
+ const effectManifest = createRequire(effect.cliPath).resolve(`${effectName}/package.json`);
125
+ const platform = JSON.parse(readFileSync(effectManifest, 'utf8'));
126
+ const metadataPath = join(dirname(effectManifest), 'lib/upstream.json');
127
+ const metadata = JSON.parse(readFileSync(metadataPath, 'utf8'));
128
+ const component = metadata.components?.tsrs?.[manifest.version];
129
+ if (platform.name !== effectName || platform.version !== effect.packageJson.version || 5 !== metadata.schemaVersion || !/^[a-f\d]{40}$/u.test(component?.gitHead ?? '') || component?.typescript?.version !== embedded.typescriptVersion || component.typescript.gitHead !== embedded.typescriptCommit) throw new Error(`Effect replacement metadata does not match tsrs: ${metadataPath}`);
130
+ const compiler = readCompilerArtifact(configuredCompiler ?? join(dirname(effectManifest), 'artifacts/tsrs', manifest.version, 'win32' === process.platform ? 'tsrs.exe' : 'tsrs'));
131
+ const version = configuredVersion ?? compilerVersion(compiler);
132
+ const stamp = /\+effect-tsgo\.([\d.]+)\s+\(tsrs ([^,]+), microsoft\/TypeScript@([a-f\d]+)\)$/u.exec(version);
133
+ if (!stamp || stamp[1] !== effect.packageJson.version || stamp[2] !== manifest.version || stamp[3].length < 12 || !embedded.typescriptCommit.startsWith(stamp[3])) throw new Error(`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.`);
134
+ return compiler;
135
+ }
136
+ function validateConfiguredEffectCompiler(compiler, from) {
137
+ const version = compilerVersion(compiler);
138
+ if (!/^Version \d+\.\d+\.\d+[\w.-]*\+effect-tsgo\.\d+\.\d+\.\d+(?:\s|$)/u.test(version)) throw new Error(`EFFECT_TSGO_BIN must select an Effect-enabled native compiler: ${compiler}`);
139
+ if (version.includes('(tsrs ')) {
140
+ const manifest = resolveTsrsManifest(from);
141
+ if (!manifest) throw new Error(`Cannot validate tsrs without its installed package metadata for ${String(from)}`);
142
+ resolveTsrsCompiler(manifest, resolveEffectTsgoPackage(from), compiler, version);
143
+ }
144
+ }
75
145
  function resolveInstalledEffectCompiler(from) {
76
146
  let stage = 'Package CLI resolution';
77
147
  try {
78
148
  const effect = resolveEffectTsgoPackage(from);
149
+ stage = 'Native tsrs package resolution';
150
+ const tsrsManifest = resolveTsrsManifest(from);
151
+ const tsrsTarget = tsrsManifest ? tsrsPlatform(tsrsManifest) : void 0;
152
+ if (tsrsTarget && effect.packageJson.version !== EFFECT_TSRS_PROVIDER_VERSION) throw new Error(`Unreviewed Effect tsrs capability contract: ${effect.packageJson.version}`);
153
+ const configuredTsrsCompiler = process.env.TSRS_BINARY || void 0;
154
+ if (tsrsManifest && tsrsTarget?.supported && (configuredTsrsCompiler || EFFECT_TSRS_TARGETS.has(tsrsTarget.nativeName))) {
155
+ stage = 'Native tsrs validation';
156
+ return resolveTsrsCompiler(tsrsManifest, effect, configuredTsrsCompiler);
157
+ }
158
+ if (tsrsTarget && !reportedUnsupportedTsrsTargets.has(tsrsTarget.nativeName)) {
159
+ reportedUnsupportedTsrsTargets.add(tsrsTarget.nativeName);
160
+ console.warn(`[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.`);
161
+ }
79
162
  stage = 'Native TypeScript package resolution';
80
163
  const typeScriptManifest = resolveNativeTypeScriptManifest(from);
81
164
  const typeScript = JSON.parse(readFileSync(typeScriptManifest, 'utf8'));
@@ -93,11 +176,13 @@ function resolveInstalledEffectCompiler(from) {
93
176
  const metadataPath = join(dirname(effectManifest), 'lib', 'upstream.json');
94
177
  const metadata = JSON.parse(readFileSync(metadataPath, 'utf8'));
95
178
  const component = metadata.components?.typescript?.[native.version];
96
- if (5 !== metadata.schemaVersion || component?.provider !== "typescript-go" || component.gitHead !== native.gitHead) throw new Error(`Effect replacement metadata does not match the selected native TypeScript backend: ${metadataPath}`);
97
- return readCompilerArtifact(join(dirname(effectManifest), 'artifacts', "typescript", native.version, binaryName));
179
+ const latestTypeScript = metadata.tags?.typescript?.latest;
180
+ if (5 !== metadata.schemaVersion || 'string' != typeof latestTypeScript || component?.provider !== "typescript-go" || component.gitHead !== native.gitHead) throw new Error(`Effect replacement metadata does not match the selected native TypeScript backend: ${metadataPath}`);
181
+ const compilerDirectory = native.version === latestTypeScript ? join(dirname(effectManifest), 'lib') : join(dirname(effectManifest), 'artifacts', "typescript", native.version);
182
+ return readCompilerArtifact(join(compilerDirectory, binaryName));
98
183
  } catch (error) {
99
184
  if (error && 'object' == typeof error && !failureStages.has(error)) failureStages.set(error, stage);
100
185
  throw error;
101
186
  }
102
187
  }
103
- export { effectCompilerDiscoveryFailureStage, resolveInstalledEffectCompiler };
188
+ export { effectCompilerDiscoveryFailureStage, resolveInstalledEffectCompiler, validateConfiguredEffectCompiler };
@@ -1,30 +1,60 @@
1
1
  import "node:module";
2
- import { execFile } from "node:child_process";
2
+ import { execFile, execFileSync } from "node:child_process";
3
3
  import { randomUUID } from "node:crypto";
4
- import { existsSync, readFileSync, realpathSync, statSync, unlinkSync, writeFileSync } from "node:fs";
4
+ import { existsSync, readFileSync, realpathSync, unlinkSync, writeFileSync } from "node:fs";
5
+ import { createRequire } from "node:module";
5
6
  import node_path from "node:path";
6
7
  import { promisify } from "node:util";
7
8
  import { refreshTsgoCheckerConfig } from "@modern-js/builder";
8
9
  import { parse, printParseErrorCode } from "jsonc-parser";
10
+ import { resolveEffectTsgoCompiler } from "./build-config/build-environment.mjs";
9
11
  const execute = promisify(execFile);
10
12
  const native_type_checker_name = 'UltramodernNativeTypeChecker';
11
- function resolveNativeTypeCheckerCommand(packageJsonPath) {
12
- const manifestFile = realpathSync(packageJsonPath);
13
- const directory = node_path.dirname(manifestFile);
14
- const manifest = JSON.parse(readFileSync(manifestFile, 'utf8'));
15
- if ("typescript" !== manifest.name || '7.0.2' !== manifest.version) throw new Error(`${native_type_checker_name} requires typescript@7.0.2; found ${String(manifest.name)}@${String(manifest.version)} at ${manifestFile}.`);
16
- const bin = manifest.bin?.tsc;
17
- if ('string' != typeof bin || !bin || node_path.isAbsolute(bin)) throw new Error(`${native_type_checker_name} requires the selected package's public tsc bin.`);
18
- const launcher = realpathSync(node_path.resolve(directory, bin));
19
- const relative = node_path.relative(directory, launcher);
20
- if (!relative || node_path.isAbsolute(relative) || '..' === relative || relative.startsWith(`..${node_path.sep}`) || !statSync(launcher).isFile()) throw new Error(`${native_type_checker_name} public tsc bin must belong to its selected package.`);
13
+ function resolveNativeTypeCheckerCommand(from) {
14
+ const executable = resolveEffectTsgoCompiler({
15
+ from
16
+ });
17
+ const version = execFileSync(executable, [
18
+ '--version'
19
+ ], {
20
+ encoding: 'utf8',
21
+ env: {
22
+ ...process.env,
23
+ TSRS_CHECKER_ASSIGNMENT: process.env.TSRS_CHECKER_ASSIGNMENT || 'go'
24
+ },
25
+ timeout: 10000
26
+ });
27
+ if (version.includes('(tsrs ')) return {
28
+ executable,
29
+ args: [],
30
+ configApi: createRequire(from).resolve('tsrs/sync')
31
+ };
21
32
  return {
22
- executable: process.execPath,
23
- args: [
24
- launcher
25
- ]
33
+ executable,
34
+ args: []
26
35
  };
27
36
  }
37
+ const inspectNativeConfig = `
38
+ import { pathToFileURL } from 'node:url';
39
+ const [modulePath, compiler, configFile] = process.argv.slice(1);
40
+ const { API, formatDiagnostics } = await import(pathToFileURL(modulePath).href);
41
+ const api = new API({ tsserverPath: compiler });
42
+ try {
43
+ const config = api.parseConfigFile(configFile);
44
+ if (config.errors.length) {
45
+ process.stdout.write(formatDiagnostics(config.errors, api));
46
+ process.exitCode = 1;
47
+ } else {
48
+ process.stdout.write(JSON.stringify({
49
+ compilerOptions: config.options,
50
+ files: config.fileNames,
51
+ references: config.projectReferences,
52
+ }));
53
+ }
54
+ } finally {
55
+ api.close();
56
+ }
57
+ `;
28
58
  const watchDependencyPath = (file)=>{
29
59
  if ('win32' !== process.platform) return file;
30
60
  try {
@@ -136,19 +166,37 @@ class UltramodernNativeTypeChecker {
136
166
  executable: selected,
137
167
  args: []
138
168
  } : selected;
139
- const result = await execute(command.executable, [
169
+ const inspect = '--showConfig' === args[0] && command.configApi;
170
+ const result = await execute(inspect ? process.execPath : command.executable, inspect ? [
171
+ '--input-type=module',
172
+ '--eval',
173
+ inspectNativeConfig,
174
+ command.configApi,
175
+ command.executable,
176
+ args[args.indexOf('--project') + 1]
177
+ ] : [
140
178
  ...command.args,
141
179
  ...args
142
180
  ], {
143
181
  cwd: node_path.dirname(this.options.configFile),
144
- maxBuffer: 16777216
182
+ env: {
183
+ ...process.env,
184
+ TSRS_CHECKER_ASSIGNMENT: process.env.TSRS_CHECKER_ASSIGNMENT || 'go'
185
+ },
186
+ maxBuffer: 16777216,
187
+ ...inspect ? {
188
+ timeout: 10000
189
+ } : {}
145
190
  });
146
191
  return result.stdout;
147
192
  } catch (cause) {
148
193
  const output = cause;
149
194
  const diagnostics = `${output.stdout ?? ''}${output.stderr ?? ''}`;
150
- throw new Error(`${native_type_checker_name} failed:\n${diagnostics || (cause instanceof Error ? cause.message : String(cause))}${missingJsxRuntimeHint(diagnostics)}`, {
195
+ throw Object.assign(new Error(`${native_type_checker_name} failed:\n${diagnostics || (cause instanceof Error ? cause.message : String(cause))}${missingJsxRuntimeHint(diagnostics)}`, {
151
196
  cause
197
+ }), {
198
+ code: output.code,
199
+ signal: output.signal
152
200
  });
153
201
  }
154
202
  }
@@ -210,9 +258,7 @@ class UltramodernNativeTypeChecker {
210
258
  this.removeProjection(configFile);
211
259
  }
212
260
  } catch (cause) {
213
- compilation.errors.push(new Error(cause instanceof Error ? cause.message : String(cause), {
214
- cause
215
- }));
261
+ compilation.errors.push(cause instanceof Error ? cause : new Error(String(cause)));
216
262
  }
217
263
  });
218
264
  });
@@ -21,7 +21,7 @@ const gitOutput = (workspaceRoot, args)=>{
21
21
  return;
22
22
  }
23
23
  };
24
- const createUltramodernReleaseBuildMarker = ({ generationBuildMarker, sourceRevision, unitId })=>createHash('sha256').update(`${BUILD_MARKER_NAMESPACE}:${unitId}:${generationBuildMarker}:${sourceRevision}`).digest('hex').slice(0, 16);
24
+ const createUltramodernReleaseBuildMarker = ({ generationBuildMarker, sourceRevision, unitId })=>createHash('sha256').update(`${BUILD_MARKER_NAMESPACE}:${unitId}:${generationBuildMarker}:${sourceRevision}`).digest('hex');
25
25
  const resolveUltramodernSourceRevision = (workspaceRoot = process.cwd(), configuredSourceRevision, environment = process.env)=>{
26
26
  const configuredArgumentValue = configuredSourceRevision?.trim();
27
27
  const configuredEnvironmentValue = environment.ULTRAMODERN_SOURCE_REVISION?.trim();
@@ -11,6 +11,7 @@ const LOCKFILES = [
11
11
  'bun.lock',
12
12
  'bun.lockb'
13
13
  ];
14
+ const RELEASE_BUILD_MARKER_PATTERN = /^[a-f0-9]{64}$/u;
14
15
  const processNonce = randomUUID();
15
16
  const sha256 = (value)=>createHash('sha256').update(value).digest('hex');
16
17
  function rendererProfileKey(profile) {
@@ -55,12 +56,21 @@ function resolveRendererBuildIdentities(options) {
55
56
  const projectRoot = node_path.resolve(options.projectRoot);
56
57
  const appId = options.appId ?? JSON.parse(node_fs.readFileSync(node_path.join(projectRoot, 'package.json'), 'utf8')).name;
57
58
  if ('string' != typeof appId || !appId || appId.trim() !== appId) throw new Error('Renderer application identity requires a delivery artifact appId or a package name.');
59
+ const { deliveryUnit } = options;
60
+ if (void 0 !== deliveryUnit && ('string' != typeof deliveryUnit.unitId || !deliveryUnit.unitId || deliveryUnit.unitId.trim() !== deliveryUnit.unitId)) throw new Error('Renderer delivery-unit identity requires a nonempty trimmed unitId.');
58
61
  const profileKey = rendererProfileKey(options.profile);
59
- const sourceRevision = resolveUltramodernSourceRevision(projectRoot, options.sourceRevision);
60
- const buildId = sha256(JSON.stringify([
62
+ const sourceRevision = resolveUltramodernSourceRevision(projectRoot, deliveryUnit ? deliveryUnit.sourceRevision : options.sourceRevision);
63
+ const promotable = 'production' === options.mode && 'workspace' !== sourceRevision;
64
+ let buildId;
65
+ if (promotable && deliveryUnit) {
66
+ if (deliveryUnit.sourceRevision !== sourceRevision || !RELEASE_BUILD_MARKER_PATTERN.test(deliveryUnit.buildMarker)) throw new Error(`Renderer delivery unit ${deliveryUnit.unitId} must carry the release identity of source revision ${sourceRevision}.`);
67
+ buildId = deliveryUnit.buildMarker;
68
+ } else buildId = sha256(JSON.stringify([
69
+ appId,
70
+ deliveryUnit?.unitId ?? null,
61
71
  profileKey,
62
72
  lockfileHash(projectRoot),
63
- 'development' === options.mode || 'workspace' === sourceRevision ? processNonce : sourceRevision
73
+ promotable ? sourceRevision : processNonce
64
74
  ]));
65
75
  const identities = Object.fromEntries(entries.map((entryName)=>[
66
76
  entryName,
@@ -306,7 +306,24 @@ async function invokeNativeRouteWorker(route, identity, request, env, ctx) {
306
306
  const resources =
307
307
  nativeRenderer?.renderer === identity.renderer &&
308
308
  Object.hasOwn(nativeRenderer.entries, route.entryName)
309
- ? nativeRenderer.entries[route.entryName]
309
+ ? {
310
+ ...nativeRenderer.entries[route.entryName],
311
+ ...(Object.hasOwn(nativeRenderer, 'workerFederation')
312
+ ? { workerFederation: nativeRenderer.workerFederation }
313
+ : {}),
314
+ ...(Object.hasOwn(nativeRenderer, 'workerFederationManifestUrl')
315
+ ? {
316
+ workerFederationManifestUrl:
317
+ nativeRenderer.workerFederationManifestUrl,
318
+ }
319
+ : {}),
320
+ ...(Object.hasOwn(nativeRenderer, 'workerFederationServices')
321
+ ? {
322
+ workerFederationServices:
323
+ nativeRenderer.workerFederationServices,
324
+ }
325
+ : {}),
326
+ }
310
327
  : undefined;
311
328
  // Native renderers have no Flight transport. Reject before the bundle loads.
312
329
  if (
@@ -9,6 +9,8 @@ export type ResolveEffectTsgoCompilerOptions = {
9
9
  from: string | URL;
10
10
  };
11
11
  /**
12
- * Resolves the Effect TS-Go executable used by Module Federation DTS builds.
12
+ * Resolves the Effect-enabled native executable for checking and DTS builds.
13
+ * Use metadata-bound tsrs where both tsrs and the Effect provider support it.
14
+ * Unsupported targets use Effect-Go. Missing supported artifacts remain fatal.
13
15
  */
14
16
  export declare function resolveEffectTsgoCompiler(options: ResolveEffectTsgoCompilerOptions): string;
@@ -1,4 +1,6 @@
1
1
  import { type URL } from 'node:url';
2
2
  export declare function effectCompilerDiscoveryFailureStage(error: unknown): string | undefined;
3
- /** Selects the exact native replacement without invoking the provider. */
3
+ /** Explicit native binaries must still report Effect diagnostics support. */
4
+ export declare function validateConfiguredEffectCompiler(compiler: string, from: string | URL): void;
5
+ /** Selects the exact native replacement without invoking the provider CLI. */
4
6
  export declare function resolveInstalledEffectCompiler(from: string | URL): string;
@@ -1,3 +1,4 @@
1
+ import type { BffEffectDataPlatformUserConfig, BffEffectOpenApiUserConfig } from '@modern-js/server-runtime-extensions/server-config';
1
2
  import type { DeliveryUnitStamp } from './delivery-unit.js';
2
3
  import type { CloudflareAppContext, CloudflareModernConfig } from './types.js';
3
4
  export declare const createWorkerManifest: (outputDirectory: string, modernConfig: CloudflareModernConfig, appContext: CloudflareAppContext, deliveryUnitStamp: DeliveryUnitStamp | undefined) => Promise<{
@@ -118,8 +119,8 @@ export declare const createWorkerManifest: (outputDirectory: string, modernConfi
118
119
  prefix: string;
119
120
  worker: string;
120
121
  effect: {
121
- openapi?: import("@modern-js/runtime-extensions/server-config").BffEffectOpenApiUserConfig | undefined;
122
- dataPlatform?: import("@modern-js/runtime-extensions/server-config").BffEffectDataPlatformUserConfig | undefined;
122
+ openapi?: BffEffectOpenApiUserConfig | undefined;
123
+ dataPlatform?: BffEffectDataPlatformUserConfig | undefined;
123
124
  crossProjectPolicy: {
124
125
  allowedNamespaces?: string[];
125
126
  verifyProducerIdentity?: (headers: Record<string, unknown>) => string | undefined;
@@ -226,6 +226,10 @@ export interface CloudflareWorkerDeployConfig {
226
226
  * `env[binding].fetch(request)`.
227
227
  */
228
228
  services?: CloudflareWorkerServiceBindingConfig[];
229
+ /** Native Worker context profiles, registered before federated exposes load. */
230
+ federation?: {
231
+ contextProfiles?: readonly string[];
232
+ };
229
233
  /**
230
234
  * First-class Workers VPC service bindings to private origins reached
231
235
  * through a Cloudflare Tunnel. Modern.js writes these to `wrangler.json`
@@ -2,9 +2,11 @@ import type { Rspack, RspackChain } from '@rsbuild/core';
2
2
  export interface NativeTypeCheckerCommand {
3
3
  executable: string;
4
4
  args: readonly string[];
5
+ /** The selected package's native config API. tsrs has no --showConfig CLI. */
6
+ configApi?: string;
5
7
  }
6
- /** Launch the selected stable package through its declared public compiler bin. */
7
- export declare function resolveNativeTypeCheckerCommand(packageJsonPath: string): NativeTypeCheckerCommand;
8
+ /** Resolve the Effect-enabled native compiler from the application's origin. */
9
+ export declare function resolveNativeTypeCheckerCommand(from: string): NativeTypeCheckerCommand;
8
10
  interface TypeCheckerConfig {
9
11
  compilerOptions?: Record<string, unknown>;
10
12
  references?: Array<{