@ilha/router 0.9.0 → 0.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +32 -16
- package/dist/{plugin-DPGzrIVj.js → plugin-DogkskcY.js} +1 -1
- package/dist/{request-scope-D6_4rqMb.js → request-scope-C4reU4v0.js} +10 -3
- package/dist/request-scope.d.ts +4 -2
- package/dist/rolldown.d.ts +1 -1
- package/dist/rolldown.js +1 -1
- package/dist/rspack.js +1 -1
- package/dist/server-island-registry.js +10 -6
- package/dist/ssr.js +7 -1
- package/dist/vite.js +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -601,7 +601,7 @@ async function withViewSwap(mutate) {
|
|
|
601
601
|
* shape, so all client mount paths handle both sources identically. Loader
|
|
602
602
|
* `head` contributions are dropped, matching the endpoint fetch path.
|
|
603
603
|
*/
|
|
604
|
-
async function runLocalLoader(loader, matchParams, pathWithSearch, signal
|
|
604
|
+
async function runLocalLoader(loader, matchParams, pathWithSearch, signal) {
|
|
605
605
|
const url = new URL(pathWithSearch, location.origin);
|
|
606
606
|
const params = extractParams(matchParams);
|
|
607
607
|
const headEntries = [];
|
|
@@ -624,14 +624,7 @@ async function runLocalLoader(loader, matchParams, pathWithSearch, signal, isCli
|
|
|
624
624
|
};
|
|
625
625
|
}
|
|
626
626
|
if (result.kind === "data") {
|
|
627
|
-
const data =
|
|
628
|
-
...result.data,
|
|
629
|
-
load: {
|
|
630
|
-
loading: false,
|
|
631
|
-
value: result.data ?? {},
|
|
632
|
-
error: void 0
|
|
633
|
-
}
|
|
634
|
-
} : result.data;
|
|
627
|
+
const data = envelopLoad(result.data);
|
|
635
628
|
return headEntries.length > 0 ? {
|
|
636
629
|
kind: "data",
|
|
637
630
|
data,
|
|
@@ -659,7 +652,7 @@ async function fetchLoaderData(pathWithSearch, signal) {
|
|
|
659
652
|
const pathOnly = pathWithSearch.split("?")[0] ?? "";
|
|
660
653
|
const localMatch = matchRoute(_routes, pathOnly);
|
|
661
654
|
const localLoader = localMatch?.data?.clientLoader ?? localMatch?.data?.loader;
|
|
662
|
-
if (localLoader) return runLocalLoader(localLoader, localMatch?.params, pathWithSearch, signal
|
|
655
|
+
if (localLoader) return runLocalLoader(localLoader, localMatch?.params, pathWithSearch, signal);
|
|
663
656
|
const url = `${LOADER_ENDPOINT}?path=${encodeURIComponent(pathWithSearch)}`;
|
|
664
657
|
try {
|
|
665
658
|
const res = await fetch(url, {
|
|
@@ -677,7 +670,12 @@ async function fetchLoaderData(pathWithSearch, signal) {
|
|
|
677
670
|
message: res.statusText
|
|
678
671
|
};
|
|
679
672
|
}
|
|
680
|
-
|
|
673
|
+
const parsed = await res.json();
|
|
674
|
+
if (parsed.kind === "data" && !localMatch?.data?.clientLoader && parsed.data && typeof parsed.data === "object" && !("load" in parsed.data)) return {
|
|
675
|
+
...parsed,
|
|
676
|
+
data: envelopLoad(parsed.data)
|
|
677
|
+
};
|
|
678
|
+
return parsed;
|
|
681
679
|
} catch (e) {
|
|
682
680
|
if (e?.name === "AbortError") throw e;
|
|
683
681
|
return {
|
|
@@ -983,6 +981,14 @@ function activeIsland(value) {
|
|
|
983
981
|
return store ? store.island : _activeIslandSig();
|
|
984
982
|
}
|
|
985
983
|
let _routes = createRouteRegistry();
|
|
984
|
+
/** Wrap loader data in the load envelope (plain, serializable). */
|
|
985
|
+
function envelopLoad(data) {
|
|
986
|
+
return { load: {
|
|
987
|
+
loading: false,
|
|
988
|
+
value: data ?? {},
|
|
989
|
+
error: void 0
|
|
990
|
+
} };
|
|
991
|
+
}
|
|
986
992
|
function createRouteRegistry() {
|
|
987
993
|
return [];
|
|
988
994
|
}
|
|
@@ -1553,8 +1559,10 @@ function loaderAbort(request, timeout) {
|
|
|
1553
1559
|
const ctrl = new AbortController();
|
|
1554
1560
|
const abort = () => ctrl.abort();
|
|
1555
1561
|
const reqSignal = request?.signal;
|
|
1556
|
-
if (reqSignal)
|
|
1557
|
-
|
|
1562
|
+
if (reqSignal) {
|
|
1563
|
+
if (reqSignal.aborted) abort();
|
|
1564
|
+
else reqSignal.addEventListener("abort", abort, { once: true });
|
|
1565
|
+
}
|
|
1558
1566
|
let timer;
|
|
1559
1567
|
if (timeout && timeout > 0) timer = setTimeout(abort, timeout);
|
|
1560
1568
|
return {
|
|
@@ -2068,9 +2076,17 @@ function router(options = {}) {
|
|
|
2068
2076
|
};
|
|
2069
2077
|
}
|
|
2070
2078
|
if (result.kind !== "data") return result;
|
|
2071
|
-
|
|
2072
|
-
return {
|
|
2079
|
+
const enveloped = {
|
|
2073
2080
|
...result,
|
|
2081
|
+
data: { load: {
|
|
2082
|
+
loading: false,
|
|
2083
|
+
value: result.data ?? {},
|
|
2084
|
+
error: void 0
|
|
2085
|
+
} }
|
|
2086
|
+
};
|
|
2087
|
+
if (headStore.entries.length === 0) return enveloped;
|
|
2088
|
+
return {
|
|
2089
|
+
...enveloped,
|
|
2074
2090
|
head: serializeHead(headStore.entries),
|
|
2075
2091
|
headEntries: headStore.entries
|
|
2076
2092
|
};
|
|
@@ -2179,7 +2195,7 @@ function router(options = {}) {
|
|
|
2179
2195
|
head: serializeHead(headStore.entries)
|
|
2180
2196
|
};
|
|
2181
2197
|
}
|
|
2182
|
-
props = result.data;
|
|
2198
|
+
props = envelopLoad(result.data);
|
|
2183
2199
|
}
|
|
2184
2200
|
const name = buildReverseRegistry(registry).get(island);
|
|
2185
2201
|
if (!name) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as runWithIslandRequest } from "./request-scope-
|
|
1
|
+
import { t as runWithIslandRequest } from "./request-scope-C4reU4v0.js";
|
|
2
2
|
import { FrameError, getFrameGuard, renderServerIsland, setFrameGuard } from "./server-island-registry.js";
|
|
3
3
|
import { existsSync, readFileSync, statSync, watch } from "node:fs";
|
|
4
4
|
import { basename, dirname, extname, join, relative, resolve, sep } from "node:path";
|
|
@@ -8,7 +8,7 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
8
8
|
* page SSR through the router, or streamed frames through the plugin's
|
|
9
9
|
* `/__ilha/frame` endpoint. Both seed this scope with the originating
|
|
10
10
|
* `Request`, so render functions can read request data (URL, headers,
|
|
11
|
-
* cookies)
|
|
11
|
+
* cookies) through `useContext().request` or a host integration such as Oxide's `useRequest()`.
|
|
12
12
|
*
|
|
13
13
|
* The storage lives on `globalThis` under `ilha.requestAls` so every module
|
|
14
14
|
* copy (plugin bundle, SSR graph) shares one instance. The public accessor
|
|
@@ -17,10 +17,17 @@ import { AsyncLocalStorage } from "node:async_hooks";
|
|
|
17
17
|
* sole place that constructs it.
|
|
18
18
|
*/
|
|
19
19
|
const REQUEST_ALS_KEY = Symbol.for("ilha.requestAls");
|
|
20
|
-
/**
|
|
20
|
+
/** Installed by oxidejs when its module loads. Lets `useRequest()` resolve
|
|
21
|
+
* inside island renders and frames, not just `/__oxide/action`. */
|
|
22
|
+
const OXIDE_RUN_WITH_REQUEST = Symbol.for("oxidejs.runWithRequest");
|
|
23
|
+
/** Run `fn` with `request` available to `useContext().request`. When oxidejs
|
|
24
|
+
* is loaded, its action scope is entered too, so `useRequest()` works in
|
|
25
|
+
* island renders and streamed frames. */
|
|
21
26
|
function runWithIslandRequest(request, fn) {
|
|
22
27
|
const g = globalThis;
|
|
23
|
-
|
|
28
|
+
const als = g[REQUEST_ALS_KEY] ??= new AsyncLocalStorage();
|
|
29
|
+
const oxide = g[OXIDE_RUN_WITH_REQUEST];
|
|
30
|
+
return als.run(request, () => oxide ? oxide(request, fn) : fn());
|
|
24
31
|
}
|
|
25
32
|
|
|
26
33
|
//#endregion
|
package/dist/request-scope.d.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* page SSR through the router, or streamed frames through the plugin's
|
|
6
6
|
* `/__ilha/frame` endpoint. Both seed this scope with the originating
|
|
7
7
|
* `Request`, so render functions can read request data (URL, headers,
|
|
8
|
-
* cookies)
|
|
8
|
+
* cookies) through `useContext().request` or a host integration such as Oxide's `useRequest()`.
|
|
9
9
|
*
|
|
10
10
|
* The storage lives on `globalThis` under `ilha.requestAls` so every module
|
|
11
11
|
* copy (plugin bundle, SSR graph) shares one instance. The public accessor
|
|
@@ -15,6 +15,8 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import type { IslandContext } from "./index";
|
|
17
17
|
export declare const REQUEST_ALS_KEY: unique symbol;
|
|
18
|
-
/** Run `fn` with `request` available to `useContext().request`.
|
|
18
|
+
/** Run `fn` with `request` available to `useContext().request`. When oxidejs
|
|
19
|
+
* is loaded, its action scope is entered too, so `useRequest()` works in
|
|
20
|
+
* island renders and streamed frames. */
|
|
19
21
|
export declare function runWithIslandRequest<T>(request: Request, fn: () => T): T;
|
|
20
22
|
export type { IslandContext };
|
package/dist/rolldown.d.ts
CHANGED
|
@@ -2,5 +2,5 @@ export type { LayoutHandler, ErrorHandler, RouteSnapshot, AppError } from "./ind
|
|
|
2
2
|
export { ilhaPages, type IlhaPagesOptions } from "./plugin";
|
|
3
3
|
import { type IlhaPagesOptions } from "./plugin";
|
|
4
4
|
/** Rolldown plugin — use via `@ilha/router/rolldown`. */
|
|
5
|
-
export declare function pages(options?: IlhaPagesOptions): import("
|
|
5
|
+
export declare function pages(options?: IlhaPagesOptions): import("rolldown").Plugin<any> | import("rolldown").Plugin<any>[];
|
|
6
6
|
export default pages;
|
package/dist/rolldown.js
CHANGED
package/dist/rspack.js
CHANGED
|
@@ -104,12 +104,16 @@ async function renderServerIsland(id, request, runWithScope) {
|
|
|
104
104
|
const params = entry.pattern ? matchPatternParams(entry.pattern, url.pathname) : {};
|
|
105
105
|
if (!params) throw new FrameError(400, "frame failed");
|
|
106
106
|
try {
|
|
107
|
-
props =
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
107
|
+
props = { load: {
|
|
108
|
+
loading: false,
|
|
109
|
+
value: await entry.load({
|
|
110
|
+
params,
|
|
111
|
+
request,
|
|
112
|
+
url,
|
|
113
|
+
signal: request.signal
|
|
114
|
+
}) ?? {},
|
|
115
|
+
error: void 0
|
|
116
|
+
} };
|
|
113
117
|
} catch (error) {
|
|
114
118
|
const marker = error;
|
|
115
119
|
if (marker.__ilhaRedirect === true) {
|
package/dist/ssr.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as runWithIslandRequest } from "./request-scope-
|
|
1
|
+
import { t as runWithIslandRequest } from "./request-scope-C4reU4v0.js";
|
|
2
2
|
import { FrameError, getFrameGuard, getFrameLoaderRunner, renderServerIsland } from "./server-island-registry.js";
|
|
3
3
|
|
|
4
4
|
//#region src/ssr.ts
|
|
@@ -136,6 +136,12 @@ async function ssr(request) {
|
|
|
136
136
|
method: "POST",
|
|
137
137
|
headers
|
|
138
138
|
});
|
|
139
|
+
for (const sym of Object.getOwnPropertySymbols(request)) {
|
|
140
|
+
if (Symbol.keyFor(sym) === void 0) continue;
|
|
141
|
+
try {
|
|
142
|
+
scoped[sym] = request[sym];
|
|
143
|
+
} catch {}
|
|
144
|
+
}
|
|
139
145
|
return json(200, { html: await renderServerIsland(id, scoped, (scopedRequest, fn) => Promise.resolve(runWithIslandRequest(scopedRequest, fn))) });
|
|
140
146
|
} catch (error) {
|
|
141
147
|
if (error instanceof FrameError) {
|
package/dist/vite.js
CHANGED