@jk2908/solas 0.3.1 → 0.3.2
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 +5 -0
- package/dist/cli/build.d.ts +7 -0
- package/dist/cli/build.js +183 -0
- package/dist/cli/dev.d.ts +4 -0
- package/dist/cli/dev.js +13 -0
- package/dist/cli/preview.d.ts +1 -0
- package/dist/cli/preview.js +47 -0
- package/dist/cli.js +4 -238
- package/dist/index.js +2 -0
- package/dist/internal/browser-router/link.d.ts +17 -0
- package/dist/internal/{navigation → browser-router}/link.js +22 -16
- package/dist/internal/browser-router/router.d.ts +184 -0
- package/dist/internal/{router/router-provider.js → browser-router/router.js} +81 -12
- package/dist/internal/{router → browser-router}/use-router.d.ts +1 -1
- package/dist/internal/browser-router/use-router.js +5 -0
- package/dist/internal/browser-router/use-search-params.d.ts +1 -0
- package/dist/internal/browser-router/use-search-params.js +15 -0
- package/dist/internal/build.js +2 -2
- package/dist/internal/codegen/types.d.ts +5 -0
- package/dist/internal/codegen/types.js +48 -0
- package/dist/internal/env/browser.js +6 -6
- package/dist/internal/env/flight.d.ts +29 -0
- package/dist/internal/env/flight.js +187 -0
- package/dist/internal/env/request-context.d.ts +1 -1
- package/dist/internal/env/rsc.d.ts +1 -1
- package/dist/internal/env/rsc.js +23 -28
- package/dist/internal/env/ssr.d.ts +2 -2
- package/dist/internal/env/ssr.js +27 -13
- package/dist/internal/env/utils.js +13 -1
- package/dist/internal/http-router/create-http-router.d.ts +6 -0
- package/dist/internal/{router/create-router.js → http-router/create-http-router.js} +5 -5
- package/dist/internal/{router → http-router}/router.d.ts +9 -9
- package/dist/internal/{router → http-router}/router.js +20 -19
- package/dist/internal/{router → http-router}/utils.d.ts +11 -3
- package/dist/internal/{router → http-router}/utils.js +9 -1
- package/dist/internal/metadata.js +10 -10
- package/dist/internal/prerender.d.ts +4 -9
- package/dist/internal/prerender.js +6 -23
- package/dist/internal/render/head.js +1 -1
- package/dist/internal/render/tree.d.ts +1 -1
- package/dist/internal/render/tree.js +17 -13
- package/dist/internal/{router/resolver.d.ts → resolver.d.ts} +41 -41
- package/dist/internal/{router/resolver.js → resolver.js} +7 -7
- package/dist/internal/server/actions.js +1 -1
- package/dist/internal/server/cookies.d.ts +3 -2
- package/dist/internal/server/cookies.js +4 -3
- package/dist/internal/server/dynamic.d.ts +1 -3
- package/dist/internal/server/dynamic.js +3 -11
- package/dist/internal/server/headers.d.ts +2 -2
- package/dist/internal/server/headers.js +3 -3
- package/dist/internal/server/url.d.ts +2 -2
- package/dist/internal/server/url.js +3 -3
- package/dist/navigation.d.ts +0 -2
- package/dist/navigation.js +0 -2
- package/dist/router.d.ts +3 -4
- package/dist/router.js +3 -4
- package/dist/solas.d.ts +3 -1
- package/dist/solas.js +1 -1
- package/dist/types.d.ts +15 -7
- package/dist/utils/logger.js +1 -1
- package/package.json +2 -7
- package/dist/internal/navigation/link.d.ts +0 -13
- package/dist/internal/navigation/use-search-params.d.ts +0 -11
- package/dist/internal/navigation/use-search-params.js +0 -34
- package/dist/internal/router/create-router.d.ts +0 -6
- package/dist/internal/router/router-context.d.ts +0 -15
- package/dist/internal/router/router-context.js +0 -8
- package/dist/internal/router/router-provider.d.ts +0 -10
- package/dist/internal/router/use-router.js +0 -5
- /package/dist/internal/{router/prefetcher.d.ts → prefetcher.d.ts} +0 -0
- /package/dist/internal/{router/prefetcher.js → prefetcher.js} +0 -0
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import { compile } from 'path-to-regexp';
|
|
3
|
-
import { Solas } from '../solas.js';
|
|
4
3
|
import { Logger } from '../utils/logger.js';
|
|
5
4
|
import { Time } from '../utils/time.js';
|
|
6
|
-
import {
|
|
5
|
+
import { Solas } from '../solas.js';
|
|
6
|
+
import { toPathPattern } from './http-router/utils.js';
|
|
7
7
|
const logger = new Logger();
|
|
8
8
|
export { Prerender };
|
|
9
9
|
var Prerender;
|
|
@@ -63,12 +63,9 @@ var Prerender;
|
|
|
63
63
|
}
|
|
64
64
|
Artifact.getFilePath = getFilePath;
|
|
65
65
|
/**
|
|
66
|
-
*
|
|
66
|
+
* File name used for saved full-prerender html inside each route artifact directory
|
|
67
67
|
*/
|
|
68
|
-
|
|
69
|
-
return `html.${Bun.hash(html).toString(16)}.html`;
|
|
70
|
-
}
|
|
71
|
-
Artifact.getFullHtmlFileName = getFullHtmlFileName;
|
|
68
|
+
Artifact.FULL_PRERENDER_FILENAME = 'prerendered.html';
|
|
72
69
|
/**
|
|
73
70
|
* Load the prerender artifact manifest for faster runtime route mode checks
|
|
74
71
|
*/
|
|
@@ -91,12 +88,7 @@ var Prerender;
|
|
|
91
88
|
manifestCache.set(outDir, null);
|
|
92
89
|
return null;
|
|
93
90
|
}
|
|
94
|
-
const generatedAt = value.generatedAt;
|
|
95
91
|
const routes = value.routes;
|
|
96
|
-
if (typeof generatedAt !== 'number') {
|
|
97
|
-
manifestCache.set(outDir, null);
|
|
98
|
-
return null;
|
|
99
|
-
}
|
|
100
92
|
if (!routes || typeof routes !== 'object') {
|
|
101
93
|
manifestCache.set(outDir, null);
|
|
102
94
|
return null;
|
|
@@ -107,16 +99,12 @@ var Prerender;
|
|
|
107
99
|
manifestCache.set(outDir, null);
|
|
108
100
|
return null;
|
|
109
101
|
}
|
|
110
|
-
const { mode,
|
|
102
|
+
const { mode, files } = entry;
|
|
111
103
|
// only allow known modes
|
|
112
104
|
if (mode !== 'full' && mode !== 'ppr') {
|
|
113
105
|
manifestCache.set(outDir, null);
|
|
114
106
|
return null;
|
|
115
107
|
}
|
|
116
|
-
if (typeof createdAt !== 'number') {
|
|
117
|
-
manifestCache.set(outDir, null);
|
|
118
|
-
return null;
|
|
119
|
-
}
|
|
120
108
|
if (files !== undefined) {
|
|
121
109
|
if (!Array.isArray(files)) {
|
|
122
110
|
manifestCache.set(outDir, null);
|
|
@@ -133,13 +121,8 @@ var Prerender;
|
|
|
133
121
|
}
|
|
134
122
|
}
|
|
135
123
|
}
|
|
136
|
-
if (entry.fullPrerenderFilename !== undefined &&
|
|
137
|
-
!isArtifactFileName(entry.fullPrerenderFilename)) {
|
|
138
|
-
manifestCache.set(outDir, null);
|
|
139
|
-
return null;
|
|
140
|
-
}
|
|
141
124
|
}
|
|
142
|
-
const manifest =
|
|
125
|
+
const manifest = routes;
|
|
143
126
|
// cache validated manifest to avoid reparsing on every request
|
|
144
127
|
manifestCache.set(outDir, manifest);
|
|
145
128
|
return manifest;
|
|
@@ -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
|
-
import { Solas } from '../../solas.js';
|
|
4
3
|
import { Logger } from '../../utils/logger.js';
|
|
4
|
+
import { Solas } from '../../solas.js';
|
|
5
5
|
const logger = new Logger();
|
|
6
6
|
const cache = new WeakMap();
|
|
7
7
|
/**
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Suspense } from 'react';
|
|
3
|
-
import { HttpException, isHttpException } from '../navigation/http-exception.js';
|
|
4
3
|
import { HttpExceptionBoundary } from '../navigation/http-exception-boundary.js';
|
|
4
|
+
import { HttpException, isHttpException } from '../navigation/http-exception.js';
|
|
5
5
|
import DefaultErr from '../ui/defaults/error.js';
|
|
6
|
+
const UNAUTHORISED_ERROR = new HttpException(401, 'Unauthorised');
|
|
7
|
+
const FORBIDDEN_ERROR = new HttpException(403, 'Forbidden');
|
|
8
|
+
const NOT_FOUND_ERROR = new HttpException(404, 'Not found');
|
|
9
|
+
const SERVER_ERROR = new HttpException(500, 'Internal Server Error');
|
|
6
10
|
/**
|
|
7
11
|
* Render the resolved route tree for a matched page
|
|
8
12
|
*
|
|
@@ -42,7 +46,7 @@ import DefaultErr from '../ui/defaults/error.js';
|
|
|
42
46
|
* ```
|
|
43
47
|
*/
|
|
44
48
|
export function Tree({ depth, params, error, ui, }) {
|
|
45
|
-
const { layouts, Page, '401s':
|
|
49
|
+
const { layouts, Page, '401s': unauthorised, '403s': forbidden, '404s': notFounds, '500s': serverErrors, loaders, } = ui;
|
|
46
50
|
const Shell = layouts[0];
|
|
47
51
|
if (!Shell)
|
|
48
52
|
throw new Error('Shell layout is required in the route tree');
|
|
@@ -50,7 +54,7 @@ export function Tree({ depth, params, error, ui, }) {
|
|
|
50
54
|
let inner = null;
|
|
51
55
|
// map http status codes to exception components
|
|
52
56
|
const httpExceptionMap = {
|
|
53
|
-
401:
|
|
57
|
+
401: unauthorised,
|
|
54
58
|
403: forbidden,
|
|
55
59
|
404: notFounds,
|
|
56
60
|
500: serverErrors,
|
|
@@ -69,7 +73,7 @@ export function Tree({ depth, params, error, ui, }) {
|
|
|
69
73
|
for (let idx = layouts.length - 1; idx >= 1; idx--) {
|
|
70
74
|
const Layout = layouts[idx];
|
|
71
75
|
const Loading = loaders[idx];
|
|
72
|
-
const
|
|
76
|
+
const Unauthorised = unauthorised[idx];
|
|
73
77
|
const Forbidden = forbidden[idx];
|
|
74
78
|
const NotFound = notFounds[idx];
|
|
75
79
|
const ServerError = serverErrors[idx];
|
|
@@ -82,10 +86,10 @@ export function Tree({ depth, params, error, ui, }) {
|
|
|
82
86
|
inner = _jsx(Suspense, { fallback: _jsx(Loading, {}), children: inner });
|
|
83
87
|
}
|
|
84
88
|
const errorBoundaries = {
|
|
85
|
-
401:
|
|
86
|
-
403: Forbidden ? _jsx(Forbidden, { error:
|
|
87
|
-
404: NotFound ? _jsx(NotFound, { error:
|
|
88
|
-
500: ServerError ?
|
|
89
|
+
401: Unauthorised ? _jsx(Unauthorised, { error: UNAUTHORISED_ERROR }) : null,
|
|
90
|
+
403: Forbidden ? _jsx(Forbidden, { error: FORBIDDEN_ERROR }) : null,
|
|
91
|
+
404: NotFound ? _jsx(NotFound, { error: NOT_FOUND_ERROR }) : null,
|
|
92
|
+
500: ServerError ? _jsx(ServerError, { error: SERVER_ERROR }) : null,
|
|
89
93
|
};
|
|
90
94
|
// wrap in error boundaries (if supplied for this segment's http errors)
|
|
91
95
|
if (Object.values(errorBoundaries).some(c => c !== null)) {
|
|
@@ -95,14 +99,14 @@ export function Tree({ depth, params, error, ui, }) {
|
|
|
95
99
|
// now wrap with shell structure: shell renders immediately,
|
|
96
100
|
// inner streams inside Suspense
|
|
97
101
|
const ShellLoading = loaders[0];
|
|
98
|
-
const
|
|
102
|
+
const Shellunauthorised = unauthorised[0];
|
|
99
103
|
const ShellForbidden = forbidden[0];
|
|
100
104
|
const ShellNotFound = notFounds[0];
|
|
101
105
|
const ShellServerError = serverErrors[0];
|
|
102
106
|
return (_jsx(HttpExceptionBoundary, { components: {
|
|
103
|
-
401:
|
|
104
|
-
403: ShellForbidden ? _jsx(ShellForbidden, {}) : null,
|
|
105
|
-
404: ShellNotFound ? _jsx(ShellNotFound, {}) : null,
|
|
106
|
-
500: ShellServerError ? _jsx(ShellServerError, {}) : null,
|
|
107
|
+
401: Shellunauthorised ? _jsx(Shellunauthorised, { error: UNAUTHORISED_ERROR }) : null,
|
|
108
|
+
403: ShellForbidden ? _jsx(ShellForbidden, { error: FORBIDDEN_ERROR }) : null,
|
|
109
|
+
404: ShellNotFound ? _jsx(ShellNotFound, { error: NOT_FOUND_ERROR }) : null,
|
|
110
|
+
500: ShellServerError ? _jsx(ShellServerError, { error: SERVER_ERROR }) : null,
|
|
107
111
|
}, children: _jsx(Suspense, { fallback: ShellLoading ? _jsx(ShellLoading, {}) : null, children: _jsx(Shell, { params: params, children: inner }) }) }));
|
|
108
112
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { ImportMap, Manifest, ManifestEntry, Primitive, View } from '
|
|
2
|
-
import
|
|
3
|
-
import { Metadata } from '
|
|
4
|
-
import { HttpException } from '
|
|
1
|
+
import type { ImportMap, Manifest, ManifestEntry, Primitive, View } from '../types.js';
|
|
2
|
+
import { HttpRouter } from './http-router/router.js';
|
|
3
|
+
import { Metadata } from './metadata.js';
|
|
4
|
+
import { HttpException } from './navigation/http-exception.js';
|
|
5
5
|
export declare namespace Resolver {
|
|
6
6
|
type ReconciledMatch = ReturnType<Resolver['reconcile']>;
|
|
7
7
|
type CachedEnhancedMatch = Omit<EnhancedMatch, 'params' | 'error'>;
|
|
@@ -9,11 +9,11 @@ export declare namespace Resolver {
|
|
|
9
9
|
ui: {
|
|
10
10
|
layouts: (View<{
|
|
11
11
|
children?: React.ReactNode;
|
|
12
|
-
params?:
|
|
12
|
+
params?: HttpRouter.Params;
|
|
13
13
|
}> | null)[];
|
|
14
14
|
Page: View<{
|
|
15
15
|
children?: React.ReactNode;
|
|
16
|
-
params?:
|
|
16
|
+
params?: HttpRouter.Params;
|
|
17
17
|
}> | null;
|
|
18
18
|
'401s': (View<{
|
|
19
19
|
children?: React.ReactNode;
|
|
@@ -37,13 +37,13 @@ export declare namespace Resolver {
|
|
|
37
37
|
};
|
|
38
38
|
error?: HttpException | Error;
|
|
39
39
|
endpoint?: (req?: Request & {
|
|
40
|
-
params?:
|
|
40
|
+
params?: HttpRouter.Params;
|
|
41
41
|
}) => unknown;
|
|
42
|
-
metadata?: (input: Metadata.Input<
|
|
42
|
+
metadata?: (input: Metadata.Input<HttpRouter.Params>) => Metadata.Task[];
|
|
43
43
|
};
|
|
44
44
|
}
|
|
45
45
|
/**
|
|
46
|
-
* Resolve
|
|
46
|
+
* Resolve HttpRouter matches against the application manifest and import map
|
|
47
47
|
*/
|
|
48
48
|
export declare class Resolver {
|
|
49
49
|
#private;
|
|
@@ -55,15 +55,17 @@ export declare class Resolver {
|
|
|
55
55
|
/**
|
|
56
56
|
* Narrow down a route entry to a page entry if it exists
|
|
57
57
|
*/
|
|
58
|
-
static narrow(entry?: ManifestEntry | ManifestEntry[]): import("
|
|
58
|
+
static narrow(entry?: ManifestEntry | ManifestEntry[]): import("../types.js").Segment | null;
|
|
59
59
|
/**
|
|
60
60
|
* Get the status code for a matched route that may or may not have errored
|
|
61
61
|
*/
|
|
62
62
|
static getMatchStatusCode(match: Resolver.ReconciledMatch | Resolver.EnhancedMatch | null): 200 | HttpException.StatusCode;
|
|
63
63
|
/**
|
|
64
|
-
* Reconcile a
|
|
64
|
+
* Reconcile a HttpRouter match against a manifest entry
|
|
65
65
|
*/
|
|
66
|
-
reconcile(path: string, match:
|
|
66
|
+
reconcile(path: string, match: HttpRouter.Match | null, error?: Error): {
|
|
67
|
+
params: HttpRouter.Params;
|
|
68
|
+
error: Error | undefined;
|
|
67
69
|
__id: string;
|
|
68
70
|
__path: string;
|
|
69
71
|
__params: string[];
|
|
@@ -83,9 +85,9 @@ export declare class Resolver {
|
|
|
83
85
|
prerender: "full" | "ppr" | false;
|
|
84
86
|
dynamic: boolean;
|
|
85
87
|
wildcard: boolean;
|
|
86
|
-
params: Router.Params;
|
|
87
|
-
error: Error | undefined;
|
|
88
88
|
} | {
|
|
89
|
+
params: {};
|
|
90
|
+
error: HttpException;
|
|
89
91
|
__id: string;
|
|
90
92
|
__path: string;
|
|
91
93
|
__params: string[];
|
|
@@ -105,40 +107,19 @@ export declare class Resolver {
|
|
|
105
107
|
prerender: "full" | "ppr" | false;
|
|
106
108
|
dynamic: boolean;
|
|
107
109
|
wildcard: boolean;
|
|
108
|
-
params: {};
|
|
109
|
-
error: HttpException;
|
|
110
110
|
} | null;
|
|
111
111
|
/**
|
|
112
112
|
* Enhance a matched route with its associated components
|
|
113
113
|
*/
|
|
114
114
|
enhance(match: Resolver.ReconciledMatch | null): {
|
|
115
|
-
__id: string;
|
|
116
|
-
__path: string;
|
|
117
|
-
__params: string[];
|
|
118
|
-
__kind: "$P";
|
|
119
|
-
__depth: number;
|
|
120
|
-
method: "get";
|
|
121
|
-
paths: {
|
|
122
|
-
layouts: (string | null)[];
|
|
123
|
-
'401s': (string | null)[];
|
|
124
|
-
'403s': (string | null)[];
|
|
125
|
-
'404s': (string | null)[];
|
|
126
|
-
'500s': (string | null)[];
|
|
127
|
-
loaders: (string | null)[];
|
|
128
|
-
middlewares: (string | null)[];
|
|
129
|
-
page?: string | null | undefined;
|
|
130
|
-
};
|
|
131
|
-
prerender: "full" | "ppr" | false;
|
|
132
|
-
dynamic: boolean;
|
|
133
|
-
wildcard: boolean;
|
|
134
115
|
ui: {
|
|
135
116
|
layouts: (View<{
|
|
136
117
|
children?: import("react").ReactNode;
|
|
137
|
-
params?:
|
|
118
|
+
params?: HttpRouter.Params | undefined;
|
|
138
119
|
}> | null)[];
|
|
139
120
|
Page: View<{
|
|
140
121
|
children?: import("react").ReactNode;
|
|
141
|
-
params?:
|
|
122
|
+
params?: HttpRouter.Params | undefined;
|
|
142
123
|
}> | null;
|
|
143
124
|
'401s': (View<{
|
|
144
125
|
children?: import("react").ReactNode;
|
|
@@ -161,14 +142,33 @@ export declare class Resolver {
|
|
|
161
142
|
}> | null)[];
|
|
162
143
|
};
|
|
163
144
|
endpoint?: ((req?: (Request & {
|
|
164
|
-
params?:
|
|
145
|
+
params?: HttpRouter.Params | undefined;
|
|
165
146
|
}) | undefined) => unknown) | undefined;
|
|
166
|
-
metadata?: ((input: Metadata.Input<
|
|
167
|
-
params:
|
|
147
|
+
metadata?: ((input: Metadata.Input<HttpRouter.Params, Error>) => Metadata.Task[]) | undefined;
|
|
148
|
+
params: HttpRouter.Params | {};
|
|
168
149
|
error: Error | HttpException | undefined;
|
|
150
|
+
__id: string;
|
|
151
|
+
__path: string;
|
|
152
|
+
__params: string[];
|
|
153
|
+
__kind: "$P";
|
|
154
|
+
__depth: number;
|
|
155
|
+
method: "get";
|
|
156
|
+
paths: {
|
|
157
|
+
layouts: (string | null)[];
|
|
158
|
+
'401s': (string | null)[];
|
|
159
|
+
'403s': (string | null)[];
|
|
160
|
+
'404s': (string | null)[];
|
|
161
|
+
'500s': (string | null)[];
|
|
162
|
+
loaders: (string | null)[];
|
|
163
|
+
middlewares: (string | null)[];
|
|
164
|
+
page?: string | null | undefined;
|
|
165
|
+
};
|
|
166
|
+
prerender: "full" | "ppr" | false;
|
|
167
|
+
dynamic: boolean;
|
|
168
|
+
wildcard: boolean;
|
|
169
169
|
} | null;
|
|
170
170
|
/**
|
|
171
171
|
* Find the closest ancestor entry for a given path and property
|
|
172
172
|
*/
|
|
173
|
-
closest(path: string, property: string, value?: Omit<Primitive, 'undefined'>): import("
|
|
173
|
+
closest(path: string, property: string, value?: Omit<Primitive, 'undefined'>): import("../types.js").Segment | null;
|
|
174
174
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { lazy } from 'react';
|
|
2
|
-
import { Logger } from '
|
|
3
|
-
import { Build } from '
|
|
4
|
-
import { Metadata } from '
|
|
5
|
-
import { HttpException, isHttpException } from '
|
|
2
|
+
import { Logger } from '../utils/logger.js';
|
|
3
|
+
import { Build } from './build.js';
|
|
4
|
+
import { Metadata } from './metadata.js';
|
|
5
|
+
import { HttpException, isHttpException } from './navigation/http-exception.js';
|
|
6
6
|
const logger = new Logger();
|
|
7
7
|
const IS_DEV = import.meta.env.DEV;
|
|
8
8
|
/**
|
|
9
|
-
* Resolve
|
|
9
|
+
* Resolve HttpRouter matches against the application manifest and import map
|
|
10
10
|
*/
|
|
11
11
|
export class Resolver {
|
|
12
12
|
/**
|
|
@@ -122,13 +122,13 @@ export class Resolver {
|
|
|
122
122
|
return entry.Component;
|
|
123
123
|
}
|
|
124
124
|
/**
|
|
125
|
-
* Reconcile a
|
|
125
|
+
* Reconcile a HttpRouter match against a manifest entry
|
|
126
126
|
*/
|
|
127
127
|
reconcile(path, match, error) {
|
|
128
128
|
if (match) {
|
|
129
129
|
const entry = Resolver.narrow(Resolver.#getEntryByPath(this.#manifest, match.route.path));
|
|
130
130
|
if (entry) {
|
|
131
|
-
// normal case, the
|
|
131
|
+
// normal case, the HttpRouter matched a page route so just attach request state
|
|
132
132
|
return {
|
|
133
133
|
...entry,
|
|
134
134
|
params: match.params,
|
|
@@ -68,7 +68,7 @@ export async function processActionRequest(req) {
|
|
|
68
68
|
// we might have already parsed FormData in the router for multipart action
|
|
69
69
|
// detection should be attached to the SolasRequest, so we can reuse that
|
|
70
70
|
// to avoid parsing twice
|
|
71
|
-
const parsedFormData = req[Solas.Config.
|
|
71
|
+
const parsedFormData = req[Solas.Config.REQUEST_META_KEY]?.parsedFormData;
|
|
72
72
|
const formData = parsedFormData ?? (await req.formData());
|
|
73
73
|
const decodedAction = await decodeAction(formData);
|
|
74
74
|
const result = await decodedAction();
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { Cookies } from '../../utils/cookies.js';
|
|
2
2
|
/**
|
|
3
3
|
* Get the request cookies as a Cookies instance
|
|
4
|
-
* @returns a read-only Cookies instance containing the
|
|
4
|
+
* @returns a Promise resolving to a read-only Cookies instance containing the
|
|
5
|
+
* request cookies
|
|
5
6
|
*/
|
|
6
|
-
export declare function cookies(): Readonly<ReturnType<typeof Cookies.parse
|
|
7
|
+
export declare function cookies(): Promise<Readonly<ReturnType<typeof Cookies.parse>>>;
|
|
@@ -3,10 +3,11 @@ import { RequestContext } from '../env/request-context.js';
|
|
|
3
3
|
import { dynamic } from './dynamic.js';
|
|
4
4
|
/**
|
|
5
5
|
* Get the request cookies as a Cookies instance
|
|
6
|
-
* @returns a read-only Cookies instance containing the
|
|
6
|
+
* @returns a Promise resolving to a read-only Cookies instance containing the
|
|
7
|
+
* request cookies
|
|
7
8
|
*/
|
|
8
|
-
export function cookies() {
|
|
9
|
-
dynamic();
|
|
9
|
+
export async function cookies() {
|
|
10
|
+
await dynamic();
|
|
10
11
|
const { req, cache } = RequestContext.use();
|
|
11
12
|
// use request cache if possible to avoid reparsing
|
|
12
13
|
if (cache.cookies)
|
|
@@ -3,7 +3,5 @@
|
|
|
3
3
|
* @description in prerender mode this suspends forever so the nearest Suspense
|
|
4
4
|
* boundary renders its fallback into the static shell. In request mode this
|
|
5
5
|
* resolves immediately
|
|
6
|
-
* @returns void during normal requests or prerender not in ppr mode
|
|
7
|
-
* @throws if called in prerender mode (the desired effect)
|
|
8
6
|
*/
|
|
9
|
-
export declare function dynamic(): void
|
|
7
|
+
export declare function dynamic(): Promise<void>;
|
|
@@ -1,22 +1,14 @@
|
|
|
1
|
-
import { Logger } from '../../utils/logger.js';
|
|
2
1
|
import { RequestContext } from '../env/request-context.js';
|
|
3
|
-
const logger = new Logger();
|
|
4
2
|
const NEVER = new Promise(() => { });
|
|
5
3
|
/**
|
|
6
4
|
* Declaratively mark render below this call as request-time only
|
|
7
5
|
* @description in prerender mode this suspends forever so the nearest Suspense
|
|
8
6
|
* boundary renders its fallback into the static shell. In request mode this
|
|
9
7
|
* resolves immediately
|
|
10
|
-
* @returns void during normal requests or prerender not in ppr mode
|
|
11
|
-
* @throws if called in prerender mode (the desired effect)
|
|
12
8
|
*/
|
|
13
|
-
export function dynamic() {
|
|
9
|
+
export async function dynamic() {
|
|
14
10
|
const { prerender } = RequestContext.use();
|
|
15
|
-
if (
|
|
11
|
+
if (prerender !== 'ppr')
|
|
16
12
|
return;
|
|
17
|
-
|
|
18
|
-
logger.warn('[dynamic]', "dynamic() was called but prerender mode is not 'ppr'. This means the component will be rendered at build time, which may not be what you intended");
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
21
|
-
throw NEVER;
|
|
13
|
+
await NEVER;
|
|
22
14
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Get the request headers as a read-only map
|
|
3
|
-
* @returns a read-only map of request headers
|
|
3
|
+
* @returns a Promise resolving to a read-only map of request headers
|
|
4
4
|
*/
|
|
5
|
-
export declare function headers(): ReadonlyMap<string, string
|
|
5
|
+
export declare function headers(): Promise<ReadonlyMap<string, string>>;
|
|
@@ -2,10 +2,10 @@ import { RequestContext } from '../env/request-context.js';
|
|
|
2
2
|
import { dynamic } from './dynamic.js';
|
|
3
3
|
/**
|
|
4
4
|
* Get the request headers as a read-only map
|
|
5
|
-
* @returns a read-only map of request headers
|
|
5
|
+
* @returns a Promise resolving to a read-only map of request headers
|
|
6
6
|
*/
|
|
7
|
-
export function headers() {
|
|
8
|
-
dynamic();
|
|
7
|
+
export async function headers() {
|
|
8
|
+
await dynamic();
|
|
9
9
|
const { req, cache } = RequestContext.use();
|
|
10
10
|
// use request cache if possible to avoid reconstructing the map
|
|
11
11
|
if (cache.headers)
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Get the request url as a URL instance
|
|
3
|
-
* @returns a URL instance containing the request url
|
|
3
|
+
* @returns a Promise resolving to a URL instance containing the request url
|
|
4
4
|
*/
|
|
5
|
-
export declare function url(): URL
|
|
5
|
+
export declare function url(): Promise<URL>;
|
|
@@ -4,10 +4,10 @@ import { dynamic } from './dynamic.js';
|
|
|
4
4
|
const logger = new Logger();
|
|
5
5
|
/**
|
|
6
6
|
* Get the request url as a URL instance
|
|
7
|
-
* @returns a URL instance containing the request url
|
|
7
|
+
* @returns a Promise resolving to a URL instance containing the request url
|
|
8
8
|
*/
|
|
9
|
-
export function url() {
|
|
10
|
-
dynamic();
|
|
9
|
+
export async function url() {
|
|
10
|
+
await dynamic();
|
|
11
11
|
const { req, cache } = RequestContext.use();
|
|
12
12
|
// always return a clone so consumers can mutate (e.g. searchParams.set)
|
|
13
13
|
// without corrupting the cached instance shared across the request
|
package/dist/navigation.d.ts
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
export { HttpExceptionBoundary } from './internal/navigation/http-exception-boundary.js';
|
|
2
2
|
export { HttpException, abort, isHttpException, } from './internal/navigation/http-exception.js';
|
|
3
|
-
export { Link } from './internal/navigation/link.js';
|
|
4
3
|
export { RedirectBoundary } from './internal/navigation/redirect-boundary.js';
|
|
5
4
|
export { Redirect, isRedirect, redirect } from './internal/navigation/redirect.js';
|
|
6
|
-
export { useSearchParams } from './internal/navigation/use-search-params.js';
|
package/dist/navigation.js
CHANGED
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
export { HttpExceptionBoundary } from './internal/navigation/http-exception-boundary.js';
|
|
2
2
|
export { HttpException, abort, isHttpException, } from './internal/navigation/http-exception.js';
|
|
3
|
-
export { Link } from './internal/navigation/link.js';
|
|
4
3
|
export { RedirectBoundary } from './internal/navigation/redirect-boundary.js';
|
|
5
4
|
export { Redirect, isRedirect, redirect } from './internal/navigation/redirect.js';
|
|
6
|
-
export { useSearchParams } from './internal/navigation/use-search-params.js';
|
package/dist/router.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export { useRouter } from './internal/router/use-router.js';
|
|
1
|
+
export { Link } from './internal/browser-router/link.js';
|
|
2
|
+
export { useRouter } from './internal/browser-router/use-router.js';
|
|
3
|
+
export { useSearchParams } from './internal/browser-router/use-search-params.js';
|
package/dist/router.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
export {
|
|
2
|
-
export {
|
|
3
|
-
export {
|
|
4
|
-
export { useRouter } from './internal/router/use-router.js';
|
|
1
|
+
export { Link } from './internal/browser-router/link.js';
|
|
2
|
+
export { useRouter } from './internal/browser-router/use-router.js';
|
|
3
|
+
export { useSearchParams } from './internal/browser-router/use-search-params.js';
|
package/dist/solas.d.ts
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import type { PluginConfig } from './types.js';
|
|
2
2
|
export declare namespace Solas {
|
|
3
|
+
interface Routes {
|
|
4
|
+
}
|
|
3
5
|
namespace Config {
|
|
4
6
|
const NAME = "Solas";
|
|
5
7
|
const SLUG: string;
|
|
@@ -12,7 +14,7 @@ export declare namespace Solas {
|
|
|
12
14
|
const ENTRY_BROWSER = "entry.browser.tsx";
|
|
13
15
|
const ASSETS_DIR = "assets";
|
|
14
16
|
const $: unique symbol;
|
|
15
|
-
const
|
|
17
|
+
const REQUEST_META_KEY: string;
|
|
16
18
|
const LOG_LEVELS: readonly ["debug", "info", "warn", "error", "fatal"];
|
|
17
19
|
const PRERENDER_MODES: readonly ["full", "ppr", false];
|
|
18
20
|
const TRAILING_SLASH_MODES: readonly ["always", "never", "ignore"];
|
package/dist/solas.js
CHANGED
|
@@ -14,7 +14,7 @@ var Solas;
|
|
|
14
14
|
Config.ENTRY_BROWSER = 'entry.browser.tsx';
|
|
15
15
|
Config.ASSETS_DIR = 'assets';
|
|
16
16
|
Config.$ = Symbol(Config.SLUG);
|
|
17
|
-
Config.
|
|
17
|
+
Config.REQUEST_META_KEY = `__${Config.SLUG.toUpperCase()}__`;
|
|
18
18
|
Config.LOG_LEVELS = ['debug', 'info', 'warn', 'error', 'fatal'];
|
|
19
19
|
Config.PRERENDER_MODES = ['full', 'ppr', false];
|
|
20
20
|
Config.TRAILING_SLASH_MODES = ['always', 'never', 'ignore'];
|
package/dist/types.d.ts
CHANGED
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
type BunRequest = Request & {
|
|
2
2
|
params?: Record<string, string | string[]>;
|
|
3
3
|
};
|
|
4
|
-
import { Solas } from './solas.js';
|
|
5
4
|
import { ExportReader } from './utils/export-reader.js';
|
|
6
5
|
import type { Build } from './internal/build.js';
|
|
6
|
+
import type { HttpRouter } from './internal/http-router/router.js';
|
|
7
7
|
import type { Metadata } from './internal/metadata.js';
|
|
8
8
|
import type { HttpException } from './internal/navigation/http-exception.js';
|
|
9
|
-
import
|
|
9
|
+
import { BrowserRouter } from './internal/browser-router/router.js';
|
|
10
|
+
import { Solas } from './solas.js';
|
|
10
11
|
export type LogLevel = (typeof Solas.Config.LOG_LEVELS)[number];
|
|
11
12
|
type PluginConfigBase = {
|
|
12
13
|
port?: number;
|
|
13
14
|
precompress?: boolean;
|
|
14
15
|
prerender?: Route.Prerender;
|
|
15
16
|
metadata?: Metadata.Item;
|
|
16
|
-
trailingSlash?:
|
|
17
|
+
trailingSlash?: (typeof Solas.Config.TRAILING_SLASH_MODES)[number];
|
|
17
18
|
readonly logger?: {
|
|
18
19
|
level?: LogLevel;
|
|
19
20
|
};
|
|
@@ -36,6 +37,13 @@ export type BuildContext = {
|
|
|
36
37
|
knownRoutes: Set<string>;
|
|
37
38
|
exportReader: ExportReader;
|
|
38
39
|
};
|
|
40
|
+
export type RequestMeta = {
|
|
41
|
+
error?: HttpException | Error;
|
|
42
|
+
action?: boolean;
|
|
43
|
+
match: HttpRouter.Match | null;
|
|
44
|
+
parsedFormData?: FormData | null;
|
|
45
|
+
url?: URL;
|
|
46
|
+
};
|
|
39
47
|
export type SolasRequest = Request & {};
|
|
40
48
|
export type Segment = {
|
|
41
49
|
__id: string;
|
|
@@ -68,6 +76,7 @@ export type Endpoint = {
|
|
|
68
76
|
middlewares: (string | null)[];
|
|
69
77
|
};
|
|
70
78
|
export type ManifestEntry = Segment | Endpoint;
|
|
79
|
+
export type ManifestEntryGroup = ManifestEntry | [ManifestEntry, ...ManifestEntry[]];
|
|
71
80
|
export type Manifest = Awaited<ReturnType<typeof Build.Finder.prototype.process>>['manifest'];
|
|
72
81
|
export type View<TProps> = React.ComponentType<TProps> | React.LazyExoticComponent<React.ComponentType<TProps>>;
|
|
73
82
|
export type StaticImport = Record<string, unknown>;
|
|
@@ -81,7 +90,7 @@ export type MapEntry = {
|
|
|
81
90
|
'404s'?: readonly (DynamicImport | null)[];
|
|
82
91
|
'500s'?: readonly (DynamicImport | null)[];
|
|
83
92
|
loaders?: readonly (DynamicImport | null)[];
|
|
84
|
-
middlewares?: readonly (
|
|
93
|
+
middlewares?: readonly (HttpRouter.Middleware | null)[];
|
|
85
94
|
endpoint?: (req?: BunRequest) => unknown;
|
|
86
95
|
};
|
|
87
96
|
export type ImportMap = Record<string, MapEntry>;
|
|
@@ -92,13 +101,12 @@ export type BuildManifest = {
|
|
|
92
101
|
prerenderRoutes: string[];
|
|
93
102
|
sitemapRoutes: string[];
|
|
94
103
|
precompress: boolean;
|
|
95
|
-
trailingSlash:
|
|
104
|
+
trailingSlash: (typeof Solas.Config.TRAILING_SLASH_MODES)[number];
|
|
96
105
|
url?: PluginConfig['url'];
|
|
97
106
|
};
|
|
98
107
|
export declare namespace Route {
|
|
99
|
-
type Metadata = Metadata.Item | ((input: Metadata.Input<
|
|
108
|
+
type Metadata = Metadata.Item | ((input: Metadata.Input<BrowserRouter.Params>) => Promise<Metadata.Item> | Metadata.Item);
|
|
100
109
|
type Prerender = (typeof Solas.Config.PRERENDER_MODES)[number];
|
|
101
|
-
type TrailingSlash = (typeof Solas.Config.TRAILING_SLASH_MODES)[number];
|
|
102
110
|
}
|
|
103
111
|
export type BoundaryError = Error & {
|
|
104
112
|
digest?: string;
|
package/dist/utils/logger.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@jk2908/solas",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "A React Server Components meta-framework powered by Vite",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"framework",
|
|
@@ -71,10 +71,6 @@
|
|
|
71
71
|
"./error-boundary": {
|
|
72
72
|
"types": "./dist/error-boundary.d.ts",
|
|
73
73
|
"import": "./dist/error-boundary.js"
|
|
74
|
-
},
|
|
75
|
-
"./solas": {
|
|
76
|
-
"types": "./dist/solas.d.ts",
|
|
77
|
-
"import": "./dist/solas.js"
|
|
78
74
|
}
|
|
79
75
|
},
|
|
80
76
|
"scripts": {
|
|
@@ -89,8 +85,7 @@
|
|
|
89
85
|
},
|
|
90
86
|
"dependencies": {
|
|
91
87
|
"@vitejs/plugin-rsc": "^0.5.20",
|
|
92
|
-
"path-to-regexp": "^8.3.0"
|
|
93
|
-
"rsc-html-stream": "^0.0.7"
|
|
88
|
+
"path-to-regexp": "^8.3.0"
|
|
94
89
|
},
|
|
95
90
|
"devDependencies": {
|
|
96
91
|
"@prettier/plugin-oxc": "^0.1.3",
|