@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/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 config of configs) {
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 (head.description) {
486
+ if (normalizedHead.description) {
426
487
  tags.push(
427
- `<meta ${createManagedAttributes()} name="description" content="${escapeHtml(head.description)}" />`
488
+ `<meta ${createManagedAttributes()} name="description" content="${escapeHtml(normalizedHead.description)}" />`
428
489
  );
429
490
  }
430
- if (head.favicon) {
491
+ if (normalizedHead.favicon) {
431
492
  tags.push(
432
- `<link ${createManagedAttributes()} rel="icon" href="${escapeHtml(head.favicon)}" />`
493
+ `<link ${createManagedAttributes()} rel="icon" href="${escapeHtml(normalizedHead.favicon)}" />`
433
494
  );
434
495
  }
435
- for (const meta of head.meta ?? []) {
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 head.links ?? []) {
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 config of configs) {
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 (head.description) {
450
+ if (normalizedHead.description) {
390
451
  tags.push(
391
- `<meta ${createManagedAttributes()} name="description" content="${escapeHtml(head.description)}" />`
452
+ `<meta ${createManagedAttributes()} name="description" content="${escapeHtml(normalizedHead.description)}" />`
392
453
  );
393
454
  }
394
- if (head.favicon) {
455
+ if (normalizedHead.favicon) {
395
456
  tags.push(
396
- `<link ${createManagedAttributes()} rel="icon" href="${escapeHtml(head.favicon)}" />`
457
+ `<link ${createManagedAttributes()} rel="icon" href="${escapeHtml(normalizedHead.favicon)}" />`
397
458
  );
398
459
  }
399
- for (const meta of head.meta ?? []) {
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 head.links ?? []) {
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 config of configs) {
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 (head.description) {
344
+ if (normalizedHead.description) {
284
345
  tags.push(
285
- `<meta ${createManagedAttributes()} name="description" content="${escapeHtml(head.description)}" />`
346
+ `<meta ${createManagedAttributes()} name="description" content="${escapeHtml(normalizedHead.description)}" />`
286
347
  );
287
348
  }
288
- if (head.favicon) {
349
+ if (normalizedHead.favicon) {
289
350
  tags.push(
290
- `<link ${createManagedAttributes()} rel="icon" href="${escapeHtml(head.favicon)}" />`
351
+ `<link ${createManagedAttributes()} rel="icon" href="${escapeHtml(normalizedHead.favicon)}" />`
291
352
  );
292
353
  }
293
- for (const meta of head.meta ?? []) {
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 head.links ?? []) {
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
  }