@rshono/core 1.0.0-rc.14 → 1.0.0-rc.15
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/dist/deploy/contract.d.ts +6 -1
- package/dist/deploy/contract.d.ts.map +1 -1
- package/dist/deploy/contract.js.map +1 -1
- package/dist/deploy/vercel/runtime.d.ts +7 -0
- package/dist/deploy/vercel/runtime.d.ts.map +1 -1
- package/dist/deploy/vercel/runtime.js +36 -2
- package/dist/deploy/vercel/runtime.js.map +1 -1
- package/package.json +1 -1
|
@@ -32,7 +32,12 @@ export interface DeployRuntime {
|
|
|
32
32
|
/**
|
|
33
33
|
* Hands the app to the platform and returns whatever the entry module should `export default` there:
|
|
34
34
|
* nothing where rshono owns the process (this binds the port), otherwise the export the platform looks
|
|
35
|
-
* for — `{ fetch }` on Workers, a handler
|
|
35
|
+
* for — `{ fetch }` on Workers, a streaming handler on Lambda, and on Vercel a Node
|
|
36
|
+
* `(IncomingMessage, ServerResponse)` listener, which is what its `Nodejs` launcher calls.
|
|
37
|
+
*
|
|
38
|
+
* Note that a web `Request` is not the common currency here: two of the three targets are handed one by
|
|
39
|
+
* their platform, and Vercel is not, so converting is part of the handoff rather than something the
|
|
40
|
+
* request-handling code below can assume has already happened.
|
|
36
41
|
*/
|
|
37
42
|
serveApp(app: Hono): unknown;
|
|
38
43
|
/** Mounts the hashed client bundle at `/_static`, ahead of the app's routes. A no-op where a CDN serves it. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/deploy/contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAElF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,YAAY,GAAG,QAAQ,GAAG,YAAY,CAAC;AAE3E;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/deploy/contract.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC1C,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAElF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,YAAY,GAAG,QAAQ,GAAG,YAAY,CAAC;AAE3E;;;;;;GAMG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;;;;;OASG;IACH,QAAQ,CAAC,GAAG,EAAE,IAAI,GAAG,OAAO,CAAC;IAC7B,+GAA+G;IAC/G,iBAAiB,CAAC,GAAG,EAAE,IAAI,GAAG,IAAI,CAAC;IACnC,sGAAsG;IACtG,mBAAmB,CAAC,GAAG,EAAE,IAAI,GAAG,IAAI,CAAC;IACrC;;;;;;;OAOG;IACH,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IACxF,yFAAyF;IACzF,OAAO,IAAI,IAAI,CAAC;CACjB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../src/deploy/contract.ts"],"names":[],"mappings":"","sourcesContent":["import type { Context, Hono } from 'hono';\nimport type { PrerenderVariant, PrerenderedPage } from '../server/prerendered.js';\n\n/**\n * A hosting platform `rshono build` targets. Selected with `deploy` in `rshono.config.ts`, the\n * `--deploy` flag or the `RSHONO_DEPLOY` env var.\n *\n * - `'node'` (the default) — rshono binds the port and you run the build with `rshono start`. Covers a\n * VPS, a container, a PaaS, and — through `node:` compatibility — Bun and Deno.\n * - `'cloudflare'` — a Worker; the entry exports `{ fetch }`.\n * - `'vercel'` — a Vercel function, plus the on-disk layout and config streaming needs there.\n * - `'aws-lambda'` — a streaming Lambda handler.\n *\n * There is one target per *handoff* — who opens the socket, and what shape a request arrives in — since\n * that is the part an app cannot arrange for itself. `rshono dev` always runs the `node` server.\n *\n * @example\n * ```ts\n * export default defineConfig({ deploy: 'cloudflare' });\n * ```\n *\n * @see {@link https://www.rshono.com/docs/deployment#the-targets | Docs — the targets}\n */\nexport type DeployTarget = 'node' | 'cloudflare' | 'vercel' | 'aws-lambda';\n\n/**\n * Everything the app server needs from the platform it runs on — the whole of what \"which platform is\n * this\" means at request time, since `runtime/entry.rsc.tsx` is written against this and nothing else.\n *\n * One preset implements it per target, and the build-time `@rshono/deploy` alias resolves to exactly\n * that module, so only the selected platform's code is ever in the bundle.\n */\nexport interface DeployRuntime {\n /**\n * Hands the app to the platform and returns whatever the entry module should `export default` there:\n * nothing where rshono owns the process (this binds the port), otherwise the export the platform looks\n * for — `{ fetch }` on Workers, a handler
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../src/deploy/contract.ts"],"names":[],"mappings":"","sourcesContent":["import type { Context, Hono } from 'hono';\nimport type { PrerenderVariant, PrerenderedPage } from '../server/prerendered.js';\n\n/**\n * A hosting platform `rshono build` targets. Selected with `deploy` in `rshono.config.ts`, the\n * `--deploy` flag or the `RSHONO_DEPLOY` env var.\n *\n * - `'node'` (the default) — rshono binds the port and you run the build with `rshono start`. Covers a\n * VPS, a container, a PaaS, and — through `node:` compatibility — Bun and Deno.\n * - `'cloudflare'` — a Worker; the entry exports `{ fetch }`.\n * - `'vercel'` — a Vercel function, plus the on-disk layout and config streaming needs there.\n * - `'aws-lambda'` — a streaming Lambda handler.\n *\n * There is one target per *handoff* — who opens the socket, and what shape a request arrives in — since\n * that is the part an app cannot arrange for itself. `rshono dev` always runs the `node` server.\n *\n * @example\n * ```ts\n * export default defineConfig({ deploy: 'cloudflare' });\n * ```\n *\n * @see {@link https://www.rshono.com/docs/deployment#the-targets | Docs — the targets}\n */\nexport type DeployTarget = 'node' | 'cloudflare' | 'vercel' | 'aws-lambda';\n\n/**\n * Everything the app server needs from the platform it runs on — the whole of what \"which platform is\n * this\" means at request time, since `runtime/entry.rsc.tsx` is written against this and nothing else.\n *\n * One preset implements it per target, and the build-time `@rshono/deploy` alias resolves to exactly\n * that module, so only the selected platform's code is ever in the bundle.\n */\nexport interface DeployRuntime {\n /**\n * Hands the app to the platform and returns whatever the entry module should `export default` there:\n * nothing where rshono owns the process (this binds the port), otherwise the export the platform looks\n * for — `{ fetch }` on Workers, a streaming handler on Lambda, and on Vercel a Node\n * `(IncomingMessage, ServerResponse)` listener, which is what its `Nodejs` launcher calls.\n *\n * Note that a web `Request` is not the common currency here: two of the three targets are handed one by\n * their platform, and Vercel is not, so converting is part of the handoff rather than something the\n * request-handling code below can assume has already happened.\n */\n serveApp(app: Hono): unknown;\n /** Mounts the hashed client bundle at `/_static`, ahead of the app's routes. A no-op where a CDN serves it. */\n mountStaticAssets(app: Hono): void;\n /** Mounts `public/` at the web root, after every route, so it only answers paths no route claimed. */\n mountPublicFallback(app: Hono): void;\n /**\n * Reads the page prerendered for `c.req.path`, or `null` when there is none — in which case the route\n * renders per request.\n *\n * Takes the whole {@link Context} because without a filesystem the store *is* a request-scoped\n * binding (`c.env.ASSETS` on Workers). The path is untrusted either way, so an implementation treats\n * traversal as a miss — see `prerenderedRelPath`.\n */\n readPrerendered(c: Context, variant: PrerenderVariant): Promise<PrerenderedPage | null>;\n /** Loads `.env` files where the platform has a filesystem. Env is bindings elsewhere. */\n loadEnv(): void;\n}\n"]}
|
|
@@ -2,6 +2,13 @@ import type { DeployRuntime } from '../contract.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Vercel, as a single Node function fed by the platform's own router.
|
|
4
4
|
*
|
|
5
|
+
* The function is invoked the way `launcherType: 'Nodejs'` invokes one — with `(IncomingMessage,
|
|
6
|
+
* ServerResponse)`, not a web `Request`. That is the whole of the Build Output API's Node contract; the
|
|
7
|
+
* `Request`/`Response` handler shape the platform documents elsewhere belongs to the `@vercel/node` builder,
|
|
8
|
+
* which compiles and wraps a source file, and a `--prebuilt` upload never runs it. So the handoff converts,
|
|
9
|
+
* and `hono/vercel`'s `handle` — a pass-through that forwards its first argument straight to `app.fetch` —
|
|
10
|
+
* cannot be what does it.
|
|
11
|
+
*
|
|
5
12
|
* `/_static` and `public/` are in the static output, and `config.json` puts the filesystem handler ahead of the
|
|
6
13
|
* function, so mounting them here would be dead weight. Prerendered pages are *not* static output — one URL
|
|
7
14
|
* answers with a document or a flight payload on the `RSC` request header, and a path-keyed CDN cannot choose — so
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/deploy/vercel/runtime.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/deploy/vercel/runtime.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAoBpD;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,OAAO,EAAE,aA+BrB,CAAC"}
|
|
@@ -1,8 +1,31 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getRequestListener } from '@hono/node-server';
|
|
2
2
|
import { fileSystemRuntime } from '../filesystem.js';
|
|
3
|
+
/**
|
|
4
|
+
* The scheme the browser used, which the socket cannot answer for: Vercel terminates TLS at the edge and
|
|
5
|
+
* reaches the function over plain HTTP, so an `https://` request arrives on an unencrypted socket and every
|
|
6
|
+
* absolute URL the app derived from it would carry the wrong scheme — a redirect back to `http://`, an
|
|
7
|
+
* origin check comparing against one.
|
|
8
|
+
*
|
|
9
|
+
* Read without `trustProxy`, unlike `publicUrl`, because on this target the header is not
|
|
10
|
+
* client-supplied: the function is reachable only through Vercel's edge, which sets it on every request. The
|
|
11
|
+
* config field stays what it is — the answer for a proxy *you* put in front, which the framework cannot vouch
|
|
12
|
+
* for. Falls back to `https`, the only scheme a deployment is served on.
|
|
13
|
+
*/
|
|
14
|
+
function browserScheme(incoming) {
|
|
15
|
+
const header = incoming.headers['x-forwarded-proto'];
|
|
16
|
+
const value = (Array.isArray(header) ? header[0] : header)?.split(',')[0]?.trim();
|
|
17
|
+
return value === 'http' ? 'http' : 'https';
|
|
18
|
+
}
|
|
3
19
|
/**
|
|
4
20
|
* Vercel, as a single Node function fed by the platform's own router.
|
|
5
21
|
*
|
|
22
|
+
* The function is invoked the way `launcherType: 'Nodejs'` invokes one — with `(IncomingMessage,
|
|
23
|
+
* ServerResponse)`, not a web `Request`. That is the whole of the Build Output API's Node contract; the
|
|
24
|
+
* `Request`/`Response` handler shape the platform documents elsewhere belongs to the `@vercel/node` builder,
|
|
25
|
+
* which compiles and wraps a source file, and a `--prebuilt` upload never runs it. So the handoff converts,
|
|
26
|
+
* and `hono/vercel`'s `handle` — a pass-through that forwards its first argument straight to `app.fetch` —
|
|
27
|
+
* cannot be what does it.
|
|
28
|
+
*
|
|
6
29
|
* `/_static` and `public/` are in the static output, and `config.json` puts the filesystem handler ahead of the
|
|
7
30
|
* function, so mounting them here would be dead weight. Prerendered pages are *not* static output — one URL
|
|
8
31
|
* answers with a document or a flight payload on the `RSC` request header, and a path-keyed CDN cannot choose — so
|
|
@@ -23,7 +46,18 @@ export const runtime = {
|
|
|
23
46
|
// handler does that; `serveStatic`, which the filesystem targets use, is no longer in the path.
|
|
24
47
|
},
|
|
25
48
|
serveApp(app) {
|
|
26
|
-
|
|
49
|
+
// The same conversion `rshono start` runs on, so a request is built here exactly as it is on the `node`
|
|
50
|
+
// target — including a streamed response body, which `supportsResponseStreaming` in `.vc-config.json`
|
|
51
|
+
// then keeps unbuffered on the way out.
|
|
52
|
+
const listener = getRequestListener(app.fetch);
|
|
53
|
+
return (incoming, outgoing) => {
|
|
54
|
+
const host = incoming.headers.host;
|
|
55
|
+
// Left alone when there is no `Host`, so the listener answers with its own 400 rather than this
|
|
56
|
+
// building `https://undefined/…` and the app rejecting a URL it should never have been handed.
|
|
57
|
+
if (host)
|
|
58
|
+
incoming.url = `${browserScheme(incoming)}://${host}${incoming.url ?? '/'}`;
|
|
59
|
+
return listener(incoming, outgoing);
|
|
60
|
+
};
|
|
27
61
|
},
|
|
28
62
|
};
|
|
29
63
|
//# sourceMappingURL=runtime.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/deploy/vercel/runtime.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/deploy/vercel/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AAIvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD;;;;;;;;;;GAUG;AACH,SAAS,aAAa,CAAC,QAAyB;IAC9C,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC;IACrD,MAAM,KAAK,GAAG,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC;IAClF,OAAO,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC;AAC7C,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,OAAO,GAAkB;IACpC,GAAG,iBAAiB;IAEpB,iBAAiB;QACf,gEAAgE;IAClE,CAAC;IAED,mBAAmB;QACjB,sGAAsG;QACtG,wGAAwG;QACxG,yGAAyG;QACzG,qDAAqD;QACrD,EAAE;QACF,uGAAuG;QACvG,gGAAgG;IAClG,CAAC;IAED,QAAQ,CAAC,GAAS;QAChB,wGAAwG;QACxG,sGAAsG;QACtG,wCAAwC;QACxC,MAAM,QAAQ,GAAG,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QAE/C,OAAO,CAAC,QAAyB,EAAE,QAAwB,EAAiB,EAAE;YAC5E,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC;YACnC,gGAAgG;YAChG,+FAA+F;YAC/F,IAAI,IAAI;gBAAE,QAAQ,CAAC,GAAG,GAAG,GAAG,aAAa,CAAC,QAAQ,CAAC,MAAM,IAAI,GAAG,QAAQ,CAAC,GAAG,IAAI,GAAG,EAAE,CAAC;YACtF,OAAO,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QACtC,CAAC,CAAC;IACJ,CAAC;CACF,CAAC","sourcesContent":["import { getRequestListener } from '@hono/node-server';\nimport type { Hono } from 'hono';\nimport type { IncomingMessage, ServerResponse } from 'node:http';\nimport type { DeployRuntime } from '../contract.js';\nimport { fileSystemRuntime } from '../filesystem.js';\n\n/**\n * The scheme the browser used, which the socket cannot answer for: Vercel terminates TLS at the edge and\n * reaches the function over plain HTTP, so an `https://` request arrives on an unencrypted socket and every\n * absolute URL the app derived from it would carry the wrong scheme — a redirect back to `http://`, an\n * origin check comparing against one.\n *\n * Read without `trustProxy`, unlike `publicUrl`, because on this target the header is not\n * client-supplied: the function is reachable only through Vercel's edge, which sets it on every request. The\n * config field stays what it is — the answer for a proxy *you* put in front, which the framework cannot vouch\n * for. Falls back to `https`, the only scheme a deployment is served on.\n */\nfunction browserScheme(incoming: IncomingMessage): string {\n const header = incoming.headers['x-forwarded-proto'];\n const value = (Array.isArray(header) ? header[0] : header)?.split(',')[0]?.trim();\n return value === 'http' ? 'http' : 'https';\n}\n\n/**\n * Vercel, as a single Node function fed by the platform's own router.\n *\n * The function is invoked the way `launcherType: 'Nodejs'` invokes one — with `(IncomingMessage,\n * ServerResponse)`, not a web `Request`. That is the whole of the Build Output API's Node contract; the\n * `Request`/`Response` handler shape the platform documents elsewhere belongs to the `@vercel/node` builder,\n * which compiles and wraps a source file, and a `--prebuilt` upload never runs it. So the handoff converts,\n * and `hono/vercel`'s `handle` — a pass-through that forwards its first argument straight to `app.fetch` —\n * cannot be what does it.\n *\n * `/_static` and `public/` are in the static output, and `config.json` puts the filesystem handler ahead of the\n * function, so mounting them here would be dead weight. Prerendered pages are *not* static output — one URL\n * answers with a document or a flight payload on the `RSC` request header, and a path-keyed CDN cannot choose — so\n * they ship inside the function and are read from its read-only disk, exactly as on a server.\n */\nexport const runtime: DeployRuntime = {\n ...fileSystemRuntime,\n\n mountStaticAssets(): void {\n // Served from `.vercel/output/static` before the function runs.\n },\n\n mountPublicFallback(): void {\n // As above: `public/` is in the static output and `{ handle: 'filesystem' }` is matched ahead of this\n // function, so nothing here could ever answer for one of those paths. Stated as an override rather than\n // left to fall out of `dist/public` not being uploaded, because that would make the behaviour incidental\n // to a `cpSync` in `build.ts` instead of a decision.\n //\n // The one thing this hands to the platform: resolving a directory to its `index.html`. Vercel's static\n // handler does that; `serveStatic`, which the filesystem targets use, is no longer in the path.\n },\n\n serveApp(app: Hono): unknown {\n // The same conversion `rshono start` runs on, so a request is built here exactly as it is on the `node`\n // target — including a streamed response body, which `supportsResponseStreaming` in `.vc-config.json`\n // then keeps unbuffered on the way out.\n const listener = getRequestListener(app.fetch);\n\n return (incoming: IncomingMessage, outgoing: ServerResponse): Promise<void> => {\n const host = incoming.headers.host;\n // Left alone when there is no `Host`, so the listener answers with its own 400 rather than this\n // building `https://undefined/…` and the app rejecting a URL it should never have been handed.\n if (host) incoming.url = `${browserScheme(incoming)}://${host}${incoming.url ?? '/'}`;\n return listener(incoming, outgoing);\n };\n },\n};\n"]}
|
package/package.json
CHANGED