@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/dist/react-router.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Alxia, AnyAlxia,
|
|
1
|
+
import type { Alxia, AnyAlxia, BaseContext, MaybePromise, RouteDefinition } from '@alxia/core';
|
|
2
2
|
import { RouterContextProvider, type ServerBuild } from 'react-router';
|
|
3
3
|
export interface ReactRouterOptions<Ctx> {
|
|
4
4
|
/**
|
|
@@ -13,8 +13,8 @@ export interface ReactRouterOptions<Ctx> {
|
|
|
13
13
|
readonly mode?: 'development' | 'production';
|
|
14
14
|
/**
|
|
15
15
|
* Sets the app's own keys on React Router's context provider, from the
|
|
16
|
-
* context alxia's
|
|
17
|
-
* `
|
|
16
|
+
* context alxia's middlewares built. `ctx` is typed by the app at the point of
|
|
17
|
+
* `app.plugin`: reading what nothing before it adds is a compile error.
|
|
18
18
|
* `alxiaContext` is always set, whether or not this is given.
|
|
19
19
|
*/
|
|
20
20
|
readonly getLoadContext?: (ctx: BaseContext & Ctx, context: RouterContextProvider) => MaybePromise<void>;
|
|
@@ -28,34 +28,34 @@ export interface ReactRouterOptions<Ctx> {
|
|
|
28
28
|
}
|
|
29
29
|
/**
|
|
30
30
|
* Whether `reactRouter()` declared this route: the catch-all, or one of the
|
|
31
|
-
* client build's files. For `@alxia/openapi`'s `
|
|
32
|
-
*
|
|
31
|
+
* client build's files. For `@alxia/openapi`'s `matchesSpec`, whose
|
|
32
|
+
* `exclude` leaves them out, so the app's routes are checked against the
|
|
33
|
+
* operations of its OpenAPI document and its pages are not.
|
|
33
34
|
*
|
|
34
35
|
* ```ts
|
|
35
|
-
*
|
|
36
|
+
* matchesSpec(app, operations, { exclude: isReactRouterRoute });
|
|
36
37
|
* ```
|
|
37
38
|
*/
|
|
38
39
|
export declare function isReactRouterRoute(route: RouteDefinition): boolean;
|
|
39
40
|
/**
|
|
40
41
|
* A React Router framework app, server rendered on `app`: `GET`, `POST`,
|
|
41
|
-
* `PUT`, `PATCH` and `DELETE` at `/*`, behind every
|
|
42
|
-
* before it. Each loader, action and middleware reads what those
|
|
43
|
-
*
|
|
42
|
+
* `PUT`, `PATCH` and `DELETE` at `/*`, behind every middleware declared on `app`
|
|
43
|
+
* before it. Each loader, action and middleware reads what those added
|
|
44
|
+
* through `alxiaOf<App>(context)`. The app's own routes — an `/api`
|
|
44
45
|
* — answer their paths, declared before it or after; the client build's
|
|
45
|
-
* files are served when `client` is given.
|
|
46
|
-
* the app's route table: pages are not something the typed client calls.
|
|
46
|
+
* files are served when `client` is given.
|
|
47
47
|
*
|
|
48
48
|
* ```ts
|
|
49
|
-
* const app = base.
|
|
49
|
+
* const app = base.plugin((app) =>
|
|
50
50
|
* reactRouter(app, { build: () => import('./build/server/index.js'), client: 'build/client' }),
|
|
51
51
|
* );
|
|
52
52
|
* ```
|
|
53
53
|
*/
|
|
54
|
-
export declare function reactRouter<Ctx extends object,
|
|
54
|
+
export declare function reactRouter<Ctx extends object, Prefix extends string>(app: Alxia<Ctx, Prefix>, options: ReactRouterOptions<Ctx>): Alxia<Ctx, Prefix>;
|
|
55
55
|
/**
|
|
56
56
|
* Declares the client build's files on `app`, marked for
|
|
57
57
|
* `isReactRouterRoute`: what `reactRouter()` does with `client`, apart, so
|
|
58
|
-
* that `createServer()` serves them before the
|
|
58
|
+
* that `createServer()` serves them before the middlewares of `configure`.
|
|
59
59
|
*/
|
|
60
60
|
export declare function declareClient(app: AnyAlxia, client: string | URL): void;
|
|
61
61
|
//# sourceMappingURL=react-router.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"react-router.d.ts","sourceRoot":"","sources":["../src/react-router.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,KAAK,EACL,QAAQ,EACR,
|
|
1
|
+
{"version":3,"file":"react-router.d.ts","sourceRoot":"","sources":["../src/react-router.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACX,KAAK,EACL,QAAQ,EACR,WAAW,EACX,YAAY,EACZ,eAAe,EAEf,MAAM,aAAa,CAAC;AACrB,OAAO,EAGN,qBAAqB,EACrB,KAAK,WAAW,EAChB,MAAM,cAAc,CAAC;AAItB,MAAM,WAAW,kBAAkB,CAAC,GAAG;IACtC;;;;;;OAMG;IACH,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,CAAC,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC;IAChE,2DAA2D;IAC3D,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;IAC7C;;;;;OAKG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,CACzB,GAAG,EAAE,WAAW,GAAG,GAAG,EACtB,OAAO,EAAE,qBAAqB,KAC1B,YAAY,CAAC,IAAI,CAAC,CAAC;IACxB;;;;;OAKG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,CAAC;CAC/B;AAQD;;;;;;;;;GASG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,eAAe,GAAG,OAAO,CAElE;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,WAAW,CAAC,GAAG,SAAS,MAAM,EAAE,MAAM,SAAS,MAAM,EACpE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,EACvB,OAAO,EAAE,kBAAkB,CAAC,GAAG,CAAC,GAC9B,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,CA8BpB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,GAAG,GAAG,GAAG,IAAI,CAEvE"}
|
package/dist/server.d.ts
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { type Alxia, type AnyAlxia, type ContextOf, type Empty, type ListenOptions, type MaybePromise } from '@alxia/core';
|
|
8
8
|
import type { RouterContextProvider, ServerBuild } from 'react-router';
|
|
9
9
|
/** An app as `alxia()` makes it: what `beforeAll`, or `configure`, receives. */
|
|
10
|
-
export type FreshApp = Alxia<Empty,
|
|
10
|
+
export type FreshApp = Alxia<Empty, ''>;
|
|
11
11
|
/**
|
|
12
12
|
* What the Vite plugin hands the server, and a test passes to `create`:
|
|
13
13
|
* React Router's server build, its mode, and the client build's folder.
|
|
@@ -31,7 +31,7 @@ export interface ServerOptions<Before extends AnyAlxia, App extends AnyAlxia> {
|
|
|
31
31
|
*/
|
|
32
32
|
readonly beforeAll?: (app: FreshApp) => Before;
|
|
33
33
|
/**
|
|
34
|
-
* The app the pages run behind: its
|
|
34
|
+
* The app the pages run behind: its middlewares, its plugins, its `/api`.
|
|
35
35
|
* Declared after the client's files and before the catch-all. Returns
|
|
36
36
|
* the app: what it builds is what the loaders read through `alxiaOf`.
|
|
37
37
|
*/
|
|
@@ -52,13 +52,15 @@ export interface ServerOptions<Before extends AnyAlxia, App extends AnyAlxia> {
|
|
|
52
52
|
*/
|
|
53
53
|
readonly client?: string | URL | false;
|
|
54
54
|
/**
|
|
55
|
-
* `listen`'s options for `bun build/server/index.js
|
|
55
|
+
* `listen`'s options for `bun build/server/index.js` — `shutdownTimeout`,
|
|
56
|
+
* `signals` among them; a `port` or `hostname` here wins over `PORT` (3000)
|
|
56
57
|
* and `HOST` (`0.0.0.0`) from the environment.
|
|
57
58
|
*/
|
|
58
59
|
readonly listen?: ListenOptions;
|
|
59
60
|
/**
|
|
60
61
|
* Called once the built server listens and its `SIGINT` and `SIGTERM` handlers are in place.
|
|
61
|
-
* Prints `alxia listening on <url>` by default
|
|
62
|
+
* Prints `alxia listening on <url>` by default, and in dev the route
|
|
63
|
+
* table (`alxia({ dev })`). An `onListen` in `listen` wins over it.
|
|
62
64
|
*/
|
|
63
65
|
readonly onListen?: (server: Bun.Server<unknown>) => void;
|
|
64
66
|
}
|
|
@@ -77,9 +79,10 @@ export interface ReactRouterServer<App extends AnyAlxia> {
|
|
|
77
79
|
*/
|
|
78
80
|
create(wiring: ServerWiring): App;
|
|
79
81
|
/**
|
|
80
|
-
* Listens with `app`, on `listen`, `PORT` and `HOST`, and
|
|
81
|
-
* `SIGINT` or `SIGTERM
|
|
82
|
-
*
|
|
82
|
+
* Listens with `app`, on `listen`, `PORT` and `HOST`, and shuts it down
|
|
83
|
+
* gracefully on `SIGINT` or `SIGTERM`, as `@alxia/core`'s `listen` does:
|
|
84
|
+
* the requests in flight finish within `shutdownTimeout`, its `onStop`
|
|
85
|
+
* hooks run, and the process exits. What `bun build/server/index.js` runs.
|
|
83
86
|
*/
|
|
84
87
|
start(app: App): Bun.Server<unknown>;
|
|
85
88
|
}
|
package/dist/server.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACN,KAAK,KAAK,EACV,KAAK,QAAQ,EAEb,KAAK,SAAS,EACd,KAAK,KAAK,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../src/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EACN,KAAK,KAAK,EACV,KAAK,QAAQ,EAEb,KAAK,SAAS,EACd,KAAK,KAAK,EAEV,KAAK,aAAa,EAClB,KAAK,YAAY,EACjB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,qBAAqB,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGvE,gFAAgF;AAChF,MAAM,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AAExC;;;GAGG;AACH,MAAM,WAAW,YAAY;IAC5B;;;OAGG;IACH,QAAQ,CAAC,KAAK,EAAE,WAAW,GAAG,CAAC,MAAM,YAAY,CAAC,WAAW,CAAC,CAAC,CAAC;IAChE,uFAAuF;IACvF,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;IAC7C,kFAAkF;IAClF,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,GAAG,SAAS,CAAC;CAC3C;AAED,MAAM,WAAW,aAAa,CAAC,MAAM,SAAS,QAAQ,EAAE,GAAG,SAAS,QAAQ;IAC3E;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,KAAK,MAAM,CAAC;IAC/C;;;;OAIG;IACH,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,GAAG,CAAC;IAC1C;;;OAGG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,CACzB,GAAG,EAAE,SAAS,CAAC,GAAG,CAAC,EACnB,OAAO,EAAE,qBAAqB,KAC1B,YAAY,CAAC,IAAI,CAAC,CAAC;IACxB,0DAA0D;IAC1D,QAAQ,CAAC,KAAK,CAAC,EAAE,YAAY,CAAC,OAAO,CAAC,CAAC;IACvC,qFAAqF;IACrF,QAAQ,CAAC,IAAI,CAAC,EAAE,aAAa,GAAG,YAAY,CAAC;IAC7C;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,GAAG,GAAG,KAAK,CAAC;IACvC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,CAAC,EAAE,aAAa,CAAC;IAChC;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,CAAC;CAC1D;AAED;;;GAGG;AACH,MAAM,WAAW,iBAAiB,CAAC,GAAG,SAAS,QAAQ;IACtD;;;;;;;OAOG;IACH,MAAM,CAAC,MAAM,EAAE,YAAY,GAAG,GAAG,CAAC;IAClC;;;;;OAKG;IACH,KAAK,CAAC,GAAG,EAAE,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;CACrC;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,YAAY,CAC3B,MAAM,SAAS,QAAQ,GAAG,QAAQ,EAClC,GAAG,SAAS,QAAQ,GAAG,MAAM,EAC5B,OAAO,GAAE,aAAa,CAAC,MAAM,EAAE,GAAG,CAAM,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAkDlE"}
|
package/dist/vite/index.js.map
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
"/**\n * The server build, self-contained: every dependency bundled into\n * `build/server/index.js`, so that running it needs `build/` and Bun, and\n * no `node_modules`. A Docker image's final stage copies `build/` alone.\n */\nimport type { EnvironmentOptions } from 'vite';\nimport { bunEnvironment } from './bun';\n\n/**\n * What the plugin adds to the `ssr` environment under `react-router build`,\n * given its options as the config and the plugins left them:\n * `resolve.noExternal: true`, every package bundled. Never in dev, where\n * Vite's SSR runner loads the packages from `node_modules`.\n *\n * What the app set wins:\n *\n * - `ssr.external: ['sharp']`, or the same on `environments.ssr.resolve`,\n * keeps those packages external, imported from `node_modules` at\n * runtime: Vite reads `external` before `noExternal`. Bun's own modules,\n * `bun` and `bun:*`, and Node's are builtins, external whatever this says.\n * - `ssr.external: true` keeps every package external, Vite's own default:\n * the plugin adds nothing then.\n * - `ssr.noExternal`, a list, is a subset of everything: it changes nothing.\n *\n * React Router's own plugin reads `noExternal: true` and adds no externals\n * of its own; it runs after this one, which is `enforce: 'pre'`.\n */\nexport function bundledEnvironment(\n\toptions: EnvironmentOptions,\n): EnvironmentOptions | undefined {\n\tif (options.resolve?.external === true) return undefined;\n\treturn { resolve: { noExternal: true } };\n}\n\n/**\n * Everything the plugin adds to the `ssr` environment: built for Bun under\n * either command, and self-contained under `build` alone. In dev, Vite's\n * SSR runner loads the packages from `node_modules`.\n */\nexport function ssrEnvironment(\n\toptions: EnvironmentOptions,\n\tcommand: 'build' | 'serve',\n): EnvironmentOptions {\n\tconst added = bunEnvironment(options);\n\tconst bundled = command === 'build' ? bundledEnvironment(options) : undefined;\n\tif (bundled === undefined) return added;\n\treturn { ...added, resolve: { ...added.resolve, ...bundled.resolve } };\n}\n",
|
|
8
8
|
"/**\n * What the plugin reads of Vite's and React Router's config: the server\n * file, the client folder, and the server build's bundler options.\n */\nimport { existsSync } from 'node:fs';\nimport { dirname, isAbsolute, join, relative, resolve } from 'node:path';\nimport type { ResolvedConfig } from 'vite';\nimport { NAME } from './entry';\n\n/** The server build's input, and in dev the module the requests go to. */\nexport const SERVER = 'virtual:alxia-react-router/server';\n/** The same, when there is no server file: `createServer()` as it is. */\nexport const DEFAULT = `${SERVER}-default`;\n\n/** What the plugin reads of React Router's own config. */\nexport interface ReactRouterConfig {\n\treadonly appDirectory: string;\n\treadonly buildDirectory: string;\n\treadonly serverBuildFile: string;\n\treadonly ssr: boolean;\n\treadonly serverBundles?: unknown;\n}\n\n/** React Router's config, which its plugin puts on Vite's. */\nexport function contextOf(config: object): ReactRouterConfig {\n\tconst context = (\n\t\tconfig as {\n\t\t\treadonly __reactRouterPluginContext?: {\n\t\t\t\treadonly reactRouterConfig: ReactRouterConfig;\n\t\t\t};\n\t\t}\n\t).__reactRouterPluginContext;\n\tif (context === undefined) {\n\t\tthrow new Error(\n\t\t\t`${NAME}: React Router's Vite plugin is not in this config. Add reactRouter() from @react-router/dev/vite beside alxia() in vite.config.ts.`,\n\t\t);\n\t}\n\treturn context.reactRouterConfig;\n}\n\n/** React Router's child compiler: a Vite server without its plugin, cached apart. */\nexport function isChildCompiler(config: ResolvedConfig): boolean {\n\treturn (\n\t\t(config as { readonly __reactRouterPluginContext?: unknown })\n\t\t\t.__reactRouterPluginContext === undefined &&\n\t\tconfig.cacheDir.endsWith('.vite-child-compiler')\n\t);\n}\n\n/**\n * The server file: `entry`, which must exist, or `app/server.ts` when it\n * does, or `undefined` for the default server.\n */\nexport function serverFile(\n\tentry: string | undefined,\n\tconfig: ResolvedConfig,\n): string | undefined {\n\tif (entry !== undefined) {\n\t\tconst file = isAbsolute(entry) ? entry : resolve(config.root, entry);\n\t\tif (!existsSync(file)) {\n\t\t\tthrow new Error(\n\t\t\t\t`${NAME}: the entry ${entry} does not exist. Create it, or leave entry out to use app/server.ts, or the default server without it.`,\n\t\t\t);\n\t\t}\n\t\treturn file;\n\t}\n\tconst file = join(contextOf(config).appDirectory, 'server.ts');\n\treturn existsSync(file) ? file : undefined;\n}\n\n/** The built server, absolute: `build/server/index.js`. */\nexport function serverBuildPath(config: ResolvedConfig): string {\n\tconst rr = contextOf(config);\n\tconst outDir = resolve(\n\t\tconfig.root,\n\t\tconfig.environments['ssr']?.build.outDir ??\n\t\t\tjoin(rr.buildDirectory, 'server'),\n\t);\n\treturn join(outDir, rr.serverBuildFile);\n}\n\n/** `build/client`, relative to the built `build/server/index.js`. */\nexport function clientPath(config: ResolvedConfig): string {\n\tconst built = dirname(serverBuildPath(config));\n\tconst path = relative(\n\t\tbuilt,\n\t\tjoin(contextOf(config).buildDirectory, 'client'),\n\t);\n\treturn path.startsWith('.') ? path : `./${path}`;\n}\n\n/**\n * The ssr build's options: one file, `build/server/index.js`, the server\n * and React Router's build together. Rolldown, under Vite 8, names the\n * option otherwise.\n */\nexport function serverBuildOptions(rolldown: boolean): object {\n\treturn rolldown\n\t\t? {\n\t\t\t\trolldownOptions: {\n\t\t\t\t\tinput: SERVER,\n\t\t\t\t\toutput: { codeSplitting: false },\n\t\t\t\t},\n\t\t\t}\n\t\t: {\n\t\t\t\trollupOptions: {\n\t\t\t\t\tinput: SERVER,\n\t\t\t\t\toutput: { inlineDynamicImports: true },\n\t\t\t\t},\n\t\t\t};\n}\n",
|
|
9
9
|
"/**\n * The few lines between Vite's dev and preview servers, which speak\n * `node:http`, and an alxia app, which speaks `Request` and `Response`: no\n * dependency, Bun's own `node:http` and `node:stream` underneath.\n */\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport { Readable } from 'node:stream';\n\n/** What Connect, Vite's middleware stack, adds to a request: the URL before any rewrite. */\ntype ConnectRequest = IncomingMessage & {\n\treadonly originalUrl?: string | undefined;\n};\n\n/** The `Request` a Node request stands for. Aborted when the client goes away. */\nexport function toRequest(req: ConnectRequest, res: ServerResponse): Request {\n\tconst secure = (req.socket as { encrypted?: boolean }).encrypted === true;\n\tconst url = new URL(\n\t\treq.originalUrl ?? req.url ?? '/',\n\t\t`${secure ? 'https' : 'http'}://${req.headers.host ?? 'localhost'}`,\n\t);\n\tconst headers = new Headers();\n\tconst raw = req.rawHeaders;\n\tfor (let i = 0; i + 1 < raw.length; i += 2) {\n\t\tconst name = raw[i] as string;\n\t\t// HTTP/2's pseudo-headers (`:path`, `:method`) are not headers.\n\t\tif (!name.startsWith(':')) headers.append(name, raw[i + 1] as string);\n\t}\n\tconst controller = new AbortController();\n\tres.once('close', () => {\n\t\tif (!res.writableFinished) controller.abort();\n\t});\n\tconst method = req.method ?? 'GET';\n\tconst init: RequestInit & { duplex?: 'half' } = {\n\t\tmethod,\n\t\theaders,\n\t\tsignal: controller.signal,\n\t};\n\tif (method !== 'GET' && method !== 'HEAD') {\n\t\tinit.body = Readable.toWeb(req) as unknown as ReadableStream<Uint8Array>;\n\t\tinit.duplex = 'half';\n\t}\n\treturn new Request(url, init);\n}\n\n/** Writes `response` to `res`, streaming its body chunk by chunk as it comes. */\nexport async function send(\n\tres: ServerResponse,\n\tresponse: Response,\n): Promise<void> {\n\tres.statusCode = response.status;\n\tif (response.statusText !== '') res.statusMessage = response.statusText;\n\tfor (const [name, value] of response.headers) {\n\t\tif (name !== 'set-cookie') res.setHeader(name, value);\n\t}\n\tconst cookies = response.headers.getSetCookie();\n\tif (cookies.length > 0) res.setHeader('set-cookie', cookies);\n\tif (response.body === null) {\n\t\tres.end();\n\t\treturn;\n\t}\n\tres.flushHeaders();\n\tconst reader = response.body.getReader();\n\tconst cancel = () => void reader.cancel().catch(() => {});\n\tres.once('close', cancel);\n\ttry {\n\t\tfor (;;) {\n\t\t\tconst { done, value } = await reader.read();\n\t\t\tif (done) break;\n\t\t\tif (res.destroyed) return;\n\t\t\tif (!res.write(value)) {\n\t\t\t\tawait new Promise<void>((resolve) => {\n\t\t\t\t\tconst go = () => {\n\t\t\t\t\t\tres.off('drain', go);\n\t\t\t\t\t\tres.off('close', go);\n\t\t\t\t\t\tresolve();\n\t\t\t\t\t};\n\t\t\t\t\tres.on('drain', go);\n\t\t\t\t\tres.on('close', go);\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\tres.end();\n\t} finally {\n\t\tres.off('close', cancel);\n\t}\n}\n",
|
|
10
|
-
"/**\n * Under `react-router dev` and `vite preview`: the app's WebSocket routes. Vite's server is a\n * `node:http` one, and an alxia socket is `Bun.serve`'s upgrade, so each\n * upgrade Vite leaves is relayed, bytes as they come, to a `Bun.serve` of\n * the app's own on a loopback port: its
|
|
10
|
+
"/**\n * Under `react-router dev` and `vite preview`: the app's WebSocket routes. Vite's server is a\n * `node:http` one, and an alxia socket is `Bun.serve`'s upgrade, so each\n * upgrade Vite leaves is relayed, bytes as they come, to a `Bun.serve` of\n * the app's own on a loopback port: its middlewares, its validation, its socket\n * handlers, exactly as `listen` runs them.\n */\nimport type { IncomingMessage } from 'node:http';\nimport { connect, type Socket } from 'node:net';\nimport type { DevApp } from './dev';\nimport { NAME } from './entry';\n\n/** The subprotocols of Vite's own socket, the HMR one and its ping: Vite answers them. */\nconst VITE = new Set(['vite-hmr', 'vite-ping']);\n\n/** Whether the upgrade asks for Vite's own socket. */\nexport function isVites(req: Pick<IncomingMessage, 'headers'>): boolean {\n\tconst protocols = req.headers['sec-websocket-protocol'];\n\tif (protocols === undefined) return false;\n\treturn protocols.split(',').some((protocol) => VITE.has(protocol.trim()));\n}\n\n/** One entry of Vite's `server.proxy`, as far as its sockets go. */\ntype ProxyEntry = string | { readonly ws?: boolean; readonly target?: unknown };\n\n/**\n * Whether Vite's `server.proxy` relays this upgrade itself: an entry whose\n * context matches the URL, as Vite matches it (`^…` a RegExp, otherwise a\n * prefix), and that proxies sockets (`ws: true`, or a `ws:`/`wss:` target).\n */\nexport function isProxied(\n\turl: string,\n\tproxy: Readonly<Record<string, ProxyEntry>> | undefined,\n): boolean {\n\tfor (const [context, entry] of Object.entries(proxy ?? {})) {\n\t\tconst matches =\n\t\t\t(context.startsWith('^') && new RegExp(context).test(url)) ||\n\t\t\turl.startsWith(context);\n\t\tif (!matches) continue;\n\t\tconst options = typeof entry === 'string' ? { target: entry } : entry;\n\t\tconst target = String(options.target ?? '');\n\t\tif (\n\t\t\toptions.ws === true ||\n\t\t\ttarget.startsWith('ws:') ||\n\t\t\ttarget.startsWith('wss:')\n\t\t) {\n\t\t\treturn true;\n\t\t}\n\t}\n\treturn false;\n}\n\n/** The request line and headers of `req`, as they came: what the side server reads. */\nexport function head(\n\treq: Pick<IncomingMessage, 'method' | 'url' | 'rawHeaders'>,\n): string {\n\tconst lines = [`${req.method ?? 'GET'} ${req.url ?? '/'} HTTP/1.1`];\n\tconst raw = req.rawHeaders;\n\tfor (let i = 0; i + 1 < raw.length; i += 2) {\n\t\tlines.push(`${raw[i]}: ${raw[i + 1]}`);\n\t}\n\treturn `${lines.join('\\r\\n')}\\r\\n\\r\\n`;\n}\n\n/** The side servers: the current app's, and those an edit retired, until their sockets close. */\nexport interface Sides {\n\tcurrent:\n\t\t| { readonly app: DevApp; readonly side: Bun.Server<unknown> }\n\t\t| undefined;\n\treadonly retired: Set<Bun.Server<unknown>>;\n}\n\n/**\n * The side server of `app`, started on its first upgrade. A new app, an\n * edit's, retires the previous one: no new connection, and the sockets open\n * on it stay, with the handlers they opened with, until they close.\n */\nexport function sideFor(sides: Sides, app: DevApp): Bun.Server<unknown> {\n\tif (sides.current?.app === app) return sides.current.side;\n\tconst side = Bun.serve({\n\t\tport: 0,\n\t\thostname: '127.0.0.1',\n\t\tfetch: (request, bun) => app.fetch(request, bun),\n\t\twebsocket: app.websocket,\n\t} as Bun.Serve.Options<never>) as Bun.Server<unknown>;\n\tconst old = sides.current?.side;\n\tif (old !== undefined) {\n\t\tsides.retired.add(old);\n\t\tvoid old.stop().then(() => sides.retired.delete(old));\n\t}\n\tsides.current = { app, side };\n\treturn side;\n}\n\n/** Stops every side server, open sockets and all: Vite's server closed. */\nexport function closeAll(sides: Sides): void {\n\tfor (const side of [...sides.retired, sides.current?.side]) {\n\t\tvoid side?.stop(true);\n\t}\n\tsides.current = undefined;\n\tsides.retired.clear();\n}\n\n/** Relays the upgrade on `socket` to the side server on `port`, both ways. */\nfunction relay(\n\treq: IncomingMessage,\n\tsocket: Socket,\n\tbytes: Buffer,\n\tport: number,\n): void {\n\tconst upstream = connect(port, '127.0.0.1', () => {\n\t\tupstream.write(head(req));\n\t\tif (bytes.length > 0) upstream.write(bytes);\n\t\tupstream.pipe(socket);\n\t\tsocket.pipe(upstream);\n\t});\n\tupstream.on('error', () => socket.destroy());\n\tupstream.on('close', () => socket.destroy());\n\tsocket.on('close', () => upstream.destroy());\n}\n\n/** What the relay listens to on Vite's HTTP server, HTTP/1 or HTTP/2 alike. */\ninterface Upgrades {\n\ton(\n\t\tevent: 'upgrade',\n\t\tlistener: (req: IncomingMessage, socket: Socket, bytes: Buffer) => void,\n\t): unknown;\n\tonce(event: 'close', listener: () => void): unknown;\n}\n\n/** What the relay needs of the server it listens on: Vite's dev server or its preview. */\nexport interface Bridge {\n\t/** Vite's `server.proxy` (or `preview.proxy`): the upgrades it relays are its own. */\n\treadonly proxy: Readonly<Record<string, ProxyEntry>> | undefined;\n\t/** The app, as it is now. */\n\treadonly load: () => Promise<DevApp>;\n\t/** Where an upgrade that failed is printed: Vite's logger. */\n\treadonly logger: { error(message: string): void };\n\t/** Maps an error's stack to the source, as Vite's `ssrFixStacktrace` does. */\n\treadonly fix?: (error: Error) => void;\n}\n\n/** An upgrade the app could not take: reported, and a 500 to the client. */\nfunction refuse(bridge: Bridge, socket: Socket, error: unknown): void {\n\tif (error instanceof Error) bridge.fix?.(error);\n\tbridge.logger.error(\n\t\t`${NAME}: a WebSocket upgrade failed: ${error instanceof Error ? (error.stack ?? error.message) : String(error)}`,\n\t);\n\tif (socket.writable) {\n\t\tsocket.end(\n\t\t\t'HTTP/1.1 500 Internal Server Error\\r\\nConnection: close\\r\\nContent-Length: 0\\r\\n\\r\\n',\n\t\t);\n\t}\n}\n\n/**\n * Relays the app's upgrades on Vite's HTTP server to a side server of the\n * app. Vite's own socket and the sockets its proxy relays are left to\n * Vite. Without an HTTP server (Vite's middleware mode), there is nothing\n * to listen on.\n */\nexport function bridgeSockets(http: Upgrades | null, bridge: Bridge): void {\n\tif (http === null) return;\n\tconst sides: Sides = { current: undefined, retired: new Set() };\n\thttp.on('upgrade', (req: IncomingMessage, socket: Socket, bytes: Buffer) => {\n\t\tif (isVites(req) || isProxied(req.url ?? '/', bridge.proxy)) return;\n\t\tsocket.on('error', () => socket.destroy());\n\t\tbridge\n\t\t\t.load()\n\t\t\t.then((app) => {\n\t\t\t\tif (socket.destroyed) return;\n\t\t\t\trelay(req, socket, bytes, sideFor(sides, app).port as number);\n\t\t\t})\n\t\t\t.catch((error: unknown) => refuse(bridge, socket, error));\n\t});\n\thttp.once('close', () => closeAll(sides));\n}\n",
|
|
11
11
|
"/**\n * Under `react-router dev`: a request Vite left, answered by the server,\n * loaded through the ssr environment's module runner.\n */\nimport type { ViteDevServer } from 'vite';\nimport { DEFAULT, SERVER, serverFile } from './config';\nimport { NAME } from './entry';\nimport { send, toRequest } from './node';\nimport { bridgeSockets } from './socket';\n\n/** What the dev server module exports: the alxia app, as `server.create` made it. */\nexport interface DevApp {\n\tfetch(request: Request, server?: Bun.Server<unknown>): Promise<Response>;\n\treadonly websocket: Bun.WebSocketHandler<never>;\n}\n\n/**\n * The app, as the server file is now: the runner keeps the module until an\n * edit invalidates it, so an edit is a new app.\n */\nexport async function loadApp(\n\tserver: ViteDevServer,\n\tentry: string | undefined,\n): Promise<DevApp> {\n\t// Duck-typed rather than Vite's `isRunnableDevEnvironment`: the app's\n\t// Vite may be another copy than the one this package would import.\n\tconst runner = (\n\t\tserver.environments.ssr as\n\t\t\t| { readonly runner?: { readonly import?: unknown } }\n\t\t\t| undefined\n\t)?.runner;\n\tif (typeof runner?.import !== 'function') {\n\t\tthrow new Error(\n\t\t\t`${NAME}: Vite's ssr environment does not run modules in this process, so the server cannot be loaded.`,\n\t\t);\n\t}\n\t// Chosen on each request: a server file created or deleted while the\n\t// dev server runs is used from the next one.\n\tconst id = serverFile(entry, server.config) === undefined ? DEFAULT : SERVER;\n\tconst module = (await (runner.import as (id: string) => Promise<unknown>)(\n\t\tid,\n\t)) as { readonly default: DevApp };\n\treturn module.default;\n}\n\nexport async function serveFromEntry(\n\tserver: ViteDevServer,\n\tentry: string | undefined,\n\treq: Parameters<typeof toRequest>[0],\n\tres: Parameters<typeof toRequest>[1],\n): Promise<void> {\n\tconst app = await loadApp(server, entry);\n\tawait send(res, await app.fetch(toRequest(req, res)));\n}\n\n/**\n * `react-router dev`: the app's sockets on Vite's server now, and, returned\n * for after Vite's own middlewares, every request Vite leaves to the app.\n */\nexport function serveDev(\n\tserver: ViteDevServer,\n\tentry: string | undefined,\n): () => void {\n\tbridgeSockets(server.httpServer, {\n\t\tproxy: server.config.server.proxy,\n\t\tload: () => loadApp(server, entry),\n\t\tlogger: server.config.logger,\n\t\tfix: (error) => server.ssrFixStacktrace(error),\n\t});\n\treturn () => {\n\t\tserver.middlewares.use((req, res, next) => {\n\t\t\tserveFromEntry(server, entry, req, res).catch((error: unknown) => {\n\t\t\t\tif (error instanceof Error) server.ssrFixStacktrace(error);\n\t\t\t\tnext(error);\n\t\t\t});\n\t\t});\n\t};\n}\n",
|
|
12
|
-
"/**\n * Under `vite preview`, and React Router's prerendering, which runs on it:\n * every request goes to the built server, `build/server/index.js`'s\n * default export, as `bun build/server/index.js` would answer it — its\n *
|
|
12
|
+
"/**\n * Under `vite preview`, and React Router's prerendering, which runs on it:\n * every request goes to the built server, `build/server/index.js`'s\n * default export, as `bun build/server/index.js` would answer it — its\n * middlewares, its `/api`, the client's files and the pages.\n */\nimport { existsSync } from 'node:fs';\nimport { relative } from 'node:path';\nimport { pathToFileURL } from 'node:url';\nimport type { PreviewServer } from 'vite';\nimport { serverBuildPath } from './config';\nimport type { DevApp } from './dev';\nimport { NAME } from './entry';\nimport { send, toRequest } from './node';\nimport { bridgeSockets } from './socket';\n\n/** What the built server's default export is: the alxia app. */\ninterface Fetcher {\n\tfetch(request: Request): Response | Promise<Response>;\n}\n\n/** The built server's app, or an error saying why there is none. */\nasync function load(file: string, label: string): Promise<Fetcher> {\n\tif (!existsSync(file)) {\n\t\tthrow new Error(\n\t\t\t`${NAME}: ${label} does not exist. Run react-router build before vite preview.`,\n\t\t);\n\t}\n\tconst module = (await import(pathToFileURL(file).href)) as {\n\t\treadonly default?: Partial<Fetcher>;\n\t};\n\tif (typeof module.default?.fetch !== 'function') {\n\t\tthrow new Error(\n\t\t\t`${NAME}: ${label} is not alxia's server: its default export has no fetch. Build it with alxia() in vite.config.ts's plugins, then run vite preview again.`,\n\t\t);\n\t}\n\treturn module.default as Fetcher;\n}\n\n/**\n * Hands every request to the built server, before Vite's own files: the\n * app serves `build/client` itself, with its middlewares and cache headers. Its\n * WebSocket routes connect too, relayed as under `react-router dev`.\n */\nexport function servePreview(server: PreviewServer): void {\n\tconst file = serverBuildPath(server.config);\n\tconst label = relative(server.config.root, file);\n\t// Loaded on the first request, as `bun build/server/index.js` would be\n\t// at startup; a failed load is tried again on the next, after a build.\n\tlet app: Promise<Fetcher> | undefined;\n\tconst current = (): Promise<Fetcher> => {\n\t\tapp ??= load(file, label);\n\t\treturn app;\n\t};\n\tbridgeSockets(server.httpServer, {\n\t\tproxy: server.config.preview.proxy,\n\t\t// The built server's default export is the alxia app, `websocket` and all.\n\t\tload: () =>\n\t\t\tcurrent().catch((error: unknown) => {\n\t\t\t\tapp = undefined;\n\t\t\t\tthrow error;\n\t\t\t}) as Promise<DevApp>,\n\t\tlogger: server.config.logger,\n\t});\n\tserver.middlewares.use((req, res, next) => {\n\t\tcurrent().then(\n\t\t\tasync (loaded) => {\n\t\t\t\ttry {\n\t\t\t\t\tawait send(res, await loaded.fetch(toRequest(req, res)));\n\t\t\t\t} catch (error) {\n\t\t\t\t\t// Mid-body, the response has started: end it rather than answer twice.\n\t\t\t\t\tif (res.headersSent) res.destroy(error as Error);\n\t\t\t\t\telse next(error);\n\t\t\t\t}\n\t\t\t},\n\t\t\t(error: unknown) => {\n\t\t\t\tapp = undefined;\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\tserver.config.logger.error(message);\n\t\t\t\tres.statusCode = 500;\n\t\t\t\tres.setHeader('content-type', 'text/plain; charset=utf-8');\n\t\t\t\tres.end(message);\n\t\t\t},\n\t\t);\n\t});\n}\n",
|
|
13
13
|
"import { NAME } from './entry';\n\n/**\n * Refuses, with what to do, a dev or preview server running on Node. The\n * React Router CLI's `#!/usr/bin/env node` runs it on Node whenever a node\n * is installed, even from `bun run dev`, and alxia's server then fails on\n * its first request with `ReferenceError: Bun is not defined`.\n */\nexport function requireBun(\n\tcommand: string,\n\thint = `bun --bun ${command}`,\n\tonBun = (globalThis as { Bun?: unknown }).Bun !== undefined,\n): void {\n\tif (onBun) return;\n\tthrow new Error(\n\t\t`${NAME}: ${command} is running on Node, and alxia's server runs on Bun. Add a bunfig.toml beside package.json with \"[run]\" and \"bun = true\", so bun run starts it on Bun, or run it as ${hint}.`,\n\t);\n}\n"
|
|
14
14
|
],
|
|
15
15
|
"mappings": ";;;;;;;AAKA,qBAAS;;;ACAT;AAIA,IAAM,gBAAgB;AAOtB,IAAM,gBAA8C;AAAA,EACnD,GAAG,eAAe,OAAO,CAAC,OAAO,CAAC,GAAG,SAAS,GAAG,CAAC;AAAA,EAClD;AAAA,EACA;AACD;AAOA,IAAM,kBAAkB,CAAC,UAAU,QAAQ,wBAAwB;AACnE,IAAM,2BAA2B,CAAC,QAAQ,aAAa;AAGvD,IAAM,eAA6C,CAAC,eAAe,OAAO;AAO1E,SAAS,MAAiC,CACzC,SACA,UACA,QACM;AAAA,EACN,MAAM,OAAO,WAAW;AAAA,EACxB,MAAM,MAAM,CAAC,SACZ,KAAK,KAAK,CAAC,UACV,OAAO,SAAS,WACb,UAAU,OACV,iBAAiB,UAAU,MAAM,WAAW,KAAK,MACrD;AAAA,EACD,OAAO;AAAA,IACN,GAAI,YAAY,YAAY,WAAW,CAAC;AAAA,IACxC,GAAG,OAAO,OAAO,CAAC,SAAS,CAAC,IAAI,IAAI,CAAC;AAAA,EACtC;AAAA;AAqBM,SAAS,cAAc,CAC7B,SACqB;AAAA,EACrB,MAAM,UAAU,QAAQ,WAAW,CAAC;AAAA,EACpC,MAAM,QAA4B;AAAA,IACjC,SAAS;AAAA,MACR,YAAY,OAAO,QAAQ,YAAY,iBAAiB,CAAC,aAAa,CAAC;AAAA,MACvE,oBAAoB,OACnB,QAAQ,oBACR,0BACA,CAAC,aAAa,CACf;AAAA,MACA,UAAU,OAAO,QAAQ,UAAU,eAAe,YAAY;AAAA,IAC/D;AAAA,EACD;AAAA,EACA,IAAI,QAAQ,OAAO,WAAW,WAAW;AAAA,IACxC,MAAM,QAAQ,EAAE,QAAQ,SAAS;AAAA,EAClC;AAAA,EACA,OAAO;AAAA;;;ACjED,SAAS,kBAAkB,CACjC,SACiC;AAAA,EACjC,IAAI,QAAQ,SAAS,aAAa;AAAA,IAAM;AAAA,EACxC,OAAO,EAAE,SAAS,EAAE,YAAY,KAAK,EAAE;AAAA;AAQjC,SAAS,cAAc,CAC7B,SACA,SACqB;AAAA,EACrB,MAAM,QAAQ,eAAe,OAAO;AAAA,EACpC,MAAM,UAAU,YAAY,UAAU,mBAAmB,OAAO,IAAI;AAAA,EACpE,IAAI,YAAY;AAAA,IAAW,OAAO;AAAA,EAClC,OAAO,KAAK,OAAO,SAAS,KAAK,MAAM,YAAY,QAAQ,QAAQ,EAAE;AAAA;;;AC1CtE;AACA;AAKO,IAAM,SAAS;AAEf,IAAM,UAAU,GAAG;AAYnB,SAAS,SAAS,CAAC,QAAmC;AAAA,EAC5D,MAAM,UACL,OAKC;AAAA,EACF,IAAI,YAAY,WAAW;AAAA,IAC1B,MAAM,IAAI,MACT,GAAG,yIACJ;AAAA,EACD;AAAA,EACA,OAAO,QAAQ;AAAA;AAIT,SAAS,eAAe,CAAC,QAAiC;AAAA,EAChE,OACE,OACC,+BAA+B,aACjC,OAAO,SAAS,SAAS,sBAAsB;AAAA;AAQ1C,SAAS,UAAU,CACzB,OACA,QACqB;AAAA,EACrB,IAAI,UAAU,WAAW;AAAA,IACxB,MAAM,OAAO,WAAW,KAAK,IAAI,QAAQ,QAAQ,OAAO,MAAM,KAAK;AAAA,IACnE,IAAI,CAAC,WAAW,IAAI,GAAG;AAAA,MACtB,MAAM,IAAI,MACT,GAAG,mBAAmB,6GACvB;AAAA,IACD;AAAA,IACA,OAAO;AAAA,EACR;AAAA,EACA,MAAM,OAAO,KAAK,UAAU,MAAM,EAAE,cAAc,WAAW;AAAA,EAC7D,OAAO,WAAW,IAAI,IAAI,OAAO;AAAA;AAI3B,SAAS,eAAe,CAAC,QAAgC;AAAA,EAC/D,MAAM,KAAK,UAAU,MAAM;AAAA,EAC3B,MAAM,SAAS,QACd,OAAO,MACP,OAAO,aAAa,QAAQ,MAAM,UACjC,KAAK,GAAG,gBAAgB,QAAQ,CAClC;AAAA,EACA,OAAO,KAAK,QAAQ,GAAG,eAAe;AAAA;AAIhC,SAAS,UAAU,CAAC,QAAgC;AAAA,EAC1D,MAAM,QAAQ,QAAQ,gBAAgB,MAAM,CAAC;AAAA,EAC7C,MAAM,OAAO,SACZ,OACA,KAAK,UAAU,MAAM,EAAE,gBAAgB,QAAQ,CAChD;AAAA,EACA,OAAO,KAAK,WAAW,GAAG,IAAI,OAAO,KAAK;AAAA;AAQpC,SAAS,kBAAkB,CAAC,UAA2B;AAAA,EAC7D,OAAO,WACJ;AAAA,IACA,iBAAiB;AAAA,MAChB,OAAO;AAAA,MACP,QAAQ,EAAE,eAAe,MAAM;AAAA,IAChC;AAAA,EACD,IACC;AAAA,IACA,eAAe;AAAA,MACd,OAAO;AAAA,MACP,QAAQ,EAAE,sBAAsB,KAAK;AAAA,IACtC;AAAA,EACD;AAAA;;;ACvGH;AAQO,SAAS,SAAS,CAAC,KAAqB,KAA8B;AAAA,EAC5E,MAAM,SAAU,IAAI,OAAmC,cAAc;AAAA,EACrE,MAAM,MAAM,IAAI,IACf,IAAI,eAAe,IAAI,OAAO,KAC9B,GAAG,SAAS,UAAU,YAAY,IAAI,QAAQ,QAAQ,aACvD;AAAA,EACA,MAAM,UAAU,IAAI;AAAA,EACpB,MAAM,MAAM,IAAI;AAAA,EAChB,SAAS,IAAI,EAAG,IAAI,IAAI,IAAI,QAAQ,KAAK,GAAG;AAAA,IAC3C,MAAM,OAAO,IAAI;AAAA,IAEjB,IAAI,CAAC,KAAK,WAAW,GAAG;AAAA,MAAG,QAAQ,OAAO,MAAM,IAAI,IAAI,EAAY;AAAA,EACrE;AAAA,EACA,MAAM,aAAa,IAAI;AAAA,EACvB,IAAI,KAAK,SAAS,MAAM;AAAA,IACvB,IAAI,CAAC,IAAI;AAAA,MAAkB,WAAW,MAAM;AAAA,GAC5C;AAAA,EACD,MAAM,SAAS,IAAI,UAAU;AAAA,EAC7B,MAAM,OAA0C;AAAA,IAC/C;AAAA,IACA;AAAA,IACA,QAAQ,WAAW;AAAA,EACpB;AAAA,EACA,IAAI,WAAW,SAAS,WAAW,QAAQ;AAAA,IAC1C,KAAK,OAAO,SAAS,MAAM,GAAG;AAAA,IAC9B,KAAK,SAAS;AAAA,EACf;AAAA,EACA,OAAO,IAAI,QAAQ,KAAK,IAAI;AAAA;AAI7B,eAAsB,IAAI,CACzB,KACA,UACgB;AAAA,EAChB,IAAI,aAAa,SAAS;AAAA,EAC1B,IAAI,SAAS,eAAe;AAAA,IAAI,IAAI,gBAAgB,SAAS;AAAA,EAC7D,YAAY,MAAM,UAAU,SAAS,SAAS;AAAA,IAC7C,IAAI,SAAS;AAAA,MAAc,IAAI,UAAU,MAAM,KAAK;AAAA,EACrD;AAAA,EACA,MAAM,UAAU,SAAS,QAAQ,aAAa;AAAA,EAC9C,IAAI,QAAQ,SAAS;AAAA,IAAG,IAAI,UAAU,cAAc,OAAO;AAAA,EAC3D,IAAI,SAAS,SAAS,MAAM;AAAA,IAC3B,IAAI,IAAI;AAAA,IACR;AAAA,EACD;AAAA,EACA,IAAI,aAAa;AAAA,EACjB,MAAM,SAAS,SAAS,KAAK,UAAU;AAAA,EACvC,MAAM,SAAS,MAAM,KAAK,OAAO,OAAO,EAAE,MAAM,MAAM,EAAE;AAAA,EACxD,IAAI,KAAK,SAAS,MAAM;AAAA,EACxB,IAAI;AAAA,IACH,UAAS;AAAA,MACR,QAAQ,MAAM,UAAU,MAAM,OAAO,KAAK;AAAA,MAC1C,IAAI;AAAA,QAAM;AAAA,MACV,IAAI,IAAI;AAAA,QAAW;AAAA,MACnB,IAAI,CAAC,IAAI,MAAM,KAAK,GAAG;AAAA,QACtB,MAAM,IAAI,QAAc,CAAC,YAAY;AAAA,UACpC,MAAM,KAAK,MAAM;AAAA,YAChB,IAAI,IAAI,SAAS,EAAE;AAAA,YACnB,IAAI,IAAI,SAAS,EAAE;AAAA,YACnB,QAAQ;AAAA;AAAA,UAET,IAAI,GAAG,SAAS,EAAE;AAAA,UAClB,IAAI,GAAG,SAAS,EAAE;AAAA,SAClB;AAAA,MACF;AAAA,IACD;AAAA,IACA,IAAI,IAAI;AAAA,YACP;AAAA,IACD,IAAI,IAAI,SAAS,MAAM;AAAA;AAAA;;;AC3EzB;AAKA,IAAM,OAAO,IAAI,IAAI,CAAC,YAAY,WAAW,CAAC;AAGvC,SAAS,OAAO,CAAC,KAAgD;AAAA,EACvE,MAAM,YAAY,IAAI,QAAQ;AAAA,EAC9B,IAAI,cAAc;AAAA,IAAW,OAAO;AAAA,EACpC,OAAO,UAAU,MAAM,GAAG,EAAE,KAAK,CAAC,aAAa,KAAK,IAAI,SAAS,KAAK,CAAC,CAAC;AAAA;AAWlE,SAAS,SAAS,CACxB,KACA,OACU;AAAA,EACV,YAAY,SAAS,UAAU,OAAO,QAAQ,SAAS,CAAC,CAAC,GAAG;AAAA,IAC3D,MAAM,UACJ,QAAQ,WAAW,GAAG,KAAK,IAAI,OAAO,OAAO,EAAE,KAAK,GAAG,KACxD,IAAI,WAAW,OAAO;AAAA,IACvB,IAAI,CAAC;AAAA,MAAS;AAAA,IACd,MAAM,UAAU,OAAO,UAAU,WAAW,EAAE,QAAQ,MAAM,IAAI;AAAA,IAChE,MAAM,SAAS,OAAO,QAAQ,UAAU,EAAE;AAAA,IAC1C,IACC,QAAQ,OAAO,QACf,OAAO,WAAW,KAAK,KACvB,OAAO,WAAW,MAAM,GACvB;AAAA,MACD,OAAO;AAAA,IACR;AAAA,EACD;AAAA,EACA,OAAO;AAAA;AAID,SAAS,IAAI,CACnB,KACS;AAAA,EACT,MAAM,QAAQ,CAAC,GAAG,IAAI,UAAU,SAAS,IAAI,OAAO,cAAc;AAAA,EAClE,MAAM,MAAM,IAAI;AAAA,EAChB,SAAS,IAAI,EAAG,IAAI,IAAI,IAAI,QAAQ,KAAK,GAAG;AAAA,IAC3C,MAAM,KAAK,GAAG,IAAI,OAAO,IAAI,IAAI,IAAI;AAAA,EACtC;AAAA,EACA,OAAO,GAAG,MAAM,KAAK;AAAA,CAAM;AAAA;AAAA;AAAA;AAgBrB,SAAS,OAAO,CAAC,OAAc,KAAkC;AAAA,EACvE,IAAI,MAAM,SAAS,QAAQ;AAAA,IAAK,OAAO,MAAM,QAAQ;AAAA,EACrD,MAAM,OAAO,IAAI,MAAM;AAAA,IACtB,MAAM;AAAA,IACN,UAAU;AAAA,IACV,OAAO,CAAC,SAAS,QAAQ,IAAI,MAAM,SAAS,GAAG;AAAA,IAC/C,WAAW,IAAI;AAAA,EAChB,CAA6B;AAAA,EAC7B,MAAM,MAAM,MAAM,SAAS;AAAA,EAC3B,IAAI,QAAQ,WAAW;AAAA,IACtB,MAAM,QAAQ,IAAI,GAAG;AAAA,IAChB,IAAI,KAAK,EAAE,KAAK,MAAM,MAAM,QAAQ,OAAO,GAAG,CAAC;AAAA,EACrD;AAAA,EACA,MAAM,UAAU,EAAE,KAAK,KAAK;AAAA,EAC5B,OAAO;AAAA;AAID,SAAS,QAAQ,CAAC,OAAoB;AAAA,EAC5C,WAAW,QAAQ,CAAC,GAAG,MAAM,SAAS,MAAM,SAAS,IAAI,GAAG;AAAA,IACtD,MAAM,KAAK,IAAI;AAAA,EACrB;AAAA,EACA,MAAM,UAAU;AAAA,EAChB,MAAM,QAAQ,MAAM;AAAA;AAIrB,SAAS,KAAK,CACb,KACA,QACA,OACA,MACO;AAAA,EACP,MAAM,WAAW,QAAQ,MAAM,aAAa,MAAM;AAAA,IACjD,SAAS,MAAM,KAAK,GAAG,CAAC;AAAA,IACxB,IAAI,MAAM,SAAS;AAAA,MAAG,SAAS,MAAM,KAAK;AAAA,IAC1C,SAAS,KAAK,MAAM;AAAA,IACpB,OAAO,KAAK,QAAQ;AAAA,GACpB;AAAA,EACD,SAAS,GAAG,SAAS,MAAM,OAAO,QAAQ,CAAC;AAAA,EAC3C,SAAS,GAAG,SAAS,MAAM,OAAO,QAAQ,CAAC;AAAA,EAC3C,OAAO,GAAG,SAAS,MAAM,SAAS,QAAQ,CAAC;AAAA;AAyB5C,SAAS,MAAM,CAAC,QAAgB,QAAgB,OAAsB;AAAA,EACrE,IAAI,iBAAiB;AAAA,IAAO,OAAO,MAAM,KAAK;AAAA,EAC9C,OAAO,OAAO,MACb,GAAG,qCAAqC,iBAAiB,QAAS,MAAM,SAAS,MAAM,UAAW,OAAO,KAAK,GAC/G;AAAA,EACA,IAAI,OAAO,UAAU;AAAA,IACpB,OAAO,IACN;AAAA;AAAA;AAAA;AAAA,CACD;AAAA,EACD;AAAA;AASM,SAAS,aAAa,CAAC,MAAuB,QAAsB;AAAA,EAC1E,IAAI,SAAS;AAAA,IAAM;AAAA,EACnB,MAAM,QAAe,EAAE,SAAS,WAAW,SAAS,IAAI,IAAM;AAAA,EAC9D,KAAK,GAAG,WAAW,CAAC,KAAsB,QAAgB,UAAkB;AAAA,IAC3E,IAAI,QAAQ,GAAG,KAAK,UAAU,IAAI,OAAO,KAAK,OAAO,KAAK;AAAA,MAAG;AAAA,IAC7D,OAAO,GAAG,SAAS,MAAM,OAAO,QAAQ,CAAC;AAAA,IACzC,OACE,KAAK,EACL,KAAK,CAAC,QAAQ;AAAA,MACd,IAAI,OAAO;AAAA,QAAW;AAAA,MACtB,MAAM,KAAK,QAAQ,OAAO,QAAQ,OAAO,GAAG,EAAE,IAAc;AAAA,KAC5D,EACA,MAAM,CAAC,UAAmB,OAAO,QAAQ,QAAQ,KAAK,CAAC;AAAA,GACzD;AAAA,EACD,KAAK,KAAK,SAAS,MAAM,SAAS,KAAK,CAAC;AAAA;;;AC3JzC,eAAsB,OAAO,CAC5B,QACA,OACkB;AAAA,EAGlB,MAAM,SACL,OAAO,aAAa,KAGlB;AAAA,EACH,IAAI,OAAO,QAAQ,WAAW,YAAY;AAAA,IACzC,MAAM,IAAI,MACT,GAAG,oGACJ;AAAA,EACD;AAAA,EAGA,MAAM,KAAK,WAAW,OAAO,OAAO,MAAM,MAAM,YAAY,UAAU;AAAA,EACtE,MAAM,SAAU,MAAO,OAAO,OAC7B,EACD;AAAA,EACA,OAAO,OAAO;AAAA;AAGf,eAAsB,cAAc,CACnC,QACA,OACA,KACA,KACgB;AAAA,EAChB,MAAM,MAAM,MAAM,QAAQ,QAAQ,KAAK;AAAA,EACvC,MAAM,KAAK,KAAK,MAAM,IAAI,MAAM,UAAU,KAAK,GAAG,CAAC,CAAC;AAAA;AAO9C,SAAS,QAAQ,CACvB,QACA,OACa;AAAA,EACb,cAAc,OAAO,YAAY;AAAA,IAChC,OAAO,OAAO,OAAO,OAAO;AAAA,IAC5B,MAAM,MAAM,QAAQ,QAAQ,KAAK;AAAA,IACjC,QAAQ,OAAO,OAAO;AAAA,IACtB,KAAK,CAAC,UAAU,OAAO,iBAAiB,KAAK;AAAA,EAC9C,CAAC;AAAA,EACD,OAAO,MAAM;AAAA,IACZ,OAAO,YAAY,IAAI,CAAC,KAAK,KAAK,SAAS;AAAA,MAC1C,eAAe,QAAQ,OAAO,KAAK,GAAG,EAAE,MAAM,CAAC,UAAmB;AAAA,QACjE,IAAI,iBAAiB;AAAA,UAAO,OAAO,iBAAiB,KAAK;AAAA,QACzD,KAAK,KAAK;AAAA,OACV;AAAA,KACD;AAAA;AAAA;;;ACrEH,uBAAS;AACT,qBAAS;AACT;AAcA,eAAe,IAAI,CAAC,MAAc,OAAiC;AAAA,EAClE,IAAI,CAAC,YAAW,IAAI,GAAG;AAAA,IACtB,MAAM,IAAI,MACT,GAAG,SAAS,mEACb;AAAA,EACD;AAAA,EACA,MAAM,SAAU,MAAa,qBAAc,IAAI,EAAE;AAAA,EAGjD,IAAI,OAAO,OAAO,SAAS,UAAU,YAAY;AAAA,IAChD,MAAM,IAAI,MACT,GAAG,SAAS,+IACb;AAAA,EACD;AAAA,EACA,OAAO,OAAO;AAAA;AAQR,SAAS,YAAY,CAAC,QAA6B;AAAA,EACzD,MAAM,OAAO,gBAAgB,OAAO,MAAM;AAAA,EAC1C,MAAM,QAAQ,UAAS,OAAO,OAAO,MAAM,IAAI;AAAA,EAG/C,IAAI;AAAA,EACJ,MAAM,UAAU,MAAwB;AAAA,IACvC,QAAQ,KAAK,MAAM,KAAK;AAAA,IACxB,OAAO;AAAA;AAAA,EAER,cAAc,OAAO,YAAY;AAAA,IAChC,OAAO,OAAO,OAAO,QAAQ;AAAA,IAE7B,MAAM,MACL,QAAQ,EAAE,MAAM,CAAC,UAAmB;AAAA,MACnC,MAAM;AAAA,MACN,MAAM;AAAA,KACN;AAAA,IACF,QAAQ,OAAO,OAAO;AAAA,EACvB,CAAC;AAAA,EACD,OAAO,YAAY,IAAI,CAAC,KAAK,KAAK,SAAS;AAAA,IAC1C,QAAQ,EAAE,KACT,OAAO,WAAW;AAAA,MACjB,IAAI;AAAA,QACH,MAAM,KAAK,KAAK,MAAM,OAAO,MAAM,UAAU,KAAK,GAAG,CAAC,CAAC;AAAA,QACtD,OAAO,OAAO;AAAA,QAEf,IAAI,IAAI;AAAA,UAAa,IAAI,QAAQ,KAAc;AAAA,QAC1C;AAAA,eAAK,KAAK;AAAA;AAAA,OAGjB,CAAC,UAAmB;AAAA,MACnB,MAAM;AAAA,MACN,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AAAA,MACrE,OAAO,OAAO,OAAO,MAAM,OAAO;AAAA,MAClC,IAAI,aAAa;AAAA,MACjB,IAAI,UAAU,gBAAgB,2BAA2B;AAAA,MACzD,IAAI,IAAI,OAAO;AAAA,KAEjB;AAAA,GACA;AAAA;;;AC5EK,SAAS,UAAU,CACzB,SACA,OAAO,aAAa,WACpB,QAAS,WAAiC,QAAQ,WAC3C;AAAA,EACP,IAAI;AAAA,IAAO;AAAA,EACX,MAAM,IAAI,MACT,GAAG,SAAS,8KAA8K,OAC3L;AAAA;;;ARkBD,IAAM,kBAAkB,OAAK;AAC7B,IAAM,mBAAmB,OAAK;AA8BvB,SAAS,KAAK,CAAC,UAAwB,CAAC,GAAW;AAAA,EACzD,IAAI;AAAA,EACJ,IAAI,UAAU;AAAA,EAEd,OAAO;AAAA,IACN,MAAM;AAAA,IAIN,SAAS;AAAA,IACT,MAAM,CAAC,SAAS,KAAK;AAAA,MACpB,IAAI,IAAI,YAAY;AAAA,QAAS;AAAA,MAE7B,MAAM,OAAO,KAAK;AAAA,MAClB,MAAM,UAAU,mBAAmB,KAAK,oBAAoB,SAAS;AAAA,MACrE,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,OAAO,QAAiB,EAAE,EAAE;AAAA;AAAA,IAE7D,iBAAiB,CAAC,MAAM,SAAS,KAAK;AAAA,MAIrC,IAAI,SAAS,SAAS,IAAI,yBAAyB;AAAA,QAAM;AAAA,MACzD,OAAO,eAAe,SAAS,IAAI,OAAO;AAAA;AAAA,IAE3C,cAAc,CAAC,UAAU;AAAA,MACxB,SAAS;AAAA,MAGT,IAAI,gBAAgB,QAAQ,GAAG;AAAA,QAC9B,UAAU;AAAA,QACV;AAAA,MACD;AAAA,MACA,MAAM,KAAK,UAAU,QAAQ;AAAA,MAE7B,UAAU,GAAG;AAAA,MACb,IAAI,WAAW,GAAG,kBAAkB,WAAW;AAAA,QAC9C,MAAM,IAAI,MACT,GAAG,4IACJ;AAAA,MACD;AAAA;AAAA,IAED,SAAS,CAAC,IAAI;AAAA,MACb,IAAI,OAAO;AAAA,QAAQ,OAAO;AAAA,MAC1B,IAAI,OAAO;AAAA,QAAS,OAAO;AAAA,MAC3B;AAAA;AAAA,IAED,IAAI,CAAC,IAAI;AAAA,MACR,IAAI,OAAO,mBAAmB,OAAO;AAAA,QAAkB;AAAA,MACvD,IAAI,WAAW;AAAA,QAAW;AAAA,MAG1B,IAAI,CAAC;AAAA,QAAS,OAAO;AAAA,MACrB,MAAM,MAAM,OAAO,YAAY;AAAA,MAC/B,MAAM,OACL,OAAO,mBAAmB,YAAY,WAAW,QAAQ,OAAO,MAAM;AAAA,MACvE,OAAO,YAAY;AAAA,QAClB;AAAA,QACA,OAAO,SAAS,YAAY,KAAK,UAAS,OAAO,MAAM,IAAI;AAAA,QAC3D;AAAA,QACA,QAAQ,MAAM,YAAY,WAAW,MAAM;AAAA,MAC5C,CAAC;AAAA;AAAA,IAEF,eAAe,CAAC,QAAQ;AAAA,MACvB,IAAI,CAAC;AAAA,QAAS;AAAA,MACd,WAAW,kBAAkB;AAAA,MAC7B,OAAO,SAAS,QAAQ,QAAQ,KAAK;AAAA;AAAA,IAEtC,sBAAsB,CAAC,QAAQ;AAAA,MAC9B,IAAI,CAAC;AAAA,QAAS;AAAA,MAGd,WACC,0DACA,wDACD;AAAA,MAEA,aAAa,MAAM;AAAA;AAAA,EAErB;AAAA;",
|
package/dist/vite/preview.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { PreviewServer } from 'vite';
|
|
2
2
|
/**
|
|
3
3
|
* Hands every request to the built server, before Vite's own files: the
|
|
4
|
-
* app serves `build/client` itself, with its
|
|
4
|
+
* app serves `build/client` itself, with its middlewares and cache headers. Its
|
|
5
5
|
* WebSocket routes connect too, relayed as under `react-router dev`.
|
|
6
6
|
*/
|
|
7
7
|
export declare function servePreview(server: PreviewServer): void;
|
package/dist/vite/socket.d.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Under `react-router dev` and `vite preview`: the app's WebSocket routes. Vite's server is a
|
|
3
3
|
* `node:http` one, and an alxia socket is `Bun.serve`'s upgrade, so each
|
|
4
4
|
* upgrade Vite leaves is relayed, bytes as they come, to a `Bun.serve` of
|
|
5
|
-
* the app's own on a loopback port: its
|
|
5
|
+
* the app's own on a loopback port: its middlewares, its validation, its socket
|
|
6
6
|
* handlers, exactly as `listen` runs them.
|
|
7
7
|
*/
|
|
8
8
|
import type { IncomingMessage } from 'node:http';
|
package/docs/README.md
CHANGED
|
@@ -7,6 +7,13 @@ do with each message.
|
|
|
7
7
|
|
|
8
8
|
| Page | Read it when |
|
|
9
9
|
| --- | --- |
|
|
10
|
-
| [Guide](guide.md) | adding alxia to the official template, revealing the default server with `bunx alxia-react-router reveal`, customising the server with `createServer()`, typing the loaders with `Register` or a type argument, the app's own context keys, what `vite preview` and prerendering serve, what the plugin sets so the server is built for Bun, the escape hatches (another entry, overriding the wiring, a server of your own), what runs around the pages, WebSockets in dev, in preview and in the build, the client's files, OpenAPI, testing, or deploying, with the Docker image |
|
|
10
|
+
| [Guide](guide.md) | starting a new app with `bun create @alxia --template react-router`, adding alxia to the official template or an existing app, revealing the default server with `bunx alxia-react-router reveal`, customising the server with `createServer()`, typing the loaders with `Register` or a type argument, the app's own context keys, what `vite preview` and prerendering serve, what the plugin sets so the server is built for Bun, the escape hatches (another entry, overriding the wiring, a server of your own), what runs around the pages, WebSockets in dev, in preview and in the build, the client's files, OpenAPI, testing, or deploying, with the Docker image |
|
|
11
11
|
| [Troubleshooting](troubleshooting.md) | something went wrong and you have the message, or a page streams, hydrates or reads its context unlike you expected |
|
|
12
12
|
| [Roadmap](roadmap.md) | wondering what is coming, and what is not planned |
|
|
13
|
+
|
|
14
|
+
## Recipes
|
|
15
|
+
|
|
16
|
+
A task that crosses packages, in [the repository's recipes](https://github.com/softistx/alxia/blob/develop/docs/recipes/README.md), each with a complete example:
|
|
17
|
+
|
|
18
|
+
- [Deploy with Docker](https://github.com/softistx/alxia/blob/develop/docs/recipes/deploying.md): the build stage, the final image, `NODE_ENV=production`
|
|
19
|
+
- [Health checks and graceful shutdown](https://github.com/softistx/alxia/blob/develop/docs/recipes/health-and-shutdown.md): probes, the drain, Docker and Kubernetes
|