@webtypen/webframez-react 0.0.25 → 0.0.28
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 +20 -1
- package/dist/client.cjs +1 -1
- package/dist/client.js +1 -1
- package/dist/http.cjs +143 -11
- package/dist/http.js +143 -11
- package/dist/index.cjs +143 -11
- package/dist/index.js +143 -11
- package/dist/router.cjs +74 -7
- package/dist/router.js +74 -7
- package/dist/types.d.ts +16 -6
- package/dist/webframez-core.cjs +143 -11
- package/dist/webframez-core.js +143 -11
- package/package.json +7 -7
package/dist/index.cjs
CHANGED
|
@@ -183,6 +183,62 @@ var import_node_fs = __toESM(require("node:fs"), 1);
|
|
|
183
183
|
var import_node_module2 = __toESM(require("node:module"), 1);
|
|
184
184
|
var import_node_path2 = __toESM(require("node:path"), 1);
|
|
185
185
|
|
|
186
|
+
// src/head.ts
|
|
187
|
+
var ABSOLUTE_ASSET_URL_PATTERN = /^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/|#)/;
|
|
188
|
+
function normalizeHeadBasename(value) {
|
|
189
|
+
const trimmed = value?.trim();
|
|
190
|
+
if (!trimmed) {
|
|
191
|
+
return void 0;
|
|
192
|
+
}
|
|
193
|
+
if (trimmed === "/") {
|
|
194
|
+
return "/";
|
|
195
|
+
}
|
|
196
|
+
return trimmed.replace(/\/+$/, "");
|
|
197
|
+
}
|
|
198
|
+
function resolveHeadAssetUrl(assetUrl, basename) {
|
|
199
|
+
const normalizedAssetUrl = assetUrl.trim();
|
|
200
|
+
const normalizedBasename = normalizeHeadBasename(basename);
|
|
201
|
+
if (!normalizedAssetUrl || !normalizedBasename) {
|
|
202
|
+
return normalizedAssetUrl;
|
|
203
|
+
}
|
|
204
|
+
if (ABSOLUTE_ASSET_URL_PATTERN.test(normalizedAssetUrl)) {
|
|
205
|
+
return normalizedAssetUrl;
|
|
206
|
+
}
|
|
207
|
+
if (normalizedBasename !== "/" && (normalizedAssetUrl === normalizedBasename || normalizedAssetUrl.startsWith(`${normalizedBasename}/`))) {
|
|
208
|
+
return normalizedAssetUrl;
|
|
209
|
+
}
|
|
210
|
+
if (normalizedBasename === "/") {
|
|
211
|
+
return normalizedAssetUrl.startsWith("/") ? normalizedAssetUrl : `/${normalizedAssetUrl}`;
|
|
212
|
+
}
|
|
213
|
+
if (normalizedAssetUrl.startsWith("/")) {
|
|
214
|
+
return `${normalizedBasename}${normalizedAssetUrl}`;
|
|
215
|
+
}
|
|
216
|
+
return `${normalizedBasename}/${normalizedAssetUrl}`;
|
|
217
|
+
}
|
|
218
|
+
function normalizeHeadConfig(head, inheritedBasename) {
|
|
219
|
+
if (!head) {
|
|
220
|
+
return void 0;
|
|
221
|
+
}
|
|
222
|
+
const effectiveBasename = normalizeHeadBasename(head.basename) ?? normalizeHeadBasename(inheritedBasename);
|
|
223
|
+
const normalizedHead = {
|
|
224
|
+
...head,
|
|
225
|
+
...effectiveBasename ? { basename: effectiveBasename } : {}
|
|
226
|
+
};
|
|
227
|
+
if (normalizedHead.favicon) {
|
|
228
|
+
normalizedHead.favicon = resolveHeadAssetUrl(
|
|
229
|
+
normalizedHead.favicon,
|
|
230
|
+
effectiveBasename
|
|
231
|
+
);
|
|
232
|
+
}
|
|
233
|
+
if (normalizedHead.links) {
|
|
234
|
+
normalizedHead.links = normalizedHead.links.map((link) => ({
|
|
235
|
+
...link,
|
|
236
|
+
href: resolveHeadAssetUrl(link.href, effectiveBasename)
|
|
237
|
+
}));
|
|
238
|
+
}
|
|
239
|
+
return normalizedHead;
|
|
240
|
+
}
|
|
241
|
+
|
|
186
242
|
// src/router-runtime.tsx
|
|
187
243
|
var import_react = __toESM(require("react"), 1);
|
|
188
244
|
var ROUTE_CHILDREN_TAG = "webframez-route-children";
|
|
@@ -398,7 +454,8 @@ function mergeHead(...configs) {
|
|
|
398
454
|
meta: [],
|
|
399
455
|
links: []
|
|
400
456
|
};
|
|
401
|
-
for (const
|
|
457
|
+
for (const candidate of configs) {
|
|
458
|
+
const config = normalizeHeadConfig(candidate, merged.basename);
|
|
402
459
|
if (!config) {
|
|
403
460
|
continue;
|
|
404
461
|
}
|
|
@@ -408,6 +465,9 @@ function mergeHead(...configs) {
|
|
|
408
465
|
if (config.description) {
|
|
409
466
|
merged.description = config.description;
|
|
410
467
|
}
|
|
468
|
+
if (config.basename) {
|
|
469
|
+
merged.basename = config.basename;
|
|
470
|
+
}
|
|
411
471
|
if (config.favicon) {
|
|
412
472
|
merged.favicon = config.favicon;
|
|
413
473
|
}
|
|
@@ -421,22 +481,23 @@ function mergeHead(...configs) {
|
|
|
421
481
|
return merged;
|
|
422
482
|
}
|
|
423
483
|
function renderHeadToString(head) {
|
|
484
|
+
const normalizedHead = normalizeHeadConfig(head) ?? head;
|
|
424
485
|
const tags = [];
|
|
425
|
-
if (
|
|
486
|
+
if (normalizedHead.description) {
|
|
426
487
|
tags.push(
|
|
427
|
-
`<meta ${createManagedAttributes()} name="description" content="${escapeHtml(
|
|
488
|
+
`<meta ${createManagedAttributes()} name="description" content="${escapeHtml(normalizedHead.description)}" />`
|
|
428
489
|
);
|
|
429
490
|
}
|
|
430
|
-
if (
|
|
491
|
+
if (normalizedHead.favicon) {
|
|
431
492
|
tags.push(
|
|
432
|
-
`<link ${createManagedAttributes()} rel="icon" href="${escapeHtml(
|
|
493
|
+
`<link ${createManagedAttributes()} rel="icon" href="${escapeHtml(normalizedHead.favicon)}" />`
|
|
433
494
|
);
|
|
434
495
|
}
|
|
435
|
-
for (const meta of
|
|
496
|
+
for (const meta of normalizedHead.meta ?? []) {
|
|
436
497
|
const attrs = Object.entries(meta).filter(([, value]) => Boolean(value)).map(([key, value]) => `${key}="${escapeHtml(String(value))}"`).join(" ");
|
|
437
498
|
tags.push(`<meta ${createManagedAttributes()} ${attrs} />`);
|
|
438
499
|
}
|
|
439
|
-
for (const link of
|
|
500
|
+
for (const link of normalizedHead.links ?? []) {
|
|
440
501
|
const attrs = Object.entries(link).filter(([, value]) => Boolean(value)).map(([key, value]) => `${key}="${escapeHtml(String(value))}"`).join(" ");
|
|
441
502
|
tags.push(`<link ${createManagedAttributes()} ${attrs} />`);
|
|
442
503
|
}
|
|
@@ -652,6 +713,12 @@ function createFileRouter(options) {
|
|
|
652
713
|
params: {},
|
|
653
714
|
searchParams: input.searchParams,
|
|
654
715
|
cookies: input.cookies ?? {},
|
|
716
|
+
request: input.request ?? {
|
|
717
|
+
host: null,
|
|
718
|
+
pathname,
|
|
719
|
+
originalPathname: pathname,
|
|
720
|
+
headers: {}
|
|
721
|
+
},
|
|
655
722
|
abort: (options2) => {
|
|
656
723
|
throw createAbort(options2);
|
|
657
724
|
}
|
|
@@ -883,6 +950,60 @@ function normalizeBasePath(basePath) {
|
|
|
883
950
|
const withLeadingSlash = basePath.startsWith("/") ? basePath : `/${basePath}`;
|
|
884
951
|
return withLeadingSlash.endsWith("/") ? withLeadingSlash.slice(0, -1) : withLeadingSlash;
|
|
885
952
|
}
|
|
953
|
+
function normalizeRequestHostValue(value) {
|
|
954
|
+
const trimmed = value.trim();
|
|
955
|
+
if (!trimmed) {
|
|
956
|
+
return null;
|
|
957
|
+
}
|
|
958
|
+
const firstValue = trimmed.split(",")[0]?.trim() || "";
|
|
959
|
+
if (!firstValue) {
|
|
960
|
+
return null;
|
|
961
|
+
}
|
|
962
|
+
if (firstValue.startsWith("[")) {
|
|
963
|
+
const closingIndex = firstValue.indexOf("]");
|
|
964
|
+
if (closingIndex > 0) {
|
|
965
|
+
return firstValue.slice(1, closingIndex).toLowerCase();
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
return firstValue.replace(/:\d+$/, "").toLowerCase();
|
|
969
|
+
}
|
|
970
|
+
function getRequestHost(req) {
|
|
971
|
+
const candidates = [
|
|
972
|
+
req.headers["x-forwarded-host"],
|
|
973
|
+
req.headers["x-original-host"],
|
|
974
|
+
req.headers.host
|
|
975
|
+
];
|
|
976
|
+
for (const candidate of candidates) {
|
|
977
|
+
if (Array.isArray(candidate)) {
|
|
978
|
+
for (const singleValue of candidate) {
|
|
979
|
+
if (typeof singleValue !== "string") {
|
|
980
|
+
continue;
|
|
981
|
+
}
|
|
982
|
+
const normalized2 = normalizeRequestHostValue(singleValue);
|
|
983
|
+
if (normalized2) {
|
|
984
|
+
return normalized2;
|
|
985
|
+
}
|
|
986
|
+
}
|
|
987
|
+
continue;
|
|
988
|
+
}
|
|
989
|
+
if (typeof candidate !== "string") {
|
|
990
|
+
continue;
|
|
991
|
+
}
|
|
992
|
+
const normalized = normalizeRequestHostValue(candidate);
|
|
993
|
+
if (normalized) {
|
|
994
|
+
return normalized;
|
|
995
|
+
}
|
|
996
|
+
}
|
|
997
|
+
return null;
|
|
998
|
+
}
|
|
999
|
+
function createRouteRequestContext(req, pathname, originalPathname) {
|
|
1000
|
+
return {
|
|
1001
|
+
host: getRequestHost(req),
|
|
1002
|
+
pathname,
|
|
1003
|
+
originalPathname,
|
|
1004
|
+
headers: req.headers
|
|
1005
|
+
};
|
|
1006
|
+
}
|
|
886
1007
|
function stripBasePath(pathname, basePath) {
|
|
887
1008
|
if (!basePath) {
|
|
888
1009
|
return pathname;
|
|
@@ -1228,13 +1349,19 @@ function createNodeRequestHandler(options) {
|
|
|
1228
1349
|
}
|
|
1229
1350
|
if (url.pathname === rscPath) {
|
|
1230
1351
|
const pathname = stripBasePath(url.searchParams.get("path") || "/", basePath);
|
|
1352
|
+
const requestContext = createRouteRequestContext(
|
|
1353
|
+
req,
|
|
1354
|
+
pathname,
|
|
1355
|
+
url.searchParams.get("path") || "/"
|
|
1356
|
+
);
|
|
1231
1357
|
const search = new URLSearchParams(url.searchParams.get("search") || "");
|
|
1232
1358
|
const resolved2 = await withRequestBasename(
|
|
1233
1359
|
basePath,
|
|
1234
1360
|
() => router.resolve({
|
|
1235
1361
|
pathname,
|
|
1236
1362
|
searchParams: parseSearchParams(search),
|
|
1237
|
-
cookies: requestCookies
|
|
1363
|
+
cookies: requestCookies,
|
|
1364
|
+
request: requestContext
|
|
1238
1365
|
})
|
|
1239
1366
|
);
|
|
1240
1367
|
const payload = {
|
|
@@ -1274,7 +1401,12 @@ function createNodeRequestHandler(options) {
|
|
|
1274
1401
|
() => router.resolve({
|
|
1275
1402
|
pathname: stripBasePath(url.pathname, basePath),
|
|
1276
1403
|
searchParams: parseSearchParams(url.searchParams),
|
|
1277
|
-
cookies: requestCookies
|
|
1404
|
+
cookies: requestCookies,
|
|
1405
|
+
request: createRouteRequestContext(
|
|
1406
|
+
req,
|
|
1407
|
+
stripBasePath(url.pathname, basePath),
|
|
1408
|
+
url.pathname
|
|
1409
|
+
)
|
|
1278
1410
|
})
|
|
1279
1411
|
);
|
|
1280
1412
|
const initialPayload = {
|
|
@@ -1318,7 +1450,7 @@ function createNodeRequestHandler(options) {
|
|
|
1318
1450
|
rscEndpoint: rscPath,
|
|
1319
1451
|
rootHtml: createInitialHtmlErrorMarkup("Initial HTML render failed."),
|
|
1320
1452
|
initialFlightData,
|
|
1321
|
-
basename: basePath,
|
|
1453
|
+
basename: resolved?.head?.basename ?? basePath,
|
|
1322
1454
|
liveReloadPath: liveReloadPath || void 0,
|
|
1323
1455
|
liveReloadServerId: liveReloadPath ? devServerId : void 0
|
|
1324
1456
|
})
|
|
@@ -1337,7 +1469,7 @@ function createNodeRequestHandler(options) {
|
|
|
1337
1469
|
rscEndpoint: rscPath,
|
|
1338
1470
|
rootHtml,
|
|
1339
1471
|
initialFlightData,
|
|
1340
|
-
basename: basePath,
|
|
1472
|
+
basename: resolved.head.basename ?? basePath,
|
|
1341
1473
|
liveReloadPath: liveReloadPath || void 0,
|
|
1342
1474
|
liveReloadServerId: liveReloadPath ? devServerId : void 0
|
|
1343
1475
|
})
|
package/dist/index.js
CHANGED
|
@@ -147,6 +147,62 @@ import fs from "node:fs";
|
|
|
147
147
|
import Module from "node:module";
|
|
148
148
|
import path2 from "node:path";
|
|
149
149
|
|
|
150
|
+
// src/head.ts
|
|
151
|
+
var ABSOLUTE_ASSET_URL_PATTERN = /^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/|#)/;
|
|
152
|
+
function normalizeHeadBasename(value) {
|
|
153
|
+
const trimmed = value?.trim();
|
|
154
|
+
if (!trimmed) {
|
|
155
|
+
return void 0;
|
|
156
|
+
}
|
|
157
|
+
if (trimmed === "/") {
|
|
158
|
+
return "/";
|
|
159
|
+
}
|
|
160
|
+
return trimmed.replace(/\/+$/, "");
|
|
161
|
+
}
|
|
162
|
+
function resolveHeadAssetUrl(assetUrl, basename) {
|
|
163
|
+
const normalizedAssetUrl = assetUrl.trim();
|
|
164
|
+
const normalizedBasename = normalizeHeadBasename(basename);
|
|
165
|
+
if (!normalizedAssetUrl || !normalizedBasename) {
|
|
166
|
+
return normalizedAssetUrl;
|
|
167
|
+
}
|
|
168
|
+
if (ABSOLUTE_ASSET_URL_PATTERN.test(normalizedAssetUrl)) {
|
|
169
|
+
return normalizedAssetUrl;
|
|
170
|
+
}
|
|
171
|
+
if (normalizedBasename !== "/" && (normalizedAssetUrl === normalizedBasename || normalizedAssetUrl.startsWith(`${normalizedBasename}/`))) {
|
|
172
|
+
return normalizedAssetUrl;
|
|
173
|
+
}
|
|
174
|
+
if (normalizedBasename === "/") {
|
|
175
|
+
return normalizedAssetUrl.startsWith("/") ? normalizedAssetUrl : `/${normalizedAssetUrl}`;
|
|
176
|
+
}
|
|
177
|
+
if (normalizedAssetUrl.startsWith("/")) {
|
|
178
|
+
return `${normalizedBasename}${normalizedAssetUrl}`;
|
|
179
|
+
}
|
|
180
|
+
return `${normalizedBasename}/${normalizedAssetUrl}`;
|
|
181
|
+
}
|
|
182
|
+
function normalizeHeadConfig(head, inheritedBasename) {
|
|
183
|
+
if (!head) {
|
|
184
|
+
return void 0;
|
|
185
|
+
}
|
|
186
|
+
const effectiveBasename = normalizeHeadBasename(head.basename) ?? normalizeHeadBasename(inheritedBasename);
|
|
187
|
+
const normalizedHead = {
|
|
188
|
+
...head,
|
|
189
|
+
...effectiveBasename ? { basename: effectiveBasename } : {}
|
|
190
|
+
};
|
|
191
|
+
if (normalizedHead.favicon) {
|
|
192
|
+
normalizedHead.favicon = resolveHeadAssetUrl(
|
|
193
|
+
normalizedHead.favicon,
|
|
194
|
+
effectiveBasename
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
if (normalizedHead.links) {
|
|
198
|
+
normalizedHead.links = normalizedHead.links.map((link) => ({
|
|
199
|
+
...link,
|
|
200
|
+
href: resolveHeadAssetUrl(link.href, effectiveBasename)
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
203
|
+
return normalizedHead;
|
|
204
|
+
}
|
|
205
|
+
|
|
150
206
|
// src/router-runtime.tsx
|
|
151
207
|
import React from "react";
|
|
152
208
|
var ROUTE_CHILDREN_TAG = "webframez-route-children";
|
|
@@ -362,7 +418,8 @@ function mergeHead(...configs) {
|
|
|
362
418
|
meta: [],
|
|
363
419
|
links: []
|
|
364
420
|
};
|
|
365
|
-
for (const
|
|
421
|
+
for (const candidate of configs) {
|
|
422
|
+
const config = normalizeHeadConfig(candidate, merged.basename);
|
|
366
423
|
if (!config) {
|
|
367
424
|
continue;
|
|
368
425
|
}
|
|
@@ -372,6 +429,9 @@ function mergeHead(...configs) {
|
|
|
372
429
|
if (config.description) {
|
|
373
430
|
merged.description = config.description;
|
|
374
431
|
}
|
|
432
|
+
if (config.basename) {
|
|
433
|
+
merged.basename = config.basename;
|
|
434
|
+
}
|
|
375
435
|
if (config.favicon) {
|
|
376
436
|
merged.favicon = config.favicon;
|
|
377
437
|
}
|
|
@@ -385,22 +445,23 @@ function mergeHead(...configs) {
|
|
|
385
445
|
return merged;
|
|
386
446
|
}
|
|
387
447
|
function renderHeadToString(head) {
|
|
448
|
+
const normalizedHead = normalizeHeadConfig(head) ?? head;
|
|
388
449
|
const tags = [];
|
|
389
|
-
if (
|
|
450
|
+
if (normalizedHead.description) {
|
|
390
451
|
tags.push(
|
|
391
|
-
`<meta ${createManagedAttributes()} name="description" content="${escapeHtml(
|
|
452
|
+
`<meta ${createManagedAttributes()} name="description" content="${escapeHtml(normalizedHead.description)}" />`
|
|
392
453
|
);
|
|
393
454
|
}
|
|
394
|
-
if (
|
|
455
|
+
if (normalizedHead.favicon) {
|
|
395
456
|
tags.push(
|
|
396
|
-
`<link ${createManagedAttributes()} rel="icon" href="${escapeHtml(
|
|
457
|
+
`<link ${createManagedAttributes()} rel="icon" href="${escapeHtml(normalizedHead.favicon)}" />`
|
|
397
458
|
);
|
|
398
459
|
}
|
|
399
|
-
for (const meta of
|
|
460
|
+
for (const meta of normalizedHead.meta ?? []) {
|
|
400
461
|
const attrs = Object.entries(meta).filter(([, value]) => Boolean(value)).map(([key, value]) => `${key}="${escapeHtml(String(value))}"`).join(" ");
|
|
401
462
|
tags.push(`<meta ${createManagedAttributes()} ${attrs} />`);
|
|
402
463
|
}
|
|
403
|
-
for (const link of
|
|
464
|
+
for (const link of normalizedHead.links ?? []) {
|
|
404
465
|
const attrs = Object.entries(link).filter(([, value]) => Boolean(value)).map(([key, value]) => `${key}="${escapeHtml(String(value))}"`).join(" ");
|
|
405
466
|
tags.push(`<link ${createManagedAttributes()} ${attrs} />`);
|
|
406
467
|
}
|
|
@@ -616,6 +677,12 @@ function createFileRouter(options) {
|
|
|
616
677
|
params: {},
|
|
617
678
|
searchParams: input.searchParams,
|
|
618
679
|
cookies: input.cookies ?? {},
|
|
680
|
+
request: input.request ?? {
|
|
681
|
+
host: null,
|
|
682
|
+
pathname,
|
|
683
|
+
originalPathname: pathname,
|
|
684
|
+
headers: {}
|
|
685
|
+
},
|
|
619
686
|
abort: (options2) => {
|
|
620
687
|
throw createAbort(options2);
|
|
621
688
|
}
|
|
@@ -847,6 +914,60 @@ function normalizeBasePath(basePath) {
|
|
|
847
914
|
const withLeadingSlash = basePath.startsWith("/") ? basePath : `/${basePath}`;
|
|
848
915
|
return withLeadingSlash.endsWith("/") ? withLeadingSlash.slice(0, -1) : withLeadingSlash;
|
|
849
916
|
}
|
|
917
|
+
function normalizeRequestHostValue(value) {
|
|
918
|
+
const trimmed = value.trim();
|
|
919
|
+
if (!trimmed) {
|
|
920
|
+
return null;
|
|
921
|
+
}
|
|
922
|
+
const firstValue = trimmed.split(",")[0]?.trim() || "";
|
|
923
|
+
if (!firstValue) {
|
|
924
|
+
return null;
|
|
925
|
+
}
|
|
926
|
+
if (firstValue.startsWith("[")) {
|
|
927
|
+
const closingIndex = firstValue.indexOf("]");
|
|
928
|
+
if (closingIndex > 0) {
|
|
929
|
+
return firstValue.slice(1, closingIndex).toLowerCase();
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
return firstValue.replace(/:\d+$/, "").toLowerCase();
|
|
933
|
+
}
|
|
934
|
+
function getRequestHost(req) {
|
|
935
|
+
const candidates = [
|
|
936
|
+
req.headers["x-forwarded-host"],
|
|
937
|
+
req.headers["x-original-host"],
|
|
938
|
+
req.headers.host
|
|
939
|
+
];
|
|
940
|
+
for (const candidate of candidates) {
|
|
941
|
+
if (Array.isArray(candidate)) {
|
|
942
|
+
for (const singleValue of candidate) {
|
|
943
|
+
if (typeof singleValue !== "string") {
|
|
944
|
+
continue;
|
|
945
|
+
}
|
|
946
|
+
const normalized2 = normalizeRequestHostValue(singleValue);
|
|
947
|
+
if (normalized2) {
|
|
948
|
+
return normalized2;
|
|
949
|
+
}
|
|
950
|
+
}
|
|
951
|
+
continue;
|
|
952
|
+
}
|
|
953
|
+
if (typeof candidate !== "string") {
|
|
954
|
+
continue;
|
|
955
|
+
}
|
|
956
|
+
const normalized = normalizeRequestHostValue(candidate);
|
|
957
|
+
if (normalized) {
|
|
958
|
+
return normalized;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
return null;
|
|
962
|
+
}
|
|
963
|
+
function createRouteRequestContext(req, pathname, originalPathname) {
|
|
964
|
+
return {
|
|
965
|
+
host: getRequestHost(req),
|
|
966
|
+
pathname,
|
|
967
|
+
originalPathname,
|
|
968
|
+
headers: req.headers
|
|
969
|
+
};
|
|
970
|
+
}
|
|
850
971
|
function stripBasePath(pathname, basePath) {
|
|
851
972
|
if (!basePath) {
|
|
852
973
|
return pathname;
|
|
@@ -1192,13 +1313,19 @@ function createNodeRequestHandler(options) {
|
|
|
1192
1313
|
}
|
|
1193
1314
|
if (url.pathname === rscPath) {
|
|
1194
1315
|
const pathname = stripBasePath(url.searchParams.get("path") || "/", basePath);
|
|
1316
|
+
const requestContext = createRouteRequestContext(
|
|
1317
|
+
req,
|
|
1318
|
+
pathname,
|
|
1319
|
+
url.searchParams.get("path") || "/"
|
|
1320
|
+
);
|
|
1195
1321
|
const search = new URLSearchParams(url.searchParams.get("search") || "");
|
|
1196
1322
|
const resolved2 = await withRequestBasename(
|
|
1197
1323
|
basePath,
|
|
1198
1324
|
() => router.resolve({
|
|
1199
1325
|
pathname,
|
|
1200
1326
|
searchParams: parseSearchParams(search),
|
|
1201
|
-
cookies: requestCookies
|
|
1327
|
+
cookies: requestCookies,
|
|
1328
|
+
request: requestContext
|
|
1202
1329
|
})
|
|
1203
1330
|
);
|
|
1204
1331
|
const payload = {
|
|
@@ -1238,7 +1365,12 @@ function createNodeRequestHandler(options) {
|
|
|
1238
1365
|
() => router.resolve({
|
|
1239
1366
|
pathname: stripBasePath(url.pathname, basePath),
|
|
1240
1367
|
searchParams: parseSearchParams(url.searchParams),
|
|
1241
|
-
cookies: requestCookies
|
|
1368
|
+
cookies: requestCookies,
|
|
1369
|
+
request: createRouteRequestContext(
|
|
1370
|
+
req,
|
|
1371
|
+
stripBasePath(url.pathname, basePath),
|
|
1372
|
+
url.pathname
|
|
1373
|
+
)
|
|
1242
1374
|
})
|
|
1243
1375
|
);
|
|
1244
1376
|
const initialPayload = {
|
|
@@ -1282,7 +1414,7 @@ function createNodeRequestHandler(options) {
|
|
|
1282
1414
|
rscEndpoint: rscPath,
|
|
1283
1415
|
rootHtml: createInitialHtmlErrorMarkup("Initial HTML render failed."),
|
|
1284
1416
|
initialFlightData,
|
|
1285
|
-
basename: basePath,
|
|
1417
|
+
basename: resolved?.head?.basename ?? basePath,
|
|
1286
1418
|
liveReloadPath: liveReloadPath || void 0,
|
|
1287
1419
|
liveReloadServerId: liveReloadPath ? devServerId : void 0
|
|
1288
1420
|
})
|
|
@@ -1301,7 +1433,7 @@ function createNodeRequestHandler(options) {
|
|
|
1301
1433
|
rscEndpoint: rscPath,
|
|
1302
1434
|
rootHtml,
|
|
1303
1435
|
initialFlightData,
|
|
1304
|
-
basename: basePath,
|
|
1436
|
+
basename: resolved.head.basename ?? basePath,
|
|
1305
1437
|
liveReloadPath: liveReloadPath || void 0,
|
|
1306
1438
|
liveReloadServerId: liveReloadPath ? devServerId : void 0
|
|
1307
1439
|
})
|
package/dist/router.cjs
CHANGED
|
@@ -41,6 +41,62 @@ var import_node_fs = __toESM(require("node:fs"), 1);
|
|
|
41
41
|
var import_node_module = __toESM(require("node:module"), 1);
|
|
42
42
|
var import_node_path = __toESM(require("node:path"), 1);
|
|
43
43
|
|
|
44
|
+
// src/head.ts
|
|
45
|
+
var ABSOLUTE_ASSET_URL_PATTERN = /^(?:[a-zA-Z][a-zA-Z\d+\-.]*:|\/\/|#)/;
|
|
46
|
+
function normalizeHeadBasename(value) {
|
|
47
|
+
const trimmed = value?.trim();
|
|
48
|
+
if (!trimmed) {
|
|
49
|
+
return void 0;
|
|
50
|
+
}
|
|
51
|
+
if (trimmed === "/") {
|
|
52
|
+
return "/";
|
|
53
|
+
}
|
|
54
|
+
return trimmed.replace(/\/+$/, "");
|
|
55
|
+
}
|
|
56
|
+
function resolveHeadAssetUrl(assetUrl, basename) {
|
|
57
|
+
const normalizedAssetUrl = assetUrl.trim();
|
|
58
|
+
const normalizedBasename = normalizeHeadBasename(basename);
|
|
59
|
+
if (!normalizedAssetUrl || !normalizedBasename) {
|
|
60
|
+
return normalizedAssetUrl;
|
|
61
|
+
}
|
|
62
|
+
if (ABSOLUTE_ASSET_URL_PATTERN.test(normalizedAssetUrl)) {
|
|
63
|
+
return normalizedAssetUrl;
|
|
64
|
+
}
|
|
65
|
+
if (normalizedBasename !== "/" && (normalizedAssetUrl === normalizedBasename || normalizedAssetUrl.startsWith(`${normalizedBasename}/`))) {
|
|
66
|
+
return normalizedAssetUrl;
|
|
67
|
+
}
|
|
68
|
+
if (normalizedBasename === "/") {
|
|
69
|
+
return normalizedAssetUrl.startsWith("/") ? normalizedAssetUrl : `/${normalizedAssetUrl}`;
|
|
70
|
+
}
|
|
71
|
+
if (normalizedAssetUrl.startsWith("/")) {
|
|
72
|
+
return `${normalizedBasename}${normalizedAssetUrl}`;
|
|
73
|
+
}
|
|
74
|
+
return `${normalizedBasename}/${normalizedAssetUrl}`;
|
|
75
|
+
}
|
|
76
|
+
function normalizeHeadConfig(head, inheritedBasename) {
|
|
77
|
+
if (!head) {
|
|
78
|
+
return void 0;
|
|
79
|
+
}
|
|
80
|
+
const effectiveBasename = normalizeHeadBasename(head.basename) ?? normalizeHeadBasename(inheritedBasename);
|
|
81
|
+
const normalizedHead = {
|
|
82
|
+
...head,
|
|
83
|
+
...effectiveBasename ? { basename: effectiveBasename } : {}
|
|
84
|
+
};
|
|
85
|
+
if (normalizedHead.favicon) {
|
|
86
|
+
normalizedHead.favicon = resolveHeadAssetUrl(
|
|
87
|
+
normalizedHead.favicon,
|
|
88
|
+
effectiveBasename
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
if (normalizedHead.links) {
|
|
92
|
+
normalizedHead.links = normalizedHead.links.map((link) => ({
|
|
93
|
+
...link,
|
|
94
|
+
href: resolveHeadAssetUrl(link.href, effectiveBasename)
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
return normalizedHead;
|
|
98
|
+
}
|
|
99
|
+
|
|
44
100
|
// src/router-runtime.tsx
|
|
45
101
|
var import_react = __toESM(require("react"), 1);
|
|
46
102
|
var ROUTE_CHILDREN_TAG = "webframez-route-children";
|
|
@@ -256,7 +312,8 @@ function mergeHead(...configs) {
|
|
|
256
312
|
meta: [],
|
|
257
313
|
links: []
|
|
258
314
|
};
|
|
259
|
-
for (const
|
|
315
|
+
for (const candidate of configs) {
|
|
316
|
+
const config = normalizeHeadConfig(candidate, merged.basename);
|
|
260
317
|
if (!config) {
|
|
261
318
|
continue;
|
|
262
319
|
}
|
|
@@ -266,6 +323,9 @@ function mergeHead(...configs) {
|
|
|
266
323
|
if (config.description) {
|
|
267
324
|
merged.description = config.description;
|
|
268
325
|
}
|
|
326
|
+
if (config.basename) {
|
|
327
|
+
merged.basename = config.basename;
|
|
328
|
+
}
|
|
269
329
|
if (config.favicon) {
|
|
270
330
|
merged.favicon = config.favicon;
|
|
271
331
|
}
|
|
@@ -279,22 +339,23 @@ function mergeHead(...configs) {
|
|
|
279
339
|
return merged;
|
|
280
340
|
}
|
|
281
341
|
function renderHeadToString(head) {
|
|
342
|
+
const normalizedHead = normalizeHeadConfig(head) ?? head;
|
|
282
343
|
const tags = [];
|
|
283
|
-
if (
|
|
344
|
+
if (normalizedHead.description) {
|
|
284
345
|
tags.push(
|
|
285
|
-
`<meta ${createManagedAttributes()} name="description" content="${escapeHtml(
|
|
346
|
+
`<meta ${createManagedAttributes()} name="description" content="${escapeHtml(normalizedHead.description)}" />`
|
|
286
347
|
);
|
|
287
348
|
}
|
|
288
|
-
if (
|
|
349
|
+
if (normalizedHead.favicon) {
|
|
289
350
|
tags.push(
|
|
290
|
-
`<link ${createManagedAttributes()} rel="icon" href="${escapeHtml(
|
|
351
|
+
`<link ${createManagedAttributes()} rel="icon" href="${escapeHtml(normalizedHead.favicon)}" />`
|
|
291
352
|
);
|
|
292
353
|
}
|
|
293
|
-
for (const meta of
|
|
354
|
+
for (const meta of normalizedHead.meta ?? []) {
|
|
294
355
|
const attrs = Object.entries(meta).filter(([, value]) => Boolean(value)).map(([key, value]) => `${key}="${escapeHtml(String(value))}"`).join(" ");
|
|
295
356
|
tags.push(`<meta ${createManagedAttributes()} ${attrs} />`);
|
|
296
357
|
}
|
|
297
|
-
for (const link of
|
|
358
|
+
for (const link of normalizedHead.links ?? []) {
|
|
298
359
|
const attrs = Object.entries(link).filter(([, value]) => Boolean(value)).map(([key, value]) => `${key}="${escapeHtml(String(value))}"`).join(" ");
|
|
299
360
|
tags.push(`<link ${createManagedAttributes()} ${attrs} />`);
|
|
300
361
|
}
|
|
@@ -510,6 +571,12 @@ function createFileRouter(options) {
|
|
|
510
571
|
params: {},
|
|
511
572
|
searchParams: input.searchParams,
|
|
512
573
|
cookies: input.cookies ?? {},
|
|
574
|
+
request: input.request ?? {
|
|
575
|
+
host: null,
|
|
576
|
+
pathname,
|
|
577
|
+
originalPathname: pathname,
|
|
578
|
+
headers: {}
|
|
579
|
+
},
|
|
513
580
|
abort: (options2) => {
|
|
514
581
|
throw createAbort(options2);
|
|
515
582
|
}
|