@bleedingdev/modern-js-plugin-bff 3.5.0-ultramodern.97 → 3.5.0-ultramodern.99

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.
@@ -37,6 +37,11 @@ __webpack_require__.d(__webpack_exports__, {
37
37
  });
38
38
  const bff_core_namespaceObject = require("@modern-js/bff-core");
39
39
  const external_entry_shape_js_namespaceObject = require("./entry-shape.js");
40
+ function resolveEffectEndpointName(endpoint) {
41
+ if ('string' == typeof endpoint.identifier && endpoint.identifier) return endpoint.identifier;
42
+ if ('string' == typeof endpoint.name && endpoint.name) return endpoint.name;
43
+ return '';
44
+ }
40
45
  function ensureLeadingSlash(pathname) {
41
46
  return pathname.startsWith('/') ? pathname : `/${pathname}`;
42
47
  }
@@ -65,7 +70,7 @@ function collectEffectEndpoints(reflect, api, prefix) {
65
70
  endpoints.push({
66
71
  apiId,
67
72
  groupName: String(group.identifier),
68
- endpointName: String(endpoint.name),
73
+ endpointName: resolveEffectEndpointName(endpoint),
69
74
  method: String(endpoint.method).toUpperCase(),
70
75
  routePath: getEffectRoutePath(prefix, String(endpoint.path))
71
76
  });
@@ -39,7 +39,6 @@ __webpack_require__.r(__webpack_exports__);
39
39
  __webpack_require__.d(__webpack_exports__, {
40
40
  HonoAdapter: ()=>HonoAdapter
41
41
  });
42
- const server_core_namespaceObject = require("@modern-js/server-core");
43
42
  const utils_namespaceObject = require("@modern-js/utils");
44
43
  const createHonoRoutes_js_namespaceObject = require("../../utils/createHonoRoutes.js");
45
44
  var createHonoRoutes_js_default = /*#__PURE__*/ __webpack_require__.n(createHonoRoutes_js_namespaceObject);
@@ -50,17 +49,9 @@ const before = [
50
49
  'custom-server-middleware',
51
50
  'render'
52
51
  ];
53
- const kParentHonoVars = Symbol.for('modernjs.hono.parentVars');
54
52
  class HonoAdapter {
55
- wrapInArray(handler) {
56
- if (Array.isArray(handler)) return handler;
57
- return [
58
- handler
59
- ];
60
- }
61
53
  constructor(api){
62
54
  this.apiMiddleware = [];
63
- this.apiServer = null;
64
55
  this.isHono = true;
65
56
  this.prefix = '/api';
66
57
  this.setHandlers = async ()=>{
@@ -71,7 +62,7 @@ class HonoAdapter {
71
62
  name: 'hono-bff-api',
72
63
  path,
73
64
  method,
74
- handler,
65
+ handler: this.withErrorBoundary(handler),
75
66
  order: 'post',
76
67
  before
77
68
  }));
@@ -92,85 +83,47 @@ class HonoAdapter {
92
83
  });
93
84
  }
94
85
  };
95
- this.registerApiRoutes = async ()=>{
96
- if (!this.isHono) return;
97
- this.apiServer = new server_core_namespaceObject.Hono();
98
- this.apiServer.use('*', server_core_namespaceObject.run);
99
- this.apiServer.use('*', async (c, next)=>{
100
- const nodeReq = c.env?.node?.req;
101
- const parentVars = nodeReq?.[kParentHonoVars];
102
- if (parentVars && 'object' == typeof parentVars) {
103
- delete nodeReq[kParentHonoVars];
104
- for (const [key, value] of Object.entries(parentVars))if (void 0 === c.get(key)) c.set(key, value);
105
- }
106
- await next();
107
- });
108
- this.apiMiddleware.forEach(({ path = '*', method = 'all', handler })=>{
109
- const handlers = this.wrapInArray(handler);
110
- if (0 === handlers.length) return;
111
- const firstHandler = handlers[0];
112
- const restHandlers = handlers.slice(1);
113
- const m = method;
114
- const server = this.apiServer;
115
- if (!server) return;
116
- const register = server[m];
117
- register.call(server, path, firstHandler, ...restHandlers);
118
- });
119
- this.apiServer.onError(async (err, c)=>{
120
- try {
121
- const serverConfig = this.api.getServerConfig();
122
- const onErrorHandler = serverConfig?.onError;
123
- if (onErrorHandler) {
124
- const result = await onErrorHandler(err, c);
125
- if (result instanceof Response) return result;
126
- } else utils_namespaceObject.logger.error(err);
127
- } catch (configError) {
128
- utils_namespaceObject.logger.error(`Error in serverConfig.onError handler: ${configError}`);
129
- }
130
- return (0, external_safe_failure_js_namespaceObject.createSafeFailureResponse)(err);
131
- });
132
- };
133
- this.registerMiddleware = async (options)=>{
134
- const { prefix } = options;
86
+ this.registerMiddleware = async (options = {})=>{
135
87
  const { bffRuntimeFramework } = this.api.getServerContext();
136
88
  if ('hono' !== bffRuntimeFramework) {
137
89
  this.isHono = false;
138
90
  return;
139
91
  }
92
+ const { prefix } = options;
140
93
  this.prefix = prefix || this.prefix;
141
94
  const { middlewares: globalMiddlewares } = this.api.getServerContext();
142
95
  await this.setHandlers();
143
- if ((0, utils_namespaceObject.isProd)()) globalMiddlewares.push(...this.apiMiddleware);
144
- else {
145
- await this.registerApiRoutes();
146
- const dynamicApiMiddleware = {
147
- name: 'dynamic-bff-handler',
148
- path: `${prefix}/*`,
149
- method: 'all',
150
- order: 'post',
151
- before,
152
- handler: async (c, next)=>{
153
- if (this.apiServer) {
154
- const nodeReq = c.env?.node?.req;
155
- if (nodeReq) {
156
- const parentVars = c?.var;
157
- nodeReq[kParentHonoVars] = parentVars && 'object' == typeof parentVars ? {
158
- ...parentVars
159
- } : parentVars;
160
- }
161
- const response = await this.apiServer.fetch(c.req.raw, c.env);
162
- if (404 !== response.status) return new Response(response.body, response);
163
- }
164
- await next();
165
- }
166
- };
167
- globalMiddlewares.push(dynamicApiMiddleware);
96
+ globalMiddlewares.push(...this.apiMiddleware);
97
+ };
98
+ this.handleRouteError = async (error, c)=>{
99
+ try {
100
+ const onErrorHandler = this.api.getServerConfig()?.onError;
101
+ if (onErrorHandler) {
102
+ const result = await onErrorHandler(error, c);
103
+ if (result instanceof Response) return result;
104
+ } else utils_namespaceObject.logger.error(error);
105
+ } catch (configError) {
106
+ utils_namespaceObject.logger.error(`Error in serverConfig.onError handler: ${configError}`);
168
107
  }
108
+ return (0, external_safe_failure_js_namespaceObject.createSafeFailureResponse)(error);
169
109
  };
170
- this.onApiHandlersUpdated = async ()=>{
171
- if (!this.isHono) return;
172
- await this.setHandlers();
173
- await this.registerApiRoutes();
110
+ this.withErrorBoundary = (handler)=>{
111
+ const handlers = Array.isArray(handler) ? handler : [
112
+ handler
113
+ ];
114
+ const [firstHandler, ...restHandlers] = handlers;
115
+ if (!firstHandler) return handler;
116
+ const boundary = async (c, next)=>{
117
+ try {
118
+ return await firstHandler(c, next);
119
+ } catch (error) {
120
+ return this.handleRouteError(error, c);
121
+ }
122
+ };
123
+ return Array.isArray(handler) ? [
124
+ boundary,
125
+ ...restHandlers
126
+ ] : boundary;
174
127
  };
175
128
  this.api = api;
176
129
  }
@@ -43,15 +43,17 @@ const bff_core_namespaceObject = require("@modern-js/bff-core");
43
43
  const utils_namespaceObject = require("@modern-js/utils");
44
44
  const external_path_namespaceObject = require("path");
45
45
  var external_path_default = /*#__PURE__*/ __webpack_require__.n(external_path_namespaceObject);
46
- const adapter_js_namespaceObject = require("./runtime/effect/adapter.js");
47
- const hono_adapter_js_namespaceObject = require("./runtime/hono/adapter.js");
48
- const RUNTIME_ADAPTER_FACTORIES = {
49
- hono: [
50
- (api)=>new hono_adapter_js_namespaceObject.HonoAdapter(api)
51
- ],
52
- effect: [
53
- (api)=>new adapter_js_namespaceObject.EffectAdapter(api)
54
- ]
46
+ const adapter_js_namespaceObject = require("./runtime/hono/adapter.js");
47
+ const RUNTIME_ADAPTER_LOADERS = {
48
+ hono: async (api)=>[
49
+ new adapter_js_namespaceObject.HonoAdapter(api)
50
+ ],
51
+ effect: async (api)=>{
52
+ const { EffectAdapter } = await import("./runtime/effect/adapter.js");
53
+ return [
54
+ new EffectAdapter(api)
55
+ ];
56
+ }
55
57
  };
56
58
  const normalizePrefixList = (prefix)=>{
57
59
  if (Array.isArray(prefix)) return prefix.filter(Boolean);
@@ -64,9 +66,6 @@ function resolveRuntimeFramework(runtimeFramework) {
64
66
  return 'hono' === runtimeFramework ? 'hono' : 'effect';
65
67
  }
66
68
  class Storage {
67
- reset() {
68
- this.middlewares = [];
69
- }
70
69
  constructor(){
71
70
  this.middlewares = [];
72
71
  }
@@ -78,7 +77,6 @@ const server = ()=>({
78
77
  let apiRouter = null;
79
78
  const appContext = api.getServerContext();
80
79
  const runtimeFramework = resolveRuntimeFramework(appContext.bffRuntimeFramework);
81
- const runtimeAdapters = RUNTIME_ADAPTER_FACTORIES[runtimeFramework].map((createAdapter)=>createAdapter(api));
82
80
  api.onPrepare(async ()=>{
83
81
  const appContext = api.getServerContext();
84
82
  const { render } = appContext;
@@ -124,29 +122,20 @@ const server = ()=>({
124
122
  ]
125
123
  });
126
124
  }
125
+ const runtimeAdapters = await RUNTIME_ADAPTER_LOADERS[runtimeFramework](api);
127
126
  await Promise.all(runtimeAdapters.map((adapter)=>adapter.registerMiddleware({
128
127
  prefix,
129
128
  enableHandleWeb
130
129
  })));
131
130
  });
132
131
  api.onReset(async ({ event })=>{
133
- storage.reset();
134
- const appContext = api.getServerContext();
135
- const { middlewares } = storage;
136
- api.updateServerContext({
137
- ...appContext,
138
- apiMiddlewares: middlewares
139
- });
140
- if ('file-change' === event.type) {
141
- if ('hono' === runtimeFramework && apiRouter) {
142
- const apiHandlerInfos = await apiRouter.getApiHandlers();
143
- const appContext = api.getServerContext();
144
- api.updateServerContext({
145
- ...appContext,
146
- apiHandlerInfos
147
- });
148
- }
149
- await Promise.all(runtimeAdapters.map((adapter)=>adapter.onApiHandlersUpdated?.()));
132
+ if ('file-change' === event.type && apiRouter) {
133
+ const appContext = api.getServerContext();
134
+ const apiHandlerInfos = await apiRouter.getApiHandlers();
135
+ api.updateServerContext({
136
+ ...appContext,
137
+ apiHandlerInfos
138
+ });
150
139
  }
151
140
  });
152
141
  const prepareApiServer = async (input, next)=>{
@@ -112,7 +112,7 @@ async function setPackage(files, appDirectory, relativeDistPath) {
112
112
  }
113
113
  });
114
114
  (0, external_package_json_js_namespaceObject.mergePackageJson)(packageJson, addFiles, typesVersions, exports1, relativeDistPath);
115
- await utils_namespaceObject.fs.promises.writeFile(packagePath, JSON.stringify(packageJson, null, 2));
115
+ await utils_namespaceObject.fs.promises.writeFile(packagePath, `${JSON.stringify(packageJson, null, 2)}\n`);
116
116
  }
117
117
  exports.setPackage = __webpack_exports__.setPackage;
118
118
  exports.writeClientModuleBoundary = __webpack_exports__.writeClientModuleBoundary;
@@ -1,5 +1,10 @@
1
1
  import { createOperationContractHash } from "@modern-js/bff-core";
2
2
  import { classifyEffectBffEntryModule, isValidatorAwareHandlerFactory } from "./entry-shape.mjs";
3
+ function resolveEffectEndpointName(endpoint) {
4
+ if ('string' == typeof endpoint.identifier && endpoint.identifier) return endpoint.identifier;
5
+ if ('string' == typeof endpoint.name && endpoint.name) return endpoint.name;
6
+ return '';
7
+ }
3
8
  function ensureLeadingSlash(pathname) {
4
9
  return pathname.startsWith('/') ? pathname : `/${pathname}`;
5
10
  }
@@ -28,7 +33,7 @@ function collectEffectEndpoints(reflect, api, prefix) {
28
33
  endpoints.push({
29
34
  apiId,
30
35
  groupName: String(group.identifier),
31
- endpointName: String(endpoint.name),
36
+ endpointName: resolveEffectEndpointName(endpoint),
32
37
  method: String(endpoint.method).toUpperCase(),
33
38
  routePath: getEffectRoutePath(prefix, String(endpoint.path))
34
39
  });
@@ -1,5 +1,4 @@
1
- import { Hono, run } from "@modern-js/server-core";
2
- import { isProd, logger } from "@modern-js/utils";
1
+ import { logger } from "@modern-js/utils";
3
2
  import createHonoRoutes from "../../utils/createHonoRoutes.mjs";
4
3
  import { checkCrossProjectPolicyResponse, resolveAdapterCrossProjectPolicy } from "../../utils/crossProjectServerPolicy.mjs";
5
4
  import { createSafeFailureResponse } from "../safe-failure.mjs";
@@ -8,17 +7,9 @@ const before = [
8
7
  'custom-server-middleware',
9
8
  'render'
10
9
  ];
11
- const kParentHonoVars = Symbol.for('modernjs.hono.parentVars');
12
10
  class HonoAdapter {
13
- wrapInArray(handler) {
14
- if (Array.isArray(handler)) return handler;
15
- return [
16
- handler
17
- ];
18
- }
19
11
  constructor(api){
20
12
  this.apiMiddleware = [];
21
- this.apiServer = null;
22
13
  this.isHono = true;
23
14
  this.prefix = '/api';
24
15
  this.setHandlers = async ()=>{
@@ -29,7 +20,7 @@ class HonoAdapter {
29
20
  name: 'hono-bff-api',
30
21
  path,
31
22
  method,
32
- handler,
23
+ handler: this.withErrorBoundary(handler),
33
24
  order: 'post',
34
25
  before: before
35
26
  }));
@@ -50,85 +41,47 @@ class HonoAdapter {
50
41
  });
51
42
  }
52
43
  };
53
- this.registerApiRoutes = async ()=>{
54
- if (!this.isHono) return;
55
- this.apiServer = new Hono();
56
- this.apiServer.use('*', run);
57
- this.apiServer.use('*', async (c, next)=>{
58
- const nodeReq = c.env?.node?.req;
59
- const parentVars = nodeReq?.[kParentHonoVars];
60
- if (parentVars && 'object' == typeof parentVars) {
61
- delete nodeReq[kParentHonoVars];
62
- for (const [key, value] of Object.entries(parentVars))if (void 0 === c.get(key)) c.set(key, value);
63
- }
64
- await next();
65
- });
66
- this.apiMiddleware.forEach(({ path = '*', method = 'all', handler })=>{
67
- const handlers = this.wrapInArray(handler);
68
- if (0 === handlers.length) return;
69
- const firstHandler = handlers[0];
70
- const restHandlers = handlers.slice(1);
71
- const m = method;
72
- const server = this.apiServer;
73
- if (!server) return;
74
- const register = server[m];
75
- register.call(server, path, firstHandler, ...restHandlers);
76
- });
77
- this.apiServer.onError(async (err, c)=>{
78
- try {
79
- const serverConfig = this.api.getServerConfig();
80
- const onErrorHandler = serverConfig?.onError;
81
- if (onErrorHandler) {
82
- const result = await onErrorHandler(err, c);
83
- if (result instanceof Response) return result;
84
- } else logger.error(err);
85
- } catch (configError) {
86
- logger.error(`Error in serverConfig.onError handler: ${configError}`);
87
- }
88
- return createSafeFailureResponse(err);
89
- });
90
- };
91
- this.registerMiddleware = async (options)=>{
92
- const { prefix } = options;
44
+ this.registerMiddleware = async (options = {})=>{
93
45
  const { bffRuntimeFramework } = this.api.getServerContext();
94
46
  if ('hono' !== bffRuntimeFramework) {
95
47
  this.isHono = false;
96
48
  return;
97
49
  }
50
+ const { prefix } = options;
98
51
  this.prefix = prefix || this.prefix;
99
52
  const { middlewares: globalMiddlewares } = this.api.getServerContext();
100
53
  await this.setHandlers();
101
- if (isProd()) globalMiddlewares.push(...this.apiMiddleware);
102
- else {
103
- await this.registerApiRoutes();
104
- const dynamicApiMiddleware = {
105
- name: 'dynamic-bff-handler',
106
- path: `${prefix}/*`,
107
- method: 'all',
108
- order: 'post',
109
- before: before,
110
- handler: async (c, next)=>{
111
- if (this.apiServer) {
112
- const nodeReq = c.env?.node?.req;
113
- if (nodeReq) {
114
- const parentVars = c?.var;
115
- nodeReq[kParentHonoVars] = parentVars && 'object' == typeof parentVars ? {
116
- ...parentVars
117
- } : parentVars;
118
- }
119
- const response = await this.apiServer.fetch(c.req.raw, c.env);
120
- if (404 !== response.status) return new Response(response.body, response);
121
- }
122
- await next();
123
- }
124
- };
125
- globalMiddlewares.push(dynamicApiMiddleware);
54
+ globalMiddlewares.push(...this.apiMiddleware);
55
+ };
56
+ this.handleRouteError = async (error, c)=>{
57
+ try {
58
+ const onErrorHandler = this.api.getServerConfig()?.onError;
59
+ if (onErrorHandler) {
60
+ const result = await onErrorHandler(error, c);
61
+ if (result instanceof Response) return result;
62
+ } else logger.error(error);
63
+ } catch (configError) {
64
+ logger.error(`Error in serverConfig.onError handler: ${configError}`);
126
65
  }
66
+ return createSafeFailureResponse(error);
127
67
  };
128
- this.onApiHandlersUpdated = async ()=>{
129
- if (!this.isHono) return;
130
- await this.setHandlers();
131
- await this.registerApiRoutes();
68
+ this.withErrorBoundary = (handler)=>{
69
+ const handlers = Array.isArray(handler) ? handler : [
70
+ handler
71
+ ];
72
+ const [firstHandler, ...restHandlers] = handlers;
73
+ if (!firstHandler) return handler;
74
+ const boundary = async (c, next)=>{
75
+ try {
76
+ return await firstHandler(c, next);
77
+ } catch (error) {
78
+ return this.handleRouteError(error, c);
79
+ }
80
+ };
81
+ return Array.isArray(handler) ? [
82
+ boundary,
83
+ ...restHandlers
84
+ ] : boundary;
132
85
  };
133
86
  this.api = api;
134
87
  }
@@ -1,15 +1,17 @@
1
1
  import { ApiRouter } from "@modern-js/bff-core";
2
2
  import { API_DIR, isFunction, isWebOnly } from "@modern-js/utils";
3
3
  import path from "path";
4
- import { EffectAdapter } from "./runtime/effect/adapter.mjs";
5
4
  import { HonoAdapter } from "./runtime/hono/adapter.mjs";
6
- const RUNTIME_ADAPTER_FACTORIES = {
7
- hono: [
8
- (api)=>new HonoAdapter(api)
9
- ],
10
- effect: [
11
- (api)=>new EffectAdapter(api)
12
- ]
5
+ const RUNTIME_ADAPTER_LOADERS = {
6
+ hono: async (api)=>[
7
+ new HonoAdapter(api)
8
+ ],
9
+ effect: async (api)=>{
10
+ const { EffectAdapter } = await import("./runtime/effect/adapter.mjs");
11
+ return [
12
+ new EffectAdapter(api)
13
+ ];
14
+ }
13
15
  };
14
16
  const normalizePrefixList = (prefix)=>{
15
17
  if (Array.isArray(prefix)) return prefix.filter(Boolean);
@@ -22,9 +24,6 @@ function resolveRuntimeFramework(runtimeFramework) {
22
24
  return 'hono' === runtimeFramework ? 'hono' : 'effect';
23
25
  }
24
26
  class Storage {
25
- reset() {
26
- this.middlewares = [];
27
- }
28
27
  constructor(){
29
28
  this.middlewares = [];
30
29
  }
@@ -36,7 +35,6 @@ const server = ()=>({
36
35
  let apiRouter = null;
37
36
  const appContext = api.getServerContext();
38
37
  const runtimeFramework = resolveRuntimeFramework(appContext.bffRuntimeFramework);
39
- const runtimeAdapters = RUNTIME_ADAPTER_FACTORIES[runtimeFramework].map((createAdapter)=>createAdapter(api));
40
38
  api.onPrepare(async ()=>{
41
39
  const appContext = api.getServerContext();
42
40
  const { render } = appContext;
@@ -82,29 +80,20 @@ const server = ()=>({
82
80
  ]
83
81
  });
84
82
  }
83
+ const runtimeAdapters = await RUNTIME_ADAPTER_LOADERS[runtimeFramework](api);
85
84
  await Promise.all(runtimeAdapters.map((adapter)=>adapter.registerMiddleware({
86
85
  prefix,
87
86
  enableHandleWeb
88
87
  })));
89
88
  });
90
89
  api.onReset(async ({ event })=>{
91
- storage.reset();
92
- const appContext = api.getServerContext();
93
- const { middlewares } = storage;
94
- api.updateServerContext({
95
- ...appContext,
96
- apiMiddlewares: middlewares
97
- });
98
- if ('file-change' === event.type) {
99
- if ('hono' === runtimeFramework && apiRouter) {
100
- const apiHandlerInfos = await apiRouter.getApiHandlers();
101
- const appContext = api.getServerContext();
102
- api.updateServerContext({
103
- ...appContext,
104
- apiHandlerInfos
105
- });
106
- }
107
- await Promise.all(runtimeAdapters.map((adapter)=>adapter.onApiHandlersUpdated?.()));
90
+ if ('file-change' === event.type && apiRouter) {
91
+ const appContext = api.getServerContext();
92
+ const apiHandlerInfos = await apiRouter.getApiHandlers();
93
+ api.updateServerContext({
94
+ ...appContext,
95
+ apiHandlerInfos
96
+ });
108
97
  }
109
98
  });
110
99
  const prepareApiServer = async (input, next)=>{
@@ -69,6 +69,6 @@ async function setPackage(files, appDirectory, relativeDistPath) {
69
69
  }
70
70
  });
71
71
  mergePackageJson(packageJson, addFiles, typesVersions, exports, relativeDistPath);
72
- await fs.promises.writeFile(packagePath, JSON.stringify(packageJson, null, 2));
72
+ await fs.promises.writeFile(packagePath, `${JSON.stringify(packageJson, null, 2)}\n`);
73
73
  }
74
74
  export { setPackage, writeClientModuleBoundary };
@@ -1,6 +1,11 @@
1
1
  import "node:module";
2
2
  import { createOperationContractHash } from "@modern-js/bff-core";
3
3
  import { classifyEffectBffEntryModule, isValidatorAwareHandlerFactory } from "./entry-shape.mjs";
4
+ function resolveEffectEndpointName(endpoint) {
5
+ if ('string' == typeof endpoint.identifier && endpoint.identifier) return endpoint.identifier;
6
+ if ('string' == typeof endpoint.name && endpoint.name) return endpoint.name;
7
+ return '';
8
+ }
4
9
  function ensureLeadingSlash(pathname) {
5
10
  return pathname.startsWith('/') ? pathname : `/${pathname}`;
6
11
  }
@@ -29,7 +34,7 @@ function collectEffectEndpoints(reflect, api, prefix) {
29
34
  endpoints.push({
30
35
  apiId,
31
36
  groupName: String(group.identifier),
32
- endpointName: String(endpoint.name),
37
+ endpointName: resolveEffectEndpointName(endpoint),
33
38
  method: String(endpoint.method).toUpperCase(),
34
39
  routePath: getEffectRoutePath(prefix, String(endpoint.path))
35
40
  });
@@ -1,6 +1,5 @@
1
1
  import "node:module";
2
- import { Hono, run } from "@modern-js/server-core";
3
- import { isProd, logger } from "@modern-js/utils";
2
+ import { logger } from "@modern-js/utils";
4
3
  import createHonoRoutes from "../../utils/createHonoRoutes.mjs";
5
4
  import { checkCrossProjectPolicyResponse, resolveAdapterCrossProjectPolicy } from "../../utils/crossProjectServerPolicy.mjs";
6
5
  import { createSafeFailureResponse } from "../safe-failure.mjs";
@@ -9,17 +8,9 @@ const before = [
9
8
  'custom-server-middleware',
10
9
  'render'
11
10
  ];
12
- const kParentHonoVars = Symbol.for('modernjs.hono.parentVars');
13
11
  class HonoAdapter {
14
- wrapInArray(handler) {
15
- if (Array.isArray(handler)) return handler;
16
- return [
17
- handler
18
- ];
19
- }
20
12
  constructor(api){
21
13
  this.apiMiddleware = [];
22
- this.apiServer = null;
23
14
  this.isHono = true;
24
15
  this.prefix = '/api';
25
16
  this.setHandlers = async ()=>{
@@ -30,7 +21,7 @@ class HonoAdapter {
30
21
  name: 'hono-bff-api',
31
22
  path,
32
23
  method,
33
- handler,
24
+ handler: this.withErrorBoundary(handler),
34
25
  order: 'post',
35
26
  before: before
36
27
  }));
@@ -51,85 +42,47 @@ class HonoAdapter {
51
42
  });
52
43
  }
53
44
  };
54
- this.registerApiRoutes = async ()=>{
55
- if (!this.isHono) return;
56
- this.apiServer = new Hono();
57
- this.apiServer.use('*', run);
58
- this.apiServer.use('*', async (c, next)=>{
59
- const nodeReq = c.env?.node?.req;
60
- const parentVars = nodeReq?.[kParentHonoVars];
61
- if (parentVars && 'object' == typeof parentVars) {
62
- delete nodeReq[kParentHonoVars];
63
- for (const [key, value] of Object.entries(parentVars))if (void 0 === c.get(key)) c.set(key, value);
64
- }
65
- await next();
66
- });
67
- this.apiMiddleware.forEach(({ path = '*', method = 'all', handler })=>{
68
- const handlers = this.wrapInArray(handler);
69
- if (0 === handlers.length) return;
70
- const firstHandler = handlers[0];
71
- const restHandlers = handlers.slice(1);
72
- const m = method;
73
- const server = this.apiServer;
74
- if (!server) return;
75
- const register = server[m];
76
- register.call(server, path, firstHandler, ...restHandlers);
77
- });
78
- this.apiServer.onError(async (err, c)=>{
79
- try {
80
- const serverConfig = this.api.getServerConfig();
81
- const onErrorHandler = serverConfig?.onError;
82
- if (onErrorHandler) {
83
- const result = await onErrorHandler(err, c);
84
- if (result instanceof Response) return result;
85
- } else logger.error(err);
86
- } catch (configError) {
87
- logger.error(`Error in serverConfig.onError handler: ${configError}`);
88
- }
89
- return createSafeFailureResponse(err);
90
- });
91
- };
92
- this.registerMiddleware = async (options)=>{
93
- const { prefix } = options;
45
+ this.registerMiddleware = async (options = {})=>{
94
46
  const { bffRuntimeFramework } = this.api.getServerContext();
95
47
  if ('hono' !== bffRuntimeFramework) {
96
48
  this.isHono = false;
97
49
  return;
98
50
  }
51
+ const { prefix } = options;
99
52
  this.prefix = prefix || this.prefix;
100
53
  const { middlewares: globalMiddlewares } = this.api.getServerContext();
101
54
  await this.setHandlers();
102
- if (isProd()) globalMiddlewares.push(...this.apiMiddleware);
103
- else {
104
- await this.registerApiRoutes();
105
- const dynamicApiMiddleware = {
106
- name: 'dynamic-bff-handler',
107
- path: `${prefix}/*`,
108
- method: 'all',
109
- order: 'post',
110
- before: before,
111
- handler: async (c, next)=>{
112
- if (this.apiServer) {
113
- const nodeReq = c.env?.node?.req;
114
- if (nodeReq) {
115
- const parentVars = c?.var;
116
- nodeReq[kParentHonoVars] = parentVars && 'object' == typeof parentVars ? {
117
- ...parentVars
118
- } : parentVars;
119
- }
120
- const response = await this.apiServer.fetch(c.req.raw, c.env);
121
- if (404 !== response.status) return new Response(response.body, response);
122
- }
123
- await next();
124
- }
125
- };
126
- globalMiddlewares.push(dynamicApiMiddleware);
55
+ globalMiddlewares.push(...this.apiMiddleware);
56
+ };
57
+ this.handleRouteError = async (error, c)=>{
58
+ try {
59
+ const onErrorHandler = this.api.getServerConfig()?.onError;
60
+ if (onErrorHandler) {
61
+ const result = await onErrorHandler(error, c);
62
+ if (result instanceof Response) return result;
63
+ } else logger.error(error);
64
+ } catch (configError) {
65
+ logger.error(`Error in serverConfig.onError handler: ${configError}`);
127
66
  }
67
+ return createSafeFailureResponse(error);
128
68
  };
129
- this.onApiHandlersUpdated = async ()=>{
130
- if (!this.isHono) return;
131
- await this.setHandlers();
132
- await this.registerApiRoutes();
69
+ this.withErrorBoundary = (handler)=>{
70
+ const handlers = Array.isArray(handler) ? handler : [
71
+ handler
72
+ ];
73
+ const [firstHandler, ...restHandlers] = handlers;
74
+ if (!firstHandler) return handler;
75
+ const boundary = async (c, next)=>{
76
+ try {
77
+ return await firstHandler(c, next);
78
+ } catch (error) {
79
+ return this.handleRouteError(error, c);
80
+ }
81
+ };
82
+ return Array.isArray(handler) ? [
83
+ boundary,
84
+ ...restHandlers
85
+ ] : boundary;
133
86
  };
134
87
  this.api = api;
135
88
  }
@@ -2,15 +2,17 @@ import "node:module";
2
2
  import { ApiRouter } from "@modern-js/bff-core";
3
3
  import { API_DIR, isFunction, isWebOnly } from "@modern-js/utils";
4
4
  import path from "path";
5
- import { EffectAdapter } from "./runtime/effect/adapter.mjs";
6
5
  import { HonoAdapter } from "./runtime/hono/adapter.mjs";
7
- const RUNTIME_ADAPTER_FACTORIES = {
8
- hono: [
9
- (api)=>new HonoAdapter(api)
10
- ],
11
- effect: [
12
- (api)=>new EffectAdapter(api)
13
- ]
6
+ const RUNTIME_ADAPTER_LOADERS = {
7
+ hono: async (api)=>[
8
+ new HonoAdapter(api)
9
+ ],
10
+ effect: async (api)=>{
11
+ const { EffectAdapter } = await import("./runtime/effect/adapter.mjs");
12
+ return [
13
+ new EffectAdapter(api)
14
+ ];
15
+ }
14
16
  };
15
17
  const normalizePrefixList = (prefix)=>{
16
18
  if (Array.isArray(prefix)) return prefix.filter(Boolean);
@@ -23,9 +25,6 @@ function resolveRuntimeFramework(runtimeFramework) {
23
25
  return 'hono' === runtimeFramework ? 'hono' : 'effect';
24
26
  }
25
27
  class Storage {
26
- reset() {
27
- this.middlewares = [];
28
- }
29
28
  constructor(){
30
29
  this.middlewares = [];
31
30
  }
@@ -37,7 +36,6 @@ const server = ()=>({
37
36
  let apiRouter = null;
38
37
  const appContext = api.getServerContext();
39
38
  const runtimeFramework = resolveRuntimeFramework(appContext.bffRuntimeFramework);
40
- const runtimeAdapters = RUNTIME_ADAPTER_FACTORIES[runtimeFramework].map((createAdapter)=>createAdapter(api));
41
39
  api.onPrepare(async ()=>{
42
40
  const appContext = api.getServerContext();
43
41
  const { render } = appContext;
@@ -83,29 +81,20 @@ const server = ()=>({
83
81
  ]
84
82
  });
85
83
  }
84
+ const runtimeAdapters = await RUNTIME_ADAPTER_LOADERS[runtimeFramework](api);
86
85
  await Promise.all(runtimeAdapters.map((adapter)=>adapter.registerMiddleware({
87
86
  prefix,
88
87
  enableHandleWeb
89
88
  })));
90
89
  });
91
90
  api.onReset(async ({ event })=>{
92
- storage.reset();
93
- const appContext = api.getServerContext();
94
- const { middlewares } = storage;
95
- api.updateServerContext({
96
- ...appContext,
97
- apiMiddlewares: middlewares
98
- });
99
- if ('file-change' === event.type) {
100
- if ('hono' === runtimeFramework && apiRouter) {
101
- const apiHandlerInfos = await apiRouter.getApiHandlers();
102
- const appContext = api.getServerContext();
103
- api.updateServerContext({
104
- ...appContext,
105
- apiHandlerInfos
106
- });
107
- }
108
- await Promise.all(runtimeAdapters.map((adapter)=>adapter.onApiHandlersUpdated?.()));
91
+ if ('file-change' === event.type && apiRouter) {
92
+ const appContext = api.getServerContext();
93
+ const apiHandlerInfos = await apiRouter.getApiHandlers();
94
+ api.updateServerContext({
95
+ ...appContext,
96
+ apiHandlerInfos
97
+ });
109
98
  }
110
99
  });
111
100
  const prepareApiServer = async (input, next)=>{
@@ -70,6 +70,6 @@ async function setPackage(files, appDirectory, relativeDistPath) {
70
70
  }
71
71
  });
72
72
  mergePackageJson(packageJson, addFiles, typesVersions, exports, relativeDistPath);
73
- await fs.promises.writeFile(packagePath, JSON.stringify(packageJson, null, 2));
73
+ await fs.promises.writeFile(packagePath, `${JSON.stringify(packageJson, null, 2)}\n`);
74
74
  }
75
75
  export { setPackage, writeClientModuleBoundary };
@@ -25,6 +25,12 @@ type HttpApiGroupLike = {
25
25
  identifier?: unknown;
26
26
  };
27
27
  type HttpApiEndpointLike = {
28
+ /**
29
+ * effect 4.0.0-beta.98 renamed the endpoint `name` property to `identifier`,
30
+ * matching `HttpApiGroup`. `name` is kept as a fallback so reflection over an
31
+ * older Effect build does not silently degrade to the class name.
32
+ */
33
+ identifier?: unknown;
28
34
  name?: unknown;
29
35
  method?: unknown;
30
36
  path?: unknown;
@@ -1,7 +1,7 @@
1
1
  import type { HttpApi } from 'effect/unstable/httpapi';
2
2
  import type { Rpc } from 'effect/unstable/rpc';
3
3
  import type { EffectBffRuntime, EffectDataPlatformValidationOptions, EffectRpcBffDefinition, EffectRpcBffHandlerFactory, EffectRpcRuntimeLayer, EffectRuntimeLayer } from './types';
4
- export declare function defineEffectBff<TApi extends HttpApi.AnyWithProps, TLayer extends EffectRuntimeLayer, TRpcs extends Rpc.Any = Rpc.Any>(definition: {
4
+ export declare function defineEffectBff<TApi extends HttpApi.Constraint, TLayer extends EffectRuntimeLayer, TRpcs extends Rpc.Any = Rpc.Any>(definition: {
5
5
  api: TApi;
6
6
  layer: TLayer;
7
7
  rpc?: EffectRpcBffDefinition<TRpcs>;
@@ -1,7 +1,7 @@
1
1
  import type { HttpApi } from 'effect/unstable/httpapi';
2
2
  import type { Rpc } from 'effect/unstable/rpc';
3
3
  import type { EffectBffOpenApiConfig, EffectDataPlatformValidationOptions, EffectRequestValidator, EffectRpcBffDefinition, EffectRuntimeLayer } from './types';
4
- export declare function createHttpApiHandler<TApi extends HttpApi.AnyWithProps = HttpApi.AnyWithProps, TRpcs extends Rpc.Any = Rpc.Any>(options: {
4
+ export declare function createHttpApiHandler<TApi extends HttpApi.Constraint = HttpApi.Top, TRpcs extends Rpc.Any = Rpc.Any>(options: {
5
5
  api: TApi;
6
6
  layer: EffectRuntimeLayer;
7
7
  openapi?: EffectBffOpenApiConfig;
@@ -1,4 +1,4 @@
1
1
  import { HttpRouter } from 'effect/unstable/http';
2
2
  import { type HttpApi } from 'effect/unstable/httpapi';
3
3
  import type { EffectBffOpenApiConfig } from './types';
4
- export declare function createOpenApiLayer(api: HttpApi.AnyWithProps, openapi: EffectBffOpenApiConfig | undefined): import("effect/Layer").Layer<never, never, HttpRouter.HttpRouter> | null;
4
+ export declare function createOpenApiLayer(api: HttpApi.Constraint, openapi: EffectBffOpenApiConfig | undefined): import("effect/Layer").Layer<never, never, HttpRouter.HttpRouter> | null;
@@ -28,9 +28,9 @@ type EffectApiPromiseClient<TClient> = {
28
28
  [EndpointName in keyof TClient[GroupName]]: TClient[GroupName][EndpointName] extends (...args: infer TArgs) => infer TResult ? TResult extends EffectType.Effect<unknown, unknown, unknown> ? (...args: TArgs) => Promise<Exclude<EffectType.Success<TResult>, readonly [unknown, unknown]>> : never : never;
29
29
  };
30
30
  };
31
- export type EffectApiClientFromApi<TApi extends HttpApi.AnyWithProps = HttpApi.AnyWithProps> = TApi extends HttpApi.HttpApi<infer _ApiId, infer Groups> ? HttpApiClient.Client<Extract<Groups, HttpApiGroup.Any>, never, never> : never;
32
- export type EffectApiPromiseClientFromApi<TApi extends HttpApi.AnyWithProps = HttpApi.AnyWithProps> = EffectApiPromiseClient<EffectApiClientFromApi<TApi>>;
33
- export type EffectBffDefinition<TApi extends HttpApi.AnyWithProps = HttpApi.AnyWithProps, TLayer extends EffectRuntimeLayer = EffectRuntimeLayer, TRpcs extends Rpc.Any = Rpc.Any> = {
31
+ export type EffectApiClientFromApi<TApi extends HttpApi.Constraint = HttpApi.Top> = TApi extends HttpApi.HttpApi<infer _ApiId, infer Groups> ? HttpApiClient.Client<Extract<Groups, HttpApiGroup.Constraint>, never, never> : never;
32
+ export type EffectApiPromiseClientFromApi<TApi extends HttpApi.Constraint = HttpApi.Top> = EffectApiPromiseClient<EffectApiClientFromApi<TApi>>;
33
+ export type EffectBffDefinition<TApi extends HttpApi.Constraint = HttpApi.Top, TLayer extends EffectRuntimeLayer = EffectRuntimeLayer, TRpcs extends Rpc.Any = Rpc.Any> = {
34
34
  api: TApi;
35
35
  layer: TLayer;
36
36
  rpc?: EffectRpcBffDefinition<TRpcs>;
@@ -131,13 +131,13 @@ export type EffectDataPlatformValidationOptions = {
131
131
  * cannot bypass it.
132
132
  */
133
133
  export type EffectRequestValidator = (request: Request) => Response | null | undefined;
134
- export type EffectBffHandlerFactory<TApi extends HttpApi.AnyWithProps = HttpApi.AnyWithProps, TLayer extends EffectRuntimeLayer = EffectRuntimeLayer> = (options?: {
134
+ export type EffectBffHandlerFactory<TApi extends HttpApi.Constraint = HttpApi.Top, TLayer extends EffectRuntimeLayer = EffectRuntimeLayer> = (options?: {
135
135
  openapi?: EffectBffOpenApiConfig;
136
136
  rpc?: Partial<EffectRpcBffHandlerOptions>;
137
137
  dataPlatform?: Partial<EffectDataPlatformValidationOptions>;
138
138
  validateRequest?: EffectRequestValidator;
139
139
  }) => ReturnType<typeof createHttpApiHandler>;
140
- export type EffectBffRuntime<TApi extends HttpApi.AnyWithProps = HttpApi.AnyWithProps, TLayer extends EffectRuntimeLayer = EffectRuntimeLayer> = {
140
+ export type EffectBffRuntime<TApi extends HttpApi.Constraint = HttpApi.Top, TLayer extends EffectRuntimeLayer = EffectRuntimeLayer> = {
141
141
  createHandler: EffectBffHandlerFactory<TApi, TLayer>;
142
142
  client: EffectApiPromiseClientFromApi<TApi>;
143
143
  };
@@ -53,6 +53,6 @@ export type EffectRpcClientHandle<Rpcs extends Rpc.Any, Flatten extends boolean
53
53
  export declare function view<T>(): <const Selection extends EffectViewSelection<T>>(selection: Selection) => Selection;
54
54
  export declare function mask<T, const Selection extends EffectViewSelection<T>>(value: T, selection: Selection): EffectViewData<T, Selection>;
55
55
  export declare function runEffectView<T, const Selection extends EffectViewSelection<T>>(request: PromiseLike<T>, selection: Selection): Promise<EffectViewData<T, Selection>>;
56
- export declare function makeEffectHttpApiClient<ApiId extends string, Groups extends HttpApiGroup.Any>(api: HttpApi.HttpApi<ApiId, Groups>, options?: EffectHttpApiClientOptions): Effect.Effect<HttpApiClient.Client<Groups, never, never>, never, HttpApiGroup.MiddlewareClient<Groups>>;
56
+ export declare function makeEffectHttpApiClient<ApiId extends string, Groups extends HttpApiGroup.Constraint>(api: HttpApi.HttpApi<ApiId, Groups>, options?: EffectHttpApiClientOptions): Effect.Effect<HttpApiClient.Client<Groups, never, never>, never, HttpApiGroup.MiddlewareClient<Groups>>;
57
57
  export declare function makeEffectRpcClient<Rpcs extends Rpc.Any, const Flatten extends boolean = false>(group: RpcGroup.RpcGroup<Rpcs>, options: EffectRpcClientOptions<Rpcs, Flatten>): Effect.Effect<EffectRpcClientHandle<Rpcs, Flatten>, EffectRpcClientError, never>;
58
58
  export declare const runEffectRequest: <A, E>(effect: Effect.Effect<A, E>, options?: Effect.RunOptions | undefined) => Promise<A>;
@@ -1,22 +1,28 @@
1
- import type { MiddlewareHandler, ServerMiddleware, ServerPluginAPI } from '@modern-js/server-core';
2
- import { Hono } from '@modern-js/server-core';
1
+ import type { ServerMiddleware, ServerPluginAPI } from '@modern-js/server-core';
3
2
  import { type ResolvedCrossProjectPolicy } from '../../utils/crossProjectServerPolicy';
4
3
  interface MiddlewareOptions {
5
- prefix: string;
4
+ prefix?: string;
6
5
  enableHandleWeb?: boolean;
7
6
  }
8
7
  export declare class HonoAdapter {
9
8
  apiMiddleware: ServerMiddleware[];
10
- apiServer: Hono | null;
11
9
  api: ServerPluginAPI;
12
10
  isHono: boolean;
13
11
  prefix: string;
14
12
  crossProjectPolicy: ResolvedCrossProjectPolicy | undefined;
15
13
  constructor(api: ServerPluginAPI);
16
14
  setHandlers: () => Promise<void>;
17
- registerApiRoutes: () => Promise<void>;
18
- registerMiddleware: (options: MiddlewareOptions) => Promise<void>;
19
- onApiHandlersUpdated: () => Promise<void>;
20
- wrapInArray(handler: MiddlewareHandler[] | MiddlewareHandler): MiddlewareHandler[];
15
+ /**
16
+ * Register the BFF API routes as ordinary server middlewares.
17
+ *
18
+ * Dev and prod now share this single path: the routes are pushed straight
19
+ * into the server's middleware list. In dev, hot updates are handled by the
20
+ * unified `@modern-js/server` runtime reload (which rebuilds the whole
21
+ * runtime — including this plugin — from scratch), so BFF no longer needs its
22
+ * own swappable Hono sub-app / dynamic dispatch middleware.
23
+ */
24
+ registerMiddleware: (options?: MiddlewareOptions) => Promise<void>;
25
+ private handleRouteError;
26
+ private withErrorBoundary;
21
27
  }
22
28
  export {};
package/package.json CHANGED
@@ -17,7 +17,7 @@
17
17
  "modern",
18
18
  "modern.js"
19
19
  ],
20
- "version": "3.5.0-ultramodern.97",
20
+ "version": "3.5.0-ultramodern.99",
21
21
  "types": "./dist/types/cli.d.ts",
22
22
  "main": "./dist/cjs/cli.js",
23
23
  "exports": {
@@ -153,13 +153,12 @@
153
153
  }
154
154
  },
155
155
  "dependencies": {
156
- "@effect/opentelemetry": "4.0.0-beta.97",
157
- "@modern-js/bff-core": "npm:@bleedingdev/modern-js-bff-core@3.5.0-ultramodern.97",
158
- "@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.5.0-ultramodern.97",
159
- "@modern-js/create-request": "npm:@bleedingdev/modern-js-create-request@3.5.0-ultramodern.97",
160
- "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.5.0-ultramodern.97",
161
- "@modern-js/server-utils": "npm:@bleedingdev/modern-js-server-utils@3.5.0-ultramodern.97",
162
- "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.5.0-ultramodern.97",
156
+ "@modern-js/bff-core": "npm:@bleedingdev/modern-js-bff-core@3.5.0-ultramodern.99",
157
+ "@modern-js/builder": "npm:@bleedingdev/modern-js-builder@3.5.0-ultramodern.99",
158
+ "@modern-js/create-request": "npm:@bleedingdev/modern-js-create-request@3.5.0-ultramodern.99",
159
+ "@modern-js/server-core": "npm:@bleedingdev/modern-js-server-core@3.5.0-ultramodern.99",
160
+ "@modern-js/server-utils": "npm:@bleedingdev/modern-js-server-utils@3.5.0-ultramodern.99",
161
+ "@modern-js/utils": "npm:@bleedingdev/modern-js-utils@3.5.0-ultramodern.99",
163
162
  "@module-federation/runtime": "2.8.0",
164
163
  "@opentelemetry/api": "1.9.1",
165
164
  "@opentelemetry/api-logs": "0.220.0",
@@ -172,17 +171,29 @@
172
171
  "@opentelemetry/semantic-conventions": "1.43.0",
173
172
  "@swc/core": "1.15.43",
174
173
  "@swc/helpers": "^0.5.23",
175
- "effect": "4.0.0-beta.97",
176
174
  "esbuild": "^0.28.1",
177
175
  "qs": "^6.15.3",
178
176
  "type-is": "^2.1.0"
179
177
  },
178
+ "peerDependencies": {
179
+ "@effect/opentelemetry": "4.0.0-beta.102",
180
+ "effect": "4.0.0-beta.102"
181
+ },
182
+ "peerDependenciesMeta": {
183
+ "@effect/opentelemetry": {
184
+ "optional": true
185
+ },
186
+ "effect": {
187
+ "optional": true
188
+ }
189
+ },
180
190
  "devDependencies": {
181
- "@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.5.0-ultramodern.97",
182
- "@modern-js/bff-runtime": "npm:@bleedingdev/modern-js-bff-runtime@3.5.0-ultramodern.97",
183
- "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.5.0-ultramodern.97",
184
- "@modern-js/runtime": "npm:@bleedingdev/modern-js-runtime@3.5.0-ultramodern.97",
185
- "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.5.0-ultramodern.97",
191
+ "@effect/opentelemetry": "4.0.0-beta.102",
192
+ "@modern-js/app-tools": "npm:@bleedingdev/modern-js-app-tools@3.5.0-ultramodern.99",
193
+ "@modern-js/bff-runtime": "npm:@bleedingdev/modern-js-bff-runtime@3.5.0-ultramodern.99",
194
+ "@modern-js/plugin": "npm:@bleedingdev/modern-js-plugin@3.5.0-ultramodern.99",
195
+ "@modern-js/runtime": "npm:@bleedingdev/modern-js-runtime@3.5.0-ultramodern.99",
196
+ "@modern-js/types": "npm:@bleedingdev/modern-js-types@3.5.0-ultramodern.99",
186
197
  "@rsbuild/core": "2.1.5",
187
198
  "@rslib/core": "0.23.2",
188
199
  "@scripts/rstest-config": "2.66.0",
@@ -190,6 +201,7 @@
190
201
  "@types/qs": "^6.15.1",
191
202
  "@types/type-is": "^1.6.7",
192
203
  "@typescript/native-preview": "7.0.0-dev.20260707.2",
204
+ "effect": "4.0.0-beta.102",
193
205
  "memfs": "^4.64.0",
194
206
  "typescript": "^7.0.2",
195
207
  "zod": "^4.4.3"