@bleedingdev/modern-js-main-doc 3.9.0-ultramodern.4 → 3.9.0-ultramodern.5
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/docs/en/components/hono.mdx +3 -3
- package/docs/en/components/init-app.mdx +1 -5
- package/docs/en/configure/app/bff/effect.mdx +27 -21
- package/docs/en/guides/advanced-features/bff/data-platform.mdx +2 -2
- package/docs/en/guides/advanced-features/bff/frameworks.mdx +24 -17
- package/docs/en/guides/advanced-features/bff/function.mdx +2 -2
- package/docs/en/guides/advanced-features/bff/operators.mdx +17 -17
- package/docs/en/guides/get-started/ultramodern.mdx +1 -1
- package/docs/zh/components/bff-operator-code.mdx +1 -1
- package/docs/zh/components/hono.mdx +3 -3
- package/docs/zh/configure/app/bff/effect.mdx +22 -19
- package/docs/zh/guides/advanced-features/bff/data-platform.mdx +2 -2
- package/docs/zh/guides/advanced-features/bff/frameworks.mdx +22 -16
- package/docs/zh/guides/advanced-features/bff/function.mdx +2 -2
- package/docs/zh/guides/advanced-features/bff/operators.mdx +17 -17
- package/docs/zh/guides/get-started/ultramodern.mdx +1 -1
- package/package.json +3 -3
- package/src/sandbox/csr-auth/src/routes/Auth-tsx.txt +10 -6
- package/src/sandbox/csr-auth/src/routes/page-tsx.txt +1 -0
|
@@ -21,7 +21,7 @@ For more details, refer to [useHonoContext](/apis/app/runtime/bff/use-backend-co
|
|
|
21
21
|
When getting cookies in BFF functions, you need to get the request context through `useHonoContext`, then use `c.req.header('cookie')` to get the Cookie string and parse it manually:
|
|
22
22
|
|
|
23
23
|
```ts title="api/lambda/cookies.ts"
|
|
24
|
-
import { Api, Get } from '@modern-js/plugin-bff/
|
|
24
|
+
import { Api, Get } from '@modern-js/plugin-bff/server';
|
|
25
25
|
import { useHonoContext } from '@modern-js/server-runtime';
|
|
26
26
|
|
|
27
27
|
// Helper function to parse Cookie string
|
|
@@ -64,7 +64,7 @@ The `c.req.cookie()` method does not exist in the current version. You need to u
|
|
|
64
64
|
When using Hono as the runtime framework, you can define interfaces through [Api functions](/guides/advanced-features/bff/operators.html):
|
|
65
65
|
|
|
66
66
|
```ts title="api/lambda/user.ts"
|
|
67
|
-
import { Api, Get, Query } from '@modern-js/plugin-bff/
|
|
67
|
+
import { Api, Get, Query } from '@modern-js/plugin-bff/server';
|
|
68
68
|
import { z } from 'zod';
|
|
69
69
|
|
|
70
70
|
const QuerySchema = z.object({
|
|
@@ -93,7 +93,7 @@ For more details about Api functions and operators, refer to [Creating Extensibl
|
|
|
93
93
|
Hono supports a rich middleware ecosystem, and you can use middleware in BFF functions:
|
|
94
94
|
|
|
95
95
|
```ts title="api/lambda/user.ts"
|
|
96
|
-
import { Api, Get, Middleware } from '@modern-js/plugin-bff/
|
|
96
|
+
import { Api, Get, Middleware } from '@modern-js/plugin-bff/server';
|
|
97
97
|
|
|
98
98
|
export const getUser = Api(
|
|
99
99
|
Get('/user'),
|
|
@@ -71,11 +71,7 @@ Now, the project structure is as follows:
|
|
|
71
71
|
```
|
|
72
72
|
|
|
73
73
|
The default workspace starts shell-only and installs the published BleedingDev
|
|
74
|
-
package aliases
|
|
75
|
-
|
|
76
|
-
```bash
|
|
77
|
-
pnpm dlx @bleedingdev/modern-js-ultramodern-create my-super-app
|
|
78
|
-
```
|
|
74
|
+
package aliases.
|
|
79
75
|
|
|
80
76
|
From a generated SuperApp workspace, add a business MicroVertical in place:
|
|
81
77
|
|
|
@@ -47,21 +47,33 @@ import EnableBFFCaution from "@site-docs-en/components/enable-bff-caution";
|
|
|
47
47
|
|
|
48
48
|
:::caution Install the Effect peers yourself
|
|
49
49
|
`effect` and `@effect/opentelemetry` are **optional exact peer dependencies** of
|
|
50
|
-
`@modern-js/
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
`/effect-server`, `/effect-edge` or `/effect-client`, install the exact cohort:
|
|
50
|
+
`@modern-js/bff-effect`. Install them in the application so its API modules and
|
|
51
|
+
the framework use the same Effect instance. Before setting
|
|
52
|
+
`runtimeFramework: 'effect'` or importing `@modern-js/bff-effect/effect`,
|
|
53
|
+
`/effect-edge` or `/effect-client`, install the exact cohort:
|
|
55
54
|
|
|
56
55
|
```bash
|
|
57
56
|
pnpm add effect@4.0.0-rc.112 @effect/opentelemetry@4.0.0-rc.112
|
|
58
57
|
```
|
|
59
58
|
|
|
60
59
|
The pin is exact because UltraModern ships Effect as one lockstep cohort. Apps
|
|
61
|
-
using only `runtimeFramework: 'hono'` or
|
|
62
|
-
package.
|
|
60
|
+
using only native `runtimeFramework: 'hono'` or
|
|
61
|
+
`@modern-js/bff-effect/data-platform` need neither package.
|
|
63
62
|
:::
|
|
64
63
|
|
|
64
|
+
Use `bffPlugin` from `@modern-js/plugin-bff-build-extensions` to register the
|
|
65
|
+
Effect runtime. It composes the native BFF plugin. Install
|
|
66
|
+
`@modern-js/bff-effect` and `@modern-js/plugin-bff-extensions` from the same
|
|
67
|
+
framework cohort as application production dependencies, so the adapter remains
|
|
68
|
+
available after development dependencies are removed. The build plugin can be a
|
|
69
|
+
development dependency. See the [runtime configuration example](/guides/advanced-features/bff/frameworks).
|
|
70
|
+
|
|
71
|
+
Native `@modern-js/plugin-bff/server` exports Hono APIs. For Node Effect APIs,
|
|
72
|
+
import framework helpers such as `defineEffectBff` from
|
|
73
|
+
`@modern-js/bff-effect/effect` and namespaces from the corresponding `effect/*`
|
|
74
|
+
modules. Worker handlers and worker request context use
|
|
75
|
+
`@modern-js/bff-effect/effect-edge`.
|
|
76
|
+
|
|
65
77
|
Generated UltraModern workspaces use this runtime as the only generated HTTP API
|
|
66
78
|
path. The API contract lives at `shared/api.ts`, the server runtime lives at
|
|
67
79
|
`api/index.ts`, clients live under `src/api/*-client.ts`, and generated checks
|
|
@@ -244,7 +256,7 @@ Strict Effect APIs should test the declared `HttpApi` contract, not a raw
|
|
|
244
256
|
request handler. Edge-compatible tests can use the framework helper:
|
|
245
257
|
|
|
246
258
|
```ts
|
|
247
|
-
import { createEffectBffTestHandler } from '@modern-js/
|
|
259
|
+
import { createEffectBffTestHandler } from '@modern-js/bff-effect/effect-edge';
|
|
248
260
|
import apiModule from '../api/index';
|
|
249
261
|
|
|
250
262
|
const testApi = await createEffectBffTestHandler({
|
|
@@ -259,12 +271,9 @@ If you manually compose an Effect web handler in a low-level proof, provide the
|
|
|
259
271
|
platform services explicitly:
|
|
260
272
|
|
|
261
273
|
```ts
|
|
262
|
-
import
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
HttpServer,
|
|
266
|
-
Layer,
|
|
267
|
-
} from '@modern-js/plugin-bff/effect-server';
|
|
274
|
+
import * as Layer from 'effect/Layer';
|
|
275
|
+
import { HttpRouter, HttpServer } from 'effect/unstable/http';
|
|
276
|
+
import { HttpApiBuilder } from 'effect/unstable/httpapi';
|
|
268
277
|
|
|
269
278
|
const handler = HttpRouter.toWebHandler(
|
|
270
279
|
HttpApiBuilder.layer(api).pipe(
|
|
@@ -284,13 +293,10 @@ current Effect v4 beta cohort, `HttpRouter.middleware(...)` returns a `Layer`
|
|
|
284
293
|
directly:
|
|
285
294
|
|
|
286
295
|
```ts
|
|
287
|
-
import
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
HttpRouter,
|
|
292
|
-
Layer,
|
|
293
|
-
} from '@modern-js/plugin-bff/effect-server';
|
|
296
|
+
import * as Effect from 'effect/Effect';
|
|
297
|
+
import * as Layer from 'effect/Layer';
|
|
298
|
+
import { HttpMiddleware, HttpRouter } from 'effect/unstable/http';
|
|
299
|
+
import { HttpApiBuilder } from 'effect/unstable/httpapi';
|
|
294
300
|
|
|
295
301
|
const corsLayer = HttpRouter.middleware(
|
|
296
302
|
Effect.succeed(
|
|
@@ -17,7 +17,7 @@ Modern.js Effect API runtime now supports a request-envelope based data platform
|
|
|
17
17
|
|
|
18
18
|
## Runtime contract helpers
|
|
19
19
|
|
|
20
|
-
Use `@modern-js/
|
|
20
|
+
Use `@modern-js/bff-effect/data-platform` helpers to build and validate contracts:
|
|
21
21
|
|
|
22
22
|
```ts
|
|
23
23
|
import {
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
validateHydrationEnvelope,
|
|
31
31
|
createInvalidationEvent,
|
|
32
32
|
shouldApplyInvalidation,
|
|
33
|
-
} from '@modern-js/
|
|
33
|
+
} from '@modern-js/bff-effect/data-platform';
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
## Effect runtime validation
|
|
@@ -5,10 +5,10 @@ title: Runtime Framework
|
|
|
5
5
|
|
|
6
6
|
# Runtime Framework
|
|
7
7
|
|
|
8
|
-
Modern.js
|
|
8
|
+
Modern.js and the UltraModern BFF extension provide two runtime frameworks:
|
|
9
9
|
|
|
10
|
-
- `
|
|
11
|
-
- `
|
|
10
|
+
- `hono` is the native plugin default and uses file-convention handlers from `api/lambda/**`.
|
|
11
|
+
- `effect` is the UltraModern extension default and uses [Effect HttpApi](https://effect.website/) from `api/index`.
|
|
12
12
|
|
|
13
13
|
`effect` and `hono` are strict runtime modes. There is no automatic fallback between them.
|
|
14
14
|
|
|
@@ -19,12 +19,18 @@ Generated UltraModern workspaces use strict Effect APIs: author HTTP APIs in
|
|
|
19
19
|
|
|
20
20
|
## Switch to Effect runtime
|
|
21
21
|
|
|
22
|
+
Use the fork build plugin below. It includes the native BFF plugin and registers
|
|
23
|
+
the Effect adapter. The application needs `@modern-js/bff-effect` and
|
|
24
|
+
`@modern-js/plugin-bff-extensions` as production dependencies from the same
|
|
25
|
+
framework cohort. Install the exact Effect peers described in
|
|
26
|
+
[`bff.effect`](/configure/app/bff/effect).
|
|
27
|
+
|
|
22
28
|
```ts title="modern.config.ts"
|
|
23
|
-
import { bffPlugin } from '@modern-js/plugin-bff';
|
|
24
|
-
import { defineConfig } from '@modern-js/app-tools';
|
|
29
|
+
import { bffPlugin } from '@modern-js/plugin-bff-build-extensions';
|
|
30
|
+
import { appTools, defineConfig } from '@modern-js/app-tools';
|
|
25
31
|
|
|
26
32
|
export default defineConfig({
|
|
27
|
-
plugins: [bffPlugin()],
|
|
33
|
+
plugins: [appTools(), bffPlugin()],
|
|
28
34
|
bff: {
|
|
29
35
|
runtimeFramework: 'effect',
|
|
30
36
|
effect: {
|
|
@@ -46,7 +52,7 @@ import {
|
|
|
46
52
|
HttpApiEndpoint,
|
|
47
53
|
HttpApiGroup,
|
|
48
54
|
Schema,
|
|
49
|
-
} from '@modern-js/
|
|
55
|
+
} from '@modern-js/bff-effect/effect-client';
|
|
50
56
|
|
|
51
57
|
export const bffApi = HttpApi.make('MyApi').add(
|
|
52
58
|
HttpApiGroup.make('hello').add(
|
|
@@ -60,14 +66,12 @@ export const bffApi = HttpApi.make('MyApi').add(
|
|
|
60
66
|
Implement your Effect API entry at `api/index.ts`:
|
|
61
67
|
|
|
62
68
|
```ts title="api/index.ts"
|
|
63
|
-
import {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
ServiceMap,
|
|
70
|
-
} from '@modern-js/plugin-bff/effect-server';
|
|
69
|
+
import { defineEffectBff } from '@modern-js/bff-effect/effect';
|
|
70
|
+
import * as Context from 'effect/Context';
|
|
71
|
+
import * as Effect from 'effect/Effect';
|
|
72
|
+
import * as Layer from 'effect/Layer';
|
|
73
|
+
import * as Schema from 'effect/Schema';
|
|
74
|
+
import { HttpApiBuilder } from 'effect/unstable/httpapi';
|
|
71
75
|
import { bffApi } from '../shared/api';
|
|
72
76
|
|
|
73
77
|
class GreetingUnavailableError extends Schema.TaggedError<GreetingUnavailableError>()(
|
|
@@ -77,7 +81,7 @@ class GreetingUnavailableError extends Schema.TaggedError<GreetingUnavailableErr
|
|
|
77
81
|
},
|
|
78
82
|
) {}
|
|
79
83
|
|
|
80
|
-
class GreetingService extends
|
|
84
|
+
class GreetingService extends Context.Service<GreetingService>()('GreetingService', {
|
|
81
85
|
make: Effect.succeed({
|
|
82
86
|
hello: Effect.fn('GreetingService.hello')(function* () {
|
|
83
87
|
if (Date.now() < 0) {
|
|
@@ -124,7 +128,10 @@ The `api.client.*` surface is materialized by the BFF loader for `@api/index` im
|
|
|
124
128
|
|
|
125
129
|
For UltraModern, Effect `HttpApi` plus Effect BFF is the single blessed authored HTTP path. Use `HttpApi` endpoints with `query`, `params`, `payload`, `success`, and declared errors such as `HttpApiSchema.status(...)`; implement them with `HttpApiBuilder.group(...).handle(...)` and `HttpApiBuilder.layer(...).pipe(Layer.provide(...))`, then default-export the entry as `defineEffectBff({ api, layer })`. See `packages/server/bff-effect/tests/effect-edge-runtime.test.ts` for the live runtime shape.
|
|
126
130
|
|
|
127
|
-
Hono
|
|
131
|
+
Native Hono applications import operators from `@modern-js/plugin-bff/server`.
|
|
132
|
+
UltraModern-generated applications keep their strict Effect API model. Worker
|
|
133
|
+
handlers use `@modern-js/bff-effect/effect-edge`, including its worker request
|
|
134
|
+
context exports; Node handlers use the Effect entry shown above.
|
|
128
135
|
|
|
129
136
|
import Hono from '@site-docs-en/components/hono';
|
|
130
137
|
|
|
@@ -191,7 +191,7 @@ Parameters following the dynamic path are an object called `RequestOption`, whic
|
|
|
191
191
|
In a standard function without dynamic routes, `RequestOption` can be obtained from the first parameter, for example:
|
|
192
192
|
|
|
193
193
|
```ts title="api/lambda/hello.ts"
|
|
194
|
-
import type { RequestOption } from '@modern-js/plugin-bff/
|
|
194
|
+
import type { RequestOption } from '@modern-js/plugin-bff/server';
|
|
195
195
|
|
|
196
196
|
export async function post({
|
|
197
197
|
query,
|
|
@@ -204,7 +204,7 @@ export async function post({
|
|
|
204
204
|
Custom types can also be used here:
|
|
205
205
|
|
|
206
206
|
```ts title="api/lambda/hello.ts"
|
|
207
|
-
import type { RequestOption } from '@modern-js/plugin-bff/
|
|
207
|
+
import type { RequestOption } from '@modern-js/plugin-bff/server';
|
|
208
208
|
|
|
209
209
|
type IQuery = {
|
|
210
210
|
// some types
|
|
@@ -36,7 +36,7 @@ import BFFOperatorCode from '@site-docs/components/bff-operator-code';
|
|
|
36
36
|
<BFFOperatorCode>
|
|
37
37
|
|
|
38
38
|
```typescript title="api/lambda/user.ts"
|
|
39
|
-
import { Api, Post, Query, Data } from '@modern-js/plugin-bff/
|
|
39
|
+
import { Api, Post, Query, Data } from '@modern-js/plugin-bff/server';
|
|
40
40
|
import { z } from 'zod';
|
|
41
41
|
|
|
42
42
|
const UserSchema = z.object({
|
|
@@ -89,7 +89,7 @@ As shown in the example below, you can specify the route and HTTP Method through
|
|
|
89
89
|
<BFFOperatorCode>
|
|
90
90
|
|
|
91
91
|
```typescript title="api/lambda/user.ts"
|
|
92
|
-
import { Api, Get, Query, Data } from '@modern-js/plugin-bff/
|
|
92
|
+
import { Api, Get, Query, Data } from '@modern-js/plugin-bff/server';
|
|
93
93
|
|
|
94
94
|
// Specify the interface route, Modern.js sets `bff.prefix` to `/api` by default,
|
|
95
95
|
// so the interface route is `/api/user`, and the HTTP Method is GET.
|
|
@@ -107,7 +107,7 @@ When the route is not specified, the interface route is defined according to the
|
|
|
107
107
|
<BFFOperatorCode>
|
|
108
108
|
|
|
109
109
|
```typescript title="api/lambda/user.ts"
|
|
110
|
-
import { Api, Get, Query, Data } from '@modern-js/plugin-bff/
|
|
110
|
+
import { Api, Get, Query, Data } from '@modern-js/plugin-bff/server';
|
|
111
111
|
|
|
112
112
|
// No interface route specified, according to file convention and function name, the interface is api/user, HTTP Method is get.
|
|
113
113
|
export const get = Api(Query(UserSchema), async ({ query }) => query);
|
|
@@ -144,7 +144,7 @@ Using the `Query` function, you can define the type of query. After using the `Q
|
|
|
144
144
|
|
|
145
145
|
```typescript title="api/lambda/user.ts"
|
|
146
146
|
// Server-side code
|
|
147
|
-
import { Api, Query } from '@modern-js/plugin-bff/
|
|
147
|
+
import { Api, Query } from '@modern-js/plugin-bff/server';
|
|
148
148
|
import { z } from 'zod';
|
|
149
149
|
|
|
150
150
|
const UserSchema = z.object({
|
|
@@ -176,7 +176,7 @@ URL query parameters are strings by default. If you need numeric types, you need
|
|
|
176
176
|
<BFFOperatorCode>
|
|
177
177
|
|
|
178
178
|
```typescript title="api/lambda/user.ts"
|
|
179
|
-
import { Api, Get, Query } from '@modern-js/plugin-bff/
|
|
179
|
+
import { Api, Get, Query } from '@modern-js/plugin-bff/server';
|
|
180
180
|
import { z } from 'zod';
|
|
181
181
|
|
|
182
182
|
const QuerySchema = z.object({
|
|
@@ -216,7 +216,7 @@ If you use the Data function, you must follow the HTTP protocol. When the HTTP M
|
|
|
216
216
|
<BFFOperatorCode>
|
|
217
217
|
|
|
218
218
|
```typescript title="api/lambda/user.ts"
|
|
219
|
-
import { Api, Data } from '@modern-js/plugin-bff/
|
|
219
|
+
import { Api, Data } from '@modern-js/plugin-bff/server';
|
|
220
220
|
import { z } from 'zod';
|
|
221
221
|
|
|
222
222
|
const DataSchema = z.object({
|
|
@@ -249,7 +249,7 @@ Route parameters can implement dynamic routes and get parameters from the path.
|
|
|
249
249
|
<BFFOperatorCode>
|
|
250
250
|
|
|
251
251
|
```typescript
|
|
252
|
-
import { Api, Get, Params } from '@modern-js/plugin-bff/
|
|
252
|
+
import { Api, Get, Params } from '@modern-js/plugin-bff/server';
|
|
253
253
|
import { z } from 'zod';
|
|
254
254
|
|
|
255
255
|
const UserSchema = z.object({
|
|
@@ -274,7 +274,7 @@ You can define the request headers required by the interface through the `Header
|
|
|
274
274
|
<BFFOperatorCode>
|
|
275
275
|
|
|
276
276
|
```typescript
|
|
277
|
-
import { Api, Headers } from '@modern-js/plugin-bff/
|
|
277
|
+
import { Api, Headers } from '@modern-js/plugin-bff/server';
|
|
278
278
|
import { z } from 'zod';
|
|
279
279
|
|
|
280
280
|
const headerSchema = z.object({
|
|
@@ -336,7 +336,7 @@ The `Middleware` operator can be configured multiple times, and the execution or
|
|
|
336
336
|
<BFFOperatorCode>
|
|
337
337
|
|
|
338
338
|
```typescript
|
|
339
|
-
import { Api, Query, Middleware } from '@modern-js/plugin-bff/
|
|
339
|
+
import { Api, Query, Middleware } from '@modern-js/plugin-bff/server';
|
|
340
340
|
import { z } from 'zod';
|
|
341
341
|
|
|
342
342
|
const UserSchema = z.object({
|
|
@@ -376,7 +376,7 @@ The `Pipe` operator can be configured multiple times. The execution order of fun
|
|
|
376
376
|
<BFFOperatorCode>
|
|
377
377
|
|
|
378
378
|
```typescript
|
|
379
|
-
import { Api, Query, Pipe } from '@modern-js/plugin-bff/
|
|
379
|
+
import { Api, Query, Pipe } from '@modern-js/plugin-bff/server';
|
|
380
380
|
import { z } from 'zod';
|
|
381
381
|
|
|
382
382
|
const UserSchema = z.object({
|
|
@@ -408,7 +408,7 @@ Also,
|
|
|
408
408
|
<BFFOperatorCode>
|
|
409
409
|
|
|
410
410
|
```typescript
|
|
411
|
-
import { Api, Query, Pipe } from '@modern-js/plugin-bff/
|
|
411
|
+
import { Api, Query, Pipe } from '@modern-js/plugin-bff/server';
|
|
412
412
|
import { z } from 'zod';
|
|
413
413
|
|
|
414
414
|
const UserSchema = z.object({
|
|
@@ -443,7 +443,7 @@ If you need to do more custom operations on the response, you can pass a functio
|
|
|
443
443
|
<BFFOperatorCode>
|
|
444
444
|
|
|
445
445
|
```typescript
|
|
446
|
-
import { Api, Query, Pipe } from '@modern-js/plugin-bff/
|
|
446
|
+
import { Api, Query, Pipe } from '@modern-js/plugin-bff/server';
|
|
447
447
|
import { z } from 'zod';
|
|
448
448
|
|
|
449
449
|
const UserSchema = z.object({
|
|
@@ -487,7 +487,7 @@ You can specify the status code returned by the interface through the `HttpCode(
|
|
|
487
487
|
<BFFOperatorCode>
|
|
488
488
|
|
|
489
489
|
```typescript
|
|
490
|
-
import { Api, Query, Data, HttpCode } from '@modern-js/plugin-bff/
|
|
490
|
+
import { Api, Query, Data, HttpCode } from '@modern-js/plugin-bff/server';
|
|
491
491
|
import { z } from 'zod';
|
|
492
492
|
|
|
493
493
|
const UserSchema = z.object({
|
|
@@ -523,7 +523,7 @@ Supports setting response headers through the `SetHeaders(headers: Record<string
|
|
|
523
523
|
<BFFOperatorCode>
|
|
524
524
|
|
|
525
525
|
```typescript
|
|
526
|
-
import { Api, Get, SetHeaders } from '@modern-js/plugin-bff/
|
|
526
|
+
import { Api, Get, SetHeaders } from '@modern-js/plugin-bff/server';
|
|
527
527
|
|
|
528
528
|
export default Api(
|
|
529
529
|
Get('/hello'),
|
|
@@ -543,7 +543,7 @@ Supports redirecting the interface through `Redirect(url: string)`:
|
|
|
543
543
|
<BFFOperatorCode>
|
|
544
544
|
|
|
545
545
|
```typescript
|
|
546
|
-
import { Api, Get, Redirect } from '@modern-js/plugin-bff/
|
|
546
|
+
import { Api, Get, Redirect } from '@modern-js/plugin-bff/server';
|
|
547
547
|
|
|
548
548
|
export default Api(
|
|
549
549
|
Get('/hello'),
|
|
@@ -561,7 +561,7 @@ As mentioned above, through operators, you can get `query`, `data`, `params`, et
|
|
|
561
561
|
<BFFOperatorCode>
|
|
562
562
|
|
|
563
563
|
```typescript title="api/lambda/user.ts"
|
|
564
|
-
import { Api, Get, Query } from '@modern-js/plugin-bff/
|
|
564
|
+
import { Api, Get, Query } from '@modern-js/plugin-bff/server';
|
|
565
565
|
import { useHonoContext } from '@modern-js/server-runtime';
|
|
566
566
|
import { z } from 'zod';
|
|
567
567
|
|
|
@@ -610,7 +610,7 @@ In frontend development, some server interfaces (such as some configuration inte
|
|
|
610
610
|
<BFFOperatorCode>
|
|
611
611
|
|
|
612
612
|
```typescript
|
|
613
|
-
import { Api, SetHeaders } from '@modern-js/plugin-bff/
|
|
613
|
+
import { Api, SetHeaders } from '@modern-js/plugin-bff/server';
|
|
614
614
|
|
|
615
615
|
export const get = Api(
|
|
616
616
|
// Cache will only take effect when using integrated calls or fetch for requests
|
|
@@ -213,7 +213,7 @@ transport surfaces when needed. They do not make raw request handlers valid
|
|
|
213
213
|
inside generated HTTP API modules.
|
|
214
214
|
|
|
215
215
|
Strict API tests should exercise the `HttpApi` contract. Use
|
|
216
|
-
`createEffectBffTestHandler` from `@modern-js/
|
|
216
|
+
`createEffectBffTestHandler` from `@modern-js/bff-effect/effect-edge` for
|
|
217
217
|
edge-compatible proof tests; if you manually compose a web handler, provide
|
|
218
218
|
`HttpServer.layerServices` beside your API group layer before calling
|
|
219
219
|
`HttpRouter.toWebHandler`.
|
|
@@ -21,7 +21,7 @@ export const get = async () => {
|
|
|
21
21
|
在 BFF 函数中获取 Cookie 时,需要通过 `useHonoContext` 获取请求上下文,然后使用 `c.req.header('cookie')` 获取 Cookie 字符串并手动解析:
|
|
22
22
|
|
|
23
23
|
```ts title="api/lambda/cookies.ts"
|
|
24
|
-
import { Api, Get } from '@modern-js/plugin-bff/
|
|
24
|
+
import { Api, Get } from '@modern-js/plugin-bff/server';
|
|
25
25
|
import { useHonoContext } from '@modern-js/server-runtime';
|
|
26
26
|
|
|
27
27
|
// 解析 Cookie 字符串的辅助函数
|
|
@@ -64,7 +64,7 @@ export const getCookies = Api(Get('/cookies'), async () => {
|
|
|
64
64
|
使用 Hono 作为运行时框架时,可以通过 [Api 函数](/guides/advanced-features/bff/operators.html) 定义接口:
|
|
65
65
|
|
|
66
66
|
```ts title="api/lambda/user.ts"
|
|
67
|
-
import { Api, Get, Query } from '@modern-js/plugin-bff/
|
|
67
|
+
import { Api, Get, Query } from '@modern-js/plugin-bff/server';
|
|
68
68
|
import { z } from 'zod';
|
|
69
69
|
|
|
70
70
|
const QuerySchema = z.object({
|
|
@@ -93,7 +93,7 @@ export const getUser = Api(
|
|
|
93
93
|
Hono 支持丰富的中间件生态,可以在 BFF 函数中使用中间件:
|
|
94
94
|
|
|
95
95
|
```ts title="api/lambda/user.ts"
|
|
96
|
-
import { Api, Get, Middleware } from '@modern-js/plugin-bff/
|
|
96
|
+
import { Api, Get, Middleware } from '@modern-js/plugin-bff/server';
|
|
97
97
|
|
|
98
98
|
export const getUser = Api(
|
|
99
99
|
Get('/user'),
|
|
@@ -46,10 +46,9 @@ import EnableBFFCaution from "@site-docs/components/enable-bff-caution";
|
|
|
46
46
|
仅当 `bff.runtimeFramework` 设置为 `'effect'` 时,`bff.effect` 才会生效。
|
|
47
47
|
|
|
48
48
|
:::caution 需要自行安装 Effect peer 依赖
|
|
49
|
-
`effect` 与 `@effect/opentelemetry` 是 `@modern-js/
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
或引入 `@modern-js/plugin-bff/effect`、`/effect-server`、`/effect-edge`、
|
|
49
|
+
`effect` 与 `@effect/opentelemetry` 是 `@modern-js/bff-effect` 的**可选精确 peer
|
|
50
|
+
依赖**。应用必须安装这些依赖,让 API 模块与框架使用同一个 Effect 实例。在设置
|
|
51
|
+
`runtimeFramework: 'effect'` 或引入 `@modern-js/bff-effect/effect`、`/effect-edge`、
|
|
53
52
|
`/effect-client` 之前,请安装精确版本的依赖组:
|
|
54
53
|
|
|
55
54
|
```bash
|
|
@@ -57,9 +56,19 @@ pnpm add effect@4.0.0-rc.112 @effect/opentelemetry@4.0.0-rc.112
|
|
|
57
56
|
```
|
|
58
57
|
|
|
59
58
|
采用精确版本是因为 UltraModern 以锁步依赖组的方式发布 Effect。只使用
|
|
60
|
-
`runtimeFramework: 'hono'` 或
|
|
59
|
+
原生 `runtimeFramework: 'hono'` 或 `@modern-js/bff-effect/data-platform` 的应用无需安装这两个包。
|
|
61
60
|
:::
|
|
62
61
|
|
|
62
|
+
使用 `@modern-js/plugin-bff-build-extensions` 导出的 `bffPlugin` 注册 Effect
|
|
63
|
+
运行时,它会组合原生 BFF 插件。将同一框架版本组中的 `@modern-js/bff-effect` 和
|
|
64
|
+
`@modern-js/plugin-bff-extensions` 安装为应用的生产依赖,保证移除开发依赖后仍能加载
|
|
65
|
+
运行时适配器。构建插件可以作为开发依赖。参见[运行时配置示例](/guides/advanced-features/bff/frameworks)。
|
|
66
|
+
|
|
67
|
+
原生 `@modern-js/plugin-bff/server` 导出 Hono API。Node Effect API 从
|
|
68
|
+
`@modern-js/bff-effect/effect` 导入 `defineEffectBff` 等框架 helper,命名空间从对应的
|
|
69
|
+
`effect/*` 模块导入。Worker handler 和 Worker 请求上下文使用
|
|
70
|
+
`@modern-js/bff-effect/effect-edge`。
|
|
71
|
+
|
|
63
72
|
生成的 UltraModern workspace 只把这个运行时作为生成 HTTP API 路径。API 契约固定在
|
|
64
73
|
`shared/api.ts`,服务端运行时固定在 `api/index.ts`,客户端固定在
|
|
65
74
|
`src/api/*-client.ts`。生成检查会拒绝 `api/effect`、`api/lambda`、
|
|
@@ -237,7 +246,7 @@ attestation 的迁移,并不等同于 release-age 审批。
|
|
|
237
246
|
Edge 兼容测试可以使用框架 helper:
|
|
238
247
|
|
|
239
248
|
```ts
|
|
240
|
-
import { createEffectBffTestHandler } from '@modern-js/
|
|
249
|
+
import { createEffectBffTestHandler } from '@modern-js/bff-effect/effect-edge';
|
|
241
250
|
import apiModule from '../api/index';
|
|
242
251
|
|
|
243
252
|
const testApi = await createEffectBffTestHandler({
|
|
@@ -252,12 +261,9 @@ const response = await testApi.handler(new Request('http://localhost/api/ping'))
|
|
|
252
261
|
`HttpServer.layerServices`:
|
|
253
262
|
|
|
254
263
|
```ts
|
|
255
|
-
import
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
HttpServer,
|
|
259
|
-
Layer,
|
|
260
|
-
} from '@modern-js/plugin-bff/effect-server';
|
|
264
|
+
import * as Layer from 'effect/Layer';
|
|
265
|
+
import { HttpRouter, HttpServer } from 'effect/unstable/http';
|
|
266
|
+
import { HttpApiBuilder } from 'effect/unstable/httpapi';
|
|
261
267
|
|
|
262
268
|
const handler = HttpRouter.toWebHandler(
|
|
263
269
|
HttpApiBuilder.layer(api).pipe(
|
|
@@ -275,13 +281,10 @@ const handler = HttpRouter.toWebHandler(
|
|
|
275
281
|
Effect v4 beta 版本组中,`HttpRouter.middleware(...)` 直接返回 `Layer`:
|
|
276
282
|
|
|
277
283
|
```ts
|
|
278
|
-
import
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
HttpRouter,
|
|
283
|
-
Layer,
|
|
284
|
-
} from '@modern-js/plugin-bff/effect-server';
|
|
284
|
+
import * as Effect from 'effect/Effect';
|
|
285
|
+
import * as Layer from 'effect/Layer';
|
|
286
|
+
import { HttpMiddleware, HttpRouter } from 'effect/unstable/http';
|
|
287
|
+
import { HttpApiBuilder } from 'effect/unstable/httpapi';
|
|
285
288
|
|
|
286
289
|
const corsLayer = HttpRouter.middleware(
|
|
287
290
|
Effect.succeed(
|
|
@@ -17,7 +17,7 @@ Modern.js 的 Effect BFF 已支持基于请求信封(request envelope)的数
|
|
|
17
17
|
|
|
18
18
|
## 运行时契约工具
|
|
19
19
|
|
|
20
|
-
可通过 `@modern-js/
|
|
20
|
+
可通过 `@modern-js/bff-effect/data-platform` 使用以下能力:
|
|
21
21
|
|
|
22
22
|
```ts
|
|
23
23
|
import {
|
|
@@ -30,7 +30,7 @@ import {
|
|
|
30
30
|
validateHydrationEnvelope,
|
|
31
31
|
createInvalidationEvent,
|
|
32
32
|
shouldApplyInvalidation,
|
|
33
|
-
} from '@modern-js/
|
|
33
|
+
} from '@modern-js/bff-effect/data-platform';
|
|
34
34
|
```
|
|
35
35
|
|
|
36
36
|
## Effect 运行时校验
|
|
@@ -5,10 +5,10 @@ title: 运行时框架
|
|
|
5
5
|
|
|
6
6
|
# 运行时框架
|
|
7
7
|
|
|
8
|
-
Modern.js
|
|
8
|
+
Modern.js 与 UltraModern BFF 扩展提供两种运行时框架:
|
|
9
9
|
|
|
10
|
-
- `
|
|
11
|
-
- `
|
|
10
|
+
- `hono` 是原生插件的默认运行时,使用 `api/lambda/**` 的文件约定处理函数。
|
|
11
|
+
- `effect` 是 UltraModern 扩展的默认运行时,使用 `api/index` 的 [Effect HttpApi](https://effect.website/) 运行时。
|
|
12
12
|
|
|
13
13
|
`effect` 与 `hono` 为严格模式,两者之间不会自动回退。
|
|
14
14
|
|
|
@@ -22,12 +22,16 @@ workspace 中加入 Hono/file-convention handler、原始 request parsing 或手
|
|
|
22
22
|
|
|
23
23
|
## 切换到 Effect 运行时
|
|
24
24
|
|
|
25
|
+
使用下面的 fork 构建插件,它会包含原生 BFF 插件并注册 Effect 适配器。应用需要将
|
|
26
|
+
同一框架版本组中的 `@modern-js/bff-effect` 和 `@modern-js/plugin-bff-extensions`
|
|
27
|
+
安装为生产依赖。Effect 的精确 peer 版本见 [`bff.effect`](/configure/app/bff/effect)。
|
|
28
|
+
|
|
25
29
|
```ts title="modern.config.ts"
|
|
26
|
-
import { bffPlugin } from '@modern-js/plugin-bff';
|
|
27
|
-
import { defineConfig } from '@modern-js/app-tools';
|
|
30
|
+
import { bffPlugin } from '@modern-js/plugin-bff-build-extensions';
|
|
31
|
+
import { appTools, defineConfig } from '@modern-js/app-tools';
|
|
28
32
|
|
|
29
33
|
export default defineConfig({
|
|
30
|
-
plugins: [bffPlugin()],
|
|
34
|
+
plugins: [appTools(), bffPlugin()],
|
|
31
35
|
bff: {
|
|
32
36
|
runtimeFramework: 'effect',
|
|
33
37
|
effect: {
|
|
@@ -49,7 +53,7 @@ import {
|
|
|
49
53
|
HttpApiEndpoint,
|
|
50
54
|
HttpApiGroup,
|
|
51
55
|
Schema,
|
|
52
|
-
} from '@modern-js/
|
|
56
|
+
} from '@modern-js/bff-effect/effect-client';
|
|
53
57
|
|
|
54
58
|
export const bffApi = HttpApi.make('MyApi').add(
|
|
55
59
|
HttpApiGroup.make('hello').add(
|
|
@@ -63,14 +67,12 @@ export const bffApi = HttpApi.make('MyApi').add(
|
|
|
63
67
|
然后在 `api/index.ts` 中实现 Effect BFF 入口:
|
|
64
68
|
|
|
65
69
|
```ts title="api/index.ts"
|
|
66
|
-
import {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
ServiceMap,
|
|
73
|
-
} from '@modern-js/plugin-bff/effect-server';
|
|
70
|
+
import { defineEffectBff } from '@modern-js/bff-effect/effect';
|
|
71
|
+
import * as Context from 'effect/Context';
|
|
72
|
+
import * as Effect from 'effect/Effect';
|
|
73
|
+
import * as Layer from 'effect/Layer';
|
|
74
|
+
import * as Schema from 'effect/Schema';
|
|
75
|
+
import { HttpApiBuilder } from 'effect/unstable/httpapi';
|
|
74
76
|
import { bffApi } from '../shared/api';
|
|
75
77
|
|
|
76
78
|
class GreetingUnavailableError extends Schema.TaggedError<GreetingUnavailableError>()(
|
|
@@ -80,7 +82,7 @@ class GreetingUnavailableError extends Schema.TaggedError<GreetingUnavailableErr
|
|
|
80
82
|
},
|
|
81
83
|
) {}
|
|
82
84
|
|
|
83
|
-
class GreetingService extends
|
|
85
|
+
class GreetingService extends Context.Service<GreetingService>()('GreetingService', {
|
|
84
86
|
make: Effect.succeed({
|
|
85
87
|
hello: Effect.fn('GreetingService.hello')(function* () {
|
|
86
88
|
if (Date.now() < 0) {
|
|
@@ -125,6 +127,10 @@ const response = await api.client.hello.ping({});
|
|
|
125
127
|
|
|
126
128
|
`api.client.*` 由 BFF loader 针对 `@api/index` 导入物化生成。不要直接导入 `api/index` 并期望在服务端代码、脚本或测试中运行 `client`;直接导入入口时拿到的是服务端运行时定义,其中的 `client` 只是类型占位。
|
|
127
129
|
|
|
130
|
+
原生 Hono 应用从 `@modern-js/plugin-bff/server` 导入操作符。生成的 UltraModern
|
|
131
|
+
应用继续使用严格 Effect API。Worker handler 及其请求上下文使用
|
|
132
|
+
`@modern-js/bff-effect/effect-edge`;Node handler 使用上面示例中的 Effect 入口。
|
|
133
|
+
|
|
128
134
|
import Hono from '@site-docs/components/hono';
|
|
129
135
|
|
|
130
136
|
<Hono />
|
|
@@ -188,7 +188,7 @@ Dynamic Path 之后的参数是包含 querystring、request body 的对象 `Requ
|
|
|
188
188
|
在不存在动态路由的普通函数中,可以从第一个入参中获取传入的 `data` 和 `query`,例如:
|
|
189
189
|
|
|
190
190
|
```ts title="api/lambda/hello.ts"
|
|
191
|
-
import type { RequestOption } from '@modern-js/plugin-bff/
|
|
191
|
+
import type { RequestOption } from '@modern-js/plugin-bff/server';
|
|
192
192
|
|
|
193
193
|
export async function post({
|
|
194
194
|
query,
|
|
@@ -201,7 +201,7 @@ export async function post({
|
|
|
201
201
|
这里你也可以使用自定义类型:
|
|
202
202
|
|
|
203
203
|
```ts title="api/lambda/hello.ts"
|
|
204
|
-
import type { RequestOption } from '@modern-js/plugin-bff/
|
|
204
|
+
import type { RequestOption } from '@modern-js/plugin-bff/server';
|
|
205
205
|
|
|
206
206
|
type IQuery = {
|
|
207
207
|
// some types
|
|
@@ -36,7 +36,7 @@ import BFFOperatorCode from '@site-docs/components/bff-operator-code';
|
|
|
36
36
|
<BFFOperatorCode>
|
|
37
37
|
|
|
38
38
|
```typescript title="api/lambda/user.ts"
|
|
39
|
-
import { Api, Post, Query, Data } from '@modern-js/plugin-bff/
|
|
39
|
+
import { Api, Post, Query, Data } from '@modern-js/plugin-bff/server';
|
|
40
40
|
import { z } from 'zod';
|
|
41
41
|
|
|
42
42
|
const UserSchema = z.object({
|
|
@@ -89,7 +89,7 @@ addUser({
|
|
|
89
89
|
<BFFOperatorCode>
|
|
90
90
|
|
|
91
91
|
```typescript title="api/lambda/user.ts"
|
|
92
|
-
import { Api, Get, Query, Data } from '@modern-js/plugin-bff/
|
|
92
|
+
import { Api, Get, Query, Data } from '@modern-js/plugin-bff/server';
|
|
93
93
|
|
|
94
94
|
// 指定接口路由,Modern.js 默认设置 `bff.prefix` 为 `/api`,
|
|
95
95
|
// 因此该接口路由为 `/api/user`,Http Method 为 GET。
|
|
@@ -107,7 +107,7 @@ export const getHello = Api(
|
|
|
107
107
|
<BFFOperatorCode>
|
|
108
108
|
|
|
109
109
|
```typescript title="api/lambda/user.ts"
|
|
110
|
-
import { Api, Get, Query, Data } from '@modern-js/plugin-bff/
|
|
110
|
+
import { Api, Get, Query, Data } from '@modern-js/plugin-bff/server';
|
|
111
111
|
|
|
112
112
|
// 未指定接口路由,根据文件约定和函数名,该接口为 api/user,Http Method 为 get。
|
|
113
113
|
export const get = Api(Query(UserSchema), async ({ query }) => query);
|
|
@@ -144,7 +144,7 @@ Modern.js 推荐基于文件约定去定义接口,保持项目中路由清晰
|
|
|
144
144
|
|
|
145
145
|
```typescript title="api/lambda/user.ts"
|
|
146
146
|
// 服务端代码
|
|
147
|
-
import { Api, Query } from '@modern-js/plugin-bff/
|
|
147
|
+
import { Api, Query } from '@modern-js/plugin-bff/server';
|
|
148
148
|
import { z } from 'zod';
|
|
149
149
|
|
|
150
150
|
const UserSchema = z.object({
|
|
@@ -176,7 +176,7 @@ URL query 参数默认是字符串类型,如果需要数字类型,需要使
|
|
|
176
176
|
<BFFOperatorCode>
|
|
177
177
|
|
|
178
178
|
```typescript title="api/lambda/user.ts"
|
|
179
|
-
import { Api, Get, Query } from '@modern-js/plugin-bff/
|
|
179
|
+
import { Api, Get, Query } from '@modern-js/plugin-bff/server';
|
|
180
180
|
import { z } from 'zod';
|
|
181
181
|
|
|
182
182
|
const QuerySchema = z.object({
|
|
@@ -216,7 +216,7 @@ URL query 参数都是字符串类型,如果需要数字类型,需要使用
|
|
|
216
216
|
<BFFOperatorCode>
|
|
217
217
|
|
|
218
218
|
```typescript title="api/lambda/user.ts"
|
|
219
|
-
import { Api, Data } from '@modern-js/plugin-bff/
|
|
219
|
+
import { Api, Data } from '@modern-js/plugin-bff/server';
|
|
220
220
|
import { z } from 'zod';
|
|
221
221
|
|
|
222
222
|
const DataSchema = z.object({
|
|
@@ -249,7 +249,7 @@ post({
|
|
|
249
249
|
<BFFOperatorCode>
|
|
250
250
|
|
|
251
251
|
```typescript
|
|
252
|
-
import { Api, Get, Params } from '@modern-js/plugin-bff/
|
|
252
|
+
import { Api, Get, Params } from '@modern-js/plugin-bff/server';
|
|
253
253
|
import { z } from 'zod';
|
|
254
254
|
|
|
255
255
|
const UserSchema = z.object({
|
|
@@ -274,7 +274,7 @@ export const queryUser = Api(
|
|
|
274
274
|
<BFFOperatorCode>
|
|
275
275
|
|
|
276
276
|
```typescript
|
|
277
|
-
import { Api, Headers } from '@modern-js/plugin-bff/
|
|
277
|
+
import { Api, Headers } from '@modern-js/plugin-bff/server';
|
|
278
278
|
import { z } from 'zod';
|
|
279
279
|
|
|
280
280
|
const headerSchema = z.object({
|
|
@@ -336,7 +336,7 @@ try {
|
|
|
336
336
|
<BFFOperatorCode>
|
|
337
337
|
|
|
338
338
|
```typescript
|
|
339
|
-
import { Api, Query, Middleware } from '@modern-js/plugin-bff/
|
|
339
|
+
import { Api, Query, Middleware } from '@modern-js/plugin-bff/server';
|
|
340
340
|
import { z } from 'zod';
|
|
341
341
|
|
|
342
342
|
const UserSchema = z.object({
|
|
@@ -376,7 +376,7 @@ export const get = Api(
|
|
|
376
376
|
<BFFOperatorCode>
|
|
377
377
|
|
|
378
378
|
```typescript
|
|
379
|
-
import { Api, Query, Pipe } from '@modern-js/plugin-bff/
|
|
379
|
+
import { Api, Query, Pipe } from '@modern-js/plugin-bff/server';
|
|
380
380
|
import { z } from 'zod';
|
|
381
381
|
|
|
382
382
|
const UserSchema = z.object({
|
|
@@ -408,7 +408,7 @@ export const get = Api(
|
|
|
408
408
|
<BFFOperatorCode>
|
|
409
409
|
|
|
410
410
|
```typescript
|
|
411
|
-
import { Api, Query, Pipe } from '@modern-js/plugin-bff/
|
|
411
|
+
import { Api, Query, Pipe } from '@modern-js/plugin-bff/server';
|
|
412
412
|
import { z } from 'zod';
|
|
413
413
|
|
|
414
414
|
const UserSchema = z.object({
|
|
@@ -443,7 +443,7 @@ export const get = Api(
|
|
|
443
443
|
<BFFOperatorCode>
|
|
444
444
|
|
|
445
445
|
```typescript
|
|
446
|
-
import { Api, Query, Pipe } from '@modern-js/plugin-bff/
|
|
446
|
+
import { Api, Query, Pipe } from '@modern-js/plugin-bff/server';
|
|
447
447
|
import { z } from 'zod';
|
|
448
448
|
|
|
449
449
|
const UserSchema = z.object({
|
|
@@ -487,7 +487,7 @@ export const get = Api(
|
|
|
487
487
|
<BFFOperatorCode>
|
|
488
488
|
|
|
489
489
|
```typescript
|
|
490
|
-
import { Api, Query, Data, HttpCode } from '@modern-js/plugin-bff/
|
|
490
|
+
import { Api, Query, Data, HttpCode } from '@modern-js/plugin-bff/server';
|
|
491
491
|
import { z } from 'zod';
|
|
492
492
|
|
|
493
493
|
const UserSchema = z.object({
|
|
@@ -523,7 +523,7 @@ export const post = Api(
|
|
|
523
523
|
<BFFOperatorCode>
|
|
524
524
|
|
|
525
525
|
```typescript
|
|
526
|
-
import { Api, Get, SetHeaders } from '@modern-js/plugin-bff/
|
|
526
|
+
import { Api, Get, SetHeaders } from '@modern-js/plugin-bff/server';
|
|
527
527
|
|
|
528
528
|
export default Api(
|
|
529
529
|
Get('/hello'),
|
|
@@ -543,7 +543,7 @@ export default Api(
|
|
|
543
543
|
<BFFOperatorCode>
|
|
544
544
|
|
|
545
545
|
```typescript
|
|
546
|
-
import { Api, Get, Redirect } from '@modern-js/plugin-bff/
|
|
546
|
+
import { Api, Get, Redirect } from '@modern-js/plugin-bff/server';
|
|
547
547
|
|
|
548
548
|
export default Api(
|
|
549
549
|
Get('/hello'),
|
|
@@ -561,7 +561,7 @@ export default Api(
|
|
|
561
561
|
<BFFOperatorCode>
|
|
562
562
|
|
|
563
563
|
```typescript title="api/lambda/user.ts"
|
|
564
|
-
import { Api, Get, Query } from '@modern-js/plugin-bff/
|
|
564
|
+
import { Api, Get, Query } from '@modern-js/plugin-bff/server';
|
|
565
565
|
import { useHonoContext } from '@modern-js/server-runtime';
|
|
566
566
|
import { z } from 'zod';
|
|
567
567
|
|
|
@@ -610,7 +610,7 @@ export const queryUser = Api(
|
|
|
610
610
|
<BFFOperatorCode>
|
|
611
611
|
|
|
612
612
|
```typescript
|
|
613
|
-
import { Api, SetHeaders } from '@modern-js/plugin-bff/
|
|
613
|
+
import { Api, SetHeaders } from '@modern-js/plugin-bff/server';
|
|
614
614
|
|
|
615
615
|
export const get = Api(
|
|
616
616
|
// 缓存使用一体化调用或者 fetch 进行请求才会生效
|
|
@@ -190,7 +190,7 @@ Effect RPC、WebSockets 和其他传输方式应在需要时作为显式 transpo
|
|
|
190
190
|
它们不能作为在生成 HTTP API 模块中重新引入原始 request handler 的理由。
|
|
191
191
|
|
|
192
192
|
严格 API 测试应执行 `HttpApi` 契约。Edge 兼容 proof 测试使用
|
|
193
|
-
`@modern-js/
|
|
193
|
+
`@modern-js/bff-effect/effect-edge` 的 `createEffectBffTestHandler`;如果必须手动组合
|
|
194
194
|
web handler,在调用 `HttpRouter.toWebHandler` 前要把 `HttpServer.layerServices` 和
|
|
195
195
|
API group layer 一起提供。
|
|
196
196
|
|
package/package.json
CHANGED
|
@@ -19,13 +19,13 @@
|
|
|
19
19
|
"modern.js",
|
|
20
20
|
"ultramodern.js"
|
|
21
21
|
],
|
|
22
|
-
"version": "3.9.0-ultramodern.
|
|
22
|
+
"version": "3.9.0-ultramodern.5",
|
|
23
23
|
"publishConfig": {
|
|
24
24
|
"access": "public"
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
|
-
"@modern-js/sandpack-react": "npm:@bleedingdev/modern-js-sandpack-react@3.9.0-ultramodern.
|
|
28
|
-
"@modern-js/ultramodern-sandpack-profile": "npm:@bleedingdev/modern-js-ultramodern-sandpack-profile@3.9.0-ultramodern.
|
|
27
|
+
"@modern-js/sandpack-react": "npm:@bleedingdev/modern-js-sandpack-react@3.9.0-ultramodern.5",
|
|
28
|
+
"@modern-js/ultramodern-sandpack-profile": "npm:@bleedingdev/modern-js-ultramodern-sandpack-profile@3.9.0-ultramodern.5",
|
|
29
29
|
"mermaid": "^11.17.2"
|
|
30
30
|
},
|
|
31
31
|
"devDependencies": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
Navigate,
|
|
3
|
-
|
|
3
|
+
useMatch,
|
|
4
4
|
useNavigate,
|
|
5
5
|
} from '@modern-js/plugin-tanstack/runtime';
|
|
6
6
|
import React from 'react';
|
|
@@ -52,8 +52,9 @@ export function AuthStatus() {
|
|
|
52
52
|
Welcome {auth.user}!{' '}
|
|
53
53
|
<button
|
|
54
54
|
type="button"
|
|
55
|
-
onClick={() => {
|
|
56
|
-
|
|
55
|
+
onClick={async () => {
|
|
56
|
+
await navigate({ to: '/' });
|
|
57
|
+
auth.signout(() => {});
|
|
57
58
|
}}
|
|
58
59
|
>
|
|
59
60
|
Sign out
|
|
@@ -62,9 +63,12 @@ export function AuthStatus() {
|
|
|
62
63
|
);
|
|
63
64
|
}
|
|
64
65
|
|
|
65
|
-
export function RequireAuth({ children }: { children: JSX.Element }) {
|
|
66
|
+
export function RequireAuth({ children }: { children: React.JSX.Element }) {
|
|
66
67
|
const auth = useAuth();
|
|
67
|
-
const
|
|
68
|
+
const pathname = useMatch({
|
|
69
|
+
strict: false,
|
|
70
|
+
select: match => match.pathname,
|
|
71
|
+
});
|
|
68
72
|
|
|
69
73
|
if (!auth.user) {
|
|
70
74
|
// Redirect them to the /login page, but save the current location they were
|
|
@@ -74,7 +78,7 @@ export function RequireAuth({ children }: { children: JSX.Element }) {
|
|
|
74
78
|
return (
|
|
75
79
|
<Navigate
|
|
76
80
|
replace
|
|
77
|
-
search={{ redirect:
|
|
81
|
+
search={{ redirect: pathname }}
|
|
78
82
|
to="/login"
|
|
79
83
|
/>
|
|
80
84
|
);
|