@markless/router 0.5.0 → 0.6.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.
@@ -0,0 +1,248 @@
1
+ import { createExternalDelegateStructureTokens, createExternalDelegateView } from "@markless/web/fns/external-delegate";
2
+ //#region src/route-dom.d.ts
3
+ declare const HTML_ATTRIBUTES_SLOT = "__marklessRouterHtmlAttributes";
4
+ //#endregion
5
+ //#region src/route-manifest.d.ts
6
+ interface RouteManifestRoute {
7
+ readonly pathname: string;
8
+ readonly pattern: string;
9
+ readonly file: string;
10
+ readonly params: readonly RouteManifestParam[];
11
+ }
12
+ interface RouteManifestParam {
13
+ readonly name: string;
14
+ readonly kind: 'dynamic' | 'catch-all';
15
+ }
16
+ interface RouteManifestStatusPages {
17
+ readonly notFound?: string;
18
+ readonly error?: string;
19
+ }
20
+ interface RouteManifest {
21
+ readonly routes: readonly RouteManifestRoute[];
22
+ readonly statusPages: RouteManifestStatusPages;
23
+ }
24
+ interface RouteManifestMatch {
25
+ readonly route: RouteManifestRoute;
26
+ readonly params: Readonly<Record<string, string>>;
27
+ }
28
+ declare function buildRouteManifestFromFileIds(fileIds: readonly string[]): RouteManifest;
29
+ declare function normalizeRequestPathname(pathname: string): string;
30
+ declare function normalizeRouteFileId(fileId: string): string;
31
+ declare function matchRouteManifest(pathname: string, manifest: RouteManifest): RouteManifestMatch | undefined;
32
+ //#endregion
33
+ //#region src/request-files.d.ts
34
+ type RequestFileDiagnosticCode = 'http-method-export' | 'invalid-cache-metadata' | 'missing-default-function';
35
+ interface RequestFileDiagnostic {
36
+ readonly code: RequestFileDiagnosticCode;
37
+ readonly message: string;
38
+ }
39
+ interface RequestFileDefaultExport {
40
+ readonly kind: 'function';
41
+ readonly parameterName?: string;
42
+ }
43
+ interface RequestFileParam {
44
+ readonly name: string;
45
+ readonly kind: 'dynamic' | 'catch-all';
46
+ }
47
+ interface ApiRequestFileRoute {
48
+ readonly pathname: string;
49
+ readonly pattern: string;
50
+ readonly params: readonly RequestFileParam[];
51
+ }
52
+ interface ApiRequestFileCache {
53
+ readonly maxAge: number;
54
+ }
55
+ interface RequestFileTransformResult {
56
+ readonly code: string;
57
+ readonly file: string;
58
+ readonly kind: 'api' | 'middleware';
59
+ }
60
+ type ApiRequestFileMethod = 'all' | 'connect' | 'delete' | 'get' | 'head' | 'options' | 'patch' | 'post' | 'put' | 'trace';
61
+ type RequestFileParseResult = {
62
+ readonly diagnostics: readonly [];
63
+ readonly file: string;
64
+ readonly kind: 'none';
65
+ } | {
66
+ readonly cache?: ApiRequestFileCache;
67
+ readonly defaultExport?: RequestFileDefaultExport;
68
+ readonly diagnostics: readonly RequestFileDiagnostic[];
69
+ readonly file: string;
70
+ readonly kind: 'api';
71
+ readonly method: ApiRequestFileMethod;
72
+ readonly route: ApiRequestFileRoute;
73
+ } | {
74
+ readonly defaultExport?: RequestFileDefaultExport;
75
+ readonly diagnostics: readonly RequestFileDiagnostic[];
76
+ readonly file: string;
77
+ readonly kind: 'middleware';
78
+ };
79
+ declare function parseRequestFile(fileId: string, sourceText: string): RequestFileParseResult;
80
+ declare function normalizeRequestFileId(fileId: string): string;
81
+ declare function transformRequestFileSource(fileId: string, sourceText: string): RequestFileTransformResult | undefined;
82
+ //#endregion
83
+ //#region src/navigate.d.ts
84
+ interface NavigateOptions {
85
+ /** Replace the current history entry instead of adding one. */
86
+ readonly replace?: boolean;
87
+ /** `false` keeps the scroll position. */
88
+ readonly scroll?: boolean;
89
+ }
90
+ /**
91
+ * Navigates to `href` exactly as a click on `<Link href={href}>` would: a page of this app swaps in
92
+ * place, anything else loads as a document. The promise resolves once the new page is in place; a
93
+ * navigation that loads a new document leaves this page, so its promise never settles.
94
+ * Runs in the browser only.
95
+ */
96
+ declare function navigate(href: string | URL, options?: NavigateOptions): Promise<void>;
97
+ //#endregion
98
+ //#region src/route-renderer.d.ts
99
+ declare function startRouteUpdateRenderer(document?: Document): void;
100
+ //#endregion
101
+ //#region src/spa-navigation.d.ts
102
+ type MarklessRouterNavigationRuntime = Pick<Navigation, 'addEventListener' | 'navigate'>;
103
+ interface MarklessRouterNavigationWindow {
104
+ readonly document: Document;
105
+ readonly location: Location;
106
+ navigation?: MarklessRouterNavigationRuntime;
107
+ addEventListener(type: 'click', listener: (event: MouseEvent) => void, options?: boolean | AddEventListenerOptions): void;
108
+ }
109
+ interface MarklessRouterNavigationPolyfillModule {
110
+ applyPolyfill(options: {
111
+ readonly interceptEvents: boolean;
112
+ readonly window: MarklessRouterNavigationWindow;
113
+ }): unknown;
114
+ }
115
+ interface StartSpaNavigationOptions {
116
+ readonly documentModuleLoader?: () => Promise<unknown>;
117
+ readonly documentNavigation?: 'client' | 'document';
118
+ readonly loadPolyfill?: () => Promise<MarklessRouterNavigationPolyfillModule>;
119
+ readonly pageModuleLoaders: Record<string, () => Promise<unknown>>;
120
+ readonly preloadRouteModule?: (file: string) => unknown;
121
+ readonly routeFileIds: readonly string[];
122
+ readonly window?: MarklessRouterNavigationWindow;
123
+ }
124
+ declare function __marklessRouterStartSpaNavigation(options: StartSpaNavigationOptions): Promise<void>;
125
+ declare function ensureNavigationRuntime(runtimeWindow?: MarklessRouterNavigationWindow, loadPolyfill?: () => Promise<MarklessRouterNavigationPolyfillModule>): Promise<MarklessRouterNavigationRuntime>;
126
+ //#endregion
127
+ //#region src/route-state.d.ts
128
+ declare const MARKLESS_ROUTER_ROUTE_EVENT = "marklessrouternavigate";
129
+ declare const MARKLESS_ROUTER_RENDERED_EVENT = "marklessrouterrendered";
130
+ interface RouteState {
131
+ readonly file: string;
132
+ readonly params: Readonly<Record<string, string>>;
133
+ readonly status: number;
134
+ readonly url: string;
135
+ }
136
+ interface RoutePageModule {
137
+ readonly default?: unknown;
138
+ }
139
+ interface RouteDocumentModule {
140
+ readonly default?: unknown;
141
+ }
142
+ interface RouteUpdate {
143
+ readonly document?: RouteDocumentModule;
144
+ readonly page: RoutePageModule;
145
+ readonly route: RouteState;
146
+ readonly signal?: AbortSignal;
147
+ readonly onRendered?: () => void;
148
+ }
149
+ declare function routePageProps(route: RouteState): Omit<PageProps, 'http'>;
150
+ declare function dispatchRouteUpdate(document: Document, update: RouteUpdate): void;
151
+ //#endregion
152
+ //#region src/index.d.ts
153
+ interface PageProps<Params extends object = Readonly<Record<string, string>>, Locals extends object = AppLocals> {
154
+ /**
155
+ * The request and the response being written, the same object API routes and middleware get.
156
+ * It exists only while the page renders on the server: the compiler refuses any read of it from
157
+ * code that runs in the browser. Set `http.response.status` and `http.response.headers` before the
158
+ * first byte is sent; a later write that changes them throws `MARKLESS_ROUTER_RESPONSE_COMMITTED`.
159
+ */
160
+ readonly http: HttpContext<Locals>;
161
+ readonly params: Readonly<Params>;
162
+ readonly url: {
163
+ readonly href: string;
164
+ readonly pathname: string;
165
+ readonly search: string;
166
+ };
167
+ readonly status: number;
168
+ }
169
+ interface MarklessRouterGeneratedRoutes {}
170
+ interface LinkNavigationProps {
171
+ /**
172
+ * `false`: nothing for this link downloads before it is clicked. Only page routes are ever
173
+ * prefetched (with a `Purpose: prefetch` header), never `/api` endpoints; set `false` on a link to
174
+ * a page whose GET has side effects (a one-time token, a counter) so only the click requests it.
175
+ */
176
+ readonly prefetch?: boolean;
177
+ readonly replace?: boolean;
178
+ readonly scroll?: boolean;
179
+ }
180
+ type DefaultLinkProps = {
181
+ readonly href?: string;
182
+ readonly children?: __MarklessTypeService.Child;
183
+ readonly class?: string;
184
+ readonly id?: string;
185
+ readonly target?: string;
186
+ readonly rel?: string;
187
+ readonly [prop: string]: unknown;
188
+ } & LinkNavigationProps;
189
+ type LinkProps = MarklessRouterGeneratedRoutes extends {
190
+ readonly link: infer Props;
191
+ } ? Props & Pick<DefaultLinkProps, 'children' | 'class' | 'id' | 'target' | 'rel'> & {
192
+ readonly [prop: string]: unknown;
193
+ } : DefaultLinkProps;
194
+ interface AppLocals {}
195
+ interface HttpResponse {
196
+ readonly headers: Headers;
197
+ status?: number;
198
+ statusText?: string;
199
+ }
200
+ interface HttpContext<Locals extends object = AppLocals> {
201
+ readonly locals: Locals;
202
+ readonly request: Request;
203
+ readonly response: HttpResponse;
204
+ readonly url: URL;
205
+ }
206
+ interface EndpointHttpContext<Params extends object = Readonly<Record<string, string>>, Locals extends object = AppLocals> extends HttpContext<Locals> {
207
+ readonly params: Readonly<Params>;
208
+ }
209
+ interface MiddlewareHttpContext<Locals extends object = AppLocals> extends HttpContext<Locals> {}
210
+ type RuntimeHttpEvent = {
211
+ readonly context?: Record<string, unknown>;
212
+ readonly req?: Request;
213
+ readonly res?: HttpResponse;
214
+ readonly url?: URL;
215
+ };
216
+ declare function __marklessCreateHttpContext<Params extends object = Readonly<Record<string, string>>, Locals extends object = AppLocals>(event: RuntimeHttpEvent): EndpointHttpContext<Params, Locals>;
217
+ declare const Html: ((props: {
218
+ readonly children?: __MarklessTypeService.Child;
219
+ }) => unknown) & {
220
+ renderSsr(props?: {
221
+ readonly children?: __MarklessTypeService.Child;
222
+ readonly [name: string]: unknown;
223
+ }, renderContext?: {
224
+ readonly [HTML_ATTRIBUTES_SLOT]?: Record<string, unknown>;
225
+ }): {
226
+ html: string;
227
+ elementCount: number;
228
+ };
229
+ };
230
+ type LinkComponent = {
231
+ (props?: LinkProps): unknown;
232
+ renderCsr(props?: LinkProps): {
233
+ root: HTMLAnchorElement;
234
+ view: ReturnType<typeof createExternalDelegateView>;
235
+ liveHostNodes: Map<string, HTMLAnchorElement>;
236
+ };
237
+ renderSsr(props?: LinkProps, renderContext?: {
238
+ readonly idPrefix?: string;
239
+ }): {
240
+ html: string;
241
+ elementCount: number;
242
+ structureTokens: ReturnType<typeof createExternalDelegateStructureTokens>;
243
+ view: ReturnType<typeof createExternalDelegateView>;
244
+ };
245
+ };
246
+ declare const Link: LinkComponent;
247
+ //#endregion
248
+ export { RequestFileDefaultExport as A, RouteManifestMatch as B, ensureNavigationRuntime as C, ApiRequestFileCache as D, navigate as E, RequestFileTransformResult as F, matchRouteManifest as G, RouteManifestRoute as H, normalizeRequestFileId as I, normalizeRequestPathname as K, parseRequestFile as L, RequestFileDiagnosticCode as M, RequestFileParam as N, ApiRequestFileMethod as O, RequestFileParseResult as P, transformRequestFileSource as R, __marklessRouterStartSpaNavigation as S, NavigateOptions as T, RouteManifestStatusPages as U, RouteManifestParam as V, buildRouteManifestFromFileIds as W, RoutePageModule as _, HttpContext as a, dispatchRouteUpdate as b, LinkNavigationProps as c, MiddlewareHttpContext as d, PageProps as f, RouteDocumentModule as g, MARKLESS_ROUTER_ROUTE_EVENT as h, Html as i, RequestFileDiagnostic as j, ApiRequestFileRoute as k, LinkProps as l, MARKLESS_ROUTER_RENDERED_EVENT as m, DefaultLinkProps as n, HttpResponse as o, __marklessCreateHttpContext as p, normalizeRouteFileId as q, EndpointHttpContext as r, Link as s, AppLocals as t, MarklessRouterGeneratedRoutes as u, RouteState as v, startRouteUpdateRenderer as w, routePageProps as x, RouteUpdate as y, RouteManifest as z };
package/dist/index.d.ts CHANGED
@@ -1,233 +1,2 @@
1
- import { createExternalDelegateStructureTokens, createExternalDelegateView } from "@markless/web/fns/external-delegate";
2
- //#region src/route-dom.d.ts
3
- declare const HTML_ATTRIBUTES_SLOT = "__marklessRouterHtmlAttributes";
4
- //#endregion
5
- //#region src/route-manifest.d.ts
6
- interface RouteManifestRoute {
7
- readonly pathname: string;
8
- readonly pattern: string;
9
- readonly file: string;
10
- readonly params: readonly RouteManifestParam[];
11
- }
12
- interface RouteManifestParam {
13
- readonly name: string;
14
- readonly kind: 'dynamic' | 'catch-all';
15
- }
16
- interface RouteManifestStatusPages {
17
- readonly notFound?: string;
18
- readonly error?: string;
19
- }
20
- interface RouteManifest {
21
- readonly routes: readonly RouteManifestRoute[];
22
- readonly statusPages: RouteManifestStatusPages;
23
- }
24
- interface RouteManifestMatch {
25
- readonly route: RouteManifestRoute;
26
- readonly params: Readonly<Record<string, string>>;
27
- }
28
- export declare function buildRouteManifestFromFileIds(fileIds: readonly string[]): RouteManifest;
29
- export declare function normalizeRequestPathname(pathname: string): string;
30
- export declare function normalizeRouteFileId(fileId: string): string;
31
- export declare function matchRouteManifest(pathname: string, manifest: RouteManifest): RouteManifestMatch | undefined;
32
- //#endregion
33
- //#region src/request-files.d.ts
34
- type RequestFileDiagnosticCode = 'http-method-export' | 'invalid-cache-metadata' | 'missing-default-function';
35
- interface RequestFileDiagnostic {
36
- readonly code: RequestFileDiagnosticCode;
37
- readonly message: string;
38
- }
39
- interface RequestFileDefaultExport {
40
- readonly kind: 'function';
41
- readonly parameterName?: string;
42
- }
43
- interface RequestFileParam {
44
- readonly name: string;
45
- readonly kind: 'dynamic' | 'catch-all';
46
- }
47
- interface ApiRequestFileRoute {
48
- readonly pathname: string;
49
- readonly pattern: string;
50
- readonly params: readonly RequestFileParam[];
51
- }
52
- interface ApiRequestFileCache {
53
- readonly maxAge: number;
54
- }
55
- interface RequestFileTransformResult {
56
- readonly code: string;
57
- readonly file: string;
58
- readonly kind: 'api' | 'middleware';
59
- }
60
- type ApiRequestFileMethod = 'all' | 'connect' | 'delete' | 'get' | 'head' | 'options' | 'patch' | 'post' | 'put' | 'trace';
61
- type RequestFileParseResult = {
62
- readonly diagnostics: readonly [];
63
- readonly file: string;
64
- readonly kind: 'none';
65
- } | {
66
- readonly cache?: ApiRequestFileCache;
67
- readonly defaultExport?: RequestFileDefaultExport;
68
- readonly diagnostics: readonly RequestFileDiagnostic[];
69
- readonly file: string;
70
- readonly kind: 'api';
71
- readonly method: ApiRequestFileMethod;
72
- readonly route: ApiRequestFileRoute;
73
- } | {
74
- readonly defaultExport?: RequestFileDefaultExport;
75
- readonly diagnostics: readonly RequestFileDiagnostic[];
76
- readonly file: string;
77
- readonly kind: 'middleware';
78
- };
79
- export declare function parseRequestFile(fileId: string, sourceText: string): RequestFileParseResult;
80
- export declare function normalizeRequestFileId(fileId: string): string;
81
- export declare function transformRequestFileSource(fileId: string, sourceText: string): RequestFileTransformResult | undefined;
82
- //#endregion
83
- //#region src/route-renderer.d.ts
84
- export declare function startRouteUpdateRenderer(document?: Document): void;
85
- //#endregion
86
- //#region src/spa-navigation.d.ts
87
- type MarklessRouterNavigationRuntime = Pick<Navigation, 'addEventListener' | 'navigate'>;
88
- interface MarklessRouterNavigationWindow {
89
- readonly document: Document;
90
- readonly location: Location;
91
- navigation?: MarklessRouterNavigationRuntime;
92
- addEventListener(type: 'click', listener: (event: MouseEvent) => void, options?: boolean | AddEventListenerOptions): void;
93
- }
94
- interface MarklessRouterNavigationPolyfillModule {
95
- applyPolyfill(options: {
96
- readonly interceptEvents: boolean;
97
- readonly window: MarklessRouterNavigationWindow;
98
- }): unknown;
99
- }
100
- interface StartSpaNavigationOptions {
101
- readonly documentModuleLoader?: () => Promise<unknown>;
102
- readonly documentNavigation?: 'client' | 'document';
103
- readonly loadPolyfill?: () => Promise<MarklessRouterNavigationPolyfillModule>;
104
- readonly pageModuleLoaders: Record<string, () => Promise<unknown>>;
105
- readonly preloadRouteModule?: (file: string) => unknown;
106
- readonly routeFileIds: readonly string[];
107
- readonly window?: MarklessRouterNavigationWindow;
108
- }
109
- export declare function __marklessRouterStartSpaNavigation(options: StartSpaNavigationOptions): Promise<void>;
110
- export declare function ensureNavigationRuntime(runtimeWindow?: MarklessRouterNavigationWindow, loadPolyfill?: () => Promise<MarklessRouterNavigationPolyfillModule>): Promise<MarklessRouterNavigationRuntime>;
111
- //#endregion
112
- //#region src/route-state.d.ts
113
- export declare const MARKLESS_ROUTER_ROUTE_EVENT = "marklessrouternavigate";
114
- export declare const MARKLESS_ROUTER_RENDERED_EVENT = "marklessrouterrendered";
115
- interface RouteState {
116
- readonly file: string;
117
- readonly params: Readonly<Record<string, string>>;
118
- readonly status: number;
119
- readonly url: string;
120
- }
121
- interface RoutePageModule {
122
- readonly default?: unknown;
123
- }
124
- interface RouteDocumentModule {
125
- readonly default?: unknown;
126
- }
127
- interface RouteUpdate {
128
- readonly document?: RouteDocumentModule;
129
- readonly page: RoutePageModule;
130
- readonly route: RouteState;
131
- readonly signal?: AbortSignal;
132
- readonly onRendered?: () => void;
133
- }
134
- export declare function routePageProps(route: RouteState): Omit<PageProps, 'http'>;
135
- export declare function dispatchRouteUpdate(document: Document, update: RouteUpdate): void;
136
- //#endregion
137
- //#region src/index.d.ts
138
- export interface PageProps<Params extends object = Readonly<Record<string, string>>, Locals extends object = AppLocals> {
139
- /**
140
- * The request and the response being written, the same object API routes and middleware get.
141
- * It exists only while the page renders on the server: the compiler refuses any read of it from
142
- * code that runs in the browser. Set `http.response.status` and `http.response.headers` before the
143
- * first byte is sent; a later write that changes them throws `MARKLESS_ROUTER_RESPONSE_COMMITTED`.
144
- */
145
- readonly http: HttpContext<Locals>;
146
- readonly params: Readonly<Params>;
147
- readonly url: {
148
- readonly href: string;
149
- readonly pathname: string;
150
- readonly search: string;
151
- };
152
- readonly status: number;
153
- }
154
- export interface MarklessRouterGeneratedRoutes {}
155
- export interface LinkNavigationProps {
156
- /**
157
- * `false`: nothing for this link downloads before it is clicked. Only page routes are ever
158
- * prefetched (with a `Purpose: prefetch` header), never `/api` endpoints; set `false` on a link to
159
- * a page whose GET has side effects (a one-time token, a counter) so only the click requests it.
160
- */
161
- readonly prefetch?: boolean;
162
- readonly replace?: boolean;
163
- readonly scroll?: boolean;
164
- }
165
- export type DefaultLinkProps = {
166
- readonly href?: string;
167
- readonly children?: __MarklessTypeService.Child;
168
- readonly class?: string;
169
- readonly id?: string;
170
- readonly target?: string;
171
- readonly rel?: string;
172
- readonly [prop: string]: unknown;
173
- } & LinkNavigationProps;
174
- export type LinkProps = MarklessRouterGeneratedRoutes extends {
175
- readonly link: infer Props;
176
- } ? Props & Pick<DefaultLinkProps, 'children' | 'class' | 'id' | 'target' | 'rel'> & {
177
- readonly [prop: string]: unknown;
178
- } : DefaultLinkProps;
179
- export interface AppLocals {}
180
- export interface HttpResponse {
181
- readonly headers: Headers;
182
- status?: number;
183
- statusText?: string;
184
- }
185
- export interface HttpContext<Locals extends object = AppLocals> {
186
- readonly locals: Locals;
187
- readonly request: Request;
188
- readonly response: HttpResponse;
189
- readonly url: URL;
190
- }
191
- export interface EndpointHttpContext<Params extends object = Readonly<Record<string, string>>, Locals extends object = AppLocals> extends HttpContext<Locals> {
192
- readonly params: Readonly<Params>;
193
- }
194
- export interface MiddlewareHttpContext<Locals extends object = AppLocals> extends HttpContext<Locals> {}
195
- type RuntimeHttpEvent = {
196
- readonly context?: Record<string, unknown>;
197
- readonly req?: Request;
198
- readonly res?: HttpResponse;
199
- readonly url?: URL;
200
- };
201
- export declare function __marklessCreateHttpContext<Params extends object = Readonly<Record<string, string>>, Locals extends object = AppLocals>(event: RuntimeHttpEvent): EndpointHttpContext<Params, Locals>;
202
- export declare const Html: ((props: {
203
- readonly children?: __MarklessTypeService.Child;
204
- }) => unknown) & {
205
- renderSsr(props?: {
206
- readonly children?: __MarklessTypeService.Child;
207
- readonly [name: string]: unknown;
208
- }, renderContext?: {
209
- readonly [HTML_ATTRIBUTES_SLOT]?: Record<string, unknown>;
210
- }): {
211
- html: string;
212
- elementCount: number;
213
- };
214
- };
215
- type LinkComponent = {
216
- (props?: LinkProps): unknown;
217
- renderCsr(props?: LinkProps): {
218
- root: HTMLAnchorElement;
219
- view: ReturnType<typeof createExternalDelegateView>;
220
- liveHostNodes: Map<string, HTMLAnchorElement>;
221
- };
222
- renderSsr(props?: LinkProps, renderContext?: {
223
- readonly idPrefix?: string;
224
- }): {
225
- html: string;
226
- elementCount: number;
227
- structureTokens: ReturnType<typeof createExternalDelegateStructureTokens>;
228
- view: ReturnType<typeof createExternalDelegateView>;
229
- };
230
- };
231
- export declare const Link: LinkComponent;
232
- //#endregion
233
- export type { ApiRequestFileCache, ApiRequestFileMethod, ApiRequestFileRoute, RequestFileDefaultExport, RequestFileDiagnostic, RequestFileDiagnosticCode, RequestFileParam, RequestFileParseResult, RequestFileTransformResult, RouteDocumentModule, RouteManifest, RouteManifestMatch, RouteManifestParam, RouteManifestRoute, RouteManifestStatusPages, RoutePageModule, RouteState, RouteUpdate };
1
+ import { A as RequestFileDefaultExport, B as RouteManifestMatch, C as ensureNavigationRuntime, D as ApiRequestFileCache, E as navigate, F as RequestFileTransformResult, G as matchRouteManifest, H as RouteManifestRoute, I as normalizeRequestFileId, K as normalizeRequestPathname, L as parseRequestFile, M as RequestFileDiagnosticCode, N as RequestFileParam, O as ApiRequestFileMethod, P as RequestFileParseResult, R as transformRequestFileSource, S as __marklessRouterStartSpaNavigation, T as NavigateOptions, U as RouteManifestStatusPages, V as RouteManifestParam, W as buildRouteManifestFromFileIds, _ as RoutePageModule, a as HttpContext, b as dispatchRouteUpdate, c as LinkNavigationProps, d as MiddlewareHttpContext, f as PageProps, g as RouteDocumentModule, h as MARKLESS_ROUTER_ROUTE_EVENT, i as Html, j as RequestFileDiagnostic, k as ApiRequestFileRoute, l as LinkProps, m as MARKLESS_ROUTER_RENDERED_EVENT, n as DefaultLinkProps, o as HttpResponse, p as __marklessCreateHttpContext, q as normalizeRouteFileId, r as EndpointHttpContext, s as Link, t as AppLocals, u as MarklessRouterGeneratedRoutes, v as RouteState, w as startRouteUpdateRenderer, x as routePageProps, y as RouteUpdate, z as RouteManifest } from "./index-BjxpxRL7.js";
2
+ export { type ApiRequestFileCache, type ApiRequestFileMethod, type ApiRequestFileRoute, AppLocals, DefaultLinkProps, EndpointHttpContext, Html, HttpContext, HttpResponse, Link, LinkNavigationProps, LinkProps, MARKLESS_ROUTER_RENDERED_EVENT, MARKLESS_ROUTER_ROUTE_EVENT, MarklessRouterGeneratedRoutes, MiddlewareHttpContext, type NavigateOptions, PageProps, type RequestFileDefaultExport, type RequestFileDiagnostic, type RequestFileDiagnosticCode, type RequestFileParam, type RequestFileParseResult, type RequestFileTransformResult, type RouteDocumentModule, type RouteManifest, type RouteManifestMatch, type RouteManifestParam, type RouteManifestRoute, type RouteManifestStatusPages, type RoutePageModule, type RouteState, type RouteUpdate, __marklessCreateHttpContext, __marklessRouterStartSpaNavigation, buildRouteManifestFromFileIds, dispatchRouteUpdate, ensureNavigationRuntime, matchRouteManifest, navigate, normalizeRequestFileId, normalizeRequestPathname, normalizeRouteFileId, parseRequestFile, routePageProps, startRouteUpdateRenderer, transformRequestFileSource };
package/dist/index.js CHANGED
@@ -1,19 +1,8 @@
1
- import { i as SCROLL_ATTRIBUTE, n as PREFETCH_ATTRIBUTE, r as REPLACE_ATTRIBUTE, t as LINK_ATTRIBUTE } from "./link-attributes-nY1Qkmx2.js";
2
- import { a as routeMountTarget, r as HTML_ATTRIBUTES_SLOT, t as rememberRequestLocals } from "./request-locals-BFPF6Vdm.js";
3
- import { a as normalizeRouteFileId, i as normalizeRequestPathname, r as matchRouteManifest, t as buildRouteManifestFromFileIds } from "./route-manifest-Bw_nFohL.js";
4
- import { n as parseRequestFile, r as transformRequestFileSource, t as normalizeRequestFileId } from "./request-files-Ca8E0FOo.js";
1
+ import { c as PREFETCH_ATTRIBUTE, i as HTML_ATTRIBUTES_SLOT, l as REPLACE_ATTRIBUTE, o as routeMountTarget, s as LINK_ATTRIBUTE, t as rememberRequestLocals, u as SCROLL_ATTRIBUTE } from "./request-locals-z3rJTizs.js";
2
+ import { a as normalizeRequestPathname, c as parseRequestFile, i as matchRouteManifest, l as transformRequestFileSource, n as buildRouteManifestFromFileIds, o as normalizeRouteFileId, s as normalizeRequestFileId } from "./route-manifest-DMizh42B.js";
5
3
  import { createExternalDelegateStructureTokens, createExternalDelegateView } from "@markless/web/fns/external-delegate";
6
4
  import { render } from "@markless/web/render";
7
5
  import { MARKLESS_PENDING_MIN_VISIBLE_MS as MARKLESS_NAV_PENDING_MIN_MS, settleOrPendingDeadline } from "@markless/web/fns/pending-timing";
8
- //#region src/navigation-hold.ts
9
- async function holdNavigationSwapUntilSettled(input) {
10
- const settled = input.runtime.whenAsyncBoundariesSettled?.();
11
- if (settled) {
12
- if (await settleOrPendingDeadline(settled, input.clock?.wait) === "deadline") await input.runtime.holdPendingSettleCommits?.(MARKLESS_NAV_PENDING_MIN_MS);
13
- }
14
- if (input.signal?.aborted) return false;
15
- }
16
- //#endregion
17
6
  //#region src/route-state.ts
18
7
  const MARKLESS_ROUTER_ROUTE_EVENT = "marklessrouternavigate";
19
8
  const MARKLESS_ROUTER_RENDERED_EVENT = "marklessrouterrendered";
@@ -34,6 +23,66 @@ function dispatchRouteUpdate(document, update) {
34
23
  document.dispatchEvent(new CustomEvent(MARKLESS_ROUTER_ROUTE_EVENT, { detail: update }));
35
24
  }
36
25
  //#endregion
26
+ //#region src/navigate.ts
27
+ /**
28
+ * Navigates to `href` exactly as a click on `<Link href={href}>` would: a page of this app swaps in
29
+ * place, anything else loads as a document. The promise resolves once the new page is in place; a
30
+ * navigation that loads a new document leaves this page, so its promise never settles.
31
+ * Runs in the browser only.
32
+ */
33
+ function navigate(href, options = {}) {
34
+ if (typeof document === "undefined") throw new Error("MARKLESS_ROUTER_NAVIGATE_SERVER: navigate() runs in the browser. Call it from an event handler or other browser code, not while the page renders on the server.");
35
+ const d = document;
36
+ const w = d.defaultView ?? window;
37
+ const url = new URL(href, d.baseURI);
38
+ const rendered = new Promise((resolve) => d.addEventListener(MARKLESS_ROUTER_RENDERED_EVENT, () => resolve(), { once: true }));
39
+ const anchor = d.createElement("a");
40
+ anchor.href = url.href;
41
+ anchor.hidden = true;
42
+ anchor.setAttribute(LINK_ATTRIBUTE, "");
43
+ if (options.replace) anchor.setAttribute(REPLACE_ATTRIBUTE, "");
44
+ if (options.scroll === false) anchor.setAttribute(SCROLL_ATTRIBUTE, "manual");
45
+ let reached = false;
46
+ let routed = false;
47
+ const last = (event) => {
48
+ if (event.target !== anchor) return;
49
+ reached = true;
50
+ routed = event.defaultPrevented;
51
+ event.preventDefault();
52
+ };
53
+ w.addEventListener("click", last);
54
+ d.body.append(anchor);
55
+ try {
56
+ anchor.dispatchEvent(new MouseEvent("click", {
57
+ bubbles: true,
58
+ cancelable: true,
59
+ composed: true,
60
+ button: 0
61
+ }));
62
+ } finally {
63
+ anchor.remove();
64
+ w.removeEventListener("click", last);
65
+ }
66
+ if (routed || !reached) return rendered;
67
+ const inPage = url.hash !== "" && withoutHash(url.href) === withoutHash(w.location.href);
68
+ if (options.replace) w.location.replace(url.href);
69
+ else w.location.assign(url.href);
70
+ return inPage ? Promise.resolve() : new Promise(() => {});
71
+ }
72
+ function withoutHash(href) {
73
+ const at = href.indexOf("#");
74
+ return at === -1 ? href : href.slice(0, at);
75
+ }
76
+ //#endregion
77
+ //#region src/navigation-hold.ts
78
+ async function holdNavigationSwapUntilSettled(input) {
79
+ const settled = input.runtime.whenAsyncBoundariesSettled?.();
80
+ if (settled) {
81
+ if (await settleOrPendingDeadline(settled, input.clock?.wait) === "deadline") await input.runtime.holdPendingSettleCommits?.(MARKLESS_NAV_PENDING_MIN_MS);
82
+ }
83
+ if (input.signal?.aborted) return false;
84
+ }
85
+ //#endregion
37
86
  //#region src/route-renderer.ts
38
87
  const CURRENT_ROUTE_CONTAINER = "__marklessRouterCurrentRouteContainer";
39
88
  function startRouteUpdateRenderer(document = window.document) {
@@ -241,7 +290,7 @@ function browserWindow() {
241
290
  function __marklessCreateHttpContext(event) {
242
291
  const context = event.context ?? {};
243
292
  const url = event.url ?? new URL("http://localhost/");
244
- if (event.req) rememberRequestLocals(event.req, context);
293
+ if (event.req) rememberRequestLocals(event.req, context, event.res?.headers);
245
294
  return {
246
295
  locals: context,
247
296
  params: context.params ?? {},
@@ -325,4 +374,4 @@ function escapeHtml(value) {
325
374
  return value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;");
326
375
  }
327
376
  //#endregion
328
- export { Html, Link, MARKLESS_ROUTER_RENDERED_EVENT, MARKLESS_ROUTER_ROUTE_EVENT, __marklessCreateHttpContext, __marklessRouterStartSpaNavigation, buildRouteManifestFromFileIds, dispatchRouteUpdate, ensureNavigationRuntime, matchRouteManifest, normalizeRequestFileId, normalizeRequestPathname, normalizeRouteFileId, parseRequestFile, routePageProps, startRouteUpdateRenderer, transformRequestFileSource };
377
+ export { Html, Link, MARKLESS_ROUTER_RENDERED_EVENT, MARKLESS_ROUTER_ROUTE_EVENT, __marklessCreateHttpContext, __marklessRouterStartSpaNavigation, buildRouteManifestFromFileIds, dispatchRouteUpdate, ensureNavigationRuntime, matchRouteManifest, navigate, normalizeRequestFileId, normalizeRequestPathname, normalizeRouteFileId, parseRequestFile, routePageProps, startRouteUpdateRenderer, transformRequestFileSource };
@@ -0,0 +1,90 @@
1
+ import { CONTAINER_ATTRIBUTE, PROTOCOL_CONTAINER_END_COMMENT, PROTOCOL_CONTAINER_START_COMMENT, PROTOCOL_LOCATOR_PATHS_ATTRIBUTE } from "@markless/web/fns/container-region";
2
+ //#region src/link-attributes.ts
3
+ const LINK_ATTRIBUTE = "data-markless-router-link";
4
+ const REPLACE_ATTRIBUTE = "data-markless-router-replace";
5
+ const SCROLL_ATTRIBUTE = "data-markless-router-scroll";
6
+ const PREFETCH_ATTRIBUTE = "data-markless-router-prefetch";
7
+ //#endregion
8
+ //#region src/route-dom.ts
9
+ const ROUTE_SCRIPT_TYPE = "@markless/core/route";
10
+ const HTML_ATTRIBUTES_SLOT = "__marklessRouterHtmlAttributes";
11
+ function routeMountTarget(document, currentRoot) {
12
+ const root = currentRoot ?? document.querySelector(`script[type="@markless/core/route"]`)?.parentElement;
13
+ if (!root) return document.body;
14
+ const host = [root, root.parentElement].find((element) => element && containerPageEnd(element));
15
+ if (host) return authorElementTarget(document, host);
16
+ return {
17
+ ownerDocument: document,
18
+ replaceChildren(...children) {
19
+ root.replaceWith(...children);
20
+ }
21
+ };
22
+ }
23
+ function containerPageEnd(host) {
24
+ for (let node = host.lastChild; node; node = node.previousSibling) if (node.nodeType === 8 && node.data === PROTOCOL_CONTAINER_END_COMMENT) return node;
25
+ }
26
+ function containerPageStart(host) {
27
+ for (let node = host.firstChild; node; node = node.nextSibling) if (node.nodeType === 8 && node.data === PROTOCOL_CONTAINER_START_COMMENT) return node;
28
+ }
29
+ function authorElementTarget(document, host) {
30
+ const copy = () => {
31
+ const next = host.cloneNode(false);
32
+ next.removeAttribute(CONTAINER_ATTRIBUTE);
33
+ next.removeAttribute(PROTOCOL_LOCATOR_PATHS_ATTRIBUTE);
34
+ return next;
35
+ };
36
+ let holder;
37
+ return {
38
+ ownerDocument: document,
39
+ createHolder: () => holder = copy(),
40
+ replaceChildren(...children) {
41
+ const next = children.length === 1 && children[0] === holder ? holder : copy();
42
+ if (next !== holder) next.append(...children);
43
+ const end = containerPageEnd(host);
44
+ const focused = document.activeElement;
45
+ const start = containerPageStart(host);
46
+ if (start) {
47
+ const before = [];
48
+ for (let node = host.firstChild; node !== start; node = node.nextSibling) before.push(node);
49
+ next.prepend(...before, document.createComment(PROTOCOL_CONTAINER_START_COMMENT));
50
+ }
51
+ next.append(document.createComment(PROTOCOL_CONTAINER_END_COMMENT));
52
+ while (end.nextSibling) next.append(end.nextSibling);
53
+ host.replaceWith(next);
54
+ if (focused && focused !== document.activeElement && next.contains(focused)) focused.focus({ preventScroll: true });
55
+ }
56
+ };
57
+ }
58
+ //#endregion
59
+ //#region src/request-locals.ts
60
+ const REQUEST_LOCALS = Symbol.for("@markless/router/request-locals");
61
+ function table() {
62
+ const scope = globalThis;
63
+ return scope[REQUEST_LOCALS] ??= /* @__PURE__ */ new WeakMap();
64
+ }
65
+ function rememberRequestLocals(request, locals, headers) {
66
+ const known = table().get(request);
67
+ table().set(request, {
68
+ locals,
69
+ headers: headers ?? known?.headers,
70
+ taken: known?.taken
71
+ });
72
+ }
73
+ function requestLocals(request) {
74
+ return table().get(request)?.locals;
75
+ }
76
+ /**
77
+ * The response headers middleware wrote for this request, moved off the server's
78
+ * response: it drops them from a non-2xx page and would repeat them on a 2xx one.
79
+ */
80
+ function takeMiddlewareHeaders(request) {
81
+ const record = table().get(request);
82
+ if (!record?.headers) return void 0;
83
+ if (!record.taken) {
84
+ record.taken = new Headers(record.headers);
85
+ for (const name of Array.from(record.headers.keys())) record.headers.delete(name);
86
+ }
87
+ return record.taken;
88
+ }
89
+ //#endregion
90
+ export { ROUTE_SCRIPT_TYPE as a, PREFETCH_ATTRIBUTE as c, HTML_ATTRIBUTES_SLOT as i, REPLACE_ATTRIBUTE as l, requestLocals as n, routeMountTarget as o, takeMiddlewareHeaders as r, LINK_ATTRIBUTE as s, rememberRequestLocals as t, SCROLL_ATTRIBUTE as u };