@jk2908/solas 0.5.4 → 0.7.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 (75) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/README.md +34 -94
  3. package/dist/config.d.ts +24 -0
  4. package/dist/config.js +143 -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 -41
  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 +1 -1
  12. package/dist/internal/browser-router/link.d.ts +1 -1
  13. package/dist/internal/browser-router/link.js +1 -1
  14. package/dist/internal/browser-router/router.d.ts +2 -2
  15. package/dist/internal/browser-router/router.js +5 -5
  16. package/dist/internal/browser-router/shared.d.ts +182 -184
  17. package/dist/internal/browser-router/shared.js +49 -56
  18. package/dist/internal/browser-router/use-router.d.ts +1 -1
  19. package/dist/internal/browser-router/use-search-params.js +3 -3
  20. package/dist/internal/build.d.ts +108 -110
  21. package/dist/internal/build.js +569 -581
  22. package/dist/internal/codegen/config.js +4 -5
  23. package/dist/internal/codegen/environments.d.ts +1 -1
  24. package/dist/internal/codegen/environments.js +6 -9
  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 +3 -3
  34. package/dist/internal/env/rsc.js +26 -26
  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/runtimes/runtime.d.ts +7 -21
  49. package/dist/internal/runtimes/runtime.js +24 -19
  50. package/dist/internal/server/actions.js +2 -2
  51. package/dist/internal/ui/error-boundary.d.ts +1 -1
  52. package/dist/manifest.d.ts +7 -0
  53. package/dist/manifest.js +85 -0
  54. package/dist/prerender.d.ts +1 -1
  55. package/dist/prerender.js +1 -1
  56. package/dist/solas.d.ts +2 -46
  57. package/dist/solas.js +6 -266
  58. package/dist/types.d.ts +14 -25
  59. package/dist/types.js +1 -1
  60. package/dist/utils/base-path.d.ts +12 -14
  61. package/dist/utils/base-path.js +75 -82
  62. package/dist/utils/compress.d.ts +9 -11
  63. package/dist/utils/compress.js +59 -64
  64. package/dist/utils/context.d.ts +4 -6
  65. package/dist/utils/context.js +17 -22
  66. package/dist/utils/logger.js +2 -2
  67. package/dist/utils/time.d.ts +2 -4
  68. package/dist/utils/time.js +23 -29
  69. package/package.json +18 -8
  70. package/dist/internal/runtimes/bun.d.ts +0 -9
  71. package/dist/internal/runtimes/bun.js +0 -33
  72. package/dist/internal/runtimes/create.d.ts +0 -4
  73. package/dist/internal/runtimes/create.js +0 -9
  74. package/dist/internal/runtimes/node.d.ts +0 -9
  75. package/dist/internal/runtimes/node.js +0 -31
@@ -1,18 +1,17 @@
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
5
5
  */
6
6
  export function writeConfig(config) {
7
- const { runtime: _runtime, ...runtimeConfig } = config;
8
7
  const loggerLevel = config.logger?.level;
9
8
  const importLines = [
10
- `import type { RuntimeConfig } from '${Solas.Config.PKG_NAME}'`,
11
- loggerLevel ? `import { Logger } from '${Solas.Config.PKG_NAME}/utils/logger'` : '',
9
+ `import type { RuntimeConfig } from '${Config.PKG_NAME}'`,
10
+ loggerLevel ? `import { Logger } from '${Config.PKG_NAME}/utils/logger'` : '',
12
11
  ]
13
12
  .filter(Boolean)
14
13
  .join('\n');
15
- const configStatement = `const config = ${toSourceLiteral(runtimeConfig)} as const satisfies RuntimeConfig`;
14
+ const configStatement = `const config = ${toSourceLiteral(config)} as const satisfies RuntimeConfig`;
16
15
  const loggerStatement = loggerLevel
17
16
  ? `Logger.defaultLevel = ${toSourceLiteral(loggerLevel)}`
18
17
  : '';
@@ -2,7 +2,7 @@ import type { ConfiguredPluginConfig } from '../../types.js';
2
2
  /**
3
3
  * Generates the RSC entry code
4
4
  */
5
- export declare function writeRSCEntry(config: ConfiguredPluginConfig): string;
5
+ export declare function writeRSCEntry(_config: ConfiguredPluginConfig): string;
6
6
  /**
7
7
  * Generates the SSR entry code
8
8
  */
@@ -1,22 +1,19 @@
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
5
5
  */
6
- export function writeRSCEntry(config) {
7
- const runtime = toStringLiteral(config.runtime);
6
+ export function writeRSCEntry(_config) {
8
7
  return source `
9
8
  ${AUTOGEN_MSG}
10
9
 
11
- import { createHandler, createRuntime, Runtime } from '${Solas.Config.PKG_NAME}/env/rsc'
12
- import { Solas } from '${Solas.Config.PKG_NAME}/$'
10
+ import { createHandler, loadManifest } from '${Config.PKG_NAME}/env/rsc'
13
11
 
14
12
  import { manifest } from './manifest.js'
15
13
  import { importMap } from './maps.js'
16
14
  import { config } from './config.js'
17
15
 
18
- Runtime.runtime = createRuntime(${runtime})
19
- const runtimeManifest = await Solas.Runtime.loadManifest(Solas.Config.OUT_DIR)
16
+ const runtimeManifest = await loadManifest(${toStringLiteral(Config.OUT_DIR)})
20
17
 
21
18
  export default createHandler(config, manifest, importMap, runtimeManifest)
22
19
 
@@ -32,7 +29,7 @@ export function writeSSREntry() {
32
29
  return source `
33
30
  ${AUTOGEN_MSG}
34
31
 
35
- export { prerender, resume, ssr } from '${Solas.Config.PKG_NAME}/env/ssr'
32
+ export { prerender, resume, ssr } from '${Config.PKG_NAME}/env/ssr'
36
33
  `;
37
34
  }
38
35
  /**
@@ -42,7 +39,7 @@ export function writeBrowserEntry() {
42
39
  return source `
43
40
  ${AUTOGEN_MSG}
44
41
 
45
- import { browser } from '${Solas.Config.PKG_NAME}/env/browser'
42
+ import { browser } from '${Config.PKG_NAME}/env/browser'
46
43
 
47
44
  browser()
48
45
  `;
@@ -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,9 @@
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
- export { createRuntime } from '../runtimes/create.js';
6
5
  export { Runtime } from '../runtimes/runtime.js';
6
+ export { loadManifest } from '../../manifest.js';
7
7
  export type RscPayload = {
8
8
  returnValue?: {
9
9
  ok: boolean;
@@ -23,6 +23,6 @@ export type RscPayload = {
23
23
  * route manifest, and import map to build the router once, then returns an object
24
24
  * with a fetch method that handles requests
25
25
  */
26
- export declare function createHandler(config: RuntimeConfig, manifest: Manifest, importMap: ImportMap, runtimeManifest?: Solas.Runtime.Manifest | null): {
26
+ export declare function createHandler(config: RuntimeConfig, manifest: Manifest, importMap: ImportMap, runtimeManifest?: RuntimeManifest.Manifest | null): {
27
27
  fetch(req: Request): Promise<Response>;
28
28
  };
@@ -1,26 +1,26 @@
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';
17
17
  import DefaultErr from '../ui/defaults/error.js';
18
18
  import { RequestContext } from './request-context.js';
19
19
  import { getKnownDigest, isKnownError } from './utils.js';
20
- export { createRuntime } from '../runtimes/create.js';
21
20
  export { Runtime } from '../runtimes/runtime.js';
21
+ export { loadManifest } from '../../manifest.js';
22
22
  const logger = new Logger();
23
- const BASE_PATH = BasePath.normalise(import.meta.env.BASE_URL);
23
+ const BASE_PATH = normaliseBasePath(import.meta.env.BASE_URL);
24
24
  function resolveFilePath(root, relativePath) {
25
25
  try {
26
26
  const decodedPath = decodeURIComponent(relativePath);
@@ -43,16 +43,16 @@ function resolveFilePath(root, relativePath) {
43
43
  */
44
44
  async function createPayload(req, manifest, importMap, baseMetadata, returnValue, formState, temporaryReferences) {
45
45
  const resolver = new Resolver(manifest, importMap);
46
- const prerender = req.headers.get(`x-${Solas.Config.SLUG}-prerender`) === '1';
46
+ const prerender = req.headers.get(`x-${Config.SLUG}-prerender`) === '1';
47
47
  const url = new URL(req.url);
48
- const routedPath = BasePath.strip(url.pathname, BASE_PATH) ?? url.pathname;
48
+ const routedPath = stripBasePath(url.pathname, BASE_PATH) ?? url.pathname;
49
49
  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));
50
+ const match = resolver.enhance(resolver.reconcile(pathname, req[Config.REQUEST_META_KEY].match, req[Config.REQUEST_META_KEY].error));
51
51
  // if there's no match then no user supplied error boundary
52
52
  // has been found, and we should server render a default
53
53
  // error screen
54
54
  if (!match) {
55
- const error = toHttpExceptionLike(req[Solas.Config.REQUEST_META_KEY].error ?? new HttpException(404, 'Not found'));
55
+ const error = toHttpExceptionLike(req[Config.REQUEST_META_KEY].error ?? new HttpException(404, 'Not found'));
56
56
  const title = `${error.status ? `${error.status} -` : ''}${error.message}`;
57
57
  const rscPayload = {
58
58
  root: (_jsxs("html", { lang: "en", children: [
@@ -163,11 +163,11 @@ async function createPayload(req, manifest, importMap, baseMetadata, returnValue
163
163
  * with a fetch method that handles requests
164
164
  */
165
165
  export function createHandler(config, manifest, importMap, runtimeManifest = null) {
166
- const CLIENT_OUTPUT_DIR = path.resolve(Solas.Config.OUT_DIR, 'client');
166
+ const CLIENT_OUTPUT_DIR = path.resolve(Config.OUT_DIR, 'client');
167
167
  // vite emits solas-controlled assets under dist/client/_solas
168
- const SOLAS_ASSETS_DIR = path.resolve(CLIENT_OUTPUT_DIR, Solas.Config.ASSETS_DIR);
168
+ const SOLAS_ASSETS_DIR = path.resolve(CLIENT_OUTPUT_DIR, Config.ASSETS_DIR);
169
169
  // requests for /_solas and /_solas/* are reserved
170
- const SOLAS_ASSETS_URL_ROOT = `/${Solas.Config.ASSETS_DIR}`;
170
+ const SOLAS_ASSETS_URL_ROOT = `/${Config.ASSETS_DIR}`;
171
171
  const prerenderPathMode = config.trailingSlash === 'always' ? 'always' : 'never';
172
172
  /**
173
173
  * Create the HTTP response for a single incoming request. Runs actions when needed,
@@ -180,7 +180,7 @@ export function createHandler(config, manifest, importMap, runtimeManifest = nul
180
180
  temporaryReferences: undefined,
181
181
  returnValue: undefined,
182
182
  };
183
- if (req[Solas.Config.REQUEST_META_KEY].action) {
183
+ if (req[Config.REQUEST_META_KEY].action) {
184
184
  opts = await processActionRequest(req, {
185
185
  trustedOrigins: config.trustedOrigins,
186
186
  url: config.url,
@@ -206,16 +206,16 @@ export function createHandler(config, manifest, importMap, runtimeManifest = nul
206
206
  if (isRedirect(err)) {
207
207
  const redirect = toRedirect(err);
208
208
  const location = redirect.url.startsWith('/')
209
- ? new URL(BasePath.apply(redirect.url, BASE_PATH), req.url).toString()
209
+ ? new URL(applyBasePath(redirect.url, BASE_PATH), req.url).toString()
210
210
  : redirect.url;
211
211
  return Response.redirect(location, redirect.status);
212
212
  }
213
- if (req[Solas.Config.REQUEST_META_KEY].error || !isHttpException(err)) {
213
+ if (req[Config.REQUEST_META_KEY].error || !isHttpException(err)) {
214
214
  return null;
215
215
  }
216
216
  // retry once with the surfaced HttpException attached so createPayload can
217
217
  // rebuild the route through the nearest matching status boundary
218
- req[Solas.Config.REQUEST_META_KEY].error = toHttpException(err);
218
+ req[Config.REQUEST_META_KEY].error = toHttpException(err);
219
219
  try {
220
220
  const { stream: retriedRscStream, status: retriedStatus } = await createPayload(req, manifest, importMap, config.metadata, opts.returnValue, opts.formState, opts.temporaryReferences);
221
221
  const retriedStream = await retriedRscStream;
@@ -225,13 +225,13 @@ export function createHandler(config, manifest, importMap, runtimeManifest = nul
225
225
  };
226
226
  }
227
227
  finally {
228
- req[Solas.Config.REQUEST_META_KEY].error = undefined;
228
+ req[Config.REQUEST_META_KEY].error = undefined;
229
229
  }
230
230
  }
231
231
  // prerender artifact requests bypass the normal document path so the cli
232
232
  // gets structured JSON instead of a rendered html response
233
- if (req.headers.get(`x-${Solas.Config.SLUG}-prerender`) === '1' &&
234
- req.headers.get(`x-${Solas.Config.SLUG}-prerender-artifact`) === '1') {
233
+ if (req.headers.get(`x-${Config.SLUG}-prerender`) === '1' &&
234
+ req.headers.get(`x-${Config.SLUG}-prerender-artifact`) === '1') {
235
235
  try {
236
236
  const artifact = await mod.prerender(stream, {
237
237
  formState: opts.formState,
@@ -275,8 +275,8 @@ export function createHandler(config, manifest, importMap, runtimeManifest = nul
275
275
  : null;
276
276
  const tryPrelude = artifactEntry?.mode === 'ppr';
277
277
  if (tryPrelude) {
278
- const postponedState = await Prerender.Artifact.loadPostponedState(Solas.Config.OUT_DIR, lookupPath);
279
- const prelude = await Prerender.Artifact.loadPrelude(Solas.Config.OUT_DIR, lookupPath);
278
+ const postponedState = await Prerender.loadPostponedState(Config.OUT_DIR, lookupPath);
279
+ const prelude = await Prerender.loadPrelude(Config.OUT_DIR, lookupPath);
280
280
  // resumable ppr responses splice fresh streamed content into the cached
281
281
  // prelude when postponed state is available for this route
282
282
  if (postponedState) {
@@ -287,7 +287,7 @@ export function createHandler(config, manifest, importMap, runtimeManifest = nul
287
287
  injectPayload: false,
288
288
  });
289
289
  const body = prelude
290
- ? Prerender.Artifact.composePreludeAndResume(prelude, resumeStream)
290
+ ? Prerender.composePreludeAndResume(prelude, resumeStream)
291
291
  : resumeStream;
292
292
  return new Response(body, {
293
293
  headers: {
@@ -343,13 +343,13 @@ export function createHandler(config, manifest, importMap, runtimeManifest = nul
343
343
  if (method !== 'GET' && method !== 'HEAD')
344
344
  return httpRouter.fetch(req);
345
345
  const accept = req.headers.get('accept') ?? '';
346
- const routedPath = BasePath.strip(url.pathname, BASE_PATH);
346
+ const routedPath = stripBasePath(url.pathname, BASE_PATH);
347
347
  const canonicalPath = routedPath == null
348
348
  ? null
349
349
  : config.trailingSlash === 'ignore'
350
350
  ? routedPath
351
351
  : normalisePathname(routedPath, config.trailingSlash);
352
- const canonicalPathname = canonicalPath == null ? null : BasePath.apply(canonicalPath, BASE_PATH);
352
+ const canonicalPathname = canonicalPath == null ? null : applyBasePath(canonicalPath, BASE_PATH);
353
353
  if (canonicalPathname != null &&
354
354
  (method === 'GET' || method === 'HEAD') &&
355
355
  config.trailingSlash !== 'ignore' &&
@@ -384,12 +384,12 @@ export function createHandler(config, manifest, importMap, runtimeManifest = nul
384
384
  if (canonicalPath != null &&
385
385
  !import.meta.env.DEV &&
386
386
  accept.includes('text/html') &&
387
- req.headers.get(`x-${Solas.Config.SLUG}-prerender-artifact`) !== '1') {
387
+ req.headers.get(`x-${Config.SLUG}-prerender-artifact`) !== '1') {
388
388
  // turn the request path into the normal route shape we use for artifact lookups
389
389
  const lookupPath = normalisePathname(canonicalPath, prerenderPathMode);
390
390
  // only full prerender routes have a saved html file we can serve directly
391
391
  const prerenderPath = runtimeManifest?.artifacts[lookupPath]?.mode === 'full'
392
- ? Prerender.Artifact.getFilePath(Solas.Config.OUT_DIR, lookupPath, Prerender.Artifact.FULL_PRERENDER_FILENAME)
392
+ ? Prerender.getArtifactFilePath(Config.OUT_DIR, lookupPath, Prerender.FULL_PRERENDER_FILENAME)
393
393
  : null;
394
394
  if (prerenderPath) {
395
395
  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);