fuzor 0.5.1 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (314) hide show
  1. package/dist/browser.d.ts +2 -0
  2. package/dist/browser.d.ts.map +1 -1
  3. package/dist/browser.js +1 -0
  4. package/dist/browser.js.map +1 -1
  5. package/dist/cli.js +10 -0
  6. package/dist/cli.js.map +1 -1
  7. package/dist/compiler/data-document.d.ts +20 -1
  8. package/dist/compiler/data-document.d.ts.map +1 -1
  9. package/dist/compiler/data-document.js +80 -7
  10. package/dist/compiler/data-document.js.map +1 -1
  11. package/dist/compiler/docs.d.ts.map +1 -1
  12. package/dist/compiler/docs.js +49 -11
  13. package/dist/compiler/docs.js.map +1 -1
  14. package/dist/compiler/index.d.ts +2 -0
  15. package/dist/compiler/index.d.ts.map +1 -1
  16. package/dist/compiler/index.js +23 -6
  17. package/dist/compiler/index.js.map +1 -1
  18. package/dist/compiler/islands.d.ts +1 -0
  19. package/dist/compiler/islands.d.ts.map +1 -1
  20. package/dist/compiler/native-authoring.d.ts +45 -0
  21. package/dist/compiler/native-authoring.d.ts.map +1 -0
  22. package/dist/compiler/native-authoring.js +569 -0
  23. package/dist/compiler/native-authoring.js.map +1 -0
  24. package/dist/compiler/native-manifest.d.ts +33 -0
  25. package/dist/compiler/native-manifest.d.ts.map +1 -0
  26. package/dist/compiler/native-manifest.js +53 -0
  27. package/dist/compiler/native-manifest.js.map +1 -0
  28. package/dist/compiler/native-ranges.d.ts +8 -0
  29. package/dist/compiler/native-ranges.d.ts.map +1 -0
  30. package/dist/compiler/native-ranges.js +92 -0
  31. package/dist/compiler/native-ranges.js.map +1 -0
  32. package/dist/compiler/native-scripts.js +2 -2
  33. package/dist/compiler/native-scripts.js.map +1 -1
  34. package/dist/compiler/page-scripts.d.ts +6 -0
  35. package/dist/compiler/page-scripts.d.ts.map +1 -1
  36. package/dist/compiler/page-scripts.js +25 -6
  37. package/dist/compiler/page-scripts.js.map +1 -1
  38. package/dist/compiler/route-policy.d.ts +1 -0
  39. package/dist/compiler/route-policy.d.ts.map +1 -1
  40. package/dist/compiler/route-policy.js +4 -1
  41. package/dist/compiler/route-policy.js.map +1 -1
  42. package/dist/compiler/select-options.d.ts +7 -0
  43. package/dist/compiler/select-options.d.ts.map +1 -0
  44. package/dist/compiler/select-options.js +22 -0
  45. package/dist/compiler/select-options.js.map +1 -0
  46. package/dist/compiler/server-actions.d.ts +9 -0
  47. package/dist/compiler/server-actions.d.ts.map +1 -0
  48. package/dist/compiler/server-actions.js +65 -0
  49. package/dist/compiler/server-actions.js.map +1 -0
  50. package/dist/data-bindings.d.ts +4 -0
  51. package/dist/data-bindings.d.ts.map +1 -0
  52. package/dist/data-bindings.js +18 -0
  53. package/dist/data-bindings.js.map +1 -0
  54. package/dist/dom-ownership.d.ts +5 -0
  55. package/dist/dom-ownership.d.ts.map +1 -0
  56. package/dist/dom-ownership.js +49 -0
  57. package/dist/dom-ownership.js.map +1 -0
  58. package/dist/index.d.ts +2 -0
  59. package/dist/index.d.ts.map +1 -1
  60. package/dist/index.js +1 -0
  61. package/dist/index.js.map +1 -1
  62. package/dist/internal-specifiers.d.ts +3 -0
  63. package/dist/internal-specifiers.d.ts.map +1 -0
  64. package/dist/internal-specifiers.js +22 -0
  65. package/dist/internal-specifiers.js.map +1 -0
  66. package/dist/islands/react.d.ts +0 -6
  67. package/dist/islands/react.d.ts.map +1 -1
  68. package/dist/islands/react.js +9 -26
  69. package/dist/islands/react.js.map +1 -1
  70. package/dist/json-value.d.ts +4 -0
  71. package/dist/json-value.d.ts.map +1 -0
  72. package/dist/json-value.js +10 -0
  73. package/dist/json-value.js.map +1 -0
  74. package/dist/native-expressions.d.ts +34 -0
  75. package/dist/native-expressions.d.ts.map +1 -0
  76. package/dist/native-expressions.js +118 -0
  77. package/dist/native-expressions.js.map +1 -0
  78. package/dist/native-manifest.d.ts +7 -0
  79. package/dist/native-manifest.d.ts.map +1 -0
  80. package/dist/native-manifest.js +4 -0
  81. package/dist/native-manifest.js.map +1 -0
  82. package/dist/native-ranges.d.ts +25 -0
  83. package/dist/native-ranges.d.ts.map +1 -0
  84. package/dist/native-ranges.js +51 -0
  85. package/dist/native-ranges.js.map +1 -0
  86. package/dist/native-state.d.ts +14 -0
  87. package/dist/native-state.d.ts.map +1 -0
  88. package/dist/native-state.js +27 -0
  89. package/dist/native-state.js.map +1 -0
  90. package/dist/route-path.d.ts +2 -0
  91. package/dist/route-path.d.ts.map +1 -1
  92. package/dist/route-path.js +2 -0
  93. package/dist/route-path.js.map +1 -1
  94. package/dist/runtime/binding-updates.d.ts +11 -0
  95. package/dist/runtime/binding-updates.d.ts.map +1 -0
  96. package/dist/runtime/binding-updates.js +45 -0
  97. package/dist/runtime/binding-updates.js.map +1 -0
  98. package/dist/runtime/data.d.ts +28 -1
  99. package/dist/runtime/data.d.ts.map +1 -1
  100. package/dist/runtime/data.js +101 -25
  101. package/dist/runtime/data.js.map +1 -1
  102. package/dist/runtime/docs-search.d.ts +20 -4
  103. package/dist/runtime/docs-search.d.ts.map +1 -1
  104. package/dist/runtime/docs-search.js +135 -159
  105. package/dist/runtime/docs-search.js.map +1 -1
  106. package/dist/runtime/docs-ui.d.ts +3 -1
  107. package/dist/runtime/docs-ui.d.ts.map +1 -1
  108. package/dist/runtime/docs-ui.js +19 -29
  109. package/dist/runtime/docs-ui.js.map +1 -1
  110. package/dist/runtime/index.d.ts +1 -0
  111. package/dist/runtime/index.d.ts.map +1 -1
  112. package/dist/runtime/islands.d.ts.map +1 -1
  113. package/dist/runtime/islands.js +2 -1
  114. package/dist/runtime/islands.js.map +1 -1
  115. package/dist/runtime/native-graph.d.ts +15 -0
  116. package/dist/runtime/native-graph.d.ts.map +1 -0
  117. package/dist/runtime/native-graph.js +103 -0
  118. package/dist/runtime/native-graph.js.map +1 -0
  119. package/dist/runtime/native-manifest.d.ts +17 -0
  120. package/dist/runtime/native-manifest.d.ts.map +1 -0
  121. package/dist/runtime/native-manifest.js +111 -0
  122. package/dist/runtime/native-manifest.js.map +1 -0
  123. package/dist/runtime/native-ranges.d.ts +8 -0
  124. package/dist/runtime/native-ranges.d.ts.map +1 -0
  125. package/dist/runtime/native-ranges.js +100 -0
  126. package/dist/runtime/native-ranges.js.map +1 -0
  127. package/dist/runtime/native-stream-reader.d.ts +7 -0
  128. package/dist/runtime/native-stream-reader.d.ts.map +1 -0
  129. package/dist/runtime/native-stream-reader.js +79 -0
  130. package/dist/runtime/native-stream-reader.js.map +1 -0
  131. package/dist/runtime/native-stream.d.ts +5 -0
  132. package/dist/runtime/native-stream.d.ts.map +1 -0
  133. package/dist/runtime/native-stream.js +14 -0
  134. package/dist/runtime/native-stream.js.map +1 -0
  135. package/dist/runtime/native.d.ts +41 -0
  136. package/dist/runtime/native.d.ts.map +1 -1
  137. package/dist/runtime/native.js +176 -55
  138. package/dist/runtime/native.js.map +1 -1
  139. package/dist/runtime/page-scripts.d.ts.map +1 -1
  140. package/dist/runtime/page-scripts.js +8 -3
  141. package/dist/runtime/page-scripts.js.map +1 -1
  142. package/dist/runtime/route-views.d.ts +15 -0
  143. package/dist/runtime/route-views.d.ts.map +1 -0
  144. package/dist/runtime/route-views.js +133 -0
  145. package/dist/runtime/route-views.js.map +1 -0
  146. package/dist/runtime/router-embedded.d.ts +1 -0
  147. package/dist/runtime/router-embedded.d.ts.map +1 -1
  148. package/dist/runtime/router-navigation-api.d.ts +1 -0
  149. package/dist/runtime/router-navigation-api.d.ts.map +1 -1
  150. package/dist/runtime/router.d.ts +1 -0
  151. package/dist/runtime/router.d.ts.map +1 -1
  152. package/dist/runtime/router.js +11 -2
  153. package/dist/runtime/router.js.map +1 -1
  154. package/dist/runtime/server-actions.d.ts +5 -0
  155. package/dist/runtime/server-actions.d.ts.map +1 -0
  156. package/dist/runtime/server-actions.js +79 -0
  157. package/dist/runtime/server-actions.js.map +1 -0
  158. package/dist/server-actions.d.ts +18 -0
  159. package/dist/server-actions.d.ts.map +1 -0
  160. package/dist/server-actions.js +138 -0
  161. package/dist/server-actions.js.map +1 -0
  162. package/dist/server-components/closures.d.ts +1 -12
  163. package/dist/server-components/closures.d.ts.map +1 -1
  164. package/dist/server-components/closures.js +0 -75
  165. package/dist/server-components/closures.js.map +1 -1
  166. package/dist/server-components/continuation.d.ts +7 -0
  167. package/dist/server-components/continuation.d.ts.map +1 -0
  168. package/dist/server-components/continuation.js +17 -0
  169. package/dist/server-components/continuation.js.map +1 -0
  170. package/dist/server-components/environment.js +1 -1
  171. package/dist/server-components/environment.js.map +1 -1
  172. package/dist/server-components/protocol.d.ts +5 -1
  173. package/dist/server-components/protocol.d.ts.map +1 -1
  174. package/dist/server-components/protocol.js +9 -1
  175. package/dist/server-components/protocol.js.map +1 -1
  176. package/dist/server-components/server.d.ts +4 -7
  177. package/dist/server-components/server.d.ts.map +1 -1
  178. package/dist/server-components/server.js +2 -185
  179. package/dist/server-components/server.js.map +1 -1
  180. package/dist/server-components/stream-server.d.ts +6 -0
  181. package/dist/server-components/stream-server.d.ts.map +1 -0
  182. package/dist/server-components/stream-server.js +197 -0
  183. package/dist/server-components/stream-server.js.map +1 -0
  184. package/dist/server-components/stream.d.ts +16 -3
  185. package/dist/server-components/stream.d.ts.map +1 -1
  186. package/dist/server-components/stream.js +31 -4
  187. package/dist/server-components/stream.js.map +1 -1
  188. package/dist/server-components/transport.d.ts +20 -0
  189. package/dist/server-components/transport.d.ts.map +1 -0
  190. package/dist/server-components/transport.js +2 -0
  191. package/dist/server-components/transport.js.map +1 -0
  192. package/dist/server-components/updates.d.ts +56 -0
  193. package/dist/server-components/updates.d.ts.map +1 -0
  194. package/dist/server-components/updates.js +319 -0
  195. package/dist/server-components/updates.js.map +1 -0
  196. package/dist/server-data-protocol.d.ts +14 -0
  197. package/dist/server-data-protocol.d.ts.map +1 -0
  198. package/dist/server-data-protocol.js +15 -0
  199. package/dist/server-data-protocol.js.map +1 -0
  200. package/dist/server-data.d.ts +18 -0
  201. package/dist/server-data.d.ts.map +1 -1
  202. package/dist/server-data.js.map +1 -1
  203. package/dist/server-document.d.ts +21 -0
  204. package/dist/server-document.d.ts.map +1 -0
  205. package/dist/server-document.js +3 -0
  206. package/dist/server-document.js.map +1 -0
  207. package/dist/server-native-document.d.ts +13 -0
  208. package/dist/server-native-document.d.ts.map +1 -0
  209. package/dist/server-native-document.js +154 -0
  210. package/dist/server-native-document.js.map +1 -0
  211. package/dist/server-native-stream.d.ts +5 -0
  212. package/dist/server-native-stream.d.ts.map +1 -0
  213. package/dist/server-native-stream.js +39 -0
  214. package/dist/server-native-stream.js.map +1 -0
  215. package/dist/server-native.d.ts +24 -0
  216. package/dist/server-native.d.ts.map +1 -0
  217. package/dist/server-native.js +70 -0
  218. package/dist/server-native.js.map +1 -0
  219. package/dist/server-reactivity.d.ts +13 -0
  220. package/dist/server-reactivity.d.ts.map +1 -0
  221. package/dist/server-reactivity.js +49 -0
  222. package/dist/server-reactivity.js.map +1 -0
  223. package/dist/server.d.ts +11 -5
  224. package/dist/server.d.ts.map +1 -1
  225. package/dist/server.js +68 -16
  226. package/dist/server.js.map +1 -1
  227. package/dist/ui/behaviors/accordion.d.ts.map +1 -1
  228. package/dist/ui/behaviors/accordion.js +4 -3
  229. package/dist/ui/behaviors/accordion.js.map +1 -1
  230. package/dist/ui/behaviors/collapsible.d.ts.map +1 -1
  231. package/dist/ui/behaviors/collapsible.js +2 -1
  232. package/dist/ui/behaviors/collapsible.js.map +1 -1
  233. package/dist/ui/behaviors/dialog.d.ts.map +1 -1
  234. package/dist/ui/behaviors/dialog.js +5 -4
  235. package/dist/ui/behaviors/dialog.js.map +1 -1
  236. package/dist/ui/behaviors/menu.d.ts.map +1 -1
  237. package/dist/ui/behaviors/menu.js +4 -3
  238. package/dist/ui/behaviors/menu.js.map +1 -1
  239. package/dist/ui/behaviors/select.d.ts +23 -1
  240. package/dist/ui/behaviors/select.d.ts.map +1 -1
  241. package/dist/ui/behaviors/select.js +81 -11
  242. package/dist/ui/behaviors/select.js.map +1 -1
  243. package/dist/ui/behaviors/switch.d.ts.map +1 -1
  244. package/dist/ui/behaviors/switch.js +2 -1
  245. package/dist/ui/behaviors/switch.js.map +1 -1
  246. package/dist/ui/behaviors/toolbar.d.ts.map +1 -1
  247. package/dist/ui/behaviors/toolbar.js +2 -1
  248. package/dist/ui/behaviors/toolbar.js.map +1 -1
  249. package/dist/ui/catalogue.d.ts +1 -1
  250. package/dist/ui/components/accordion/accordion.d.ts.map +1 -1
  251. package/dist/ui/components/accordion/accordion.js +3 -2
  252. package/dist/ui/components/accordion/accordion.js.map +1 -1
  253. package/dist/ui/components/collapsible/collapsible.d.ts.map +1 -1
  254. package/dist/ui/components/collapsible/collapsible.js +2 -1
  255. package/dist/ui/components/collapsible/collapsible.js.map +1 -1
  256. package/dist/ui/components/dialog/dialog.d.ts.map +1 -1
  257. package/dist/ui/components/dialog/dialog.js +4 -3
  258. package/dist/ui/components/dialog/dialog.js.map +1 -1
  259. package/dist/ui/components/navigation/breadcrumbs.d.ts.map +1 -1
  260. package/dist/ui/components/navigation/breadcrumbs.js +2 -1
  261. package/dist/ui/components/navigation/breadcrumbs.js.map +1 -1
  262. package/dist/ui/components/select/select.d.ts +20 -0
  263. package/dist/ui/components/select/select.d.ts.map +1 -1
  264. package/dist/ui/components/select/select.js +20 -0
  265. package/dist/ui/components/select/select.js.map +1 -1
  266. package/dist/ui/components/tabs/tabs.d.ts.map +1 -1
  267. package/dist/ui/components/tabs/tabs.js +6 -5
  268. package/dist/ui/components/tabs/tabs.js.map +1 -1
  269. package/dist/ui/core/brand.d.ts +33 -0
  270. package/dist/ui/core/brand.d.ts.map +1 -0
  271. package/dist/ui/core/brand.js +96 -0
  272. package/dist/ui/core/brand.js.map +1 -0
  273. package/dist/ui/core/component-styles.d.ts.map +1 -1
  274. package/dist/ui/core/component-styles.js +14 -8
  275. package/dist/ui/core/component-styles.js.map +1 -1
  276. package/dist/ui/core/element.d.ts.map +1 -1
  277. package/dist/ui/core/element.js +2 -3
  278. package/dist/ui/core/element.js.map +1 -1
  279. package/dist/ui/core/index.d.ts +1 -0
  280. package/dist/ui/core/index.d.ts.map +1 -1
  281. package/dist/ui/core/index.js +1 -0
  282. package/dist/ui/core/index.js.map +1 -1
  283. package/dist/ui/core/layout-styles.d.ts.map +1 -1
  284. package/dist/ui/core/layout-styles.js +12 -6
  285. package/dist/ui/core/layout-styles.js.map +1 -1
  286. package/dist/ui/core/parts.d.ts.map +1 -1
  287. package/dist/ui/core/parts.js +5 -4
  288. package/dist/ui/core/parts.js.map +1 -1
  289. package/dist/ui/core/portal.d.ts.map +1 -1
  290. package/dist/ui/core/portal.js +17 -1
  291. package/dist/ui/core/portal.js.map +1 -1
  292. package/dist/ui/machine-state.d.ts +11 -11
  293. package/dist/ui/state.d.ts +1 -1
  294. package/dist/vite.d.ts +5 -10
  295. package/dist/vite.d.ts.map +1 -1
  296. package/dist/vite.js +119 -116
  297. package/dist/vite.js.map +1 -1
  298. package/package.json +2 -12
  299. package/dist/server-components/browser.d.ts +0 -75
  300. package/dist/server-components/browser.d.ts.map +0 -1
  301. package/dist/server-components/browser.js +0 -558
  302. package/dist/server-components/browser.js.map +0 -1
  303. package/dist/server-components/compiler.d.ts +0 -6
  304. package/dist/server-components/compiler.d.ts.map +0 -1
  305. package/dist/server-components/compiler.js +0 -118
  306. package/dist/server-components/compiler.js.map +0 -1
  307. package/dist/server-components/navigation.d.ts +0 -10
  308. package/dist/server-components/navigation.d.ts.map +0 -1
  309. package/dist/server-components/navigation.js +0 -105
  310. package/dist/server-components/navigation.js.map +0 -1
  311. package/dist/server-components/references.d.ts +0 -22
  312. package/dist/server-components/references.d.ts.map +0 -1
  313. package/dist/server-components/references.js +0 -94
  314. package/dist/server-components/references.js.map +0 -1
@@ -1,5 +1,20 @@
1
1
  /** Browser side of server data. Documents stay precompiled; data arrives separately after commit. */
2
2
  import { showLoading } from "./loading.js";
3
+ import { validateDataPatch } from "../server-data-protocol.js";
4
+ import * as Effect from "effect/Effect";
5
+ /** The page's path below the deployment base its data endpoint carries, so a stream's scope does not depend on where the app is mounted. */
6
+ export function appRelative(page, endpoint) {
7
+ const at = endpoint.indexOf("_fuzor/data/");
8
+ const base = at > 0 ? endpoint.slice(0, at) : "/";
9
+ if (base === "/")
10
+ return page;
11
+ if (page === base.slice(0, -1))
12
+ return "/";
13
+ return page.startsWith(base) ? page.slice(base.length - 1) : page;
14
+ }
15
+ let transport;
16
+ /** Installed only by compiler output containing request-time HTML owners. */
17
+ export function setRouteDataTransport(value) { transport = value; }
3
18
  export class RouteDataError extends Error {
4
19
  status;
5
20
  _tag = "RouteDataError";
@@ -9,6 +24,7 @@ export class RouteDataError extends Error {
9
24
  }
10
25
  }
11
26
  const loads = new WeakMap();
27
+ const snapshots = new WeakMap();
12
28
  function valueAt(data, name) {
13
29
  let value = data;
14
30
  for (const key of name.split(".")) {
@@ -19,12 +35,17 @@ function valueAt(data, name) {
19
35
  return value;
20
36
  }
21
37
  /** Fills `<fuzor-data name="a.b">` slots with text. Missing or non-text values keep the fallback content. */
22
- export function fillDataSlots(root, data) {
38
+ export function fillDataSlots(root, data, accepts = () => true) {
23
39
  for (const slot of root.querySelectorAll("fuzor-data[name]")) {
24
- const value = valueAt(data, slot.getAttribute("name"));
40
+ const name = slot.getAttribute("name");
41
+ if (!accepts(name, slot))
42
+ continue;
43
+ const value = valueAt(data, name);
25
44
  if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
26
- slot.textContent = String(value);
27
- slot.setAttribute("data-fuzor-state", "ready");
45
+ if (slot.textContent !== String(value))
46
+ slot.textContent = String(value);
47
+ if (slot.getAttribute("data-fuzor-state") !== "ready")
48
+ slot.setAttribute("data-fuzor-state", "ready");
28
49
  }
29
50
  else {
30
51
  slot.setAttribute("data-fuzor-state", "missing");
@@ -41,50 +62,82 @@ function markSlots(root, state) {
41
62
  * cancels the previous request; cancelled loads never touch the DOM.
42
63
  */
43
64
  export function loadRouteData(outlet, options = {}) {
65
+ if (options.force)
66
+ outlet.removeAttribute("data-fuzor-data-ready");
44
67
  if (outlet.hasAttribute("data-fuzor-data-ready")) {
45
68
  const seed = outlet.ownerDocument.querySelector("script[data-fuzor-route-data]");
46
69
  if (seed) {
47
70
  const saved = JSON.parse(seed.textContent ?? "{}");
48
- if (saved.search === (options.search ?? outlet.ownerDocument.defaultView?.location.search ?? ""))
49
- return Promise.resolve(saved.data);
71
+ if (saved.search === (options.search ?? outlet.ownerDocument.defaultView?.location.search ?? "")) {
72
+ outlet.removeAttribute("data-fuzor-data-ready");
73
+ const promise = Promise.resolve(saved.data);
74
+ const url = `${outlet.getAttribute("data-fuzor-data")}${saved.search}`;
75
+ loads.set(outlet, { url, controller: new AbortController(), promise });
76
+ snapshots.set(outlet, { url, page: outlet.ownerDocument.defaultView?.location.pathname ?? "", data: saved.data });
77
+ return promise;
78
+ }
50
79
  }
51
80
  outlet.removeAttribute("data-fuzor-data-ready");
52
81
  }
53
82
  const endpoint = outlet.getAttribute("data-fuzor-data");
83
+ const previous = snapshots.get(outlet);
54
84
  abortRouteData(outlet);
55
85
  if (!endpoint)
56
86
  return Promise.resolve(undefined);
57
87
  const window = outlet.ownerDocument.defaultView;
58
88
  const search = options.search ?? window?.location.search ?? "";
59
89
  const url = `${endpoint}${search}`;
90
+ const page = window?.location.pathname ?? "";
91
+ if (previous?.url === url && previous.page === page)
92
+ snapshots.set(outlet, previous);
60
93
  const controller = new AbortController();
94
+ const signal = options.signal ? AbortSignal.any([controller.signal, options.signal]) : controller.signal;
61
95
  const request = options.fetch ?? window?.fetch?.bind(window) ?? fetch;
62
96
  markSlots(outlet, "pending");
63
97
  // Page-level indicators; those inside islands belong to island activation.
64
98
  const loading = showLoading([...outlet.querySelectorAll("fuzor-loading")].filter(element => !element.closest("fuzor-island")));
65
- controller.signal.addEventListener("abort", loading.cancel, { once: true });
66
- const promise = (async () => {
67
- const response = await request(url, { headers: { accept: "application/json" }, signal: controller.signal });
68
- if (!response.ok)
69
- throw new RouteDataError(response.status, `Server data request failed with ${response.status}`);
70
- const body = await response.json();
71
- return body.data;
72
- })().then(data => {
73
- if (controller.signal.aborted)
74
- return data;
75
- // Data is shown at once; only the indicator waits out its minimum display time.
76
- void loading.finish();
77
- fillDataSlots(outlet, data);
78
- outlet.dispatchEvent(new (window?.CustomEvent ?? CustomEvent)("fuzor:data", { detail: { data } }));
79
- return data;
80
- }, error => {
99
+ signal.addEventListener("abort", loading.cancel, { once: true });
100
+ const publish = ({ data, nativeKeys }) => {
101
+ if (signal.aborted)
102
+ return;
103
+ const current = loads.get(outlet);
104
+ if (current?.mutedNative && nativeKeys) {
105
+ nativeKeys = new Set([...nativeKeys].filter(key => !current.mutedNative.has(key)));
106
+ const old = snapshots.get(outlet).data, incoming = data;
107
+ data = { ...(current.muteBase ? old : incoming), __fuzor_native: { ...old.__fuzor_native, ...Object.fromEntries([...nativeKeys].map(key => [key, incoming.__fuzor_native[key]])) } };
108
+ }
109
+ snapshots.set(outlet, { url, page, data });
110
+ if (current?.controller === controller)
111
+ loads.set(outlet, { ...current, promise: Promise.resolve(data) });
112
+ fillDataSlots(outlet, data, name => !nativeKeys || !name.startsWith("__fuzor_native.") || nativeKeys.has(name.split(".")[1]));
113
+ outlet.dispatchEvent(new (window?.CustomEvent ?? CustomEvent)("fuzor:data", { detail: { data, nativeKeys } }));
114
+ };
115
+ const fail = (error) => {
81
116
  loading.cancel();
82
- if (!controller.signal.aborted) {
117
+ if (!signal.aborted) {
83
118
  markSlots(outlet, "failed");
84
119
  outlet.dispatchEvent(new (window?.CustomEvent ?? CustomEvent)("fuzor:data-error", { detail: { error } }));
85
120
  }
86
- throw error instanceof RouteDataError || controller.signal.aborted ? error : new RouteDataError(undefined, String(error));
87
- });
121
+ };
122
+ const finish = () => { const current = loads.get(outlet); if (current?.controller === controller)
123
+ loads.set(outlet, { ...current, following: false }); void loading.finish(); signal.removeEventListener("abort", loading.cancel); };
124
+ const promise = Effect.runPromise(Effect.gen(function* () {
125
+ const response = yield* Effect.tryPromise({ try: () => request(url, { headers: { accept: "application/json", ...transport?.headers, ...(window?.location ? { "x-fuzor-page": window.location.pathname } : {}) }, signal }), catch: error => error });
126
+ if (!response.ok)
127
+ return yield* Effect.fail(new RouteDataError(response.status, `Server data request failed with ${response.status}`));
128
+ const session = transport ? yield* transport.open(response, { outlet, scope: appRelative(page, endpoint) + search, signal, ...(previous?.page === page ? { previous: previous.data } : {}) })
129
+ : { data: (yield* Effect.tryPromise({ try: () => response.json(), catch: error => error })).data };
130
+ publish({ data: session.data });
131
+ if (session.follow) {
132
+ const current = loads.get(outlet);
133
+ if (current?.controller === controller)
134
+ loads.set(outlet, { ...current, following: true });
135
+ Effect.runFork(session.follow(publish).pipe(Effect.catch(error => Effect.sync(() => fail(error))), Effect.ensuring(Effect.sync(finish))), { signal });
136
+ }
137
+ else
138
+ finish();
139
+ return session.data;
140
+ }).pipe(Effect.tapError(error => Effect.sync(() => { fail(error); finish(); }))));
88
141
  // Callers that only await routeData() must not produce unhandled rejections.
89
142
  promise.catch(() => { });
90
143
  loads.set(outlet, { url, controller, promise });
@@ -93,6 +146,29 @@ export function loadRouteData(outlet, options = {}) {
93
146
  export function abortRouteData(outlet) {
94
147
  loads.get(outlet)?.controller.abort();
95
148
  loads.delete(outlet);
149
+ snapshots.delete(outlet);
150
+ }
151
+ /** Apply server-owned complete seeds; omitted instances retain their current data and are not notified. */
152
+ export function patchRouteData(outlet, patch, search, signal) {
153
+ validateDataPatch(patch);
154
+ if (signal.aborted || !outlet.isConnected)
155
+ return;
156
+ const url = `${outlet.getAttribute("data-fuzor-data")}${search}`, previous = snapshots.get(outlet);
157
+ if (!previous || previous.url !== url || previous.page !== (outlet.ownerDocument.defaultView?.location.pathname ?? "") || !previous.data || typeof previous.data !== "object" || Array.isArray(previous.data))
158
+ throw new Error("Server data patch has no matching page snapshot");
159
+ const nativeKeys = new Set(Object.keys(patch.native));
160
+ if (patch.base === undefined && !nativeKeys.size)
161
+ return;
162
+ const old = previous.data;
163
+ const data = { ...(patch.base ?? old), __fuzor_native: { ...(old.__fuzor_native ?? {}), ...patch.native } };
164
+ const current = loads.get(outlet);
165
+ if (!current?.following)
166
+ abortRouteData(outlet);
167
+ snapshots.set(outlet, { url, page: previous.page, data });
168
+ loads.set(outlet, current?.following ? { ...current, promise: Promise.resolve(data), mutedNative: new Set([...current.mutedNative ?? [], ...nativeKeys]), muteBase: current.muteBase || patch.base !== undefined } : { url, controller: new AbortController(), promise: Promise.resolve(data) });
169
+ fillDataSlots(outlet, data, (name, slot) => slot.getAttribute("data-fuzor-state") === "pending" || (name.startsWith("__fuzor_native.") ? nativeKeys.has(name.split(".")[1]) : patch.base !== undefined));
170
+ const window = outlet.ownerDocument.defaultView;
171
+ outlet.dispatchEvent(new (window?.CustomEvent ?? CustomEvent)("fuzor:data", { detail: { data, nativeKeys } }));
96
172
  }
97
173
  /**
98
174
  * Data for the page containing `element`, for islands. Shares the outlet's current request and starts one
@@ -1 +1 @@
1
- {"version":3,"file":"data.js","sourceRoot":"","sources":["../../src/runtime/data.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"data.js","sourceRoot":"","sources":["../../src/runtime/data.ts"],"names":[],"mappings":"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"}
@@ -1,13 +1,29 @@
1
1
  import * as Effect from "effect/Effect";
2
2
  import * as Scope from "effect/Scope";
3
+ export type DocsSearchResult = {
4
+ id: number;
5
+ path: string;
6
+ title: string;
7
+ snippet: string;
8
+ };
9
+ export type DocsSearchAnswer = {
10
+ query: string;
11
+ status: "idle" | "loading" | "ready" | "fallback";
12
+ rows: DocsSearchResult[];
13
+ };
3
14
  export type DocsSearchOptions = {
4
15
  readonly document: Document;
5
16
  readonly base?: string;
6
17
  readonly fetch?: typeof globalThis.fetch;
7
- readonly openDialog?: (root: HTMLElement) => Promise<void>;
18
+ readonly openDialog?: (root: HTMLElement) => Effect.Effect<void, unknown>;
8
19
  };
9
- /** Search owns its listeners and requests until the page scope closes. Each navigation replaces its dialog scope. */
20
+ /** Post-commit notification adopts text entered before the native listener loaded. */
21
+ export declare function refreshDocsSearch(element: HTMLElement): void;
22
+ /** A synchronous native action reads the latest input and the external index cache.
23
+ * Fetch completion sends an input notification; it never writes cells or renders DOM.
24
+ */
25
+ export declare function readDocsSearch(element: HTMLElement): DocsSearchAnswer;
26
+ /** Browser I/O/keyboard adapter. The compiled HTML owns query, result state and all DOM. */
10
27
  export declare const mountDocsSearchEffect: (options: DocsSearchOptions) => Effect.Effect<void, never, Scope.Scope>;
11
- /** Imperative bridge for Vite's generated bootstrap; disposal closes all Effect-owned resources. */
12
- export declare function mountDocsSearch(options: DocsSearchOptions): Promise<() => void>;
28
+ export declare function mountDocsSearch(options: DocsSearchOptions): Promise<() => Promise<void>>;
13
29
  //# sourceMappingURL=docs-search.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"docs-search.d.ts","sourceRoot":"","sources":["../../src/runtime/docs-search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAGxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAetC,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IACzC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC;CAC5D,CAAC;AAOF,qHAAqH;AACrH,eAAO,MAAM,qBAAqB,GAAI,SAAS,iBAAiB,KAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CA4IvG,CAAC;AAEH,oGAAoG;AACpG,wBAAsB,eAAe,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,IAAI,CAAC,CAKrF"}
1
+ {"version":3,"file":"docs-search.d.ts","sourceRoot":"","sources":["../../src/runtime/docs-search.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,MAAM,eAAe,CAAC;AAIxC,OAAO,KAAK,KAAK,MAAM,cAAc,CAAC;AAQtC,MAAM,MAAM,gBAAgB,GAAG;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC;AAC5F,MAAM,MAAM,gBAAgB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,GAAG,UAAU,CAAC;IAAC,IAAI,EAAE,gBAAgB,EAAE,CAAA;CAAE,CAAC;AAC9H,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC;IAC5B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAC;IACzC,QAAQ,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,WAAW,KAAK,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;CAC3E,CAAC;AAWF,sFAAsF;AACtF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI,CAG5D;AAQD;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,WAAW,GAAG,gBAAgB,CAqBrE;AAsBD,4FAA4F;AAC5F,eAAO,MAAM,qBAAqB,GAAI,SAAS,iBAAiB,KAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,CA0DvG,CAAC;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,iBAAiB,GAAG,OAAO,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,CAGxF"}
@@ -1,153 +1,154 @@
1
1
  import * as Effect from "effect/Effect";
2
2
  import * as Exit from "effect/Exit";
3
+ import * as Fiber from "effect/Fiber";
3
4
  import * as Schema from "effect/Schema";
4
5
  import * as Scope from "effect/Scope";
6
+ import { normalizeBase } from "../route-path.js";
7
+ import { ownsDom } from "../dom-ownership.js";
5
8
  const SearchIndex = Schema.Struct({ documents: Schema.Array(Schema.Struct({
6
- path: Schema.String,
7
- title: Schema.String,
8
- headings: Schema.Array(Schema.String),
9
- text: Schema.String
9
+ path: Schema.String, title: Schema.String, headings: Schema.Array(Schema.String), text: Schema.String,
10
10
  })) });
11
- class DocsSearchError extends Schema.TaggedError()("DocsSearchError", {
12
- reason: Schema.Literals(["request", "response", "decode"]),
13
- cause: Schema.Defect()
14
- }) {
11
+ const sessions = new WeakMap();
12
+ const external = (call) => Effect.tryPromise({ try: call, catch: error => error });
13
+ const listen = (target, type, handler) => Effect.acquireRelease(Effect.sync(() => target.addEventListener(type, handler)), () => Effect.sync(() => target.removeEventListener(type, handler)));
14
+ function activeInput(document) {
15
+ const dialog = document.getElementById("docs-search-dialog");
16
+ return dialog ? [...document.querySelectorAll(".docs-search-input")].find(input => ownsDom(dialog, input)) : undefined;
15
17
  }
16
- const listen = (target, event, handler) => Effect.acquireRelease(Effect.sync(() => target.addEventListener(event, handler)), () => Effect.sync(() => target.removeEventListener(event, handler)));
17
- /** Search owns its listeners and requests until the page scope closes. Each navigation replaces its dialog scope. */
18
+ /** Post-commit notification adopts text entered before the native listener loaded. */
19
+ export function refreshDocsSearch(element) {
20
+ const input = activeInput(element.ownerDocument), window = element.ownerDocument.defaultView;
21
+ if (window && input?.value.trim())
22
+ input.dispatchEvent(new window.Event("input", { bubbles: true }));
23
+ }
24
+ function localPath(path, document, base) {
25
+ if (path.length > 2048 || !path.startsWith("/") || path.startsWith("//") || /[\\\u0000-\u0020\u007f]/.test(path))
26
+ return;
27
+ try {
28
+ const url = new URL(path, document.defaultView.location.href);
29
+ if (url.origin === document.defaultView.location.origin && url.pathname.startsWith(`${base}docs/`))
30
+ return url.pathname + url.search + url.hash;
31
+ }
32
+ catch {
33
+ return;
34
+ }
35
+ }
36
+ /** A synchronous native action reads the latest input and the external index cache.
37
+ * Fetch completion sends an input notification; it never writes cells or renders DOM.
38
+ */
39
+ export function readDocsSearch(element) {
40
+ const document = element.ownerDocument, session = sessions.get(document);
41
+ if (!session)
42
+ throw new Error("Docs search source is not mounted");
43
+ const input = activeInput(document);
44
+ const query = (input?.value ?? "").slice(0, 256), needle = query.trim().toLowerCase();
45
+ if (!needle)
46
+ return { query, status: "idle", rows: [] };
47
+ session.start();
48
+ if (session.status === "loading")
49
+ return { query, status: "loading", rows: [] };
50
+ const documents = session.status === "ready" ? session.documents : Array.from(document.querySelectorAll(".docs-sidebar nav a")).slice(0, 4096).map(link => ({ path: link.getAttribute("href") ?? "", title: link.textContent ?? "", text: "", headings: [] }));
51
+ const rows = [], seen = new Set();
52
+ for (const doc of documents) {
53
+ const path = localPath(doc.path, document, session.base);
54
+ if (!path || seen.has(path) || ![doc.title, doc.text, ...doc.headings].some(text => text.toLowerCase().includes(needle)))
55
+ continue;
56
+ seen.add(path);
57
+ let id = session.ids.get(path);
58
+ if (id === undefined) {
59
+ if (session.ids.size >= 8192)
60
+ throw new Error("Docs search identity limit exceeded");
61
+ session.ids.set(path, id = session.ids.size);
62
+ }
63
+ const at = doc.text.toLowerCase().indexOf(needle);
64
+ rows.push({ id, path, title: doc.title || path, snippet: at < 0 ? "" : `${doc.text.slice(Math.max(0, at - 25), at + 75)}...` });
65
+ if (rows.length === 8)
66
+ break;
67
+ }
68
+ return { query, status: session.status === "ready" ? "ready" : "fallback", rows };
69
+ }
70
+ const readIndex = (response) => Effect.gen(function* () {
71
+ if (!response.ok || !response.body) {
72
+ yield* external(() => response.body?.cancel() ?? Promise.resolve());
73
+ return yield* Effect.fail(new Error("Docs search index unavailable"));
74
+ }
75
+ const reader = response.body.getReader(), decoder = new TextDecoder();
76
+ let bytes = 0, text = "";
77
+ return yield* Effect.gen(function* () {
78
+ while (true) {
79
+ const part = yield* external(() => reader.read());
80
+ if (part.done)
81
+ break;
82
+ if ((bytes += part.value.byteLength) > 2 * 1024 * 1024)
83
+ return yield* Effect.fail(new Error("Docs search index byte limit exceeded"));
84
+ text += decoder.decode(part.value, { stream: true });
85
+ }
86
+ text += decoder.decode();
87
+ const raw = yield* Effect.try(() => JSON.parse(text));
88
+ const index = yield* Schema.decodeUnknownEffect(SearchIndex)(raw);
89
+ if (index.documents.length > 4096)
90
+ return yield* Effect.fail(new Error("Docs search index document limit exceeded"));
91
+ return index.documents;
92
+ }).pipe(Effect.ensuring(external(() => reader.cancel()).pipe(Effect.catch(error => Effect.logWarning("Docs search reader cleanup failed", error)), Effect.ensuring(Effect.sync(() => reader.releaseLock())))));
93
+ });
94
+ /** Browser I/O/keyboard adapter. The compiled HTML owns query, result state and all DOM. */
18
95
  export const mountDocsSearchEffect = (options) => Effect.gen(function* () {
19
- const { document } = options;
20
- const window = document.defaultView;
96
+ const { document } = options, window = document.defaultView;
21
97
  if (!window)
22
98
  return;
23
- const base = options.base ?? "/";
24
- const fetch = options.fetch ?? window.fetch?.bind(window) ?? globalThis.fetch;
99
+ if (sessions.has(document))
100
+ throw new Error("Docs search already has an owner");
25
101
  const lifetime = yield* Effect.acquireRelease(Effect.sync(() => new AbortController()), controller => Effect.sync(() => controller.abort()));
26
- let cached;
27
- let pending;
28
- let dialogScope;
29
- let attachedDialog = null;
30
- const localPath = (path) => {
31
- if (!path.startsWith("/") || path.startsWith("//") || path.includes("\\"))
32
- return;
33
- try {
34
- const url = new URL(path, window.location.href);
35
- if (url.origin !== window.location.origin || !url.pathname.startsWith(`${base}docs/`))
102
+ const fetch = options.fetch ?? window.fetch?.bind(window) ?? globalThis.fetch;
103
+ let fiber, dialogScope, attachedDialog = null;
104
+ const session = { base: normalizeBase(options.base), status: "cold", documents: [], ids: new Map(), start() {
105
+ if (session.status !== "cold" || lifetime.signal.aborted)
36
106
  return;
37
- return url.pathname + url.search + url.hash;
38
- }
39
- catch {
40
- return;
41
- }
42
- };
43
- const loadIndex = () => {
44
- if (cached)
45
- return Promise.resolve(cached);
46
- if (pending)
47
- return pending;
48
- const fetchIndex = Effect.fn("Fuzor.docsSearch.loadIndex")(function* () {
49
- const response = yield* Effect.tryPromise({
50
- try: signal => fetch(`${base}search-index.json`, { signal }),
51
- catch: cause => new DocsSearchError({ reason: "request", cause })
52
- });
53
- if (!response.ok)
54
- return yield* Effect.fail(new DocsSearchError({ reason: "response", cause: response.status }));
55
- const json = yield* Effect.tryPromise({ try: () => response.json(), catch: cause => new DocsSearchError({ reason: "decode", cause }) });
56
- const index = yield* Schema.decodeUnknownEffect(SearchIndex)(json).pipe(Effect.mapError(cause => new DocsSearchError({ reason: "decode", cause })));
57
- return index.documents;
58
- });
59
- const load = fetchIndex().pipe(Effect.catchTag("DocsSearchError", () => Effect.succeed(null)));
60
- pending = Effect.runPromiseExit(load, { signal: lifetime.signal }).then(exit => {
61
- if (Exit.isFailure(exit))
62
- return null;
63
- const docs = exit.value;
64
- if (docs)
65
- cached = docs;
66
- return docs;
67
- }).finally(() => { pending = undefined; });
68
- return pending;
69
- };
107
+ session.status = "loading";
108
+ const load = Effect.scoped(Effect.gen(function* () {
109
+ const request = yield* Effect.acquireRelease(Effect.sync(() => new AbortController()), controller => Effect.sync(() => controller.abort()));
110
+ const response = yield* Effect.tryPromise({ try: signal => fetch(`${session.base}search-index.json`, { signal: AbortSignal.any([signal, request.signal, lifetime.signal]) }), catch: error => error });
111
+ return yield* readIndex(response);
112
+ })).pipe(Effect.timeout(10000), Effect.map(documents => ({ documents, status: "ready" })), Effect.catchCause(() => Effect.succeed({ documents: [], status: "fallback" })), Effect.flatMap(answer => Effect.sync(() => {
113
+ if (lifetime.signal.aborted)
114
+ return;
115
+ session.documents = answer.documents;
116
+ session.status = answer.status;
117
+ activeInput(document)?.dispatchEvent(new window.Event("input", { bubbles: true }));
118
+ })));
119
+ fiber = Effect.runFork(load, { signal: lifetime.signal });
120
+ } };
121
+ sessions.set(document, session);
122
+ yield* Effect.addFinalizer(() => Effect.gen(function* () {
123
+ lifetime.abort();
124
+ sessions.delete(document);
125
+ if (dialogScope)
126
+ yield* Scope.close(dialogScope, Exit.void);
127
+ if (fiber)
128
+ yield* Fiber.interrupt(fiber);
129
+ }));
70
130
  const attach = () => {
71
131
  if (dialogScope)
72
132
  Effect.runSync(Scope.close(dialogScope, Exit.void));
73
- dialogScope = undefined;
74
133
  const dialog = document.getElementById("docs-search-dialog");
75
134
  attachedDialog = dialog;
76
- const input = document.querySelector(".docs-search-input");
77
- const results = document.querySelector(".docs-search-results");
135
+ dialogScope = undefined;
136
+ const input = activeInput(document), results = input?.closest(".docs-search-body")?.querySelector(".docs-search-results") ?? dialog?.querySelector(".docs-search-results");
78
137
  if (!dialog || !input || !results)
79
138
  return;
80
139
  const scope = dialogScope = Scope.makeUnsafe();
81
- let disposed = false;
82
- let revision = 0;
83
- Effect.runSync(Scope.addFinalizer(scope, Effect.sync(() => { disposed = true; })));
84
- const subscribe = (target, event, handler) => Effect.runSync(listen(target, event, handler).pipe(Effect.provideService(Scope.Scope, scope)));
85
- const empty = (message) => {
86
- const node = document.createElement("div");
87
- node.className = "docs-search-empty";
88
- node.textContent = message;
89
- results.replaceChildren(node);
90
- };
91
- const render = (docs, query) => {
92
- const fragment = document.createDocumentFragment();
93
- for (const doc of docs.slice(0, 8)) {
94
- const path = localPath(doc.path);
95
- if (!path)
96
- continue;
97
- const link = document.createElement("a");
98
- link.href = path;
99
- link.className = "docs-search-result-item";
100
- const span = (className, text) => {
101
- const node = document.createElement("span");
102
- node.className = className;
103
- node.textContent = text;
104
- link.append(node);
105
- };
106
- span("result-title", doc.title || path);
107
- const at = doc.text.toLowerCase().indexOf(query);
108
- if (at >= 0)
109
- span("result-snippet", `${doc.text.slice(Math.max(0, at - 25), at + 75)}...`);
110
- span("result-path", path);
111
- fragment.append(link);
112
- }
113
- if (fragment.childNodes.length)
114
- results.replaceChildren(fragment);
115
- else
116
- empty(`No matching pages found for "${query}".`);
117
- };
118
- subscribe(input, "input", () => {
119
- const query = input.value.trim().toLowerCase();
120
- const current = ++revision;
121
- if (!query) {
122
- empty("Type a query or navigate docs links...");
123
- return;
124
- }
125
- void loadIndex().then(index => {
126
- if (disposed || lifetime.signal.aborted || revision !== current)
127
- return;
128
- const docs = index ?? Array.from(document.querySelectorAll(".docs-sidebar nav a")).map(link => ({
129
- path: link.getAttribute("href") ?? "", title: link.textContent ?? "", text: "", headings: []
130
- }));
131
- render(docs.filter(doc => localPath(doc.path) && [doc.title, doc.text, ...doc.headings].some(text => text.toLowerCase().includes(query))), query);
132
- });
133
- });
134
- subscribe(dialog, "ui:open-change", event => {
135
- if (event.detail?.open)
136
- input.focus();
137
- });
138
- subscribe(input, "keydown", event => {
139
- const key = event.key;
140
- if (key === "ArrowDown") {
141
- event.preventDefault();
142
- results.querySelector("a")?.focus();
143
- }
144
- });
140
+ const subscribe = (target, type, handler) => Effect.runSync(listen(target, type, handler).pipe(Effect.provideService(Scope.Scope, scope)));
141
+ subscribe(dialog, "ui:open-change", event => { if (event.detail?.open)
142
+ input.focus(); });
143
+ subscribe(input, "keydown", event => { if (event.key === "ArrowDown") {
144
+ event.preventDefault();
145
+ results.querySelector("a")?.focus();
146
+ } });
145
147
  subscribe(results, "keydown", event => {
146
148
  const key = event.key;
147
149
  if (key !== "ArrowDown" && key !== "ArrowUp")
148
150
  return;
149
- const links = Array.from(results.querySelectorAll("a"));
150
- const index = links.findIndex(link => link === document.activeElement);
151
+ const links = Array.from(results.querySelectorAll("a")), index = links.findIndex(link => link === document.activeElement);
151
152
  if (index < 0)
152
153
  return;
153
154
  event.preventDefault();
@@ -157,49 +158,24 @@ export const mountDocsSearchEffect = (options) => Effect.gen(function* () {
157
158
  links[index + (key === "ArrowDown" ? 1 : -1)]?.focus();
158
159
  });
159
160
  };
160
- yield* Effect.addFinalizer(() => Effect.sync(() => {
161
- if (dialogScope)
162
- Effect.runSync(Scope.close(dialogScope, Exit.void));
163
- }));
164
161
  yield* listen(window, "fuzor:navigate", attach);
165
- // The router owns page swaps through its renderer, rather than a global
166
- // navigation event. Observe actual identity changes, including its first mount.
167
162
  yield* Effect.acquireRelease(Effect.sync(() => {
168
- const observer = new window.MutationObserver(() => {
169
- if (document.getElementById("docs-search-dialog") !== attachedDialog)
170
- attach();
171
- });
163
+ const observer = new window.MutationObserver(() => { if (document.getElementById("docs-search-dialog") !== attachedDialog)
164
+ attach(); });
172
165
  observer.observe(document.documentElement, { childList: true, subtree: true });
173
166
  return observer;
174
167
  }), observer => Effect.sync(() => observer.disconnect()));
175
168
  yield* listen(window, "keydown", event => {
176
- const key = event;
177
- if (!(key.metaKey || key.ctrlKey) || key.key.toLowerCase() !== "k" || key.defaultPrevented)
178
- return;
179
- const dialog = document.getElementById("docs-search-dialog");
180
- if (!dialog)
169
+ const key = event, dialog = document.getElementById("docs-search-dialog");
170
+ if (!(key.metaKey || key.ctrlKey) || key.key.toLowerCase() !== "k" || key.defaultPrevented || !dialog || !options.openDialog)
181
171
  return;
182
- if (options.openDialog) {
183
- key.preventDefault();
184
- void options.openDialog(dialog).catch(error => window.console.error(error));
185
- }
186
- else if (typeof dialog.open === "function") {
187
- key.preventDefault();
188
- dialog.open();
189
- }
172
+ key.preventDefault();
173
+ Effect.runFork(options.openDialog(dialog).pipe(Effect.catch(error => Effect.logError("Docs search dialog failed", error))), { signal: lifetime.signal });
190
174
  });
191
175
  attach();
192
176
  });
193
- /** Imperative bridge for Vite's generated bootstrap; disposal closes all Effect-owned resources. */
194
- export async function mountDocsSearch(options) {
177
+ export function mountDocsSearch(options) {
195
178
  const scope = Scope.makeUnsafe();
196
- try {
197
- await Effect.runPromise(mountDocsSearchEffect(options).pipe(Effect.provideService(Scope.Scope, scope)));
198
- }
199
- catch (error) {
200
- Effect.runSync(Scope.close(scope, Exit.void));
201
- throw error;
202
- }
203
- return () => Effect.runSync(Scope.close(scope, Exit.void));
179
+ return Effect.runPromise(mountDocsSearchEffect(options).pipe(Effect.provideService(Scope.Scope, scope), Effect.onError(() => Scope.close(scope, Exit.void)), Effect.as(() => Effect.runPromise(Scope.close(scope, Exit.void)))));
204
180
  }
205
181
  //# sourceMappingURL=docs-search.js.map