@jk2908/solas 0.3.7 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +24 -0
- package/README.md +66 -6
- package/dist/index.d.ts +2 -2
- package/dist/index.js +75 -6
- package/dist/internal/browser-router/link.d.ts +1 -1
- package/dist/internal/browser-router/link.js +1 -1
- package/dist/internal/browser-router/router.d.ts +2 -165
- package/dist/internal/browser-router/router.js +3 -99
- package/dist/internal/browser-router/shared.d.ts +169 -0
- package/dist/internal/browser-router/shared.js +71 -0
- package/dist/internal/browser-router/use-router.d.ts +1 -1
- package/dist/internal/build.js +14 -14
- package/dist/internal/codegen/environments.js +5 -4
- package/dist/internal/env/browser.js +11 -9
- package/dist/internal/env/rsc.d.ts +2 -2
- package/dist/internal/env/rsc.js +170 -86
- package/dist/internal/http-router/create-http-router.d.ts +1 -1
- package/dist/internal/http-router/create-http-router.js +4 -2
- package/dist/internal/http-router/router.d.ts +4 -14
- package/dist/internal/http-router/router.js +32 -59
- package/dist/internal/navigation/http-exception.d.ts +8 -4
- package/dist/internal/navigation/http-exception.js +46 -6
- package/dist/internal/postbuild.d.ts +1 -0
- package/dist/{cli/build.js → internal/postbuild.js} +13 -48
- package/dist/internal/prerender.d.ts +4 -19
- package/dist/internal/prerender.js +8 -98
- package/dist/internal/public-files.d.ts +18 -0
- package/dist/internal/public-files.js +63 -0
- package/dist/internal/render/tree.d.ts +0 -3
- package/dist/internal/render/tree.js +1 -6
- package/dist/internal/resolver.d.ts +31 -23
- package/dist/internal/server/actions.d.ts +2 -5
- package/dist/internal/server/actions.js +4 -35
- package/dist/internal/server/csrf.d.ts +14 -0
- package/dist/internal/server/csrf.js +98 -0
- package/dist/internal/ui/defaults/error.d.ts +2 -0
- package/dist/internal/ui/defaults/error.js +1 -1
- package/dist/navigation.d.ts +1 -1
- package/dist/router.d.ts +1 -0
- package/dist/router.js +1 -0
- package/dist/solas.d.ts +12 -1
- package/dist/solas.js +116 -1
- package/dist/types.d.ts +27 -5
- package/dist/utils/base-path.d.ts +14 -0
- package/dist/utils/base-path.js +85 -0
- package/dist/utils/export-reader.d.ts +6 -1
- package/dist/utils/export-reader.js +24 -15
- package/package.json +3 -6
- package/dist/cli/build.d.ts +0 -7
- package/dist/cli/dev.d.ts +0 -4
- package/dist/cli/dev.js +0 -13
- package/dist/cli/preview.d.ts +0 -1
- package/dist/cli/preview.js +0 -47
- package/dist/cli.d.ts +0 -2
- package/dist/cli.js +0 -28
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
import { Solas } from '../../solas.js';
|
|
2
|
+
export declare namespace BrowserRouter {
|
|
3
|
+
export type Params = Record<string, string>;
|
|
4
|
+
export type Query = Record<string, string | number | boolean>;
|
|
5
|
+
export type Path = keyof Solas.Routes & string;
|
|
6
|
+
type Replace = {
|
|
7
|
+
replace?: boolean;
|
|
8
|
+
};
|
|
9
|
+
export type GoOptions = {
|
|
10
|
+
replace?: boolean;
|
|
11
|
+
query?: Query;
|
|
12
|
+
params?: Params;
|
|
13
|
+
};
|
|
14
|
+
/**
|
|
15
|
+
* These targets are used as-is. They are not matched against the route table,
|
|
16
|
+
* so this covers normal external URLs and hash-only links
|
|
17
|
+
*/
|
|
18
|
+
export type ExternalTarget = `${string}:${string}` | `//${string}` | `#${string}`;
|
|
19
|
+
export function isHashOnlyTarget(target: string): boolean;
|
|
20
|
+
export function isExternalTarget(target: string, origin: string): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Turn a route pattern into the real path shape a caller can use. In practice,
|
|
23
|
+
* every ':param' or '*' part becomes a plain string slot
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* // '/p/:id' becomes '/p/${string}'
|
|
28
|
+
* // '/test/*' becomes '/test/${string}'
|
|
29
|
+
* // '/posts' stays '/posts'
|
|
30
|
+
* ```
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```ts
|
|
34
|
+
* type A = ResolvedPath<'/posts/:id'>
|
|
35
|
+
* // '/posts/${string}'
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```ts
|
|
40
|
+
* type B = ResolvedPath<'/docs/*'>
|
|
41
|
+
* // '/docs/${string}'
|
|
42
|
+
* ```
|
|
43
|
+
*/
|
|
44
|
+
export type ResolvedPath<TPath extends string> = TPath extends `${infer Start}:${string}/${infer Rest}` ? `${Start}${string}/${ResolvedPath<Rest>}` : TPath extends `${infer Start}:${string}` ? `${Start}${string}` : TPath extends `${infer Start}*${infer Rest}` ? `${Start}${string}${ResolvedPath<Rest>}` : TPath;
|
|
45
|
+
/**
|
|
46
|
+
* Once we have a real path, also allow the usual query-string and hash forms
|
|
47
|
+
*
|
|
48
|
+
* @example
|
|
49
|
+
* ```ts
|
|
50
|
+
* type A = TargetSuffix<'/posts/123'>
|
|
51
|
+
* // '/posts/123' | '/posts/123?${string}' | '/posts/123#${string}' | '/posts/123?${string}#${string}'
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export type TargetSuffix<TPath extends string> = TPath | `${TPath}?${string}` | `${TPath}#${string}` | `${TPath}?${string}#${string}`;
|
|
55
|
+
/**
|
|
56
|
+
* This is the final string form a caller can navigate to. It can be an external
|
|
57
|
+
* URL, or a concrete URL that matches one of the known routes
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* type A = Target
|
|
62
|
+
* // 'https://example.com'
|
|
63
|
+
* // '#intro'
|
|
64
|
+
* // '/posts/123'
|
|
65
|
+
* // '/posts/123?draft=true'
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
export type Target = ExternalTarget | TargetSuffix<ResolvedPath<Path>>;
|
|
69
|
+
/**
|
|
70
|
+
* Extra options for callers who already have a finished target string
|
|
71
|
+
*
|
|
72
|
+
* @example
|
|
73
|
+
* ```ts
|
|
74
|
+
* const a: TargetConfig = { query: { page: 2 } }
|
|
75
|
+
* // params is rejected here because the path is already complete
|
|
76
|
+
* ```
|
|
77
|
+
*/
|
|
78
|
+
type TargetConfig = {
|
|
79
|
+
params?: never;
|
|
80
|
+
query?: Query;
|
|
81
|
+
};
|
|
82
|
+
/**
|
|
83
|
+
* Extra options for callers who pass a route pattern and params separately.
|
|
84
|
+
* If the route definition says that route needs params, this type makes
|
|
85
|
+
* those params required. If the route has no params, it rejects them
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```ts
|
|
89
|
+
* // if Solas.Routes['/posts/:id'] is { params: { id: string } }
|
|
90
|
+
* type A = PatternConfig<'/posts/:id'>
|
|
91
|
+
* // { query?: Query } & { params: { id: string } }
|
|
92
|
+
* ```
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```ts
|
|
96
|
+
* // if Solas.Routes['/about'] has no params field
|
|
97
|
+
* type B = PatternConfig<'/about'>
|
|
98
|
+
* // { query?: Query } & { params?: never }
|
|
99
|
+
* ```
|
|
100
|
+
*/
|
|
101
|
+
type PatternConfig<TPath extends Path> = {
|
|
102
|
+
query?: Query;
|
|
103
|
+
} & (Solas.Routes[TPath] extends {
|
|
104
|
+
params: infer TParams extends Params;
|
|
105
|
+
} ? {
|
|
106
|
+
params: TParams;
|
|
107
|
+
} : {
|
|
108
|
+
params?: never;
|
|
109
|
+
});
|
|
110
|
+
/**
|
|
111
|
+
* Typed <Link /> props, using `href` instead of the internal `to` name
|
|
112
|
+
*
|
|
113
|
+
* `query` is always allowed
|
|
114
|
+
* `params` are only allowed when `href` is a known route pattern
|
|
115
|
+
*
|
|
116
|
+
* @example
|
|
117
|
+
* ```ts
|
|
118
|
+
* const a: LinkProps = { href: '/posts/:id', params: { id: '123' } }
|
|
119
|
+
* const b: LinkProps = { href: '/posts/123?draft=true' }
|
|
120
|
+
* ```
|
|
121
|
+
*/
|
|
122
|
+
export type LinkProps = ({
|
|
123
|
+
href: Target;
|
|
124
|
+
} & TargetConfig) | (keyof Solas.Routes extends never ? never : {
|
|
125
|
+
[TPath in Path]: {
|
|
126
|
+
href: TPath;
|
|
127
|
+
} & PatternConfig<TPath>;
|
|
128
|
+
}[Path]);
|
|
129
|
+
/**
|
|
130
|
+
* Typed input for router.go(), using the same route rules as <Link />
|
|
131
|
+
*
|
|
132
|
+
* @example
|
|
133
|
+
* ```ts
|
|
134
|
+
* go('/p/post-2')
|
|
135
|
+
* go('/?foo=bar', { replace: true })
|
|
136
|
+
* ```
|
|
137
|
+
*
|
|
138
|
+
* @example
|
|
139
|
+
* ```ts
|
|
140
|
+
* go('/p/:id', { params: { id: 'post-2' }, replace: true })
|
|
141
|
+
* ```
|
|
142
|
+
*
|
|
143
|
+
* The last overload is the fallback for plain `string` values. The
|
|
144
|
+
* `string extends TTo` check stops that fallback from taking over
|
|
145
|
+
* when TypeScript already knows the caller passed a more specific
|
|
146
|
+
* string literal
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* ```ts
|
|
150
|
+
* declare const dynamicPath: string
|
|
151
|
+
* go(dynamicPath, { replace: true })
|
|
152
|
+
* ```
|
|
153
|
+
*/
|
|
154
|
+
export type Go = {
|
|
155
|
+
<TTo extends Path>(to: TTo, opts?: PatternConfig<TTo> & Replace): Promise<string>;
|
|
156
|
+
<TTo extends Target>(to: TTo, opts?: TargetConfig & Replace): Promise<string>;
|
|
157
|
+
<TTo extends string>(to: string extends TTo ? TTo : never, opts?: GoOptions): Promise<string>;
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Convert a route pattern and params into a real path string. This is used internally
|
|
161
|
+
* to implement <Link /> and router.go
|
|
162
|
+
*/
|
|
163
|
+
export function toTarget(path: string, params?: Record<string, string>, query?: Query): string;
|
|
164
|
+
export {};
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* Apply the base path to a target string when needed
|
|
168
|
+
*/
|
|
169
|
+
export declare function withBase(target: string): string;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { BasePath } from '../../utils/base-path.js';
|
|
2
|
+
const BASE_PATH = BasePath.normalise(import.meta.env.BASE_URL);
|
|
3
|
+
export { BrowserRouter };
|
|
4
|
+
var BrowserRouter;
|
|
5
|
+
(function (BrowserRouter) {
|
|
6
|
+
function isHashOnlyTarget(target) {
|
|
7
|
+
return target.startsWith('#');
|
|
8
|
+
}
|
|
9
|
+
BrowserRouter.isHashOnlyTarget = isHashOnlyTarget;
|
|
10
|
+
function isExternalTarget(target, origin) {
|
|
11
|
+
if (isHashOnlyTarget(target))
|
|
12
|
+
return false;
|
|
13
|
+
try {
|
|
14
|
+
return new URL(target, origin).origin !== origin;
|
|
15
|
+
}
|
|
16
|
+
catch {
|
|
17
|
+
return false;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
BrowserRouter.isExternalTarget = isExternalTarget;
|
|
21
|
+
/**
|
|
22
|
+
* Convert a route pattern and params into a real path string. This is used internally
|
|
23
|
+
* to implement <Link /> and router.go
|
|
24
|
+
*/
|
|
25
|
+
function toTarget(path, params, query) {
|
|
26
|
+
const used = new Set();
|
|
27
|
+
let to = path.replaceAll(/:([A-Za-z0-9_]+)/g, (_, key) => {
|
|
28
|
+
const value = params?.[key];
|
|
29
|
+
if (value == null) {
|
|
30
|
+
throw new Error(`[Link]: missing route param: ${key}`);
|
|
31
|
+
}
|
|
32
|
+
used.add(key);
|
|
33
|
+
return encodeURIComponent(value);
|
|
34
|
+
});
|
|
35
|
+
if (to.includes('*')) {
|
|
36
|
+
const remaining = Object.entries(params ?? {}).filter(([key]) => !used.has(key));
|
|
37
|
+
if (remaining.length !== 1) {
|
|
38
|
+
throw new Error('[Link]: wildcard routes require exactly one unmatched param');
|
|
39
|
+
}
|
|
40
|
+
to = to.replace('*', remaining[0][1].split('/').map(encodeURIComponent).join('/'));
|
|
41
|
+
}
|
|
42
|
+
if (!query)
|
|
43
|
+
return withBase(to);
|
|
44
|
+
const hashIndex = to.indexOf('#');
|
|
45
|
+
const hash = hashIndex >= 0 ? to.slice(hashIndex) : '';
|
|
46
|
+
const pathWithSearch = hashIndex >= 0 ? to.slice(0, hashIndex) : to;
|
|
47
|
+
const searchIndex = pathWithSearch.indexOf('?');
|
|
48
|
+
const pathname = searchIndex >= 0 ? pathWithSearch.slice(0, searchIndex) : pathWithSearch;
|
|
49
|
+
const currentSearch = searchIndex >= 0 ? pathWithSearch.slice(searchIndex + 1) : '';
|
|
50
|
+
const search = new URLSearchParams(currentSearch);
|
|
51
|
+
for (const [key, value] of Object.entries(query)) {
|
|
52
|
+
search.set(key, String(value));
|
|
53
|
+
}
|
|
54
|
+
const value = search.toString();
|
|
55
|
+
return withBase(`${pathname}${value.length > 0 ? `?${value}` : ''}${hash}`);
|
|
56
|
+
}
|
|
57
|
+
BrowserRouter.toTarget = toTarget;
|
|
58
|
+
})(BrowserRouter || (BrowserRouter = {}));
|
|
59
|
+
/**
|
|
60
|
+
* Apply the base path to a target string when needed
|
|
61
|
+
*/
|
|
62
|
+
export function withBase(target) {
|
|
63
|
+
if (BrowserRouter.isHashOnlyTarget(target))
|
|
64
|
+
return target;
|
|
65
|
+
if (target.startsWith('//') || /^[A-Za-z][A-Za-z\d+.-]*:/.test(target))
|
|
66
|
+
return target;
|
|
67
|
+
const suffixIndex = target.search(/[?#]/);
|
|
68
|
+
const pathname = suffixIndex === -1 ? target : target.slice(0, suffixIndex);
|
|
69
|
+
const suffix = suffixIndex === -1 ? '' : target.slice(suffixIndex);
|
|
70
|
+
return `${BasePath.apply(pathname || '/', BASE_PATH)}${suffix}`;
|
|
71
|
+
}
|
package/dist/internal/build.js
CHANGED
|
@@ -324,7 +324,7 @@ var Build;
|
|
|
324
324
|
try {
|
|
325
325
|
if (!this.buildContext || !this.config)
|
|
326
326
|
continue;
|
|
327
|
-
const { shell: shellPath, layouts: layoutPaths, '401s':
|
|
327
|
+
const { shell: shellPath, layouts: layoutPaths, '401s': unauthorisedPaths, '403s': forbiddenPaths, page: pagePath, '404s': notFoundPaths, '500s': serverErrorPaths, loaders: loaderPaths, middlewares: middlewarePaths, dir, } = segment;
|
|
328
328
|
// derive the route pattern from the directory path, falling
|
|
329
329
|
// back to a synthetic +page.tsx when this is
|
|
330
330
|
// a layout-only segment
|
|
@@ -347,7 +347,7 @@ var Build;
|
|
|
347
347
|
const shellImport = Finder.getImportPath(shellPath);
|
|
348
348
|
const shellId = `${Build.EntryKind.SHELL}${Bun.hash(shellImport)}`;
|
|
349
349
|
const layoutIds = [];
|
|
350
|
-
const
|
|
350
|
+
const unauthorisedIds = [];
|
|
351
351
|
const forbiddenIds = [];
|
|
352
352
|
const notFoundIds = [];
|
|
353
353
|
const serverErrorIds = [];
|
|
@@ -375,17 +375,17 @@ var Build;
|
|
|
375
375
|
applyPrerenderMode(prerenderCache.get(layoutPath));
|
|
376
376
|
layoutIds.push(layoutId);
|
|
377
377
|
}
|
|
378
|
-
for (const
|
|
379
|
-
if (!
|
|
380
|
-
|
|
378
|
+
for (const unauthorisedPath of unauthorisedPaths) {
|
|
379
|
+
if (!unauthorisedPath) {
|
|
380
|
+
unauthorisedIds.push(null);
|
|
381
381
|
continue;
|
|
382
382
|
}
|
|
383
|
-
const
|
|
384
|
-
const
|
|
385
|
-
|
|
386
|
-
if (!processed.has(
|
|
387
|
-
imports.components.dynamic.set(
|
|
388
|
-
processed.add(
|
|
383
|
+
const unauthorisedImport = Finder.getImportPath(unauthorisedPath);
|
|
384
|
+
const unauthorisedId = `${Build.EntryKind['401']}${Bun.hash(unauthorisedImport)}`;
|
|
385
|
+
unauthorisedIds.push(unauthorisedId);
|
|
386
|
+
if (!processed.has(unauthorisedPath)) {
|
|
387
|
+
imports.components.dynamic.set(unauthorisedId, unauthorisedImport);
|
|
388
|
+
processed.add(unauthorisedPath);
|
|
389
389
|
}
|
|
390
390
|
}
|
|
391
391
|
for (const forbiddenPath of forbiddenPaths) {
|
|
@@ -475,7 +475,7 @@ var Build;
|
|
|
475
475
|
processed.add(pagePath);
|
|
476
476
|
}
|
|
477
477
|
// resolve final prerender mode after shell → layout → page overrides
|
|
478
|
-
const shouldPrerender = currentPrerenderMode !== false;
|
|
478
|
+
const shouldPrerender = currentPrerenderMode !== false && this.buildContext.command === 'build';
|
|
479
479
|
const prerenderMode = shouldPrerender
|
|
480
480
|
? currentPrerenderMode
|
|
481
481
|
: false;
|
|
@@ -506,7 +506,7 @@ var Build;
|
|
|
506
506
|
method: 'get',
|
|
507
507
|
paths: {
|
|
508
508
|
layouts: [shellPath, ...layoutPaths].map(layout => layout ? Finder.getImportPath(layout) : null),
|
|
509
|
-
'401s':
|
|
509
|
+
'401s': unauthorisedPaths.map(unauthorised => unauthorised ? Finder.getImportPath(unauthorised) : null),
|
|
510
510
|
'403s': forbiddenPaths.map(forbidden => forbidden ? Finder.getImportPath(forbidden) : null),
|
|
511
511
|
'404s': notFoundPaths.map(notFound => notFound ? Finder.getImportPath(notFound) : null),
|
|
512
512
|
'500s': serverErrorPaths.map(serverError => serverError ? Finder.getImportPath(serverError) : null),
|
|
@@ -533,7 +533,7 @@ var Build;
|
|
|
533
533
|
shellId,
|
|
534
534
|
layoutIds,
|
|
535
535
|
pageId: pagePath ? entryId : undefined,
|
|
536
|
-
'401Ids':
|
|
536
|
+
'401Ids': unauthorisedIds,
|
|
537
537
|
'403Ids': forbiddenIds,
|
|
538
538
|
'404Ids': notFoundIds,
|
|
539
539
|
'500Ids': serverErrorIds,
|
|
@@ -8,18 +8,19 @@ export function writeRSCEntry() {
|
|
|
8
8
|
${AUTOGEN_MSG}
|
|
9
9
|
|
|
10
10
|
import { createHandler } from '${Solas.Config.PKG_NAME}/env/rsc'
|
|
11
|
-
import { Prerender } from '${Solas.Config.PKG_NAME}/prerender'
|
|
12
11
|
import { Solas } from '${Solas.Config.PKG_NAME}'
|
|
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
|
-
const
|
|
17
|
+
const runtimeManifest = await Solas.Runtime.loadManifest(Solas.Config.OUT_DIR)
|
|
19
18
|
|
|
20
|
-
export default createHandler(config, manifest, importMap,
|
|
19
|
+
export default createHandler(config, manifest, importMap, runtimeManifest)
|
|
21
20
|
|
|
22
|
-
import.meta.hot
|
|
21
|
+
if (import.meta.hot) {
|
|
22
|
+
import.meta.hot.accept()
|
|
23
|
+
}
|
|
23
24
|
`;
|
|
24
25
|
}
|
|
25
26
|
/**
|
|
@@ -50,13 +50,15 @@ export async function browser() {
|
|
|
50
50
|
hydrateRoot(document, _jsx(StrictMode, { children: _jsx(A, {}) }), {
|
|
51
51
|
formState: payload.formState,
|
|
52
52
|
});
|
|
53
|
-
import.meta.hot
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
53
|
+
if (import.meta.hot) {
|
|
54
|
+
import.meta.hot.on?.('rsc:update', async () => {
|
|
55
|
+
try {
|
|
56
|
+
const p = await createFromFetch(fetch(window.location.href, { headers: { Accept: 'text/x-component' } }));
|
|
57
|
+
payloadSetter.current(p);
|
|
58
|
+
}
|
|
59
|
+
catch (err) {
|
|
60
|
+
console.error('[hmr] failed to refresh rsc payload', err);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
62
64
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
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
4
|
import { Metadata } from '../metadata.js';
|
|
4
|
-
import { Prerender } from '../prerender.js';
|
|
5
5
|
export type RscPayload = {
|
|
6
6
|
returnValue?: {
|
|
7
7
|
ok: boolean;
|
|
@@ -20,6 +20,6 @@ export type RscPayload = {
|
|
|
20
20
|
* route manifest, and import map to build the router once, then returns an object
|
|
21
21
|
* with a fetch method that handles requests
|
|
22
22
|
*/
|
|
23
|
-
export declare function createHandler(config: RuntimeConfig, manifest: Manifest, importMap: ImportMap,
|
|
23
|
+
export declare function createHandler(config: RuntimeConfig, manifest: Manifest, importMap: ImportMap, runtimeManifest?: Solas.Runtime.Manifest | null): {
|
|
24
24
|
fetch(req: Request): Promise<Response>;
|
|
25
25
|
};
|