@bleedingdev/modern-js-plugin-bff 3.2.0-ultramodern.0

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 (88) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +26 -0
  3. package/cli.js +1 -0
  4. package/dist/cjs/cli.js +294 -0
  5. package/dist/cjs/constants.js +48 -0
  6. package/dist/cjs/index.js +58 -0
  7. package/dist/cjs/loader.js +106 -0
  8. package/dist/cjs/runtime/create-request/index.js +48 -0
  9. package/dist/cjs/runtime/data-platform/index.js +693 -0
  10. package/dist/cjs/runtime/effect/adapter.js +311 -0
  11. package/dist/cjs/runtime/effect/context.js +48 -0
  12. package/dist/cjs/runtime/effect/index.js +608 -0
  13. package/dist/cjs/runtime/effect-client/index.js +178 -0
  14. package/dist/cjs/runtime/hono/adapter.js +168 -0
  15. package/dist/cjs/runtime/hono/index.js +65 -0
  16. package/dist/cjs/runtime/hono/operators.js +68 -0
  17. package/dist/cjs/server.js +179 -0
  18. package/dist/cjs/utils/clientGenerator.js +342 -0
  19. package/dist/cjs/utils/createHonoRoutes.js +138 -0
  20. package/dist/cjs/utils/crossProjectApiPlugin.js +118 -0
  21. package/dist/cjs/utils/effectClientGenerator.js +673 -0
  22. package/dist/cjs/utils/pluginGenerator.js +73 -0
  23. package/dist/cjs/utils/runtimeGenerator.js +133 -0
  24. package/dist/esm/cli.mjs +245 -0
  25. package/dist/esm/constants.mjs +11 -0
  26. package/dist/esm/index.mjs +1 -0
  27. package/dist/esm/loader.mjs +62 -0
  28. package/dist/esm/runtime/create-request/index.mjs +1 -0
  29. package/dist/esm/runtime/data-platform/index.mjs +599 -0
  30. package/dist/esm/runtime/effect/adapter.mjs +267 -0
  31. package/dist/esm/runtime/effect/context.mjs +11 -0
  32. package/dist/esm/runtime/effect/index.mjs +438 -0
  33. package/dist/esm/runtime/effect-client/index.mjs +90 -0
  34. package/dist/esm/runtime/hono/adapter.mjs +124 -0
  35. package/dist/esm/runtime/hono/index.mjs +2 -0
  36. package/dist/esm/runtime/hono/operators.mjs +31 -0
  37. package/dist/esm/server.mjs +135 -0
  38. package/dist/esm/utils/clientGenerator.mjs +293 -0
  39. package/dist/esm/utils/createHonoRoutes.mjs +92 -0
  40. package/dist/esm/utils/crossProjectApiPlugin.mjs +54 -0
  41. package/dist/esm/utils/effectClientGenerator.mjs +623 -0
  42. package/dist/esm/utils/pluginGenerator.mjs +29 -0
  43. package/dist/esm/utils/runtimeGenerator.mjs +89 -0
  44. package/dist/esm-node/cli.mjs +249 -0
  45. package/dist/esm-node/constants.mjs +12 -0
  46. package/dist/esm-node/index.mjs +2 -0
  47. package/dist/esm-node/loader.mjs +64 -0
  48. package/dist/esm-node/runtime/create-request/index.mjs +2 -0
  49. package/dist/esm-node/runtime/data-platform/index.mjs +600 -0
  50. package/dist/esm-node/runtime/effect/adapter.mjs +269 -0
  51. package/dist/esm-node/runtime/effect/context.mjs +12 -0
  52. package/dist/esm-node/runtime/effect/index.mjs +439 -0
  53. package/dist/esm-node/runtime/effect-client/index.mjs +91 -0
  54. package/dist/esm-node/runtime/hono/adapter.mjs +125 -0
  55. package/dist/esm-node/runtime/hono/index.mjs +3 -0
  56. package/dist/esm-node/runtime/hono/operators.mjs +32 -0
  57. package/dist/esm-node/server.mjs +136 -0
  58. package/dist/esm-node/utils/clientGenerator.mjs +294 -0
  59. package/dist/esm-node/utils/createHonoRoutes.mjs +93 -0
  60. package/dist/esm-node/utils/crossProjectApiPlugin.mjs +55 -0
  61. package/dist/esm-node/utils/effectClientGenerator.mjs +625 -0
  62. package/dist/esm-node/utils/pluginGenerator.mjs +33 -0
  63. package/dist/esm-node/utils/runtimeGenerator.mjs +91 -0
  64. package/dist/types/cli.d.ts +3 -0
  65. package/dist/types/constants.d.ts +2 -0
  66. package/dist/types/index.d.ts +1 -0
  67. package/dist/types/loader.d.ts +27 -0
  68. package/dist/types/runtime/create-request/index.d.ts +2 -0
  69. package/dist/types/runtime/data-platform/index.d.ts +187 -0
  70. package/dist/types/runtime/effect/adapter.d.ts +22 -0
  71. package/dist/types/runtime/effect/context.d.ts +8 -0
  72. package/dist/types/runtime/effect/index.d.ts +171 -0
  73. package/dist/types/runtime/effect-client/index.d.ts +47 -0
  74. package/dist/types/runtime/hono/adapter.d.ts +19 -0
  75. package/dist/types/runtime/hono/index.d.ts +2 -0
  76. package/dist/types/runtime/hono/operators.d.ts +10 -0
  77. package/dist/types/server.d.ts +3 -0
  78. package/dist/types/utils/clientGenerator.d.ts +37 -0
  79. package/dist/types/utils/createHonoRoutes.d.ts +10 -0
  80. package/dist/types/utils/crossProjectApiPlugin.d.ts +9 -0
  81. package/dist/types/utils/effectClientGenerator.d.ts +27 -0
  82. package/dist/types/utils/pluginGenerator.d.ts +9 -0
  83. package/dist/types/utils/runtimeGenerator.d.ts +7 -0
  84. package/docs/data-platform-architecture.md +61 -0
  85. package/package.json +172 -0
  86. package/rslib.config.mts +4 -0
  87. package/rstest.config.mts +10 -0
  88. package/server.js +1 -0
@@ -0,0 +1,91 @@
1
+ import __rslib_shim_module__ from "node:module";
2
+ const require = /*#__PURE__*/ __rslib_shim_module__.createRequire(/*#__PURE__*/ (()=>import.meta.url)());
3
+ import { fs } from "@modern-js/utils";
4
+ import path from "path";
5
+ const getPackageName = (appDirectory)=>{
6
+ try {
7
+ const packageJsonPath = path.resolve(appDirectory, './package.json');
8
+ const packageJson = require(packageJsonPath);
9
+ return packageJson.name;
10
+ } catch (error) {
11
+ return;
12
+ }
13
+ };
14
+ async function runtimeGenerator({ runtime, appDirectory, relativeDistPath, packageName }) {
15
+ const pluginDir = path.resolve(appDirectory, `./${relativeDistPath}`, 'runtime');
16
+ const requestId = packageName || getPackageName(appDirectory) || process.env.npm_package_name || 'default';
17
+ const runtimeImportPath = JSON.stringify(runtime);
18
+ const requestIdValue = JSON.stringify(requestId);
19
+ const source = `const { configure: _configure } = require(${runtimeImportPath});
20
+ const defaultSecureOptions = {
21
+ requestId: ${requestIdValue},
22
+ requireEnvelope: true,
23
+ identityBinding: {
24
+ enabled: true,
25
+ strict: true,
26
+ },
27
+ operationContract: {
28
+ enabled: true,
29
+ strict: true,
30
+ requireSchemaHash: true,
31
+ requireOperationVersion: true,
32
+ },
33
+ };
34
+ const initProducerClient = (options) => {
35
+ return _configure({
36
+ ...defaultSecureOptions,
37
+ ...options,
38
+ identityBinding: {
39
+ ...defaultSecureOptions.identityBinding,
40
+ ...(options && options.identityBinding ? options.identityBinding : {}),
41
+ },
42
+ operationContract: {
43
+ ...defaultSecureOptions.operationContract,
44
+ ...(options && options.operationContract ? options.operationContract : {}),
45
+ },
46
+ });
47
+ }
48
+ const configure = initProducerClient;
49
+ Object.defineProperty(exports, '__esModule', { value: true });
50
+ exports.initProducerClient = initProducerClient;
51
+ exports.configure = configure;
52
+ `;
53
+ const pluginPath = path.join(pluginDir, 'index.js');
54
+ await fs.ensureFile(pluginPath);
55
+ await fs.writeFile(pluginPath, source);
56
+ const tsSource = `type ProducerRuntimeModule = typeof import(${runtimeImportPath});
57
+ type ProducerClientOptions = ProducerRuntimeModule extends {
58
+ configure: (options: infer TOptions) => unknown;
59
+ }
60
+ ? TOptions
61
+ : {
62
+ request?: typeof fetch;
63
+ interceptor?: (request: typeof fetch) => typeof fetch;
64
+ allowedHeaders?: string[];
65
+ requireEnvelope?: boolean;
66
+ allowCrossOriginEnvelope?: boolean;
67
+ identityBinding?: {
68
+ enabled?: boolean;
69
+ strict?: boolean;
70
+ protectedHeaders?: string[];
71
+ };
72
+ operationContract?: {
73
+ enabled?: boolean;
74
+ strict?: boolean;
75
+ requireSchemaHash?: boolean;
76
+ requireOperationVersion?: boolean;
77
+ };
78
+ setDomain?: (ops?: {
79
+ target: 'server' | 'browser';
80
+ requestId?: string;
81
+ }) => string;
82
+ requestId?: string;
83
+ };
84
+ export declare const initProducerClient: (options: ProducerClientOptions) => void;
85
+ export declare const configure: typeof initProducerClient;`;
86
+ const pluginTypePath = path.join(pluginDir, 'index.d.ts');
87
+ await fs.ensureFile(pluginTypePath);
88
+ await fs.writeFile(pluginTypePath, tsSource);
89
+ }
90
+ const utils_runtimeGenerator = runtimeGenerator;
91
+ export default utils_runtimeGenerator;
@@ -0,0 +1,3 @@
1
+ import type { AppTools, CliPlugin } from '@modern-js/app-tools';
2
+ export declare const bffPlugin: () => CliPlugin<AppTools>;
3
+ export default bffPlugin;
@@ -0,0 +1,2 @@
1
+ export declare const API_APP_NAME = "_app";
2
+ export declare const BUILD_FILES: string[];
@@ -0,0 +1 @@
1
+ export * from './constants';
@@ -0,0 +1,27 @@
1
+ import type { HttpMethodDecider } from '@modern-js/types';
2
+ import type { Rspack } from '@rsbuild/core';
3
+ export type APILoaderOptions = {
4
+ prefix: string;
5
+ appDir: string;
6
+ apiDir: string;
7
+ lambdaDir: string;
8
+ existLambda: boolean;
9
+ port: number;
10
+ fetcher?: string;
11
+ requestCreator?: string;
12
+ target: string;
13
+ httpMethodDecider?: HttpMethodDecider;
14
+ bffRuntimeFramework?: 'hono' | 'effect';
15
+ effectEntry?: string;
16
+ effectDataPlatformBatch?: {
17
+ enabled?: boolean;
18
+ endpoint?: string;
19
+ flushIntervalMs?: number;
20
+ maxBatchSize?: number;
21
+ maxBatchBytes?: number;
22
+ requestTimeoutMs?: number;
23
+ allowedMethods?: string[];
24
+ };
25
+ };
26
+ declare function loader(this: Rspack.LoaderContext<APILoaderOptions>, source: string): Promise<void>;
27
+ export default loader;
@@ -0,0 +1,2 @@
1
+ import { configure, createRequest, createRequestContextHeaders, createRequestContextSnapshot, createUploader } from '@modern-js/create-request';
2
+ export { configure, createRequest, createRequestContextHeaders, createRequestContextSnapshot, createUploader, };
@@ -0,0 +1,187 @@
1
+ export type DataRequestMode = 'cache-first' | 'stale-while-revalidate' | 'network-only';
2
+ export type DataMutationMode = 'optimistic' | 'pessimistic' | 'fire-and-forget';
3
+ export type SelectionPlan = {
4
+ [field: string]: true | SelectionPlan;
5
+ };
6
+ export interface OperationDescriptor {
7
+ appNamespace: string;
8
+ apiId: string;
9
+ group: string;
10
+ endpoint: string;
11
+ schemaHash?: string;
12
+ version?: number;
13
+ }
14
+ export interface CacheScope {
15
+ appNamespace: string;
16
+ origin: string;
17
+ tenantId?: string;
18
+ userId?: string;
19
+ sessionId?: string;
20
+ }
21
+ export interface TraceContext {
22
+ traceId: string;
23
+ spanId: string;
24
+ sampled: boolean;
25
+ parentSpanId?: string;
26
+ }
27
+ export interface RequestEnvelope<Input = unknown> {
28
+ protocolVersion: 1;
29
+ operationId: string;
30
+ appNamespace: string;
31
+ origin: string;
32
+ requestMode: DataRequestMode;
33
+ mutationMode?: DataMutationMode;
34
+ scopeKey: string;
35
+ input: Input;
36
+ inputHash: string;
37
+ selectionPlan?: SelectionPlan;
38
+ selectionHash?: string;
39
+ traceparent?: string;
40
+ timestamp: number;
41
+ }
42
+ export interface HydrationEnvelope<Payload = unknown> {
43
+ protocolVersion: 1;
44
+ runtimeVersion: string;
45
+ appNamespace: string;
46
+ origin: string;
47
+ createdAt: number;
48
+ payload: Payload;
49
+ checksum: string;
50
+ }
51
+ export interface InvalidationEvent {
52
+ sourceNamespace: string;
53
+ sourceOperationId: string;
54
+ scopeKey: string;
55
+ targetNamespaces?: string[];
56
+ targetOperationIds?: string[];
57
+ }
58
+ export interface InvalidationSubscriber {
59
+ namespace: string;
60
+ operationIds?: string[];
61
+ scopeKey?: string;
62
+ acceptCrossNamespace?: boolean;
63
+ }
64
+ export interface DataBatchRequestItem {
65
+ id: string;
66
+ path: string;
67
+ method: string;
68
+ headers?: Record<string, string>;
69
+ body?: string;
70
+ }
71
+ export interface DataBatchRequestPayload {
72
+ protocolVersion: 1;
73
+ batchId: string;
74
+ sentAt: number;
75
+ items: DataBatchRequestItem[];
76
+ }
77
+ export interface DataBatchResponseItem {
78
+ id: string;
79
+ status: number;
80
+ headers?: Record<string, string>;
81
+ body?: string;
82
+ }
83
+ export interface DataBatchResponsePayload {
84
+ protocolVersion: 1;
85
+ batchId: string;
86
+ receivedAt: number;
87
+ items: DataBatchResponseItem[];
88
+ }
89
+ export interface DataBatchTransportEvent {
90
+ type: 'enqueue' | 'flush' | 'fallback' | 'disable';
91
+ endpoint: string;
92
+ batchId?: string;
93
+ size?: number;
94
+ reason?: string;
95
+ }
96
+ export interface DataBatchTransportOptions {
97
+ endpoint?: string;
98
+ fetch?: (input: DataTransportRequestInfo, init?: RequestInit) => Promise<Response>;
99
+ flushIntervalMs?: number;
100
+ maxBatchSize?: number;
101
+ maxBatchBytes?: number;
102
+ requestTimeoutMs?: number;
103
+ allowedMethods?: string[];
104
+ onEvent?: (event: DataBatchTransportEvent) => void;
105
+ }
106
+ export interface SelectionPlanValidationOptions {
107
+ maxDepth?: number;
108
+ maxFields?: number;
109
+ allowedLeafPaths?: ReadonlyArray<string>;
110
+ }
111
+ export interface SelectionPlanValidationResult {
112
+ ok: boolean;
113
+ errors: string[];
114
+ stats: {
115
+ maxDepth: number;
116
+ fieldCount: number;
117
+ };
118
+ }
119
+ export interface RequestEnvelopeValidationOptions {
120
+ expectedProtocolVersion?: number;
121
+ expectedNamespace?: string;
122
+ expectedOrigin?: string;
123
+ requireTraceContext?: boolean;
124
+ }
125
+ export interface HydrationEnvelopeValidationOptions {
126
+ expectedProtocolVersion?: number;
127
+ expectedNamespace?: string;
128
+ expectedOrigin?: string;
129
+ expectedRuntimeVersion?: string;
130
+ }
131
+ export declare const DEFAULT_DATA_ENVELOPE_HEADER = "x-modernjs-data-envelope";
132
+ export declare const DEFAULT_DATA_BATCH_ENDPOINT = "/_data/batch";
133
+ export declare const DEFAULT_DATA_BATCH_HEADER = "x-modernjs-data-batch";
134
+ type DataTransportRequestInfo = string | URL | Request;
135
+ export declare function stableStringify(value: unknown): string;
136
+ export declare function encodeRequestEnvelopeHeader(envelope: RequestEnvelope): string;
137
+ export declare function decodeRequestEnvelopeHeader(value: string): RequestEnvelope | null;
138
+ export declare function normalizeOrigin(origin: string): string;
139
+ export declare function createOperationId(input: OperationDescriptor): string;
140
+ export declare function buildScopeKey(scope: CacheScope): string;
141
+ export declare function buildQueryKey(input: {
142
+ operationId: string;
143
+ scopeKey: string;
144
+ requestMode?: DataRequestMode;
145
+ requestInput?: unknown;
146
+ selectionPlan?: SelectionPlan;
147
+ }): string;
148
+ export declare function parseTraceparentHeader(header: string): TraceContext | null;
149
+ export declare function formatTraceparentHeader(trace: TraceContext): string;
150
+ export declare function deriveChildTraceContext(parent: TraceContext, childSpanId: string): TraceContext;
151
+ export declare function validateSelectionPlan(plan: SelectionPlan, options?: SelectionPlanValidationOptions): SelectionPlanValidationResult;
152
+ export declare function createRequestEnvelope<Input>(input: {
153
+ operation: OperationDescriptor;
154
+ scope: CacheScope;
155
+ requestInput: Input;
156
+ selectionPlan?: SelectionPlan;
157
+ requestMode?: DataRequestMode;
158
+ mutationMode?: DataMutationMode;
159
+ traceContext?: TraceContext;
160
+ requireTraceContext?: boolean;
161
+ timestamp?: number;
162
+ protocolVersion?: 1;
163
+ }): RequestEnvelope<Input>;
164
+ export declare function validateRequestEnvelope(envelope: RequestEnvelope, options?: RequestEnvelopeValidationOptions): {
165
+ ok: boolean;
166
+ errors: string[];
167
+ };
168
+ export declare function createHydrationEnvelope<Payload>(input: {
169
+ runtimeVersion: string;
170
+ scope: Pick<CacheScope, 'appNamespace' | 'origin'>;
171
+ payload: Payload;
172
+ createdAt?: number;
173
+ protocolVersion?: 1;
174
+ }): HydrationEnvelope<Payload>;
175
+ export declare function validateHydrationEnvelope(envelope: HydrationEnvelope, options?: HydrationEnvelopeValidationOptions): {
176
+ ok: boolean;
177
+ errors: string[];
178
+ };
179
+ export declare function createInvalidationEvent(input: {
180
+ sourceOperation: OperationDescriptor;
181
+ sourceScope: CacheScope;
182
+ targetNamespaces?: string[];
183
+ targetOperations?: OperationDescriptor[];
184
+ }): InvalidationEvent;
185
+ export declare function shouldApplyInvalidation(event: InvalidationEvent, subscriber: InvalidationSubscriber): boolean;
186
+ export declare function createDataBatchTransport(options?: DataBatchTransportOptions): (input: DataTransportRequestInfo, init?: RequestInit) => Promise<any>;
187
+ export {};
@@ -0,0 +1,22 @@
1
+ import type { ServerMiddleware, ServerPluginAPI } from '@modern-js/server-core';
2
+ interface MiddlewareOptions {
3
+ prefix: string;
4
+ enableHandleWeb?: boolean;
5
+ }
6
+ export declare class EffectAdapter {
7
+ api: ServerPluginAPI;
8
+ isEffect: boolean;
9
+ effectMiddleware: ServerMiddleware | null;
10
+ private handler;
11
+ private dispose;
12
+ constructor(api: ServerPluginAPI);
13
+ registerMiddleware: (options: MiddlewareOptions) => Promise<void>;
14
+ onApiHandlersUpdated: () => Promise<void>;
15
+ private resolveEntryFile;
16
+ private loadEffectHandlerFromModule;
17
+ private reloadHandler;
18
+ private disposeCurrentHandler;
19
+ private handleRuntimeError;
20
+ private ensureJsonContext;
21
+ }
22
+ export {};
@@ -0,0 +1,8 @@
1
+ export type EffectContext = {
2
+ request: Request;
3
+ env: Record<string, unknown>;
4
+ path: string;
5
+ method: string;
6
+ };
7
+ export declare const runWithEffectContext: <T>(context: EffectContext, cb: () => T) => T;
8
+ export declare const useEffectContext: () => EffectContext;
@@ -0,0 +1,171 @@
1
+ import type * as EffectType from 'effect/Effect';
2
+ import * as Layer from 'effect/Layer';
3
+ import { type HttpApi, type HttpApiClient, type HttpApiGroup } from 'effect/unstable/httpapi';
4
+ import { type Rpc, type RpcGroup } from 'effect/unstable/rpc';
5
+ export * as OpenTelemetry from '@effect/opentelemetry';
6
+ export * as Config from 'effect/Config';
7
+ export * as Effect from 'effect/Effect';
8
+ export * as Layer from 'effect/Layer';
9
+ export * as Option from 'effect/Option';
10
+ export * as Schema from 'effect/Schema';
11
+ export * from 'effect/unstable/http';
12
+ export { HttpTraceContext } from 'effect/unstable/http';
13
+ export * from 'effect/unstable/httpapi';
14
+ export { HttpApiBuilder } from 'effect/unstable/httpapi';
15
+ export * from 'effect/unstable/rpc';
16
+ export { type EffectContext, useEffectContext } from './context';
17
+ export type EffectRuntimeLayer = Layer.Layer<any, unknown, any>;
18
+ export type EffectRpcSerialization = 'json' | 'ndjson' | 'jsonRpc' | 'ndJsonRpc' | 'msgPack';
19
+ export type EffectRpcRuntimeLayer<TRpcs extends Rpc.Any = Rpc.Any> = Layer.Layer<Rpc.ToHandler<TRpcs> | Rpc.Middleware<TRpcs> | Rpc.ServicesServer<TRpcs>, unknown, never>;
20
+ export type EffectRpcBffDefinition<TRpcs extends Rpc.Any = Rpc.Any, TRpcLayer extends EffectRpcRuntimeLayer<TRpcs> = EffectRpcRuntimeLayer<TRpcs>> = {
21
+ group: RpcGroup.RpcGroup<TRpcs>;
22
+ layer: TRpcLayer;
23
+ path?: `/${string}`;
24
+ serialization?: EffectRpcSerialization;
25
+ disableTracing?: boolean;
26
+ spanPrefix?: string;
27
+ spanAttributes?: Record<string, unknown>;
28
+ disableFatalDefects?: boolean;
29
+ };
30
+ export type EffectRpcBffHandlerOptions = Pick<EffectRpcBffDefinition, 'path' | 'serialization' | 'disableTracing' | 'spanPrefix' | 'spanAttributes' | 'disableFatalDefects'>;
31
+ type EffectApiPromiseClient<TClient> = {
32
+ [GroupName in keyof TClient]: {
33
+ [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;
34
+ };
35
+ };
36
+ export type EffectApiClientFromApi<TApi extends HttpApi.AnyWithProps = HttpApi.AnyWithProps> = TApi extends HttpApi.HttpApi<infer _ApiId, infer Groups> ? HttpApiClient.Client<Extract<Groups, HttpApiGroup.Any>, unknown, never> : never;
37
+ export type EffectApiPromiseClientFromApi<TApi extends HttpApi.AnyWithProps = HttpApi.AnyWithProps> = EffectApiPromiseClient<EffectApiClientFromApi<TApi>>;
38
+ export type EffectBffDefinition<TApi extends HttpApi.AnyWithProps = HttpApi.AnyWithProps, TLayer extends EffectRuntimeLayer = EffectRuntimeLayer, TRpcs extends Rpc.Any = Rpc.Any> = {
39
+ api: TApi;
40
+ layer: TLayer;
41
+ rpc?: EffectRpcBffDefinition<TRpcs>;
42
+ dataPlatform?: EffectDataPlatformValidationOptions;
43
+ };
44
+ export type EffectDataPlatformSelectionValidationOptions = {
45
+ maxDepth?: number;
46
+ maxFields?: number;
47
+ allowedLeafPaths?: string[];
48
+ };
49
+ export type EffectDataPlatformBatchOptions = {
50
+ /**
51
+ * Enable network batching endpoint for Effect HttpApi requests.
52
+ * Defaults to `true`.
53
+ */
54
+ enabled?: boolean;
55
+ /**
56
+ * Batch endpoint path mounted under BFF prefix.
57
+ * Defaults to `/_data/batch`.
58
+ */
59
+ endpoint?: `/${string}`;
60
+ /**
61
+ * Maximum request items accepted per batch call.
62
+ * Defaults to `16`.
63
+ */
64
+ maxBatchSize?: number;
65
+ /**
66
+ * Maximum serialized request payload size in bytes.
67
+ * Defaults to `65536` (64KiB).
68
+ */
69
+ maxBatchBytes?: number;
70
+ /**
71
+ * Client-side micro-batch flush window in milliseconds.
72
+ * Server runtime ignores this value and passes it through for codegen.
73
+ * Defaults to `8`.
74
+ */
75
+ flushIntervalMs?: number;
76
+ /**
77
+ * Maximum per-batch internal request concurrency.
78
+ * Defaults to `4`.
79
+ */
80
+ maxConcurrency?: number;
81
+ /**
82
+ * Optional timeout per internal request in milliseconds.
83
+ * Defaults to `10000`.
84
+ */
85
+ requestTimeoutMs?: number;
86
+ /**
87
+ * Allowed HTTP methods for internal batched dispatch.
88
+ * Defaults to `['GET']`.
89
+ */
90
+ allowedMethods?: string[];
91
+ };
92
+ export type EffectDataPlatformValidationOptions = {
93
+ /**
94
+ * Enable envelope validation for HttpApi requests.
95
+ * Defaults to `true`.
96
+ */
97
+ enabled?: boolean;
98
+ /**
99
+ * Require every HttpApi request to include an envelope header.
100
+ * Defaults to `false`.
101
+ */
102
+ requireEnvelope?: boolean;
103
+ /**
104
+ * Header name used by client/server for the serialized request envelope.
105
+ * Defaults to `x-modernjs-data-envelope`.
106
+ */
107
+ envelopeHeader?: string;
108
+ /**
109
+ * Optional namespace assertion for envelope validation.
110
+ */
111
+ expectedNamespace?: string;
112
+ /**
113
+ * Validate envelope origin against incoming request origin.
114
+ * Defaults to `true`.
115
+ */
116
+ validateOrigin?: boolean;
117
+ /**
118
+ * Require trace context inside request envelope.
119
+ * Defaults to `false`.
120
+ */
121
+ requireTraceContext?: boolean;
122
+ /**
123
+ * Selection plan guardrails for server-side validation.
124
+ */
125
+ selection?: EffectDataPlatformSelectionValidationOptions;
126
+ /**
127
+ * Network batching gateway configuration.
128
+ */
129
+ batch?: EffectDataPlatformBatchOptions;
130
+ };
131
+ export type EffectBffHandlerFactory<TApi extends HttpApi.AnyWithProps = HttpApi.AnyWithProps, TLayer extends EffectRuntimeLayer = EffectRuntimeLayer> = (options?: {
132
+ openapi?: EffectBffOpenApiConfig;
133
+ rpc?: Partial<EffectRpcBffHandlerOptions>;
134
+ dataPlatform?: Partial<EffectDataPlatformValidationOptions>;
135
+ }) => ReturnType<typeof createHttpApiHandler>;
136
+ export type EffectBffRuntime<TApi extends HttpApi.AnyWithProps = HttpApi.AnyWithProps, TLayer extends EffectRuntimeLayer = EffectRuntimeLayer> = {
137
+ createHandler: EffectBffHandlerFactory<TApi, TLayer>;
138
+ client: EffectApiPromiseClientFromApi<TApi>;
139
+ };
140
+ export type EffectBffOpenApiConfig = boolean | {
141
+ path?: string;
142
+ };
143
+ export type EffectRpcBffHandlerFactory<TRpcs extends Rpc.Any = Rpc.Any> = (options?: Partial<EffectRpcBffHandlerOptions>) => ReturnType<typeof createRpcApiHandler<TRpcs>>;
144
+ declare function createRpcApiHandler<TRpcs extends Rpc.Any = Rpc.Any>(options: EffectRpcBffDefinition<TRpcs>): {
145
+ readonly handler: (request: globalThis.Request, context?: import("effect/Context").Context<never> | undefined) => Promise<Response>;
146
+ readonly dispose: () => Promise<void>;
147
+ };
148
+ export declare function defineEffectBff<TApi extends HttpApi.AnyWithProps, TLayer extends EffectRuntimeLayer, TRpcs extends Rpc.Any = Rpc.Any>(definition: {
149
+ api: TApi;
150
+ layer: TLayer;
151
+ rpc?: EffectRpcBffDefinition<TRpcs>;
152
+ dataPlatform?: EffectDataPlatformValidationOptions;
153
+ }): {
154
+ api: TApi;
155
+ layer: TLayer;
156
+ rpc?: EffectRpcBffDefinition<TRpcs>;
157
+ dataPlatform?: EffectDataPlatformValidationOptions;
158
+ } & EffectBffRuntime<TApi, TLayer>;
159
+ export declare function defineEffectRpcBff<TRpcs extends Rpc.Any = Rpc.Any, TLayer extends EffectRpcRuntimeLayer<TRpcs> = EffectRpcRuntimeLayer<TRpcs>>(definition: EffectRpcBffDefinition<TRpcs, TLayer>): EffectRpcBffDefinition<TRpcs, TLayer> & {
160
+ createHandler: EffectRpcBffHandlerFactory<TRpcs>;
161
+ };
162
+ export declare function createHttpApiHandler<TApi extends HttpApi.AnyWithProps = HttpApi.AnyWithProps, TRpcs extends Rpc.Any = Rpc.Any>(options: {
163
+ api: TApi;
164
+ layer: EffectRuntimeLayer;
165
+ openapi?: EffectBffOpenApiConfig;
166
+ rpc?: EffectRpcBffDefinition<TRpcs>;
167
+ dataPlatform?: EffectDataPlatformValidationOptions;
168
+ }): {
169
+ handler: (request: Request, context?: Parameters<(request: globalThis.Request, context?: import("effect/Context").Context<never> | undefined) => Promise<Response>>[1]) => Promise<Response>;
170
+ dispose: () => Promise<void>;
171
+ };
@@ -0,0 +1,47 @@
1
+ import * as Effect from 'effect/Effect';
2
+ import * as Layer from 'effect/Layer';
3
+ import { HttpApi, HttpApiClient, HttpApiEndpoint, HttpApiGroup, HttpApiSchema } from 'effect/unstable/httpapi';
4
+ import { Rpc, RpcClient, RpcGroup, RpcSchema, RpcSerialization } from 'effect/unstable/rpc';
5
+ export * as Effect from 'effect/Effect';
6
+ export * as Layer from 'effect/Layer';
7
+ export * as Schema from 'effect/Schema';
8
+ export { HttpApi, HttpApiClient, HttpApiEndpoint, HttpApiGroup, HttpApiSchema, Rpc, RpcClient, RpcGroup, RpcSchema, RpcSerialization, };
9
+ export type EffectHttpApiClientOptions = {
10
+ baseUrl?: URL | string;
11
+ };
12
+ type Nullish = null | undefined;
13
+ type NonNullish<T> = Exclude<T, Nullish>;
14
+ type PreserveNullish<T, Next> = Extract<T, Nullish> extends never ? Next : Next | Extract<T, Nullish>;
15
+ type EffectViewObjectSelection<T> = NonNullish<T> extends Record<string, unknown> ? EffectViewSelection<NonNullish<T>> : never;
16
+ type EffectViewSelectionValue<T> = NonNullish<T> extends readonly (infer Item)[] ? true | EffectViewObjectSelection<Item> : NonNullish<T> extends Record<string, unknown> ? true | EffectViewSelection<NonNullish<T>> : true;
17
+ type EffectMaskedValue<T, Selection> = Selection extends true ? T : NonNullish<T> extends readonly (infer Item)[] ? PreserveNullish<T, Array<EffectMaskedValue<Item, Selection>>> : NonNullish<T> extends Record<string, unknown> ? PreserveNullish<T, EffectViewData<NonNullish<T>, Selection>> : T;
18
+ export type EffectViewSelection<T> = {
19
+ [K in keyof T]?: EffectViewSelectionValue<T[K]>;
20
+ };
21
+ export type EffectViewData<T, Selection> = Selection extends true ? T : Selection extends Record<string, unknown> ? {
22
+ [K in keyof Selection & keyof T]: EffectMaskedValue<T[K], Selection[K]>;
23
+ } : T;
24
+ export type EffectRpcSerialization = 'json' | 'ndjson' | 'jsonRpc' | 'ndJsonRpc' | 'msgPack';
25
+ type EffectRpcMiddlewareLayerOption<Rpcs extends Rpc.Any> = [
26
+ Rpc.MiddlewareClient<Rpcs>
27
+ ] extends [never] ? {
28
+ middlewareLayer?: Layer.Layer<Rpc.MiddlewareClient<Rpcs>, never, never>;
29
+ } : {
30
+ middlewareLayer: Layer.Layer<Rpc.MiddlewareClient<Rpcs>, unknown, never>;
31
+ };
32
+ export type EffectRpcClientOptions<Rpcs extends Rpc.Any, Flatten extends boolean = false> = EffectRpcMiddlewareLayerOption<Rpcs> & {
33
+ url: string;
34
+ flatten?: Flatten;
35
+ serialization?: EffectRpcSerialization;
36
+ };
37
+ export type EffectRpcClientHandle<Rpcs extends Rpc.Any, Flatten extends boolean = false> = (Flatten extends true ? RpcClient.RpcClient.Flat<Rpcs, unknown> : RpcClient.RpcClient<Rpcs, unknown>) & {
38
+ dispose: () => Promise<void>;
39
+ };
40
+ export declare function view<T>(): <const Selection extends EffectViewSelection<T>>(selection: Selection) => Selection;
41
+ export declare function mask<T, const Selection extends EffectViewSelection<T>>(value: T, selection: Selection): EffectViewData<T, Selection>;
42
+ export declare function runEffectView<T, const Selection extends EffectViewSelection<T>>(request: PromiseLike<T>, selection: Selection): Promise<EffectViewData<T, Selection>>;
43
+ export declare function makeEffectHttpApiClient<ApiId extends string, Groups extends HttpApiGroup.Any>(api: HttpApi.HttpApi<ApiId, Groups>, options?: EffectHttpApiClientOptions): Effect.Effect<import("effect/Types").Simplify<{ readonly [Group in Extract<Groups, {
44
+ readonly topLevel: false;
45
+ }> as HttpApiGroup.Name<Group>]: HttpApiClient.Client.Group<Group, Group["identifier"], never, never>; } & { readonly [Method in HttpApiClient.Client.TopLevelMethods<Groups, never, never> as Method[0]]: Method[1]; }>, never, Exclude<import("effect/unstable/httpapi/HttpApiMiddleware").MiddlewareClient<HttpApiEndpoint.Middleware<HttpApiGroup.Endpoints<Groups>>>, import("effect/unstable/http/HttpClient").HttpClient>>;
46
+ 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>, Error, never>;
47
+ export declare const runEffectRequest: <A, E>(effect: Effect.Effect<A, E>, options?: Effect.RunOptions | undefined) => Promise<A>;
@@ -0,0 +1,19 @@
1
+ import type { MiddlewareHandler, ServerMiddleware, ServerPluginAPI } from '@modern-js/server-core';
2
+ import { Hono } from '@modern-js/server-core';
3
+ interface MiddlewareOptions {
4
+ prefix: string;
5
+ enableHandleWeb?: boolean;
6
+ }
7
+ export declare class HonoAdapter {
8
+ apiMiddleware: ServerMiddleware[];
9
+ apiServer: Hono | null;
10
+ api: ServerPluginAPI;
11
+ isHono: boolean;
12
+ constructor(api: ServerPluginAPI);
13
+ setHandlers: () => Promise<void>;
14
+ registerApiRoutes: () => Promise<void>;
15
+ registerMiddleware: (options: MiddlewareOptions) => Promise<void>;
16
+ onApiHandlersUpdated: () => Promise<void>;
17
+ wrapInArray(handler: MiddlewareHandler[] | MiddlewareHandler): MiddlewareHandler[];
18
+ }
19
+ export {};
@@ -0,0 +1,2 @@
1
+ export * from '@modern-js/bff-core';
2
+ export * from './operators';
@@ -0,0 +1,10 @@
1
+ import type { Operator } from '@modern-js/bff-core';
2
+ import { type Context, type Next } from '@modern-js/server-core';
3
+ export type EndFunction = ((func: (res: Response) => void) => void) & ((data: unknown) => void);
4
+ type MaybeAsync<T> = T | Promise<T>;
5
+ type PipeFunction<T> = (value: T, end: EndFunction) => MaybeAsync<void> | MaybeAsync<T>;
6
+ export declare const Pipe: <T>(func: PipeFunction<T>) => Operator<T>;
7
+ export type Pipe = typeof Pipe;
8
+ export declare const Middleware: (middleware: (c: Context, next: Next) => void) => Operator<void>;
9
+ export type Middleware = typeof Middleware;
10
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { ServerPlugin } from '@modern-js/server-core';
2
+ declare const _default: () => ServerPlugin;
3
+ export default _default;
@@ -0,0 +1,37 @@
1
+ import type { HttpMethodDecider } from '@modern-js/types';
2
+ export type APILoaderOptions = {
3
+ prefix: string;
4
+ appDir: string;
5
+ apiDir: string;
6
+ lambdaDir: string;
7
+ existLambda: boolean;
8
+ port?: number;
9
+ requestCreator?: string;
10
+ httpMethodDecider?: HttpMethodDecider;
11
+ relativeDistPath: string;
12
+ relativeApiPath: string;
13
+ bffRuntimeFramework?: 'hono' | 'effect';
14
+ effectEntry?: string;
15
+ effectDataPlatformBatch?: {
16
+ enabled?: boolean;
17
+ endpoint?: string;
18
+ flushIntervalMs?: number;
19
+ maxBatchSize?: number;
20
+ maxBatchBytes?: number;
21
+ requestTimeoutMs?: number;
22
+ allowedMethods?: string[];
23
+ };
24
+ };
25
+ interface FileDetails {
26
+ resourcePath: string;
27
+ source: string;
28
+ targetDir: string;
29
+ name: string;
30
+ absTargetDir: string;
31
+ relativeTargetDistDir: string;
32
+ exportKey: string;
33
+ }
34
+ export declare function readDirectoryFiles(appDirectory: string, directory: string, relativeDistPath: string): Promise<FileDetails[]>;
35
+ export declare function copyFiles(from: string, to: string): Promise<void>;
36
+ declare function clientGenerator(draftOptions: APILoaderOptions): Promise<void>;
37
+ export default clientGenerator;
@@ -0,0 +1,10 @@
1
+ import type { APIHandlerInfo } from '@modern-js/bff-core';
2
+ import type { Context } from '@modern-js/server-core';
3
+ type Handler = APIHandlerInfo['handler'];
4
+ declare const createHonoRoutes: (handlerInfos?: APIHandlerInfo[]) => {
5
+ method: any;
6
+ path: string;
7
+ handler: any[] | ((c: Context) => Promise<void | Response>);
8
+ }[];
9
+ export declare const createHonoHandler: (handler: Handler) => (c: Context) => Promise<void | Response>;
10
+ export default createHonoRoutes;