@torpor/build 1.0.0 → 1.0.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/dist/{flattenHeaders-C_YYLdOq.mjs → Server-BnjLJleZ.mjs} +2 -12
- package/dist/Server-BnjLJleZ.mjs.map +1 -0
- package/dist/{Server-C_IKav_e.d.mts → Server-Cler2w5O.d.mts} +3 -48
- package/dist/Server-Cler2w5O.d.mts.map +1 -0
- package/dist/ServerEvent-CTx3Q-hk.d.mts +48 -0
- package/dist/ServerEvent-CTx3Q-hk.d.mts.map +1 -0
- package/dist/{Site-CMa153FA.d.mts → Site-CE0_o5Ci.d.mts} +3 -2
- package/dist/Site-CE0_o5Ci.d.mts.map +1 -0
- package/dist/bin/index.js +1 -1
- package/dist/clientEntry.d.mts +1 -0
- package/dist/clientEntry.mjs +59 -0
- package/dist/clientEntry.mjs.map +1 -0
- package/dist/clientEntryDev.d.mts +1 -0
- package/dist/clientEntryDev.mjs +7 -0
- package/dist/clientEntryDev.mjs.map +1 -0
- package/dist/dev.d.mts +3 -0
- package/dist/dev.mjs +3 -0
- package/dist/endpoint-EULRGCKA.mjs +108 -0
- package/dist/endpoint-EULRGCKA.mjs.map +1 -0
- package/dist/flattenHeaders-DM5qsSqO.mjs +13 -0
- package/dist/flattenHeaders-DM5qsSqO.mjs.map +1 -0
- package/dist/index.d.mts +1 -1
- package/dist/load-BntzvmwL.mjs +228 -0
- package/dist/load-BntzvmwL.mjs.map +1 -0
- package/dist/nav.mjs +1 -225
- package/dist/nav.mjs.map +1 -1
- package/dist/openapi.d.mts +1 -1
- package/dist/run.d.mts +1 -1
- package/dist/run.d.mts.map +1 -1
- package/dist/run.mjs +1 -1
- package/dist/{runOpenApi-BUi1RH1l.mjs → runOpenApi-C8eI2Fh0.mjs} +54 -16
- package/dist/runOpenApi-C8eI2Fh0.mjs.map +1 -0
- package/dist/server/Server.d.mts +2 -0
- package/dist/server/Server.mjs +2 -0
- package/dist/server.d.mts +2 -1
- package/dist/server.d.mts.map +1 -1
- package/dist/server.mjs +2 -1
- package/dist/server.mjs.map +1 -1
- package/dist/serverEntry-1qY3wZig.mjs +351 -0
- package/dist/serverEntry-1qY3wZig.mjs.map +1 -0
- package/dist/serverEntry-BAO8m03V.d.mts +6 -0
- package/dist/serverEntry-BAO8m03V.d.mts.map +1 -0
- package/dist/serverEntry.d.mts +2 -0
- package/dist/serverEntry.mjs +2 -0
- package/dist/test.d.mts +2 -2
- package/dist/test.mjs +2 -104
- package/dist/test.mjs.map +1 -1
- package/package.json +9 -8
- package/dist/Server-C_IKav_e.d.mts.map +0 -1
- package/dist/Site-CMa153FA.d.mts.map +0 -1
- package/dist/flattenHeaders-C_YYLdOq.mjs.map +0 -1
- package/dist/runOpenApi-BUi1RH1l.mjs.map +0 -1
- package/src/bin/index.ts +0 -22
- package/src/dev.ts +0 -10
- package/src/form/formDataToRecord.ts +0 -23
- package/src/form/readForm.ts +0 -71
- package/src/form.ts +0 -4
- package/src/index.ts +0 -82
- package/src/nav/api.test-d.ts +0 -79
- package/src/nav/api.ts +0 -104
- package/src/nav/formSubmit.ts +0 -70
- package/src/nav/load.ts +0 -9
- package/src/nav/loadData.ts +0 -134
- package/src/nav/navigate.ts +0 -189
- package/src/nav/reload.ts +0 -9
- package/src/nav/route.ts +0 -38
- package/src/nav.ts +0 -6
- package/src/openapi/docsHtml.ts +0 -25
- package/src/openapi/document.ts +0 -154
- package/src/openapi/plugin.ts +0 -78
- package/src/openapi/types.ts +0 -82
- package/src/openapi.ts +0 -14
- package/src/response/TypedResponse.ts +0 -17
- package/src/response/badRequest.ts +0 -31
- package/src/response/created.ts +0 -31
- package/src/response/forbidden.ts +0 -21
- package/src/response/found.ts +0 -30
- package/src/response/methodNotAllowed.ts +0 -18
- package/src/response/movedPermanently.ts +0 -25
- package/src/response/notFound.ts +0 -24
- package/src/response/notModified.ts +0 -34
- package/src/response/ok.ts +0 -38
- package/src/response/permanentRedirect.ts +0 -30
- package/src/response/response.ts +0 -22
- package/src/response/seeOther.ts +0 -19
- package/src/response/serverError.ts +0 -24
- package/src/response/temporaryRedirect.ts +0 -31
- package/src/response/transfer.ts +0 -14
- package/src/response/unauthorized.ts +0 -21
- package/src/response/unprocessable.ts +0 -30
- package/src/response.ts +0 -37
- package/src/run/depCache.ts +0 -175
- package/src/run/devPlugin.ts +0 -128
- package/src/run/prepareTemplate.ts +0 -42
- package/src/run/run.ts +0 -86
- package/src/run/runBuild.ts +0 -128
- package/src/run/runDev.ts +0 -177
- package/src/run/runOpenApi.ts +0 -52
- package/src/run/runPreview.ts +0 -84
- package/src/run/staleTorpCopies.ts +0 -100
- package/src/run.ts +0 -7
- package/src/schema.ts +0 -7
- package/src/server/CookieHelper.ts +0 -46
- package/src/server/HeaderHelper.ts +0 -25
- package/src/server/Server.ts +0 -168
- package/src/server/ServerEvent.ts +0 -62
- package/src/server/connect/connectMiddleware.ts +0 -85
- package/src/server/connect/flattenHeaders.ts +0 -22
- package/src/server/connect/nodeMessageToNodeResponse.ts +0 -89
- package/src/server/connect/requestToNodeMessage.ts +0 -29
- package/src/server/contentType.ts +0 -85
- package/src/server/types/HttpMethod.ts +0 -12
- package/src/server/types/MiddlewareFunction.ts +0 -22
- package/src/server/types/ServerFunction.ts +0 -7
- package/src/server.ts +0 -7
- package/src/site/Router.ts +0 -175
- package/src/site/Site.ts +0 -388
- package/src/site/checkLayoutSlots.ts +0 -114
- package/src/site/checkRoutes.ts +0 -435
- package/src/site/clientEntry.ts +0 -121
- package/src/site/clientEntryDev.ts +0 -3
- package/src/site/defaultAdapter.ts +0 -11
- package/src/site/layoutSlots.ts +0 -53
- package/src/site/manifest.ts +0 -173
- package/src/site/serverEntry.ts +0 -648
- package/src/state/$page.ts +0 -25
- package/src/state/$serverPage.ts +0 -22
- package/src/state/client.ts +0 -15
- package/src/state.ts +0 -3
- package/src/test/runTest.ts +0 -538
- package/src/test.ts +0 -3
- package/src/types/Adapter.ts +0 -20
- package/src/types/ClientState.ts +0 -8
- package/src/types/InternalState.ts +0 -7
- package/src/types/Jsonify.ts +0 -20
- package/src/types/LayoutHandler.ts +0 -5
- package/src/types/LayoutPath.ts +0 -10
- package/src/types/ManifestRoute.ts +0 -6
- package/src/types/PageData.test-d.ts +0 -136
- package/src/types/PageData.ts +0 -35
- package/src/types/PageEndPoint.ts +0 -55
- package/src/types/PageForm.test-d.ts +0 -78
- package/src/types/PageForm.ts +0 -29
- package/src/types/PageLoadEvent.ts +0 -26
- package/src/types/PageLoadReturn.ts +0 -13
- package/src/types/PageProps.ts +0 -14
- package/src/types/PageServerAction.ts +0 -13
- package/src/types/PageServerEndPoint.test-d.ts +0 -105
- package/src/types/PageServerEndPoint.ts +0 -110
- package/src/types/PageServerLoad.ts +0 -15
- package/src/types/PageState.ts +0 -8
- package/src/types/ParseRouteParams.test-d.ts +0 -84
- package/src/types/ParseRouteParams.ts +0 -64
- package/src/types/Route.ts +0 -30
- package/src/types/RouteHandler.ts +0 -23
- package/src/types/RouteLayoutHandler.ts +0 -5
- package/src/types/RouteMatchResult.ts +0 -7
- package/src/types/RouteType.ts +0 -19
- package/src/types/ServerEndPoint.test-d.ts +0 -77
- package/src/types/ServerEndPoint.ts +0 -169
- package/src/types/ServerHook.ts +0 -18
- package/src/types/ServerLoadEvent.ts +0 -82
- package/src/types/ServerRequest.ts +0 -15
- package/src/types/SitePlugin.ts +0 -24
- package/src/types/StandardSchema.ts +0 -109
- package/src/utils/pathToRegex.ts +0 -17
- package/src/utils/pathTrie.ts +0 -182
- package/src/utils/searchParamsToRecord.ts +0 -18
- package/src/utils/torporPackages.ts +0 -150
- package/src/utils/tsconfigAliases.ts +0 -90
- package/src/validation/ValidationError.ts +0 -18
- package/src/validation/endpoint.ts +0 -83
- package/src/validation/validate.ts +0 -26
- package/src/vite-env.d.ts +0 -2
package/src/state/client.ts
DELETED
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type ClientState from "../types/ClientState";
|
|
2
|
-
|
|
3
|
-
const CLIENT_SYMBOL: unique symbol = Symbol.for("torp.Client");
|
|
4
|
-
|
|
5
|
-
const client: ClientState =
|
|
6
|
-
// @ts-ignore
|
|
7
|
-
(globalThis[CLIENT_SYMBOL] ??= {
|
|
8
|
-
// @ts-ignore This will definitely, 100% get set
|
|
9
|
-
router: null,
|
|
10
|
-
layoutStack: [],
|
|
11
|
-
// TODO: Probably expire after 30 seconds or something?
|
|
12
|
-
prefetchedData: {},
|
|
13
|
-
});
|
|
14
|
-
|
|
15
|
-
export default client;
|
package/src/state.ts
DELETED
package/src/test/runTest.ts
DELETED
|
@@ -1,538 +0,0 @@
|
|
|
1
|
-
import { type ServerComponent, type ServerSlotRender } from "@torpor/view/ssr";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import formDataToRecord from "../form/formDataToRecord.ts";
|
|
4
|
-
import notFound from "../response/notFound.ts";
|
|
5
|
-
import ok from "../response/ok.ts";
|
|
6
|
-
import seeOther from "../response/seeOther.ts";
|
|
7
|
-
import ServerEvent from "../server/ServerEvent.ts";
|
|
8
|
-
import Router from "../site/Router.ts";
|
|
9
|
-
import Site from "../site/Site";
|
|
10
|
-
import $page from "../state/$serverPage.ts";
|
|
11
|
-
import type PageEndPoint from "../types/PageEndPoint.ts";
|
|
12
|
-
import type PageServerEndPoint from "../types/PageServerEndPoint.ts";
|
|
13
|
-
import type RouteHandler from "../types/RouteHandler.ts";
|
|
14
|
-
import type ServerRequest from "../types/ServerRequest.ts";
|
|
15
|
-
import {
|
|
16
|
-
ERROR_ROUTE,
|
|
17
|
-
HOOK_ROUTE,
|
|
18
|
-
HOOK_SERVER_ROUTE,
|
|
19
|
-
LAYOUT_ROUTE,
|
|
20
|
-
LAYOUT_SERVER_ROUTE,
|
|
21
|
-
PAGE_ROUTE,
|
|
22
|
-
PAGE_SERVER_ROUTE,
|
|
23
|
-
SERVER_ROUTE,
|
|
24
|
-
} from "../types/RouteType";
|
|
25
|
-
import type ServerEndPoint from "../types/ServerEndPoint.ts";
|
|
26
|
-
import type ServerHook from "../types/ServerHook.ts";
|
|
27
|
-
import type ServerLoadEvent from "../types/ServerLoadEvent.ts";
|
|
28
|
-
import searchParamsToRecord from "../utils/searchParamsToRecord.ts";
|
|
29
|
-
import validate from "../validation/validate.ts";
|
|
30
|
-
import ValidationError from "../validation/ValidationError.ts";
|
|
31
|
-
import {
|
|
32
|
-
endpointSchema,
|
|
33
|
-
validateEndpointParams,
|
|
34
|
-
validateHandlerInput,
|
|
35
|
-
validationErrorResponse,
|
|
36
|
-
} from "../validation/endpoint.ts";
|
|
37
|
-
|
|
38
|
-
/**
|
|
39
|
-
* Runs a site route in test mode
|
|
40
|
-
* @param site The site configuration, with routing configured
|
|
41
|
-
* @param route The route path e.g. `/home`
|
|
42
|
-
* @param ev An optional ServerEvent, which you can use to set test cookies and headers
|
|
43
|
-
* @returns An HTTP response containing the requested data, HTML, or error status
|
|
44
|
-
*/
|
|
45
|
-
export default async function runTest(
|
|
46
|
-
site: Site,
|
|
47
|
-
route: string,
|
|
48
|
-
ev?: ServerEvent,
|
|
49
|
-
): Promise<Response> {
|
|
50
|
-
if (!route.startsWith("/")) route += "/";
|
|
51
|
-
if (!ev) {
|
|
52
|
-
const req = new Request(`http://localhost${route}`);
|
|
53
|
-
ev = new ServerEvent(req);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
// Build the router from the Site object created by the user
|
|
57
|
-
const router = new Router();
|
|
58
|
-
router.addPages(
|
|
59
|
-
site.routes.map((r) => ({
|
|
60
|
-
path: r.path,
|
|
61
|
-
type: r.type,
|
|
62
|
-
endPoint: async () => {
|
|
63
|
-
if (r.file) {
|
|
64
|
-
const mod = await import(/* @vite-ignore */ path.join(site.root, r.file));
|
|
65
|
-
// A .torp file's default export is a component, so wrap it as
|
|
66
|
-
// a PageEndPoint ({ component }) for the entries
|
|
67
|
-
if (r.file.endsWith(".torp")) {
|
|
68
|
-
return { default: { component: mod.default } };
|
|
69
|
-
}
|
|
70
|
-
return mod;
|
|
71
|
-
}
|
|
72
|
-
// Inline endpoint (no file) — return directly from memory
|
|
73
|
-
return { default: r.endPoint };
|
|
74
|
-
},
|
|
75
|
-
subFolder: r.subFolder,
|
|
76
|
-
})),
|
|
77
|
-
);
|
|
78
|
-
|
|
79
|
-
return await load(router, ev, "%COMPONENT_BODY%");
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// HACK: This is a copy of serverEntry
|
|
83
|
-
// TODO: Make it shared instead!
|
|
84
|
-
async function load(router: Router, ev: ServerEvent, template: string): Promise<Response> {
|
|
85
|
-
//const url = new URL(`http://${process.env.HOST ?? "localhost"}${ev.request.url}`);
|
|
86
|
-
const url = ev.url;
|
|
87
|
-
const path = url.pathname;
|
|
88
|
-
const query = url.searchParams;
|
|
89
|
-
|
|
90
|
-
//console.log(`handling ${ev.request.method} for '${path}'${query.size ? ` with ${query}` : ""}`);
|
|
91
|
-
|
|
92
|
-
const route = router.match(path, query);
|
|
93
|
-
if (!route) {
|
|
94
|
-
return notFound();
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
// Update $page before building the components
|
|
98
|
-
// TODO: Find somewhere better to put this
|
|
99
|
-
$page.url = url;
|
|
100
|
-
if (path.endsWith("/_error")) {
|
|
101
|
-
$page.status = parseInt(query.get("status") ?? "404");
|
|
102
|
-
$page.error = { message: query.get("message") ?? "" };
|
|
103
|
-
} else {
|
|
104
|
-
$page.status = 200;
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
const handler = route.handler;
|
|
108
|
-
const params = route.params || {};
|
|
109
|
-
|
|
110
|
-
// TODO: Hit the server hook out here
|
|
111
|
-
// We could maybe set data loading up as middleware on a route??????
|
|
112
|
-
|
|
113
|
-
switch (handler.type) {
|
|
114
|
-
case PAGE_ROUTE:
|
|
115
|
-
case LAYOUT_ROUTE: {
|
|
116
|
-
// It's a /+page.ts or /_layout.ts endpoint
|
|
117
|
-
if (ev.request.method === "GET") {
|
|
118
|
-
return await loadView(ev, url, handler, params, template);
|
|
119
|
-
} else if (ev.request.method === "POST") {
|
|
120
|
-
const serverEndPoint: PageServerEndPoint | undefined =
|
|
121
|
-
handler.serverEndPoint && (await handler.serverEndPoint()).default;
|
|
122
|
-
return await runAction(ev, url, handler, serverEndPoint, params, query);
|
|
123
|
-
}
|
|
124
|
-
break;
|
|
125
|
-
}
|
|
126
|
-
case PAGE_SERVER_ROUTE:
|
|
127
|
-
case LAYOUT_SERVER_ROUTE: {
|
|
128
|
-
// It's a /+page.server.ts or /_layout.server.ts endpoint
|
|
129
|
-
if (ev.request.method === "GET") {
|
|
130
|
-
return await loadData(ev, url, handler, "load", params);
|
|
131
|
-
} else if (ev.request.method === "POST") {
|
|
132
|
-
const serverEndPoint: PageServerEndPoint | undefined =
|
|
133
|
-
handler.endPoint && (await handler.endPoint()).default;
|
|
134
|
-
return await runAction(ev, url, handler, serverEndPoint, params, query);
|
|
135
|
-
}
|
|
136
|
-
break;
|
|
137
|
-
}
|
|
138
|
-
case SERVER_ROUTE: {
|
|
139
|
-
// It's a /+server.ts endpoint
|
|
140
|
-
const functionName = ev.request.method.toLowerCase().replace("delete", "del");
|
|
141
|
-
return await loadData(ev, url, handler, functionName, params);
|
|
142
|
-
}
|
|
143
|
-
case ERROR_ROUTE: {
|
|
144
|
-
return await loadView(ev, url, handler, params, template);
|
|
145
|
-
}
|
|
146
|
-
case HOOK_ROUTE:
|
|
147
|
-
case HOOK_SERVER_ROUTE: {
|
|
148
|
-
break;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
return notFound();
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
async function loadData(
|
|
156
|
-
ev: ServerEvent,
|
|
157
|
-
url: URL,
|
|
158
|
-
handler: RouteHandler,
|
|
159
|
-
functionName: string,
|
|
160
|
-
params: Record<string, any>,
|
|
161
|
-
) {
|
|
162
|
-
const serverEndPoint: ServerEndPoint | undefined = (await handler.endPoint()).default;
|
|
163
|
-
// `functionName` is computed from the request method, so the handlers are
|
|
164
|
-
// accessed through a loose record
|
|
165
|
-
const handlers = serverEndPoint as unknown as Record<string, ServerRequest | undefined>;
|
|
166
|
-
const handlerFn: ServerRequest | undefined = handlers?.[functionName];
|
|
167
|
-
if (serverEndPoint && handlerFn) {
|
|
168
|
-
// Route params come from the URL, so a failed validation means the
|
|
169
|
-
// resource doesn't exist
|
|
170
|
-
try {
|
|
171
|
-
params = await validateEndpointParams(serverEndPoint, params);
|
|
172
|
-
} catch (error) {
|
|
173
|
-
if (error instanceof ValidationError) return notFound();
|
|
174
|
-
throw error;
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
try {
|
|
178
|
-
// If the endpoint declares a schema for this handler, validate its
|
|
179
|
-
// input up front and reject with 422 if it fails. get/head schemas
|
|
180
|
-
// validate the query string; other schemas validate the json body
|
|
181
|
-
const schema = endpointSchema(serverEndPoint, functionName);
|
|
182
|
-
const values = await validateHandlerInput(schema, functionName, url, ev);
|
|
183
|
-
|
|
184
|
-
const serverParams = buildServerParams(ev, url, params, values);
|
|
185
|
-
|
|
186
|
-
const serverHooks = await loadServerHooks(handler);
|
|
187
|
-
let entered = 0;
|
|
188
|
-
let enterResponse: Response | undefined = undefined;
|
|
189
|
-
try {
|
|
190
|
-
// Hooks run from the root down; a hook's enter can return a
|
|
191
|
-
// Response to short-circuit the request
|
|
192
|
-
for (; entered < serverHooks.length && !enterResponse; entered++) {
|
|
193
|
-
const hookResult = await serverHooks[entered].enter?.(serverParams);
|
|
194
|
-
if (hookResult) {
|
|
195
|
-
enterResponse = hookResult;
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
const result = enterResponse || (await handlerFn(serverParams));
|
|
200
|
-
|
|
201
|
-
// If there was no response returned from load (such as errors or a
|
|
202
|
-
// redirect), send an ok response
|
|
203
|
-
return result || ok();
|
|
204
|
-
} finally {
|
|
205
|
-
// Run exit hooks in reverse order for hooks that were entered
|
|
206
|
-
while (entered > 0) {
|
|
207
|
-
entered--;
|
|
208
|
-
await serverHooks[entered].exit?.(serverParams);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
} catch (error) {
|
|
212
|
-
const response = validationErrorResponse(error);
|
|
213
|
-
if (response) return response;
|
|
214
|
-
throw error;
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
return notFound();
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
async function loadView(
|
|
222
|
-
ev: ServerEvent,
|
|
223
|
-
url: URL,
|
|
224
|
-
handler: RouteHandler,
|
|
225
|
-
params: Record<string, any>,
|
|
226
|
-
template: string,
|
|
227
|
-
) {
|
|
228
|
-
// There must be a client endpoint with a component
|
|
229
|
-
const clientEndPoint: PageEndPoint | undefined = (await handler.endPoint()).default;
|
|
230
|
-
if (!clientEndPoint?.component) {
|
|
231
|
-
return notFound();
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// There may be a server endpoint
|
|
235
|
-
const serverEndPoint: PageServerEndPoint | undefined =
|
|
236
|
-
handler.serverEndPoint && (await handler.serverEndPoint())?.default;
|
|
237
|
-
|
|
238
|
-
// Validate the route params and the load query against the server
|
|
239
|
-
// endpoint's schemas, if it declares any. Params come from the URL, so a
|
|
240
|
-
// failed validation means the resource doesn't exist; a failed query
|
|
241
|
-
// returns like any other load failure
|
|
242
|
-
let query: unknown;
|
|
243
|
-
if (serverEndPoint) {
|
|
244
|
-
try {
|
|
245
|
-
params = await validateEndpointParams(serverEndPoint, params);
|
|
246
|
-
} catch (error) {
|
|
247
|
-
if (error instanceof ValidationError) return notFound();
|
|
248
|
-
throw error;
|
|
249
|
-
}
|
|
250
|
-
const loadSchema = endpointSchema(serverEndPoint, "load");
|
|
251
|
-
if (loadSchema) {
|
|
252
|
-
try {
|
|
253
|
-
query = await validate(loadSchema, searchParamsToRecord(url.searchParams));
|
|
254
|
-
} catch (error) {
|
|
255
|
-
const response = validationErrorResponse(error);
|
|
256
|
-
if (response) return response;
|
|
257
|
-
throw error;
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// Maybe hit the server hooks
|
|
263
|
-
const serverParams = buildServerParams(ev, url, params, query ? { query } : {});
|
|
264
|
-
const serverHooks = await loadServerHooks(handler);
|
|
265
|
-
let entered = 0;
|
|
266
|
-
let enterResponse: Response | undefined = undefined;
|
|
267
|
-
try {
|
|
268
|
-
// Hooks run from the root down; a hook's enter can return a Response
|
|
269
|
-
// to short-circuit the request
|
|
270
|
-
for (; entered < serverHooks.length && !enterResponse; entered++) {
|
|
271
|
-
const hookResult = await serverHooks[entered].enter?.(serverParams);
|
|
272
|
-
if (hookResult) {
|
|
273
|
-
enterResponse = hookResult;
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
if (enterResponse) {
|
|
277
|
-
return enterResponse;
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
// Pass the data into $props
|
|
281
|
-
// TODO: Promise.all
|
|
282
|
-
// NOTE: We're loading data from top to bottom, overriding as we go, and I'm not sure if this is the best way to go
|
|
283
|
-
let data = {};
|
|
284
|
-
if (handler.layouts) {
|
|
285
|
-
for (let layout of handler.layouts) {
|
|
286
|
-
const layoutEndPoint: PageEndPoint | undefined = (await layout.endPoint())?.default;
|
|
287
|
-
const layoutServerEndPoint: PageServerEndPoint | undefined =
|
|
288
|
-
layout.serverEndPoint && (await layout.serverEndPoint())?.default;
|
|
289
|
-
const layoutResponse = await loadClientAndServerData(
|
|
290
|
-
url,
|
|
291
|
-
params,
|
|
292
|
-
serverParams,
|
|
293
|
-
data,
|
|
294
|
-
layoutEndPoint,
|
|
295
|
-
layoutServerEndPoint,
|
|
296
|
-
);
|
|
297
|
-
if (layoutResponse?.ok === false) {
|
|
298
|
-
return layoutResponse;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
let endPointResponse = await loadClientAndServerData(
|
|
303
|
-
url,
|
|
304
|
-
params,
|
|
305
|
-
serverParams,
|
|
306
|
-
data,
|
|
307
|
-
clientEndPoint,
|
|
308
|
-
serverEndPoint,
|
|
309
|
-
);
|
|
310
|
-
if (endPointResponse?.ok === false) {
|
|
311
|
-
return endPointResponse;
|
|
312
|
-
}
|
|
313
|
-
let $props: Record<string, any> = { data };
|
|
314
|
-
|
|
315
|
-
let styles = "";
|
|
316
|
-
|
|
317
|
-
// If there are layouts, work our way upwards, pushing each component into
|
|
318
|
-
// the default slot of its parent
|
|
319
|
-
// TODO: Also handle layout server data
|
|
320
|
-
// TODO: There's probably a nicer way to do this with reducers or something
|
|
321
|
-
let component = clientEndPoint.component as ServerComponent;
|
|
322
|
-
let slots: Record<string, ServerSlotRender> | undefined = undefined;
|
|
323
|
-
if (handler.layouts) {
|
|
324
|
-
let slotFunctions: ServerSlotRender[] = [];
|
|
325
|
-
slotFunctions[handler.layouts.length] = (_, $context) => {
|
|
326
|
-
let { body, head } = (clientEndPoint.component as ServerComponent)($props, $context);
|
|
327
|
-
styles += head;
|
|
328
|
-
return body;
|
|
329
|
-
};
|
|
330
|
-
for (let i = handler.layouts.length - 1; i >= 0; i--) {
|
|
331
|
-
const layoutEndPoint: PageEndPoint | undefined = (await handler.layouts[i].endPoint())
|
|
332
|
-
?.default;
|
|
333
|
-
if (layoutEndPoint?.component) {
|
|
334
|
-
if (i === 0) {
|
|
335
|
-
component = layoutEndPoint.component as ServerComponent;
|
|
336
|
-
slots = { _: slotFunctions[i + 1] };
|
|
337
|
-
} else {
|
|
338
|
-
slotFunctions[i] = (_, $context) => {
|
|
339
|
-
let { body, head } = (layoutEndPoint.component as ServerComponent)($props, $context, {
|
|
340
|
-
_: slotFunctions[i + 1],
|
|
341
|
-
});
|
|
342
|
-
styles += head;
|
|
343
|
-
return body;
|
|
344
|
-
};
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
}
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
let html;
|
|
351
|
-
try {
|
|
352
|
-
let { body, head } = component($props, undefined, slots);
|
|
353
|
-
styles += head;
|
|
354
|
-
html = template.replace("%COMPONENT_BODY%", body).replace("%COMPONENT_HEAD%", styles);
|
|
355
|
-
} catch (error) {
|
|
356
|
-
// TODO: Show a proper Error component
|
|
357
|
-
html = '<span style="color: red">Script syntax error</span><p>' + error + "</p>";
|
|
358
|
-
console.log(error);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
return new Response(html, {
|
|
362
|
-
status: 200,
|
|
363
|
-
headers: {
|
|
364
|
-
"Content-Type": "text/html",
|
|
365
|
-
},
|
|
366
|
-
});
|
|
367
|
-
} finally {
|
|
368
|
-
// Run exit hooks in reverse order for hooks that were entered
|
|
369
|
-
while (entered > 0) {
|
|
370
|
-
entered--;
|
|
371
|
-
await serverHooks[entered].exit?.(serverParams);
|
|
372
|
-
}
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
async function runAction(
|
|
377
|
-
ev: ServerEvent,
|
|
378
|
-
url: URL,
|
|
379
|
-
handler: RouteHandler,
|
|
380
|
-
serverEndPoint: PageServerEndPoint | undefined,
|
|
381
|
-
params: Record<string, any>,
|
|
382
|
-
query: URLSearchParams,
|
|
383
|
-
) {
|
|
384
|
-
const actionName = (Array.from(query.keys())[0] || "default").replace(/^\//, "");
|
|
385
|
-
if (serverEndPoint?.actions) {
|
|
386
|
-
const action = serverEndPoint.actions[actionName];
|
|
387
|
-
if (action) {
|
|
388
|
-
if (actionName === "load" || actionName === "params") {
|
|
389
|
-
// These names are reserved in the endpoint's schema map: `load`
|
|
390
|
-
// validates the query string and `params` the route params, so
|
|
391
|
-
// an action with one of these names would get the wrong schema
|
|
392
|
-
// applied to its form data
|
|
393
|
-
throw new Error(
|
|
394
|
-
`The action name "${actionName}" is reserved. ` +
|
|
395
|
-
`Rename the action (and its schema key, if any), e.g. to "save".`,
|
|
396
|
-
);
|
|
397
|
-
}
|
|
398
|
-
// TODO: form.errors etc
|
|
399
|
-
// Route params come from the URL, so a failed validation means the
|
|
400
|
-
// resource doesn't exist
|
|
401
|
-
try {
|
|
402
|
-
params = await validateEndpointParams(serverEndPoint, params);
|
|
403
|
-
} catch (error) {
|
|
404
|
-
if (error instanceof ValidationError) return notFound();
|
|
405
|
-
throw error;
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
let result: Response | undefined | void;
|
|
409
|
-
try {
|
|
410
|
-
// If the endpoint declares a schema for this action, validate the
|
|
411
|
-
// submitted form data up front and reject with 422 if it fails
|
|
412
|
-
const schema = endpointSchema(serverEndPoint, actionName);
|
|
413
|
-
const form = schema
|
|
414
|
-
? await validate(schema, await formDataToRecord(ev.request))
|
|
415
|
-
: undefined;
|
|
416
|
-
|
|
417
|
-
const serverParams = buildServerParams(ev, url, params, form ? { form } : {});
|
|
418
|
-
|
|
419
|
-
const serverHooks = await loadServerHooks(handler);
|
|
420
|
-
let entered = 0;
|
|
421
|
-
let enterResponse: Response | undefined = undefined;
|
|
422
|
-
try {
|
|
423
|
-
// Hooks run from the root down; a hook's enter can return a
|
|
424
|
-
// Response to short-circuit the action
|
|
425
|
-
for (; entered < serverHooks.length && !enterResponse; entered++) {
|
|
426
|
-
const hookResult = await serverHooks[entered].enter?.(serverParams);
|
|
427
|
-
if (hookResult) {
|
|
428
|
-
enterResponse = hookResult;
|
|
429
|
-
}
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
result = enterResponse || (await action(serverParams));
|
|
433
|
-
} finally {
|
|
434
|
-
// Run exit hooks in reverse order for hooks that were entered
|
|
435
|
-
while (entered > 0) {
|
|
436
|
-
entered--;
|
|
437
|
-
await serverHooks[entered].exit?.(serverParams);
|
|
438
|
-
}
|
|
439
|
-
}
|
|
440
|
-
} catch (error) {
|
|
441
|
-
const response = validationErrorResponse(error);
|
|
442
|
-
if (response) return response;
|
|
443
|
-
throw error;
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
// If there was no response returned from the action (such as errors
|
|
447
|
-
// or a redirect), reload the page by redirecting
|
|
448
|
-
return result || seeOther(url.pathname);
|
|
449
|
-
}
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
return notFound();
|
|
453
|
-
}
|
|
454
|
-
|
|
455
|
-
async function loadClientAndServerData(
|
|
456
|
-
url: URL,
|
|
457
|
-
params: Record<string, any>,
|
|
458
|
-
serverParams: ServerLoadEvent,
|
|
459
|
-
data: Record<string, any>,
|
|
460
|
-
clientEndPoint?: PageEndPoint,
|
|
461
|
-
serverEndPoint?: PageServerEndPoint,
|
|
462
|
-
) {
|
|
463
|
-
if (clientEndPoint?.load) {
|
|
464
|
-
const clientParams = buildClientParams(url, params, data);
|
|
465
|
-
const clientResponse = await clientEndPoint.load(clientParams);
|
|
466
|
-
if (clientResponse) {
|
|
467
|
-
if (clientResponse.ok) {
|
|
468
|
-
if (clientResponse.headers.get("Content-Type")?.includes("application/json")) {
|
|
469
|
-
Object.assign(data, await clientResponse.json());
|
|
470
|
-
}
|
|
471
|
-
} else {
|
|
472
|
-
return clientResponse;
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
if (serverEndPoint?.load) {
|
|
477
|
-
const serverResponse = await serverEndPoint.load(serverParams);
|
|
478
|
-
if (serverResponse) {
|
|
479
|
-
if (serverResponse.ok) {
|
|
480
|
-
if (serverResponse.headers.get("Content-Type")?.includes("application/json")) {
|
|
481
|
-
Object.assign(data, await serverResponse.json());
|
|
482
|
-
}
|
|
483
|
-
} else {
|
|
484
|
-
return serverResponse;
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
}
|
|
489
|
-
|
|
490
|
-
function buildClientParams(url: URL, params: Record<string, any>, data: Record<string, any>) {
|
|
491
|
-
return {
|
|
492
|
-
url,
|
|
493
|
-
params,
|
|
494
|
-
data,
|
|
495
|
-
};
|
|
496
|
-
}
|
|
497
|
-
|
|
498
|
-
/**
|
|
499
|
-
* Loads the route's server hooks, from the root down
|
|
500
|
-
*/
|
|
501
|
-
async function loadServerHooks(handler: RouteHandler): Promise<ServerHook[]> {
|
|
502
|
-
const hooks: ServerHook[] = [];
|
|
503
|
-
if (handler.serverHooks) {
|
|
504
|
-
for (let serverHook of handler.serverHooks) {
|
|
505
|
-
hooks.push((await serverHook()).default);
|
|
506
|
-
}
|
|
507
|
-
}
|
|
508
|
-
return hooks;
|
|
509
|
-
}
|
|
510
|
-
|
|
511
|
-
function buildServerParams(
|
|
512
|
-
ev: ServerEvent,
|
|
513
|
-
url: URL,
|
|
514
|
-
params: Record<string, any>,
|
|
515
|
-
values: { json?: unknown; form?: unknown; query?: unknown } = {},
|
|
516
|
-
): ServerLoadEvent {
|
|
517
|
-
return {
|
|
518
|
-
url,
|
|
519
|
-
params,
|
|
520
|
-
appData: {},
|
|
521
|
-
request: ev.request,
|
|
522
|
-
// The inputs may have been validated already, in which case the request
|
|
523
|
-
// body has been consumed and the parsed values are returned instead.
|
|
524
|
-
// Their types come from the endpoint's schemas, so they are loosely
|
|
525
|
-
// typed here
|
|
526
|
-
json: (): Promise<any> =>
|
|
527
|
-
values.json !== undefined ? Promise.resolve(values.json) : ev.json(),
|
|
528
|
-
form: (): Promise<any> =>
|
|
529
|
-
values.form !== undefined ? Promise.resolve(values.form) : formDataToRecord(ev.request),
|
|
530
|
-
query: (): Promise<any> =>
|
|
531
|
-
values.query !== undefined
|
|
532
|
-
? Promise.resolve(values.query)
|
|
533
|
-
: Promise.resolve(searchParamsToRecord(url.searchParams)),
|
|
534
|
-
cookies: ev.cookies,
|
|
535
|
-
headers: ev.headers,
|
|
536
|
-
adapter: ev.adapter,
|
|
537
|
-
};
|
|
538
|
-
}
|
package/src/test.ts
DELETED
package/src/types/Adapter.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import type { Plugin } from "vite";
|
|
2
|
-
import Server from "../server/Server";
|
|
3
|
-
import Site from "../site/Site";
|
|
4
|
-
|
|
5
|
-
export default interface Adapter {
|
|
6
|
-
prebuild?: (site: Site) => Promise<void> | void;
|
|
7
|
-
postbuild?: (site: Site) => Promise<void> | void;
|
|
8
|
-
/**
|
|
9
|
-
* Vite plugin(s) used to drive dev mode. The adapter owns where server code
|
|
10
|
-
* runs (e.g. the default Node runtime, or workerd via miniflare) and how
|
|
11
|
-
* requests reach it. When omitted, the framework's default Node-runtime dev
|
|
12
|
-
* plugin is used.
|
|
13
|
-
*/
|
|
14
|
-
dev?: (site: Site) => Plugin | Plugin[] | void;
|
|
15
|
-
/**
|
|
16
|
-
* Serve the built output (preview). Receives a torpor Server configured to
|
|
17
|
-
* load the built server entry.
|
|
18
|
-
*/
|
|
19
|
-
serve: (server: Server, site: Site) => void;
|
|
20
|
-
}
|
package/src/types/ClientState.ts
DELETED
package/src/types/Jsonify.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The JSON-serialized form of a type: what a value looks like after a
|
|
3
|
-
* JSON.stringify / JSON.parse round trip. Dates become strings, functions and
|
|
4
|
-
* undefined properties are dropped.
|
|
5
|
-
*/
|
|
6
|
-
export type Jsonify<T> = T extends string | number | boolean | null
|
|
7
|
-
? T
|
|
8
|
-
: T extends undefined | ((...args: any[]) => any)
|
|
9
|
-
? never
|
|
10
|
-
: T extends Date
|
|
11
|
-
? string
|
|
12
|
-
: T extends Array<infer Item>
|
|
13
|
-
? Array<Jsonify<Item>>
|
|
14
|
-
: T extends object
|
|
15
|
-
? {
|
|
16
|
-
[Key in keyof T as T[Key] extends undefined | ((...args: any[]) => any)
|
|
17
|
-
? never
|
|
18
|
-
: Key]: Jsonify<T[Key]>;
|
|
19
|
-
}
|
|
20
|
-
: T;
|
package/src/types/LayoutPath.ts
DELETED
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
// Store the current layout stack, so that we can re-use parts of it as necessary
|
|
2
|
-
export default interface LayoutPath {
|
|
3
|
-
path: string;
|
|
4
|
-
/** Whether to re-use this layout */
|
|
5
|
-
reuse: boolean;
|
|
6
|
-
/** Data loaded from endpoints that should be re-used */
|
|
7
|
-
data: any;
|
|
8
|
-
/** The range of the UI in this layout's slot */
|
|
9
|
-
slotRegion: any;
|
|
10
|
-
}
|