@torpor/build 1.1.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Jsonify-Dg6gChd3.d.mts.map +1 -1
- package/dist/MiddlewareFunction-BZilnEei.d.mts +50 -0
- package/dist/MiddlewareFunction-BZilnEei.d.mts.map +1 -0
- package/dist/{Router-COdQuVUi.d.mts → Router-dAu_5PlG.d.mts} +2 -2
- package/dist/{Router-COdQuVUi.d.mts.map → Router-dAu_5PlG.d.mts.map} +1 -1
- package/dist/{Server-Dr6yqVa5.mjs → Server-CSti9cvM.mjs} +2 -2
- package/dist/Server-CSti9cvM.mjs.map +1 -0
- package/dist/{Server-Cler2w5O.d.mts → Server-qn5Ws_d0.d.mts} +3 -23
- package/dist/Server-qn5Ws_d0.d.mts.map +1 -0
- package/dist/ServerEvent-Bh9cEpro.mjs +335 -0
- package/dist/ServerEvent-Bh9cEpro.mjs.map +1 -0
- package/dist/ServerHook-BTSGfLiJ.d.mts +21 -0
- package/dist/ServerHook-BTSGfLiJ.d.mts.map +1 -0
- package/dist/{ServerHook-BlLArueW.d.mts → ServerLoadEvent-DzbxxkF8.d.mts} +13 -21
- package/dist/ServerLoadEvent-DzbxxkF8.d.mts.map +1 -0
- package/dist/SessionHelper-MaodMaLU.d.mts +148 -0
- package/dist/SessionHelper-MaodMaLU.d.mts.map +1 -0
- package/dist/{Site-CTADVh7d.d.mts → Site-CWyj0R-l.d.mts} +89 -75
- package/dist/Site-CWyj0R-l.d.mts.map +1 -0
- package/dist/{_page-4cQKs_Dn.mjs → _page-CW6SLuT4.mjs} +2 -1
- package/dist/{_page-4cQKs_Dn.mjs.map → _page-CW6SLuT4.mjs.map} +1 -1
- package/dist/basePath-DQnbHc7o.mjs +99 -0
- package/dist/basePath-DQnbHc7o.mjs.map +1 -0
- package/dist/bin/index.js +1 -1
- package/dist/clientEntry.mjs +16 -5
- package/dist/clientEntry.mjs.map +1 -1
- package/dist/dev.d.mts +2 -2
- package/dist/dev.mjs +2 -2
- package/dist/discovery.d.mts +43 -0
- package/dist/discovery.d.mts.map +1 -0
- package/dist/discovery.mjs +72 -0
- package/dist/discovery.mjs.map +1 -0
- package/dist/env-C2SUAwAq.mjs +49 -0
- package/dist/env-C2SUAwAq.mjs.map +1 -0
- package/dist/env.d.mts +84 -0
- package/dist/env.d.mts.map +1 -0
- package/dist/env.mjs +2 -0
- package/dist/form.d.mts +14 -5
- package/dist/form.d.mts.map +1 -1
- package/dist/form.mjs +14 -4
- package/dist/form.mjs.map +1 -1
- package/dist/index.d.mts +5 -3
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +54 -0
- package/dist/index.mjs.map +1 -1
- package/dist/{load-C9RpS_4j.mjs → load-CydkUApM.mjs} +31 -20
- package/dist/load-CydkUApM.mjs.map +1 -0
- package/dist/nav.d.mts.map +1 -1
- package/dist/nav.mjs +4 -2
- 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-yIzYasNN.mjs → runOpenApi-6iKszj_5.mjs} +230 -24
- package/dist/runOpenApi-6iKszj_5.mjs.map +1 -0
- package/dist/server/Server.d.mts +1 -1
- package/dist/server/Server.mjs +1 -1
- package/dist/server.d.mts +3 -2
- package/dist/server.d.mts.map +1 -1
- package/dist/server.mjs +2 -2
- package/dist/serverEntry-CnCVNNjp.mjs +13 -0
- package/dist/serverEntry-CnCVNNjp.mjs.map +1 -0
- package/dist/{serverEntry-DVv9YI3I.d.mts → serverEntry-fj0XfTs4.d.mts} +5 -4
- package/dist/serverEntry-fj0XfTs4.d.mts.map +1 -0
- package/dist/serverEntry.d.mts +2 -2
- package/dist/serverEntry.mjs +2 -2
- package/dist/{serverHandlers-DeL1qZJa.mjs → serverHandlers-B6EcNfBP.mjs} +100 -28
- package/dist/serverHandlers-B6EcNfBP.mjs.map +1 -0
- package/dist/sitemap-4imxJVrG.mjs +30 -0
- package/dist/sitemap-4imxJVrG.mjs.map +1 -0
- package/dist/sitemap-BjqN4d4W.d.mts +112 -0
- package/dist/sitemap-BjqN4d4W.d.mts.map +1 -0
- package/dist/state.d.mts +6 -0
- package/dist/state.d.mts.map +1 -1
- package/dist/state.mjs +1 -1
- package/dist/test.d.mts +2 -2
- package/dist/test.mjs +2 -2
- package/package.json +11 -3
- package/src/types/manifest.d.ts +3 -0
- package/dist/Server-Cler2w5O.d.mts.map +0 -1
- package/dist/Server-Dr6yqVa5.mjs.map +0 -1
- package/dist/ServerEvent-CTx3Q-hk.d.mts +0 -48
- package/dist/ServerEvent-CTx3Q-hk.d.mts.map +0 -1
- package/dist/ServerEvent-gmOvC_Yf.mjs +0 -100
- package/dist/ServerEvent-gmOvC_Yf.mjs.map +0 -1
- package/dist/ServerHook-BlLArueW.d.mts.map +0 -1
- package/dist/Site-CTADVh7d.d.mts.map +0 -1
- package/dist/load-C9RpS_4j.mjs.map +0 -1
- package/dist/runOpenApi-yIzYasNN.mjs.map +0 -1
- package/dist/serverEntry-DVv9YI3I.d.mts.map +0 -1
- package/dist/serverEntry-LyB5pl0E.mjs +0 -11
- package/dist/serverEntry-LyB5pl0E.mjs.map +0 -1
- package/dist/serverHandlers-DeL1qZJa.mjs.map +0 -1
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { SerializeOptions } from "cookie";
|
|
2
|
+
//#region src/server/CookieHelper.d.ts
|
|
3
|
+
declare class CookieHelper {
|
|
4
|
+
request: Request;
|
|
5
|
+
cookies: Map<string, string>;
|
|
6
|
+
constructor(request: Request);
|
|
7
|
+
get(name: string): string | undefined;
|
|
8
|
+
set(name: string, value: string, options?: SerializeOptions): void;
|
|
9
|
+
delete(name: string, options?: SerializeOptions): void;
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
//#region src/server/FlashHelper.d.ts
|
|
13
|
+
/**
|
|
14
|
+
* A one-time values store set in a form action and shown on the next page
|
|
15
|
+
* render, which survives the redirect. Available as `event.flash`; the
|
|
16
|
+
* framework reads it into `$page.flash` when a page is rendered, so
|
|
17
|
+
* components display it reactively:
|
|
18
|
+
*
|
|
19
|
+
* ```ts
|
|
20
|
+
* actions: {
|
|
21
|
+
* save: async (event) => {
|
|
22
|
+
* // ...save...
|
|
23
|
+
* event.flash.set("Project saved"); // { message: "Project saved" }
|
|
24
|
+
* event.flash.set({ error: "Import failed", retryable: true });
|
|
25
|
+
* return seeOther(`/projects/${id}`);
|
|
26
|
+
* },
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* ```torp
|
|
31
|
+
* @if ($page.flash?.message) {
|
|
32
|
+
* <p class="flash">{$page.flash.message}</p>
|
|
33
|
+
* }
|
|
34
|
+
* ```
|
|
35
|
+
*
|
|
36
|
+
* The values ride in a (session-lifetime) cookie that is deleted when it is
|
|
37
|
+
* read, so a page refresh shows them once. No signing: the only person who
|
|
38
|
+
* can fake a flash is the one seeing it, and values are rendered as text.
|
|
39
|
+
* They must be JSON-safe and small enough to fit in the cookie (~4KB). A
|
|
40
|
+
* common shape for a styled banner is `{ type, message }`, for use e.g.
|
|
41
|
+
* with the Notification component -- but the framework only requires the
|
|
42
|
+
* values to be an object. Without cookies the message is simply lost --
|
|
43
|
+
* the action itself still completes.
|
|
44
|
+
*/
|
|
45
|
+
declare class FlashHelper {
|
|
46
|
+
#private;
|
|
47
|
+
constructor(cookies: CookieHelper);
|
|
48
|
+
/**
|
|
49
|
+
* Reads the flash values, if any, and clears them: the same response
|
|
50
|
+
* deletes the cookie, so the message shows exactly once. (When the
|
|
51
|
+
* message was set during this same request, e.g. a form action that
|
|
52
|
+
* re-renders instead of redirecting, the cookie is consumed without it
|
|
53
|
+
* ever reaching the browser.)
|
|
54
|
+
*/
|
|
55
|
+
get(): Record<string, unknown> | undefined;
|
|
56
|
+
/**
|
|
57
|
+
* Sets the flash values. A string is stored as `{ message: value }`, an
|
|
58
|
+
* object as-is, e.g. `flash.set({ error: "Import failed" })`.
|
|
59
|
+
*/
|
|
60
|
+
set(value: string | Record<string, unknown>): void;
|
|
61
|
+
/**
|
|
62
|
+
* Clears an unread flash message, e.g. so it isn't shown on a later
|
|
63
|
+
* re-render of the same page.
|
|
64
|
+
*/
|
|
65
|
+
clear(): void;
|
|
66
|
+
}
|
|
67
|
+
//#endregion
|
|
68
|
+
//#region src/server/HeaderHelper.d.ts
|
|
69
|
+
declare class HeaderHelper {
|
|
70
|
+
request: Request;
|
|
71
|
+
headers: Map<string, string>;
|
|
72
|
+
constructor(request: Request);
|
|
73
|
+
get(name: string): string | undefined;
|
|
74
|
+
set(name: string, value: string): void;
|
|
75
|
+
delete(name: string): void;
|
|
76
|
+
}
|
|
77
|
+
//#endregion
|
|
78
|
+
//#region src/server/SessionHelper.d.ts
|
|
79
|
+
/**
|
|
80
|
+
* The data stored in the session. Must be JSON-safe, and small enough to
|
|
81
|
+
* fit in a cookie (4KB) along with the id, expiry and signature.
|
|
82
|
+
*/
|
|
83
|
+
type SessionData = Record<string, unknown>;
|
|
84
|
+
/**
|
|
85
|
+
* A helper for reading and writing the signed session cookie, available as
|
|
86
|
+
* `event.session` in load functions, actions, +server endpoints and hooks.
|
|
87
|
+
*
|
|
88
|
+
* The value is signed with HMAC-SHA256 using `TORPOR_SESSION_SECRET` from
|
|
89
|
+
* the environment, so it can't be forged or tampered with -- but it is
|
|
90
|
+
* still client-side storage: everything rides in the cookie, it can't be
|
|
91
|
+
* revoked individually, and it is limited to ~4KB. When you need
|
|
92
|
+
* revocation, store `session.id` in your database, check it on each
|
|
93
|
+
* authed request (e.g. in a `_hook.server.ts`), and delete the row to
|
|
94
|
+
* revoke.
|
|
95
|
+
*
|
|
96
|
+
* ```ts
|
|
97
|
+
* // Login action
|
|
98
|
+
* const user = await checkPassword(event.form());
|
|
99
|
+
* await event.session.regenerate({ userId: user.id });
|
|
100
|
+
*
|
|
101
|
+
* // Root hook
|
|
102
|
+
* const session = await event.session.get();
|
|
103
|
+
* if (session) {
|
|
104
|
+
* event.appData.user = await getUser(session.userId);
|
|
105
|
+
* }
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
declare class SessionHelper {
|
|
109
|
+
#private;
|
|
110
|
+
constructor(cookies: CookieHelper);
|
|
111
|
+
/**
|
|
112
|
+
* The id embedded in the current session cookie, or undefined when
|
|
113
|
+
* there is no valid session. Stable across `set` calls, so it can be
|
|
114
|
+
* used as a database key; `regenerate` mints a new one.
|
|
115
|
+
*/
|
|
116
|
+
get id(): string | undefined;
|
|
117
|
+
/**
|
|
118
|
+
* Reads and verifies the session, returning its data, or undefined when
|
|
119
|
+
* there is no cookie, the signature doesn't match, or the session has
|
|
120
|
+
* expired.
|
|
121
|
+
*/
|
|
122
|
+
get(): Promise<SessionData | undefined>;
|
|
123
|
+
/**
|
|
124
|
+
* Writes the session, signing the data and setting the cookie. Keeps
|
|
125
|
+
* the current session id, minting one when there isn't a valid session
|
|
126
|
+
* yet. Call `regenerate` instead when the session's identity should
|
|
127
|
+
* change (e.g. at login, to prevent session fixation).
|
|
128
|
+
*/
|
|
129
|
+
set(data: SessionData, options?: {
|
|
130
|
+
maxAge?: number;
|
|
131
|
+
}): Promise<void>;
|
|
132
|
+
/**
|
|
133
|
+
* Writes the session with a fresh id, replacing any existing one. Use
|
|
134
|
+
* it when a session's privilege level changes (login, permission
|
|
135
|
+
* upgrade), so a cookie that was set before the change can't be reused.
|
|
136
|
+
*/
|
|
137
|
+
regenerate(data?: SessionData, options?: {
|
|
138
|
+
maxAge?: number;
|
|
139
|
+
}): Promise<void>;
|
|
140
|
+
/**
|
|
141
|
+
* Deletes the session cookie. Note that a server-side record (if you
|
|
142
|
+
* keep one) must be deleted or revoked separately.
|
|
143
|
+
*/
|
|
144
|
+
destroy(): Promise<void>;
|
|
145
|
+
}
|
|
146
|
+
//#endregion
|
|
147
|
+
export { CookieHelper as i, HeaderHelper as n, FlashHelper as r, SessionHelper as t };
|
|
148
|
+
//# sourceMappingURL=SessionHelper-MaodMaLU.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SessionHelper-MaodMaLU.d.mts","names":[],"sources":["../src/server/CookieHelper.ts","../src/server/FlashHelper.ts","../src/server/HeaderHelper.ts","../src/server/SessionHelper.ts"],"mappings":";;cAEqB;EACpB,SAAS;EACT,SAAS;EAET,YAAY,SAAS;EAIrB,IAAI;EAaJ,IAAI,cAAc,eAAe,UAAU;EAU3C,OAAO,cAAc,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cCGX;;EAGpB,YAAY,SAAS;;;;;;;;EAWrB,OAAO;;;;;EAmBP,IAAI,gBAAgB;;;;;EASpB;;;;cC9EoB;EACpB,SAAS;EACT,SAAS;EAET,YAAY,SAAS;EAIrB,IAAI;EASJ,IAAI,cAAc;EAIlB,OAAO;;;;;;;;KCXH,cAAc;;;;;;;;;;;;;;;;;;;;;;;;;cAqCE;;EAIpB,YAAY,SAAS;;;;;;MASjB;;;;;;EASJ,OAAa,QAAQ;;;;;;;EAerB,IAAU,MAAM,aAAa;IAAY;MAAoB;;;;;;EAW7D,WAAiB,OAAM,aAAkB;IAAY;MAAoB;;;;;EAUzE,WAAiB"}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import { t as
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import { n as
|
|
1
|
+
import { t as MiddlewareFunction } from "./MiddlewareFunction-BZilnEei.mjs";
|
|
2
|
+
import { t as Server } from "./Server-qn5Ws_d0.mjs";
|
|
3
|
+
import { a as RouteParamsOf } from "./ParseRouteParams-DBmqlmLh.mjs";
|
|
4
|
+
import { n as QueryRecord, r as ServerLoadEvent, t as FormDataRecord } from "./ServerLoadEvent-DzbxxkF8.mjs";
|
|
5
|
+
import { t as ServerHook } from "./ServerHook-BTSGfLiJ.mjs";
|
|
6
|
+
import { a as PageLoadReturn, i as PageEndPoint, t as SitemapOptions } from "./sitemap-BjqN4d4W.mjs";
|
|
5
7
|
import { t as StandardSchemaV1 } from "./StandardSchema-D28L8_zZ.mjs";
|
|
6
|
-
import { Component } from "@torpor/view";
|
|
7
8
|
import { Plugin, UserConfig } from "vite";
|
|
8
9
|
//#region src/types/Adapter.d.ts
|
|
9
10
|
interface Adapter {
|
|
@@ -45,74 +46,6 @@ interface Adapter {
|
|
|
45
46
|
*/
|
|
46
47
|
type SitePlugin = (site: Site) => void | Promise<void>;
|
|
47
48
|
//#endregion
|
|
48
|
-
//#region src/types/PageLoadEvent.d.ts
|
|
49
|
-
/**
|
|
50
|
-
* The event passed to client load functions. Annotate with a route path to
|
|
51
|
-
* get typed params, e.g. `PageLoadEvent<"/posts/[id]">`, and with a data type
|
|
52
|
-
* to type the data accumulated from the layouts above, e.g.
|
|
53
|
-
* `PageLoadEvent<"/posts/[id]", PageData<typeof layoutServer>>`.
|
|
54
|
-
*/
|
|
55
|
-
interface PageLoadEvent<Route extends string | undefined = undefined, Data = Record<string, any>> {
|
|
56
|
-
/**
|
|
57
|
-
* The URL for the server function.
|
|
58
|
-
*/
|
|
59
|
-
url: URL;
|
|
60
|
-
/**
|
|
61
|
-
* Route params from the URL and route path.
|
|
62
|
-
*/
|
|
63
|
-
params: RouteParamsOf<Route>;
|
|
64
|
-
/**
|
|
65
|
-
* Data loaded by the layouts above, accumulated top down. Loads may add to
|
|
66
|
-
* it, and the merged result is passed into the page as `$props.data`.
|
|
67
|
-
*/
|
|
68
|
-
data: Data;
|
|
69
|
-
}
|
|
70
|
-
//#endregion
|
|
71
|
-
//#region src/types/PageLoadReturn.d.ts
|
|
72
|
-
/**
|
|
73
|
-
* What a load function may return. When `Data` is provided, a typed response
|
|
74
|
-
* (e.g. `ok({ ... })`) must only contain keys the page expects; untyped
|
|
75
|
-
* responses (redirects, errors, plain text) are always allowed.
|
|
76
|
-
*/
|
|
77
|
-
type PageLoadReturn<Data> = TypedResponse<Partial<Data>> | UntypedResponse | undefined | void;
|
|
78
|
-
//#endregion
|
|
79
|
-
//#region src/types/PageEndPoint.d.ts
|
|
80
|
-
/**
|
|
81
|
-
* For +page. Annotate with a route path to get typed params, and with a data
|
|
82
|
-
* shape to flag loads that return keys the page doesn't expect, e.g.
|
|
83
|
-
* `PageEndPoint<"/posts/[id]", PageData<typeof server>>`.
|
|
84
|
-
*/
|
|
85
|
-
interface PageEndPoint<Route extends string | undefined = undefined, Data = Record<string, any>> {
|
|
86
|
-
/**
|
|
87
|
-
* Builds the route path for the page in a type-safe manner. The params
|
|
88
|
-
* object is checked for exact keys when `Route` is annotated.
|
|
89
|
-
*
|
|
90
|
-
* NOTE: The rest args conditional must stay INLINE — routing it through a
|
|
91
|
-
* type alias defeats `Params` inference, and excess keys stop being checked
|
|
92
|
-
*/
|
|
93
|
-
route?: <Params extends RouteParamsOf<Route>>(...args: Route extends string ? string extends Route ? [params?: Record<string, string>] : keyof ParseRouteParams<Route> extends never ? [] : [params: Params & ExactRouteParams<Params, ParseRouteParams<Route>>] : [params?: Record<string, string>]) => string;
|
|
94
|
-
/**
|
|
95
|
-
* Loads data for the page.
|
|
96
|
-
*/
|
|
97
|
-
load?: (event: PageLoadEvent<Route>) => PageLoadReturn<Data> | Promise<PageLoadReturn<Data>>;
|
|
98
|
-
/**
|
|
99
|
-
* The component that is displayed for the page.
|
|
100
|
-
*/
|
|
101
|
-
component?: Component;
|
|
102
|
-
/**
|
|
103
|
-
* The head element data for the page, which may include a <title> and <meta> elements.
|
|
104
|
-
*/
|
|
105
|
-
head?: HeadElement[] | ((event: PageLoadEvent<Route>) => HeadElement[]);
|
|
106
|
-
}
|
|
107
|
-
type HeadElement = TitleElement | MetaElement;
|
|
108
|
-
interface TitleElement {
|
|
109
|
-
title: string;
|
|
110
|
-
}
|
|
111
|
-
interface MetaElement {
|
|
112
|
-
name: string;
|
|
113
|
-
content: string;
|
|
114
|
-
}
|
|
115
|
-
//#endregion
|
|
116
49
|
//#region src/types/PageServerAction.d.ts
|
|
117
50
|
type PageServerAction<Route extends string | undefined = undefined, FormBody = FormDataRecord, Params = RouteParamsOf<Route>> = (event: ServerLoadEvent<Route, unknown, FormBody, QueryRecord, Params>) => Response | undefined | void | Promise<Response | undefined | void>;
|
|
118
51
|
//#endregion
|
|
@@ -198,6 +131,26 @@ interface PageServerEndPoint<Route extends string | undefined = undefined, Data
|
|
|
198
131
|
* ```
|
|
199
132
|
*/
|
|
200
133
|
schema?: Schemas | undefined;
|
|
134
|
+
/**
|
|
135
|
+
* Marks the page for prerendering. Set `true` for a static route, or
|
|
136
|
+
* `params` entries letting `tb build` render it once per entry for a
|
|
137
|
+
* dynamic route, e.g. `prerender: { params: [{ id: "1" }] }` under
|
|
138
|
+
* `/posts/[id]`. Params are typed by the route annotation (or the
|
|
139
|
+
* `params` schema), so the entries are checked.
|
|
140
|
+
*
|
|
141
|
+
* The load function runs at build time with a synthetic request, exactly
|
|
142
|
+
* as for a real GET.
|
|
143
|
+
*/
|
|
144
|
+
prerender?: boolean | {
|
|
145
|
+
params: LoadParams<Schemas, Route>[];
|
|
146
|
+
};
|
|
147
|
+
/**
|
|
148
|
+
* Route middleware, run for this route's loads and actions after the
|
|
149
|
+
* global middleware (see `site.middleware`) and before folder hooks.
|
|
150
|
+
* `enter` may return a Response to short-circuit; `exit` hooks run in
|
|
151
|
+
* reverse. Middleware see the raw request url.
|
|
152
|
+
*/
|
|
153
|
+
middleware?: MiddlewareFunction[];
|
|
201
154
|
}
|
|
202
155
|
//#endregion
|
|
203
156
|
//#region src/types/ServerRequest.d.ts
|
|
@@ -303,6 +256,13 @@ type ServerEndPoint<Route extends string | undefined = undefined, Schemas extend
|
|
|
303
256
|
* Performs a HEAD request. Its schema validates the query string.
|
|
304
257
|
*/
|
|
305
258
|
head?: ServerRequest<Route, unknown, FormDataRecord, SchemaQuery<Schemas, "head">, ParamsOf<Schemas, Route>>;
|
|
259
|
+
/**
|
|
260
|
+
* Route middleware, run for this endpoint's handlers after the global
|
|
261
|
+
* middleware (see `site.middleware`). `enter` may return a Response to
|
|
262
|
+
* short-circuit; `exit` hooks run in reverse. Middleware see the raw
|
|
263
|
+
* request url.
|
|
264
|
+
*/
|
|
265
|
+
middleware?: MiddlewareFunction[];
|
|
306
266
|
};
|
|
307
267
|
//#endregion
|
|
308
268
|
//#region src/types/RouteType.d.ts
|
|
@@ -404,6 +364,60 @@ declare class Site {
|
|
|
404
364
|
* instances, `Symbol()` ones are not.
|
|
405
365
|
*/
|
|
406
366
|
pluginState: Map<PropertyKey, unknown>;
|
|
367
|
+
/**
|
|
368
|
+
* The path the site is mounted under, e.g. "/app". Incoming server
|
|
369
|
+
* requests that don't carry it are not found; everything the framework
|
|
370
|
+
* generates (HTML attributes, redirect locations, paths from `route()`)
|
|
371
|
+
* gets it added. Server code and markup stay base-free.
|
|
372
|
+
*/
|
|
373
|
+
basePath: string;
|
|
374
|
+
/**
|
|
375
|
+
* Prerendering, applied to every page route that doesn't have (or
|
|
376
|
+
* inherit) a `prerender` flag of its own. `true` prerenders everything;
|
|
377
|
+
* a `Record<string, boolean>` maps route paths -- exact (`/about`) or
|
|
378
|
+
* prefix (`/blog/**` for a path and everything below it) -- to flags,
|
|
379
|
+
* with the most specific matching key winning. Route endpoint and
|
|
380
|
+
* layout flags always take precedence over this.
|
|
381
|
+
*/
|
|
382
|
+
prerender?: boolean | Record<string, boolean>;
|
|
383
|
+
/**
|
|
384
|
+
* The site's absolute origin, e.g. "https://example.com". Required for
|
|
385
|
+
* a build-time sitemap (see `sitemap`), since there is no request to
|
|
386
|
+
* take the host from.
|
|
387
|
+
*/
|
|
388
|
+
origin?: string;
|
|
389
|
+
/**
|
|
390
|
+
* Global middleware, run for every request before routing -- including
|
|
391
|
+
* requests that won't match a route (maintenance mode, legacy url
|
|
392
|
+
* redirects, etc). Each middleware's `enter` runs in order and may
|
|
393
|
+
* return a Response to short-circuit the request; `exit` hooks run in
|
|
394
|
+
* reverse after the handler. Middleware see the raw request url.
|
|
395
|
+
*
|
|
396
|
+
* Route middleware (scoped to a single route) is set on the route's
|
|
397
|
+
* server endpoint instead, e.g. `middleware: [...]` in
|
|
398
|
+
* `+page.server.ts` or `+server.ts`.
|
|
399
|
+
*/
|
|
400
|
+
middleware: MiddlewareFunction[];
|
|
401
|
+
/**
|
|
402
|
+
* Writes a sitemap.xml listing the prerendered pages at build time
|
|
403
|
+
* (see `prerender`). Pass a custom path (e.g. "/blog/sitemap.xml") or
|
|
404
|
+
* `true` for "/sitemap.xml"; requires `origin` to be set.
|
|
405
|
+
*
|
|
406
|
+
* For a runtime sitemap -- one that reads the database and keeps up with
|
|
407
|
+
* content that isn't prerendered -- pass a config instead, e.g.
|
|
408
|
+
* `sitemap = { get: async () => ["/posts/a", "/posts/b"] }`, which serves
|
|
409
|
+
* the XML live at that path (customizable with `path`).
|
|
410
|
+
*/
|
|
411
|
+
sitemap?: SitemapOptions | boolean | string;
|
|
412
|
+
/**
|
|
413
|
+
* A Standard Schema (zod, valibot, arktype, etc) used to validate (and
|
|
414
|
+
* parse) the server environment. When set, `env()` from
|
|
415
|
+
* `@torpor/build/env` checks the environment on first use per request and
|
|
416
|
+
* throws with the schema's issues -- so a missing or invalid key fails
|
|
417
|
+
* immediately instead of passing `undefined` along. The schema must
|
|
418
|
+
* validate synchronously.
|
|
419
|
+
*/
|
|
420
|
+
env?: StandardSchemaV1<unknown, TorporEnv>;
|
|
407
421
|
/**
|
|
408
422
|
* Inline endpoints keyed by `"path:type"`. Populated by `addRoute` when
|
|
409
423
|
* the user passes an inline endpoint object instead of a file path.
|
|
@@ -483,5 +497,5 @@ declare class Site {
|
|
|
483
497
|
}, subFolder?: string): void;
|
|
484
498
|
}
|
|
485
499
|
//#endregion
|
|
486
|
-
export {
|
|
487
|
-
//# sourceMappingURL=Site-
|
|
500
|
+
export { ServerEndPoint as a, ActionBody as c, PageServerActionSchemas as d, PageServerEndPoint as f, Adapter as g, SitePlugin as h, SchemaQuery as i, LoadParams as l, PageServerAction as m, ParamsOf as n, ServerEndPointSchemas as o, PageServerLoad as p, SchemaBody as r, ServerRequest as s, Site as t, LoadQuery as u };
|
|
501
|
+
//# sourceMappingURL=Site-CWyj0R-l.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Site-CWyj0R-l.d.mts","names":[],"sources":["../src/types/Adapter.ts","../src/types/SitePlugin.ts","../src/types/PageServerAction.ts","../src/types/PageServerLoad.ts","../src/types/PageServerEndPoint.ts","../src/types/ServerRequest.ts","../src/types/ServerEndPoint.ts","../src/types/RouteType.ts","../src/types/Route.ts","../src/site/Site.ts"],"mappings":"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"}
|
|
@@ -5,9 +5,10 @@ const $page = globalThis[PAGE_SYMBOL] ??= $watch({
|
|
|
5
5
|
status: 404,
|
|
6
6
|
url: new URL("http://localhost"),
|
|
7
7
|
form: void 0,
|
|
8
|
+
flash: void 0,
|
|
8
9
|
error: { message: "" }
|
|
9
10
|
}, { shallow: true });
|
|
10
11
|
//#endregion
|
|
11
12
|
export { $page as t };
|
|
12
13
|
|
|
13
|
-
//# sourceMappingURL=_page-
|
|
14
|
+
//# sourceMappingURL=_page-CW6SLuT4.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"_page-
|
|
1
|
+
{"version":3,"file":"_page-CW6SLuT4.mjs","names":[],"sources":["../src/state/$page.ts"],"sourcesContent":["import { $watch } from \"@torpor/view\";\nimport type PageState from \"../types/PageState\";\n\nconst PAGE_SYMBOL: unique symbol = Symbol.for(\"torp.Page\");\n\nconst $page: PageState =\n\t// @ts-ignore\n\t(globalThis[PAGE_SYMBOL] ??=\n\t\t// The server request path uses `state/$serverPage`, which stores the\n\t\t// same state (same `globalThis` slot) without a reactive proxy\n\t\t$watch(\n\t\t\t{\n\t\t\t\tstatus: 404,\n\t\t\t\turl: new URL(\"http://localhost\"),\n\t\t\t\tform: undefined,\n\t\t\t\tflash: undefined,\n\t\t\t\terror: {\n\t\t\t\t\tmessage: \"\",\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tshallow: true,\n\t\t\t},\n\t\t));\n\nexport default $page;\n"],"mappings":";;AAGA,MAAM,cAA6B,OAAO,IAAI,WAAW;AAEzD,MAAM,QAEJ,WAAW,iBAGX,OACC;CACC,QAAQ;CACR,KAAK,IAAI,IAAI,kBAAkB;CAC/B,MAAM,KAAA;CACN,OAAO,KAAA;CACP,OAAO,EACN,SAAS,GACV;AACD,GACA,EACC,SAAS,KACV,CACD"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
//#region src/site/basePath.ts
|
|
2
|
+
/**
|
|
3
|
+
* The site's base path, e.g. "/app" when the site is mounted under a
|
|
4
|
+
* subpath. Inherited from `site.basePath` through the manifest at startup
|
|
5
|
+
* (see serverEntry and clientEntry); default "" when the site is served
|
|
6
|
+
* from the root.
|
|
7
|
+
*
|
|
8
|
+
* Server code and user markup are written base-free: the server strips the
|
|
9
|
+
* base from incoming URLs before routing (requests that don't carry it get
|
|
10
|
+
* a 404), and adds it back to generated HTML attributes, redirect
|
|
11
|
+
* locations and paths built with `route()`. The client router does the
|
|
12
|
+
* mirror image: strips for matching, adds for data fetches.
|
|
13
|
+
*/
|
|
14
|
+
let basePath = "";
|
|
15
|
+
/**
|
|
16
|
+
* Validates and sets the site's base path: must be "", start with "/" and
|
|
17
|
+
* not end with "/" (a trailing slash is stripped, "/" is normalized to "")
|
|
18
|
+
*/
|
|
19
|
+
function setBasePath(value) {
|
|
20
|
+
basePath = normalizeBasePath(value);
|
|
21
|
+
}
|
|
22
|
+
function getBasePath() {
|
|
23
|
+
return basePath;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Normalizes a base path value, throwing a descriptive error when it
|
|
27
|
+
* can't be one. Trailing slashes are stripped and "/" is normalized to "".
|
|
28
|
+
*/
|
|
29
|
+
function normalizeBasePath(value) {
|
|
30
|
+
const trimmed = (value ?? "").trim();
|
|
31
|
+
if (trimmed === "" || trimmed === "/") return "";
|
|
32
|
+
if (!trimmed.startsWith("/") || /\s/.test(trimmed)) throw new Error(`The base path must be an absolute path without spaces (e.g. "/app"), got "${value}"`);
|
|
33
|
+
return trimmed.replace(/\/+$/, "");
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Normalizes a site origin value, throwing a descriptive error when it
|
|
37
|
+
* isn't an absolute http(s) origin without a path or spaces.
|
|
38
|
+
*/
|
|
39
|
+
function normalizeOrigin(value) {
|
|
40
|
+
const trimmed = (value ?? "").trim();
|
|
41
|
+
if (trimmed === "") throw new Error(`The site origin is empty (e.g. "https://example.com")`);
|
|
42
|
+
let url;
|
|
43
|
+
try {
|
|
44
|
+
url = new URL(trimmed);
|
|
45
|
+
} catch {
|
|
46
|
+
throw new Error(`The site origin must be an absolute url (e.g. "https://example.com"), got "${value}"`);
|
|
47
|
+
}
|
|
48
|
+
if (url.protocol !== "https:" && url.protocol !== "http:" || url.pathname !== "/" || /\s/.test(trimmed)) throw new Error(`The site origin must be an http(s) url without spaces or a path (e.g. "https://example.com"), got "${value}"`);
|
|
49
|
+
return url.origin;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Strips the base from a URL's pathname, copying the URL so it can be used
|
|
53
|
+
* for routing without disturbing the request. Returns undefined when there
|
|
54
|
+
* is a base and the URL doesn't carry it -- the caller should then return
|
|
55
|
+
* a not-found response, since the site only serves requests under its
|
|
56
|
+
* mount point.
|
|
57
|
+
*/
|
|
58
|
+
function stripBaseFromUrl(url, base) {
|
|
59
|
+
const stripped = new URL(url);
|
|
60
|
+
if (!base) return stripped;
|
|
61
|
+
if (stripped.pathname === base) {
|
|
62
|
+
stripped.pathname = "/";
|
|
63
|
+
return stripped;
|
|
64
|
+
}
|
|
65
|
+
if (stripped.pathname.startsWith(base + "/")) {
|
|
66
|
+
stripped.pathname = stripped.pathname.slice(base.length) || "/";
|
|
67
|
+
return stripped;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Adds the base to an absolute path, idempotent for paths that already
|
|
72
|
+
* carry it. Relative paths ("other/page"), protocol-relative ("//...") and
|
|
73
|
+
* full URLs are left alone.
|
|
74
|
+
*/
|
|
75
|
+
function addBaseToPath(path, base) {
|
|
76
|
+
if (!base || !path.startsWith("/") || path.startsWith("//")) return path;
|
|
77
|
+
if (path === "/") return base + "/";
|
|
78
|
+
if (path === base || path.startsWith(base + "/")) return path;
|
|
79
|
+
return base + path;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Rewrites absolute-path `href`, `action` and `src` attribute values in
|
|
83
|
+
* rendered HTML, so that markup can be written base-free. Values that
|
|
84
|
+
* aren't absolute paths (relative, "//...", "http://...", "mailto:...")
|
|
85
|
+
* are left alone, as are ones that already carry the base.
|
|
86
|
+
*/
|
|
87
|
+
function rewriteBaseInHtml(html, base) {
|
|
88
|
+
if (!base) return html;
|
|
89
|
+
return html.replace(/\s(href|action|src)\s*=\s*("([^"]*)"|'([^']*)')/g, (match, name, _quoted, double, single) => {
|
|
90
|
+
const value = double ?? single ?? "";
|
|
91
|
+
const rewritten = addBaseToPath(value, base);
|
|
92
|
+
if (rewritten === value) return match;
|
|
93
|
+
return ` ${name}="${rewritten}"`;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
//#endregion
|
|
97
|
+
export { rewriteBaseInHtml as a, normalizeOrigin as i, getBasePath as n, setBasePath as o, normalizeBasePath as r, stripBaseFromUrl as s, addBaseToPath as t };
|
|
98
|
+
|
|
99
|
+
//# sourceMappingURL=basePath-DQnbHc7o.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"basePath-DQnbHc7o.mjs","names":[],"sources":["../src/site/basePath.ts"],"sourcesContent":["/**\n * The site's base path, e.g. \"/app\" when the site is mounted under a\n * subpath. Inherited from `site.basePath` through the manifest at startup\n * (see serverEntry and clientEntry); default \"\" when the site is served\n * from the root.\n *\n * Server code and user markup are written base-free: the server strips the\n * base from incoming URLs before routing (requests that don't carry it get\n * a 404), and adds it back to generated HTML attributes, redirect\n * locations and paths built with `route()`. The client router does the\n * mirror image: strips for matching, adds for data fetches.\n */\nlet basePath = \"\";\n\n/**\n * Validates and sets the site's base path: must be \"\", start with \"/\" and\n * not end with \"/\" (a trailing slash is stripped, \"/\" is normalized to \"\")\n */\nexport function setBasePath(value: string | undefined): void {\n\tbasePath = normalizeBasePath(value);\n}\n\nexport function getBasePath(): string {\n\treturn basePath;\n}\n\n/**\n * Normalizes a base path value, throwing a descriptive error when it\n * can't be one. Trailing slashes are stripped and \"/\" is normalized to \"\".\n */\nexport function normalizeBasePath(value: string | undefined): string {\n\tconst trimmed = (value ?? \"\").trim();\n\tif (trimmed === \"\" || trimmed === \"/\") return \"\";\n\tif (!trimmed.startsWith(\"/\") || /\\s/.test(trimmed)) {\n\t\tthrow new Error(\n\t\t\t`The base path must be an absolute path without spaces (e.g. \"/app\"), ` + `got \"${value}\"`,\n\t\t);\n\t}\n\treturn trimmed.replace(/\\/+$/, \"\");\n}\n\n/**\n * Normalizes a site origin value, throwing a descriptive error when it\n * isn't an absolute http(s) origin without a path or spaces.\n */\nexport function normalizeOrigin(value: string | undefined): string {\n\tconst trimmed = (value ?? \"\").trim();\n\tif (trimmed === \"\") {\n\t\tthrow new Error(`The site origin is empty (e.g. \"https://example.com\")`);\n\t}\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(trimmed);\n\t} catch {\n\t\tthrow new Error(\n\t\t\t`The site origin must be an absolute url (e.g. \"https://example.com\"), got \"${value}\"`,\n\t\t);\n\t}\n\tif (\n\t\t(url.protocol !== \"https:\" && url.protocol !== \"http:\") ||\n\t\turl.pathname !== \"/\" ||\n\t\t/\\s/.test(trimmed)\n\t) {\n\t\tthrow new Error(\n\t\t\t`The site origin must be an http(s) url without spaces or a path ` +\n\t\t\t\t`(e.g. \"https://example.com\"), got \"${value}\"`,\n\t\t);\n\t}\n\t// A trailing slash is allowed\n\treturn url.origin;\n}\n\n/**\n * Strips the base from a URL's pathname, copying the URL so it can be used\n * for routing without disturbing the request. Returns undefined when there\n * is a base and the URL doesn't carry it -- the caller should then return\n * a not-found response, since the site only serves requests under its\n * mount point.\n */\nexport function stripBaseFromUrl(url: URL, base: string): URL | undefined {\n\tconst stripped = new URL(url);\n\tif (!base) return stripped;\n\tif (stripped.pathname === base) {\n\t\tstripped.pathname = \"/\";\n\t\treturn stripped;\n\t}\n\tif (stripped.pathname.startsWith(base + \"/\")) {\n\t\tstripped.pathname = stripped.pathname.slice(base.length) || \"/\";\n\t\treturn stripped;\n\t}\n\treturn undefined;\n}\n\n/**\n * Adds the base to an absolute path, idempotent for paths that already\n * carry it. Relative paths (\"other/page\"), protocol-relative (\"//...\") and\n * full URLs are left alone.\n */\nexport function addBaseToPath(path: string, base: string): string {\n\tif (!base || !path.startsWith(\"/\") || path.startsWith(\"//\")) return path;\n\tif (path === \"/\") return base + \"/\";\n\tif (path === base || path.startsWith(base + \"/\")) return path;\n\treturn base + path;\n}\n\n/**\n * Rewrites absolute-path `href`, `action` and `src` attribute values in\n * rendered HTML, so that markup can be written base-free. Values that\n * aren't absolute paths (relative, \"//...\", \"http://...\", \"mailto:...\")\n * are left alone, as are ones that already carry the base.\n */\nexport function rewriteBaseInHtml(html: string, base: string): string {\n\tif (!base) return html;\n\treturn html.replace(\n\t\t/\\s(href|action|src)\\s*=\\s*(\"([^\"]*)\"|'([^']*)')/g,\n\t\t(match, name: string, _quoted: string, double: string, single: string) => {\n\t\t\tconst value = double ?? single ?? \"\";\n\t\t\tconst rewritten = addBaseToPath(value, base);\n\t\t\tif (rewritten === value) return match;\n\t\t\treturn ` ${name}=\"${rewritten}\"`;\n\t\t},\n\t);\n}\n"],"mappings":";;;;;;;;;;;;;AAYA,IAAI,WAAW;;;;;AAMf,SAAgB,YAAY,OAAiC;CAC5D,WAAW,kBAAkB,KAAK;AACnC;AAEA,SAAgB,cAAsB;CACrC,OAAO;AACR;;;;;AAMA,SAAgB,kBAAkB,OAAmC;CACpE,MAAM,WAAW,SAAS,GAAA,CAAI,KAAK;CACnC,IAAI,YAAY,MAAM,YAAY,KAAK,OAAO;CAC9C,IAAI,CAAC,QAAQ,WAAW,GAAG,KAAK,KAAK,KAAK,OAAO,GAChD,MAAM,IAAI,MACT,6EAAkF,MAAM,EACzF;CAED,OAAO,QAAQ,QAAQ,QAAQ,EAAE;AAClC;;;;;AAMA,SAAgB,gBAAgB,OAAmC;CAClE,MAAM,WAAW,SAAS,GAAA,CAAI,KAAK;CACnC,IAAI,YAAY,IACf,MAAM,IAAI,MAAM,uDAAuD;CAExE,IAAI;CACJ,IAAI;EACH,MAAM,IAAI,IAAI,OAAO;CACtB,QAAQ;EACP,MAAM,IAAI,MACT,8EAA8E,MAAM,EACrF;CACD;CACA,IACE,IAAI,aAAa,YAAY,IAAI,aAAa,WAC/C,IAAI,aAAa,OACjB,KAAK,KAAK,OAAO,GAEjB,MAAM,IAAI,MACT,sGACuC,MAAM,EAC9C;CAGD,OAAO,IAAI;AACZ;;;;;;;;AASA,SAAgB,iBAAiB,KAAU,MAA+B;CACzE,MAAM,WAAW,IAAI,IAAI,GAAG;CAC5B,IAAI,CAAC,MAAM,OAAO;CAClB,IAAI,SAAS,aAAa,MAAM;EAC/B,SAAS,WAAW;EACpB,OAAO;CACR;CACA,IAAI,SAAS,SAAS,WAAW,OAAO,GAAG,GAAG;EAC7C,SAAS,WAAW,SAAS,SAAS,MAAM,KAAK,MAAM,KAAK;EAC5D,OAAO;CACR;AAED;;;;;;AAOA,SAAgB,cAAc,MAAc,MAAsB;CACjE,IAAI,CAAC,QAAQ,CAAC,KAAK,WAAW,GAAG,KAAK,KAAK,WAAW,IAAI,GAAG,OAAO;CACpE,IAAI,SAAS,KAAK,OAAO,OAAO;CAChC,IAAI,SAAS,QAAQ,KAAK,WAAW,OAAO,GAAG,GAAG,OAAO;CACzD,OAAO,OAAO;AACf;;;;;;;AAQA,SAAgB,kBAAkB,MAAc,MAAsB;CACrE,IAAI,CAAC,MAAM,OAAO;CAClB,OAAO,KAAK,QACX,qDACC,OAAO,MAAc,SAAiB,QAAgB,WAAmB;EACzE,MAAM,QAAQ,UAAU,UAAU;EAClC,MAAM,YAAY,cAAc,OAAO,IAAI;EAC3C,IAAI,cAAc,OAAO,OAAO;EAChC,OAAO,IAAI,KAAK,IAAI,UAAU;CAC/B,CACD;AACD"}
|
package/dist/bin/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#! /usr/bin/env node
|
|
2
|
-
import { n as loadSite, r as run, t as runOpenApi } from "../runOpenApi-
|
|
2
|
+
import { n as loadSite, r as run, t as runOpenApi } from "../runOpenApi-6iKszj_5.mjs";
|
|
3
3
|
//#region src/bin/index.ts
|
|
4
4
|
const workingDir = process.cwd();
|
|
5
5
|
if (process.argv.includes("--openapi")) {
|
package/dist/clientEntry.mjs
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { t as Router } from "./Router-C4ADUfhv.mjs";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { o as setBasePath } from "./basePath-DQnbHc7o.mjs";
|
|
3
|
+
import { t as $page } from "./_page-CW6SLuT4.mjs";
|
|
4
|
+
import { a as client, n as navigate, r as loadData } from "./load-CydkUApM.mjs";
|
|
4
5
|
import manifest from "@torpor/build/manifest";
|
|
5
6
|
//#region src/site/clientEntry.ts
|
|
7
|
+
setBasePath(manifest.base);
|
|
6
8
|
const router = new Router();
|
|
7
9
|
router.addPages(manifest.routes);
|
|
8
10
|
client.router = router;
|
|
@@ -13,8 +15,10 @@ window.addEventListener("click", async (e) => {
|
|
|
13
15
|
e.preventDefault();
|
|
14
16
|
const href = link.href;
|
|
15
17
|
const url = new URL(href);
|
|
16
|
-
if (await navigate(url))
|
|
17
|
-
|
|
18
|
+
if (await navigate(url)) {
|
|
19
|
+
window.history.replaceState({ scroll: window.scrollY }, "", document.location.href);
|
|
20
|
+
window.history.pushState({ scroll: 0 }, "", url);
|
|
21
|
+
} else window.location.href = href;
|
|
18
22
|
}
|
|
19
23
|
});
|
|
20
24
|
window.addEventListener("mouseover", maybePrefetch);
|
|
@@ -47,7 +51,14 @@ function ignoreAnchorMouseEvent(link, e) {
|
|
|
47
51
|
return e.defaultPrevented || e.altKey || e.ctrlKey || e.metaKey || e.shiftKey || link.target && link.target !== "_self" || link.rel === "external" || link.hasAttribute("download") || link.isContentEditable;
|
|
48
52
|
}
|
|
49
53
|
window.addEventListener("popstate", async () => {
|
|
50
|
-
await navigateToLocation(document.location)
|
|
54
|
+
if (!await navigateToLocation(document.location)) {
|
|
55
|
+
window.location.reload();
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
requestAnimationFrame(() => {
|
|
59
|
+
const state = window.history.state;
|
|
60
|
+
window.scrollTo(0, state?.scroll ?? 0);
|
|
61
|
+
});
|
|
51
62
|
});
|
|
52
63
|
await navigateToLocation(document.location, true);
|
|
53
64
|
async function navigateToLocation(location, firstTime = false) {
|
package/dist/clientEntry.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"clientEntry.mjs","names":[],"sources":["../src/site/clientEntry.ts"],"sourcesContent":["import manifest from \"@torpor/build/manifest\";\nimport loadData from \"../nav/loadData.ts\";\nimport navigate from \"../nav/navigate.ts\";\nimport $page from \"../state/$page.ts\";\nimport client from \"../state/client\";\nimport type LayoutPath from \"../types/LayoutPath\";\nimport type PageEndPoint from \"../types/PageEndPoint\";\nimport type PageServerEndPoint from \"../types/PageServerEndPoint\";\nimport Router from \"./Router.ts\";\n\n// Build the router from the Site object created by the user\nconst router = new Router();\nrouter.addPages(manifest.routes);\n\n// Put it in client state so that it can be accessed from navigate. We can't\n// just import it to navigate because that gets built by tsdown, without Vite\n// and the manifest\nclient.router = router;\n\n// Intercept clicks on links\nwindow.addEventListener(\"click\", async (e) => {\n\tconst link = getLink(e.target);\n\tif (link) {\n\t\tif (ignoreAnchorMouseEvent(link, e)) {\n\t\t\treturn;\n\t\t}\n\n\t\te.preventDefault();\n\n\t\tconst href = link.href;\n\t\tconst url = new URL(href);\n\n\t\tif (await navigate(url)) {\n\t\t\twindow.history.pushState(
|
|
1
|
+
{"version":3,"file":"clientEntry.mjs","names":[],"sources":["../src/site/clientEntry.ts"],"sourcesContent":["import manifest from \"@torpor/build/manifest\";\nimport loadData from \"../nav/loadData.ts\";\nimport navigate from \"../nav/navigate.ts\";\nimport $page from \"../state/$page.ts\";\nimport client from \"../state/client\";\nimport type LayoutPath from \"../types/LayoutPath\";\nimport type PageEndPoint from \"../types/PageEndPoint\";\nimport type PageServerEndPoint from \"../types/PageServerEndPoint\";\nimport Router from \"./Router.ts\";\nimport { setBasePath } from \"./basePath.ts\";\n\nsetBasePath(manifest.base);\n\n// Build the router from the Site object created by the user\nconst router = new Router();\nrouter.addPages(manifest.routes);\n\n// Put it in client state so that it can be accessed from navigate. We can't\n// just import it to navigate because that gets built by tsdown, without Vite\n// and the manifest\nclient.router = router;\n\n// Intercept clicks on links\nwindow.addEventListener(\"click\", async (e) => {\n\tconst link = getLink(e.target);\n\tif (link) {\n\t\tif (ignoreAnchorMouseEvent(link, e)) {\n\t\t\treturn;\n\t\t}\n\n\t\te.preventDefault();\n\n\t\tconst href = link.href;\n\t\tconst url = new URL(href);\n\n\t\tif (await navigate(url)) {\n\t\t\t// Save the scroll position of the outgoing page on the current\n\t\t\t// history entry, so that going (or coming) back can restore it\n\t\t\twindow.history.replaceState({ scroll: window.scrollY }, \"\", document.location.href);\n\t\t\twindow.history.pushState({ scroll: 0 }, \"\", url);\n\t\t} else {\n\t\t\twindow.location.href = href;\n\t\t}\n\t}\n});\n\n// Intercept mouseover/focus/touchstart on links for prefetching\n// TODO: settings e.g. <a href=\"\" data-tb-prefetch=\"eager\"/\"visible\"/\"hover\"/\"touch\">\nwindow.addEventListener(\"mouseover\", maybePrefetch);\nwindow.addEventListener(\"touchstart\", maybePrefetch);\n\nasync function maybePrefetch(e: MouseEvent | TouchEvent) {\n\tconst link = getLink(e.target);\n\tif (link) {\n\t\tif (ignoreAnchorMouseEvent(link, e)) {\n\t\t\treturn;\n\t\t}\n\n\t\tconst href = link.href;\n\t\tconst url = new URL(href);\n\n\t\tconst path = url.pathname;\n\t\tconst query = url.searchParams;\n\t\tconst route = router.match(path, query);\n\t\tif (route) {\n\t\t\tconst handler = route.handler;\n\t\t\tconst params = route.params || {};\n\n\t\t\t// There should be a client endpoint\n\t\t\tconst clientEndPoint: PageEndPoint | undefined = (await handler.endPoint()).default;\n\n\t\t\t// There may be a server endpoint\n\t\t\tconst serverEndPoint: PageServerEndPoint | undefined =\n\t\t\t\thandler.serverEndPoint && (await handler.serverEndPoint())?.default;\n\n\t\t\t// Just dummy this up\n\t\t\tlet newStack: LayoutPath[] = [];\n\n\t\t\tawait loadData(handler, params, path, query, newStack, clientEndPoint, serverEndPoint, true);\n\t\t}\n\t}\n}\n\nfunction getLink(target: EventTarget | null): HTMLAnchorElement | undefined {\n\t// The target may be a child element of the link (e.g. an icon inside it),\n\t// so walk up to the nearest actual link. Fragment-only links (href=\"#...\")\n\t// are left to the browser's native jump-to-anchor behavior\n\tif (!(target instanceof Element)) return;\n\tconst link = target.closest(\"a[href]\");\n\tif (link?.getAttribute(\"href\")?.startsWith(\"#\")) return;\n\treturn (link as HTMLAnchorElement) ?? undefined;\n}\n\nfunction ignoreAnchorMouseEvent(link: HTMLAnchorElement, e: MouseEvent | TouchEvent) {\n\t// Ignore the event if it was already handled (e.g. a user handler calling\n\t// preventDefault), a modifier key is pressed, the target is not \"_self\"\n\t// (e.g. \"_blank\"), rel=\"external\", it's a download link, or it's in a\n\t// contenteditable region\n\treturn (\n\t\te.defaultPrevented ||\n\t\te.altKey ||\n\t\te.ctrlKey ||\n\t\te.metaKey ||\n\t\te.shiftKey ||\n\t\t(link.target && link.target !== \"_self\") ||\n\t\tlink.rel === \"external\" ||\n\t\tlink.hasAttribute(\"download\") ||\n\t\tlink.isContentEditable\n\t);\n}\n\n// Listen for changes to the URL that occur when the user navigates using the\n// back or forward buttons\nwindow.addEventListener(\"popstate\", async () => {\n\tconst navigated = await navigateToLocation(document.location);\n\tif (!navigated) {\n\t\twindow.location.reload();\n\t\treturn;\n\t}\n\t// Restore the scroll position that was saved on the history entry\n\trequestAnimationFrame(() => {\n\t\tconst state = window.history.state as { scroll?: number } | null;\n\t\twindow.scrollTo(0, state?.scroll ?? 0);\n\t});\n});\n\n// Do the initial navigation and hydration\nawait navigateToLocation(document.location, true);\n\nasync function navigateToLocation(location: Location, firstTime = false) {\n\t// Reset $page on submit and link navigation\n\t// TODO: Should we put data in $page.data??\n\t$page.form = undefined;\n\n\treturn await navigate(new URL(location.toString()), firstTime);\n}\n"],"mappings":";;;;;;AAWA,YAAY,SAAS,IAAI;AAGzB,MAAM,SAAS,IAAI,OAAO;AAC1B,OAAO,SAAS,SAAS,MAAM;AAK/B,OAAO,SAAS;AAGhB,OAAO,iBAAiB,SAAS,OAAO,MAAM;CAC7C,MAAM,OAAO,QAAQ,EAAE,MAAM;CAC7B,IAAI,MAAM;EACT,IAAI,uBAAuB,MAAM,CAAC,GACjC;EAGD,EAAE,eAAe;EAEjB,MAAM,OAAO,KAAK;EAClB,MAAM,MAAM,IAAI,IAAI,IAAI;EAExB,IAAI,MAAM,SAAS,GAAG,GAAG;GAGxB,OAAO,QAAQ,aAAa,EAAE,QAAQ,OAAO,QAAQ,GAAG,IAAI,SAAS,SAAS,IAAI;GAClF,OAAO,QAAQ,UAAU,EAAE,QAAQ,EAAE,GAAG,IAAI,GAAG;EAChD,OACC,OAAO,SAAS,OAAO;CAEzB;AACD,CAAC;AAID,OAAO,iBAAiB,aAAa,aAAa;AAClD,OAAO,iBAAiB,cAAc,aAAa;AAEnD,eAAe,cAAc,GAA4B;CACxD,MAAM,OAAO,QAAQ,EAAE,MAAM;CAC7B,IAAI,MAAM;EACT,IAAI,uBAAuB,MAAM,CAAC,GACjC;EAGD,MAAM,OAAO,KAAK;EAClB,MAAM,MAAM,IAAI,IAAI,IAAI;EAExB,MAAM,OAAO,IAAI;EACjB,MAAM,QAAQ,IAAI;EAClB,MAAM,QAAQ,OAAO,MAAM,MAAM,KAAK;EACtC,IAAI,OAAO;GACV,MAAM,UAAU,MAAM;GACtB,MAAM,SAAS,MAAM,UAAU,CAAC;GAGhC,MAAM,kBAA4C,MAAM,QAAQ,SAAS,EAAA,CAAG;GAG5E,MAAM,iBACL,QAAQ,mBAAmB,MAAM,QAAQ,eAAe,EAAA,EAAI;GAK7D,MAAM,SAAS,SAAS,QAAQ,MAAM,OAAO,CAAO,GAAG,gBAAgB,gBAAgB,IAAI;EAC5F;CACD;AACD;AAEA,SAAS,QAAQ,QAA2D;CAI3E,IAAI,EAAE,kBAAkB,UAAU;CAClC,MAAM,OAAO,OAAO,QAAQ,SAAS;CACrC,IAAI,MAAM,aAAa,MAAM,CAAC,EAAE,WAAW,GAAG,GAAG;CACjD,OAAQ,QAA8B,KAAA;AACvC;AAEA,SAAS,uBAAuB,MAAyB,GAA4B;CAKpF,OACC,EAAE,oBACF,EAAE,UACF,EAAE,WACF,EAAE,WACF,EAAE,YACD,KAAK,UAAU,KAAK,WAAW,WAChC,KAAK,QAAQ,cACb,KAAK,aAAa,UAAU,KAC5B,KAAK;AAEP;AAIA,OAAO,iBAAiB,YAAY,YAAY;CAE/C,IAAI,CAAC,MADmB,mBAAmB,SAAS,QAAQ,GAC5C;EACf,OAAO,SAAS,OAAO;EACvB;CACD;CAEA,4BAA4B;EAC3B,MAAM,QAAQ,OAAO,QAAQ;EAC7B,OAAO,SAAS,GAAG,OAAO,UAAU,CAAC;CACtC,CAAC;AACF,CAAC;AAGD,MAAM,mBAAmB,SAAS,UAAU,IAAI;AAEhD,eAAe,mBAAmB,UAAoB,YAAY,OAAO;CAGxE,MAAM,OAAO,KAAA;CAEb,OAAO,MAAM,SAAS,IAAI,IAAI,SAAS,SAAS,CAAC,GAAG,SAAS;AAC9D"}
|
package/dist/dev.d.mts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { t as Server } from "./Server-
|
|
2
|
-
import { t as load } from "./serverEntry-
|
|
1
|
+
import { t as Server } from "./Server-qn5Ws_d0.mjs";
|
|
2
|
+
import { t as load } from "./serverEntry-fj0XfTs4.mjs";
|
|
3
3
|
export { Server, load };
|
package/dist/dev.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { t as Server } from "./Server-
|
|
2
|
-
import { t as load } from "./serverEntry-
|
|
1
|
+
import { t as Server } from "./Server-CSti9cvM.mjs";
|
|
2
|
+
import { t as load } from "./serverEntry-CnCVNNjp.mjs";
|
|
3
3
|
export { Server, load };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { n as sitemapResponse, r as HeadElement, t as SitemapOptions } from "./sitemap-BjqN4d4W.mjs";
|
|
2
|
+
//#region src/discovery/seo.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* The elements to build head markup from: a page title, a description and
|
|
5
|
+
* (for social media) an image and a canonical URL.
|
|
6
|
+
*/
|
|
7
|
+
type SeoOptions = {
|
|
8
|
+
title?: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
image?: string;
|
|
11
|
+
url?: string;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Builds head element data for a page: a title, a description, and Open
|
|
15
|
+
* Graph / Twitter (property metas) when an image or url is included, e.g.
|
|
16
|
+
*
|
|
17
|
+
* ```ts
|
|
18
|
+
* import { seo } from "@torpor/build/discovery";
|
|
19
|
+
*
|
|
20
|
+
* export default {
|
|
21
|
+
* component,
|
|
22
|
+
* head: (event) => seo({
|
|
23
|
+
* title: post.title,
|
|
24
|
+
* description: post.excerpt,
|
|
25
|
+
* image: post.coverImage,
|
|
26
|
+
* url: event.url.href,
|
|
27
|
+
* }),
|
|
28
|
+
* } satisfies PageEndPoint;
|
|
29
|
+
* ```
|
|
30
|
+
*
|
|
31
|
+
* The values are rendered into the document head at render time (with
|
|
32
|
+
* `@head` markup from the component around them), overriding any static
|
|
33
|
+
* `<title>` in the site template. A twitter:card is included only when an
|
|
34
|
+
* image is set, with `og:title`/`og:description`/`og:url` set from the
|
|
35
|
+
* other values.
|
|
36
|
+
*
|
|
37
|
+
* @param options The values to include
|
|
38
|
+
* @returns The head element data
|
|
39
|
+
*/
|
|
40
|
+
declare function seo(options: SeoOptions): HeadElement[];
|
|
41
|
+
//#endregion
|
|
42
|
+
export { type SeoOptions, type SitemapOptions, seo, sitemapResponse };
|
|
43
|
+
//# sourceMappingURL=discovery.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.mts","names":[],"sources":["../src/discovery/seo.ts"],"mappings":";;;;;;KAMY;EACX;EACA;EACA;EACA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8BuB,IAAI,SAAS,aAAa"}
|