@solidjs/router 2.0.0-next.25 → 2.0.0-next.26
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/README.md +2 -0
- package/dist/data/query.js +36 -6
- package/dist/index.js +26 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -519,6 +519,8 @@ getUser.keyFor(5); // "users[5]"
|
|
|
519
519
|
|
|
520
520
|
Revalidate with the `revalidate` export or by setting `revalidate` keys on action responses — the whole key invalidates every entry for the query, `keyFor` invalidates one.
|
|
521
521
|
|
|
522
|
+
A query may also redirect — a guard read that throws or returns `redirect()` (from `@solidjs/web`) navigates instead of resolving: same-origin targets navigate softly with `replace`, other origins leave the document, any `revalidate` keys on the response invalidate first, and the read itself stays pending so nothing renders the redirect as data. This holds for `"use server"` queries too, where the transport carries the redirect to the client rather than letting `fetch` follow it.
|
|
523
|
+
|
|
522
524
|
### `liveQuery` (experimental)
|
|
523
525
|
|
|
524
526
|
`query`'s live sibling: a keyed query over a value-shaped stream. The function is an async iterable (typically an async generator server function) whose yields are successive **values of one logical query** — each yield is the current state, not an event — with the contract that it re-yields current state on every invocation:
|
package/dist/data/query.js
CHANGED
|
@@ -1,15 +1,20 @@
|
|
|
1
1
|
import { createSignal, getObserver, getOwner, onCleanup, sharedConfig, untrack } from "solid-js";
|
|
2
2
|
// Everything server-function-shaped comes off the CORE entry: detection
|
|
3
3
|
// (isServerFunction/getServerFunctionMetadata, registered-symbol reads) and
|
|
4
|
-
// the late-bound RPC seam (getServerFunctionRPC). The
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
4
|
+
// the late-bound RPC seam (getServerFunctionRPC). The transport itself —
|
|
5
|
+
// the fetch RPC client + the seroval codec behind it — is deliberately NOT
|
|
6
|
+
// imported here: query() is in every router app's eager graph, and a static
|
|
7
|
+
// import of `decodeResponse` made every zero-server-function app ship
|
|
8
8
|
// ~9 KB gz of codec it could never invoke. The transport registers itself
|
|
9
9
|
// into the seam when a `'use server'` reference is created (compiled
|
|
10
10
|
// output, module scope), so by the time a server function can reach
|
|
11
11
|
// query() the seam is filled; plain-fetch apps read undefined forever.
|
|
12
12
|
import { getRequestEvent, getServerFunctionMetadata, getServerFunctionRPC, isResponseEnvelope, isServer, isServerFunction, REVALIDATE_HEADER } from "@solidjs/web";
|
|
13
|
+
// The redirect carrier's name and decoder are the exception: two pure,
|
|
14
|
+
// dependency-free bindings off a `sideEffects: false` entry, so they
|
|
15
|
+
// tree-shake to a few hundred bytes without dragging the codec in (the same
|
|
16
|
+
// bindings action.ts already imports statically).
|
|
17
|
+
import { decodeRedirectHeaderValue, REDIRECT_HEADER } from "@solidjs/web/server-functions";
|
|
13
18
|
import { useRouter, getIntent, getInPreloadFn } from "../routing.js";
|
|
14
19
|
const LocationHeader = "Location";
|
|
15
20
|
const PRELOAD_TIMEOUT = 5000;
|
|
@@ -62,7 +67,12 @@ export function revalidate(key, force = true) {
|
|
|
62
67
|
const now = Date.now();
|
|
63
68
|
cacheKeyOp(key, entry => {
|
|
64
69
|
force && (entry[0] = 0); //force cache miss
|
|
65
|
-
|
|
70
|
+
// retrigger live signals. The version is the entry's fetch stamp, and
|
|
71
|
+
// a signal write of an equal value is a no-op — an entry fetched within
|
|
72
|
+
// this same millisecond (a mount whose redirect lands before the clock
|
|
73
|
+
// ticks) would otherwise never be told to refetch, and the surviving
|
|
74
|
+
// consumer paints stale. A sweep must notify unconditionally.
|
|
75
|
+
entry[4][1](v => (v === now ? now + 1 : now));
|
|
66
76
|
});
|
|
67
77
|
const keys = key === undefined ? undefined : Array.isArray(key) ? key : [key];
|
|
68
78
|
for (const hook of revalidateHooks)
|
|
@@ -251,7 +261,27 @@ export function query(fn, name) {
|
|
|
251
261
|
e.response.headers.set(key, value);
|
|
252
262
|
}
|
|
253
263
|
}
|
|
254
|
-
|
|
264
|
+
let url = v.headers.get(LocationHeader);
|
|
265
|
+
// A `"use server"` redirect reaches a client-side read masked: the
|
|
266
|
+
// transport answers scripted callers with a 200, drops `Location`
|
|
267
|
+
// and carries "<status> <absolute-url>" in REDIRECT_HEADER instead.
|
|
268
|
+
// Decode it with the runtime's own reader, as action() does. The
|
|
269
|
+
// carrier arrives RESOLVED to an absolute url, so same-origin vs
|
|
270
|
+
// cross-origin is a real origin comparison: same-origin folds to
|
|
271
|
+
// a path the soft branch below navigates under the router, any
|
|
272
|
+
// other origin keeps its href and the document goes with it. This
|
|
273
|
+
// stays synchronous on purpose — navigate runs in the same tick as
|
|
274
|
+
// the `Location` branch would, so the transition semantics match.
|
|
275
|
+
if (url === null && !isServer && v.headers.has(REDIRECT_HEADER)) {
|
|
276
|
+
const carried = decodeRedirectHeaderValue(v.headers.get(REDIRECT_HEADER));
|
|
277
|
+
if (carried) {
|
|
278
|
+
const target = new URL(carried.url);
|
|
279
|
+
url =
|
|
280
|
+
target.origin === window.location.origin
|
|
281
|
+
? target.pathname + target.search + target.hash
|
|
282
|
+
: target.href;
|
|
283
|
+
}
|
|
284
|
+
}
|
|
255
285
|
if (url !== null) {
|
|
256
286
|
// invalidate the redirect's revalidation keys before navigating so
|
|
257
287
|
// the destination's preloads see the miss and fetch fresh (#580 thread).
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { getOwner, runWithOwner, createMemo, createRenderEffect, onCleanup, untrack, createContext, createSignal, useContext, NotReadyError, isPending, DEV, latest, createComponent, createRoot, Show, createEffect, sharedConfig, OBSERVE, onSettled, getObserver, $TRACK, action as action$1 } from 'solid-js';
|
|
2
2
|
import { registerElementClaim, delegateEvents, isServer, getRequestEvent, hasFlashCookie, clearFlashCookie, createComponent as createComponent$1, memo, isServerFunction, getServerFunctionMetadata, getServerFunctionRPC, isResponseEnvelope, REVALIDATE_HEADER } from '@solidjs/web';
|
|
3
|
-
import {
|
|
3
|
+
import { REDIRECT_HEADER, decodeRedirectHeaderValue, subscribeFlightData, decodeResponsePayload, parseServerFunctionActionUrl, createServerReference } from '@solidjs/web/server-functions';
|
|
4
4
|
import { decodeFlashCookie } from '@solidjs/web/server-functions/server';
|
|
5
5
|
|
|
6
6
|
const hasSchemeRegex = /^(?:[a-z0-9]+:)?\/\//i;
|
|
@@ -2457,7 +2457,12 @@ function revalidate(key, force = true) {
|
|
|
2457
2457
|
const now = Date.now();
|
|
2458
2458
|
cacheKeyOp(key, entry => {
|
|
2459
2459
|
force && (entry[0] = 0); //force cache miss
|
|
2460
|
-
|
|
2460
|
+
// retrigger live signals. The version is the entry's fetch stamp, and
|
|
2461
|
+
// a signal write of an equal value is a no-op — an entry fetched within
|
|
2462
|
+
// this same millisecond (a mount whose redirect lands before the clock
|
|
2463
|
+
// ticks) would otherwise never be told to refetch, and the surviving
|
|
2464
|
+
// consumer paints stale. A sweep must notify unconditionally.
|
|
2465
|
+
entry[4][1](v => v === now ? now + 1 : now);
|
|
2461
2466
|
});
|
|
2462
2467
|
const keys = key === undefined ? undefined : Array.isArray(key) ? key : [key];
|
|
2463
2468
|
for (const hook of revalidateHooks) hook(keys, force);
|
|
@@ -2619,7 +2624,25 @@ function query(fn, name) {
|
|
|
2619
2624
|
if (key == "set-cookie") e.response.headers.append("set-cookie", value);else e.response.headers.set(key, value);
|
|
2620
2625
|
}
|
|
2621
2626
|
}
|
|
2622
|
-
|
|
2627
|
+
let url = v.headers.get(LocationHeader);
|
|
2628
|
+
|
|
2629
|
+
// A `"use server"` redirect reaches a client-side read masked: the
|
|
2630
|
+
// transport answers scripted callers with a 200, drops `Location`
|
|
2631
|
+
// and carries "<status> <absolute-url>" in REDIRECT_HEADER instead.
|
|
2632
|
+
// Decode it with the runtime's own reader, as action() does. The
|
|
2633
|
+
// carrier arrives RESOLVED to an absolute url, so same-origin vs
|
|
2634
|
+
// cross-origin is a real origin comparison: same-origin folds to
|
|
2635
|
+
// a path the soft branch below navigates under the router, any
|
|
2636
|
+
// other origin keeps its href and the document goes with it. This
|
|
2637
|
+
// stays synchronous on purpose — navigate runs in the same tick as
|
|
2638
|
+
// the `Location` branch would, so the transition semantics match.
|
|
2639
|
+
if (url === null && !isServer && v.headers.has(REDIRECT_HEADER)) {
|
|
2640
|
+
const carried = decodeRedirectHeaderValue(v.headers.get(REDIRECT_HEADER));
|
|
2641
|
+
if (carried) {
|
|
2642
|
+
const target = new URL(carried.url);
|
|
2643
|
+
url = target.origin === window.location.origin ? target.pathname + target.search + target.hash : target.href;
|
|
2644
|
+
}
|
|
2645
|
+
}
|
|
2623
2646
|
if (url !== null) {
|
|
2624
2647
|
// invalidate the redirect's revalidation keys before navigating so
|
|
2625
2648
|
// the destination's preloads see the miss and fetch fresh (#580 thread).
|