@canonical/react-ssr 0.27.1-experimental.0 → 0.28.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 +74 -27
- package/dist/esm/bin/serve-bun.js +77 -0
- package/dist/esm/bin/serve-bun.js.map +1 -0
- package/dist/esm/bin/serve-express.js +19 -36
- package/dist/esm/bin/serve-express.js.map +1 -1
- package/dist/esm/lib/adapter/index.js +1 -1
- package/dist/esm/lib/adapter/index.js.map +1 -1
- package/dist/esm/lib/adapter/mime.js +7 -0
- package/dist/esm/lib/adapter/mime.js.map +1 -1
- package/dist/esm/lib/renderer/JSXRenderer.js +2 -0
- package/dist/esm/lib/renderer/JSXRenderer.js.map +1 -1
- package/dist/esm/lib/renderer/SitemapRenderer.js +2 -0
- package/dist/esm/lib/renderer/SitemapRenderer.js.map +1 -1
- package/dist/esm/lib/server/StaticMount.js +2 -0
- package/dist/esm/lib/server/StaticMount.js.map +1 -0
- package/dist/esm/lib/server/getRequestUrl.js +41 -0
- package/dist/esm/lib/server/getRequestUrl.js.map +1 -0
- package/dist/esm/lib/server/index.js +6 -0
- package/dist/esm/lib/server/index.js.map +1 -1
- package/dist/esm/lib/server/matchStaticRoute.js +14 -0
- package/dist/esm/lib/server/matchStaticRoute.js.map +1 -0
- package/dist/esm/lib/server/parseStaticPair.js +20 -0
- package/dist/esm/lib/server/parseStaticPair.js.map +1 -0
- package/dist/esm/lib/server/resolvePort.js +29 -0
- package/dist/esm/lib/server/resolvePort.js.map +1 -0
- package/dist/esm/lib/server/resolveStaticFile.js +61 -0
- package/dist/esm/lib/server/resolveStaticFile.js.map +1 -0
- package/dist/esm/lib/server/serveStream.js +1 -1
- package/dist/esm/lib/server/serveStream.js.map +1 -1
- package/dist/esm/lib/server/viteFetchMiddleware.js +152 -0
- package/dist/esm/lib/server/viteFetchMiddleware.js.map +1 -0
- package/dist/types/bin/serve-bun.d.ts +25 -0
- package/dist/types/bin/serve-bun.d.ts.map +1 -0
- package/dist/types/bin/serve-express.d.ts +6 -3
- package/dist/types/bin/serve-express.d.ts.map +1 -1
- package/dist/types/lib/adapter/index.d.ts +1 -1
- package/dist/types/lib/adapter/index.d.ts.map +1 -1
- package/dist/types/lib/adapter/mime.d.ts +7 -0
- package/dist/types/lib/adapter/mime.d.ts.map +1 -1
- package/dist/types/lib/adapter/types.d.ts +8 -10
- package/dist/types/lib/adapter/types.d.ts.map +1 -1
- package/dist/types/lib/renderer/JSXRenderer.d.ts +2 -0
- package/dist/types/lib/renderer/JSXRenderer.d.ts.map +1 -1
- package/dist/types/lib/renderer/SitemapRenderer.d.ts +2 -0
- package/dist/types/lib/renderer/SitemapRenderer.d.ts.map +1 -1
- package/dist/types/lib/server/StaticMount.d.ts +11 -0
- package/dist/types/lib/server/StaticMount.d.ts.map +1 -0
- package/dist/types/lib/server/getRequestUrl.d.ts +29 -0
- package/dist/types/lib/server/getRequestUrl.d.ts.map +1 -0
- package/dist/types/lib/server/index.d.ts +7 -0
- package/dist/types/lib/server/index.d.ts.map +1 -1
- package/dist/types/lib/server/matchStaticRoute.d.ts +12 -0
- package/dist/types/lib/server/matchStaticRoute.d.ts.map +1 -0
- package/dist/types/lib/server/parseStaticPair.d.ts +12 -0
- package/dist/types/lib/server/parseStaticPair.d.ts.map +1 -0
- package/dist/types/lib/server/resolvePort.d.ts +20 -0
- package/dist/types/lib/server/resolvePort.d.ts.map +1 -0
- package/dist/types/lib/server/resolveStaticFile.d.ts +20 -0
- package/dist/types/lib/server/resolveStaticFile.d.ts.map +1 -0
- package/dist/types/lib/server/serveStream.d.ts +1 -0
- package/dist/types/lib/server/serveStream.d.ts.map +1 -1
- package/dist/types/lib/server/viteFetchMiddleware.d.ts +81 -0
- package/dist/types/lib/server/viteFetchMiddleware.d.ts.map +1 -0
- package/package.json +11 -7
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
import { matchStaticRoute } from "./matchStaticRoute.js";
|
|
3
|
+
/** True when the path's last segment carries a file extension (e.g. `.js`, `.txt`). */
|
|
4
|
+
function hasFileExtension(pathname) {
|
|
5
|
+
return /\.[a-z0-9]+$/i.test(pathname);
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Resolve the on-disk path for a request under a static mount, or `null` if the
|
|
9
|
+
* request does not match the mount, is not a static-file request, or attempts to
|
|
10
|
+
* escape the mount directory.
|
|
11
|
+
*
|
|
12
|
+
* Only paths that carry a **file extension** are treated as static, so a root
|
|
13
|
+
* mount (`/`) serves `/robots.txt`, `/sitemap.xml`, `/favicon.ico`, and the
|
|
14
|
+
* hashed `/assets/*` while extensionless routes (`/`, `/about`) fall through to
|
|
15
|
+
* be server-rendered — `index.html` is never served in place of the SSR page.
|
|
16
|
+
*
|
|
17
|
+
* Guards against path traversal: the URL tail is decoded (so `%2e%2e`/`%2f`
|
|
18
|
+
* forms are caught) and rejected if it contains a `..` segment; as defence in
|
|
19
|
+
* depth the resolved path must remain within the mount directory. This mirrors
|
|
20
|
+
* the Deno adapter's guard so the bins cannot drift from it.
|
|
21
|
+
*
|
|
22
|
+
* @returns The absolute file path to serve, or `null` to skip this mount.
|
|
23
|
+
*/
|
|
24
|
+
export function resolveStaticFile(pathname, mount) {
|
|
25
|
+
if (!matchStaticRoute(pathname, mount.route))
|
|
26
|
+
return null;
|
|
27
|
+
if (!hasFileExtension(pathname))
|
|
28
|
+
return null;
|
|
29
|
+
// A root mount serves from the mount dir itself; a prefixed mount strips the
|
|
30
|
+
// prefix so the remainder resolves under the dir.
|
|
31
|
+
const tail = mount.route === "/" ? pathname : pathname.slice(mount.route.length);
|
|
32
|
+
let decoded;
|
|
33
|
+
try {
|
|
34
|
+
decoded = decodeURIComponent(tail);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Malformed percent-encoding — reject.
|
|
38
|
+
return null;
|
|
39
|
+
}
|
|
40
|
+
// Reject any traversal segment (covers `..`, `%2e%2e`, and `%2f`-smuggled
|
|
41
|
+
// separators since `tail` is decoded above).
|
|
42
|
+
if (decoded.split(/[/\\]/).includes(".."))
|
|
43
|
+
return null;
|
|
44
|
+
// Strip the leading separator so `path.join` cannot treat an absolute-looking
|
|
45
|
+
// tail (e.g. `/etc/passwd`) as a root and discard the mount directory. Resolve
|
|
46
|
+
// against the mount and verify the result stays within it — a path that
|
|
47
|
+
// escapes (via absolute tail or otherwise) is rejected. This containment check
|
|
48
|
+
// is the real guard; the `..` rejection above is defence in depth.
|
|
49
|
+
const relative = decoded.replace(/^[/\\]+/, "");
|
|
50
|
+
const resolvedDir = path.resolve(mount.dir);
|
|
51
|
+
const resolved = path.resolve(resolvedDir, relative);
|
|
52
|
+
/* v8 ignore next 4 -- defensive backstop: the `..` rejection and leading-separator
|
|
53
|
+
strip above already prevent every known escape, so this containment check is
|
|
54
|
+
not reachable in tests; it stays as a last line of defence against future drift. */
|
|
55
|
+
if (resolved !== resolvedDir &&
|
|
56
|
+
!resolved.startsWith(`${resolvedDir}${path.sep}`)) {
|
|
57
|
+
return null;
|
|
58
|
+
}
|
|
59
|
+
return resolved;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=resolveStaticFile.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveStaticFile.js","sourceRoot":"","sources":["../../../../src/lib/server/resolveStaticFile.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAGzD,uFAAuF;AACvF,SAAS,gBAAgB,CAAC,QAAgB;IACxC,OAAO,eAAe,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;AACxC,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAAgB,EAChB,KAAkB;IAElB,IAAI,CAAC,gBAAgB,CAAC,QAAQ,EAAE,KAAK,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1D,IAAI,CAAC,gBAAgB,CAAC,QAAQ,CAAC;QAAE,OAAO,IAAI,CAAC;IAE7C,6EAA6E;IAC7E,kDAAkD;IAClD,MAAM,IAAI,GACR,KAAK,CAAC,KAAK,KAAK,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IAEtE,IAAI,OAAe,CAAC;IACpB,IAAI,CAAC;QACH,OAAO,GAAG,kBAAkB,CAAC,IAAI,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,uCAAuC;QACvC,OAAO,IAAI,CAAC;IACd,CAAC;IACD,0EAA0E;IAC1E,6CAA6C;IAC7C,IAAI,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAEvD,8EAA8E;IAC9E,+EAA+E;IAC/E,wEAAwE;IACxE,+EAA+E;IAC/E,mEAAmE;IACnE,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;IAChD,MAAM,WAAW,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,QAAQ,CAAC,CAAC;IACrD;;0FAEsF;IACtF,IACE,QAAQ,KAAK,WAAW;QACxB,CAAC,QAAQ,CAAC,UAAU,CAAC,GAAG,WAAW,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC,EACjD,CAAC;QACD,OAAO,IAAI,CAAC;IACd,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC"}
|
|
@@ -37,7 +37,7 @@ export function serveStream(factory) {
|
|
|
37
37
|
const result = renderer.renderToPipeableStream();
|
|
38
38
|
await renderer.statusReady;
|
|
39
39
|
res.writeHead(renderer.statusCode, {
|
|
40
|
-
"Content-Type": "text/html; charset=utf-8",
|
|
40
|
+
"Content-Type": renderer.contentType ?? "text/html; charset=utf-8",
|
|
41
41
|
});
|
|
42
42
|
result.pipe(res);
|
|
43
43
|
/* v8 ignore next -- finish event fires after stream completes; not triggered in unit tests */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serveStream.js","sourceRoot":"","sources":["../../../../src/lib/server/serveStream.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,UAAU,WAAW,CACzB,
|
|
1
|
+
{"version":3,"file":"serveStream.js","sourceRoot":"","sources":["../../../../src/lib/server/serveStream.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,MAAM,UAAU,WAAW,CACzB,OAOC;IAED,OAAO,KAAK,EAAE,GAAoB,EAAE,GAAmB,EAAE,EAAE;QACzD,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC;YAC9B,MAAM,MAAM,GAAG,QAAQ,CAAC,sBAAsB,EAAE,CAAC;YACjD,MAAM,QAAQ,CAAC,WAAW,CAAC;YAC3B,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,UAAU,EAAE;gBACjC,cAAc,EAAE,QAAQ,CAAC,WAAW,IAAI,0BAA0B;aACnE,CAAC,CAAC;YACH,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;YACjB,8FAA8F;YAC9F,GAAG,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,CAAC;QACpC,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;YAChD,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC;YACrB,GAAG,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACnC,CAAC;IACH,CAAC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { IncomingMessage, ServerResponse } from "node:http";
|
|
2
|
+
import { Socket } from "node:net";
|
|
3
|
+
/**
|
|
4
|
+
* Bridge Vite's connect-style middleware into a `fetch`-style handler.
|
|
5
|
+
*
|
|
6
|
+
* Runtime SSR dev servers built on `Bun.serve` (or any Web `fetch` server)
|
|
7
|
+
* cannot mount Vite's `(req, res, next)` middleware directly: that stack
|
|
8
|
+
* expects Node's `http.IncomingMessage` / `ServerResponse`, while `fetch`
|
|
9
|
+
* deals in Web `Request` / `Response`. Without delegating to Vite, every
|
|
10
|
+
* request — including `/@vite/client`, `/src/**`, `/@id/**`, `/@fs/**`,
|
|
11
|
+
* `/@react-refresh`, and `/node_modules/.vite/**` — would have to be
|
|
12
|
+
* server-rendered, so client modules and HMR assets would be returned as the
|
|
13
|
+
* SSR HTML page with the wrong `Content-Type` (browsers then block them as
|
|
14
|
+
* modules and the page never hydrates).
|
|
15
|
+
*
|
|
16
|
+
* This helper adapts a Web `Request` into a Node `req`/`res` pair, runs Vite's
|
|
17
|
+
* middleware against it, and returns a Web `Response` if the middleware handled
|
|
18
|
+
* the request — or `null` if the stack called `next()` (a page route the
|
|
19
|
+
* caller should server-render).
|
|
20
|
+
*
|
|
21
|
+
* The bridge is **runtime-agnostic**: it depends only on `node:http` /
|
|
22
|
+
* `node:net` and Web globals (`Request`, `Response`), so it works under Bun,
|
|
23
|
+
* Node's own `fetch` servers, Deno, and Workers — not just Bun. The `vite`
|
|
24
|
+
* instance is injected, not imported, keeping this module free of a runtime
|
|
25
|
+
* Vite dependency.
|
|
26
|
+
*
|
|
27
|
+
* The response body is **buffered**: chunks written by the middleware are
|
|
28
|
+
* collected and the `Response` resolves on `end`, with `status` and `headers`
|
|
29
|
+
* read from the (by-then-final) `ServerResponse`. This is correct and robust
|
|
30
|
+
* for dev assets — transformed JS/CSS modules and source maps, which are small
|
|
31
|
+
* and already in memory when Vite writes them. Streaming would buy near-zero
|
|
32
|
+
* latency here (SSR render streaming goes through the renderer's
|
|
33
|
+
* `renderToReadableStream`, never this bridge) while introducing header-timing
|
|
34
|
+
* and backpressure hazards, so it is deliberately avoided.
|
|
35
|
+
*
|
|
36
|
+
* Headers set via `res.writeHead(status, headers)` are captured in addition to
|
|
37
|
+
* `res.getHeaders()` (Vite's static-file middleware sets `Content-Type` etc.
|
|
38
|
+
* that way for non-JS assets), and multi-value headers such as `set-cookie` are
|
|
39
|
+
* preserved as separate entries rather than comma-folded.
|
|
40
|
+
*
|
|
41
|
+
* Only `GET`/`HEAD` requests are bridged. A bare `IncomingMessage` carries no
|
|
42
|
+
* request body, so any middleware that reads one would hang; requests with a
|
|
43
|
+
* body (and other methods) return `null` so the caller handles them. This
|
|
44
|
+
* matches Vite's asset/module/HMR surface, which is entirely `GET`/`HEAD`.
|
|
45
|
+
*
|
|
46
|
+
* @param vite - A Vite dev server created with `middlewareMode: true`.
|
|
47
|
+
* @returns A function mapping a Web `Request` to a `Response` (Vite handled it)
|
|
48
|
+
* or `null` (a page route, a non-`GET`/`HEAD` request — pass through to SSR).
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```ts
|
|
52
|
+
* import { createServer as createViteServer } from "vite";
|
|
53
|
+
* import { viteFetchMiddleware } from "@canonical/react-ssr/server";
|
|
54
|
+
*
|
|
55
|
+
* const vite = await createViteServer({
|
|
56
|
+
* server: { middlewareMode: true },
|
|
57
|
+
* appType: "custom",
|
|
58
|
+
* });
|
|
59
|
+
* const handleAsset = viteFetchMiddleware(vite);
|
|
60
|
+
*
|
|
61
|
+
* Bun.serve({
|
|
62
|
+
* async fetch(req) {
|
|
63
|
+
* const asset = await handleAsset(req);
|
|
64
|
+
* if (asset) return asset; // /@vite/client, /src/**, CSS, HMR …
|
|
65
|
+
* return ssrRender(req); // page route
|
|
66
|
+
* },
|
|
67
|
+
* });
|
|
68
|
+
* ```
|
|
69
|
+
*/
|
|
70
|
+
export function viteFetchMiddleware(vite) {
|
|
71
|
+
return (request) => {
|
|
72
|
+
// Asset-only contract: a bare IncomingMessage carries no request body, so a
|
|
73
|
+
// middleware that reads one (e.g. Vite's proxy when `server.proxy` is set)
|
|
74
|
+
// would hang. Asset/module/HMR requests are all GET/HEAD; pass anything else
|
|
75
|
+
// through to the caller (page POSTs are server-rendered, not bridged).
|
|
76
|
+
if (request.method !== "GET" && request.method !== "HEAD") {
|
|
77
|
+
return Promise.resolve(null);
|
|
78
|
+
}
|
|
79
|
+
return new Promise((resolve, reject) => {
|
|
80
|
+
const url = new URL(request.url);
|
|
81
|
+
// A bare IncomingMessage needs a socket and a populated, lower-cased
|
|
82
|
+
// headers object before Vite's middleware runs — Vite reads navigation
|
|
83
|
+
// hints (e.g. `sec-fetch-mode`) and will throw on an empty header bag.
|
|
84
|
+
const socket = new Socket();
|
|
85
|
+
const req = new IncomingMessage(socket);
|
|
86
|
+
req.url = url.pathname + url.search;
|
|
87
|
+
req.method = request.method;
|
|
88
|
+
const headers = {};
|
|
89
|
+
request.headers.forEach((value, key) => {
|
|
90
|
+
headers[key.toLowerCase()] = value;
|
|
91
|
+
});
|
|
92
|
+
if (!headers.host)
|
|
93
|
+
headers.host = url.host;
|
|
94
|
+
req.headers = headers;
|
|
95
|
+
const res = new ServerResponse(req);
|
|
96
|
+
const chunks = [];
|
|
97
|
+
const originalWrite = res.write.bind(res);
|
|
98
|
+
const originalEnd = res.end.bind(res);
|
|
99
|
+
const originalWriteHead = res.writeHead.bind(res);
|
|
100
|
+
// Headers passed to writeHead(status, [statusMessage,] headers) are NOT
|
|
101
|
+
// returned by res.getHeaders() unless also set via setHeader, so capture
|
|
102
|
+
// them here. Vite's static (sirv) middleware sets Content-Type, ETag,
|
|
103
|
+
// Cache-Control this way for non-JS assets (svg, fonts, images, maps).
|
|
104
|
+
let writeHeadHeaders;
|
|
105
|
+
res.writeHead = ((statusCode, ...rest) => {
|
|
106
|
+
const last = rest[rest.length - 1];
|
|
107
|
+
if (last && typeof last === "object" && !Array.isArray(last)) {
|
|
108
|
+
writeHeadHeaders = last;
|
|
109
|
+
}
|
|
110
|
+
return originalWriteHead(statusCode, ...rest);
|
|
111
|
+
});
|
|
112
|
+
res.write = ((chunk, ...rest) => {
|
|
113
|
+
chunks.push(Buffer.from(chunk));
|
|
114
|
+
return originalWrite(chunk, ...rest);
|
|
115
|
+
});
|
|
116
|
+
res.end = ((chunk, ...rest) => {
|
|
117
|
+
if (chunk != null && typeof chunk !== "function") {
|
|
118
|
+
chunks.push(Buffer.from(chunk));
|
|
119
|
+
}
|
|
120
|
+
const result = originalEnd(chunk, ...rest);
|
|
121
|
+
// Merge setHeader() headers with writeHead() headers (the latter win),
|
|
122
|
+
// and preserve multi-value headers (e.g. set-cookie) as separate
|
|
123
|
+
// entries rather than comma-folding them via String().
|
|
124
|
+
const responseHeaders = new Headers();
|
|
125
|
+
const merged = {
|
|
126
|
+
...res.getHeaders(),
|
|
127
|
+
...writeHeadHeaders,
|
|
128
|
+
};
|
|
129
|
+
for (const [key, value] of Object.entries(merged)) {
|
|
130
|
+
if (value == null)
|
|
131
|
+
continue;
|
|
132
|
+
if (Array.isArray(value)) {
|
|
133
|
+
for (const item of value)
|
|
134
|
+
responseHeaders.append(key, String(item));
|
|
135
|
+
}
|
|
136
|
+
else {
|
|
137
|
+
responseHeaders.set(key, String(value));
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
resolve(new Response(chunks.length ? Buffer.concat(chunks) : null, {
|
|
141
|
+
status: res.statusCode,
|
|
142
|
+
headers: responseHeaders,
|
|
143
|
+
}));
|
|
144
|
+
return result;
|
|
145
|
+
});
|
|
146
|
+
res.on("error", reject);
|
|
147
|
+
// `next()` → Vite did not handle it (a page route); the caller renders it.
|
|
148
|
+
vite.middlewares(req, res, () => resolve(null));
|
|
149
|
+
});
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
//# sourceMappingURL=viteFetchMiddleware.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"viteFetchMiddleware.js","sourceRoot":"","sources":["../../../../src/lib/server/viteFetchMiddleware.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
#!/usr/bin/env bun
|
|
2
|
+
/**
|
|
3
|
+
* Standalone Bun server for serving an SSR application with stream rendering.
|
|
4
|
+
*
|
|
5
|
+
* Uses `Bun.serve()` for the HTTP layer and `Bun.file()` for zero-copy static
|
|
6
|
+
* file serving. The renderer module must default-export a factory that accepts a
|
|
7
|
+
* `Request` and returns a renderer with `renderToReadableStream`.
|
|
8
|
+
*
|
|
9
|
+
* Argument parsing, port resolution, and static-file matching live in
|
|
10
|
+
* `@canonical/react-ssr/server` (covered by unit tests); this bin is the thin
|
|
11
|
+
* Bun-specific shell around them.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```sh
|
|
15
|
+
* # Single static directory
|
|
16
|
+
* serve-bun dist/server/renderer.js --static assets:dist/client/assets
|
|
17
|
+
*
|
|
18
|
+
* # Multiple static directories, custom port
|
|
19
|
+
* serve-bun dist/server/renderer.js -p 3000 \
|
|
20
|
+
* --static assets:dist/client/assets \
|
|
21
|
+
* --static public:dist/client/public
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
export {};
|
|
25
|
+
//# sourceMappingURL=serve-bun.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"serve-bun.d.ts","sourceRoot":"","sources":["../../../src/bin/serve-bun.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;GAqBG"}
|
|
@@ -2,9 +2,12 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* Standalone Express server for serving an SSR application.
|
|
4
4
|
*
|
|
5
|
-
* Dynamically imports a renderer module that exports a factory
|
|
6
|
-
*
|
|
7
|
-
*
|
|
5
|
+
* Dynamically imports a renderer module that default-exports a factory. The
|
|
6
|
+
* factory receives a Node `IncomingMessage` and returns a renderer. Supports
|
|
7
|
+
* both streaming (`--streaming`) and string rendering modes.
|
|
8
|
+
*
|
|
9
|
+
* Argument parsing and port resolution live in `@canonical/react-ssr/server`
|
|
10
|
+
* (covered by unit tests); this bin is the thin Express-specific shell.
|
|
8
11
|
*
|
|
9
12
|
* @example
|
|
10
13
|
* ```sh
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serve-express.d.ts","sourceRoot":"","sources":["../../../src/bin/serve-express.ts"],"names":[],"mappings":";AAEA
|
|
1
|
+
{"version":3,"file":"serve-express.d.ts","sourceRoot":"","sources":["../../../src/bin/serve-express.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;;GAuBG"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { buildCacheControl, getMimeType, matchPattern } from "./mime.js";
|
|
1
|
+
export { buildCacheControl, getMimeType, IMMUTABLE_ASSET_CACHE_CONTROL, matchPattern, } from "./mime.js";
|
|
2
2
|
export type { CacheConfig, RendererFactory, RendererResult, RouteDefinition, StaticAssetConfig, } from "./types.js";
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapter/index.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapter/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iBAAiB,EACjB,WAAW,EACX,6BAA6B,EAC7B,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,WAAW,EACX,eAAe,EACf,cAAc,EACd,eAAe,EACf,iBAAiB,GAClB,MAAM,YAAY,CAAC"}
|
|
@@ -7,6 +7,13 @@
|
|
|
7
7
|
*
|
|
8
8
|
* No external dependencies — the lookup is a plain record.
|
|
9
9
|
*/
|
|
10
|
+
/**
|
|
11
|
+
* `Cache-Control` value for immutable, content-hashed static assets (e.g. Vite
|
|
12
|
+
* build output). One year, immutable — the canonical policy every adapter
|
|
13
|
+
* applies when serving fingerprinted assets. Centralised here so the three
|
|
14
|
+
* deployment adapters cannot drift.
|
|
15
|
+
*/
|
|
16
|
+
export declare const IMMUTABLE_ASSET_CACHE_CONTROL = "public, max-age=31536000, immutable";
|
|
10
17
|
/**
|
|
11
18
|
* Look up the MIME type for a file path based on its extension.
|
|
12
19
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mime.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapter/mime.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"mime.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapter/mime.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,wCACH,CAAC;AA0BxC;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAKhD;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE;IACvC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B,GAAG,MAAM,CAOT;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAOvE"}
|
|
@@ -65,21 +65,19 @@ export interface CacheConfig {
|
|
|
65
65
|
staleWhileRevalidate?: number;
|
|
66
66
|
}
|
|
67
67
|
/**
|
|
68
|
-
* Configuration for serving static assets (CSS, JS, images, fonts)
|
|
68
|
+
* Configuration for serving static assets (CSS, JS, images, fonts) from a
|
|
69
|
+
* runtime that has no static layer in front of the SSR handler.
|
|
69
70
|
*
|
|
70
|
-
*
|
|
71
|
-
*
|
|
72
|
-
*
|
|
71
|
+
* Only the Deno/Bun adapters use this: their runtimes serve the SSR handler
|
|
72
|
+
* directly, so the handler reads matching files from the filesystem. Cloudflare
|
|
73
|
+
* and Vercel do NOT use it — those platforms serve static assets at the edge
|
|
74
|
+
* before the SSR function runs (Workers Static Assets / the Vercel CDN), so
|
|
75
|
+
* their adapters take no `staticAssets` config. See each adapter's README.
|
|
73
76
|
*/
|
|
74
77
|
export interface StaticAssetConfig {
|
|
75
78
|
/** URL path prefix (e.g. `"/assets"`). */
|
|
76
79
|
urlPrefix: string;
|
|
77
|
-
/**
|
|
78
|
-
* Source directory or key prefix.
|
|
79
|
-
* - Cloudflare: R2 key prefix (e.g. `"assets"`)
|
|
80
|
-
* - Vercel: not used (static assets served by CDN from `.vercel/output/static/`)
|
|
81
|
-
* - Deno/Bun: filesystem path (e.g. `"dist/client/assets"`)
|
|
82
|
-
*/
|
|
80
|
+
/** Filesystem path the prefix maps to (e.g. `"dist/client/assets"`). */
|
|
83
81
|
directory: string;
|
|
84
82
|
}
|
|
85
83
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapter/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,qFAAqF;IACrF,sBAAsB,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAE1E,oDAAoD;IACpD,UAAU,EAAE,MAAM,CAAC;IAEnB,gDAAgD;IAChD,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,cAAc,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,+DAA+D;IAC/D,OAAO,EAAE,MAAM,CAAC;IAEhB,4DAA4D;IAC5D,OAAO,EAAE,eAAe,CAAC;IAEzB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,yDAAyD;IACzD,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW;IAC1B,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,wFAAwF;IACxF,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/lib/adapter/types.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH;;;;;GAKG;AACH,MAAM,WAAW,cAAc;IAC7B,qFAAqF;IACrF,sBAAsB,EAAE,CAAC,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC,cAAc,CAAC,CAAC;IAE1E,oDAAoD;IACpD,UAAU,EAAE,MAAM,CAAC;IAEnB,gDAAgD;IAChD,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5B;AAED;;;;;;GAMG;AACH,MAAM,MAAM,eAAe,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,cAAc,CAAC;AAEnE;;;;;;GAMG;AACH,MAAM,WAAW,eAAe;IAC9B,+DAA+D;IAC/D,OAAO,EAAE,MAAM,CAAC;IAEhB,4DAA4D;IAC5D,OAAO,EAAE,eAAe,CAAC;IAEzB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB,yDAAyD;IACzD,KAAK,CAAC,EAAE,WAAW,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,WAAW;IAC1B,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,uDAAuD;IACvD,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,wFAAwF;IACxF,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;AAED;;;;;;;;;GASG;AACH,MAAM,WAAW,iBAAiB;IAChC,0CAA0C;IAC1C,SAAS,EAAE,MAAM,CAAC;IAElB,wEAAwE;IACxE,SAAS,EAAE,MAAM,CAAC;CACnB"}
|
|
@@ -49,6 +49,8 @@ export default class JSXRenderer<TComponent extends ServerEntrypoint<InitialData
|
|
|
49
49
|
* `renderToString`) or after awaiting `statusReady` (for `renderToPipeableStream`).
|
|
50
50
|
*/
|
|
51
51
|
statusCode: number;
|
|
52
|
+
/** MIME type of the rendered output, for the consumer's `Content-Type` header. */
|
|
53
|
+
readonly contentType = "text/html; charset=utf-8";
|
|
52
54
|
/**
|
|
53
55
|
* Resolves when `statusCode` is determined.
|
|
54
56
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"JSXRenderer.d.ts","sourceRoot":"","sources":["../../../../src/lib/renderer/JSXRenderer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AAGtE,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,KAAK,EACV,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAmBpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,CAAC,OAAO,OAAO,WAAW,CAC9B,UAAU,SAAS,gBAAgB,CAAC,WAAW,CAAC,EAChD,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"JSXRenderer.d.ts","sourceRoot":"","sources":["../../../../src/lib/renderer/JSXRenderer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,6BAA6B,EAAE,MAAM,kBAAkB,CAAC;AAGtE,OAAO,SAAS,MAAM,gBAAgB,CAAC;AACvC,OAAO,KAAK,EACV,oBAAoB,EACpB,eAAe,EACf,gBAAgB,EAChB,qBAAqB,EACtB,MAAM,YAAY,CAAC;AAmBpB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,MAAM,CAAC,OAAO,OAAO,WAAW,CAC9B,UAAU,SAAS,gBAAgB,CAAC,WAAW,CAAC,EAChD,WAAW,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IAuCzC,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,UAAU;IACxC,SAAS,CAAC,QAAQ,CAAC,WAAW,EAAE,WAAW;IAC3C,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,eAAe;IAvC7C,SAAS,CAAC,SAAS,EAAE,SAAS,GAAG,SAAS,CAAC;IAE3C;;;;;;;;OAQG;IACI,UAAU,SAAO;IAExB,kFAAkF;IAClF,SAAgB,WAAW,8BAA8B;IAEzD;;;;;;OAMG;IACI,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC,CAAqB;IAEtD;;;;;;;;;;OAUG;gBAEkB,SAAS,EAAE,UAAU,EACrB,WAAW,GAAE,WAA+B,EAC5C,OAAO,GAAE,eAAoB;IAOlD;;;;;;OAMG;IACI,SAAS,IAAI,MAAM;IAI1B;;;;;;OAMG;IACH,SAAS,CAAC,iBAAiB,IAAI,qBAAqB,CAAC,WAAW,CAAC;IAUjE;;;;;;;;;;OAUG;IACH,SAAS,CAAC,sBAAsB,CAC9B,OAAO,EAAE,KAAK,CAAC,YAAY,EAAE,EAC7B,IAAI,EAAE,QAAQ,GAAG,SAAS,GACzB,MAAM,EAAE;IAmBX;;;;;;;;;;;;;;OAcG;IACH,SAAS,CAAC,qBAAqB,CAC7B,KAAK,EAAE,qBAAqB,CAAC,WAAW,CAAC,GACxC,6BAA6B;IA8BhC;;;;;;;;;;;;;;OAcG;IACH,sBAAsB,GACpB,SAAS,WAAW,KACnB,OAAO,CAAC,cAAc,CAAC,CAuCxB;IAEF;;;;;;;;;;;;;;OAcG;IACH,sBAAsB,QAAO,oBAAoB,CAkD/C;IAEF;;;;;;;;;;;;OAYG;IACH,cAAc,QAAO,MAAM,CAOzB;CACH"}
|
|
@@ -37,6 +37,8 @@ export default class SitemapRenderer {
|
|
|
37
37
|
* error handler decides the status code for unexpected failures.
|
|
38
38
|
*/
|
|
39
39
|
statusCode: number;
|
|
40
|
+
/** MIME type of the rendered output, for the consumer's `Content-Type` header. */
|
|
41
|
+
readonly contentType = "application/xml; charset=utf-8";
|
|
40
42
|
/**
|
|
41
43
|
* Resolves when `statusCode` is determined.
|
|
42
44
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SitemapRenderer.d.ts","sourceRoot":"","sources":["../../../../src/lib/renderer/SitemapRenderer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,OAAO,OAAO,eAAe;
|
|
1
|
+
{"version":3,"file":"SitemapRenderer.d.ts","sourceRoot":"","sources":["../../../../src/lib/renderer/SitemapRenderer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,oBAAoB,EACpB,aAAa,EACb,aAAa,EACb,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,MAAM,CAAC,OAAO,OAAO,eAAe;IA8BhC,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,SAAS,aAAa,EAAE;IACpD,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,aAAa;IA9B1C;;;;;;OAMG;IACI,UAAU,SAAO;IAExB,kFAAkF;IAClF,SAAgB,WAAW,oCAAoC;IAE/D;;;;;;OAMG;IACI,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC,CAAqB;IAEtD;;;;;;OAMG;gBAEkB,OAAO,EAAE,SAAS,aAAa,EAAE,EACjC,MAAM,EAAE,aAAa;IAG1C;;;;;;;;OAQG;cACa,SAAS,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;IAKnD;;;;;;;;;;;OAWG;IACH,SAAS,CAAC,WAAW,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,GAAG,WAAW,EAAE;IAcnE;;;;;;;;OAQG;IACH,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM,GAAG,MAAM;IAKxD;;;;;;;;OAQG;IACH,SAAS,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM;IASjD;;;;;;;;;OASG;IACH,SAAS,CAAC,KAAK,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,GAAG,MAAM;IA6BtD;;;OAGG;cACa,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAM3C;;;;;;;;;;OAUG;IACH,sBAAsB,GACpB,UAAU,WAAW,KACpB,OAAO,CAAC,cAAc,CAAC,CAWxB;IAEF;;;;;;;;;;OAUG;IACH,sBAAsB,QAAO,oBAAoB,CAqB/C;IAEF;;;;;;;;;;;OAWG;IACH,cAAc,QAAa,OAAO,CAAC,MAAM,CAAC,CAKxC;CACH"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A static mount: a URL route prefix mapped to a filesystem directory.
|
|
3
|
+
*/
|
|
4
|
+
export interface StaticMount {
|
|
5
|
+
/** URL prefix, always leading-slashed, e.g. `/assets`. The root mount `/`
|
|
6
|
+
* serves a whole directory. */
|
|
7
|
+
route: string;
|
|
8
|
+
/** Absolute directory the route serves from. */
|
|
9
|
+
dir: string;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=StaticMount.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"StaticMount.d.ts","sourceRoot":"","sources":["../../../../src/lib/server/StaticMount.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B;mCAC+B;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,gDAAgD;IAChD,GAAG,EAAE,MAAM,CAAC;CACb"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { IncomingMessage } from "node:http";
|
|
2
|
+
/**
|
|
3
|
+
* Extract the request path (`pathname` + `search`) from either a Web `Request`
|
|
4
|
+
* or a Node `IncomingMessage`.
|
|
5
|
+
*
|
|
6
|
+
* The `serve-bun` and `serve-express` bins call a renderer factory with
|
|
7
|
+
* different request shapes — `serve-bun` passes a Web `Request` (whose `url` is
|
|
8
|
+
* absolute, e.g. `https://host/a/b?x=1`), while `serve-express` (via
|
|
9
|
+
* `serveStream`) passes a Node `IncomingMessage` (whose `url` is already a path,
|
|
10
|
+
* e.g. `/a/b?x=1`). A renderer factory that needs the URL for routing must
|
|
11
|
+
* handle both; this helper normalises them to a single path string.
|
|
12
|
+
*
|
|
13
|
+
* @param request - A Web `Request` or a Node `IncomingMessage`.
|
|
14
|
+
* @returns The request path including query string, e.g. `/a/b?x=1`. Defaults to
|
|
15
|
+
* `/` when no URL is present.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```ts
|
|
19
|
+
* import { JSXRenderer } from "@canonical/react-ssr/renderer";
|
|
20
|
+
* import { getRequestUrl } from "@canonical/react-ssr/server";
|
|
21
|
+
*
|
|
22
|
+
* export default function createRenderer(request: Request | IncomingMessage) {
|
|
23
|
+
* const url = getRequestUrl(request);
|
|
24
|
+
* return new JSXRenderer(EntryServer, { url }, { htmlString });
|
|
25
|
+
* }
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function getRequestUrl(request: Request | IncomingMessage): string;
|
|
29
|
+
//# sourceMappingURL=getRequestUrl.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"getRequestUrl.d.ts","sourceRoot":"","sources":["../../../../src/lib/server/getRequestUrl.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAEjD;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,OAAO,GAAG,eAAe,GAAG,MAAM,CAWxE"}
|
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
export { getRequestUrl } from "./getRequestUrl.js";
|
|
2
|
+
export { matchStaticRoute } from "./matchStaticRoute.js";
|
|
3
|
+
export { parseStaticPair } from "./parseStaticPair.js";
|
|
4
|
+
export { resolvePort } from "./resolvePort.js";
|
|
5
|
+
export { resolveStaticFile } from "./resolveStaticFile.js";
|
|
6
|
+
export type { StaticMount } from "./StaticMount.js";
|
|
1
7
|
export { serveStream } from "./serveStream.js";
|
|
2
8
|
export { serveString } from "./serveString.js";
|
|
9
|
+
export { type ViteMiddlewareServer, viteFetchMiddleware, } from "./viteFetchMiddleware.js";
|
|
3
10
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/lib/server/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AACvD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAC3D,YAAY,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EACL,KAAK,oBAAoB,EACzB,mBAAmB,GACpB,MAAM,0BAA0B,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Does `pathname` fall under `route`, matched on a path-segment boundary?
|
|
3
|
+
*
|
|
4
|
+
* `/assets` matches `/assets` and `/assets/x` but NOT `/assetsfoo/x` — a plain
|
|
5
|
+
* `startsWith` would wrongly match the latter. The root mount `/` matches every
|
|
6
|
+
* path, so a single `:dir` mount can serve a whole built client directory.
|
|
7
|
+
*
|
|
8
|
+
* @param pathname - The request pathname (no query string).
|
|
9
|
+
* @param route - The mount's route prefix.
|
|
10
|
+
*/
|
|
11
|
+
export declare function matchStaticRoute(pathname: string, route: string): boolean;
|
|
12
|
+
//# sourceMappingURL=matchStaticRoute.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matchStaticRoute.d.ts","sourceRoot":"","sources":["../../../../src/lib/server/matchStaticRoute.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAIzE"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { StaticMount } from "./StaticMount.js";
|
|
2
|
+
/**
|
|
3
|
+
* Parse a `route:filepath` pair (e.g. `"assets:dist/client/assets"`) into a
|
|
4
|
+
* {@link StaticMount}. With no separator the whole string is both the route and
|
|
5
|
+
* the (cwd-relative) directory; an empty route (`":dist/client"`) is the root
|
|
6
|
+
* mount. The directory is resolved against `cwd`.
|
|
7
|
+
*
|
|
8
|
+
* @param pair - A `"route:filepath"` or bare `"name"` string.
|
|
9
|
+
* @param cwd - Base directory for resolving the filepath (default `process.cwd()`).
|
|
10
|
+
*/
|
|
11
|
+
export declare function parseStaticPair(pair: string, cwd?: string): StaticMount;
|
|
12
|
+
//# sourceMappingURL=parseStaticPair.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseStaticPair.d.ts","sourceRoot":"","sources":["../../../../src/lib/server/parseStaticPair.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAEpD;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,MAAM,EACZ,GAAG,GAAE,MAAsB,GAC1B,WAAW,CAQb"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve the port a `serve-*` bin should listen on.
|
|
3
|
+
*
|
|
4
|
+
* Precedence: an explicit `--port`/`-p` flag, then the `PORT` env var, then the
|
|
5
|
+
* default `5174`. A value that is *present but not a valid TCP port* (non-integer
|
|
6
|
+
* or outside `1..65535`, including `"0"`) is a user error — it throws rather than
|
|
7
|
+
* silently falling back to the default, so a typo'd port fails loudly instead of
|
|
8
|
+
* binding the wrong one. Only an absent value falls through to the default.
|
|
9
|
+
*
|
|
10
|
+
* The `5174` default matches the SSR dev servers (`PORT || 5174`), so every SSR
|
|
11
|
+
* target — dev and preview, Bun and Node — lands on the same port by default.
|
|
12
|
+
*
|
|
13
|
+
* @param flag - The `--port`/`-p` value, if supplied.
|
|
14
|
+
* @param env - The `PORT` env var, if set.
|
|
15
|
+
* @param fallback - Port to use when neither is supplied (default `5174`).
|
|
16
|
+
* @returns The resolved port number.
|
|
17
|
+
* @throws If a supplied value is not an integer in `1..65535`.
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolvePort(flag: string | undefined, env: string | undefined, fallback?: number): number;
|
|
20
|
+
//# sourceMappingURL=resolvePort.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolvePort.d.ts","sourceRoot":"","sources":["../../../../src/lib/server/resolvePort.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,GAAG,EAAE,MAAM,GAAG,SAAS,EACvB,QAAQ,SAAO,GACd,MAAM,CAWR"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { StaticMount } from "./StaticMount.js";
|
|
2
|
+
/**
|
|
3
|
+
* Resolve the on-disk path for a request under a static mount, or `null` if the
|
|
4
|
+
* request does not match the mount, is not a static-file request, or attempts to
|
|
5
|
+
* escape the mount directory.
|
|
6
|
+
*
|
|
7
|
+
* Only paths that carry a **file extension** are treated as static, so a root
|
|
8
|
+
* mount (`/`) serves `/robots.txt`, `/sitemap.xml`, `/favicon.ico`, and the
|
|
9
|
+
* hashed `/assets/*` while extensionless routes (`/`, `/about`) fall through to
|
|
10
|
+
* be server-rendered — `index.html` is never served in place of the SSR page.
|
|
11
|
+
*
|
|
12
|
+
* Guards against path traversal: the URL tail is decoded (so `%2e%2e`/`%2f`
|
|
13
|
+
* forms are caught) and rejected if it contains a `..` segment; as defence in
|
|
14
|
+
* depth the resolved path must remain within the mount directory. This mirrors
|
|
15
|
+
* the Deno adapter's guard so the bins cannot drift from it.
|
|
16
|
+
*
|
|
17
|
+
* @returns The absolute file path to serve, or `null` to skip this mount.
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveStaticFile(pathname: string, mount: StaticMount): string | null;
|
|
20
|
+
//# sourceMappingURL=resolveStaticFile.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolveStaticFile.d.ts","sourceRoot":"","sources":["../../../../src/lib/server/resolveStaticFile.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAOpD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,WAAW,GACjB,MAAM,GAAG,IAAI,CAuCf"}
|
|
@@ -37,5 +37,6 @@ export declare function serveStream(factory: (req: IncomingMessage) => {
|
|
|
37
37
|
};
|
|
38
38
|
statusCode: number;
|
|
39
39
|
statusReady: Promise<void>;
|
|
40
|
+
contentType?: string;
|
|
40
41
|
}): (req: IncomingMessage, res: ServerResponse) => Promise<void>;
|
|
41
42
|
//# sourceMappingURL=serveStream.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serveStream.d.ts","sourceRoot":"","sources":["../../../../src/lib/server/serveStream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK;IACjC,sBAAsB,EAAE,MAAM;QAC5B,IAAI,EAAE,CAAC,CAAC,SAAS,MAAM,CAAC,cAAc,EAAE,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC;KAC9D,CAAC;IACF,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"serveStream.d.ts","sourceRoot":"","sources":["../../../../src/lib/server/serveStream.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AAEjE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,WAAW,CACzB,OAAO,EAAE,CAAC,GAAG,EAAE,eAAe,KAAK;IACjC,sBAAsB,EAAE,MAAM;QAC5B,IAAI,EAAE,CAAC,CAAC,SAAS,MAAM,CAAC,cAAc,EAAE,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC;KAC9D,CAAC;IACF,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,IAEa,KAAK,eAAe,EAAE,KAAK,cAAc,mBAiBxD"}
|