@rshono/core 1.0.0-rc.2 → 1.0.0-rc.4
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 +45 -29
- package/dist/builder/rspack-config.d.ts +3 -3
- package/dist/builder/rspack-config.js +3 -3
- package/dist/builder/rspack-config.js.map +1 -1
- package/dist/cli/build.d.ts +2 -2
- package/dist/cli/build.js.map +1 -1
- package/dist/cli/dev.d.ts +2 -2
- package/dist/cli/dev.js.map +1 -1
- package/dist/cli/index.js +11 -10
- package/dist/cli/index.js.map +1 -1
- package/dist/config.d.ts +4 -17
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js.map +1 -1
- package/dist/deploy/cloudflare/build.js +1 -1
- package/dist/deploy/cloudflare/build.js.map +1 -1
- package/dist/deploy/cloudflare/runtime.d.ts.map +1 -1
- package/dist/deploy/cloudflare/runtime.js +7 -37
- package/dist/deploy/cloudflare/runtime.js.map +1 -1
- package/dist/deploy/contract.d.ts +14 -13
- package/dist/deploy/contract.d.ts.map +1 -1
- package/dist/deploy/contract.js.map +1 -1
- package/dist/deploy/filesystem.d.ts +1 -1
- package/dist/deploy/filesystem.d.ts.map +1 -1
- package/dist/deploy/filesystem.js +1 -3
- package/dist/deploy/filesystem.js.map +1 -1
- package/dist/deploy/node/runtime.d.ts +6 -2
- package/dist/deploy/node/runtime.d.ts.map +1 -1
- package/dist/deploy/node/runtime.js +30 -5
- package/dist/deploy/node/runtime.js.map +1 -1
- package/dist/deploy/presets.d.ts +5 -1
- package/dist/deploy/presets.d.ts.map +1 -1
- package/dist/deploy/presets.js +15 -28
- package/dist/deploy/presets.js.map +1 -1
- package/dist/deploy/vercel/runtime.d.ts.map +1 -1
- package/dist/deploy/vercel/runtime.js +0 -3
- package/dist/deploy/vercel/runtime.js.map +1 -1
- package/dist/index.d.ts +4 -9
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -3
- package/dist/index.js.map +1 -1
- package/dist/router.d.ts +14 -15
- package/dist/router.d.ts.map +1 -1
- package/dist/router.js +5 -6
- package/dist/router.js.map +1 -1
- package/dist/runtime/client.d.ts +5 -6
- package/dist/runtime/client.d.ts.map +1 -1
- package/dist/runtime/client.js +5 -6
- package/dist/runtime/client.js.map +1 -1
- package/dist/runtime/context.d.ts +36 -40
- package/dist/runtime/context.d.ts.map +1 -1
- package/dist/runtime/context.js +41 -53
- package/dist/runtime/context.js.map +1 -1
- package/dist/runtime/entry.client.d.ts +4 -0
- package/dist/runtime/entry.client.d.ts.map +1 -1
- package/dist/runtime/entry.client.js +161 -147
- package/dist/runtime/entry.client.js.map +1 -1
- package/dist/runtime/entry.rsc.d.ts.map +1 -1
- package/dist/runtime/entry.rsc.js +80 -63
- package/dist/runtime/entry.rsc.js.map +1 -1
- package/dist/runtime/entry.ssr.d.ts +9 -1
- package/dist/runtime/entry.ssr.d.ts.map +1 -1
- package/dist/runtime/entry.ssr.js +36 -18
- package/dist/runtime/entry.ssr.js.map +1 -1
- package/dist/runtime/flight-inject.d.ts +31 -0
- package/dist/runtime/flight-inject.d.ts.map +1 -0
- package/dist/runtime/flight-inject.js +221 -0
- package/dist/runtime/flight-inject.js.map +1 -0
- package/dist/runtime/navigation.d.ts +10 -39
- package/dist/runtime/navigation.d.ts.map +1 -1
- package/dist/runtime/navigation.js +7 -53
- package/dist/runtime/navigation.js.map +1 -1
- package/dist/runtime/request.d.ts +6 -0
- package/dist/runtime/request.d.ts.map +1 -1
- package/dist/runtime/request.js +8 -0
- package/dist/runtime/request.js.map +1 -1
- package/dist/runtime/server.d.ts +2 -2
- package/dist/runtime/server.d.ts.map +1 -1
- package/dist/runtime/server.js +2 -2
- package/dist/runtime/server.js.map +1 -1
- package/dist/server/headers.d.ts +9 -9
- package/dist/server/headers.js +9 -9
- package/dist/server/headers.js.map +1 -1
- package/dist/server/load-config.d.ts +2 -2
- package/dist/server/load-config.d.ts.map +1 -1
- package/dist/server/load-config.js +22 -11
- package/dist/server/load-config.js.map +1 -1
- package/dist/server/prerendered.d.ts +52 -9
- package/dist/server/prerendered.d.ts.map +1 -1
- package/dist/server/prerendered.js +57 -0
- package/dist/server/prerendered.js.map +1 -1
- package/dist/server/server-config.d.ts +11 -18
- package/dist/server/server-config.d.ts.map +1 -1
- package/dist/server/server-config.js +9 -12
- package/dist/server/server-config.js.map +1 -1
- package/dist/server/ssg.d.ts +2 -2
- package/dist/server/ssg.d.ts.map +1 -1
- package/dist/server/ssg.js +11 -23
- package/dist/server/ssg.js.map +1 -1
- package/package.json +13 -16
- package/dist/deploy/bun/runtime.d.ts +0 -11
- package/dist/deploy/bun/runtime.d.ts.map +0 -1
- package/dist/deploy/bun/runtime.js +0 -22
- package/dist/deploy/bun/runtime.js.map +0 -1
- package/dist/deploy/deno/runtime.d.ts +0 -11
- package/dist/deploy/deno/runtime.d.ts.map +0 -1
- package/dist/deploy/deno/runtime.js +0 -16
- package/dist/deploy/deno/runtime.js.map +0 -1
- package/dist/deploy/listen.d.ts +0 -20
- package/dist/deploy/listen.d.ts.map +0 -1
- package/dist/deploy/listen.js +0 -24
- package/dist/deploy/listen.js.map +0 -1
- package/dist/deploy/netlify/build.d.ts +0 -8
- package/dist/deploy/netlify/build.d.ts.map +0 -1
- package/dist/deploy/netlify/build.js +0 -52
- package/dist/deploy/netlify/build.js.map +0 -1
- package/dist/deploy/netlify/runtime.d.ts +0 -13
- package/dist/deploy/netlify/runtime.d.ts.map +0 -1
- package/dist/deploy/netlify/runtime.js +0 -24
- package/dist/deploy/netlify/runtime.js.map +0 -1
- package/dist/server/compress.d.ts +0 -15
- package/dist/server/compress.d.ts.map +0 -1
- package/dist/server/compress.js +0 -76
- package/dist/server/compress.js.map +0 -1
package/dist/config.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { RspackOptions } from '@rspack/core';
|
|
2
2
|
import type { DeployTarget } from './deploy/contract.js';
|
|
3
|
-
/** Which of the two Rspack compilers the {@link
|
|
3
|
+
/** Which of the two Rspack compilers the {@link RshonoConfig.rspack} hook is being called for. */
|
|
4
4
|
export interface RspackHookContext {
|
|
5
5
|
/** `true` for the server (`target: node`) bundle, `false` for the client (`target: web`) bundle. */
|
|
6
6
|
isServer: boolean;
|
|
@@ -22,7 +22,7 @@ export interface RspackHookContext {
|
|
|
22
22
|
* });
|
|
23
23
|
* ```
|
|
24
24
|
*/
|
|
25
|
-
export interface
|
|
25
|
+
export interface RshonoConfig {
|
|
26
26
|
/**
|
|
27
27
|
* The hosting platform `rshono build` targets. Default `'node'` — a long-lived server process, for
|
|
28
28
|
* a VPS, a container or anywhere else you run `rshono start`.
|
|
@@ -44,13 +44,9 @@ export interface RSHonoConfig {
|
|
|
44
44
|
* The origin is what's used; a path is rejected rather than silently dropped.
|
|
45
45
|
*/
|
|
46
46
|
siteUrl?: string;
|
|
47
|
-
/** Default port for `dev` / `start`. Overridden by the `--port` flag or the `PORT` env var. Default `3000`. */
|
|
48
|
-
port?: number;
|
|
49
|
-
/** Bind address for `start`. Overridden by the `HOST` env var. Default `'0.0.0.0'`. */
|
|
50
|
-
host?: string;
|
|
51
47
|
/**
|
|
52
48
|
* Honour `X-Forwarded-Host` / `X-Forwarded-Proto` when resolving the browser-facing request
|
|
53
|
-
* URL (`
|
|
49
|
+
* URL (`getRequestContext().url`, a page's `url` prop, and the origin the CSRF check compares against).
|
|
54
50
|
*
|
|
55
51
|
* **Off by default, and leave it off unless a proxy you control sets those headers**, because
|
|
56
52
|
* any client can send them: with it on and nothing stripping them at the edge, one request can
|
|
@@ -100,15 +96,6 @@ export interface RSHonoConfig {
|
|
|
100
96
|
* Default `'1mb'`.
|
|
101
97
|
*/
|
|
102
98
|
bodySizeLimit?: string | number | false;
|
|
103
|
-
/** Deadline in milliseconds for a single page render (flight + SSR). Default `10000`. */
|
|
104
|
-
renderTimeout?: number;
|
|
105
|
-
/**
|
|
106
|
-
* Gzip compressible responses (HTML, flight payloads, JSON, CSS, JS). Streaming-safe — each
|
|
107
|
-
* chunk the renderer flushes is flushed on the wire too. Default `true`.
|
|
108
|
-
*
|
|
109
|
-
* Set `false` behind a proxy or CDN that already compresses, to avoid doing the work twice.
|
|
110
|
-
*/
|
|
111
|
-
compress?: boolean;
|
|
112
99
|
/**
|
|
113
100
|
* Escape hatch: mutate the generated Rspack config just before it's compiled. Called once per
|
|
114
101
|
* compiler — inspect {@link RspackHookContext.isServer} to tell them apart. Mutate `config` in
|
|
@@ -117,5 +104,5 @@ export interface RSHonoConfig {
|
|
|
117
104
|
rspack?: (config: RspackOptions, ctx: RspackHookContext) => RspackOptions | void;
|
|
118
105
|
}
|
|
119
106
|
/** Identity helper that types a config object — gives editor autocomplete without an explicit annotation. */
|
|
120
|
-
export declare function defineConfig(config:
|
|
107
|
+
export declare function defineConfig(config: RshonoConfig): RshonoConfig;
|
|
121
108
|
//# sourceMappingURL=config.d.ts.map
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,kGAAkG;AAClG,MAAM,WAAW,iBAAiB;IAChC,oGAAoG;IACpG,QAAQ,EAAE,OAAO,CAAC;IAClB,+DAA+D;IAC/D,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAClD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAEzD,kGAAkG;AAClG,MAAM,WAAW,iBAAiB;IAChC,oGAAoG;IACpG,QAAQ,EAAE,OAAO,CAAC;IAClB,+DAA+D;IAC/D,KAAK,EAAE,OAAO,CAAC;CAChB;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,YAAY;IAC3B;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,YAAY,CAAC;IACtB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;;;;;;;OAUG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;OAGG;IACH,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B;;;;OAIG;IACH,GAAG,CAAC,EAAE,OAAO,CAAC;IACd;;;;;;;;;;;;;;;;OAgBG;IACH,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACvC;;;;OAIG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,KAAK,CAAC;IACxC;;;;OAIG;IACH,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,iBAAiB,KAAK,aAAa,GAAG,IAAI,CAAC;CAClF;AAED,6GAA6G;AAC7G,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,YAAY,CAE/D"}
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AA4GA,6GAA6G;AAC7G,MAAM,UAAU,YAAY,CAAC,MAAoB;IAC/C,OAAO,MAAM,CAAC;AAChB,CAAC","sourcesContent":["import type { RspackOptions } from '@rspack/core';\nimport type { DeployTarget } from './deploy/contract.js';\n\n/** Which of the two Rspack compilers the {@link RshonoConfig.rspack} hook is being called for. */\nexport interface RspackHookContext {\n /** `true` for the server (`target: node`) bundle, `false` for the client (`target: web`) bundle. */\n isServer: boolean;\n /** `true` under `rshono dev`, `false` under `rshono build`. */\n isDev: boolean;\n}\n\n/**\n * Project configuration for rshono, default-exported from `rshono.config.ts` at the project root\n * (`.js` / `.mjs` also work). Every field is optional; omit the file entirely to accept all defaults.\n *\n * @example\n * ```ts\n * import { defineConfig } from '@rshono/core';\n *\n * export default defineConfig({\n * csp: true,\n * bodySizeLimit: '4mb',\n * allowedOrigins: ['https://admin.example.com'],\n * });\n * ```\n */\nexport interface RshonoConfig {\n /**\n * The hosting platform `rshono build` targets. Default `'node'` — a long-lived server process, for\n * a VPS, a container or anywhere else you run `rshono start`.\n *\n * Overridden by the `--deploy` flag or the `RSHONO_DEPLOY` env var, so one config can still be\n * built for more than one place. `rshono dev` ignores it entirely and always runs the Node dev\n * server.\n */\n deploy?: DeployTarget;\n /**\n * The public origin the site is served from, e.g. `'https://example.com'`.\n *\n * Only used when prerendering `render: 'static'` routes. A prerendered page is one fixed file\n * handed to everyone, so any absolute URL inside it has to be decided at build time — there is no\n * request to read a `Host` from. That is what a page's `url` prop is, so without this a static\n * page bakes in `http://localhost` wherever it builds a canonical tag, an absolute link or an\n * `og:url`. Dynamic routes are unaffected: they resolve the URL per request.\n *\n * The origin is what's used; a path is rejected rather than silently dropped.\n */\n siteUrl?: string;\n /**\n * Honour `X-Forwarded-Host` / `X-Forwarded-Proto` when resolving the browser-facing request\n * URL (`getRequestContext().url`, a page's `url` prop, and the origin the CSRF check compares against).\n *\n * **Off by default, and leave it off unless a proxy you control sets those headers**, because\n * any client can send them: with it on and nothing stripping them at the edge, one request can\n * point every absolute URL your app builds at an attacker's host (and poison a shared cache).\n * Turn it on when you terminate TLS or rewrite `Host` at a reverse proxy / load balancer.\n * Always `true` under `rshono dev`, where the framework's own proxy sets them and binds to\n * localhost. Default `false`.\n */\n trustProxy?: boolean;\n /**\n * CSRF origin check on server-action POSTs — rejects a cross-origin request with 403.\n * Turn off only behind a gateway that already enforces it. Default `true`.\n */\n checkOrigin?: boolean;\n /**\n * Extra origins allowed to post server actions, in addition to the app's own origin.\n * Accepts full origins or bare hosts, e.g. `['https://admin.example.com', 'localhost:4000']`.\n */\n allowedOrigins?: string[];\n /**\n * Send a strict per-request-nonce `Content-Security-Policy` with every HTML document.\n * While enabled, `render: 'static'` routes render per request (a prerendered file can't carry a\n * per-request nonce). Default `false`.\n */\n csp?: boolean;\n /**\n * Directives merged over the built-in {@link csp} policy, which is deliberately strict\n * (`default-src 'self'`, no framing, no plugins) and so blocks third-party images, fonts and\n * API hosts until you widen it here. Set a directive to `''` to drop it entirely.\n *\n * The per-request nonce is always appended to `script-src`, whatever you put there.\n * Ignored unless `csp` is `true`.\n *\n * @example\n * ```ts\n * cspDirectives: {\n * 'img-src': \"'self' data: https://images.example.com\",\n * 'font-src': \"'self' https://fonts.gstatic.com\",\n * 'frame-ancestors': \"'self'\",\n * }\n * ```\n */\n cspDirectives?: Record<string, string>;\n /**\n * Max server-action request body before it's rejected with 413 — a memory-exhaustion guard.\n * A number is bytes; a string carries a unit (`'512kb'`, `'4mb'`); `false` (or `0`) disables the cap.\n * Default `'1mb'`.\n */\n bodySizeLimit?: string | number | false;\n /**\n * Escape hatch: mutate the generated Rspack config just before it's compiled. Called once per\n * compiler — inspect {@link RspackHookContext.isServer} to tell them apart. Mutate `config` in\n * place and return nothing, or return a replacement.\n */\n rspack?: (config: RspackOptions, ctx: RspackHookContext) => RspackOptions | void;\n}\n\n/** Identity helper that types a config object — gives editor autocomplete without an explicit annotation. */\nexport function defineConfig(config: RshonoConfig): RshonoConfig {\n return config;\n}\n"]}
|
|
@@ -32,7 +32,7 @@ function wranglerConfig(rootDir, today) {
|
|
|
32
32
|
name: workerName(rootDir),
|
|
33
33
|
main: 'dist/server/main.mjs',
|
|
34
34
|
compatibility_date: today,
|
|
35
|
-
// AsyncLocalStorage — how the framework binds the request context that `
|
|
35
|
+
// AsyncLocalStorage — how the framework binds the request context that `getRequestContext()` reads.
|
|
36
36
|
compatibility_flags: ['nodejs_compat'],
|
|
37
37
|
assets: {
|
|
38
38
|
directory: `dist/${ASSETS_DIR.split(/[\\/]/).join('/')}`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/deploy/cloudflare/build.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACvE,OAAO,EAAE,EAAE,EAAE,MAAM,kBAAkB,CAAC;AACtC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAG3C,2GAA2G;AAC3G,MAAM,UAAU,GAAG,IAAI,CAAC,YAAY,EAAE,QAAQ,CAAC,CAAC;AAEhD,MAAM,cAAc,GAAG,CAAC,gBAAgB,EAAE,eAAe,EAAE,eAAe,CAAC,CAAC;AAE5E;;;;;;;GAOG;AACH,MAAM,YAAY,GAAG;;;;;CAKpB,CAAC;AAEF,6EAA6E;AAC7E,SAAS,UAAU,CAAC,OAAe;IACjC,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC;SAC3B,WAAW,EAAE;SACb,OAAO,CAAC,cAAc,EAAE,GAAG,CAAC;SAC5B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC,CAAC;IAC3B,OAAO,IAAI,IAAI,YAAY,CAAC;AAC9B,CAAC;AAED,SAAS,cAAc,CAAC,OAAe,EAAE,KAAa;IACpD,OAAO,GAAG,IAAI,CAAC,SAAS,CACtB;QACE,OAAO,EAAE,0CAA0C;QACnD,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC;QACzB,IAAI,EAAE,sBAAsB;QAC5B,kBAAkB,EAAE,KAAK;QACzB,
|
|
1
|
+
{"version":3,"file":"build.js","sourceRoot":"","sources":["../../../src/deploy/cloudflare/build.ts"],"names":[],"mappings":"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","sourcesContent":["import { cpSync, existsSync, mkdirSync, writeFileSync } from 'node:fs';\nimport { rm } from 'node:fs/promises';\nimport { basename, join } from 'node:path';\nimport type { DeployBuildContext } from '../presets.js';\n\n/** Wrangler serves one directory, so the three kinds of asset the build produces are assembled into it. */\nconst ASSETS_DIR = join('cloudflare', 'assets');\n\nconst WRANGLER_FILES = ['wrangler.jsonc', 'wrangler.json', 'wrangler.toml'];\n\n/**\n * Caching and crawler rules for the assembled tree, in the file Workers Assets reads them from.\n *\n * The hashed bundle is immutable by construction, which is the one thing the CDN cannot infer. The\n * prerender tree is reachable under its own prefix (see `SSG_PREFIX` in `runtime.ts`) and holds a\n * second copy of pages that already have real URLs, so it is marked `noindex` rather than left for a\n * crawler to find twice.\n */\nconst HEADERS_FILE = `/_static/*\n Cache-Control: public, max-age=31536000, immutable\n\n/__ssg/*\n X-Robots-Tag: noindex\n`;\n\n/** A Wrangler worker name: lowercase, and only the characters it accepts. */\nfunction workerName(rootDir: string): string {\n const name = basename(rootDir)\n .toLowerCase()\n .replace(/[^a-z0-9-]+/g, '-')\n .replace(/^-+|-+$/g, '');\n return name || 'rshono-app';\n}\n\nfunction wranglerConfig(rootDir: string, today: string): string {\n return `${JSON.stringify(\n {\n $schema: 'node_modules/wrangler/config-schema.json',\n name: workerName(rootDir),\n main: 'dist/server/main.mjs',\n compatibility_date: today,\n // AsyncLocalStorage — how the framework binds the request context that `getRequestContext()` reads.\n compatibility_flags: ['nodejs_compat'],\n assets: {\n directory: `dist/${ASSETS_DIR.split(/[\\\\/]/).join('/')}`,\n // Read by the worker for `public/` files and prerendered pages; the CDN still answers first.\n binding: 'ASSETS',\n },\n },\n null,\n 2,\n )}\\n`;\n}\n\n/**\n * Arranges a Workers deployment: one assets directory holding everything the CDN should serve, and a\n * `wrangler.jsonc` to deploy with if the project has no Wrangler config of its own.\n */\nexport async function finalizeCloudflareBuild(ctx: DeployBuildContext): Promise<void> {\n const assetsDir = join(ctx.distDir, ASSETS_DIR);\n // Rebuilt from scratch, so a file deleted from `public/` or a route that stopped being static does\n // not survive in the deployed tree.\n await rm(assetsDir, { recursive: true, force: true });\n mkdirSync(assetsDir, { recursive: true });\n\n cpSync(ctx.staticDir, join(assetsDir, '_static'), { recursive: true });\n if (ctx.publicDir) cpSync(ctx.publicDir, assetsDir, { recursive: true });\n if (existsSync(ctx.ssgDir)) cpSync(ctx.ssgDir, join(assetsDir, '__ssg'), { recursive: true });\n\n const headersFile = join(assetsDir, '_headers');\n if (existsSync(headersFile)) {\n console.warn(` ⚠ public/_headers is in the way of the generated one — /_static/* will not be marked immutable.`);\n } else {\n writeFileSync(headersFile, HEADERS_FILE);\n }\n\n const existing = WRANGLER_FILES.find((file) => existsSync(join(ctx.rootDir, file)));\n if (!existing) {\n const today = new Date().toISOString().slice(0, 10);\n writeFileSync(join(ctx.rootDir, 'wrangler.jsonc'), wranglerConfig(ctx.rootDir, today));\n console.log(' • wrote wrangler.jsonc (yours now — edit freely, the build will not touch it again)');\n }\n\n console.log(` • assembled ${join('dist', ASSETS_DIR)} for Workers Assets`);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/deploy/cloudflare/runtime.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/deploy/cloudflare/runtime.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAuDpD;;;;;;GAMG;AACH,eAAO,MAAM,OAAO,EAAE,aAgDrB,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { prerenderedRelPath } from '../../server/prerendered.js';
|
|
1
|
+
import { createPageCache, prerenderedRelPath, toPrerenderedPage } from '../../server/prerendered.js';
|
|
2
2
|
/**
|
|
3
3
|
* Where `finalize` puts the prerendered pages inside the assets directory.
|
|
4
4
|
*
|
|
@@ -41,27 +41,8 @@ async function assetResponse(c, path, headers) {
|
|
|
41
41
|
function serveAsset(asset) {
|
|
42
42
|
return new Response(asset.body, asset);
|
|
43
43
|
}
|
|
44
|
-
/**
|
|
45
|
-
|
|
46
|
-
*
|
|
47
|
-
* Web Crypto rather than `node:crypto`: this module is compiled for `workerd`, and the digest is the
|
|
48
|
-
* one thing here that has a platform-neutral form.
|
|
49
|
-
*/
|
|
50
|
-
async function weakEtag(body) {
|
|
51
|
-
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(body));
|
|
52
|
-
const bytes = String.fromCharCode(...new Uint8Array(digest));
|
|
53
|
-
const base64url = btoa(bytes).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, '');
|
|
54
|
-
return `W/"${base64url.slice(0, 22)}"`;
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Prerendered pages, keyed by the path that produced them.
|
|
58
|
-
*
|
|
59
|
-
* Per isolate rather than per process, and bounded for the same reason the Node cache is: a site with
|
|
60
|
-
* thousands of prerendered pages should keep a working set, not the whole build. Only *hits* are
|
|
61
|
-
* cached, so nobody can mint entries by requesting paths that do not exist.
|
|
62
|
-
*/
|
|
63
|
-
const pageCache = new Map();
|
|
64
|
-
const MAX_CACHED_PAGES = 128;
|
|
44
|
+
/** Prerendered pages, keyed by the path that produced them. Per isolate rather than per process. */
|
|
45
|
+
const pageCache = createPageCache();
|
|
65
46
|
/**
|
|
66
47
|
* Cloudflare Workers: the host owns the process, so there is nothing to listen on; the CDN owns the
|
|
67
48
|
* assets, so there is nothing to serve from disk; and there is no filesystem, so `.env` files and a
|
|
@@ -72,7 +53,7 @@ const MAX_CACHED_PAGES = 128;
|
|
|
72
53
|
export const runtime = {
|
|
73
54
|
serveApp(app) {
|
|
74
55
|
// What Workers looks for on the default export. `app.fetch` already takes `(request, env, ctx)`,
|
|
75
|
-
// which is why bindings arrive as `c.env` — and so why `
|
|
56
|
+
// which is why bindings arrive as `c.env` — and so why `getRequestContext().env` sees them.
|
|
76
57
|
return { fetch: app.fetch };
|
|
77
58
|
},
|
|
78
59
|
mountStaticAssets(app) {
|
|
@@ -105,25 +86,14 @@ export const runtime = {
|
|
|
105
86
|
const asset = await assetResponse(c, `${SSG_PREFIX}/${relPath}`);
|
|
106
87
|
if (!asset || asset.status !== 200)
|
|
107
88
|
return null;
|
|
108
|
-
|
|
109
|
-
const page =
|
|
110
|
-
body,
|
|
111
|
-
contentLength: String(new TextEncoder().encode(body).byteLength),
|
|
112
|
-
// The store's own validator where it has one — it already describes these exact bytes. Weakened
|
|
113
|
-
// because compression downstream would make a strong one wrong for the compressed encoding.
|
|
114
|
-
etag: asset.headers.get('etag')?.replace(/^(?!W\/)/, 'W/') ?? (await weakEtag(body)),
|
|
115
|
-
};
|
|
89
|
+
// The store's own validator where it has one — it already describes these exact bytes.
|
|
90
|
+
const page = await toPrerenderedPage(new Uint8Array(await asset.arrayBuffer()), asset.headers.get('etag'));
|
|
116
91
|
pageCache.set(key, page);
|
|
117
|
-
if (pageCache.size > MAX_CACHED_PAGES)
|
|
118
|
-
pageCache.delete(pageCache.keys().next().value);
|
|
119
92
|
return page;
|
|
120
93
|
},
|
|
121
|
-
// Cloudflare compresses on the way out at the edge, and `workerd` has no `node:zlib` stream to do
|
|
122
|
-
// it with anyway. Doing it here would only spend CPU on bytes the edge is about to re-encode.
|
|
123
|
-
compress: null,
|
|
124
94
|
loadEnv() {
|
|
125
95
|
// Nothing to load: a Worker has no filesystem and no `.env`. Secrets and bindings arrive per
|
|
126
|
-
// request as `c.env`, which `
|
|
96
|
+
// request as `c.env`, which `getRequestContext().env` already merges — see `runtime/context.ts`.
|
|
127
97
|
},
|
|
128
98
|
};
|
|
129
99
|
//# sourceMappingURL=runtime.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/deploy/cloudflare/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Context, Hono } from 'hono';\nimport { prerenderedRelPath, type PrerenderedPage } from '../../server/prerendered.js';\nimport type { DeployRuntime } from '../contract.js';\n\n/**\n * Where `finalize` puts the prerendered pages inside the assets directory.\n *\n * A prefix of its own, rather than the pages' real URLs, is what keeps every page URL reaching the\n * worker: one URL answers with a document or a flight payload depending on `Accept`, and a CDN keyed\n * on the path alone cannot make that choice. Assets miss, the worker runs, the worker negotiates.\n *\n * The bytes are public either way — they are a public page — but they are also reachable under this\n * path, so `finalize` writes a `_headers` rule marking the tree `noindex` rather than leaving a\n * crawler to find the same page twice.\n */\nconst SSG_PREFIX = '/__ssg';\n\n/** The Workers Assets binding, as much of it as this file uses. */\ninterface AssetsBinding {\n fetch(request: Request): Promise<Response>;\n}\n\nfunction assetsBinding(c: Context): AssetsBinding | null {\n const binding = (c.env as { ASSETS?: AssetsBinding } | undefined)?.ASSETS;\n return binding && typeof binding.fetch === 'function' ? binding : null;\n}\n\n/**\n * Asks the assets binding for one path, or `null` when there is no binding at all — so a caller can\n * tell \"this deployment serves its assets some other way\" from \"that file is not there\".\n *\n * `headers` is passed on only where the *client's* conditional and range requests should be answered\n * by the store: forwarding an `If-None-Match` while fetching a page to serve would come back 304 with\n * no body, which is a useless answer to \"give me this page\".\n */\nasync function assetResponse(c: Context, path: string, headers?: Headers): Promise<Response | null> {\n const binding = assetsBinding(c);\n if (!binding) return null;\n // Resolved against the request so the asset request carries this deployment's own origin; only the\n // path is ever used to look one up.\n const url = new URL(path, c.req.url);\n return binding.fetch(new Request(url, { method: 'GET', headers }));\n}\n\n/**\n * Hands an asset response back as the app's own.\n *\n * Rebuilt rather than returned as-is because a `Response` that came from `fetch` has immutable\n * headers, and the framework's outermost middleware sets its baseline security headers on the way out.\n */\nfunction serveAsset(asset: Response): Response {\n return new Response(asset.body, asset);\n}\n\n/**\n * A weak `ETag` for a body the asset store gave us no validator for.\n *\n * Web Crypto rather than `node:crypto`: this module is compiled for `workerd`, and the digest is the\n * one thing here that has a platform-neutral form.\n */\nasync function weakEtag(body: string): Promise<string> {\n const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(body));\n const bytes = String.fromCharCode(...new Uint8Array(digest));\n const base64url = btoa(bytes).replace(/\\+/g, '-').replace(/\\//g, '_').replace(/=+$/, '');\n return `W/\"${base64url.slice(0, 22)}\"`;\n}\n\n/**\n * Prerendered pages, keyed by the path that produced them.\n *\n * Per isolate rather than per process, and bounded for the same reason the Node cache is: a site with\n * thousands of prerendered pages should keep a working set, not the whole build. Only *hits* are\n * cached, so nobody can mint entries by requesting paths that do not exist.\n */\nconst pageCache = new Map<string, PrerenderedPage>();\nconst MAX_CACHED_PAGES = 128;\n\n/**\n * Cloudflare Workers: the host owns the process, so there is nothing to listen on; the CDN owns the\n * assets, so there is nothing to serve from disk; and there is no filesystem, so `.env` files and a\n * streaming gzip are both out.\n *\n * What is left is the assets binding, which every read here goes through.\n */\nexport const runtime: DeployRuntime = {\n serveApp(app: Hono): unknown {\n // What Workers looks for on the default export. `app.fetch` already takes `(request, env, ctx)`,\n // which is why bindings arrive as `c.env` — and so why `getContext().env` sees them.\n return { fetch: app.fetch };\n },\n\n mountStaticAssets(app: Hono): void {\n // Normally dead: with the scaffolded config the CDN answers `/_static/*` before the worker is\n // invoked at all. It exists so the deployment is still correct — if slower — under an assets\n // configuration that routes everything to the worker first.\n app.on(['GET', 'HEAD'], '/_static/*', async (c, next) => {\n const asset = await assetResponse(c, c.req.path, c.req.raw.headers);\n return asset && asset.status !== 404 ? serveAsset(asset) : next();\n });\n },\n\n mountPublicFallback(app: Hono): void {\n app.on(['GET', 'HEAD'], '/*', async (c, next) => {\n // The prerender tree lives in the same store; it is reachable directly from the CDN by design,\n // but the app itself only ever serves it through `readPrerendered`, negotiated on `Accept`.\n if (c.req.path.startsWith(`${SSG_PREFIX}/`)) return next();\n const asset = await assetResponse(c, c.req.path, c.req.raw.headers);\n return asset && asset.status !== 404 ? serveAsset(asset) : next();\n });\n },\n\n async readPrerendered(c: Context, variant): Promise<PrerenderedPage | null> {\n const relPath = prerenderedRelPath(c.req.path, variant);\n if (relPath === null) return null;\n\n const key = `${variant}\\0${relPath}`;\n const cached = pageCache.get(key);\n if (cached) return cached;\n\n const asset = await assetResponse(c, `${SSG_PREFIX}/${relPath}`);\n if (!asset || asset.status !== 200) return null;\n\n const body = await asset.text();\n const page: PrerenderedPage = {\n body,\n contentLength: String(new TextEncoder().encode(body).byteLength),\n // The store's own validator where it has one — it already describes these exact bytes. Weakened\n // because compression downstream would make a strong one wrong for the compressed encoding.\n etag: asset.headers.get('etag')?.replace(/^(?!W\\/)/, 'W/') ?? (await weakEtag(body)),\n };\n\n pageCache.set(key, page);\n if (pageCache.size > MAX_CACHED_PAGES) pageCache.delete(pageCache.keys().next().value!);\n return page;\n },\n\n // Cloudflare compresses on the way out at the edge, and `workerd` has no `node:zlib` stream to do\n // it with anyway. Doing it here would only spend CPU on bytes the edge is about to re-encode.\n compress: null,\n\n loadEnv(): void {\n // Nothing to load: a Worker has no filesystem and no `.env`. Secrets and bindings arrive per\n // request as `c.env`, which `getContext().env` already merges — see `runtime/context.ts`.\n },\n};\n"]}
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/deploy/cloudflare/runtime.ts"],"names":[],"mappings":"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","sourcesContent":["import type { Context, Hono } from 'hono';\nimport { createPageCache, prerenderedRelPath, toPrerenderedPage, type PrerenderedPage } from '../../server/prerendered.js';\nimport type { DeployRuntime } from '../contract.js';\n\n/**\n * Where `finalize` puts the prerendered pages inside the assets directory.\n *\n * A prefix of its own, rather than the pages' real URLs, is what keeps every page URL reaching the\n * worker: one URL answers with a document or a flight payload depending on `Accept`, and a CDN keyed\n * on the path alone cannot make that choice. Assets miss, the worker runs, the worker negotiates.\n *\n * The bytes are public either way — they are a public page — but they are also reachable under this\n * path, so `finalize` writes a `_headers` rule marking the tree `noindex` rather than leaving a\n * crawler to find the same page twice.\n */\nconst SSG_PREFIX = '/__ssg';\n\n/** The Workers Assets binding, as much of it as this file uses. */\ninterface AssetsBinding {\n fetch(request: Request): Promise<Response>;\n}\n\nfunction assetsBinding(c: Context): AssetsBinding | null {\n const binding = (c.env as { ASSETS?: AssetsBinding } | undefined)?.ASSETS;\n return binding && typeof binding.fetch === 'function' ? binding : null;\n}\n\n/**\n * Asks the assets binding for one path, or `null` when there is no binding at all — so a caller can\n * tell \"this deployment serves its assets some other way\" from \"that file is not there\".\n *\n * `headers` is passed on only where the *client's* conditional and range requests should be answered\n * by the store: forwarding an `If-None-Match` while fetching a page to serve would come back 304 with\n * no body, which is a useless answer to \"give me this page\".\n */\nasync function assetResponse(c: Context, path: string, headers?: Headers): Promise<Response | null> {\n const binding = assetsBinding(c);\n if (!binding) return null;\n // Resolved against the request so the asset request carries this deployment's own origin; only the\n // path is ever used to look one up.\n const url = new URL(path, c.req.url);\n return binding.fetch(new Request(url, { method: 'GET', headers }));\n}\n\n/**\n * Hands an asset response back as the app's own.\n *\n * Rebuilt rather than returned as-is because a `Response` that came from `fetch` has immutable\n * headers, and the framework's outermost middleware sets its baseline security headers on the way out.\n */\nfunction serveAsset(asset: Response): Response {\n return new Response(asset.body, asset);\n}\n\n/** Prerendered pages, keyed by the path that produced them. Per isolate rather than per process. */\nconst pageCache = createPageCache();\n\n/**\n * Cloudflare Workers: the host owns the process, so there is nothing to listen on; the CDN owns the\n * assets, so there is nothing to serve from disk; and there is no filesystem, so `.env` files and a\n * streaming gzip are both out.\n *\n * What is left is the assets binding, which every read here goes through.\n */\nexport const runtime: DeployRuntime = {\n serveApp(app: Hono): unknown {\n // What Workers looks for on the default export. `app.fetch` already takes `(request, env, ctx)`,\n // which is why bindings arrive as `c.env` — and so why `getRequestContext().env` sees them.\n return { fetch: app.fetch };\n },\n\n mountStaticAssets(app: Hono): void {\n // Normally dead: with the scaffolded config the CDN answers `/_static/*` before the worker is\n // invoked at all. It exists so the deployment is still correct — if slower — under an assets\n // configuration that routes everything to the worker first.\n app.on(['GET', 'HEAD'], '/_static/*', async (c, next) => {\n const asset = await assetResponse(c, c.req.path, c.req.raw.headers);\n return asset && asset.status !== 404 ? serveAsset(asset) : next();\n });\n },\n\n mountPublicFallback(app: Hono): void {\n app.on(['GET', 'HEAD'], '/*', async (c, next) => {\n // The prerender tree lives in the same store; it is reachable directly from the CDN by design,\n // but the app itself only ever serves it through `readPrerendered`, negotiated on `Accept`.\n if (c.req.path.startsWith(`${SSG_PREFIX}/`)) return next();\n const asset = await assetResponse(c, c.req.path, c.req.raw.headers);\n return asset && asset.status !== 404 ? serveAsset(asset) : next();\n });\n },\n\n async readPrerendered(c: Context, variant): Promise<PrerenderedPage | null> {\n const relPath = prerenderedRelPath(c.req.path, variant);\n if (relPath === null) return null;\n\n const key = `${variant}\\0${relPath}`;\n const cached = pageCache.get(key);\n if (cached) return cached;\n\n const asset = await assetResponse(c, `${SSG_PREFIX}/${relPath}`);\n if (!asset || asset.status !== 200) return null;\n\n // The store's own validator where it has one — it already describes these exact bytes.\n const page = await toPrerenderedPage(new Uint8Array(await asset.arrayBuffer()), asset.headers.get('etag'));\n pageCache.set(key, page);\n return page;\n },\n\n loadEnv(): void {\n // Nothing to load: a Worker has no filesystem and no `.env`. Secrets and bindings arrive per\n // request as `c.env`, which `getRequestContext().env` already merges — see `runtime/context.ts`.\n },\n};\n"]}
|
|
@@ -1,13 +1,21 @@
|
|
|
1
|
-
import type { Context, Hono
|
|
1
|
+
import type { Context, Hono } from 'hono';
|
|
2
2
|
import type { PrerenderVariant, PrerenderedPage } from '../server/prerendered.js';
|
|
3
3
|
/**
|
|
4
|
-
* A hosting platform rshono can build for. Selected with {@link
|
|
4
|
+
* A hosting platform rshono can build for. Selected with {@link RshonoConfig.deploy}, the
|
|
5
5
|
* `--deploy` flag or the `RSHONO_DEPLOY` env var, and resolved to a preset by `deploy/presets.ts`.
|
|
6
6
|
*
|
|
7
|
+
* One per *handoff*, which is the thing an app cannot arrange for itself: `node` binds its own port (and
|
|
8
|
+
* so covers a VPS, a container, a PaaS, and — through `node:` compatibility — Bun and Deno);
|
|
9
|
+
* `cloudflare`, `vercel` and `aws-lambda` are each handed a request by their host, in three different
|
|
10
|
+
* shapes, two of which also need a specific on-disk layout and a config file to stream at all.
|
|
11
|
+
*
|
|
12
|
+
* There is deliberately no target whose only content would be "run the Node build". Bun and Deno had one
|
|
13
|
+
* each and that is all they were, so importing the bundle under those runtimes replaces them.
|
|
14
|
+
*
|
|
7
15
|
* `rshono dev` always runs the `node` server whatever this says — the dev server owns the process,
|
|
8
16
|
* watches both compilers and fronts them on one port, none of which a hosting platform provides.
|
|
9
17
|
*/
|
|
10
|
-
export type DeployTarget = 'node' | 'cloudflare' | '
|
|
18
|
+
export type DeployTarget = 'node' | 'cloudflare' | 'vercel' | 'aws-lambda';
|
|
11
19
|
/**
|
|
12
20
|
* Everything the app server needs from the platform it is running on.
|
|
13
21
|
*
|
|
@@ -16,9 +24,9 @@ export type DeployTarget = 'node' | 'cloudflare' | 'bun' | 'deno' | 'vercel' | '
|
|
|
16
24
|
* ever in the bundle. `runtime/entry.rsc.tsx` is written against this interface and nothing else —
|
|
17
25
|
* it is the whole of what "which platform is this" means at request time.
|
|
18
26
|
*
|
|
19
|
-
* The
|
|
20
|
-
*
|
|
21
|
-
*
|
|
27
|
+
* The members are the capabilities that genuinely differ between a host with a disk and one without:
|
|
28
|
+
* who opens the socket, who serves the assets, where a prerendered page is read from, and whether
|
|
29
|
+
* there is a `.env` to load at all.
|
|
22
30
|
*/
|
|
23
31
|
export interface DeployRuntime {
|
|
24
32
|
/**
|
|
@@ -52,13 +60,6 @@ export interface DeployRuntime {
|
|
|
52
60
|
* (see `prerenderedRelPath`).
|
|
53
61
|
*/
|
|
54
62
|
readPrerendered(c: Context, variant: PrerenderVariant): Promise<PrerenderedPage | null>;
|
|
55
|
-
/**
|
|
56
|
-
* Response compression, or `null` where the platform already compresses on the way out (and
|
|
57
|
-
* doing it twice would only cost CPU) or cannot stream a compressor at all.
|
|
58
|
-
*
|
|
59
|
-
* Whether it is *used* is still the app's `compress` setting; this is only whether it is available.
|
|
60
|
-
*/
|
|
61
|
-
compress: MiddlewareHandler | null;
|
|
62
63
|
/** Loads `.env` files, where the platform has a filesystem to read them from. Env is bindings elsewhere. */
|
|
63
64
|
loadEnv(): void;
|
|
64
65
|
}
|
|
@@ -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,
|
|
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;;;;;;;;;;;;;;GAcG;AACH,MAAM,MAAM,YAAY,GAAG,MAAM,GAAG,YAAY,GAAG,QAAQ,GAAG,YAAY,CAAC;AAE3E;;;;;;;;;;;GAWG;AACH,MAAM,WAAW,aAAa;IAC5B;;;;;;;OAOG;IACH,QAAQ,CAAC,GAAG,EAAE,IAAI,GAAG,OAAO,CAAC;IAC7B;;;;;OAKG;IACH,iBAAiB,CAAC,GAAG,EAAE,IAAI,GAAG,IAAI,CAAC;IACnC;;;OAGG;IACH,mBAAmB,CAAC,GAAG,EAAE,IAAI,GAAG,IAAI,CAAC;IACrC;;;;;;;;OAQG;IACH,eAAe,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,eAAe,GAAG,IAAI,CAAC,CAAC;IACxF,4GAA4G;IAC5G,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
|
|
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 can build for. Selected with {@link RshonoConfig.deploy}, the\n * `--deploy` flag or the `RSHONO_DEPLOY` env var, and resolved to a preset by `deploy/presets.ts`.\n *\n * One per *handoff*, which is the thing an app cannot arrange for itself: `node` binds its own port (and\n * so covers a VPS, a container, a PaaS, and — through `node:` compatibility — Bun and Deno);\n * `cloudflare`, `vercel` and `aws-lambda` are each handed a request by their host, in three different\n * shapes, two of which also need a specific on-disk layout and a config file to stream at all.\n *\n * There is deliberately no target whose only content would be \"run the Node build\". Bun and Deno had one\n * each and that is all they were, so importing the bundle under those runtimes replaces them.\n *\n * `rshono dev` always runs the `node` server whatever this says — the dev server owns the process,\n * watches both compilers and fronts them on one port, none of which a hosting platform provides.\n */\nexport type DeployTarget = 'node' | 'cloudflare' | 'vercel' | 'aws-lambda';\n\n/**\n * Everything the app server needs from the platform it is running on.\n *\n * One preset implements this per target, and the `@rshono/deploy` alias resolves to exactly that\n * module at build time (see `builder/rspack-config.ts`), so only the selected platform's code is\n * ever in the bundle. `runtime/entry.rsc.tsx` is written against this interface and nothing else —\n * it is the whole of what \"which platform is this\" means at request time.\n *\n * The members are the capabilities that genuinely differ between a host with a disk and one without:\n * who opens the socket, who serves the assets, where a prerendered page is read from, and whether\n * there is a `.env` to load at all.\n */\nexport interface DeployRuntime {\n /**\n * Hands the assembled app to the platform, and returns whatever the entry module should\n * `export default` there.\n *\n * The two shapes hosting takes, in one call: where rshono owns the process (node, bun, deno) this\n * binds a port and returns nothing; where the host owns it, it returns the export the platform\n * looks for — `{ fetch }` on Workers, a handler function on Vercel/Netlify/Lambda.\n */\n serveApp(app: Hono): unknown;\n /**\n * Mounts the hashed client bundle at `/_static`. A no-op where the platform's own CDN serves it\n * before a request ever reaches the app.\n *\n * Called *before* the app's routes, so the bundle is never shadowed by one.\n */\n mountStaticAssets(app: Hono): void;\n /**\n * Mounts the `public/` fallback at the web root — files served verbatim, and only for paths no\n * route claimed. Called *after* every route for exactly that reason.\n */\n mountPublicFallback(app: Hono): void;\n /**\n * Reads the page prerendered for `c.req.path` by `rshono build`, or `null` when there is none (in\n * which case the route renders per request, which is always a valid answer).\n *\n * Takes the whole {@link Context} rather than just the path because on a platform with no\n * filesystem the store *is* a request-scoped binding — `c.env.ASSETS` on Workers. The path is\n * untrusted either way, so an implementation has to treat traversal as a miss, not a lookup\n * (see `prerenderedRelPath`).\n */\n readPrerendered(c: Context, variant: PrerenderVariant): Promise<PrerenderedPage | null>;\n /** Loads `.env` files, where the platform has a filesystem to read them from. Env is bindings elsewhere. */\n loadEnv(): void;\n}\n"]}
|
|
@@ -2,7 +2,7 @@ import type { DeployRuntime } from './contract.js';
|
|
|
2
2
|
/**
|
|
3
3
|
* Everything a deploy target with a real filesystem does the same way.
|
|
4
4
|
*
|
|
5
|
-
* Node
|
|
5
|
+
* Node and the serverless runtimes that unpack a bundle onto a read-only disk (Vercel, AWS Lambda)
|
|
6
6
|
* differ only in how the finished app is handed over — so each of those presets is this object plus
|
|
7
7
|
* its own {@link DeployRuntime.serveApp}, and the implementations live once, in `server/`.
|
|
8
8
|
*/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filesystem.d.ts","sourceRoot":"","sources":["../../src/deploy/filesystem.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"filesystem.d.ts","sourceRoot":"","sources":["../../src/deploy/filesystem.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAqBnD;;;;;;GAMG;AACH,eAAO,MAAM,iBAAiB,EAAE,IAAI,CAAC,aAAa,EAAE,UAAU,CAiB7D,CAAC"}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
-
import { compress } from '../server/compress.js';
|
|
4
3
|
import { loadEnvFiles } from '../server/load-env.js';
|
|
5
4
|
import { readPrerendered } from '../server/ssg.js';
|
|
6
5
|
import { createPublicFallback, createStaticAssetsApp } from '../server/static.js';
|
|
@@ -23,7 +22,7 @@ const publicDir = isDev ? join(rootDir, 'public') : join(rootDir, 'dist', 'publi
|
|
|
23
22
|
/**
|
|
24
23
|
* Everything a deploy target with a real filesystem does the same way.
|
|
25
24
|
*
|
|
26
|
-
* Node
|
|
25
|
+
* Node and the serverless runtimes that unpack a bundle onto a read-only disk (Vercel, AWS Lambda)
|
|
27
26
|
* differ only in how the finished app is handed over — so each of those presets is this object plus
|
|
28
27
|
* its own {@link DeployRuntime.serveApp}, and the implementations live once, in `server/`.
|
|
29
28
|
*/
|
|
@@ -39,7 +38,6 @@ export const fileSystemRuntime = {
|
|
|
39
38
|
readPrerendered(c, variant) {
|
|
40
39
|
return readPrerendered(ssgDir, c.req.path, variant);
|
|
41
40
|
},
|
|
42
|
-
compress: compress(),
|
|
43
41
|
loadEnv() {
|
|
44
42
|
loadEnvFiles(rootDir);
|
|
45
43
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"filesystem.js","sourceRoot":"","sources":["../../src/deploy/filesystem.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"filesystem.js","sourceRoot":"","sources":["../../src/deploy/filesystem.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAGlF,MAAM,KAAK,GAAG,iBAAiB,CAAC,KAAK,CAAC;AAEtC;;;;;;;;;GASG;AACH,MAAM,OAAO,GAAG,IAAI,CAAC,OAAO,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AAEtD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;AAClD,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,KAAK,CAAC,CAAC;AAC5C,kHAAkH;AAClH,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,CAAC;AAEpF;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,iBAAiB,GAAoC;IAChE,iBAAiB,CAAC,GAAS;QACzB,GAAG,CAAC,KAAK,CAAC,UAAU,EAAE,qBAAqB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IAC3E,CAAC;IAED,mBAAmB,CAAC,GAAS;QAC3B,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;YAAE,OAAO;QACnC,GAAG,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,EAAE,IAAI,EAAE,oBAAoB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;IAClF,CAAC;IAED,eAAe,CAAC,CAAC,EAAE,OAAO;QACxB,OAAO,eAAe,CAAC,MAAM,EAAE,CAAC,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;IACtD,CAAC;IAED,OAAO;QACL,YAAY,CAAC,OAAO,CAAC,CAAC;IACxB,CAAC;CACF,CAAC","sourcesContent":["import type { Hono } from 'hono';\nimport { existsSync } from 'node:fs';\nimport { join } from 'node:path';\nimport { loadEnvFiles } from '../server/load-env.js';\nimport { readPrerendered } from '../server/ssg.js';\nimport { createPublicFallback, createStaticAssetsApp } from '../server/static.js';\nimport type { DeployRuntime } from './contract.js';\n\nconst isDev = __RSHONO_CONFIG__.isDev;\n\n/**\n * The project root, derived from where the bundle itself ended up: `rshono build` writes the server\n * bundle to `<root>/dist/server/main.mjs`, and this module is bundled into it, which makes\n * `import.meta.dirname` `<root>/dist/server` at runtime.\n *\n * Derived rather than baked in at build time on purpose: an absolute build-time path would tie the\n * output to the machine that produced it, and building in CI to run somewhere else is the normal case.\n * A preset that relocates the bundle keeps `dist/server/main.mjs` intact inside its own layout for\n * exactly this reason.\n */\nconst rootDir = join(import.meta.dirname, '..', '..');\n\nconst staticDir = join(rootDir, 'dist', 'static');\nconst ssgDir = join(rootDir, 'dist', 'ssg');\n/** `public/` is copied into `dist/` by the build, so a deployed build is self-contained; dev reads the source. */\nconst publicDir = isDev ? join(rootDir, 'public') : join(rootDir, 'dist', 'public');\n\n/**\n * Everything a deploy target with a real filesystem does the same way.\n *\n * Node and the serverless runtimes that unpack a bundle onto a read-only disk (Vercel, AWS Lambda)\n * differ only in how the finished app is handed over — so each of those presets is this object plus\n * its own {@link DeployRuntime.serveApp}, and the implementations live once, in `server/`.\n */\nexport const fileSystemRuntime: Omit<DeployRuntime, 'serveApp'> = {\n mountStaticAssets(app: Hono): void {\n app.route('/_static', createStaticAssetsApp({ root: staticDir, isDev }));\n },\n\n mountPublicFallback(app: Hono): void {\n if (!existsSync(publicDir)) return;\n app.on(['GET', 'HEAD'], '/*', createPublicFallback({ root: publicDir, isDev }));\n },\n\n readPrerendered(c, variant) {\n return readPrerendered(ssgDir, c.req.path, variant);\n },\n\n loadEnv(): void {\n loadEnvFiles(rootDir);\n },\n};\n"]}
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import type { DeployRuntime } from '../contract.js';
|
|
2
2
|
/**
|
|
3
|
-
* Node: a long-lived process that owns its own port, with a filesystem behind every asset. The shape
|
|
4
|
-
*
|
|
3
|
+
* Node: a long-lived process that owns its own port, with a filesystem behind every asset. The shape the
|
|
4
|
+
* framework was built against, and the only target `rshono dev` ever produces.
|
|
5
|
+
*
|
|
6
|
+
* Anything that runs a Node process runs this build — a VPS, a container, a PaaS — and Bun and Deno are
|
|
7
|
+
* expected to as well, since the listener below is `@hono/node-server` and both implement the `node:`
|
|
8
|
+
* APIs it needs. They get no preset of their own: there was nothing in one but this.
|
|
5
9
|
*/
|
|
6
10
|
export declare const runtime: DeployRuntime;
|
|
7
11
|
//# sourceMappingURL=runtime.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/deploy/node/runtime.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../../src/deploy/node/runtime.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAyBpD;;;;;;;GAOG;AACH,eAAO,MAAM,OAAO,EAAE,aA4BrB,CAAC"}
|
|
@@ -1,11 +1,35 @@
|
|
|
1
1
|
import { serve } from '@hono/node-server';
|
|
2
2
|
import { parentPort, workerData } from 'node:worker_threads';
|
|
3
|
+
import { SERVER_DEFAULTS } from '../../server/server-config.js';
|
|
3
4
|
import { onShutdown } from '../../server/shutdown.js';
|
|
4
5
|
import { fileSystemRuntime } from '../filesystem.js';
|
|
5
|
-
|
|
6
|
+
/** Bound to every interface — so the address printed on start is `localhost`, not this. */
|
|
7
|
+
const WILDCARD_HOST = '0.0.0.0';
|
|
6
8
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
+
* Resolves the address to listen on: an explicit override (the dev server, which picks the port for its
|
|
10
|
+
* worker) beats the environment, which beats the built-in default.
|
|
11
|
+
*
|
|
12
|
+
* `PORT` and `HOST` are the whole interface, because that is the deployment convention everywhere this
|
|
13
|
+
* runs — a container, a process manager, a PaaS. `??` rather than `||` so an explicit `PORT=0`, which
|
|
14
|
+
* means "any free port", is honoured.
|
|
15
|
+
*
|
|
16
|
+
* Lives here rather than in a `deploy/listen.ts` of its own because `node` is the only target that
|
|
17
|
+
* binds anything: every other one is handed a request by its host.
|
|
18
|
+
*/
|
|
19
|
+
function listenAddress(overrides) {
|
|
20
|
+
const envPort = process.env.PORT !== undefined ? Number(process.env.PORT) : undefined;
|
|
21
|
+
return {
|
|
22
|
+
port: overrides?.port ?? envPort ?? SERVER_DEFAULTS.port,
|
|
23
|
+
hostname: overrides?.hostname ?? process.env.HOST ?? SERVER_DEFAULTS.host,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Node: a long-lived process that owns its own port, with a filesystem behind every asset. The shape the
|
|
28
|
+
* framework was built against, and the only target `rshono dev` ever produces.
|
|
29
|
+
*
|
|
30
|
+
* Anything that runs a Node process runs this build — a VPS, a container, a PaaS — and Bun and Deno are
|
|
31
|
+
* expected to as well, since the listener below is `@hono/node-server` and both implement the `node:`
|
|
32
|
+
* APIs it needs. They get no preset of their own: there was nothing in one but this.
|
|
9
33
|
*/
|
|
10
34
|
export const runtime = {
|
|
11
35
|
...fileSystemRuntime,
|
|
@@ -16,7 +40,7 @@ export const runtime = {
|
|
|
16
40
|
if (process.env.RSHONO_PRERENDER)
|
|
17
41
|
return;
|
|
18
42
|
// The dev server runs this bundle in a worker thread and picks the port itself, so its choice wins
|
|
19
|
-
// over
|
|
43
|
+
// over the environment.
|
|
20
44
|
const devWorker = workerData;
|
|
21
45
|
const address = listenAddress(devWorker ?? undefined);
|
|
22
46
|
const server = serve({ fetch: app.fetch, ...address }, (info) => {
|
|
@@ -24,7 +48,8 @@ export const runtime = {
|
|
|
24
48
|
parentPort.postMessage({ type: 'ready', port: info.port });
|
|
25
49
|
}
|
|
26
50
|
else {
|
|
27
|
-
|
|
51
|
+
const host = address.hostname === WILDCARD_HOST ? 'localhost' : address.hostname;
|
|
52
|
+
console.log(` ➜ rshono serving on http://${host}:${info.port}`);
|
|
28
53
|
}
|
|
29
54
|
});
|
|
30
55
|
onShutdown(() => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/deploy/node/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"runtime.js","sourceRoot":"","sources":["../../../src/deploy/node/runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAE1C,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,2FAA2F;AAC3F,MAAM,aAAa,GAAG,SAAS,CAAC;AAEhC;;;;;;;;;;GAUG;AACH,SAAS,aAAa,CAAC,SAAgD;IACrE,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IACtF,OAAO;QACL,IAAI,EAAE,SAAS,EAAE,IAAI,IAAI,OAAO,IAAI,eAAe,CAAC,IAAI;QACxD,QAAQ,EAAE,SAAS,EAAE,QAAQ,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,eAAe,CAAC,IAAI;KAC1E,CAAC;AACJ,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,CAAC,MAAM,OAAO,GAAkB;IACpC,GAAG,iBAAiB;IAEpB,QAAQ,CAAC,GAAS;QAChB,+FAA+F;QAC/F,+FAA+F;QAC/F,0BAA0B;QAC1B,IAAI,OAAO,CAAC,GAAG,CAAC,gBAAgB;YAAE,OAAO;QAEzC,mGAAmG;QACnG,wBAAwB;QACxB,MAAM,SAAS,GAAG,UAAyD,CAAC;QAC5E,MAAM,OAAO,GAAG,aAAa,CAAC,SAAS,IAAI,SAAS,CAAC,CAAC;QAEtD,MAAM,MAAM,GAAG,KAAK,CAAC,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,GAAG,OAAO,EAAE,EAAE,CAAC,IAAI,EAAE,EAAE;YAC9D,IAAI,UAAU,EAAE,CAAC;gBACf,UAAU,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YAC7D,CAAC;iBAAM,CAAC;gBACN,MAAM,IAAI,GAAG,OAAO,CAAC,QAAQ,KAAK,aAAa,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;gBACjF,OAAO,CAAC,GAAG,CAAC,gCAAgC,IAAI,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YACnE,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,UAAU,CAAC,GAAG,EAAE;YACd,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YACpC,UAAU,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,EAAE,CAAC;QAClD,CAAC,CAAC,CAAC;IACL,CAAC;CACF,CAAC","sourcesContent":["import { serve } from '@hono/node-server';\nimport type { Hono } from 'hono';\nimport { parentPort, workerData } from 'node:worker_threads';\nimport { SERVER_DEFAULTS } from '../../server/server-config.js';\nimport { onShutdown } from '../../server/shutdown.js';\nimport type { DeployRuntime } from '../contract.js';\nimport { fileSystemRuntime } from '../filesystem.js';\n\n/** Bound to every interface — so the address printed on start is `localhost`, not this. */\nconst WILDCARD_HOST = '0.0.0.0';\n\n/**\n * Resolves the address to listen on: an explicit override (the dev server, which picks the port for its\n * worker) beats the environment, which beats the built-in default.\n *\n * `PORT` and `HOST` are the whole interface, because that is the deployment convention everywhere this\n * runs — a container, a process manager, a PaaS. `??` rather than `||` so an explicit `PORT=0`, which\n * means \"any free port\", is honoured.\n *\n * Lives here rather than in a `deploy/listen.ts` of its own because `node` is the only target that\n * binds anything: every other one is handed a request by its host.\n */\nfunction listenAddress(overrides?: { port?: number; hostname?: string }): { port: number; hostname: string } {\n const envPort = process.env.PORT !== undefined ? Number(process.env.PORT) : undefined;\n return {\n port: overrides?.port ?? envPort ?? SERVER_DEFAULTS.port,\n hostname: overrides?.hostname ?? process.env.HOST ?? SERVER_DEFAULTS.host,\n };\n}\n\n/**\n * Node: a long-lived process that owns its own port, with a filesystem behind every asset. The shape the\n * framework was built against, and the only target `rshono dev` ever produces.\n *\n * Anything that runs a Node process runs this build — a VPS, a container, a PaaS — and Bun and Deno are\n * expected to as well, since the listener below is `@hono/node-server` and both implement the `node:`\n * APIs it needs. They get no preset of their own: there was nothing in one but this.\n */\nexport const runtime: DeployRuntime = {\n ...fileSystemRuntime,\n\n serveApp(app: Hono): undefined {\n // `rshono build` imports this bundle to prerender `render: 'static'` routes. That pass renders\n // through `app.fetch` directly and must not bind a port — nothing is listening for it, and the\n // build would never exit.\n if (process.env.RSHONO_PRERENDER) return;\n\n // The dev server runs this bundle in a worker thread and picks the port itself, so its choice wins\n // over the environment.\n const devWorker = workerData as { port?: number; hostname?: string } | null;\n const address = listenAddress(devWorker ?? undefined);\n\n const server = serve({ fetch: app.fetch, ...address }, (info) => {\n if (parentPort) {\n parentPort.postMessage({ type: 'ready', port: info.port });\n } else {\n const host = address.hostname === WILDCARD_HOST ? 'localhost' : address.hostname;\n console.log(` ➜ rshono serving on http://${host}:${info.port}`);\n }\n });\n\n onShutdown(() => {\n server.close(() => process.exit(0));\n setTimeout(() => process.exit(0), 3000).unref();\n });\n },\n};\n"]}
|
package/dist/deploy/presets.d.ts
CHANGED
|
@@ -59,6 +59,10 @@ export interface DeployPreset {
|
|
|
59
59
|
* Node: a long-lived server process. The generated config is already this shape, so the preset has
|
|
60
60
|
* nothing to contribute — the platform-specific settings still living in `builder/rspack-config.ts`
|
|
61
61
|
* (`target: 'node'`, the externals policy, ESM chunk output) are the Node ones by default.
|
|
62
|
+
*
|
|
63
|
+
* Anywhere that runs a Node process runs this build: a VPS, a container, a PaaS. Bun and Deno are
|
|
64
|
+
* expected to as well, through their `node:` compatibility — they had a preset each, and since neither
|
|
65
|
+
* held anything but a default export, running the bundle (`bun dist/server/main.mjs`) replaces it.
|
|
62
66
|
*/
|
|
63
67
|
export declare const NODE_PRESET: DeployPreset;
|
|
64
68
|
/** Every target `deploy` accepts, for error messages and docs. */
|
|
@@ -74,7 +78,7 @@ export interface DeploySources {
|
|
|
74
78
|
flag?: string;
|
|
75
79
|
/** The `RSHONO_DEPLOY` env var — for a CI job that deploys the same app to more than one place. */
|
|
76
80
|
env?: string;
|
|
77
|
-
/** {@link
|
|
81
|
+
/** {@link RshonoConfig.deploy} from `rshono.config.ts`. */
|
|
78
82
|
config?: string;
|
|
79
83
|
}
|
|
80
84
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../src/deploy/presets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"presets.d.ts","sourceRoot":"","sources":["../../src/deploy/presets.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAElD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAGlD,6FAA6F;AAC7F,MAAM,WAAW,kBAAkB;IACjC,uGAAuG;IACvG,OAAO,EAAE,MAAM,CAAC;IAChB,qBAAqB;IACrB,OAAO,EAAE,MAAM,CAAC;IAChB,6EAA6E;IAC7E,SAAS,EAAE,MAAM,CAAC;IAClB,2FAA2F;IAC3F,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,kGAAkG;IAClG,MAAM,EAAE,MAAM,CAAC;CAChB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,YAAY;IAC3B,QAAQ,CAAC,IAAI,EAAE,YAAY,CAAC;IAC5B;;;OAGG;IACH,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,8EAA8E;IAC9E,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;IAC5B;;;;;;OAMG;IACH,QAAQ,CAAC,iBAAiB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC/C,qFAAqF;IACrF,QAAQ,CAAC,aAAa,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IAC3C;;;;OAIG;IACH,eAAe,CAAC,CAAC,MAAM,EAAE,aAAa,GAAG,IAAI,CAAC;IAC9C;;;;;;OAMG;IACH,QAAQ,CAAC,CAAC,GAAG,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CAC1D;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,WAAW,EAAE,YAIzB,CAAC;AA4DF,kEAAkE;AAClE,eAAO,MAAM,cAAc,EAA2B,YAAY,EAAE,CAAC;AAErE;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE3D;AAED,+DAA+D;AAC/D,MAAM,WAAW,aAAa;IAC5B,2BAA2B;IAC3B,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mGAAmG;IACnG,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,2DAA2D;IAC3D,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,aAAkB,GAAG,YAAY,CAS7E"}
|