@jk2908/solas 0.5.3 → 0.6.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.
Files changed (69) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +81 -85
  3. package/dist/config.d.ts +25 -0
  4. package/dist/config.js +152 -0
  5. package/dist/events.d.ts +4 -0
  6. package/dist/events.js +5 -0
  7. package/dist/index.d.ts +1 -2
  8. package/dist/index.js +59 -37
  9. package/dist/internal/boundary-error.d.ts +4 -0
  10. package/dist/internal/boundary-error.js +8 -0
  11. package/dist/internal/browser-router/history.d.ts +46 -0
  12. package/dist/internal/browser-router/history.js +131 -0
  13. package/dist/internal/browser-router/link.d.ts +1 -1
  14. package/dist/internal/browser-router/link.js +1 -1
  15. package/dist/internal/browser-router/router.d.ts +6 -14
  16. package/dist/internal/browser-router/router.js +39 -13
  17. package/dist/internal/browser-router/shared.d.ts +183 -164
  18. package/dist/internal/browser-router/shared.js +49 -56
  19. package/dist/internal/browser-router/use-router.d.ts +1 -10
  20. package/dist/internal/browser-router/use-search-params.js +3 -3
  21. package/dist/internal/build.d.ts +108 -110
  22. package/dist/internal/build.js +569 -581
  23. package/dist/internal/codegen/config.js +3 -3
  24. package/dist/internal/codegen/environments.js +5 -6
  25. package/dist/internal/codegen/format.d.ts +6 -0
  26. package/dist/internal/codegen/format.js +24 -0
  27. package/dist/internal/codegen/manifest.js +2 -2
  28. package/dist/internal/codegen/maps.d.ts +1 -1
  29. package/dist/internal/codegen/maps.js +2 -2
  30. package/dist/internal/codegen/types.js +4 -4
  31. package/dist/internal/codegen/utils.js +2 -2
  32. package/dist/internal/env/request-context.js +1 -1
  33. package/dist/internal/env/rsc.d.ts +6 -4
  34. package/dist/internal/env/rsc.js +27 -25
  35. package/dist/internal/env/ssr.js +4 -4
  36. package/dist/internal/http-router/router.js +8 -8
  37. package/dist/internal/metadata.d.ts +1 -1
  38. package/dist/internal/metadata.js +1 -1
  39. package/dist/internal/navigation/http-exception-boundary.d.ts +1 -1
  40. package/dist/internal/navigation/redirect-boundary.d.ts +1 -1
  41. package/dist/internal/navigation/redirect.js +6 -6
  42. package/dist/internal/postbuild.js +18 -17
  43. package/dist/internal/prerender.d.ts +130 -138
  44. package/dist/internal/prerender.js +326 -354
  45. package/dist/internal/public-files.js +2 -4
  46. package/dist/internal/render/head.js +2 -2
  47. package/dist/internal/resolver.js +1 -1
  48. package/dist/internal/server/actions.js +2 -2
  49. package/dist/internal/ui/error-boundary.d.ts +1 -1
  50. package/dist/manifest.d.ts +7 -0
  51. package/dist/manifest.js +85 -0
  52. package/dist/prerender.d.ts +1 -1
  53. package/dist/prerender.js +1 -1
  54. package/dist/solas.d.ts +2 -46
  55. package/dist/solas.js +6 -266
  56. package/dist/types.d.ts +14 -21
  57. package/dist/types.js +1 -1
  58. package/dist/utils/base-path.d.ts +12 -14
  59. package/dist/utils/base-path.js +75 -82
  60. package/dist/utils/compress.d.ts +9 -11
  61. package/dist/utils/compress.js +59 -64
  62. package/dist/utils/context.d.ts +4 -6
  63. package/dist/utils/context.js +17 -22
  64. package/dist/utils/logger.js +2 -2
  65. package/dist/utils/time.d.ts +2 -4
  66. package/dist/utils/time.js +23 -29
  67. package/package.json +18 -8
  68. package/dist/runtimes/bun.d.ts +0 -13
  69. package/dist/runtimes/bun.js +0 -39
@@ -1,4 +1,4 @@
1
- import { Solas } from '../../solas.js';
1
+ import * as Config from '../../config.js';
2
2
  import { AUTOGEN_MSG, source, toSourceLiteral } from './utils.js';
3
3
  /**
4
4
  * Generates the code to create an exported config object
@@ -7,8 +7,8 @@ export function writeConfig(config) {
7
7
  const { runtime: _runtime, ...runtimeConfig } = config;
8
8
  const loggerLevel = config.logger?.level;
9
9
  const importLines = [
10
- `import type { RuntimeConfig } from '${Solas.Config.PKG_NAME}'`,
11
- loggerLevel ? `import { Logger } from '${Solas.Config.PKG_NAME}/utils/logger'` : '',
10
+ `import type { RuntimeConfig } from '${Config.PKG_NAME}'`,
11
+ loggerLevel ? `import { Logger } from '${Config.PKG_NAME}/utils/logger'` : '',
12
12
  ]
13
13
  .filter(Boolean)
14
14
  .join('\n');
@@ -1,4 +1,4 @@
1
- import { Solas } from '../../solas.js';
1
+ import * as Config from '../../config.js';
2
2
  import { AUTOGEN_MSG, source, toStringLiteral } from './utils.js';
3
3
  /**
4
4
  * Generates the RSC entry code
@@ -8,15 +8,14 @@ export function writeRSCEntry(config) {
8
8
  return source `
9
9
  ${AUTOGEN_MSG}
10
10
 
11
- import { createHandler, createRuntime, Runtime } from '${Solas.Config.PKG_NAME}/env/rsc'
12
- import { Solas } from '${Solas.Config.PKG_NAME}/$'
11
+ import { createHandler, createRuntime, loadManifest, Runtime } from '${Config.PKG_NAME}/env/rsc'
13
12
 
14
13
  import { manifest } from './manifest.js'
15
14
  import { importMap } from './maps.js'
16
15
  import { config } from './config.js'
17
16
 
18
17
  Runtime.runtime = createRuntime(${runtime})
19
- const runtimeManifest = await Solas.Runtime.loadManifest(Solas.Config.OUT_DIR)
18
+ const runtimeManifest = await loadManifest(${toStringLiteral(Config.OUT_DIR)})
20
19
 
21
20
  export default createHandler(config, manifest, importMap, runtimeManifest)
22
21
 
@@ -32,7 +31,7 @@ export function writeSSREntry() {
32
31
  return source `
33
32
  ${AUTOGEN_MSG}
34
33
 
35
- export { prerender, resume, ssr } from '${Solas.Config.PKG_NAME}/env/ssr'
34
+ export { prerender, resume, ssr } from '${Config.PKG_NAME}/env/ssr'
36
35
  `;
37
36
  }
38
37
  /**
@@ -42,7 +41,7 @@ export function writeBrowserEntry() {
42
41
  return source `
43
42
  ${AUTOGEN_MSG}
44
43
 
45
- import { browser } from '${Solas.Config.PKG_NAME}/env/browser'
44
+ import { browser } from '${Config.PKG_NAME}/env/browser'
46
45
 
47
46
  browser()
48
47
  `;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Format generated source before it is written to disk. Falls back to the
3
+ * unformatted content when parsing fails so codegen never blocks on a
4
+ * formatter error
5
+ */
6
+ export declare function format(fileName: string, content: string): Promise<string>;
@@ -0,0 +1,24 @@
1
+ import { format as oxfmtFormat } from 'oxfmt';
2
+ const FORMAT_OPTIONS = {
3
+ useTabs: true,
4
+ tabWidth: 2,
5
+ printWidth: 90,
6
+ singleQuote: true,
7
+ quoteProps: 'as-needed',
8
+ trailingComma: 'all',
9
+ semi: false,
10
+ arrowParens: 'avoid',
11
+ bracketSameLine: true,
12
+ bracketSpacing: true,
13
+ };
14
+ /**
15
+ * Format generated source before it is written to disk. Falls back to the
16
+ * unformatted content when parsing fails so codegen never blocks on a
17
+ * formatter error
18
+ */
19
+ export async function format(fileName, content) {
20
+ const result = await oxfmtFormat(fileName, content, FORMAT_OPTIONS);
21
+ if (result.errors.length > 0)
22
+ return content;
23
+ return result.code;
24
+ }
@@ -1,4 +1,4 @@
1
- import { Solas } from '../../solas.js';
1
+ import * as Config from '../../config.js';
2
2
  import { AUTOGEN_MSG, source, toSourceLiteral } from './utils.js';
3
3
  /**
4
4
  * Generates the code to create an exported manifest object
@@ -7,7 +7,7 @@ export function writeManifest(manifest) {
7
7
  return source `
8
8
  ${AUTOGEN_MSG}
9
9
 
10
- import type { Manifest } from '${Solas.Config.PKG_NAME}'
10
+ import type { Manifest } from '${Config.PKG_NAME}'
11
11
 
12
12
  export const manifest = ${toSourceLiteral(manifest)} as const satisfies Manifest
13
13
  `;
@@ -1,4 +1,4 @@
1
- import type { Build } from '../build.js';
1
+ import * as Build from '../build.js';
2
2
  /**
3
3
  * Generates the import map for all route components, endpoints, layouts, shells, and middlewares
4
4
  */
@@ -1,4 +1,4 @@
1
- import { Solas } from '../../solas.js';
1
+ import * as Config from '../../config.js';
2
2
  import { AUTOGEN_MSG, indent, source, toIdentifier, toIdentifierList, toRelativeModuleSpecifier, toStringLiteral, } from './utils.js';
3
3
  /**
4
4
  * Generates the import map for all route components, endpoints, layouts, shells, and middlewares
@@ -69,7 +69,7 @@ export function writeMaps(imports, modules) {
69
69
  return source `
70
70
  ${AUTOGEN_MSG}
71
71
 
72
- import type { ImportMap } from '${Solas.Config.PKG_NAME}'
72
+ import type { ImportMap } from '${Config.PKG_NAME}'
73
73
 
74
74
  ${importLines
75
75
  ? `
@@ -1,5 +1,5 @@
1
- import { Solas } from '../../solas.js';
2
- import { Build } from '../build.js';
1
+ import * as Config from '../../config.js';
2
+ import * as Build from '../build.js';
3
3
  import { AUTOGEN_MSG, source } from './utils.js';
4
4
  function render(path, params) {
5
5
  if (!params || params.length === 0) {
@@ -36,9 +36,9 @@ export function writeTypes(manifest) {
36
36
  return source `
37
37
  ${AUTOGEN_MSG}
38
38
 
39
- import '${Solas.Config.PKG_NAME}'
39
+ import '${Config.PKG_NAME}'
40
40
 
41
- declare module '${Solas.Config.PKG_NAME}' {
41
+ declare module '${Config.PKG_NAME}' {
42
42
  export namespace Solas {
43
43
  export interface Routes {
44
44
  ${body}
@@ -1,5 +1,5 @@
1
- import { Solas } from '../../solas.js';
2
- export const AUTOGEN_MSG = `// auto-generated by ${Solas.Config.NAME}`;
1
+ import * as Config from '../../config.js';
2
+ export const AUTOGEN_MSG = `// auto-generated by ${Config.NAME}`;
3
3
  const INDENT = '\t';
4
4
  const IDENTIFIER = /^[$A-Z_a-z][$\w]*$/;
5
5
  /**
@@ -1,2 +1,2 @@
1
- import { Context } from '../../utils/context.js';
1
+ import * as Context from '../../utils/context.js';
2
2
  export const RequestContext = Context.create('request');
@@ -1,9 +1,10 @@
1
1
  import type { ReactFormState } from 'react-dom/client';
2
2
  import type { ImportMap, Manifest, RuntimeConfig } from '../../types.js';
3
- import { Solas } from '../../solas.js';
3
+ import * as RuntimeManifest from '../../manifest.js';
4
4
  import { Metadata } from '../metadata.js';
5
5
  export { createRuntime } from '../runtimes/create.js';
6
6
  export { Runtime } from '../runtimes/runtime.js';
7
+ export { loadManifest } from '../../manifest.js';
7
8
  export type RscPayload = {
8
9
  returnValue?: {
9
10
  ok: boolean;
@@ -12,9 +13,10 @@ export type RscPayload = {
12
13
  formState?: ReactFormState;
13
14
  root: React.ReactNode;
14
15
  metadata?: Promise<Metadata.Item>;
15
- url?: {
16
- pathname?: string;
16
+ url: {
17
+ pathname: string;
17
18
  search?: string;
19
+ hash?: string;
18
20
  };
19
21
  };
20
22
  /**
@@ -22,6 +24,6 @@ export type RscPayload = {
22
24
  * route manifest, and import map to build the router once, then returns an object
23
25
  * with a fetch method that handles requests
24
26
  */
25
- export declare function createHandler(config: RuntimeConfig, manifest: Manifest, importMap: ImportMap, runtimeManifest?: Solas.Runtime.Manifest | null): {
27
+ export declare function createHandler(config: RuntimeConfig, manifest: Manifest, importMap: ImportMap, runtimeManifest?: RuntimeManifest.Manifest | null): {
26
28
  fetch(req: Request): Promise<Response>;
27
29
  };
@@ -1,16 +1,16 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import path from 'node:path';
3
3
  import { renderToReadableStream } from '@vitejs/plugin-rsc/rsc';
4
- import { BasePath } from '../../utils/base-path.js';
4
+ import { applyBasePath, normaliseBasePath, stripBasePath } from '../../utils/base-path.js';
5
5
  import { Logger } from '../../utils/logger.js';
6
- import { Solas } from '../../solas.js';
6
+ import * as Config from '../../config.js';
7
7
  import { createHttpRouter } from '../http-router/create-http-router.js';
8
8
  import { HttpRouter } from '../http-router/router.js';
9
9
  import { normalisePathname } 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';
13
- import { Prerender } from '../prerender.js';
13
+ import * as Prerender from '../prerender.js';
14
14
  import { Tree } from '../render/tree.js';
15
15
  import { Resolver } from '../resolver.js';
16
16
  import { processActionRequest } from '../server/actions.js';
@@ -19,8 +19,9 @@ import { RequestContext } from './request-context.js';
19
19
  import { getKnownDigest, isKnownError } from './utils.js';
20
20
  export { createRuntime } from '../runtimes/create.js';
21
21
  export { Runtime } from '../runtimes/runtime.js';
22
+ export { loadManifest } from '../../manifest.js';
22
23
  const logger = new Logger();
23
- const BASE_PATH = BasePath.normalise(import.meta.env.BASE_URL);
24
+ const BASE_PATH = normaliseBasePath(import.meta.env.BASE_URL);
24
25
  function resolveFilePath(root, relativePath) {
25
26
  try {
26
27
  const decodedPath = decodeURIComponent(relativePath);
@@ -43,16 +44,16 @@ function resolveFilePath(root, relativePath) {
43
44
  */
44
45
  async function createPayload(req, manifest, importMap, baseMetadata, returnValue, formState, temporaryReferences) {
45
46
  const resolver = new Resolver(manifest, importMap);
46
- const prerender = req.headers.get(`x-${Solas.Config.SLUG}-prerender`) === '1';
47
+ const prerender = req.headers.get(`x-${Config.SLUG}-prerender`) === '1';
47
48
  const url = new URL(req.url);
48
- const routedPath = BasePath.strip(url.pathname, BASE_PATH) ?? url.pathname;
49
+ const routedPath = stripBasePath(url.pathname, BASE_PATH) ?? url.pathname;
49
50
  const pathname = routedPath.endsWith('/') && routedPath !== '/' ? routedPath.slice(0, -1) : routedPath;
50
- const match = resolver.enhance(resolver.reconcile(pathname, req[Solas.Config.REQUEST_META_KEY].match, req[Solas.Config.REQUEST_META_KEY].error));
51
+ const match = resolver.enhance(resolver.reconcile(pathname, req[Config.REQUEST_META_KEY].match, req[Config.REQUEST_META_KEY].error));
51
52
  // if there's no match then no user supplied error boundary
52
53
  // has been found, and we should server render a default
53
54
  // error screen
54
55
  if (!match) {
55
- const error = toHttpExceptionLike(req[Solas.Config.REQUEST_META_KEY].error ?? new HttpException(404, 'Not found'));
56
+ const error = toHttpExceptionLike(req[Config.REQUEST_META_KEY].error ?? new HttpException(404, 'Not found'));
56
57
  const title = `${error.status ? `${error.status} -` : ''}${error.message}`;
57
58
  const rscPayload = {
58
59
  root: (_jsxs("html", { lang: "en", children: [
@@ -65,6 +66,7 @@ async function createPayload(req, manifest, importMap, baseMetadata, returnValue
65
66
  url: {
66
67
  pathname: url.pathname,
67
68
  search: url.search,
69
+ hash: url.hash,
68
70
  },
69
71
  };
70
72
  return {
@@ -162,11 +164,11 @@ async function createPayload(req, manifest, importMap, baseMetadata, returnValue
162
164
  * with a fetch method that handles requests
163
165
  */
164
166
  export function createHandler(config, manifest, importMap, runtimeManifest = null) {
165
- const CLIENT_OUTPUT_DIR = path.resolve(Solas.Config.OUT_DIR, 'client');
167
+ const CLIENT_OUTPUT_DIR = path.resolve(Config.OUT_DIR, 'client');
166
168
  // vite emits solas-controlled assets under dist/client/_solas
167
- const SOLAS_ASSETS_DIR = path.resolve(CLIENT_OUTPUT_DIR, Solas.Config.ASSETS_DIR);
169
+ const SOLAS_ASSETS_DIR = path.resolve(CLIENT_OUTPUT_DIR, Config.ASSETS_DIR);
168
170
  // requests for /_solas and /_solas/* are reserved
169
- const SOLAS_ASSETS_URL_ROOT = `/${Solas.Config.ASSETS_DIR}`;
171
+ const SOLAS_ASSETS_URL_ROOT = `/${Config.ASSETS_DIR}`;
170
172
  const prerenderPathMode = config.trailingSlash === 'always' ? 'always' : 'never';
171
173
  /**
172
174
  * Create the HTTP response for a single incoming request. Runs actions when needed,
@@ -179,7 +181,7 @@ export function createHandler(config, manifest, importMap, runtimeManifest = nul
179
181
  temporaryReferences: undefined,
180
182
  returnValue: undefined,
181
183
  };
182
- if (req[Solas.Config.REQUEST_META_KEY].action) {
184
+ if (req[Config.REQUEST_META_KEY].action) {
183
185
  opts = await processActionRequest(req, {
184
186
  trustedOrigins: config.trustedOrigins,
185
187
  url: config.url,
@@ -205,16 +207,16 @@ export function createHandler(config, manifest, importMap, runtimeManifest = nul
205
207
  if (isRedirect(err)) {
206
208
  const redirect = toRedirect(err);
207
209
  const location = redirect.url.startsWith('/')
208
- ? new URL(BasePath.apply(redirect.url, BASE_PATH), req.url).toString()
210
+ ? new URL(applyBasePath(redirect.url, BASE_PATH), req.url).toString()
209
211
  : redirect.url;
210
212
  return Response.redirect(location, redirect.status);
211
213
  }
212
- if (req[Solas.Config.REQUEST_META_KEY].error || !isHttpException(err)) {
214
+ if (req[Config.REQUEST_META_KEY].error || !isHttpException(err)) {
213
215
  return null;
214
216
  }
215
217
  // retry once with the surfaced HttpException attached so createPayload can
216
218
  // rebuild the route through the nearest matching status boundary
217
- req[Solas.Config.REQUEST_META_KEY].error = toHttpException(err);
219
+ req[Config.REQUEST_META_KEY].error = toHttpException(err);
218
220
  try {
219
221
  const { stream: retriedRscStream, status: retriedStatus } = await createPayload(req, manifest, importMap, config.metadata, opts.returnValue, opts.formState, opts.temporaryReferences);
220
222
  const retriedStream = await retriedRscStream;
@@ -224,13 +226,13 @@ export function createHandler(config, manifest, importMap, runtimeManifest = nul
224
226
  };
225
227
  }
226
228
  finally {
227
- req[Solas.Config.REQUEST_META_KEY].error = undefined;
229
+ req[Config.REQUEST_META_KEY].error = undefined;
228
230
  }
229
231
  }
230
232
  // prerender artifact requests bypass the normal document path so the cli
231
233
  // gets structured JSON instead of a rendered html response
232
- if (req.headers.get(`x-${Solas.Config.SLUG}-prerender`) === '1' &&
233
- req.headers.get(`x-${Solas.Config.SLUG}-prerender-artifact`) === '1') {
234
+ if (req.headers.get(`x-${Config.SLUG}-prerender`) === '1' &&
235
+ req.headers.get(`x-${Config.SLUG}-prerender-artifact`) === '1') {
234
236
  try {
235
237
  const artifact = await mod.prerender(stream, {
236
238
  formState: opts.formState,
@@ -274,8 +276,8 @@ export function createHandler(config, manifest, importMap, runtimeManifest = nul
274
276
  : null;
275
277
  const tryPrelude = artifactEntry?.mode === 'ppr';
276
278
  if (tryPrelude) {
277
- const postponedState = await Prerender.Artifact.loadPostponedState(Solas.Config.OUT_DIR, lookupPath);
278
- const prelude = await Prerender.Artifact.loadPrelude(Solas.Config.OUT_DIR, lookupPath);
279
+ const postponedState = await Prerender.loadPostponedState(Config.OUT_DIR, lookupPath);
280
+ const prelude = await Prerender.loadPrelude(Config.OUT_DIR, lookupPath);
279
281
  // resumable ppr responses splice fresh streamed content into the cached
280
282
  // prelude when postponed state is available for this route
281
283
  if (postponedState) {
@@ -286,7 +288,7 @@ export function createHandler(config, manifest, importMap, runtimeManifest = nul
286
288
  injectPayload: false,
287
289
  });
288
290
  const body = prelude
289
- ? Prerender.Artifact.composePreludeAndResume(prelude, resumeStream)
291
+ ? Prerender.composePreludeAndResume(prelude, resumeStream)
290
292
  : resumeStream;
291
293
  return new Response(body, {
292
294
  headers: {
@@ -342,13 +344,13 @@ export function createHandler(config, manifest, importMap, runtimeManifest = nul
342
344
  if (method !== 'GET' && method !== 'HEAD')
343
345
  return httpRouter.fetch(req);
344
346
  const accept = req.headers.get('accept') ?? '';
345
- const routedPath = BasePath.strip(url.pathname, BASE_PATH);
347
+ const routedPath = stripBasePath(url.pathname, BASE_PATH);
346
348
  const canonicalPath = routedPath == null
347
349
  ? null
348
350
  : config.trailingSlash === 'ignore'
349
351
  ? routedPath
350
352
  : normalisePathname(routedPath, config.trailingSlash);
351
- const canonicalPathname = canonicalPath == null ? null : BasePath.apply(canonicalPath, BASE_PATH);
353
+ const canonicalPathname = canonicalPath == null ? null : applyBasePath(canonicalPath, BASE_PATH);
352
354
  if (canonicalPathname != null &&
353
355
  (method === 'GET' || method === 'HEAD') &&
354
356
  config.trailingSlash !== 'ignore' &&
@@ -383,12 +385,12 @@ export function createHandler(config, manifest, importMap, runtimeManifest = nul
383
385
  if (canonicalPath != null &&
384
386
  !import.meta.env.DEV &&
385
387
  accept.includes('text/html') &&
386
- req.headers.get(`x-${Solas.Config.SLUG}-prerender-artifact`) !== '1') {
388
+ req.headers.get(`x-${Config.SLUG}-prerender-artifact`) !== '1') {
387
389
  // turn the request path into the normal route shape we use for artifact lookups
388
390
  const lookupPath = normalisePathname(canonicalPath, prerenderPathMode);
389
391
  // only full prerender routes have a saved html file we can serve directly
390
392
  const prerenderPath = runtimeManifest?.artifacts[lookupPath]?.mode === 'full'
391
- ? Prerender.Artifact.getFilePath(Solas.Config.OUT_DIR, lookupPath, Prerender.Artifact.FULL_PRERENDER_FILENAME)
393
+ ? Prerender.getArtifactFilePath(Config.OUT_DIR, lookupPath, Prerender.FULL_PRERENDER_FILENAME)
392
394
  : null;
393
395
  if (prerenderPath) {
394
396
  const res = await HttpRouter.serveStatic(prerenderPath, req, config.precompress, {
@@ -4,10 +4,10 @@ import { resume as reactResume, renderToReadableStream } from 'react-dom/server.
4
4
  import { prerender as reactPrerender } from 'react-dom/static.edge';
5
5
  import { createFromReadableStream } from '@vitejs/plugin-rsc/ssr';
6
6
  import { Logger } from '../../utils/logger.js';
7
- import { Solas } from '../../solas.js';
7
+ import * as Solas from '../../solas.js';
8
8
  import { BrowserRouterProvider } from '../browser-router/router.js';
9
9
  import { RedirectBoundary } from '../navigation/redirect-boundary.js';
10
- import { Prerender } from '../prerender.js';
10
+ import * as Prerender from '../prerender.js';
11
11
  import { Head } from '../render/head.js';
12
12
  import { ErrorBoundary } from '../ui/error-boundary.js';
13
13
  import { captureBuffered, injectPayload } from './flight.js';
@@ -78,13 +78,13 @@ async function prerender(rscStream, opts = {}) {
78
78
  // abort on a macrotask so sync and microtask work still lands in prelude
79
79
  // unresolved work is captured as postponed state for resume
80
80
  setTimeout(() => {
81
- controller.abort(new Prerender.Runtime.Postponed());
81
+ controller.abort(new Prerender.Postponed());
82
82
  }, 0);
83
83
  const { prelude, postponed } = await reactPrerender(_jsx(A, { payloadPromise: payloadPromise }), {
84
84
  bootstrapScriptContent,
85
85
  signal: controller.signal,
86
86
  onError(err) {
87
- if (Prerender.Runtime.isPostponed(err))
87
+ if (Prerender.isPostponed(err))
88
88
  return;
89
89
  const digest = getKnownDigest(err);
90
90
  if (digest)
@@ -1,12 +1,12 @@
1
1
  import { match as createMatch } from 'path-to-regexp';
2
- import { BasePath } from '../../utils/base-path.js';
3
- import { Solas } from '../../solas.js';
2
+ import { applyBasePath, normaliseBasePath, stripBasePath } from '../../utils/base-path.js';
3
+ import * as Config from '../../config.js';
4
4
  import { HttpException } from '../navigation/http-exception.js';
5
5
  import { Runtime } from '../runtimes/runtime.js';
6
6
  import { maybeAction } from '../server/actions.js';
7
7
  import { enforce } from '../server/csrf.js';
8
8
  import { getAlternatePathname, normalisePathname, toPathPattern } from './utils.js';
9
- const BASE_PATH = BasePath.normalise(import.meta.env.BASE_URL);
9
+ const BASE_PATH = normaliseBasePath(import.meta.env.BASE_URL);
10
10
  /**
11
11
  * Handle routing and matching for server requests
12
12
  */
@@ -166,7 +166,7 @@ export class HttpRouter {
166
166
  async fetch(req) {
167
167
  const url = new URL(req.url);
168
168
  const trailingSlash = this.opts.trailingSlash ?? 'never';
169
- const routedPath = BasePath.strip(url.pathname, BASE_PATH);
169
+ const routedPath = stripBasePath(url.pathname, BASE_PATH);
170
170
  const path = routedPath == null
171
171
  ? null
172
172
  : trailingSlash === 'ignore'
@@ -176,7 +176,7 @@ export class HttpRouter {
176
176
  let action = false;
177
177
  try {
178
178
  const method = req.method.toUpperCase();
179
- const canonicalPathname = path == null ? null : BasePath.apply(path, BASE_PATH);
179
+ const canonicalPathname = path == null ? null : applyBasePath(path, BASE_PATH);
180
180
  if (canonicalPathname != null &&
181
181
  (method === 'GET' || method === 'HEAD') &&
182
182
  canonicalPathname !== url.pathname) {
@@ -197,13 +197,13 @@ export class HttpRouter {
197
197
  const error = new HttpException(404, 'Not found');
198
198
  // unmatched requests still go through the same error hook shape as matched ones
199
199
  return (this.#onError?.(error, Object.assign(req, {
200
- [Solas.Config.REQUEST_META_KEY]: { match: null, error, action },
200
+ [Config.REQUEST_META_KEY]: { match: null, error, action },
201
201
  })) ?? new Response(error.message, { status: error.status }));
202
202
  }
203
203
  const matched = match;
204
204
  // attach route state once so middleware and handlers read the same request data
205
205
  const request = Object.assign(req, {
206
- [Solas.Config.REQUEST_META_KEY]: { match: matched, action, parsedFormData },
206
+ [Config.REQUEST_META_KEY]: { match: matched, action, parsedFormData },
207
207
  });
208
208
  // check csrf before any middleware or handler runs
209
209
  enforce(request, this.opts.csrf);
@@ -215,7 +215,7 @@ export class HttpRouter {
215
215
  // turn unknown throws into Error objects so the error hook sees one shape
216
216
  const error = err instanceof Error ? err : new Error(String(err), { cause: err });
217
217
  const request = Object.assign(req, {
218
- [Solas.Config.REQUEST_META_KEY]: { match, error, action },
218
+ [Config.REQUEST_META_KEY]: { match, error, action },
219
219
  });
220
220
  if (this.#onError)
221
221
  return this.#onError(error, request);
@@ -1,5 +1,5 @@
1
1
  import type { HttpException } from './navigation/http-exception.js';
2
- import { Build } from './build.js';
2
+ import * as Build from './build.js';
3
3
  type EntryKind = typeof Build.EntryKind;
4
4
  export declare namespace Metadata {
5
5
  type EntrySource = Exclude<EntryKind[keyof EntryKind], typeof Build.EntryKind.ENDPOINT | typeof Build.EntryKind.MIDDLEWARE>;
@@ -1,4 +1,4 @@
1
- import { Build } from './build.js';
1
+ import * as Build from './build.js';
2
2
  import { isHttpException } from './navigation/http-exception.js';
3
3
  const TITLE_TEMPLATE_STR = '%s';
4
4
  export { Metadata };
@@ -1,4 +1,4 @@
1
- import type { BoundaryError } from '../../types.js';
1
+ import type { BoundaryError } from '../boundary-error.js';
2
2
  import { type HttpException } from './http-exception.js';
3
3
  type ComponentsMap = Partial<Record<HttpException.StatusCode, React.ReactElement | null>>;
4
4
  export type Props = {
@@ -1,4 +1,4 @@
1
- import type { BoundaryError } from '../../types.js';
1
+ import type { BoundaryError } from '../boundary-error.js';
2
2
  export type Props = {
3
3
  fallback: ((error: BoundaryError) => React.ReactNode) | React.ReactNode;
4
4
  children: React.ReactNode;
@@ -1,4 +1,4 @@
1
- import { Solas } from '../../solas.js';
1
+ import * as Config from '../../config.js';
2
2
  function isRedirectStatusCode(value) {
3
3
  return value === 301 || value === 302 || value === 307 || value === 308;
4
4
  }
@@ -24,12 +24,12 @@ export const REDIRECT_DIGEST_PREFIX = 'REDIRECT';
24
24
  */
25
25
  function validate(url) {
26
26
  if (url.startsWith('//')) {
27
- throw new TypeError(`[${Solas.Config.NAME}] redirect() does not allow protocol-relative urls`);
27
+ throw new TypeError(`[${Config.NAME}] redirect() does not allow protocol-relative urls`);
28
28
  }
29
29
  // reject urls with control characters to prevent header injection
30
30
  for (const char of url) {
31
31
  if (char === '\r' || char === '\n') {
32
- throw new TypeError(`[${Solas.Config.NAME}] redirect() does not allow control characters`);
32
+ throw new TypeError(`[${Config.NAME}] redirect() does not allow control characters`);
33
33
  }
34
34
  }
35
35
  // good
@@ -40,10 +40,10 @@ function validate(url) {
40
40
  parsed = new URL(url);
41
41
  }
42
42
  catch {
43
- throw new TypeError(`[${Solas.Config.NAME}] redirect() only supports relative paths or absolute http/https urls`);
43
+ throw new TypeError(`[${Config.NAME}] redirect() only supports relative paths or absolute http/https urls`);
44
44
  }
45
45
  if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
46
- throw new TypeError(`[${Solas.Config.NAME}] redirect() only supports http:// and https:// urls`);
46
+ throw new TypeError(`[${Config.NAME}] redirect() only supports http:// and https:// urls`);
47
47
  }
48
48
  }
49
49
  /**
@@ -87,7 +87,7 @@ export function toRedirect(err) {
87
87
  ? err.url
88
88
  : undefined);
89
89
  if (!url) {
90
- throw new TypeError(`[${Solas.Config.NAME}] failed to reconstruct redirect`);
90
+ throw new TypeError(`[${Config.NAME}] failed to reconstruct redirect`);
91
91
  }
92
92
  return new Redirect(url, status);
93
93
  }
@@ -1,13 +1,14 @@
1
1
  import fs from 'node:fs/promises';
2
2
  import path from 'node:path';
3
- import { Compress } from '../utils/compress.js';
3
+ import * as Compress from '../utils/compress.js';
4
4
  import { Logger } from '../utils/logger.js';
5
- import { Solas } from '../solas.js';
6
- import { Prerender } from './prerender.js';
5
+ import * as Config from '../config.js';
6
+ import * as Manifest from '../manifest.js';
7
+ import * as Prerender from './prerender.js';
7
8
  import { Runtime } from './runtimes/runtime.js';
8
9
  const logger = new Logger();
9
10
  export async function postbuild(cwd = process.cwd()) {
10
- const manifestPath = path.join(cwd, Solas.Config.GENERATED_DIR, 'build.json');
11
+ const manifestPath = path.join(cwd, Config.GENERATED_DIR, 'build.json');
11
12
  let manifest;
12
13
  try {
13
14
  const raw = await fs.readFile(manifestPath, 'utf-8');
@@ -17,15 +18,15 @@ export async function postbuild(cwd = process.cwd()) {
17
18
  logger.error('[build] failed to read build manifest', err);
18
19
  throw err;
19
20
  }
20
- const outDir = path.resolve(cwd, Solas.Config.OUT_DIR);
21
+ const outDir = path.resolve(cwd, Config.OUT_DIR);
21
22
  const rscDir = path.join(outDir, 'rsc');
22
- const artifactRoot = Prerender.Artifact.getRootPath(outDir);
23
+ const artifactRoot = Prerender.getArtifactRootPath(outDir);
23
24
  // clear old prerender artifacts so routes that have switched modes
24
25
  // do not keep stale metadata from a previous build
25
26
  await fs.rm(artifactRoot, { recursive: true, force: true });
26
- const artifactManifest = {};
27
+ const artfifactManifest = {};
27
28
  if (manifest.prerenderRoutes.length > 0) {
28
- const concurrency = Prerender.Build.getConcurrency();
29
+ const concurrency = Prerender.getConcurrency();
29
30
  const pendingWrites = new Set();
30
31
  logger.info('[prerender]', `prerendering ${manifest.prerenderRoutes.length} routes (concurrency: ${concurrency})...`);
31
32
  const rscEntry = path.join(rscDir, 'index.js');
@@ -39,7 +40,7 @@ export async function postbuild(cwd = process.cwd()) {
39
40
  await Promise.race(pendingWrites);
40
41
  }
41
42
  }
42
- for await (const result of Prerender.Build.run(app, manifest.prerenderRoutes, {
43
+ for await (const result of Prerender.run(app, manifest.prerenderRoutes, {
43
44
  base: manifest.base,
44
45
  concurrency,
45
46
  origin: manifest.url,
@@ -54,7 +55,7 @@ export async function postbuild(cwd = process.cwd()) {
54
55
  continue;
55
56
  }
56
57
  const artifact = result.artifact;
57
- const artifactDir = Prerender.Artifact.getPath(outDir, route);
58
+ const artifactDir = Prerender.getArtifactPath(outDir, route);
58
59
  await enqueueWrite(async () => {
59
60
  try {
60
61
  if (artifact.mode === 'ppr') {
@@ -72,7 +73,7 @@ export async function postbuild(cwd = process.cwd()) {
72
73
  writes.push(Runtime.write(path.join(artifactDir, 'postponed.json'), JSON.stringify(artifact.postponed)));
73
74
  }
74
75
  await Promise.all(writes);
75
- artifactManifest[route] = {
76
+ artfifactManifest[route] = {
76
77
  mode: artifact.mode,
77
78
  files: artifact.postponed !== undefined
78
79
  ? ['metadata', 'prelude', 'postponed']
@@ -89,9 +90,9 @@ export async function postbuild(cwd = process.cwd()) {
89
90
  createdAt: artifact.createdAt,
90
91
  mode: artifact.mode,
91
92
  })),
92
- Runtime.write(Prerender.Artifact.getFilePath(outDir, route, Prerender.Artifact.FULL_PRERENDER_FILENAME), artifact.html),
93
+ Runtime.write(Prerender.getArtifactFilePath(outDir, route, Prerender.FULL_PRERENDER_FILENAME), artifact.html),
93
94
  ]);
94
- artifactManifest[route] = {
95
+ artfifactManifest[route] = {
95
96
  mode: artifact.mode,
96
97
  files: ['metadata', 'html'],
97
98
  };
@@ -106,10 +107,10 @@ export async function postbuild(cwd = process.cwd()) {
106
107
  }
107
108
  await fs.mkdir(artifactRoot, { recursive: true });
108
109
  const runtimeManifest = {
109
- artifacts: artifactManifest,
110
+ artifacts: artfifactManifest,
110
111
  publicFiles: manifest.publicFiles,
111
112
  };
112
- await Runtime.write(Solas.Runtime.getManifestPath(outDir), JSON.stringify(runtimeManifest));
113
+ await Runtime.write(Manifest.getManifestPath(outDir), JSON.stringify(runtimeManifest));
113
114
  if (manifest.sitemapRoutes.length > 0 && manifest.url) {
114
115
  const origin = manifest.url.replace(/\/$/, '');
115
116
  const urls = manifest.sitemapRoutes
@@ -141,8 +142,8 @@ export async function postbuild(cwd = process.cwd()) {
141
142
  }
142
143
  // full prerendered html is served straight from disk, but internal ppr
143
144
  // support files like prelude/metadata/postponed are read by the server
144
- return (normalisedPath.startsWith(`${Solas.Config.GENERATED_DIR}/ppr/`) &&
145
- normalisedPath.endsWith(`/${Prerender.Artifact.FULL_PRERENDER_FILENAME}`));
145
+ return (normalisedPath.startsWith(`${Config.GENERATED_DIR}/ppr/`) &&
146
+ normalisedPath.endsWith(`/${Prerender.FULL_PRERENDER_FILENAME}`));
146
147
  },
147
148
  })) {
148
149
  await Runtime.write(`${input}.br`, compressed);