@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,6 +1,6 @@
1
1
  import { promises as fs } from 'node:fs';
2
2
  import path from 'node:path';
3
- import { Solas } from '../solas.js';
3
+ import * as Config from '../config.js';
4
4
  /**
5
5
  * Collect the root request paths for files that originate in Vite's public dir.
6
6
  * Vite copies these files into the built client output unchanged. Solas stores
@@ -37,9 +37,7 @@ export async function collect(root) {
37
37
  for (const entry of entries) {
38
38
  // top-level /public/_solas would collide with framework assets served
39
39
  // from /_solas, so keep that namespace reserved
40
- if (parts.length === 0 &&
41
- entry.isDirectory() &&
42
- entry.name === Solas.Config.ASSETS_DIR) {
40
+ if (parts.length === 0 && entry.isDirectory() && entry.name === Config.ASSETS_DIR) {
43
41
  continue;
44
42
  }
45
43
  const nextParts = [...parts, entry.name];
@@ -1,7 +1,7 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { use } from 'react';
3
3
  import { Logger } from '../../utils/logger.js';
4
- import { Solas } from '../../solas.js';
4
+ import * as Config from '../../config.js';
5
5
  const logger = new Logger();
6
6
  const cache = new WeakMap();
7
7
  /**
@@ -37,7 +37,7 @@ export function Head({ metadata: m, }) {
37
37
  return null;
38
38
  const metadata = use(toSafeUsable(m));
39
39
  return (_jsxs(_Fragment, { children: [
40
- _jsx("meta", { name: "generator", content: Solas.Config.NAME }), toContent(metadata.title) !== undefined && (_jsx("title", { children: toContent(metadata.title) })), metadata.meta?.map(meta => {
40
+ _jsx("meta", { name: "generator", content: Config.NAME }), toContent(metadata.title) !== undefined && (_jsx("title", { children: toContent(metadata.title) })), metadata.meta?.map(meta => {
41
41
  if ('charSet' in meta) {
42
42
  return _jsx("meta", { charSet: meta.charSet }, meta.charSet);
43
43
  }
@@ -1,6 +1,6 @@
1
1
  import { lazy } from 'react';
2
2
  import { Logger } from '../utils/logger.js';
3
- import { Build } from './build.js';
3
+ import * as Build from './build.js';
4
4
  import { Metadata } from './metadata.js';
5
5
  import { HttpException, isHttpException } from './navigation/http-exception.js';
6
6
  const logger = new Logger();
@@ -1,25 +1,11 @@
1
- export declare namespace Runtime {
2
- type Impl = {
3
- exists: (filePath: string) => Promise<boolean>;
4
- readText: (filePath: string) => Promise<string>;
5
- readBuffer: (filePath: string) => Promise<ArrayBuffer>;
6
- mimeType: (filePath: string) => string;
7
- write: (filePath: string, content: string | NodeJS.ArrayBufferView) => Promise<void>;
8
- hash: (value: string) => string;
9
- };
10
- }
11
- export declare abstract class RuntimeBase implements Runtime.Impl {
12
- abstract exists(filePath: string): Promise<boolean>;
13
- abstract readText(filePath: string): Promise<string>;
14
- abstract readBuffer(filePath: string): Promise<ArrayBuffer>;
15
- abstract mimeType(filePath: string): string;
16
- abstract write(filePath: string, content: string | NodeJS.ArrayBufferView): Promise<void>;
17
- abstract hash(value: string): string;
18
- }
1
+ /**
2
+ * A single filesystem/hash/mime implementation shared by every runtime.
3
+ *
4
+ * Bun runs the Node standard library natively, so there is no need for
5
+ * per-runtime adapters: `node:fs` and `node:crypto` behave identically under
6
+ * Bun and Node, and mime lookups go through the same table for both.
7
+ */
19
8
  export declare class Runtime {
20
- #private;
21
- static set runtime(runtime: Runtime.Impl);
22
- static get runtime(): Runtime.Impl;
23
9
  static exists(filePath: string): Promise<boolean>;
24
10
  static readText(filePath: string): Promise<string>;
25
11
  static readBuffer(filePath: string): Promise<ArrayBuffer>;
@@ -1,32 +1,37 @@
1
- export class RuntimeBase {
2
- }
1
+ import { createHash } from 'node:crypto';
2
+ import fs from 'node:fs/promises';
3
+ import { getMimeTypeFromPath } from './mime.js';
4
+ /**
5
+ * A single filesystem/hash/mime implementation shared by every runtime.
6
+ *
7
+ * Bun runs the Node standard library natively, so there is no need for
8
+ * per-runtime adapters: `node:fs` and `node:crypto` behave identically under
9
+ * Bun and Node, and mime lookups go through the same table for both.
10
+ */
3
11
  export class Runtime {
4
- static #runtime;
5
- static set runtime(runtime) {
6
- this.#runtime = runtime;
7
- }
8
- static get runtime() {
9
- if (!this.#runtime) {
10
- throw new Error('No runtime configured. Please set the runtime implementation before using runtime methods.');
12
+ static async exists(filePath) {
13
+ try {
14
+ await fs.access(filePath);
15
+ return true;
16
+ }
17
+ catch {
18
+ return false;
11
19
  }
12
- return this.#runtime;
13
- }
14
- static exists(filePath) {
15
- return this.runtime.exists(filePath);
16
20
  }
17
21
  static readText(filePath) {
18
- return this.runtime.readText(filePath);
22
+ return fs.readFile(filePath, 'utf-8');
19
23
  }
20
- static readBuffer(filePath) {
21
- return this.runtime.readBuffer(filePath);
24
+ static async readBuffer(filePath) {
25
+ const buffer = await fs.readFile(filePath);
26
+ return buffer.buffer.slice(buffer.byteOffset, buffer.byteOffset + buffer.byteLength);
22
27
  }
23
28
  static mimeType(filePath) {
24
- return this.runtime.mimeType(filePath);
29
+ return getMimeTypeFromPath(filePath);
25
30
  }
26
31
  static write(filePath, content) {
27
- return this.runtime.write(filePath, content);
32
+ return fs.writeFile(filePath, content);
28
33
  }
29
34
  static hash(value) {
30
- return this.runtime.hash(value);
35
+ return createHash('sha256').update(value).digest('hex').slice(0, 16);
31
36
  }
32
37
  }
@@ -1,5 +1,5 @@
1
1
  import { createTemporaryReferenceSet, decodeAction, decodeFormState, decodeReply, loadServerAction, } from '@vitejs/plugin-rsc/rsc';
2
- import { Solas } from '../../solas.js';
2
+ import * as Config from '../../config.js';
3
3
  import { enforce } from './csrf.js';
4
4
  /**
5
5
  * Check if a request is an action request and reuse parsed FormData
@@ -66,7 +66,7 @@ export async function processActionRequest(req, csrf = {}) {
66
66
  // we might have already parsed FormData in the router for multipart action
67
67
  // detection should be attached to the SolasRequest, so we can reuse that
68
68
  // to avoid parsing twice
69
- const parsedFormData = req[Solas.Config.REQUEST_META_KEY]?.parsedFormData;
69
+ const parsedFormData = req[Config.REQUEST_META_KEY]?.parsedFormData;
70
70
  const formData = parsedFormData ?? (await req.formData());
71
71
  const decodedAction = await decodeAction(formData);
72
72
  const result = await decodedAction();
@@ -1,5 +1,5 @@
1
1
  import { Component } from 'react';
2
- import type { BoundaryError } from '../../types.js';
2
+ import type { BoundaryError } from '../boundary-error.js';
3
3
  export type Props = {
4
4
  fallback: ((error: BoundaryError, reset: () => void) => React.ReactNode) | React.ReactNode;
5
5
  onError?: (error: BoundaryError) => void;
@@ -0,0 +1,7 @@
1
+ import * as Prerender from './internal/prerender.js';
2
+ export type Manifest = {
3
+ artifacts: Prerender.ArtifactManifest;
4
+ publicFiles: ReadonlySet<string>;
5
+ };
6
+ export declare function getManifestPath(outDir: string): string;
7
+ export declare function loadManifest(outDir: string): Promise<Manifest | null>;
@@ -0,0 +1,85 @@
1
+ import * as Config from './config.js';
2
+ import { Runtime } from './internal/runtimes/runtime.js';
3
+ const manifestCache = new Map();
4
+ export function getManifestPath(outDir) {
5
+ return [outDir, Config.GENERATED_DIR, Config.RUNTIME_MANIFEST]
6
+ .map((part, index) => {
7
+ const normalised = part.replace(/\\/g, '/').replace(/\/+/g, '/');
8
+ if (index === 0)
9
+ return normalised.replace(/\/+$/, '');
10
+ return normalised.replace(/^\/+/, '').replace(/\/+$/, '');
11
+ })
12
+ .join('/');
13
+ }
14
+ export async function loadManifest(outDir) {
15
+ if (manifestCache.has(outDir)) {
16
+ return manifestCache.get(outDir) ?? null;
17
+ }
18
+ const manifestPath = getManifestPath(outDir);
19
+ if (!(await Runtime.exists(manifestPath))) {
20
+ manifestCache.set(outDir, null);
21
+ return null;
22
+ }
23
+ try {
24
+ const value = JSON.parse(await Runtime.readText(manifestPath));
25
+ if (!isRecord(value)) {
26
+ manifestCache.set(outDir, null);
27
+ return null;
28
+ }
29
+ const artifacts = value.artifacts ?? value.routes;
30
+ const publicFiles = value.publicFiles;
31
+ if (!isRecord(artifacts)) {
32
+ manifestCache.set(outDir, null);
33
+ return null;
34
+ }
35
+ if (publicFiles !== undefined && !Array.isArray(publicFiles)) {
36
+ manifestCache.set(outDir, null);
37
+ return null;
38
+ }
39
+ for (const entry of Object.values(artifacts)) {
40
+ if (!isRecord(entry)) {
41
+ manifestCache.set(outDir, null);
42
+ return null;
43
+ }
44
+ const { mode, files } = entry;
45
+ if (mode !== 'full' && mode !== 'ppr') {
46
+ manifestCache.set(outDir, null);
47
+ return null;
48
+ }
49
+ if (files !== undefined) {
50
+ if (!Array.isArray(files)) {
51
+ manifestCache.set(outDir, null);
52
+ return null;
53
+ }
54
+ for (const file of files) {
55
+ if (file !== 'html' &&
56
+ file !== 'prelude' &&
57
+ file !== 'postponed' &&
58
+ file !== 'metadata') {
59
+ manifestCache.set(outDir, null);
60
+ return null;
61
+ }
62
+ }
63
+ }
64
+ }
65
+ for (const entry of publicFiles ?? []) {
66
+ if (typeof entry !== 'string' || !entry.startsWith('/')) {
67
+ manifestCache.set(outDir, null);
68
+ return null;
69
+ }
70
+ }
71
+ const runtimeManifest = {
72
+ artifacts: artifacts,
73
+ publicFiles: new Set(publicFiles ?? []),
74
+ };
75
+ manifestCache.set(outDir, runtimeManifest);
76
+ return runtimeManifest;
77
+ }
78
+ catch {
79
+ manifestCache.set(outDir, null);
80
+ return null;
81
+ }
82
+ }
83
+ function isRecord(value) {
84
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
85
+ }
@@ -1 +1 @@
1
- export { Prerender } from './internal/prerender.js';
1
+ export * as Prerender from './internal/prerender.js';
package/dist/prerender.js CHANGED
@@ -1 +1 @@
1
- export { Prerender } from './internal/prerender.js';
1
+ export * as Prerender from './internal/prerender.js';
package/dist/solas.d.ts CHANGED
@@ -1,47 +1,3 @@
1
- import type { Prerender } from './internal/prerender.js';
2
- import type { PluginConfig } from './types.js';
3
- export declare namespace Solas {
4
- interface Routes {
5
- }
6
- namespace Config {
7
- const NAME = "Solas";
8
- const SLUG: string;
9
- const PKG_NAME: string;
10
- const OUT_DIR = "dist";
11
- const APP_DIR = "app";
12
- const GENERATED_DIR: string;
13
- const ENTRY_RSC = "entry.rsc.tsx";
14
- const ENTRY_SSR = "entry.ssr.tsx";
15
- const ENTRY_BROWSER = "entry.browser.tsx";
16
- const ASSETS_DIR: string;
17
- const PUBLIC_DIR = "public";
18
- const $: unique symbol;
19
- const REQUEST_META_KEY: string;
20
- const LOG_LEVELS: readonly ["debug", "info", "warn", "error", "fatal"];
21
- const RUNTIMES: readonly ["auto", "node", "bun"];
22
- const PRERENDER_MODES: readonly ["full", "ppr", false];
23
- const TRAILING_SLASH_MODES: readonly ["always", "never", "ignore"];
24
- const RUNTIME_MANIFEST = "runtime-manifest.json";
25
- /**
26
- * Validate the plugin configuration object, throwing an error if invalid
27
- * @param input - the unvalidated configuration object
28
- * @return the typed and validated configuration object
29
- */
30
- function validate(input: unknown): PluginConfig;
31
- }
32
- function getVersion(): string;
33
- namespace Runtime {
34
- type Manifest = {
35
- artifacts: Prerender.Artifact.Manifest;
36
- publicFiles: ReadonlySet<string>;
37
- };
38
- function getManifestPath(outDir: string): string;
39
- function loadManifest(outDir: string): Promise<Manifest | null>;
40
- }
41
- namespace Events {
42
- const names: {
43
- readonly NAVIGATION: `${string}navigation`;
44
- readonly NAVIGATION_ERROR: `${string}navigationerror`;
45
- };
46
- }
1
+ export interface Routes {
47
2
  }
3
+ export declare function getVersion(): string;
package/dist/solas.js CHANGED
@@ -1,268 +1,8 @@
1
- import { Runtime as InternalRuntime } from './internal/runtimes/runtime.js';
2
- export { Solas };
3
- var Solas;
4
- (function (Solas) {
5
- let Config;
6
- (function (Config) {
7
- Config.NAME = 'Solas';
8
- Config.SLUG = Config.NAME.toLowerCase();
9
- Config.PKG_NAME = `@jk2908/${Config.SLUG}`;
10
- Config.OUT_DIR = 'dist';
11
- Config.APP_DIR = 'app';
12
- Config.GENERATED_DIR = `.${Config.SLUG}`;
13
- Config.ENTRY_RSC = 'entry.rsc.tsx';
14
- Config.ENTRY_SSR = 'entry.ssr.tsx';
15
- Config.ENTRY_BROWSER = 'entry.browser.tsx';
16
- Config.ASSETS_DIR = `_${Config.SLUG}`;
17
- Config.PUBLIC_DIR = 'public';
18
- Config.$ = Symbol(Config.SLUG);
19
- Config.REQUEST_META_KEY = `__${Config.SLUG.toUpperCase()}__`;
20
- Config.LOG_LEVELS = ['debug', 'info', 'warn', 'error', 'fatal'];
21
- Config.RUNTIMES = ['auto', 'node', 'bun'];
22
- Config.PRERENDER_MODES = ['full', 'ppr', false];
23
- Config.TRAILING_SLASH_MODES = ['always', 'never', 'ignore'];
24
- Config.RUNTIME_MANIFEST = 'runtime-manifest.json';
25
- const CONFIG_KEYS = new Set([
26
- 'runtime',
27
- 'port',
28
- 'logger',
29
- 'metadata',
30
- 'precompress',
31
- 'prerender',
32
- 'sitemap',
33
- 'trustedOrigins',
34
- 'trailingSlash',
35
- 'url',
36
- ]);
37
- const LOGGER_KEYS = new Set(['level']);
38
- /**
39
- * Validate the plugin configuration object, throwing an error if invalid
40
- * @param input - the unvalidated configuration object
41
- * @return the typed and validated configuration object
42
- */
43
- function validate(input) {
44
- if (input === undefined)
45
- return {};
46
- const errors = [];
47
- if (!isRecord(input)) {
48
- throw new Error(`[${Config.NAME}] Invalid config:\n- Expected plugin config to be an object`);
49
- }
50
- for (const key of Object.keys(input)) {
51
- if (!CONFIG_KEYS.has(key)) {
52
- errors.push(`Unknown config key: ${key}`);
53
- }
54
- }
55
- if ('runtime' in input &&
56
- input.runtime !== undefined &&
57
- !isRuntime(input.runtime)) {
58
- errors.push("config.runtime must be 'auto', 'node', or 'bun'");
59
- }
60
- if ('url' in input && input.url !== undefined) {
61
- if (typeof input.url !== 'string') {
62
- errors.push('config.url must be a string');
63
- }
64
- else {
65
- try {
66
- const url = new URL(input.url);
67
- if (url.protocol !== 'http:' && url.protocol !== 'https:') {
68
- errors.push('config.url must use http:// or https://');
69
- }
70
- }
71
- catch {
72
- errors.push('config.url must be a valid URL');
73
- }
74
- }
75
- }
76
- if ('precompress' in input && input.precompress !== undefined) {
77
- if (typeof input.precompress !== 'boolean') {
78
- errors.push('config.precompress must be a boolean');
79
- }
80
- }
81
- if ('trustedOrigins' in input && input.trustedOrigins !== undefined) {
82
- if (!Array.isArray(input.trustedOrigins)) {
83
- errors.push('config.trustedOrigins must be an array of origins');
84
- }
85
- else {
86
- for (const [index, value] of input.trustedOrigins.entries()) {
87
- if (typeof value !== 'string') {
88
- errors.push(`config.trustedOrigins[${index}] must be a string`);
89
- continue;
90
- }
91
- try {
92
- const url = new URL(value);
93
- const canonical = value.replace(/\/$/, '');
94
- if (url.protocol !== 'http:' && url.protocol !== 'https:') {
95
- errors.push(`config.trustedOrigins[${index}] must use http:// or https://`);
96
- continue;
97
- }
98
- if (canonical !== url.origin) {
99
- errors.push(`config.trustedOrigins[${index}] must be an origin without a path, query, or hash`);
100
- }
101
- }
102
- catch {
103
- errors.push(`config.trustedOrigins[${index}] must be a valid URL origin`);
104
- }
105
- }
106
- }
107
- }
108
- if ('sitemap' in input && input.sitemap !== undefined && input.sitemap !== false) {
109
- if (typeof input.sitemap !== 'boolean' && typeof input.sitemap !== 'object') {
110
- errors.push('config.sitemap must be a boolean or an object with a routes function');
111
- }
112
- if (typeof input.sitemap === 'object' &&
113
- input.sitemap !== null &&
114
- typeof input.sitemap.routes !== 'function') {
115
- errors.push('config.sitemap.routes must be a function');
116
- }
117
- if (!input.url) {
118
- errors.push('config.url is required when sitemap is enabled');
119
- }
120
- }
121
- if ('prerender' in input && input.prerender !== undefined) {
122
- if (!new Set(Config.PRERENDER_MODES).has(input.prerender)) {
123
- errors.push("config.prerender must be 'full', 'ppr', or false");
124
- }
125
- }
126
- if ('trailingSlash' in input && input.trailingSlash !== undefined) {
127
- if (typeof input.trailingSlash !== 'string' ||
128
- !new Set(Config.TRAILING_SLASH_MODES).has(input.trailingSlash)) {
129
- errors.push("config.trailingSlash must be 'always', 'never', or 'ignore'");
130
- }
131
- }
132
- if ('metadata' in input &&
133
- input.metadata !== undefined &&
134
- !isRecord(input.metadata)) {
135
- errors.push('config.metadata must be an object when provided');
136
- }
137
- if ('logger' in input && input.logger !== undefined) {
138
- if (!isRecord(input.logger)) {
139
- errors.push('config.logger must be an object when provided');
140
- }
141
- else {
142
- for (const key of Object.keys(input.logger)) {
143
- if (!LOGGER_KEYS.has(key)) {
144
- errors.push(`Unknown config.logger key: ${key}`);
145
- }
146
- }
147
- if ('level' in input.logger && input.logger.level !== undefined) {
148
- if (typeof input.logger.level !== 'string' ||
149
- !new Set(Config.LOG_LEVELS).has(input.logger.level)) {
150
- errors.push('config.logger.level must be one of: debug, info, warn, error, fatal');
151
- }
152
- }
153
- }
154
- }
155
- if (errors.length > 0) {
156
- throw new Error(`[${Config.NAME}] Invalid config:\n- ${errors.join('\n- ')}`);
157
- }
158
- return input;
159
- }
160
- Config.validate = validate;
161
- })(Config = Solas.Config || (Solas.Config = {}));
162
- function getVersion() {
163
- const value = import.meta.env.SOLAS_VERSION;
164
- if (typeof value !== 'string' || value.length === 0) {
165
- throw new Error(`[${Config.NAME}] Missing ${Config.NAME} package version`);
166
- }
167
- return value;
1
+ import * as Config from './config.js';
2
+ export function getVersion() {
3
+ const value = import.meta.env.SOLAS_VERSION;
4
+ if (typeof value !== 'string' || value.length === 0) {
5
+ throw new Error(`[${Config.NAME}] Missing ${Config.NAME} package version`);
168
6
  }
169
- Solas.getVersion = getVersion;
170
- let Runtime;
171
- (function (Runtime) {
172
- const manifestCache = new Map();
173
- function getManifestPath(outDir) {
174
- return [outDir, Config.GENERATED_DIR, Config.RUNTIME_MANIFEST]
175
- .map((part, index) => {
176
- const normalised = part.replace(/\\/g, '/').replace(/\/+/g, '/');
177
- if (index === 0)
178
- return normalised.replace(/\/+$/, '');
179
- return normalised.replace(/^\/+/, '').replace(/\/+$/, '');
180
- })
181
- .join('/');
182
- }
183
- Runtime.getManifestPath = getManifestPath;
184
- async function loadManifest(outDir) {
185
- if (manifestCache.has(outDir)) {
186
- return manifestCache.get(outDir) ?? null;
187
- }
188
- const manifestPath = getManifestPath(outDir);
189
- if (!(await InternalRuntime.exists(manifestPath))) {
190
- manifestCache.set(outDir, null);
191
- return null;
192
- }
193
- try {
194
- const value = JSON.parse(await InternalRuntime.readText(manifestPath));
195
- if (!isRecord(value)) {
196
- manifestCache.set(outDir, null);
197
- return null;
198
- }
199
- const artifacts = value.artifacts ?? value.routes;
200
- const publicFiles = value.publicFiles;
201
- if (!isRecord(artifacts)) {
202
- manifestCache.set(outDir, null);
203
- return null;
204
- }
205
- if (publicFiles !== undefined && !Array.isArray(publicFiles)) {
206
- manifestCache.set(outDir, null);
207
- return null;
208
- }
209
- for (const entry of Object.values(artifacts)) {
210
- if (!isRecord(entry)) {
211
- manifestCache.set(outDir, null);
212
- return null;
213
- }
214
- const { mode, files } = entry;
215
- if (mode !== 'full' && mode !== 'ppr') {
216
- manifestCache.set(outDir, null);
217
- return null;
218
- }
219
- if (files !== undefined) {
220
- if (!Array.isArray(files)) {
221
- manifestCache.set(outDir, null);
222
- return null;
223
- }
224
- for (const file of files) {
225
- if (file !== 'html' &&
226
- file !== 'prelude' &&
227
- file !== 'postponed' &&
228
- file !== 'metadata') {
229
- manifestCache.set(outDir, null);
230
- return null;
231
- }
232
- }
233
- }
234
- }
235
- for (const entry of publicFiles ?? []) {
236
- if (typeof entry !== 'string' || !entry.startsWith('/')) {
237
- manifestCache.set(outDir, null);
238
- return null;
239
- }
240
- }
241
- const runtimeManifest = {
242
- artifacts: artifacts,
243
- publicFiles: new Set(publicFiles ?? []),
244
- };
245
- manifestCache.set(outDir, runtimeManifest);
246
- return runtimeManifest;
247
- }
248
- catch {
249
- manifestCache.set(outDir, null);
250
- return null;
251
- }
252
- }
253
- Runtime.loadManifest = loadManifest;
254
- })(Runtime = Solas.Runtime || (Solas.Runtime = {}));
255
- let Events;
256
- (function (Events) {
257
- Events.names = {
258
- NAVIGATION: `${Config.SLUG}navigation`,
259
- NAVIGATION_ERROR: `${Config.SLUG}navigationerror`,
260
- };
261
- })(Events = Solas.Events || (Solas.Events = {}));
262
- })(Solas || (Solas = {}));
263
- function isRecord(value) {
264
- return typeof value === 'object' && value !== null && !Array.isArray(value);
265
- }
266
- function isRuntime(value) {
267
- return typeof value === 'string' && new Set(Solas.Config.RUNTIMES).has(value);
7
+ return value;
268
8
  }
package/dist/types.d.ts CHANGED
@@ -2,40 +2,32 @@ type BunRequest = Request & {
2
2
  params?: Record<string, string | string[]>;
3
3
  };
4
4
  import { ExportReader } from './utils/export-reader.js';
5
- import type { BrowserRouter } from './internal/browser-router/shared.js';
6
- import type { Build } from './internal/build.js';
5
+ import type * as BrowserRouter from './internal/browser-router/shared.js';
7
6
  import type { HttpRouter } from './internal/http-router/router.js';
8
7
  import type { Metadata } from './internal/metadata.js';
9
8
  import type { HttpException } from './internal/navigation/http-exception.js';
10
- import { Solas } from './solas.js';
11
- export type LogLevel = (typeof Solas.Config.LOG_LEVELS)[number];
12
- export type Runtime = (typeof Solas.Config.RUNTIMES)[number];
13
- type Origin = `http://${string}` | `https://${string}`;
9
+ import * as Config from './config.js';
10
+ import * as Build from './internal/build.js';
11
+ export type LogLevel = (typeof Config.LOG_LEVELS)[number];
12
+ export type Origin = `http://${string}` | `https://${string}`;
14
13
  type PluginConfigBase = {
15
- runtime?: Runtime;
16
- port?: number;
17
14
  precompress?: boolean;
18
15
  prerender?: Route.Prerender;
19
16
  metadata?: Metadata.Item;
20
- trailingSlash?: (typeof Solas.Config.TRAILING_SLASH_MODES)[number];
17
+ trailingSlash?: (typeof Config.TRAILING_SLASH_MODES)[number];
21
18
  trustedOrigins?: readonly Origin[];
22
19
  readonly logger?: {
23
20
  level?: LogLevel;
24
21
  };
25
22
  };
26
- export type PluginConfig = PluginConfigBase & ({
27
- url: Origin;
28
- sitemap: true | {
23
+ export type PluginConfig = PluginConfigBase & {
24
+ url?: Origin;
25
+ sitemap?: boolean | {
29
26
  routes: (existing: string[]) => string[] | Promise<string[]>;
30
27
  };
31
- } | {
32
- url?: Origin;
33
- sitemap?: false;
34
- });
35
- export type ConfiguredPluginConfig = PluginConfig & {
36
- runtime: Runtime;
37
28
  };
38
- export type RuntimeConfig = Omit<PluginConfig, 'runtime'> & {
29
+ export type ConfiguredPluginConfig = PluginConfig;
30
+ export type RuntimeConfig = PluginConfig & {
39
31
  precompress: NonNullable<PluginConfig['precompress']>;
40
32
  trailingSlash: NonNullable<PluginConfig['trailingSlash']>;
41
33
  trustedOrigins: NonNullable<PluginConfig['trustedOrigins']>;
@@ -112,8 +104,8 @@ export type BuildManifest = {
112
104
  prerenderRoutes: string[];
113
105
  sitemapRoutes: string[];
114
106
  precompress: boolean;
115
- trailingSlash: (typeof Solas.Config.TRAILING_SLASH_MODES)[number];
116
- url?: PluginConfig['url'];
107
+ trailingSlash: (typeof Config.TRAILING_SLASH_MODES)[number];
108
+ url?: Origin;
117
109
  };
118
110
  export declare namespace Route {
119
111
  type ParamsOf<TRoute> = TRoute extends {
@@ -132,10 +124,7 @@ export declare namespace Route {
132
124
  } : {
133
125
  params: ParamsOf<TRoute>;
134
126
  }) & ErrorPropsOf<TError>;
135
- export type Prerender = (typeof Solas.Config.PRERENDER_MODES)[number];
127
+ export type Prerender = (typeof Config.PRERENDER_MODES)[number];
136
128
  export {};
137
129
  }
138
- export type BoundaryError = Error & {
139
- digest?: string;
140
- };
141
130
  export {};