@takazudo/zfb-runtime 4.3.0 → 4.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -37,7 +37,7 @@ export declare const updateScrollPosition: (positions: {
37
37
  scrollX: number;
38
38
  scrollY: number;
39
39
  }) => void;
40
- export declare function doSwap(afterPreparation: BeforeEvent, viewTransition: ViewTransition, afterDispatch?: () => Promise<void>, beforeSwap?: (event: TransitionBeforeSwapEvent) => void): Promise<{
40
+ export declare function doSwap(afterPreparation: BeforeEvent, viewTransition: ViewTransition, afterDispatch?: () => Promise<void>, beforeSwap?: (event: TransitionBeforeSwapEvent) => boolean | void): Promise<{
41
41
  swapped: false;
42
42
  event: TransitionBeforeSwapEvent;
43
43
  } | {
@@ -103,7 +103,9 @@ export const updateScrollPosition = (positions) => {
103
103
  safeReplaceState({ ...history.state, ...positions }, "");
104
104
  }
105
105
  };
106
- export async function doSwap(afterPreparation, viewTransition, afterDispatch, beforeSwap) {
106
+ export async function doSwap(afterPreparation, viewTransition, afterDispatch,
107
+ // Returning `false` vetoes the swap. It must do so before any teardown.
108
+ beforeSwap) {
107
109
  const event = new TransitionBeforeSwapEvent(afterPreparation, viewTransition);
108
110
  document.dispatchEvent(event);
109
111
  if (afterDispatch) {
@@ -115,7 +117,9 @@ export async function doSwap(afterPreparation, viewTransition, afterDispatch, be
115
117
  // This callback and event.swap() deliberately form one synchronous commit
116
118
  // section. Once teardown starts, the navigation must finish even if an
117
119
  // observer aborts its signal from inside an overridden swap().
118
- beforeSwap?.(event);
120
+ if (beforeSwap?.(event) === false) {
121
+ return { swapped: false, event };
122
+ }
119
123
  event.swap();
120
124
  return { swapped: true, event };
121
125
  }
@@ -1 +1 @@
1
- {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/client-router/events.ts"],"names":[],"mappings":"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","sourcesContent":["/// <reference lib=\"dom\" />\nimport { safeReplaceState } from \"./history-safe.js\";\nimport { swap } from \"./swap-functions.js\";\nimport type { Direction, NavigationTypeString } from \"./types.js\";\n\nexport const TRANSITION_BEFORE_PREPARATION = \"zfb:before-preparation\";\nexport const TRANSITION_AFTER_PREPARATION = \"zfb:after-preparation\";\nexport const TRANSITION_BEFORE_SWAP = \"zfb:before-swap\";\nexport const TRANSITION_AFTER_SWAP = \"zfb:after-swap\";\nexport const TRANSITION_PAGE_LOAD = \"zfb:page-load\";\nexport const TRANSITION_NAVIGATION_ABORTED = \"zfb:navigation-aborted\";\n\ntype Events =\n | \"zfb:after-preparation\"\n | \"zfb:after-swap\"\n | \"zfb:page-load\"\n | \"zfb:navigation-aborted\";\nexport const triggerEvent = (name: Events) => document.dispatchEvent(new Event(name));\nexport const onPageLoad = () => triggerEvent(\"zfb:page-load\");\n\n/*\n * Common stuff\n */\nclass BeforeEvent extends Event {\n readonly from: URL;\n to: URL;\n direction: Direction | string;\n readonly navigationType: NavigationTypeString;\n readonly sourceElement: Element | undefined;\n readonly info: any;\n newDocument: Document;\n readonly signal: AbortSignal;\n\n constructor(\n type: string,\n eventInitDict: EventInit | undefined,\n from: URL,\n to: URL,\n direction: Direction | string,\n navigationType: NavigationTypeString,\n sourceElement: Element | undefined,\n info: any,\n newDocument: Document,\n signal: AbortSignal,\n ) {\n super(type, eventInitDict);\n this.from = from;\n this.to = to;\n this.direction = direction;\n this.navigationType = navigationType;\n this.sourceElement = sourceElement;\n this.info = info;\n this.newDocument = newDocument;\n this.signal = signal;\n\n Object.defineProperties(this, {\n from: { enumerable: true },\n to: { enumerable: true, writable: true },\n direction: { enumerable: true, writable: true },\n navigationType: { enumerable: true },\n sourceElement: { enumerable: true },\n info: { enumerable: true },\n newDocument: { enumerable: true, writable: true },\n signal: { enumerable: true },\n });\n }\n}\n\n/*\n * TransitionBeforePreparationEvent\n\n */\nexport const isTransitionBeforePreparationEvent = (\n value: any,\n): value is TransitionBeforePreparationEvent =>\n typeof value === \"object\" && value !== null && value.type === TRANSITION_BEFORE_PREPARATION;\nexport class TransitionBeforePreparationEvent extends BeforeEvent {\n formData: FormData | undefined;\n loader: () => Promise<void>;\n constructor(\n from: URL,\n to: URL,\n direction: Direction | string,\n navigationType: NavigationTypeString,\n sourceElement: Element | undefined,\n info: any,\n newDocument: Document,\n signal: AbortSignal,\n formData: FormData | undefined,\n loader: (event: TransitionBeforePreparationEvent) => Promise<void>,\n ) {\n super(\n TRANSITION_BEFORE_PREPARATION,\n { cancelable: true },\n from,\n to,\n direction,\n navigationType,\n sourceElement,\n info,\n newDocument,\n signal,\n );\n this.formData = formData;\n this.loader = loader.bind(this, this);\n Object.defineProperties(this, {\n formData: { enumerable: true },\n loader: { enumerable: true, writable: true },\n });\n }\n}\n\n/*\n * TransitionBeforeSwapEvent\n */\nexport const isTransitionBeforeSwapEvent = (value: any): value is TransitionBeforeSwapEvent =>\n typeof value === \"object\" && value !== null && value.type === TRANSITION_BEFORE_SWAP;\nexport class TransitionBeforeSwapEvent extends BeforeEvent {\n override readonly direction: Direction | string;\n readonly viewTransition: ViewTransition;\n swap: () => void;\n\n constructor(afterPreparation: BeforeEvent, viewTransition: ViewTransition) {\n super(\n TRANSITION_BEFORE_SWAP,\n undefined,\n afterPreparation.from,\n afterPreparation.to,\n afterPreparation.direction,\n afterPreparation.navigationType,\n afterPreparation.sourceElement,\n afterPreparation.info,\n afterPreparation.newDocument,\n afterPreparation.signal,\n );\n this.direction = afterPreparation.direction;\n this.viewTransition = viewTransition;\n this.swap = () => swap(this.newDocument);\n\n Object.defineProperties(this, {\n direction: { enumerable: true },\n viewTransition: { enumerable: true },\n swap: { enumerable: true, writable: true },\n });\n }\n}\n\nexport async function doPreparation(\n from: URL,\n to: URL,\n direction: Direction | string,\n navigationType: NavigationTypeString,\n sourceElement: Element | undefined,\n info: any,\n signal: AbortSignal,\n formData: FormData | undefined,\n defaultLoader: (event: TransitionBeforePreparationEvent) => Promise<void>,\n) {\n const event = new TransitionBeforePreparationEvent(\n from,\n to,\n direction,\n navigationType,\n sourceElement,\n info,\n window.document,\n signal,\n formData,\n defaultLoader,\n );\n if (document.dispatchEvent(event)) {\n await event.loader();\n if (!event.defaultPrevented) {\n triggerEvent(\"zfb:after-preparation\");\n if (event.navigationType !== \"traverse\") {\n // save the current scroll position before we change the DOM and transition to the new page\n updateScrollPosition({ scrollX, scrollY });\n }\n }\n }\n return event;\n}\n\n// only update history entries that are managed by us\n// leave other entries alone and do not accidentally add state.\nexport const updateScrollPosition = (positions: { scrollX: number; scrollY: number }) => {\n if (history.state) {\n history.scrollRestoration = \"manual\";\n safeReplaceState({ ...history.state, ...positions }, \"\");\n }\n};\n\nexport async function doSwap(\n afterPreparation: BeforeEvent,\n viewTransition: ViewTransition,\n afterDispatch?: () => Promise<void>,\n beforeSwap?: (event: TransitionBeforeSwapEvent) => void,\n) {\n const event = new TransitionBeforeSwapEvent(afterPreparation, viewTransition);\n document.dispatchEvent(event);\n if (afterDispatch) {\n await afterDispatch();\n }\n if (event.signal.aborted) {\n return { swapped: false as const, event };\n }\n // This callback and event.swap() deliberately form one synchronous commit\n // section. Once teardown starts, the navigation must finish even if an\n // observer aborts its signal from inside an overridden swap().\n beforeSwap?.(event);\n event.swap();\n return { swapped: true as const, event };\n}\n"]}
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../src/client-router/events.ts"],"names":[],"mappings":"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","sourcesContent":["/// <reference lib=\"dom\" />\nimport { safeReplaceState } from \"./history-safe.js\";\nimport { swap } from \"./swap-functions.js\";\nimport type { Direction, NavigationTypeString } from \"./types.js\";\n\nexport const TRANSITION_BEFORE_PREPARATION = \"zfb:before-preparation\";\nexport const TRANSITION_AFTER_PREPARATION = \"zfb:after-preparation\";\nexport const TRANSITION_BEFORE_SWAP = \"zfb:before-swap\";\nexport const TRANSITION_AFTER_SWAP = \"zfb:after-swap\";\nexport const TRANSITION_PAGE_LOAD = \"zfb:page-load\";\nexport const TRANSITION_NAVIGATION_ABORTED = \"zfb:navigation-aborted\";\n\ntype Events =\n | \"zfb:after-preparation\"\n | \"zfb:after-swap\"\n | \"zfb:page-load\"\n | \"zfb:navigation-aborted\";\nexport const triggerEvent = (name: Events) => document.dispatchEvent(new Event(name));\nexport const onPageLoad = () => triggerEvent(\"zfb:page-load\");\n\n/*\n * Common stuff\n */\nclass BeforeEvent extends Event {\n readonly from: URL;\n to: URL;\n direction: Direction | string;\n readonly navigationType: NavigationTypeString;\n readonly sourceElement: Element | undefined;\n readonly info: any;\n newDocument: Document;\n readonly signal: AbortSignal;\n\n constructor(\n type: string,\n eventInitDict: EventInit | undefined,\n from: URL,\n to: URL,\n direction: Direction | string,\n navigationType: NavigationTypeString,\n sourceElement: Element | undefined,\n info: any,\n newDocument: Document,\n signal: AbortSignal,\n ) {\n super(type, eventInitDict);\n this.from = from;\n this.to = to;\n this.direction = direction;\n this.navigationType = navigationType;\n this.sourceElement = sourceElement;\n this.info = info;\n this.newDocument = newDocument;\n this.signal = signal;\n\n Object.defineProperties(this, {\n from: { enumerable: true },\n to: { enumerable: true, writable: true },\n direction: { enumerable: true, writable: true },\n navigationType: { enumerable: true },\n sourceElement: { enumerable: true },\n info: { enumerable: true },\n newDocument: { enumerable: true, writable: true },\n signal: { enumerable: true },\n });\n }\n}\n\n/*\n * TransitionBeforePreparationEvent\n\n */\nexport const isTransitionBeforePreparationEvent = (\n value: any,\n): value is TransitionBeforePreparationEvent =>\n typeof value === \"object\" && value !== null && value.type === TRANSITION_BEFORE_PREPARATION;\nexport class TransitionBeforePreparationEvent extends BeforeEvent {\n formData: FormData | undefined;\n loader: () => Promise<void>;\n constructor(\n from: URL,\n to: URL,\n direction: Direction | string,\n navigationType: NavigationTypeString,\n sourceElement: Element | undefined,\n info: any,\n newDocument: Document,\n signal: AbortSignal,\n formData: FormData | undefined,\n loader: (event: TransitionBeforePreparationEvent) => Promise<void>,\n ) {\n super(\n TRANSITION_BEFORE_PREPARATION,\n { cancelable: true },\n from,\n to,\n direction,\n navigationType,\n sourceElement,\n info,\n newDocument,\n signal,\n );\n this.formData = formData;\n this.loader = loader.bind(this, this);\n Object.defineProperties(this, {\n formData: { enumerable: true },\n loader: { enumerable: true, writable: true },\n });\n }\n}\n\n/*\n * TransitionBeforeSwapEvent\n */\nexport const isTransitionBeforeSwapEvent = (value: any): value is TransitionBeforeSwapEvent =>\n typeof value === \"object\" && value !== null && value.type === TRANSITION_BEFORE_SWAP;\nexport class TransitionBeforeSwapEvent extends BeforeEvent {\n override readonly direction: Direction | string;\n readonly viewTransition: ViewTransition;\n swap: () => void;\n\n constructor(afterPreparation: BeforeEvent, viewTransition: ViewTransition) {\n super(\n TRANSITION_BEFORE_SWAP,\n undefined,\n afterPreparation.from,\n afterPreparation.to,\n afterPreparation.direction,\n afterPreparation.navigationType,\n afterPreparation.sourceElement,\n afterPreparation.info,\n afterPreparation.newDocument,\n afterPreparation.signal,\n );\n this.direction = afterPreparation.direction;\n this.viewTransition = viewTransition;\n this.swap = () => swap(this.newDocument);\n\n Object.defineProperties(this, {\n direction: { enumerable: true },\n viewTransition: { enumerable: true },\n swap: { enumerable: true, writable: true },\n });\n }\n}\n\nexport async function doPreparation(\n from: URL,\n to: URL,\n direction: Direction | string,\n navigationType: NavigationTypeString,\n sourceElement: Element | undefined,\n info: any,\n signal: AbortSignal,\n formData: FormData | undefined,\n defaultLoader: (event: TransitionBeforePreparationEvent) => Promise<void>,\n) {\n const event = new TransitionBeforePreparationEvent(\n from,\n to,\n direction,\n navigationType,\n sourceElement,\n info,\n window.document,\n signal,\n formData,\n defaultLoader,\n );\n if (document.dispatchEvent(event)) {\n await event.loader();\n if (!event.defaultPrevented) {\n triggerEvent(\"zfb:after-preparation\");\n if (event.navigationType !== \"traverse\") {\n // save the current scroll position before we change the DOM and transition to the new page\n updateScrollPosition({ scrollX, scrollY });\n }\n }\n }\n return event;\n}\n\n// only update history entries that are managed by us\n// leave other entries alone and do not accidentally add state.\nexport const updateScrollPosition = (positions: { scrollX: number; scrollY: number }) => {\n if (history.state) {\n history.scrollRestoration = \"manual\";\n safeReplaceState({ ...history.state, ...positions }, \"\");\n }\n};\n\nexport async function doSwap(\n afterPreparation: BeforeEvent,\n viewTransition: ViewTransition,\n afterDispatch?: () => Promise<void>,\n // Returning `false` vetoes the swap. It must do so before any teardown.\n beforeSwap?: (event: TransitionBeforeSwapEvent) => boolean | void,\n) {\n const event = new TransitionBeforeSwapEvent(afterPreparation, viewTransition);\n document.dispatchEvent(event);\n if (afterDispatch) {\n await afterDispatch();\n }\n if (event.signal.aborted) {\n return { swapped: false as const, event };\n }\n // This callback and event.swap() deliberately form one synchronous commit\n // section. Once teardown starts, the navigation must finish even if an\n // observer aborts its signal from inside an overridden swap().\n if (beforeSwap?.(event) === false) {\n return { swapped: false as const, event };\n }\n event.swap();\n return { swapped: true as const, event };\n}\n"]}
@@ -1,2 +1,12 @@
1
+ export type HistoryWriteResult = {
2
+ readonly outcome: "committed";
3
+ } | {
4
+ readonly outcome: "tolerated";
5
+ readonly error: unknown;
6
+ } | {
7
+ readonly outcome: "rejected";
8
+ readonly error: unknown;
9
+ };
10
+ export declare function tryReplaceState(...args: Parameters<History["replaceState"]>): HistoryWriteResult;
11
+ export declare function tryPushState(...args: Parameters<History["pushState"]>): HistoryWriteResult;
1
12
  export declare function safeReplaceState(...args: Parameters<History["replaceState"]>): void;
2
- export declare function safePushState(...args: Parameters<History["pushState"]>): void;
@@ -1,34 +1,61 @@
1
1
  /// <reference lib="dom" />
2
- // zfb-only addition (no Astro upstream — #2424).
2
+ // zfb-only addition (no Astro upstream — #2424, #4127).
3
3
  //
4
- // Inside an `about:srcdoc` document (e.g. an SPA-preview iframe shell),
5
- // Chromium refuses `history.replaceState`/`pushState` and throws. The router
6
- // calls these unconditionally — at module init and from several
7
- // navigation-adjacent paths — so a zfb page loaded via `srcdoc` would break
8
- // on the very first call. These wrappers swallow that failure so the router
9
- // degrades silently instead of propagating the throw.
4
+ // The browser can refuse a History write for two very different reasons:
10
5
  //
11
- // In a normal document the History API never throws here, so the try/catch
12
- // is a no-op passthrough: same call, same arguments, same behavior.
6
+ // - Inside an `about:srcdoc` document (e.g. an SPA-preview iframe shell),
7
+ // Chromium refuses `history.replaceState`/`pushState` with a SecurityError.
8
+ // The router must keep working there, so that restriction is TOLERATED.
9
+ // - In an ordinary document the write can still be REJECTED — WebKit, for
10
+ // example, throws once a page exceeds its History-write rate limit (#4125).
11
+ // The URL did not change, so a caller that goes on as if it had would leave
12
+ // the page content, the address bar and the router bookkeeping disagreeing.
13
+ //
14
+ // `tryPushState`/`tryReplaceState` report which of the three outcomes happened
15
+ // so navigation code can advance its bookkeeping only on a committed write.
16
+ // `safeReplaceState` is for metadata-only writes (the init seed, scroll-position
17
+ // saves) whose existing contract is best-effort: it swallows every failure.
13
18
  //
14
19
  // `...args` (rather than naming `data`/`unused`/`url`) preserves the exact
15
20
  // call arity — several call sites omit the trailing `url` argument, and
16
21
  // spreading a shorter tuple calls the native method with that same shorter
17
22
  // arity rather than passing an explicit `undefined`.
18
- export function safeReplaceState(...args) {
23
+ const COMMITTED = { outcome: "committed" };
24
+ // Identify srcdoc by the document's own address. `document.baseURI` is
25
+ // deliberately NOT consulted: a srcdoc document inherits its parent's base URL,
26
+ // so an HTTP baseURI says nothing about which kind of document this is. A
27
+ // fragment navigation inside the srcdoc document keeps it a srcdoc document
28
+ // while its URL becomes `about:srcdoc#…`, so the fragment is ignored.
29
+ const isSrcdocDocument = () => document.URL.split("#", 1)[0] === "about:srcdoc";
30
+ const isSecurityError = (error) => typeof error === "object" &&
31
+ error !== null &&
32
+ error.name === "SecurityError";
33
+ function classify(error) {
34
+ // A SecurityError alone is not proof of srcdoc — an ordinary document can
35
+ // throw one too — so both the document identity and the error must match.
36
+ return isSrcdocDocument() && isSecurityError(error)
37
+ ? { outcome: "tolerated", error }
38
+ : { outcome: "rejected", error };
39
+ }
40
+ export function tryReplaceState(...args) {
19
41
  try {
20
42
  history.replaceState(...args);
43
+ return COMMITTED;
21
44
  }
22
- catch {
23
- // e.g. about:srcdoc — degrade silently, see file header.
45
+ catch (error) {
46
+ return classify(error);
24
47
  }
25
48
  }
26
- export function safePushState(...args) {
49
+ export function tryPushState(...args) {
27
50
  try {
28
51
  history.pushState(...args);
52
+ return COMMITTED;
29
53
  }
30
- catch {
31
- // e.g. about:srcdoc — degrade silently, see file header.
54
+ catch (error) {
55
+ return classify(error);
32
56
  }
33
57
  }
58
+ export function safeReplaceState(...args) {
59
+ tryReplaceState(...args);
60
+ }
34
61
  //# sourceMappingURL=history-safe.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"history-safe.js","sourceRoot":"","sources":["../../src/client-router/history-safe.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,iDAAiD;AACjD,EAAE;AACF,wEAAwE;AACxE,6EAA6E;AAC7E,gEAAgE;AAChE,4EAA4E;AAC5E,4EAA4E;AAC5E,sDAAsD;AACtD,EAAE;AACF,2EAA2E;AAC3E,oEAAoE;AACpE,EAAE;AACF,2EAA2E;AAC3E,wEAAwE;AACxE,2EAA2E;AAC3E,qDAAqD;AAErD,MAAM,UAAU,gBAAgB,CAAC,GAAG,IAAyC;IAC3E,IAAI,CAAC;QACH,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC,CAAC;IAChC,CAAC;IAAC,MAAM,CAAC;QACP,yDAAyD;IAC3D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,GAAG,IAAsC;IACrE,IAAI,CAAC;QACH,OAAO,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC;IAC7B,CAAC;IAAC,MAAM,CAAC;QACP,yDAAyD;IAC3D,CAAC;AACH,CAAC","sourcesContent":["/// <reference lib=\"dom\" />\n// zfb-only addition (no Astro upstream — #2424).\n//\n// Inside an `about:srcdoc` document (e.g. an SPA-preview iframe shell),\n// Chromium refuses `history.replaceState`/`pushState` and throws. The router\n// calls these unconditionally — at module init and from several\n// navigation-adjacent paths — so a zfb page loaded via `srcdoc` would break\n// on the very first call. These wrappers swallow that failure so the router\n// degrades silently instead of propagating the throw.\n//\n// In a normal document the History API never throws here, so the try/catch\n// is a no-op passthrough: same call, same arguments, same behavior.\n//\n// `...args` (rather than naming `data`/`unused`/`url`) preserves the exact\n// call arity — several call sites omit the trailing `url` argument, and\n// spreading a shorter tuple calls the native method with that same shorter\n// arity rather than passing an explicit `undefined`.\n\nexport function safeReplaceState(...args: Parameters<History[\"replaceState\"]>): void {\n try {\n history.replaceState(...args);\n } catch {\n // e.g. about:srcdoc — degrade silently, see file header.\n }\n}\n\nexport function safePushState(...args: Parameters<History[\"pushState\"]>): void {\n try {\n history.pushState(...args);\n } catch {\n // e.g. about:srcdoc — degrade silently, see file header.\n }\n}\n"]}
1
+ {"version":3,"file":"history-safe.js","sourceRoot":"","sources":["../../src/client-router/history-safe.ts"],"names":[],"mappings":"AAAA,2BAA2B;AAC3B,wDAAwD;AACxD,EAAE;AACF,yEAAyE;AACzE,EAAE;AACF,4EAA4E;AAC5E,gFAAgF;AAChF,4EAA4E;AAC5E,4EAA4E;AAC5E,gFAAgF;AAChF,gFAAgF;AAChF,gFAAgF;AAChF,EAAE;AACF,+EAA+E;AAC/E,4EAA4E;AAC5E,iFAAiF;AACjF,4EAA4E;AAC5E,EAAE;AACF,2EAA2E;AAC3E,wEAAwE;AACxE,2EAA2E;AAC3E,qDAAqD;AAOrD,MAAM,SAAS,GAAuB,EAAE,OAAO,EAAE,WAAW,EAAE,CAAC;AAE/D,uEAAuE;AACvE,gFAAgF;AAChF,0EAA0E;AAC1E,4EAA4E;AAC5E,sEAAsE;AACtE,MAAM,gBAAgB,GAAG,GAAY,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,cAAc,CAAC;AAEzF,MAAM,eAAe,GAAG,CAAC,KAAc,EAAW,EAAE,CAClD,OAAO,KAAK,KAAK,QAAQ;IACzB,KAAK,KAAK,IAAI;IACb,KAA4B,CAAC,IAAI,KAAK,eAAe,CAAC;AAEzD,SAAS,QAAQ,CAAC,KAAc;IAC9B,0EAA0E;IAC1E,0EAA0E;IAC1E,OAAO,gBAAgB,EAAE,IAAI,eAAe,CAAC,KAAK,CAAC;QACjD,CAAC,CAAC,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE;QACjC,CAAC,CAAC,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC;AACrC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,GAAG,IAAyC;IAC1E,IAAI,CAAC;QACH,OAAO,CAAC,YAAY,CAAC,GAAG,IAAI,CAAC,CAAC;QAC9B,OAAO,SAAS,CAAC;IACnB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,GAAG,IAAsC;IACpE,IAAI,CAAC;QACH,OAAO,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,CAAC;QAC3B,OAAO,SAAS,CAAC;IACnB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,QAAQ,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,GAAG,IAAyC;IAC3E,eAAe,CAAC,GAAG,IAAI,CAAC,CAAC;AAC3B,CAAC","sourcesContent":["/// <reference lib=\"dom\" />\n// zfb-only addition (no Astro upstream — #2424, #4127).\n//\n// The browser can refuse a History write for two very different reasons:\n//\n// - Inside an `about:srcdoc` document (e.g. an SPA-preview iframe shell),\n// Chromium refuses `history.replaceState`/`pushState` with a SecurityError.\n// The router must keep working there, so that restriction is TOLERATED.\n// - In an ordinary document the write can still be REJECTED — WebKit, for\n// example, throws once a page exceeds its History-write rate limit (#4125).\n// The URL did not change, so a caller that goes on as if it had would leave\n// the page content, the address bar and the router bookkeeping disagreeing.\n//\n// `tryPushState`/`tryReplaceState` report which of the three outcomes happened\n// so navigation code can advance its bookkeeping only on a committed write.\n// `safeReplaceState` is for metadata-only writes (the init seed, scroll-position\n// saves) whose existing contract is best-effort: it swallows every failure.\n//\n// `...args` (rather than naming `data`/`unused`/`url`) preserves the exact\n// call arity — several call sites omit the trailing `url` argument, and\n// spreading a shorter tuple calls the native method with that same shorter\n// arity rather than passing an explicit `undefined`.\n\nexport type HistoryWriteResult =\n | { readonly outcome: \"committed\" }\n | { readonly outcome: \"tolerated\"; readonly error: unknown }\n | { readonly outcome: \"rejected\"; readonly error: unknown };\n\nconst COMMITTED: HistoryWriteResult = { outcome: \"committed\" };\n\n// Identify srcdoc by the document's own address. `document.baseURI` is\n// deliberately NOT consulted: a srcdoc document inherits its parent's base URL,\n// so an HTTP baseURI says nothing about which kind of document this is. A\n// fragment navigation inside the srcdoc document keeps it a srcdoc document\n// while its URL becomes `about:srcdoc#…`, so the fragment is ignored.\nconst isSrcdocDocument = (): boolean => document.URL.split(\"#\", 1)[0] === \"about:srcdoc\";\n\nconst isSecurityError = (error: unknown): boolean =>\n typeof error === \"object\" &&\n error !== null &&\n (error as { name?: unknown }).name === \"SecurityError\";\n\nfunction classify(error: unknown): HistoryWriteResult {\n // A SecurityError alone is not proof of srcdoc — an ordinary document can\n // throw one too — so both the document identity and the error must match.\n return isSrcdocDocument() && isSecurityError(error)\n ? { outcome: \"tolerated\", error }\n : { outcome: \"rejected\", error };\n}\n\nexport function tryReplaceState(...args: Parameters<History[\"replaceState\"]>): HistoryWriteResult {\n try {\n history.replaceState(...args);\n return COMMITTED;\n } catch (error) {\n return classify(error);\n }\n}\n\nexport function tryPushState(...args: Parameters<History[\"pushState\"]>): HistoryWriteResult {\n try {\n history.pushState(...args);\n return COMMITTED;\n } catch (error) {\n return classify(error);\n }\n}\n\nexport function safeReplaceState(...args: Parameters<History[\"replaceState\"]>): void {\n tryReplaceState(...args);\n}\n"]}
@@ -27,6 +27,13 @@ export declare function getFallback(): Fallback;
27
27
  * @param options.state - Merged into the entry's `history.state`; the
28
28
  * router's own bookkeeping keys (`index`, `scrollX`, `scrollY`) always win
29
29
  * on a colliding key.
30
+ * @throws The browser's own History error, rethrown unchanged, when it rejects
31
+ * the URL write (e.g. WebKit's History-write rate limit). The router's
32
+ * tracked history index and "from" URL are left describing the entry that
33
+ * is still current; no navigation, fetch, DOM change or scroll happens. A
34
+ * push may already have saved the outgoing entry's scroll position. Inside
35
+ * an `about:srcdoc` document the browser's History restriction is tolerated
36
+ * instead: the call returns without writing or throwing.
30
37
  */
31
38
  export declare function syncHistoryEntry(url: string | URL, options?: SyncHistoryEntryOptions): void;
32
39
  export declare function navigate(href: string, options?: Options): Promise<void>;
@@ -52,7 +52,7 @@
52
52
  // - `derivePopDirection` hardens the popstate forward/back calc against an unchanged or
53
53
  // missing/NaN `state.index` that a bfcache restore can leave behind (#1076).
54
54
  import { doPreparation, doSwap, onPageLoad, triggerEvent, updateScrollPosition, } from "./events.js";
55
- import { safePushState, safeReplaceState } from "./history-safe.js";
55
+ import { safeReplaceState, tryPushState, tryReplaceState, } from "./history-safe.js";
56
56
  import { assertUniquePersistKeys, detectScriptExecuted } from "./swap-functions.js";
57
57
  // Island re-bootstrap and deferred-cancel after body swap (W1B §12.2, §12.5).
58
58
  // mountNewIslands() is called after runScripts() and before onPageLoad().
@@ -88,6 +88,11 @@ let mostRecentTransition;
88
88
  // When we traverse the history, the window.location is already set to the new location.
89
89
  // This variable tells us where we came from
90
90
  let originalLocation;
91
+ // True while the current history entry belongs to a navigation that committed
92
+ // its URL early but never rendered its page (the final write was rejected). The
93
+ // address bar then names a page the live DOM is not, so URL equality must not be
94
+ // taken as "already rendered" until a swap settles the location.
95
+ let currentEntryUnrendered = false;
91
96
  // Route announcer — ported from Astro's announce(). Each navigation appends a fresh
92
97
  // aria-live <div> (after removing any prior announcer, so exactly one ever exists) and
93
98
  // writes the new page title into it 60ms later, so screen readers announce the new page.
@@ -263,47 +268,57 @@ function runScripts() {
263
268
  }
264
269
  return wait;
265
270
  }
266
- // Add a new entry to the browser history. This also sets the new page in the browser address bar.
267
- // Sets the scroll position according to the hash fragment of the new location.
268
- const moveToLocation = (to, from, options, pageTitleForBrowserHistory, historyState,
269
- // True when transition() already committed a history entry for THIS
270
- // navigation before the swap ran (the WebKit-workaround early commit
271
- // below). `to` here may differ from that committed entry's URL if a
272
- // `zfb:before-swap` listener mutated `event.to` (writable per Astro
273
- // parity) after the early commit already ran — in that case we must
274
- // REPLACE the already-committed entry instead of pushing a second one, or
275
- // a single navigation would leave two history entries (a phantom Back
276
- // stop). #1398.
277
- historyCommittedEarly = false) => {
271
+ const UNCHANGED = { status: "unchanged" };
272
+ // Point the current history entry at `to` (push or replace), advancing the
273
+ // tracked index only once the browser has actually accepted a push.
274
+ //
275
+ // `early` is the write transition() already made for this navigation. When a
276
+ // `zfb:before-swap` listener has since changed `event.to` (writable per Astro
277
+ // parity), the already-committed entry is REPLACED rather than a second one
278
+ // pushed — one navigation must never leave a phantom Back stop (#1398).
279
+ //
280
+ // A push from inside a native View Transition update callback is not reliably
281
+ // committed by WebKit (zudolab/zzmod#662), so it is reported as rejected
282
+ // without being attempted; the caller recovers with a full document load.
283
+ const writeLocationEntry = (to, options, historyState, early, insideNativeViewTransition) => {
284
+ // A traverse already moved the browser; a srcdoc restriction is not retried.
285
+ if (historyState || early === "tolerated" || to.href === location.href)
286
+ return UNCHANGED;
287
+ const replace = options.history === "replace" || early === "committed";
288
+ let result;
289
+ if (replace) {
290
+ // `history.state` can be null or a foreign shape (page entered without a
291
+ // transition state, or written by raw-History code); fall back per field.
292
+ const current = history.state;
293
+ result = tryReplaceState({
294
+ ...options.state,
295
+ index: current != null && Number.isFinite(current.index) ? current.index : currentHistoryIndex,
296
+ scrollX: Number.isFinite(current?.scrollX) ? current.scrollX : scrollX,
297
+ scrollY: Number.isFinite(current?.scrollY) ? current.scrollY : scrollY,
298
+ }, "", to.href);
299
+ }
300
+ else {
301
+ if (insideNativeViewTransition)
302
+ return { status: "rejected", replace: false };
303
+ const index = currentHistoryIndex + 1;
304
+ result = tryPushState({ ...options.state, index, scrollX: 0, scrollY: 0 }, "", to.href);
305
+ if (result.outcome === "committed")
306
+ currentHistoryIndex = index;
307
+ }
308
+ return result.outcome === "rejected"
309
+ ? { status: "rejected", replace, error: result.error }
310
+ : { status: result.outcome };
311
+ };
312
+ // Settle the page on its new location after the entry was written: re-point
313
+ // the "from" URL and set the scroll position according to the hash fragment
314
+ // (or the traversed entry's saved scroll).
315
+ const settleLocation = (to, from, historyState) => {
278
316
  const intraPage = samePage(from, to);
279
- const targetPageTitle = document.title;
280
- document.title = pageTitleForBrowserHistory;
281
317
  let scrolledToTop = false;
282
- if (to.href !== location.href && !historyState) {
283
- if (options.history === "replace" || historyCommittedEarly) {
284
- // Astro reads current.index/scrollX/scrollY directly; `history.state` can be
285
- // null (page entered without a transition state), which would throw a
286
- // TypeError. Fall back to a synthesized state from the tracked index/scroll.
287
- const current = history.state ?? {
288
- index: currentHistoryIndex,
289
- scrollX,
290
- scrollY,
291
- };
292
- safeReplaceState({
293
- ...options.state,
294
- index: current.index,
295
- scrollX: current.scrollX,
296
- scrollY: current.scrollY,
297
- }, "", to.href);
298
- }
299
- else {
300
- safePushState({ ...options.state, index: ++currentHistoryIndex, scrollX: 0, scrollY: 0 }, "", to.href);
301
- }
302
- }
303
- document.title = targetPageTitle;
304
318
  // now we are on the new page for non-history navigation!
305
319
  // (with history navigation page change happens before popstate is fired)
306
320
  originalLocation = to;
321
+ currentEntryUnrendered = false;
307
322
  // freshly loaded pages start from the top
308
323
  if (!intraPage) {
309
324
  scrollTo({ left: 0, top: 0, behavior: "instant" });
@@ -366,6 +381,13 @@ let syncHistoryEntryOnServerWarned = false;
366
381
  * @param options.state - Merged into the entry's `history.state`; the
367
382
  * router's own bookkeeping keys (`index`, `scrollX`, `scrollY`) always win
368
383
  * on a colliding key.
384
+ * @throws The browser's own History error, rethrown unchanged, when it rejects
385
+ * the URL write (e.g. WebKit's History-write rate limit). The router's
386
+ * tracked history index and "from" URL are left describing the entry that
387
+ * is still current; no navigation, fetch, DOM change or scroll happens. A
388
+ * push may already have saved the outgoing entry's scroll position. Inside
389
+ * an `about:srcdoc` document the browser's History restriction is tolerated
390
+ * instead: the call returns without writing or throwing.
369
391
  */
370
392
  export function syncHistoryEntry(url, options = {}) {
371
393
  // SSR guard: no window/history to touch. Mirror navigate()'s server no-op +
@@ -394,13 +416,14 @@ export function syncHistoryEntry(url, options = {}) {
394
416
  if (to.origin !== location.origin) {
395
417
  throw new Error(`syncHistoryEntry(): refusing to write a cross-origin history entry for "${to.href}" (current origin: ${location.origin}).`);
396
418
  }
419
+ let write;
397
420
  if (options.replace) {
398
421
  // Replace keeps the current entry's index. A consumer migrating from raw
399
422
  // history.pushState may have left a missing/invalid index, so fall back to
400
423
  // the tracked index rather than stamping NaN/undefined.
401
424
  const current = history.state;
402
425
  const index = current != null && Number.isFinite(current.index) ? current.index : currentHistoryIndex;
403
- safeReplaceState({
426
+ write = tryReplaceState({
404
427
  ...options.state,
405
428
  index,
406
429
  scrollX: Number.isFinite(current?.scrollX) ? current.scrollX : scrollX,
@@ -415,16 +438,25 @@ export function syncHistoryEntry(url, options = {}) {
415
438
  // Stamp the CURRENT scroll on the freshly-pushed entry too — NOT (0,0).
416
439
  // This is a same-page push (dialog/photo-viewer pattern): the underlying
417
440
  // page never actually scrolled anywhere, it just gained an overlay. A
418
- // (0,0)-stamped entry would make the traverse fast-path (moveToLocation's
419
- // historyState branch below) scrollTo(0,0) when this entry is later
441
+ // (0,0)-stamped entry would make the traverse fast-path (settleLocation's
442
+ // historyState branch) scrollTo(0,0) when this entry is later
420
443
  // Forward-reopened, snapping the page to the top under the reopened
421
444
  // dialog. #1398.
422
- safePushState({ ...options.state, index: ++currentHistoryIndex, scrollX, scrollY }, "", to.href);
445
+ const index = currentHistoryIndex + 1;
446
+ write = tryPushState({ ...options.state, index, scrollX, scrollY }, "", to.href);
447
+ if (write.outcome === "committed")
448
+ currentHistoryIndex = index;
423
449
  }
424
- // Always re-point originalLocation so the next transition()/onPopState uses the
450
+ // The browser kept the old URL: report it with the browser's own error and
451
+ // leave the bookkeeping describing the entry that is actually current.
452
+ if (write.outcome === "rejected")
453
+ throw write.error;
454
+ // Re-point originalLocation so the next transition()/onPopState uses the
425
455
  // correct "from" URL. Skipping this is exactly what makes a raw pushState
426
456
  // desync the router (a same-page Back would miss the traverse fast path).
427
- originalLocation = to;
457
+ // A tolerated srcdoc restriction did not move the URL, so neither does this.
458
+ if (write.outcome === "committed")
459
+ originalLocation = to;
428
460
  }
429
461
  function preloadStyleLinks(newDocument) {
430
462
  const links = [];
@@ -460,9 +492,7 @@ function preloadStyleLinks(newDocument) {
460
492
  // if !popstate, update the history entry and scroll position according to toLocation
461
493
  // if popState is given, this holds the scroll position for history navigation
462
494
  // if fallback === "animate" then simulate view transitions
463
- async function updateDOM(preparationEvent, options, currentNavigation, currentTransition, historyState, fallback,
464
- // Forwarded to moveToLocation() — see its parameter doc. #1398.
465
- historyCommittedEarly = false) {
495
+ async function updateDOM(preparationEvent, options, currentNavigation, currentTransition, historyState, fallback, historyCommit) {
466
496
  async function animate(phase) {
467
497
  function isInfinite(animation) {
468
498
  const effect = animation.effect;
@@ -504,24 +534,37 @@ historyCommittedEarly = false) {
504
534
  // commit but before the update callback started.
505
535
  if (preparationEvent.signal.aborted)
506
536
  return finishAbortedUpdate();
507
- const pageTitleForBrowserHistory = document.title; // document.title will be overridden by swap()
537
+ let rejectedWrite = undefined;
508
538
  const swapResult = await doSwap(preparationEvent, currentTransition.viewTransition, animateFallbackOld, (event) => {
509
539
  // Teardown and swap are a synchronous point-of-no-return. doSwap checks
510
540
  // the signal after the animation await and invokes this callback only for
511
541
  // a navigation that still owns the commit.
512
542
  assertUniquePersistKeys(document, "current");
513
543
  assertUniquePersistKeys(event.newDocument, "incoming");
544
+ // Commit the final URL — a before-swap listener may have changed
545
+ // `event.to` — while the old page is still intact. Written before the
546
+ // swap, the outgoing entry also keeps the old page's title.
547
+ const write = writeLocationEntry(event.to, options, historyState, historyCommit.early, historyCommit.insideNativeViewTransition);
548
+ if (write.status === "rejected") {
549
+ rejectedWrite = write;
550
+ return false;
551
+ }
514
552
  currentNavigation.domCommitStarted = true;
515
553
  cancelPendingIslands();
516
554
  // Unmount mounted islands on the OLD body before the swap so component
517
555
  // trees receive render(null, element) / root.unmount() and their useEffect
518
556
  // cleanups fire. Pass the incoming body so persisted islands are kept.
519
557
  unmountIslands(document.body, event.newDocument.body);
558
+ return true;
520
559
  });
521
- if (!swapResult.swapped)
560
+ if (!swapResult.swapped) {
561
+ if (rejectedWrite) {
562
+ abandonNavigation(currentNavigation, swapResult.event.to, rejectedWrite, historyCommit.recoverByDocumentLoad);
563
+ }
522
564
  return finishAbortedUpdate();
565
+ }
523
566
  const swapEvent = swapResult.event;
524
- moveToLocation(swapEvent.to, swapEvent.from, options, pageTitleForBrowserHistory, historyState, historyCommittedEarly);
567
+ settleLocation(swapEvent.to, swapEvent.from, historyState);
525
568
  triggerEvent("zfb:after-swap");
526
569
  // Resolve the finished promise of the simulation's ViewTransition.
527
570
  // For 'animate', wait for the new-page animation to complete first.
@@ -542,6 +585,38 @@ function notifyNavigationAborted(navigation) {
542
585
  navigation.abortEventEmitted = true;
543
586
  triggerEvent("zfb:navigation-aborted");
544
587
  }
588
+ // End a navigation whose URL write the browser rejected, before any DOM
589
+ // change. A GET is recovered with one deliberate document load of its resolved
590
+ // destination (replacing the entry this navigation already made, or honoring
591
+ // its replace intent); anything else stays on the intact old page.
592
+ function abandonNavigation(navigation, to, write, recoverByDocumentLoad) {
593
+ if (write.error !== undefined) {
594
+ const err = write.error;
595
+ // biome-ignore lint/suspicious/noConsole: allowed
596
+ console.log("[zfb]", err?.name, err?.message);
597
+ }
598
+ // An early write may already have moved the URL; describe where the browser
599
+ // actually is rather than the location this navigation started from. Done
600
+ // before the abort event so a navigation started by a listener sees it too.
601
+ // That entry's page was never rendered, so remember the mismatch.
602
+ const actual = new URL(location.href);
603
+ if (!samePage(actual, originalLocation))
604
+ currentEntryUnrendered = true;
605
+ originalLocation = actual;
606
+ notifyNavigationAborted(navigation);
607
+ // An abort listener may have started a newer navigation, which now owns the
608
+ // page; this one must not load over it.
609
+ if (navigation.controller.signal.aborted)
610
+ return;
611
+ if (navigation === mostRecentNavigation)
612
+ mostRecentNavigation = undefined;
613
+ if (!recoverByDocumentLoad)
614
+ return;
615
+ if (write.replace)
616
+ location.replace(to.href);
617
+ else
618
+ location.href = to.href;
619
+ }
545
620
  function abortAndRecreateMostRecentNavigation() {
546
621
  const previousNavigation = mostRecentNavigation;
547
622
  const nextNavigation = {
@@ -587,14 +662,23 @@ async function transition(direction, from, to, options, historyState, hasUAVisua
587
662
  if (navigationType !== "traverse") {
588
663
  updateScrollPosition({ scrollX, scrollY });
589
664
  }
590
- if (samePage(from, to) && !options.formData) {
665
+ // An unrendered early entry shares its URL with no live DOM: never serve it
666
+ // from the current page, fetch and swap instead.
667
+ if (samePage(from, to) && !options.formData && !currentEntryUnrendered) {
591
668
  if (
592
669
  // Same-page Back/Forward: serve from the live DOM (no re-fetch/re-swap)
593
670
  // unless this page opted back into the fetch (per-request SSR). #1374/#1376.
594
671
  (navigationType === "traverse" && !traverseRefetchOptedOut()) ||
595
672
  (direction !== "back" && to.hash) ||
596
673
  (direction === "back" && from.hash)) {
597
- moveToLocation(to, from, options, document.title, historyState);
674
+ const write = writeLocationEntry(to, options, historyState, "none", false);
675
+ if (write.status === "rejected") {
676
+ // A clean abort: the page and URL stay as they are, with no fragment
677
+ // scroll and no state advance for a location that never happened.
678
+ abandonNavigation(currentNavigation, to, write, false);
679
+ return;
680
+ }
681
+ settleLocation(to, from, historyState);
598
682
  if (currentNavigation === mostRecentNavigation)
599
683
  mostRecentNavigation = undefined;
600
684
  return;
@@ -711,7 +795,16 @@ async function transition(direction, from, to, options, historyState, hasUAVisua
711
795
  notifyNavigationAborted(currentNavigation);
712
796
  return;
713
797
  }
714
- document.documentElement.setAttribute(DIRECTION_ATTR, prepEvent.direction);
798
+ // A submitted form's request may already have changed server state, so a
799
+ // rejected URL write can be neither retried as a document load nor followed
800
+ // by an SPA swap. Its single history write is therefore deferred until the
801
+ // final target is known — after zfb:before-swap, right before teardown — so
802
+ // no early entry can strand the old page under an intermediate URL. That
803
+ // write may push a new entry, which must not happen inside a native View
804
+ // Transition callback (see below), so form navigations swap through the
805
+ // simulated transition instead.
806
+ const submittedForm = options.formData !== undefined || prepEvent.formData !== undefined;
807
+ const useNativeViewTransition = supportsViewTransitions && !hasUAVisualTransition && !submittedForm;
715
808
  // Commit the SPA history entry BEFORE the transition's update callback runs.
716
809
  //
717
810
  // WebKit (all iOS browsers, incl. iOS Chrome) does not reliably commit a
@@ -720,52 +813,43 @@ async function transition(direction, from, to, options, historyState, hasUAVisua
720
813
  // updates but no new entry is created, so a single Back press falls off the
721
814
  // site to the browser home (zudolab/zzmod#662). Committing the entry here —
722
815
  // outside the transition's update callback — makes WebKit create it; Chromium
723
- // is unaffected either way. moveToLocation() (called later from updateDOM,
724
- // inside the callback) then no-ops its own push/replace via the
725
- // `to.href !== location.href` guard, since location is already at the
726
- // committed URL, so currentHistoryIndex is not double-advanced.
816
+ // is unaffected either way. The final write in updateDOM (inside the
817
+ // callback) then has nothing left to do unless a zfb:before-swap listener
818
+ // retargets `event.to`, in which case it replaces this entry.
727
819
  //
728
820
  // We use prepEvent.to (redirects are already resolved into it during
729
821
  // preparation) and write before the swap, while document.title is still the
730
- // old page's title — so the back entry keeps the correct (old-page) title
731
- // without needing moveToLocation's title juggle. Writing here also covers the
732
- // non-VT fallback path below in one place.
822
+ // old page's title — so the back entry keeps the correct (old-page) title.
823
+ // Writing here also covers the non-VT fallback path below in one place.
733
824
  //
734
825
  // Traverse (popstate) navigations carry historyState: the browser has already
735
826
  // moved, so they must NOT create a new entry here.
736
- //
737
- // Tracks whether this block ran (push OR replace) so moveToLocation (called
738
- // later, from updateDOM) knows a commit already happened for THIS navigation
739
- // — see moveToLocation's `historyCommittedEarly` parameter doc. #1398.
740
- let historyCommittedEarly = false;
741
- if (!historyState && prepEvent.to.href !== location.href) {
742
- historyCommittedEarly = true;
743
- if (options.history === "replace") {
744
- // Mirror of the moveToLocation replace-path guard: `history.state` can be
745
- // null here too (page entered without a transition state), so synthesize a
746
- // state from the tracked index/scroll instead of dereferencing null.
747
- const current = history.state ?? {
748
- index: currentHistoryIndex,
749
- scrollX,
750
- scrollY,
751
- };
752
- safeReplaceState({
753
- ...options.state,
754
- index: current.index,
755
- scrollX: current.scrollX,
756
- scrollY: current.scrollY,
757
- }, "", prepEvent.to.href);
758
- }
759
- else {
760
- safePushState({ ...options.state, index: ++currentHistoryIndex, scrollX: 0, scrollY: 0 }, "", prepEvent.to.href);
827
+ let early = "none";
828
+ if (!submittedForm) {
829
+ const write = writeLocationEntry(prepEvent.to, options, historyState, "none", false);
830
+ if (write.status === "rejected") {
831
+ // Nothing has been swapped or started yet: release the transition slot
832
+ // and let the browser load the resolved destination itself.
833
+ if (currentTransition === mostRecentTransition)
834
+ mostRecentTransition = undefined;
835
+ abandonNavigation(currentNavigation, prepEvent.to, write, true);
836
+ return;
761
837
  }
838
+ if (write.status !== "unchanged")
839
+ early = write.status;
762
840
  }
841
+ const historyCommit = {
842
+ early,
843
+ insideNativeViewTransition: useNativeViewTransition,
844
+ recoverByDocumentLoad: !submittedForm,
845
+ };
846
+ document.documentElement.setAttribute(DIRECTION_ATTR, prepEvent.direction);
763
847
  let domUpdateOutcome;
764
- if (supportsViewTransitions && !hasUAVisualTransition) {
848
+ if (useNativeViewTransition) {
765
849
  // This automatically cancels any previous transition
766
850
  // We also already took care that the earlier update callback got through
767
851
  currentTransition.viewTransition = document.startViewTransition(async () => {
768
- domUpdateOutcome = await updateDOM(prepEvent, options, currentNavigation, currentTransition, historyState, undefined, historyCommittedEarly);
852
+ domUpdateOutcome = await updateDOM(prepEvent, options, currentNavigation, currentTransition, historyState, undefined, historyCommit);
769
853
  });
770
854
  // A skipped native transition rejects ready even when its update callback
771
855
  // succeeds (or never runs). The browser does not mark ready as handled.
@@ -776,11 +860,11 @@ async function transition(direction, from, to, options, historyState, hasUAVisua
776
860
  // Simulation mode requires a bit more manual work.
777
861
  // Also used when PopStateEvent.hasUAVisualTransition indicates the browser already
778
862
  // provided a visual transition (e.g. Safari swipe gesture) — in that case, fallback
779
- // is "swap" to skip animations.
863
+ // is "swap" to skip animations. Submitted forms use it too (see submittedForm).
780
864
  const updateDone = (async () => {
781
865
  // Immediately paused to set up the ViewTransition object for Fallback mode
782
866
  await Promise.resolve(); // hop through the micro task queue
783
- domUpdateOutcome = await updateDOM(prepEvent, options, currentNavigation, currentTransition, historyState, hasUAVisualTransition ? "swap" : getFallback(), historyCommittedEarly);
867
+ domUpdateOutcome = await updateDOM(prepEvent, options, currentNavigation, currentTransition, historyState, hasUAVisualTransition ? "swap" : getFallback(), historyCommit);
784
868
  return undefined;
785
869
  })();
786
870
  // When the updateDone promise is settled,
@@ -950,6 +1034,7 @@ const onPageShow = (ev) => {
950
1034
  // both here so the next transition() gets the correct `from` URL (a stale
951
1035
  // `originalLocation` would feed onPopState the wrong origin).
952
1036
  originalLocation = new URL(location.href);
1037
+ currentEntryUnrendered = false;
953
1038
  const index = history.state?.index;
954
1039
  if (Number.isFinite(index)) {
955
1040
  currentHistoryIndex = index;
@@ -1201,6 +1286,7 @@ export function init(_options) {
1201
1286
  // syncHistoryEntry() already primed it via ensureNavigationState().
1202
1287
  navigationStateSeeded = true;
1203
1288
  originalLocation = new URL(location.href);
1289
+ currentEntryUnrendered = false;
1204
1290
  registerNavigationListeners();
1205
1291
  document.addEventListener("click", handleClick);
1206
1292
  document.addEventListener("submit", handleSubmit);
@@ -1 +1 @@
1
- {"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/client-router/router.ts"],"names":[],"mappings":"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","sourcesContent":["/// <reference lib=\"dom\" />\n/// <reference lib=\"dom.iterable\" />\n// Ported from Astro transitions/router.ts (transition orchestration half).\n// Source: https://raw.githubusercontent.com/withastro/astro/main/packages/astro/src/transitions/router.ts\n// Issue: zudolab/zudo-doc#1516 (W3C1), parent epic zudolab/zudo-doc#1510.\n//\n// Mechanical renames per W1B §13.5:\n// astro:* event names → zfb:*\n// data-astro-* attributes → data-zfb-*\n// astro-view-transitions-* → zfb-view-transitions-*\n// .astro-route-announcer → .zfb-route-announcer\n// dataset.astroExec → dataset.zfbExec\n// dataset.astroHistory → dataset.zfbHistory\n// dataset.astroRerun → dataset.zfbRerun\n//\n// Named-cause deviations:\n// - `internalFetchHeaders` import dropped; replaced with `{}` (W1B §13.5 — zfb adapters\n// do not currently expose a per-fetch internal-headers contract).\n// - `prepareForClientOnlyComponents` dropped entirely (W1B §13.5 / W3C2 — DEV-only\n// iframe trick that compensates for Vite per-component CSS injection on hydrate;\n// not applicable to zfb islands which inject CSS via the bundle).\n// - `import.meta.env.SSR` access uses `(import.meta as any).env?.SSR` (no Vite\n// ambient types in zfb-runtime tsconfig — same workaround used in W3B).\n// - `inBrowser` evaluates to `typeof document !== \"undefined\"` rather than relying\n// on the SSR flag, because the runtime package serves both server- and client-side\n// code; same observable behavior in browser and on SSR.\n// - `announce()` was a TODO stub at W1B port time; W3C3 implemented it and #1063 gave\n// its 60ms timer explicit lifecycle ownership — see the route-announcer block below.\n//\n// W3C2 additions (this file):\n// - `navigate()` public entry.\n// - `onPopState`, `onScrollEnd`.\n// - Seeding `currentHistoryIndex` from `history.state`, registering popstate /\n// load / scrollend listeners, and marking already-executed scripts with\n// `dataset[\"zfbExec\"] = \"\"`. W3C2 did all of this in two bare top-level\n// `if (inBrowser)` blocks; #2436 folded both into `init()` (see the two\n// once-guards there) so evaluating this module has no side effect at all.\n//\n// W3C1 items deferred to — and since implemented in — W3C3:\n// - `announce()` route-announcer implementation (see the route-announcer block below;\n// timer lifecycle ownership hardened in #1063).\n// - Click + form intercept (see `handleClick` / `handleSubmit` / `init()` below).\n//\n// zfb-only additions (no Astro upstream — #1076):\n// - `onPageShow` pageshow/bfcache re-sync, registered inside the init block alongside\n// popstate/load/scrollend. Verified against live Astro `main`: neither\n// `transitions/router.ts` nor `ClientRouter.astro` has any pageshow/`persisted`\n// handler, so this is original design, not a port. WebKit serves Back after an SPA\n// route change from the bfcache without re-evaluating this module, desyncing the\n// tracked `currentHistoryIndex` from the live history stack; `onPageShow` re-seeds it\n// (and restores scroll) on a persisted restore — see the `onPageShow` block below.\n// - `derivePopDirection` hardens the popstate forward/back calc against an unchanged or\n// missing/NaN `state.index` that a bfcache restore can leave behind (#1076).\n\nimport {\n doPreparation,\n doSwap,\n onPageLoad,\n triggerEvent,\n updateScrollPosition,\n type TransitionBeforePreparationEvent,\n} from \"./events.js\";\nimport { safePushState, safeReplaceState } from \"./history-safe.js\";\nimport { assertUniquePersistKeys, detectScriptExecuted } from \"./swap-functions.js\";\nimport type { Direction, Fallback, Options, SyncHistoryEntryOptions } from \"./types.js\";\n// Island re-bootstrap and deferred-cancel after body swap (W1B §12.2, §12.5).\n// mountNewIslands() is called after runScripts() and before onPageLoad().\n// cancelPendingIslands() and unmountIslands() run inside doSwap()'s synchronous\n// commit section so deferred callbacks cannot fire against orphan elements.\nimport { cancelPendingIslands, mountNewIslands, unmountIslands } from \"@takazudo/zfb/runtime\";\n\ntype State = {\n index: number;\n scrollX: number;\n scrollY: number;\n};\ntype Navigation = {\n controller: AbortController;\n domCommitStarted: boolean;\n abortEventEmitted: boolean;\n};\ntype Transition = {\n // The view transitions object (API and simulation)\n viewTransition?: ViewTransition;\n // Simulation: Whether transition was skipped\n transitionSkipped: boolean;\n // Simulation: The resolve function of the finished promise\n viewTransitionFinished?: () => void;\n};\n\ntype DOMUpdateOutcome = \"swapped\" | \"aborted\";\n\n// Adapter-specific internal fetch headers. zfb adapters do not currently expose this\n// contract — the empty object preserves the call-shape so the loop in fetchHTML is a\n// no-op until/unless an adapter wires this up.\nconst internalFetchHeaders: Record<string, string> = {};\n\n// Detect browser context. Astro uses `import.meta.env.SSR === false` (Vite-injected).\n// The zfb-runtime tsconfig has no Vite ambient types; checking for `document` is\n// behaviorally identical and avoids a Vite type dependency.\nconst inBrowser = typeof document !== \"undefined\";\n\nexport const supportsViewTransitions = inBrowser && !!document.startViewTransition;\n\nexport const transitionEnabledOnThisPage = () =>\n inBrowser && !!document.querySelector('[name=\"zfb-view-transitions-enabled\"]');\n\n// A same-page Back/Forward traversal (two history entries sharing pathname +\n// search) is served from the live DOM by the fast-path in transition() — no\n// re-fetch, no re-swap, no lifecycle events. A per-request SSR page\n// (`prerender = false`) whose server output can differ between two visits to\n// the SAME url opts back INTO the fetch by emitting\n// <meta name=\"zfb-traverse-refetch\" content=\"true\"> (via <ClientRouter\n// traverseRefetch />); skipping the fetch on such a page would pin the stale\n// first-render content. Read from the CURRENT document — for a same-page\n// traverse the current document IS the target page. Mirrors the\n// zfb-prefetch-disabled meta reader. (#1376)\nconst traverseRefetchOptedOut = () =>\n inBrowser && !!document.querySelector('meta[name=\"zfb-traverse-refetch\"][content=\"true\"]');\n\nconst samePage = (thisLocation: URL, otherLocation: URL) =>\n thisLocation.pathname === otherLocation.pathname && thisLocation.search === otherLocation.search;\n\n// The previous navigation that might still be in processing\nlet mostRecentNavigation: Navigation | undefined;\n// The previous transition that might still be in processing\nlet mostRecentTransition: Transition | undefined;\n// When we traverse the history, the window.location is already set to the new location.\n// This variable tells us where we came from\nlet originalLocation: URL;\n\n// Route announcer — ported from Astro's announce(). Each navigation appends a fresh\n// aria-live <div> (after removing any prior announcer, so exactly one ever exists) and\n// writes the new page title into it 60ms later, so screen readers announce the new page.\n//\n// zfb deviation from Astro / design decision for #1063 (timer lifecycle ownership):\n// - The 60ms timer id is stored and cleared when a newer navigation supersedes a\n// still-pending announcement, so a superseded page's title is never written to a\n// now-detached announcer. (Astro leaves the timer fire-and-forget.)\n// - The previous announcer is removed before a new one is appended, so they never\n// accumulate. We deliberately do NOT *reuse* one element across navigations (which\n// #1063 floated): a reused live region is detached and re-inserted into the a11y\n// tree on every body swap, and a repeated title would be a no-op text write — both\n// make re-announcement unreliable across screen readers. Creating a fresh empty\n// element and writing text 60ms later is Astro's proven, reliable announce trigger.\n//\n// The 60ms delay is Astro's magic number: screen readers need to see the element change\n// and may miss it if it happens too quickly.\nlet announceTimer: number | undefined;\n\nconst announce = () => {\n // A newer navigation supersedes any still-pending announcement: cancel the old\n // timer so it can't write a now-stale title after this navigation's swap.\n if (announceTimer !== undefined) window.clearTimeout(announceTimer);\n\n // Keep exactly one announcer: drop any leftover from a prior navigation that the\n // body swap did not already detach.\n document.querySelector(\".zfb-route-announcer\")?.remove();\n const div = document.createElement(\"div\");\n div.setAttribute(\"aria-live\", \"assertive\");\n div.setAttribute(\"aria-atomic\", \"true\");\n div.className = \"zfb-route-announcer\";\n document.body.append(div);\n\n announceTimer = window.setTimeout(() => {\n announceTimer = undefined;\n // This timer can outlive its document context — a test-env teardown\n // (vitest/happy-dom) or a real page unload removes `document` (and\n // `location`) before the 60ms elapses. `typeof` is safe even when the\n // global is gone, so bail out instead of throwing an unhandled\n // ReferenceError (#1061); the announcement is moot once the page is gone.\n // Both globals the callback dereferences are checked, not just `document`.\n if (typeof document === \"undefined\" || typeof location === \"undefined\") return;\n const title = document.title || document.querySelector(\"h1\")?.textContent || location.pathname;\n div.textContent = title;\n }, 60);\n};\n\nconst PERSIST_ATTR = \"data-zfb-transition-persist\";\n\nconst attrValueSelector = (attr: string, value: string): string =>\n value === \"\" ? `[${attr}=\"\"]` : `[${attr}=${CSS.escape(value)}]`;\n\nconst querySelectorWithAttrValue = (\n root: ParentNode,\n selectorPrefix: string,\n attr: string,\n value: string,\n): Element | null => {\n const escapedMatch = root.querySelector(`${selectorPrefix}${attrValueSelector(attr, value)}`);\n if (escapedMatch) return escapedMatch;\n return (\n Array.from(root.querySelectorAll(`${selectorPrefix}[${attr}]`)).find(\n (el) => el.getAttribute(attr) === value,\n ) ?? null\n );\n};\nconst DIRECTION_ATTR = \"data-zfb-transition\";\nconst OLD_NEW_ATTR = \"data-zfb-transition-fallback\";\n\nlet parser: DOMParser;\n\n// The History API does not tell you if navigation is forward or back, so\n// you can figure it using an index. On pushState the index is incremented so you\n// can use that to determine popstate if going forward or back.\nlet currentHistoryIndex = 0;\n\n// Once-guard for the navigation bookkeeping below. `init()` sets it too, so a\n// later ensureNavigationState() can never clobber the activation-time seed.\nlet navigationStateSeeded = false;\n\n/**\n * Seed the module's navigation bookkeeping — `originalLocation` (declared\n * without an initializer) and the tracked history index — from the live\n * document, once.\n *\n * Deliberately side-effect free beyond those two variables: it registers no\n * listener, writes no history entry, never scrolls, and never marks scripts.\n * All of that belongs to {@link init}. Its only job is to keep an init-less\n * `navigate()` / `syncHistoryEntry()` from reading `undefined` or stamping a\n * fresh entry with the module default index — using the router without\n * activating it is documented as unsupported, but it must not throw and must\n * not mis-stamp. An existing finite `history.state.index` is ADOPTED, never\n * reset: on a page whose entry is already index 7, the next push must be 8. (#2436)\n */\nfunction ensureNavigationState(): void {\n if (navigationStateSeeded || !inBrowser) return;\n navigationStateSeeded = true;\n originalLocation = new URL(location.href);\n const index = history.state?.index;\n if (Number.isFinite(index)) currentHistoryIndex = index;\n}\n\n// returns the contents of the page or null if the router can't deal with it.\nasync function fetchHTML(\n href: string,\n init?: RequestInit,\n): Promise<null | { html: string; redirected?: string; mediaType: DOMParserSupportedType }> {\n try {\n // Apply adapter-specific headers for internal fetches\n const headers = new Headers(init?.headers);\n for (const [key, value] of Object.entries(internalFetchHeaders) as [string, string][]) {\n headers.set(key, value);\n }\n const res = await fetch(href, { ...init, headers });\n const contentType = res.headers.get(\"content-type\") ?? \"\";\n // drop potential charset (+ other name/value pairs) as parser needs the mediaType\n const mediaType = contentType.split(\";\", 1)[0]!.trim();\n // the DOMParser can handle two types of HTML\n if (mediaType !== \"text/html\" && mediaType !== \"application/xhtml+xml\") {\n // everything else (e.g. audio/mp3) will be handled by the browser but not by us\n return null;\n }\n const html = await res.text();\n // exactOptionalPropertyTypes: true forbids assigning `undefined` to a `redirected?: string`\n // slot, so omit the property when not redirected instead of setting it to undefined.\n return res.redirected ? { html, redirected: res.url, mediaType } : { html, mediaType };\n } catch {\n // can't fetch, let someone else deal with it.\n return null;\n }\n}\n\nexport function getFallback(): Fallback {\n const el = document.querySelector('[name=\"zfb-view-transitions-fallback\"]');\n if (el) {\n // Astro casts `content` straight to Fallback; harden against an arbitrary/typo'd\n // attribute value by validating against the known set and defaulting to \"animate\".\n const content = el.getAttribute(\"content\");\n if (content === \"none\" || content === \"animate\" || content === \"swap\") {\n return content;\n }\n }\n return \"animate\";\n}\n\n// Upper bound (ms) for waiting on a single external <script>'s load/error in\n// runScripts(). Not an Astro upstream value — added so a slow/broken external\n// script can never hang the transition indefinitely.\nconst EXTERNAL_SCRIPT_WAIT_TIMEOUT = 5000;\n\nfunction runScripts() {\n let wait = Promise.resolve();\n let needsWaitForInlineModuleScript = false;\n // The original code made the assumption that all inline scripts are directly executed when inserted into the DOM.\n // This is not true for inline module scripts, which are deferred but still executed in order.\n // inline module scripts cannot be awaited for with onload.\n // Thus to be able to wait for the execution of all scripts, we make sure that the last inline module script\n // is always followed by an external module script\n for (const script of document.getElementsByTagName(\"script\")) {\n script.dataset[\"zfbExec\"] === undefined &&\n script.getAttribute(\"type\") === \"module\" &&\n (needsWaitForInlineModuleScript = script.getAttribute(\"src\") === null);\n }\n needsWaitForInlineModuleScript &&\n document.body.insertAdjacentHTML(\n \"beforeend\",\n `<script type=\"module\" src=\"data:application/javascript,\"/>`,\n );\n\n for (const script of document.getElementsByTagName(\"script\")) {\n if (script.dataset[\"zfbExec\"] === \"\") continue;\n const type = script.getAttribute(\"type\");\n if (type && type !== \"module\" && type !== \"text/javascript\") continue;\n const newScript = document.createElement(\"script\");\n newScript.innerHTML = script.innerHTML;\n for (const attr of script.attributes) {\n if (attr.name === \"src\") {\n // Astro awaits onload/onerror with no upper bound; a slow or broken\n // external <script> would then hang the whole transition. Race the\n // load against a timeout so the transition can always proceed.\n const p = new Promise<void>((r) => {\n let timer: ReturnType<typeof setTimeout>;\n const done = () => {\n clearTimeout(timer);\n r();\n };\n newScript.onload = newScript.onerror = done;\n timer = setTimeout(done, EXTERNAL_SCRIPT_WAIT_TIMEOUT);\n });\n wait = wait.then(() => p as any);\n }\n newScript.setAttribute(attr.name, attr.value);\n }\n newScript.dataset[\"zfbExec\"] = \"\";\n script.replaceWith(newScript);\n }\n return wait;\n}\n\n// Add a new entry to the browser history. This also sets the new page in the browser address bar.\n// Sets the scroll position according to the hash fragment of the new location.\nconst moveToLocation = (\n to: URL,\n from: URL,\n options: Options,\n pageTitleForBrowserHistory: string,\n historyState?: State,\n // True when transition() already committed a history entry for THIS\n // navigation before the swap ran (the WebKit-workaround early commit\n // below). `to` here may differ from that committed entry's URL if a\n // `zfb:before-swap` listener mutated `event.to` (writable per Astro\n // parity) after the early commit already ran — in that case we must\n // REPLACE the already-committed entry instead of pushing a second one, or\n // a single navigation would leave two history entries (a phantom Back\n // stop). #1398.\n historyCommittedEarly = false,\n) => {\n const intraPage = samePage(from, to);\n\n const targetPageTitle = document.title;\n document.title = pageTitleForBrowserHistory;\n\n let scrolledToTop = false;\n if (to.href !== location.href && !historyState) {\n if (options.history === \"replace\" || historyCommittedEarly) {\n // Astro reads current.index/scrollX/scrollY directly; `history.state` can be\n // null (page entered without a transition state), which would throw a\n // TypeError. Fall back to a synthesized state from the tracked index/scroll.\n const current = history.state ?? {\n index: currentHistoryIndex,\n scrollX,\n scrollY,\n };\n safeReplaceState(\n {\n ...options.state,\n index: current.index,\n scrollX: current.scrollX,\n scrollY: current.scrollY,\n },\n \"\",\n to.href,\n );\n } else {\n safePushState(\n { ...options.state, index: ++currentHistoryIndex, scrollX: 0, scrollY: 0 },\n \"\",\n to.href,\n );\n }\n }\n document.title = targetPageTitle;\n // now we are on the new page for non-history navigation!\n // (with history navigation page change happens before popstate is fired)\n originalLocation = to;\n\n // freshly loaded pages start from the top\n if (!intraPage) {\n scrollTo({ left: 0, top: 0, behavior: \"instant\" });\n scrolledToTop = true;\n }\n\n if (historyState) {\n // Raw-History consumers may push partial/empty state (`{}`), so the tracked\n // scroll fields can be absent or non-finite. Never scrollTo(undefined, …) —\n // leave scroll where it is rather than jumping to (0,0). #1376.\n if (Number.isFinite(historyState.scrollX) && Number.isFinite(historyState.scrollY)) {\n scrollTo(historyState.scrollX, historyState.scrollY);\n }\n } else {\n if (to.hash) {\n // because we are already on the target page ...\n // ... what comes next is an intra-page navigation\n // that won't reload the page but instead scroll to the fragment\n history.scrollRestoration = \"auto\";\n const savedState = history.state;\n location.href = to.href; // this kills the history state on Firefox\n if (!history.state) {\n safeReplaceState(savedState, \"\"); // this restores the history state\n if (intraPage) {\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n }\n }\n } else {\n if (!scrolledToTop) {\n scrollTo({ left: 0, top: 0, behavior: \"instant\" });\n }\n }\n history.scrollRestoration = \"manual\";\n }\n};\n\nlet syncHistoryEntryOnServerWarned = false;\n\n/**\n * Write a router-managed history entry (push or replace) WITHOUT any\n * navigation, DOM, or lifecycle side effect. This is the supported path for\n * consumers deep-linking transient UI state (dialogs/modals, a photo\n * viewer's `/photos/<slug>/` URL). Hand-rolled raw `history.pushState`\n * desyncs `originalLocation` and the index bookkeeping that popstate\n * direction detection ({@link derivePopDirection}) and the same-page\n * traverse fast-path depend on; `navigate()` can't be used instead because\n * it forces a fetch. See #1377 / #1374.\n *\n * Never scrolls the viewport itself — but the entry it writes IS stamped\n * with the CURRENT scroll position (`scrollX`/`scrollY` at call time), not\n * `(0, 0)` (issue #1398). This matters only for a later Forward-traversal\n * back to this entry: the same-page traverse fast-path restores whatever\n * scroll position was stamped on the entry, so a same-page push (e.g.\n * opening a dialog) does not snap the underlying page to the top when the\n * dialog is later reopened via Forward.\n *\n * @param url - The URL to write. Cross-origin URLs throw rather than\n * silently falling back to a full-page load.\n * @param options.replace - Use `history.replaceState` instead of\n * `history.pushState` (no new Back-button entry). Default: push.\n * @param options.state - Merged into the entry's `history.state`; the\n * router's own bookkeeping keys (`index`, `scrollX`, `scrollY`) always win\n * on a colliding key.\n */\nexport function syncHistoryEntry(url: string | URL, options: SyncHistoryEntryOptions = {}): void {\n // SSR guard: no window/history to touch. Mirror navigate()'s server no-op +\n // one-time console warning. Checked at call time via `typeof document` (not the\n // module-eval `inBrowser` const) so the branch is reachable and behavior is\n // identical in a real environment (document is always present in a browser).\n if (typeof document === \"undefined\") {\n if (!syncHistoryEntryOnServerWarned) {\n // instantiate an error for the stacktrace to show to user.\n const warning = new Error(\n \"syncHistoryEntry() was called during a server side render. This may be unintentional as it is expected to be called in response to a client-side user interaction. Please make sure that your usage is correct.\",\n );\n warning.name = \"Warning\";\n // biome-ignore lint/suspicious/noConsole: allowed\n console.warn(warning);\n syncHistoryEntryOnServerWarned = true;\n }\n return;\n }\n\n // Adopt this page's existing history index before stamping an entry — an\n // init-less caller must not reset a live entry's index to the module default.\n ensureNavigationState();\n\n const to = new URL(url, location.href);\n\n // Cross-origin is not ours to manage. The History API would throw a native\n // SecurityError for a cross-origin URL, but we guard explicitly so the failure\n // is a clear, documented contract violation rather than an opaque platform\n // error — and never a silent full-page load. #1377.\n if (to.origin !== location.origin) {\n throw new Error(\n `syncHistoryEntry(): refusing to write a cross-origin history entry for \"${to.href}\" (current origin: ${location.origin}).`,\n );\n }\n\n if (options.replace) {\n // Replace keeps the current entry's index. A consumer migrating from raw\n // history.pushState may have left a missing/invalid index, so fall back to\n // the tracked index rather than stamping NaN/undefined.\n const current = history.state;\n const index =\n current != null && Number.isFinite(current.index) ? current.index : currentHistoryIndex;\n safeReplaceState(\n {\n ...options.state,\n index,\n scrollX: Number.isFinite(current?.scrollX) ? current.scrollX : scrollX,\n scrollY: Number.isFinite(current?.scrollY) ? current.scrollY : scrollY,\n },\n \"\",\n to.href,\n );\n } else {\n // Persist the CURRENT (outgoing) entry's latest scroll before pushing, so a\n // later Back restoration can't lose scroll that `scrollend` hasn't flushed\n // yet — the same guard transition() applies before a non-traverse push.\n updateScrollPosition({ scrollX, scrollY });\n // Stamp the CURRENT scroll on the freshly-pushed entry too — NOT (0,0).\n // This is a same-page push (dialog/photo-viewer pattern): the underlying\n // page never actually scrolled anywhere, it just gained an overlay. A\n // (0,0)-stamped entry would make the traverse fast-path (moveToLocation's\n // historyState branch below) scrollTo(0,0) when this entry is later\n // Forward-reopened, snapping the page to the top under the reopened\n // dialog. #1398.\n safePushState(\n { ...options.state, index: ++currentHistoryIndex, scrollX, scrollY },\n \"\",\n to.href,\n );\n }\n\n // Always re-point originalLocation so the next transition()/onPopState uses the\n // correct \"from\" URL. Skipping this is exactly what makes a raw pushState\n // desync the router (a same-page Back would miss the traverse fast path).\n originalLocation = to;\n}\n\nfunction preloadStyleLinks(newDocument: Document) {\n const links: Promise<any>[] = [];\n for (const el of newDocument.querySelectorAll(\"head link[rel=stylesheet]\")) {\n const persistId = el.getAttribute(PERSIST_ATTR);\n const href = el.getAttribute(\"href\");\n const existingSelectors = [\n persistId !== null ? attrValueSelector(PERSIST_ATTR, persistId) : null,\n href !== null ? `link[rel=stylesheet]${attrValueSelector(\"href\", href)}` : null,\n ].filter((selector): selector is string => selector !== null);\n const existingLink =\n (existingSelectors.length ? document.querySelector(existingSelectors.join(\", \")) : null) ??\n (persistId !== null\n ? querySelectorWithAttrValue(document, \"\", PERSIST_ATTR, persistId)\n : null) ??\n (href !== null\n ? querySelectorWithAttrValue(document, \"link[rel=stylesheet]\", \"href\", href)\n : null);\n\n // Do not preload links that are already on the page.\n if (href !== null && !existingLink) {\n const c = document.createElement(\"link\");\n c.setAttribute(\"rel\", \"preload\");\n c.setAttribute(\"as\", \"style\");\n c.setAttribute(\"href\", href);\n links.push(\n new Promise<any>((resolve) => {\n [\"load\", \"error\"].forEach((evName) => c.addEventListener(evName, resolve));\n document.head.append(c);\n }),\n );\n }\n }\n return links;\n}\n\n// replace head and body of the windows document with contents from newDocument\n// if !popstate, update the history entry and scroll position according to toLocation\n// if popState is given, this holds the scroll position for history navigation\n// if fallback === \"animate\" then simulate view transitions\nasync function updateDOM(\n preparationEvent: TransitionBeforePreparationEvent,\n options: Options,\n currentNavigation: Navigation,\n currentTransition: Transition,\n historyState?: State,\n fallback?: Fallback,\n // Forwarded to moveToLocation() — see its parameter doc. #1398.\n historyCommittedEarly = false,\n): Promise<DOMUpdateOutcome> {\n async function animate(phase: string) {\n function isInfinite(animation: Animation) {\n const effect = animation.effect;\n if (!effect || !(effect instanceof KeyframeEffect) || !effect.target) return false;\n const style = window.getComputedStyle(effect.target, effect.pseudoElement);\n return style.animationIterationCount === \"infinite\";\n }\n const currentAnimations = document.getAnimations();\n // Trigger view transition animations waiting for data-zfb-transition-fallback\n document.documentElement.setAttribute(OLD_NEW_ATTR, phase);\n const nextAnimations = document.getAnimations();\n const newAnimations = nextAnimations.filter(\n (a) => !currentAnimations.includes(a) && !isInfinite(a),\n );\n // Wait for all new animations to finish (resolved or rejected).\n // Do not reject on canceled ones.\n return Promise.allSettled(newAnimations.map((a) => a.finished));\n }\n\n const animateFallbackOld = async () => {\n if (\n fallback === \"animate\" &&\n !currentTransition.transitionSkipped &&\n !preparationEvent.signal.aborted\n ) {\n try {\n await animate(\"old\");\n } catch {\n // animate might reject as a consequence of a call to skipTransition()\n // ignored on purpose\n }\n }\n };\n\n const finishAbortedUpdate = (): DOMUpdateOutcome => {\n notifyNavigationAborted(currentNavigation);\n // Simulation owns its `finished` promise explicitly. Resolve it on the\n // no-swap path so transition cleanup still runs.\n currentTransition.viewTransitionFinished?.();\n return \"aborted\";\n };\n\n // A newer navigation or popstate may have won after preparation/history\n // commit but before the update callback started.\n if (preparationEvent.signal.aborted) return finishAbortedUpdate();\n\n const pageTitleForBrowserHistory = document.title; // document.title will be overridden by swap()\n const swapResult = await doSwap(\n preparationEvent,\n currentTransition.viewTransition!,\n animateFallbackOld,\n (event) => {\n // Teardown and swap are a synchronous point-of-no-return. doSwap checks\n // the signal after the animation await and invokes this callback only for\n // a navigation that still owns the commit.\n assertUniquePersistKeys(document, \"current\");\n assertUniquePersistKeys(event.newDocument, \"incoming\");\n currentNavigation.domCommitStarted = true;\n cancelPendingIslands();\n // Unmount mounted islands on the OLD body before the swap so component\n // trees receive render(null, element) / root.unmount() and their useEffect\n // cleanups fire. Pass the incoming body so persisted islands are kept.\n unmountIslands(document.body, event.newDocument.body);\n },\n );\n if (!swapResult.swapped) return finishAbortedUpdate();\n\n const swapEvent = swapResult.event;\n moveToLocation(\n swapEvent.to,\n swapEvent.from,\n options,\n pageTitleForBrowserHistory,\n historyState,\n historyCommittedEarly,\n );\n triggerEvent(\"zfb:after-swap\");\n\n // Resolve the finished promise of the simulation's ViewTransition.\n // For 'animate', wait for the new-page animation to complete first.\n // For other fallback modes (e.g. 'swap'), resolve immediately — no animation needed.\n if (fallback === \"animate\" && !currentTransition.transitionSkipped) {\n animate(\"new\").finally(() => currentTransition.viewTransitionFinished!());\n } else {\n currentTransition.viewTransitionFinished?.();\n }\n return \"swapped\";\n}\n\nfunction notifyNavigationAborted(navigation: Navigation): void {\n // From island teardown onward the navigation is committed and must finish,\n // even if an overridden event.swap() synchronously starts a newer one.\n if (navigation.domCommitStarted || navigation.abortEventEmitted) return;\n navigation.abortEventEmitted = true;\n triggerEvent(\"zfb:navigation-aborted\");\n}\n\nfunction abortAndRecreateMostRecentNavigation(): Navigation {\n const previousNavigation = mostRecentNavigation;\n const nextNavigation: Navigation = {\n controller: new AbortController(),\n domCommitStarted: false,\n abortEventEmitted: false,\n };\n // Install the new owner before abort/event dispatch. Either operation can\n // synchronously re-enter navigate(); that newer call must remain the winner.\n mostRecentNavigation = nextNavigation;\n if (previousNavigation) {\n previousNavigation.controller.abort();\n // Native View Transitions may settle updateCallbackDone without ever\n // invoking the skipped update callback. Emit here so updateDOM is not the\n // only observer of a real pre-commit abort.\n notifyNavigationAborted(previousNavigation);\n }\n return nextNavigation;\n}\n\nasync function transition(\n direction: Direction,\n from: URL,\n to: URL,\n options: Options,\n historyState?: State,\n hasUAVisualTransition = false,\n) {\n // The most recent navigation always has precedence\n // Yes, there can be several navigation instances as the user can click links\n // while we fetch content or simulate view transitions. Even synchronous creations are possible\n // e.g. by calling navigate() from a transition event.\n // Invariant: all but the most recent navigation are already aborted.\n\n const currentNavigation = abortAndRecreateMostRecentNavigation();\n\n // Emitting the previous navigation's abort event is synchronous. A listener\n // may have started an even newer navigation before this call resumes.\n if (currentNavigation.controller.signal.aborted) return;\n\n // not ours\n if (!transitionEnabledOnThisPage() || location.origin !== to.origin) {\n if (currentNavigation === mostRecentNavigation) mostRecentNavigation = undefined;\n location.href = to.href;\n return;\n }\n\n const navigationType = historyState\n ? \"traverse\"\n : options.history === \"replace\"\n ? \"replace\"\n : \"push\";\n\n if (navigationType !== \"traverse\") {\n updateScrollPosition({ scrollX, scrollY });\n }\n if (samePage(from, to) && !options.formData) {\n if (\n // Same-page Back/Forward: serve from the live DOM (no re-fetch/re-swap)\n // unless this page opted back into the fetch (per-request SSR). #1374/#1376.\n (navigationType === \"traverse\" && !traverseRefetchOptedOut()) ||\n (direction !== \"back\" && to.hash) ||\n (direction === \"back\" && from.hash)\n ) {\n moveToLocation(to, from, options, document.title, historyState);\n if (currentNavigation === mostRecentNavigation) mostRecentNavigation = undefined;\n return;\n }\n }\n\n const prepEvent = await doPreparation(\n from,\n to,\n direction,\n navigationType,\n options.sourceElement,\n options.info,\n currentNavigation!.controller.signal,\n options.formData,\n defaultLoader,\n );\n if (prepEvent.defaultPrevented || prepEvent.signal.aborted) {\n if (currentNavigation === mostRecentNavigation) mostRecentNavigation = undefined;\n notifyNavigationAborted(currentNavigation);\n if (!prepEvent.signal.aborted) {\n // not aborted -> delegate to browser\n location.href = to.href;\n }\n // and / or exit\n return;\n }\n\n async function defaultLoader(preparationEvent: TransitionBeforePreparationEvent) {\n const href = preparationEvent.to.href;\n const init: RequestInit = { signal: preparationEvent.signal };\n if (preparationEvent.formData) {\n init.method = \"POST\";\n const form =\n preparationEvent.sourceElement instanceof HTMLFormElement\n ? preparationEvent.sourceElement\n : preparationEvent.sourceElement instanceof HTMLElement &&\n \"form\" in preparationEvent.sourceElement\n ? (preparationEvent.sourceElement.form as HTMLFormElement)\n : preparationEvent.sourceElement?.closest(\"form\");\n // Form elements without enctype explicitly set default to application/x-www-form-urlencoded.\n // In order to maintain compatibility with Astro 4.x, we need to check the value of enctype\n // on the attributes property rather than accessing .enctype directly. Astro 5.x may\n // introduce defaulting to application/x-www-form-urlencoded as a breaking change, and then\n // we can access .enctype directly.\n //\n // Note: getNamedItem can return null in real life, even if TypeScript doesn't think so, hence\n // the ?.\n // `form` can be null (closest() miss, or a form-less form-associated\n // element) — `!= null` covers both null and undefined so Reflect.get\n // is never invoked on a non-element receiver (\"Illegal invocation\").\n init.body =\n form != null &&\n Reflect.get(HTMLFormElement.prototype, \"attributes\", form).getNamedItem(\"enctype\")\n ?.value === \"application/x-www-form-urlencoded\"\n ? new URLSearchParams(preparationEvent.formData as any)\n : preparationEvent.formData;\n }\n const response = await fetchHTML(href, init);\n // If there is a problem fetching the new page, just do an MPA navigation to it.\n if (response === null) {\n preparationEvent.preventDefault();\n return;\n }\n // if there was a redirection, show the final URL in the browser's address bar\n if (response.redirected) {\n const redirectedTo = new URL(response.redirected);\n // but do not redirect cross origin\n if (redirectedTo.origin !== preparationEvent.to.origin) {\n preparationEvent.preventDefault();\n return;\n }\n // preserve fragment\n const fragment = preparationEvent.to.hash;\n preparationEvent.to = redirectedTo;\n preparationEvent.to.hash = fragment;\n }\n\n parser ??= new DOMParser();\n\n preparationEvent.newDocument = parser.parseFromString(response.html, response.mediaType);\n // The next line might look like a hack,\n // but it is actually necessary as noscript elements\n // and their contents are returned as markup by the parser,\n // see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString\n preparationEvent.newDocument.querySelectorAll(\"noscript\").forEach((el) => el.remove());\n\n // If ClientRouter is not enabled on the incoming page, do a full page load to it.\n // Unless this was a form submission, in which case we do not want to trigger another mutation.\n if (\n !preparationEvent.newDocument.querySelector('[name=\"zfb-view-transitions-enabled\"]') &&\n !preparationEvent.formData\n ) {\n preparationEvent.preventDefault();\n return;\n }\n\n const links = preloadStyleLinks(preparationEvent.newDocument);\n links.length && !preparationEvent.signal.aborted && (await Promise.all(links));\n\n // W3C2: prepareForClientOnlyComponents() goes here. Astro's DEV-only iframe\n // trick that hoists Vite per-component CSS for client:only islands does not\n // apply to zfb (W1B §13.5 — zfb islands inject CSS via the bundle), so the\n // call is intentionally absent rather than stubbed.\n }\n async function abortAndRecreateMostRecentTransition(): Promise<Transition> {\n if (mostRecentTransition) {\n if (mostRecentTransition.viewTransition) {\n try {\n mostRecentTransition.viewTransition.skipTransition();\n } catch {\n // might throw AbortError DOMException. Ignored on purpose.\n }\n try {\n // UpdateCallbackDone might already been settled, i.e. if the previous transition finished updating the DOM.\n // Could not take long, we wait for it to avoid parallel updates\n // (which are very unlikely as long as swap() is not async).\n await mostRecentTransition.viewTransition.updateCallbackDone;\n } catch {\n // There was an error in the update callback of the transition which we cancel.\n // Ignored on purpose\n }\n }\n }\n return (mostRecentTransition = { transitionSkipped: false });\n }\n\n const currentTransition = await abortAndRecreateMostRecentTransition();\n\n if (prepEvent.signal.aborted) {\n if (currentNavigation === mostRecentNavigation) mostRecentNavigation = undefined;\n notifyNavigationAborted(currentNavigation);\n return;\n }\n\n document.documentElement.setAttribute(DIRECTION_ATTR, prepEvent.direction);\n\n // Commit the SPA history entry BEFORE the transition's update callback runs.\n //\n // WebKit (all iOS browsers, incl. iOS Chrome) does not reliably commit a\n // distinct back/forward history entry when history.pushState() is issued\n // *inside* the document.startViewTransition() update callback: the URL bar\n // updates but no new entry is created, so a single Back press falls off the\n // site to the browser home (zudolab/zzmod#662). Committing the entry here —\n // outside the transition's update callback — makes WebKit create it; Chromium\n // is unaffected either way. moveToLocation() (called later from updateDOM,\n // inside the callback) then no-ops its own push/replace via the\n // `to.href !== location.href` guard, since location is already at the\n // committed URL, so currentHistoryIndex is not double-advanced.\n //\n // We use prepEvent.to (redirects are already resolved into it during\n // preparation) and write before the swap, while document.title is still the\n // old page's title — so the back entry keeps the correct (old-page) title\n // without needing moveToLocation's title juggle. Writing here also covers the\n // non-VT fallback path below in one place.\n //\n // Traverse (popstate) navigations carry historyState: the browser has already\n // moved, so they must NOT create a new entry here.\n //\n // Tracks whether this block ran (push OR replace) so moveToLocation (called\n // later, from updateDOM) knows a commit already happened for THIS navigation\n // — see moveToLocation's `historyCommittedEarly` parameter doc. #1398.\n let historyCommittedEarly = false;\n if (!historyState && prepEvent.to.href !== location.href) {\n historyCommittedEarly = true;\n if (options.history === \"replace\") {\n // Mirror of the moveToLocation replace-path guard: `history.state` can be\n // null here too (page entered without a transition state), so synthesize a\n // state from the tracked index/scroll instead of dereferencing null.\n const current = history.state ?? {\n index: currentHistoryIndex,\n scrollX,\n scrollY,\n };\n safeReplaceState(\n {\n ...options.state,\n index: current.index,\n scrollX: current.scrollX,\n scrollY: current.scrollY,\n },\n \"\",\n prepEvent.to.href,\n );\n } else {\n safePushState(\n { ...options.state, index: ++currentHistoryIndex, scrollX: 0, scrollY: 0 },\n \"\",\n prepEvent.to.href,\n );\n }\n }\n\n let domUpdateOutcome: DOMUpdateOutcome | undefined;\n\n if (supportsViewTransitions && !hasUAVisualTransition) {\n // This automatically cancels any previous transition\n // We also already took care that the earlier update callback got through\n currentTransition.viewTransition = document.startViewTransition(async () => {\n domUpdateOutcome = await updateDOM(\n prepEvent,\n options,\n currentNavigation,\n currentTransition,\n historyState,\n undefined,\n historyCommittedEarly,\n );\n });\n // A skipped native transition rejects ready even when its update callback\n // succeeds (or never runs). The browser does not mark ready as handled.\n // Update failures are reported through updateCallbackDone below.\n currentTransition.viewTransition.ready.catch(() => {});\n } else {\n // Simulation mode requires a bit more manual work.\n // Also used when PopStateEvent.hasUAVisualTransition indicates the browser already\n // provided a visual transition (e.g. Safari swipe gesture) — in that case, fallback\n // is \"swap\" to skip animations.\n const updateDone = (async () => {\n // Immediately paused to set up the ViewTransition object for Fallback mode\n await Promise.resolve(); // hop through the micro task queue\n domUpdateOutcome = await updateDOM(\n prepEvent,\n options,\n currentNavigation,\n currentTransition,\n historyState,\n hasUAVisualTransition ? \"swap\" : getFallback(),\n historyCommittedEarly,\n );\n return undefined;\n })();\n\n // When the updateDone promise is settled,\n // we have run and awaited all swap functions and the after-swap event\n // This qualifies for \"updateCallbackDone\".\n //\n // For the build in ViewTransition, \"ready\" settles shortly after \"updateCallbackDone\",\n // i.e. after all pseudo elements are created and the animation is about to start.\n // In simulation mode the \"old\" animation starts before swap,\n // the \"new\" animation starts after swap. That is not really comparable.\n // Thus we go with \"very, very shortly after updateCallbackDone\" and make both equal.\n //\n // \"finished\" resolves after all animations are done.\n\n currentTransition.viewTransition = {\n updateCallbackDone: updateDone, // this is about correct\n ready: updateDone, // good enough\n // Finished promise could have been done better: finished rejects iff updateDone does.\n // Our simulation always resolves, never rejects.\n finished: new Promise((r) => (currentTransition.viewTransitionFinished = r as () => void)), // see end of updateDOM\n skipTransition: () => {\n currentTransition.transitionSkipped = true;\n // This cancels all animations of the simulation\n document.documentElement.removeAttribute(OLD_NEW_ATTR);\n },\n types: new Set<string>(), // empty by default\n };\n }\n // In earlier versions was then'ed on viewTransition.ready which would not execute\n // if the visual part of the transition has errors or was skipped\n currentTransition.viewTransition?.updateCallbackDone.then(\n async () => {\n if (domUpdateOutcome !== \"swapped\") return;\n await runScripts();\n // Mount new island markers introduced by the body swap. Fire-and-forget;\n // each island's scheduleHydrate call is async (idle / visible). Called after\n // runScripts() so any new mountIslands() registration from inline scripts in\n // the new page has already run. Called before onPageLoad() per W1B §12.2.\n mountNewIslands();\n onPageLoad();\n announce();\n },\n () => {}, // the await below reports genuine update callback errors\n );\n // finished.ready and finished.finally are the same for the simulation but not\n // necessarily for native view transition, where finished rejects when updateCallbackDone does.\n const clearTransition = () => {\n // exactOptionalPropertyTypes: true forbids assigning `undefined` to an optional\n // `viewTransition?: ViewTransition` slot — `delete` is the equivalent reset.\n delete currentTransition.viewTransition;\n if (currentTransition === mostRecentTransition) mostRecentTransition = undefined;\n if (currentNavigation === mostRecentNavigation) mostRecentNavigation = undefined;\n document.documentElement.removeAttribute(DIRECTION_ATTR);\n document.documentElement.removeAttribute(OLD_NEW_ATTR);\n };\n // A discarded finally() child would itself reject on an update error.\n currentTransition.viewTransition?.finished.then(clearTransition, clearTransition);\n try {\n // Compatibility:\n // In an earlier version we awaited viewTransition.ready, which includes animation setup.\n // Scripts that depend on the view transition pseudo elements should hook on viewTransition.ready.\n await currentTransition.viewTransition?.updateCallbackDone;\n } catch (e) {\n // This log doesn't make it worse than before, where we got error messages about uncaught exceptions, which can't be caught when the trigger was a click or history traversal.\n // Needs more investigation on root causes if errors still occur sporadically\n const err = e as Error;\n // biome-ignore lint/suspicious/noConsole: allowed\n console.log(\"[zfb]\", err.name, err.message, err.stack);\n }\n}\n\nlet navigateOnServerWarned = false;\n\nexport async function navigate(href: string, options?: Options) {\n if (inBrowser === false) {\n if (!navigateOnServerWarned) {\n // instantiate an error for the stacktrace to show to user.\n const warning = new Error(\n \"The view transitions client API was called during a server side render. This may be unintentional as the navigate() function is expected to be called in response to user interactions. Please make sure that your usage is correct.\",\n );\n warning.name = \"Warning\";\n // biome-ignore lint/suspicious/noConsole: allowed\n console.warn(warning);\n navigateOnServerWarned = true;\n }\n return;\n }\n if (!supportsViewTransitions && getFallback() === \"none\") {\n const url = new URL(href, location.href);\n // Honor the history option on the full-load fallback path: \"replace\"\n // must not leave a back-button entry, so use location.replace().\n if (options?.history === \"replace\") {\n location.replace(url.href);\n } else {\n location.href = url.href;\n }\n return;\n }\n // `originalLocation` is seeded by init(); seed it here too so an init-less\n // caller never hands transition() an undefined \"from\" URL.\n ensureNavigationState();\n await transition(\"forward\", originalLocation, new URL(href, location.href), options ?? {});\n}\n\nfunction onPopState(ev: PopStateEvent) {\n if (!transitionEnabledOnThisPage() && ev.state) {\n // The current page doesn't have View Transitions enabled\n // but the page we navigate to does (because it set the state).\n // Do a full page refresh to reload the client-side router from the new page.\n location.reload();\n return;\n }\n\n // History entries without state are created by the browser (e.g. for hash links)\n // Our view transition entries always have state.\n // Just ignore stateless entries.\n // The browser will handle navigation fine without our help\n if (ev.state === null) {\n return;\n }\n const state: State = history.state;\n const nextIndex = state.index;\n const direction: Direction = derivePopDirection(nextIndex, currentHistoryIndex);\n // Only advance the tracked index when the entry carries a usable index.\n // After a bfcache restore the index can be missing/NaN; clobbering the\n // tracked value with NaN would poison every subsequent direction calc, so\n // keep the last known-good index in that case (see derivePopDirection).\n if (Number.isFinite(nextIndex)) {\n currentHistoryIndex = nextIndex;\n }\n transition(\n direction,\n originalLocation,\n new URL(location.href),\n {},\n state,\n ev.hasUAVisualTransition,\n );\n}\n\n// Decide forward vs back from the popped entry's index against the last\n// tracked index. Two desync cases a WebKit bfcache restore can produce:\n// - missing / NaN `next` (restored entry lost its index): handled explicitly\n// below — we cannot prove a forward move, so treat it as \"back\" (the safe\n// default; a forward misclassification is what makes Back skip to the wrong\n// page).\n// - `next === current` (index unchanged after a desync/replace): falls out of\n// the `>` comparison as \"back\" — not a forward navigation.\nfunction derivePopDirection(nextIndex: number, trackedIndex: number): Direction {\n if (!Number.isFinite(nextIndex)) return \"back\";\n return nextIndex > trackedIndex ? \"forward\" : \"back\";\n}\n\nconst onScrollEnd = () => {\n // NOTE: our \"popstate\" event handler may call `pushState()` or\n // `replaceState()` and then `scrollTo()`, which will fire \"scroll\" and\n // \"scrollend\" events. To avoid redundant work and expensive calls to\n // `replaceState()`, we simply check that the values are different before\n // updating.\n if (history.state && (scrollX !== history.state.scrollX || scrollY !== history.state.scrollY)) {\n updateScrollPosition({ scrollX, scrollY });\n }\n};\n\n// zfb-only addition (no Astro upstream — see file header \"zfb-only additions\").\n// WebKit serves Back navigations after an SPA route change from the bfcache:\n// the page is restored without re-evaluating this module or re-running init(),\n// so `seedPageState()` below (which sets `currentHistoryIndex` from\n// `history.state.index`) never re-runs and the tracked index can desync from\n// the live history stack. A desynced index makes onPopState's direction calc\n// misfire, so Back skips an entry. On a persisted (bfcache) restore we re-seed\n// the tracked index and the `originalLocation` \"from\" URL from the live state,\n// and restore scroll — mirroring that seed. This is a no-op on a normal load\n// (`persisted` falsy/absent) and idempotent (re-seeding from the same state\n// twice changes nothing and fires no transition).\nconst onPageShow = (ev: PageTransitionEvent) => {\n // Normal (non-bfcache) loads already ran init()'s seed; leave them be.\n if (!ev.persisted) return;\n // init() seeds `originalLocation` and `currentHistoryIndex` together; re-sync\n // both here so the next transition() gets the correct `from` URL (a stale\n // `originalLocation` would feed onPopState the wrong origin).\n originalLocation = new URL(location.href);\n const index = history.state?.index;\n if (Number.isFinite(index)) {\n currentHistoryIndex = index;\n }\n if (history.state) {\n scrollTo({ left: history.state.scrollX, top: history.state.scrollY });\n }\n};\n\n// ---- initialization (folded out of module scope by #2436) ----\n\n// Once-guard for the page-state phase of init(). Deliberately SEPARATE from the\n// `initialized` latch below, because the two phases have different eligibility:\n// this one runs on EVERY browser page — including one where view transitions\n// are ineligible (no native support and fallback \"none\") — while the activation\n// listeners are VT-gated. A single shared latch would either skip this phase\n// forever after an ineligible early call, or latch activation on a page that\n// never qualified for it. (#2436)\nlet pageStateSeeded = false;\n\n/**\n * Everything module evaluation used to do for EVERY browser page, regardless\n * of view-transition eligibility: restore (or seed) this page's history entry\n * and its scroll position, and mark the scripts the initial page load already\n * executed so runScripts() does not re-run them after a swap.\n *\n * Called from init() BEFORE its eligibility early-return — that gating\n * asymmetry is load-bearing and predates the fold: a page with fallback \"none\"\n * still needs its history entry restored and its scripts marked. (#2436)\n */\nfunction seedPageState(): void {\n if (pageStateSeeded) return;\n pageStateSeeded = true;\n\n if (history.state) {\n // Here we reloaded a page with history state\n // (e.g. history navigation from non-transition page or browser reload)\n // Adopt only a finite index — a foreign pre-init history.state (e.g. a\n // consumer's own replaceState({modal: true})) has no router index, and\n // adopting undefined would stamp the next push with NaN. Same guard as\n // ensureNavigationState() and onPageShow(). (#2436)\n const index = history.state.index;\n if (Number.isFinite(index)) currentHistoryIndex = index;\n // Skip the scroll restore when an init-less navigate()/syncHistoryEntry()\n // already ran on this page (navigationStateSeeded latched before init):\n // the entry it pushed is stamped scrollX/scrollY 0, and a late-activating\n // init() must not yank the already-scrolled viewport to the top. (#2436)\n if (!navigationStateSeeded) {\n scrollTo({ left: history.state.scrollX, top: history.state.scrollY });\n }\n } else if (transitionEnabledOnThisPage()) {\n // This page is loaded from the browser address bar or via a link from extern,\n // it needs a state in the history\n safeReplaceState({ index: currentHistoryIndex, scrollX, scrollY }, \"\");\n history.scrollRestoration = \"manual\";\n }\n\n for (const script of document.getElementsByTagName(\"script\")) {\n detectScriptExecuted(script);\n script.dataset[\"zfbExec\"] = \"\";\n }\n}\n\n/**\n * Register the window-level navigation listeners. Called from init() only\n * after the view-transition eligibility check, and only once — the\n * `initialized` latch owns this phase.\n */\nfunction registerNavigationListeners(): void {\n addEventListener(\"popstate\", onPopState);\n addEventListener(\"load\", onPageLoad);\n // Re-sync the tracked history index + scroll on a WebKit bfcache restore;\n // a no-op on normal loads. See onPageShow above.\n addEventListener(\"pageshow\", onPageShow);\n // There's not a good way to record scroll position before a history back\n // navigation, so we will record it when the user has stopped scrolling.\n if (\"onscrollend\" in window) addEventListener(\"scrollend\", onScrollEnd);\n else {\n // Keep track of state between intervals\n let intervalId: number | undefined, lastY: number, lastX: number, lastIndex: State[\"index\"];\n const scrollInterval = () => {\n // The interval can outlive its document context — a test-env teardown or a\n // real page unload removes window/history before the 50ms tick. `typeof`\n // never throws even when the global is gone: stop the interval and bail\n // rather than dereferencing a torn-down global (the #1061 bug class; #1063).\n // In a real browser these globals always exist, so this path is test-env\n // only. clearInterval may itself be mid-teardown, so guard the call too.\n if (typeof window === \"undefined\" || typeof history === \"undefined\") {\n if (typeof clearInterval === \"function\") clearInterval(intervalId);\n intervalId = undefined;\n return;\n }\n // Check the index to see if a popstate event was fired\n if (lastIndex !== history.state?.index) {\n clearInterval(intervalId);\n intervalId = undefined;\n return;\n }\n // Check if the user stopped scrolling\n if (lastY === scrollY && lastX === scrollX) {\n // Cancel the interval and update scroll positions\n clearInterval(intervalId);\n intervalId = undefined;\n onScrollEnd();\n return;\n } else {\n ((lastY = scrollY), (lastX = scrollX));\n }\n };\n // We can't know when or how often scroll events fire, so we'll just use them to start intervals\n addEventListener(\n \"scroll\",\n () => {\n if (intervalId !== undefined) return;\n ((lastIndex = history.state?.index), (lastY = scrollY), (lastX = scrollX));\n intervalId = window.setInterval(scrollInterval, 50);\n },\n { passive: true },\n );\n }\n}\n\n// ---- W3C3: click + form intercept, public idempotent init() ----\n\n// Returns true when the modifier-key combo or mouse button means \"open in new tab / download\".\n// Matches Astro's `leavesWindow` helper in ClientRouter.astro.\nconst leavesWindow = (ev: MouseEvent): boolean =>\n (ev.button !== undefined && ev.button !== 0) || // non-left-click\n ev.metaKey || // new tab (Mac)\n ev.ctrlKey || // new tab (Windows/Linux)\n ev.altKey || // download\n ev.shiftKey; // new window\n\n// Track the last clicked element that will leave the window so form submit can check it.\nlet lastClickedElementLeavingWindow: EventTarget | null = null;\n\nfunction handleClick(ev: MouseEvent): void {\n let link: EventTarget | null = ev.target;\n\n // Record whether this click will leave the window (used by form submit handler).\n lastClickedElementLeavingWindow = leavesWindow(ev) ? link : null;\n\n // Shadow DOM: prefer composedPath target over ev.target.\n if (ev.composed) {\n link = ev.composedPath()[0] ?? link;\n }\n\n // Walk up to the nearest <a>, <area>, or <svg:a>.\n if (link instanceof Element) {\n link = link.closest(\"a, area\");\n }\n\n if (\n !(link instanceof HTMLAnchorElement) &&\n !(link instanceof SVGAElement) &&\n !(link instanceof HTMLAreaElement)\n ) {\n return;\n }\n\n const linkEl = link as HTMLAnchorElement | SVGAElement | HTMLAreaElement;\n const linkTarget =\n linkEl instanceof HTMLElement ? linkEl.target : (linkEl as SVGAElement).target.baseVal;\n const href = linkEl instanceof HTMLElement ? linkEl.href : (linkEl as SVGAElement).href.baseVal;\n\n if (!href) return;\n\n const origin = new URL(href, location.href).origin;\n\n if (\n // data-zfb-reload: caller wants a full browser reload, not a SPA transition.\n (linkEl as HTMLElement).dataset[\"zfbReload\"] !== undefined ||\n // download attribute: let browser handle download.\n linkEl.hasAttribute(\"download\") ||\n // Non-self target opens in a new context — skip.\n (linkTarget && linkTarget !== \"_self\") ||\n // Cross-origin: not ours to handle.\n origin !== location.origin ||\n // Modifier key / non-left-click combo: user wants new tab / window / download.\n lastClickedElementLeavingWindow !== null ||\n // Another handler already handled this event.\n ev.defaultPrevented\n ) {\n return;\n }\n\n ev.preventDefault();\n navigate(href, {\n // data-zfb-history=\"replace\" opts a link into replaceState instead of pushState.\n history: (linkEl as HTMLElement).dataset[\"zfbHistory\"] === \"replace\" ? \"replace\" : \"auto\",\n sourceElement: linkEl,\n });\n}\n\nfunction handleSubmit(ev: SubmitEvent): void {\n const el = ev.target as HTMLElement;\n const submitter = ev.submitter as HTMLElement | null;\n\n // If the submit was triggered by a modifier-key click, treat as normal browser submit.\n const clickedWithKeys = submitter !== null && submitter === lastClickedElementLeavingWindow;\n lastClickedElementLeavingWindow = null;\n\n if (\n el.tagName !== \"FORM\" ||\n ev.defaultPrevented ||\n el.dataset[\"zfbReload\"] !== undefined ||\n clickedWithKeys\n ) {\n return;\n }\n\n const form = el as HTMLFormElement;\n const formData = new FormData(form, submitter ?? undefined);\n\n // form.action / form.method can be shadowed by <input name=\"action\"> / <input name=\"method\">,\n // so fall back to getAttribute() when the property is not a string. (Astro's comment.)\n const formAction = typeof form.action === \"string\" ? form.action : form.getAttribute(\"action\");\n const formMethod = typeof form.method === \"string\" ? form.method : form.getAttribute(\"method\");\n\n // Resolve action: submitter formaction attr overrides form action, fallback to current path.\n let action = submitter?.getAttribute(\"formaction\") ?? formAction ?? location.pathname;\n // Resolve method: submitter formmethod attr overrides form method, fallback to \"get\".\n const method = submitter?.getAttribute(\"formmethod\") ?? formMethod ?? \"get\";\n\n // The \"dialog\" method is a special keyword used within <dialog> elements —\n // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fs-method\n if (method === \"dialog\" || location.origin !== new URL(action, location.href).origin) {\n // No SPA transition in these cases — let browser handle it.\n return;\n }\n\n const options: import(\"./types.js\").Options = { sourceElement: submitter ?? form };\n if (method === \"get\") {\n const params = new URLSearchParams(formData as any);\n const url = new URL(action, location.href);\n url.search = params.toString();\n action = url.toString();\n } else {\n options.formData = formData;\n }\n\n ev.preventDefault();\n navigate(action, options);\n}\n\nexport interface InitOptions {\n /** Reserved for forward-compat with Astro's prefetch integration. Ignored in v1. */\n prefetchAll?: boolean;\n}\n\n// Guard flag — ensures the activation listeners (popstate/load/pageshow/scroll\n// plus click + submit) are registered only once even if init() is called\n// multiple times (e.g. two <ClientRouter> mounts on the same page).\nlet initialized = false;\n\n/**\n * Bootstrap the client router on this page: restore its history entry, mark\n * the already-executed scripts, and wire up the navigation, click and\n * form-submit listeners. Safe to call multiple times — each of the two phases\n * runs at most once (idempotent).\n *\n * Evaluating this module does nothing; every side effect the router performs\n * at startup happens here (#2436). Two once-guards rather than one, because\n * the phases have different eligibility — see `pageStateSeeded`.\n *\n * @param _options - Forward-compat hook matching Astro's init() signature. Ignored in v1.\n */\nexport function init(_options?: InitOptions): void {\n if (!inBrowser) return;\n\n // Phase 1 — runs on every browser page, even a view-transition-ineligible\n // one, and therefore BEFORE the eligibility early-return below.\n seedPageState();\n\n if (initialized) return;\n\n // Phase 2 — activation. Latch the guard only AFTER this eligibility check:\n // an ineligible early call (fallback \"none\" and no native view transitions)\n // must not permanently latch `initialized`, or a later legitimately-eligible\n // init() would no-op forever.\n if (!supportsViewTransitions && getFallback() === \"none\") return;\n\n initialized = true;\n\n // Where we came from, for the first transition() of this page. Re-seeded\n // unconditionally at activation (as module evaluation used to do), so it\n // reflects the URL at activation time even if an init-less navigate() or\n // syncHistoryEntry() already primed it via ensureNavigationState().\n navigationStateSeeded = true;\n originalLocation = new URL(location.href);\n\n registerNavigationListeners();\n\n document.addEventListener(\"click\", handleClick);\n document.addEventListener(\"submit\", handleSubmit as EventListener);\n\n // Prefetch hook intentionally omitted from v1 — see https://github.com/zudolab/zudo-doc/issues/1527\n // (Followup tracker for porting Astro prefetch module).\n}\n"]}
1
+ {"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/client-router/router.ts"],"names":[],"mappings":"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","sourcesContent":["/// <reference lib=\"dom\" />\n/// <reference lib=\"dom.iterable\" />\n// Ported from Astro transitions/router.ts (transition orchestration half).\n// Source: https://raw.githubusercontent.com/withastro/astro/main/packages/astro/src/transitions/router.ts\n// Issue: zudolab/zudo-doc#1516 (W3C1), parent epic zudolab/zudo-doc#1510.\n//\n// Mechanical renames per W1B §13.5:\n// astro:* event names → zfb:*\n// data-astro-* attributes → data-zfb-*\n// astro-view-transitions-* → zfb-view-transitions-*\n// .astro-route-announcer → .zfb-route-announcer\n// dataset.astroExec → dataset.zfbExec\n// dataset.astroHistory → dataset.zfbHistory\n// dataset.astroRerun → dataset.zfbRerun\n//\n// Named-cause deviations:\n// - `internalFetchHeaders` import dropped; replaced with `{}` (W1B §13.5 — zfb adapters\n// do not currently expose a per-fetch internal-headers contract).\n// - `prepareForClientOnlyComponents` dropped entirely (W1B §13.5 / W3C2 — DEV-only\n// iframe trick that compensates for Vite per-component CSS injection on hydrate;\n// not applicable to zfb islands which inject CSS via the bundle).\n// - `import.meta.env.SSR` access uses `(import.meta as any).env?.SSR` (no Vite\n// ambient types in zfb-runtime tsconfig — same workaround used in W3B).\n// - `inBrowser` evaluates to `typeof document !== \"undefined\"` rather than relying\n// on the SSR flag, because the runtime package serves both server- and client-side\n// code; same observable behavior in browser and on SSR.\n// - `announce()` was a TODO stub at W1B port time; W3C3 implemented it and #1063 gave\n// its 60ms timer explicit lifecycle ownership — see the route-announcer block below.\n//\n// W3C2 additions (this file):\n// - `navigate()` public entry.\n// - `onPopState`, `onScrollEnd`.\n// - Seeding `currentHistoryIndex` from `history.state`, registering popstate /\n// load / scrollend listeners, and marking already-executed scripts with\n// `dataset[\"zfbExec\"] = \"\"`. W3C2 did all of this in two bare top-level\n// `if (inBrowser)` blocks; #2436 folded both into `init()` (see the two\n// once-guards there) so evaluating this module has no side effect at all.\n//\n// W3C1 items deferred to — and since implemented in — W3C3:\n// - `announce()` route-announcer implementation (see the route-announcer block below;\n// timer lifecycle ownership hardened in #1063).\n// - Click + form intercept (see `handleClick` / `handleSubmit` / `init()` below).\n//\n// zfb-only additions (no Astro upstream — #1076):\n// - `onPageShow` pageshow/bfcache re-sync, registered inside the init block alongside\n// popstate/load/scrollend. Verified against live Astro `main`: neither\n// `transitions/router.ts` nor `ClientRouter.astro` has any pageshow/`persisted`\n// handler, so this is original design, not a port. WebKit serves Back after an SPA\n// route change from the bfcache without re-evaluating this module, desyncing the\n// tracked `currentHistoryIndex` from the live history stack; `onPageShow` re-seeds it\n// (and restores scroll) on a persisted restore — see the `onPageShow` block below.\n// - `derivePopDirection` hardens the popstate forward/back calc against an unchanged or\n// missing/NaN `state.index` that a bfcache restore can leave behind (#1076).\n\nimport {\n doPreparation,\n doSwap,\n onPageLoad,\n triggerEvent,\n updateScrollPosition,\n type TransitionBeforePreparationEvent,\n} from \"./events.js\";\nimport {\n safeReplaceState,\n tryPushState,\n tryReplaceState,\n type HistoryWriteResult,\n} from \"./history-safe.js\";\nimport { assertUniquePersistKeys, detectScriptExecuted } from \"./swap-functions.js\";\nimport type { Direction, Fallback, Options, SyncHistoryEntryOptions } from \"./types.js\";\n// Island re-bootstrap and deferred-cancel after body swap (W1B §12.2, §12.5).\n// mountNewIslands() is called after runScripts() and before onPageLoad().\n// cancelPendingIslands() and unmountIslands() run inside doSwap()'s synchronous\n// commit section so deferred callbacks cannot fire against orphan elements.\nimport { cancelPendingIslands, mountNewIslands, unmountIslands } from \"@takazudo/zfb/runtime\";\n\ntype State = {\n index: number;\n scrollX: number;\n scrollY: number;\n};\ntype Navigation = {\n controller: AbortController;\n domCommitStarted: boolean;\n abortEventEmitted: boolean;\n};\ntype Transition = {\n // The view transitions object (API and simulation)\n viewTransition?: ViewTransition;\n // Simulation: Whether transition was skipped\n transitionSkipped: boolean;\n // Simulation: The resolve function of the finished promise\n viewTransitionFinished?: () => void;\n};\n\ntype DOMUpdateOutcome = \"swapped\" | \"aborted\";\n\n// Adapter-specific internal fetch headers. zfb adapters do not currently expose this\n// contract — the empty object preserves the call-shape so the loop in fetchHTML is a\n// no-op until/unless an adapter wires this up.\nconst internalFetchHeaders: Record<string, string> = {};\n\n// Detect browser context. Astro uses `import.meta.env.SSR === false` (Vite-injected).\n// The zfb-runtime tsconfig has no Vite ambient types; checking for `document` is\n// behaviorally identical and avoids a Vite type dependency.\nconst inBrowser = typeof document !== \"undefined\";\n\nexport const supportsViewTransitions = inBrowser && !!document.startViewTransition;\n\nexport const transitionEnabledOnThisPage = () =>\n inBrowser && !!document.querySelector('[name=\"zfb-view-transitions-enabled\"]');\n\n// A same-page Back/Forward traversal (two history entries sharing pathname +\n// search) is served from the live DOM by the fast-path in transition() — no\n// re-fetch, no re-swap, no lifecycle events. A per-request SSR page\n// (`prerender = false`) whose server output can differ between two visits to\n// the SAME url opts back INTO the fetch by emitting\n// <meta name=\"zfb-traverse-refetch\" content=\"true\"> (via <ClientRouter\n// traverseRefetch />); skipping the fetch on such a page would pin the stale\n// first-render content. Read from the CURRENT document — for a same-page\n// traverse the current document IS the target page. Mirrors the\n// zfb-prefetch-disabled meta reader. (#1376)\nconst traverseRefetchOptedOut = () =>\n inBrowser && !!document.querySelector('meta[name=\"zfb-traverse-refetch\"][content=\"true\"]');\n\nconst samePage = (thisLocation: URL, otherLocation: URL) =>\n thisLocation.pathname === otherLocation.pathname && thisLocation.search === otherLocation.search;\n\n// The previous navigation that might still be in processing\nlet mostRecentNavigation: Navigation | undefined;\n// The previous transition that might still be in processing\nlet mostRecentTransition: Transition | undefined;\n// When we traverse the history, the window.location is already set to the new location.\n// This variable tells us where we came from\nlet originalLocation: URL;\n// True while the current history entry belongs to a navigation that committed\n// its URL early but never rendered its page (the final write was rejected). The\n// address bar then names a page the live DOM is not, so URL equality must not be\n// taken as \"already rendered\" until a swap settles the location.\nlet currentEntryUnrendered = false;\n\n// Route announcer — ported from Astro's announce(). Each navigation appends a fresh\n// aria-live <div> (after removing any prior announcer, so exactly one ever exists) and\n// writes the new page title into it 60ms later, so screen readers announce the new page.\n//\n// zfb deviation from Astro / design decision for #1063 (timer lifecycle ownership):\n// - The 60ms timer id is stored and cleared when a newer navigation supersedes a\n// still-pending announcement, so a superseded page's title is never written to a\n// now-detached announcer. (Astro leaves the timer fire-and-forget.)\n// - The previous announcer is removed before a new one is appended, so they never\n// accumulate. We deliberately do NOT *reuse* one element across navigations (which\n// #1063 floated): a reused live region is detached and re-inserted into the a11y\n// tree on every body swap, and a repeated title would be a no-op text write — both\n// make re-announcement unreliable across screen readers. Creating a fresh empty\n// element and writing text 60ms later is Astro's proven, reliable announce trigger.\n//\n// The 60ms delay is Astro's magic number: screen readers need to see the element change\n// and may miss it if it happens too quickly.\nlet announceTimer: number | undefined;\n\nconst announce = () => {\n // A newer navigation supersedes any still-pending announcement: cancel the old\n // timer so it can't write a now-stale title after this navigation's swap.\n if (announceTimer !== undefined) window.clearTimeout(announceTimer);\n\n // Keep exactly one announcer: drop any leftover from a prior navigation that the\n // body swap did not already detach.\n document.querySelector(\".zfb-route-announcer\")?.remove();\n const div = document.createElement(\"div\");\n div.setAttribute(\"aria-live\", \"assertive\");\n div.setAttribute(\"aria-atomic\", \"true\");\n div.className = \"zfb-route-announcer\";\n document.body.append(div);\n\n announceTimer = window.setTimeout(() => {\n announceTimer = undefined;\n // This timer can outlive its document context — a test-env teardown\n // (vitest/happy-dom) or a real page unload removes `document` (and\n // `location`) before the 60ms elapses. `typeof` is safe even when the\n // global is gone, so bail out instead of throwing an unhandled\n // ReferenceError (#1061); the announcement is moot once the page is gone.\n // Both globals the callback dereferences are checked, not just `document`.\n if (typeof document === \"undefined\" || typeof location === \"undefined\") return;\n const title = document.title || document.querySelector(\"h1\")?.textContent || location.pathname;\n div.textContent = title;\n }, 60);\n};\n\nconst PERSIST_ATTR = \"data-zfb-transition-persist\";\n\nconst attrValueSelector = (attr: string, value: string): string =>\n value === \"\" ? `[${attr}=\"\"]` : `[${attr}=${CSS.escape(value)}]`;\n\nconst querySelectorWithAttrValue = (\n root: ParentNode,\n selectorPrefix: string,\n attr: string,\n value: string,\n): Element | null => {\n const escapedMatch = root.querySelector(`${selectorPrefix}${attrValueSelector(attr, value)}`);\n if (escapedMatch) return escapedMatch;\n return (\n Array.from(root.querySelectorAll(`${selectorPrefix}[${attr}]`)).find(\n (el) => el.getAttribute(attr) === value,\n ) ?? null\n );\n};\nconst DIRECTION_ATTR = \"data-zfb-transition\";\nconst OLD_NEW_ATTR = \"data-zfb-transition-fallback\";\n\nlet parser: DOMParser;\n\n// The History API does not tell you if navigation is forward or back, so\n// you can figure it using an index. On pushState the index is incremented so you\n// can use that to determine popstate if going forward or back.\nlet currentHistoryIndex = 0;\n\n// Once-guard for the navigation bookkeeping below. `init()` sets it too, so a\n// later ensureNavigationState() can never clobber the activation-time seed.\nlet navigationStateSeeded = false;\n\n/**\n * Seed the module's navigation bookkeeping — `originalLocation` (declared\n * without an initializer) and the tracked history index — from the live\n * document, once.\n *\n * Deliberately side-effect free beyond those two variables: it registers no\n * listener, writes no history entry, never scrolls, and never marks scripts.\n * All of that belongs to {@link init}. Its only job is to keep an init-less\n * `navigate()` / `syncHistoryEntry()` from reading `undefined` or stamping a\n * fresh entry with the module default index — using the router without\n * activating it is documented as unsupported, but it must not throw and must\n * not mis-stamp. An existing finite `history.state.index` is ADOPTED, never\n * reset: on a page whose entry is already index 7, the next push must be 8. (#2436)\n */\nfunction ensureNavigationState(): void {\n if (navigationStateSeeded || !inBrowser) return;\n navigationStateSeeded = true;\n originalLocation = new URL(location.href);\n const index = history.state?.index;\n if (Number.isFinite(index)) currentHistoryIndex = index;\n}\n\n// returns the contents of the page or null if the router can't deal with it.\nasync function fetchHTML(\n href: string,\n init?: RequestInit,\n): Promise<null | { html: string; redirected?: string; mediaType: DOMParserSupportedType }> {\n try {\n // Apply adapter-specific headers for internal fetches\n const headers = new Headers(init?.headers);\n for (const [key, value] of Object.entries(internalFetchHeaders) as [string, string][]) {\n headers.set(key, value);\n }\n const res = await fetch(href, { ...init, headers });\n const contentType = res.headers.get(\"content-type\") ?? \"\";\n // drop potential charset (+ other name/value pairs) as parser needs the mediaType\n const mediaType = contentType.split(\";\", 1)[0]!.trim();\n // the DOMParser can handle two types of HTML\n if (mediaType !== \"text/html\" && mediaType !== \"application/xhtml+xml\") {\n // everything else (e.g. audio/mp3) will be handled by the browser but not by us\n return null;\n }\n const html = await res.text();\n // exactOptionalPropertyTypes: true forbids assigning `undefined` to a `redirected?: string`\n // slot, so omit the property when not redirected instead of setting it to undefined.\n return res.redirected ? { html, redirected: res.url, mediaType } : { html, mediaType };\n } catch {\n // can't fetch, let someone else deal with it.\n return null;\n }\n}\n\nexport function getFallback(): Fallback {\n const el = document.querySelector('[name=\"zfb-view-transitions-fallback\"]');\n if (el) {\n // Astro casts `content` straight to Fallback; harden against an arbitrary/typo'd\n // attribute value by validating against the known set and defaulting to \"animate\".\n const content = el.getAttribute(\"content\");\n if (content === \"none\" || content === \"animate\" || content === \"swap\") {\n return content;\n }\n }\n return \"animate\";\n}\n\n// Upper bound (ms) for waiting on a single external <script>'s load/error in\n// runScripts(). Not an Astro upstream value — added so a slow/broken external\n// script can never hang the transition indefinitely.\nconst EXTERNAL_SCRIPT_WAIT_TIMEOUT = 5000;\n\nfunction runScripts() {\n let wait = Promise.resolve();\n let needsWaitForInlineModuleScript = false;\n // The original code made the assumption that all inline scripts are directly executed when inserted into the DOM.\n // This is not true for inline module scripts, which are deferred but still executed in order.\n // inline module scripts cannot be awaited for with onload.\n // Thus to be able to wait for the execution of all scripts, we make sure that the last inline module script\n // is always followed by an external module script\n for (const script of document.getElementsByTagName(\"script\")) {\n script.dataset[\"zfbExec\"] === undefined &&\n script.getAttribute(\"type\") === \"module\" &&\n (needsWaitForInlineModuleScript = script.getAttribute(\"src\") === null);\n }\n needsWaitForInlineModuleScript &&\n document.body.insertAdjacentHTML(\n \"beforeend\",\n `<script type=\"module\" src=\"data:application/javascript,\"/>`,\n );\n\n for (const script of document.getElementsByTagName(\"script\")) {\n if (script.dataset[\"zfbExec\"] === \"\") continue;\n const type = script.getAttribute(\"type\");\n if (type && type !== \"module\" && type !== \"text/javascript\") continue;\n const newScript = document.createElement(\"script\");\n newScript.innerHTML = script.innerHTML;\n for (const attr of script.attributes) {\n if (attr.name === \"src\") {\n // Astro awaits onload/onerror with no upper bound; a slow or broken\n // external <script> would then hang the whole transition. Race the\n // load against a timeout so the transition can always proceed.\n const p = new Promise<void>((r) => {\n let timer: ReturnType<typeof setTimeout>;\n const done = () => {\n clearTimeout(timer);\n r();\n };\n newScript.onload = newScript.onerror = done;\n timer = setTimeout(done, EXTERNAL_SCRIPT_WAIT_TIMEOUT);\n });\n wait = wait.then(() => p as any);\n }\n newScript.setAttribute(attr.name, attr.value);\n }\n newScript.dataset[\"zfbExec\"] = \"\";\n script.replaceWith(newScript);\n }\n return wait;\n}\n\n// What transition() already wrote for THIS navigation before the swap (the\n// WebKit early commit, outside any native View Transition callback).\n// \"tolerated\" means the write reached an about:srcdoc restriction, which the\n// router degrades through without touching History again.\ntype EarlyCommit = \"none\" | \"committed\" | \"tolerated\";\n\ntype LocationWrite =\n | { readonly status: \"unchanged\" | \"committed\" | \"tolerated\" }\n // `replace`: a deliberate recovery load must replace the current entry\n // rather than add one. `error` is absent when no write was attempted\n // because a new entry cannot be pushed from inside a native View Transition.\n | { readonly status: \"rejected\"; readonly replace: boolean; readonly error?: unknown };\n\nconst UNCHANGED: LocationWrite = { status: \"unchanged\" };\n\n// Point the current history entry at `to` (push or replace), advancing the\n// tracked index only once the browser has actually accepted a push.\n//\n// `early` is the write transition() already made for this navigation. When a\n// `zfb:before-swap` listener has since changed `event.to` (writable per Astro\n// parity), the already-committed entry is REPLACED rather than a second one\n// pushed — one navigation must never leave a phantom Back stop (#1398).\n//\n// A push from inside a native View Transition update callback is not reliably\n// committed by WebKit (zudolab/zzmod#662), so it is reported as rejected\n// without being attempted; the caller recovers with a full document load.\nconst writeLocationEntry = (\n to: URL,\n options: Options,\n historyState: State | undefined,\n early: EarlyCommit,\n insideNativeViewTransition: boolean,\n): LocationWrite => {\n // A traverse already moved the browser; a srcdoc restriction is not retried.\n if (historyState || early === \"tolerated\" || to.href === location.href) return UNCHANGED;\n const replace = options.history === \"replace\" || early === \"committed\";\n let result: HistoryWriteResult;\n if (replace) {\n // `history.state` can be null or a foreign shape (page entered without a\n // transition state, or written by raw-History code); fall back per field.\n const current = history.state;\n result = tryReplaceState(\n {\n ...options.state,\n index:\n current != null && Number.isFinite(current.index) ? current.index : currentHistoryIndex,\n scrollX: Number.isFinite(current?.scrollX) ? current.scrollX : scrollX,\n scrollY: Number.isFinite(current?.scrollY) ? current.scrollY : scrollY,\n },\n \"\",\n to.href,\n );\n } else {\n if (insideNativeViewTransition) return { status: \"rejected\", replace: false };\n const index = currentHistoryIndex + 1;\n result = tryPushState({ ...options.state, index, scrollX: 0, scrollY: 0 }, \"\", to.href);\n if (result.outcome === \"committed\") currentHistoryIndex = index;\n }\n return result.outcome === \"rejected\"\n ? { status: \"rejected\", replace, error: result.error }\n : { status: result.outcome };\n};\n\n// Settle the page on its new location after the entry was written: re-point\n// the \"from\" URL and set the scroll position according to the hash fragment\n// (or the traversed entry's saved scroll).\nconst settleLocation = (to: URL, from: URL, historyState?: State) => {\n const intraPage = samePage(from, to);\n\n let scrolledToTop = false;\n // now we are on the new page for non-history navigation!\n // (with history navigation page change happens before popstate is fired)\n originalLocation = to;\n currentEntryUnrendered = false;\n\n // freshly loaded pages start from the top\n if (!intraPage) {\n scrollTo({ left: 0, top: 0, behavior: \"instant\" });\n scrolledToTop = true;\n }\n\n if (historyState) {\n // Raw-History consumers may push partial/empty state (`{}`), so the tracked\n // scroll fields can be absent or non-finite. Never scrollTo(undefined, …) —\n // leave scroll where it is rather than jumping to (0,0). #1376.\n if (Number.isFinite(historyState.scrollX) && Number.isFinite(historyState.scrollY)) {\n scrollTo(historyState.scrollX, historyState.scrollY);\n }\n } else {\n if (to.hash) {\n // because we are already on the target page ...\n // ... what comes next is an intra-page navigation\n // that won't reload the page but instead scroll to the fragment\n history.scrollRestoration = \"auto\";\n const savedState = history.state;\n location.href = to.href; // this kills the history state on Firefox\n if (!history.state) {\n safeReplaceState(savedState, \"\"); // this restores the history state\n if (intraPage) {\n window.dispatchEvent(new PopStateEvent(\"popstate\"));\n }\n }\n } else {\n if (!scrolledToTop) {\n scrollTo({ left: 0, top: 0, behavior: \"instant\" });\n }\n }\n history.scrollRestoration = \"manual\";\n }\n};\n\nlet syncHistoryEntryOnServerWarned = false;\n\n/**\n * Write a router-managed history entry (push or replace) WITHOUT any\n * navigation, DOM, or lifecycle side effect. This is the supported path for\n * consumers deep-linking transient UI state (dialogs/modals, a photo\n * viewer's `/photos/<slug>/` URL). Hand-rolled raw `history.pushState`\n * desyncs `originalLocation` and the index bookkeeping that popstate\n * direction detection ({@link derivePopDirection}) and the same-page\n * traverse fast-path depend on; `navigate()` can't be used instead because\n * it forces a fetch. See #1377 / #1374.\n *\n * Never scrolls the viewport itself — but the entry it writes IS stamped\n * with the CURRENT scroll position (`scrollX`/`scrollY` at call time), not\n * `(0, 0)` (issue #1398). This matters only for a later Forward-traversal\n * back to this entry: the same-page traverse fast-path restores whatever\n * scroll position was stamped on the entry, so a same-page push (e.g.\n * opening a dialog) does not snap the underlying page to the top when the\n * dialog is later reopened via Forward.\n *\n * @param url - The URL to write. Cross-origin URLs throw rather than\n * silently falling back to a full-page load.\n * @param options.replace - Use `history.replaceState` instead of\n * `history.pushState` (no new Back-button entry). Default: push.\n * @param options.state - Merged into the entry's `history.state`; the\n * router's own bookkeeping keys (`index`, `scrollX`, `scrollY`) always win\n * on a colliding key.\n * @throws The browser's own History error, rethrown unchanged, when it rejects\n * the URL write (e.g. WebKit's History-write rate limit). The router's\n * tracked history index and \"from\" URL are left describing the entry that\n * is still current; no navigation, fetch, DOM change or scroll happens. A\n * push may already have saved the outgoing entry's scroll position. Inside\n * an `about:srcdoc` document the browser's History restriction is tolerated\n * instead: the call returns without writing or throwing.\n */\nexport function syncHistoryEntry(url: string | URL, options: SyncHistoryEntryOptions = {}): void {\n // SSR guard: no window/history to touch. Mirror navigate()'s server no-op +\n // one-time console warning. Checked at call time via `typeof document` (not the\n // module-eval `inBrowser` const) so the branch is reachable and behavior is\n // identical in a real environment (document is always present in a browser).\n if (typeof document === \"undefined\") {\n if (!syncHistoryEntryOnServerWarned) {\n // instantiate an error for the stacktrace to show to user.\n const warning = new Error(\n \"syncHistoryEntry() was called during a server side render. This may be unintentional as it is expected to be called in response to a client-side user interaction. Please make sure that your usage is correct.\",\n );\n warning.name = \"Warning\";\n // biome-ignore lint/suspicious/noConsole: allowed\n console.warn(warning);\n syncHistoryEntryOnServerWarned = true;\n }\n return;\n }\n\n // Adopt this page's existing history index before stamping an entry — an\n // init-less caller must not reset a live entry's index to the module default.\n ensureNavigationState();\n\n const to = new URL(url, location.href);\n\n // Cross-origin is not ours to manage. The History API would throw a native\n // SecurityError for a cross-origin URL, but we guard explicitly so the failure\n // is a clear, documented contract violation rather than an opaque platform\n // error — and never a silent full-page load. #1377.\n if (to.origin !== location.origin) {\n throw new Error(\n `syncHistoryEntry(): refusing to write a cross-origin history entry for \"${to.href}\" (current origin: ${location.origin}).`,\n );\n }\n\n let write: HistoryWriteResult;\n if (options.replace) {\n // Replace keeps the current entry's index. A consumer migrating from raw\n // history.pushState may have left a missing/invalid index, so fall back to\n // the tracked index rather than stamping NaN/undefined.\n const current = history.state;\n const index =\n current != null && Number.isFinite(current.index) ? current.index : currentHistoryIndex;\n write = tryReplaceState(\n {\n ...options.state,\n index,\n scrollX: Number.isFinite(current?.scrollX) ? current.scrollX : scrollX,\n scrollY: Number.isFinite(current?.scrollY) ? current.scrollY : scrollY,\n },\n \"\",\n to.href,\n );\n } else {\n // Persist the CURRENT (outgoing) entry's latest scroll before pushing, so a\n // later Back restoration can't lose scroll that `scrollend` hasn't flushed\n // yet — the same guard transition() applies before a non-traverse push.\n updateScrollPosition({ scrollX, scrollY });\n // Stamp the CURRENT scroll on the freshly-pushed entry too — NOT (0,0).\n // This is a same-page push (dialog/photo-viewer pattern): the underlying\n // page never actually scrolled anywhere, it just gained an overlay. A\n // (0,0)-stamped entry would make the traverse fast-path (settleLocation's\n // historyState branch) scrollTo(0,0) when this entry is later\n // Forward-reopened, snapping the page to the top under the reopened\n // dialog. #1398.\n const index = currentHistoryIndex + 1;\n write = tryPushState({ ...options.state, index, scrollX, scrollY }, \"\", to.href);\n if (write.outcome === \"committed\") currentHistoryIndex = index;\n }\n\n // The browser kept the old URL: report it with the browser's own error and\n // leave the bookkeeping describing the entry that is actually current.\n if (write.outcome === \"rejected\") throw write.error;\n // Re-point originalLocation so the next transition()/onPopState uses the\n // correct \"from\" URL. Skipping this is exactly what makes a raw pushState\n // desync the router (a same-page Back would miss the traverse fast path).\n // A tolerated srcdoc restriction did not move the URL, so neither does this.\n if (write.outcome === \"committed\") originalLocation = to;\n}\n\nfunction preloadStyleLinks(newDocument: Document) {\n const links: Promise<any>[] = [];\n for (const el of newDocument.querySelectorAll(\"head link[rel=stylesheet]\")) {\n const persistId = el.getAttribute(PERSIST_ATTR);\n const href = el.getAttribute(\"href\");\n const existingSelectors = [\n persistId !== null ? attrValueSelector(PERSIST_ATTR, persistId) : null,\n href !== null ? `link[rel=stylesheet]${attrValueSelector(\"href\", href)}` : null,\n ].filter((selector): selector is string => selector !== null);\n const existingLink =\n (existingSelectors.length ? document.querySelector(existingSelectors.join(\", \")) : null) ??\n (persistId !== null\n ? querySelectorWithAttrValue(document, \"\", PERSIST_ATTR, persistId)\n : null) ??\n (href !== null\n ? querySelectorWithAttrValue(document, \"link[rel=stylesheet]\", \"href\", href)\n : null);\n\n // Do not preload links that are already on the page.\n if (href !== null && !existingLink) {\n const c = document.createElement(\"link\");\n c.setAttribute(\"rel\", \"preload\");\n c.setAttribute(\"as\", \"style\");\n c.setAttribute(\"href\", href);\n links.push(\n new Promise<any>((resolve) => {\n [\"load\", \"error\"].forEach((evName) => c.addEventListener(evName, resolve));\n document.head.append(c);\n }),\n );\n }\n }\n return links;\n}\n\n// replace head and body of the windows document with contents from newDocument\n// if !popstate, update the history entry and scroll position according to toLocation\n// if popState is given, this holds the scroll position for history navigation\n// if fallback === \"animate\" then simulate view transitions\nasync function updateDOM(\n preparationEvent: TransitionBeforePreparationEvent,\n options: Options,\n currentNavigation: Navigation,\n currentTransition: Transition,\n historyState: State | undefined,\n fallback: Fallback | undefined,\n historyCommit: HistoryCommitPlan,\n): Promise<DOMUpdateOutcome> {\n async function animate(phase: string) {\n function isInfinite(animation: Animation) {\n const effect = animation.effect;\n if (!effect || !(effect instanceof KeyframeEffect) || !effect.target) return false;\n const style = window.getComputedStyle(effect.target, effect.pseudoElement);\n return style.animationIterationCount === \"infinite\";\n }\n const currentAnimations = document.getAnimations();\n // Trigger view transition animations waiting for data-zfb-transition-fallback\n document.documentElement.setAttribute(OLD_NEW_ATTR, phase);\n const nextAnimations = document.getAnimations();\n const newAnimations = nextAnimations.filter(\n (a) => !currentAnimations.includes(a) && !isInfinite(a),\n );\n // Wait for all new animations to finish (resolved or rejected).\n // Do not reject on canceled ones.\n return Promise.allSettled(newAnimations.map((a) => a.finished));\n }\n\n const animateFallbackOld = async () => {\n if (\n fallback === \"animate\" &&\n !currentTransition.transitionSkipped &&\n !preparationEvent.signal.aborted\n ) {\n try {\n await animate(\"old\");\n } catch {\n // animate might reject as a consequence of a call to skipTransition()\n // ignored on purpose\n }\n }\n };\n\n const finishAbortedUpdate = (): DOMUpdateOutcome => {\n notifyNavigationAborted(currentNavigation);\n // Simulation owns its `finished` promise explicitly. Resolve it on the\n // no-swap path so transition cleanup still runs.\n currentTransition.viewTransitionFinished?.();\n return \"aborted\";\n };\n\n // A newer navigation or popstate may have won after preparation/history\n // commit but before the update callback started.\n if (preparationEvent.signal.aborted) return finishAbortedUpdate();\n\n let rejectedWrite = undefined as RejectedLocationWrite | undefined;\n const swapResult = await doSwap(\n preparationEvent,\n currentTransition.viewTransition!,\n animateFallbackOld,\n (event) => {\n // Teardown and swap are a synchronous point-of-no-return. doSwap checks\n // the signal after the animation await and invokes this callback only for\n // a navigation that still owns the commit.\n assertUniquePersistKeys(document, \"current\");\n assertUniquePersistKeys(event.newDocument, \"incoming\");\n // Commit the final URL — a before-swap listener may have changed\n // `event.to` — while the old page is still intact. Written before the\n // swap, the outgoing entry also keeps the old page's title.\n const write = writeLocationEntry(\n event.to,\n options,\n historyState,\n historyCommit.early,\n historyCommit.insideNativeViewTransition,\n );\n if (write.status === \"rejected\") {\n rejectedWrite = write;\n return false;\n }\n currentNavigation.domCommitStarted = true;\n cancelPendingIslands();\n // Unmount mounted islands on the OLD body before the swap so component\n // trees receive render(null, element) / root.unmount() and their useEffect\n // cleanups fire. Pass the incoming body so persisted islands are kept.\n unmountIslands(document.body, event.newDocument.body);\n return true;\n },\n );\n if (!swapResult.swapped) {\n if (rejectedWrite) {\n abandonNavigation(\n currentNavigation,\n swapResult.event.to,\n rejectedWrite,\n historyCommit.recoverByDocumentLoad,\n );\n }\n return finishAbortedUpdate();\n }\n\n const swapEvent = swapResult.event;\n settleLocation(swapEvent.to, swapEvent.from, historyState);\n triggerEvent(\"zfb:after-swap\");\n\n // Resolve the finished promise of the simulation's ViewTransition.\n // For 'animate', wait for the new-page animation to complete first.\n // For other fallback modes (e.g. 'swap'), resolve immediately — no animation needed.\n if (fallback === \"animate\" && !currentTransition.transitionSkipped) {\n animate(\"new\").finally(() => currentTransition.viewTransitionFinished!());\n } else {\n currentTransition.viewTransitionFinished?.();\n }\n return \"swapped\";\n}\n\nfunction notifyNavigationAborted(navigation: Navigation): void {\n // From island teardown onward the navigation is committed and must finish,\n // even if an overridden event.swap() synchronously starts a newer one.\n if (navigation.domCommitStarted || navigation.abortEventEmitted) return;\n navigation.abortEventEmitted = true;\n triggerEvent(\"zfb:navigation-aborted\");\n}\n\ntype RejectedLocationWrite = Extract<LocationWrite, { status: \"rejected\" }>;\n\ntype HistoryCommitPlan = {\n early: EarlyCommit;\n // The swap runs inside a native startViewTransition update callback.\n insideNativeViewTransition: boolean;\n // False for a submitted form: its request may already have changed server\n // state, so a rejected URL write must never be retried as a document load.\n recoverByDocumentLoad: boolean;\n};\n\n// End a navigation whose URL write the browser rejected, before any DOM\n// change. A GET is recovered with one deliberate document load of its resolved\n// destination (replacing the entry this navigation already made, or honoring\n// its replace intent); anything else stays on the intact old page.\nfunction abandonNavigation(\n navigation: Navigation,\n to: URL,\n write: RejectedLocationWrite,\n recoverByDocumentLoad: boolean,\n): void {\n if (write.error !== undefined) {\n const err = write.error as Error;\n // biome-ignore lint/suspicious/noConsole: allowed\n console.log(\"[zfb]\", err?.name, err?.message);\n }\n // An early write may already have moved the URL; describe where the browser\n // actually is rather than the location this navigation started from. Done\n // before the abort event so a navigation started by a listener sees it too.\n // That entry's page was never rendered, so remember the mismatch.\n const actual = new URL(location.href);\n if (!samePage(actual, originalLocation)) currentEntryUnrendered = true;\n originalLocation = actual;\n notifyNavigationAborted(navigation);\n // An abort listener may have started a newer navigation, which now owns the\n // page; this one must not load over it.\n if (navigation.controller.signal.aborted) return;\n if (navigation === mostRecentNavigation) mostRecentNavigation = undefined;\n if (!recoverByDocumentLoad) return;\n if (write.replace) location.replace(to.href);\n else location.href = to.href;\n}\n\nfunction abortAndRecreateMostRecentNavigation(): Navigation {\n const previousNavigation = mostRecentNavigation;\n const nextNavigation: Navigation = {\n controller: new AbortController(),\n domCommitStarted: false,\n abortEventEmitted: false,\n };\n // Install the new owner before abort/event dispatch. Either operation can\n // synchronously re-enter navigate(); that newer call must remain the winner.\n mostRecentNavigation = nextNavigation;\n if (previousNavigation) {\n previousNavigation.controller.abort();\n // Native View Transitions may settle updateCallbackDone without ever\n // invoking the skipped update callback. Emit here so updateDOM is not the\n // only observer of a real pre-commit abort.\n notifyNavigationAborted(previousNavigation);\n }\n return nextNavigation;\n}\n\nasync function transition(\n direction: Direction,\n from: URL,\n to: URL,\n options: Options,\n historyState?: State,\n hasUAVisualTransition = false,\n) {\n // The most recent navigation always has precedence\n // Yes, there can be several navigation instances as the user can click links\n // while we fetch content or simulate view transitions. Even synchronous creations are possible\n // e.g. by calling navigate() from a transition event.\n // Invariant: all but the most recent navigation are already aborted.\n\n const currentNavigation = abortAndRecreateMostRecentNavigation();\n\n // Emitting the previous navigation's abort event is synchronous. A listener\n // may have started an even newer navigation before this call resumes.\n if (currentNavigation.controller.signal.aborted) return;\n\n // not ours\n if (!transitionEnabledOnThisPage() || location.origin !== to.origin) {\n if (currentNavigation === mostRecentNavigation) mostRecentNavigation = undefined;\n location.href = to.href;\n return;\n }\n\n const navigationType = historyState\n ? \"traverse\"\n : options.history === \"replace\"\n ? \"replace\"\n : \"push\";\n\n if (navigationType !== \"traverse\") {\n updateScrollPosition({ scrollX, scrollY });\n }\n // An unrendered early entry shares its URL with no live DOM: never serve it\n // from the current page, fetch and swap instead.\n if (samePage(from, to) && !options.formData && !currentEntryUnrendered) {\n if (\n // Same-page Back/Forward: serve from the live DOM (no re-fetch/re-swap)\n // unless this page opted back into the fetch (per-request SSR). #1374/#1376.\n (navigationType === \"traverse\" && !traverseRefetchOptedOut()) ||\n (direction !== \"back\" && to.hash) ||\n (direction === \"back\" && from.hash)\n ) {\n const write = writeLocationEntry(to, options, historyState, \"none\", false);\n if (write.status === \"rejected\") {\n // A clean abort: the page and URL stay as they are, with no fragment\n // scroll and no state advance for a location that never happened.\n abandonNavigation(currentNavigation, to, write, false);\n return;\n }\n settleLocation(to, from, historyState);\n if (currentNavigation === mostRecentNavigation) mostRecentNavigation = undefined;\n return;\n }\n }\n\n const prepEvent = await doPreparation(\n from,\n to,\n direction,\n navigationType,\n options.sourceElement,\n options.info,\n currentNavigation!.controller.signal,\n options.formData,\n defaultLoader,\n );\n if (prepEvent.defaultPrevented || prepEvent.signal.aborted) {\n if (currentNavigation === mostRecentNavigation) mostRecentNavigation = undefined;\n notifyNavigationAborted(currentNavigation);\n if (!prepEvent.signal.aborted) {\n // not aborted -> delegate to browser\n location.href = to.href;\n }\n // and / or exit\n return;\n }\n\n async function defaultLoader(preparationEvent: TransitionBeforePreparationEvent) {\n const href = preparationEvent.to.href;\n const init: RequestInit = { signal: preparationEvent.signal };\n if (preparationEvent.formData) {\n init.method = \"POST\";\n const form =\n preparationEvent.sourceElement instanceof HTMLFormElement\n ? preparationEvent.sourceElement\n : preparationEvent.sourceElement instanceof HTMLElement &&\n \"form\" in preparationEvent.sourceElement\n ? (preparationEvent.sourceElement.form as HTMLFormElement)\n : preparationEvent.sourceElement?.closest(\"form\");\n // Form elements without enctype explicitly set default to application/x-www-form-urlencoded.\n // In order to maintain compatibility with Astro 4.x, we need to check the value of enctype\n // on the attributes property rather than accessing .enctype directly. Astro 5.x may\n // introduce defaulting to application/x-www-form-urlencoded as a breaking change, and then\n // we can access .enctype directly.\n //\n // Note: getNamedItem can return null in real life, even if TypeScript doesn't think so, hence\n // the ?.\n // `form` can be null (closest() miss, or a form-less form-associated\n // element) — `!= null` covers both null and undefined so Reflect.get\n // is never invoked on a non-element receiver (\"Illegal invocation\").\n init.body =\n form != null &&\n Reflect.get(HTMLFormElement.prototype, \"attributes\", form).getNamedItem(\"enctype\")\n ?.value === \"application/x-www-form-urlencoded\"\n ? new URLSearchParams(preparationEvent.formData as any)\n : preparationEvent.formData;\n }\n const response = await fetchHTML(href, init);\n // If there is a problem fetching the new page, just do an MPA navigation to it.\n if (response === null) {\n preparationEvent.preventDefault();\n return;\n }\n // if there was a redirection, show the final URL in the browser's address bar\n if (response.redirected) {\n const redirectedTo = new URL(response.redirected);\n // but do not redirect cross origin\n if (redirectedTo.origin !== preparationEvent.to.origin) {\n preparationEvent.preventDefault();\n return;\n }\n // preserve fragment\n const fragment = preparationEvent.to.hash;\n preparationEvent.to = redirectedTo;\n preparationEvent.to.hash = fragment;\n }\n\n parser ??= new DOMParser();\n\n preparationEvent.newDocument = parser.parseFromString(response.html, response.mediaType);\n // The next line might look like a hack,\n // but it is actually necessary as noscript elements\n // and their contents are returned as markup by the parser,\n // see https://developer.mozilla.org/en-US/docs/Web/API/DOMParser/parseFromString\n preparationEvent.newDocument.querySelectorAll(\"noscript\").forEach((el) => el.remove());\n\n // If ClientRouter is not enabled on the incoming page, do a full page load to it.\n // Unless this was a form submission, in which case we do not want to trigger another mutation.\n if (\n !preparationEvent.newDocument.querySelector('[name=\"zfb-view-transitions-enabled\"]') &&\n !preparationEvent.formData\n ) {\n preparationEvent.preventDefault();\n return;\n }\n\n const links = preloadStyleLinks(preparationEvent.newDocument);\n links.length && !preparationEvent.signal.aborted && (await Promise.all(links));\n\n // W3C2: prepareForClientOnlyComponents() goes here. Astro's DEV-only iframe\n // trick that hoists Vite per-component CSS for client:only islands does not\n // apply to zfb (W1B §13.5 — zfb islands inject CSS via the bundle), so the\n // call is intentionally absent rather than stubbed.\n }\n async function abortAndRecreateMostRecentTransition(): Promise<Transition> {\n if (mostRecentTransition) {\n if (mostRecentTransition.viewTransition) {\n try {\n mostRecentTransition.viewTransition.skipTransition();\n } catch {\n // might throw AbortError DOMException. Ignored on purpose.\n }\n try {\n // UpdateCallbackDone might already been settled, i.e. if the previous transition finished updating the DOM.\n // Could not take long, we wait for it to avoid parallel updates\n // (which are very unlikely as long as swap() is not async).\n await mostRecentTransition.viewTransition.updateCallbackDone;\n } catch {\n // There was an error in the update callback of the transition which we cancel.\n // Ignored on purpose\n }\n }\n }\n return (mostRecentTransition = { transitionSkipped: false });\n }\n\n const currentTransition = await abortAndRecreateMostRecentTransition();\n\n if (prepEvent.signal.aborted) {\n if (currentNavigation === mostRecentNavigation) mostRecentNavigation = undefined;\n notifyNavigationAborted(currentNavigation);\n return;\n }\n\n // A submitted form's request may already have changed server state, so a\n // rejected URL write can be neither retried as a document load nor followed\n // by an SPA swap. Its single history write is therefore deferred until the\n // final target is known — after zfb:before-swap, right before teardown — so\n // no early entry can strand the old page under an intermediate URL. That\n // write may push a new entry, which must not happen inside a native View\n // Transition callback (see below), so form navigations swap through the\n // simulated transition instead.\n const submittedForm = options.formData !== undefined || prepEvent.formData !== undefined;\n const useNativeViewTransition =\n supportsViewTransitions && !hasUAVisualTransition && !submittedForm;\n\n // Commit the SPA history entry BEFORE the transition's update callback runs.\n //\n // WebKit (all iOS browsers, incl. iOS Chrome) does not reliably commit a\n // distinct back/forward history entry when history.pushState() is issued\n // *inside* the document.startViewTransition() update callback: the URL bar\n // updates but no new entry is created, so a single Back press falls off the\n // site to the browser home (zudolab/zzmod#662). Committing the entry here —\n // outside the transition's update callback — makes WebKit create it; Chromium\n // is unaffected either way. The final write in updateDOM (inside the\n // callback) then has nothing left to do unless a zfb:before-swap listener\n // retargets `event.to`, in which case it replaces this entry.\n //\n // We use prepEvent.to (redirects are already resolved into it during\n // preparation) and write before the swap, while document.title is still the\n // old page's title — so the back entry keeps the correct (old-page) title.\n // Writing here also covers the non-VT fallback path below in one place.\n //\n // Traverse (popstate) navigations carry historyState: the browser has already\n // moved, so they must NOT create a new entry here.\n let early: EarlyCommit = \"none\";\n if (!submittedForm) {\n const write = writeLocationEntry(prepEvent.to, options, historyState, \"none\", false);\n if (write.status === \"rejected\") {\n // Nothing has been swapped or started yet: release the transition slot\n // and let the browser load the resolved destination itself.\n if (currentTransition === mostRecentTransition) mostRecentTransition = undefined;\n abandonNavigation(currentNavigation, prepEvent.to, write, true);\n return;\n }\n if (write.status !== \"unchanged\") early = write.status;\n }\n const historyCommit: HistoryCommitPlan = {\n early,\n insideNativeViewTransition: useNativeViewTransition,\n recoverByDocumentLoad: !submittedForm,\n };\n\n document.documentElement.setAttribute(DIRECTION_ATTR, prepEvent.direction);\n\n let domUpdateOutcome: DOMUpdateOutcome | undefined;\n\n if (useNativeViewTransition) {\n // This automatically cancels any previous transition\n // We also already took care that the earlier update callback got through\n currentTransition.viewTransition = document.startViewTransition(async () => {\n domUpdateOutcome = await updateDOM(\n prepEvent,\n options,\n currentNavigation,\n currentTransition,\n historyState,\n undefined,\n historyCommit,\n );\n });\n // A skipped native transition rejects ready even when its update callback\n // succeeds (or never runs). The browser does not mark ready as handled.\n // Update failures are reported through updateCallbackDone below.\n currentTransition.viewTransition.ready.catch(() => {});\n } else {\n // Simulation mode requires a bit more manual work.\n // Also used when PopStateEvent.hasUAVisualTransition indicates the browser already\n // provided a visual transition (e.g. Safari swipe gesture) — in that case, fallback\n // is \"swap\" to skip animations. Submitted forms use it too (see submittedForm).\n const updateDone = (async () => {\n // Immediately paused to set up the ViewTransition object for Fallback mode\n await Promise.resolve(); // hop through the micro task queue\n domUpdateOutcome = await updateDOM(\n prepEvent,\n options,\n currentNavigation,\n currentTransition,\n historyState,\n hasUAVisualTransition ? \"swap\" : getFallback(),\n historyCommit,\n );\n return undefined;\n })();\n\n // When the updateDone promise is settled,\n // we have run and awaited all swap functions and the after-swap event\n // This qualifies for \"updateCallbackDone\".\n //\n // For the build in ViewTransition, \"ready\" settles shortly after \"updateCallbackDone\",\n // i.e. after all pseudo elements are created and the animation is about to start.\n // In simulation mode the \"old\" animation starts before swap,\n // the \"new\" animation starts after swap. That is not really comparable.\n // Thus we go with \"very, very shortly after updateCallbackDone\" and make both equal.\n //\n // \"finished\" resolves after all animations are done.\n\n currentTransition.viewTransition = {\n updateCallbackDone: updateDone, // this is about correct\n ready: updateDone, // good enough\n // Finished promise could have been done better: finished rejects iff updateDone does.\n // Our simulation always resolves, never rejects.\n finished: new Promise((r) => (currentTransition.viewTransitionFinished = r as () => void)), // see end of updateDOM\n skipTransition: () => {\n currentTransition.transitionSkipped = true;\n // This cancels all animations of the simulation\n document.documentElement.removeAttribute(OLD_NEW_ATTR);\n },\n types: new Set<string>(), // empty by default\n };\n }\n // In earlier versions was then'ed on viewTransition.ready which would not execute\n // if the visual part of the transition has errors or was skipped\n currentTransition.viewTransition?.updateCallbackDone.then(\n async () => {\n if (domUpdateOutcome !== \"swapped\") return;\n await runScripts();\n // Mount new island markers introduced by the body swap. Fire-and-forget;\n // each island's scheduleHydrate call is async (idle / visible). Called after\n // runScripts() so any new mountIslands() registration from inline scripts in\n // the new page has already run. Called before onPageLoad() per W1B §12.2.\n mountNewIslands();\n onPageLoad();\n announce();\n },\n () => {}, // the await below reports genuine update callback errors\n );\n // finished.ready and finished.finally are the same for the simulation but not\n // necessarily for native view transition, where finished rejects when updateCallbackDone does.\n const clearTransition = () => {\n // exactOptionalPropertyTypes: true forbids assigning `undefined` to an optional\n // `viewTransition?: ViewTransition` slot — `delete` is the equivalent reset.\n delete currentTransition.viewTransition;\n if (currentTransition === mostRecentTransition) mostRecentTransition = undefined;\n if (currentNavigation === mostRecentNavigation) mostRecentNavigation = undefined;\n document.documentElement.removeAttribute(DIRECTION_ATTR);\n document.documentElement.removeAttribute(OLD_NEW_ATTR);\n };\n // A discarded finally() child would itself reject on an update error.\n currentTransition.viewTransition?.finished.then(clearTransition, clearTransition);\n try {\n // Compatibility:\n // In an earlier version we awaited viewTransition.ready, which includes animation setup.\n // Scripts that depend on the view transition pseudo elements should hook on viewTransition.ready.\n await currentTransition.viewTransition?.updateCallbackDone;\n } catch (e) {\n // This log doesn't make it worse than before, where we got error messages about uncaught exceptions, which can't be caught when the trigger was a click or history traversal.\n // Needs more investigation on root causes if errors still occur sporadically\n const err = e as Error;\n // biome-ignore lint/suspicious/noConsole: allowed\n console.log(\"[zfb]\", err.name, err.message, err.stack);\n }\n}\n\nlet navigateOnServerWarned = false;\n\nexport async function navigate(href: string, options?: Options) {\n if (inBrowser === false) {\n if (!navigateOnServerWarned) {\n // instantiate an error for the stacktrace to show to user.\n const warning = new Error(\n \"The view transitions client API was called during a server side render. This may be unintentional as the navigate() function is expected to be called in response to user interactions. Please make sure that your usage is correct.\",\n );\n warning.name = \"Warning\";\n // biome-ignore lint/suspicious/noConsole: allowed\n console.warn(warning);\n navigateOnServerWarned = true;\n }\n return;\n }\n if (!supportsViewTransitions && getFallback() === \"none\") {\n const url = new URL(href, location.href);\n // Honor the history option on the full-load fallback path: \"replace\"\n // must not leave a back-button entry, so use location.replace().\n if (options?.history === \"replace\") {\n location.replace(url.href);\n } else {\n location.href = url.href;\n }\n return;\n }\n // `originalLocation` is seeded by init(); seed it here too so an init-less\n // caller never hands transition() an undefined \"from\" URL.\n ensureNavigationState();\n await transition(\"forward\", originalLocation, new URL(href, location.href), options ?? {});\n}\n\nfunction onPopState(ev: PopStateEvent) {\n if (!transitionEnabledOnThisPage() && ev.state) {\n // The current page doesn't have View Transitions enabled\n // but the page we navigate to does (because it set the state).\n // Do a full page refresh to reload the client-side router from the new page.\n location.reload();\n return;\n }\n\n // History entries without state are created by the browser (e.g. for hash links)\n // Our view transition entries always have state.\n // Just ignore stateless entries.\n // The browser will handle navigation fine without our help\n if (ev.state === null) {\n return;\n }\n const state: State = history.state;\n const nextIndex = state.index;\n const direction: Direction = derivePopDirection(nextIndex, currentHistoryIndex);\n // Only advance the tracked index when the entry carries a usable index.\n // After a bfcache restore the index can be missing/NaN; clobbering the\n // tracked value with NaN would poison every subsequent direction calc, so\n // keep the last known-good index in that case (see derivePopDirection).\n if (Number.isFinite(nextIndex)) {\n currentHistoryIndex = nextIndex;\n }\n transition(\n direction,\n originalLocation,\n new URL(location.href),\n {},\n state,\n ev.hasUAVisualTransition,\n );\n}\n\n// Decide forward vs back from the popped entry's index against the last\n// tracked index. Two desync cases a WebKit bfcache restore can produce:\n// - missing / NaN `next` (restored entry lost its index): handled explicitly\n// below — we cannot prove a forward move, so treat it as \"back\" (the safe\n// default; a forward misclassification is what makes Back skip to the wrong\n// page).\n// - `next === current` (index unchanged after a desync/replace): falls out of\n// the `>` comparison as \"back\" — not a forward navigation.\nfunction derivePopDirection(nextIndex: number, trackedIndex: number): Direction {\n if (!Number.isFinite(nextIndex)) return \"back\";\n return nextIndex > trackedIndex ? \"forward\" : \"back\";\n}\n\nconst onScrollEnd = () => {\n // NOTE: our \"popstate\" event handler may call `pushState()` or\n // `replaceState()` and then `scrollTo()`, which will fire \"scroll\" and\n // \"scrollend\" events. To avoid redundant work and expensive calls to\n // `replaceState()`, we simply check that the values are different before\n // updating.\n if (history.state && (scrollX !== history.state.scrollX || scrollY !== history.state.scrollY)) {\n updateScrollPosition({ scrollX, scrollY });\n }\n};\n\n// zfb-only addition (no Astro upstream — see file header \"zfb-only additions\").\n// WebKit serves Back navigations after an SPA route change from the bfcache:\n// the page is restored without re-evaluating this module or re-running init(),\n// so `seedPageState()` below (which sets `currentHistoryIndex` from\n// `history.state.index`) never re-runs and the tracked index can desync from\n// the live history stack. A desynced index makes onPopState's direction calc\n// misfire, so Back skips an entry. On a persisted (bfcache) restore we re-seed\n// the tracked index and the `originalLocation` \"from\" URL from the live state,\n// and restore scroll — mirroring that seed. This is a no-op on a normal load\n// (`persisted` falsy/absent) and idempotent (re-seeding from the same state\n// twice changes nothing and fires no transition).\nconst onPageShow = (ev: PageTransitionEvent) => {\n // Normal (non-bfcache) loads already ran init()'s seed; leave them be.\n if (!ev.persisted) return;\n // init() seeds `originalLocation` and `currentHistoryIndex` together; re-sync\n // both here so the next transition() gets the correct `from` URL (a stale\n // `originalLocation` would feed onPopState the wrong origin).\n originalLocation = new URL(location.href);\n currentEntryUnrendered = false;\n const index = history.state?.index;\n if (Number.isFinite(index)) {\n currentHistoryIndex = index;\n }\n if (history.state) {\n scrollTo({ left: history.state.scrollX, top: history.state.scrollY });\n }\n};\n\n// ---- initialization (folded out of module scope by #2436) ----\n\n// Once-guard for the page-state phase of init(). Deliberately SEPARATE from the\n// `initialized` latch below, because the two phases have different eligibility:\n// this one runs on EVERY browser page — including one where view transitions\n// are ineligible (no native support and fallback \"none\") — while the activation\n// listeners are VT-gated. A single shared latch would either skip this phase\n// forever after an ineligible early call, or latch activation on a page that\n// never qualified for it. (#2436)\nlet pageStateSeeded = false;\n\n/**\n * Everything module evaluation used to do for EVERY browser page, regardless\n * of view-transition eligibility: restore (or seed) this page's history entry\n * and its scroll position, and mark the scripts the initial page load already\n * executed so runScripts() does not re-run them after a swap.\n *\n * Called from init() BEFORE its eligibility early-return — that gating\n * asymmetry is load-bearing and predates the fold: a page with fallback \"none\"\n * still needs its history entry restored and its scripts marked. (#2436)\n */\nfunction seedPageState(): void {\n if (pageStateSeeded) return;\n pageStateSeeded = true;\n\n if (history.state) {\n // Here we reloaded a page with history state\n // (e.g. history navigation from non-transition page or browser reload)\n // Adopt only a finite index — a foreign pre-init history.state (e.g. a\n // consumer's own replaceState({modal: true})) has no router index, and\n // adopting undefined would stamp the next push with NaN. Same guard as\n // ensureNavigationState() and onPageShow(). (#2436)\n const index = history.state.index;\n if (Number.isFinite(index)) currentHistoryIndex = index;\n // Skip the scroll restore when an init-less navigate()/syncHistoryEntry()\n // already ran on this page (navigationStateSeeded latched before init):\n // the entry it pushed is stamped scrollX/scrollY 0, and a late-activating\n // init() must not yank the already-scrolled viewport to the top. (#2436)\n if (!navigationStateSeeded) {\n scrollTo({ left: history.state.scrollX, top: history.state.scrollY });\n }\n } else if (transitionEnabledOnThisPage()) {\n // This page is loaded from the browser address bar or via a link from extern,\n // it needs a state in the history\n safeReplaceState({ index: currentHistoryIndex, scrollX, scrollY }, \"\");\n history.scrollRestoration = \"manual\";\n }\n\n for (const script of document.getElementsByTagName(\"script\")) {\n detectScriptExecuted(script);\n script.dataset[\"zfbExec\"] = \"\";\n }\n}\n\n/**\n * Register the window-level navigation listeners. Called from init() only\n * after the view-transition eligibility check, and only once — the\n * `initialized` latch owns this phase.\n */\nfunction registerNavigationListeners(): void {\n addEventListener(\"popstate\", onPopState);\n addEventListener(\"load\", onPageLoad);\n // Re-sync the tracked history index + scroll on a WebKit bfcache restore;\n // a no-op on normal loads. See onPageShow above.\n addEventListener(\"pageshow\", onPageShow);\n // There's not a good way to record scroll position before a history back\n // navigation, so we will record it when the user has stopped scrolling.\n if (\"onscrollend\" in window) addEventListener(\"scrollend\", onScrollEnd);\n else {\n // Keep track of state between intervals\n let intervalId: number | undefined, lastY: number, lastX: number, lastIndex: State[\"index\"];\n const scrollInterval = () => {\n // The interval can outlive its document context — a test-env teardown or a\n // real page unload removes window/history before the 50ms tick. `typeof`\n // never throws even when the global is gone: stop the interval and bail\n // rather than dereferencing a torn-down global (the #1061 bug class; #1063).\n // In a real browser these globals always exist, so this path is test-env\n // only. clearInterval may itself be mid-teardown, so guard the call too.\n if (typeof window === \"undefined\" || typeof history === \"undefined\") {\n if (typeof clearInterval === \"function\") clearInterval(intervalId);\n intervalId = undefined;\n return;\n }\n // Check the index to see if a popstate event was fired\n if (lastIndex !== history.state?.index) {\n clearInterval(intervalId);\n intervalId = undefined;\n return;\n }\n // Check if the user stopped scrolling\n if (lastY === scrollY && lastX === scrollX) {\n // Cancel the interval and update scroll positions\n clearInterval(intervalId);\n intervalId = undefined;\n onScrollEnd();\n return;\n } else {\n ((lastY = scrollY), (lastX = scrollX));\n }\n };\n // We can't know when or how often scroll events fire, so we'll just use them to start intervals\n addEventListener(\n \"scroll\",\n () => {\n if (intervalId !== undefined) return;\n ((lastIndex = history.state?.index), (lastY = scrollY), (lastX = scrollX));\n intervalId = window.setInterval(scrollInterval, 50);\n },\n { passive: true },\n );\n }\n}\n\n// ---- W3C3: click + form intercept, public idempotent init() ----\n\n// Returns true when the modifier-key combo or mouse button means \"open in new tab / download\".\n// Matches Astro's `leavesWindow` helper in ClientRouter.astro.\nconst leavesWindow = (ev: MouseEvent): boolean =>\n (ev.button !== undefined && ev.button !== 0) || // non-left-click\n ev.metaKey || // new tab (Mac)\n ev.ctrlKey || // new tab (Windows/Linux)\n ev.altKey || // download\n ev.shiftKey; // new window\n\n// Track the last clicked element that will leave the window so form submit can check it.\nlet lastClickedElementLeavingWindow: EventTarget | null = null;\n\nfunction handleClick(ev: MouseEvent): void {\n let link: EventTarget | null = ev.target;\n\n // Record whether this click will leave the window (used by form submit handler).\n lastClickedElementLeavingWindow = leavesWindow(ev) ? link : null;\n\n // Shadow DOM: prefer composedPath target over ev.target.\n if (ev.composed) {\n link = ev.composedPath()[0] ?? link;\n }\n\n // Walk up to the nearest <a>, <area>, or <svg:a>.\n if (link instanceof Element) {\n link = link.closest(\"a, area\");\n }\n\n if (\n !(link instanceof HTMLAnchorElement) &&\n !(link instanceof SVGAElement) &&\n !(link instanceof HTMLAreaElement)\n ) {\n return;\n }\n\n const linkEl = link as HTMLAnchorElement | SVGAElement | HTMLAreaElement;\n const linkTarget =\n linkEl instanceof HTMLElement ? linkEl.target : (linkEl as SVGAElement).target.baseVal;\n const href = linkEl instanceof HTMLElement ? linkEl.href : (linkEl as SVGAElement).href.baseVal;\n\n if (!href) return;\n\n const origin = new URL(href, location.href).origin;\n\n if (\n // data-zfb-reload: caller wants a full browser reload, not a SPA transition.\n (linkEl as HTMLElement).dataset[\"zfbReload\"] !== undefined ||\n // download attribute: let browser handle download.\n linkEl.hasAttribute(\"download\") ||\n // Non-self target opens in a new context — skip.\n (linkTarget && linkTarget !== \"_self\") ||\n // Cross-origin: not ours to handle.\n origin !== location.origin ||\n // Modifier key / non-left-click combo: user wants new tab / window / download.\n lastClickedElementLeavingWindow !== null ||\n // Another handler already handled this event.\n ev.defaultPrevented\n ) {\n return;\n }\n\n ev.preventDefault();\n navigate(href, {\n // data-zfb-history=\"replace\" opts a link into replaceState instead of pushState.\n history: (linkEl as HTMLElement).dataset[\"zfbHistory\"] === \"replace\" ? \"replace\" : \"auto\",\n sourceElement: linkEl,\n });\n}\n\nfunction handleSubmit(ev: SubmitEvent): void {\n const el = ev.target as HTMLElement;\n const submitter = ev.submitter as HTMLElement | null;\n\n // If the submit was triggered by a modifier-key click, treat as normal browser submit.\n const clickedWithKeys = submitter !== null && submitter === lastClickedElementLeavingWindow;\n lastClickedElementLeavingWindow = null;\n\n if (\n el.tagName !== \"FORM\" ||\n ev.defaultPrevented ||\n el.dataset[\"zfbReload\"] !== undefined ||\n clickedWithKeys\n ) {\n return;\n }\n\n const form = el as HTMLFormElement;\n const formData = new FormData(form, submitter ?? undefined);\n\n // form.action / form.method can be shadowed by <input name=\"action\"> / <input name=\"method\">,\n // so fall back to getAttribute() when the property is not a string. (Astro's comment.)\n const formAction = typeof form.action === \"string\" ? form.action : form.getAttribute(\"action\");\n const formMethod = typeof form.method === \"string\" ? form.method : form.getAttribute(\"method\");\n\n // Resolve action: submitter formaction attr overrides form action, fallback to current path.\n let action = submitter?.getAttribute(\"formaction\") ?? formAction ?? location.pathname;\n // Resolve method: submitter formmethod attr overrides form method, fallback to \"get\".\n const method = submitter?.getAttribute(\"formmethod\") ?? formMethod ?? \"get\";\n\n // The \"dialog\" method is a special keyword used within <dialog> elements —\n // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fs-method\n if (method === \"dialog\" || location.origin !== new URL(action, location.href).origin) {\n // No SPA transition in these cases — let browser handle it.\n return;\n }\n\n const options: import(\"./types.js\").Options = { sourceElement: submitter ?? form };\n if (method === \"get\") {\n const params = new URLSearchParams(formData as any);\n const url = new URL(action, location.href);\n url.search = params.toString();\n action = url.toString();\n } else {\n options.formData = formData;\n }\n\n ev.preventDefault();\n navigate(action, options);\n}\n\nexport interface InitOptions {\n /** Reserved for forward-compat with Astro's prefetch integration. Ignored in v1. */\n prefetchAll?: boolean;\n}\n\n// Guard flag — ensures the activation listeners (popstate/load/pageshow/scroll\n// plus click + submit) are registered only once even if init() is called\n// multiple times (e.g. two <ClientRouter> mounts on the same page).\nlet initialized = false;\n\n/**\n * Bootstrap the client router on this page: restore its history entry, mark\n * the already-executed scripts, and wire up the navigation, click and\n * form-submit listeners. Safe to call multiple times — each of the two phases\n * runs at most once (idempotent).\n *\n * Evaluating this module does nothing; every side effect the router performs\n * at startup happens here (#2436). Two once-guards rather than one, because\n * the phases have different eligibility — see `pageStateSeeded`.\n *\n * @param _options - Forward-compat hook matching Astro's init() signature. Ignored in v1.\n */\nexport function init(_options?: InitOptions): void {\n if (!inBrowser) return;\n\n // Phase 1 — runs on every browser page, even a view-transition-ineligible\n // one, and therefore BEFORE the eligibility early-return below.\n seedPageState();\n\n if (initialized) return;\n\n // Phase 2 — activation. Latch the guard only AFTER this eligibility check:\n // an ineligible early call (fallback \"none\" and no native view transitions)\n // must not permanently latch `initialized`, or a later legitimately-eligible\n // init() would no-op forever.\n if (!supportsViewTransitions && getFallback() === \"none\") return;\n\n initialized = true;\n\n // Where we came from, for the first transition() of this page. Re-seeded\n // unconditionally at activation (as module evaluation used to do), so it\n // reflects the URL at activation time even if an init-less navigate() or\n // syncHistoryEntry() already primed it via ensureNavigationState().\n navigationStateSeeded = true;\n originalLocation = new URL(location.href);\n currentEntryUnrendered = false;\n\n registerNavigationListeners();\n\n document.addEventListener(\"click\", handleClick);\n document.addEventListener(\"submit\", handleSubmit as EventListener);\n\n // Prefetch hook intentionally omitted from v1 — see https://github.com/zudolab/zudo-doc/issues/1527\n // (Followup tracker for porting Astro prefetch module).\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@takazudo/zfb-runtime",
3
- "version": "4.3.0",
3
+ "version": "4.3.1",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "JavaScript runtime for zfb static sites — Hono-backed page router, content snapshots, and client-side hydration.",
@@ -72,10 +72,10 @@
72
72
  "hono": "^4.12.25"
73
73
  },
74
74
  "peerDependencies": {
75
- "@takazudo/zfb": "4.3.0"
75
+ "@takazudo/zfb": "4.3.1"
76
76
  },
77
77
  "devDependencies": {
78
- "@takazudo/zfb": "4.3.0",
78
+ "@takazudo/zfb": "4.3.1",
79
79
  "@types/node": "^22.0.0",
80
80
  "happy-dom": "^15.7.4",
81
81
  "typescript": "7.0.2",