convex-cms 0.0.1 → 0.0.3
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/LICENSE +190 -0
- package/README.md +99 -0
- package/admin-dist/nitro.json +15 -0
- package/admin-dist/public/assets/CmsEmptyState-CRswfTzk.js +5 -0
- package/admin-dist/public/assets/CmsPageHeader-CirpXndm.js +1 -0
- package/admin-dist/public/assets/CmsStatusBadge-CbEUpQu-.js +1 -0
- package/admin-dist/public/assets/CmsToolbar-BI2nZOXp.js +1 -0
- package/admin-dist/public/assets/ContentEntryEditor-CBeCyK_m.js +4 -0
- package/admin-dist/public/assets/ErrorState-BIVaWmom.js +1 -0
- package/admin-dist/public/assets/TaxonomyFilter-ChaY6Y_x.js +1 -0
- package/admin-dist/public/assets/_contentTypeId-DQ8k_Rvw.js +1 -0
- package/admin-dist/public/assets/_entryId-CKU_glsK.js +1 -0
- package/admin-dist/public/assets/alert-BXjTqrwQ.js +1 -0
- package/admin-dist/public/assets/badge-hvUOzpVZ.js +1 -0
- package/admin-dist/public/assets/circle-check-big-CF_pR17r.js +1 -0
- package/admin-dist/public/assets/command-DU82cJlt.js +1 -0
- package/admin-dist/public/assets/content-_LXl3pp7.js +1 -0
- package/admin-dist/public/assets/content-types-KjxaXGxY.js +2 -0
- package/admin-dist/public/assets/globals-CS6BZ0zp.css +1 -0
- package/admin-dist/public/assets/index-DNGIZHL-.js +1 -0
- package/admin-dist/public/assets/label-KNtpL71g.js +1 -0
- package/admin-dist/public/assets/link-2-Bw2aI4V4.js +1 -0
- package/admin-dist/public/assets/list-sYepHjt_.js +1 -0
- package/admin-dist/public/assets/main-CKj5yfEi.js +97 -0
- package/admin-dist/public/assets/media-Bkrkffm7.js +1 -0
- package/admin-dist/public/assets/new._contentTypeId-C3LstjNs.js +1 -0
- package/admin-dist/public/assets/plus-DUn8v_Xf.js +1 -0
- package/admin-dist/public/assets/rotate-ccw-DJEoHcRI.js +1 -0
- package/admin-dist/public/assets/scroll-area-DfIlT0in.js +1 -0
- package/admin-dist/public/assets/search-MuAUDJKR.js +1 -0
- package/admin-dist/public/assets/select-BD29IXCI.js +1 -0
- package/admin-dist/public/assets/settings-DmMyn_6A.js +1 -0
- package/admin-dist/public/assets/switch-h3Rrnl5i.js +1 -0
- package/admin-dist/public/assets/tabs-imc8h-Dp.js +1 -0
- package/admin-dist/public/assets/taxonomies-dAsrT65H.js +1 -0
- package/admin-dist/public/assets/textarea-BTy7nwzR.js +1 -0
- package/admin-dist/public/assets/trash-SAWKZZHv.js +1 -0
- package/admin-dist/public/assets/triangle-alert-E52Vfeuh.js +1 -0
- package/admin-dist/public/assets/useBreadcrumbLabel-BECBMCzM.js +1 -0
- package/admin-dist/public/assets/usePermissions-Basjs9BT.js +1 -0
- package/admin-dist/public/favicon.ico +0 -0
- package/admin-dist/server/_chunks/_libs/@date-fns/tz.mjs +217 -0
- package/admin-dist/server/_chunks/_libs/@floating-ui/core.mjs +719 -0
- package/admin-dist/server/_chunks/_libs/@floating-ui/dom.mjs +622 -0
- package/admin-dist/server/_chunks/_libs/@floating-ui/react-dom.mjs +292 -0
- package/admin-dist/server/_chunks/_libs/@floating-ui/utils.mjs +320 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/number.mjs +6 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/primitive.mjs +11 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-arrow.mjs +23 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-avatar.mjs +119 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-checkbox.mjs +270 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-collection.mjs +69 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-compose-refs.mjs +39 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-context.mjs +137 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-dialog.mjs +325 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-direction.mjs +9 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-dismissable-layer.mjs +210 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-dropdown-menu.mjs +253 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-focus-guards.mjs +29 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-focus-scope.mjs +206 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-id.mjs +14 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-label.mjs +23 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-menu.mjs +812 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-popover.mjs +300 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-popper.mjs +286 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-portal.mjs +16 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-presence.mjs +128 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-primitive.mjs +141 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-roving-focus.mjs +224 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-scroll-area.mjs +721 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-select.mjs +1163 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-separator.mjs +28 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-slot.mjs +601 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-switch.mjs +152 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-tabs.mjs +189 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-callback-ref.mjs +11 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-controllable-state.mjs +69 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-effect-event.mjs +1 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-escape-keydown.mjs +17 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-is-hydrated.mjs +15 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-layout-effect.mjs +6 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-previous.mjs +14 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-use-size.mjs +39 -0
- package/admin-dist/server/_chunks/_libs/@radix-ui/react-visually-hidden.mjs +33 -0
- package/admin-dist/server/_chunks/_libs/@tanstack/history.mjs +409 -0
- package/admin-dist/server/_chunks/_libs/@tanstack/react-router.mjs +1711 -0
- package/admin-dist/server/_chunks/_libs/@tanstack/react-store.mjs +56 -0
- package/admin-dist/server/_chunks/_libs/@tanstack/router-core.mjs +4829 -0
- package/admin-dist/server/_chunks/_libs/@tanstack/store.mjs +134 -0
- package/admin-dist/server/_chunks/_libs/react-dom.mjs +10781 -0
- package/admin-dist/server/_chunks/_libs/react.mjs +513 -0
- package/admin-dist/server/_libs/aria-hidden.mjs +122 -0
- package/admin-dist/server/_libs/class-variance-authority.mjs +44 -0
- package/admin-dist/server/_libs/clsx.mjs +16 -0
- package/admin-dist/server/_libs/cmdk.mjs +315 -0
- package/admin-dist/server/_libs/convex.mjs +4841 -0
- package/admin-dist/server/_libs/cookie-es.mjs +58 -0
- package/admin-dist/server/_libs/croner.mjs +1 -0
- package/admin-dist/server/_libs/crossws.mjs +1 -0
- package/admin-dist/server/_libs/date-fns.mjs +1716 -0
- package/admin-dist/server/_libs/detect-node-es.mjs +1 -0
- package/admin-dist/server/_libs/get-nonce.mjs +9 -0
- package/admin-dist/server/_libs/h3-v2.mjs +277 -0
- package/admin-dist/server/_libs/h3.mjs +401 -0
- package/admin-dist/server/_libs/hookable.mjs +1 -0
- package/admin-dist/server/_libs/isbot.mjs +20 -0
- package/admin-dist/server/_libs/lucide-react.mjs +850 -0
- package/admin-dist/server/_libs/ohash.mjs +1 -0
- package/admin-dist/server/_libs/react-day-picker.mjs +2201 -0
- package/admin-dist/server/_libs/react-remove-scroll-bar.mjs +82 -0
- package/admin-dist/server/_libs/react-remove-scroll.mjs +328 -0
- package/admin-dist/server/_libs/react-style-singleton.mjs +69 -0
- package/admin-dist/server/_libs/rou3.mjs +8 -0
- package/admin-dist/server/_libs/seroval-plugins.mjs +58 -0
- package/admin-dist/server/_libs/seroval.mjs +1765 -0
- package/admin-dist/server/_libs/srvx.mjs +719 -0
- package/admin-dist/server/_libs/tailwind-merge.mjs +3010 -0
- package/admin-dist/server/_libs/tiny-invariant.mjs +12 -0
- package/admin-dist/server/_libs/tiny-warning.mjs +5 -0
- package/admin-dist/server/_libs/tslib.mjs +39 -0
- package/admin-dist/server/_libs/ufo.mjs +54 -0
- package/admin-dist/server/_libs/unctx.mjs +1 -0
- package/admin-dist/server/_libs/unstorage.mjs +1 -0
- package/admin-dist/server/_libs/use-callback-ref.mjs +66 -0
- package/admin-dist/server/_libs/use-sidecar.mjs +106 -0
- package/admin-dist/server/_libs/use-sync-external-store.mjs +139 -0
- package/admin-dist/server/_libs/zod.mjs +4223 -0
- package/admin-dist/server/_ssr/CmsEmptyState-DU7-7-mV.mjs +290 -0
- package/admin-dist/server/_ssr/CmsPageHeader-CseW0AHm.mjs +24 -0
- package/admin-dist/server/_ssr/CmsStatusBadge-B_pi4KCp.mjs +127 -0
- package/admin-dist/server/_ssr/CmsToolbar-X75ex6ek.mjs +49 -0
- package/admin-dist/server/_ssr/ContentEntryEditor-CepusRsA.mjs +3720 -0
- package/admin-dist/server/_ssr/ErrorState-cI-bKLez.mjs +89 -0
- package/admin-dist/server/_ssr/TaxonomyFilter-Bwrq0-cz.mjs +188 -0
- package/admin-dist/server/_ssr/_contentTypeId-BqYKEcLr.mjs +379 -0
- package/admin-dist/server/_ssr/_entryId-CRfnqeDf.mjs +161 -0
- package/admin-dist/server/_ssr/_tanstack-start-manifest_v-BwDlABVk.mjs +4 -0
- package/admin-dist/server/_ssr/alert-CVt45UUP.mjs +92 -0
- package/admin-dist/server/_ssr/badge-6BsP37vG.mjs +125 -0
- package/admin-dist/server/_ssr/command-fy8epIKf.mjs +128 -0
- package/admin-dist/server/_ssr/config.server-D7JHDcDv.mjs +117 -0
- package/admin-dist/server/_ssr/content-B5RhL7uW.mjs +532 -0
- package/admin-dist/server/_ssr/content-types-BIOqCQYN.mjs +1166 -0
- package/admin-dist/server/_ssr/index-DHSHDPt1.mjs +193 -0
- package/admin-dist/server/_ssr/index.mjs +1275 -0
- package/admin-dist/server/_ssr/label-C8Dko1j7.mjs +22 -0
- package/admin-dist/server/_ssr/media-CSx3XttC.mjs +1832 -0
- package/admin-dist/server/_ssr/new._contentTypeId-DzanEZQM.mjs +144 -0
- package/admin-dist/server/_ssr/router-DDWcF-kt.mjs +1556 -0
- package/admin-dist/server/_ssr/scroll-area-bjPYwhXN.mjs +59 -0
- package/admin-dist/server/_ssr/select-BUhDDf4T.mjs +142 -0
- package/admin-dist/server/_ssr/settings-DAsxnw2q.mjs +348 -0
- package/admin-dist/server/_ssr/start-HYkvq4Ni.mjs +4 -0
- package/admin-dist/server/_ssr/switch-BgyRtQ1Z.mjs +31 -0
- package/admin-dist/server/_ssr/tabs-DzMdRB1A.mjs +628 -0
- package/admin-dist/server/_ssr/taxonomies-C8j8g5Q5.mjs +915 -0
- package/admin-dist/server/_ssr/textarea-9jNeYJSc.mjs +18 -0
- package/admin-dist/server/_ssr/trash-DYMxwhZB.mjs +291 -0
- package/admin-dist/server/_ssr/useBreadcrumbLabel-FNSAr2Ha.mjs +16 -0
- package/admin-dist/server/_ssr/usePermissions-BJGGahrJ.mjs +68 -0
- package/admin-dist/server/favicon.ico +0 -0
- package/admin-dist/server/index.mjs +627 -0
- package/dist/cli/index.js +0 -0
- package/dist/client/admin-config.d.ts +0 -1
- package/dist/client/admin-config.d.ts.map +1 -1
- package/dist/client/admin-config.js +0 -1
- package/dist/client/admin-config.js.map +1 -1
- package/dist/client/adminApi.d.ts.map +1 -1
- package/dist/client/agentTools.d.ts +1237 -135
- package/dist/client/agentTools.d.ts.map +1 -1
- package/dist/client/agentTools.js +33 -9
- package/dist/client/agentTools.js.map +1 -1
- package/dist/client/index.d.ts +1 -1
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js.map +1 -1
- package/dist/component/_generated/component.d.ts +9 -0
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/mediaAssets.d.ts +35 -0
- package/dist/component/mediaAssets.d.ts.map +1 -1
- package/dist/component/mediaAssets.js +81 -0
- package/dist/component/mediaAssets.js.map +1 -1
- package/dist/test.d.ts.map +1 -1
- package/dist/test.js +2 -1
- package/dist/test.js.map +1 -1
- package/package.json +24 -9
- package/dist/component/auditLog.d.ts +0 -410
- package/dist/component/auditLog.d.ts.map +0 -1
- package/dist/component/auditLog.js +0 -607
- package/dist/component/auditLog.js.map +0 -1
- package/dist/component/types.d.ts +0 -4
- package/dist/component/types.d.ts.map +0 -1
- package/dist/component/types.js +0 -2
- package/dist/component/types.js.map +0 -1
- package/src/cli/commands/admin.ts +0 -104
- package/src/cli/index.ts +0 -21
- package/src/cli/utils/detectConvexUrl.ts +0 -54
- package/src/cli/utils/openBrowser.ts +0 -16
- package/src/client/admin-config.ts +0 -138
- package/src/client/adminApi.ts +0 -942
- package/src/client/agentTools.ts +0 -1311
- package/src/client/argTypes.ts +0 -316
- package/src/client/field-types.ts +0 -187
- package/src/client/index.ts +0 -1301
- package/src/client/queryBuilder.ts +0 -1100
- package/src/client/schema/codegen.ts +0 -500
- package/src/client/schema/defineContentType.ts +0 -501
- package/src/client/schema/index.ts +0 -169
- package/src/client/schema/schemaDrift.ts +0 -574
- package/src/client/schema/typedClient.ts +0 -688
- package/src/client/schema/types.ts +0 -666
- package/src/client/types.ts +0 -723
- package/src/client/workflows.ts +0 -141
- package/src/client/wrapper.ts +0 -4304
- package/src/component/_generated/api.ts +0 -140
- package/src/component/_generated/component.ts +0 -5029
- package/src/component/_generated/dataModel.ts +0 -60
- package/src/component/_generated/server.ts +0 -156
- package/src/component/authorization.ts +0 -647
- package/src/component/authorizationHooks.ts +0 -668
- package/src/component/bulkOperations.ts +0 -687
- package/src/component/contentEntries.ts +0 -1976
- package/src/component/contentEntryMutations.ts +0 -1223
- package/src/component/contentEntryValidation.ts +0 -707
- package/src/component/contentLock.ts +0 -550
- package/src/component/contentTypeMigration.ts +0 -1064
- package/src/component/contentTypeMutations.ts +0 -969
- package/src/component/contentTypes.ts +0 -346
- package/src/component/convex.config.ts +0 -44
- package/src/component/documentTypes.ts +0 -240
- package/src/component/eventEmitter.ts +0 -485
- package/src/component/exportImport.ts +0 -1169
- package/src/component/index.ts +0 -491
- package/src/component/lib/deepReferenceResolver.ts +0 -999
- package/src/component/lib/errors.ts +0 -816
- package/src/component/lib/index.ts +0 -145
- package/src/component/lib/mediaReferenceResolver.ts +0 -495
- package/src/component/lib/metadataExtractor.ts +0 -792
- package/src/component/lib/mutationAuth.ts +0 -199
- package/src/component/lib/queries.ts +0 -79
- package/src/component/lib/ragContentChunker.ts +0 -1371
- package/src/component/lib/referenceResolver.ts +0 -430
- package/src/component/lib/slugGenerator.ts +0 -262
- package/src/component/lib/slugUniqueness.ts +0 -333
- package/src/component/lib/softDelete.ts +0 -44
- package/src/component/localeFallbackChain.ts +0 -673
- package/src/component/localeFields.ts +0 -896
- package/src/component/mediaAssetMutations.ts +0 -725
- package/src/component/mediaAssets.ts +0 -932
- package/src/component/mediaFolderMutations.ts +0 -1046
- package/src/component/mediaUploadMutations.ts +0 -224
- package/src/component/mediaVariantMutations.ts +0 -900
- package/src/component/mediaVariants.ts +0 -793
- package/src/component/ragContentIndexer.ts +0 -1067
- package/src/component/rateLimitHooks.ts +0 -572
- package/src/component/roles.ts +0 -1360
- package/src/component/scheduledPublish.ts +0 -358
- package/src/component/schema.ts +0 -617
- package/src/component/taxonomies.ts +0 -949
- package/src/component/taxonomyMutations.ts +0 -1210
- package/src/component/trash.ts +0 -724
- package/src/component/userContext.ts +0 -898
- package/src/component/validation.ts +0 -1388
- package/src/component/validators.ts +0 -949
- package/src/component/versionMutations.ts +0 -392
- package/src/component/webhookTrigger.ts +0 -1922
- package/src/react/index.ts +0 -898
- package/src/test.ts +0 -1580
|
@@ -0,0 +1,4829 @@
|
|
|
1
|
+
import { s as splitSetCookieString } from "../../../_libs/cookie-es.mjs";
|
|
2
|
+
import { b as batch, S as Store } from "./store.mjs";
|
|
3
|
+
import { c as createBrowserHistory, p as parseHref } from "./history.mjs";
|
|
4
|
+
import { i as invariant } from "../../../_libs/tiny-invariant.mjs";
|
|
5
|
+
import { n as ni, t as te, c as cn, m as mn } from "../../../_libs/seroval.mjs";
|
|
6
|
+
import { p } from "../../../_libs/seroval-plugins.mjs";
|
|
7
|
+
import { ReadableStream as ReadableStream$1 } from "node:stream/web";
|
|
8
|
+
import { Readable } from "node:stream";
|
|
9
|
+
function toHeadersInstance(init) {
|
|
10
|
+
if (init instanceof Headers) {
|
|
11
|
+
return new Headers(init);
|
|
12
|
+
} else if (Array.isArray(init)) {
|
|
13
|
+
return new Headers(init);
|
|
14
|
+
} else if (typeof init === "object") {
|
|
15
|
+
return new Headers(init);
|
|
16
|
+
} else {
|
|
17
|
+
return new Headers();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function mergeHeaders(...headers) {
|
|
21
|
+
return headers.reduce((acc, header) => {
|
|
22
|
+
const headersInstance = toHeadersInstance(header);
|
|
23
|
+
for (const [key, value] of headersInstance.entries()) {
|
|
24
|
+
if (key === "set-cookie") {
|
|
25
|
+
const splitCookies = splitSetCookieString(value);
|
|
26
|
+
splitCookies.forEach((cookie) => acc.append("set-cookie", cookie));
|
|
27
|
+
} else {
|
|
28
|
+
acc.set(key, value);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return acc;
|
|
32
|
+
}, new Headers());
|
|
33
|
+
}
|
|
34
|
+
function isNotFound(obj) {
|
|
35
|
+
return !!obj?.isNotFound;
|
|
36
|
+
}
|
|
37
|
+
function last(arr) {
|
|
38
|
+
return arr[arr.length - 1];
|
|
39
|
+
}
|
|
40
|
+
function isFunction(d) {
|
|
41
|
+
return typeof d === "function";
|
|
42
|
+
}
|
|
43
|
+
function functionalUpdate(updater, previous) {
|
|
44
|
+
if (isFunction(updater)) {
|
|
45
|
+
return updater(previous);
|
|
46
|
+
}
|
|
47
|
+
return updater;
|
|
48
|
+
}
|
|
49
|
+
const hasOwn = Object.prototype.hasOwnProperty;
|
|
50
|
+
const isEnumerable = Object.prototype.propertyIsEnumerable;
|
|
51
|
+
function replaceEqualDeep(prev, _next, _depth = 0) {
|
|
52
|
+
if (prev === _next) {
|
|
53
|
+
return prev;
|
|
54
|
+
}
|
|
55
|
+
if (_depth > 500) return _next;
|
|
56
|
+
const next = _next;
|
|
57
|
+
const array = isPlainArray(prev) && isPlainArray(next);
|
|
58
|
+
if (!array && !(isPlainObject(prev) && isPlainObject(next))) return next;
|
|
59
|
+
const prevItems = array ? prev : getEnumerableOwnKeys(prev);
|
|
60
|
+
if (!prevItems) return next;
|
|
61
|
+
const nextItems = array ? next : getEnumerableOwnKeys(next);
|
|
62
|
+
if (!nextItems) return next;
|
|
63
|
+
const prevSize = prevItems.length;
|
|
64
|
+
const nextSize = nextItems.length;
|
|
65
|
+
const copy = array ? new Array(nextSize) : {};
|
|
66
|
+
let equalItems = 0;
|
|
67
|
+
for (let i = 0; i < nextSize; i++) {
|
|
68
|
+
const key = array ? i : nextItems[i];
|
|
69
|
+
const p2 = prev[key];
|
|
70
|
+
const n = next[key];
|
|
71
|
+
if (p2 === n) {
|
|
72
|
+
copy[key] = p2;
|
|
73
|
+
if (array ? i < prevSize : hasOwn.call(prev, key)) equalItems++;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (p2 === null || n === null || typeof p2 !== "object" || typeof n !== "object") {
|
|
77
|
+
copy[key] = n;
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
const v = replaceEqualDeep(p2, n, _depth + 1);
|
|
81
|
+
copy[key] = v;
|
|
82
|
+
if (v === p2) equalItems++;
|
|
83
|
+
}
|
|
84
|
+
return prevSize === nextSize && equalItems === prevSize ? prev : copy;
|
|
85
|
+
}
|
|
86
|
+
function getEnumerableOwnKeys(o) {
|
|
87
|
+
const names = Object.getOwnPropertyNames(o);
|
|
88
|
+
for (const name of names) {
|
|
89
|
+
if (!isEnumerable.call(o, name)) return false;
|
|
90
|
+
}
|
|
91
|
+
const symbols = Object.getOwnPropertySymbols(o);
|
|
92
|
+
if (symbols.length === 0) return names;
|
|
93
|
+
const keys = names;
|
|
94
|
+
for (const symbol of symbols) {
|
|
95
|
+
if (!isEnumerable.call(o, symbol)) return false;
|
|
96
|
+
keys.push(symbol);
|
|
97
|
+
}
|
|
98
|
+
return keys;
|
|
99
|
+
}
|
|
100
|
+
function isPlainObject(o) {
|
|
101
|
+
if (!hasObjectPrototype(o)) {
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
const ctor = o.constructor;
|
|
105
|
+
if (typeof ctor === "undefined") {
|
|
106
|
+
return true;
|
|
107
|
+
}
|
|
108
|
+
const prot = ctor.prototype;
|
|
109
|
+
if (!hasObjectPrototype(prot)) {
|
|
110
|
+
return false;
|
|
111
|
+
}
|
|
112
|
+
if (!prot.hasOwnProperty("isPrototypeOf")) {
|
|
113
|
+
return false;
|
|
114
|
+
}
|
|
115
|
+
return true;
|
|
116
|
+
}
|
|
117
|
+
function hasObjectPrototype(o) {
|
|
118
|
+
return Object.prototype.toString.call(o) === "[object Object]";
|
|
119
|
+
}
|
|
120
|
+
function isPlainArray(value) {
|
|
121
|
+
return Array.isArray(value) && value.length === Object.keys(value).length;
|
|
122
|
+
}
|
|
123
|
+
function deepEqual(a, b, opts) {
|
|
124
|
+
if (a === b) {
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
if (typeof a !== typeof b) {
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
130
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
131
|
+
if (a.length !== b.length) return false;
|
|
132
|
+
for (let i = 0, l = a.length; i < l; i++) {
|
|
133
|
+
if (!deepEqual(a[i], b[i], opts)) return false;
|
|
134
|
+
}
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
if (isPlainObject(a) && isPlainObject(b)) {
|
|
138
|
+
const ignoreUndefined = opts?.ignoreUndefined ?? true;
|
|
139
|
+
if (opts?.partial) {
|
|
140
|
+
for (const k in b) {
|
|
141
|
+
if (!ignoreUndefined || b[k] !== void 0) {
|
|
142
|
+
if (!deepEqual(a[k], b[k], opts)) return false;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return true;
|
|
146
|
+
}
|
|
147
|
+
let aCount = 0;
|
|
148
|
+
if (!ignoreUndefined) {
|
|
149
|
+
aCount = Object.keys(a).length;
|
|
150
|
+
} else {
|
|
151
|
+
for (const k in a) {
|
|
152
|
+
if (a[k] !== void 0) aCount++;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
let bCount = 0;
|
|
156
|
+
for (const k in b) {
|
|
157
|
+
if (!ignoreUndefined || b[k] !== void 0) {
|
|
158
|
+
bCount++;
|
|
159
|
+
if (bCount > aCount || !deepEqual(a[k], b[k], opts)) return false;
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
return aCount === bCount;
|
|
163
|
+
}
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
166
|
+
function createControlledPromise(onResolve) {
|
|
167
|
+
let resolveLoadPromise;
|
|
168
|
+
let rejectLoadPromise;
|
|
169
|
+
const controlledPromise = new Promise((resolve, reject) => {
|
|
170
|
+
resolveLoadPromise = resolve;
|
|
171
|
+
rejectLoadPromise = reject;
|
|
172
|
+
});
|
|
173
|
+
controlledPromise.status = "pending";
|
|
174
|
+
controlledPromise.resolve = (value) => {
|
|
175
|
+
controlledPromise.status = "resolved";
|
|
176
|
+
controlledPromise.value = value;
|
|
177
|
+
resolveLoadPromise(value);
|
|
178
|
+
onResolve?.(value);
|
|
179
|
+
};
|
|
180
|
+
controlledPromise.reject = (e) => {
|
|
181
|
+
controlledPromise.status = "rejected";
|
|
182
|
+
rejectLoadPromise(e);
|
|
183
|
+
};
|
|
184
|
+
return controlledPromise;
|
|
185
|
+
}
|
|
186
|
+
function isModuleNotFoundError(error) {
|
|
187
|
+
if (typeof error?.message !== "string") return false;
|
|
188
|
+
return error.message.startsWith("Failed to fetch dynamically imported module") || error.message.startsWith("error loading dynamically imported module") || error.message.startsWith("Importing a module script failed");
|
|
189
|
+
}
|
|
190
|
+
function isPromise(value) {
|
|
191
|
+
return Boolean(
|
|
192
|
+
value && typeof value === "object" && typeof value.then === "function"
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
function sanitizePathSegment(segment) {
|
|
196
|
+
return segment.replace(/[\x00-\x1f\x7f]/g, "");
|
|
197
|
+
}
|
|
198
|
+
function decodeSegment(segment) {
|
|
199
|
+
let decoded;
|
|
200
|
+
try {
|
|
201
|
+
decoded = decodeURI(segment);
|
|
202
|
+
} catch {
|
|
203
|
+
decoded = segment.replaceAll(/%[0-9A-F]{2}/gi, (match) => {
|
|
204
|
+
try {
|
|
205
|
+
return decodeURI(match);
|
|
206
|
+
} catch {
|
|
207
|
+
return match;
|
|
208
|
+
}
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
return sanitizePathSegment(decoded);
|
|
212
|
+
}
|
|
213
|
+
const SAFE_URL_PROTOCOLS = ["http:", "https:", "mailto:", "tel:"];
|
|
214
|
+
function isDangerousProtocol(url) {
|
|
215
|
+
if (!url) return false;
|
|
216
|
+
try {
|
|
217
|
+
const parsed = new URL(url);
|
|
218
|
+
return !SAFE_URL_PROTOCOLS.includes(parsed.protocol);
|
|
219
|
+
} catch {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
const HTML_ESCAPE_LOOKUP = {
|
|
224
|
+
"&": "\\u0026",
|
|
225
|
+
">": "\\u003e",
|
|
226
|
+
"<": "\\u003c",
|
|
227
|
+
"\u2028": "\\u2028",
|
|
228
|
+
"\u2029": "\\u2029"
|
|
229
|
+
};
|
|
230
|
+
const HTML_ESCAPE_REGEX = /[&><\u2028\u2029]/g;
|
|
231
|
+
function escapeHtml(str) {
|
|
232
|
+
return str.replace(HTML_ESCAPE_REGEX, (match) => HTML_ESCAPE_LOOKUP[match]);
|
|
233
|
+
}
|
|
234
|
+
function decodePath(path, decodeIgnore) {
|
|
235
|
+
if (!path) return path;
|
|
236
|
+
const re = /%25|%5C/gi;
|
|
237
|
+
let cursor = 0;
|
|
238
|
+
let result = "";
|
|
239
|
+
let match;
|
|
240
|
+
while (null !== (match = re.exec(path))) {
|
|
241
|
+
result += decodeSegment(path.slice(cursor, match.index)) + match[0];
|
|
242
|
+
cursor = re.lastIndex;
|
|
243
|
+
}
|
|
244
|
+
result = result + decodeSegment(cursor ? path.slice(cursor) : path);
|
|
245
|
+
if (result.startsWith("//")) {
|
|
246
|
+
result = "/" + result.replace(/^\/+/, "");
|
|
247
|
+
}
|
|
248
|
+
return result;
|
|
249
|
+
}
|
|
250
|
+
function createLRUCache(max) {
|
|
251
|
+
const cache = /* @__PURE__ */ new Map();
|
|
252
|
+
let oldest;
|
|
253
|
+
let newest;
|
|
254
|
+
const touch = (entry) => {
|
|
255
|
+
if (!entry.next) return;
|
|
256
|
+
if (!entry.prev) {
|
|
257
|
+
entry.next.prev = void 0;
|
|
258
|
+
oldest = entry.next;
|
|
259
|
+
entry.next = void 0;
|
|
260
|
+
if (newest) {
|
|
261
|
+
entry.prev = newest;
|
|
262
|
+
newest.next = entry;
|
|
263
|
+
}
|
|
264
|
+
} else {
|
|
265
|
+
entry.prev.next = entry.next;
|
|
266
|
+
entry.next.prev = entry.prev;
|
|
267
|
+
entry.next = void 0;
|
|
268
|
+
if (newest) {
|
|
269
|
+
newest.next = entry;
|
|
270
|
+
entry.prev = newest;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
newest = entry;
|
|
274
|
+
};
|
|
275
|
+
return {
|
|
276
|
+
get(key) {
|
|
277
|
+
const entry = cache.get(key);
|
|
278
|
+
if (!entry) return void 0;
|
|
279
|
+
touch(entry);
|
|
280
|
+
return entry.value;
|
|
281
|
+
},
|
|
282
|
+
set(key, value) {
|
|
283
|
+
if (cache.size >= max && oldest) {
|
|
284
|
+
const toDelete = oldest;
|
|
285
|
+
cache.delete(toDelete.key);
|
|
286
|
+
if (toDelete.next) {
|
|
287
|
+
oldest = toDelete.next;
|
|
288
|
+
toDelete.next.prev = void 0;
|
|
289
|
+
}
|
|
290
|
+
if (toDelete === newest) {
|
|
291
|
+
newest = void 0;
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
const existing = cache.get(key);
|
|
295
|
+
if (existing) {
|
|
296
|
+
existing.value = value;
|
|
297
|
+
touch(existing);
|
|
298
|
+
} else {
|
|
299
|
+
const entry = { key, value, prev: newest };
|
|
300
|
+
if (newest) newest.next = entry;
|
|
301
|
+
newest = entry;
|
|
302
|
+
if (!oldest) oldest = entry;
|
|
303
|
+
cache.set(key, entry);
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
clear() {
|
|
307
|
+
cache.clear();
|
|
308
|
+
oldest = void 0;
|
|
309
|
+
newest = void 0;
|
|
310
|
+
}
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
const SEGMENT_TYPE_PATHNAME = 0;
|
|
314
|
+
const SEGMENT_TYPE_PARAM = 1;
|
|
315
|
+
const SEGMENT_TYPE_WILDCARD = 2;
|
|
316
|
+
const SEGMENT_TYPE_OPTIONAL_PARAM = 3;
|
|
317
|
+
const SEGMENT_TYPE_INDEX = 4;
|
|
318
|
+
const SEGMENT_TYPE_PATHLESS = 5;
|
|
319
|
+
const PARAM_W_CURLY_BRACES_RE = /^([^{]*)\{\$([a-zA-Z_$][a-zA-Z0-9_$]*)\}([^}]*)$/;
|
|
320
|
+
const OPTIONAL_PARAM_W_CURLY_BRACES_RE = /^([^{]*)\{-\$([a-zA-Z_$][a-zA-Z0-9_$]*)\}([^}]*)$/;
|
|
321
|
+
const WILDCARD_W_CURLY_BRACES_RE = /^([^{]*)\{\$\}([^}]*)$/;
|
|
322
|
+
function parseSegment(path, start, output = new Uint16Array(6)) {
|
|
323
|
+
const next = path.indexOf("/", start);
|
|
324
|
+
const end = next === -1 ? path.length : next;
|
|
325
|
+
const part = path.substring(start, end);
|
|
326
|
+
if (!part || !part.includes("$")) {
|
|
327
|
+
output[0] = SEGMENT_TYPE_PATHNAME;
|
|
328
|
+
output[1] = start;
|
|
329
|
+
output[2] = start;
|
|
330
|
+
output[3] = end;
|
|
331
|
+
output[4] = end;
|
|
332
|
+
output[5] = end;
|
|
333
|
+
return output;
|
|
334
|
+
}
|
|
335
|
+
if (part === "$") {
|
|
336
|
+
const total = path.length;
|
|
337
|
+
output[0] = SEGMENT_TYPE_WILDCARD;
|
|
338
|
+
output[1] = start;
|
|
339
|
+
output[2] = start;
|
|
340
|
+
output[3] = total;
|
|
341
|
+
output[4] = total;
|
|
342
|
+
output[5] = total;
|
|
343
|
+
return output;
|
|
344
|
+
}
|
|
345
|
+
if (part.charCodeAt(0) === 36) {
|
|
346
|
+
output[0] = SEGMENT_TYPE_PARAM;
|
|
347
|
+
output[1] = start;
|
|
348
|
+
output[2] = start + 1;
|
|
349
|
+
output[3] = end;
|
|
350
|
+
output[4] = end;
|
|
351
|
+
output[5] = end;
|
|
352
|
+
return output;
|
|
353
|
+
}
|
|
354
|
+
const wildcardBracesMatch = part.match(WILDCARD_W_CURLY_BRACES_RE);
|
|
355
|
+
if (wildcardBracesMatch) {
|
|
356
|
+
const prefix = wildcardBracesMatch[1];
|
|
357
|
+
const pLength = prefix.length;
|
|
358
|
+
output[0] = SEGMENT_TYPE_WILDCARD;
|
|
359
|
+
output[1] = start + pLength;
|
|
360
|
+
output[2] = start + pLength + 1;
|
|
361
|
+
output[3] = start + pLength + 2;
|
|
362
|
+
output[4] = start + pLength + 3;
|
|
363
|
+
output[5] = path.length;
|
|
364
|
+
return output;
|
|
365
|
+
}
|
|
366
|
+
const optionalParamBracesMatch = part.match(OPTIONAL_PARAM_W_CURLY_BRACES_RE);
|
|
367
|
+
if (optionalParamBracesMatch) {
|
|
368
|
+
const prefix = optionalParamBracesMatch[1];
|
|
369
|
+
const paramName = optionalParamBracesMatch[2];
|
|
370
|
+
const suffix = optionalParamBracesMatch[3];
|
|
371
|
+
const pLength = prefix.length;
|
|
372
|
+
output[0] = SEGMENT_TYPE_OPTIONAL_PARAM;
|
|
373
|
+
output[1] = start + pLength;
|
|
374
|
+
output[2] = start + pLength + 3;
|
|
375
|
+
output[3] = start + pLength + 3 + paramName.length;
|
|
376
|
+
output[4] = end - suffix.length;
|
|
377
|
+
output[5] = end;
|
|
378
|
+
return output;
|
|
379
|
+
}
|
|
380
|
+
const paramBracesMatch = part.match(PARAM_W_CURLY_BRACES_RE);
|
|
381
|
+
if (paramBracesMatch) {
|
|
382
|
+
const prefix = paramBracesMatch[1];
|
|
383
|
+
const paramName = paramBracesMatch[2];
|
|
384
|
+
const suffix = paramBracesMatch[3];
|
|
385
|
+
const pLength = prefix.length;
|
|
386
|
+
output[0] = SEGMENT_TYPE_PARAM;
|
|
387
|
+
output[1] = start + pLength;
|
|
388
|
+
output[2] = start + pLength + 2;
|
|
389
|
+
output[3] = start + pLength + 2 + paramName.length;
|
|
390
|
+
output[4] = end - suffix.length;
|
|
391
|
+
output[5] = end;
|
|
392
|
+
return output;
|
|
393
|
+
}
|
|
394
|
+
output[0] = SEGMENT_TYPE_PATHNAME;
|
|
395
|
+
output[1] = start;
|
|
396
|
+
output[2] = start;
|
|
397
|
+
output[3] = end;
|
|
398
|
+
output[4] = end;
|
|
399
|
+
output[5] = end;
|
|
400
|
+
return output;
|
|
401
|
+
}
|
|
402
|
+
function parseSegments(defaultCaseSensitive, data, route, start, node, depth, onRoute) {
|
|
403
|
+
onRoute?.(route);
|
|
404
|
+
let cursor = start;
|
|
405
|
+
{
|
|
406
|
+
const path = route.fullPath ?? route.from;
|
|
407
|
+
const length = path.length;
|
|
408
|
+
const caseSensitive = route.options?.caseSensitive ?? defaultCaseSensitive;
|
|
409
|
+
const skipOnParamError = !!(route.options?.params?.parse && route.options?.skipRouteOnParseError?.params);
|
|
410
|
+
while (cursor < length) {
|
|
411
|
+
const segment = parseSegment(path, cursor, data);
|
|
412
|
+
let nextNode;
|
|
413
|
+
const start2 = cursor;
|
|
414
|
+
const end = segment[5];
|
|
415
|
+
cursor = end + 1;
|
|
416
|
+
depth++;
|
|
417
|
+
const kind = segment[0];
|
|
418
|
+
switch (kind) {
|
|
419
|
+
case SEGMENT_TYPE_PATHNAME: {
|
|
420
|
+
const value = path.substring(segment[2], segment[3]);
|
|
421
|
+
if (caseSensitive) {
|
|
422
|
+
const existingNode = node.static?.get(value);
|
|
423
|
+
if (existingNode) {
|
|
424
|
+
nextNode = existingNode;
|
|
425
|
+
} else {
|
|
426
|
+
node.static ??= /* @__PURE__ */ new Map();
|
|
427
|
+
const next = createStaticNode(
|
|
428
|
+
route.fullPath ?? route.from
|
|
429
|
+
);
|
|
430
|
+
next.parent = node;
|
|
431
|
+
next.depth = depth;
|
|
432
|
+
nextNode = next;
|
|
433
|
+
node.static.set(value, next);
|
|
434
|
+
}
|
|
435
|
+
} else {
|
|
436
|
+
const name = value.toLowerCase();
|
|
437
|
+
const existingNode = node.staticInsensitive?.get(name);
|
|
438
|
+
if (existingNode) {
|
|
439
|
+
nextNode = existingNode;
|
|
440
|
+
} else {
|
|
441
|
+
node.staticInsensitive ??= /* @__PURE__ */ new Map();
|
|
442
|
+
const next = createStaticNode(
|
|
443
|
+
route.fullPath ?? route.from
|
|
444
|
+
);
|
|
445
|
+
next.parent = node;
|
|
446
|
+
next.depth = depth;
|
|
447
|
+
nextNode = next;
|
|
448
|
+
node.staticInsensitive.set(name, next);
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
453
|
+
case SEGMENT_TYPE_PARAM: {
|
|
454
|
+
const prefix_raw = path.substring(start2, segment[1]);
|
|
455
|
+
const suffix_raw = path.substring(segment[4], end);
|
|
456
|
+
const actuallyCaseSensitive = caseSensitive && !!(prefix_raw || suffix_raw);
|
|
457
|
+
const prefix = !prefix_raw ? void 0 : actuallyCaseSensitive ? prefix_raw : prefix_raw.toLowerCase();
|
|
458
|
+
const suffix = !suffix_raw ? void 0 : actuallyCaseSensitive ? suffix_raw : suffix_raw.toLowerCase();
|
|
459
|
+
const existingNode = !skipOnParamError && node.dynamic?.find(
|
|
460
|
+
(s) => !s.skipOnParamError && s.caseSensitive === actuallyCaseSensitive && s.prefix === prefix && s.suffix === suffix
|
|
461
|
+
);
|
|
462
|
+
if (existingNode) {
|
|
463
|
+
nextNode = existingNode;
|
|
464
|
+
} else {
|
|
465
|
+
const next = createDynamicNode(
|
|
466
|
+
SEGMENT_TYPE_PARAM,
|
|
467
|
+
route.fullPath ?? route.from,
|
|
468
|
+
actuallyCaseSensitive,
|
|
469
|
+
prefix,
|
|
470
|
+
suffix
|
|
471
|
+
);
|
|
472
|
+
nextNode = next;
|
|
473
|
+
next.depth = depth;
|
|
474
|
+
next.parent = node;
|
|
475
|
+
node.dynamic ??= [];
|
|
476
|
+
node.dynamic.push(next);
|
|
477
|
+
}
|
|
478
|
+
break;
|
|
479
|
+
}
|
|
480
|
+
case SEGMENT_TYPE_OPTIONAL_PARAM: {
|
|
481
|
+
const prefix_raw = path.substring(start2, segment[1]);
|
|
482
|
+
const suffix_raw = path.substring(segment[4], end);
|
|
483
|
+
const actuallyCaseSensitive = caseSensitive && !!(prefix_raw || suffix_raw);
|
|
484
|
+
const prefix = !prefix_raw ? void 0 : actuallyCaseSensitive ? prefix_raw : prefix_raw.toLowerCase();
|
|
485
|
+
const suffix = !suffix_raw ? void 0 : actuallyCaseSensitive ? suffix_raw : suffix_raw.toLowerCase();
|
|
486
|
+
const existingNode = !skipOnParamError && node.optional?.find(
|
|
487
|
+
(s) => !s.skipOnParamError && s.caseSensitive === actuallyCaseSensitive && s.prefix === prefix && s.suffix === suffix
|
|
488
|
+
);
|
|
489
|
+
if (existingNode) {
|
|
490
|
+
nextNode = existingNode;
|
|
491
|
+
} else {
|
|
492
|
+
const next = createDynamicNode(
|
|
493
|
+
SEGMENT_TYPE_OPTIONAL_PARAM,
|
|
494
|
+
route.fullPath ?? route.from,
|
|
495
|
+
actuallyCaseSensitive,
|
|
496
|
+
prefix,
|
|
497
|
+
suffix
|
|
498
|
+
);
|
|
499
|
+
nextNode = next;
|
|
500
|
+
next.parent = node;
|
|
501
|
+
next.depth = depth;
|
|
502
|
+
node.optional ??= [];
|
|
503
|
+
node.optional.push(next);
|
|
504
|
+
}
|
|
505
|
+
break;
|
|
506
|
+
}
|
|
507
|
+
case SEGMENT_TYPE_WILDCARD: {
|
|
508
|
+
const prefix_raw = path.substring(start2, segment[1]);
|
|
509
|
+
const suffix_raw = path.substring(segment[4], end);
|
|
510
|
+
const actuallyCaseSensitive = caseSensitive && !!(prefix_raw || suffix_raw);
|
|
511
|
+
const prefix = !prefix_raw ? void 0 : actuallyCaseSensitive ? prefix_raw : prefix_raw.toLowerCase();
|
|
512
|
+
const suffix = !suffix_raw ? void 0 : actuallyCaseSensitive ? suffix_raw : suffix_raw.toLowerCase();
|
|
513
|
+
const next = createDynamicNode(
|
|
514
|
+
SEGMENT_TYPE_WILDCARD,
|
|
515
|
+
route.fullPath ?? route.from,
|
|
516
|
+
actuallyCaseSensitive,
|
|
517
|
+
prefix,
|
|
518
|
+
suffix
|
|
519
|
+
);
|
|
520
|
+
nextNode = next;
|
|
521
|
+
next.parent = node;
|
|
522
|
+
next.depth = depth;
|
|
523
|
+
node.wildcard ??= [];
|
|
524
|
+
node.wildcard.push(next);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
node = nextNode;
|
|
528
|
+
}
|
|
529
|
+
if (skipOnParamError && route.children && !route.isRoot && route.id && route.id.charCodeAt(route.id.lastIndexOf("/") + 1) === 95) {
|
|
530
|
+
const pathlessNode = createStaticNode(
|
|
531
|
+
route.fullPath ?? route.from
|
|
532
|
+
);
|
|
533
|
+
pathlessNode.kind = SEGMENT_TYPE_PATHLESS;
|
|
534
|
+
pathlessNode.parent = node;
|
|
535
|
+
depth++;
|
|
536
|
+
pathlessNode.depth = depth;
|
|
537
|
+
node.pathless ??= [];
|
|
538
|
+
node.pathless.push(pathlessNode);
|
|
539
|
+
node = pathlessNode;
|
|
540
|
+
}
|
|
541
|
+
const isLeaf = (route.path || !route.children) && !route.isRoot;
|
|
542
|
+
if (isLeaf && path.endsWith("/")) {
|
|
543
|
+
const indexNode = createStaticNode(
|
|
544
|
+
route.fullPath ?? route.from
|
|
545
|
+
);
|
|
546
|
+
indexNode.kind = SEGMENT_TYPE_INDEX;
|
|
547
|
+
indexNode.parent = node;
|
|
548
|
+
depth++;
|
|
549
|
+
indexNode.depth = depth;
|
|
550
|
+
node.index = indexNode;
|
|
551
|
+
node = indexNode;
|
|
552
|
+
}
|
|
553
|
+
node.parse = route.options?.params?.parse ?? null;
|
|
554
|
+
node.skipOnParamError = skipOnParamError;
|
|
555
|
+
node.parsingPriority = route.options?.skipRouteOnParseError?.priority ?? 0;
|
|
556
|
+
if (isLeaf && !node.route) {
|
|
557
|
+
node.route = route;
|
|
558
|
+
node.fullPath = route.fullPath ?? route.from;
|
|
559
|
+
}
|
|
560
|
+
}
|
|
561
|
+
if (route.children)
|
|
562
|
+
for (const child of route.children) {
|
|
563
|
+
parseSegments(
|
|
564
|
+
defaultCaseSensitive,
|
|
565
|
+
data,
|
|
566
|
+
child,
|
|
567
|
+
cursor,
|
|
568
|
+
node,
|
|
569
|
+
depth,
|
|
570
|
+
onRoute
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
function sortDynamic(a, b) {
|
|
575
|
+
if (a.skipOnParamError && !b.skipOnParamError) return -1;
|
|
576
|
+
if (!a.skipOnParamError && b.skipOnParamError) return 1;
|
|
577
|
+
if (a.skipOnParamError && b.skipOnParamError && (a.parsingPriority || b.parsingPriority))
|
|
578
|
+
return b.parsingPriority - a.parsingPriority;
|
|
579
|
+
if (a.prefix && b.prefix && a.prefix !== b.prefix) {
|
|
580
|
+
if (a.prefix.startsWith(b.prefix)) return -1;
|
|
581
|
+
if (b.prefix.startsWith(a.prefix)) return 1;
|
|
582
|
+
}
|
|
583
|
+
if (a.suffix && b.suffix && a.suffix !== b.suffix) {
|
|
584
|
+
if (a.suffix.endsWith(b.suffix)) return -1;
|
|
585
|
+
if (b.suffix.endsWith(a.suffix)) return 1;
|
|
586
|
+
}
|
|
587
|
+
if (a.prefix && !b.prefix) return -1;
|
|
588
|
+
if (!a.prefix && b.prefix) return 1;
|
|
589
|
+
if (a.suffix && !b.suffix) return -1;
|
|
590
|
+
if (!a.suffix && b.suffix) return 1;
|
|
591
|
+
if (a.caseSensitive && !b.caseSensitive) return -1;
|
|
592
|
+
if (!a.caseSensitive && b.caseSensitive) return 1;
|
|
593
|
+
return 0;
|
|
594
|
+
}
|
|
595
|
+
function sortTreeNodes(node) {
|
|
596
|
+
if (node.pathless) {
|
|
597
|
+
for (const child of node.pathless) {
|
|
598
|
+
sortTreeNodes(child);
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
if (node.static) {
|
|
602
|
+
for (const child of node.static.values()) {
|
|
603
|
+
sortTreeNodes(child);
|
|
604
|
+
}
|
|
605
|
+
}
|
|
606
|
+
if (node.staticInsensitive) {
|
|
607
|
+
for (const child of node.staticInsensitive.values()) {
|
|
608
|
+
sortTreeNodes(child);
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
if (node.dynamic?.length) {
|
|
612
|
+
node.dynamic.sort(sortDynamic);
|
|
613
|
+
for (const child of node.dynamic) {
|
|
614
|
+
sortTreeNodes(child);
|
|
615
|
+
}
|
|
616
|
+
}
|
|
617
|
+
if (node.optional?.length) {
|
|
618
|
+
node.optional.sort(sortDynamic);
|
|
619
|
+
for (const child of node.optional) {
|
|
620
|
+
sortTreeNodes(child);
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
if (node.wildcard?.length) {
|
|
624
|
+
node.wildcard.sort(sortDynamic);
|
|
625
|
+
for (const child of node.wildcard) {
|
|
626
|
+
sortTreeNodes(child);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
function createStaticNode(fullPath) {
|
|
631
|
+
return {
|
|
632
|
+
kind: SEGMENT_TYPE_PATHNAME,
|
|
633
|
+
depth: 0,
|
|
634
|
+
pathless: null,
|
|
635
|
+
index: null,
|
|
636
|
+
static: null,
|
|
637
|
+
staticInsensitive: null,
|
|
638
|
+
dynamic: null,
|
|
639
|
+
optional: null,
|
|
640
|
+
wildcard: null,
|
|
641
|
+
route: null,
|
|
642
|
+
fullPath,
|
|
643
|
+
parent: null,
|
|
644
|
+
parse: null,
|
|
645
|
+
skipOnParamError: false,
|
|
646
|
+
parsingPriority: 0
|
|
647
|
+
};
|
|
648
|
+
}
|
|
649
|
+
function createDynamicNode(kind, fullPath, caseSensitive, prefix, suffix) {
|
|
650
|
+
return {
|
|
651
|
+
kind,
|
|
652
|
+
depth: 0,
|
|
653
|
+
pathless: null,
|
|
654
|
+
index: null,
|
|
655
|
+
static: null,
|
|
656
|
+
staticInsensitive: null,
|
|
657
|
+
dynamic: null,
|
|
658
|
+
optional: null,
|
|
659
|
+
wildcard: null,
|
|
660
|
+
route: null,
|
|
661
|
+
fullPath,
|
|
662
|
+
parent: null,
|
|
663
|
+
parse: null,
|
|
664
|
+
skipOnParamError: false,
|
|
665
|
+
parsingPriority: 0,
|
|
666
|
+
caseSensitive,
|
|
667
|
+
prefix,
|
|
668
|
+
suffix
|
|
669
|
+
};
|
|
670
|
+
}
|
|
671
|
+
function processRouteMasks(routeList, processedTree) {
|
|
672
|
+
const segmentTree = createStaticNode("/");
|
|
673
|
+
const data = new Uint16Array(6);
|
|
674
|
+
for (const route of routeList) {
|
|
675
|
+
parseSegments(false, data, route, 1, segmentTree, 0);
|
|
676
|
+
}
|
|
677
|
+
sortTreeNodes(segmentTree);
|
|
678
|
+
processedTree.masksTree = segmentTree;
|
|
679
|
+
processedTree.flatCache = createLRUCache(1e3);
|
|
680
|
+
}
|
|
681
|
+
function findFlatMatch(path, processedTree) {
|
|
682
|
+
path ||= "/";
|
|
683
|
+
const cached = processedTree.flatCache.get(path);
|
|
684
|
+
if (cached) return cached;
|
|
685
|
+
const result = findMatch(path, processedTree.masksTree);
|
|
686
|
+
processedTree.flatCache.set(path, result);
|
|
687
|
+
return result;
|
|
688
|
+
}
|
|
689
|
+
function findSingleMatch(from, caseSensitive, fuzzy, path, processedTree) {
|
|
690
|
+
from ||= "/";
|
|
691
|
+
path ||= "/";
|
|
692
|
+
const key = caseSensitive ? `case\0${from}` : from;
|
|
693
|
+
let tree = processedTree.singleCache.get(key);
|
|
694
|
+
if (!tree) {
|
|
695
|
+
tree = createStaticNode("/");
|
|
696
|
+
const data = new Uint16Array(6);
|
|
697
|
+
parseSegments(caseSensitive, data, { from }, 1, tree, 0);
|
|
698
|
+
processedTree.singleCache.set(key, tree);
|
|
699
|
+
}
|
|
700
|
+
return findMatch(path, tree, fuzzy);
|
|
701
|
+
}
|
|
702
|
+
function findRouteMatch(path, processedTree, fuzzy = false) {
|
|
703
|
+
const key = fuzzy ? path : `nofuzz\0${path}`;
|
|
704
|
+
const cached = processedTree.matchCache.get(key);
|
|
705
|
+
if (cached !== void 0) return cached;
|
|
706
|
+
path ||= "/";
|
|
707
|
+
let result;
|
|
708
|
+
try {
|
|
709
|
+
result = findMatch(
|
|
710
|
+
path,
|
|
711
|
+
processedTree.segmentTree,
|
|
712
|
+
fuzzy
|
|
713
|
+
);
|
|
714
|
+
} catch (err) {
|
|
715
|
+
if (err instanceof URIError) {
|
|
716
|
+
result = null;
|
|
717
|
+
} else {
|
|
718
|
+
throw err;
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
if (result) result.branch = buildRouteBranch(result.route);
|
|
722
|
+
processedTree.matchCache.set(key, result);
|
|
723
|
+
return result;
|
|
724
|
+
}
|
|
725
|
+
function trimPathRight$1(path) {
|
|
726
|
+
return path === "/" ? path : path.replace(/\/{1,}$/, "");
|
|
727
|
+
}
|
|
728
|
+
function processRouteTree(routeTree, caseSensitive = false, initRoute) {
|
|
729
|
+
const segmentTree = createStaticNode(routeTree.fullPath);
|
|
730
|
+
const data = new Uint16Array(6);
|
|
731
|
+
const routesById = {};
|
|
732
|
+
const routesByPath = {};
|
|
733
|
+
let index = 0;
|
|
734
|
+
parseSegments(caseSensitive, data, routeTree, 1, segmentTree, 0, (route) => {
|
|
735
|
+
initRoute?.(route, index);
|
|
736
|
+
invariant(
|
|
737
|
+
!(route.id in routesById),
|
|
738
|
+
`Duplicate routes found with id: ${String(route.id)}`
|
|
739
|
+
);
|
|
740
|
+
routesById[route.id] = route;
|
|
741
|
+
if (index !== 0 && route.path) {
|
|
742
|
+
const trimmedFullPath = trimPathRight$1(route.fullPath);
|
|
743
|
+
if (!routesByPath[trimmedFullPath] || route.fullPath.endsWith("/")) {
|
|
744
|
+
routesByPath[trimmedFullPath] = route;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
index++;
|
|
748
|
+
});
|
|
749
|
+
sortTreeNodes(segmentTree);
|
|
750
|
+
const processedTree = {
|
|
751
|
+
segmentTree,
|
|
752
|
+
singleCache: createLRUCache(1e3),
|
|
753
|
+
matchCache: createLRUCache(1e3),
|
|
754
|
+
flatCache: null,
|
|
755
|
+
masksTree: null
|
|
756
|
+
};
|
|
757
|
+
return {
|
|
758
|
+
processedTree,
|
|
759
|
+
routesById,
|
|
760
|
+
routesByPath
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
function findMatch(path, segmentTree, fuzzy = false) {
|
|
764
|
+
const parts = path.split("/");
|
|
765
|
+
const leaf = getNodeMatch(path, parts, segmentTree, fuzzy);
|
|
766
|
+
if (!leaf) return null;
|
|
767
|
+
const [rawParams] = extractParams(path, parts, leaf);
|
|
768
|
+
return {
|
|
769
|
+
route: leaf.node.route,
|
|
770
|
+
rawParams,
|
|
771
|
+
parsedParams: leaf.parsedParams
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
function extractParams(path, parts, leaf) {
|
|
775
|
+
const list = buildBranch(leaf.node);
|
|
776
|
+
let nodeParts = null;
|
|
777
|
+
const rawParams = {};
|
|
778
|
+
let partIndex = leaf.extract?.part ?? 0;
|
|
779
|
+
let nodeIndex = leaf.extract?.node ?? 0;
|
|
780
|
+
let pathIndex = leaf.extract?.path ?? 0;
|
|
781
|
+
let segmentCount = leaf.extract?.segment ?? 0;
|
|
782
|
+
for (; nodeIndex < list.length; partIndex++, nodeIndex++, pathIndex++, segmentCount++) {
|
|
783
|
+
const node = list[nodeIndex];
|
|
784
|
+
if (node.kind === SEGMENT_TYPE_INDEX) break;
|
|
785
|
+
if (node.kind === SEGMENT_TYPE_PATHLESS) {
|
|
786
|
+
segmentCount--;
|
|
787
|
+
partIndex--;
|
|
788
|
+
pathIndex--;
|
|
789
|
+
continue;
|
|
790
|
+
}
|
|
791
|
+
const part = parts[partIndex];
|
|
792
|
+
const currentPathIndex = pathIndex;
|
|
793
|
+
if (part) pathIndex += part.length;
|
|
794
|
+
if (node.kind === SEGMENT_TYPE_PARAM) {
|
|
795
|
+
nodeParts ??= leaf.node.fullPath.split("/");
|
|
796
|
+
const nodePart = nodeParts[segmentCount];
|
|
797
|
+
const preLength = node.prefix?.length ?? 0;
|
|
798
|
+
const isCurlyBraced = nodePart.charCodeAt(preLength) === 123;
|
|
799
|
+
if (isCurlyBraced) {
|
|
800
|
+
const sufLength = node.suffix?.length ?? 0;
|
|
801
|
+
const name = nodePart.substring(
|
|
802
|
+
preLength + 2,
|
|
803
|
+
nodePart.length - sufLength - 1
|
|
804
|
+
);
|
|
805
|
+
const value = part.substring(preLength, part.length - sufLength);
|
|
806
|
+
rawParams[name] = decodeURIComponent(value);
|
|
807
|
+
} else {
|
|
808
|
+
const name = nodePart.substring(1);
|
|
809
|
+
rawParams[name] = decodeURIComponent(part);
|
|
810
|
+
}
|
|
811
|
+
} else if (node.kind === SEGMENT_TYPE_OPTIONAL_PARAM) {
|
|
812
|
+
if (leaf.skipped & 1 << nodeIndex) {
|
|
813
|
+
partIndex--;
|
|
814
|
+
pathIndex = currentPathIndex - 1;
|
|
815
|
+
continue;
|
|
816
|
+
}
|
|
817
|
+
nodeParts ??= leaf.node.fullPath.split("/");
|
|
818
|
+
const nodePart = nodeParts[segmentCount];
|
|
819
|
+
const preLength = node.prefix?.length ?? 0;
|
|
820
|
+
const sufLength = node.suffix?.length ?? 0;
|
|
821
|
+
const name = nodePart.substring(
|
|
822
|
+
preLength + 3,
|
|
823
|
+
nodePart.length - sufLength - 1
|
|
824
|
+
);
|
|
825
|
+
const value = node.suffix || node.prefix ? part.substring(preLength, part.length - sufLength) : part;
|
|
826
|
+
if (value) rawParams[name] = decodeURIComponent(value);
|
|
827
|
+
} else if (node.kind === SEGMENT_TYPE_WILDCARD) {
|
|
828
|
+
const n = node;
|
|
829
|
+
const value = path.substring(
|
|
830
|
+
currentPathIndex + (n.prefix?.length ?? 0),
|
|
831
|
+
path.length - (n.suffix?.length ?? 0)
|
|
832
|
+
);
|
|
833
|
+
const splat = decodeURIComponent(value);
|
|
834
|
+
rawParams["*"] = splat;
|
|
835
|
+
rawParams._splat = splat;
|
|
836
|
+
break;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
if (leaf.rawParams) Object.assign(rawParams, leaf.rawParams);
|
|
840
|
+
return [
|
|
841
|
+
rawParams,
|
|
842
|
+
{
|
|
843
|
+
part: partIndex,
|
|
844
|
+
node: nodeIndex,
|
|
845
|
+
path: pathIndex,
|
|
846
|
+
segment: segmentCount
|
|
847
|
+
}
|
|
848
|
+
];
|
|
849
|
+
}
|
|
850
|
+
function buildRouteBranch(route) {
|
|
851
|
+
const list = [route];
|
|
852
|
+
while (route.parentRoute) {
|
|
853
|
+
route = route.parentRoute;
|
|
854
|
+
list.push(route);
|
|
855
|
+
}
|
|
856
|
+
list.reverse();
|
|
857
|
+
return list;
|
|
858
|
+
}
|
|
859
|
+
function buildBranch(node) {
|
|
860
|
+
const list = Array(node.depth + 1);
|
|
861
|
+
do {
|
|
862
|
+
list[node.depth] = node;
|
|
863
|
+
node = node.parent;
|
|
864
|
+
} while (node);
|
|
865
|
+
return list;
|
|
866
|
+
}
|
|
867
|
+
function getNodeMatch(path, parts, segmentTree, fuzzy) {
|
|
868
|
+
if (path === "/" && segmentTree.index)
|
|
869
|
+
return { node: segmentTree.index, skipped: 0 };
|
|
870
|
+
const trailingSlash = !last(parts);
|
|
871
|
+
const pathIsIndex = trailingSlash && path !== "/";
|
|
872
|
+
const partsLength = parts.length - (trailingSlash ? 1 : 0);
|
|
873
|
+
const stack = [
|
|
874
|
+
{
|
|
875
|
+
node: segmentTree,
|
|
876
|
+
index: 1,
|
|
877
|
+
skipped: 0,
|
|
878
|
+
depth: 1,
|
|
879
|
+
statics: 1,
|
|
880
|
+
dynamics: 0,
|
|
881
|
+
optionals: 0
|
|
882
|
+
}
|
|
883
|
+
];
|
|
884
|
+
let wildcardMatch = null;
|
|
885
|
+
let bestFuzzy = null;
|
|
886
|
+
let bestMatch = null;
|
|
887
|
+
while (stack.length) {
|
|
888
|
+
const frame = stack.pop();
|
|
889
|
+
const { node, index, skipped, depth, statics, dynamics, optionals } = frame;
|
|
890
|
+
let { extract, rawParams, parsedParams } = frame;
|
|
891
|
+
if (node.skipOnParamError) {
|
|
892
|
+
const result = validateMatchParams(path, parts, frame);
|
|
893
|
+
if (!result) continue;
|
|
894
|
+
rawParams = frame.rawParams;
|
|
895
|
+
extract = frame.extract;
|
|
896
|
+
parsedParams = frame.parsedParams;
|
|
897
|
+
}
|
|
898
|
+
if (fuzzy && node.route && node.kind !== SEGMENT_TYPE_INDEX && isFrameMoreSpecific(bestFuzzy, frame)) {
|
|
899
|
+
bestFuzzy = frame;
|
|
900
|
+
}
|
|
901
|
+
const isBeyondPath = index === partsLength;
|
|
902
|
+
if (isBeyondPath) {
|
|
903
|
+
if (node.route && !pathIsIndex && isFrameMoreSpecific(bestMatch, frame)) {
|
|
904
|
+
bestMatch = frame;
|
|
905
|
+
}
|
|
906
|
+
if (!node.optional && !node.wildcard && !node.index && !node.pathless)
|
|
907
|
+
continue;
|
|
908
|
+
}
|
|
909
|
+
const part = isBeyondPath ? void 0 : parts[index];
|
|
910
|
+
let lowerPart;
|
|
911
|
+
if (isBeyondPath && node.index) {
|
|
912
|
+
const indexFrame = {
|
|
913
|
+
node: node.index,
|
|
914
|
+
index,
|
|
915
|
+
skipped,
|
|
916
|
+
depth: depth + 1,
|
|
917
|
+
statics,
|
|
918
|
+
dynamics,
|
|
919
|
+
optionals,
|
|
920
|
+
extract,
|
|
921
|
+
rawParams,
|
|
922
|
+
parsedParams
|
|
923
|
+
};
|
|
924
|
+
let indexValid = true;
|
|
925
|
+
if (node.index.skipOnParamError) {
|
|
926
|
+
const result = validateMatchParams(path, parts, indexFrame);
|
|
927
|
+
if (!result) indexValid = false;
|
|
928
|
+
}
|
|
929
|
+
if (indexValid) {
|
|
930
|
+
if (statics === partsLength && !dynamics && !optionals && !skipped) {
|
|
931
|
+
return indexFrame;
|
|
932
|
+
}
|
|
933
|
+
if (isFrameMoreSpecific(bestMatch, indexFrame)) {
|
|
934
|
+
bestMatch = indexFrame;
|
|
935
|
+
}
|
|
936
|
+
}
|
|
937
|
+
}
|
|
938
|
+
if (node.wildcard && isFrameMoreSpecific(wildcardMatch, frame)) {
|
|
939
|
+
for (const segment of node.wildcard) {
|
|
940
|
+
const { prefix, suffix } = segment;
|
|
941
|
+
if (prefix) {
|
|
942
|
+
if (isBeyondPath) continue;
|
|
943
|
+
const casePart = segment.caseSensitive ? part : lowerPart ??= part.toLowerCase();
|
|
944
|
+
if (!casePart.startsWith(prefix)) continue;
|
|
945
|
+
}
|
|
946
|
+
if (suffix) {
|
|
947
|
+
if (isBeyondPath) continue;
|
|
948
|
+
const end = parts.slice(index).join("/").slice(-suffix.length);
|
|
949
|
+
const casePart = segment.caseSensitive ? end : end.toLowerCase();
|
|
950
|
+
if (casePart !== suffix) continue;
|
|
951
|
+
}
|
|
952
|
+
const frame2 = {
|
|
953
|
+
node: segment,
|
|
954
|
+
index: partsLength,
|
|
955
|
+
skipped,
|
|
956
|
+
depth,
|
|
957
|
+
statics,
|
|
958
|
+
dynamics,
|
|
959
|
+
optionals,
|
|
960
|
+
extract,
|
|
961
|
+
rawParams,
|
|
962
|
+
parsedParams
|
|
963
|
+
};
|
|
964
|
+
if (segment.skipOnParamError) {
|
|
965
|
+
const result = validateMatchParams(path, parts, frame2);
|
|
966
|
+
if (!result) continue;
|
|
967
|
+
}
|
|
968
|
+
wildcardMatch = frame2;
|
|
969
|
+
break;
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
if (node.optional) {
|
|
973
|
+
const nextSkipped = skipped | 1 << depth;
|
|
974
|
+
const nextDepth = depth + 1;
|
|
975
|
+
for (let i = node.optional.length - 1; i >= 0; i--) {
|
|
976
|
+
const segment = node.optional[i];
|
|
977
|
+
stack.push({
|
|
978
|
+
node: segment,
|
|
979
|
+
index,
|
|
980
|
+
skipped: nextSkipped,
|
|
981
|
+
depth: nextDepth,
|
|
982
|
+
statics,
|
|
983
|
+
dynamics,
|
|
984
|
+
optionals,
|
|
985
|
+
extract,
|
|
986
|
+
rawParams,
|
|
987
|
+
parsedParams
|
|
988
|
+
});
|
|
989
|
+
}
|
|
990
|
+
if (!isBeyondPath) {
|
|
991
|
+
for (let i = node.optional.length - 1; i >= 0; i--) {
|
|
992
|
+
const segment = node.optional[i];
|
|
993
|
+
const { prefix, suffix } = segment;
|
|
994
|
+
if (prefix || suffix) {
|
|
995
|
+
const casePart = segment.caseSensitive ? part : lowerPart ??= part.toLowerCase();
|
|
996
|
+
if (prefix && !casePart.startsWith(prefix)) continue;
|
|
997
|
+
if (suffix && !casePart.endsWith(suffix)) continue;
|
|
998
|
+
}
|
|
999
|
+
stack.push({
|
|
1000
|
+
node: segment,
|
|
1001
|
+
index: index + 1,
|
|
1002
|
+
skipped,
|
|
1003
|
+
depth: nextDepth,
|
|
1004
|
+
statics,
|
|
1005
|
+
dynamics,
|
|
1006
|
+
optionals: optionals + 1,
|
|
1007
|
+
extract,
|
|
1008
|
+
rawParams,
|
|
1009
|
+
parsedParams
|
|
1010
|
+
});
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
if (!isBeyondPath && node.dynamic && part) {
|
|
1015
|
+
for (let i = node.dynamic.length - 1; i >= 0; i--) {
|
|
1016
|
+
const segment = node.dynamic[i];
|
|
1017
|
+
const { prefix, suffix } = segment;
|
|
1018
|
+
if (prefix || suffix) {
|
|
1019
|
+
const casePart = segment.caseSensitive ? part : lowerPart ??= part.toLowerCase();
|
|
1020
|
+
if (prefix && !casePart.startsWith(prefix)) continue;
|
|
1021
|
+
if (suffix && !casePart.endsWith(suffix)) continue;
|
|
1022
|
+
}
|
|
1023
|
+
stack.push({
|
|
1024
|
+
node: segment,
|
|
1025
|
+
index: index + 1,
|
|
1026
|
+
skipped,
|
|
1027
|
+
depth: depth + 1,
|
|
1028
|
+
statics,
|
|
1029
|
+
dynamics: dynamics + 1,
|
|
1030
|
+
optionals,
|
|
1031
|
+
extract,
|
|
1032
|
+
rawParams,
|
|
1033
|
+
parsedParams
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
if (!isBeyondPath && node.staticInsensitive) {
|
|
1038
|
+
const match = node.staticInsensitive.get(
|
|
1039
|
+
lowerPart ??= part.toLowerCase()
|
|
1040
|
+
);
|
|
1041
|
+
if (match) {
|
|
1042
|
+
stack.push({
|
|
1043
|
+
node: match,
|
|
1044
|
+
index: index + 1,
|
|
1045
|
+
skipped,
|
|
1046
|
+
depth: depth + 1,
|
|
1047
|
+
statics: statics + 1,
|
|
1048
|
+
dynamics,
|
|
1049
|
+
optionals,
|
|
1050
|
+
extract,
|
|
1051
|
+
rawParams,
|
|
1052
|
+
parsedParams
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
if (!isBeyondPath && node.static) {
|
|
1057
|
+
const match = node.static.get(part);
|
|
1058
|
+
if (match) {
|
|
1059
|
+
stack.push({
|
|
1060
|
+
node: match,
|
|
1061
|
+
index: index + 1,
|
|
1062
|
+
skipped,
|
|
1063
|
+
depth: depth + 1,
|
|
1064
|
+
statics: statics + 1,
|
|
1065
|
+
dynamics,
|
|
1066
|
+
optionals,
|
|
1067
|
+
extract,
|
|
1068
|
+
rawParams,
|
|
1069
|
+
parsedParams
|
|
1070
|
+
});
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
if (node.pathless) {
|
|
1074
|
+
const nextDepth = depth + 1;
|
|
1075
|
+
for (let i = node.pathless.length - 1; i >= 0; i--) {
|
|
1076
|
+
const segment = node.pathless[i];
|
|
1077
|
+
stack.push({
|
|
1078
|
+
node: segment,
|
|
1079
|
+
index,
|
|
1080
|
+
skipped,
|
|
1081
|
+
depth: nextDepth,
|
|
1082
|
+
statics,
|
|
1083
|
+
dynamics,
|
|
1084
|
+
optionals,
|
|
1085
|
+
extract,
|
|
1086
|
+
rawParams,
|
|
1087
|
+
parsedParams
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
if (bestMatch && wildcardMatch) {
|
|
1093
|
+
return isFrameMoreSpecific(wildcardMatch, bestMatch) ? bestMatch : wildcardMatch;
|
|
1094
|
+
}
|
|
1095
|
+
if (bestMatch) return bestMatch;
|
|
1096
|
+
if (wildcardMatch) return wildcardMatch;
|
|
1097
|
+
if (fuzzy && bestFuzzy) {
|
|
1098
|
+
let sliceIndex = bestFuzzy.index;
|
|
1099
|
+
for (let i = 0; i < bestFuzzy.index; i++) {
|
|
1100
|
+
sliceIndex += parts[i].length;
|
|
1101
|
+
}
|
|
1102
|
+
const splat = sliceIndex === path.length ? "/" : path.slice(sliceIndex);
|
|
1103
|
+
bestFuzzy.rawParams ??= {};
|
|
1104
|
+
bestFuzzy.rawParams["**"] = decodeURIComponent(splat);
|
|
1105
|
+
return bestFuzzy;
|
|
1106
|
+
}
|
|
1107
|
+
return null;
|
|
1108
|
+
}
|
|
1109
|
+
function validateMatchParams(path, parts, frame) {
|
|
1110
|
+
try {
|
|
1111
|
+
const [rawParams, state] = extractParams(path, parts, frame);
|
|
1112
|
+
frame.rawParams = rawParams;
|
|
1113
|
+
frame.extract = state;
|
|
1114
|
+
const parsed = frame.node.parse(rawParams);
|
|
1115
|
+
frame.parsedParams = Object.assign({}, frame.parsedParams, parsed);
|
|
1116
|
+
return true;
|
|
1117
|
+
} catch {
|
|
1118
|
+
return null;
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
function isFrameMoreSpecific(prev, next) {
|
|
1122
|
+
if (!prev) return true;
|
|
1123
|
+
return next.statics > prev.statics || next.statics === prev.statics && (next.dynamics > prev.dynamics || next.dynamics === prev.dynamics && (next.optionals > prev.optionals || next.optionals === prev.optionals && ((next.node.kind === SEGMENT_TYPE_INDEX) > (prev.node.kind === SEGMENT_TYPE_INDEX) || next.node.kind === SEGMENT_TYPE_INDEX === (prev.node.kind === SEGMENT_TYPE_INDEX) && next.depth > prev.depth)));
|
|
1124
|
+
}
|
|
1125
|
+
function joinPaths(paths) {
|
|
1126
|
+
return cleanPath(
|
|
1127
|
+
paths.filter((val) => {
|
|
1128
|
+
return val !== void 0;
|
|
1129
|
+
}).join("/")
|
|
1130
|
+
);
|
|
1131
|
+
}
|
|
1132
|
+
function cleanPath(path) {
|
|
1133
|
+
return path.replace(/\/{2,}/g, "/");
|
|
1134
|
+
}
|
|
1135
|
+
function trimPathLeft(path) {
|
|
1136
|
+
return path === "/" ? path : path.replace(/^\/{1,}/, "");
|
|
1137
|
+
}
|
|
1138
|
+
function trimPathRight(path) {
|
|
1139
|
+
const len = path.length;
|
|
1140
|
+
return len > 1 && path[len - 1] === "/" ? path.replace(/\/{1,}$/, "") : path;
|
|
1141
|
+
}
|
|
1142
|
+
function trimPath(path) {
|
|
1143
|
+
return trimPathRight(trimPathLeft(path));
|
|
1144
|
+
}
|
|
1145
|
+
function removeTrailingSlash(value, basepath) {
|
|
1146
|
+
if (value?.endsWith("/") && value !== "/" && value !== `${basepath}/`) {
|
|
1147
|
+
return value.slice(0, -1);
|
|
1148
|
+
}
|
|
1149
|
+
return value;
|
|
1150
|
+
}
|
|
1151
|
+
function exactPathTest(pathName1, pathName2, basepath) {
|
|
1152
|
+
return removeTrailingSlash(pathName1, basepath) === removeTrailingSlash(pathName2, basepath);
|
|
1153
|
+
}
|
|
1154
|
+
function resolvePath({
|
|
1155
|
+
base,
|
|
1156
|
+
to,
|
|
1157
|
+
trailingSlash = "never",
|
|
1158
|
+
cache
|
|
1159
|
+
}) {
|
|
1160
|
+
const isAbsolute = to.startsWith("/");
|
|
1161
|
+
const isBase = !isAbsolute && to === ".";
|
|
1162
|
+
let key;
|
|
1163
|
+
if (cache) {
|
|
1164
|
+
key = isAbsolute ? to : isBase ? base : base + "\0" + to;
|
|
1165
|
+
const cached = cache.get(key);
|
|
1166
|
+
if (cached) return cached;
|
|
1167
|
+
}
|
|
1168
|
+
let baseSegments;
|
|
1169
|
+
if (isBase) {
|
|
1170
|
+
baseSegments = base.split("/");
|
|
1171
|
+
} else if (isAbsolute) {
|
|
1172
|
+
baseSegments = to.split("/");
|
|
1173
|
+
} else {
|
|
1174
|
+
baseSegments = base.split("/");
|
|
1175
|
+
while (baseSegments.length > 1 && last(baseSegments) === "") {
|
|
1176
|
+
baseSegments.pop();
|
|
1177
|
+
}
|
|
1178
|
+
const toSegments = to.split("/");
|
|
1179
|
+
for (let index = 0, length = toSegments.length; index < length; index++) {
|
|
1180
|
+
const value = toSegments[index];
|
|
1181
|
+
if (value === "") {
|
|
1182
|
+
if (!index) {
|
|
1183
|
+
baseSegments = [value];
|
|
1184
|
+
} else if (index === length - 1) {
|
|
1185
|
+
baseSegments.push(value);
|
|
1186
|
+
} else ;
|
|
1187
|
+
} else if (value === "..") {
|
|
1188
|
+
baseSegments.pop();
|
|
1189
|
+
} else if (value === ".") ;
|
|
1190
|
+
else {
|
|
1191
|
+
baseSegments.push(value);
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
if (baseSegments.length > 1) {
|
|
1196
|
+
if (last(baseSegments) === "") {
|
|
1197
|
+
if (trailingSlash === "never") {
|
|
1198
|
+
baseSegments.pop();
|
|
1199
|
+
}
|
|
1200
|
+
} else if (trailingSlash === "always") {
|
|
1201
|
+
baseSegments.push("");
|
|
1202
|
+
}
|
|
1203
|
+
}
|
|
1204
|
+
let segment;
|
|
1205
|
+
let joined = "";
|
|
1206
|
+
for (let i = 0; i < baseSegments.length; i++) {
|
|
1207
|
+
if (i > 0) joined += "/";
|
|
1208
|
+
const part = baseSegments[i];
|
|
1209
|
+
if (!part) continue;
|
|
1210
|
+
segment = parseSegment(part, 0, segment);
|
|
1211
|
+
const kind = segment[0];
|
|
1212
|
+
if (kind === SEGMENT_TYPE_PATHNAME) {
|
|
1213
|
+
joined += part;
|
|
1214
|
+
continue;
|
|
1215
|
+
}
|
|
1216
|
+
const end = segment[5];
|
|
1217
|
+
const prefix = part.substring(0, segment[1]);
|
|
1218
|
+
const suffix = part.substring(segment[4], end);
|
|
1219
|
+
const value = part.substring(segment[2], segment[3]);
|
|
1220
|
+
if (kind === SEGMENT_TYPE_PARAM) {
|
|
1221
|
+
joined += prefix || suffix ? `${prefix}{$${value}}${suffix}` : `$${value}`;
|
|
1222
|
+
} else if (kind === SEGMENT_TYPE_WILDCARD) {
|
|
1223
|
+
joined += prefix || suffix ? `${prefix}{$}${suffix}` : "$";
|
|
1224
|
+
} else {
|
|
1225
|
+
joined += `${prefix}{-$${value}}${suffix}`;
|
|
1226
|
+
}
|
|
1227
|
+
}
|
|
1228
|
+
joined = cleanPath(joined);
|
|
1229
|
+
const result = joined || "/";
|
|
1230
|
+
if (key && cache) cache.set(key, result);
|
|
1231
|
+
return result;
|
|
1232
|
+
}
|
|
1233
|
+
function encodeParam(key, params, decodeCharMap) {
|
|
1234
|
+
const value = params[key];
|
|
1235
|
+
if (typeof value !== "string") return value;
|
|
1236
|
+
if (key === "_splat") {
|
|
1237
|
+
return encodeURI(value);
|
|
1238
|
+
} else {
|
|
1239
|
+
return encodePathParam(value, decodeCharMap);
|
|
1240
|
+
}
|
|
1241
|
+
}
|
|
1242
|
+
function interpolatePath({
|
|
1243
|
+
path,
|
|
1244
|
+
params,
|
|
1245
|
+
decodeCharMap
|
|
1246
|
+
}) {
|
|
1247
|
+
let isMissingParams = false;
|
|
1248
|
+
const usedParams = {};
|
|
1249
|
+
if (!path || path === "/")
|
|
1250
|
+
return { interpolatedPath: "/", usedParams, isMissingParams };
|
|
1251
|
+
if (!path.includes("$"))
|
|
1252
|
+
return { interpolatedPath: path, usedParams, isMissingParams };
|
|
1253
|
+
const length = path.length;
|
|
1254
|
+
let cursor = 0;
|
|
1255
|
+
let segment;
|
|
1256
|
+
let joined = "";
|
|
1257
|
+
while (cursor < length) {
|
|
1258
|
+
const start = cursor;
|
|
1259
|
+
segment = parseSegment(path, start, segment);
|
|
1260
|
+
const end = segment[5];
|
|
1261
|
+
cursor = end + 1;
|
|
1262
|
+
if (start === end) continue;
|
|
1263
|
+
const kind = segment[0];
|
|
1264
|
+
if (kind === SEGMENT_TYPE_PATHNAME) {
|
|
1265
|
+
joined += "/" + path.substring(start, end);
|
|
1266
|
+
continue;
|
|
1267
|
+
}
|
|
1268
|
+
if (kind === SEGMENT_TYPE_WILDCARD) {
|
|
1269
|
+
const splat = params._splat;
|
|
1270
|
+
usedParams._splat = splat;
|
|
1271
|
+
usedParams["*"] = splat;
|
|
1272
|
+
const prefix = path.substring(start, segment[1]);
|
|
1273
|
+
const suffix = path.substring(segment[4], end);
|
|
1274
|
+
if (!splat) {
|
|
1275
|
+
isMissingParams = true;
|
|
1276
|
+
if (prefix || suffix) {
|
|
1277
|
+
joined += "/" + prefix + suffix;
|
|
1278
|
+
}
|
|
1279
|
+
continue;
|
|
1280
|
+
}
|
|
1281
|
+
const value = encodeParam("_splat", params, decodeCharMap);
|
|
1282
|
+
joined += "/" + prefix + value + suffix;
|
|
1283
|
+
continue;
|
|
1284
|
+
}
|
|
1285
|
+
if (kind === SEGMENT_TYPE_PARAM) {
|
|
1286
|
+
const key = path.substring(segment[2], segment[3]);
|
|
1287
|
+
if (!isMissingParams && !(key in params)) {
|
|
1288
|
+
isMissingParams = true;
|
|
1289
|
+
}
|
|
1290
|
+
usedParams[key] = params[key];
|
|
1291
|
+
const prefix = path.substring(start, segment[1]);
|
|
1292
|
+
const suffix = path.substring(segment[4], end);
|
|
1293
|
+
const value = encodeParam(key, params, decodeCharMap) ?? "undefined";
|
|
1294
|
+
joined += "/" + prefix + value + suffix;
|
|
1295
|
+
continue;
|
|
1296
|
+
}
|
|
1297
|
+
if (kind === SEGMENT_TYPE_OPTIONAL_PARAM) {
|
|
1298
|
+
const key = path.substring(segment[2], segment[3]);
|
|
1299
|
+
const valueRaw = params[key];
|
|
1300
|
+
if (valueRaw == null) continue;
|
|
1301
|
+
usedParams[key] = valueRaw;
|
|
1302
|
+
const prefix = path.substring(start, segment[1]);
|
|
1303
|
+
const suffix = path.substring(segment[4], end);
|
|
1304
|
+
const value = encodeParam(key, params, decodeCharMap) ?? "";
|
|
1305
|
+
joined += "/" + prefix + value + suffix;
|
|
1306
|
+
continue;
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
if (path.endsWith("/")) joined += "/";
|
|
1310
|
+
const interpolatedPath = joined || "/";
|
|
1311
|
+
return { usedParams, interpolatedPath, isMissingParams };
|
|
1312
|
+
}
|
|
1313
|
+
function encodePathParam(value, decodeCharMap) {
|
|
1314
|
+
let encoded = encodeURIComponent(value);
|
|
1315
|
+
if (decodeCharMap) {
|
|
1316
|
+
for (const [encodedChar, char] of decodeCharMap) {
|
|
1317
|
+
encoded = encoded.replaceAll(encodedChar, char);
|
|
1318
|
+
}
|
|
1319
|
+
}
|
|
1320
|
+
return encoded;
|
|
1321
|
+
}
|
|
1322
|
+
function getSafeSessionStorage() {
|
|
1323
|
+
try {
|
|
1324
|
+
if (typeof window !== "undefined" && typeof window.sessionStorage === "object") {
|
|
1325
|
+
return window.sessionStorage;
|
|
1326
|
+
}
|
|
1327
|
+
} catch {
|
|
1328
|
+
}
|
|
1329
|
+
return void 0;
|
|
1330
|
+
}
|
|
1331
|
+
const storageKey = "tsr-scroll-restoration-v1_3";
|
|
1332
|
+
const throttle = (fn, wait) => {
|
|
1333
|
+
let timeout;
|
|
1334
|
+
return (...args) => {
|
|
1335
|
+
if (!timeout) {
|
|
1336
|
+
timeout = setTimeout(() => {
|
|
1337
|
+
fn(...args);
|
|
1338
|
+
timeout = null;
|
|
1339
|
+
}, wait);
|
|
1340
|
+
}
|
|
1341
|
+
};
|
|
1342
|
+
};
|
|
1343
|
+
function createScrollRestorationCache() {
|
|
1344
|
+
const safeSessionStorage = getSafeSessionStorage();
|
|
1345
|
+
if (!safeSessionStorage) {
|
|
1346
|
+
return null;
|
|
1347
|
+
}
|
|
1348
|
+
const persistedState = safeSessionStorage.getItem(storageKey);
|
|
1349
|
+
let state = persistedState ? JSON.parse(persistedState) : {};
|
|
1350
|
+
return {
|
|
1351
|
+
state,
|
|
1352
|
+
// This setter is simply to make sure that we set the sessionStorage right
|
|
1353
|
+
// after the state is updated. It doesn't necessarily need to be a functional
|
|
1354
|
+
// update.
|
|
1355
|
+
set: (updater) => {
|
|
1356
|
+
state = functionalUpdate(updater, state) || state;
|
|
1357
|
+
try {
|
|
1358
|
+
safeSessionStorage.setItem(storageKey, JSON.stringify(state));
|
|
1359
|
+
} catch {
|
|
1360
|
+
console.warn(
|
|
1361
|
+
"[ts-router] Could not persist scroll restoration state to sessionStorage."
|
|
1362
|
+
);
|
|
1363
|
+
}
|
|
1364
|
+
}
|
|
1365
|
+
};
|
|
1366
|
+
}
|
|
1367
|
+
const scrollRestorationCache = createScrollRestorationCache();
|
|
1368
|
+
const defaultGetScrollRestorationKey = (location) => {
|
|
1369
|
+
return location.state.__TSR_key || location.href;
|
|
1370
|
+
};
|
|
1371
|
+
function getCssSelector(el) {
|
|
1372
|
+
const path = [];
|
|
1373
|
+
let parent;
|
|
1374
|
+
while (parent = el.parentNode) {
|
|
1375
|
+
path.push(
|
|
1376
|
+
`${el.tagName}:nth-child(${Array.prototype.indexOf.call(parent.children, el) + 1})`
|
|
1377
|
+
);
|
|
1378
|
+
el = parent;
|
|
1379
|
+
}
|
|
1380
|
+
return `${path.reverse().join(" > ")}`.toLowerCase();
|
|
1381
|
+
}
|
|
1382
|
+
let ignoreScroll = false;
|
|
1383
|
+
function restoreScroll({
|
|
1384
|
+
storageKey: storageKey2,
|
|
1385
|
+
key,
|
|
1386
|
+
behavior,
|
|
1387
|
+
shouldScrollRestoration,
|
|
1388
|
+
scrollToTopSelectors,
|
|
1389
|
+
location
|
|
1390
|
+
}) {
|
|
1391
|
+
let byKey;
|
|
1392
|
+
try {
|
|
1393
|
+
byKey = JSON.parse(sessionStorage.getItem(storageKey2) || "{}");
|
|
1394
|
+
} catch (error) {
|
|
1395
|
+
console.error(error);
|
|
1396
|
+
return;
|
|
1397
|
+
}
|
|
1398
|
+
const resolvedKey = key || window.history.state?.__TSR_key;
|
|
1399
|
+
const elementEntries = byKey[resolvedKey];
|
|
1400
|
+
ignoreScroll = true;
|
|
1401
|
+
scroll: {
|
|
1402
|
+
if (shouldScrollRestoration && elementEntries && Object.keys(elementEntries).length > 0) {
|
|
1403
|
+
for (const elementSelector in elementEntries) {
|
|
1404
|
+
const entry = elementEntries[elementSelector];
|
|
1405
|
+
if (elementSelector === "window") {
|
|
1406
|
+
window.scrollTo({
|
|
1407
|
+
top: entry.scrollY,
|
|
1408
|
+
left: entry.scrollX,
|
|
1409
|
+
behavior
|
|
1410
|
+
});
|
|
1411
|
+
} else if (elementSelector) {
|
|
1412
|
+
const element = document.querySelector(elementSelector);
|
|
1413
|
+
if (element) {
|
|
1414
|
+
element.scrollLeft = entry.scrollX;
|
|
1415
|
+
element.scrollTop = entry.scrollY;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
break scroll;
|
|
1420
|
+
}
|
|
1421
|
+
const hash = (location ?? window.location).hash.split("#", 2)[1];
|
|
1422
|
+
if (hash) {
|
|
1423
|
+
const hashScrollIntoViewOptions = window.history.state?.__hashScrollIntoViewOptions ?? true;
|
|
1424
|
+
if (hashScrollIntoViewOptions) {
|
|
1425
|
+
const el = document.getElementById(hash);
|
|
1426
|
+
if (el) {
|
|
1427
|
+
el.scrollIntoView(hashScrollIntoViewOptions);
|
|
1428
|
+
}
|
|
1429
|
+
}
|
|
1430
|
+
break scroll;
|
|
1431
|
+
}
|
|
1432
|
+
const scrollOptions = { top: 0, left: 0, behavior };
|
|
1433
|
+
window.scrollTo(scrollOptions);
|
|
1434
|
+
if (scrollToTopSelectors) {
|
|
1435
|
+
for (const selector of scrollToTopSelectors) {
|
|
1436
|
+
if (selector === "window") continue;
|
|
1437
|
+
const element = typeof selector === "function" ? selector() : document.querySelector(selector);
|
|
1438
|
+
if (element) element.scrollTo(scrollOptions);
|
|
1439
|
+
}
|
|
1440
|
+
}
|
|
1441
|
+
}
|
|
1442
|
+
ignoreScroll = false;
|
|
1443
|
+
}
|
|
1444
|
+
function setupScrollRestoration(router, force) {
|
|
1445
|
+
if (!scrollRestorationCache && !router.isServer) {
|
|
1446
|
+
return;
|
|
1447
|
+
}
|
|
1448
|
+
const shouldScrollRestoration = router.options.scrollRestoration ?? false;
|
|
1449
|
+
if (shouldScrollRestoration) {
|
|
1450
|
+
router.isScrollRestoring = true;
|
|
1451
|
+
}
|
|
1452
|
+
if (router.isServer || router.isScrollRestorationSetup || !scrollRestorationCache) {
|
|
1453
|
+
return;
|
|
1454
|
+
}
|
|
1455
|
+
router.isScrollRestorationSetup = true;
|
|
1456
|
+
ignoreScroll = false;
|
|
1457
|
+
const getKey = router.options.getScrollRestorationKey || defaultGetScrollRestorationKey;
|
|
1458
|
+
window.history.scrollRestoration = "manual";
|
|
1459
|
+
const onScroll = (event) => {
|
|
1460
|
+
if (ignoreScroll || !router.isScrollRestoring) {
|
|
1461
|
+
return;
|
|
1462
|
+
}
|
|
1463
|
+
let elementSelector = "";
|
|
1464
|
+
if (event.target === document || event.target === window) {
|
|
1465
|
+
elementSelector = "window";
|
|
1466
|
+
} else {
|
|
1467
|
+
const attrId = event.target.getAttribute(
|
|
1468
|
+
"data-scroll-restoration-id"
|
|
1469
|
+
);
|
|
1470
|
+
if (attrId) {
|
|
1471
|
+
elementSelector = `[data-scroll-restoration-id="${attrId}"]`;
|
|
1472
|
+
} else {
|
|
1473
|
+
elementSelector = getCssSelector(event.target);
|
|
1474
|
+
}
|
|
1475
|
+
}
|
|
1476
|
+
const restoreKey = getKey(router.state.location);
|
|
1477
|
+
scrollRestorationCache.set((state) => {
|
|
1478
|
+
const keyEntry = state[restoreKey] ||= {};
|
|
1479
|
+
const elementEntry = keyEntry[elementSelector] ||= {};
|
|
1480
|
+
if (elementSelector === "window") {
|
|
1481
|
+
elementEntry.scrollX = window.scrollX || 0;
|
|
1482
|
+
elementEntry.scrollY = window.scrollY || 0;
|
|
1483
|
+
} else if (elementSelector) {
|
|
1484
|
+
const element = document.querySelector(elementSelector);
|
|
1485
|
+
if (element) {
|
|
1486
|
+
elementEntry.scrollX = element.scrollLeft || 0;
|
|
1487
|
+
elementEntry.scrollY = element.scrollTop || 0;
|
|
1488
|
+
}
|
|
1489
|
+
}
|
|
1490
|
+
return state;
|
|
1491
|
+
});
|
|
1492
|
+
};
|
|
1493
|
+
if (typeof document !== "undefined") {
|
|
1494
|
+
document.addEventListener("scroll", throttle(onScroll, 100), true);
|
|
1495
|
+
}
|
|
1496
|
+
router.subscribe("onRendered", (event) => {
|
|
1497
|
+
const cacheKey = getKey(event.toLocation);
|
|
1498
|
+
const resetScroll = event.toLocation.state.__TSR_resetScroll ?? true;
|
|
1499
|
+
if (!resetScroll) {
|
|
1500
|
+
return;
|
|
1501
|
+
}
|
|
1502
|
+
if (typeof router.options.scrollRestoration === "function") {
|
|
1503
|
+
const shouldRestore = router.options.scrollRestoration({
|
|
1504
|
+
location: router.latestLocation
|
|
1505
|
+
});
|
|
1506
|
+
if (!shouldRestore) {
|
|
1507
|
+
return;
|
|
1508
|
+
}
|
|
1509
|
+
}
|
|
1510
|
+
restoreScroll({
|
|
1511
|
+
storageKey,
|
|
1512
|
+
key: cacheKey,
|
|
1513
|
+
behavior: router.options.scrollRestorationBehavior,
|
|
1514
|
+
shouldScrollRestoration: router.isScrollRestoring,
|
|
1515
|
+
scrollToTopSelectors: router.options.scrollToTopSelectors,
|
|
1516
|
+
location: router.history.location
|
|
1517
|
+
});
|
|
1518
|
+
if (router.isScrollRestoring) {
|
|
1519
|
+
scrollRestorationCache.set((state) => {
|
|
1520
|
+
state[cacheKey] ||= {};
|
|
1521
|
+
return state;
|
|
1522
|
+
});
|
|
1523
|
+
}
|
|
1524
|
+
});
|
|
1525
|
+
}
|
|
1526
|
+
function handleHashScroll(router) {
|
|
1527
|
+
if (typeof document !== "undefined" && document.querySelector) {
|
|
1528
|
+
const hashScrollIntoViewOptions = router.state.location.state.__hashScrollIntoViewOptions ?? true;
|
|
1529
|
+
if (hashScrollIntoViewOptions && router.state.location.hash !== "") {
|
|
1530
|
+
const el = document.getElementById(router.state.location.hash);
|
|
1531
|
+
if (el) {
|
|
1532
|
+
el.scrollIntoView(hashScrollIntoViewOptions);
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
function encode(obj, stringify = String) {
|
|
1538
|
+
const result = new URLSearchParams();
|
|
1539
|
+
for (const key in obj) {
|
|
1540
|
+
const val = obj[key];
|
|
1541
|
+
if (val !== void 0) {
|
|
1542
|
+
result.set(key, stringify(val));
|
|
1543
|
+
}
|
|
1544
|
+
}
|
|
1545
|
+
return result.toString();
|
|
1546
|
+
}
|
|
1547
|
+
function toValue(str) {
|
|
1548
|
+
if (!str) return "";
|
|
1549
|
+
if (str === "false") return false;
|
|
1550
|
+
if (str === "true") return true;
|
|
1551
|
+
return +str * 0 === 0 && +str + "" === str ? +str : str;
|
|
1552
|
+
}
|
|
1553
|
+
function decode(str) {
|
|
1554
|
+
const searchParams = new URLSearchParams(str);
|
|
1555
|
+
const result = {};
|
|
1556
|
+
for (const [key, value] of searchParams.entries()) {
|
|
1557
|
+
const previousValue = result[key];
|
|
1558
|
+
if (previousValue == null) {
|
|
1559
|
+
result[key] = toValue(value);
|
|
1560
|
+
} else if (Array.isArray(previousValue)) {
|
|
1561
|
+
previousValue.push(toValue(value));
|
|
1562
|
+
} else {
|
|
1563
|
+
result[key] = [previousValue, toValue(value)];
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
return result;
|
|
1567
|
+
}
|
|
1568
|
+
const defaultParseSearch = parseSearchWith(JSON.parse);
|
|
1569
|
+
const defaultStringifySearch = stringifySearchWith(
|
|
1570
|
+
JSON.stringify,
|
|
1571
|
+
JSON.parse
|
|
1572
|
+
);
|
|
1573
|
+
function parseSearchWith(parser) {
|
|
1574
|
+
return (searchStr) => {
|
|
1575
|
+
if (searchStr[0] === "?") {
|
|
1576
|
+
searchStr = searchStr.substring(1);
|
|
1577
|
+
}
|
|
1578
|
+
const query = decode(searchStr);
|
|
1579
|
+
for (const key in query) {
|
|
1580
|
+
const value = query[key];
|
|
1581
|
+
if (typeof value === "string") {
|
|
1582
|
+
try {
|
|
1583
|
+
query[key] = parser(value);
|
|
1584
|
+
} catch (_err) {
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
}
|
|
1588
|
+
return query;
|
|
1589
|
+
};
|
|
1590
|
+
}
|
|
1591
|
+
function stringifySearchWith(stringify, parser) {
|
|
1592
|
+
const hasParser = typeof parser === "function";
|
|
1593
|
+
function stringifyValue(val) {
|
|
1594
|
+
if (typeof val === "object" && val !== null) {
|
|
1595
|
+
try {
|
|
1596
|
+
return stringify(val);
|
|
1597
|
+
} catch (_err) {
|
|
1598
|
+
}
|
|
1599
|
+
} else if (hasParser && typeof val === "string") {
|
|
1600
|
+
try {
|
|
1601
|
+
parser(val);
|
|
1602
|
+
return stringify(val);
|
|
1603
|
+
} catch (_err) {
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
return val;
|
|
1607
|
+
}
|
|
1608
|
+
return (search) => {
|
|
1609
|
+
const searchStr = encode(search, stringifyValue);
|
|
1610
|
+
return searchStr ? `?${searchStr}` : "";
|
|
1611
|
+
};
|
|
1612
|
+
}
|
|
1613
|
+
const rootRouteId = "__root__";
|
|
1614
|
+
function redirect(opts) {
|
|
1615
|
+
opts.statusCode = opts.statusCode || opts.code || 307;
|
|
1616
|
+
if (typeof opts.href === "string" && isDangerousProtocol(opts.href)) {
|
|
1617
|
+
throw new Error(
|
|
1618
|
+
`Redirect blocked: unsafe protocol in href "${opts.href}". Only ${SAFE_URL_PROTOCOLS.join(", ")} protocols are allowed.`
|
|
1619
|
+
);
|
|
1620
|
+
}
|
|
1621
|
+
if (!opts.reloadDocument && typeof opts.href === "string") {
|
|
1622
|
+
try {
|
|
1623
|
+
new URL(opts.href);
|
|
1624
|
+
opts.reloadDocument = true;
|
|
1625
|
+
} catch {
|
|
1626
|
+
}
|
|
1627
|
+
}
|
|
1628
|
+
const headers = new Headers(opts.headers);
|
|
1629
|
+
if (opts.href && headers.get("Location") === null) {
|
|
1630
|
+
headers.set("Location", opts.href);
|
|
1631
|
+
}
|
|
1632
|
+
const response = new Response(null, {
|
|
1633
|
+
status: opts.statusCode,
|
|
1634
|
+
headers
|
|
1635
|
+
});
|
|
1636
|
+
response.options = opts;
|
|
1637
|
+
if (opts.throw) {
|
|
1638
|
+
throw response;
|
|
1639
|
+
}
|
|
1640
|
+
return response;
|
|
1641
|
+
}
|
|
1642
|
+
function isRedirect(obj) {
|
|
1643
|
+
return obj instanceof Response && !!obj.options;
|
|
1644
|
+
}
|
|
1645
|
+
function isResolvedRedirect(obj) {
|
|
1646
|
+
return isRedirect(obj) && !!obj.options.href;
|
|
1647
|
+
}
|
|
1648
|
+
function parseRedirect(obj) {
|
|
1649
|
+
if (obj !== null && typeof obj === "object" && obj.isSerializedRedirect) {
|
|
1650
|
+
return redirect(obj);
|
|
1651
|
+
}
|
|
1652
|
+
return void 0;
|
|
1653
|
+
}
|
|
1654
|
+
const triggerOnReady = (inner) => {
|
|
1655
|
+
if (!inner.rendered) {
|
|
1656
|
+
inner.rendered = true;
|
|
1657
|
+
return inner.onReady?.();
|
|
1658
|
+
}
|
|
1659
|
+
};
|
|
1660
|
+
const resolvePreload = (inner, matchId) => {
|
|
1661
|
+
return !!(inner.preload && !inner.router.state.matches.some((d) => d.id === matchId));
|
|
1662
|
+
};
|
|
1663
|
+
const buildMatchContext = (inner, index, includeCurrentMatch = true) => {
|
|
1664
|
+
const context = {
|
|
1665
|
+
...inner.router.options.context ?? {}
|
|
1666
|
+
};
|
|
1667
|
+
const end = includeCurrentMatch ? index : index - 1;
|
|
1668
|
+
for (let i = 0; i <= end; i++) {
|
|
1669
|
+
const innerMatch = inner.matches[i];
|
|
1670
|
+
if (!innerMatch) continue;
|
|
1671
|
+
const m = inner.router.getMatch(innerMatch.id);
|
|
1672
|
+
if (!m) continue;
|
|
1673
|
+
Object.assign(context, m.__routeContext, m.__beforeLoadContext);
|
|
1674
|
+
}
|
|
1675
|
+
return context;
|
|
1676
|
+
};
|
|
1677
|
+
const _handleNotFound = (inner, err) => {
|
|
1678
|
+
const routeCursor = inner.router.routesById[err.routeId ?? ""] ?? inner.router.routeTree;
|
|
1679
|
+
if (!routeCursor.options.notFoundComponent && inner.router.options?.defaultNotFoundComponent) {
|
|
1680
|
+
routeCursor.options.notFoundComponent = inner.router.options.defaultNotFoundComponent;
|
|
1681
|
+
}
|
|
1682
|
+
invariant(
|
|
1683
|
+
routeCursor.options.notFoundComponent
|
|
1684
|
+
);
|
|
1685
|
+
const matchForRoute = inner.matches.find((m) => m.routeId === routeCursor.id);
|
|
1686
|
+
invariant(matchForRoute, "Could not find match for route: " + routeCursor.id);
|
|
1687
|
+
inner.updateMatch(matchForRoute.id, (prev) => ({
|
|
1688
|
+
...prev,
|
|
1689
|
+
status: "notFound",
|
|
1690
|
+
error: err,
|
|
1691
|
+
isFetching: false
|
|
1692
|
+
}));
|
|
1693
|
+
if (err.routerCode === "BEFORE_LOAD" && routeCursor.parentRoute) {
|
|
1694
|
+
err.routeId = routeCursor.parentRoute.id;
|
|
1695
|
+
_handleNotFound(inner, err);
|
|
1696
|
+
}
|
|
1697
|
+
};
|
|
1698
|
+
const handleRedirectAndNotFound = (inner, match, err) => {
|
|
1699
|
+
if (!isRedirect(err) && !isNotFound(err)) return;
|
|
1700
|
+
if (isRedirect(err) && err.redirectHandled && !err.options.reloadDocument) {
|
|
1701
|
+
throw err;
|
|
1702
|
+
}
|
|
1703
|
+
if (match) {
|
|
1704
|
+
match._nonReactive.beforeLoadPromise?.resolve();
|
|
1705
|
+
match._nonReactive.loaderPromise?.resolve();
|
|
1706
|
+
match._nonReactive.beforeLoadPromise = void 0;
|
|
1707
|
+
match._nonReactive.loaderPromise = void 0;
|
|
1708
|
+
const status = isRedirect(err) ? "redirected" : "notFound";
|
|
1709
|
+
match._nonReactive.error = err;
|
|
1710
|
+
inner.updateMatch(match.id, (prev) => ({
|
|
1711
|
+
...prev,
|
|
1712
|
+
status,
|
|
1713
|
+
context: buildMatchContext(inner, match.index),
|
|
1714
|
+
isFetching: false,
|
|
1715
|
+
error: err
|
|
1716
|
+
}));
|
|
1717
|
+
if (isNotFound(err) && !err.routeId) {
|
|
1718
|
+
err.routeId = match.routeId;
|
|
1719
|
+
}
|
|
1720
|
+
match._nonReactive.loadPromise?.resolve();
|
|
1721
|
+
}
|
|
1722
|
+
if (isRedirect(err)) {
|
|
1723
|
+
inner.rendered = true;
|
|
1724
|
+
err.options._fromLocation = inner.location;
|
|
1725
|
+
err.redirectHandled = true;
|
|
1726
|
+
err = inner.router.resolveRedirect(err);
|
|
1727
|
+
throw err;
|
|
1728
|
+
} else {
|
|
1729
|
+
_handleNotFound(inner, err);
|
|
1730
|
+
throw err;
|
|
1731
|
+
}
|
|
1732
|
+
};
|
|
1733
|
+
const shouldSkipLoader = (inner, matchId) => {
|
|
1734
|
+
const match = inner.router.getMatch(matchId);
|
|
1735
|
+
if (!inner.router.isServer && match._nonReactive.dehydrated) {
|
|
1736
|
+
return true;
|
|
1737
|
+
}
|
|
1738
|
+
if (inner.router.isServer && match.ssr === false) {
|
|
1739
|
+
return true;
|
|
1740
|
+
}
|
|
1741
|
+
return false;
|
|
1742
|
+
};
|
|
1743
|
+
const handleSerialError = (inner, index, err, routerCode) => {
|
|
1744
|
+
const { id: matchId, routeId } = inner.matches[index];
|
|
1745
|
+
const route = inner.router.looseRoutesById[routeId];
|
|
1746
|
+
if (err instanceof Promise) {
|
|
1747
|
+
throw err;
|
|
1748
|
+
}
|
|
1749
|
+
err.routerCode = routerCode;
|
|
1750
|
+
inner.firstBadMatchIndex ??= index;
|
|
1751
|
+
handleRedirectAndNotFound(inner, inner.router.getMatch(matchId), err);
|
|
1752
|
+
try {
|
|
1753
|
+
route.options.onError?.(err);
|
|
1754
|
+
} catch (errorHandlerErr) {
|
|
1755
|
+
err = errorHandlerErr;
|
|
1756
|
+
handleRedirectAndNotFound(inner, inner.router.getMatch(matchId), err);
|
|
1757
|
+
}
|
|
1758
|
+
inner.updateMatch(matchId, (prev) => {
|
|
1759
|
+
prev._nonReactive.beforeLoadPromise?.resolve();
|
|
1760
|
+
prev._nonReactive.beforeLoadPromise = void 0;
|
|
1761
|
+
prev._nonReactive.loadPromise?.resolve();
|
|
1762
|
+
return {
|
|
1763
|
+
...prev,
|
|
1764
|
+
error: err,
|
|
1765
|
+
status: "error",
|
|
1766
|
+
isFetching: false,
|
|
1767
|
+
updatedAt: Date.now(),
|
|
1768
|
+
abortController: new AbortController()
|
|
1769
|
+
};
|
|
1770
|
+
});
|
|
1771
|
+
};
|
|
1772
|
+
const isBeforeLoadSsr = (inner, matchId, index, route) => {
|
|
1773
|
+
const existingMatch = inner.router.getMatch(matchId);
|
|
1774
|
+
const parentMatchId = inner.matches[index - 1]?.id;
|
|
1775
|
+
const parentMatch = parentMatchId ? inner.router.getMatch(parentMatchId) : void 0;
|
|
1776
|
+
if (inner.router.isShell()) {
|
|
1777
|
+
existingMatch.ssr = route.id === rootRouteId;
|
|
1778
|
+
return;
|
|
1779
|
+
}
|
|
1780
|
+
if (parentMatch?.ssr === false) {
|
|
1781
|
+
existingMatch.ssr = false;
|
|
1782
|
+
return;
|
|
1783
|
+
}
|
|
1784
|
+
const parentOverride = (tempSsr2) => {
|
|
1785
|
+
if (tempSsr2 === true && parentMatch?.ssr === "data-only") {
|
|
1786
|
+
return "data-only";
|
|
1787
|
+
}
|
|
1788
|
+
return tempSsr2;
|
|
1789
|
+
};
|
|
1790
|
+
const defaultSsr = inner.router.options.defaultSsr ?? true;
|
|
1791
|
+
if (route.options.ssr === void 0) {
|
|
1792
|
+
existingMatch.ssr = parentOverride(defaultSsr);
|
|
1793
|
+
return;
|
|
1794
|
+
}
|
|
1795
|
+
if (typeof route.options.ssr !== "function") {
|
|
1796
|
+
existingMatch.ssr = parentOverride(route.options.ssr);
|
|
1797
|
+
return;
|
|
1798
|
+
}
|
|
1799
|
+
const { search, params } = existingMatch;
|
|
1800
|
+
const ssrFnContext = {
|
|
1801
|
+
search: makeMaybe(search, existingMatch.searchError),
|
|
1802
|
+
params: makeMaybe(params, existingMatch.paramsError),
|
|
1803
|
+
location: inner.location,
|
|
1804
|
+
matches: inner.matches.map((match) => ({
|
|
1805
|
+
index: match.index,
|
|
1806
|
+
pathname: match.pathname,
|
|
1807
|
+
fullPath: match.fullPath,
|
|
1808
|
+
staticData: match.staticData,
|
|
1809
|
+
id: match.id,
|
|
1810
|
+
routeId: match.routeId,
|
|
1811
|
+
search: makeMaybe(match.search, match.searchError),
|
|
1812
|
+
params: makeMaybe(match.params, match.paramsError),
|
|
1813
|
+
ssr: match.ssr
|
|
1814
|
+
}))
|
|
1815
|
+
};
|
|
1816
|
+
const tempSsr = route.options.ssr(ssrFnContext);
|
|
1817
|
+
if (isPromise(tempSsr)) {
|
|
1818
|
+
return tempSsr.then((ssr) => {
|
|
1819
|
+
existingMatch.ssr = parentOverride(ssr ?? defaultSsr);
|
|
1820
|
+
});
|
|
1821
|
+
}
|
|
1822
|
+
existingMatch.ssr = parentOverride(tempSsr ?? defaultSsr);
|
|
1823
|
+
return;
|
|
1824
|
+
};
|
|
1825
|
+
const setupPendingTimeout = (inner, matchId, route, match) => {
|
|
1826
|
+
if (match._nonReactive.pendingTimeout !== void 0) return;
|
|
1827
|
+
const pendingMs = route.options.pendingMs ?? inner.router.options.defaultPendingMs;
|
|
1828
|
+
const shouldPending = !!(inner.onReady && !inner.router.isServer && !resolvePreload(inner, matchId) && (route.options.loader || route.options.beforeLoad || routeNeedsPreload(route)) && typeof pendingMs === "number" && pendingMs !== Infinity && (route.options.pendingComponent ?? inner.router.options?.defaultPendingComponent));
|
|
1829
|
+
if (shouldPending) {
|
|
1830
|
+
const pendingTimeout = setTimeout(() => {
|
|
1831
|
+
triggerOnReady(inner);
|
|
1832
|
+
}, pendingMs);
|
|
1833
|
+
match._nonReactive.pendingTimeout = pendingTimeout;
|
|
1834
|
+
}
|
|
1835
|
+
};
|
|
1836
|
+
const preBeforeLoadSetup = (inner, matchId, route) => {
|
|
1837
|
+
const existingMatch = inner.router.getMatch(matchId);
|
|
1838
|
+
if (!existingMatch._nonReactive.beforeLoadPromise && !existingMatch._nonReactive.loaderPromise)
|
|
1839
|
+
return;
|
|
1840
|
+
setupPendingTimeout(inner, matchId, route, existingMatch);
|
|
1841
|
+
const then = () => {
|
|
1842
|
+
const match = inner.router.getMatch(matchId);
|
|
1843
|
+
if (match.preload && (match.status === "redirected" || match.status === "notFound")) {
|
|
1844
|
+
handleRedirectAndNotFound(inner, match, match.error);
|
|
1845
|
+
}
|
|
1846
|
+
};
|
|
1847
|
+
return existingMatch._nonReactive.beforeLoadPromise ? existingMatch._nonReactive.beforeLoadPromise.then(then) : then();
|
|
1848
|
+
};
|
|
1849
|
+
const executeBeforeLoad = (inner, matchId, index, route) => {
|
|
1850
|
+
const match = inner.router.getMatch(matchId);
|
|
1851
|
+
const prevLoadPromise = match._nonReactive.loadPromise;
|
|
1852
|
+
match._nonReactive.loadPromise = createControlledPromise(() => {
|
|
1853
|
+
prevLoadPromise?.resolve();
|
|
1854
|
+
});
|
|
1855
|
+
const { paramsError, searchError } = match;
|
|
1856
|
+
if (paramsError) {
|
|
1857
|
+
handleSerialError(inner, index, paramsError, "PARSE_PARAMS");
|
|
1858
|
+
}
|
|
1859
|
+
if (searchError) {
|
|
1860
|
+
handleSerialError(inner, index, searchError, "VALIDATE_SEARCH");
|
|
1861
|
+
}
|
|
1862
|
+
setupPendingTimeout(inner, matchId, route, match);
|
|
1863
|
+
const abortController = new AbortController();
|
|
1864
|
+
const parentMatchId = inner.matches[index - 1]?.id;
|
|
1865
|
+
const parentMatch = parentMatchId ? inner.router.getMatch(parentMatchId) : void 0;
|
|
1866
|
+
parentMatch?.context ?? inner.router.options.context ?? void 0;
|
|
1867
|
+
let isPending = false;
|
|
1868
|
+
const pending = () => {
|
|
1869
|
+
if (isPending) return;
|
|
1870
|
+
isPending = true;
|
|
1871
|
+
inner.updateMatch(matchId, (prev) => ({
|
|
1872
|
+
...prev,
|
|
1873
|
+
isFetching: "beforeLoad",
|
|
1874
|
+
fetchCount: prev.fetchCount + 1,
|
|
1875
|
+
abortController
|
|
1876
|
+
// Note: We intentionally don't update context here.
|
|
1877
|
+
// Context should only be updated after beforeLoad resolves to avoid
|
|
1878
|
+
// components seeing incomplete context during async beforeLoad execution.
|
|
1879
|
+
}));
|
|
1880
|
+
};
|
|
1881
|
+
const resolve = () => {
|
|
1882
|
+
match._nonReactive.beforeLoadPromise?.resolve();
|
|
1883
|
+
match._nonReactive.beforeLoadPromise = void 0;
|
|
1884
|
+
inner.updateMatch(matchId, (prev) => ({
|
|
1885
|
+
...prev,
|
|
1886
|
+
isFetching: false
|
|
1887
|
+
}));
|
|
1888
|
+
};
|
|
1889
|
+
if (!route.options.beforeLoad) {
|
|
1890
|
+
batch(() => {
|
|
1891
|
+
pending();
|
|
1892
|
+
resolve();
|
|
1893
|
+
});
|
|
1894
|
+
return;
|
|
1895
|
+
}
|
|
1896
|
+
match._nonReactive.beforeLoadPromise = createControlledPromise();
|
|
1897
|
+
const context = {
|
|
1898
|
+
...buildMatchContext(inner, index, false),
|
|
1899
|
+
...match.__routeContext
|
|
1900
|
+
};
|
|
1901
|
+
const { search, params, cause } = match;
|
|
1902
|
+
const preload = resolvePreload(inner, matchId);
|
|
1903
|
+
const beforeLoadFnContext = {
|
|
1904
|
+
search,
|
|
1905
|
+
abortController,
|
|
1906
|
+
params,
|
|
1907
|
+
preload,
|
|
1908
|
+
context,
|
|
1909
|
+
location: inner.location,
|
|
1910
|
+
navigate: (opts) => inner.router.navigate({
|
|
1911
|
+
...opts,
|
|
1912
|
+
_fromLocation: inner.location
|
|
1913
|
+
}),
|
|
1914
|
+
buildLocation: inner.router.buildLocation,
|
|
1915
|
+
cause: preload ? "preload" : cause,
|
|
1916
|
+
matches: inner.matches,
|
|
1917
|
+
...inner.router.options.additionalContext
|
|
1918
|
+
};
|
|
1919
|
+
const updateContext = (beforeLoadContext2) => {
|
|
1920
|
+
if (beforeLoadContext2 === void 0) {
|
|
1921
|
+
batch(() => {
|
|
1922
|
+
pending();
|
|
1923
|
+
resolve();
|
|
1924
|
+
});
|
|
1925
|
+
return;
|
|
1926
|
+
}
|
|
1927
|
+
if (isRedirect(beforeLoadContext2) || isNotFound(beforeLoadContext2)) {
|
|
1928
|
+
pending();
|
|
1929
|
+
handleSerialError(inner, index, beforeLoadContext2, "BEFORE_LOAD");
|
|
1930
|
+
}
|
|
1931
|
+
batch(() => {
|
|
1932
|
+
pending();
|
|
1933
|
+
inner.updateMatch(matchId, (prev) => ({
|
|
1934
|
+
...prev,
|
|
1935
|
+
__beforeLoadContext: beforeLoadContext2
|
|
1936
|
+
}));
|
|
1937
|
+
resolve();
|
|
1938
|
+
});
|
|
1939
|
+
};
|
|
1940
|
+
let beforeLoadContext;
|
|
1941
|
+
try {
|
|
1942
|
+
beforeLoadContext = route.options.beforeLoad(beforeLoadFnContext);
|
|
1943
|
+
if (isPromise(beforeLoadContext)) {
|
|
1944
|
+
pending();
|
|
1945
|
+
return beforeLoadContext.catch((err) => {
|
|
1946
|
+
handleSerialError(inner, index, err, "BEFORE_LOAD");
|
|
1947
|
+
}).then(updateContext);
|
|
1948
|
+
}
|
|
1949
|
+
} catch (err) {
|
|
1950
|
+
pending();
|
|
1951
|
+
handleSerialError(inner, index, err, "BEFORE_LOAD");
|
|
1952
|
+
}
|
|
1953
|
+
updateContext(beforeLoadContext);
|
|
1954
|
+
return;
|
|
1955
|
+
};
|
|
1956
|
+
const handleBeforeLoad = (inner, index) => {
|
|
1957
|
+
const { id: matchId, routeId } = inner.matches[index];
|
|
1958
|
+
const route = inner.router.looseRoutesById[routeId];
|
|
1959
|
+
const serverSsr = () => {
|
|
1960
|
+
if (inner.router.isServer) {
|
|
1961
|
+
const maybePromise = isBeforeLoadSsr(inner, matchId, index, route);
|
|
1962
|
+
if (isPromise(maybePromise)) return maybePromise.then(queueExecution);
|
|
1963
|
+
}
|
|
1964
|
+
return queueExecution();
|
|
1965
|
+
};
|
|
1966
|
+
const execute = () => executeBeforeLoad(inner, matchId, index, route);
|
|
1967
|
+
const queueExecution = () => {
|
|
1968
|
+
if (shouldSkipLoader(inner, matchId)) return;
|
|
1969
|
+
const result = preBeforeLoadSetup(inner, matchId, route);
|
|
1970
|
+
return isPromise(result) ? result.then(execute) : execute();
|
|
1971
|
+
};
|
|
1972
|
+
return serverSsr();
|
|
1973
|
+
};
|
|
1974
|
+
const executeHead = (inner, matchId, route) => {
|
|
1975
|
+
const match = inner.router.getMatch(matchId);
|
|
1976
|
+
if (!match) {
|
|
1977
|
+
return;
|
|
1978
|
+
}
|
|
1979
|
+
if (!route.options.head && !route.options.scripts && !route.options.headers) {
|
|
1980
|
+
return;
|
|
1981
|
+
}
|
|
1982
|
+
const assetContext = {
|
|
1983
|
+
ssr: inner.router.options.ssr,
|
|
1984
|
+
matches: inner.matches,
|
|
1985
|
+
match,
|
|
1986
|
+
params: match.params,
|
|
1987
|
+
loaderData: match.loaderData
|
|
1988
|
+
};
|
|
1989
|
+
return Promise.all([
|
|
1990
|
+
route.options.head?.(assetContext),
|
|
1991
|
+
route.options.scripts?.(assetContext),
|
|
1992
|
+
route.options.headers?.(assetContext)
|
|
1993
|
+
]).then(([headFnContent, scripts, headers]) => {
|
|
1994
|
+
const meta = headFnContent?.meta;
|
|
1995
|
+
const links = headFnContent?.links;
|
|
1996
|
+
const headScripts = headFnContent?.scripts;
|
|
1997
|
+
const styles = headFnContent?.styles;
|
|
1998
|
+
return {
|
|
1999
|
+
meta,
|
|
2000
|
+
links,
|
|
2001
|
+
headScripts,
|
|
2002
|
+
headers,
|
|
2003
|
+
scripts,
|
|
2004
|
+
styles
|
|
2005
|
+
};
|
|
2006
|
+
});
|
|
2007
|
+
};
|
|
2008
|
+
const getLoaderContext = (inner, matchId, index, route) => {
|
|
2009
|
+
const parentMatchPromise = inner.matchPromises[index - 1];
|
|
2010
|
+
const { params, loaderDeps, abortController, cause } = inner.router.getMatch(matchId);
|
|
2011
|
+
const context = buildMatchContext(inner, index);
|
|
2012
|
+
const preload = resolvePreload(inner, matchId);
|
|
2013
|
+
return {
|
|
2014
|
+
params,
|
|
2015
|
+
deps: loaderDeps,
|
|
2016
|
+
preload: !!preload,
|
|
2017
|
+
parentMatchPromise,
|
|
2018
|
+
abortController,
|
|
2019
|
+
context,
|
|
2020
|
+
location: inner.location,
|
|
2021
|
+
navigate: (opts) => inner.router.navigate({
|
|
2022
|
+
...opts,
|
|
2023
|
+
_fromLocation: inner.location
|
|
2024
|
+
}),
|
|
2025
|
+
cause: preload ? "preload" : cause,
|
|
2026
|
+
route,
|
|
2027
|
+
...inner.router.options.additionalContext
|
|
2028
|
+
};
|
|
2029
|
+
};
|
|
2030
|
+
const runLoader = async (inner, matchId, index, route) => {
|
|
2031
|
+
try {
|
|
2032
|
+
const match = inner.router.getMatch(matchId);
|
|
2033
|
+
try {
|
|
2034
|
+
if (!inner.router.isServer || match.ssr === true) {
|
|
2035
|
+
loadRouteChunk(route);
|
|
2036
|
+
}
|
|
2037
|
+
const loaderResult = route.options.loader?.(
|
|
2038
|
+
getLoaderContext(inner, matchId, index, route)
|
|
2039
|
+
);
|
|
2040
|
+
const loaderResultIsPromise = route.options.loader && isPromise(loaderResult);
|
|
2041
|
+
const willLoadSomething = !!(loaderResultIsPromise || route._lazyPromise || route._componentsPromise || route.options.head || route.options.scripts || route.options.headers || match._nonReactive.minPendingPromise);
|
|
2042
|
+
if (willLoadSomething) {
|
|
2043
|
+
inner.updateMatch(matchId, (prev) => ({
|
|
2044
|
+
...prev,
|
|
2045
|
+
isFetching: "loader"
|
|
2046
|
+
}));
|
|
2047
|
+
}
|
|
2048
|
+
if (route.options.loader) {
|
|
2049
|
+
const loaderData = loaderResultIsPromise ? await loaderResult : loaderResult;
|
|
2050
|
+
handleRedirectAndNotFound(
|
|
2051
|
+
inner,
|
|
2052
|
+
inner.router.getMatch(matchId),
|
|
2053
|
+
loaderData
|
|
2054
|
+
);
|
|
2055
|
+
if (loaderData !== void 0) {
|
|
2056
|
+
inner.updateMatch(matchId, (prev) => ({
|
|
2057
|
+
...prev,
|
|
2058
|
+
loaderData
|
|
2059
|
+
}));
|
|
2060
|
+
}
|
|
2061
|
+
}
|
|
2062
|
+
if (route._lazyPromise) await route._lazyPromise;
|
|
2063
|
+
const pendingPromise = match._nonReactive.minPendingPromise;
|
|
2064
|
+
if (pendingPromise) await pendingPromise;
|
|
2065
|
+
if (route._componentsPromise) await route._componentsPromise;
|
|
2066
|
+
inner.updateMatch(matchId, (prev) => ({
|
|
2067
|
+
...prev,
|
|
2068
|
+
error: void 0,
|
|
2069
|
+
context: buildMatchContext(inner, index),
|
|
2070
|
+
status: "success",
|
|
2071
|
+
isFetching: false,
|
|
2072
|
+
updatedAt: Date.now()
|
|
2073
|
+
}));
|
|
2074
|
+
} catch (e) {
|
|
2075
|
+
let error = e;
|
|
2076
|
+
if (error?.name === "AbortError") {
|
|
2077
|
+
inner.updateMatch(matchId, (prev) => ({
|
|
2078
|
+
...prev,
|
|
2079
|
+
status: prev.status === "pending" ? "success" : prev.status,
|
|
2080
|
+
isFetching: false,
|
|
2081
|
+
context: buildMatchContext(inner, index)
|
|
2082
|
+
}));
|
|
2083
|
+
return;
|
|
2084
|
+
}
|
|
2085
|
+
const pendingPromise = match._nonReactive.minPendingPromise;
|
|
2086
|
+
if (pendingPromise) await pendingPromise;
|
|
2087
|
+
if (isNotFound(e)) {
|
|
2088
|
+
await route.options.notFoundComponent?.preload?.();
|
|
2089
|
+
}
|
|
2090
|
+
handleRedirectAndNotFound(inner, inner.router.getMatch(matchId), e);
|
|
2091
|
+
try {
|
|
2092
|
+
route.options.onError?.(e);
|
|
2093
|
+
} catch (onErrorError) {
|
|
2094
|
+
error = onErrorError;
|
|
2095
|
+
handleRedirectAndNotFound(
|
|
2096
|
+
inner,
|
|
2097
|
+
inner.router.getMatch(matchId),
|
|
2098
|
+
onErrorError
|
|
2099
|
+
);
|
|
2100
|
+
}
|
|
2101
|
+
inner.updateMatch(matchId, (prev) => ({
|
|
2102
|
+
...prev,
|
|
2103
|
+
error,
|
|
2104
|
+
context: buildMatchContext(inner, index),
|
|
2105
|
+
status: "error",
|
|
2106
|
+
isFetching: false
|
|
2107
|
+
}));
|
|
2108
|
+
}
|
|
2109
|
+
} catch (err) {
|
|
2110
|
+
const match = inner.router.getMatch(matchId);
|
|
2111
|
+
if (match) {
|
|
2112
|
+
match._nonReactive.loaderPromise = void 0;
|
|
2113
|
+
}
|
|
2114
|
+
handleRedirectAndNotFound(inner, match, err);
|
|
2115
|
+
}
|
|
2116
|
+
};
|
|
2117
|
+
const loadRouteMatch = async (inner, index) => {
|
|
2118
|
+
const { id: matchId, routeId } = inner.matches[index];
|
|
2119
|
+
let loaderShouldRunAsync = false;
|
|
2120
|
+
let loaderIsRunningAsync = false;
|
|
2121
|
+
const route = inner.router.looseRoutesById[routeId];
|
|
2122
|
+
if (shouldSkipLoader(inner, matchId)) {
|
|
2123
|
+
if (inner.router.isServer) {
|
|
2124
|
+
return inner.router.getMatch(matchId);
|
|
2125
|
+
}
|
|
2126
|
+
} else {
|
|
2127
|
+
const prevMatch = inner.router.getMatch(matchId);
|
|
2128
|
+
if (prevMatch._nonReactive.loaderPromise) {
|
|
2129
|
+
if (prevMatch.status === "success" && !inner.sync && !prevMatch.preload) {
|
|
2130
|
+
return prevMatch;
|
|
2131
|
+
}
|
|
2132
|
+
await prevMatch._nonReactive.loaderPromise;
|
|
2133
|
+
const match2 = inner.router.getMatch(matchId);
|
|
2134
|
+
const error = match2._nonReactive.error || match2.error;
|
|
2135
|
+
if (error) {
|
|
2136
|
+
handleRedirectAndNotFound(inner, match2, error);
|
|
2137
|
+
}
|
|
2138
|
+
} else {
|
|
2139
|
+
const age = Date.now() - prevMatch.updatedAt;
|
|
2140
|
+
const preload = resolvePreload(inner, matchId);
|
|
2141
|
+
const staleAge = preload ? route.options.preloadStaleTime ?? inner.router.options.defaultPreloadStaleTime ?? 3e4 : route.options.staleTime ?? inner.router.options.defaultStaleTime ?? 0;
|
|
2142
|
+
const shouldReloadOption = route.options.shouldReload;
|
|
2143
|
+
const shouldReload = typeof shouldReloadOption === "function" ? shouldReloadOption(getLoaderContext(inner, matchId, index, route)) : shouldReloadOption;
|
|
2144
|
+
const nextPreload = !!preload && !inner.router.state.matches.some((d) => d.id === matchId);
|
|
2145
|
+
const match2 = inner.router.getMatch(matchId);
|
|
2146
|
+
match2._nonReactive.loaderPromise = createControlledPromise();
|
|
2147
|
+
if (nextPreload !== match2.preload) {
|
|
2148
|
+
inner.updateMatch(matchId, (prev) => ({
|
|
2149
|
+
...prev,
|
|
2150
|
+
preload: nextPreload
|
|
2151
|
+
}));
|
|
2152
|
+
}
|
|
2153
|
+
const { status, invalid } = match2;
|
|
2154
|
+
loaderShouldRunAsync = status === "success" && (invalid || (shouldReload ?? age > staleAge));
|
|
2155
|
+
if (preload && route.options.preload === false) ;
|
|
2156
|
+
else if (loaderShouldRunAsync && !inner.sync) {
|
|
2157
|
+
loaderIsRunningAsync = true;
|
|
2158
|
+
(async () => {
|
|
2159
|
+
try {
|
|
2160
|
+
await runLoader(inner, matchId, index, route);
|
|
2161
|
+
const match3 = inner.router.getMatch(matchId);
|
|
2162
|
+
match3._nonReactive.loaderPromise?.resolve();
|
|
2163
|
+
match3._nonReactive.loadPromise?.resolve();
|
|
2164
|
+
match3._nonReactive.loaderPromise = void 0;
|
|
2165
|
+
} catch (err) {
|
|
2166
|
+
if (isRedirect(err)) {
|
|
2167
|
+
await inner.router.navigate(err.options);
|
|
2168
|
+
}
|
|
2169
|
+
}
|
|
2170
|
+
})();
|
|
2171
|
+
} else if (status !== "success" || loaderShouldRunAsync && inner.sync) {
|
|
2172
|
+
await runLoader(inner, matchId, index, route);
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2176
|
+
const match = inner.router.getMatch(matchId);
|
|
2177
|
+
if (!loaderIsRunningAsync) {
|
|
2178
|
+
match._nonReactive.loaderPromise?.resolve();
|
|
2179
|
+
match._nonReactive.loadPromise?.resolve();
|
|
2180
|
+
}
|
|
2181
|
+
clearTimeout(match._nonReactive.pendingTimeout);
|
|
2182
|
+
match._nonReactive.pendingTimeout = void 0;
|
|
2183
|
+
if (!loaderIsRunningAsync) match._nonReactive.loaderPromise = void 0;
|
|
2184
|
+
match._nonReactive.dehydrated = void 0;
|
|
2185
|
+
const nextIsFetching = loaderIsRunningAsync ? match.isFetching : false;
|
|
2186
|
+
if (nextIsFetching !== match.isFetching || match.invalid !== false) {
|
|
2187
|
+
inner.updateMatch(matchId, (prev) => ({
|
|
2188
|
+
...prev,
|
|
2189
|
+
isFetching: nextIsFetching,
|
|
2190
|
+
invalid: false
|
|
2191
|
+
}));
|
|
2192
|
+
return inner.router.getMatch(matchId);
|
|
2193
|
+
} else {
|
|
2194
|
+
return match;
|
|
2195
|
+
}
|
|
2196
|
+
};
|
|
2197
|
+
async function loadMatches(arg) {
|
|
2198
|
+
const inner = Object.assign(arg, {
|
|
2199
|
+
matchPromises: []
|
|
2200
|
+
});
|
|
2201
|
+
if (!inner.router.isServer && inner.router.state.matches.some((d) => d._forcePending)) {
|
|
2202
|
+
triggerOnReady(inner);
|
|
2203
|
+
}
|
|
2204
|
+
try {
|
|
2205
|
+
for (let i = 0; i < inner.matches.length; i++) {
|
|
2206
|
+
const beforeLoad = handleBeforeLoad(inner, i);
|
|
2207
|
+
if (isPromise(beforeLoad)) await beforeLoad;
|
|
2208
|
+
}
|
|
2209
|
+
const max = inner.firstBadMatchIndex ?? inner.matches.length;
|
|
2210
|
+
for (let i = 0; i < max; i++) {
|
|
2211
|
+
inner.matchPromises.push(loadRouteMatch(inner, i));
|
|
2212
|
+
}
|
|
2213
|
+
const results = await Promise.allSettled(inner.matchPromises);
|
|
2214
|
+
const failures = results.filter(
|
|
2215
|
+
(result) => result.status === "rejected"
|
|
2216
|
+
).map((result) => result.reason);
|
|
2217
|
+
let firstNotFound;
|
|
2218
|
+
for (const err of failures) {
|
|
2219
|
+
if (isRedirect(err)) {
|
|
2220
|
+
throw err;
|
|
2221
|
+
}
|
|
2222
|
+
if (!firstNotFound && isNotFound(err)) {
|
|
2223
|
+
firstNotFound = err;
|
|
2224
|
+
}
|
|
2225
|
+
}
|
|
2226
|
+
for (const match of inner.matches) {
|
|
2227
|
+
const { id: matchId, routeId } = match;
|
|
2228
|
+
const route = inner.router.looseRoutesById[routeId];
|
|
2229
|
+
try {
|
|
2230
|
+
const headResult = executeHead(inner, matchId, route);
|
|
2231
|
+
if (headResult) {
|
|
2232
|
+
const head = await headResult;
|
|
2233
|
+
inner.updateMatch(matchId, (prev) => ({
|
|
2234
|
+
...prev,
|
|
2235
|
+
...head
|
|
2236
|
+
}));
|
|
2237
|
+
}
|
|
2238
|
+
} catch (err) {
|
|
2239
|
+
console.error(`Error executing head for route ${routeId}:`, err);
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
if (firstNotFound) {
|
|
2243
|
+
throw firstNotFound;
|
|
2244
|
+
}
|
|
2245
|
+
const readyPromise = triggerOnReady(inner);
|
|
2246
|
+
if (isPromise(readyPromise)) await readyPromise;
|
|
2247
|
+
} catch (err) {
|
|
2248
|
+
if (isNotFound(err) && !inner.preload) {
|
|
2249
|
+
const readyPromise = triggerOnReady(inner);
|
|
2250
|
+
if (isPromise(readyPromise)) await readyPromise;
|
|
2251
|
+
throw err;
|
|
2252
|
+
}
|
|
2253
|
+
if (isRedirect(err)) {
|
|
2254
|
+
throw err;
|
|
2255
|
+
}
|
|
2256
|
+
}
|
|
2257
|
+
return inner.matches;
|
|
2258
|
+
}
|
|
2259
|
+
async function loadRouteChunk(route) {
|
|
2260
|
+
if (!route._lazyLoaded && route._lazyPromise === void 0) {
|
|
2261
|
+
if (route.lazyFn) {
|
|
2262
|
+
route._lazyPromise = route.lazyFn().then((lazyRoute) => {
|
|
2263
|
+
const { id: _id, ...options } = lazyRoute.options;
|
|
2264
|
+
Object.assign(route.options, options);
|
|
2265
|
+
route._lazyLoaded = true;
|
|
2266
|
+
route._lazyPromise = void 0;
|
|
2267
|
+
});
|
|
2268
|
+
} else {
|
|
2269
|
+
route._lazyLoaded = true;
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
if (!route._componentsLoaded && route._componentsPromise === void 0) {
|
|
2273
|
+
const loadComponents = () => {
|
|
2274
|
+
const preloads = [];
|
|
2275
|
+
for (const type of componentTypes) {
|
|
2276
|
+
const preload = route.options[type]?.preload;
|
|
2277
|
+
if (preload) preloads.push(preload());
|
|
2278
|
+
}
|
|
2279
|
+
if (preloads.length)
|
|
2280
|
+
return Promise.all(preloads).then(() => {
|
|
2281
|
+
route._componentsLoaded = true;
|
|
2282
|
+
route._componentsPromise = void 0;
|
|
2283
|
+
});
|
|
2284
|
+
route._componentsLoaded = true;
|
|
2285
|
+
route._componentsPromise = void 0;
|
|
2286
|
+
return;
|
|
2287
|
+
};
|
|
2288
|
+
route._componentsPromise = route._lazyPromise ? route._lazyPromise.then(loadComponents) : loadComponents();
|
|
2289
|
+
}
|
|
2290
|
+
return route._componentsPromise;
|
|
2291
|
+
}
|
|
2292
|
+
function makeMaybe(value, error) {
|
|
2293
|
+
if (error) {
|
|
2294
|
+
return { status: "error", error };
|
|
2295
|
+
}
|
|
2296
|
+
return { status: "success", value };
|
|
2297
|
+
}
|
|
2298
|
+
function routeNeedsPreload(route) {
|
|
2299
|
+
for (const componentType of componentTypes) {
|
|
2300
|
+
if (route.options[componentType]?.preload) {
|
|
2301
|
+
return true;
|
|
2302
|
+
}
|
|
2303
|
+
}
|
|
2304
|
+
return false;
|
|
2305
|
+
}
|
|
2306
|
+
const componentTypes = [
|
|
2307
|
+
"component",
|
|
2308
|
+
"errorComponent",
|
|
2309
|
+
"pendingComponent",
|
|
2310
|
+
"notFoundComponent"
|
|
2311
|
+
];
|
|
2312
|
+
function composeRewrites(rewrites) {
|
|
2313
|
+
return {
|
|
2314
|
+
input: ({ url }) => {
|
|
2315
|
+
for (const rewrite of rewrites) {
|
|
2316
|
+
url = executeRewriteInput(rewrite, url);
|
|
2317
|
+
}
|
|
2318
|
+
return url;
|
|
2319
|
+
},
|
|
2320
|
+
output: ({ url }) => {
|
|
2321
|
+
for (let i = rewrites.length - 1; i >= 0; i--) {
|
|
2322
|
+
url = executeRewriteOutput(rewrites[i], url);
|
|
2323
|
+
}
|
|
2324
|
+
return url;
|
|
2325
|
+
}
|
|
2326
|
+
};
|
|
2327
|
+
}
|
|
2328
|
+
function rewriteBasepath(opts) {
|
|
2329
|
+
const trimmedBasepath = trimPath(opts.basepath);
|
|
2330
|
+
const normalizedBasepath = `/${trimmedBasepath}`;
|
|
2331
|
+
const normalizedBasepathWithSlash = `${normalizedBasepath}/`;
|
|
2332
|
+
const checkBasepath = opts.caseSensitive ? normalizedBasepath : normalizedBasepath.toLowerCase();
|
|
2333
|
+
const checkBasepathWithSlash = opts.caseSensitive ? normalizedBasepathWithSlash : normalizedBasepathWithSlash.toLowerCase();
|
|
2334
|
+
return {
|
|
2335
|
+
input: ({ url }) => {
|
|
2336
|
+
const pathname = opts.caseSensitive ? url.pathname : url.pathname.toLowerCase();
|
|
2337
|
+
if (pathname === checkBasepath) {
|
|
2338
|
+
url.pathname = "/";
|
|
2339
|
+
} else if (pathname.startsWith(checkBasepathWithSlash)) {
|
|
2340
|
+
url.pathname = url.pathname.slice(normalizedBasepath.length);
|
|
2341
|
+
}
|
|
2342
|
+
return url;
|
|
2343
|
+
},
|
|
2344
|
+
output: ({ url }) => {
|
|
2345
|
+
url.pathname = joinPaths(["/", trimmedBasepath, url.pathname]);
|
|
2346
|
+
return url;
|
|
2347
|
+
}
|
|
2348
|
+
};
|
|
2349
|
+
}
|
|
2350
|
+
function executeRewriteInput(rewrite, url) {
|
|
2351
|
+
const res = rewrite?.input?.({ url });
|
|
2352
|
+
if (res) {
|
|
2353
|
+
if (typeof res === "string") {
|
|
2354
|
+
return new URL(res);
|
|
2355
|
+
} else if (res instanceof URL) {
|
|
2356
|
+
return res;
|
|
2357
|
+
}
|
|
2358
|
+
}
|
|
2359
|
+
return url;
|
|
2360
|
+
}
|
|
2361
|
+
function executeRewriteOutput(rewrite, url) {
|
|
2362
|
+
const res = rewrite?.output?.({ url });
|
|
2363
|
+
if (res) {
|
|
2364
|
+
if (typeof res === "string") {
|
|
2365
|
+
return new URL(res);
|
|
2366
|
+
} else if (res instanceof URL) {
|
|
2367
|
+
return res;
|
|
2368
|
+
}
|
|
2369
|
+
}
|
|
2370
|
+
return url;
|
|
2371
|
+
}
|
|
2372
|
+
function getLocationChangeInfo(routerState) {
|
|
2373
|
+
const fromLocation = routerState.resolvedLocation;
|
|
2374
|
+
const toLocation = routerState.location;
|
|
2375
|
+
const pathChanged = fromLocation?.pathname !== toLocation.pathname;
|
|
2376
|
+
const hrefChanged = fromLocation?.href !== toLocation.href;
|
|
2377
|
+
const hashChanged = fromLocation?.hash !== toLocation.hash;
|
|
2378
|
+
return { fromLocation, toLocation, pathChanged, hrefChanged, hashChanged };
|
|
2379
|
+
}
|
|
2380
|
+
class RouterCore {
|
|
2381
|
+
/**
|
|
2382
|
+
* @deprecated Use the `createRouter` function instead
|
|
2383
|
+
*/
|
|
2384
|
+
constructor(options) {
|
|
2385
|
+
this.tempLocationKey = `${Math.round(
|
|
2386
|
+
Math.random() * 1e7
|
|
2387
|
+
)}`;
|
|
2388
|
+
this.shouldViewTransition = void 0;
|
|
2389
|
+
this.isViewTransitionTypesSupported = void 0;
|
|
2390
|
+
this.subscribers = /* @__PURE__ */ new Set();
|
|
2391
|
+
this.isScrollRestoring = false;
|
|
2392
|
+
this.isScrollRestorationSetup = false;
|
|
2393
|
+
this.startTransition = (fn) => fn();
|
|
2394
|
+
this.update = (newOptions) => {
|
|
2395
|
+
if (newOptions.notFoundRoute) {
|
|
2396
|
+
console.warn(
|
|
2397
|
+
"The notFoundRoute API is deprecated and will be removed in the next major version. See https://tanstack.com/router/v1/docs/framework/react/guide/not-found-errors#migrating-from-notfoundroute for more info."
|
|
2398
|
+
);
|
|
2399
|
+
}
|
|
2400
|
+
const prevOptions = this.options;
|
|
2401
|
+
const prevBasepath = this.basepath ?? prevOptions?.basepath ?? "/";
|
|
2402
|
+
const basepathWasUnset = this.basepath === void 0;
|
|
2403
|
+
const prevRewriteOption = prevOptions?.rewrite;
|
|
2404
|
+
this.options = {
|
|
2405
|
+
...prevOptions,
|
|
2406
|
+
...newOptions
|
|
2407
|
+
};
|
|
2408
|
+
this.isServer = this.options.isServer ?? typeof document === "undefined";
|
|
2409
|
+
this.pathParamsDecodeCharMap = this.options.pathParamsAllowedCharacters ? new Map(
|
|
2410
|
+
this.options.pathParamsAllowedCharacters.map((char) => [
|
|
2411
|
+
encodeURIComponent(char),
|
|
2412
|
+
char
|
|
2413
|
+
])
|
|
2414
|
+
) : void 0;
|
|
2415
|
+
if (!this.history || this.options.history && this.options.history !== this.history) {
|
|
2416
|
+
if (!this.options.history) {
|
|
2417
|
+
if (!this.isServer) {
|
|
2418
|
+
this.history = createBrowserHistory();
|
|
2419
|
+
}
|
|
2420
|
+
} else {
|
|
2421
|
+
this.history = this.options.history;
|
|
2422
|
+
}
|
|
2423
|
+
}
|
|
2424
|
+
this.origin = this.options.origin;
|
|
2425
|
+
if (!this.origin) {
|
|
2426
|
+
if (!this.isServer && window?.origin && window.origin !== "null") {
|
|
2427
|
+
this.origin = window.origin;
|
|
2428
|
+
} else {
|
|
2429
|
+
this.origin = "http://localhost";
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
if (this.history) {
|
|
2433
|
+
this.updateLatestLocation();
|
|
2434
|
+
}
|
|
2435
|
+
if (this.options.routeTree !== this.routeTree) {
|
|
2436
|
+
this.routeTree = this.options.routeTree;
|
|
2437
|
+
this.buildRouteTree();
|
|
2438
|
+
}
|
|
2439
|
+
if (!this.__store && this.latestLocation) {
|
|
2440
|
+
this.__store = new Store(getInitialRouterState(this.latestLocation), {
|
|
2441
|
+
onUpdate: () => {
|
|
2442
|
+
this.__store.state = {
|
|
2443
|
+
...this.state,
|
|
2444
|
+
cachedMatches: this.state.cachedMatches.filter(
|
|
2445
|
+
(d) => !["redirected"].includes(d.status)
|
|
2446
|
+
)
|
|
2447
|
+
};
|
|
2448
|
+
}
|
|
2449
|
+
});
|
|
2450
|
+
setupScrollRestoration(this);
|
|
2451
|
+
}
|
|
2452
|
+
let needsLocationUpdate = false;
|
|
2453
|
+
const nextBasepath = this.options.basepath ?? "/";
|
|
2454
|
+
const nextRewriteOption = this.options.rewrite;
|
|
2455
|
+
const basepathChanged = basepathWasUnset || prevBasepath !== nextBasepath;
|
|
2456
|
+
const rewriteChanged = prevRewriteOption !== nextRewriteOption;
|
|
2457
|
+
if (basepathChanged || rewriteChanged) {
|
|
2458
|
+
this.basepath = nextBasepath;
|
|
2459
|
+
const rewrites = [];
|
|
2460
|
+
if (trimPath(nextBasepath) !== "") {
|
|
2461
|
+
rewrites.push(
|
|
2462
|
+
rewriteBasepath({
|
|
2463
|
+
basepath: nextBasepath
|
|
2464
|
+
})
|
|
2465
|
+
);
|
|
2466
|
+
}
|
|
2467
|
+
if (nextRewriteOption) {
|
|
2468
|
+
rewrites.push(nextRewriteOption);
|
|
2469
|
+
}
|
|
2470
|
+
this.rewrite = rewrites.length === 0 ? void 0 : rewrites.length === 1 ? rewrites[0] : composeRewrites(rewrites);
|
|
2471
|
+
if (this.history) {
|
|
2472
|
+
this.updateLatestLocation();
|
|
2473
|
+
}
|
|
2474
|
+
needsLocationUpdate = true;
|
|
2475
|
+
}
|
|
2476
|
+
if (needsLocationUpdate && this.__store) {
|
|
2477
|
+
this.__store.state = {
|
|
2478
|
+
...this.state,
|
|
2479
|
+
location: this.latestLocation
|
|
2480
|
+
};
|
|
2481
|
+
}
|
|
2482
|
+
if (typeof window !== "undefined" && "CSS" in window && typeof window.CSS?.supports === "function") {
|
|
2483
|
+
this.isViewTransitionTypesSupported = window.CSS.supports(
|
|
2484
|
+
"selector(:active-view-transition-type(a)"
|
|
2485
|
+
);
|
|
2486
|
+
}
|
|
2487
|
+
};
|
|
2488
|
+
this.updateLatestLocation = () => {
|
|
2489
|
+
this.latestLocation = this.parseLocation(
|
|
2490
|
+
this.history.location,
|
|
2491
|
+
this.latestLocation
|
|
2492
|
+
);
|
|
2493
|
+
};
|
|
2494
|
+
this.buildRouteTree = () => {
|
|
2495
|
+
const { routesById, routesByPath, processedTree } = processRouteTree(
|
|
2496
|
+
this.routeTree,
|
|
2497
|
+
this.options.caseSensitive,
|
|
2498
|
+
(route, i) => {
|
|
2499
|
+
route.init({
|
|
2500
|
+
originalIndex: i
|
|
2501
|
+
});
|
|
2502
|
+
}
|
|
2503
|
+
);
|
|
2504
|
+
if (this.options.routeMasks) {
|
|
2505
|
+
processRouteMasks(this.options.routeMasks, processedTree);
|
|
2506
|
+
}
|
|
2507
|
+
this.routesById = routesById;
|
|
2508
|
+
this.routesByPath = routesByPath;
|
|
2509
|
+
this.processedTree = processedTree;
|
|
2510
|
+
const notFoundRoute = this.options.notFoundRoute;
|
|
2511
|
+
if (notFoundRoute) {
|
|
2512
|
+
notFoundRoute.init({
|
|
2513
|
+
originalIndex: 99999999999
|
|
2514
|
+
});
|
|
2515
|
+
this.routesById[notFoundRoute.id] = notFoundRoute;
|
|
2516
|
+
}
|
|
2517
|
+
};
|
|
2518
|
+
this.subscribe = (eventType, fn) => {
|
|
2519
|
+
const listener = {
|
|
2520
|
+
eventType,
|
|
2521
|
+
fn
|
|
2522
|
+
};
|
|
2523
|
+
this.subscribers.add(listener);
|
|
2524
|
+
return () => {
|
|
2525
|
+
this.subscribers.delete(listener);
|
|
2526
|
+
};
|
|
2527
|
+
};
|
|
2528
|
+
this.emit = (routerEvent) => {
|
|
2529
|
+
this.subscribers.forEach((listener) => {
|
|
2530
|
+
if (listener.eventType === routerEvent.type) {
|
|
2531
|
+
listener.fn(routerEvent);
|
|
2532
|
+
}
|
|
2533
|
+
});
|
|
2534
|
+
};
|
|
2535
|
+
this.parseLocation = (locationToParse, previousLocation) => {
|
|
2536
|
+
const parse = ({
|
|
2537
|
+
href,
|
|
2538
|
+
state
|
|
2539
|
+
}) => {
|
|
2540
|
+
const fullUrl = new URL(href, this.origin);
|
|
2541
|
+
const url = executeRewriteInput(this.rewrite, fullUrl);
|
|
2542
|
+
const parsedSearch = this.options.parseSearch(url.search);
|
|
2543
|
+
const searchStr = this.options.stringifySearch(parsedSearch);
|
|
2544
|
+
url.search = searchStr;
|
|
2545
|
+
const fullPath = url.href.replace(url.origin, "");
|
|
2546
|
+
return {
|
|
2547
|
+
href: fullPath,
|
|
2548
|
+
publicHref: href,
|
|
2549
|
+
url,
|
|
2550
|
+
pathname: decodePath(url.pathname),
|
|
2551
|
+
searchStr,
|
|
2552
|
+
search: replaceEqualDeep(previousLocation?.search, parsedSearch),
|
|
2553
|
+
hash: decodePath(url.hash.split("#").reverse()[0] ?? ""),
|
|
2554
|
+
state: replaceEqualDeep(previousLocation?.state, state)
|
|
2555
|
+
};
|
|
2556
|
+
};
|
|
2557
|
+
const location = parse(locationToParse);
|
|
2558
|
+
const { __tempLocation, __tempKey } = location.state;
|
|
2559
|
+
if (__tempLocation && (!__tempKey || __tempKey === this.tempLocationKey)) {
|
|
2560
|
+
const parsedTempLocation = parse(__tempLocation);
|
|
2561
|
+
parsedTempLocation.state.key = location.state.key;
|
|
2562
|
+
parsedTempLocation.state.__TSR_key = location.state.__TSR_key;
|
|
2563
|
+
delete parsedTempLocation.state.__tempLocation;
|
|
2564
|
+
return {
|
|
2565
|
+
...parsedTempLocation,
|
|
2566
|
+
maskedLocation: location
|
|
2567
|
+
};
|
|
2568
|
+
}
|
|
2569
|
+
return location;
|
|
2570
|
+
};
|
|
2571
|
+
this.resolvePathCache = createLRUCache(1e3);
|
|
2572
|
+
this.resolvePathWithBase = (from, path) => {
|
|
2573
|
+
const resolvedPath = resolvePath({
|
|
2574
|
+
base: from,
|
|
2575
|
+
to: cleanPath(path),
|
|
2576
|
+
trailingSlash: this.options.trailingSlash,
|
|
2577
|
+
cache: this.resolvePathCache
|
|
2578
|
+
});
|
|
2579
|
+
return resolvedPath;
|
|
2580
|
+
};
|
|
2581
|
+
this.matchRoutes = (pathnameOrNext, locationSearchOrOpts, opts) => {
|
|
2582
|
+
if (typeof pathnameOrNext === "string") {
|
|
2583
|
+
return this.matchRoutesInternal(
|
|
2584
|
+
{
|
|
2585
|
+
pathname: pathnameOrNext,
|
|
2586
|
+
search: locationSearchOrOpts
|
|
2587
|
+
},
|
|
2588
|
+
opts
|
|
2589
|
+
).matches;
|
|
2590
|
+
}
|
|
2591
|
+
return this.matchRoutesInternal(pathnameOrNext, locationSearchOrOpts).matches;
|
|
2592
|
+
};
|
|
2593
|
+
this.getMatchedRoutes = (pathname) => {
|
|
2594
|
+
return getMatchedRoutes({
|
|
2595
|
+
pathname,
|
|
2596
|
+
routesById: this.routesById,
|
|
2597
|
+
processedTree: this.processedTree
|
|
2598
|
+
});
|
|
2599
|
+
};
|
|
2600
|
+
this.cancelMatch = (id) => {
|
|
2601
|
+
const match = this.getMatch(id);
|
|
2602
|
+
if (!match) return;
|
|
2603
|
+
match.abortController.abort();
|
|
2604
|
+
clearTimeout(match._nonReactive.pendingTimeout);
|
|
2605
|
+
match._nonReactive.pendingTimeout = void 0;
|
|
2606
|
+
};
|
|
2607
|
+
this.cancelMatches = () => {
|
|
2608
|
+
const currentPendingMatches = this.state.matches.filter(
|
|
2609
|
+
(match) => match.status === "pending"
|
|
2610
|
+
);
|
|
2611
|
+
const currentLoadingMatches = this.state.matches.filter(
|
|
2612
|
+
(match) => match.isFetching === "loader"
|
|
2613
|
+
);
|
|
2614
|
+
const matchesToCancelArray = /* @__PURE__ */ new Set([
|
|
2615
|
+
...this.state.pendingMatches ?? [],
|
|
2616
|
+
...currentPendingMatches,
|
|
2617
|
+
...currentLoadingMatches
|
|
2618
|
+
]);
|
|
2619
|
+
matchesToCancelArray.forEach((match) => {
|
|
2620
|
+
this.cancelMatch(match.id);
|
|
2621
|
+
});
|
|
2622
|
+
};
|
|
2623
|
+
this.buildLocation = (opts) => {
|
|
2624
|
+
const build = (dest = {}) => {
|
|
2625
|
+
const currentLocation = dest._fromLocation || this.pendingBuiltLocation || this.latestLocation;
|
|
2626
|
+
const allCurrentLocationMatches = this.matchRoutes(currentLocation, {
|
|
2627
|
+
_buildLocation: true
|
|
2628
|
+
});
|
|
2629
|
+
const lastMatch = last(allCurrentLocationMatches);
|
|
2630
|
+
if (dest.from && false) ;
|
|
2631
|
+
const defaultedFromPath = dest.unsafeRelative === "path" ? currentLocation.pathname : dest.from ?? lastMatch.fullPath;
|
|
2632
|
+
const fromPath = this.resolvePathWithBase(defaultedFromPath, ".");
|
|
2633
|
+
const fromSearch = lastMatch.search;
|
|
2634
|
+
const fromParams = { ...lastMatch.params };
|
|
2635
|
+
const nextTo = dest.to ? this.resolvePathWithBase(fromPath, `${dest.to}`) : this.resolvePathWithBase(fromPath, ".");
|
|
2636
|
+
const nextParams = dest.params === false || dest.params === null ? {} : (dest.params ?? true) === true ? fromParams : Object.assign(
|
|
2637
|
+
fromParams,
|
|
2638
|
+
functionalUpdate(dest.params, fromParams)
|
|
2639
|
+
);
|
|
2640
|
+
const interpolatedNextTo = interpolatePath({
|
|
2641
|
+
path: nextTo,
|
|
2642
|
+
params: nextParams
|
|
2643
|
+
}).interpolatedPath;
|
|
2644
|
+
const destMatchResult = this.getMatchedRoutes(interpolatedNextTo);
|
|
2645
|
+
let destRoutes = destMatchResult.matchedRoutes;
|
|
2646
|
+
const rawParams = destMatchResult.routeParams;
|
|
2647
|
+
const isGlobalNotFound = destMatchResult.foundRoute ? destMatchResult.foundRoute.path !== "/" && destMatchResult.routeParams["**"] : trimPathRight(interpolatedNextTo);
|
|
2648
|
+
let globalNotFoundRouteId;
|
|
2649
|
+
if (isGlobalNotFound) {
|
|
2650
|
+
if (this.options.notFoundRoute) {
|
|
2651
|
+
destRoutes = [...destRoutes, this.options.notFoundRoute];
|
|
2652
|
+
} else {
|
|
2653
|
+
globalNotFoundRouteId = findGlobalNotFoundRouteId(
|
|
2654
|
+
this.options.notFoundMode,
|
|
2655
|
+
destRoutes
|
|
2656
|
+
);
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2659
|
+
if (Object.keys(nextParams).length > 0) {
|
|
2660
|
+
for (const route of destRoutes) {
|
|
2661
|
+
const fn = route.options.params?.stringify ?? route.options.stringifyParams;
|
|
2662
|
+
if (fn) {
|
|
2663
|
+
Object.assign(nextParams, fn(nextParams));
|
|
2664
|
+
}
|
|
2665
|
+
}
|
|
2666
|
+
}
|
|
2667
|
+
const nextPathname = opts.leaveParams ? (
|
|
2668
|
+
// Use the original template path for interpolation
|
|
2669
|
+
// This preserves the original parameter syntax including optional parameters
|
|
2670
|
+
nextTo
|
|
2671
|
+
) : decodePath(
|
|
2672
|
+
interpolatePath({
|
|
2673
|
+
path: nextTo,
|
|
2674
|
+
params: nextParams,
|
|
2675
|
+
decodeCharMap: this.pathParamsDecodeCharMap
|
|
2676
|
+
}).interpolatedPath
|
|
2677
|
+
);
|
|
2678
|
+
let nextSearch = fromSearch;
|
|
2679
|
+
if (opts._includeValidateSearch && this.options.search?.strict) {
|
|
2680
|
+
const validatedSearch = {};
|
|
2681
|
+
destRoutes.forEach((route) => {
|
|
2682
|
+
if (route.options.validateSearch) {
|
|
2683
|
+
try {
|
|
2684
|
+
Object.assign(
|
|
2685
|
+
validatedSearch,
|
|
2686
|
+
validateSearch(route.options.validateSearch, {
|
|
2687
|
+
...validatedSearch,
|
|
2688
|
+
...nextSearch
|
|
2689
|
+
})
|
|
2690
|
+
);
|
|
2691
|
+
} catch {
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
});
|
|
2695
|
+
nextSearch = validatedSearch;
|
|
2696
|
+
}
|
|
2697
|
+
nextSearch = applySearchMiddleware({
|
|
2698
|
+
search: nextSearch,
|
|
2699
|
+
dest,
|
|
2700
|
+
destRoutes,
|
|
2701
|
+
_includeValidateSearch: opts._includeValidateSearch
|
|
2702
|
+
});
|
|
2703
|
+
nextSearch = replaceEqualDeep(fromSearch, nextSearch);
|
|
2704
|
+
const searchStr = this.options.stringifySearch(nextSearch);
|
|
2705
|
+
const hash = dest.hash === true ? currentLocation.hash : dest.hash ? functionalUpdate(dest.hash, currentLocation.hash) : void 0;
|
|
2706
|
+
const hashStr = hash ? `#${hash}` : "";
|
|
2707
|
+
let nextState = dest.state === true ? currentLocation.state : dest.state ? functionalUpdate(dest.state, currentLocation.state) : {};
|
|
2708
|
+
nextState = replaceEqualDeep(currentLocation.state, nextState);
|
|
2709
|
+
const snapshotParams = {
|
|
2710
|
+
...rawParams,
|
|
2711
|
+
...nextParams
|
|
2712
|
+
};
|
|
2713
|
+
const matchSnapshot = buildMatchSnapshotFromRoutes({
|
|
2714
|
+
routes: destRoutes,
|
|
2715
|
+
params: snapshotParams,
|
|
2716
|
+
searchStr,
|
|
2717
|
+
globalNotFoundRouteId
|
|
2718
|
+
});
|
|
2719
|
+
const fullPath = `${nextPathname}${searchStr}${hashStr}`;
|
|
2720
|
+
const url = new URL(fullPath, this.origin);
|
|
2721
|
+
const rewrittenUrl = executeRewriteOutput(this.rewrite, url);
|
|
2722
|
+
const encodedHref = url.href.replace(url.origin, "");
|
|
2723
|
+
return {
|
|
2724
|
+
publicHref: rewrittenUrl.pathname + rewrittenUrl.search + rewrittenUrl.hash,
|
|
2725
|
+
href: encodedHref,
|
|
2726
|
+
url: rewrittenUrl,
|
|
2727
|
+
pathname: nextPathname,
|
|
2728
|
+
search: nextSearch,
|
|
2729
|
+
searchStr,
|
|
2730
|
+
state: nextState,
|
|
2731
|
+
hash: hash ?? "",
|
|
2732
|
+
unmaskOnReload: dest.unmaskOnReload,
|
|
2733
|
+
_matchSnapshot: matchSnapshot
|
|
2734
|
+
};
|
|
2735
|
+
};
|
|
2736
|
+
const buildWithMatches = (dest = {}, maskedDest) => {
|
|
2737
|
+
const next = build(dest);
|
|
2738
|
+
let maskedNext = maskedDest ? build(maskedDest) : void 0;
|
|
2739
|
+
if (!maskedNext) {
|
|
2740
|
+
const params = {};
|
|
2741
|
+
if (this.options.routeMasks) {
|
|
2742
|
+
const match = findFlatMatch(
|
|
2743
|
+
next.pathname,
|
|
2744
|
+
this.processedTree
|
|
2745
|
+
);
|
|
2746
|
+
if (match) {
|
|
2747
|
+
Object.assign(params, match.rawParams);
|
|
2748
|
+
const {
|
|
2749
|
+
from: _from,
|
|
2750
|
+
params: maskParams,
|
|
2751
|
+
...maskProps
|
|
2752
|
+
} = match.route;
|
|
2753
|
+
const nextParams = maskParams === false || maskParams === null ? {} : (maskParams ?? true) === true ? params : Object.assign(params, functionalUpdate(maskParams, params));
|
|
2754
|
+
maskedDest = {
|
|
2755
|
+
from: opts.from,
|
|
2756
|
+
...maskProps,
|
|
2757
|
+
params: nextParams
|
|
2758
|
+
};
|
|
2759
|
+
maskedNext = build(maskedDest);
|
|
2760
|
+
}
|
|
2761
|
+
}
|
|
2762
|
+
}
|
|
2763
|
+
if (maskedNext) {
|
|
2764
|
+
next.maskedLocation = maskedNext;
|
|
2765
|
+
}
|
|
2766
|
+
return next;
|
|
2767
|
+
};
|
|
2768
|
+
if (opts.mask) {
|
|
2769
|
+
return buildWithMatches(opts, {
|
|
2770
|
+
from: opts.from,
|
|
2771
|
+
...opts.mask
|
|
2772
|
+
});
|
|
2773
|
+
}
|
|
2774
|
+
return buildWithMatches(opts);
|
|
2775
|
+
};
|
|
2776
|
+
this.commitLocation = async ({
|
|
2777
|
+
viewTransition,
|
|
2778
|
+
ignoreBlocker,
|
|
2779
|
+
...next
|
|
2780
|
+
}) => {
|
|
2781
|
+
const isSameState = () => {
|
|
2782
|
+
const ignoredProps = [
|
|
2783
|
+
"key",
|
|
2784
|
+
// TODO: Remove in v2 - use __TSR_key instead
|
|
2785
|
+
"__TSR_key",
|
|
2786
|
+
"__TSR_index",
|
|
2787
|
+
"__hashScrollIntoViewOptions"
|
|
2788
|
+
];
|
|
2789
|
+
ignoredProps.forEach((prop) => {
|
|
2790
|
+
next.state[prop] = this.latestLocation.state[prop];
|
|
2791
|
+
});
|
|
2792
|
+
const isEqual = deepEqual(next.state, this.latestLocation.state);
|
|
2793
|
+
ignoredProps.forEach((prop) => {
|
|
2794
|
+
delete next.state[prop];
|
|
2795
|
+
});
|
|
2796
|
+
return isEqual;
|
|
2797
|
+
};
|
|
2798
|
+
const isSameUrl = trimPathRight(this.latestLocation.href) === trimPathRight(next.href);
|
|
2799
|
+
const previousCommitPromise = this.commitLocationPromise;
|
|
2800
|
+
this.commitLocationPromise = createControlledPromise(() => {
|
|
2801
|
+
previousCommitPromise?.resolve();
|
|
2802
|
+
});
|
|
2803
|
+
if (isSameUrl && isSameState()) {
|
|
2804
|
+
this.load();
|
|
2805
|
+
return this.commitLocationPromise;
|
|
2806
|
+
}
|
|
2807
|
+
let {
|
|
2808
|
+
// eslint-disable-next-line prefer-const
|
|
2809
|
+
maskedLocation,
|
|
2810
|
+
// eslint-disable-next-line prefer-const
|
|
2811
|
+
hashScrollIntoView,
|
|
2812
|
+
// don't pass url into history since it is a URL instance that cannot be serialized
|
|
2813
|
+
// eslint-disable-next-line prefer-const
|
|
2814
|
+
url: _url,
|
|
2815
|
+
...nextHistory
|
|
2816
|
+
} = next;
|
|
2817
|
+
if (maskedLocation) {
|
|
2818
|
+
nextHistory = {
|
|
2819
|
+
...maskedLocation,
|
|
2820
|
+
state: {
|
|
2821
|
+
...maskedLocation.state,
|
|
2822
|
+
__tempKey: void 0,
|
|
2823
|
+
__tempLocation: {
|
|
2824
|
+
...nextHistory,
|
|
2825
|
+
search: nextHistory.searchStr,
|
|
2826
|
+
state: {
|
|
2827
|
+
...nextHistory.state,
|
|
2828
|
+
__tempKey: void 0,
|
|
2829
|
+
__tempLocation: void 0,
|
|
2830
|
+
__TSR_key: void 0,
|
|
2831
|
+
key: void 0
|
|
2832
|
+
// TODO: Remove in v2 - use __TSR_key instead
|
|
2833
|
+
}
|
|
2834
|
+
}
|
|
2835
|
+
}
|
|
2836
|
+
};
|
|
2837
|
+
if (nextHistory.unmaskOnReload ?? this.options.unmaskOnReload ?? false) {
|
|
2838
|
+
nextHistory.state.__tempKey = this.tempLocationKey;
|
|
2839
|
+
}
|
|
2840
|
+
}
|
|
2841
|
+
nextHistory.state.__hashScrollIntoViewOptions = hashScrollIntoView ?? this.options.defaultHashScrollIntoView ?? true;
|
|
2842
|
+
nextHistory.state.__TSR_resetScroll = next.resetScroll ?? true;
|
|
2843
|
+
this.shouldViewTransition = viewTransition;
|
|
2844
|
+
nextHistory.state.__TSR_sessionId = this.sessionId;
|
|
2845
|
+
nextHistory.state.__TSR_matches = next._matchSnapshot ?? buildMatchSnapshot({
|
|
2846
|
+
matchResult: this.getMatchedRoutes(next.pathname),
|
|
2847
|
+
pathname: next.pathname,
|
|
2848
|
+
searchStr: next.searchStr,
|
|
2849
|
+
notFoundRoute: this.options.notFoundRoute,
|
|
2850
|
+
notFoundMode: this.options.notFoundMode
|
|
2851
|
+
});
|
|
2852
|
+
const precomputedLocation = {
|
|
2853
|
+
...next,
|
|
2854
|
+
publicHref: nextHistory.publicHref,
|
|
2855
|
+
state: nextHistory.state,
|
|
2856
|
+
maskedLocation
|
|
2857
|
+
};
|
|
2858
|
+
const result = await this.history[next.replace ? "replace" : "push"](
|
|
2859
|
+
nextHistory.publicHref,
|
|
2860
|
+
nextHistory.state,
|
|
2861
|
+
{ ignoreBlocker, skipTransitionerLoad: true }
|
|
2862
|
+
);
|
|
2863
|
+
if (result.type === "BLOCKED") {
|
|
2864
|
+
this.commitLocationPromise?.resolve();
|
|
2865
|
+
return this.commitLocationPromise;
|
|
2866
|
+
}
|
|
2867
|
+
if (this.history.location.href !== nextHistory.publicHref) {
|
|
2868
|
+
return this.commitLocationPromise;
|
|
2869
|
+
}
|
|
2870
|
+
this.latestLocation = precomputedLocation;
|
|
2871
|
+
this.load({ _skipUpdateLatestLocation: true });
|
|
2872
|
+
return this.commitLocationPromise;
|
|
2873
|
+
};
|
|
2874
|
+
this.buildAndCommitLocation = ({
|
|
2875
|
+
replace,
|
|
2876
|
+
resetScroll,
|
|
2877
|
+
hashScrollIntoView,
|
|
2878
|
+
viewTransition,
|
|
2879
|
+
ignoreBlocker,
|
|
2880
|
+
href,
|
|
2881
|
+
...rest
|
|
2882
|
+
} = {}) => {
|
|
2883
|
+
if (href) {
|
|
2884
|
+
const currentIndex = this.history.location.state.__TSR_index;
|
|
2885
|
+
const parsed = parseHref(href, {
|
|
2886
|
+
__TSR_index: replace ? currentIndex : currentIndex + 1
|
|
2887
|
+
});
|
|
2888
|
+
const hrefUrl = new URL(parsed.pathname, this.origin);
|
|
2889
|
+
const rewrittenUrl = executeRewriteInput(this.rewrite, hrefUrl);
|
|
2890
|
+
rest.to = rewrittenUrl.pathname;
|
|
2891
|
+
rest.search = this.options.parseSearch(parsed.search);
|
|
2892
|
+
rest.hash = parsed.hash.slice(1);
|
|
2893
|
+
}
|
|
2894
|
+
const location = this.buildLocation({
|
|
2895
|
+
...rest,
|
|
2896
|
+
_includeValidateSearch: true
|
|
2897
|
+
});
|
|
2898
|
+
this.pendingBuiltLocation = location;
|
|
2899
|
+
const commitPromise = this.commitLocation({
|
|
2900
|
+
...location,
|
|
2901
|
+
viewTransition,
|
|
2902
|
+
replace,
|
|
2903
|
+
resetScroll,
|
|
2904
|
+
hashScrollIntoView,
|
|
2905
|
+
ignoreBlocker
|
|
2906
|
+
});
|
|
2907
|
+
Promise.resolve().then(() => {
|
|
2908
|
+
if (this.pendingBuiltLocation === location) {
|
|
2909
|
+
this.pendingBuiltLocation = void 0;
|
|
2910
|
+
}
|
|
2911
|
+
});
|
|
2912
|
+
return commitPromise;
|
|
2913
|
+
};
|
|
2914
|
+
this.navigate = async ({
|
|
2915
|
+
to,
|
|
2916
|
+
reloadDocument,
|
|
2917
|
+
href,
|
|
2918
|
+
publicHref,
|
|
2919
|
+
...rest
|
|
2920
|
+
}) => {
|
|
2921
|
+
let hrefIsUrl = false;
|
|
2922
|
+
if (href) {
|
|
2923
|
+
try {
|
|
2924
|
+
new URL(`${href}`);
|
|
2925
|
+
hrefIsUrl = true;
|
|
2926
|
+
} catch {
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
if (hrefIsUrl && !reloadDocument) {
|
|
2930
|
+
reloadDocument = true;
|
|
2931
|
+
}
|
|
2932
|
+
if (reloadDocument) {
|
|
2933
|
+
if (to !== void 0 || !href) {
|
|
2934
|
+
const location = this.buildLocation({ to, ...rest });
|
|
2935
|
+
href = href ?? location.url.href;
|
|
2936
|
+
publicHref = publicHref ?? location.url.href;
|
|
2937
|
+
}
|
|
2938
|
+
const reloadHref = !hrefIsUrl && publicHref ? publicHref : href;
|
|
2939
|
+
if (isDangerousProtocol(reloadHref)) {
|
|
2940
|
+
return Promise.resolve();
|
|
2941
|
+
}
|
|
2942
|
+
if (!rest.ignoreBlocker) {
|
|
2943
|
+
const historyWithBlockers = this.history;
|
|
2944
|
+
const blockers = historyWithBlockers.getBlockers?.() ?? [];
|
|
2945
|
+
for (const blocker of blockers) {
|
|
2946
|
+
if (blocker?.blockerFn) {
|
|
2947
|
+
const shouldBlock = await blocker.blockerFn({
|
|
2948
|
+
currentLocation: this.latestLocation,
|
|
2949
|
+
nextLocation: this.latestLocation,
|
|
2950
|
+
// External URLs don't have a next location in our router
|
|
2951
|
+
action: "PUSH"
|
|
2952
|
+
});
|
|
2953
|
+
if (shouldBlock) {
|
|
2954
|
+
return Promise.resolve();
|
|
2955
|
+
}
|
|
2956
|
+
}
|
|
2957
|
+
}
|
|
2958
|
+
}
|
|
2959
|
+
if (rest.replace) {
|
|
2960
|
+
window.location.replace(reloadHref);
|
|
2961
|
+
} else {
|
|
2962
|
+
window.location.href = reloadHref;
|
|
2963
|
+
}
|
|
2964
|
+
return Promise.resolve();
|
|
2965
|
+
}
|
|
2966
|
+
return this.buildAndCommitLocation({
|
|
2967
|
+
...rest,
|
|
2968
|
+
href,
|
|
2969
|
+
to,
|
|
2970
|
+
_isNavigate: true
|
|
2971
|
+
});
|
|
2972
|
+
};
|
|
2973
|
+
this.beforeLoad = (opts) => {
|
|
2974
|
+
this.cancelMatches();
|
|
2975
|
+
if (!opts?._skipUpdateLatestLocation) {
|
|
2976
|
+
this.updateLatestLocation();
|
|
2977
|
+
}
|
|
2978
|
+
if (this.isServer) {
|
|
2979
|
+
const nextLocation = this.buildLocation({
|
|
2980
|
+
to: this.latestLocation.pathname,
|
|
2981
|
+
search: true,
|
|
2982
|
+
params: true,
|
|
2983
|
+
hash: true,
|
|
2984
|
+
state: true,
|
|
2985
|
+
_includeValidateSearch: true
|
|
2986
|
+
});
|
|
2987
|
+
if (this.latestLocation.publicHref !== nextLocation.publicHref || nextLocation.url.origin !== this.origin) {
|
|
2988
|
+
const href = this.getParsedLocationHref(nextLocation);
|
|
2989
|
+
throw redirect({ href });
|
|
2990
|
+
}
|
|
2991
|
+
}
|
|
2992
|
+
const snapshot = this.latestLocation.state.__TSR_sessionId === this.sessionId ? this.latestLocation.state.__TSR_matches : void 0;
|
|
2993
|
+
const pendingMatches = this.matchRoutes(this.latestLocation, { snapshot });
|
|
2994
|
+
this.__store.setState((s) => ({
|
|
2995
|
+
...s,
|
|
2996
|
+
status: "pending",
|
|
2997
|
+
statusCode: 200,
|
|
2998
|
+
isLoading: true,
|
|
2999
|
+
location: this.latestLocation,
|
|
3000
|
+
pendingMatches,
|
|
3001
|
+
// If a cached moved to pendingMatches, remove it from cachedMatches
|
|
3002
|
+
cachedMatches: s.cachedMatches.filter(
|
|
3003
|
+
(d) => !pendingMatches.some((e) => e.id === d.id)
|
|
3004
|
+
)
|
|
3005
|
+
}));
|
|
3006
|
+
};
|
|
3007
|
+
this.load = async (opts) => {
|
|
3008
|
+
let redirect2;
|
|
3009
|
+
let notFound;
|
|
3010
|
+
let loadPromise;
|
|
3011
|
+
loadPromise = new Promise((resolve) => {
|
|
3012
|
+
this.startTransition(async () => {
|
|
3013
|
+
try {
|
|
3014
|
+
this.beforeLoad({
|
|
3015
|
+
_skipUpdateLatestLocation: opts?._skipUpdateLatestLocation
|
|
3016
|
+
});
|
|
3017
|
+
const next = this.latestLocation;
|
|
3018
|
+
const prevLocation = this.state.resolvedLocation;
|
|
3019
|
+
if (!this.state.redirect) {
|
|
3020
|
+
this.emit({
|
|
3021
|
+
type: "onBeforeNavigate",
|
|
3022
|
+
...getLocationChangeInfo({
|
|
3023
|
+
resolvedLocation: prevLocation,
|
|
3024
|
+
location: next
|
|
3025
|
+
})
|
|
3026
|
+
});
|
|
3027
|
+
}
|
|
3028
|
+
this.emit({
|
|
3029
|
+
type: "onBeforeLoad",
|
|
3030
|
+
...getLocationChangeInfo({
|
|
3031
|
+
resolvedLocation: prevLocation,
|
|
3032
|
+
location: next
|
|
3033
|
+
})
|
|
3034
|
+
});
|
|
3035
|
+
await loadMatches({
|
|
3036
|
+
router: this,
|
|
3037
|
+
sync: opts?.sync,
|
|
3038
|
+
matches: this.state.pendingMatches,
|
|
3039
|
+
location: next,
|
|
3040
|
+
updateMatch: this.updateMatch,
|
|
3041
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
3042
|
+
onReady: async () => {
|
|
3043
|
+
this.startTransition(() => {
|
|
3044
|
+
this.startViewTransition(async () => {
|
|
3045
|
+
let exitingMatches = [];
|
|
3046
|
+
let enteringMatches = [];
|
|
3047
|
+
let stayingMatches = [];
|
|
3048
|
+
batch(() => {
|
|
3049
|
+
this.__store.setState((s) => {
|
|
3050
|
+
const previousMatches = s.matches;
|
|
3051
|
+
const newMatches = s.pendingMatches || s.matches;
|
|
3052
|
+
exitingMatches = previousMatches.filter(
|
|
3053
|
+
(match) => !newMatches.some((d) => d.id === match.id)
|
|
3054
|
+
);
|
|
3055
|
+
enteringMatches = newMatches.filter(
|
|
3056
|
+
(match) => !previousMatches.some((d) => d.id === match.id)
|
|
3057
|
+
);
|
|
3058
|
+
stayingMatches = newMatches.filter(
|
|
3059
|
+
(match) => previousMatches.some((d) => d.id === match.id)
|
|
3060
|
+
);
|
|
3061
|
+
return {
|
|
3062
|
+
...s,
|
|
3063
|
+
isLoading: false,
|
|
3064
|
+
loadedAt: Date.now(),
|
|
3065
|
+
matches: newMatches,
|
|
3066
|
+
pendingMatches: void 0,
|
|
3067
|
+
/**
|
|
3068
|
+
* When committing new matches, cache any exiting matches that are still usable.
|
|
3069
|
+
* Routes that resolved with `status: 'error'` or `status: 'notFound'` are
|
|
3070
|
+
* deliberately excluded from `cachedMatches` so that subsequent invalidations
|
|
3071
|
+
* or reloads re-run their loaders instead of reusing the failed/not-found data.
|
|
3072
|
+
*/
|
|
3073
|
+
cachedMatches: [
|
|
3074
|
+
...s.cachedMatches,
|
|
3075
|
+
...exitingMatches.filter(
|
|
3076
|
+
(d) => d.status !== "error" && d.status !== "notFound"
|
|
3077
|
+
)
|
|
3078
|
+
]
|
|
3079
|
+
};
|
|
3080
|
+
});
|
|
3081
|
+
this.clearExpiredCache();
|
|
3082
|
+
});
|
|
3083
|
+
[
|
|
3084
|
+
[exitingMatches, "onLeave"],
|
|
3085
|
+
[enteringMatches, "onEnter"],
|
|
3086
|
+
[stayingMatches, "onStay"]
|
|
3087
|
+
].forEach(([matches, hook]) => {
|
|
3088
|
+
matches.forEach((match) => {
|
|
3089
|
+
this.looseRoutesById[match.routeId].options[hook]?.(
|
|
3090
|
+
match
|
|
3091
|
+
);
|
|
3092
|
+
});
|
|
3093
|
+
});
|
|
3094
|
+
});
|
|
3095
|
+
});
|
|
3096
|
+
}
|
|
3097
|
+
});
|
|
3098
|
+
} catch (err) {
|
|
3099
|
+
if (isRedirect(err)) {
|
|
3100
|
+
redirect2 = err;
|
|
3101
|
+
if (!this.isServer) {
|
|
3102
|
+
this.navigate({
|
|
3103
|
+
...redirect2.options,
|
|
3104
|
+
replace: true,
|
|
3105
|
+
ignoreBlocker: true
|
|
3106
|
+
});
|
|
3107
|
+
}
|
|
3108
|
+
} else if (isNotFound(err)) {
|
|
3109
|
+
notFound = err;
|
|
3110
|
+
}
|
|
3111
|
+
this.__store.setState((s) => ({
|
|
3112
|
+
...s,
|
|
3113
|
+
statusCode: redirect2 ? redirect2.status : notFound ? 404 : s.matches.some((d) => d.status === "error") ? 500 : 200,
|
|
3114
|
+
redirect: redirect2
|
|
3115
|
+
}));
|
|
3116
|
+
}
|
|
3117
|
+
if (this.latestLoadPromise === loadPromise) {
|
|
3118
|
+
this.commitLocationPromise?.resolve();
|
|
3119
|
+
this.latestLoadPromise = void 0;
|
|
3120
|
+
this.commitLocationPromise = void 0;
|
|
3121
|
+
}
|
|
3122
|
+
resolve();
|
|
3123
|
+
});
|
|
3124
|
+
});
|
|
3125
|
+
this.latestLoadPromise = loadPromise;
|
|
3126
|
+
await loadPromise;
|
|
3127
|
+
while (this.latestLoadPromise && loadPromise !== this.latestLoadPromise) {
|
|
3128
|
+
await this.latestLoadPromise;
|
|
3129
|
+
}
|
|
3130
|
+
let newStatusCode = void 0;
|
|
3131
|
+
if (this.hasNotFoundMatch()) {
|
|
3132
|
+
newStatusCode = 404;
|
|
3133
|
+
} else if (this.__store.state.matches.some((d) => d.status === "error")) {
|
|
3134
|
+
newStatusCode = 500;
|
|
3135
|
+
}
|
|
3136
|
+
if (newStatusCode !== void 0) {
|
|
3137
|
+
this.__store.setState((s) => ({
|
|
3138
|
+
...s,
|
|
3139
|
+
statusCode: newStatusCode
|
|
3140
|
+
}));
|
|
3141
|
+
}
|
|
3142
|
+
};
|
|
3143
|
+
this.startViewTransition = (fn) => {
|
|
3144
|
+
const shouldViewTransition = this.shouldViewTransition ?? this.options.defaultViewTransition;
|
|
3145
|
+
delete this.shouldViewTransition;
|
|
3146
|
+
if (shouldViewTransition && typeof document !== "undefined" && "startViewTransition" in document && typeof document.startViewTransition === "function") {
|
|
3147
|
+
let startViewTransitionParams;
|
|
3148
|
+
if (typeof shouldViewTransition === "object" && this.isViewTransitionTypesSupported) {
|
|
3149
|
+
const next = this.latestLocation;
|
|
3150
|
+
const prevLocation = this.state.resolvedLocation;
|
|
3151
|
+
const resolvedViewTransitionTypes = typeof shouldViewTransition.types === "function" ? shouldViewTransition.types(
|
|
3152
|
+
getLocationChangeInfo({
|
|
3153
|
+
resolvedLocation: prevLocation,
|
|
3154
|
+
location: next
|
|
3155
|
+
})
|
|
3156
|
+
) : shouldViewTransition.types;
|
|
3157
|
+
if (resolvedViewTransitionTypes === false) {
|
|
3158
|
+
fn();
|
|
3159
|
+
return;
|
|
3160
|
+
}
|
|
3161
|
+
startViewTransitionParams = {
|
|
3162
|
+
update: fn,
|
|
3163
|
+
types: resolvedViewTransitionTypes
|
|
3164
|
+
};
|
|
3165
|
+
} else {
|
|
3166
|
+
startViewTransitionParams = fn;
|
|
3167
|
+
}
|
|
3168
|
+
document.startViewTransition(startViewTransitionParams);
|
|
3169
|
+
} else {
|
|
3170
|
+
fn();
|
|
3171
|
+
}
|
|
3172
|
+
};
|
|
3173
|
+
this.updateMatch = (id, updater) => {
|
|
3174
|
+
this.startTransition(() => {
|
|
3175
|
+
const matchesKey = this.state.pendingMatches?.some((d) => d.id === id) ? "pendingMatches" : this.state.matches.some((d) => d.id === id) ? "matches" : this.state.cachedMatches.some((d) => d.id === id) ? "cachedMatches" : "";
|
|
3176
|
+
if (matchesKey) {
|
|
3177
|
+
this.__store.setState((s) => ({
|
|
3178
|
+
...s,
|
|
3179
|
+
[matchesKey]: s[matchesKey]?.map(
|
|
3180
|
+
(d) => d.id === id ? updater(d) : d
|
|
3181
|
+
)
|
|
3182
|
+
}));
|
|
3183
|
+
}
|
|
3184
|
+
});
|
|
3185
|
+
};
|
|
3186
|
+
this.getMatch = (matchId) => {
|
|
3187
|
+
const findFn = (d) => d.id === matchId;
|
|
3188
|
+
return this.state.cachedMatches.find(findFn) ?? this.state.pendingMatches?.find(findFn) ?? this.state.matches.find(findFn);
|
|
3189
|
+
};
|
|
3190
|
+
this.invalidate = (opts) => {
|
|
3191
|
+
const invalidate = (d) => {
|
|
3192
|
+
if (opts?.filter?.(d) ?? true) {
|
|
3193
|
+
return {
|
|
3194
|
+
...d,
|
|
3195
|
+
invalid: true,
|
|
3196
|
+
...opts?.forcePending || d.status === "error" || d.status === "notFound" ? { status: "pending", error: void 0 } : void 0
|
|
3197
|
+
};
|
|
3198
|
+
}
|
|
3199
|
+
return d;
|
|
3200
|
+
};
|
|
3201
|
+
this.__store.setState((s) => ({
|
|
3202
|
+
...s,
|
|
3203
|
+
matches: s.matches.map(invalidate),
|
|
3204
|
+
cachedMatches: s.cachedMatches.map(invalidate),
|
|
3205
|
+
pendingMatches: s.pendingMatches?.map(invalidate)
|
|
3206
|
+
}));
|
|
3207
|
+
this.shouldViewTransition = false;
|
|
3208
|
+
return this.load({ sync: opts?.sync });
|
|
3209
|
+
};
|
|
3210
|
+
this.getParsedLocationHref = (location) => {
|
|
3211
|
+
let href = location.url.href;
|
|
3212
|
+
if (this.origin && location.url.origin === this.origin) {
|
|
3213
|
+
href = href.replace(this.origin, "") || "/";
|
|
3214
|
+
}
|
|
3215
|
+
return href;
|
|
3216
|
+
};
|
|
3217
|
+
this.resolveRedirect = (redirect2) => {
|
|
3218
|
+
const locationHeader = redirect2.headers.get("Location");
|
|
3219
|
+
if (!redirect2.options.href) {
|
|
3220
|
+
const location = this.buildLocation(redirect2.options);
|
|
3221
|
+
const href = this.getParsedLocationHref(location);
|
|
3222
|
+
redirect2.options.href = href;
|
|
3223
|
+
redirect2.headers.set("Location", href);
|
|
3224
|
+
} else if (locationHeader) {
|
|
3225
|
+
try {
|
|
3226
|
+
const url = new URL(locationHeader);
|
|
3227
|
+
if (this.origin && url.origin === this.origin) {
|
|
3228
|
+
const href = url.pathname + url.search + url.hash;
|
|
3229
|
+
redirect2.options.href = href;
|
|
3230
|
+
redirect2.headers.set("Location", href);
|
|
3231
|
+
}
|
|
3232
|
+
} catch {
|
|
3233
|
+
}
|
|
3234
|
+
}
|
|
3235
|
+
if (!redirect2.headers.get("Location")) {
|
|
3236
|
+
redirect2.headers.set("Location", redirect2.options.href);
|
|
3237
|
+
}
|
|
3238
|
+
return redirect2;
|
|
3239
|
+
};
|
|
3240
|
+
this.clearCache = (opts) => {
|
|
3241
|
+
const filter = opts?.filter;
|
|
3242
|
+
if (filter !== void 0) {
|
|
3243
|
+
this.__store.setState((s) => {
|
|
3244
|
+
return {
|
|
3245
|
+
...s,
|
|
3246
|
+
cachedMatches: s.cachedMatches.filter(
|
|
3247
|
+
(m) => !filter(m)
|
|
3248
|
+
)
|
|
3249
|
+
};
|
|
3250
|
+
});
|
|
3251
|
+
} else {
|
|
3252
|
+
this.__store.setState((s) => {
|
|
3253
|
+
return {
|
|
3254
|
+
...s,
|
|
3255
|
+
cachedMatches: []
|
|
3256
|
+
};
|
|
3257
|
+
});
|
|
3258
|
+
}
|
|
3259
|
+
};
|
|
3260
|
+
this.clearExpiredCache = () => {
|
|
3261
|
+
const filter = (d) => {
|
|
3262
|
+
const route = this.looseRoutesById[d.routeId];
|
|
3263
|
+
if (!route.options.loader) {
|
|
3264
|
+
return true;
|
|
3265
|
+
}
|
|
3266
|
+
const gcTime = (d.preload ? route.options.preloadGcTime ?? this.options.defaultPreloadGcTime : route.options.gcTime ?? this.options.defaultGcTime) ?? 5 * 60 * 1e3;
|
|
3267
|
+
const isError = d.status === "error";
|
|
3268
|
+
if (isError) return true;
|
|
3269
|
+
const gcEligible = Date.now() - d.updatedAt >= gcTime;
|
|
3270
|
+
return gcEligible;
|
|
3271
|
+
};
|
|
3272
|
+
this.clearCache({ filter });
|
|
3273
|
+
};
|
|
3274
|
+
this.loadRouteChunk = loadRouteChunk;
|
|
3275
|
+
this.preloadRoute = async (opts) => {
|
|
3276
|
+
const next = this.buildLocation(opts);
|
|
3277
|
+
let matches = this.matchRoutes(next, {
|
|
3278
|
+
throwOnError: true,
|
|
3279
|
+
preload: true,
|
|
3280
|
+
dest: opts
|
|
3281
|
+
});
|
|
3282
|
+
const activeMatchIds = new Set(
|
|
3283
|
+
[...this.state.matches, ...this.state.pendingMatches ?? []].map(
|
|
3284
|
+
(d) => d.id
|
|
3285
|
+
)
|
|
3286
|
+
);
|
|
3287
|
+
const loadedMatchIds = /* @__PURE__ */ new Set([
|
|
3288
|
+
...activeMatchIds,
|
|
3289
|
+
...this.state.cachedMatches.map((d) => d.id)
|
|
3290
|
+
]);
|
|
3291
|
+
batch(() => {
|
|
3292
|
+
matches.forEach((match) => {
|
|
3293
|
+
if (!loadedMatchIds.has(match.id)) {
|
|
3294
|
+
this.__store.setState((s) => ({
|
|
3295
|
+
...s,
|
|
3296
|
+
cachedMatches: [...s.cachedMatches, match]
|
|
3297
|
+
}));
|
|
3298
|
+
}
|
|
3299
|
+
});
|
|
3300
|
+
});
|
|
3301
|
+
try {
|
|
3302
|
+
matches = await loadMatches({
|
|
3303
|
+
router: this,
|
|
3304
|
+
matches,
|
|
3305
|
+
location: next,
|
|
3306
|
+
preload: true,
|
|
3307
|
+
updateMatch: (id, updater) => {
|
|
3308
|
+
if (activeMatchIds.has(id)) {
|
|
3309
|
+
matches = matches.map((d) => d.id === id ? updater(d) : d);
|
|
3310
|
+
} else {
|
|
3311
|
+
this.updateMatch(id, updater);
|
|
3312
|
+
}
|
|
3313
|
+
}
|
|
3314
|
+
});
|
|
3315
|
+
return matches;
|
|
3316
|
+
} catch (err) {
|
|
3317
|
+
if (isRedirect(err)) {
|
|
3318
|
+
if (err.options.reloadDocument) {
|
|
3319
|
+
return void 0;
|
|
3320
|
+
}
|
|
3321
|
+
return await this.preloadRoute({
|
|
3322
|
+
...err.options,
|
|
3323
|
+
_fromLocation: next
|
|
3324
|
+
});
|
|
3325
|
+
}
|
|
3326
|
+
if (!isNotFound(err)) {
|
|
3327
|
+
console.error(err);
|
|
3328
|
+
}
|
|
3329
|
+
return void 0;
|
|
3330
|
+
}
|
|
3331
|
+
};
|
|
3332
|
+
this.matchRoute = (location, opts) => {
|
|
3333
|
+
const matchLocation = {
|
|
3334
|
+
...location,
|
|
3335
|
+
to: location.to ? this.resolvePathWithBase(
|
|
3336
|
+
location.from || "",
|
|
3337
|
+
location.to
|
|
3338
|
+
) : void 0,
|
|
3339
|
+
params: location.params || {},
|
|
3340
|
+
leaveParams: true
|
|
3341
|
+
};
|
|
3342
|
+
const next = this.buildLocation(matchLocation);
|
|
3343
|
+
if (opts?.pending && this.state.status !== "pending") {
|
|
3344
|
+
return false;
|
|
3345
|
+
}
|
|
3346
|
+
const pending = opts?.pending === void 0 ? !this.state.isLoading : opts.pending;
|
|
3347
|
+
const baseLocation = pending ? this.latestLocation : this.state.resolvedLocation || this.state.location;
|
|
3348
|
+
const match = findSingleMatch(
|
|
3349
|
+
next.pathname,
|
|
3350
|
+
opts?.caseSensitive ?? false,
|
|
3351
|
+
opts?.fuzzy ?? false,
|
|
3352
|
+
baseLocation.pathname,
|
|
3353
|
+
this.processedTree
|
|
3354
|
+
);
|
|
3355
|
+
if (!match) {
|
|
3356
|
+
return false;
|
|
3357
|
+
}
|
|
3358
|
+
if (location.params) {
|
|
3359
|
+
if (!deepEqual(match.rawParams, location.params, { partial: true })) {
|
|
3360
|
+
return false;
|
|
3361
|
+
}
|
|
3362
|
+
}
|
|
3363
|
+
if (opts?.includeSearch ?? true) {
|
|
3364
|
+
return deepEqual(baseLocation.search, next.search, { partial: true }) ? match.rawParams : false;
|
|
3365
|
+
}
|
|
3366
|
+
return match.rawParams;
|
|
3367
|
+
};
|
|
3368
|
+
this.hasNotFoundMatch = () => {
|
|
3369
|
+
return this.__store.state.matches.some(
|
|
3370
|
+
(d) => d.status === "notFound" || d.globalNotFound
|
|
3371
|
+
);
|
|
3372
|
+
};
|
|
3373
|
+
this.sessionId = typeof crypto !== "undefined" && "randomUUID" in crypto ? crypto.randomUUID() : `${Date.now()}-${Math.random().toString(36).slice(2)}`;
|
|
3374
|
+
this.update({
|
|
3375
|
+
defaultPreloadDelay: 50,
|
|
3376
|
+
defaultPendingMs: 1e3,
|
|
3377
|
+
defaultPendingMinMs: 500,
|
|
3378
|
+
context: void 0,
|
|
3379
|
+
...options,
|
|
3380
|
+
caseSensitive: options.caseSensitive ?? false,
|
|
3381
|
+
notFoundMode: options.notFoundMode ?? "fuzzy",
|
|
3382
|
+
stringifySearch: options.stringifySearch ?? defaultStringifySearch,
|
|
3383
|
+
parseSearch: options.parseSearch ?? defaultParseSearch
|
|
3384
|
+
});
|
|
3385
|
+
if (typeof document !== "undefined") {
|
|
3386
|
+
self.__TSR_ROUTER__ = this;
|
|
3387
|
+
}
|
|
3388
|
+
}
|
|
3389
|
+
isShell() {
|
|
3390
|
+
return !!this.options.isShell;
|
|
3391
|
+
}
|
|
3392
|
+
isPrerendering() {
|
|
3393
|
+
return !!this.options.isPrerendering;
|
|
3394
|
+
}
|
|
3395
|
+
get state() {
|
|
3396
|
+
return this.__store.state;
|
|
3397
|
+
}
|
|
3398
|
+
get looseRoutesById() {
|
|
3399
|
+
return this.routesById;
|
|
3400
|
+
}
|
|
3401
|
+
matchRoutesInternal(next, opts) {
|
|
3402
|
+
const snapshot = opts?.snapshot;
|
|
3403
|
+
const snapshotValid = snapshot && snapshot.routeIds.length > 0 && snapshot.routeIds.every((id) => this.routesById[id]);
|
|
3404
|
+
let matchedRoutes;
|
|
3405
|
+
let routeParams;
|
|
3406
|
+
let rawParams;
|
|
3407
|
+
let globalNotFoundRouteId;
|
|
3408
|
+
let parsedParams;
|
|
3409
|
+
if (snapshotValid) {
|
|
3410
|
+
matchedRoutes = snapshot.routeIds.map((id) => this.routesById[id]);
|
|
3411
|
+
routeParams = { ...snapshot.params };
|
|
3412
|
+
rawParams = { ...snapshot.params };
|
|
3413
|
+
globalNotFoundRouteId = snapshot.globalNotFoundRouteId;
|
|
3414
|
+
parsedParams = snapshot.parsedParams;
|
|
3415
|
+
} else {
|
|
3416
|
+
const matchedRoutesResult = this.getMatchedRoutes(next.pathname);
|
|
3417
|
+
const { foundRoute, routeParams: rp } = matchedRoutesResult;
|
|
3418
|
+
routeParams = rp;
|
|
3419
|
+
rawParams = { ...rp };
|
|
3420
|
+
matchedRoutes = matchedRoutesResult.matchedRoutes;
|
|
3421
|
+
parsedParams = matchedRoutesResult.parsedParams;
|
|
3422
|
+
let isGlobalNotFound = false;
|
|
3423
|
+
if (
|
|
3424
|
+
// If we found a route, and it's not an index route and we have left over path
|
|
3425
|
+
foundRoute ? foundRoute.path !== "/" && routeParams["**"] : (
|
|
3426
|
+
// Or if we didn't find a route and we have left over path
|
|
3427
|
+
trimPathRight(next.pathname)
|
|
3428
|
+
)
|
|
3429
|
+
) {
|
|
3430
|
+
if (this.options.notFoundRoute) {
|
|
3431
|
+
matchedRoutes = [...matchedRoutes, this.options.notFoundRoute];
|
|
3432
|
+
} else {
|
|
3433
|
+
isGlobalNotFound = true;
|
|
3434
|
+
}
|
|
3435
|
+
}
|
|
3436
|
+
globalNotFoundRouteId = isGlobalNotFound ? findGlobalNotFoundRouteId(this.options.notFoundMode, matchedRoutes) : void 0;
|
|
3437
|
+
}
|
|
3438
|
+
const matches = [];
|
|
3439
|
+
const getParentContext = (parentMatch) => {
|
|
3440
|
+
const parentMatchId = parentMatch?.id;
|
|
3441
|
+
const parentContext = !parentMatchId ? this.options.context ?? void 0 : parentMatch.context ?? this.options.context ?? void 0;
|
|
3442
|
+
return parentContext;
|
|
3443
|
+
};
|
|
3444
|
+
const canUseCachedSearch = snapshotValid && snapshot.searchStr === next.searchStr && snapshot.validatedSearches?.length === matchedRoutes.length;
|
|
3445
|
+
const validatedSearchesToCache = [];
|
|
3446
|
+
matchedRoutes.forEach((route, index) => {
|
|
3447
|
+
const parentMatch = matches[index - 1];
|
|
3448
|
+
const [preMatchSearch, strictMatchSearch, searchError] = (() => {
|
|
3449
|
+
if (canUseCachedSearch) {
|
|
3450
|
+
const cached = snapshot.validatedSearches[index];
|
|
3451
|
+
return [cached.search, cached.strictSearch, void 0];
|
|
3452
|
+
}
|
|
3453
|
+
const parentSearch = parentMatch?.search ?? next.search;
|
|
3454
|
+
const parentStrictSearch = parentMatch?._strictSearch ?? void 0;
|
|
3455
|
+
try {
|
|
3456
|
+
const strictSearch = validateSearch(route.options.validateSearch, { ...parentSearch }) ?? void 0;
|
|
3457
|
+
return [
|
|
3458
|
+
{
|
|
3459
|
+
...parentSearch,
|
|
3460
|
+
...strictSearch
|
|
3461
|
+
},
|
|
3462
|
+
{ ...parentStrictSearch, ...strictSearch },
|
|
3463
|
+
void 0
|
|
3464
|
+
];
|
|
3465
|
+
} catch (err) {
|
|
3466
|
+
let searchParamError = err;
|
|
3467
|
+
if (!(err instanceof SearchParamError)) {
|
|
3468
|
+
searchParamError = new SearchParamError(err.message, {
|
|
3469
|
+
cause: err
|
|
3470
|
+
});
|
|
3471
|
+
}
|
|
3472
|
+
if (opts?.throwOnError) {
|
|
3473
|
+
throw searchParamError;
|
|
3474
|
+
}
|
|
3475
|
+
return [parentSearch, {}, searchParamError];
|
|
3476
|
+
}
|
|
3477
|
+
})();
|
|
3478
|
+
if (!canUseCachedSearch) {
|
|
3479
|
+
validatedSearchesToCache.push({
|
|
3480
|
+
search: preMatchSearch,
|
|
3481
|
+
strictSearch: strictMatchSearch
|
|
3482
|
+
});
|
|
3483
|
+
}
|
|
3484
|
+
const loaderDeps = route.options.loaderDeps?.({
|
|
3485
|
+
search: preMatchSearch
|
|
3486
|
+
}) ?? "";
|
|
3487
|
+
const loaderDepsHash = loaderDeps ? JSON.stringify(loaderDeps) : "";
|
|
3488
|
+
const { interpolatedPath, usedParams } = interpolatePath({
|
|
3489
|
+
path: route.fullPath,
|
|
3490
|
+
params: routeParams,
|
|
3491
|
+
decodeCharMap: this.pathParamsDecodeCharMap
|
|
3492
|
+
});
|
|
3493
|
+
const matchId = (
|
|
3494
|
+
// route.id for disambiguation
|
|
3495
|
+
route.id + // interpolatedPath for param changes
|
|
3496
|
+
interpolatedPath + // explicit deps
|
|
3497
|
+
loaderDepsHash
|
|
3498
|
+
);
|
|
3499
|
+
const existingMatch = this.getMatch(matchId);
|
|
3500
|
+
const previousMatch = this.state.matches.find(
|
|
3501
|
+
(d) => d.routeId === route.id
|
|
3502
|
+
);
|
|
3503
|
+
const strictParams = existingMatch?._strictParams ?? usedParams;
|
|
3504
|
+
let paramsError = void 0;
|
|
3505
|
+
if (!existingMatch) {
|
|
3506
|
+
if (route.options.skipRouteOnParseError) {
|
|
3507
|
+
for (const key in usedParams) {
|
|
3508
|
+
if (key in parsedParams) {
|
|
3509
|
+
strictParams[key] = parsedParams[key];
|
|
3510
|
+
}
|
|
3511
|
+
}
|
|
3512
|
+
} else {
|
|
3513
|
+
const strictParseParams = route.options.params?.parse ?? route.options.parseParams;
|
|
3514
|
+
if (strictParseParams) {
|
|
3515
|
+
try {
|
|
3516
|
+
Object.assign(
|
|
3517
|
+
strictParams,
|
|
3518
|
+
strictParseParams(strictParams)
|
|
3519
|
+
);
|
|
3520
|
+
} catch (err) {
|
|
3521
|
+
if (isNotFound(err) || isRedirect(err)) {
|
|
3522
|
+
paramsError = err;
|
|
3523
|
+
} else {
|
|
3524
|
+
paramsError = new PathParamError(err.message, {
|
|
3525
|
+
cause: err
|
|
3526
|
+
});
|
|
3527
|
+
}
|
|
3528
|
+
if (opts?.throwOnError) {
|
|
3529
|
+
throw paramsError;
|
|
3530
|
+
}
|
|
3531
|
+
}
|
|
3532
|
+
}
|
|
3533
|
+
}
|
|
3534
|
+
}
|
|
3535
|
+
Object.assign(routeParams, strictParams);
|
|
3536
|
+
const cause = previousMatch ? "stay" : "enter";
|
|
3537
|
+
let match;
|
|
3538
|
+
if (existingMatch) {
|
|
3539
|
+
match = {
|
|
3540
|
+
...existingMatch,
|
|
3541
|
+
cause,
|
|
3542
|
+
params: previousMatch ? replaceEqualDeep(previousMatch.params, routeParams) : routeParams,
|
|
3543
|
+
_strictParams: strictParams,
|
|
3544
|
+
search: previousMatch ? replaceEqualDeep(previousMatch.search, preMatchSearch) : replaceEqualDeep(existingMatch.search, preMatchSearch),
|
|
3545
|
+
_strictSearch: strictMatchSearch
|
|
3546
|
+
};
|
|
3547
|
+
} else {
|
|
3548
|
+
const status = route.options.loader || route.options.beforeLoad || route.lazyFn || routeNeedsPreload(route) ? "pending" : "success";
|
|
3549
|
+
match = {
|
|
3550
|
+
id: matchId,
|
|
3551
|
+
ssr: this.isServer ? void 0 : route.options.ssr,
|
|
3552
|
+
index,
|
|
3553
|
+
routeId: route.id,
|
|
3554
|
+
params: previousMatch ? replaceEqualDeep(previousMatch.params, routeParams) : routeParams,
|
|
3555
|
+
_strictParams: strictParams,
|
|
3556
|
+
pathname: interpolatedPath,
|
|
3557
|
+
updatedAt: Date.now(),
|
|
3558
|
+
search: previousMatch ? replaceEqualDeep(previousMatch.search, preMatchSearch) : preMatchSearch,
|
|
3559
|
+
_strictSearch: strictMatchSearch,
|
|
3560
|
+
searchError: void 0,
|
|
3561
|
+
status,
|
|
3562
|
+
isFetching: false,
|
|
3563
|
+
error: void 0,
|
|
3564
|
+
paramsError,
|
|
3565
|
+
__routeContext: void 0,
|
|
3566
|
+
_nonReactive: {
|
|
3567
|
+
loadPromise: createControlledPromise()
|
|
3568
|
+
},
|
|
3569
|
+
__beforeLoadContext: void 0,
|
|
3570
|
+
context: {},
|
|
3571
|
+
abortController: new AbortController(),
|
|
3572
|
+
fetchCount: 0,
|
|
3573
|
+
cause,
|
|
3574
|
+
loaderDeps: previousMatch ? replaceEqualDeep(previousMatch.loaderDeps, loaderDeps) : loaderDeps,
|
|
3575
|
+
invalid: false,
|
|
3576
|
+
preload: false,
|
|
3577
|
+
links: void 0,
|
|
3578
|
+
scripts: void 0,
|
|
3579
|
+
headScripts: void 0,
|
|
3580
|
+
meta: void 0,
|
|
3581
|
+
staticData: route.options.staticData || {},
|
|
3582
|
+
fullPath: route.fullPath
|
|
3583
|
+
};
|
|
3584
|
+
}
|
|
3585
|
+
if (!opts?.preload) {
|
|
3586
|
+
match.globalNotFound = globalNotFoundRouteId === route.id;
|
|
3587
|
+
}
|
|
3588
|
+
match.searchError = searchError;
|
|
3589
|
+
const parentContext = getParentContext(parentMatch);
|
|
3590
|
+
match.context = {
|
|
3591
|
+
...parentContext,
|
|
3592
|
+
...match.__routeContext,
|
|
3593
|
+
...match.__beforeLoadContext
|
|
3594
|
+
};
|
|
3595
|
+
matches.push(match);
|
|
3596
|
+
});
|
|
3597
|
+
if (!canUseCachedSearch && validatedSearchesToCache.length > 0) {
|
|
3598
|
+
const existingSnapshot = next.state?.__TSR_matches;
|
|
3599
|
+
if (existingSnapshot) {
|
|
3600
|
+
existingSnapshot.searchStr = next.searchStr;
|
|
3601
|
+
existingSnapshot.validatedSearches = validatedSearchesToCache;
|
|
3602
|
+
}
|
|
3603
|
+
}
|
|
3604
|
+
matches.forEach((match, index) => {
|
|
3605
|
+
const route = this.looseRoutesById[match.routeId];
|
|
3606
|
+
const existingMatch = this.getMatch(match.id);
|
|
3607
|
+
if (!existingMatch && opts?._buildLocation !== true) {
|
|
3608
|
+
const parentMatch = matches[index - 1];
|
|
3609
|
+
const parentContext = getParentContext(parentMatch);
|
|
3610
|
+
if (route.options.context) {
|
|
3611
|
+
const contextFnContext = {
|
|
3612
|
+
deps: match.loaderDeps,
|
|
3613
|
+
params: match.params,
|
|
3614
|
+
context: parentContext ?? {},
|
|
3615
|
+
location: next,
|
|
3616
|
+
navigate: (opts2) => this.navigate({ ...opts2, _fromLocation: next }),
|
|
3617
|
+
buildLocation: this.buildLocation,
|
|
3618
|
+
cause: match.cause,
|
|
3619
|
+
abortController: match.abortController,
|
|
3620
|
+
preload: !!match.preload,
|
|
3621
|
+
matches
|
|
3622
|
+
};
|
|
3623
|
+
match.__routeContext = route.options.context(contextFnContext) ?? void 0;
|
|
3624
|
+
}
|
|
3625
|
+
match.context = {
|
|
3626
|
+
...parentContext,
|
|
3627
|
+
...match.__routeContext,
|
|
3628
|
+
...match.__beforeLoadContext
|
|
3629
|
+
};
|
|
3630
|
+
}
|
|
3631
|
+
});
|
|
3632
|
+
return { matches, rawParams };
|
|
3633
|
+
}
|
|
3634
|
+
}
|
|
3635
|
+
class SearchParamError extends Error {
|
|
3636
|
+
}
|
|
3637
|
+
class PathParamError extends Error {
|
|
3638
|
+
}
|
|
3639
|
+
function getInitialRouterState(location) {
|
|
3640
|
+
return {
|
|
3641
|
+
loadedAt: 0,
|
|
3642
|
+
isLoading: false,
|
|
3643
|
+
isTransitioning: false,
|
|
3644
|
+
status: "idle",
|
|
3645
|
+
resolvedLocation: void 0,
|
|
3646
|
+
location,
|
|
3647
|
+
matches: [],
|
|
3648
|
+
pendingMatches: [],
|
|
3649
|
+
cachedMatches: [],
|
|
3650
|
+
statusCode: 200
|
|
3651
|
+
};
|
|
3652
|
+
}
|
|
3653
|
+
function validateSearch(validateSearch2, input) {
|
|
3654
|
+
if (validateSearch2 == null) return {};
|
|
3655
|
+
if ("~standard" in validateSearch2) {
|
|
3656
|
+
const result = validateSearch2["~standard"].validate(input);
|
|
3657
|
+
if (result instanceof Promise)
|
|
3658
|
+
throw new SearchParamError("Async validation not supported");
|
|
3659
|
+
if (result.issues)
|
|
3660
|
+
throw new SearchParamError(JSON.stringify(result.issues, void 0, 2), {
|
|
3661
|
+
cause: result
|
|
3662
|
+
});
|
|
3663
|
+
return result.value;
|
|
3664
|
+
}
|
|
3665
|
+
if ("parse" in validateSearch2) {
|
|
3666
|
+
return validateSearch2.parse(input);
|
|
3667
|
+
}
|
|
3668
|
+
if (typeof validateSearch2 === "function") {
|
|
3669
|
+
return validateSearch2(input);
|
|
3670
|
+
}
|
|
3671
|
+
return {};
|
|
3672
|
+
}
|
|
3673
|
+
function getMatchedRoutes({
|
|
3674
|
+
pathname,
|
|
3675
|
+
routesById,
|
|
3676
|
+
processedTree
|
|
3677
|
+
}) {
|
|
3678
|
+
const routeParams = {};
|
|
3679
|
+
const trimmedPath = trimPathRight(pathname);
|
|
3680
|
+
let foundRoute = void 0;
|
|
3681
|
+
let parsedParams = {};
|
|
3682
|
+
const match = findRouteMatch(trimmedPath, processedTree, true);
|
|
3683
|
+
if (match) {
|
|
3684
|
+
foundRoute = match.route;
|
|
3685
|
+
Object.assign(routeParams, match.rawParams);
|
|
3686
|
+
parsedParams = Object.assign({}, match.parsedParams);
|
|
3687
|
+
}
|
|
3688
|
+
const matchedRoutes = match?.branch || [routesById[rootRouteId]];
|
|
3689
|
+
return { matchedRoutes, routeParams, foundRoute, parsedParams };
|
|
3690
|
+
}
|
|
3691
|
+
function buildMatchSnapshot({
|
|
3692
|
+
matchResult,
|
|
3693
|
+
pathname,
|
|
3694
|
+
searchStr,
|
|
3695
|
+
notFoundRoute,
|
|
3696
|
+
notFoundMode
|
|
3697
|
+
}) {
|
|
3698
|
+
const snapshot = {
|
|
3699
|
+
routeIds: matchResult.matchedRoutes.map((r) => r.id),
|
|
3700
|
+
params: matchResult.routeParams,
|
|
3701
|
+
parsedParams: matchResult.parsedParams,
|
|
3702
|
+
searchStr
|
|
3703
|
+
};
|
|
3704
|
+
const isGlobalNotFound = matchResult.foundRoute ? matchResult.foundRoute.path !== "/" && matchResult.routeParams["**"] : trimPathRight(pathname);
|
|
3705
|
+
if (isGlobalNotFound) {
|
|
3706
|
+
if (notFoundRoute) {
|
|
3707
|
+
snapshot.globalNotFoundRouteId = notFoundRoute.id;
|
|
3708
|
+
} else {
|
|
3709
|
+
if (notFoundMode !== "root") {
|
|
3710
|
+
for (let i = matchResult.matchedRoutes.length - 1; i >= 0; i--) {
|
|
3711
|
+
const route = matchResult.matchedRoutes[i];
|
|
3712
|
+
if (route.children) {
|
|
3713
|
+
snapshot.globalNotFoundRouteId = route.id;
|
|
3714
|
+
break;
|
|
3715
|
+
}
|
|
3716
|
+
}
|
|
3717
|
+
}
|
|
3718
|
+
if (!snapshot.globalNotFoundRouteId) {
|
|
3719
|
+
snapshot.globalNotFoundRouteId = rootRouteId;
|
|
3720
|
+
}
|
|
3721
|
+
}
|
|
3722
|
+
}
|
|
3723
|
+
return snapshot;
|
|
3724
|
+
}
|
|
3725
|
+
function buildMatchSnapshotFromRoutes({
|
|
3726
|
+
routes,
|
|
3727
|
+
params,
|
|
3728
|
+
searchStr,
|
|
3729
|
+
globalNotFoundRouteId
|
|
3730
|
+
}) {
|
|
3731
|
+
const stringParams = {};
|
|
3732
|
+
for (const key in params) {
|
|
3733
|
+
const value = params[key];
|
|
3734
|
+
if (value != null) {
|
|
3735
|
+
stringParams[key] = String(value);
|
|
3736
|
+
}
|
|
3737
|
+
}
|
|
3738
|
+
const snapshot = {
|
|
3739
|
+
routeIds: routes.map((r) => r.id),
|
|
3740
|
+
params: stringParams,
|
|
3741
|
+
parsedParams: params,
|
|
3742
|
+
searchStr
|
|
3743
|
+
};
|
|
3744
|
+
if (globalNotFoundRouteId) {
|
|
3745
|
+
snapshot.globalNotFoundRouteId = globalNotFoundRouteId;
|
|
3746
|
+
}
|
|
3747
|
+
return snapshot;
|
|
3748
|
+
}
|
|
3749
|
+
function applySearchMiddleware({
|
|
3750
|
+
search,
|
|
3751
|
+
dest,
|
|
3752
|
+
destRoutes,
|
|
3753
|
+
_includeValidateSearch
|
|
3754
|
+
}) {
|
|
3755
|
+
const middleware = buildMiddlewareChain(destRoutes);
|
|
3756
|
+
return middleware(search, dest, _includeValidateSearch ?? false);
|
|
3757
|
+
}
|
|
3758
|
+
function buildMiddlewareChain(destRoutes) {
|
|
3759
|
+
const context = {
|
|
3760
|
+
dest: null,
|
|
3761
|
+
_includeValidateSearch: false,
|
|
3762
|
+
middlewares: []
|
|
3763
|
+
};
|
|
3764
|
+
for (const route of destRoutes) {
|
|
3765
|
+
if ("search" in route.options) {
|
|
3766
|
+
if (route.options.search?.middlewares) {
|
|
3767
|
+
context.middlewares.push(...route.options.search.middlewares);
|
|
3768
|
+
}
|
|
3769
|
+
} else if (route.options.preSearchFilters || route.options.postSearchFilters) {
|
|
3770
|
+
const legacyMiddleware = ({ search, next }) => {
|
|
3771
|
+
let nextSearch = search;
|
|
3772
|
+
if ("preSearchFilters" in route.options && route.options.preSearchFilters) {
|
|
3773
|
+
nextSearch = route.options.preSearchFilters.reduce(
|
|
3774
|
+
(prev, next2) => next2(prev),
|
|
3775
|
+
search
|
|
3776
|
+
);
|
|
3777
|
+
}
|
|
3778
|
+
const result = next(nextSearch);
|
|
3779
|
+
if ("postSearchFilters" in route.options && route.options.postSearchFilters) {
|
|
3780
|
+
return route.options.postSearchFilters.reduce(
|
|
3781
|
+
(prev, next2) => next2(prev),
|
|
3782
|
+
result
|
|
3783
|
+
);
|
|
3784
|
+
}
|
|
3785
|
+
return result;
|
|
3786
|
+
};
|
|
3787
|
+
context.middlewares.push(legacyMiddleware);
|
|
3788
|
+
}
|
|
3789
|
+
if (route.options.validateSearch) {
|
|
3790
|
+
const validate = ({ search, next }) => {
|
|
3791
|
+
const result = next(search);
|
|
3792
|
+
if (!context._includeValidateSearch) return result;
|
|
3793
|
+
try {
|
|
3794
|
+
const validatedSearch = {
|
|
3795
|
+
...result,
|
|
3796
|
+
...validateSearch(route.options.validateSearch, result) ?? void 0
|
|
3797
|
+
};
|
|
3798
|
+
return validatedSearch;
|
|
3799
|
+
} catch {
|
|
3800
|
+
return result;
|
|
3801
|
+
}
|
|
3802
|
+
};
|
|
3803
|
+
context.middlewares.push(validate);
|
|
3804
|
+
}
|
|
3805
|
+
}
|
|
3806
|
+
const final = ({ search }) => {
|
|
3807
|
+
const dest = context.dest;
|
|
3808
|
+
if (!dest.search) {
|
|
3809
|
+
return {};
|
|
3810
|
+
}
|
|
3811
|
+
if (dest.search === true) {
|
|
3812
|
+
return search;
|
|
3813
|
+
}
|
|
3814
|
+
return functionalUpdate(dest.search, search);
|
|
3815
|
+
};
|
|
3816
|
+
context.middlewares.push(final);
|
|
3817
|
+
const applyNext = (index, currentSearch, middlewares) => {
|
|
3818
|
+
if (index >= middlewares.length) {
|
|
3819
|
+
return currentSearch;
|
|
3820
|
+
}
|
|
3821
|
+
const middleware = middlewares[index];
|
|
3822
|
+
const next = (newSearch) => {
|
|
3823
|
+
return applyNext(index + 1, newSearch, middlewares);
|
|
3824
|
+
};
|
|
3825
|
+
return middleware({ search: currentSearch, next });
|
|
3826
|
+
};
|
|
3827
|
+
return function middleware(search, dest, _includeValidateSearch) {
|
|
3828
|
+
context.dest = dest;
|
|
3829
|
+
context._includeValidateSearch = _includeValidateSearch;
|
|
3830
|
+
return applyNext(0, search, context.middlewares);
|
|
3831
|
+
};
|
|
3832
|
+
}
|
|
3833
|
+
function findGlobalNotFoundRouteId(notFoundMode, routes) {
|
|
3834
|
+
if (notFoundMode !== "root") {
|
|
3835
|
+
for (let i = routes.length - 1; i >= 0; i--) {
|
|
3836
|
+
const route = routes[i];
|
|
3837
|
+
if (route.children) {
|
|
3838
|
+
return route.id;
|
|
3839
|
+
}
|
|
3840
|
+
}
|
|
3841
|
+
}
|
|
3842
|
+
return rootRouteId;
|
|
3843
|
+
}
|
|
3844
|
+
const preloadWarning = "Error preloading route! ☝️";
|
|
3845
|
+
class BaseRoute {
|
|
3846
|
+
constructor(options) {
|
|
3847
|
+
this.init = (opts) => {
|
|
3848
|
+
this.originalIndex = opts.originalIndex;
|
|
3849
|
+
const options2 = this.options;
|
|
3850
|
+
const isRoot = !options2?.path && !options2?.id;
|
|
3851
|
+
this.parentRoute = this.options.getParentRoute?.();
|
|
3852
|
+
if (isRoot) {
|
|
3853
|
+
this._path = rootRouteId;
|
|
3854
|
+
} else if (!this.parentRoute) {
|
|
3855
|
+
invariant(
|
|
3856
|
+
false
|
|
3857
|
+
);
|
|
3858
|
+
}
|
|
3859
|
+
let path = isRoot ? rootRouteId : options2?.path;
|
|
3860
|
+
if (path && path !== "/") {
|
|
3861
|
+
path = trimPathLeft(path);
|
|
3862
|
+
}
|
|
3863
|
+
const customId = options2?.id || path;
|
|
3864
|
+
let id = isRoot ? rootRouteId : joinPaths([
|
|
3865
|
+
this.parentRoute.id === rootRouteId ? "" : this.parentRoute.id,
|
|
3866
|
+
customId
|
|
3867
|
+
]);
|
|
3868
|
+
if (path === rootRouteId) {
|
|
3869
|
+
path = "/";
|
|
3870
|
+
}
|
|
3871
|
+
if (id !== rootRouteId) {
|
|
3872
|
+
id = joinPaths(["/", id]);
|
|
3873
|
+
}
|
|
3874
|
+
const fullPath = id === rootRouteId ? "/" : joinPaths([this.parentRoute.fullPath, path]);
|
|
3875
|
+
this._path = path;
|
|
3876
|
+
this._id = id;
|
|
3877
|
+
this._fullPath = fullPath;
|
|
3878
|
+
this._to = trimPathRight(fullPath);
|
|
3879
|
+
};
|
|
3880
|
+
this.addChildren = (children) => {
|
|
3881
|
+
return this._addFileChildren(children);
|
|
3882
|
+
};
|
|
3883
|
+
this._addFileChildren = (children) => {
|
|
3884
|
+
if (Array.isArray(children)) {
|
|
3885
|
+
this.children = children;
|
|
3886
|
+
}
|
|
3887
|
+
if (typeof children === "object" && children !== null) {
|
|
3888
|
+
this.children = Object.values(children);
|
|
3889
|
+
}
|
|
3890
|
+
return this;
|
|
3891
|
+
};
|
|
3892
|
+
this._addFileTypes = () => {
|
|
3893
|
+
return this;
|
|
3894
|
+
};
|
|
3895
|
+
this.updateLoader = (options2) => {
|
|
3896
|
+
Object.assign(this.options, options2);
|
|
3897
|
+
return this;
|
|
3898
|
+
};
|
|
3899
|
+
this.update = (options2) => {
|
|
3900
|
+
Object.assign(this.options, options2);
|
|
3901
|
+
return this;
|
|
3902
|
+
};
|
|
3903
|
+
this.lazy = (lazyFn) => {
|
|
3904
|
+
this.lazyFn = lazyFn;
|
|
3905
|
+
return this;
|
|
3906
|
+
};
|
|
3907
|
+
this.redirect = (opts) => redirect({ from: this.fullPath, ...opts });
|
|
3908
|
+
this.options = options || {};
|
|
3909
|
+
this.isRoot = !options?.getParentRoute;
|
|
3910
|
+
if (options?.id && options?.path) {
|
|
3911
|
+
throw new Error(`Route cannot have both an 'id' and a 'path' option.`);
|
|
3912
|
+
}
|
|
3913
|
+
}
|
|
3914
|
+
get to() {
|
|
3915
|
+
return this._to;
|
|
3916
|
+
}
|
|
3917
|
+
get id() {
|
|
3918
|
+
return this._id;
|
|
3919
|
+
}
|
|
3920
|
+
get path() {
|
|
3921
|
+
return this._path;
|
|
3922
|
+
}
|
|
3923
|
+
get fullPath() {
|
|
3924
|
+
return this._fullPath;
|
|
3925
|
+
}
|
|
3926
|
+
}
|
|
3927
|
+
class BaseRootRoute extends BaseRoute {
|
|
3928
|
+
constructor(options) {
|
|
3929
|
+
super(options);
|
|
3930
|
+
}
|
|
3931
|
+
}
|
|
3932
|
+
const GLOBAL_TSR = "$_TSR";
|
|
3933
|
+
const TSR_SCRIPT_BARRIER_ID = "$tsr-stream-barrier";
|
|
3934
|
+
function createSerializationAdapter(opts) {
|
|
3935
|
+
return opts;
|
|
3936
|
+
}
|
|
3937
|
+
function makeSsrSerovalPlugin(serializationAdapter, options) {
|
|
3938
|
+
return ni({
|
|
3939
|
+
tag: "$TSR/t/" + serializationAdapter.key,
|
|
3940
|
+
test: serializationAdapter.test,
|
|
3941
|
+
parse: {
|
|
3942
|
+
stream(value, ctx) {
|
|
3943
|
+
return ctx.parse(serializationAdapter.toSerializable(value));
|
|
3944
|
+
}
|
|
3945
|
+
},
|
|
3946
|
+
serialize(node, ctx) {
|
|
3947
|
+
options.didRun = true;
|
|
3948
|
+
return GLOBAL_TSR + '.t.get("' + serializationAdapter.key + '")(' + ctx.serialize(node) + ")";
|
|
3949
|
+
},
|
|
3950
|
+
// we never deserialize on the server during SSR
|
|
3951
|
+
deserialize: void 0
|
|
3952
|
+
});
|
|
3953
|
+
}
|
|
3954
|
+
function makeSerovalPlugin(serializationAdapter) {
|
|
3955
|
+
return ni({
|
|
3956
|
+
tag: "$TSR/t/" + serializationAdapter.key,
|
|
3957
|
+
test: serializationAdapter.test,
|
|
3958
|
+
parse: {
|
|
3959
|
+
sync(value, ctx) {
|
|
3960
|
+
return ctx.parse(serializationAdapter.toSerializable(value));
|
|
3961
|
+
},
|
|
3962
|
+
async async(value, ctx) {
|
|
3963
|
+
return await ctx.parse(serializationAdapter.toSerializable(value));
|
|
3964
|
+
},
|
|
3965
|
+
stream(value, ctx) {
|
|
3966
|
+
return ctx.parse(serializationAdapter.toSerializable(value));
|
|
3967
|
+
}
|
|
3968
|
+
},
|
|
3969
|
+
// we don't generate JS code outside of SSR (for now)
|
|
3970
|
+
serialize: void 0,
|
|
3971
|
+
deserialize(node, ctx) {
|
|
3972
|
+
return serializationAdapter.fromSerializable(ctx.deserialize(node));
|
|
3973
|
+
}
|
|
3974
|
+
});
|
|
3975
|
+
}
|
|
3976
|
+
const ShallowErrorPlugin = /* @__PURE__ */ ni({
|
|
3977
|
+
tag: "$TSR/Error",
|
|
3978
|
+
test(value) {
|
|
3979
|
+
return value instanceof Error;
|
|
3980
|
+
},
|
|
3981
|
+
parse: {
|
|
3982
|
+
sync(value, ctx) {
|
|
3983
|
+
return {
|
|
3984
|
+
message: ctx.parse(value.message)
|
|
3985
|
+
};
|
|
3986
|
+
},
|
|
3987
|
+
async async(value, ctx) {
|
|
3988
|
+
return {
|
|
3989
|
+
message: await ctx.parse(value.message)
|
|
3990
|
+
};
|
|
3991
|
+
},
|
|
3992
|
+
stream(value, ctx) {
|
|
3993
|
+
return {
|
|
3994
|
+
message: ctx.parse(value.message)
|
|
3995
|
+
};
|
|
3996
|
+
}
|
|
3997
|
+
},
|
|
3998
|
+
serialize(node, ctx) {
|
|
3999
|
+
return "new Error(" + ctx.serialize(node.message) + ")";
|
|
4000
|
+
},
|
|
4001
|
+
deserialize(node, ctx) {
|
|
4002
|
+
return new Error(ctx.deserialize(node.message));
|
|
4003
|
+
}
|
|
4004
|
+
});
|
|
4005
|
+
class RawStream {
|
|
4006
|
+
constructor(stream, options) {
|
|
4007
|
+
this.stream = stream;
|
|
4008
|
+
this.hint = options?.hint ?? "binary";
|
|
4009
|
+
}
|
|
4010
|
+
}
|
|
4011
|
+
const BufferCtor = globalThis.Buffer;
|
|
4012
|
+
const hasNodeBuffer = !!BufferCtor && typeof BufferCtor.from === "function";
|
|
4013
|
+
function uint8ArrayToBase64(bytes) {
|
|
4014
|
+
if (bytes.length === 0) return "";
|
|
4015
|
+
if (hasNodeBuffer) {
|
|
4016
|
+
return BufferCtor.from(bytes).toString("base64");
|
|
4017
|
+
}
|
|
4018
|
+
const CHUNK_SIZE = 32768;
|
|
4019
|
+
const chunks = [];
|
|
4020
|
+
for (let i = 0; i < bytes.length; i += CHUNK_SIZE) {
|
|
4021
|
+
const chunk = bytes.subarray(i, i + CHUNK_SIZE);
|
|
4022
|
+
chunks.push(String.fromCharCode.apply(null, chunk));
|
|
4023
|
+
}
|
|
4024
|
+
return btoa(chunks.join(""));
|
|
4025
|
+
}
|
|
4026
|
+
function base64ToUint8Array(base64) {
|
|
4027
|
+
if (base64.length === 0) return new Uint8Array(0);
|
|
4028
|
+
if (hasNodeBuffer) {
|
|
4029
|
+
const buf = BufferCtor.from(base64, "base64");
|
|
4030
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
4031
|
+
}
|
|
4032
|
+
const binary = atob(base64);
|
|
4033
|
+
const bytes = new Uint8Array(binary.length);
|
|
4034
|
+
for (let i = 0; i < binary.length; i++) {
|
|
4035
|
+
bytes[i] = binary.charCodeAt(i);
|
|
4036
|
+
}
|
|
4037
|
+
return bytes;
|
|
4038
|
+
}
|
|
4039
|
+
const RAW_STREAM_FACTORY_BINARY = /* @__PURE__ */ Object.create(null);
|
|
4040
|
+
const RAW_STREAM_FACTORY_TEXT = /* @__PURE__ */ Object.create(null);
|
|
4041
|
+
const RAW_STREAM_FACTORY_CONSTRUCTOR_BINARY = (stream) => new ReadableStream({
|
|
4042
|
+
start(controller) {
|
|
4043
|
+
stream.on({
|
|
4044
|
+
next(base64) {
|
|
4045
|
+
try {
|
|
4046
|
+
controller.enqueue(base64ToUint8Array(base64));
|
|
4047
|
+
} catch {
|
|
4048
|
+
}
|
|
4049
|
+
},
|
|
4050
|
+
throw(error) {
|
|
4051
|
+
controller.error(error);
|
|
4052
|
+
},
|
|
4053
|
+
return() {
|
|
4054
|
+
try {
|
|
4055
|
+
controller.close();
|
|
4056
|
+
} catch {
|
|
4057
|
+
}
|
|
4058
|
+
}
|
|
4059
|
+
});
|
|
4060
|
+
}
|
|
4061
|
+
});
|
|
4062
|
+
const textEncoderForFactory = new TextEncoder();
|
|
4063
|
+
const RAW_STREAM_FACTORY_CONSTRUCTOR_TEXT = (stream) => {
|
|
4064
|
+
return new ReadableStream({
|
|
4065
|
+
start(controller) {
|
|
4066
|
+
stream.on({
|
|
4067
|
+
next(value) {
|
|
4068
|
+
try {
|
|
4069
|
+
if (typeof value === "string") {
|
|
4070
|
+
controller.enqueue(textEncoderForFactory.encode(value));
|
|
4071
|
+
} else {
|
|
4072
|
+
controller.enqueue(base64ToUint8Array(value.$b64));
|
|
4073
|
+
}
|
|
4074
|
+
} catch {
|
|
4075
|
+
}
|
|
4076
|
+
},
|
|
4077
|
+
throw(error) {
|
|
4078
|
+
controller.error(error);
|
|
4079
|
+
},
|
|
4080
|
+
return() {
|
|
4081
|
+
try {
|
|
4082
|
+
controller.close();
|
|
4083
|
+
} catch {
|
|
4084
|
+
}
|
|
4085
|
+
}
|
|
4086
|
+
});
|
|
4087
|
+
}
|
|
4088
|
+
});
|
|
4089
|
+
};
|
|
4090
|
+
const FACTORY_BINARY = `(s=>new ReadableStream({start(c){s.on({next(b){try{const d=atob(b),a=new Uint8Array(d.length);for(let i=0;i<d.length;i++)a[i]=d.charCodeAt(i);c.enqueue(a)}catch(_){}},throw(e){c.error(e)},return(){try{c.close()}catch(_){}}})}}))`;
|
|
4091
|
+
const FACTORY_TEXT = `(s=>{const e=new TextEncoder();return new ReadableStream({start(c){s.on({next(v){try{if(typeof v==='string'){c.enqueue(e.encode(v))}else{const d=atob(v.$b64),a=new Uint8Array(d.length);for(let i=0;i<d.length;i++)a[i]=d.charCodeAt(i);c.enqueue(a)}}catch(_){}},throw(x){c.error(x)},return(){try{c.close()}catch(_){}}})}})})`;
|
|
4092
|
+
function toBinaryStream(readable) {
|
|
4093
|
+
const stream = te();
|
|
4094
|
+
const reader = readable.getReader();
|
|
4095
|
+
(async () => {
|
|
4096
|
+
try {
|
|
4097
|
+
while (true) {
|
|
4098
|
+
const { done, value } = await reader.read();
|
|
4099
|
+
if (done) {
|
|
4100
|
+
stream.return(void 0);
|
|
4101
|
+
break;
|
|
4102
|
+
}
|
|
4103
|
+
stream.next(uint8ArrayToBase64(value));
|
|
4104
|
+
}
|
|
4105
|
+
} catch (error) {
|
|
4106
|
+
stream.throw(error);
|
|
4107
|
+
} finally {
|
|
4108
|
+
reader.releaseLock();
|
|
4109
|
+
}
|
|
4110
|
+
})();
|
|
4111
|
+
return stream;
|
|
4112
|
+
}
|
|
4113
|
+
function toTextStream(readable) {
|
|
4114
|
+
const stream = te();
|
|
4115
|
+
const reader = readable.getReader();
|
|
4116
|
+
const decoder = new TextDecoder("utf-8", { fatal: true });
|
|
4117
|
+
(async () => {
|
|
4118
|
+
try {
|
|
4119
|
+
while (true) {
|
|
4120
|
+
const { done, value } = await reader.read();
|
|
4121
|
+
if (done) {
|
|
4122
|
+
try {
|
|
4123
|
+
const remaining = decoder.decode();
|
|
4124
|
+
if (remaining.length > 0) {
|
|
4125
|
+
stream.next(remaining);
|
|
4126
|
+
}
|
|
4127
|
+
} catch {
|
|
4128
|
+
}
|
|
4129
|
+
stream.return(void 0);
|
|
4130
|
+
break;
|
|
4131
|
+
}
|
|
4132
|
+
try {
|
|
4133
|
+
const text = decoder.decode(value, { stream: true });
|
|
4134
|
+
if (text.length > 0) {
|
|
4135
|
+
stream.next(text);
|
|
4136
|
+
}
|
|
4137
|
+
} catch {
|
|
4138
|
+
stream.next({ $b64: uint8ArrayToBase64(value) });
|
|
4139
|
+
}
|
|
4140
|
+
}
|
|
4141
|
+
} catch (error) {
|
|
4142
|
+
stream.throw(error);
|
|
4143
|
+
} finally {
|
|
4144
|
+
reader.releaseLock();
|
|
4145
|
+
}
|
|
4146
|
+
})();
|
|
4147
|
+
return stream;
|
|
4148
|
+
}
|
|
4149
|
+
const RawStreamFactoryBinaryPlugin = ni({
|
|
4150
|
+
tag: "tss/RawStreamFactory",
|
|
4151
|
+
test(value) {
|
|
4152
|
+
return value === RAW_STREAM_FACTORY_BINARY;
|
|
4153
|
+
},
|
|
4154
|
+
parse: {
|
|
4155
|
+
sync() {
|
|
4156
|
+
return void 0;
|
|
4157
|
+
},
|
|
4158
|
+
async() {
|
|
4159
|
+
return Promise.resolve(void 0);
|
|
4160
|
+
},
|
|
4161
|
+
stream() {
|
|
4162
|
+
return void 0;
|
|
4163
|
+
}
|
|
4164
|
+
},
|
|
4165
|
+
serialize() {
|
|
4166
|
+
return FACTORY_BINARY;
|
|
4167
|
+
},
|
|
4168
|
+
deserialize() {
|
|
4169
|
+
return RAW_STREAM_FACTORY_BINARY;
|
|
4170
|
+
}
|
|
4171
|
+
});
|
|
4172
|
+
const RawStreamFactoryTextPlugin = ni({
|
|
4173
|
+
tag: "tss/RawStreamFactoryText",
|
|
4174
|
+
test(value) {
|
|
4175
|
+
return value === RAW_STREAM_FACTORY_TEXT;
|
|
4176
|
+
},
|
|
4177
|
+
parse: {
|
|
4178
|
+
sync() {
|
|
4179
|
+
return void 0;
|
|
4180
|
+
},
|
|
4181
|
+
async() {
|
|
4182
|
+
return Promise.resolve(void 0);
|
|
4183
|
+
},
|
|
4184
|
+
stream() {
|
|
4185
|
+
return void 0;
|
|
4186
|
+
}
|
|
4187
|
+
},
|
|
4188
|
+
serialize() {
|
|
4189
|
+
return FACTORY_TEXT;
|
|
4190
|
+
},
|
|
4191
|
+
deserialize() {
|
|
4192
|
+
return RAW_STREAM_FACTORY_TEXT;
|
|
4193
|
+
}
|
|
4194
|
+
});
|
|
4195
|
+
const RawStreamSSRPlugin = ni({
|
|
4196
|
+
tag: "tss/RawStream",
|
|
4197
|
+
extends: [RawStreamFactoryBinaryPlugin, RawStreamFactoryTextPlugin],
|
|
4198
|
+
test(value) {
|
|
4199
|
+
return value instanceof RawStream;
|
|
4200
|
+
},
|
|
4201
|
+
parse: {
|
|
4202
|
+
sync(value, ctx) {
|
|
4203
|
+
const factory = value.hint === "text" ? RAW_STREAM_FACTORY_TEXT : RAW_STREAM_FACTORY_BINARY;
|
|
4204
|
+
return {
|
|
4205
|
+
hint: value.hint,
|
|
4206
|
+
factory: ctx.parse(factory),
|
|
4207
|
+
stream: ctx.parse(te())
|
|
4208
|
+
};
|
|
4209
|
+
},
|
|
4210
|
+
async async(value, ctx) {
|
|
4211
|
+
const factory = value.hint === "text" ? RAW_STREAM_FACTORY_TEXT : RAW_STREAM_FACTORY_BINARY;
|
|
4212
|
+
const encodedStream = value.hint === "text" ? toTextStream(value.stream) : toBinaryStream(value.stream);
|
|
4213
|
+
return {
|
|
4214
|
+
hint: value.hint,
|
|
4215
|
+
factory: await ctx.parse(factory),
|
|
4216
|
+
stream: await ctx.parse(encodedStream)
|
|
4217
|
+
};
|
|
4218
|
+
},
|
|
4219
|
+
stream(value, ctx) {
|
|
4220
|
+
const factory = value.hint === "text" ? RAW_STREAM_FACTORY_TEXT : RAW_STREAM_FACTORY_BINARY;
|
|
4221
|
+
const encodedStream = value.hint === "text" ? toTextStream(value.stream) : toBinaryStream(value.stream);
|
|
4222
|
+
return {
|
|
4223
|
+
hint: value.hint,
|
|
4224
|
+
factory: ctx.parse(factory),
|
|
4225
|
+
stream: ctx.parse(encodedStream)
|
|
4226
|
+
};
|
|
4227
|
+
}
|
|
4228
|
+
},
|
|
4229
|
+
serialize(node, ctx) {
|
|
4230
|
+
return "(" + ctx.serialize(node.factory) + ")(" + ctx.serialize(node.stream) + ")";
|
|
4231
|
+
},
|
|
4232
|
+
deserialize(node, ctx) {
|
|
4233
|
+
const stream = ctx.deserialize(node.stream);
|
|
4234
|
+
return node.hint === "text" ? RAW_STREAM_FACTORY_CONSTRUCTOR_TEXT(stream) : RAW_STREAM_FACTORY_CONSTRUCTOR_BINARY(stream);
|
|
4235
|
+
}
|
|
4236
|
+
});
|
|
4237
|
+
function createRawStreamRPCPlugin(onRawStream) {
|
|
4238
|
+
let nextStreamId = 1;
|
|
4239
|
+
return ni({
|
|
4240
|
+
tag: "tss/RawStream",
|
|
4241
|
+
test(value) {
|
|
4242
|
+
return value instanceof RawStream;
|
|
4243
|
+
},
|
|
4244
|
+
parse: {
|
|
4245
|
+
async(value) {
|
|
4246
|
+
const streamId = nextStreamId++;
|
|
4247
|
+
onRawStream(streamId, value.stream);
|
|
4248
|
+
return Promise.resolve({ streamId });
|
|
4249
|
+
},
|
|
4250
|
+
stream(value) {
|
|
4251
|
+
const streamId = nextStreamId++;
|
|
4252
|
+
onRawStream(streamId, value.stream);
|
|
4253
|
+
return { streamId };
|
|
4254
|
+
}
|
|
4255
|
+
},
|
|
4256
|
+
serialize() {
|
|
4257
|
+
throw new Error(
|
|
4258
|
+
"RawStreamRPCPlugin.serialize should not be called. RPC uses JSON serialization, not JS code generation."
|
|
4259
|
+
);
|
|
4260
|
+
},
|
|
4261
|
+
deserialize() {
|
|
4262
|
+
throw new Error(
|
|
4263
|
+
"RawStreamRPCPlugin.deserialize should not be called. Use createRawStreamDeserializePlugin on client."
|
|
4264
|
+
);
|
|
4265
|
+
}
|
|
4266
|
+
});
|
|
4267
|
+
}
|
|
4268
|
+
const defaultSerovalPlugins = [
|
|
4269
|
+
ShallowErrorPlugin,
|
|
4270
|
+
// RawStreamSSRPlugin must come before ReadableStreamPlugin to match first
|
|
4271
|
+
RawStreamSSRPlugin,
|
|
4272
|
+
// ReadableStreamNode is not exported by seroval
|
|
4273
|
+
p
|
|
4274
|
+
];
|
|
4275
|
+
const minifiedTsrBootStrapScript = "self.$_TSR={h(){this.hydrated=!0,this.c()},e(){this.streamEnded=!0,this.c()},c(){this.hydrated&&this.streamEnded&&(delete self.$_TSR,delete self.$R.tsr)},p(e){this.initialized?e():this.buffer.push(e)},buffer:[]};\n";
|
|
4276
|
+
const SCOPE_ID = "tsr";
|
|
4277
|
+
function dehydrateMatch(match) {
|
|
4278
|
+
const dehydratedMatch = {
|
|
4279
|
+
i: match.id,
|
|
4280
|
+
u: match.updatedAt,
|
|
4281
|
+
s: match.status
|
|
4282
|
+
};
|
|
4283
|
+
const properties = [
|
|
4284
|
+
["__beforeLoadContext", "b"],
|
|
4285
|
+
["loaderData", "l"],
|
|
4286
|
+
["error", "e"],
|
|
4287
|
+
["ssr", "ssr"]
|
|
4288
|
+
];
|
|
4289
|
+
for (const [key, shorthand] of properties) {
|
|
4290
|
+
if (match[key] !== void 0) {
|
|
4291
|
+
dehydratedMatch[shorthand] = match[key];
|
|
4292
|
+
}
|
|
4293
|
+
}
|
|
4294
|
+
return dehydratedMatch;
|
|
4295
|
+
}
|
|
4296
|
+
const INITIAL_SCRIPTS = [
|
|
4297
|
+
mn(SCOPE_ID),
|
|
4298
|
+
minifiedTsrBootStrapScript
|
|
4299
|
+
];
|
|
4300
|
+
class ScriptBuffer {
|
|
4301
|
+
constructor(router) {
|
|
4302
|
+
this._scriptBarrierLifted = false;
|
|
4303
|
+
this._cleanedUp = false;
|
|
4304
|
+
this._pendingMicrotask = false;
|
|
4305
|
+
this.router = router;
|
|
4306
|
+
this._queue = INITIAL_SCRIPTS.slice();
|
|
4307
|
+
}
|
|
4308
|
+
enqueue(script) {
|
|
4309
|
+
if (this._cleanedUp) return;
|
|
4310
|
+
this._queue.push(script);
|
|
4311
|
+
if (this._scriptBarrierLifted && !this._pendingMicrotask) {
|
|
4312
|
+
this._pendingMicrotask = true;
|
|
4313
|
+
queueMicrotask(() => {
|
|
4314
|
+
this._pendingMicrotask = false;
|
|
4315
|
+
this.injectBufferedScripts();
|
|
4316
|
+
});
|
|
4317
|
+
}
|
|
4318
|
+
}
|
|
4319
|
+
liftBarrier() {
|
|
4320
|
+
if (this._scriptBarrierLifted || this._cleanedUp) return;
|
|
4321
|
+
this._scriptBarrierLifted = true;
|
|
4322
|
+
if (this._queue.length > 0 && !this._pendingMicrotask) {
|
|
4323
|
+
this._pendingMicrotask = true;
|
|
4324
|
+
queueMicrotask(() => {
|
|
4325
|
+
this._pendingMicrotask = false;
|
|
4326
|
+
this.injectBufferedScripts();
|
|
4327
|
+
});
|
|
4328
|
+
}
|
|
4329
|
+
}
|
|
4330
|
+
/**
|
|
4331
|
+
* Flushes any pending scripts synchronously.
|
|
4332
|
+
* Call this before emitting onSerializationFinished to ensure all scripts are injected.
|
|
4333
|
+
*
|
|
4334
|
+
* IMPORTANT: Only injects if the barrier has been lifted. Before the barrier is lifted,
|
|
4335
|
+
* scripts should remain in the queue so takeBufferedScripts() can retrieve them
|
|
4336
|
+
*/
|
|
4337
|
+
flush() {
|
|
4338
|
+
if (!this._scriptBarrierLifted) return;
|
|
4339
|
+
if (this._cleanedUp) return;
|
|
4340
|
+
this._pendingMicrotask = false;
|
|
4341
|
+
const scriptsToInject = this.takeAll();
|
|
4342
|
+
if (scriptsToInject && this.router?.serverSsr) {
|
|
4343
|
+
this.router.serverSsr.injectScript(scriptsToInject);
|
|
4344
|
+
}
|
|
4345
|
+
}
|
|
4346
|
+
takeAll() {
|
|
4347
|
+
const bufferedScripts = this._queue;
|
|
4348
|
+
this._queue = [];
|
|
4349
|
+
if (bufferedScripts.length === 0) {
|
|
4350
|
+
return void 0;
|
|
4351
|
+
}
|
|
4352
|
+
return bufferedScripts.join(";") + ";document.currentScript.remove()";
|
|
4353
|
+
}
|
|
4354
|
+
injectBufferedScripts() {
|
|
4355
|
+
if (this._cleanedUp) return;
|
|
4356
|
+
if (this._queue.length === 0) return;
|
|
4357
|
+
const scriptsToInject = this.takeAll();
|
|
4358
|
+
if (scriptsToInject && this.router?.serverSsr) {
|
|
4359
|
+
this.router.serverSsr.injectScript(scriptsToInject);
|
|
4360
|
+
}
|
|
4361
|
+
}
|
|
4362
|
+
cleanup() {
|
|
4363
|
+
this._cleanedUp = true;
|
|
4364
|
+
this._queue = [];
|
|
4365
|
+
this.router = void 0;
|
|
4366
|
+
}
|
|
4367
|
+
}
|
|
4368
|
+
function attachRouterServerSsrUtils({
|
|
4369
|
+
router,
|
|
4370
|
+
manifest
|
|
4371
|
+
}) {
|
|
4372
|
+
router.ssr = {
|
|
4373
|
+
manifest
|
|
4374
|
+
};
|
|
4375
|
+
let _dehydrated = false;
|
|
4376
|
+
let _serializationFinished = false;
|
|
4377
|
+
const renderFinishedListeners = [];
|
|
4378
|
+
const serializationFinishedListeners = [];
|
|
4379
|
+
const scriptBuffer = new ScriptBuffer(router);
|
|
4380
|
+
let injectedHtmlBuffer = [];
|
|
4381
|
+
router.serverSsr = {
|
|
4382
|
+
injectHtml: (html) => {
|
|
4383
|
+
if (!html) return;
|
|
4384
|
+
injectedHtmlBuffer.push(html);
|
|
4385
|
+
router.emit({
|
|
4386
|
+
type: "onInjectedHtml"
|
|
4387
|
+
});
|
|
4388
|
+
},
|
|
4389
|
+
injectScript: (script) => {
|
|
4390
|
+
if (!script) return;
|
|
4391
|
+
const html = `<script${router.options.ssr?.nonce ? ` nonce='${router.options.ssr.nonce}'` : ""}>${script}<\/script>`;
|
|
4392
|
+
router.serverSsr.injectHtml(html);
|
|
4393
|
+
},
|
|
4394
|
+
dehydrate: async () => {
|
|
4395
|
+
invariant(!_dehydrated);
|
|
4396
|
+
let matchesToDehydrate = router.state.matches;
|
|
4397
|
+
if (router.isShell()) {
|
|
4398
|
+
matchesToDehydrate = matchesToDehydrate.slice(0, 1);
|
|
4399
|
+
}
|
|
4400
|
+
const matches = matchesToDehydrate.map(dehydrateMatch);
|
|
4401
|
+
let manifestToDehydrate = void 0;
|
|
4402
|
+
if (manifest) {
|
|
4403
|
+
const currentRouteIds = new Set(
|
|
4404
|
+
router.state.matches.map((k) => k.routeId)
|
|
4405
|
+
);
|
|
4406
|
+
const filteredRoutes = Object.fromEntries(
|
|
4407
|
+
Object.entries(manifest.routes).flatMap(
|
|
4408
|
+
([routeId, routeManifest]) => {
|
|
4409
|
+
if (currentRouteIds.has(routeId)) {
|
|
4410
|
+
return [[routeId, routeManifest]];
|
|
4411
|
+
} else if (routeManifest.assets && routeManifest.assets.length > 0) {
|
|
4412
|
+
return [
|
|
4413
|
+
[
|
|
4414
|
+
routeId,
|
|
4415
|
+
{
|
|
4416
|
+
assets: routeManifest.assets
|
|
4417
|
+
}
|
|
4418
|
+
]
|
|
4419
|
+
];
|
|
4420
|
+
}
|
|
4421
|
+
return [];
|
|
4422
|
+
}
|
|
4423
|
+
)
|
|
4424
|
+
);
|
|
4425
|
+
manifestToDehydrate = {
|
|
4426
|
+
routes: filteredRoutes
|
|
4427
|
+
};
|
|
4428
|
+
}
|
|
4429
|
+
const dehydratedRouter = {
|
|
4430
|
+
manifest: manifestToDehydrate,
|
|
4431
|
+
matches
|
|
4432
|
+
};
|
|
4433
|
+
const lastMatchId = matchesToDehydrate[matchesToDehydrate.length - 1]?.id;
|
|
4434
|
+
if (lastMatchId) {
|
|
4435
|
+
dehydratedRouter.lastMatchId = lastMatchId;
|
|
4436
|
+
}
|
|
4437
|
+
const dehydratedData = await router.options.dehydrate?.();
|
|
4438
|
+
if (dehydratedData) {
|
|
4439
|
+
dehydratedRouter.dehydratedData = dehydratedData;
|
|
4440
|
+
}
|
|
4441
|
+
_dehydrated = true;
|
|
4442
|
+
const trackPlugins = { didRun: false };
|
|
4443
|
+
const serializationAdapters = router.options.serializationAdapters;
|
|
4444
|
+
const plugins = serializationAdapters ? serializationAdapters.map((t) => makeSsrSerovalPlugin(t, trackPlugins)).concat(defaultSerovalPlugins) : defaultSerovalPlugins;
|
|
4445
|
+
const signalSerializationComplete = () => {
|
|
4446
|
+
_serializationFinished = true;
|
|
4447
|
+
try {
|
|
4448
|
+
serializationFinishedListeners.forEach((l) => l());
|
|
4449
|
+
router.emit({ type: "onSerializationFinished" });
|
|
4450
|
+
} catch (err) {
|
|
4451
|
+
console.error("Serialization listener error:", err);
|
|
4452
|
+
} finally {
|
|
4453
|
+
serializationFinishedListeners.length = 0;
|
|
4454
|
+
renderFinishedListeners.length = 0;
|
|
4455
|
+
}
|
|
4456
|
+
};
|
|
4457
|
+
cn(dehydratedRouter, {
|
|
4458
|
+
refs: /* @__PURE__ */ new Map(),
|
|
4459
|
+
plugins,
|
|
4460
|
+
onSerialize: (data, initial) => {
|
|
4461
|
+
let serialized = initial ? GLOBAL_TSR + ".router=" + data : data;
|
|
4462
|
+
if (trackPlugins.didRun) {
|
|
4463
|
+
serialized = GLOBAL_TSR + ".p(()=>" + serialized + ")";
|
|
4464
|
+
}
|
|
4465
|
+
scriptBuffer.enqueue(serialized);
|
|
4466
|
+
},
|
|
4467
|
+
scopeId: SCOPE_ID,
|
|
4468
|
+
onDone: () => {
|
|
4469
|
+
scriptBuffer.enqueue(GLOBAL_TSR + ".e()");
|
|
4470
|
+
scriptBuffer.flush();
|
|
4471
|
+
signalSerializationComplete();
|
|
4472
|
+
},
|
|
4473
|
+
onError: (err) => {
|
|
4474
|
+
console.error("Serialization error:", err);
|
|
4475
|
+
signalSerializationComplete();
|
|
4476
|
+
}
|
|
4477
|
+
});
|
|
4478
|
+
},
|
|
4479
|
+
isDehydrated() {
|
|
4480
|
+
return _dehydrated;
|
|
4481
|
+
},
|
|
4482
|
+
isSerializationFinished() {
|
|
4483
|
+
return _serializationFinished;
|
|
4484
|
+
},
|
|
4485
|
+
onRenderFinished: (listener) => renderFinishedListeners.push(listener),
|
|
4486
|
+
onSerializationFinished: (listener) => serializationFinishedListeners.push(listener),
|
|
4487
|
+
setRenderFinished: () => {
|
|
4488
|
+
try {
|
|
4489
|
+
renderFinishedListeners.forEach((l) => l());
|
|
4490
|
+
} catch (err) {
|
|
4491
|
+
console.error("Error in render finished listener:", err);
|
|
4492
|
+
} finally {
|
|
4493
|
+
renderFinishedListeners.length = 0;
|
|
4494
|
+
}
|
|
4495
|
+
scriptBuffer.liftBarrier();
|
|
4496
|
+
},
|
|
4497
|
+
takeBufferedScripts() {
|
|
4498
|
+
const scripts = scriptBuffer.takeAll();
|
|
4499
|
+
const serverBufferedScript = {
|
|
4500
|
+
tag: "script",
|
|
4501
|
+
attrs: {
|
|
4502
|
+
nonce: router.options.ssr?.nonce,
|
|
4503
|
+
className: "$tsr",
|
|
4504
|
+
id: TSR_SCRIPT_BARRIER_ID
|
|
4505
|
+
},
|
|
4506
|
+
children: scripts
|
|
4507
|
+
};
|
|
4508
|
+
return serverBufferedScript;
|
|
4509
|
+
},
|
|
4510
|
+
liftScriptBarrier() {
|
|
4511
|
+
scriptBuffer.liftBarrier();
|
|
4512
|
+
},
|
|
4513
|
+
takeBufferedHtml() {
|
|
4514
|
+
if (injectedHtmlBuffer.length === 0) {
|
|
4515
|
+
return void 0;
|
|
4516
|
+
}
|
|
4517
|
+
const buffered = injectedHtmlBuffer.join("");
|
|
4518
|
+
injectedHtmlBuffer = [];
|
|
4519
|
+
return buffered;
|
|
4520
|
+
},
|
|
4521
|
+
cleanup() {
|
|
4522
|
+
if (!router.serverSsr) return;
|
|
4523
|
+
renderFinishedListeners.length = 0;
|
|
4524
|
+
serializationFinishedListeners.length = 0;
|
|
4525
|
+
injectedHtmlBuffer = [];
|
|
4526
|
+
scriptBuffer.cleanup();
|
|
4527
|
+
router.serverSsr = void 0;
|
|
4528
|
+
}
|
|
4529
|
+
};
|
|
4530
|
+
}
|
|
4531
|
+
function getOrigin(request) {
|
|
4532
|
+
try {
|
|
4533
|
+
return new URL(request.url).origin;
|
|
4534
|
+
} catch {
|
|
4535
|
+
}
|
|
4536
|
+
return "http://localhost";
|
|
4537
|
+
}
|
|
4538
|
+
function getNormalizedURL(url, base) {
|
|
4539
|
+
if (typeof url === "string") url = url.replace("\\", "%5C");
|
|
4540
|
+
const rawUrl = new URL(url, base);
|
|
4541
|
+
const decodedPathname = decodePath(rawUrl.pathname);
|
|
4542
|
+
const searchParams = new URLSearchParams(rawUrl.search);
|
|
4543
|
+
const normalizedHref = decodedPathname + (searchParams.size > 0 ? "?" : "") + searchParams.toString() + rawUrl.hash;
|
|
4544
|
+
return new URL(normalizedHref, rawUrl.origin);
|
|
4545
|
+
}
|
|
4546
|
+
function defineHandlerCallback(handler) {
|
|
4547
|
+
return handler;
|
|
4548
|
+
}
|
|
4549
|
+
function transformReadableStreamWithRouter(router, routerStream) {
|
|
4550
|
+
return transformStreamWithRouter(router, routerStream);
|
|
4551
|
+
}
|
|
4552
|
+
function transformPipeableStreamWithRouter(router, routerStream) {
|
|
4553
|
+
return Readable.fromWeb(
|
|
4554
|
+
transformStreamWithRouter(router, Readable.toWeb(routerStream))
|
|
4555
|
+
);
|
|
4556
|
+
}
|
|
4557
|
+
const BODY_END_TAG = "</body>";
|
|
4558
|
+
const HTML_END_TAG = "</html>";
|
|
4559
|
+
const MIN_CLOSING_TAG_LENGTH = 4;
|
|
4560
|
+
const DEFAULT_SERIALIZATION_TIMEOUT_MS = 6e4;
|
|
4561
|
+
const DEFAULT_LIFETIME_TIMEOUT_MS = 6e4;
|
|
4562
|
+
const textEncoder = new TextEncoder();
|
|
4563
|
+
function findLastClosingTagEnd(str) {
|
|
4564
|
+
const len = str.length;
|
|
4565
|
+
if (len < MIN_CLOSING_TAG_LENGTH) return -1;
|
|
4566
|
+
let i = len - 1;
|
|
4567
|
+
while (i >= MIN_CLOSING_TAG_LENGTH - 1) {
|
|
4568
|
+
if (str.charCodeAt(i) === 62) {
|
|
4569
|
+
let j = i - 1;
|
|
4570
|
+
while (j >= 1) {
|
|
4571
|
+
const code = str.charCodeAt(j);
|
|
4572
|
+
if (code >= 97 && code <= 122 || // a-z
|
|
4573
|
+
code >= 65 && code <= 90 || // A-Z
|
|
4574
|
+
code >= 48 && code <= 57 || // 0-9
|
|
4575
|
+
code === 95 || // _
|
|
4576
|
+
code === 58 || // :
|
|
4577
|
+
code === 46 || // .
|
|
4578
|
+
code === 45) {
|
|
4579
|
+
j--;
|
|
4580
|
+
} else {
|
|
4581
|
+
break;
|
|
4582
|
+
}
|
|
4583
|
+
}
|
|
4584
|
+
const tagNameStart = j + 1;
|
|
4585
|
+
if (tagNameStart < i) {
|
|
4586
|
+
const startCode = str.charCodeAt(tagNameStart);
|
|
4587
|
+
if (startCode >= 97 && startCode <= 122 || startCode >= 65 && startCode <= 90) {
|
|
4588
|
+
if (j >= 1 && str.charCodeAt(j) === 47 && str.charCodeAt(j - 1) === 60) {
|
|
4589
|
+
return i + 1;
|
|
4590
|
+
}
|
|
4591
|
+
}
|
|
4592
|
+
}
|
|
4593
|
+
}
|
|
4594
|
+
i--;
|
|
4595
|
+
}
|
|
4596
|
+
return -1;
|
|
4597
|
+
}
|
|
4598
|
+
function transformStreamWithRouter(router, appStream, opts) {
|
|
4599
|
+
let stopListeningToInjectedHtml;
|
|
4600
|
+
let stopListeningToSerializationFinished;
|
|
4601
|
+
let serializationTimeoutHandle;
|
|
4602
|
+
let lifetimeTimeoutHandle;
|
|
4603
|
+
let cleanedUp = false;
|
|
4604
|
+
let controller;
|
|
4605
|
+
let isStreamClosed = false;
|
|
4606
|
+
const serializationAlreadyFinished = router.serverSsr?.isSerializationFinished() ?? false;
|
|
4607
|
+
function cleanup() {
|
|
4608
|
+
if (cleanedUp) return;
|
|
4609
|
+
cleanedUp = true;
|
|
4610
|
+
try {
|
|
4611
|
+
stopListeningToInjectedHtml?.();
|
|
4612
|
+
stopListeningToSerializationFinished?.();
|
|
4613
|
+
} catch (e) {
|
|
4614
|
+
}
|
|
4615
|
+
stopListeningToInjectedHtml = void 0;
|
|
4616
|
+
stopListeningToSerializationFinished = void 0;
|
|
4617
|
+
if (serializationTimeoutHandle !== void 0) {
|
|
4618
|
+
clearTimeout(serializationTimeoutHandle);
|
|
4619
|
+
serializationTimeoutHandle = void 0;
|
|
4620
|
+
}
|
|
4621
|
+
if (lifetimeTimeoutHandle !== void 0) {
|
|
4622
|
+
clearTimeout(lifetimeTimeoutHandle);
|
|
4623
|
+
lifetimeTimeoutHandle = void 0;
|
|
4624
|
+
}
|
|
4625
|
+
pendingRouterHtmlParts = [];
|
|
4626
|
+
leftover = "";
|
|
4627
|
+
pendingClosingTags = "";
|
|
4628
|
+
router.serverSsr?.cleanup();
|
|
4629
|
+
}
|
|
4630
|
+
const textDecoder = new TextDecoder();
|
|
4631
|
+
function safeEnqueue(chunk) {
|
|
4632
|
+
if (isStreamClosed) return;
|
|
4633
|
+
if (typeof chunk === "string") {
|
|
4634
|
+
controller.enqueue(textEncoder.encode(chunk));
|
|
4635
|
+
} else {
|
|
4636
|
+
controller.enqueue(chunk);
|
|
4637
|
+
}
|
|
4638
|
+
}
|
|
4639
|
+
function safeClose() {
|
|
4640
|
+
if (isStreamClosed) return;
|
|
4641
|
+
isStreamClosed = true;
|
|
4642
|
+
try {
|
|
4643
|
+
controller.close();
|
|
4644
|
+
} catch {
|
|
4645
|
+
}
|
|
4646
|
+
}
|
|
4647
|
+
function safeError(error) {
|
|
4648
|
+
if (isStreamClosed) return;
|
|
4649
|
+
isStreamClosed = true;
|
|
4650
|
+
try {
|
|
4651
|
+
controller.error(error);
|
|
4652
|
+
} catch {
|
|
4653
|
+
}
|
|
4654
|
+
}
|
|
4655
|
+
const stream = new ReadableStream$1({
|
|
4656
|
+
start(c) {
|
|
4657
|
+
controller = c;
|
|
4658
|
+
},
|
|
4659
|
+
cancel() {
|
|
4660
|
+
isStreamClosed = true;
|
|
4661
|
+
cleanup();
|
|
4662
|
+
}
|
|
4663
|
+
});
|
|
4664
|
+
let isAppRendering = true;
|
|
4665
|
+
let streamBarrierLifted = false;
|
|
4666
|
+
let leftover = "";
|
|
4667
|
+
let pendingClosingTags = "";
|
|
4668
|
+
let serializationFinished = serializationAlreadyFinished;
|
|
4669
|
+
let pendingRouterHtmlParts = [];
|
|
4670
|
+
const bufferedHtml = router.serverSsr?.takeBufferedHtml();
|
|
4671
|
+
if (bufferedHtml) {
|
|
4672
|
+
pendingRouterHtmlParts.push(bufferedHtml);
|
|
4673
|
+
}
|
|
4674
|
+
function flushPendingRouterHtml() {
|
|
4675
|
+
if (pendingRouterHtmlParts.length > 0) {
|
|
4676
|
+
safeEnqueue(pendingRouterHtmlParts.join(""));
|
|
4677
|
+
pendingRouterHtmlParts = [];
|
|
4678
|
+
}
|
|
4679
|
+
}
|
|
4680
|
+
function tryFinish() {
|
|
4681
|
+
if (isAppRendering || !serializationFinished) return;
|
|
4682
|
+
if (cleanedUp || isStreamClosed) return;
|
|
4683
|
+
if (serializationTimeoutHandle !== void 0) {
|
|
4684
|
+
clearTimeout(serializationTimeoutHandle);
|
|
4685
|
+
serializationTimeoutHandle = void 0;
|
|
4686
|
+
}
|
|
4687
|
+
const decoderRemainder = textDecoder.decode();
|
|
4688
|
+
if (leftover) safeEnqueue(leftover);
|
|
4689
|
+
if (decoderRemainder) safeEnqueue(decoderRemainder);
|
|
4690
|
+
flushPendingRouterHtml();
|
|
4691
|
+
if (pendingClosingTags) safeEnqueue(pendingClosingTags);
|
|
4692
|
+
safeClose();
|
|
4693
|
+
cleanup();
|
|
4694
|
+
}
|
|
4695
|
+
const lifetimeMs = DEFAULT_LIFETIME_TIMEOUT_MS;
|
|
4696
|
+
lifetimeTimeoutHandle = setTimeout(() => {
|
|
4697
|
+
if (!cleanedUp && !isStreamClosed) {
|
|
4698
|
+
console.warn(
|
|
4699
|
+
`SSR stream transform exceeded maximum lifetime (${lifetimeMs}ms), forcing cleanup`
|
|
4700
|
+
);
|
|
4701
|
+
safeError(new Error("Stream lifetime exceeded"));
|
|
4702
|
+
cleanup();
|
|
4703
|
+
}
|
|
4704
|
+
}, lifetimeMs);
|
|
4705
|
+
if (!serializationAlreadyFinished) {
|
|
4706
|
+
stopListeningToInjectedHtml = router.subscribe("onInjectedHtml", () => {
|
|
4707
|
+
if (cleanedUp || isStreamClosed) return;
|
|
4708
|
+
const html = router.serverSsr?.takeBufferedHtml();
|
|
4709
|
+
if (!html) return;
|
|
4710
|
+
if (isAppRendering) {
|
|
4711
|
+
pendingRouterHtmlParts.push(html);
|
|
4712
|
+
} else {
|
|
4713
|
+
safeEnqueue(html);
|
|
4714
|
+
}
|
|
4715
|
+
});
|
|
4716
|
+
stopListeningToSerializationFinished = router.subscribe(
|
|
4717
|
+
"onSerializationFinished",
|
|
4718
|
+
() => {
|
|
4719
|
+
serializationFinished = true;
|
|
4720
|
+
tryFinish();
|
|
4721
|
+
}
|
|
4722
|
+
);
|
|
4723
|
+
}
|
|
4724
|
+
(async () => {
|
|
4725
|
+
const reader = appStream.getReader();
|
|
4726
|
+
try {
|
|
4727
|
+
while (true) {
|
|
4728
|
+
const { done, value } = await reader.read();
|
|
4729
|
+
if (done) break;
|
|
4730
|
+
if (cleanedUp || isStreamClosed) return;
|
|
4731
|
+
const text = value instanceof Uint8Array ? textDecoder.decode(value, { stream: true }) : String(value);
|
|
4732
|
+
const chunkString = leftover + text;
|
|
4733
|
+
if (!streamBarrierLifted) {
|
|
4734
|
+
if (chunkString.includes(TSR_SCRIPT_BARRIER_ID)) {
|
|
4735
|
+
streamBarrierLifted = true;
|
|
4736
|
+
router.serverSsr?.liftScriptBarrier();
|
|
4737
|
+
}
|
|
4738
|
+
}
|
|
4739
|
+
const bodyEndIndex = chunkString.indexOf(BODY_END_TAG);
|
|
4740
|
+
const htmlEndIndex = chunkString.indexOf(HTML_END_TAG);
|
|
4741
|
+
if (bodyEndIndex !== -1 && htmlEndIndex !== -1 && bodyEndIndex < htmlEndIndex) {
|
|
4742
|
+
pendingClosingTags = chunkString.slice(bodyEndIndex);
|
|
4743
|
+
safeEnqueue(chunkString.slice(0, bodyEndIndex));
|
|
4744
|
+
flushPendingRouterHtml();
|
|
4745
|
+
leftover = "";
|
|
4746
|
+
continue;
|
|
4747
|
+
}
|
|
4748
|
+
const lastClosingTagEnd = findLastClosingTagEnd(chunkString);
|
|
4749
|
+
if (lastClosingTagEnd > 0) {
|
|
4750
|
+
safeEnqueue(chunkString.slice(0, lastClosingTagEnd));
|
|
4751
|
+
flushPendingRouterHtml();
|
|
4752
|
+
leftover = chunkString.slice(lastClosingTagEnd);
|
|
4753
|
+
} else {
|
|
4754
|
+
leftover = chunkString;
|
|
4755
|
+
}
|
|
4756
|
+
}
|
|
4757
|
+
if (cleanedUp || isStreamClosed) return;
|
|
4758
|
+
isAppRendering = false;
|
|
4759
|
+
router.serverSsr?.setRenderFinished();
|
|
4760
|
+
if (serializationFinished) {
|
|
4761
|
+
tryFinish();
|
|
4762
|
+
} else {
|
|
4763
|
+
const timeoutMs = opts?.timeoutMs ?? DEFAULT_SERIALIZATION_TIMEOUT_MS;
|
|
4764
|
+
serializationTimeoutHandle = setTimeout(() => {
|
|
4765
|
+
if (!cleanedUp && !isStreamClosed) {
|
|
4766
|
+
console.error("Serialization timeout after app render finished");
|
|
4767
|
+
safeError(
|
|
4768
|
+
new Error("Serialization timeout after app render finished")
|
|
4769
|
+
);
|
|
4770
|
+
cleanup();
|
|
4771
|
+
}
|
|
4772
|
+
}, timeoutMs);
|
|
4773
|
+
}
|
|
4774
|
+
} catch (error) {
|
|
4775
|
+
if (cleanedUp) return;
|
|
4776
|
+
console.error("Error reading appStream:", error);
|
|
4777
|
+
isAppRendering = false;
|
|
4778
|
+
router.serverSsr?.setRenderFinished();
|
|
4779
|
+
safeError(error);
|
|
4780
|
+
cleanup();
|
|
4781
|
+
} finally {
|
|
4782
|
+
reader.releaseLock();
|
|
4783
|
+
}
|
|
4784
|
+
})().catch((error) => {
|
|
4785
|
+
if (cleanedUp) return;
|
|
4786
|
+
console.error("Error in stream transform:", error);
|
|
4787
|
+
safeError(error);
|
|
4788
|
+
cleanup();
|
|
4789
|
+
});
|
|
4790
|
+
return stream;
|
|
4791
|
+
}
|
|
4792
|
+
export {
|
|
4793
|
+
attachRouterServerSsrUtils as A,
|
|
4794
|
+
BaseRootRoute as B,
|
|
4795
|
+
createSerializationAdapter as C,
|
|
4796
|
+
createRawStreamRPCPlugin as D,
|
|
4797
|
+
isResolvedRedirect as E,
|
|
4798
|
+
executeRewriteInput as F,
|
|
4799
|
+
defaultSerovalPlugins as G,
|
|
4800
|
+
makeSerovalPlugin as H,
|
|
4801
|
+
defineHandlerCallback as I,
|
|
4802
|
+
RouterCore as R,
|
|
4803
|
+
restoreScroll as a,
|
|
4804
|
+
rootRouteId as b,
|
|
4805
|
+
createControlledPromise as c,
|
|
4806
|
+
defaultGetScrollRestorationKey as d,
|
|
4807
|
+
escapeHtml as e,
|
|
4808
|
+
isRedirect as f,
|
|
4809
|
+
getLocationChangeInfo as g,
|
|
4810
|
+
handleHashScroll as h,
|
|
4811
|
+
isNotFound as i,
|
|
4812
|
+
transformReadableStreamWithRouter as j,
|
|
4813
|
+
transformPipeableStreamWithRouter as k,
|
|
4814
|
+
isDangerousProtocol as l,
|
|
4815
|
+
functionalUpdate as m,
|
|
4816
|
+
exactPathTest as n,
|
|
4817
|
+
removeTrailingSlash as o,
|
|
4818
|
+
preloadWarning as p,
|
|
4819
|
+
deepEqual as q,
|
|
4820
|
+
replaceEqualDeep as r,
|
|
4821
|
+
storageKey as s,
|
|
4822
|
+
trimPathRight as t,
|
|
4823
|
+
BaseRoute as u,
|
|
4824
|
+
isModuleNotFoundError as v,
|
|
4825
|
+
parseRedirect as w,
|
|
4826
|
+
mergeHeaders as x,
|
|
4827
|
+
getNormalizedURL as y,
|
|
4828
|
+
getOrigin as z
|
|
4829
|
+
};
|