@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.
@@ -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 hook of the server derives. With the type
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 hook set a nonce, and
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 hook or a route reads `ctx.server`, or the app declares a `page()`,
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 hooks read a server
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.4.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.1.2",
55
- "@alxia/core": "^0.3.1",
56
- "@alxia/openapi": "^0.3.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.3.1",
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"