@bleedingdev/modern-js-app-tools-extensions 3.8.3-ultramodern.6 → 3.9.0-ultramodern.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (133) hide show
  1. package/dist/cjs/backend-federation-build/codegen.js +256 -0
  2. package/dist/cjs/backend-federation-build/config.js +189 -0
  3. package/dist/cjs/backend-federation-build/emit.js +150 -0
  4. package/dist/cjs/backend-federation-build/index.js +53 -0
  5. package/dist/cjs/build-config/build-environment.js +268 -0
  6. package/dist/cjs/build-config/precompress/plugin.js +124 -0
  7. package/dist/cjs/build-config/precompress/types.js +18 -0
  8. package/dist/cjs/build-config/public.js +46 -0
  9. package/dist/cjs/cloudflare/constants.js +1 -1
  10. package/dist/cjs/cloudflare/delivery-unit.js +7 -16
  11. package/dist/cjs/cloudflare-output-contract.js +37 -1
  12. package/dist/cjs/cloudflare-output-verifier/identity.js +6 -6
  13. package/dist/cjs/cloudflare-output-verifier/worker-bundles.js +4 -1
  14. package/dist/cjs/config.js +29 -1
  15. package/dist/cjs/deploy-output/npmAliases.js +226 -0
  16. package/dist/cjs/deploy-output/plugin.js +76 -0
  17. package/dist/cjs/deploy-output/target.js +48 -0
  18. package/dist/cjs/native-type-checker.js +193 -0
  19. package/dist/cjs/policy-defaults.js +101 -0
  20. package/dist/cjs/release-envelope/framework-output.js +77 -32
  21. package/dist/cjs/release-envelope/plugin.js +5 -3
  22. package/dist/cjs/release-identity.js +3 -6
  23. package/dist/cjs/runtime-package-resolution.js +118 -0
  24. package/dist/esm/backend-federation-build/codegen.mjs +205 -0
  25. package/dist/esm/backend-federation-build/config.mjs +116 -0
  26. package/dist/esm/backend-federation-build/emit.mjs +99 -0
  27. package/dist/esm/backend-federation-build/index.mjs +1 -0
  28. package/dist/esm/build-config/build-environment.mjs +224 -0
  29. package/dist/esm/build-config/precompress/plugin.mjs +76 -0
  30. package/dist/esm/build-config/precompress/types.mjs +0 -0
  31. package/dist/esm/build-config/public.mjs +1 -0
  32. package/dist/esm/cloudflare/constants.mjs +1 -1
  33. package/dist/esm/cloudflare/delivery-unit.mjs +1 -10
  34. package/dist/esm/cloudflare-output-contract.mjs +35 -2
  35. package/dist/esm/cloudflare-output-verifier/identity.mjs +1 -1
  36. package/dist/esm/cloudflare-output-verifier/worker-bundles.mjs +5 -2
  37. package/dist/esm/config.mjs +1 -0
  38. package/dist/esm/deploy-output/npmAliases.mjs +174 -0
  39. package/dist/esm/deploy-output/plugin.mjs +28 -0
  40. package/dist/esm/deploy-output/target.mjs +10 -0
  41. package/dist/esm/native-type-checker.mjs +142 -0
  42. package/dist/esm/policy-defaults.mjs +45 -0
  43. package/dist/esm/release-envelope/framework-output.mjs +51 -6
  44. package/dist/esm/release-envelope/plugin.mjs +5 -3
  45. package/dist/esm/release-identity.mjs +3 -6
  46. package/dist/esm/runtime-package-resolution.mjs +60 -0
  47. package/dist/esm-node/backend-federation-build/codegen.mjs +206 -0
  48. package/dist/esm-node/backend-federation-build/config.mjs +117 -0
  49. package/dist/esm-node/backend-federation-build/emit.mjs +100 -0
  50. package/dist/esm-node/backend-federation-build/index.mjs +2 -0
  51. package/dist/esm-node/build-config/build-environment.mjs +225 -0
  52. package/dist/esm-node/build-config/precompress/plugin.mjs +77 -0
  53. package/dist/esm-node/build-config/precompress/types.mjs +1 -0
  54. package/dist/esm-node/build-config/public.mjs +2 -0
  55. package/dist/esm-node/cloudflare/constants.mjs +1 -1
  56. package/dist/esm-node/cloudflare/delivery-unit.mjs +1 -10
  57. package/dist/esm-node/cloudflare-output-contract.mjs +35 -2
  58. package/dist/esm-node/cloudflare-output-verifier/identity.mjs +1 -1
  59. package/dist/esm-node/cloudflare-output-verifier/worker-bundles.mjs +5 -2
  60. package/dist/esm-node/config.mjs +1 -0
  61. package/dist/esm-node/deploy-output/npmAliases.mjs +175 -0
  62. package/dist/esm-node/deploy-output/plugin.mjs +31 -0
  63. package/dist/esm-node/deploy-output/target.mjs +11 -0
  64. package/dist/esm-node/native-type-checker.mjs +143 -0
  65. package/dist/esm-node/policy-defaults.mjs +46 -0
  66. package/dist/esm-node/release-envelope/framework-output.mjs +51 -6
  67. package/dist/esm-node/release-envelope/plugin.mjs +5 -3
  68. package/dist/esm-node/release-identity.mjs +3 -6
  69. package/dist/esm-node/runtime-package-resolution.mjs +61 -0
  70. package/dist/types/backend-federation-build/codegen.d.ts +86 -0
  71. package/dist/types/backend-federation-build/config.d.ts +102 -0
  72. package/dist/types/backend-federation-build/emit.d.ts +21 -0
  73. package/dist/types/backend-federation-build/index.d.ts +2 -0
  74. package/dist/types/build-config/build-environment.d.ts +22 -0
  75. package/dist/types/build-config/precompress/plugin.d.ts +4 -0
  76. package/dist/types/build-config/precompress/types.d.ts +19 -0
  77. package/dist/types/build-config/public.d.ts +2 -0
  78. package/dist/types/cloudflare/artifacts.d.ts +1 -1
  79. package/dist/types/cloudflare/constants.d.ts +2 -2
  80. package/dist/types/cloudflare/delivery-unit.d.ts +2 -2
  81. package/dist/types/cloudflare/i18n-worker.d.ts +1 -1
  82. package/dist/types/cloudflare/index.d.ts +1 -1
  83. package/dist/types/cloudflare/security-policies.d.ts +1 -1
  84. package/dist/types/cloudflare/types.d.ts +1 -1
  85. package/dist/types/cloudflare/utils.d.ts +1 -1
  86. package/dist/types/cloudflare/worker-manifest.d.ts +4 -4
  87. package/dist/types/cloudflare/wrangler-config.d.ts +2 -2
  88. package/dist/types/cloudflare-output-contract.d.ts +2 -1
  89. package/dist/types/cloudflare-output-plan.d.ts +1 -1
  90. package/dist/types/cloudflare-output-verifier/identity.d.ts +2 -2
  91. package/dist/types/cloudflare-output-verifier/index.d.ts +5 -5
  92. package/dist/types/cloudflare-output-verifier/manifest.d.ts +1 -1
  93. package/dist/types/cloudflare-output-verifier/mutation-policy.d.ts +1 -1
  94. package/dist/types/cloudflare-output-verifier/worker-bundles.d.ts +1 -1
  95. package/dist/types/config.d.ts +2 -0
  96. package/dist/types/deploy-output/npmAliases.d.ts +14 -0
  97. package/dist/types/deploy-output/plugin.d.ts +15 -0
  98. package/dist/types/deploy-output/target.d.ts +6 -0
  99. package/dist/types/index.d.ts +10 -10
  100. package/dist/types/native-type-checker.d.ts +15 -0
  101. package/dist/types/policy-defaults.d.ts +46 -0
  102. package/dist/types/precompress/LICENSE +20 -0
  103. package/dist/types/precompress/index.d.ts +76 -0
  104. package/dist/types/release-envelope/canonical.d.ts +1 -1
  105. package/dist/types/release-envelope/framework-output.d.ts +3 -2
  106. package/dist/types/release-envelope/index.d.ts +3 -3
  107. package/dist/types/runtime-package-resolution.d.ts +28 -0
  108. package/package.json +72 -14
  109. package/src/backend-federation-build/codegen.ts +245 -0
  110. package/src/backend-federation-build/config.ts +356 -0
  111. package/src/backend-federation-build/emit.ts +202 -0
  112. package/src/backend-federation-build/index.ts +2 -0
  113. package/src/build-config/build-environment.ts +404 -0
  114. package/src/build-config/precompress/plugin.ts +140 -0
  115. package/src/build-config/precompress/types.ts +26 -0
  116. package/src/build-config/public.ts +6 -0
  117. package/src/cloudflare/constants.ts +1 -1
  118. package/src/cloudflare/delivery-unit.ts +3 -20
  119. package/src/cloudflare/worker-manifest.ts +1 -0
  120. package/src/cloudflare-builder.ts +1 -0
  121. package/src/cloudflare-output-contract.ts +37 -0
  122. package/src/cloudflare-output-verifier/identity.ts +1 -1
  123. package/src/cloudflare-output-verifier/worker-bundles.ts +5 -3
  124. package/src/config.ts +7 -0
  125. package/src/deploy-output/npmAliases.ts +333 -0
  126. package/src/deploy-output/plugin.ts +49 -0
  127. package/src/deploy-output/target.ts +23 -0
  128. package/src/native-type-checker.ts +183 -0
  129. package/src/policy-defaults.ts +127 -0
  130. package/src/release-envelope/framework-output.ts +135 -4
  131. package/src/release-envelope/plugin.ts +15 -3
  132. package/src/release-identity.ts +3 -2
  133. package/src/runtime-package-resolution.ts +115 -0
@@ -0,0 +1,143 @@
1
+ import "node:module";
2
+ import { execFile } from "node:child_process";
3
+ import { existsSync, realpathSync } from "node:fs";
4
+ import node_path from "node:path";
5
+ import { promisify } from "node:util";
6
+ import { refreshTsgoCheckerConfig } from "@modern-js/builder";
7
+ const execute = promisify(execFile);
8
+ const native_type_checker_name = 'UltramodernNativeTypeChecker';
9
+ const watchDependencyPath = (file)=>{
10
+ if ('win32' !== process.platform) return file;
11
+ try {
12
+ return realpathSync.native(file);
13
+ } catch {
14
+ return file;
15
+ }
16
+ };
17
+ class UltramodernNativeTypeChecker {
18
+ async check() {
19
+ const { configFile, build } = this.options;
20
+ if (!build) {
21
+ const config = JSON.parse(await this.run([
22
+ '--showConfig',
23
+ '--project',
24
+ configFile
25
+ ]));
26
+ if (config.references?.length) await this.run([
27
+ '--build',
28
+ ...config.references.map((reference)=>node_path.resolve(node_path.dirname(configFile), reference.path)),
29
+ '--stopBuildOnErrors',
30
+ '--pretty',
31
+ 'false'
32
+ ]);
33
+ }
34
+ const args = build ? [
35
+ '--build',
36
+ configFile,
37
+ '--stopBuildOnErrors'
38
+ ] : [
39
+ '--project',
40
+ configFile,
41
+ '--noEmit'
42
+ ];
43
+ await this.run([
44
+ ...args,
45
+ '--pretty',
46
+ 'false'
47
+ ]);
48
+ }
49
+ async run(args) {
50
+ try {
51
+ const result = await execute(this.options.compiler(), args, {
52
+ cwd: node_path.dirname(this.options.configFile),
53
+ maxBuffer: 16777216
54
+ });
55
+ return result.stdout;
56
+ } catch (cause) {
57
+ const output = cause;
58
+ const diagnostics = `${output.stdout ?? ''}${output.stderr ?? ''}`;
59
+ throw new Error(`${native_type_checker_name} failed:\n${diagnostics || (cause instanceof Error ? cause.message : String(cause))}`, {
60
+ cause
61
+ });
62
+ }
63
+ }
64
+ async watchInputs() {
65
+ const inputs = new Set();
66
+ const missing = new Set();
67
+ const projects = [
68
+ this.options.configFile
69
+ ];
70
+ const visited = new Set();
71
+ for (const configFile of projects){
72
+ if (visited.has(configFile)) continue;
73
+ visited.add(configFile);
74
+ inputs.add(configFile);
75
+ if (!existsSync(configFile)) {
76
+ missing.add(configFile);
77
+ continue;
78
+ }
79
+ let config;
80
+ try {
81
+ config = JSON.parse(await this.run([
82
+ '--showConfig',
83
+ '--project',
84
+ configFile
85
+ ]));
86
+ } catch {
87
+ continue;
88
+ }
89
+ const directory = node_path.dirname(configFile);
90
+ for (const file of config.files ?? [])inputs.add(node_path.resolve(directory, file));
91
+ for (const reference of config.references ?? []){
92
+ const target = node_path.resolve(directory, reference.path);
93
+ projects.push('.json' === node_path.extname(target) ? target : node_path.join(target, 'tsconfig.json'));
94
+ }
95
+ }
96
+ return {
97
+ inputs,
98
+ missing
99
+ };
100
+ }
101
+ apply(compiler) {
102
+ compiler.hooks.thisCompilation.tap(native_type_checker_name, (compilation)=>{
103
+ compilation.hooks.processAssets.tapPromise(native_type_checker_name, async ()=>{
104
+ try {
105
+ compilation.fileDependencies.add(watchDependencyPath(this.options.configFile));
106
+ const projectConfigFile = refreshTsgoCheckerConfig(this.options.configFile);
107
+ if (projectConfigFile) {
108
+ const watched = watchDependencyPath(projectConfigFile);
109
+ compilation.fileDependencies.add(watched);
110
+ if (!existsSync(projectConfigFile)) compilation.missingDependencies.add(watched);
111
+ }
112
+ const { inputs, missing } = await this.watchInputs();
113
+ for (const file of inputs)compilation.fileDependencies.add(watchDependencyPath(file));
114
+ for (const file of missing)compilation.missingDependencies.add(watchDependencyPath(file));
115
+ await this.check();
116
+ } catch (cause) {
117
+ compilation.errors.push(new Error(cause instanceof Error ? cause.message : String(cause), {
118
+ cause
119
+ }));
120
+ }
121
+ });
122
+ });
123
+ }
124
+ constructor(options){
125
+ this.options = options;
126
+ }
127
+ }
128
+ function configureUltramodernTypeChecker(chain, pluginId, resolveCompiler) {
129
+ if (!chain.plugins.has(pluginId)) return;
130
+ const options = chain.plugin(pluginId).get('args')?.[0];
131
+ const typescript = options?.typescript;
132
+ if (typescript?.tsgo === false) return;
133
+ if (!typescript?.configFile) throw new Error(`${native_type_checker_name} requires the configured TypeScript project.`);
134
+ const configFile = node_path.resolve(typescript.configFile);
135
+ chain.plugin(pluginId).use(UltramodernNativeTypeChecker, [
136
+ {
137
+ build: true === typescript.build,
138
+ compiler: ()=>resolveCompiler(configFile),
139
+ configFile
140
+ }
141
+ ]);
142
+ }
143
+ export { UltramodernNativeTypeChecker, configureUltramodernTypeChecker };
@@ -0,0 +1,46 @@
1
+ import "node:module";
2
+ import { collectRuntimePackageModuleDirectories, createRuntimePackageResolutionPlugin } from "./runtime-package-resolution.mjs";
3
+ const RENDERER_EXTENSIONS_PACKAGE = '@modern-js/runtime-renderer-extensions';
4
+ const RENDERER_EXTENSIONS_PLUGIN_NAME = 'rendererHead';
5
+ const SERVER_EXTENSIONS_PLUGIN_NAME = '@modern-js/app-tools/server-plugin';
6
+ const POLICY_DEFAULTS_PLUGIN_NAME = '@modern-js/ultramodern-policy-defaults';
7
+ const applyPolicyDefaults = (api, options = {})=>{
8
+ if (false !== options.rendererExtensions) {
9
+ api._internalRuntimePlugins(({ entrypoint, plugins })=>{
10
+ if (!plugins.some((plugin)=>plugin.path === RENDERER_EXTENSIONS_PACKAGE)) plugins.push({
11
+ name: RENDERER_EXTENSIONS_PLUGIN_NAME,
12
+ path: RENDERER_EXTENSIONS_PACKAGE,
13
+ config: {}
14
+ });
15
+ return {
16
+ entrypoint,
17
+ plugins
18
+ };
19
+ });
20
+ const moduleDirectories = collectRuntimePackageModuleDirectories([
21
+ RENDERER_EXTENSIONS_PACKAGE
22
+ ], import.meta.url);
23
+ if (moduleDirectories.length > 0) api.modifyResolvedConfig((config)=>({
24
+ ...config,
25
+ builderPlugins: [
26
+ ...config.builderPlugins ?? [],
27
+ createRuntimePackageResolutionPlugin(moduleDirectories)
28
+ ]
29
+ }));
30
+ }
31
+ if (false !== options.serverExtensions) api._internalServerPlugins(({ plugins })=>{
32
+ if (!plugins.some((plugin)=>plugin.name === SERVER_EXTENSIONS_PLUGIN_NAME)) plugins.push({
33
+ name: SERVER_EXTENSIONS_PLUGIN_NAME
34
+ });
35
+ return {
36
+ plugins
37
+ };
38
+ });
39
+ };
40
+ const createPolicyDefaultsPlugin = (options = {})=>({
41
+ name: POLICY_DEFAULTS_PLUGIN_NAME,
42
+ setup (api) {
43
+ applyPolicyDefaults(api, options);
44
+ }
45
+ });
46
+ export { POLICY_DEFAULTS_PLUGIN_NAME, RENDERER_EXTENSIONS_PACKAGE, RENDERER_EXTENSIONS_PLUGIN_NAME, SERVER_EXTENSIONS_PLUGIN_NAME, applyPolicyDefaults, createPolicyDefaultsPlugin };
@@ -2,7 +2,7 @@ import "node:module";
2
2
  import { createHash } from "node:crypto";
3
3
  import promises from "node:fs/promises";
4
4
  import node_path from "node:path";
5
- import { BACKEND_FEDERATION_MANIFEST_FILE, BACKEND_FEDERATION_REMOTE_ENTRY_FILE, ULTRAMODERN_BUILD_ARTIFACT_FILE, isUltramodernBuildArtifact } from "@modern-js/utils/universal";
5
+ import { BACKEND_FEDERATION_MANIFEST_FILE, BACKEND_FEDERATION_REMOTE_ENTRY_FILE, ULTRAMODERN_BUILD_ARTIFACT_FILE, isUltramodernBuildArtifact } from "@modern-js/backend-federation-contracts";
6
6
  import { canonicalSerializeMicroVerticalReleaseEnvelope, createMicroVerticalReleaseEnvelope, verifyMicroVerticalReleaseEnvelope } from "./index.mjs";
7
7
  const MICROVERTICAL_RELEASE_ENVELOPE_PATH = 'release/microvertical-release-envelope.json';
8
8
  const MICROVERTICAL_RELEASE_IDENTITY_CARRIERS_PATH = 'release/microvertical-release-identity-carriers.json';
@@ -22,6 +22,46 @@ const collectNestedStrings = (value, key)=>{
22
22
  ...collectNestedStrings(entryValue, key)
23
23
  ]);
24
24
  };
25
+ const emptyProducerRouteModules = async (distDirectory, files, manifest, manifestLogicalPath)=>{
26
+ if (!isRecord(manifest) || !Array.isArray(manifest.exposes) || 0 !== manifest.exposes.length || !Array.isArray(manifest.remotes) || 0 !== manifest.remotes.length || !isRecord(manifest.metaData) || !isRecord(manifest.metaData.remoteEntry) || '' !== manifest.metaData.remoteEntry.name || '' !== manifest.metaData.remoteEntry.path || 'global' !== manifest.metaData.remoteEntry.type) return [];
27
+ const publicPath = manifest.metaData.publicPath;
28
+ const safeReference = (value)=>'string' == typeof value && value.length > 0 && !/[\\\\%?#\s]/u.test(value) && !value.split('/').some((segment)=>'.' === segment || '..' === segment);
29
+ if (!safeReference(publicPath)) return [];
30
+ const absoluteBase = /^https?:\/\//u.test(publicPath);
31
+ if ('auto' !== publicPath && (!publicPath.endsWith('/') || !absoluteBase && (!publicPath.startsWith('/') || publicPath.startsWith('//')))) return [];
32
+ if (absoluteBase) {
33
+ const base = new URL(publicPath);
34
+ if (base.username || base.password || base.href !== publicPath) return [];
35
+ }
36
+ const directory = node_path.posix.dirname(manifestLogicalPath);
37
+ const routesManifest = await readJson(node_path.join(distDirectory, directory, 'routes-manifest.json'));
38
+ if (!isRecord(routesManifest) || !isRecord(routesManifest.routeAssets)) return [];
39
+ const modules = new Set();
40
+ for (const route of Object.values(routesManifest.routeAssets)){
41
+ if (!isRecord(route) || !Array.isArray(route.assets)) return [];
42
+ for (const reference of route.assets){
43
+ if (!safeReference(reference) || reference.startsWith('//')) return [];
44
+ let relative = reference;
45
+ if (/^https?:\/\//u.test(reference)) {
46
+ if (!absoluteBase || !reference.startsWith(publicPath)) return [];
47
+ relative = reference.slice(publicPath.length);
48
+ } else if (reference.startsWith('/')) {
49
+ const prefix = 'auto' === publicPath ? '/' : absoluteBase ? new URL(publicPath).pathname : publicPath;
50
+ if (!reference.startsWith(prefix)) return [];
51
+ relative = reference.slice(prefix.length);
52
+ }
53
+ if (!/^(?:static|html|public)\/[^:]+$/u.test(relative) || relative.includes('//')) return [];
54
+ const logicalPath = node_path.posix.join(directory, relative);
55
+ if (!files.includes(logicalPath)) return [];
56
+ const assetStat = await promises.lstat(node_path.join(distDirectory, logicalPath));
57
+ if (!assetStat.isFile()) return [];
58
+ if (COMPILED_MODULE_PATTERN.test(logicalPath)) modules.add(logicalPath);
59
+ }
60
+ }
61
+ return [
62
+ ...modules
63
+ ];
64
+ };
25
65
  const manifestReferencedClientModules = async (distDirectory, files, manifestLogicalPath = 'mf-manifest.json')=>{
26
66
  const manifest = await readJson(node_path.join(distDirectory, manifestLogicalPath));
27
67
  const references = [
@@ -31,9 +71,10 @@ const manifestReferencedClientModules = async (distDirectory, files, manifestLog
31
71
  ...collectNestedStrings(manifest, 'async')
32
72
  ];
33
73
  const normalizedReferences = new Set(references.filter((value)=>'string' == typeof value).map((value)=>value.replace(/^https?:\/\/[^/]+/u, '')).map((value)=>value.replace(/^\/+/u, '')));
34
- return files.filter((logicalPath)=>COMPILED_MODULE_PATTERN.test(logicalPath) && [
74
+ const modules = files.filter((logicalPath)=>COMPILED_MODULE_PATTERN.test(logicalPath) && [
35
75
  ...normalizedReferences
36
76
  ].some((reference)=>reference === logicalPath || reference.endsWith(`/${logicalPath}`) || logicalPath.endsWith(`/${reference}`)));
77
+ return modules.length > 0 ? modules : emptyProducerRouteModules(distDirectory, files, manifest, manifestLogicalPath);
37
78
  };
38
79
  const routeReferencedSsrModules = async (distDirectory, files, target, routeSpecLogicalPath = 'route.json')=>{
39
80
  const routeSpec = await readJson(node_path.join(distDirectory, routeSpecLogicalPath));
@@ -83,11 +124,14 @@ const writeReleaseEnvelope = async (artifactRoot, envelope)=>{
83
124
  if (!envelopePath) throw new Error('[ultramodern-release-envelope] could not resolve release envelope path.');
84
125
  await promises.writeFile(envelopePath, `${canonicalSerializeMicroVerticalReleaseEnvelope(envelope)}\n`);
85
126
  };
86
- const readBuildArtifact = async (distDirectory)=>{
127
+ const readBuildArtifact = async (distDirectory, requirePromotable = true)=>{
87
128
  const artifactPath = node_path.join(distDirectory, ULTRAMODERN_BUILD_ARTIFACT_FILE);
88
129
  const artifact = await readJson(artifactPath);
89
130
  if (!isUltramodernBuildArtifact(artifact)) throw new Error(`[ultramodern-release-envelope] ${ULTRAMODERN_BUILD_ARTIFACT_FILE} is missing or invalid.`);
90
- if ('workspace' === artifact.deliveryUnit.sourceRevision) throw new Error('[ultramodern-release-envelope] sourceRevision "workspace" cannot produce a promotable full-stack envelope.');
131
+ if ('workspace' === artifact.deliveryUnit.sourceRevision) {
132
+ if (!requirePromotable) return;
133
+ throw new Error('[ultramodern-release-envelope] sourceRevision "workspace" cannot produce a promotable full-stack envelope.');
134
+ }
91
135
  return artifact;
92
136
  };
93
137
  const assertIdentityBlock = (value, identity, location, includeReleaseVersion)=>{
@@ -285,7 +329,7 @@ const pathExists = async (filePath)=>{
285
329
  return false;
286
330
  }
287
331
  };
288
- const emitFrameworkMicroVerticalReleaseEnvelope = async ({ apiOnly, distDirectory, target })=>{
332
+ const emitFrameworkMicroVerticalReleaseEnvelope = async ({ apiOnly, distDirectory, requirePromotable = true, target })=>{
289
333
  if (apiOnly) return;
290
334
  const backendManifestPath = node_path.join(distDirectory, BACKEND_FEDERATION_MANIFEST_FILE);
291
335
  const backendContainerPath = node_path.join(distDirectory, BACKEND_FEDERATION_REMOTE_ENTRY_FILE);
@@ -295,7 +339,8 @@ const emitFrameworkMicroVerticalReleaseEnvelope = async ({ apiOnly, distDirector
295
339
  ]);
296
340
  if (!hasBackendManifest && !hasBackendContainer) return;
297
341
  if (!hasBackendManifest || !hasBackendContainer) throw new Error('[ultramodern-release-envelope] full-stack MicroVertical backend federation manifest and container must be emitted together.');
298
- const buildArtifact = await readBuildArtifact(distDirectory);
342
+ const buildArtifact = await readBuildArtifact(distDirectory, requirePromotable);
343
+ if (!buildArtifact) return;
299
344
  const identity = {
300
345
  unitId: buildArtifact.deliveryUnit.unitId,
301
346
  buildMarker: buildArtifact.deliveryUnit.buildMarker,
@@ -11,24 +11,26 @@ const createUltramodernReleaseEnvelopePlugin = ({ resolveDeployTarget })=>({
11
11
  name: '@modern-js/ultramodern-release-envelope',
12
12
  pre: [
13
13
  '@modern-js/backend-federation-build',
14
- '@modern-js/plugin-bff'
14
+ '@modern-js/plugin-bff',
15
+ '@modern-js/deploy-output-aliases'
15
16
  ],
16
17
  post: [
17
18
  '@modern-js/plugin-deploy'
18
19
  ],
19
20
  setup (api) {
20
- const emitBuildEnvelope = async (target)=>{
21
+ const emitBuildEnvelope = async (target, requirePromotable = true)=>{
21
22
  const { apiOnly, distDirectory } = api.getAppContext();
22
23
  await emitFrameworkMicroVerticalReleaseEnvelope({
23
24
  apiOnly,
24
25
  distDirectory,
26
+ requirePromotable,
25
27
  target
26
28
  });
27
29
  };
28
30
  api.onAfterBuild(async ()=>{
29
31
  const configuredTarget = resolveDeployTarget(api.getNormalizedConfig());
30
32
  if ('node' !== configuredTarget && 'cloudflare' !== configuredTarget) return;
31
- await emitBuildEnvelope(configuredTarget);
33
+ await emitBuildEnvelope(configuredTarget, false);
32
34
  });
33
35
  api.onBeforeDeploy(async ()=>{
34
36
  const configuredTarget = resolveActiveDeployTarget(api, resolveDeployTarget);
@@ -5,11 +5,8 @@ const BUILD_MARKER_NAMESPACE = 'ultramodern-delivery-unit-release-build-marker:v
5
5
  const PROMOTABLE_SOURCE_REVISION_PATTERN = /^(?:[a-f0-9]{40}|[a-f0-9]{64})$/u;
6
6
  const gitOutput = (workspaceRoot, args)=>{
7
7
  try {
8
- return execFileSync('git', [
9
- '-C',
10
- workspaceRoot,
11
- ...args
12
- ], {
8
+ return execFileSync('git', args, {
9
+ cwd: workspaceRoot,
13
10
  encoding: 'utf8',
14
11
  stdio: [
15
12
  'ignore',
@@ -44,7 +41,7 @@ const resolveUltramodernSourceRevision = (workspaceRoot = process.cwd(), configu
44
41
  ]);
45
42
  const status = gitOutput(gitRoot, [
46
43
  'status',
47
- '--porcelain=v1',
44
+ '--porcelain',
48
45
  '--untracked-files=all'
49
46
  ]);
50
47
  if (!revision || void 0 === status || status.length > 0) return 'workspace';
@@ -0,0 +1,61 @@
1
+ import "node:module";
2
+ import node_fs from "node:fs";
3
+ import { createRequire } from "node:module";
4
+ import node_path from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ const findHostingModuleDirectory = (packageName, fromDirectory)=>{
7
+ let directory = node_path.resolve(fromDirectory);
8
+ for(;;){
9
+ const candidate = node_path.join(directory, 'node_modules');
10
+ if (node_fs.existsSync(node_path.join(candidate, packageName))) return candidate;
11
+ const parent = node_path.dirname(directory);
12
+ if (parent === directory) return;
13
+ directory = parent;
14
+ }
15
+ };
16
+ const collectRuntimePackageModuleDirectories = (packageNames, registrarUrl)=>{
17
+ const registrarDirectory = node_path.dirname(fileURLToPath(registrarUrl));
18
+ const directories = [];
19
+ for (const packageName of packageNames){
20
+ const directory = findHostingModuleDirectory(packageName, registrarDirectory);
21
+ if (directory && !directories.includes(directory)) directories.push(directory);
22
+ }
23
+ return directories;
24
+ };
25
+ const appendModuleDirectories = (config, directories)=>{
26
+ if (0 === directories.length) return;
27
+ config.resolve ??= {};
28
+ const existing = config.resolve.modules ?? [
29
+ 'node_modules'
30
+ ];
31
+ config.resolve.modules = [
32
+ ...existing,
33
+ ...directories.filter((directory)=>!existing.includes(directory))
34
+ ];
35
+ };
36
+ const createRuntimePackageResolutionPlugin = (directories)=>({
37
+ name: 'ultramodern:runtime-package-resolution',
38
+ setup (api) {
39
+ api.modifyRspackConfig({
40
+ order: 'post',
41
+ handler (config) {
42
+ appendModuleDirectories(config, directories);
43
+ }
44
+ });
45
+ api.onBeforeCreateCompiler({
46
+ order: 'post',
47
+ handler ({ bundlerConfigs }) {
48
+ for (const config of bundlerConfigs)appendModuleDirectories(config, directories);
49
+ }
50
+ });
51
+ }
52
+ });
53
+ const canResolveRuntimePackage = (packageName, registrarUrl)=>{
54
+ try {
55
+ createRequire(registrarUrl).resolve(packageName);
56
+ return true;
57
+ } catch {
58
+ return false;
59
+ }
60
+ };
61
+ export { canResolveRuntimePackage, collectRuntimePackageModuleDirectories, createRuntimePackageResolutionPlugin, findHostingModuleDirectory };
@@ -0,0 +1,86 @@
1
+ import type { BackendFederationEntryIntegrity } from '@modern-js/server-runtime-extensions/backend-federation-security';
2
+ import { type BackendFederationApp } from './config.js';
3
+ export declare const createBackendRemoteEntrySource: (workspaceRoot: string, app: BackendFederationApp, effectApiPath: string, entryPath: string) => Promise<string>;
4
+ export declare const createBackendManifest: (workspaceRoot: string, distDirectory: string, app: BackendFederationApp, entryIntegrity: BackendFederationEntryIntegrity) => {
5
+ schemaVersion: number;
6
+ id: string;
7
+ name: string;
8
+ version: string | undefined;
9
+ buildVersion: string | undefined;
10
+ metaData: {
11
+ name: string;
12
+ type: string;
13
+ buildInfo: {
14
+ buildVersion: string | undefined;
15
+ buildName: string | undefined;
16
+ };
17
+ remoteEntry: {
18
+ name: string;
19
+ path: string;
20
+ type: string;
21
+ };
22
+ globalName: string;
23
+ publicPath: string;
24
+ ssrRemoteEntry: {
25
+ name: string;
26
+ path: string;
27
+ type: string;
28
+ };
29
+ ssrPublicPath: string;
30
+ };
31
+ entry: {
32
+ byteLength: number;
33
+ sha256: string;
34
+ file: string;
35
+ path: string;
36
+ type: string;
37
+ url: string;
38
+ };
39
+ exposes: {
40
+ id: string;
41
+ name: string;
42
+ path: string;
43
+ assets: {
44
+ js: {
45
+ async: never[];
46
+ sync: string[];
47
+ };
48
+ css: {
49
+ async: never[];
50
+ sync: never[];
51
+ };
52
+ };
53
+ }[];
54
+ shared: never[];
55
+ backendFederation: {
56
+ role: string;
57
+ appId: string;
58
+ name: string;
59
+ runtimeFramework: string;
60
+ strictEffectApproach: boolean;
61
+ contractVersion: string;
62
+ nodeAdapterVersion: string;
63
+ remoteType: string;
64
+ expose: string;
65
+ manifestUrl: string;
66
+ containerEntry: string;
67
+ source: {
68
+ module: string;
69
+ };
70
+ readinessPath: string;
71
+ openapiPath: string;
72
+ deliveryUnit?: import("@modern-js/backend-federation-contracts").DeliveryUnitContractBlock | undefined;
73
+ versionBoundary: {
74
+ invariant: string;
75
+ packageName: string | undefined;
76
+ version: string | undefined;
77
+ buildVersion: string | undefined;
78
+ uiManifestUrl?: string | undefined;
79
+ deliveryUnit?: {
80
+ unitId: string;
81
+ buildMarker: string;
82
+ sourceRevision: string;
83
+ } | undefined;
84
+ };
85
+ };
86
+ };
@@ -0,0 +1,102 @@
1
+ import { type DeliveryUnitContractBlock, type UltramodernBuildArtifact } from '@modern-js/backend-federation-contracts';
2
+ export declare const COMPACT_CONFIG_PATH = ".modernjs/ultramodern.json";
3
+ export type CompactApp = {
4
+ id?: unknown;
5
+ kind?: unknown;
6
+ path?: unknown;
7
+ package?: unknown;
8
+ port?: unknown;
9
+ api?: {
10
+ prefix?: unknown;
11
+ stem?: unknown;
12
+ };
13
+ moduleFederation?: {
14
+ name?: unknown;
15
+ manifestUrl?: unknown;
16
+ };
17
+ backendFederation?: {
18
+ name?: unknown;
19
+ versionBoundary?: {
20
+ ui?: {
21
+ manifestUrl?: unknown;
22
+ };
23
+ };
24
+ executionSurfaces?: {
25
+ node?: {
26
+ remoteName?: unknown;
27
+ manifestUrl?: unknown;
28
+ containerEntry?: unknown;
29
+ remoteType?: unknown;
30
+ };
31
+ };
32
+ };
33
+ deliveryUnit?: {
34
+ unitId?: unknown;
35
+ buildMarker?: unknown;
36
+ sourceRevision?: unknown;
37
+ packageName?: unknown;
38
+ version?: unknown;
39
+ };
40
+ serverExecution?: {
41
+ node?: {
42
+ remoteName?: unknown;
43
+ manifestUrl?: unknown;
44
+ containerEntry?: unknown;
45
+ remoteType?: unknown;
46
+ };
47
+ };
48
+ };
49
+ export type CompactConfig = {
50
+ topology?: {
51
+ apps?: CompactApp[];
52
+ };
53
+ };
54
+ export type BackendFederationApp = {
55
+ id: string;
56
+ directory: string;
57
+ packageName?: string;
58
+ version?: string;
59
+ buildVersion?: string;
60
+ unitId?: string;
61
+ sourceRevision?: string;
62
+ deliveryUnit?: DeliveryUnitContractBlock;
63
+ port: number;
64
+ apiPrefix: string;
65
+ apiStem: string;
66
+ backendName: string;
67
+ manifestUrl: string;
68
+ containerEntry: string;
69
+ remoteType: string;
70
+ uiManifestUrl?: string;
71
+ compactDeliveryUnit?: {
72
+ unitId?: string;
73
+ buildMarker?: string;
74
+ sourceRevision?: string;
75
+ packageName?: string;
76
+ version?: string;
77
+ };
78
+ };
79
+ export type BackendFederationBuildIdentity = {
80
+ appId?: string;
81
+ packageName?: string;
82
+ version?: string;
83
+ buildVersion?: string;
84
+ unitId?: string;
85
+ sourceRevision?: string;
86
+ artifact?: UltramodernBuildArtifact;
87
+ };
88
+ export declare const normalizeRelativePath: (value: string) => string;
89
+ export declare const buildArtifactPathFor: (appDirectory: string) => string;
90
+ export declare const readBuildIdentity: (appDirectory: string) => Promise<BackendFederationBuildIdentity>;
91
+ export declare const findWorkspaceRoot: (appDirectory: string) => string | undefined;
92
+ export declare const resolveWorkspaceSourceRevision: (workspaceRoot: string) => Promise<string>;
93
+ export declare const createStampedDeliveryUnit: (input: {
94
+ appId: string;
95
+ unitId?: string;
96
+ buildMarker?: string;
97
+ packageName?: string;
98
+ version?: string;
99
+ sourceRevision: string;
100
+ }) => DeliveryUnitContractBlock | undefined;
101
+ export declare const createAppFromCompactMetadata: (workspaceRoot: string, appDirectory: string, compactApp: CompactApp) => BackendFederationApp | undefined;
102
+ export declare const findBackendFederationApp: (workspaceRoot: string, appDirectory: string) => Promise<BackendFederationApp | undefined>;
@@ -0,0 +1,21 @@
1
+ export type { BackendFederationBuildIdentity } from './config.js';
2
+ export type BackendFederationArtifactResult = {
3
+ appId: string;
4
+ manifestPath: string;
5
+ containerPath: string;
6
+ deliveryUnitArtifactPath?: string;
7
+ remoteName: string;
8
+ remoteType: string;
9
+ };
10
+ export declare const emitBackendFederationArtifacts: (appDirectory: string, distDirectory: string) => Promise<BackendFederationArtifactResult | undefined>;
11
+ export default _default;
12
+ declare function _default(): {
13
+ name: string;
14
+ setup(api: {
15
+ getAppContext(): {
16
+ appDirectory: string;
17
+ distDirectory: string;
18
+ };
19
+ onAfterBuild(handler: () => Promise<void>): void;
20
+ }): void;
21
+ };
@@ -0,0 +1,2 @@
1
+ export type { BackendFederationArtifactResult } from './emit.js';
2
+ export { default, emitBackendFederationArtifacts } from './emit.js';
@@ -0,0 +1,22 @@
1
+ import type { URL } from 'node:url';
2
+ import type { Rspack } from '@rsbuild/core';
3
+ /**
4
+ * Reads an environment variable while keeping generated build configs free of
5
+ * direct process access.
6
+ */
7
+ export declare function getBuildConfigEnvironment(name: string): string | undefined;
8
+ /**
9
+ * Runs a Rspack config setup under a leased environment value. The lease is
10
+ * restored when that compiler reaches any supported terminal hook.
11
+ */
12
+ export declare function withBuildConfigEnvironment<Config extends {
13
+ plugins?: Rspack.Plugin[];
14
+ }, SetupArguments extends unknown[]>(name: string, value: string, setup: (config: Config, ...args: SetupArguments) => Config | void | Promise<Config | void>): (config: Config, ...args: SetupArguments) => Promise<Config>;
15
+ export type ResolveEffectTsgoCompilerOptions = {
16
+ /** Module URL or absolute filename used to resolve the consumer's compiler. */
17
+ from: string | URL;
18
+ };
19
+ /**
20
+ * Resolves the Effect TS-Go executable used by Module Federation DTS builds.
21
+ */
22
+ export declare function resolveEffectTsgoCompiler(options: ResolveEffectTsgoCompilerOptions): string;
@@ -0,0 +1,4 @@
1
+ import type { RsbuildPlugin } from '@rsbuild/core';
2
+ import type { PrecompressConfig } from './types.js';
3
+ export type { PrecompressCodecOptions, PrecompressConfig } from './types.js';
4
+ export declare const builderPluginAdapterPrecompress: (precompress: boolean | PrecompressConfig | undefined) => RsbuildPlugin;
@@ -0,0 +1,19 @@
1
+ import type { CompressionPluginOptions } from '../../precompress/index.js';
2
+ export type PrecompressCodecOptions = boolean | Partial<CompressionPluginOptions>;
3
+ export interface PrecompressConfig {
4
+ /**
5
+ * Configure gzip precompression options.
6
+ * `true` means using default options.
7
+ * `false` means disabling gzip precompression.
8
+ * @default true
9
+ */
10
+ gzip?: PrecompressCodecOptions;
11
+ /**
12
+ * Configure brotli precompression options.
13
+ * `true` means using default options.
14
+ * `false` means disabling brotli precompression.
15
+ * @default true
16
+ */
17
+ brotli?: PrecompressCodecOptions;
18
+ }
19
+ export {};