@bleedingdev/modern-js-plugin-bff 3.5.0-ultramodern.98 → 3.8.1-ultramodern.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/cli/compress.js +1 -1
- package/dist/cjs/cli/generator.js +106 -97
- package/dist/cjs/cli/serverGlobalVars.js +43 -57
- package/dist/cjs/cli.js +6 -2
- package/dist/cjs/loader.js +6 -5
- package/dist/cjs/runtime/effect/adapter/cross-project-policy.js +17 -12
- package/dist/cjs/runtime/effect/adapter/entry.js +13 -5
- package/dist/cjs/runtime/effect/adapter/error-response.js +11 -9
- package/dist/cjs/runtime/effect/adapter.js +2 -2
- package/dist/cjs/runtime/effect/backend-federation/load.js +26 -17
- package/dist/cjs/runtime/effect/backend-federation/plugin.js +12 -2
- package/dist/cjs/runtime/effect/backend-federation/remotes.js +5 -4
- package/dist/cjs/runtime/effect/backend-federation/runtime.js +80 -16
- package/dist/cjs/runtime/effect/edge-dispatcher.js +148 -0
- package/dist/cjs/runtime/effect/edge.js +19 -100
- package/dist/cjs/runtime/effect/endpoint-contracts.js +6 -1
- package/dist/cjs/runtime/effect/handler/definition.js +1 -0
- package/dist/cjs/runtime/effect/handler/http.js +17 -6
- package/dist/cjs/runtime/hono/adapter.js +32 -79
- package/dist/cjs/server.js +19 -30
- package/dist/cjs/utils/client-generator/write-package.js +1 -1
- package/dist/cjs/utils/crossProjectApiPlugin.js +21 -2
- package/dist/cjs/utils/effect-client-generator/generator.js +17 -16
- package/dist/cjs/utils/effect-client-generator/paths.js +4 -15
- package/dist/cjs/utils/effect-client-generator/rendering.js +8 -19
- package/dist/cjs/utils/effect-client-generator/runtime.js +15 -32
- package/dist/cjs/utils/effectSourceLoader.js +70 -10
- package/dist/cjs/utils/pluginGenerator.js +4 -4
- package/dist/esm/cli/compress.mjs +1 -1
- package/dist/esm/cli/generator.mjs +108 -98
- package/dist/esm/cli/serverGlobalVars.mjs +44 -48
- package/dist/esm/cli.mjs +2 -0
- package/dist/esm/loader.mjs +6 -5
- package/dist/esm/runtime/effect/adapter/cross-project-policy.mjs +17 -12
- package/dist/esm/runtime/effect/adapter/entry.mjs +13 -5
- package/dist/esm/runtime/effect/adapter/error-response.mjs +11 -9
- package/dist/esm/runtime/effect/adapter.mjs +3 -3
- package/dist/esm/runtime/effect/backend-federation/load.mjs +26 -17
- package/dist/esm/runtime/effect/backend-federation/plugin.mjs +12 -2
- package/dist/esm/runtime/effect/backend-federation/remotes.mjs +5 -4
- package/dist/esm/runtime/effect/backend-federation/runtime.mjs +80 -16
- package/dist/esm/runtime/effect/edge-dispatcher.mjs +38 -0
- package/dist/esm/runtime/effect/edge.mjs +1 -38
- package/dist/esm/runtime/effect/endpoint-contracts.mjs +6 -1
- package/dist/esm/runtime/effect/handler/definition.mjs +1 -0
- package/dist/esm/runtime/effect/handler/http.mjs +17 -6
- package/dist/esm/runtime/hono/adapter.mjs +33 -80
- package/dist/esm/server.mjs +18 -29
- package/dist/esm/utils/client-generator/write-package.mjs +1 -1
- package/dist/esm/utils/crossProjectApiPlugin.mjs +16 -3
- package/dist/esm/utils/effect-client-generator/generator.mjs +17 -16
- package/dist/esm/utils/effect-client-generator/paths.mjs +5 -6
- package/dist/esm/utils/effect-client-generator/rendering.mjs +9 -10
- package/dist/esm/utils/effect-client-generator/runtime.mjs +16 -23
- package/dist/esm/utils/effectSourceLoader.mjs +69 -12
- package/dist/esm/utils/pluginGenerator.mjs +5 -5
- package/dist/esm-node/cli/compress.mjs +1 -1
- package/dist/esm-node/cli/generator.mjs +108 -98
- package/dist/esm-node/cli/serverGlobalVars.mjs +44 -48
- package/dist/esm-node/cli.mjs +2 -0
- package/dist/esm-node/loader.mjs +6 -5
- package/dist/esm-node/runtime/effect/adapter/cross-project-policy.mjs +17 -12
- package/dist/esm-node/runtime/effect/adapter/entry.mjs +13 -5
- package/dist/esm-node/runtime/effect/adapter/error-response.mjs +11 -9
- package/dist/esm-node/runtime/effect/adapter.mjs +3 -3
- package/dist/esm-node/runtime/effect/backend-federation/load.mjs +26 -17
- package/dist/esm-node/runtime/effect/backend-federation/plugin.mjs +12 -2
- package/dist/esm-node/runtime/effect/backend-federation/remotes.mjs +5 -4
- package/dist/esm-node/runtime/effect/backend-federation/runtime.mjs +80 -16
- package/dist/esm-node/runtime/effect/edge-dispatcher.mjs +39 -0
- package/dist/esm-node/runtime/effect/edge.mjs +1 -38
- package/dist/esm-node/runtime/effect/endpoint-contracts.mjs +6 -1
- package/dist/esm-node/runtime/effect/handler/definition.mjs +1 -0
- package/dist/esm-node/runtime/effect/handler/http.mjs +17 -6
- package/dist/esm-node/runtime/hono/adapter.mjs +33 -80
- package/dist/esm-node/server.mjs +18 -29
- package/dist/esm-node/utils/client-generator/write-package.mjs +1 -1
- package/dist/esm-node/utils/crossProjectApiPlugin.mjs +16 -3
- package/dist/esm-node/utils/effect-client-generator/generator.mjs +17 -16
- package/dist/esm-node/utils/effect-client-generator/paths.mjs +5 -6
- package/dist/esm-node/utils/effect-client-generator/rendering.mjs +9 -10
- package/dist/esm-node/utils/effect-client-generator/runtime.mjs +16 -23
- package/dist/esm-node/utils/effectSourceLoader.mjs +69 -12
- package/dist/esm-node/utils/pluginGenerator.mjs +5 -5
- package/dist/types/cli/generator.d.ts +2 -2
- package/dist/types/cli/serverGlobalVars.d.ts +4 -2
- package/dist/types/cli.d.ts +1 -0
- package/dist/types/runtime/effect/adapter/cross-project-policy.d.ts +1 -1
- package/dist/types/runtime/effect/backend-federation/runtime.d.ts +1 -1
- package/dist/types/runtime/effect/edge-dispatcher.d.ts +26 -0
- package/dist/types/runtime/effect/edge.d.ts +1 -26
- package/dist/types/runtime/effect/endpoint-contracts.d.ts +6 -0
- package/dist/types/runtime/effect/handler/definition.d.ts +2 -12
- package/dist/types/runtime/effect/handler/http.d.ts +3 -2
- package/dist/types/runtime/effect/handler/openapi.d.ts +1 -1
- package/dist/types/runtime/effect/handler/types.d.ts +10 -5
- package/dist/types/runtime/effect-client/index.d.ts +1 -1
- package/dist/types/runtime/hono/adapter.d.ts +14 -8
- package/dist/types/utils/crossProjectApiPlugin.d.ts +2 -0
- package/dist/types/utils/effectSourceLoader.d.ts +10 -0
- package/dist/types/utils/pluginGenerator.d.ts +3 -1
- package/package.json +44 -16
|
@@ -38,6 +38,7 @@ var __webpack_exports__ = {};
|
|
|
38
38
|
__webpack_require__.r(__webpack_exports__);
|
|
39
39
|
__webpack_require__.d(__webpack_exports__, {
|
|
40
40
|
bundleEffectEntryForNode: ()=>bundleEffectEntryForNode,
|
|
41
|
+
loadEffectBuiltModule: ()=>loadEffectBuiltModule,
|
|
41
42
|
loadEffectSourceModule: ()=>loadEffectSourceModule
|
|
42
43
|
});
|
|
43
44
|
const external_node_crypto_namespaceObject = require("node:crypto");
|
|
@@ -120,10 +121,29 @@ const nodeBuiltins = new Set([
|
|
|
120
121
|
...external_node_module_namespaceObject.builtinModules.map((name)=>`node:${name}`)
|
|
121
122
|
]);
|
|
122
123
|
const dependencyResolutionMarker = 'modern-js-effect-dependency-resolution';
|
|
124
|
+
async function isEsmOnlyFile(filename) {
|
|
125
|
+
const extension = external_node_path_default().extname(filename).toLowerCase();
|
|
126
|
+
if ('.mjs' === extension || '.mts' === extension) return true;
|
|
127
|
+
if ('.cjs' === extension || '.cts' === extension) return false;
|
|
128
|
+
let directory = external_node_path_default().dirname(filename);
|
|
129
|
+
while(true){
|
|
130
|
+
const packagePath = external_node_path_default().join(directory, 'package.json');
|
|
131
|
+
try {
|
|
132
|
+
const packageJson = JSON.parse(await external_node_fs_default().promises.readFile(packagePath, 'utf8'));
|
|
133
|
+
return 'module' === packageJson.type;
|
|
134
|
+
} catch (error) {
|
|
135
|
+
if (!error || 'object' != typeof error || !('code' in error) || 'ENOENT' !== error.code) throw error;
|
|
136
|
+
}
|
|
137
|
+
const parent = external_node_path_default().dirname(directory);
|
|
138
|
+
if (parent === directory) return false;
|
|
139
|
+
directory = parent;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
123
142
|
function isBareSpecifier(specifier) {
|
|
124
143
|
return !specifier.startsWith('.') && !specifier.startsWith('/') && !external_node_path_default().isAbsolute(specifier);
|
|
125
144
|
}
|
|
126
|
-
function externalizeInstalledDependencies() {
|
|
145
|
+
function externalizeInstalledDependencies(options) {
|
|
146
|
+
const runtimeRequire = (0, external_node_module_namespaceObject.createRequire)(external_node_path_default().join(options.runtimeResolveDir, '__modern_effect_entry.cjs'));
|
|
127
147
|
return {
|
|
128
148
|
name: 'modern-js-effect-installed-dependencies',
|
|
129
149
|
setup (buildApi) {
|
|
@@ -153,19 +173,46 @@ function externalizeInstalledDependencies() {
|
|
|
153
173
|
path: args.path
|
|
154
174
|
};
|
|
155
175
|
const realPath = await external_node_fs_default().promises.realpath(resolution.path).catch(()=>resolution.path);
|
|
156
|
-
if (realPath.includes(`${external_node_path_default().sep}node_modules${external_node_path_default().sep}`))
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
176
|
+
if (realPath.includes(`${external_node_path_default().sep}node_modules${external_node_path_default().sep}`)) {
|
|
177
|
+
const runtimeResolution = await buildApi.resolve(args.path, {
|
|
178
|
+
importer: '',
|
|
179
|
+
kind: args.kind,
|
|
180
|
+
namespace: 'file',
|
|
181
|
+
pluginData: {
|
|
182
|
+
[dependencyResolutionMarker]: true
|
|
183
|
+
},
|
|
184
|
+
resolveDir: options.runtimeResolveDir
|
|
185
|
+
});
|
|
186
|
+
if (0 === runtimeResolution.errors.length && runtimeResolution.path) {
|
|
187
|
+
if ('cjs' === options.format) {
|
|
188
|
+
let requiredPath;
|
|
189
|
+
try {
|
|
190
|
+
requiredPath = runtimeRequire.resolve(args.path);
|
|
191
|
+
} catch {
|
|
192
|
+
requiredPath = runtimeResolution.path;
|
|
193
|
+
}
|
|
194
|
+
if (await isEsmOnlyFile(requiredPath)) return {
|
|
195
|
+
namespace: resolution.namespace,
|
|
196
|
+
path: resolution.path,
|
|
197
|
+
pluginData: resolution.pluginData,
|
|
198
|
+
sideEffects: resolution.sideEffects,
|
|
199
|
+
suffix: resolution.suffix,
|
|
200
|
+
warnings: resolution.warnings
|
|
201
|
+
};
|
|
202
|
+
}
|
|
203
|
+
return {
|
|
204
|
+
external: true,
|
|
205
|
+
path: args.path
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
}
|
|
160
209
|
return {
|
|
161
210
|
namespace: resolution.namespace,
|
|
162
211
|
path: resolution.path,
|
|
163
212
|
pluginData: resolution.pluginData,
|
|
164
213
|
sideEffects: resolution.sideEffects,
|
|
165
214
|
suffix: resolution.suffix,
|
|
166
|
-
warnings: resolution.warnings
|
|
167
|
-
watchDirs: resolution.watchDirs,
|
|
168
|
-
watchFiles: resolution.watchFiles
|
|
215
|
+
warnings: resolution.warnings
|
|
169
216
|
};
|
|
170
217
|
});
|
|
171
218
|
}
|
|
@@ -184,7 +231,10 @@ async function bundleEffectEntryForNode(options) {
|
|
|
184
231
|
outfile: options.entryPath,
|
|
185
232
|
platform: 'node',
|
|
186
233
|
plugins: [
|
|
187
|
-
externalizeInstalledDependencies(
|
|
234
|
+
externalizeInstalledDependencies({
|
|
235
|
+
format: options.format,
|
|
236
|
+
runtimeResolveDir: options.appDir
|
|
237
|
+
}),
|
|
188
238
|
preserveSourceModuleSemantics()
|
|
189
239
|
],
|
|
190
240
|
target: 'node20'
|
|
@@ -200,6 +250,11 @@ function normalizeImportedModule(module) {
|
|
|
200
250
|
if (1 === Object.keys(namespace).length && null !== commonJsModule && 'object' == typeof commonJsModule && true === commonJsModule.__esModule) return commonJsModule;
|
|
201
251
|
return module;
|
|
202
252
|
}
|
|
253
|
+
async function loadEffectBuiltModule(resourcePath) {
|
|
254
|
+
const canonicalPath = await external_node_fs_default().promises.realpath(external_node_path_default().resolve(resourcePath));
|
|
255
|
+
if (!await isEsmOnlyFile(canonicalPath)) return (0, external_node_module_namespaceObject.createRequire)(canonicalPath)(canonicalPath);
|
|
256
|
+
return normalizeImportedModule(await dynamicImport((0, external_node_url_namespaceObject.pathToFileURL)(canonicalPath).href));
|
|
257
|
+
}
|
|
203
258
|
async function loadEffectSourceModule(options) {
|
|
204
259
|
const resourcePath = external_node_path_default().resolve(options.resourcePath);
|
|
205
260
|
const appDir = external_node_path_default().resolve(options.appDir ?? external_node_path_default().dirname(resourcePath));
|
|
@@ -226,7 +281,10 @@ async function loadEffectSourceModule(options) {
|
|
|
226
281
|
outfile: outputPath,
|
|
227
282
|
platform: 'node',
|
|
228
283
|
plugins: [
|
|
229
|
-
externalizeInstalledDependencies(
|
|
284
|
+
externalizeInstalledDependencies({
|
|
285
|
+
format: 'esm',
|
|
286
|
+
runtimeResolveDir: appDir
|
|
287
|
+
}),
|
|
230
288
|
preserveSourceModuleSemantics()
|
|
231
289
|
],
|
|
232
290
|
sourcemap: 'inline',
|
|
@@ -242,9 +300,11 @@ async function loadEffectSourceModule(options) {
|
|
|
242
300
|
return normalizeImportedModule(await dynamicImport(`${(0, external_node_url_namespaceObject.pathToFileURL)(outputPath).href}?v=${revision}`));
|
|
243
301
|
}
|
|
244
302
|
exports.bundleEffectEntryForNode = __webpack_exports__.bundleEffectEntryForNode;
|
|
303
|
+
exports.loadEffectBuiltModule = __webpack_exports__.loadEffectBuiltModule;
|
|
245
304
|
exports.loadEffectSourceModule = __webpack_exports__.loadEffectSourceModule;
|
|
246
305
|
for(var __rspack_i in __webpack_exports__)if (-1 === [
|
|
247
306
|
"bundleEffectEntryForNode",
|
|
307
|
+
"loadEffectBuiltModule",
|
|
248
308
|
"loadEffectSourceModule"
|
|
249
309
|
].indexOf(__rspack_i)) exports[__rspack_i] = __webpack_exports__[__rspack_i];
|
|
250
310
|
Object.defineProperty(exports, '__esModule', {
|
|
@@ -43,18 +43,18 @@ const utils_namespaceObject = require("@modern-js/utils");
|
|
|
43
43
|
const external_path_namespaceObject = require("path");
|
|
44
44
|
var external_path_default = /*#__PURE__*/ __webpack_require__.n(external_path_namespaceObject);
|
|
45
45
|
const external_crossProjectApiPlugin_js_namespaceObject = require("./crossProjectApiPlugin.js");
|
|
46
|
-
function replaceContent(source, packageName, prefix, relativeDistPath, relativeApiPath, relativeLambdaPath, runtimeFramework) {
|
|
47
|
-
const updatedSource = source.replace(new RegExp(external_crossProjectApiPlugin_js_namespaceObject.PACKAGE_NAME, 'g'), packageName).replace(new RegExp(external_crossProjectApiPlugin_js_namespaceObject.PREFIX, 'g'), prefix).replace(new RegExp(external_crossProjectApiPlugin_js_namespaceObject.DIST_DIR, 'g'), (0, utils_namespaceObject.normalizeToPosixPath)(relativeDistPath)).replace(new RegExp(external_crossProjectApiPlugin_js_namespaceObject.API_DIR, 'g'), (0, utils_namespaceObject.normalizeToPosixPath)(relativeApiPath)).replace(new RegExp(external_crossProjectApiPlugin_js_namespaceObject.LAMBDA_DIR, 'g'), (0, utils_namespaceObject.normalizeToPosixPath)(relativeLambdaPath)).replace(new RegExp(external_crossProjectApiPlugin_js_namespaceObject.RUNTIME_FRAMEWORK, 'g'), runtimeFramework);
|
|
46
|
+
function replaceContent(source, packageName, prefix, relativeDistPath, relativeApiPath, relativeLambdaPath, runtimeFramework, relativeEffectEntry, operationContracts) {
|
|
47
|
+
const updatedSource = source.replace(new RegExp(external_crossProjectApiPlugin_js_namespaceObject.PACKAGE_NAME, 'g'), packageName).replace(new RegExp(external_crossProjectApiPlugin_js_namespaceObject.PREFIX, 'g'), prefix).replace(new RegExp(external_crossProjectApiPlugin_js_namespaceObject.DIST_DIR, 'g'), (0, utils_namespaceObject.normalizeToPosixPath)(relativeDistPath)).replace(new RegExp(external_crossProjectApiPlugin_js_namespaceObject.API_DIR, 'g'), (0, utils_namespaceObject.normalizeToPosixPath)(relativeApiPath)).replace(new RegExp(external_crossProjectApiPlugin_js_namespaceObject.LAMBDA_DIR, 'g'), (0, utils_namespaceObject.normalizeToPosixPath)(relativeLambdaPath)).replace(new RegExp(external_crossProjectApiPlugin_js_namespaceObject.RUNTIME_FRAMEWORK, 'g'), runtimeFramework).replace(new RegExp(external_crossProjectApiPlugin_js_namespaceObject.EFFECT_ENTRY, 'g'), (0, utils_namespaceObject.normalizeToPosixPath)(relativeEffectEntry)).replace(`'${external_crossProjectApiPlugin_js_namespaceObject.OPERATION_CONTRACTS_JSON}'`, ()=>JSON.stringify(JSON.stringify(operationContracts)));
|
|
48
48
|
return updatedSource;
|
|
49
49
|
}
|
|
50
|
-
async function pluginGenerator({ prefix, appDirectory, relativeDistPath, relativeApiPath, relativeLambdaPath, runtimeFramework }) {
|
|
50
|
+
async function pluginGenerator({ prefix, appDirectory, relativeDistPath, relativeApiPath, relativeLambdaPath, runtimeFramework, relativeEffectEntry, operationContracts }) {
|
|
51
51
|
try {
|
|
52
52
|
const packageContent = await utils_namespaceObject.fs.readFile(external_path_default().resolve(appDirectory, './package.json'), 'utf8');
|
|
53
53
|
const packageJson = JSON.parse(packageContent);
|
|
54
54
|
const pluginDir = external_path_default().resolve(appDirectory, `./${relativeDistPath}`, 'plugin');
|
|
55
55
|
const pluginPath = external_path_default().join(pluginDir, 'index.js');
|
|
56
56
|
const pluginTemplate = await utils_namespaceObject.fs.readFile(external_path_default().resolve(__dirname, 'crossProjectApiPlugin.js'), 'utf8');
|
|
57
|
-
const updatedPlugin = replaceContent(pluginTemplate, packageJson.name, prefix, relativeDistPath, relativeApiPath, relativeLambdaPath, runtimeFramework);
|
|
57
|
+
const updatedPlugin = replaceContent(pluginTemplate, packageJson.name, prefix, relativeDistPath, relativeApiPath, relativeLambdaPath, runtimeFramework, relativeEffectEntry, operationContracts);
|
|
58
58
|
await utils_namespaceObject.fs.ensureFile(pluginPath);
|
|
59
59
|
await utils_namespaceObject.fs.writeFile(pluginPath, updatedPlugin);
|
|
60
60
|
const typeContent = `import type { AppTools, CliPlugin } from '@modern-js/app-tools';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { normalizePrefixList } from "./prefix.mjs";
|
|
2
2
|
const createCompressConfig = (devServer, prefix)=>{
|
|
3
|
-
if (
|
|
3
|
+
if (void 0 === devServer || 'object' != typeof devServer || Array.isArray(devServer)) return;
|
|
4
4
|
const { compress } = devServer;
|
|
5
5
|
if (void 0 === compress || true === compress) {
|
|
6
6
|
const prefixes = normalizePrefixList(prefix);
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { ApiRouter } from "@modern-js/bff-core";
|
|
1
|
+
import { ApiRouter, buildOperationContractMap, deriveOperationVersion } from "@modern-js/bff-core";
|
|
2
2
|
import { compile } from "@modern-js/server-utils";
|
|
3
|
-
import { API_DIR, SHARED_DIR, fs, resolveServerTsconfig } from "@modern-js/utils";
|
|
4
|
-
import path from "path";
|
|
3
|
+
import { API_DIR, SHARED_DIR, fs, resolveServerTsconfig, upath } from "@modern-js/utils";
|
|
5
4
|
import clientGenerator from "../utils/clientGenerator.mjs";
|
|
6
5
|
import { bundleEffectEntryForNode } from "../utils/effectSourceLoader.mjs";
|
|
7
6
|
import pluginGenerator from "../utils/pluginGenerator.mjs";
|
|
@@ -20,110 +19,121 @@ const effectEntryExtensions = [
|
|
|
20
19
|
'.cts'
|
|
21
20
|
];
|
|
22
21
|
function resolveEffectSourceEntry(appDirectory, apiDirectory, configuredEntry) {
|
|
23
|
-
const entry = configuredEntry ?
|
|
24
|
-
return
|
|
22
|
+
const entry = void 0 !== configuredEntry && configuredEntry.length > 0 ? upath.isAbsolute(configuredEntry) ? configuredEntry : upath.resolve(appDirectory, configuredEntry) : upath.resolve(apiDirectory, 'index');
|
|
23
|
+
return upath.extname(entry).length > 0 ? entry : effectEntryExtensions.map((extension)=>`${entry}${extension}`).find((candidate)=>fs.existsSync(candidate));
|
|
25
24
|
}
|
|
26
25
|
function resolveBuiltEffectEntry(appDirectory, distDirectory, sourceEntry) {
|
|
27
|
-
if (
|
|
28
|
-
const relativeEntry =
|
|
29
|
-
if ('..' === relativeEntry || relativeEntry.startsWith(`..${
|
|
30
|
-
const builtEntry =
|
|
26
|
+
if (void 0 === sourceEntry || 0 === sourceEntry.length) return;
|
|
27
|
+
const relativeEntry = upath.relative(appDirectory, sourceEntry);
|
|
28
|
+
if ('..' === relativeEntry || relativeEntry.startsWith(`..${upath.sep}`)) throw new Error(`Effect BFF entry must be inside the application directory: ${sourceEntry}`);
|
|
29
|
+
const builtEntry = upath.resolve(distDirectory, relativeEntry).replace(/\.(?:[cm]?ts|tsx|jsx)$/u, '.js');
|
|
31
30
|
return fs.existsSync(builtEntry) ? builtEntry : void 0;
|
|
32
31
|
}
|
|
33
32
|
const createBffGenerator = (api)=>{
|
|
34
|
-
const compileApi =
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
alias
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
33
|
+
const compileApi = ()=>Promise.resolve().then(()=>{
|
|
34
|
+
const { appDirectory, distDirectory, apiDirectory, bffRuntimeFramework, sharedDirectory, moduleType } = api.getAppContext();
|
|
35
|
+
const modernConfig = api.getNormalizedConfig();
|
|
36
|
+
const distDir = upath.resolve(distDirectory);
|
|
37
|
+
const apiDir = apiDirectory || upath.resolve(appDirectory, API_DIR);
|
|
38
|
+
const sharedDir = sharedDirectory || upath.resolve(appDirectory, SHARED_DIR);
|
|
39
|
+
const tsconfigPath = resolveServerTsconfig(appDirectory, modernConfig?.server?.tsconfigPath);
|
|
40
|
+
const sourceDirs = [];
|
|
41
|
+
return fs.pathExists(apiDir).then((apiDirectoryExists)=>{
|
|
42
|
+
if (apiDirectoryExists) sourceDirs.push(apiDir);
|
|
43
|
+
return fs.pathExists(sharedDir);
|
|
44
|
+
}).then((sharedDirectoryExists)=>{
|
|
45
|
+
if (sharedDirectoryExists) sourceDirs.push(sharedDir);
|
|
46
|
+
if (0 === sourceDirs.length) return;
|
|
47
|
+
const { alias, globalVars } = modernConfig.source;
|
|
48
|
+
const { alias: resolveAlias } = modernConfig.resolve;
|
|
49
|
+
const combinedAlias = [].concat(alias ?? []).concat(resolveAlias ?? []);
|
|
50
|
+
const serializedGlobalVars = serializeServerGlobalVars(globalVars);
|
|
51
|
+
return compile(appDirectory, {
|
|
52
|
+
alias: combinedAlias
|
|
53
|
+
}, {
|
|
54
|
+
sourceDirs,
|
|
55
|
+
distDir,
|
|
56
|
+
tsconfigPath,
|
|
57
|
+
moduleType,
|
|
58
|
+
throwErrorInsteadOfExit: true
|
|
59
|
+
}).then(()=>transformServerGlobalVars(sourceDirs.map((sourceDir)=>upath.resolve(distDir, upath.relative(appDirectory, sourceDir))), serializedGlobalVars)).then(()=>{
|
|
60
|
+
if ('effect' !== bffRuntimeFramework) return;
|
|
61
|
+
const sourceEntry = resolveEffectSourceEntry(appDirectory, apiDir, modernConfig.bff?.effect?.entry);
|
|
62
|
+
const builtEntry = resolveBuiltEffectEntry(appDirectory, distDir, sourceEntry);
|
|
63
|
+
if (void 0 === builtEntry || 0 === builtEntry.length) throw new Error(`Effect BFF entry was not emitted into ${distDir}: ${sourceEntry ?? upath.resolve(apiDir, 'index')}`);
|
|
64
|
+
return bundleEffectEntryForNode({
|
|
65
|
+
appDir: appDirectory,
|
|
66
|
+
entryPath: builtEntry,
|
|
67
|
+
format: 'module' === moduleType ? 'esm' : 'cjs'
|
|
68
|
+
});
|
|
67
69
|
});
|
|
68
|
-
}
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
const generate = async ()=>{
|
|
72
|
-
const { appDirectory, apiDirectory, lambdaDirectory, port, bffRuntimeFramework } = api.getAppContext();
|
|
73
|
-
const modernConfig = api.getNormalizedConfig();
|
|
74
|
-
const relativeDistPath = modernConfig?.output?.distPath?.root || 'dist';
|
|
75
|
-
const { bff } = modernConfig || {};
|
|
76
|
-
const prefix = getPrimaryPrefix(bff?.prefix);
|
|
77
|
-
const httpMethodDecider = bff?.httpMethodDecider;
|
|
78
|
-
const apiRouter = new ApiRouter({
|
|
79
|
-
apiDir: apiDirectory,
|
|
80
|
-
appDir: appDirectory,
|
|
81
|
-
lambdaDir: lambdaDirectory,
|
|
82
|
-
prefix,
|
|
83
|
-
httpMethodDecider,
|
|
84
|
-
isBuild: true
|
|
85
|
-
});
|
|
86
|
-
const lambdaDir = apiRouter.getLambdaDir();
|
|
87
|
-
const existLambda = apiRouter.isExistLambda();
|
|
88
|
-
const runtime = bff?.runtimeCreateRequest || RUNTIME_CREATE_REQUEST;
|
|
89
|
-
const relativeApiPath = path.relative(appDirectory, apiDirectory);
|
|
90
|
-
const relativeLambdaPath = path.relative(appDirectory, lambdaDir);
|
|
91
|
-
await pluginGenerator({
|
|
92
|
-
prefix,
|
|
93
|
-
appDirectory,
|
|
94
|
-
relativeDistPath,
|
|
95
|
-
relativeApiPath,
|
|
96
|
-
relativeLambdaPath,
|
|
97
|
-
runtimeFramework: 'hono' === bffRuntimeFramework ? 'hono' : 'effect'
|
|
70
|
+
});
|
|
98
71
|
});
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
72
|
+
const generate = ()=>Promise.resolve().then(()=>{
|
|
73
|
+
const { appDirectory, apiDirectory, lambdaDirectory, port, bffRuntimeFramework, packageName } = api.getAppContext();
|
|
74
|
+
const modernConfig = api.getNormalizedConfig();
|
|
75
|
+
const relativeDistPath = modernConfig?.output?.distPath?.root || 'dist';
|
|
76
|
+
const { bff } = modernConfig || {};
|
|
77
|
+
const prefix = getPrimaryPrefix(bff?.prefix);
|
|
78
|
+
const httpMethodDecider = bff?.httpMethodDecider;
|
|
79
|
+
const apiRouter = new ApiRouter({
|
|
80
|
+
apiDir: apiDirectory,
|
|
81
|
+
appDir: appDirectory,
|
|
82
|
+
lambdaDir: lambdaDirectory,
|
|
83
|
+
prefix,
|
|
84
|
+
httpMethodDecider,
|
|
85
|
+
isBuild: true
|
|
86
|
+
});
|
|
87
|
+
const lambdaDir = apiRouter.getLambdaDir();
|
|
88
|
+
const existLambda = apiRouter.isExistLambda();
|
|
89
|
+
const packageJson = fs.readJSONSync(upath.resolve(appDirectory, 'package.json'));
|
|
90
|
+
const requestId = packageJson.name || packageName;
|
|
91
|
+
const operationContractsPromise = existLambda ? apiRouter.getApiHandlers().then((handlers)=>buildOperationContractMap({
|
|
92
|
+
handlers,
|
|
93
|
+
requestId,
|
|
94
|
+
operationVersion: deriveOperationVersion(packageJson.version)
|
|
95
|
+
})) : Promise.resolve({});
|
|
96
|
+
return operationContractsPromise.then((operationContracts)=>{
|
|
97
|
+
const runtime = bff?.runtimeCreateRequest || RUNTIME_CREATE_REQUEST;
|
|
98
|
+
const relativeApiPath = upath.relative(appDirectory, apiDirectory);
|
|
99
|
+
const relativeLambdaPath = upath.relative(appDirectory, lambdaDir);
|
|
100
|
+
const sourceEffectEntry = 'effect' === bffRuntimeFramework ? resolveEffectSourceEntry(appDirectory, apiDirectory, bff?.effect?.entry) : void 0;
|
|
101
|
+
const relativeEffectEntry = void 0 !== sourceEffectEntry && sourceEffectEntry.length > 0 ? upath.relative(appDirectory, sourceEffectEntry).replace(/\.(?:[cm]?ts|tsx|jsx)$/u, '.js') : '';
|
|
102
|
+
return pluginGenerator({
|
|
103
|
+
prefix,
|
|
104
|
+
appDirectory,
|
|
105
|
+
relativeDistPath,
|
|
106
|
+
relativeApiPath,
|
|
107
|
+
relativeLambdaPath,
|
|
108
|
+
runtimeFramework: 'hono' === bffRuntimeFramework ? 'hono' : 'effect',
|
|
109
|
+
relativeEffectEntry,
|
|
110
|
+
operationContracts
|
|
111
|
+
}).then(()=>clientGenerator({
|
|
112
|
+
prefix,
|
|
113
|
+
appDir: appDirectory,
|
|
114
|
+
apiDir: apiDirectory,
|
|
115
|
+
lambdaDir,
|
|
116
|
+
existLambda,
|
|
117
|
+
port,
|
|
118
|
+
requestCreator: bff?.requestCreator,
|
|
119
|
+
httpMethodDecider,
|
|
120
|
+
relativeDistPath,
|
|
121
|
+
relativeApiPath,
|
|
122
|
+
bffRuntimeFramework,
|
|
123
|
+
effectEntry: bff?.effect?.entry,
|
|
124
|
+
effectDataPlatformBatch: bff?.effect?.dataPlatform?.batch
|
|
125
|
+
})).then(()=>runtimeGenerator({
|
|
126
|
+
runtime,
|
|
127
|
+
appDirectory,
|
|
128
|
+
relativeDistPath
|
|
129
|
+
}));
|
|
130
|
+
});
|
|
113
131
|
});
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
132
|
+
const handleCrossProjectInvocation = (isBuild = false)=>Promise.resolve().then(()=>{
|
|
133
|
+
const { bff } = api.getNormalizedConfig();
|
|
134
|
+
if (bff?.crossProject !== true) return;
|
|
135
|
+
return isBuild ? generate() : compileApi().then(()=>generate());
|
|
118
136
|
});
|
|
119
|
-
};
|
|
120
|
-
const handleCrossProjectInvocation = async (isBuild = false)=>{
|
|
121
|
-
const { bff } = api.getNormalizedConfig();
|
|
122
|
-
if (bff?.crossProject) {
|
|
123
|
-
if (!isBuild) await compileApi();
|
|
124
|
-
await generate();
|
|
125
|
-
}
|
|
126
|
-
};
|
|
127
137
|
return {
|
|
128
138
|
compileApi,
|
|
129
139
|
generate,
|
|
@@ -1,24 +1,19 @@
|
|
|
1
|
-
import { applyOptionsChain, fs } from "@modern-js/utils";
|
|
1
|
+
import { applyOptionsChain, fs, upath } from "@modern-js/utils";
|
|
2
2
|
import { transform } from "@swc/core";
|
|
3
|
-
import path from "path";
|
|
4
3
|
const RELEASE_IDENTITY_GLOBAL_NAMES = [
|
|
5
4
|
'ULTRAMODERN_BUILD_MARKER',
|
|
6
5
|
'ULTRAMODERN_SOURCE_REVISION',
|
|
7
6
|
'ULTRAMODERN_RELEASE_VERSION'
|
|
8
7
|
];
|
|
9
|
-
const collectJavaScriptFiles =
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
] : [];
|
|
19
|
-
}));
|
|
20
|
-
return nested.flat();
|
|
21
|
-
};
|
|
8
|
+
const collectJavaScriptFiles = (directory)=>Promise.resolve().then(()=>fs.readdir(directory, {
|
|
9
|
+
withFileTypes: true
|
|
10
|
+
})).then((entries)=>Promise.all(entries.map((entry)=>{
|
|
11
|
+
const absolutePath = upath.join(directory, entry.name);
|
|
12
|
+
if (entry.isDirectory()) return collectJavaScriptFiles(absolutePath);
|
|
13
|
+
return /\.(?:c|m)?js$/u.test(entry.name) ? [
|
|
14
|
+
absolutePath
|
|
15
|
+
] : [];
|
|
16
|
+
})).then((nested)=>nested.flat()));
|
|
22
17
|
const serializeServerGlobalVars = (options)=>{
|
|
23
18
|
const globalVars = applyOptionsChain({}, options, {
|
|
24
19
|
env: 'server',
|
|
@@ -40,37 +35,38 @@ const serializeServerGlobalVars = (options)=>{
|
|
|
40
35
|
];
|
|
41
36
|
}));
|
|
42
37
|
};
|
|
43
|
-
const transformServerGlobalVars =
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
};
|
|
38
|
+
const transformServerGlobalVars = (outputDirectories, globalVars)=>Promise.resolve().then(()=>{
|
|
39
|
+
if (0 === Object.keys(globalVars).length) return;
|
|
40
|
+
return Promise.all(outputDirectories.map((directory)=>fs.pathExists(directory).then((directoryExists)=>directoryExists ? directory : void 0))).then((existingDirectories)=>{
|
|
41
|
+
const filesPromise = Promise.all(existingDirectories.filter((directory)=>void 0 !== directory).map(collectJavaScriptFiles)).then((files)=>files.flat());
|
|
42
|
+
const releaseIdentityBanner = RELEASE_IDENTITY_GLOBAL_NAMES.every((name)=>Object.hasOwn(globalVars, name)) ? `${RELEASE_IDENTITY_GLOBAL_NAMES.map((name)=>`void ${globalVars[name]};`).join('')}\n` : '';
|
|
43
|
+
return filesPromise.then((files)=>Promise.all(files.map((filename)=>fs.readFile(filename, 'utf8').then((source)=>{
|
|
44
|
+
const sourceMapFilename = `${filename}.map`;
|
|
45
|
+
return fs.pathExists(sourceMapFilename).then((sourceMapExists)=>{
|
|
46
|
+
const inputSourceMapPromise = sourceMapExists ? fs.readFile(sourceMapFilename, 'utf8') : Promise.resolve(void 0);
|
|
47
|
+
return inputSourceMapPromise.then((inputSourceMap)=>transform(`${releaseIdentityBanner}${source}`, {
|
|
48
|
+
filename,
|
|
49
|
+
inputSourceMap,
|
|
50
|
+
sourceMaps: sourceMapExists,
|
|
51
|
+
jsc: {
|
|
52
|
+
parser: {
|
|
53
|
+
syntax: "ecmascript"
|
|
54
|
+
},
|
|
55
|
+
preserveAllComments: true,
|
|
56
|
+
target: 'es2022',
|
|
57
|
+
transform: {
|
|
58
|
+
optimizer: {
|
|
59
|
+
globals: {
|
|
60
|
+
vars: globalVars
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}).then((result)=>fs.writeFile(filename, result.code).then(()=>{
|
|
66
|
+
if (sourceMapExists && void 0 !== result.map && result.map.length > 0) return fs.writeFile(sourceMapFilename, result.map);
|
|
67
|
+
})));
|
|
68
|
+
});
|
|
69
|
+
}))));
|
|
70
|
+
}).then(()=>void 0);
|
|
71
|
+
});
|
|
76
72
|
export { serializeServerGlobalVars, transformServerGlobalVars };
|
package/dist/esm/cli.mjs
CHANGED
package/dist/esm/loader.mjs
CHANGED
|
@@ -4,6 +4,7 @@ import path from "path";
|
|
|
4
4
|
import { generateEffectClientCode, resolveEffectEntryFile } from "./utils/effectClientGenerator.mjs";
|
|
5
5
|
const EFFECT_BFF_WORKER_RUNTIME_QUERY = 'modern-bff-runtime';
|
|
6
6
|
const EFFECT_BFF_WORKER_RUNTIME_SOURCE_QUERY = 'modern-bff-runtime-source';
|
|
7
|
+
const createErrorModule = (message)=>`throw new Error(${JSON.stringify(message)});`;
|
|
7
8
|
async function transformEffectRuntimeSource(source, filename) {
|
|
8
9
|
const swc = await import("@swc/core");
|
|
9
10
|
const result = await swc.transform(source, {
|
|
@@ -25,7 +26,7 @@ async function transformEffectRuntimeSource(source, filename) {
|
|
|
25
26
|
function createEffectWorkerRuntimeWrapper(resourcePath) {
|
|
26
27
|
const sourceRequest = `${resourcePath}?${EFFECT_BFF_WORKER_RUNTIME_SOURCE_QUERY}`;
|
|
27
28
|
return `import * as effectBffModule from ${JSON.stringify(sourceRequest)};
|
|
28
|
-
import { createEffectBffEdgeDispatcher } from '@modern-js/plugin-bff/effect-edge';
|
|
29
|
+
import { createEffectBffEdgeDispatcher } from '@modern-js/plugin-bff/effect-edge/dispatcher';
|
|
29
30
|
|
|
30
31
|
export const __modern_create_effect_bff_dispatcher = options =>
|
|
31
32
|
createEffectBffEdgeDispatcher({
|
|
@@ -66,13 +67,13 @@ async function loader(source) {
|
|
|
66
67
|
onDependency: (dependency)=>this.addDependency(dependency)
|
|
67
68
|
});
|
|
68
69
|
if (code) return void callback(void 0, code);
|
|
69
|
-
callback(void 0, `
|
|
70
|
+
callback(void 0, createErrorModule(`Failed to generate Effect client for ${resourcePath}`));
|
|
70
71
|
return;
|
|
71
72
|
}
|
|
72
73
|
const warning = `The file ${resourcePath} is not allowed to be imported in src directory, only API definition files are allowed.`;
|
|
73
74
|
if (!draftOptions.existLambda) {
|
|
74
75
|
logger.warn(warning);
|
|
75
|
-
callback(null,
|
|
76
|
+
callback(null, createErrorModule(warning));
|
|
76
77
|
return;
|
|
77
78
|
}
|
|
78
79
|
const options = {
|
|
@@ -89,14 +90,14 @@ async function loader(source) {
|
|
|
89
90
|
const { lambdaDir } = draftOptions;
|
|
90
91
|
if (!resourcePath.startsWith(lambdaDir)) {
|
|
91
92
|
logger.warn(warning);
|
|
92
|
-
callback(null,
|
|
93
|
+
callback(null, createErrorModule(warning));
|
|
93
94
|
return;
|
|
94
95
|
}
|
|
95
96
|
if (draftOptions.fetcher) options.fetcher = draftOptions.fetcher;
|
|
96
97
|
if (draftOptions.requestCreator) options.requestCreator = draftOptions.requestCreator;
|
|
97
98
|
options.requireResolve = require.resolve;
|
|
98
99
|
const result = await generateClient(options);
|
|
99
|
-
callback(void 0, result.isOk ? result.value :
|
|
100
|
+
callback(void 0, result.isOk ? result.value : createErrorModule(result.value));
|
|
100
101
|
}
|
|
101
102
|
const src_loader = loader;
|
|
102
103
|
export default src_loader;
|
|
@@ -2,22 +2,27 @@ import { logger } from "@modern-js/utils";
|
|
|
2
2
|
import { HttpApi } from "effect/unstable/httpapi";
|
|
3
3
|
import { resolveAdapterCrossProjectPolicy } from "../../../utils/crossProjectServerPolicy.mjs";
|
|
4
4
|
import { collectEffectEndpoints, extractHttpApiFromModule, toOperationContractSources } from "../endpoint-contracts.mjs";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
5
|
+
function resolveEffectAdapterCrossProjectPolicy(api, prefix, mod) {
|
|
6
|
+
const contractSourcesPromise = null === mod ? Promise.resolve([]) : Promise.resolve().then(()=>extractHttpApiFromModule(mod, HttpApi.isHttpApi)).then((effectApi)=>{
|
|
7
|
+
if (null !== effectApi) {
|
|
8
|
+
const reflect = (apiValue, handlers)=>{
|
|
9
|
+
if (!HttpApi.isHttpApi(apiValue)) throw new Error('[BFF][Effect] Endpoint reflection received a non-HttpApi value.');
|
|
10
|
+
HttpApi.reflect(apiValue, {
|
|
11
11
|
onGroup: handlers.onGroup ?? (()=>{}),
|
|
12
12
|
onEndpoint: handlers.onEndpoint
|
|
13
13
|
});
|
|
14
|
-
|
|
14
|
+
};
|
|
15
|
+
return toOperationContractSources(collectEffectEndpoints(reflect, effectApi, prefix));
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
+
return [];
|
|
18
|
+
}).catch((error)=>{
|
|
17
19
|
logger.warn(`[BFF][Effect] Failed reflect HttpApi endpoints cross-project policy: ${String(error)}`);
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
return [];
|
|
21
|
+
});
|
|
22
|
+
return contractSourcesPromise.then((contractSources)=>{
|
|
23
|
+
const policy = resolveAdapterCrossProjectPolicy(api, contractSources);
|
|
24
|
+
if (policy?.enabled === true && 0 === contractSources.length) logger.warn('[BFF][Effect] Cross-project policy enabled but no HttpApi endpoints could be reflected; requests fail operation-contract matching unless allowUnknownOperations is enabled.');
|
|
25
|
+
return policy;
|
|
26
|
+
});
|
|
22
27
|
}
|
|
23
28
|
export { resolveEffectAdapterCrossProjectPolicy };
|