@alxia/react-router 0.4.0 → 0.6.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.
- package/README.md +70 -34
- package/dist/cli/index.js +3 -3
- package/dist/cli/index.js.map +4 -4
- package/dist/cli/template.d.ts +1 -1
- package/dist/cli/template.d.ts.map +1 -1
- package/dist/context.d.ts +23 -12
- package/dist/context.d.ts.map +1 -1
- package/dist/index.js +15 -16
- package/dist/index.js.map +6 -6
- package/dist/nonce.d.ts +2 -2
- package/dist/nonce.d.ts.map +1 -1
- package/dist/react-router.d.ts +14 -14
- package/dist/react-router.d.ts.map +1 -1
- package/dist/server.d.ts +10 -7
- package/dist/server.d.ts.map +1 -1
- package/dist/vite/index.js.map +2 -2
- package/dist/vite/preview.d.ts +1 -1
- package/dist/vite/socket.d.ts +1 -1
- package/docs/README.md +8 -1
- package/docs/guide.md +179 -64
- package/docs/roadmap.md +34 -15
- package/docs/troubleshooting.md +51 -5
- package/package.json +5 -5
package/docs/troubleshooting.md
CHANGED
|
@@ -55,6 +55,8 @@ a loader, a message React Router or the browser prints, or an error from
|
|
|
55
55
|
- [A page answers alxia's JSON 404 or 405 instead of rendering](#a-page-answers-alxias-json-404-or-405-instead-of-rendering)
|
|
56
56
|
- [A streamed page arrives in one piece](#a-streamed-page-arrives-in-one-piece)
|
|
57
57
|
- [The logger times a streamed page at a few milliseconds](#the-logger-times-a-streamed-page-at-a-few-milliseconds)
|
|
58
|
+
- [A page, or a missing path, answers 401 behind a guard](#a-page-or-a-missing-path-answers-401-behind-a-guard)
|
|
59
|
+
- [The logger, CORS or secure headers miss the client's files](#the-logger-cors-or-secure-headers-miss-the-clients-files)
|
|
58
60
|
- [`ctx.server` is `undefined` under `react-router dev`](#ctxserver-is-undefined-under-react-router-dev)
|
|
59
61
|
- [A `publish` under `react-router dev` misses the sockets opened before an edit](#a-publish-under-react-router-dev-misses-the-sockets-opened-before-an-edit)
|
|
60
62
|
- [The build has a package's Node variant, not its `bun` one](#the-build-has-a-packages-node-variant-not-its-bun-one)
|
|
@@ -727,6 +729,12 @@ COPY --from=production-dependencies /app/node_modules ./node_modules
|
|
|
727
729
|
`grep '^import' build/server/index.js` lists what the build still
|
|
728
730
|
imports: `node:*`, `bun`, `bun:*` and the packages `ssr.external` names.
|
|
729
731
|
|
|
732
|
+
The image runs on `oven/bun:1-alpine`, whose C library is musl. A native
|
|
733
|
+
addon built for glibc alone then stops it with
|
|
734
|
+
`… is linked against glibc (DT_NEEDED …), but this Bun build uses musl.`:
|
|
735
|
+
put the final stage back on `oven/bun:1`
|
|
736
|
+
([`@alxia/create`'s troubleshooting](https://github.com/softistx/alxia/blob/develop/packages/create/docs/troubleshooting.md#error--is-linked-against-glibc-dt_needed-libmso6-but-this-bun-build-uses-musl)).
|
|
737
|
+
|
|
730
738
|
## Types
|
|
731
739
|
|
|
732
740
|
### `Property '…' does not exist on type 'BaseContext & …'`
|
|
@@ -736,10 +744,12 @@ error TS2339: Property 'tenant' does not exist on type 'BaseContext & Empty & {
|
|
|
736
744
|
```
|
|
737
745
|
|
|
738
746
|
**When:** a loader reads, through `alxiaOf`, or `getLoadContext`
|
|
739
|
-
destructures, something no
|
|
747
|
+
destructures, something no middleware of the server derives. With the type
|
|
740
748
|
`'BaseContext & Empty'` alone, `alxiaOf(context)` has no server to read:
|
|
741
749
|
`app/server.ts` has no `Register` declaration, or there is no
|
|
742
|
-
`app/server.ts
|
|
750
|
+
`app/server.ts`, and `@alxia/core`'s `Register` names no base either.
|
|
751
|
+
With core's `Register` alone, `alxiaOf` reads that base: a key
|
|
752
|
+
`configure` adds after it is missing.
|
|
743
753
|
|
|
744
754
|
**Why:** the type is the app's context at the point of the catch-all, as
|
|
745
755
|
for any route: "order is meaning".
|
|
@@ -862,7 +872,7 @@ argument, `alxiaOf<Server>(context)`.
|
|
|
862
872
|
error TS2375: Type '{ context: EntryContext; url: string; nonce: string | undefined; }' is not assignable to type 'ServerRouterProps' with 'exactOptionalPropertyTypes: true'. Consider adding 'undefined' to the types of the target's properties.
|
|
863
873
|
```
|
|
864
874
|
|
|
865
|
-
**Why:** `nonceOf` returns `undefined` when no
|
|
875
|
+
**Why:** `nonceOf` returns `undefined` when no middleware set a nonce, and
|
|
866
876
|
`ServerRouterProps.nonce` is optional without `undefined`. React's
|
|
867
877
|
`nonce` option takes `undefined`, so only the prop complains.
|
|
868
878
|
|
|
@@ -987,9 +997,45 @@ deferred value later. If the whole page comes at once:
|
|
|
987
997
|
page that streams for 800 ms is logged at its first byte. The duration is
|
|
988
998
|
the server's time to first byte, not the page's.
|
|
989
999
|
|
|
1000
|
+
### A page, or a missing path, answers 401 behind a guard
|
|
1001
|
+
|
|
1002
|
+
A guard given to `use` in `configure` or `beforeAll` runs on every request
|
|
1003
|
+
it is in front of, a request no route matches included, and answers before
|
|
1004
|
+
the 404. An anonymous request to `/nope` gets the 401, not the 404, and so
|
|
1005
|
+
does the login page the guard sits in front of. Scope the guard to what it
|
|
1006
|
+
guards, with a path. A path-scoped `use` takes a middleware that adds nothing
|
|
1007
|
+
to the context, so `bearer`, which adds `user`, does not compile there: write
|
|
1008
|
+
the guard as a middleware that only refuses. The pages are a catch-all outside
|
|
1009
|
+
any `group`, so a `group` would not reach them.
|
|
1010
|
+
|
|
1011
|
+
```ts
|
|
1012
|
+
import { defineMiddleware } from '@alxia/core';
|
|
1013
|
+
|
|
1014
|
+
const account = defineMiddleware(async ({ request, reply }, next) => {
|
|
1015
|
+
const token = request.headers.get('authorization')?.slice('Bearer '.length) ?? '';
|
|
1016
|
+
return (await jwt.verify(token)).ok ? next() : reply(401, { error: 'unauthorized' as const });
|
|
1017
|
+
});
|
|
1018
|
+
|
|
1019
|
+
createServer({
|
|
1020
|
+
configure: (app) => app.use('/account', account), // the pages under /account only
|
|
1021
|
+
});
|
|
1022
|
+
```
|
|
1023
|
+
|
|
1024
|
+
### The logger, CORS or secure headers miss the client's files
|
|
1025
|
+
|
|
1026
|
+
A middleware in `configure` runs for the routes declared after it. The
|
|
1027
|
+
client's files are declared before `configure`, after `beforeAll`: what must
|
|
1028
|
+
see them too goes in `beforeAll`.
|
|
1029
|
+
|
|
1030
|
+
```ts
|
|
1031
|
+
createServer({
|
|
1032
|
+
beforeAll: (app) => app.use(logger()).use(secureHeaders()),
|
|
1033
|
+
});
|
|
1034
|
+
```
|
|
1035
|
+
|
|
990
1036
|
### `ctx.server` is `undefined` under `react-router dev`
|
|
991
1037
|
|
|
992
|
-
A
|
|
1038
|
+
A middleware or a route reads `ctx.server`, or the app declares a `page()`,
|
|
993
1039
|
under `react-router dev` or `vite preview`; the same code works from
|
|
994
1040
|
`bun build/server/index.js`.
|
|
995
1041
|
|
|
@@ -998,7 +1044,7 @@ the preview server under `vite preview`. An HTTP request reaches the app
|
|
|
998
1044
|
through `app.fetch`, as in a test, not through `listen`: there is no
|
|
999
1045
|
`Bun.serve` behind it, so `ctx.server` is `undefined`, the default
|
|
1000
1046
|
`ctx.ip` too, and a `page()` (Bun's HTML bundle) is not served. A socket's upgrade is the exception: the plugin relays it
|
|
1001
|
-
to a `Bun.serve` of the app, so its
|
|
1047
|
+
to a `Bun.serve` of the app, so its middlewares read a server
|
|
1002
1048
|
([WebSockets](guide.md#under-react-router-dev)).
|
|
1003
1049
|
|
|
1004
1050
|
**Fix:** read `ctx.server` as optional, and publish to sockets from the
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@alxia/react-router",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "alxia as the server of a React Router framework app: server rendering behind the app's hooks, loaders reading its typed context, the client's assets served",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -51,9 +51,9 @@
|
|
|
51
51
|
]
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
|
-
"@alxia/compress": "^0.
|
|
55
|
-
"@alxia/core": "^0.
|
|
56
|
-
"@alxia/openapi": "^0.
|
|
54
|
+
"@alxia/compress": "^0.3.0",
|
|
55
|
+
"@alxia/core": "^0.5.0",
|
|
56
|
+
"@alxia/openapi": "^0.5.0",
|
|
57
57
|
"@react-router/dev": "^8.4.0",
|
|
58
58
|
"@types/bun": "^1.4.2",
|
|
59
59
|
"@types/react": "^19.3.0",
|
|
@@ -65,7 +65,7 @@
|
|
|
65
65
|
"vite": "^7.0.0"
|
|
66
66
|
},
|
|
67
67
|
"peerDependencies": {
|
|
68
|
-
"@alxia/core": "^0.
|
|
68
|
+
"@alxia/core": "^0.5.0",
|
|
69
69
|
"react-router": "^8.0.0",
|
|
70
70
|
"typescript": "^6.0.3 || ^7.0.0",
|
|
71
71
|
"vite": "^7.0.0 || ^8.0.0"
|