void 0.7.4 → 0.7.6
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/{better-auth-shared-BrfZ78iY.mjs → better-auth-shared-CjnJZFC0.mjs} +3 -7
- package/dist/cli/cli.mjs +8 -8
- package/dist/{db-RqxhOT2E.mjs → db-DvBg7Oc5.mjs} +1 -1
- package/dist/{deploy-CRIz77mw.mjs → deploy-B5rTuzXw.mjs} +39 -12
- package/dist/index.mjs +463 -34
- package/dist/{init-FMZ29UZW.mjs → init-BiXWyKEf.mjs} +2 -2
- package/dist/pages/client.d.mts +4 -3
- package/dist/pages/client.mjs +18 -6
- package/dist/pages/index.d.mts +1 -1
- package/dist/pages/islands-plugin.d.mts +2 -11
- package/dist/pages/islands-plugin.mjs +1 -63
- package/dist/pages/protocol.d.mts +1 -1
- package/dist/pages/protocol.mjs +101 -12
- package/dist/plugin-inference-CXUuq0aC.mjs +577 -0
- package/dist/{prepare-PqAbhLte.mjs → prepare-BrfiJBju.mjs} +2 -2
- package/dist/{preset-jKn1hQwP.mjs → preset-BhnZpb7t.mjs} +1 -1
- package/dist/{protocol-CK4OFwfR.d.mts → protocol-COz1NHxc.d.mts} +4 -0
- package/dist/runtime/better-auth-pg.mjs +1 -1
- package/dist/runtime/better-auth.mjs +1 -1
- package/dist/{scan-QtRTdh94.mjs → scan-vv5u7rHu.mjs} +1 -1
- package/dist/{types-AdKzPp2C.d.mts → types-D6AuY5Bf.d.mts} +9 -1
- package/package.json +3 -3
- package/skills/void/docs/guide/pages-routing/overview.md +11 -0
- package/skills/void/docs/reference/api.md +8 -4
- package/dist/plugin-inference-CCtRkt9O.mjs +0 -2476
package/dist/pages/client.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as PageObject } from "../protocol-
|
|
1
|
+
import { t as PageObject } from "../protocol-COz1NHxc.mjs";
|
|
2
2
|
import { CacheForInput, CacheForResult } from "./prefetch.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/pages/action-result.d.ts
|
|
@@ -147,6 +147,7 @@ interface VoidRouter {
|
|
|
147
147
|
readonly url: URL;
|
|
148
148
|
readonly path: string;
|
|
149
149
|
readonly query: URLSearchParams;
|
|
150
|
+
readonly params: Record<string, string>;
|
|
150
151
|
visit(url: string | URL, options?: VisitOptions): Promise<unknown>;
|
|
151
152
|
refresh(options?: VisitOptions): Promise<unknown>;
|
|
152
153
|
prefetch(url: string | URL, options?: PrefetchOptions): Promise<unknown>;
|
|
@@ -178,8 +179,8 @@ interface VoidRouterConfig {
|
|
|
178
179
|
onNavigationChange?(navigation: NavigationState): void;
|
|
179
180
|
}
|
|
180
181
|
declare function idleNavigationState(): NavigationState;
|
|
181
|
-
declare function createRouterFacade(router: VoidRouter, getCurrentUrl: () => string): VoidRouter;
|
|
182
|
-
declare function createSsrRouter(url?: string): VoidRouter;
|
|
182
|
+
declare function createRouterFacade(router: VoidRouter, getCurrentUrl: () => string, getCurrentParams?: () => Record<string, string>): VoidRouter;
|
|
183
|
+
declare function createSsrRouter(url?: string, params?: Record<string, string>): VoidRouter;
|
|
183
184
|
declare function isFile(value: unknown): boolean;
|
|
184
185
|
declare function hasFiles(data: unknown): boolean;
|
|
185
186
|
declare function objectToFormData(source: Record<string, unknown>, form?: FormData, parentKey?: string): FormData;
|
package/dist/pages/client.mjs
CHANGED
|
@@ -756,7 +756,7 @@ function idleNavigationState() {
|
|
|
756
756
|
method: null
|
|
757
757
|
};
|
|
758
758
|
}
|
|
759
|
-
function createRouterFacade(router, getCurrentUrl) {
|
|
759
|
+
function createRouterFacade(router, getCurrentUrl, getCurrentParams = () => router.params) {
|
|
760
760
|
return {
|
|
761
761
|
get _hoverDelay() {
|
|
762
762
|
return router._hoverDelay;
|
|
@@ -770,6 +770,9 @@ function createRouterFacade(router, getCurrentUrl) {
|
|
|
770
770
|
get query() {
|
|
771
771
|
return this.url.searchParams;
|
|
772
772
|
},
|
|
773
|
+
get params() {
|
|
774
|
+
return getCurrentParams();
|
|
775
|
+
},
|
|
773
776
|
visit(url, options = {}) {
|
|
774
777
|
return router.visit(url, options);
|
|
775
778
|
},
|
|
@@ -787,7 +790,7 @@ function createRouterFacade(router, getCurrentUrl) {
|
|
|
787
790
|
}
|
|
788
791
|
};
|
|
789
792
|
}
|
|
790
|
-
function createSsrRouter(url = "/") {
|
|
793
|
+
function createSsrRouter(url = "/", params = {}) {
|
|
791
794
|
return {
|
|
792
795
|
_hoverDelay: 75,
|
|
793
796
|
get url() {
|
|
@@ -799,6 +802,9 @@ function createSsrRouter(url = "/") {
|
|
|
799
802
|
get query() {
|
|
800
803
|
return this.url.searchParams;
|
|
801
804
|
},
|
|
805
|
+
get params() {
|
|
806
|
+
return params;
|
|
807
|
+
},
|
|
802
808
|
visit() {
|
|
803
809
|
throw new Error("Void Router: visit() is not available during SSR.");
|
|
804
810
|
},
|
|
@@ -870,9 +876,11 @@ async function createVoidRouter(config) {
|
|
|
870
876
|
{
|
|
871
877
|
const engine = await createPageNavigationEngine(config);
|
|
872
878
|
let routeUrl = currentUrl();
|
|
879
|
+
let routeParams = engine.initialPageData.params ?? {};
|
|
873
880
|
let activeNavigationId = null;
|
|
874
|
-
const
|
|
881
|
+
const setRouteState = (url, params = routeParams) => {
|
|
875
882
|
routeUrl = url;
|
|
883
|
+
routeParams = params;
|
|
876
884
|
config.onRouteChange?.(url);
|
|
877
885
|
};
|
|
878
886
|
const setNavigation = (navigation) => {
|
|
@@ -884,11 +892,12 @@ async function createVoidRouter(config) {
|
|
|
884
892
|
try {
|
|
885
893
|
const result = await resource.shell;
|
|
886
894
|
if (!result) return;
|
|
895
|
+
setRouteState(result.pageData.url || resource.fetchUrl + resource.hash, result.pageData.params ?? {});
|
|
887
896
|
const applyUpdate = () => config.adapter.applyUpdate(result.pageData, result.component, result.layouts);
|
|
888
897
|
if ((resource.options.viewTransition ?? config.viewTransitions) && document.startViewTransition) await document.startViewTransition(() => applyUpdate()).updateCallbackDone;
|
|
889
898
|
else await applyUpdate();
|
|
890
899
|
await resource.commit();
|
|
891
|
-
if (activeNavigationId === resource.id)
|
|
900
|
+
if (activeNavigationId === resource.id) setRouteState(currentUrl(), result.pageData.params ?? {});
|
|
892
901
|
return result.pageData;
|
|
893
902
|
} catch (error) {
|
|
894
903
|
if (resource.method.toUpperCase() === "GET" && !resource.options._resolveOnShell && isAbortError(error)) return;
|
|
@@ -896,7 +905,7 @@ async function createVoidRouter(config) {
|
|
|
896
905
|
} finally {
|
|
897
906
|
if (activeNavigationId === resource.id) {
|
|
898
907
|
activeNavigationId = null;
|
|
899
|
-
|
|
908
|
+
setRouteState(currentUrl());
|
|
900
909
|
setNavigation(idleNavigationState());
|
|
901
910
|
}
|
|
902
911
|
}
|
|
@@ -912,6 +921,9 @@ async function createVoidRouter(config) {
|
|
|
912
921
|
get query() {
|
|
913
922
|
return this.url.searchParams;
|
|
914
923
|
},
|
|
924
|
+
get params() {
|
|
925
|
+
return routeParams;
|
|
926
|
+
},
|
|
915
927
|
visit(url, options = {}) {
|
|
916
928
|
return applyNavigationResource(engine.prepareVisit(normalizeUrl(url), options));
|
|
917
929
|
},
|
|
@@ -932,7 +944,7 @@ async function createVoidRouter(config) {
|
|
|
932
944
|
engine.flushAll();
|
|
933
945
|
}
|
|
934
946
|
};
|
|
935
|
-
const router = createRouterFacade(rawRouter, () => routeUrl);
|
|
947
|
+
const router = createRouterFacade(rawRouter, () => routeUrl, () => routeParams);
|
|
936
948
|
engine.setPopStateHandler((url, options) => {
|
|
937
949
|
router.visit(url, options);
|
|
938
950
|
});
|
package/dist/pages/index.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { a as renderHtmlAttrs, i as renderHeadToString, n as HeadDescriptor, o as resolveHead, r as renderBodyAttrs, t as HeadConfig } from "../head-CZGAunBV.mjs";
|
|
2
|
-
import {
|
|
2
|
+
import { a as PageScanResult, i as PageDefinition, n as LayoutDefinition, r as NamedLayoutDefinition } from "../types-D6AuY5Bf.mjs";
|
|
3
3
|
import { serializePageData } from "./serialize.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/pages/layout-resolution.d.ts
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { a as PageScanResult } from "../types-D6AuY5Bf.mjs";
|
|
2
2
|
import { ResolvedConfig, ViteDevServer } from "vite";
|
|
3
3
|
|
|
4
4
|
//#region src/pages/islands-plugin.d.ts
|
|
@@ -17,8 +17,6 @@ declare function resolveSpecifier(specifier: string, importerDir: string, extens
|
|
|
17
17
|
* or any .md file has a `<script>` block.
|
|
18
18
|
*/
|
|
19
19
|
declare function needsIslandClientBundle(dir: string, islandFilePattern: RegExp, checkStyleBlocks: boolean): boolean;
|
|
20
|
-
/** Check if a file has CSS import statements (JS-style imports). */
|
|
21
|
-
declare function fileHasCssImports(filePath: string): boolean;
|
|
22
20
|
/**
|
|
23
21
|
* Rewrite a matched CSS import line so relative specifiers resolve from the
|
|
24
22
|
* virtual module. Absolute and bare specifiers are kept as-is.
|
|
@@ -26,16 +24,9 @@ declare function fileHasCssImports(filePath: string): boolean;
|
|
|
26
24
|
declare function rewriteCssImportForVirtualModule(matchedLine: string, specifier: string, sourceFilePath: string): string;
|
|
27
25
|
/** Extract CSS import statements from a file and return them as @import rules. */
|
|
28
26
|
declare function extractCssImports(filePath: string): string;
|
|
29
|
-
/** Rebuild islandCssMap from current file contents. */
|
|
30
|
-
declare function rebuildIslandCssMap(pageScan: PageScanResult, pagesDir: string, islandCssMap: Map<string, Array<string>>, fileHasCssFn: (filePath: string) => boolean): void;
|
|
31
27
|
/** Compute which island pages need client-side JavaScript. */
|
|
32
28
|
declare function computePagesNeedingClientJS(pageScan: PageScanResult, pagesDir: string, resolvedConfig: ResolvedConfig | null): Set<string>;
|
|
33
29
|
/**
|
|
34
|
-
* Configure the Vite dev server for island CSS serving.
|
|
35
|
-
* Sets up file watching and a middleware for serving virtual CSS modules.
|
|
36
|
-
*/
|
|
37
|
-
declare function configureIslandCssServer(server: ViteDevServer, islandCssFiles: Set<string>, viteRoot: string, rebuildCssMap: () => void): void;
|
|
38
|
-
/**
|
|
39
30
|
* Watch the pages directory for structural changes (add/remove) and .md content
|
|
40
31
|
* changes (frontmatter layout field) so that new layouts and named layouts are
|
|
41
32
|
* picked up without a dev server restart.
|
|
@@ -47,4 +38,4 @@ declare function watchPagesForRescan(server: ViteDevServer, pagesDir: string, ro
|
|
|
47
38
|
flush: () => Promise<void>;
|
|
48
39
|
};
|
|
49
40
|
//#endregion
|
|
50
|
-
export { ISLANDS_CLIENT_ENTRY_ID, ISLANDS_RENDERER_ID, IslandEntry, computePagesNeedingClientJS,
|
|
41
|
+
export { ISLANDS_CLIENT_ENTRY_ID, ISLANDS_RENDERER_ID, IslandEntry, computePagesNeedingClientJS, extractCssImports, needsIslandClientBundle, resolveSpecifier, rewriteCssImportForVirtualModule, watchPagesForRescan };
|
|
@@ -43,15 +43,6 @@ function needsIslandClientBundle(dir, islandFilePattern, checkStyleBlocks) {
|
|
|
43
43
|
} catch {}
|
|
44
44
|
return false;
|
|
45
45
|
}
|
|
46
|
-
/** Check if a file has CSS import statements (JS-style imports). */
|
|
47
|
-
function fileHasCssImports(filePath) {
|
|
48
|
-
try {
|
|
49
|
-
const code = readFileSync(filePath, "utf-8");
|
|
50
|
-
return /import\b[^"']*["'][^"']+\.(?:css|scss|sass|less|styl|stylus|pcss|postcss)["']/.test(code);
|
|
51
|
-
} catch {
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
46
|
/**
|
|
56
47
|
* Rewrite a matched CSS import line so relative specifiers resolve from the
|
|
57
48
|
* virtual module. Absolute and bare specifiers are kept as-is.
|
|
@@ -72,22 +63,6 @@ function extractCssImports(filePath) {
|
|
|
72
63
|
while ((match = re.exec(code)) !== null) imports.push(`@import ${JSON.stringify(match[1])};`);
|
|
73
64
|
return imports.join("\n");
|
|
74
65
|
}
|
|
75
|
-
/** Rebuild islandCssMap from current file contents. */
|
|
76
|
-
function rebuildIslandCssMap(pageScan, pagesDir, islandCssMap, fileHasCssFn) {
|
|
77
|
-
islandCssMap.clear();
|
|
78
|
-
for (const page of pageScan.pages) {
|
|
79
|
-
if (!page.island) continue;
|
|
80
|
-
const cssPaths = [];
|
|
81
|
-
const layoutChain = resolveEffectiveLayoutChain(page, pageScan.layouts, pageScan.namedLayouts);
|
|
82
|
-
for (const layout of layoutChain) {
|
|
83
|
-
const layoutPath = resolve(pagesDir, layout.filePath);
|
|
84
|
-
if (fileHasCssFn(layoutPath)) cssPaths.push(layoutPath);
|
|
85
|
-
}
|
|
86
|
-
const pagePath = resolve(pagesDir, page.componentPath);
|
|
87
|
-
if (fileHasCssFn(pagePath)) cssPaths.push(pagePath);
|
|
88
|
-
if (cssPaths.length > 0) islandCssMap.set(page.componentId, cssPaths);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
66
|
/** Compute which island pages need client-side JavaScript. */
|
|
92
67
|
function computePagesNeedingClientJS(pageScan, pagesDir, resolvedConfig) {
|
|
93
68
|
const mdPlugin = resolvedConfig?.plugins?.find((plugin) => plugin.name === "void-md");
|
|
@@ -122,43 +97,6 @@ function computePagesNeedingClientJS(pageScan, pagesDir, resolvedConfig) {
|
|
|
122
97
|
return result;
|
|
123
98
|
}
|
|
124
99
|
/**
|
|
125
|
-
* Configure the Vite dev server for island CSS serving.
|
|
126
|
-
* Sets up file watching and a middleware for serving virtual CSS modules.
|
|
127
|
-
*/
|
|
128
|
-
function configureIslandCssServer(server, islandCssFiles, viteRoot, rebuildCssMap) {
|
|
129
|
-
server.watcher.on("change", (path) => {
|
|
130
|
-
const normalizedPath = normalizePath(path);
|
|
131
|
-
if (!islandCssFiles.has(normalizedPath)) return;
|
|
132
|
-
rebuildCssMap();
|
|
133
|
-
for (const env of Object.values(server.environments)) {
|
|
134
|
-
const mod = env.moduleGraph.getModuleById("\0" + ISLANDS_RENDERER_ID);
|
|
135
|
-
if (mod) env.moduleGraph.invalidateModule(mod);
|
|
136
|
-
}
|
|
137
|
-
const cssMod = server.environments.client?.moduleGraph.getModuleById(normalizedPath + ".css");
|
|
138
|
-
if (cssMod) server.environments.client.moduleGraph.invalidateModule(cssMod);
|
|
139
|
-
});
|
|
140
|
-
server.middlewares.use(async (req, res, next) => {
|
|
141
|
-
if (!req.url) return next();
|
|
142
|
-
const url = req.url.split("?")[0];
|
|
143
|
-
if (!url.endsWith(".css")) return next();
|
|
144
|
-
const srcPath = normalizePath(resolve(viteRoot, url.slice(1, -4)));
|
|
145
|
-
if (!islandCssFiles.has(srcPath)) return next();
|
|
146
|
-
try {
|
|
147
|
-
const result = await server.environments.client.transformRequest(url);
|
|
148
|
-
if (result) {
|
|
149
|
-
const m = result.code.match(/\b__vite__css\s*=\s*("(?:[^"\\]|\\.)*")/) || result.code.match(/export\s+default\s+("(?:[^"\\]|\\.)*")/);
|
|
150
|
-
if (m) {
|
|
151
|
-
res.setHeader("Content-Type", "text/css");
|
|
152
|
-
res.statusCode = 200;
|
|
153
|
-
res.end(JSON.parse(m[1]));
|
|
154
|
-
return;
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
} catch {}
|
|
158
|
-
next();
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
/**
|
|
162
100
|
* Watch the pages directory for structural changes (add/remove) and .md content
|
|
163
101
|
* changes (frontmatter layout field) so that new layouts and named layouts are
|
|
164
102
|
* picked up without a dev server restart.
|
|
@@ -192,4 +130,4 @@ function watchPagesForRescan(server, pagesDir, root, onRescan) {
|
|
|
192
130
|
return { flush: () => pending ?? Promise.resolve() };
|
|
193
131
|
}
|
|
194
132
|
//#endregion
|
|
195
|
-
export { ISLANDS_CLIENT_ENTRY_ID, ISLANDS_RENDERER_ID, computePagesNeedingClientJS,
|
|
133
|
+
export { ISLANDS_CLIENT_ENTRY_ID, ISLANDS_RENDERER_ID, computePagesNeedingClientJS, extractCssImports, needsIslandClientBundle, resolveSpecifier, rewriteCssImportForVirtualModule, watchPagesForRescan };
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { S as ValidationError } from "../handler-dKQWyF-G.mjs";
|
|
2
|
-
import { a as handlePageMutation, i as handlePageGet, n as PageRenderResult, o as safeJsonStringify, r as flattenValidationErrors, t as PageObject } from "../protocol-
|
|
2
|
+
import { a as handlePageMutation, i as handlePageGet, n as PageRenderResult, o as safeJsonStringify, r as flattenValidationErrors, t as PageObject } from "../protocol-COz1NHxc.mjs";
|
|
3
3
|
export { PageObject, PageRenderResult, ValidationError, flattenValidationErrors, handlePageGet, handlePageMutation, safeJsonStringify };
|
package/dist/pages/protocol.mjs
CHANGED
|
@@ -3,6 +3,7 @@ import { i as ValidationError, r as separateDeferred, t as DEFERRED } from "../d
|
|
|
3
3
|
import { resolveHead } from "./head.mjs";
|
|
4
4
|
//#region src/pages/protocol.ts
|
|
5
5
|
const POWERED_BY = { "X-Powered-By": "Void" };
|
|
6
|
+
const RENDER_ERROR_ASSET_TAGS_KEY = "__voidPageAssetTags";
|
|
6
7
|
/** Escape characters that are unsafe inside inline <script> tags to prevent XSS. */
|
|
7
8
|
function safeJsonStringify(value) {
|
|
8
9
|
return (JSON.stringify(value) ?? "null").replaceAll("<", "\\u003c").replaceAll(">", "\\u003e").replaceAll("&", "\\u0026").replaceAll("\u2028", "\\u2028").replaceAll("\u2029", "\\u2029");
|
|
@@ -15,6 +16,85 @@ function pageResponseHeaders(c, headers) {
|
|
|
15
16
|
for (const [key, value] of Object.entries(headers)) out.set(key, value);
|
|
16
17
|
return out;
|
|
17
18
|
}
|
|
19
|
+
function escapeHtmlAttr(value) {
|
|
20
|
+
return value.replaceAll("&", "&").replaceAll("\"", """).replaceAll("<", "<");
|
|
21
|
+
}
|
|
22
|
+
function serializeStyleCss(css) {
|
|
23
|
+
return css.replace(/<\/style/gi, "<\\/style");
|
|
24
|
+
}
|
|
25
|
+
function serializeDevCssAssets(assets, nonce) {
|
|
26
|
+
return assets.map((asset) => `<style data-vite-dev-id="${escapeHtmlAttr(asset.id ?? asset.url)}" nonce="${escapeHtmlAttr(nonce)}">${serializeStyleCss(asset.css)}</style>`).join("\n");
|
|
27
|
+
}
|
|
28
|
+
function hasCompatibleStyleSource(value, nonceSource) {
|
|
29
|
+
return value === "'unsafe-inline'" || value === nonceSource;
|
|
30
|
+
}
|
|
31
|
+
function adjustCspValue(value, nonce) {
|
|
32
|
+
const nonceSource = `'nonce-${nonce}'`;
|
|
33
|
+
const parsed = value.split(";").map((part) => part.trim()).filter(Boolean).map((directive) => {
|
|
34
|
+
const [name = "", ...sources] = directive.split(/\s+/);
|
|
35
|
+
return {
|
|
36
|
+
name: name.toLowerCase(),
|
|
37
|
+
originalName: name,
|
|
38
|
+
sources
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
const styleElem = parsed.find((directive) => directive.name === "style-src-elem");
|
|
42
|
+
if (styleElem) {
|
|
43
|
+
if (!styleElem.sources.some((source) => hasCompatibleStyleSource(source, nonceSource))) styleElem.sources.push(nonceSource);
|
|
44
|
+
return parsed.map((directive) => [directive.originalName, ...directive.sources].join(" ")).join("; ");
|
|
45
|
+
}
|
|
46
|
+
const style = parsed.find((directive) => directive.name === "style-src");
|
|
47
|
+
if (style) {
|
|
48
|
+
if (!style.sources.some((source) => hasCompatibleStyleSource(source, nonceSource))) style.sources.push(nonceSource);
|
|
49
|
+
return parsed.map((directive) => [directive.originalName, ...directive.sources].join(" ")).join("; ");
|
|
50
|
+
}
|
|
51
|
+
const defaultSrc = parsed.find((directive) => directive.name === "default-src");
|
|
52
|
+
if (defaultSrc) {
|
|
53
|
+
parsed.push({
|
|
54
|
+
name: "style-src",
|
|
55
|
+
originalName: "style-src",
|
|
56
|
+
sources: [...defaultSrc.sources, nonceSource]
|
|
57
|
+
});
|
|
58
|
+
return parsed.map((directive) => [directive.originalName, ...directive.sources].join(" ")).join("; ");
|
|
59
|
+
}
|
|
60
|
+
parsed.push({
|
|
61
|
+
name: "style-src",
|
|
62
|
+
originalName: "style-src",
|
|
63
|
+
sources: [nonceSource]
|
|
64
|
+
});
|
|
65
|
+
return parsed.map((directive) => [directive.originalName, ...directive.sources].join(" ")).join("; ");
|
|
66
|
+
}
|
|
67
|
+
function adjustDevCssCsp(headers, nonce) {
|
|
68
|
+
if (!nonce) return headers;
|
|
69
|
+
const csp = headers.get("content-security-policy");
|
|
70
|
+
if (csp) headers.set("content-security-policy", adjustCspValue(csp, nonce));
|
|
71
|
+
const cspReportOnly = headers.get("content-security-policy-report-only");
|
|
72
|
+
if (cspReportOnly) headers.set("content-security-policy-report-only", adjustCspValue(cspReportOnly, nonce));
|
|
73
|
+
return headers;
|
|
74
|
+
}
|
|
75
|
+
function prepareAssetTags(assetTags) {
|
|
76
|
+
if (!assetTags.devCss || assetTags.devCss.length === 0) return assetTags;
|
|
77
|
+
const nonce = crypto.randomUUID().replaceAll("-", "");
|
|
78
|
+
return {
|
|
79
|
+
...assetTags,
|
|
80
|
+
css: [assetTags.css, serializeDevCssAssets(assetTags.devCss, nonce)].filter(Boolean).join("\n"),
|
|
81
|
+
devCssNonce: nonce
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
function attachRenderErrorAssetTags(error, assetTags) {
|
|
85
|
+
if ((typeof error === "object" || typeof error === "function") && error !== null) Object.defineProperty(error, RENDER_ERROR_ASSET_TAGS_KEY, {
|
|
86
|
+
configurable: true,
|
|
87
|
+
value: assetTags
|
|
88
|
+
});
|
|
89
|
+
throw error;
|
|
90
|
+
}
|
|
91
|
+
async function renderWithAssetTags(renderFn, pageObj, assetTags) {
|
|
92
|
+
try {
|
|
93
|
+
return await renderFn(pageObj, assetTags);
|
|
94
|
+
} catch (error) {
|
|
95
|
+
attachRenderErrorAssetTags(error, assetTags);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
18
98
|
function pageJsonResponse(c, pageObj) {
|
|
19
99
|
return Response.json(pageObj, { headers: pageResponseHeaders(c, {
|
|
20
100
|
"X-VoidPages": "true",
|
|
@@ -25,6 +105,9 @@ function pageJsonResponse(c, pageObj) {
|
|
|
25
105
|
function requestPathWithSearch(c) {
|
|
26
106
|
return c.req.path + new URL(c.req.url).search;
|
|
27
107
|
}
|
|
108
|
+
function requestParams(c) {
|
|
109
|
+
return c.req.param();
|
|
110
|
+
}
|
|
28
111
|
/** Extract props from a handler result, handling Response wrapping from withValidator */
|
|
29
112
|
async function extractProps(result) {
|
|
30
113
|
if (result instanceof Response) {
|
|
@@ -62,14 +145,14 @@ async function writeRenderResult(writer, encoder, result) {
|
|
|
62
145
|
await writer.write(value);
|
|
63
146
|
}
|
|
64
147
|
}
|
|
65
|
-
function renderedResponse(c, result, contentType) {
|
|
66
|
-
return new Response(result, { headers: pageResponseHeaders(c, {
|
|
148
|
+
function renderedResponse(c, result, contentType, assetTags) {
|
|
149
|
+
return new Response(result, { headers: adjustDevCssCsp(pageResponseHeaders(c, {
|
|
67
150
|
"content-type": contentType,
|
|
68
151
|
...POWERED_BY
|
|
69
|
-
}) });
|
|
152
|
+
}), assetTags?.devCssNonce) });
|
|
70
153
|
}
|
|
71
154
|
/** Build a streaming response that sends an initial chunk then streams deferred results. */
|
|
72
|
-
function streamDeferredResponse(initialChunk, deferredMap, c, contentType, formatResolved, formatRejected) {
|
|
155
|
+
function streamDeferredResponse(initialChunk, deferredMap, c, contentType, formatResolved, formatRejected, assetTags) {
|
|
73
156
|
const encoder = new TextEncoder();
|
|
74
157
|
const { readable, writable } = new TransformStream();
|
|
75
158
|
const writer = writable.getWriter();
|
|
@@ -81,10 +164,10 @@ function streamDeferredResponse(initialChunk, deferredMap, c, contentType, forma
|
|
|
81
164
|
})().catch((error) => {
|
|
82
165
|
writer.abort(error).catch(() => {});
|
|
83
166
|
});
|
|
84
|
-
return new Response(readable, { headers: pageResponseHeaders(c, {
|
|
167
|
+
return new Response(readable, { headers: adjustDevCssCsp(pageResponseHeaders(c, {
|
|
85
168
|
"content-type": contentType,
|
|
86
169
|
...POWERED_BY
|
|
87
|
-
}) });
|
|
170
|
+
}), assetTags?.devCssNonce) });
|
|
88
171
|
}
|
|
89
172
|
/** Handle GET page request — run handler, return page object or SSR HTML */
|
|
90
173
|
async function handlePageGet(handler, headFn, c, componentId, renderFn, getAssetTags, configHead, island) {
|
|
@@ -107,6 +190,7 @@ async function handlePageGet(handler, headFn, c, componentId, renderFn, getAsset
|
|
|
107
190
|
const pageObj = {
|
|
108
191
|
component: componentId,
|
|
109
192
|
props: immediateProps,
|
|
193
|
+
params: requestParams(c),
|
|
110
194
|
shared,
|
|
111
195
|
url: requestPathWithSearch(c),
|
|
112
196
|
errors: null,
|
|
@@ -146,9 +230,10 @@ async function handlePageGet(handler, headFn, c, componentId, renderFn, getAsset
|
|
|
146
230
|
error
|
|
147
231
|
}) + "\n");
|
|
148
232
|
}
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
return
|
|
233
|
+
const assetTags = prepareAssetTags(await getAssetTags(c.req.raw, c.env, componentId));
|
|
234
|
+
const html = await renderWithAssetTags(renderFn, pageObj, assetTags);
|
|
235
|
+
if (!hasDeferred) return renderedResponse(c, html, "text/html; charset=utf-8", assetTags);
|
|
236
|
+
return streamDeferredResponse(html, deferredMap, c, "text/html; charset=utf-8", (group, data) => `\n<script>window.__resolveDeferred?window.__resolveDeferred(${safeJsonStringify(group)},${safeJsonStringify(data)}):(window.__deferredQueue??=[]).push([${safeJsonStringify(group)},${safeJsonStringify(data)}])<\/script>`, (group, error) => `\n<script>window.__rejectDeferred?window.__rejectDeferred(${safeJsonStringify(group)},${safeJsonStringify(error)}):(window.__deferredQueue??=[]).push([${safeJsonStringify(group)},0,${safeJsonStringify(error)}])<\/script>`, assetTags);
|
|
152
237
|
}
|
|
153
238
|
/** Handle POST/PUT/DELETE page request — run mutation, then re-run GET or redirect */
|
|
154
239
|
async function handlePageMutation(mutationHandler, getHandler, headFn, c, componentId, renderFn, getAssetTags, configHead, island) {
|
|
@@ -159,6 +244,7 @@ async function handlePageMutation(mutationHandler, getHandler, headFn, c, compon
|
|
|
159
244
|
return {
|
|
160
245
|
component: componentId,
|
|
161
246
|
props,
|
|
247
|
+
params: requestParams(c),
|
|
162
248
|
shared,
|
|
163
249
|
url: requestPathWithSearch(c),
|
|
164
250
|
errors,
|
|
@@ -173,7 +259,8 @@ async function handlePageMutation(mutationHandler, getHandler, headFn, c, compon
|
|
|
173
259
|
if (island) return Response.json({ errors: e.errors }, { status: 422 });
|
|
174
260
|
const pageObj = buildMutationPageObj(stripDeferred(getHandler ? await extractProps(await getHandler(c)) : {}), e.errors);
|
|
175
261
|
if (isPagesRequest(c)) return pageJsonResponse(c, pageObj);
|
|
176
|
-
|
|
262
|
+
const assetTags = prepareAssetTags(await getAssetTags(c.req.raw, c.env, componentId));
|
|
263
|
+
return renderedResponse(c, await renderWithAssetTags(renderFn, pageObj, assetTags), "text/html; charset=utf-8", assetTags);
|
|
177
264
|
}
|
|
178
265
|
throw e;
|
|
179
266
|
}
|
|
@@ -185,14 +272,16 @@ async function handlePageMutation(mutationHandler, getHandler, headFn, c, compon
|
|
|
185
272
|
if (island) return Response.json({ errors }, { status: 422 });
|
|
186
273
|
const pageObj = buildMutationPageObj(stripDeferred(getHandler ? await extractProps(await getHandler(c)) : {}), errors);
|
|
187
274
|
if (isPagesRequest(c)) return pageJsonResponse(c, pageObj);
|
|
188
|
-
|
|
275
|
+
const assetTags = prepareAssetTags(await getAssetTags(c.req.raw, c.env, componentId));
|
|
276
|
+
return renderedResponse(c, await renderWithAssetTags(renderFn, pageObj, assetTags), "text/html; charset=utf-8", assetTags);
|
|
189
277
|
}
|
|
190
278
|
if (status !== 204) return result;
|
|
191
279
|
}
|
|
192
280
|
if (island) return Response.json({ success: true });
|
|
193
281
|
const pageObj = buildMutationPageObj(stripDeferred(getHandler ? await extractProps(await getHandler(c)) : {}), null);
|
|
194
282
|
if (isPagesRequest(c)) return pageJsonResponse(c, pageObj);
|
|
195
|
-
|
|
283
|
+
const assetTags = prepareAssetTags(await getAssetTags(c.req.raw, c.env, componentId));
|
|
284
|
+
return renderedResponse(c, await renderWithAssetTags(renderFn, pageObj, assetTags), "text/html; charset=utf-8", assetTags);
|
|
196
285
|
}
|
|
197
286
|
//#endregion
|
|
198
287
|
export { ValidationError, flattenValidationErrors, handlePageGet, handlePageMutation, safeJsonStringify };
|