@jk2908/solas 0.11.0 → 0.11.1

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,11 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.11.1
4
+
5
+ ### Fixes
6
+
7
+ - A document request is now served as HTML by default. Solas only returns the RSC payload when the client asks for `text/x-component` (and not `text/html`); a request to a page without that, such as `Accept: */*` or no `Accept` header, used to receive the RSC payload — and, for a page with no endpoint, an error.
8
+
3
9
  ## 0.11.0
4
10
 
5
11
  ### Breaking
@@ -6,7 +6,7 @@ import * as Config from '../../config.js';
6
6
  import * as RuntimeManifest from '../../manifest.js';
7
7
  import { createHttpRouter } from '../http-router/create-http-router.js';
8
8
  import { HttpRouter } from '../http-router/router.js';
9
- import { normaliseTrailingSlash } from '../http-router/utils.js';
9
+ import { isRscRequest, normaliseTrailingSlash } from '../http-router/utils.js';
10
10
  import { Metadata } from '../metadata.js';
11
11
  import { HttpException, isHttpException, toHttpException, toHttpExceptionLike, } from '../navigation/http-exception.js';
12
12
  import { isRedirect, toRedirect } from '../navigation/redirect.js';
@@ -190,7 +190,7 @@ export function createHandler(config, manifest, importMap, options = {}) {
190
190
  }
191
191
  const { stream: rscStream, status, ppr, } = await createPayload(req, manifest, importMap, config.metadata, opts.returnValue, opts.formState, opts.temporaryReferences);
192
192
  const stream = await rscStream;
193
- if (!req.headers.get('accept')?.includes('text/html')) {
193
+ if (isRscRequest(req)) {
194
194
  return new Response(stream, {
195
195
  headers: {
196
196
  'Cache-Control': 'private, no-store',
@@ -338,14 +338,13 @@ export function createHandler(config, manifest, importMap, options = {}) {
338
338
  /**
339
339
  * Serve the saved HTML for a fully prerendered route. Runs as the route
340
340
  * handler, after middleware, so middleware applies to static routes too. It
341
- * returns null for anything else (a route without a saved prerender, an RSC
342
- * navigation, or a request without an HTML accept header), so the caller
343
- * falls back to rendering.
341
+ * returns null for anything else (a route without a saved prerender or an RSC
342
+ * navigation), so the caller falls back to rendering.
344
343
  */
345
344
  async function serveFullPrerender(req) {
346
345
  if (import.meta.env.DEV)
347
346
  return null;
348
- if (!(req.headers.get('accept') ?? '').includes('text/html'))
347
+ if (isRscRequest(req))
349
348
  return null;
350
349
  if (req.headers.get(`x-${Config.SLUG}-prerender-artifact`) === '1')
351
350
  return null;
@@ -1,4 +1,5 @@
1
1
  import { HttpRouter } from './router.js';
2
+ import { isRscRequest } from './utils.js';
2
3
  function callEndpoint(fn, req) {
3
4
  // endpoint modules may export either a zero-arg handler or one that expects the request
4
5
  if (fn.length === 0)
@@ -82,12 +83,12 @@ export function createHttpRouter(config, manifest, importMap, rsc, serveFullPrer
82
83
  const middlewares = mergeMiddlewares(importMap[page.__id]?.middlewares, endpointEntry ? importMap[endpointEntry.__id]?.middlewares : undefined);
83
84
  router.add(page.__path, 'GET', async req => {
84
85
  const accept = req.headers.get('accept') ?? '';
85
- if (accept.includes('text/html') || accept.includes('text/x-component')) {
86
+ // a request that asks for a document or the RSC payload is rendered,
87
+ // as is any request to a page with no endpoint; anything else is the
88
+ // endpoint's own body
89
+ if (isRscRequest(req) || accept.includes('text/html') || !endpoint) {
86
90
  return (await serveFullPrerender?.(req)) ?? rsc(req);
87
91
  }
88
- if (!endpoint) {
89
- throw new Error(`Missing unified endpoint handler for ${page.__path}`);
90
- }
91
92
  return callEndpoint(endpoint, req);
92
93
  }, page.__params, middlewares);
93
94
  }
@@ -1,4 +1,12 @@
1
1
  import type { PluginConfig } from '../../types.js';
2
+ /**
3
+ * Whether a request wants the RSC payload rather than a document.
4
+ *
5
+ * The client asks for `text/x-component` on navigations. Anything else (a
6
+ * browser, or a fetch with no explicit preference) should get HTML, so a plain
7
+ * request to a page never receives the RSC payload.
8
+ */
9
+ export declare function isRscRequest(req: Request): boolean;
2
10
  export type PathPattern = {
3
11
  path: string;
4
12
  wildcardNames: Set<string>;
@@ -1,3 +1,14 @@
1
+ /**
2
+ * Whether a request wants the RSC payload rather than a document.
3
+ *
4
+ * The client asks for `text/x-component` on navigations. Anything else (a
5
+ * browser, or a fetch with no explicit preference) should get HTML, so a plain
6
+ * request to a page never receives the RSC payload.
7
+ */
8
+ export function isRscRequest(req) {
9
+ const accept = req.headers.get('accept') ?? '';
10
+ return accept.includes('text/x-component') && !accept.includes('text/html');
11
+ }
1
12
  /**
2
13
  * Escape a literal path segment so it can be used safely in a
3
14
  * path-to-regexp pattern.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jk2908/solas",
3
- "version": "0.11.0",
3
+ "version": "0.11.1",
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",