@jk2908/solas 0.13.2 → 0.15.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/CHANGELOG.md CHANGED
@@ -1,5 +1,21 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.15.0
4
+
5
+ ### Features
6
+
7
+ - `@jk2908/solas/runtime/node` exports `createHttpRequestListener` for caller-owned `http` and `https` servers and `createHttp2RequestListener` for `http2` compatibility servers, with an exported `Http2RequestListener` type. HTTP/2 pseudo-headers are filtered out of the forwarded fetch `Request`, and `:authority` is used when there is no `host` header.
8
+
9
+ ### Changed
10
+
11
+ - Internal asset-store and MIME helpers moved from `internal/runtimes` to `internal/assets.ts` and `internal/mime.ts`. The public `runtime/*` entries are unchanged.
12
+
13
+ ## 0.14.0
14
+
15
+ ### Breaking
16
+
17
+ - Runtime helpers moved out of `@jk2908/solas/adapters/*`: `serve` is now a named export from `@jk2908/solas/runtime/node`, and `createWorker`/`createCloudflareAssets` are now `@jk2908/solas/runtime/cloudflare`. The old `@jk2908/solas/adapters/node` and `@jk2908/solas/adapters/cloudflare/runtime` entries are removed. `@jk2908/solas/adapters/*` now contains build adapters only.
18
+
3
19
  ## 0.13.2
4
20
 
5
21
  ### Changed
package/README.md CHANGED
@@ -659,18 +659,18 @@ Because workers have no filesystem, the Worker reads its own output through the
659
659
  `cloudflare()` forwards its `cloudflare` option to `@cloudflare/vite-plugin`. To build a Worker manually, `createWorker` composes the entry behaviour, and `createCloudflareAssets` builds the store directly:
660
660
 
661
661
  ```ts
662
- import { createCloudflareAssets } from '@jk2908/solas/adapters/cloudflare/runtime'
662
+ import { createCloudflareAssets } from '@jk2908/solas/runtime/cloudflare'
663
663
 
664
664
  const assets = createCloudflareAssets(env)
665
665
  ```
666
666
 
667
667
  ## Node
668
668
 
669
- `vite dev` and `vite preview` already run the built handler in Node (via `@vitejs/plugin-rsc`'s default server handler), so nothing extra is needed locally. For a production Node server, use `@jk2908/solas/adapters/node`:
669
+ `vite dev` and `vite preview` already run the built handler in Node (via `@vitejs/plugin-rsc`'s default server handler), so nothing extra is needed locally. For a production Node server, use `@jk2908/solas/runtime/node`:
670
670
 
671
671
  ```ts
672
672
  // server.ts
673
- import serve from '@jk2908/solas/adapters/node'
673
+ import { serve } from '@jk2908/solas/runtime/node'
674
674
 
675
675
  await serve()
676
676
  ```
@@ -679,13 +679,50 @@ await serve()
679
679
  {
680
680
  "scripts": {
681
681
  "build": "vite build",
682
- "start": "node server.ts"
682
+ "start": "NODE_ENV=production node server.ts"
683
683
  }
684
684
  }
685
685
  ```
686
686
 
687
+ Set `NODE_ENV=production` before starting. React reads it when the built handler loads; without it the server renders development payloads, which include debug data and are noticeably larger.
688
+
687
689
  `serve()` loads the built RSC entry (`dist/rsc/index.js` by default) and forwards requests to its fetch handler, which already serves prerendered routes, client assets, and RSC/SSR responses. Options: `port` (defaults to `PORT` or `3000`), `host`, `outDir`, and `entry`. Run from the project root so the handler can resolve `dist`.
688
690
 
691
+ Set `precompress: true` in the Solas config to emit brotli variants of client and prerendered assets at build time. `serve()` negotiates them when the client sends `accept-encoding: br` and falls back to the original file otherwise. Dynamic HTML and RSC responses are streamed per request and are not precompressed, so compress those at a proxy or CDN if you need it.
692
+
693
+ `serve` is a runtime helper, not a build adapter: it starts an HTTP server and returns it, so it belongs in `server.ts`. Do not pass it to `solas({ adapter })`; that option expects an `Adapter` with `name` and `plugins`, such as `cloudflare()` or the static adapter.
694
+
695
+ For TLS, mount the handler on your own `https` server:
696
+
697
+ ```ts
698
+ import { createServer } from 'node:https'
699
+
700
+ import { createHttpRequestListener } from '@jk2908/solas/runtime/node'
701
+
702
+ import handler from './dist/rsc/index.js'
703
+
704
+ createServer({ key, cert }, createHttpRequestListener(handler)).listen(443)
705
+ ```
706
+
707
+ For HTTP/2, use `createHttp2RequestListener` with the compatibility API. Browsers only negotiate HTTP/2 over TLS, and `allowHTTP1` keeps clients that do not speak it working:
708
+
709
+ ```ts
710
+ import http2 from 'node:http2'
711
+
712
+ import { createHttp2RequestListener } from '@jk2908/solas/runtime/node'
713
+
714
+ import handler from './dist/rsc/index.js'
715
+
716
+ http2
717
+ .createSecureServer(
718
+ { key, cert, allowHTTP1: true },
719
+ createHttp2RequestListener(handler),
720
+ )
721
+ .listen(443)
722
+ ```
723
+
724
+ `serve()` itself is HTTP/1.1. TLS and HTTP/2 termination still belong at your proxy or CDN when you have one; these listeners are for deployments that terminate at Node.
725
+
689
726
  Bun and Deno do not need the helper. Their native servers pass the handler a `Request` directly and expect a `Response`, so the Node-specific HTTP-to-Fetch bridging (streams, `duplex`, backpressure) is not needed:
690
727
 
691
728
  ```ts
@@ -702,7 +739,7 @@ import handler from './dist/rsc/index.js'
702
739
  Deno.serve(request => handler.fetch(request))
703
740
  ```
704
741
 
705
- The handler reads `dist` through `node:fs`, which Bun and Deno (2.x, via Node compat) provide. Run from the project root. Bun can also run `@jk2908/solas/adapters/node` as-is, since it implements `node:http`.
742
+ The handler reads `dist` through `node:fs`, which Bun and Deno (2.x, via Node compat) provide. Run from the project root. Bun can also run `@jk2908/solas/runtime/node` as-is, since it implements `node:http`.
706
743
 
707
744
  ## Static
708
745
 
@@ -731,7 +768,7 @@ Server actions and runtime endpoints also need a server, so the build warns when
731
768
 
732
769
  ## Runtime
733
770
 
734
- At request time Solas reads its output through an `Assets` interface (`exists`/`readText`/`readBuffer`/`mimeType`) injected into `createHandler`, defaulting to the Node standard library (which Bun runs natively). References are logical (`{ namespace, path }`), where the namespaces are `client` (Vite client output), `static` (full prerenders), and `artifact` (runtime manifest and ppr files). Platforms without a filesystem provide their own store; `@jk2908/solas/adapters/cloudflare/runtime` builds one around the `ASSETS` binding via `createWorker`. Build-time reads and writes use `node:fs` directly and are not abstracted.
771
+ At request time Solas reads its output through an `Assets` interface (`exists`/`readText`/`readBuffer`/`mimeType`) injected into `createHandler`, defaulting to the Node standard library (which Bun runs natively). References are logical (`{ namespace, path }`), where the namespaces are `client` (Vite client output), `static` (full prerenders), and `artifact` (runtime manifest and ppr files). Platforms without a filesystem provide their own store; `@jk2908/solas/runtime/cloudflare` builds one around the `ASSETS` binding via `createWorker`. Build-time reads and writes use `node:fs` directly and are not abstracted.
735
772
 
736
773
  ## Scripts
737
774
 
@@ -4,7 +4,7 @@ import { cloudflare as cloudflareVitePlugin } from '@cloudflare/vite-plugin';
4
4
  import * as Config from '../../config.js';
5
5
  import { writeCloudflareEntry } from '../../internal/codegen/environments.js';
6
6
  import { setPrerenderImport, setRscEntry } from '../../internal/postbuild.js';
7
- import { NAMESPACE_PREFIX } from './assets.js';
7
+ import { NAMESPACE_PREFIX } from '../../runtime/cloudflare/assets.js';
8
8
  import { withBindingsShim } from './bindings.js';
9
9
  const VIRTUAL_ENTRY = 'virtual:solas-cloudflare-entry';
10
10
  /**
@@ -1,6 +1,6 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
- import * as Config from '../../config.js';
3
+ import * as Config from '../config.js';
4
4
  import { getMimeTypeFromPath } from './mime.js';
5
5
  const NAMESPACE_DIRS = {
6
6
  client: 'client',
@@ -31,7 +31,7 @@ export function writeCloudflareEntry() {
31
31
  return source `
32
32
  ${AUTOGEN_MSG}
33
33
 
34
- import { createWorker } from '${Config.PKG_NAME}/adapters/cloudflare/runtime'
34
+ import { createWorker } from '${Config.PKG_NAME}/runtime/cloudflare'
35
35
 
36
36
  import { manifest } from './manifest.js'
37
37
  import { importMap } from './maps.js'
@@ -1,10 +1,10 @@
1
1
  import type { ReactFormState } from 'react-dom/client';
2
2
  import type { ImportMap, Manifest, RuntimeConfig } from '../../types.js';
3
- import type { Assets } from '../runtimes/assets.js';
3
+ import type { Assets } from '../assets.js';
4
4
  import * as RuntimeManifest from '../../manifest.js';
5
5
  import { Metadata } from '../metadata.js';
6
6
  export { loadManifest } from '../../manifest.js';
7
- export type { Assets } from '../runtimes/assets.js';
7
+ export type { Assets } from '../assets.js';
8
8
  export type HandlerOptions = {
9
9
  /**
10
10
  * Static asset store used to serve prerendered HTML, PPR artifacts, and
@@ -4,6 +4,7 @@ import { applyBasePath, normaliseBasePath, stripBasePath } from '../../utils/bas
4
4
  import { Logger } from '../../utils/logger.js';
5
5
  import * as Config from '../../config.js';
6
6
  import * as RuntimeManifest from '../../manifest.js';
7
+ import { nodeAssets } from '../assets.js';
7
8
  import { createHttpRouter } from '../http-router/create-http-router.js';
8
9
  import { HttpRouter } from '../http-router/router.js';
9
10
  import { isRscRequest, normaliseTrailingSlash, resolveRequestPath, } from '../http-router/utils.js';
@@ -13,7 +14,6 @@ import { isRedirect, toRedirect } from '../navigation/redirect.js';
13
14
  import * as Prerender from '../prerender.js';
14
15
  import { Tree } from '../render/tree.js';
15
16
  import { Resolver } from '../resolver.js';
16
- import { nodeAssets } from '../runtimes/assets.js';
17
17
  import { processActionRequest } from '../server/actions.js';
18
18
  import DefaultErr from '../ui/defaults/error.js';
19
19
  import { RequestContext } from './request-context.js';
@@ -1,5 +1,5 @@
1
1
  import type { PluginConfig, SolasRequest } from '../../types.js';
2
- import type { AssetRef, Assets } from '../runtimes/assets.js';
2
+ import type { AssetRef, Assets } from '../assets.js';
3
3
  import { CsrfConfig } from '../server/csrf.js';
4
4
  export declare namespace HttpRouter {
5
5
  type Params = Record<string, string | string[]>;
@@ -1,5 +1,5 @@
1
1
  import type { BuildContext } from '../types.js';
2
- import type { Assets } from './runtimes/assets.js';
2
+ import type { Assets } from './assets.js';
3
3
  export type Mode = 'full' | 'ppr';
4
4
  export type File = 'html' | 'prelude' | 'postponed' | 'metadata';
5
5
  export type Value = {
@@ -4,8 +4,8 @@ import { applyBasePath } from '../utils/base-path.js';
4
4
  import { Logger } from '../utils/logger.js';
5
5
  import * as Config from '../config.js';
6
6
  import * as Solas from '../solas.js';
7
+ import { nodeAssets } from './assets.js';
7
8
  import { toPathPattern } from './http-router/utils.js';
8
- import { nodeAssets } from './runtimes/assets.js';
9
9
  const logger = new Logger();
10
10
  const DEFAULT_CONCURRENCY = 4;
11
11
  /**
@@ -1,4 +1,4 @@
1
- import type { Assets } from './internal/runtimes/assets.js';
1
+ import type { Assets } from './internal/assets.js';
2
2
  import * as Prerender from './internal/prerender.js';
3
3
  export type Manifest = {
4
4
  artifacts: Prerender.ArtifactManifest;
package/dist/manifest.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import * as Config from './config.js';
2
- import { nodeAssets } from './internal/runtimes/assets.js';
2
+ import { nodeAssets } from './internal/assets.js';
3
3
  export function getManifestPath(outDir) {
4
4
  return [outDir, Config.GENERATED_DIR, Config.RUNTIME_MANIFEST]
5
5
  .map((part, index) => {
@@ -1,4 +1,4 @@
1
- import type { AssetNamespace, Assets } from '../../internal/runtimes/assets.js';
1
+ import type { AssetNamespace, Assets } from '../../internal/assets.js';
2
2
  /**
3
3
  * The subset of the Cloudflare `assets` Fetcher binding that Solas needs.
4
4
  */
@@ -1,4 +1,4 @@
1
- import { getMimeTypeFromPath } from '../../internal/runtimes/mime.js';
1
+ import { getMimeTypeFromPath } from '../../internal/mime.js';
2
2
  /**
3
3
  * Path prefix the adapter copies `dist/.solas` artifacts under in the asset
4
4
  * output.
@@ -1,5 +1,5 @@
1
+ import { nodeAssets } from '../../internal/assets.js';
1
2
  import { createRuntimeHandler } from '../../internal/env/rsc.js';
2
- import { nodeAssets } from '../../internal/runtimes/assets.js';
3
3
  import { createCloudflareAssets } from './assets.js';
4
4
  /**
5
5
  * Build a Cloudflare Worker around Solas's RSC handler.
@@ -0,0 +1,89 @@
1
+ import type { Http2ServerRequest, Http2ServerResponse } from 'node:http2';
2
+ import http from 'node:http';
3
+ export type ServeOptions = {
4
+ /**
5
+ * Port to listen on. Defaults to `process.env.PORT` or `3000`.
6
+ */
7
+ port?: number;
8
+ /**
9
+ * Host to bind to. Defaults to `0.0.0.0`.
10
+ */
11
+ host?: string;
12
+ /**
13
+ * Build output directory the handler reads from. Defaults to `dist`, resolved
14
+ * relative to the current working directory.
15
+ */
16
+ outDir?: string;
17
+ /**
18
+ * Explicit path to the built RSC entry. Defaults to `<outDir>/rsc/index.js`.
19
+ */
20
+ entry?: string;
21
+ /**
22
+ * Called once the server is listening.
23
+ */
24
+ onListen?: (info: {
25
+ port: number;
26
+ host: string;
27
+ }) => void;
28
+ };
29
+ export type Server = http.Server & AsyncDisposable;
30
+ export type FetchHandler = {
31
+ fetch: (request: Request) => Response | Promise<Response>;
32
+ };
33
+ /**
34
+ * A request listener for an `http2` compatibility server.
35
+ */
36
+ export type Http2RequestListener = (req: Http2ServerRequest, res: Http2ServerResponse) => void;
37
+ /**
38
+ * Create a request listener for a built fetch handler on an `http` or `https`
39
+ * server.
40
+ *
41
+ * `serve` uses this internally. Exporting it lets you terminate TLS yourself:
42
+ *
43
+ * ```ts
44
+ * import { createServer } from 'node:https'
45
+ * import { createHttpRequestListener } from '@jk2908/solas/runtime/node'
46
+ * import handler from './dist/rsc/index.js'
47
+ *
48
+ * createServer({ key, cert }, createHttpRequestListener(handler)).listen(443)
49
+ * ```
50
+ */
51
+ declare function createHttpRequestListener(handler: FetchHandler): http.RequestListener;
52
+ /**
53
+ * Create a request listener for a built fetch handler on an `http2`
54
+ * compatibility server.
55
+ *
56
+ * Browsers only negotiate HTTP/2 over TLS, so use
57
+ * `http2.createSecureServer({ allowHTTP1: true }, listener)`. `allowHTTP1`
58
+ * keeps clients that do not speak HTTP/2 working:
59
+ *
60
+ * ```ts
61
+ * import http2 from 'node:http2'
62
+ * import { createHttp2RequestListener } from '@jk2908/solas/runtime/node'
63
+ * import handler from './dist/rsc/index.js'
64
+ *
65
+ * http2.createSecureServer(
66
+ * { key, cert, allowHTTP1: true },
67
+ * createHttp2RequestListener(handler),
68
+ * ).listen(443)
69
+ * ```
70
+ */
71
+ declare function createHttp2RequestListener(handler: FetchHandler): Http2RequestListener;
72
+ /**
73
+ * Start a production HTTP server for a Node (or Bun) deployment.
74
+ *
75
+ * Loads the built RSC entry (`dist/rsc/index.js` by default) and forwards
76
+ * requests to its fetch handler, which already serves prerendered routes,
77
+ * client assets, and RSC/SSR responses. Run it from the project root so the
78
+ * handler can resolve `dist`. The returned server is `AsyncDisposable`, so it
79
+ * can be released with `await using`.
80
+ *
81
+ * For TLS or HTTP/2, mount `createHttpRequestListener(handler)` or
82
+ * `createHttp2RequestListener(handler)` on your own server instead. Deno and Bun
83
+ * do not need this helper: use `Deno.serve(handler.fetch)` or
84
+ * `Bun.serve({ fetch: handler.fetch })` directly.
85
+ */
86
+ declare function serve(options?: ServeOptions): Promise<http.Server<typeof http.IncomingMessage, typeof http.ServerResponse> & {
87
+ [Symbol.asyncDispose](): Promise<void>;
88
+ }>;
89
+ export { createHttp2RequestListener, createHttpRequestListener, serve };
@@ -90,9 +90,16 @@ async function webToNode(stream, res) {
90
90
  * Convert a Node request into a fetch `Request`, streaming the body when present.
91
91
  */
92
92
  function toRequest(req, signal) {
93
- const url = new URL(req.url ?? '/', `http://${req.headers.host ?? 'localhost'}`);
93
+ // HTTP/2's compatibility API also exposes pseudo-headers such as `:path` and
94
+ // `:authority`. Fetch `Headers` rejects names starting with `:`, and the
95
+ // authority replaces the HTTP/1 `host` header, so normalise both here
96
+ const authority = req.headers[':authority'];
97
+ const host = req.headers.host ?? (Array.isArray(authority) ? authority[0] : authority);
98
+ const url = new URL(req.url ?? '/', `http://${host ?? 'localhost'}`);
94
99
  const headers = new Headers();
95
100
  for (const [key, value] of Object.entries(req.headers)) {
101
+ if (key.startsWith(':'))
102
+ continue;
96
103
  if (Array.isArray(value)) {
97
104
  for (const item of value)
98
105
  headers.append(key, item);
@@ -134,11 +141,84 @@ async function sendResponse(res, response) {
134
141
  }
135
142
  // send headers now so a delayed first chunk (SSE, slow streams) does not
136
143
  // leave the client waiting with no response
137
- res.flushHeaders();
144
+ res.flushHeaders?.();
138
145
  await webToNode(response.body, res);
139
146
  if (!res.destroyed)
140
147
  res.end();
141
148
  }
149
+ /**
150
+ * Handle one Node request by forwarding it to the fetch handler.
151
+ */
152
+ async function handleRequest(req, res, handler) {
153
+ const abort = new AbortController();
154
+ // `close` before the response has finished means the client went away;
155
+ // surface that through `req.signal` so long-lived work can stop
156
+ function onClose() {
157
+ if (!res.writableEnded)
158
+ abort.abort(new Error('client disconnected'));
159
+ }
160
+ res.once('close', onClose);
161
+ try {
162
+ const response = await handler.fetch(toRequest(req, abort.signal));
163
+ await sendResponse(res, response);
164
+ }
165
+ catch (err) {
166
+ console.error('[solas] request failed', err);
167
+ if (res.headersSent) {
168
+ res.destroy();
169
+ return;
170
+ }
171
+ res.statusCode = 500;
172
+ res.setHeader('content-type', 'text/plain; charset=utf-8');
173
+ res.end('Internal Server Error');
174
+ }
175
+ finally {
176
+ res.off('close', onClose);
177
+ }
178
+ }
179
+ /**
180
+ * Create a request listener for a built fetch handler on an `http` or `https`
181
+ * server.
182
+ *
183
+ * `serve` uses this internally. Exporting it lets you terminate TLS yourself:
184
+ *
185
+ * ```ts
186
+ * import { createServer } from 'node:https'
187
+ * import { createHttpRequestListener } from '@jk2908/solas/runtime/node'
188
+ * import handler from './dist/rsc/index.js'
189
+ *
190
+ * createServer({ key, cert }, createHttpRequestListener(handler)).listen(443)
191
+ * ```
192
+ */
193
+ function createHttpRequestListener(handler) {
194
+ return (req, res) => {
195
+ void handleRequest(req, res, handler);
196
+ };
197
+ }
198
+ /**
199
+ * Create a request listener for a built fetch handler on an `http2`
200
+ * compatibility server.
201
+ *
202
+ * Browsers only negotiate HTTP/2 over TLS, so use
203
+ * `http2.createSecureServer({ allowHTTP1: true }, listener)`. `allowHTTP1`
204
+ * keeps clients that do not speak HTTP/2 working:
205
+ *
206
+ * ```ts
207
+ * import http2 from 'node:http2'
208
+ * import { createHttp2RequestListener } from '@jk2908/solas/runtime/node'
209
+ * import handler from './dist/rsc/index.js'
210
+ *
211
+ * http2.createSecureServer(
212
+ * { key, cert, allowHTTP1: true },
213
+ * createHttp2RequestListener(handler),
214
+ * ).listen(443)
215
+ * ```
216
+ */
217
+ function createHttp2RequestListener(handler) {
218
+ return (req, res) => {
219
+ void handleRequest(req, res, handler);
220
+ };
221
+ }
142
222
  /**
143
223
  * Start a production HTTP server for a Node (or Bun) deployment.
144
224
  *
@@ -148,42 +228,18 @@ async function sendResponse(res, response) {
148
228
  * handler can resolve `dist`. The returned server is `AsyncDisposable`, so it
149
229
  * can be released with `await using`.
150
230
  *
151
- * Deno and Bun do not need this helper: use `Deno.serve(handler.fetch)` or
231
+ * For TLS or HTTP/2, mount `createHttpRequestListener(handler)` or
232
+ * `createHttp2RequestListener(handler)` on your own server instead. Deno and Bun
233
+ * do not need this helper: use `Deno.serve(handler.fetch)` or
152
234
  * `Bun.serve({ fetch: handler.fetch })` directly.
153
235
  */
154
- async function adapter(options = {}) {
236
+ async function serve(options = {}) {
155
237
  const outDir = options.outDir ?? 'dist';
156
238
  const entry = path.resolve(options.entry ?? path.join(outDir, 'rsc', 'index.js'));
157
239
  const port = options.port ?? (Number(process.env.PORT) || 3000);
158
240
  const host = options.host ?? '0.0.0.0';
159
241
  const handler = await loadHandler(entry);
160
- const server = http.createServer(async (req, res) => {
161
- const abort = new AbortController();
162
- // `close` before the response has finished means the client went away;
163
- // surface that through `req.signal` so long-lived work can stop
164
- function onClose() {
165
- if (!res.writableEnded)
166
- abort.abort(new Error('client disconnected'));
167
- }
168
- res.once('close', onClose);
169
- try {
170
- const response = await handler.fetch(toRequest(req, abort.signal));
171
- await sendResponse(res, response);
172
- }
173
- catch (err) {
174
- console.error('[solas] request failed', err);
175
- if (res.headersSent) {
176
- res.destroy();
177
- return;
178
- }
179
- res.statusCode = 500;
180
- res.setHeader('content-type', 'text/plain; charset=utf-8');
181
- res.end('Internal Server Error');
182
- }
183
- finally {
184
- res.off('close', onClose);
185
- }
186
- });
242
+ const server = http.createServer(createHttpRequestListener(handler));
187
243
  await new Promise(resolve => server.listen(port, host, resolve));
188
244
  options.onListen?.({ port, host });
189
245
  return Object.assign(server, {
@@ -194,4 +250,4 @@ async function adapter(options = {}) {
194
250
  },
195
251
  });
196
252
  }
197
- export { adapter as default };
253
+ export { createHttp2RequestListener, createHttpRequestListener, serve };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jk2908/solas",
3
- "version": "0.13.2",
3
+ "version": "0.15.0",
4
4
  "description": "A Vite + React meta-framework exploring streaming, Server Components, and partial prerendering. Designed for simplicity and lightness",
5
5
  "keywords": [
6
6
  "framework",
@@ -73,17 +73,17 @@
73
73
  "types": "./dist/adapters/cloudflare/index.d.ts",
74
74
  "import": "./dist/adapters/cloudflare/index.js"
75
75
  },
76
- "./adapters/cloudflare/runtime": {
77
- "types": "./dist/adapters/cloudflare/runtime.d.ts",
78
- "import": "./dist/adapters/cloudflare/runtime.js"
79
- },
80
- "./adapters/node": {
81
- "types": "./dist/adapters/node.d.ts",
82
- "import": "./dist/adapters/node.js"
83
- },
84
76
  "./adapters/static": {
85
77
  "types": "./dist/adapters/static.d.ts",
86
78
  "import": "./dist/adapters/static.js"
79
+ },
80
+ "./runtime/cloudflare": {
81
+ "types": "./dist/runtime/cloudflare/index.d.ts",
82
+ "import": "./dist/runtime/cloudflare/index.js"
83
+ },
84
+ "./runtime/node": {
85
+ "types": "./dist/runtime/node.d.ts",
86
+ "import": "./dist/runtime/node.js"
87
87
  }
88
88
  },
89
89
  "scripts": {
@@ -1,44 +0,0 @@
1
- import http from 'node:http';
2
- export type ServeOptions = {
3
- /**
4
- * Port to listen on. Defaults to `process.env.PORT` or `3000`.
5
- */
6
- port?: number;
7
- /**
8
- * Host to bind to. Defaults to `0.0.0.0`.
9
- */
10
- host?: string;
11
- /**
12
- * Build output directory the handler reads from. Defaults to `dist`, resolved
13
- * relative to the current working directory.
14
- */
15
- outDir?: string;
16
- /**
17
- * Explicit path to the built RSC entry. Defaults to `<outDir>/rsc/index.js`.
18
- */
19
- entry?: string;
20
- /**
21
- * Called once the server is listening.
22
- */
23
- onListen?: (info: {
24
- port: number;
25
- host: string;
26
- }) => void;
27
- };
28
- export type Server = http.Server & AsyncDisposable;
29
- /**
30
- * Start a production HTTP server for a Node (or Bun) deployment.
31
- *
32
- * Loads the built RSC entry (`dist/rsc/index.js` by default) and forwards
33
- * requests to its fetch handler, which already serves prerendered routes,
34
- * client assets, and RSC/SSR responses. Run it from the project root so the
35
- * handler can resolve `dist`. The returned server is `AsyncDisposable`, so it
36
- * can be released with `await using`.
37
- *
38
- * Deno and Bun do not need this helper: use `Deno.serve(handler.fetch)` or
39
- * `Bun.serve({ fetch: handler.fetch })` directly.
40
- */
41
- declare function adapter(options?: ServeOptions): Promise<http.Server<typeof http.IncomingMessage, typeof http.ServerResponse> & {
42
- [Symbol.asyncDispose](): Promise<void>;
43
- }>;
44
- export { adapter as default };
File without changes
File without changes