@torpor/build 1.0.0 → 1.0.1
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-DlOgF2Il.mjs} +54 -16
- package/dist/runOpenApi-DlOgF2Il.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
|
@@ -1,136 +0,0 @@
|
|
|
1
|
-
import found from "../response/found";
|
|
2
|
-
import ok from "../response/ok";
|
|
3
|
-
import type TypedResponse from "../response/TypedResponse";
|
|
4
|
-
import type { MergePageData, PageData } from "./PageData";
|
|
5
|
-
import type PageEndPoint from "./PageEndPoint";
|
|
6
|
-
import type PageLoadEvent from "./PageLoadEvent";
|
|
7
|
-
import type PageProps from "./PageProps";
|
|
8
|
-
import type PageServerEndPoint from "./PageServerEndPoint";
|
|
9
|
-
|
|
10
|
-
type Equals<A, B> =
|
|
11
|
-
(<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? true : false;
|
|
12
|
-
type Expect<T extends true> = T;
|
|
13
|
-
|
|
14
|
-
interface Post {
|
|
15
|
-
title: string;
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
// A server endpoint whose load returns typed data
|
|
19
|
-
interface PostsServer {
|
|
20
|
-
load: () => Promise<TypedResponse<{ posts: { title: string }[] }>>;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export const server: PostsServer = {
|
|
24
|
-
load: async () => ok({ posts: [{ title: "Hello" }] }),
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
// The shape above is a valid +page.server endpoint
|
|
28
|
-
export const serverCompat: PageServerEndPoint<"/posts"> = server;
|
|
29
|
-
|
|
30
|
-
// PageData extracts the Jsonify'd body of the load's typed responses
|
|
31
|
-
export type D01 = Expect<Equals<PageData<PostsServer>, { posts: { title: string }[] }>>;
|
|
32
|
-
|
|
33
|
-
// Dates are Jsonify'd to strings through ok()
|
|
34
|
-
interface ClockServer {
|
|
35
|
-
load: () => Promise<TypedResponse<{ now: string }>>;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
export const clockServer: ClockServer = {
|
|
39
|
-
load: async () => ok({ now: new Date() }),
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
export type D02 = Expect<Equals<PageData<ClockServer>, { now: string }>>;
|
|
43
|
-
|
|
44
|
-
// Endpoints without a load fall back to a loose record
|
|
45
|
-
export const actionsOnly: PageServerEndPoint<"/posts"> = {
|
|
46
|
-
actions: { default: async () => ok({}) },
|
|
47
|
-
};
|
|
48
|
-
export type D03 = Expect<Equals<PageData<typeof actionsOnly>, Record<string, any>>>;
|
|
49
|
-
|
|
50
|
-
// Untyped loads (redirects etc) fall back to a loose record
|
|
51
|
-
export const untypedLoad: PageServerEndPoint<"/posts"> = {
|
|
52
|
-
load: async () => found("/elsewhere"),
|
|
53
|
-
};
|
|
54
|
-
export type D04 = Expect<Equals<PageData<typeof untypedLoad>, Record<string, any>>>;
|
|
55
|
-
|
|
56
|
-
// The page endpoint: data keys are checked against Data
|
|
57
|
-
export const page: PageEndPoint<"/posts", PageData<PostsServer>> = {
|
|
58
|
-
load: async () => ok({ posts: [{ title: "Hello" }] }),
|
|
59
|
-
};
|
|
60
|
-
|
|
61
|
-
export const badPage: PageEndPoint<"/posts", PageData<PostsServer>> = {
|
|
62
|
-
// @ts-expect-error 'comments' is not part of the page's data
|
|
63
|
-
load: async () => ok({ comments: [] }),
|
|
64
|
-
};
|
|
65
|
-
|
|
66
|
-
// Untyped responses (redirects etc) are always allowed
|
|
67
|
-
export const redirecting: PageEndPoint<"/posts", PageData<PostsServer>> = {
|
|
68
|
-
load: async () => found("/elsewhere"),
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
// Loads with no return are allowed
|
|
72
|
-
export const silent: PageEndPoint<"/posts", PageData<PostsServer>> = {
|
|
73
|
-
load: async () => {},
|
|
74
|
-
};
|
|
75
|
-
|
|
76
|
-
// Server endpoints are checked the same way
|
|
77
|
-
export const checkedServer: PageServerEndPoint<"/posts", { posts: Post[] }> = {
|
|
78
|
-
load: async () => ok({ posts: [{ title: "Hello" }] }),
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
export const badServer: PageServerEndPoint<"/posts", { posts: Post[] }> = {
|
|
82
|
-
// @ts-expect-error wrong data shape is flagged on the server endpoint too
|
|
83
|
-
load: async () => ok({ posts: "not an array" }),
|
|
84
|
-
};
|
|
85
|
-
|
|
86
|
-
// PageProps: the shape page components receive
|
|
87
|
-
const props: PageProps<PageData<PostsServer>> = null as never;
|
|
88
|
-
export const posts: { title: string }[] = props.data.posts;
|
|
89
|
-
export const form: Record<string, any> | undefined = props.form;
|
|
90
|
-
|
|
91
|
-
// --- Layout data ---
|
|
92
|
-
|
|
93
|
-
// A layout endpoint with its own typed load
|
|
94
|
-
interface LayoutServer {
|
|
95
|
-
load: () => Promise<TypedResponse<{ user: { name: string } }>>;
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
export const layoutServer: LayoutServer = {
|
|
99
|
-
load: async () => ok({ user: { name: "Andrew" } }),
|
|
100
|
-
};
|
|
101
|
-
|
|
102
|
-
// MergePageData intersects layout and page data, in order
|
|
103
|
-
export type M01 = Expect<
|
|
104
|
-
Equals<
|
|
105
|
-
MergePageData<[typeof layoutServer, PostsServer]>,
|
|
106
|
-
{ user: { name: string } } & { posts: { title: string }[] }
|
|
107
|
-
>
|
|
108
|
-
>;
|
|
109
|
-
|
|
110
|
-
// A single endpoint merges to its own data
|
|
111
|
-
export type M02 = Expect<Equals<MergePageData<[PostsServer]>, { posts: { title: string }[] }>>;
|
|
112
|
-
|
|
113
|
-
// The merged shape is what the page component receives as $props.data
|
|
114
|
-
const mergedProps: PageProps<MergePageData<[typeof layoutServer, PostsServer]>> = null as never;
|
|
115
|
-
export const userName: string = mergedProps.data.user.name;
|
|
116
|
-
export const mergedPosts: { title: string }[] = mergedProps.data.posts;
|
|
117
|
-
|
|
118
|
-
// Endpoints without a typed load contribute only looseness
|
|
119
|
-
const looseProps: PageProps<MergePageData<[typeof actionsOnly, PostsServer]>> = null as never;
|
|
120
|
-
export const loosePosts: { title: string }[] = looseProps.data.posts;
|
|
121
|
-
|
|
122
|
-
// --- Client load events ---
|
|
123
|
-
|
|
124
|
-
// event.data is typed by the second annotation, e.g. the layout's data
|
|
125
|
-
export const clientLoad = (event: PageLoadEvent<"/posts", PageData<typeof layoutServer>>): void =>
|
|
126
|
-
void event.data.user.name;
|
|
127
|
-
|
|
128
|
-
// 'nope' is not part of the accumulated layout data
|
|
129
|
-
export const badClientLoad = (
|
|
130
|
-
event: PageLoadEvent<"/posts", PageData<typeof layoutServer>>,
|
|
131
|
-
): void =>
|
|
132
|
-
// @ts-expect-error 'nope' is not part of the accumulated layout data
|
|
133
|
-
void event.data.nope;
|
|
134
|
-
|
|
135
|
-
// Without a data annotation it stays loose
|
|
136
|
-
export const looseClientLoad = (event: PageLoadEvent<"/posts">): void => void event.data.whatever;
|
package/src/types/PageData.ts
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
import type TypedResponse from "../response/TypedResponse";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* The page data produced by an endpoint's `load` function, e.g.
|
|
5
|
-
*
|
|
6
|
-
* ```ts
|
|
7
|
-
* import type server from "./+page.server";
|
|
8
|
-
* type Data = PageData<typeof server>;
|
|
9
|
-
* ```
|
|
10
|
-
*
|
|
11
|
-
* Falls back to a loose record when the endpoint has no load or its load
|
|
12
|
-
* returns untyped responses.
|
|
13
|
-
*/
|
|
14
|
-
export type PageData<EndPoint> = EndPoint extends { load?: (event: any) => infer Return }
|
|
15
|
-
? NonNullable<Awaited<Return>> extends TypedResponse<infer Body>
|
|
16
|
-
? Body
|
|
17
|
-
: Record<string, any>
|
|
18
|
-
: Record<string, any>;
|
|
19
|
-
|
|
20
|
-
/**
|
|
21
|
-
* The merged page data for a page that sits under one or more layouts: pass
|
|
22
|
-
* the layout endpoints first and the page endpoint last, e.g.
|
|
23
|
-
*
|
|
24
|
-
* ```ts
|
|
25
|
-
* import type layoutServer from "../_layout.server";
|
|
26
|
-
* import type server from "./+page.server";
|
|
27
|
-
* type Data = MergePageData<typeof layoutServer, typeof server>;
|
|
28
|
-
* ```
|
|
29
|
-
*
|
|
30
|
-
* Each endpoint's data is intersected in order; endpoints without a typed
|
|
31
|
-
* `load` contribute nothing but looseness.
|
|
32
|
-
*/
|
|
33
|
-
export type MergePageData<EndPoints extends any[]> = EndPoints extends [infer First, ...infer Rest]
|
|
34
|
-
? PageData<First> & MergePageData<Rest>
|
|
35
|
-
: unknown;
|
|
@@ -1,55 +0,0 @@
|
|
|
1
|
-
import { type Component } from "@torpor/view";
|
|
2
|
-
import type { ExactRouteParams, ParseRouteParams, RouteParamsOf } from "./ParseRouteParams";
|
|
3
|
-
import type PageLoadEvent from "./PageLoadEvent";
|
|
4
|
-
import type { PageLoadReturn } from "./PageLoadReturn";
|
|
5
|
-
|
|
6
|
-
/**
|
|
7
|
-
* For +page. Annotate with a route path to get typed params, and with a data
|
|
8
|
-
* shape to flag loads that return keys the page doesn't expect, e.g.
|
|
9
|
-
* `PageEndPoint<"/posts/[id]", PageData<typeof server>>`.
|
|
10
|
-
*/
|
|
11
|
-
export default interface PageEndPoint<
|
|
12
|
-
Route extends string | undefined = undefined,
|
|
13
|
-
Data = Record<string, any>,
|
|
14
|
-
> {
|
|
15
|
-
/**
|
|
16
|
-
* Builds the route path for the page in a type-safe manner. The params
|
|
17
|
-
* object is checked for exact keys when `Route` is annotated.
|
|
18
|
-
*
|
|
19
|
-
* NOTE: The rest args conditional must stay INLINE — routing it through a
|
|
20
|
-
* type alias defeats `Params` inference, and excess keys stop being checked
|
|
21
|
-
*/
|
|
22
|
-
route?: <Params extends RouteParamsOf<Route>>(
|
|
23
|
-
...args: Route extends string
|
|
24
|
-
? string extends Route
|
|
25
|
-
? [params?: Record<string, string>]
|
|
26
|
-
: keyof ParseRouteParams<Route> extends never
|
|
27
|
-
? []
|
|
28
|
-
: [params: Params & ExactRouteParams<Params, ParseRouteParams<Route>>]
|
|
29
|
-
: [params?: Record<string, string>]
|
|
30
|
-
) => string;
|
|
31
|
-
/**
|
|
32
|
-
* Loads data for the page.
|
|
33
|
-
*/
|
|
34
|
-
load?: (event: PageLoadEvent<Route>) => PageLoadReturn<Data> | Promise<PageLoadReturn<Data>>;
|
|
35
|
-
/**
|
|
36
|
-
* The component that is displayed for the page.
|
|
37
|
-
*/
|
|
38
|
-
component?: Component;
|
|
39
|
-
// TODO: Better typing
|
|
40
|
-
/**
|
|
41
|
-
* The head element data for the page, which may include a <title> and <meta> elements.
|
|
42
|
-
*/
|
|
43
|
-
head?: HeadElement[] | ((event: PageLoadEvent<Route>) => HeadElement[]);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
type HeadElement = TitleElement | MetaElement;
|
|
47
|
-
|
|
48
|
-
interface TitleElement {
|
|
49
|
-
title: string;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
interface MetaElement {
|
|
53
|
-
name: string;
|
|
54
|
-
content: string;
|
|
55
|
-
}
|
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import badRequest from "../response/badRequest";
|
|
2
|
-
import ok from "../response/ok";
|
|
3
|
-
import type TypedResponse from "../response/TypedResponse";
|
|
4
|
-
import type { PageData } from "./PageData";
|
|
5
|
-
import type { PageForm } from "./PageForm";
|
|
6
|
-
import type PageProps from "./PageProps";
|
|
7
|
-
import type PageServerEndPoint from "./PageServerEndPoint";
|
|
8
|
-
|
|
9
|
-
type Equals<A, B> =
|
|
10
|
-
(<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? true : false;
|
|
11
|
-
type Expect<T extends true> = T;
|
|
12
|
-
|
|
13
|
-
// The docs-site form pattern: ok for success, badRequest for validation errors
|
|
14
|
-
interface FormServer {
|
|
15
|
-
actions: {
|
|
16
|
-
default: () => Promise<TypedResponse<{ ok: true } | { ok: false; message: string }>>;
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export const formServer: FormServer = {
|
|
21
|
-
actions: {
|
|
22
|
-
default: async () =>
|
|
23
|
-
Math.random() > 0.5
|
|
24
|
-
? ok({ ok: true as const })
|
|
25
|
-
: badRequest({ ok: false as const, message: "bad text" }),
|
|
26
|
-
},
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
// The shape above is a valid +page.server endpoint
|
|
30
|
-
export const formServerCompat: PageServerEndPoint<"/form"> = formServer;
|
|
31
|
-
|
|
32
|
-
// PageForm extracts the union of action result bodies
|
|
33
|
-
export type F01 = Expect<
|
|
34
|
-
Equals<PageForm<FormServer>, { ok: true } | { ok: false; message: string }>
|
|
35
|
-
>;
|
|
36
|
-
|
|
37
|
-
// PageProps carries data and form together
|
|
38
|
-
const props: PageProps<PageData<FormServer>, PageForm<FormServer>> = null as never;
|
|
39
|
-
const form = props.form;
|
|
40
|
-
export const okValue: boolean | undefined = form?.ok;
|
|
41
|
-
export const message: string = form && form.ok === false ? form.message : "";
|
|
42
|
-
|
|
43
|
-
// badRequest bodies are typed and Jsonify'd
|
|
44
|
-
export const bad: TypedResponse<{ ok: false; message: string }> = badRequest({
|
|
45
|
-
ok: false,
|
|
46
|
-
message: "bad text",
|
|
47
|
-
});
|
|
48
|
-
export const untypedBad: Response = badRequest("plain");
|
|
49
|
-
|
|
50
|
-
// Endpoints without actions fall back to a loose record
|
|
51
|
-
interface LoadOnly {
|
|
52
|
-
load: () => Promise<TypedResponse<{ posts: { title: string }[] }>>;
|
|
53
|
-
}
|
|
54
|
-
export type F02 = Expect<Equals<PageForm<LoadOnly>, Record<string, any>>>;
|
|
55
|
-
|
|
56
|
-
// Annotated (widened) endpoints fall back to a loose record
|
|
57
|
-
export const widened: PageServerEndPoint<"/form"> = {
|
|
58
|
-
actions: { default: async () => ok({ ok: true }) },
|
|
59
|
-
};
|
|
60
|
-
export type F03 = Expect<Equals<PageForm<typeof widened>, Record<string, any>>>;
|
|
61
|
-
|
|
62
|
-
// Multiple actions union their bodies
|
|
63
|
-
interface MultiServer {
|
|
64
|
-
actions: {
|
|
65
|
-
save: () => Promise<TypedResponse<{ saved: true }>>;
|
|
66
|
-
remove: () => Promise<TypedResponse<{ removed: true }>>;
|
|
67
|
-
};
|
|
68
|
-
}
|
|
69
|
-
export type F04 = Expect<Equals<PageForm<MultiServer>, { saved: true } | { removed: true }>>;
|
|
70
|
-
|
|
71
|
-
// Mixed typed and untyped action returns fall back to a loose record
|
|
72
|
-
interface MixedServer {
|
|
73
|
-
actions: {
|
|
74
|
-
save: () => Promise<TypedResponse<{ saved: true }>>;
|
|
75
|
-
other: () => Promise<Response>;
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
export type F05 = Expect<Equals<PageForm<MixedServer>, Record<string, any>>>;
|
package/src/types/PageForm.ts
DELETED
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type TypedResponse from "../response/TypedResponse";
|
|
2
|
-
|
|
3
|
-
/** The non-undefined return values of an endpoint's actions. */
|
|
4
|
-
type ActionReturns<Actions> = {
|
|
5
|
-
[K in keyof Actions]: Actions[K] extends (event: any) => infer Return
|
|
6
|
-
? NonNullable<Awaited<Return>>
|
|
7
|
-
: never;
|
|
8
|
-
}[keyof Actions];
|
|
9
|
-
|
|
10
|
-
/**
|
|
11
|
-
* The form result an endpoint's actions produce, i.e. what becomes the page's
|
|
12
|
-
* `$props.form` after a submit, e.g.
|
|
13
|
-
*
|
|
14
|
-
* ```ts
|
|
15
|
-
* import type server from "./+page.server";
|
|
16
|
-
* type Form = PageForm<typeof server>;
|
|
17
|
-
* ```
|
|
18
|
-
*
|
|
19
|
-
* Actions returning typed responses (e.g. `ok({ ... })`, `badRequest({ ... })`)
|
|
20
|
-
* contribute their JSON bodies as a union. Falls back to a loose record when
|
|
21
|
-
* there are no actions or their responses are untyped.
|
|
22
|
-
*/
|
|
23
|
-
export type PageForm<EndPoint> = EndPoint extends { actions?: infer Actions }
|
|
24
|
-
? [NonNullable<Actions>] extends [never]
|
|
25
|
-
? Record<string, any>
|
|
26
|
-
: ActionReturns<NonNullable<Actions>> extends TypedResponse<infer Body>
|
|
27
|
-
? Body
|
|
28
|
-
: Record<string, any>
|
|
29
|
-
: Record<string, any>;
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import type { RouteParamsOf } from "./ParseRouteParams";
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* The event passed to client load functions. Annotate with a route path to
|
|
5
|
-
* get typed params, e.g. `PageLoadEvent<"/posts/[id]">`, and with a data type
|
|
6
|
-
* to type the data accumulated from the layouts above, e.g.
|
|
7
|
-
* `PageLoadEvent<"/posts/[id]", PageData<typeof layoutServer>>`.
|
|
8
|
-
*/
|
|
9
|
-
export default interface PageLoadEvent<
|
|
10
|
-
Route extends string | undefined = undefined,
|
|
11
|
-
Data = Record<string, any>,
|
|
12
|
-
> {
|
|
13
|
-
/**
|
|
14
|
-
* The URL for the server function.
|
|
15
|
-
*/
|
|
16
|
-
url: URL;
|
|
17
|
-
/**
|
|
18
|
-
* Route params from the URL and route path.
|
|
19
|
-
*/
|
|
20
|
-
params: RouteParamsOf<Route>;
|
|
21
|
-
/**
|
|
22
|
-
* Data loaded by the layouts above, accumulated top down. Loads may add to
|
|
23
|
-
* it, and the merged result is passed into the page as `$props.data`.
|
|
24
|
-
*/
|
|
25
|
-
data: Data;
|
|
26
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type TypedResponse from "../response/TypedResponse";
|
|
2
|
-
import type { UntypedResponse } from "../response/TypedResponse";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* What a load function may return. When `Data` is provided, a typed response
|
|
6
|
-
* (e.g. `ok({ ... })`) must only contain keys the page expects; untyped
|
|
7
|
-
* responses (redirects, errors, plain text) are always allowed.
|
|
8
|
-
*/
|
|
9
|
-
export type PageLoadReturn<Data> =
|
|
10
|
-
| TypedResponse<Partial<Data>>
|
|
11
|
-
| UntypedResponse
|
|
12
|
-
| undefined
|
|
13
|
-
| void;
|
package/src/types/PageProps.ts
DELETED
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* The props passed to a page (or layout) component: the data accumulated from
|
|
3
|
-
* load functions, plus the result of the last form action if any.
|
|
4
|
-
*/
|
|
5
|
-
export default interface PageProps<Data = Record<string, any>, Form = Record<string, any>> {
|
|
6
|
-
/**
|
|
7
|
-
* Data loaded by the page's (and its layouts') load functions.
|
|
8
|
-
*/
|
|
9
|
-
data: Data;
|
|
10
|
-
/**
|
|
11
|
-
* The JSON result of the last form action, if a form was submitted.
|
|
12
|
-
*/
|
|
13
|
-
form: Form | undefined;
|
|
14
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import type { RouteParamsOf } from "./ParseRouteParams";
|
|
2
|
-
import type { FormDataRecord, QueryRecord } from "./ServerLoadEvent";
|
|
3
|
-
import type ServerLoadEvent from "./ServerLoadEvent";
|
|
4
|
-
|
|
5
|
-
type PageServerAction<
|
|
6
|
-
Route extends string | undefined = undefined,
|
|
7
|
-
FormBody = FormDataRecord,
|
|
8
|
-
Params = RouteParamsOf<Route>,
|
|
9
|
-
> = (
|
|
10
|
-
event: ServerLoadEvent<Route, unknown, FormBody, QueryRecord, Params>,
|
|
11
|
-
) => Response | undefined | void | Promise<Response | undefined | void>;
|
|
12
|
-
|
|
13
|
-
export default PageServerAction;
|
|
@@ -1,105 +0,0 @@
|
|
|
1
|
-
import ok from "../response/ok";
|
|
2
|
-
import type {
|
|
3
|
-
ActionBody,
|
|
4
|
-
LoadParams,
|
|
5
|
-
LoadQuery,
|
|
6
|
-
PageServerActionSchemas,
|
|
7
|
-
} from "./PageServerEndPoint";
|
|
8
|
-
import type PageServerEndPoint from "./PageServerEndPoint";
|
|
9
|
-
import type { StandardSchemaV1 } from "./StandardSchema";
|
|
10
|
-
|
|
11
|
-
type Equals<A, B> =
|
|
12
|
-
(<T>() => T extends A ? 1 : 2) extends <T>() => T extends B ? 1 : 2 ? true : false;
|
|
13
|
-
type Expect<T extends true> = T;
|
|
14
|
-
|
|
15
|
-
// A mock schema library's schema, with input and output types
|
|
16
|
-
declare const postSchema: StandardSchemaV1<{ title: string }, { title: string; upper: string }>;
|
|
17
|
-
declare const querySchema: StandardSchemaV1<{ page: string }, { page: number }>;
|
|
18
|
-
declare const paramsSchema: StandardSchemaV1<{ id: string }, { id: number }>;
|
|
19
|
-
|
|
20
|
-
const schemas: { default: typeof postSchema } = { default: postSchema };
|
|
21
|
-
|
|
22
|
-
// An endpoint declaring a schema for its default action. The `.upper` access
|
|
23
|
-
// below compiles only when form() is contextually typed from the schema's
|
|
24
|
-
// output, since actions map their body to their schema's key
|
|
25
|
-
export const endPoint: PageServerEndPoint<"/form", Record<string, any>, typeof schemas> = {
|
|
26
|
-
schema: schemas,
|
|
27
|
-
actions: {
|
|
28
|
-
default: async ({ form }) => ok({ title: (await form()).upper }),
|
|
29
|
-
},
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
// The type helpers behind the load/action signatures
|
|
33
|
-
export type A01 = Expect<
|
|
34
|
-
Equals<ActionBody<typeof schemas, "default">, { title: string; upper: string }>
|
|
35
|
-
>;
|
|
36
|
-
export type A02 = Expect<
|
|
37
|
-
Equals<
|
|
38
|
-
ActionBody<typeof schemas, "missing">,
|
|
39
|
-
Record<string, FormDataEntryValue | FormDataEntryValue[]>
|
|
40
|
-
>
|
|
41
|
-
>;
|
|
42
|
-
export type A03 = Expect<
|
|
43
|
-
Equals<
|
|
44
|
-
ActionBody<PageServerActionSchemas, "default">,
|
|
45
|
-
Record<string, FormDataEntryValue | FormDataEntryValue[]>
|
|
46
|
-
>
|
|
47
|
-
>;
|
|
48
|
-
|
|
49
|
-
// The load function's schema (the `load` key) types the query string
|
|
50
|
-
const querySchemas: { load: typeof querySchema } = { load: querySchema };
|
|
51
|
-
export type A04 = Expect<Equals<LoadQuery<typeof querySchemas>, { page: number }>>;
|
|
52
|
-
export type A05 = Expect<
|
|
53
|
-
Equals<LoadQuery<PageServerActionSchemas>, Record<string, string | string[]>>
|
|
54
|
-
>;
|
|
55
|
-
|
|
56
|
-
// The `params` key types the params of the load function and actions
|
|
57
|
-
const paramSchemas: { params: typeof paramsSchema } = { params: paramsSchema };
|
|
58
|
-
export type A06 = Expect<Equals<LoadParams<typeof paramSchemas, "/posts/[id]">, { id: number }>>;
|
|
59
|
-
export type A07 = Expect<
|
|
60
|
-
Equals<LoadParams<PageServerActionSchemas, "/posts/[id]">, { id: string }>
|
|
61
|
-
>;
|
|
62
|
-
|
|
63
|
-
// An endpoint using all of them: the `page` access below compiles only when
|
|
64
|
-
// the load's query is typed from its schema
|
|
65
|
-
export const fullEndPoint: PageServerEndPoint<
|
|
66
|
-
"/posts/[id]",
|
|
67
|
-
Record<string, any>,
|
|
68
|
-
{ params: typeof paramsSchema; load: typeof querySchema; default: typeof postSchema }
|
|
69
|
-
> = {
|
|
70
|
-
schema: {
|
|
71
|
-
params: paramsSchema,
|
|
72
|
-
load: querySchema,
|
|
73
|
-
default: postSchema,
|
|
74
|
-
},
|
|
75
|
-
load: async ({ params, query }) => ok({ id: params.id, page: (await query()).page }),
|
|
76
|
-
actions: {
|
|
77
|
-
default: async ({ params, form }) => ok({ id: params.id, title: (await form()).upper }),
|
|
78
|
-
},
|
|
79
|
-
};
|
|
80
|
-
|
|
81
|
-
// An untyped action keeps the loose form record and string params
|
|
82
|
-
type PlainAction = NonNullable<NonNullable<typeof plainEndPoint.actions>["default"]>;
|
|
83
|
-
const plainEndPoint: PageServerEndPoint<"/form"> = {
|
|
84
|
-
actions: {
|
|
85
|
-
default: async ({ form }) => ok({ title: (await form()).title }),
|
|
86
|
-
},
|
|
87
|
-
};
|
|
88
|
-
type PlainEvent = Parameters<PlainAction>[0];
|
|
89
|
-
export type A08 = Expect<
|
|
90
|
-
Equals<
|
|
91
|
-
Awaited<ReturnType<PlainEvent["form"]>>,
|
|
92
|
-
Record<string, FormDataEntryValue | FormDataEntryValue[]>
|
|
93
|
-
>
|
|
94
|
-
>;
|
|
95
|
-
|
|
96
|
-
// Typed ok() bodies still flow through actions (PageForm's source)
|
|
97
|
-
type DefaultReturn = Awaited<
|
|
98
|
-
ReturnType<NonNullable<NonNullable<typeof endPoint.actions>["default"]>>
|
|
99
|
-
>;
|
|
100
|
-
export type A09 = Expect<Equals<DefaultReturn, Response | undefined | void>>;
|
|
101
|
-
|
|
102
|
-
// The schema property is optional, as before
|
|
103
|
-
export type A10 = Expect<
|
|
104
|
-
Equals<PageServerEndPoint extends { schema?: unknown } ? true : false, true>
|
|
105
|
-
>;
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import type { RouteParamsOf } from "./ParseRouteParams";
|
|
2
|
-
import type PageServerAction from "./PageServerAction";
|
|
3
|
-
import type PageServerLoad from "./PageServerLoad";
|
|
4
|
-
import type { FormDataRecord, QueryRecord } from "./ServerLoadEvent";
|
|
5
|
-
import type { StandardSchemaV1 } from "./StandardSchema";
|
|
6
|
-
|
|
7
|
-
/**
|
|
8
|
-
* Optional standard schemas for +page.server endpoints, keyed by name. Any
|
|
9
|
-
* schema implementing the Standard Schema interface (zod, valibot, arktype,
|
|
10
|
-
* etc) can be used.
|
|
11
|
-
*
|
|
12
|
-
* - action name schemas validate the submitted form data, surfaced through
|
|
13
|
-
* `event.form()` in the action
|
|
14
|
-
* - the `load` key validates the URL's query string, surfaced through
|
|
15
|
-
* `event.query()` in the load function
|
|
16
|
-
* - a `params` key validates (and generally coerces) the route params,
|
|
17
|
-
* surfaced through `event.params` in the load function and actions
|
|
18
|
-
*
|
|
19
|
-
* When a submitted form or query string fails validation, the action or load
|
|
20
|
-
* function is not called and a 422 response with the schema's issues is
|
|
21
|
-
* returned (which becomes the page's `$props.form` for actions). When route
|
|
22
|
-
* params fail validation, a 404 response is returned, since the URL can't
|
|
23
|
-
* refer to an existing resource.
|
|
24
|
-
*/
|
|
25
|
-
export type PageServerActionSchemas = {
|
|
26
|
-
params?: StandardSchemaV1;
|
|
27
|
-
load?: StandardSchemaV1;
|
|
28
|
-
[action: string]: StandardSchemaV1 | undefined;
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* The form values type for an action, inferred from its schema. Falls back
|
|
33
|
-
* to a loose record for actions without a declared schema.
|
|
34
|
-
*/
|
|
35
|
-
export type ActionBody<Schemas extends PageServerActionSchemas, Name extends string> = [
|
|
36
|
-
Name,
|
|
37
|
-
] extends [keyof Schemas & string]
|
|
38
|
-
? Schemas[Name] extends StandardSchemaV1
|
|
39
|
-
? StandardSchemaV1.InferOutput<Schemas[Name]>
|
|
40
|
-
: FormDataRecord
|
|
41
|
-
: FormDataRecord;
|
|
42
|
-
|
|
43
|
-
/**
|
|
44
|
-
* The query type for the load function, inferred from its schema.
|
|
45
|
-
*/
|
|
46
|
-
export type LoadQuery<Schemas extends PageServerActionSchemas> = Schemas extends {
|
|
47
|
-
load: StandardSchemaV1;
|
|
48
|
-
}
|
|
49
|
-
? StandardSchemaV1.InferOutput<Schemas["load"]>
|
|
50
|
-
: QueryRecord;
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* The route params type, inferred from the `params` schema.
|
|
54
|
-
*/
|
|
55
|
-
export type LoadParams<
|
|
56
|
-
Schemas extends PageServerActionSchemas,
|
|
57
|
-
Route extends string | undefined,
|
|
58
|
-
> = Schemas extends { params: StandardSchemaV1 }
|
|
59
|
-
? StandardSchemaV1.InferOutput<Schemas["params"]>
|
|
60
|
-
: RouteParamsOf<Route>;
|
|
61
|
-
|
|
62
|
-
/**
|
|
63
|
-
* For +page.server. Annotate with a route path to get typed params, and with
|
|
64
|
-
* a data shape to flag loads that return keys the page doesn't expect, e.g.
|
|
65
|
-
* `PageServerEndPoint<"/posts/[id]", { posts: Post[] }>`. Annotate with a
|
|
66
|
-
* schemas object to get typed (and validated) form values, query strings and
|
|
67
|
-
* params, e.g. `PageServerEndPoint<"/posts", Record<string, any>, typeof schema>`.
|
|
68
|
-
*/
|
|
69
|
-
export default interface PageServerEndPoint<
|
|
70
|
-
Route extends string | undefined = undefined,
|
|
71
|
-
Data = Record<string, any>,
|
|
72
|
-
Schemas extends PageServerActionSchemas = PageServerActionSchemas,
|
|
73
|
-
> {
|
|
74
|
-
/**
|
|
75
|
-
* Loads data from the server for a page. Its schema (the `load` key)
|
|
76
|
-
* validates the URL's query string.
|
|
77
|
-
*/
|
|
78
|
-
load?: PageServerLoad<Route, Data, LoadQuery<Schemas>, LoadParams<Schemas, Route>>;
|
|
79
|
-
/**
|
|
80
|
-
* A map of actions that can be performed on the server for a page, generally from a form submit.
|
|
81
|
-
*/
|
|
82
|
-
actions?: {
|
|
83
|
-
[Name in string]: PageServerAction<
|
|
84
|
-
Route,
|
|
85
|
-
ActionBody<Schemas, Name>,
|
|
86
|
-
LoadParams<Schemas, Route>
|
|
87
|
-
>;
|
|
88
|
-
};
|
|
89
|
-
/**
|
|
90
|
-
* Optional standard schemas for validating requests, keyed by action name
|
|
91
|
-
* (plus `load` for the query string and `params` for the route params),
|
|
92
|
-
* e.g.
|
|
93
|
-
*
|
|
94
|
-
* ```ts
|
|
95
|
-
* const schema = {
|
|
96
|
-
* params: z.object({ id: z.coerce.number() }),
|
|
97
|
-
* load: z.object({ page: z.coerce.number() }),
|
|
98
|
-
* default: z.object({ title: z.string() }),
|
|
99
|
-
* };
|
|
100
|
-
* export default {
|
|
101
|
-
* schema,
|
|
102
|
-
* load: async ({ query }) => ok(await query()),
|
|
103
|
-
* actions: {
|
|
104
|
-
* default: async ({ form }) => ok((await form()).title),
|
|
105
|
-
* },
|
|
106
|
-
* } satisfies PageServerEndPoint<"/posts/[id]", Record<string, any>, typeof schema>;
|
|
107
|
-
* ```
|
|
108
|
-
*/
|
|
109
|
-
schema?: Schemas | undefined;
|
|
110
|
-
}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import type { RouteParamsOf } from "./ParseRouteParams";
|
|
2
|
-
import type { PageLoadReturn } from "./PageLoadReturn";
|
|
3
|
-
import type { FormDataRecord, QueryRecord } from "./ServerLoadEvent";
|
|
4
|
-
import type ServerLoadEvent from "./ServerLoadEvent";
|
|
5
|
-
|
|
6
|
-
type PageServerLoad<
|
|
7
|
-
Route extends string | undefined = undefined,
|
|
8
|
-
Data = Record<string, any>,
|
|
9
|
-
QueryBody = QueryRecord,
|
|
10
|
-
Params = RouteParamsOf<Route>,
|
|
11
|
-
> = (
|
|
12
|
-
event: ServerLoadEvent<Route, unknown, FormDataRecord, QueryBody, Params>,
|
|
13
|
-
) => PageLoadReturn<Data> | Promise<PageLoadReturn<Data>>;
|
|
14
|
-
|
|
15
|
-
export default PageServerLoad;
|