@solidjs/router 1.0.0-next.9 → 2.0.0-next.12

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/server.js CHANGED
@@ -3,24 +3,27 @@
3
3
  // it reaches for node async context via @solidjs/web/storage — keep it out of
4
4
  // client bundles.
5
5
  //
6
- // Two policies live here, both previously implemented inside SolidStart and
7
- // now owned by the router (the vocabulary — query keys, submissions — is the
8
- // router's):
6
+ // One policy lives here — the vocabulary (query keys, route trees, preloads)
7
+ // is the router's:
9
8
  //
10
9
  // - single-flight mutations: `createFlightDataCollector` produces the
11
10
  // `collectFlightData` hook the app hands to
12
- // `configureServerFunctionsServer` (or the handler options). After a
13
- // mutation it produces the route data the mutation invalidated for the
14
- // page the client is on (or is being redirected to), which the handler
15
- // folds into the response — mutation and fresh data in one round trip.
16
- // - the no-JS form convention: `createNoJSHandler` produces the
17
- // `handleNoJS` hook — form posts made without the client runtime redirect
18
- // back (303) carrying the outcome in a one-shot flash cookie that the
19
- // router's SSR initialization reads into submission state.
11
+ // `configureServerFunctionsServer` (or the handler options). The runtime
12
+ // pre-digests the generic halves onto the outcome (target URL,
13
+ // revalidation keys, post-mutation cookie headers); the collector runs
14
+ // the matched routes' preloads for the target and returns their `query`
15
+ // results, which the handler folds into the response — mutation and
16
+ // fresh data in one round trip.
17
+ //
18
+ // The no-JS form convention used to live here too; the runtime now owns it
19
+ // outright — it applies to browser form posts by default (redirect back with
20
+ // the outcome in a one-shot flash cookie), and `createNoJSHandler` is
21
+ // configured through @solidjs/web/server-functions/server. The router keeps
22
+ // only its read side: SSR initialization seeds the decoded cookie into
23
+ // submission state (routing.ts).
20
24
  import { provideRequestEvent } from "@solidjs/web/storage";
21
25
  import { createBranches, getRouteMatches, mergeParams, peekLazySubtrees, resolveLazySubtree } from "./routing.js";
22
26
  import { extractSearchParams } from "./utils.js";
23
- import { encodeFlashCookie } from "./data/flash.js";
24
27
  // the instance is the provider component, so it (unlike an options object) is a function
25
28
  function isRouterInstance(options) {
26
29
  return typeof options === "function";
@@ -32,13 +35,12 @@ function isRouterInstance(options) {
32
35
  * and `preload` are the single source of truth — or an options object for
33
36
  * trees not created through the factory.
34
37
  *
35
- * Strategy: rerun the route data for the URL the client will show
36
- * after the mutation — the redirect `Location` when the outcome carries
37
- * one, the referring page otherwise — collecting each `query` result under
38
- * its cache key, scoped to the outcome's `X-Revalidate` keys when present
39
- * (routes newly entered via redirect always collect fully). The returned
40
- * payload seeds the client router's cache through its registered
41
- * flight-data consumer.
38
+ * Strategy: rerun the route data for the URL the client will show after
39
+ * the mutation (the outcome's pre-digested `targetUrl`), collecting each
40
+ * `query` result under its cache key, scoped to the outcome's
41
+ * `revalidateKeys` when present (routes newly entered via redirect always
42
+ * collect fully). The returned payload seeds the client router's cache
43
+ * through its registered flight-data consumer.
42
44
  */
43
45
  export function createFlightDataCollector(options) {
44
46
  const { routes, rootPreload, base = "" } = isRouterInstance(options)
@@ -59,41 +61,29 @@ export function createFlightDataCollector(options) {
59
61
  return branches;
60
62
  };
61
63
  return async (sourceEvent, outcome) => {
62
- // no referrer, nothing to produce data for (e.g. non-browser callers)
63
- const referrer = outcome.request.headers.get("referer");
64
- if (!referrer)
65
- return undefined;
66
- // a raw body-carrying Response is the caller's verbatim payload — there
67
- // is no envelope to fold data into
68
- if (outcome.value instanceof Response && outcome.value.body)
69
- return undefined;
70
- const origin = new URL(outcome.request.url).origin;
71
- let revalidate;
72
- let url = new URL(referrer).toString();
73
- if (outcome.response) {
74
- if (outcome.response.headers.has("X-Revalidate"))
75
- revalidate = outcome.response.headers.get("X-Revalidate").split(",");
76
- if (outcome.response.headers.has("Location"))
77
- url = new URL(outcome.response.headers.get("Location"), origin + base).toString();
78
- }
79
- // redirects leaving the app can't be collected for
80
- if (new URL(url).origin !== origin)
64
+ // The generic halves arrive pre-digested on the outcome: no target
65
+ // (non-browser caller without a referer, or a redirect leaving the
66
+ // app's origin) means nothing to produce data for.
67
+ const { targetUrl, revalidateKeys } = outcome;
68
+ if (!targetUrl)
81
69
  return undefined;
70
+ // a target implies a referer — it is the fallback target
71
+ const previousUrl = outcome.request.headers.get("referer");
82
72
  // The flight event: the source event (its `response` rides along, so
83
73
  // cookies/headers set during preloads still reach the real response)
84
- // pointed at the target URL, with the mutation's own cookie mutations
85
- // folded into the request, in data-only router mode.
74
+ // pointed at the target URL, with the mutation's cookie effects already
75
+ // folded in (the outcome's `foldedHeaders`), in data-only router mode.
86
76
  const event = { ...sourceEvent };
87
- event.request = new Request(url, { headers: createSingleFlightHeaders(sourceEvent) });
77
+ event.request = new Request(targetUrl, { headers: outcome.foldedHeaders });
88
78
  event.router = {
89
- dataOnly: revalidate || true,
90
- previousUrl: referrer,
79
+ dataOnly: revalidateKeys || true,
80
+ previousUrl,
91
81
  data: {}
92
82
  };
93
83
  return provideRequestEvent(event, async () => {
94
84
  try {
95
- await resolveLazyMatches(resolveBranches, url, referrer);
96
- runPreloads(event, resolveBranches(), url, referrer, rootPreload);
85
+ await resolveLazyMatches(resolveBranches, targetUrl, previousUrl);
86
+ runPreloads(event, resolveBranches(), targetUrl, previousUrl, rootPreload);
97
87
  }
98
88
  catch (error) {
99
89
  console.error(error);
@@ -164,101 +154,3 @@ function runPreloads(event, branches, url, previousUrl, rootPreload) {
164
154
  });
165
155
  }
166
156
  }
167
- /**
168
- * The request headers for the flight-data collection pass: the source
169
- * request's headers with the mutation's `Set-Cookie` mutations folded into
170
- * the `Cookie` header, so preloads observe the post-mutation cookie state
171
- * (deletions honored via Max-Age/Expires).
172
- */
173
- export function createSingleFlightHeaders(sourceEvent) {
174
- const headers = new Headers(sourceEvent.request.headers);
175
- const setCookies = sourceEvent.response?.headers?.getSetCookie() ?? [];
176
- if (!setCookies.length)
177
- return headers;
178
- const cookies = {};
179
- for (const pair of headers.get("cookie")?.split(";") ?? []) {
180
- const eq = pair.indexOf("=");
181
- if (eq > -1)
182
- cookies[pair.slice(0, eq).trim()] = pair.slice(eq + 1).trim();
183
- }
184
- for (const setCookie of setCookies) {
185
- const parsed = parseSetCookie(setCookie);
186
- if (!parsed)
187
- continue;
188
- if ((parsed.maxAge != null && parsed.maxAge <= 0) ||
189
- (parsed.expires != null && parsed.expires.getTime() <= Date.now())) {
190
- delete cookies[parsed.name];
191
- }
192
- else {
193
- cookies[parsed.name] = parsed.value;
194
- }
195
- }
196
- headers.delete("cookie");
197
- const serialized = Object.entries(cookies)
198
- .map(([name, value]) => `${name}=${value}`)
199
- .join("; ");
200
- if (serialized)
201
- headers.set("cookie", serialized);
202
- return headers;
203
- }
204
- function parseSetCookie(setCookie) {
205
- const [pair, ...attributes] = setCookie.split(";");
206
- const eq = pair.indexOf("=");
207
- if (eq < 0)
208
- return undefined;
209
- const parsed = {
210
- name: pair.slice(0, eq).trim(),
211
- value: pair.slice(eq + 1).trim()
212
- };
213
- for (const attribute of attributes) {
214
- const attrEq = attribute.indexOf("=");
215
- const key = (attrEq < 0 ? attribute : attribute.slice(0, attrEq)).trim().toLowerCase();
216
- const value = attrEq < 0 ? "" : attribute.slice(attrEq + 1).trim();
217
- if (key === "max-age")
218
- parsed.maxAge = Number(value);
219
- else if (key === "expires")
220
- parsed.expires = new Date(value);
221
- }
222
- return parsed;
223
- }
224
- // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#redirection_messages
225
- const validRedirectStatuses = new Set([301, 302, 303, 307, 308]);
226
- /**
227
- * Produces the `handleNoJS` implementation for
228
- * `handleServerFunctionRequest` options: form posts made without the client
229
- * runtime redirect back to the referring page (or to the result's
230
- * `Location`) with the outcome riding a one-shot `flash` cookie. The
231
- * router's SSR initialization reads the cookie into submission state, so
232
- * `useSubmission()` renders the result exactly as a scripted submission
233
- * would — progressive enhancement with no app code.
234
- */
235
- export function createNoJSHandler(options = {}) {
236
- const { base = "" } = options;
237
- return function handleNoJS(result, request, args, thrown) {
238
- const url = new URL(request.url);
239
- const back = request.headers.get("referer") || url.origin + base;
240
- // form post -> GET: 303 See Other unless the result names a redirect status
241
- let status = 303;
242
- let headers;
243
- if (result instanceof Response) {
244
- headers = new Headers(result.headers);
245
- if (result.headers.has("Location")) {
246
- headers.set("Location", new URL(result.headers.get("Location"), url.origin + base).toString());
247
- if (validRedirectStatuses.has(result.status))
248
- status = result.status;
249
- }
250
- else {
251
- headers.set("Location", back);
252
- }
253
- }
254
- else {
255
- headers = new Headers({ Location: back });
256
- }
257
- // Responses carry their meaning in their metadata; anything else flashes
258
- // the outcome for the next render's submission state.
259
- if (result && !(result instanceof Response)) {
260
- headers.append("Set-Cookie", encodeFlashCookie(url.pathname + url.search, result, args, thrown));
261
- }
262
- return new Response(null, { status, headers });
263
- };
264
- }
package/dist/types.d.ts CHANGED
@@ -96,19 +96,48 @@ export interface RouterIntegration {
96
96
  utils?: Partial<RouterUtils>;
97
97
  }
98
98
  export type Intent = "initial" | "native" | "navigate" | "preload";
99
- export interface RoutePreloadFuncArgs {
100
- params: Params;
99
+ export interface RoutePreloadFuncArgs<P extends Params = Params> {
100
+ params: P;
101
101
  location: Location;
102
102
  intent: Intent;
103
103
  }
104
- export type RoutePreloadFunc<T = unknown> = (args: RoutePreloadFuncArgs) => T;
105
- export interface RouteSectionProps<T = unknown> {
106
- params: Params;
104
+ export type RoutePreloadFunc<T = unknown, P extends Params = Params> = (args: RoutePreloadFuncArgs<P>) => T;
105
+ export interface RouteSectionProps<T = unknown, P extends Params = Params> {
106
+ params: P;
107
107
  location: Location;
108
108
  data: T;
109
109
  children?: JSX.Element;
110
110
  }
111
- export type RouteSectionComponent<T = unknown> = Component<RouteSectionProps<T>> | Component<Omit<RouteSectionProps<T>, "children">> | Component<{}>;
111
+ export type RouteSectionComponent<T = unknown, P extends Params = Params> = Component<RouteSectionProps<T, P>> | Component<Omit<RouteSectionProps<T, P>, "children">> | Component<{}>;
112
+ declare const ROUTE_PATTERN: unique symbol;
113
+ export interface TypedRouteConfig<S extends string = string> {
114
+ readonly [ROUTE_PATTERN]: S;
115
+ }
116
+ type RouteDataOf<Path> = Path extends TypedRouteConfig & {
117
+ preload?: RoutePreloadFunc<infer T>;
118
+ } ? T : unknown;
119
+ /**
120
+ * Props for a route component declared away from its definition, typed by a
121
+ * path witness — the same `paths` node you navigate with, the pattern string
122
+ * when no instance is in scope, or a `defineFileRoute` config (which also
123
+ * types `data` from its `preload`):
124
+ *
125
+ * ```ts
126
+ * function Story(props: RouteProps<typeof Router.paths.stories>) {}
127
+ * function Story(props: RouteProps<"/stories/:id", StoryData>) {}
128
+ * function Post(props: RouteProps<typeof route>) {} // file-system route files
129
+ * ```
130
+ */
131
+ export type RouteProps<Path, T = RouteDataOf<Path>> = RouteSectionProps<T, Path extends TypedPath<infer P> ? SimplifyRecord<P> & Params : Path extends TypedRouteConfig<infer S> ? RouteParams<S> : RouteParams<Path>>;
132
+ /**
133
+ * Component-type counterpart of `RouteProps` — annotate the component itself
134
+ * and the props parameter infers contextually:
135
+ *
136
+ * ```ts
137
+ * const Post: RouteComponent<typeof route> = props => props.params.id;
138
+ * ```
139
+ */
140
+ export type RouteComponent<Path, T = RouteDataOf<Path>> = Component<RouteProps<Path, T>>;
112
141
  /**
113
142
  * A lazy route subtree: a thunk producing the child definitions — typically
114
143
  * `() => import("./feature/routes")` (the module's `default` or `routes`
@@ -131,15 +160,41 @@ export type RouteDefinition<S extends string | string[] = any, T = any> = {
131
160
  component?: RouteSectionComponent<T>;
132
161
  /** Standard Schema validator for this route's search params; its input type flows into the typed path proxy. */
133
162
  search?: StandardSchemaV1<any, any>;
134
- info?: Record<string, any>;
163
+ info?: RouteInfo;
135
164
  };
165
+ import type { RouteInfo } from "./index.jsx";
166
+ export type { RouteInfo };
136
167
  export type MatchFilter = readonly string[] | RegExp | ((s: string) => boolean);
137
168
  export type PathParams<P extends string | readonly string[]> = P extends `${infer Head}/${infer Tail}` ? [...PathParams<Head>, ...PathParams<Tail>] : P extends `:${infer S}?` ? [S] : P extends `:${infer S}` ? [S] : P extends `*${infer S}` ? [S] : [];
138
169
  export type MatchFilters<P extends string | readonly string[] = any> = P extends string ? {
139
170
  [K in PathParams<P>[number]]?: MatchFilter;
140
171
  } : Record<string, MatchFilter>;
141
- export interface PathMatch {
142
- params: Params;
172
+ export type DefinedRouteFilters<S> = S extends readonly (infer Member extends string)[] ? MatchFilters<Member> : S extends string | readonly string[] ? MatchFilters<S> : MatchFilters;
173
+ type FilterKeysOf<S> = S extends readonly (infer Member extends string)[] ? PathParams<Member>[number] : S extends string ? PathParams<S>[number] : string;
174
+ export type ValidFilters<F, S> = {
175
+ [K in keyof F]: string extends K ? F[K] : K extends FilterKeysOf<S> ? MatchFilter : never;
176
+ };
177
+ type PatternParams<P extends string> = P extends `${infer Head}/${infer Tail}` ? PatternParams<Head> & PatternParams<Tail> : P extends `:${infer Name}?` ? {
178
+ [K in Name]?: string;
179
+ } : P extends `:${infer Name}` ? {
180
+ [K in Name]: string;
181
+ } : P extends `*${infer Name}` ? {
182
+ [K in Name]: string;
183
+ } : {};
184
+ type SimplifyRecord<T> = {
185
+ [K in keyof T]: T[K];
186
+ } & {};
187
+ /**
188
+ * The params a route pattern guarantees, as a precise record — `:id` is
189
+ * `string`, `:tab?` is `string | undefined`, `*rest` is `string`. The record
190
+ * is intersected with the open `Params` shape so params inherited from
191
+ * parent routes stay accessible (as `string | undefined`). Array patterns
192
+ * yield the union of their members' records; non-literal patterns degrade
193
+ * to plain `Params`.
194
+ */
195
+ export type RouteParams<S> = (S extends readonly (infer Member extends string)[] ? SimplifyRecord<PatternParams<Member>> : S extends string ? string extends S ? {} : SimplifyRecord<PatternParams<S>> : {}) & Params;
196
+ export interface PathMatch<P extends Params = Params> {
197
+ params: P;
143
198
  path: string;
144
199
  }
145
200
  export interface RouteMatch extends PathMatch {
@@ -150,7 +205,7 @@ export interface OutputMatch {
150
205
  pattern: string;
151
206
  match: string;
152
207
  params: Params;
153
- info?: Record<string, any>;
208
+ info?: RouteInfo;
154
209
  }
155
210
  export interface RouteDescription {
156
211
  key: unknown;
@@ -160,7 +215,7 @@ export interface RouteDescription {
160
215
  preload?: RoutePreloadFunc;
161
216
  matcher: (location: string) => PathMatch | null;
162
217
  matchFilters?: MatchFilters;
163
- info?: Record<string, any>;
218
+ info?: RouteInfo;
164
219
  /** Present on the placeholder that stands in for an unresolved lazy subtree. */
165
220
  lazy?: LazyBoundary;
166
221
  }
@@ -250,4 +305,3 @@ export type CacheEntry = [number, Promise<any>, any, Intent | undefined, Signal<
250
305
  count: number;
251
306
  }];
252
307
  export type NarrowResponse<T> = T extends ResponseEnvelope<infer U> ? U : Exclude<T, Response>;
253
- export {};
package/package.json CHANGED
@@ -6,7 +6,7 @@
6
6
  "Ryan Turnquist"
7
7
  ],
8
8
  "license": "MIT",
9
- "version": "1.0.0-next.9",
9
+ "version": "2.0.0-next.12",
10
10
  "homepage": "https://github.com/solidjs/solid-router#readme",
11
11
  "repository": {
12
12
  "type": "git",
@@ -23,14 +23,15 @@
23
23
  "solid": "./dist/index.jsx",
24
24
  "default": "./dist/index.js"
25
25
  },
26
- "./server": "./dist/server.js"
26
+ "./server": "./dist/server.js",
27
+ "./fs": "./dist/fs.js"
27
28
  },
28
29
  "files": [
29
30
  "dist"
30
31
  ],
31
32
  "sideEffects": false,
32
33
  "devDependencies": {
33
- "@solidjs/web": "2.0.0-beta.22",
34
+ "@solidjs/web": "2.0.0-beta.28",
34
35
  "@babel/core": "^7.26.0",
35
36
  "@babel/preset-typescript": "^7.26.0",
36
37
  "@changesets/cli": "^2.27.10",
@@ -39,19 +40,19 @@
39
40
  "@rollup/plugin-terser": "0.4.4",
40
41
  "@types/jest": "^29.5.14",
41
42
  "@types/node": "^22.10.0",
42
- "babel-preset-solid": "2.0.0-beta.22",
43
+ "babel-preset-solid": "2.0.0-beta.28",
43
44
  "jsdom": "^25.0.1",
44
45
  "prettier": "^3.4.1",
45
46
  "rollup": "^4.27.4",
46
- "solid-js": "2.0.0-beta.22",
47
+ "solid-js": "2.0.0-beta.28",
47
48
  "typescript": "^5.7.2",
48
49
  "vite": "^6.0.0",
49
50
  "vite-plugin-solid": "3.0.0-next.10",
50
51
  "vitest": "^2.1.6"
51
52
  },
52
53
  "peerDependencies": {
53
- "@solidjs/web": ">=2.0.0-beta.22 <2.0.0-experimental.0",
54
- "solid-js": ">=2.0.0-beta.22 <2.0.0-experimental.0"
54
+ "@solidjs/web": ">=2.0.0-beta.28 <2.0.0-experimental.0",
55
+ "solid-js": ">=2.0.0-beta.28 <2.0.0-experimental.0"
55
56
  },
56
57
  "scripts": {
57
58
  "build": "rm -rf dist && tsc && rollup -c",
@@ -1,21 +0,0 @@
1
- export { FLASH_COOKIE, hasFlashCookie, clearFlashCookie } from "./flashCookie.js";
2
- /** What rides the cookie: a Submission minus its lifecycle methods. */
3
- export interface FlashSubmission {
4
- input: any[];
5
- url: string;
6
- result?: any;
7
- error?: any;
8
- }
9
- /**
10
- * Encodes the outcome of a no-JS submission as a Set-Cookie value. `url` is
11
- * the action url (pathname + search of the server function call) so the
12
- * seeded submission matches `useSubmission` filters; `thrown` errors land on
13
- * `error`, returned values on `result` (mirroring the scripted split).
14
- */
15
- export declare function encodeFlashCookie(url: string, result: any, input: any[], thrown?: boolean): string;
16
- /**
17
- * Decodes the flash cookie out of a request's Cookie header. Returns
18
- * undefined when absent or unreadable (a malformed cookie must never take
19
- * down SSR — it is cleared either way).
20
- */
21
- export declare function decodeFlashCookie(cookieHeader: string | null): FlashSubmission | undefined;
@@ -1,78 +0,0 @@
1
- // The no-JS form convention's cookie codec. When a form posts to a server
2
- // function without the client runtime (no instance header), the server
3
- // handler redirects back carrying the outcome in a one-shot "flash" cookie;
4
- // the next SSR pass reads it and seeds the router's submission state so
5
- // useSubmission() renders the result exactly as a scripted submission would.
6
- // Both codec halves live in this module so the write (src/server.ts, the
7
- // handler's handleNoJS) and the read (provided to the router core by
8
- // data/action.ts) can never drift apart. The cookie's name/clearing live in
9
- // flashCookie.ts — the only piece the router core itself consumes — so this
10
- // codec stays out of bundles that never load the action layer.
11
- import { FLASH_COOKIE, matchFlashCookie } from "./flashCookie.js";
12
- export { FLASH_COOKIE, hasFlashCookie, clearFlashCookie } from "./flashCookie.js";
13
- // Form payloads have no JSON encoding, so entries are captured as pair
14
- // arrays under a marker key ($f / $u) and revived to real FormData /
15
- // URLSearchParams on the way out. File entries cannot ride a cookie and are
16
- // dropped.
17
- function encodeInputValue(value) {
18
- if (value instanceof FormData)
19
- return { $f: [...value.entries()].filter(([, v]) => typeof v === "string") };
20
- if (value instanceof URLSearchParams)
21
- return { $u: [...value.entries()] };
22
- return value;
23
- }
24
- function decodeInputValue(value) {
25
- if (value && typeof value === "object") {
26
- if (Array.isArray(value.$f)) {
27
- const form = new FormData();
28
- for (const [k, v] of value.$f)
29
- form.append(k, v);
30
- return form;
31
- }
32
- if (Array.isArray(value.$u))
33
- return new URLSearchParams(value.$u);
34
- }
35
- return value;
36
- }
37
- /**
38
- * Encodes the outcome of a no-JS submission as a Set-Cookie value. `url` is
39
- * the action url (pathname + search of the server function call) so the
40
- * seeded submission matches `useSubmission` filters; `thrown` errors land on
41
- * `error`, returned values on `result` (mirroring the scripted split).
42
- */
43
- export function encodeFlashCookie(url, result, input, thrown) {
44
- const isError = result instanceof Error;
45
- const payload = {
46
- url,
47
- result: isError ? result.message : result,
48
- error: isError,
49
- thrown: !!thrown,
50
- input: input.map(encodeInputValue)
51
- };
52
- return `${FLASH_COOKIE}=${encodeURIComponent(JSON.stringify(payload))}; Secure; HttpOnly; Path=/`;
53
- }
54
- /**
55
- * Decodes the flash cookie out of a request's Cookie header. Returns
56
- * undefined when absent or unreadable (a malformed cookie must never take
57
- * down SSR — it is cleared either way).
58
- */
59
- export function decodeFlashCookie(cookieHeader) {
60
- const match = matchFlashCookie(cookieHeader);
61
- if (!match)
62
- return;
63
- try {
64
- const payload = JSON.parse(decodeURIComponent(match));
65
- if (!payload || !payload.result)
66
- return;
67
- const result = payload.error ? new Error(payload.result) : payload.result;
68
- return {
69
- input: Array.isArray(payload.input) ? payload.input.map(decodeInputValue) : [],
70
- url: payload.url,
71
- result: payload.thrown ? undefined : result,
72
- error: payload.thrown ? result : undefined
73
- };
74
- }
75
- catch (error) {
76
- console.error(error);
77
- }
78
- }
@@ -1,7 +0,0 @@
1
- export declare const FLASH_COOKIE = "flash";
2
- /** Whether a Cookie header carries a flash cookie (readable or not). */
3
- export declare function hasFlashCookie(cookieHeader: string | null): boolean;
4
- /** The raw encoded flash payload out of a Cookie header, if present. */
5
- export declare function matchFlashCookie(cookieHeader: string | null): string | undefined;
6
- /** The Set-Cookie value clearing the flash cookie after it has been read. */
7
- export declare function clearFlashCookie(): string;
@@ -1,20 +0,0 @@
1
- // The flash cookie's name and one-shot clearing — split from the codec in
2
- // flash.ts so the router core can consume the cookie eagerly (the clear must
3
- // be appended before streaming flushes the response headers, and an unread
4
- // outcome must not haunt a later request) without carrying the encode/decode
5
- // machinery into client bundles that never load the action layer.
6
- export const FLASH_COOKIE = "flash";
7
- const FLASH_MATCHER = new RegExp(`(?:^|;\\s*)${FLASH_COOKIE}=([^;]+)`);
8
- /** Whether a Cookie header carries a flash cookie (readable or not). */
9
- export function hasFlashCookie(cookieHeader) {
10
- return !!cookieHeader && FLASH_MATCHER.test(cookieHeader);
11
- }
12
- /** The raw encoded flash payload out of a Cookie header, if present. */
13
- export function matchFlashCookie(cookieHeader) {
14
- const match = cookieHeader && cookieHeader.match(FLASH_MATCHER);
15
- return match ? match[1] : undefined;
16
- }
17
- /** The Set-Cookie value clearing the flash cookie after it has been read. */
18
- export function clearFlashCookie() {
19
- return `${FLASH_COOKIE}=; Max-Age=0; Path=/`;
20
- }