@askrjs/askr 0.0.39 → 0.0.41

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 (253) hide show
  1. package/dist/bench/components/benchmark-row.d.ts.map +1 -1
  2. package/dist/bench/components/benchmark-row.js.map +1 -1
  3. package/dist/bench/components/benchmark-table.js.map +1 -1
  4. package/dist/benchmark.d.ts.map +1 -1
  5. package/dist/benchmark.js +2 -2
  6. package/dist/benchmark.js.map +1 -1
  7. package/dist/bin/askr-ssg.d.ts.map +1 -1
  8. package/dist/bin/askr-ssg.js.map +1 -1
  9. package/dist/boot/index.d.ts +9 -6
  10. package/dist/boot/index.d.ts.map +1 -1
  11. package/dist/boot/index.js +210 -75
  12. package/dist/boot/index.js.map +1 -1
  13. package/dist/common/attr-names.js +17 -0
  14. package/dist/common/attr-names.js.map +1 -0
  15. package/dist/common/component.d.ts.map +1 -1
  16. package/dist/common/control.d.ts.map +1 -1
  17. package/dist/common/control.js.map +1 -1
  18. package/dist/common/env.js.map +1 -1
  19. package/dist/common/jsx.d.ts.map +1 -1
  20. package/dist/common/jsx.js.map +1 -1
  21. package/dist/common/promise.js +8 -0
  22. package/dist/common/promise.js.map +1 -0
  23. package/dist/common/props.d.ts +286 -1
  24. package/dist/common/props.d.ts.map +1 -1
  25. package/dist/common/router-internal.js +6 -0
  26. package/dist/common/router-internal.js.map +1 -0
  27. package/dist/common/router.d.ts +45 -36
  28. package/dist/common/router.d.ts.map +1 -1
  29. package/dist/common/ssr-errors.d.ts.map +1 -1
  30. package/dist/common/ssr-errors.js.map +1 -1
  31. package/dist/common/ssr.d.ts +1 -0
  32. package/dist/common/ssr.d.ts.map +1 -1
  33. package/dist/common/ssr.js +6 -0
  34. package/dist/common/ssr.js.map +1 -0
  35. package/dist/common/vnode.d.ts +2 -1
  36. package/dist/common/vnode.d.ts.map +1 -1
  37. package/dist/common/vnode.js.map +1 -1
  38. package/dist/components/error-boundary.d.ts +7 -4
  39. package/dist/components/error-boundary.d.ts.map +1 -1
  40. package/dist/components/error-boundary.js.map +1 -1
  41. package/dist/components/link.d.ts +2 -1
  42. package/dist/components/link.d.ts.map +1 -1
  43. package/dist/components/link.js +10 -1
  44. package/dist/components/link.js.map +1 -1
  45. package/dist/control/case.d.ts +4 -2
  46. package/dist/control/case.d.ts.map +1 -1
  47. package/dist/control/case.js.map +1 -1
  48. package/dist/control/for.d.ts +2 -1
  49. package/dist/control/for.d.ts.map +1 -1
  50. package/dist/control/for.js.map +1 -1
  51. package/dist/control/shared.d.ts +9 -0
  52. package/dist/control/shared.d.ts.map +1 -0
  53. package/dist/control/shared.js.map +1 -1
  54. package/dist/control/show.d.ts +4 -3
  55. package/dist/control/show.d.ts.map +1 -1
  56. package/dist/control/show.js.map +1 -1
  57. package/dist/data/index.d.ts +94 -14
  58. package/dist/data/index.d.ts.map +1 -1
  59. package/dist/data/index.js +65 -14
  60. package/dist/data/index.js.map +1 -1
  61. package/dist/dev/invariant.js.map +1 -1
  62. package/dist/dev/logger.js.map +1 -1
  63. package/dist/foundations/icon/icon.d.ts.map +1 -1
  64. package/dist/foundations/icon/icon.js.map +1 -1
  65. package/dist/foundations/icon/icon.types.d.ts.map +1 -1
  66. package/dist/foundations/interactions/dismissable.d.ts +9 -3
  67. package/dist/foundations/interactions/dismissable.d.ts.map +1 -1
  68. package/dist/foundations/interactions/dismissable.js.map +1 -1
  69. package/dist/foundations/interactions/focusable.d.ts.map +1 -1
  70. package/dist/foundations/interactions/focusable.js.map +1 -1
  71. package/dist/foundations/interactions/hoverable.d.ts.map +1 -1
  72. package/dist/foundations/interactions/hoverable.js.map +1 -1
  73. package/dist/foundations/interactions/interaction-policy.d.ts +1 -1
  74. package/dist/foundations/interactions/interaction-policy.d.ts.map +1 -1
  75. package/dist/foundations/interactions/interaction-policy.js +3 -3
  76. package/dist/foundations/interactions/interaction-policy.js.map +1 -1
  77. package/dist/foundations/interactions/pressable.d.ts.map +1 -1
  78. package/dist/foundations/interactions/pressable.js.map +1 -1
  79. package/dist/foundations/interactions/roving-focus.d.ts.map +1 -1
  80. package/dist/foundations/interactions/roving-focus.js +8 -8
  81. package/dist/foundations/interactions/roving-focus.js.map +1 -1
  82. package/dist/foundations/state/controllable.d.ts.map +1 -1
  83. package/dist/foundations/state/controllable.js.map +1 -1
  84. package/dist/foundations/structures/collection.d.ts.map +1 -1
  85. package/dist/foundations/structures/collection.js.map +1 -1
  86. package/dist/foundations/structures/layer.d.ts.map +1 -1
  87. package/dist/foundations/structures/layer.js.map +1 -1
  88. package/dist/foundations/structures/layout.d.ts +4 -2
  89. package/dist/foundations/structures/layout.d.ts.map +1 -1
  90. package/dist/foundations/structures/layout.js.map +1 -1
  91. package/dist/foundations/structures/portal.d.ts +9 -25
  92. package/dist/foundations/structures/portal.d.ts.map +1 -1
  93. package/dist/foundations/structures/portal.js +98 -17
  94. package/dist/foundations/structures/portal.js.map +1 -1
  95. package/dist/foundations/structures/presence.d.ts +4 -3
  96. package/dist/foundations/structures/presence.d.ts.map +1 -1
  97. package/dist/foundations/structures/presence.js +2 -2
  98. package/dist/foundations/structures/presence.js.map +1 -1
  99. package/dist/foundations/structures/slot.d.ts +2 -1
  100. package/dist/foundations/structures/slot.d.ts.map +1 -1
  101. package/dist/foundations/structures/slot.js.map +1 -1
  102. package/dist/foundations/utilities/aria.d.ts.map +1 -1
  103. package/dist/foundations/utilities/aria.js.map +1 -1
  104. package/dist/foundations/utilities/compose-handlers.d.ts.map +1 -1
  105. package/dist/foundations/utilities/compose-handlers.js.map +1 -1
  106. package/dist/foundations/utilities/compose-ref.d.ts.map +1 -1
  107. package/dist/foundations/utilities/compose-ref.js.map +1 -1
  108. package/dist/foundations/utilities/event-types.d.ts.map +1 -1
  109. package/dist/foundations/utilities/merge-props.d.ts.map +1 -1
  110. package/dist/foundations/utilities/merge-props.js.map +1 -1
  111. package/dist/foundations/utilities/use-id.d.ts.map +1 -1
  112. package/dist/foundations/utilities/use-id.js.map +1 -1
  113. package/dist/fx/fx.d.ts.map +1 -1
  114. package/dist/fx/fx.js.map +1 -1
  115. package/dist/fx/noop.js.map +1 -1
  116. package/dist/fx/timing.d.ts +5 -4
  117. package/dist/fx/timing.d.ts.map +1 -1
  118. package/dist/fx/timing.js +7 -4
  119. package/dist/fx/timing.js.map +1 -1
  120. package/dist/index.js.map +1 -1
  121. package/dist/jsx/types.d.ts +3 -3
  122. package/dist/jsx/types.d.ts.map +1 -1
  123. package/dist/jsx/utils.d.ts.map +1 -1
  124. package/dist/jsx/utils.js.map +1 -1
  125. package/dist/jsx-dev-runtime.d.ts +6 -2
  126. package/dist/jsx-dev-runtime.d.ts.map +1 -1
  127. package/dist/jsx-dev-runtime.js.map +1 -1
  128. package/dist/jsx-runtime.d.ts +16 -6
  129. package/dist/jsx-runtime.d.ts.map +1 -1
  130. package/dist/jsx-runtime.js.map +1 -1
  131. package/dist/renderer/children.js.map +1 -1
  132. package/dist/renderer/cleanup.js +40 -13
  133. package/dist/renderer/cleanup.js.map +1 -1
  134. package/dist/renderer/dom.js +163 -63
  135. package/dist/renderer/dom.js.map +1 -1
  136. package/dist/renderer/evaluate.js +9 -6
  137. package/dist/renderer/evaluate.js.map +1 -1
  138. package/dist/renderer/fastpath.js.map +1 -1
  139. package/dist/renderer/for-commit.js +1 -0
  140. package/dist/renderer/for-commit.js.map +1 -1
  141. package/dist/renderer/index.js.map +1 -1
  142. package/dist/renderer/keyed.js.map +1 -1
  143. package/dist/renderer/reconcile.js +34 -0
  144. package/dist/renderer/reconcile.js.map +1 -1
  145. package/dist/renderer/utils.js +34 -3
  146. package/dist/renderer/utils.js.map +1 -1
  147. package/dist/router/index.d.ts +2 -2
  148. package/dist/router/match.js +16 -2
  149. package/dist/router/match.js.map +1 -1
  150. package/dist/router/navigate.d.ts +9 -1
  151. package/dist/router/navigate.d.ts.map +1 -1
  152. package/dist/router/navigate.js +235 -81
  153. package/dist/router/navigate.js.map +1 -1
  154. package/dist/router/policy.d.ts +7 -7
  155. package/dist/router/policy.d.ts.map +1 -1
  156. package/dist/router/policy.js +5 -7
  157. package/dist/router/policy.js.map +1 -1
  158. package/dist/router/route-context.js.map +1 -1
  159. package/dist/router/route.d.ts +20 -9
  160. package/dist/router/route.d.ts.map +1 -1
  161. package/dist/router/route.js +95 -29
  162. package/dist/router/route.js.map +1 -1
  163. package/dist/runtime/child-scope.d.ts.map +1 -1
  164. package/dist/runtime/child-scope.js +5 -1
  165. package/dist/runtime/child-scope.js.map +1 -1
  166. package/dist/runtime/component.d.ts +5 -2
  167. package/dist/runtime/component.d.ts.map +1 -1
  168. package/dist/runtime/component.js +85 -25
  169. package/dist/runtime/component.js.map +1 -1
  170. package/dist/runtime/context.d.ts +5 -2
  171. package/dist/runtime/context.d.ts.map +1 -1
  172. package/dist/runtime/context.js +5 -2
  173. package/dist/runtime/context.js.map +1 -1
  174. package/dist/runtime/control.d.ts.map +1 -1
  175. package/dist/runtime/control.js.map +1 -1
  176. package/dist/runtime/derive.d.ts.map +1 -1
  177. package/dist/runtime/derive.js +3 -1
  178. package/dist/runtime/derive.js.map +1 -1
  179. package/dist/runtime/dev-namespace.js.map +1 -1
  180. package/dist/runtime/effect.d.ts.map +1 -1
  181. package/dist/runtime/effect.js +17 -11
  182. package/dist/runtime/effect.js.map +1 -1
  183. package/dist/runtime/events.js +43 -1
  184. package/dist/runtime/events.js.map +1 -1
  185. package/dist/runtime/execution-model.js.map +1 -1
  186. package/dist/runtime/fastlane.js +2 -23
  187. package/dist/runtime/fastlane.js.map +1 -1
  188. package/dist/runtime/for-bench.d.ts.map +1 -1
  189. package/dist/runtime/for-bench.js.map +1 -1
  190. package/dist/runtime/for.d.ts +1 -1
  191. package/dist/runtime/for.d.ts.map +1 -1
  192. package/dist/runtime/for.js +36 -12
  193. package/dist/runtime/for.js.map +1 -1
  194. package/dist/runtime/operations.d.ts +3 -13
  195. package/dist/runtime/operations.d.ts.map +1 -1
  196. package/dist/runtime/operations.js +47 -39
  197. package/dist/runtime/operations.js.map +1 -1
  198. package/dist/runtime/perf-metrics.js.map +1 -1
  199. package/dist/runtime/readable.d.ts +1 -0
  200. package/dist/runtime/readable.d.ts.map +1 -1
  201. package/dist/runtime/readable.js +6 -1
  202. package/dist/runtime/readable.js.map +1 -1
  203. package/dist/runtime/resource-cell.js +13 -2
  204. package/dist/runtime/resource-cell.js.map +1 -1
  205. package/dist/runtime/scheduler.d.ts.map +1 -1
  206. package/dist/runtime/scheduler.js +8 -4
  207. package/dist/runtime/scheduler.js.map +1 -1
  208. package/dist/runtime/selector.d.ts.map +1 -1
  209. package/dist/runtime/selector.js +8 -2
  210. package/dist/runtime/selector.js.map +1 -1
  211. package/dist/runtime/snapshot-source.d.ts.map +1 -1
  212. package/dist/runtime/snapshot-source.js.map +1 -1
  213. package/dist/runtime/ssr-bridge.js.map +1 -1
  214. package/dist/runtime/state.d.ts +4 -3
  215. package/dist/runtime/state.d.ts.map +1 -1
  216. package/dist/runtime/state.js.map +1 -1
  217. package/dist/ssg/batch-render.js +4 -8
  218. package/dist/ssg/batch-render.js.map +1 -1
  219. package/dist/ssg/create-static-gen.d.ts +10 -2
  220. package/dist/ssg/create-static-gen.d.ts.map +1 -1
  221. package/dist/ssg/create-static-gen.js +5 -4
  222. package/dist/ssg/create-static-gen.js.map +1 -1
  223. package/dist/ssg/generate-metadata.js.map +1 -1
  224. package/dist/ssg/incremental-manifest.js.map +1 -1
  225. package/dist/ssg/resolve-ssg-data.js +54 -12
  226. package/dist/ssg/resolve-ssg-data.js.map +1 -1
  227. package/dist/ssg/route-utils.js.map +1 -1
  228. package/dist/ssg/types.d.ts +8 -7
  229. package/dist/ssg/types.d.ts.map +1 -1
  230. package/dist/ssg/write-static-files.js.map +1 -1
  231. package/dist/ssr/attrs.js +3 -2
  232. package/dist/ssr/attrs.js.map +1 -1
  233. package/dist/ssr/context.d.ts +1 -0
  234. package/dist/ssr/context.d.ts.map +1 -1
  235. package/dist/ssr/context.js +1 -0
  236. package/dist/ssr/context.js.map +1 -1
  237. package/dist/ssr/errors.d.ts.map +1 -1
  238. package/dist/ssr/escape.js.map +1 -1
  239. package/dist/ssr/index.d.ts +8 -11
  240. package/dist/ssr/index.d.ts.map +1 -1
  241. package/dist/ssr/index.js +55 -29
  242. package/dist/ssr/index.js.map +1 -1
  243. package/dist/ssr/render-keys.js +15 -4
  244. package/dist/ssr/render-keys.js.map +1 -1
  245. package/dist/ssr/render-resolved.d.ts +20 -0
  246. package/dist/ssr/render-resolved.d.ts.map +1 -0
  247. package/dist/ssr/render-resolved.js +33 -0
  248. package/dist/ssr/render-resolved.js.map +1 -0
  249. package/dist/ssr/sink.js.map +1 -1
  250. package/dist/ssr/types.d.ts.map +1 -1
  251. package/dist/ssr/verify-hydration.js +5 -6
  252. package/dist/ssr/verify-hydration.js.map +1 -1
  253. package/package.json +13 -5
@@ -1 +1 @@
1
- {"version":3,"file":"control.js","names":[],"sources":["../../src/runtime/control.ts"],"sourcesContent":["import type { VNode } from '../common/vnode';\nimport {\n createChildScope,\n disposeChildScope,\n type ChildScope,\n} from './child-scope';\nimport { getCurrentInstance, type ComponentInstance } from './component';\nimport type { ForState } from './for';\n\nexport interface MatchBranch {\n key: string | number;\n render: () => VNode;\n when: unknown;\n}\n\ninterface BranchControlStateBase {\n activeKey: string | number | null;\n activeScope: ChildScope | null;\n activeVNodes: VNode[];\n lastRemovedNodes: Node[];\n parentInstance: ComponentInstance | null;\n _enqueueBoundaryCommit?: (() => void) | null;\n _hasPendingBoundaryCommit?: boolean;\n}\n\nexport interface ShowState extends BranchControlStateBase {\n kind: 'show';\n fallbackScope: ChildScope | null;\n renderFallback: (() => VNode) | null;\n renderTruthy: ((value: unknown) => VNode) | (() => VNode);\n selectedValue: unknown;\n truthyScope: ChildScope | null;\n}\n\nexport interface CaseState extends BranchControlStateBase {\n kind: 'case';\n fallback: (() => VNode) | null;\n matches: MatchBranch[];\n}\n\nexport type ControlBoundaryState = ForState<unknown> | ShowState | CaseState;\n\nconst SHOW_TRUTHY_KEY = '__show-truthy__';\nconst SHOW_FALLBACK_KEY = '__show-fallback__';\nconst CASE_FALLBACK_KEY = '__case-fallback__';\n\nfunction disposeBranchScope(\n state: BranchControlStateBase,\n scope: ChildScope | null\n): void {\n if (!scope) {\n return;\n }\n const removedDom = scope.dom;\n disposeChildScope(scope);\n if (removedDom) {\n state.lastRemovedNodes.push(removedDom);\n }\n}\n\nfunction createBranchScope(\n state: BranchControlStateBase,\n key: string | number\n): ChildScope {\n return createChildScope(state.parentInstance, key, () => {\n if (state._enqueueBoundaryCommit) {\n state._enqueueBoundaryCommit();\n return;\n }\n\n state.parentInstance?._enqueueRun?.();\n });\n}\n\nexport function createShowState(\n value: unknown,\n renderTruthy: ShowState['renderTruthy'],\n renderFallback: ShowState['renderFallback']\n): ShowState {\n return {\n kind: 'show',\n activeKey: null,\n activeScope: null,\n activeVNodes: [],\n fallbackScope: null,\n lastRemovedNodes: [],\n parentInstance: getCurrentInstance(),\n _enqueueBoundaryCommit: null,\n _hasPendingBoundaryCommit: false,\n renderFallback,\n renderTruthy,\n selectedValue: value,\n truthyScope: null,\n };\n}\n\nexport function evaluateShowState(state: ShowState): VNode[] {\n state.lastRemovedNodes = [];\n\n if (state.selectedValue) {\n if (state.fallbackScope) {\n disposeBranchScope(state, state.fallbackScope);\n state.fallbackScope = null;\n }\n\n const truthyScope =\n state.truthyScope ?? createBranchScope(state, SHOW_TRUTHY_KEY);\n state.truthyScope = truthyScope;\n state.activeScope = truthyScope;\n state.activeKey = SHOW_TRUTHY_KEY;\n\n const vnode = truthyScope.render(() =>\n state.renderTruthy(state.selectedValue)\n );\n state.activeVNodes = vnode == null || vnode === false ? [] : [vnode];\n return state.activeVNodes;\n }\n\n if (state.truthyScope) {\n disposeBranchScope(state, state.truthyScope);\n state.truthyScope = null;\n }\n\n if (!state.renderFallback) {\n if (state.fallbackScope) {\n disposeBranchScope(state, state.fallbackScope);\n state.fallbackScope = null;\n }\n state.activeKey = null;\n state.activeScope = null;\n state.activeVNodes = [];\n return state.activeVNodes;\n }\n\n const fallbackScope =\n state.fallbackScope ?? createBranchScope(state, SHOW_FALLBACK_KEY);\n state.fallbackScope = fallbackScope;\n state.activeScope = fallbackScope;\n state.activeKey = SHOW_FALLBACK_KEY;\n\n const vnode = fallbackScope.render(state.renderFallback);\n state.activeVNodes = vnode == null || vnode === false ? [] : [vnode];\n return state.activeVNodes;\n}\n\nexport function clearShowDomUpdateState(state: ShowState): void {\n if (state.truthyScope) {\n state.truthyScope.needsDomUpdate = false;\n }\n if (state.fallbackScope) {\n state.fallbackScope.needsDomUpdate = false;\n }\n state.lastRemovedNodes = [];\n}\n\nexport function createCaseState(\n matches: MatchBranch[],\n fallback: (() => VNode) | null\n): CaseState {\n return {\n kind: 'case',\n activeKey: null,\n activeScope: null,\n activeVNodes: [],\n fallback,\n lastRemovedNodes: [],\n matches,\n parentInstance: getCurrentInstance(),\n _enqueueBoundaryCommit: null,\n _hasPendingBoundaryCommit: false,\n };\n}\n\nexport function evaluateCaseState(state: CaseState): VNode[] {\n state.lastRemovedNodes = [];\n\n const selectedMatch =\n state.matches.find((candidate) => Boolean(candidate.when)) ?? null;\n const nextKey =\n selectedMatch?.key ?? (state.fallback ? CASE_FALLBACK_KEY : null);\n\n if (nextKey === null) {\n if (state.activeScope) {\n disposeBranchScope(state, state.activeScope);\n }\n state.activeKey = null;\n state.activeScope = null;\n state.activeVNodes = [];\n return state.activeVNodes;\n }\n\n if (state.activeScope && state.activeKey !== nextKey) {\n disposeBranchScope(state, state.activeScope);\n state.activeScope = null;\n }\n\n const activeScope = state.activeScope ?? createBranchScope(state, nextKey);\n state.activeKey = nextKey;\n state.activeScope = activeScope;\n\n const renderBranch = selectedMatch?.render ?? state.fallback;\n const vnode = renderBranch ? activeScope.render(renderBranch) : null;\n state.activeVNodes = vnode == null || vnode === false ? [] : [vnode];\n return state.activeVNodes;\n}\n\nexport function clearCaseDomUpdateState(state: CaseState): void {\n if (state.activeScope) {\n state.activeScope.needsDomUpdate = false;\n }\n state.lastRemovedNodes = [];\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"control.js","names":[],"sources":["../../src/runtime/control.ts"],"sourcesContent":["import type { VNode } from '../common/vnode';\nimport {\n createChildScope,\n disposeChildScope,\n type ChildScope,\n} from './child-scope';\nimport { getCurrentInstance, type ComponentInstance } from './component';\nimport type { ForState } from './for';\n\nexport interface MatchBranch {\n key: string | number;\n render: () => VNode;\n when: unknown;\n}\n\ninterface BranchControlStateBase {\n activeKey: string | number | null;\n activeScope: ChildScope | null;\n activeVNodes: VNode[];\n lastRemovedNodes: Node[];\n parentInstance: ComponentInstance | null;\n _enqueueBoundaryCommit?: (() => void) | null;\n _hasPendingBoundaryCommit?: boolean;\n}\n\nexport interface ShowState extends BranchControlStateBase {\n kind: 'show';\n fallbackScope: ChildScope | null;\n renderFallback: (() => VNode) | null;\n renderTruthy: ((value: unknown) => VNode) | (() => VNode);\n selectedValue: unknown;\n truthyScope: ChildScope | null;\n}\n\nexport interface CaseState extends BranchControlStateBase {\n kind: 'case';\n fallback: (() => VNode) | null;\n matches: MatchBranch[];\n}\n\nexport type ControlBoundaryState = ForState<unknown> | ShowState | CaseState;\n\nconst SHOW_TRUTHY_KEY = '__show-truthy__';\nconst SHOW_FALLBACK_KEY = '__show-fallback__';\nconst CASE_FALLBACK_KEY = '__case-fallback__';\n\nfunction disposeBranchScope(\n state: BranchControlStateBase,\n scope: ChildScope | null\n): void {\n if (!scope) {\n return;\n }\n const removedDom = scope.dom;\n disposeChildScope(scope);\n if (removedDom) {\n state.lastRemovedNodes.push(removedDom);\n }\n}\n\nfunction createBranchScope(\n state: BranchControlStateBase,\n key: string | number\n): ChildScope {\n return createChildScope(state.parentInstance, key, () => {\n if (state._enqueueBoundaryCommit) {\n state._enqueueBoundaryCommit();\n return;\n }\n\n state.parentInstance?._enqueueRun?.();\n });\n}\n\nexport function createShowState(\n value: unknown,\n renderTruthy: ShowState['renderTruthy'],\n renderFallback: ShowState['renderFallback']\n): ShowState {\n return {\n kind: 'show',\n activeKey: null,\n activeScope: null,\n activeVNodes: [],\n fallbackScope: null,\n lastRemovedNodes: [],\n parentInstance: getCurrentInstance(),\n _enqueueBoundaryCommit: null,\n _hasPendingBoundaryCommit: false,\n renderFallback,\n renderTruthy,\n selectedValue: value,\n truthyScope: null,\n };\n}\n\nexport function evaluateShowState(state: ShowState): VNode[] {\n state.lastRemovedNodes = [];\n\n if (state.selectedValue) {\n if (state.fallbackScope) {\n disposeBranchScope(state, state.fallbackScope);\n state.fallbackScope = null;\n }\n\n const truthyScope =\n state.truthyScope ?? createBranchScope(state, SHOW_TRUTHY_KEY);\n state.truthyScope = truthyScope;\n state.activeScope = truthyScope;\n state.activeKey = SHOW_TRUTHY_KEY;\n\n const vnode = truthyScope.render(() =>\n state.renderTruthy(state.selectedValue)\n );\n state.activeVNodes = vnode == null || vnode === false ? [] : [vnode];\n return state.activeVNodes;\n }\n\n if (state.truthyScope) {\n disposeBranchScope(state, state.truthyScope);\n state.truthyScope = null;\n }\n\n if (!state.renderFallback) {\n if (state.fallbackScope) {\n disposeBranchScope(state, state.fallbackScope);\n state.fallbackScope = null;\n }\n state.activeKey = null;\n state.activeScope = null;\n state.activeVNodes = [];\n return state.activeVNodes;\n }\n\n const fallbackScope =\n state.fallbackScope ?? createBranchScope(state, SHOW_FALLBACK_KEY);\n state.fallbackScope = fallbackScope;\n state.activeScope = fallbackScope;\n state.activeKey = SHOW_FALLBACK_KEY;\n\n const vnode = fallbackScope.render(state.renderFallback);\n state.activeVNodes = vnode == null || vnode === false ? [] : [vnode];\n return state.activeVNodes;\n}\n\nexport function clearShowDomUpdateState(state: ShowState): void {\n if (state.truthyScope) {\n state.truthyScope.needsDomUpdate = false;\n }\n if (state.fallbackScope) {\n state.fallbackScope.needsDomUpdate = false;\n }\n state.lastRemovedNodes = [];\n}\n\nexport function createCaseState(\n matches: MatchBranch[],\n fallback: (() => VNode) | null\n): CaseState {\n return {\n kind: 'case',\n activeKey: null,\n activeScope: null,\n activeVNodes: [],\n fallback,\n lastRemovedNodes: [],\n matches,\n parentInstance: getCurrentInstance(),\n _enqueueBoundaryCommit: null,\n _hasPendingBoundaryCommit: false,\n };\n}\n\nexport function evaluateCaseState(state: CaseState): VNode[] {\n state.lastRemovedNodes = [];\n\n const selectedMatch =\n state.matches.find((candidate) => Boolean(candidate.when)) ?? null;\n const nextKey =\n selectedMatch?.key ?? (state.fallback ? CASE_FALLBACK_KEY : null);\n\n if (nextKey === null) {\n if (state.activeScope) {\n disposeBranchScope(state, state.activeScope);\n }\n state.activeKey = null;\n state.activeScope = null;\n state.activeVNodes = [];\n return state.activeVNodes;\n }\n\n if (state.activeScope && state.activeKey !== nextKey) {\n disposeBranchScope(state, state.activeScope);\n state.activeScope = null;\n }\n\n const activeScope = state.activeScope ?? createBranchScope(state, nextKey);\n state.activeKey = nextKey;\n state.activeScope = activeScope;\n\n const renderBranch = selectedMatch?.render ?? state.fallback;\n const vnode = renderBranch ? activeScope.render(renderBranch) : null;\n state.activeVNodes = vnode == null || vnode === false ? [] : [vnode];\n return state.activeVNodes;\n}\n\nexport function clearCaseDomUpdateState(state: CaseState): void {\n if (state.activeScope) {\n state.activeScope.needsDomUpdate = false;\n }\n state.lastRemovedNodes = [];\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"derive.d.ts","names":[],"sources":["../../src/runtime/derive.ts"],"mappings":";;;;UAmBiB,OAAA,YAAmB,cAAA,CAAe,CAAA;EAAA,IAC7C,CAAA;AAAA;AAAA,KAiBD,cAAA;EACH,KAAA,EAAO,CAAA;EACP,OAAA;EACA,KAAA,GAAQ,KAAA;AAAA,IACN,mBAAA;AAAA,iBA4LY,MAAA,MAAA,CAAa,EAAA,QAAU,IAAA,GAAO,OAAA,CAAQ,IAAA;AAAA,iBAEtC,MAAA,WAAA,CACd,MAAA,EAAQ,cAAA,CAAe,GAAA,IAAO,GAAA,UAAa,GAAA,GAC3C,GAAA,GAAM,KAAA,EAAO,GAAA,KAAQ,IAAA,GACpB,OAAA,CAAQ,IAAA"}
1
+ {"version":3,"file":"derive.d.ts","names":[],"sources":["../../src/runtime/derive.ts"],"mappings":";;;;UAmBiB,OAAA,YAAmB,cAAA,CAAe,CAAA;EAAA,IAC7C,CAAA;AAAA;AAAA,KAkBD,cAAA;EACH,KAAA,EAAO,CAAA;EACP,OAAA;EACA,KAAA,GAAQ,KAAA;AAAA,IACN,mBAAA;AAAA,iBAkMY,MAAA,OAAa,EAAA,QAAU,IAAA,GAAO,OAAA,CAAQ,IAAA;AAAA,iBAEtC,MAAA,YACd,MAAA,EAAQ,cAAA,CAAe,GAAA,IAAO,GAAA,UAAa,GAAA,GAC3C,GAAA,GAAM,KAAA,EAAO,GAAA,KAAQ,IAAA,GACpB,OAAA,CAAQ,IAAA"}
@@ -65,6 +65,7 @@ function recomputeDerivedCell(cell, notifyDownstream) {
65
65
  const valueChanged = !cell._hasValue || !Object.is(cell._value, nextValue);
66
66
  cell._hasValue = true;
67
67
  cell._value = nextValue;
68
+ cell._lastRecomputeFlushVersion = globalScheduler.getFlushVersion();
68
69
  if (valueChanged && notifyDownstream) {
69
70
  markReadableDerivedSubscribersDirty(cell);
70
71
  markReactivePropsDirtySource(cell);
@@ -85,6 +86,7 @@ function createDerivedCell(instance, hookIndex, compute) {
85
86
  cell._dirty = true;
86
87
  cell._scheduled = false;
87
88
  cell._evaluating = false;
89
+ cell._lastRecomputeFlushVersion = -1;
88
90
  cell._sources = /* @__PURE__ */ new Set();
89
91
  cell._markDirty = () => {
90
92
  markDerivedCellDirty(cell);
@@ -109,7 +111,7 @@ function getOrCreateDerivedCell(instance, hookIndex, compute) {
109
111
  const existing = store.get(hookIndex);
110
112
  if (existing) {
111
113
  existing._compute = compute;
112
- existing._dirty = true;
114
+ if (existing._lastRecomputeFlushVersion !== globalScheduler.getFlushVersion()) existing._dirty = true;
113
115
  return existing;
114
116
  }
115
117
  const created = createDerivedCell(instance, hookIndex, compute);
@@ -1 +1 @@
1
- {"version":3,"file":"derive.js","names":[],"sources":["../../src/runtime/derive.ts"],"sourcesContent":["import {\n claimHookIndex,\n getCurrentInstance,\n type ComponentInstance,\n} from './component';\nimport { globalScheduler } from './scheduler';\nimport {\n clearDerivedDependencySubscriptions,\n markReadableDerivedSubscribersDirty,\n markReactivePropsDirtySource,\n notifyReadableReaders,\n recordReadableRead,\n syncDerivedDependencySubscriptions,\n type DerivedSubscriber,\n type ReadableSource,\n withDerivedReadTracking,\n} from './readable';\nimport { isSnapshotSource, type SnapshotSourceBrand } from './snapshot-source';\n\nexport interface Derived<T> extends ReadableSource<T> {\n (): T;\n}\n\ninterface DerivedCell<T> extends Derived<T>, DerivedSubscriber {\n _owner: ComponentInstance;\n _hookIndex: number;\n _compute: () => T;\n _value: T;\n _hasValue: boolean;\n _dirty: boolean;\n _scheduled: boolean;\n _evaluating: boolean;\n _sources: Set<ReadableSource<unknown>>;\n _pendingDependencySources?: Set<ReadableSource<unknown>>;\n _cleanup(): void;\n}\n\ntype SnapshotSource<T> = {\n value: T | null;\n pending?: boolean;\n error?: Error | null;\n} & SnapshotSourceBrand;\n\nconst deriveCells = new WeakMap<\n ComponentInstance,\n Map<number, DerivedCell<unknown>>\n>();\nconst dirtyDerivedCells = new Set<DerivedCell<unknown>>();\nlet hasPendingDerivedFlush = false;\n\nfunction getDeriveStore(\n instance: ComponentInstance\n): Map<number, DerivedCell<unknown>> {\n let store = deriveCells.get(instance);\n if (!store) {\n store = new Map();\n deriveCells.set(instance, store);\n }\n return store;\n}\n\nfunction markDerivedCellDirty(cell: DerivedCell<unknown>): void {\n cell._dirty = true;\n if (cell._scheduled) {\n return;\n }\n\n cell._scheduled = true;\n dirtyDerivedCells.add(cell);\n\n if (!hasPendingDerivedFlush) {\n hasPendingDerivedFlush = true;\n globalScheduler.enqueueInLane('derived', flushDirtyDerivedCells);\n }\n}\n\nfunction flushDirtyDerivedCells(): void {\n hasPendingDerivedFlush = false;\n\n if (dirtyDerivedCells.size === 0) {\n return;\n }\n\n const pending = dirtyDerivedCells.values();\n let next = pending.next();\n\n while (!next.done) {\n const cell = next.value as DerivedCell<unknown>;\n dirtyDerivedCells.delete(cell);\n cell._scheduled = false;\n if (!cell._dirty) {\n next = pending.next();\n continue;\n }\n recomputeDerivedCell(cell, true);\n next = pending.next();\n }\n}\n\nfunction recomputeDerivedCell<T>(\n cell: DerivedCell<T>,\n notifyDownstream: boolean\n): T {\n if (!cell._dirty && cell._hasValue) {\n return cell._value;\n }\n\n if (cell._evaluating) {\n throw new Error('derive() cannot read itself recursively');\n }\n\n cell._evaluating = true;\n cell._dirty = false;\n cell._pendingDependencySources = new Set();\n\n const prevSources = cell._sources;\n let nextValue: T;\n\n try {\n nextValue = withDerivedReadTracking(cell, cell._compute);\n } catch (error) {\n cell._dirty = true;\n cell._pendingDependencySources = undefined;\n throw error;\n } finally {\n cell._evaluating = false;\n }\n\n const nextSources = cell._pendingDependencySources ?? new Set();\n cell._pendingDependencySources = undefined;\n syncDerivedDependencySubscriptions(cell, prevSources, nextSources);\n cell._sources = nextSources;\n\n const valueChanged = !cell._hasValue || !Object.is(cell._value, nextValue);\n cell._hasValue = true;\n cell._value = nextValue;\n\n if (valueChanged && notifyDownstream) {\n markReadableDerivedSubscribersDirty(cell);\n markReactivePropsDirtySource(cell);\n notifyReadableReaders(cell);\n }\n\n return cell._value;\n}\n\nfunction createDerivedCell<T>(\n instance: ComponentInstance,\n hookIndex: number,\n compute: () => T\n): DerivedCell<T> {\n const cell = function derivedGetter(): T {\n recordReadableRead(cell as DerivedCell<T>);\n return recomputeDerivedCell(\n cell as DerivedCell<T>,\n (cell as DerivedCell<T>)._scheduled\n );\n } as DerivedCell<T>;\n\n cell._owner = instance;\n cell._hookIndex = hookIndex;\n cell._compute = compute;\n cell._value = undefined as T;\n cell._hasValue = false;\n cell._dirty = true;\n cell._scheduled = false;\n cell._evaluating = false;\n cell._sources = new Set();\n cell._markDirty = () => {\n markDerivedCellDirty(cell);\n };\n cell._cleanup = () => {\n cell._scheduled = false;\n cell._dirty = false;\n cell._hasValue = false;\n dirtyDerivedCells.delete(cell);\n clearDerivedDependencySubscriptions(cell, cell._sources);\n cell._derivedSubscribers?.clear();\n cell._readers?.clear();\n };\n\n (instance.cleanupFns ??= []).push(() => {\n cell._cleanup();\n deriveCells.get(instance)?.delete(hookIndex);\n });\n\n return cell;\n}\n\nfunction getOrCreateDerivedCell<T>(\n instance: ComponentInstance,\n hookIndex: number,\n compute: () => T\n): DerivedCell<T> {\n const store = getDeriveStore(instance);\n const existing = store.get(hookIndex) as DerivedCell<T> | undefined;\n if (existing) {\n existing._compute = compute;\n existing._dirty = true;\n return existing;\n }\n\n const created = createDerivedCell(instance, hookIndex, compute);\n store.set(hookIndex, created as DerivedCell<unknown>);\n return created;\n}\n\nfunction createMappedSelector<TIn, TOut>(\n source: SnapshotSource<TIn> | TIn | (() => TIn),\n map: (value: TIn) => TOut\n): () => TOut | null {\n return () => {\n let value: TIn;\n if (typeof source === 'function') {\n value = (source as () => TIn)();\n } else if (isSnapshotSource(source)) {\n value = (source as SnapshotSource<TIn>).value ?? (source as TIn);\n } else {\n value = source as TIn;\n }\n\n if (value == null) {\n return null;\n }\n\n return map(value);\n };\n}\n\nexport function derive<TOut>(fn: () => TOut): Derived<TOut>;\n\nexport function derive<TIn, TOut>(\n source: SnapshotSource<TIn> | TIn | (() => TIn),\n map: (value: TIn) => TOut\n): Derived<TOut | null>;\n\nexport function derive<TIn, TOut>(\n source: SnapshotSource<TIn> | TIn | (() => TIn),\n map?: (value: TIn) => TOut\n): Derived<TOut | null> | Derived<TIn> {\n const instance = getCurrentInstance();\n if (!instance) {\n throw new Error(\n 'derive() can only be called during component render execution. ' +\n 'Move derive() calls to the top level of your component function.'\n );\n }\n\n const hookIndex = claimHookIndex(instance, 'derive');\n const compute =\n map === undefined\n ? () => (source as () => TIn)()\n : createMappedSelector(source, map);\n\n const cell = getOrCreateDerivedCell(\n instance,\n hookIndex,\n compute as () => TOut | null | TIn\n );\n recomputeDerivedCell(cell, false);\n return cell as Derived<TOut | null> | Derived<TIn>;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"derive.js","names":[],"sources":["../../src/runtime/derive.ts"],"sourcesContent":["import {\n claimHookIndex,\n getCurrentInstance,\n type ComponentInstance,\n} from './component';\nimport { globalScheduler } from './scheduler';\nimport {\n clearDerivedDependencySubscriptions,\n markReadableDerivedSubscribersDirty,\n markReactivePropsDirtySource,\n notifyReadableReaders,\n recordReadableRead,\n syncDerivedDependencySubscriptions,\n type DerivedSubscriber,\n type ReadableSource,\n withDerivedReadTracking,\n} from './readable';\nimport { isSnapshotSource, type SnapshotSourceBrand } from './snapshot-source';\n\nexport interface Derived<T> extends ReadableSource<T> {\n (): T;\n}\n\ninterface DerivedCell<T> extends Derived<T>, DerivedSubscriber {\n _owner: ComponentInstance;\n _hookIndex: number;\n _compute: () => T;\n _value: T;\n _hasValue: boolean;\n _dirty: boolean;\n _scheduled: boolean;\n _evaluating: boolean;\n _lastRecomputeFlushVersion: number;\n _sources: Set<ReadableSource<unknown>>;\n _pendingDependencySources?: Set<ReadableSource<unknown>>;\n _cleanup(): void;\n}\n\ntype SnapshotSource<T> = {\n value: T | null;\n pending?: boolean;\n error?: Error | null;\n} & SnapshotSourceBrand;\n\nconst deriveCells = new WeakMap<\n ComponentInstance,\n Map<number, DerivedCell<unknown>>\n>();\nconst dirtyDerivedCells = new Set<DerivedCell<unknown>>();\nlet hasPendingDerivedFlush = false;\n\nfunction getDeriveStore(\n instance: ComponentInstance\n): Map<number, DerivedCell<unknown>> {\n let store = deriveCells.get(instance);\n if (!store) {\n store = new Map();\n deriveCells.set(instance, store);\n }\n return store;\n}\n\nfunction markDerivedCellDirty(cell: DerivedCell<unknown>): void {\n cell._dirty = true;\n if (cell._scheduled) {\n return;\n }\n\n cell._scheduled = true;\n dirtyDerivedCells.add(cell);\n\n if (!hasPendingDerivedFlush) {\n hasPendingDerivedFlush = true;\n globalScheduler.enqueueInLane('derived', flushDirtyDerivedCells);\n }\n}\n\nfunction flushDirtyDerivedCells(): void {\n hasPendingDerivedFlush = false;\n\n if (dirtyDerivedCells.size === 0) {\n return;\n }\n\n const pending = dirtyDerivedCells.values();\n let next = pending.next();\n\n while (!next.done) {\n const cell = next.value as DerivedCell<unknown>;\n dirtyDerivedCells.delete(cell);\n cell._scheduled = false;\n if (!cell._dirty) {\n next = pending.next();\n continue;\n }\n recomputeDerivedCell(cell, true);\n next = pending.next();\n }\n}\n\nfunction recomputeDerivedCell<T>(\n cell: DerivedCell<T>,\n notifyDownstream: boolean\n): T {\n if (!cell._dirty && cell._hasValue) {\n return cell._value;\n }\n\n if (cell._evaluating) {\n throw new Error('derive() cannot read itself recursively');\n }\n\n cell._evaluating = true;\n cell._dirty = false;\n cell._pendingDependencySources = new Set();\n\n const prevSources = cell._sources;\n let nextValue: T;\n\n try {\n nextValue = withDerivedReadTracking(cell, cell._compute);\n } catch (error) {\n cell._dirty = true;\n cell._pendingDependencySources = undefined;\n throw error;\n } finally {\n cell._evaluating = false;\n }\n\n const nextSources = cell._pendingDependencySources ?? new Set();\n cell._pendingDependencySources = undefined;\n syncDerivedDependencySubscriptions(cell, prevSources, nextSources);\n cell._sources = nextSources;\n\n const valueChanged = !cell._hasValue || !Object.is(cell._value, nextValue);\n cell._hasValue = true;\n cell._value = nextValue;\n cell._lastRecomputeFlushVersion = globalScheduler.getFlushVersion();\n\n if (valueChanged && notifyDownstream) {\n markReadableDerivedSubscribersDirty(cell);\n markReactivePropsDirtySource(cell);\n notifyReadableReaders(cell);\n }\n\n return cell._value;\n}\n\nfunction createDerivedCell<T>(\n instance: ComponentInstance,\n hookIndex: number,\n compute: () => T\n): DerivedCell<T> {\n const cell = function derivedGetter(): T {\n recordReadableRead(cell as DerivedCell<T>);\n return recomputeDerivedCell(\n cell as DerivedCell<T>,\n (cell as DerivedCell<T>)._scheduled\n );\n } as DerivedCell<T>;\n\n cell._owner = instance;\n cell._hookIndex = hookIndex;\n cell._compute = compute;\n cell._value = undefined as T;\n cell._hasValue = false;\n cell._dirty = true;\n cell._scheduled = false;\n cell._evaluating = false;\n cell._lastRecomputeFlushVersion = -1;\n cell._sources = new Set();\n cell._markDirty = () => {\n markDerivedCellDirty(cell);\n };\n cell._cleanup = () => {\n cell._scheduled = false;\n cell._dirty = false;\n cell._hasValue = false;\n dirtyDerivedCells.delete(cell);\n clearDerivedDependencySubscriptions(cell, cell._sources);\n cell._derivedSubscribers?.clear();\n cell._readers?.clear();\n };\n\n (instance.cleanupFns ??= []).push(() => {\n cell._cleanup();\n deriveCells.get(instance)?.delete(hookIndex);\n });\n\n return cell;\n}\n\nfunction getOrCreateDerivedCell<T>(\n instance: ComponentInstance,\n hookIndex: number,\n compute: () => T\n): DerivedCell<T> {\n const store = getDeriveStore(instance);\n const existing = store.get(hookIndex) as DerivedCell<T> | undefined;\n if (existing) {\n existing._compute = compute;\n if (\n existing._lastRecomputeFlushVersion !== globalScheduler.getFlushVersion()\n ) {\n existing._dirty = true;\n }\n return existing;\n }\n\n const created = createDerivedCell(instance, hookIndex, compute);\n store.set(hookIndex, created as DerivedCell<unknown>);\n return created;\n}\n\nfunction createMappedSelector<TIn, TOut>(\n source: SnapshotSource<TIn> | TIn | (() => TIn),\n map: (value: TIn) => TOut\n): () => TOut | null {\n return () => {\n let value: TIn;\n if (typeof source === 'function') {\n value = (source as () => TIn)();\n } else if (isSnapshotSource(source)) {\n value = (source as SnapshotSource<TIn>).value ?? (source as TIn);\n } else {\n value = source as TIn;\n }\n\n if (value == null) {\n return null;\n }\n\n return map(value);\n };\n}\n\nexport function derive<TOut>(fn: () => TOut): Derived<TOut>;\n\nexport function derive<TIn, TOut>(\n source: SnapshotSource<TIn> | TIn | (() => TIn),\n map: (value: TIn) => TOut\n): Derived<TOut | null>;\n\nexport function derive<TIn, TOut>(\n source: SnapshotSource<TIn> | TIn | (() => TIn),\n map?: (value: TIn) => TOut\n): Derived<TOut | null> | Derived<TIn> {\n const instance = getCurrentInstance();\n if (!instance) {\n throw new Error(\n 'derive() can only be called during component render execution. ' +\n 'Move derive() calls to the top level of your component function.'\n );\n }\n\n const hookIndex = claimHookIndex(instance, 'derive');\n const compute =\n map === undefined\n ? () => (source as () => TIn)()\n : createMappedSelector(source, map);\n\n const cell = getOrCreateDerivedCell(\n instance,\n hookIndex,\n compute as () => TOut | null | TIn\n );\n recomputeDerivedCell(cell, false);\n return cell as Derived<TOut | null> | Derived<TIn>;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"dev-namespace.js","names":[],"sources":["../../src/runtime/dev-namespace.ts"],"sourcesContent":["/**\n * Dev-only namespace helpers for diagnostics\n *\n * Centralizes the repetitive globalThis.__ASKR__ access pattern\n * used throughout runtime for dev-mode diagnostics.\n */\n\nimport { isProductionEnvironment } from '../common/env';\n\ntype DevNamespace = Record<string, unknown>;\n\n/**\n * Get or create the __ASKR__ dev namespace on globalThis.\n * Returns empty object in production to avoid allocations.\n */\nexport function getDevNamespace(): DevNamespace {\n if (isProductionEnvironment()) return {};\n try {\n const g = globalThis as unknown as Record<string, DevNamespace>;\n if (!g.__ASKR__) g.__ASKR__ = {};\n return g.__ASKR__;\n } catch {\n return {};\n }\n}\n\n/**\n * Set a value in the dev namespace (no-op in production).\n */\nexport function setDevValue(key: string, value: unknown): void {\n if (isProductionEnvironment()) return;\n try {\n getDevNamespace()[key] = value;\n } catch {\n // ignore\n }\n}\n\n/**\n * Get a value from the dev namespace (returns undefined in production).\n */\nexport function getDevValue<T>(key: string): T | undefined {\n if (isProductionEnvironment()) return undefined;\n try {\n return getDevNamespace()[key] as T | undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Delete a value from the dev namespace (no-op in production).\n */\nexport function deleteDevValue(key: string): void {\n if (isProductionEnvironment()) return;\n try {\n delete getDevNamespace()[key];\n } catch {\n // ignore\n }\n}\n\n/**\n * Increment a counter in the dev namespace (no-op in production).\n * Safely handles non-number values by resetting to 1.\n */\nexport function incDevCounter(key: string): void {\n if (isProductionEnvironment()) return;\n try {\n const ns = getDevNamespace();\n const prev = typeof ns[key] === 'number' ? (ns[key] as number) : 0;\n ns[key] = prev + 1;\n } catch {\n // ignore\n }\n}\n"],"mappings":";;;;;;;;;;;;AAeA,SAAgB,kBAAgC;CAC9C,IAAI,yBAAyB,EAAE,OAAO,EAAE;CACxC,IAAI;EACF,MAAM,IAAI;EACV,IAAI,CAAC,EAAE,UAAU,EAAE,WAAW,EAAE;EAChC,OAAO,EAAE;SACH;EACN,OAAO,EAAE;;;;;;AAOb,SAAgB,YAAY,KAAa,OAAsB;CAC7D,IAAI,yBAAyB,EAAE;CAC/B,IAAI;EACF,iBAAiB,CAAC,OAAO;SACnB;;;;;AAQV,SAAgB,YAAe,KAA4B;CACzD,IAAI,yBAAyB,EAAE,OAAO;CACtC,IAAI;EACF,OAAO,iBAAiB,CAAC;SACnB;EACN;;;;;;;AAoBJ,SAAgB,cAAc,KAAmB;CAC/C,IAAI,yBAAyB,EAAE;CAC/B,IAAI;EACF,MAAM,KAAK,iBAAiB;EAE5B,GAAG,QADU,OAAO,GAAG,SAAS,WAAY,GAAG,OAAkB,KAChD;SACX"}
1
+ {"version":3,"file":"dev-namespace.js","names":[],"sources":["../../src/runtime/dev-namespace.ts"],"sourcesContent":["/**\n * Dev-only namespace helpers for diagnostics\n *\n * Centralizes the repetitive globalThis.__ASKR__ access pattern\n * used throughout runtime for dev-mode diagnostics.\n */\n\nimport { isProductionEnvironment } from '../common/env';\n\ntype DevNamespace = Record<string, unknown>;\n\n/**\n * Get or create the __ASKR__ dev namespace on globalThis.\n * Returns empty object in production to avoid allocations.\n */\nexport function getDevNamespace(): DevNamespace {\n if (isProductionEnvironment()) return {};\n try {\n const g = globalThis as unknown as Record<string, DevNamespace>;\n if (!g.__ASKR__) g.__ASKR__ = {};\n return g.__ASKR__;\n } catch {\n return {};\n }\n}\n\n/**\n * Set a value in the dev namespace (no-op in production).\n */\nexport function setDevValue(key: string, value: unknown): void {\n if (isProductionEnvironment()) return;\n try {\n getDevNamespace()[key] = value;\n } catch {\n // ignore\n }\n}\n\n/**\n * Get a value from the dev namespace (returns undefined in production).\n */\nexport function getDevValue<T>(key: string): T | undefined {\n if (isProductionEnvironment()) return undefined;\n try {\n return getDevNamespace()[key] as T | undefined;\n } catch {\n return undefined;\n }\n}\n\n/**\n * Delete a value from the dev namespace (no-op in production).\n */\nexport function deleteDevValue(key: string): void {\n if (isProductionEnvironment()) return;\n try {\n delete getDevNamespace()[key];\n } catch {\n // ignore\n }\n}\n\n/**\n * Increment a counter in the dev namespace (no-op in production).\n * Safely handles non-number values by resetting to 1.\n */\nexport function incDevCounter(key: string): void {\n if (isProductionEnvironment()) return;\n try {\n const ns = getDevNamespace();\n const prev = typeof ns[key] === 'number' ? (ns[key] as number) : 0;\n ns[key] = prev + 1;\n } catch {\n // ignore\n }\n}\n"],"mappings":";;;;;;;;;;;;AAeA,SAAgB,kBAAgC;CAC9C,IAAI,wBAAwB,GAAG,OAAO,CAAC;CACvC,IAAI;EACF,MAAM,IAAI;EACV,IAAI,CAAC,EAAE,UAAU,EAAE,WAAW,CAAC;EAC/B,OAAO,EAAE;CACX,QAAQ;EACN,OAAO,CAAC;CACV;AACF;;;;AAKA,SAAgB,YAAY,KAAa,OAAsB;CAC7D,IAAI,wBAAwB,GAAG;CAC/B,IAAI;EACF,gBAAgB,EAAE,OAAO;CAC3B,QAAQ,CAER;AACF;;;;AAKA,SAAgB,YAAe,KAA4B;CACzD,IAAI,wBAAwB,GAAG,OAAO;CACtC,IAAI;EACF,OAAO,gBAAgB,EAAE;CAC3B,QAAQ;EACN;CACF;AACF;;;;;AAkBA,SAAgB,cAAc,KAAmB;CAC/C,IAAI,wBAAwB,GAAG;CAC/B,IAAI;EACF,MAAM,KAAK,gBAAgB;EAE3B,GAAG,QADU,OAAO,GAAG,SAAS,WAAY,GAAG,OAAkB,KAChD;CACnB,QAAQ,CAER;AACF"}
@@ -1 +1 @@
1
- {"version":3,"file":"effect.d.ts","names":[],"sources":["../../src/runtime/effect.ts"],"mappings":";;;;UA2CiB,iBAAA;EACf,IAAA,EAAM,aAAA;EACN,OAAA,IAAW,CAAA;EACX,MAAA,CAAO,KAAA,EAAO,CAAA,EAAG,aAAA,EAAe,CAAA;EAChC,MAAA,CAAO,aAAA,EAAe,CAAA,EAAG,SAAA,EAAW,CAAA;EACpC,WAAA,EAAa,GAAA,CAAI,cAAA;EACjB,QAAA;EACA,QAAA;EACA,SAAA,EAAW,CAAA;EACX,OAAA,EAAS,KAAA;AAAA;AAAA,UAGM,uBAAA;EACf,OAAA;EACA,aAAA,CAAc,WAAA,QAAmB,CAAA;EACjC,KAAA;AAAA;AAAA,UAGe,8BAAA;EACf,IAAA,EAAM,aAAA;EACN,OAAA,QAAe,CAAA;EACf,MAAA,GAAS,KAAA,EAAO,CAAA,EAAG,aAAA,EAAe,CAAA;EAClC,MAAA,IAAU,aAAA,EAAe,CAAA,EAAG,SAAA,EAAW,CAAA;EACvC,OAAA,IAAW,KAAA;AAAA;AAAA,iBAkKG,iCAAA,CACd,MAAA,EAAQ,cAAA;AAAA,iBAmCM,uBAAA,GAAA,CACd,OAAA,EAAS,8BAAA,CAA+B,CAAA,IACvC,uBAAA,CAAwB,CAAA"}
1
+ {"version":3,"file":"effect.d.ts","names":[],"sources":["../../src/runtime/effect.ts"],"mappings":";;;;UA2CiB,iBAAA;EACf,IAAA,EAAM,aAAA;EACN,OAAA,IAAW,CAAA;EACX,MAAA,CAAO,KAAA,EAAO,CAAA,EAAG,aAAA,EAAe,CAAA;EAChC,MAAA,CAAO,aAAA,EAAe,CAAA,EAAG,SAAA,EAAW,CAAA;EACpC,WAAA,EAAa,GAAA,CAAI,cAAA;EACjB,QAAA;EACA,QAAA;EACA,SAAA,EAAW,CAAA;EACX,OAAA,EAAS,KAAA;AAAA;AAAA,UAGM,uBAAA;EACf,OAAA;EACA,aAAA,CAAc,WAAA,QAAmB,CAAC;EAClC,KAAA;AAAA;AAAA,UAGe,8BAAA;EACf,IAAA,EAAM,aAAA;EACN,OAAA,QAAe,CAAA;EACf,MAAA,GAAS,KAAA,EAAO,CAAA,EAAG,aAAA,EAAe,CAAA;EAClC,MAAA,IAAU,aAAA,EAAe,CAAA,EAAG,SAAA,EAAW,CAAA;EACvC,OAAA,IAAW,KAAA;AAAA;AAAA,iBA2KG,iCAAA,CACd,MAA+B,EAAvB,cAAc;AAAA,iBAmCR,uBAAA,IACd,OAAA,EAAS,8BAAA,CAA+B,CAAA,IACvC,uBAAA,CAAwB,CAAA"}
@@ -21,7 +21,7 @@ const dirtyLaneState = {
21
21
  reactive: false,
22
22
  post: false
23
23
  };
24
- const _evalSourceBuffer = /* @__PURE__ */ new Set();
24
+ const MAX_EFFECT_RUNS_PER_FLUSH = 50;
25
25
  const LANE_FLUSH_TASKS = {
26
26
  derived: () => flushLaneEffects("derived"),
27
27
  component: () => flushLaneEffects("component"),
@@ -55,16 +55,12 @@ function normalizeNextSources(previousSources, pendingSources) {
55
55
  return new Set(pendingSources);
56
56
  }
57
57
  function evaluateEffect(effect) {
58
- _evalSourceBuffer.clear();
59
- try {
60
- incDevCounter("effectRuns");
61
- return {
62
- value: withFineGrainedReadTracking(_evalSourceBuffer, () => effect.compute()),
63
- nextSources: normalizeNextSources(effect.readSources, _evalSourceBuffer)
64
- };
65
- } finally {
66
- _evalSourceBuffer.clear();
67
- }
58
+ const pendingSources = /* @__PURE__ */ new Set();
59
+ incDevCounter("effectRuns");
60
+ return {
61
+ value: withFineGrainedReadTracking(pendingSources, () => effect.compute()),
62
+ nextSources: normalizeNextSources(effect.readSources, pendingSources)
63
+ };
68
64
  }
69
65
  function commitEffectSubscriptions(effect, nextSources) {
70
66
  const previousSources = effect.readSources;
@@ -85,6 +81,7 @@ function flushLaneEffects(lane) {
85
81
  const effects = dirtyEffectsByLane[lane];
86
82
  if (effects.size === 0) return;
87
83
  const pending = effects.values();
84
+ const effectRuns = /* @__PURE__ */ new Map();
88
85
  let next = pending.next();
89
86
  while (!next.done) {
90
87
  const effect = next.value;
@@ -93,6 +90,15 @@ function flushLaneEffects(lane) {
93
90
  next = pending.next();
94
91
  continue;
95
92
  }
93
+ const runCount = (effectRuns.get(effect) ?? 0) + 1;
94
+ effectRuns.set(effect, runCount);
95
+ if (runCount > MAX_EFFECT_RUNS_PER_FLUSH) {
96
+ const error = /* @__PURE__ */ new Error(`[Askr] fine-grained effect exceeded ${MAX_EFFECT_RUNS_PER_FLUSH} runs in one flush. Likely reactive cycle.`);
97
+ if (effect.onError) effect.onError(error);
98
+ else throw error;
99
+ next = pending.next();
100
+ continue;
101
+ }
96
102
  try {
97
103
  const { value, nextSources } = evaluateEffect(effect);
98
104
  commitEffectResult(effect, value, nextSources);
@@ -1 +1 @@
1
- {"version":3,"file":"effect.js","names":[],"sources":["../../src/runtime/effect.ts"],"sourcesContent":["import { incDevCounter } from './dev-namespace';\nimport { type ReadableSource, withFineGrainedReadTracking } from './readable';\nimport { globalScheduler, type SchedulerLane } from './scheduler';\n\ntype EffectRegistry = WeakMap<\n ReadableSource<unknown>,\n Set<FineGrainedEffect<unknown>>\n>;\n\ntype EffectFlushSets = Record<SchedulerLane, Set<FineGrainedEffect<unknown>>>;\n\ntype EffectPendingFlushState = Record<SchedulerLane, boolean>;\ntype EffectLaneDirtyState = Record<SchedulerLane, boolean>;\n\nconst effectSources: EffectRegistry = new WeakMap();\nconst dirtyEffectsByLane: EffectFlushSets = {\n derived: new Set(),\n component: new Set(),\n reactive: new Set(),\n post: new Set(),\n};\nconst hasPendingLaneFlush: EffectPendingFlushState = {\n derived: false,\n component: false,\n reactive: false,\n post: false,\n};\n\nconst dirtyLaneState: EffectLaneDirtyState = {\n derived: false,\n component: false,\n reactive: false,\n post: false,\n};\n\nconst _evalSourceBuffer = new Set<ReadableSource<unknown>>();\nconst LANE_FLUSH_TASKS: Record<SchedulerLane, () => void> = {\n derived: () => flushLaneEffects('derived'),\n component: () => flushLaneEffects('component'),\n reactive: () => flushLaneEffects('reactive'),\n post: () => flushLaneEffects('post'),\n};\n\nexport interface FineGrainedEffect<T> {\n lane: SchedulerLane;\n compute(): T;\n commit(value: T, previousValue: T | undefined): void;\n equals(previousValue: T, nextValue: T): boolean;\n readSources: Set<ReadableSource<unknown>>;\n isActive: boolean;\n hasValue: boolean;\n lastValue: T | undefined;\n onError?(error: unknown): void;\n}\n\nexport interface FineGrainedEffectHandle<T> {\n cleanup(): void;\n updateCompute(nextCompute: () => T): void;\n flush(): void;\n}\n\nexport interface CreateFineGrainedEffectOptions<T> {\n lane: SchedulerLane;\n compute: () => T;\n commit: (value: T, previousValue: T | undefined) => void;\n equals?: (previousValue: T, nextValue: T) => boolean;\n onError?: (error: unknown) => void;\n}\n\nfunction registerEffectSource(\n source: ReadableSource<unknown>,\n effect: FineGrainedEffect<unknown>\n): void {\n let effects = effectSources.get(source);\n if (!effects) {\n effects = new Set();\n effectSources.set(source, effects);\n }\n effects.add(effect);\n}\n\nfunction unregisterEffectSource(\n source: ReadableSource<unknown>,\n effect: FineGrainedEffect<unknown>\n): void {\n effectSources.get(source)?.delete(effect);\n}\n\nfunction clearEffectSubscriptions(effect: FineGrainedEffect<unknown>): void {\n for (const source of effect.readSources) {\n unregisterEffectSource(source, effect);\n }\n effect.readSources.clear();\n}\n\nfunction normalizeNextSources(\n previousSources: Set<ReadableSource<unknown>>,\n pendingSources: Set<ReadableSource<unknown>>\n): Set<ReadableSource<unknown>> {\n if (previousSources.size === pendingSources.size) {\n let same = true;\n for (const source of previousSources) {\n if (!pendingSources.has(source)) {\n same = false;\n break;\n }\n }\n\n if (same) {\n return previousSources;\n }\n }\n\n return new Set(pendingSources);\n}\n\nfunction evaluateEffect<T>(effect: FineGrainedEffect<T>): {\n value: T;\n nextSources: Set<ReadableSource<unknown>>;\n} {\n _evalSourceBuffer.clear();\n\n try {\n incDevCounter('effectRuns');\n const value = withFineGrainedReadTracking(_evalSourceBuffer, () =>\n effect.compute()\n );\n const nextSources = normalizeNextSources(\n effect.readSources,\n _evalSourceBuffer\n );\n return { value, nextSources };\n } finally {\n _evalSourceBuffer.clear();\n }\n}\n\nfunction commitEffectSubscriptions(\n effect: FineGrainedEffect<unknown>,\n nextSources: Set<ReadableSource<unknown>>\n): void {\n const previousSources = effect.readSources;\n\n if (previousSources === nextSources) {\n return;\n }\n\n for (const source of previousSources) {\n if (!nextSources.has(source)) {\n unregisterEffectSource(source, effect);\n }\n }\n\n for (const source of nextSources) {\n if (!previousSources.has(source)) {\n registerEffectSource(source, effect);\n }\n }\n\n effect.readSources = nextSources;\n}\n\nfunction commitEffectResult<T>(\n effect: FineGrainedEffect<T>,\n value: T,\n nextSources: Set<ReadableSource<unknown>>\n): void {\n const previousValue = effect.lastValue;\n const shouldCommit =\n !effect.hasValue || !effect.equals(previousValue as T, value);\n\n if (shouldCommit) {\n effect.commit(value, effect.hasValue ? previousValue : undefined);\n }\n\n commitEffectSubscriptions(effect, nextSources);\n effect.lastValue = value;\n effect.hasValue = true;\n}\n\nfunction flushLaneEffects(lane: SchedulerLane): void {\n hasPendingLaneFlush[lane] = false;\n\n const effects = dirtyEffectsByLane[lane];\n if (effects.size === 0) {\n return;\n }\n\n const pending = effects.values();\n let next = pending.next();\n\n while (!next.done) {\n const effect = next.value as FineGrainedEffect<unknown>;\n effects.delete(effect);\n if (!effect.isActive) {\n next = pending.next();\n continue;\n }\n\n try {\n const { value, nextSources } = evaluateEffect(effect);\n commitEffectResult(effect, value, nextSources);\n } catch (error) {\n effect.onError?.(error);\n }\n\n next = pending.next();\n }\n}\n\nfunction scheduleLaneFlush(lane: SchedulerLane): void {\n if (hasPendingLaneFlush[lane]) {\n return;\n }\n\n hasPendingLaneFlush[lane] = true;\n globalScheduler.enqueueInLane(lane, LANE_FLUSH_TASKS[lane]);\n}\n\nfunction unscheduleEffect(effect: FineGrainedEffect<unknown>): void {\n dirtyEffectsByLane[effect.lane].delete(effect);\n}\n\nfunction recomputeEffectNow<T>(effect: FineGrainedEffect<T>): void {\n const { value, nextSources } = evaluateEffect(effect);\n commitEffectResult(effect, value, nextSources);\n}\n\nexport function markFineGrainedEffectsDirtySource(\n source: ReadableSource<unknown>\n): void {\n const effects = effectSources.get(source);\n if (!effects || effects.size === 0) {\n return;\n }\n\n dirtyLaneState.derived = false;\n dirtyLaneState.component = false;\n dirtyLaneState.reactive = false;\n dirtyLaneState.post = false;\n\n for (const effect of effects) {\n if (!effect.isActive) {\n continue;\n }\n const lane = effect.lane;\n dirtyEffectsByLane[lane].add(effect);\n dirtyLaneState[lane] = true;\n }\n\n if (dirtyLaneState.derived) {\n scheduleLaneFlush('derived');\n }\n if (dirtyLaneState.component) {\n scheduleLaneFlush('component');\n }\n if (dirtyLaneState.reactive) {\n scheduleLaneFlush('reactive');\n }\n if (dirtyLaneState.post) {\n scheduleLaneFlush('post');\n }\n}\n\nexport function createFineGrainedEffect<T>(\n options: CreateFineGrainedEffectOptions<T>\n): FineGrainedEffectHandle<T> {\n const effect: FineGrainedEffect<T> = {\n lane: options.lane,\n compute: options.compute,\n commit: options.commit,\n equals: options.equals ?? Object.is,\n readSources: new Set(),\n isActive: true,\n hasValue: false,\n lastValue: undefined,\n onError: options.onError,\n };\n\n recomputeEffectNow(effect);\n\n return {\n cleanup(): void {\n if (!effect.isActive) {\n return;\n }\n\n effect.isActive = false;\n unscheduleEffect(effect);\n clearEffectSubscriptions(effect);\n },\n\n updateCompute(nextCompute: () => T): void {\n if (!effect.isActive) {\n return;\n }\n\n effect.compute = nextCompute;\n unscheduleEffect(effect);\n recomputeEffectNow(effect);\n },\n\n flush(): void {\n if (!effect.isActive) {\n return;\n }\n\n unscheduleEffect(effect);\n recomputeEffectNow(effect);\n },\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"effect.js","names":[],"sources":["../../src/runtime/effect.ts"],"sourcesContent":["import { incDevCounter } from './dev-namespace';\nimport { type ReadableSource, withFineGrainedReadTracking } from './readable';\nimport { globalScheduler, type SchedulerLane } from './scheduler';\n\ntype EffectRegistry = WeakMap<\n ReadableSource<unknown>,\n Set<FineGrainedEffect<unknown>>\n>;\n\ntype EffectFlushSets = Record<SchedulerLane, Set<FineGrainedEffect<unknown>>>;\n\ntype EffectPendingFlushState = Record<SchedulerLane, boolean>;\ntype EffectLaneDirtyState = Record<SchedulerLane, boolean>;\n\nconst effectSources: EffectRegistry = new WeakMap();\nconst dirtyEffectsByLane: EffectFlushSets = {\n derived: new Set(),\n component: new Set(),\n reactive: new Set(),\n post: new Set(),\n};\nconst hasPendingLaneFlush: EffectPendingFlushState = {\n derived: false,\n component: false,\n reactive: false,\n post: false,\n};\n\nconst dirtyLaneState: EffectLaneDirtyState = {\n derived: false,\n component: false,\n reactive: false,\n post: false,\n};\n\nconst MAX_EFFECT_RUNS_PER_FLUSH = 50;\nconst LANE_FLUSH_TASKS: Record<SchedulerLane, () => void> = {\n derived: () => flushLaneEffects('derived'),\n component: () => flushLaneEffects('component'),\n reactive: () => flushLaneEffects('reactive'),\n post: () => flushLaneEffects('post'),\n};\n\nexport interface FineGrainedEffect<T> {\n lane: SchedulerLane;\n compute(): T;\n commit(value: T, previousValue: T | undefined): void;\n equals(previousValue: T, nextValue: T): boolean;\n readSources: Set<ReadableSource<unknown>>;\n isActive: boolean;\n hasValue: boolean;\n lastValue: T | undefined;\n onError?(error: unknown): void;\n}\n\nexport interface FineGrainedEffectHandle<T> {\n cleanup(): void;\n updateCompute(nextCompute: () => T): void;\n flush(): void;\n}\n\nexport interface CreateFineGrainedEffectOptions<T> {\n lane: SchedulerLane;\n compute: () => T;\n commit: (value: T, previousValue: T | undefined) => void;\n equals?: (previousValue: T, nextValue: T) => boolean;\n onError?: (error: unknown) => void;\n}\n\nfunction registerEffectSource(\n source: ReadableSource<unknown>,\n effect: FineGrainedEffect<unknown>\n): void {\n let effects = effectSources.get(source);\n if (!effects) {\n effects = new Set();\n effectSources.set(source, effects);\n }\n effects.add(effect);\n}\n\nfunction unregisterEffectSource(\n source: ReadableSource<unknown>,\n effect: FineGrainedEffect<unknown>\n): void {\n effectSources.get(source)?.delete(effect);\n}\n\nfunction clearEffectSubscriptions(effect: FineGrainedEffect<unknown>): void {\n for (const source of effect.readSources) {\n unregisterEffectSource(source, effect);\n }\n effect.readSources.clear();\n}\n\nfunction normalizeNextSources(\n previousSources: Set<ReadableSource<unknown>>,\n pendingSources: Set<ReadableSource<unknown>>\n): Set<ReadableSource<unknown>> {\n if (previousSources.size === pendingSources.size) {\n let same = true;\n for (const source of previousSources) {\n if (!pendingSources.has(source)) {\n same = false;\n break;\n }\n }\n\n if (same) {\n return previousSources;\n }\n }\n\n return new Set(pendingSources);\n}\n\nfunction evaluateEffect<T>(effect: FineGrainedEffect<T>): {\n value: T;\n nextSources: Set<ReadableSource<unknown>>;\n} {\n const pendingSources = new Set<ReadableSource<unknown>>();\n\n incDevCounter('effectRuns');\n const value = withFineGrainedReadTracking(pendingSources, () =>\n effect.compute()\n );\n const nextSources = normalizeNextSources(effect.readSources, pendingSources);\n return { value, nextSources };\n}\n\nfunction commitEffectSubscriptions(\n effect: FineGrainedEffect<unknown>,\n nextSources: Set<ReadableSource<unknown>>\n): void {\n const previousSources = effect.readSources;\n\n if (previousSources === nextSources) {\n return;\n }\n\n for (const source of previousSources) {\n if (!nextSources.has(source)) {\n unregisterEffectSource(source, effect);\n }\n }\n\n for (const source of nextSources) {\n if (!previousSources.has(source)) {\n registerEffectSource(source, effect);\n }\n }\n\n effect.readSources = nextSources;\n}\n\nfunction commitEffectResult<T>(\n effect: FineGrainedEffect<T>,\n value: T,\n nextSources: Set<ReadableSource<unknown>>\n): void {\n const previousValue = effect.lastValue;\n const shouldCommit =\n !effect.hasValue || !effect.equals(previousValue as T, value);\n\n if (shouldCommit) {\n effect.commit(value, effect.hasValue ? previousValue : undefined);\n }\n\n commitEffectSubscriptions(effect, nextSources);\n effect.lastValue = value;\n effect.hasValue = true;\n}\n\nfunction flushLaneEffects(lane: SchedulerLane): void {\n hasPendingLaneFlush[lane] = false;\n\n const effects = dirtyEffectsByLane[lane];\n if (effects.size === 0) {\n return;\n }\n\n const pending = effects.values();\n const effectRuns = new Map<FineGrainedEffect<unknown>, number>();\n let next = pending.next();\n\n while (!next.done) {\n const effect = next.value as FineGrainedEffect<unknown>;\n effects.delete(effect);\n if (!effect.isActive) {\n next = pending.next();\n continue;\n }\n\n const runCount = (effectRuns.get(effect) ?? 0) + 1;\n effectRuns.set(effect, runCount);\n if (runCount > MAX_EFFECT_RUNS_PER_FLUSH) {\n const error = new Error(\n `[Askr] fine-grained effect exceeded ${MAX_EFFECT_RUNS_PER_FLUSH} runs in one flush. Likely reactive cycle.`\n );\n if (effect.onError) {\n effect.onError(error);\n } else {\n throw error;\n }\n next = pending.next();\n continue;\n }\n\n try {\n const { value, nextSources } = evaluateEffect(effect);\n commitEffectResult(effect, value, nextSources);\n } catch (error) {\n effect.onError?.(error);\n }\n\n next = pending.next();\n }\n}\n\nfunction scheduleLaneFlush(lane: SchedulerLane): void {\n if (hasPendingLaneFlush[lane]) {\n return;\n }\n\n hasPendingLaneFlush[lane] = true;\n globalScheduler.enqueueInLane(lane, LANE_FLUSH_TASKS[lane]);\n}\n\nfunction unscheduleEffect(effect: FineGrainedEffect<unknown>): void {\n dirtyEffectsByLane[effect.lane].delete(effect);\n}\n\nfunction recomputeEffectNow<T>(effect: FineGrainedEffect<T>): void {\n const { value, nextSources } = evaluateEffect(effect);\n commitEffectResult(effect, value, nextSources);\n}\n\nexport function markFineGrainedEffectsDirtySource(\n source: ReadableSource<unknown>\n): void {\n const effects = effectSources.get(source);\n if (!effects || effects.size === 0) {\n return;\n }\n\n dirtyLaneState.derived = false;\n dirtyLaneState.component = false;\n dirtyLaneState.reactive = false;\n dirtyLaneState.post = false;\n\n for (const effect of effects) {\n if (!effect.isActive) {\n continue;\n }\n const lane = effect.lane;\n dirtyEffectsByLane[lane].add(effect);\n dirtyLaneState[lane] = true;\n }\n\n if (dirtyLaneState.derived) {\n scheduleLaneFlush('derived');\n }\n if (dirtyLaneState.component) {\n scheduleLaneFlush('component');\n }\n if (dirtyLaneState.reactive) {\n scheduleLaneFlush('reactive');\n }\n if (dirtyLaneState.post) {\n scheduleLaneFlush('post');\n }\n}\n\nexport function createFineGrainedEffect<T>(\n options: CreateFineGrainedEffectOptions<T>\n): FineGrainedEffectHandle<T> {\n const effect: FineGrainedEffect<T> = {\n lane: options.lane,\n compute: options.compute,\n commit: options.commit,\n equals: options.equals ?? Object.is,\n readSources: new Set(),\n isActive: true,\n hasValue: false,\n lastValue: undefined,\n onError: options.onError,\n };\n\n recomputeEffectNow(effect);\n\n return {\n cleanup(): void {\n if (!effect.isActive) {\n return;\n }\n\n effect.isActive = false;\n unscheduleEffect(effect);\n clearEffectSubscriptions(effect);\n },\n\n updateCompute(nextCompute: () => T): void {\n if (!effect.isActive) {\n return;\n }\n\n effect.compute = nextCompute;\n unscheduleEffect(effect);\n recomputeEffectNow(effect);\n },\n\n flush(): void {\n if (!effect.isActive) {\n return;\n }\n\n unscheduleEffect(effect);\n recomputeEffectNow(effect);\n },\n };\n}\n"],"mappings":"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"}
@@ -39,14 +39,42 @@ const DELEGATED_EVENTS = [
39
39
  const delegatedHandlers = /* @__PURE__ */ new WeakMap();
40
40
  let eventDelegationEnabled = true;
41
41
  const containerDelegatedListeners = /* @__PURE__ */ new Map();
42
+ const containerDelegatedListenerUsage = /* @__PURE__ */ new Map();
42
43
  function isEventDelegationEnabled() {
43
44
  return eventDelegationEnabled;
44
45
  }
46
+ function incrementContainerListenerUsage(container, eventName) {
47
+ let usage = containerDelegatedListenerUsage.get(container);
48
+ if (!usage) {
49
+ usage = /* @__PURE__ */ new Map();
50
+ containerDelegatedListenerUsage.set(container, usage);
51
+ }
52
+ usage.set(eventName, (usage.get(eventName) ?? 0) + 1);
53
+ }
54
+ function decrementContainerListenerUsage(entry) {
55
+ const usage = containerDelegatedListenerUsage.get(entry.container);
56
+ if (!usage) return;
57
+ const nextCount = (usage.get(entry.eventName) ?? 0) - 1;
58
+ if (nextCount > 0) {
59
+ usage.set(entry.eventName, nextCount);
60
+ return;
61
+ }
62
+ usage.delete(entry.eventName);
63
+ const listeners = containerDelegatedListeners.get(entry.container);
64
+ const listener = listeners?.get(entry.eventName);
65
+ if (listener) {
66
+ entry.container.removeEventListener(entry.eventName, listener);
67
+ listeners?.delete(entry.eventName);
68
+ }
69
+ if (listeners?.size === 0) containerDelegatedListeners.delete(entry.container);
70
+ if (usage.size === 0) containerDelegatedListenerUsage.delete(entry.container);
71
+ }
45
72
  function getDelegationContainer() {
46
73
  if (typeof document !== "undefined") return document.body;
47
74
  return null;
48
75
  }
49
76
  function attachDelegatedListener(container, element, eventName, handler, originalHandler, options) {
77
+ const hadHandler = !!getDelegatedHandlerForElement(element, eventName);
50
78
  if (!containerDelegatedListeners.has(container)) containerDelegatedListeners.set(container, /* @__PURE__ */ new Map());
51
79
  const containerListeners = containerDelegatedListeners.get(container);
52
80
  if (!containerListeners.has(eventName)) {
@@ -77,9 +105,11 @@ function attachDelegatedListener(container, element, eventName, handler, origina
77
105
  handler,
78
106
  original: originalHandler,
79
107
  element,
108
+ container,
80
109
  eventName,
81
110
  options
82
111
  });
112
+ if (!hadHandler) incrementContainerListenerUsage(container, eventName);
83
113
  }
84
114
  function setDelegatedHandlerForElement(element, entry) {
85
115
  const existing = delegatedHandlers.get(element);
@@ -112,6 +142,11 @@ function addDelegatedListener(element, eventName, handler, originalHandler, opti
112
142
  function updateDelegatedListener(element, eventName, handler, originalHandler, options) {
113
143
  const existing = getDelegatedHandlerForElement(element, eventName);
114
144
  if (!existing) return false;
145
+ const container = getDelegationContainer();
146
+ if (!container || existing.container !== container || !containerDelegatedListeners.get(existing.container)?.has(eventName)) {
147
+ removeDelegatedListener(element, eventName);
148
+ return false;
149
+ }
115
150
  existing.handler = handler;
116
151
  existing.original = originalHandler;
117
152
  existing.options = options;
@@ -121,7 +156,10 @@ function removeDelegatedListener(element, eventName) {
121
156
  const existing = delegatedHandlers.get(element);
122
157
  if (!existing) return;
123
158
  if (existing instanceof Map) {
124
- if (existing.has(eventName)) incDevCounter("listenerRemoves");
159
+ if (existing.has(eventName)) {
160
+ incDevCounter("listenerRemoves");
161
+ decrementContainerListenerUsage(existing.get(eventName));
162
+ }
125
163
  existing.delete(eventName);
126
164
  if (existing.size === 0) {
127
165
  delegatedHandlers.delete(element);
@@ -135,6 +173,7 @@ function removeDelegatedListener(element, eventName) {
135
173
  }
136
174
  if (existing.eventName === eventName) {
137
175
  incDevCounter("listenerRemoves");
176
+ decrementContainerListenerUsage(existing);
138
177
  delegatedHandlers.delete(element);
139
178
  }
140
179
  }
@@ -151,6 +190,9 @@ function getDelegatedHandlersForElement(element) {
151
190
  return new Map([[store.eventName, store]]);
152
191
  }
153
192
  function clearDelegatedHandlersForElement(element) {
193
+ const existing = delegatedHandlers.get(element);
194
+ if (existing instanceof Map) for (const entry of existing.values()) decrementContainerListenerUsage(entry);
195
+ else if (existing) decrementContainerListenerUsage(existing);
154
196
  delegatedHandlers.delete(element);
155
197
  }
156
198
  function isDelegatedEvent(eventName) {
@@ -1 +1 @@
1
- {"version":3,"file":"events.js","names":[],"sources":["../../src/runtime/events.ts"],"sourcesContent":["/**\n * Event delegation system for Askr\n *\n * Provides efficient event handling by attaching listeners to a container\n * instead of individual elements. This significantly reduces memory usage\n * and improves performance when many elements have the same event type.\n *\n * Delegated handling is enabled by default. Tests and internal runtime code\n * can still disable or re-enable it when they need to exercise both modes.\n */\n\nimport { globalScheduler } from './scheduler';\nimport { logger } from '../dev/logger';\nimport { incrementPerfMetric } from './perf-metrics';\nimport { incDevCounter } from './dev-namespace';\n\nexport interface DelegatedEventMap {\n click: MouseEvent;\n dblclick: MouseEvent;\n mousedown: MouseEvent;\n mouseup: MouseEvent;\n mouseover: MouseEvent;\n mouseout: MouseEvent;\n mousemove: MouseEvent;\n focus: FocusEvent;\n blur: FocusEvent;\n input: InputEvent;\n change: Event;\n keydown: KeyboardEvent;\n keyup: KeyboardEvent;\n keypress: KeyboardEvent;\n submit: Event;\n scroll: Event;\n wheel: WheelEvent;\n touchstart: TouchEvent;\n touchend: TouchEvent;\n touchmove: TouchEvent;\n touchcancel: TouchEvent;\n}\n\nconst DELEGATED_EVENTS: (keyof DelegatedEventMap)[] = [\n 'click',\n 'dblclick',\n 'mousedown',\n 'mouseup',\n 'mouseover',\n 'mouseout',\n 'mousemove',\n 'focus',\n 'blur',\n 'input',\n 'change',\n 'keydown',\n 'keyup',\n 'keypress',\n 'submit',\n 'scroll',\n 'wheel',\n 'touchstart',\n 'touchend',\n 'touchmove',\n 'touchcancel',\n];\n\ninterface DelegatedHandler {\n handler: EventListener;\n original: EventListener;\n element: Element;\n eventName: string;\n options?: AddEventListenerOptions;\n}\n\ntype DelegatedHandlerStore = DelegatedHandler | Map<string, DelegatedHandler>;\n\nconst delegatedHandlers = new WeakMap<Element, DelegatedHandlerStore>();\n\nlet eventDelegationEnabled = true;\nlet defaultContainer: Element | null = null;\nlet globalDelegationContainer: Element | null = null;\nconst containerDelegatedListeners = new Map<\n Element,\n Map<string, EventListener>\n>();\n\nexport function isEventDelegationEnabled(): boolean {\n return eventDelegationEnabled;\n}\n\nexport function disableEventDelegation(): void {\n eventDelegationEnabled = false;\n cleanupAllDelegatedListeners();\n}\n\nexport function enableEventDelegation(container?: Element): void {\n eventDelegationEnabled = true;\n if (container) {\n defaultContainer = container;\n }\n}\n\nexport function setGlobalDelegationContainer(container: Element): void {\n globalDelegationContainer = container;\n}\n\nfunction cleanupAllDelegatedListeners(): void {\n for (const [container, listeners] of containerDelegatedListeners) {\n for (const [eventName, handler] of listeners) {\n container.removeEventListener(eventName, handler);\n }\n }\n containerDelegatedListeners.clear();\n}\n\nfunction getDelegationContainer(): Element | null {\n if (globalDelegationContainer) return globalDelegationContainer;\n if (defaultContainer) return defaultContainer;\n if (typeof document !== 'undefined') return document.body;\n return null;\n}\n\nfunction attachDelegatedListener(\n container: Element,\n element: Element,\n eventName: string,\n handler: EventListener,\n originalHandler: EventListener,\n options?: AddEventListenerOptions\n): void {\n if (!containerDelegatedListeners.has(container)) {\n containerDelegatedListeners.set(container, new Map());\n }\n const containerListeners = containerDelegatedListeners.get(container)!;\n\n if (!containerListeners.has(eventName)) {\n const delegatedHandler = (e: Event) => {\n const target = e.target as Element;\n if (!target) return;\n\n globalScheduler.runInHandlerScope(() => {\n let current: Element | null = target;\n while (current && current !== container) {\n incrementPerfMetric('delegatedAncestorHops');\n const store = delegatedHandlers.get(current);\n const entry = !store\n ? undefined\n : store instanceof Map\n ? store.get(eventName)\n : store.eventName === eventName\n ? store\n : undefined;\n if (entry) {\n try {\n entry.handler(e);\n } catch (error) {\n logger.error('[Askr] Delegated event error:', error);\n }\n }\n\n if (e.cancelBubble) {\n break;\n }\n\n current = current.parentElement;\n }\n }, 'sync');\n };\n\n const passiveOptions = getPassiveOptions(eventName);\n const listenerOptions = passiveOptions ?? options;\n\n container.addEventListener(eventName, delegatedHandler, listenerOptions);\n containerListeners.set(eventName, delegatedHandler);\n }\n\n setDelegatedHandlerForElement(element, {\n handler,\n original: originalHandler,\n element,\n eventName,\n options,\n });\n}\n\nfunction setDelegatedHandlerForElement(\n element: Element,\n entry: DelegatedHandler\n): void {\n const existing = delegatedHandlers.get(element);\n if (!existing) {\n delegatedHandlers.set(element, entry);\n return;\n }\n\n if (existing instanceof Map) {\n existing.set(entry.eventName, entry);\n return;\n }\n\n if (existing.eventName === entry.eventName) {\n delegatedHandlers.set(element, entry);\n return;\n }\n\n const next = new Map<string, DelegatedHandler>();\n next.set(existing.eventName, existing);\n next.set(entry.eventName, entry);\n delegatedHandlers.set(element, next);\n}\n\nfunction getPassiveOptions(\n eventName: string\n): AddEventListenerOptions | undefined {\n if (\n eventName === 'wheel' ||\n eventName === 'scroll' ||\n eventName.startsWith('touch')\n ) {\n return { passive: true };\n }\n return undefined;\n}\n\nexport function addDelegatedListener(\n element: Element,\n eventName: string,\n handler: EventListener,\n originalHandler: EventListener,\n options?: AddEventListenerOptions\n): void {\n if (!eventDelegationEnabled) return;\n\n const container = getDelegationContainer();\n if (!container) return;\n\n incDevCounter('listenerAdds');\n\n attachDelegatedListener(\n container,\n element,\n eventName,\n handler,\n originalHandler,\n options\n );\n}\n\nexport function updateDelegatedListener(\n element: Element,\n eventName: string,\n handler: EventListener,\n originalHandler: EventListener,\n options?: AddEventListenerOptions\n): boolean {\n const existing = getDelegatedHandlerForElement(element, eventName);\n if (!existing) {\n return false;\n }\n\n existing.handler = handler;\n existing.original = originalHandler;\n existing.options = options;\n return true;\n}\n\nexport function removeDelegatedListener(\n element: Element,\n eventName: string\n): void {\n const existing = delegatedHandlers.get(element);\n if (!existing) {\n return;\n }\n\n if (existing instanceof Map) {\n if (existing.has(eventName)) {\n incDevCounter('listenerRemoves');\n }\n existing.delete(eventName);\n if (existing.size === 0) {\n delegatedHandlers.delete(element);\n return;\n }\n if (existing.size === 1) {\n const only = existing.values().next().value as DelegatedHandler;\n delegatedHandlers.set(element, only);\n }\n return;\n }\n\n if (existing.eventName === eventName) {\n incDevCounter('listenerRemoves');\n delegatedHandlers.delete(element);\n }\n}\n\nexport function getDelegatedHandlerForElement(\n element: Element,\n eventName: string\n): DelegatedHandler | undefined {\n const store = delegatedHandlers.get(element);\n if (!store) return undefined;\n if (store instanceof Map) return store.get(eventName);\n return store.eventName === eventName ? store : undefined;\n}\n\nexport function getDelegatedHandlersForElement(\n element: Element\n): Map<string, DelegatedHandler> | undefined {\n const store = delegatedHandlers.get(element);\n if (!store) return undefined;\n if (store instanceof Map) return store;\n return new Map([[store.eventName, store]]);\n}\n\nexport function hasDelegatedHandler(\n element: Element,\n eventName: string\n): boolean {\n return getDelegatedHandlerForElement(element, eventName) !== undefined;\n}\n\nexport function clearDelegatedHandlersForElement(element: Element): void {\n delegatedHandlers.delete(element);\n}\n\nexport function getDelegatedEventNames(): readonly (keyof DelegatedEventMap)[] {\n return DELEGATED_EVENTS;\n}\n\nexport function isDelegatedEvent(eventName: string): boolean {\n return DELEGATED_EVENTS.includes(eventName as keyof DelegatedEventMap);\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"events.js","names":[],"sources":["../../src/runtime/events.ts"],"sourcesContent":["/**\n * Event delegation system for Askr\n *\n * Provides efficient event handling by attaching listeners to a container\n * instead of individual elements. This significantly reduces memory usage\n * and improves performance when many elements have the same event type.\n *\n * Delegated handling is enabled by default. Tests and internal runtime code\n * can still disable or re-enable it when they need to exercise both modes.\n */\n\nimport { globalScheduler } from './scheduler';\nimport { logger } from '../dev/logger';\nimport { incrementPerfMetric } from './perf-metrics';\nimport { incDevCounter } from './dev-namespace';\n\nexport interface DelegatedEventMap {\n click: MouseEvent;\n dblclick: MouseEvent;\n mousedown: MouseEvent;\n mouseup: MouseEvent;\n mouseover: MouseEvent;\n mouseout: MouseEvent;\n mousemove: MouseEvent;\n focus: FocusEvent;\n blur: FocusEvent;\n input: InputEvent;\n change: Event;\n keydown: KeyboardEvent;\n keyup: KeyboardEvent;\n keypress: KeyboardEvent;\n submit: Event;\n scroll: Event;\n wheel: WheelEvent;\n touchstart: TouchEvent;\n touchend: TouchEvent;\n touchmove: TouchEvent;\n touchcancel: TouchEvent;\n}\n\nconst DELEGATED_EVENTS: (keyof DelegatedEventMap)[] = [\n 'click',\n 'dblclick',\n 'mousedown',\n 'mouseup',\n 'mouseover',\n 'mouseout',\n 'mousemove',\n 'focus',\n 'blur',\n 'input',\n 'change',\n 'keydown',\n 'keyup',\n 'keypress',\n 'submit',\n 'scroll',\n 'wheel',\n 'touchstart',\n 'touchend',\n 'touchmove',\n 'touchcancel',\n];\n\ninterface DelegatedHandler {\n handler: EventListener;\n original: EventListener;\n element: Element;\n container: Element;\n eventName: string;\n options?: AddEventListenerOptions;\n}\n\ntype DelegatedHandlerStore = DelegatedHandler | Map<string, DelegatedHandler>;\n\nconst delegatedHandlers = new WeakMap<Element, DelegatedHandlerStore>();\n\nlet eventDelegationEnabled = true;\nlet defaultContainer: Element | null = null;\nlet globalDelegationContainer: Element | null = null;\nconst containerDelegatedListeners = new Map<\n Element,\n Map<string, EventListener>\n>();\nconst containerDelegatedListenerUsage = new Map<Element, Map<string, number>>();\n\nexport function isEventDelegationEnabled(): boolean {\n return eventDelegationEnabled;\n}\n\nexport function disableEventDelegation(): void {\n eventDelegationEnabled = false;\n cleanupAllDelegatedListeners();\n}\n\nexport function enableEventDelegation(container?: Element): void {\n eventDelegationEnabled = true;\n if (container) {\n defaultContainer = container;\n }\n}\n\nexport function setGlobalDelegationContainer(container: Element): void {\n globalDelegationContainer = container;\n}\n\nfunction cleanupAllDelegatedListeners(): void {\n for (const [container, listeners] of containerDelegatedListeners) {\n for (const [eventName, handler] of listeners) {\n container.removeEventListener(eventName, handler);\n }\n }\n containerDelegatedListeners.clear();\n containerDelegatedListenerUsage.clear();\n}\n\nfunction incrementContainerListenerUsage(\n container: Element,\n eventName: string\n): void {\n let usage = containerDelegatedListenerUsage.get(container);\n if (!usage) {\n usage = new Map();\n containerDelegatedListenerUsage.set(container, usage);\n }\n usage.set(eventName, (usage.get(eventName) ?? 0) + 1);\n}\n\nfunction decrementContainerListenerUsage(entry: DelegatedHandler): void {\n const usage = containerDelegatedListenerUsage.get(entry.container);\n if (!usage) {\n return;\n }\n\n const nextCount = (usage.get(entry.eventName) ?? 0) - 1;\n if (nextCount > 0) {\n usage.set(entry.eventName, nextCount);\n return;\n }\n\n usage.delete(entry.eventName);\n const listeners = containerDelegatedListeners.get(entry.container);\n const listener = listeners?.get(entry.eventName);\n if (listener) {\n entry.container.removeEventListener(entry.eventName, listener);\n listeners?.delete(entry.eventName);\n }\n\n if (listeners?.size === 0) {\n containerDelegatedListeners.delete(entry.container);\n }\n if (usage.size === 0) {\n containerDelegatedListenerUsage.delete(entry.container);\n }\n}\n\nfunction getDelegationContainer(): Element | null {\n if (globalDelegationContainer) return globalDelegationContainer;\n if (defaultContainer) return defaultContainer;\n if (typeof document !== 'undefined') return document.body;\n return null;\n}\n\nfunction attachDelegatedListener(\n container: Element,\n element: Element,\n eventName: string,\n handler: EventListener,\n originalHandler: EventListener,\n options?: AddEventListenerOptions\n): void {\n const hadHandler = !!getDelegatedHandlerForElement(element, eventName);\n\n if (!containerDelegatedListeners.has(container)) {\n containerDelegatedListeners.set(container, new Map());\n }\n const containerListeners = containerDelegatedListeners.get(container)!;\n\n if (!containerListeners.has(eventName)) {\n const delegatedHandler = (e: Event) => {\n const target = e.target as Element;\n if (!target) return;\n\n globalScheduler.runInHandlerScope(() => {\n let current: Element | null = target;\n while (current && current !== container) {\n incrementPerfMetric('delegatedAncestorHops');\n const store = delegatedHandlers.get(current);\n const entry = !store\n ? undefined\n : store instanceof Map\n ? store.get(eventName)\n : store.eventName === eventName\n ? store\n : undefined;\n if (entry) {\n try {\n entry.handler(e);\n } catch (error) {\n logger.error('[Askr] Delegated event error:', error);\n }\n }\n\n if (e.cancelBubble) {\n break;\n }\n\n current = current.parentElement;\n }\n }, 'sync');\n };\n\n const passiveOptions = getPassiveOptions(eventName);\n const listenerOptions = passiveOptions ?? options;\n\n container.addEventListener(eventName, delegatedHandler, listenerOptions);\n containerListeners.set(eventName, delegatedHandler);\n }\n\n setDelegatedHandlerForElement(element, {\n handler,\n original: originalHandler,\n element,\n container,\n eventName,\n options,\n });\n if (!hadHandler) {\n incrementContainerListenerUsage(container, eventName);\n }\n}\n\nfunction setDelegatedHandlerForElement(\n element: Element,\n entry: DelegatedHandler\n): void {\n const existing = delegatedHandlers.get(element);\n if (!existing) {\n delegatedHandlers.set(element, entry);\n return;\n }\n\n if (existing instanceof Map) {\n existing.set(entry.eventName, entry);\n return;\n }\n\n if (existing.eventName === entry.eventName) {\n delegatedHandlers.set(element, entry);\n return;\n }\n\n const next = new Map<string, DelegatedHandler>();\n next.set(existing.eventName, existing);\n next.set(entry.eventName, entry);\n delegatedHandlers.set(element, next);\n}\n\nfunction getPassiveOptions(\n eventName: string\n): AddEventListenerOptions | undefined {\n if (\n eventName === 'wheel' ||\n eventName === 'scroll' ||\n eventName.startsWith('touch')\n ) {\n return { passive: true };\n }\n return undefined;\n}\n\nexport function addDelegatedListener(\n element: Element,\n eventName: string,\n handler: EventListener,\n originalHandler: EventListener,\n options?: AddEventListenerOptions\n): void {\n if (!eventDelegationEnabled) return;\n\n const container = getDelegationContainer();\n if (!container) return;\n\n incDevCounter('listenerAdds');\n\n attachDelegatedListener(\n container,\n element,\n eventName,\n handler,\n originalHandler,\n options\n );\n}\n\nexport function updateDelegatedListener(\n element: Element,\n eventName: string,\n handler: EventListener,\n originalHandler: EventListener,\n options?: AddEventListenerOptions\n): boolean {\n const existing = getDelegatedHandlerForElement(element, eventName);\n if (!existing) {\n return false;\n }\n\n const container = getDelegationContainer();\n if (\n !container ||\n existing.container !== container ||\n !containerDelegatedListeners.get(existing.container)?.has(eventName)\n ) {\n removeDelegatedListener(element, eventName);\n return false;\n }\n\n existing.handler = handler;\n existing.original = originalHandler;\n existing.options = options;\n return true;\n}\n\nexport function removeDelegatedListener(\n element: Element,\n eventName: string\n): void {\n const existing = delegatedHandlers.get(element);\n if (!existing) {\n return;\n }\n\n if (existing instanceof Map) {\n if (existing.has(eventName)) {\n incDevCounter('listenerRemoves');\n decrementContainerListenerUsage(existing.get(eventName)!);\n }\n existing.delete(eventName);\n if (existing.size === 0) {\n delegatedHandlers.delete(element);\n return;\n }\n if (existing.size === 1) {\n const only = existing.values().next().value as DelegatedHandler;\n delegatedHandlers.set(element, only);\n }\n return;\n }\n\n if (existing.eventName === eventName) {\n incDevCounter('listenerRemoves');\n decrementContainerListenerUsage(existing);\n delegatedHandlers.delete(element);\n }\n}\n\nexport function getDelegatedHandlerForElement(\n element: Element,\n eventName: string\n): DelegatedHandler | undefined {\n const store = delegatedHandlers.get(element);\n if (!store) return undefined;\n if (store instanceof Map) return store.get(eventName);\n return store.eventName === eventName ? store : undefined;\n}\n\nexport function getDelegatedHandlersForElement(\n element: Element\n): Map<string, DelegatedHandler> | undefined {\n const store = delegatedHandlers.get(element);\n if (!store) return undefined;\n if (store instanceof Map) return store;\n return new Map([[store.eventName, store]]);\n}\n\nexport function hasDelegatedHandler(\n element: Element,\n eventName: string\n): boolean {\n return getDelegatedHandlerForElement(element, eventName) !== undefined;\n}\n\nexport function clearDelegatedHandlersForElement(element: Element): void {\n const existing = delegatedHandlers.get(element);\n if (existing instanceof Map) {\n for (const entry of existing.values()) {\n decrementContainerListenerUsage(entry);\n }\n } else if (existing) {\n decrementContainerListenerUsage(existing);\n }\n delegatedHandlers.delete(element);\n}\n\nexport function getDelegatedEventNames(): readonly (keyof DelegatedEventMap)[] {\n return DELEGATED_EVENTS;\n}\n\nexport function isDelegatedEvent(eventName: string): boolean {\n return DELEGATED_EVENTS.includes(eventName as keyof DelegatedEventMap);\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"execution-model.js","names":[],"sources":["../../src/runtime/execution-model.ts"],"sourcesContent":["export type ExecutionModel = 'spa' | 'islands' | 'ssr';\n\nconst EXECUTION_MODEL_KEY = Symbol.for('__ASKR_EXECUTION_MODEL__');\n\nexport function getExecutionModel(): ExecutionModel | undefined {\n const g = globalThis as unknown as Record<string | symbol, unknown>;\n return g[EXECUTION_MODEL_KEY] as ExecutionModel | undefined;\n}\n\nexport function assertExecutionModel(model: ExecutionModel): void {\n // Mixing execution models is forbidden: once an app starts in one model,\n // attempting to start another is an invariant violation.\n const g = globalThis as unknown as Record<string | symbol, unknown>;\n const cur = g[EXECUTION_MODEL_KEY] as ExecutionModel | undefined;\n if (cur && cur !== model) {\n throw new Error(\n `[Askr] mixing execution models is not allowed (current: ${cur}, attempted: ${model}). ` +\n `Choose exactly one: createSPA, createSSR, or createIslands.`\n );\n }\n if (!cur) g[EXECUTION_MODEL_KEY] = model;\n}\n"],"mappings":";AAEA,MAAM,sBAAsB,OAAO,IAAI,2BAA2B;AAElE,SAAgB,oBAAgD;CAE9D,OAAO,WAAE;;AAGX,SAAgB,qBAAqB,OAA6B;CAGhE,MAAM,IAAI;CACV,MAAM,MAAM,EAAE;CACd,IAAI,OAAO,QAAQ,OACjB,MAAM,IAAI,MACR,2DAA2D,IAAI,eAAe,MAAM,gEAErF;CAEH,IAAI,CAAC,KAAK,EAAE,uBAAuB"}
1
+ {"version":3,"file":"execution-model.js","names":[],"sources":["../../src/runtime/execution-model.ts"],"sourcesContent":["export type ExecutionModel = 'spa' | 'islands' | 'ssr';\n\nconst EXECUTION_MODEL_KEY = Symbol.for('__ASKR_EXECUTION_MODEL__');\n\nexport function getExecutionModel(): ExecutionModel | undefined {\n const g = globalThis as unknown as Record<string | symbol, unknown>;\n return g[EXECUTION_MODEL_KEY] as ExecutionModel | undefined;\n}\n\nexport function assertExecutionModel(model: ExecutionModel): void {\n // Mixing execution models is forbidden: once an app starts in one model,\n // attempting to start another is an invariant violation.\n const g = globalThis as unknown as Record<string | symbol, unknown>;\n const cur = g[EXECUTION_MODEL_KEY] as ExecutionModel | undefined;\n if (cur && cur !== model) {\n throw new Error(\n `[Askr] mixing execution models is not allowed (current: ${cur}, attempted: ${model}). ` +\n `Choose exactly one: createSPA, createSSR, or createIslands.`\n );\n }\n if (!cur) g[EXECUTION_MODEL_KEY] = model;\n}\n"],"mappings":";AAEA,MAAM,sBAAsB,OAAO,IAAI,0BAA0B;AAEjE,SAAgB,oBAAgD;CAE9D,OAAO,WAAE;AACX;AAEA,SAAgB,qBAAqB,OAA6B;CAGhE,MAAM,IAAI;CACV,MAAM,MAAM,EAAE;CACd,IAAI,OAAO,QAAQ,OACjB,MAAM,IAAI,MACR,2DAA2D,IAAI,eAAe,MAAM,+DAEtF;CAEF,IAAI,CAAC,KAAK,EAAE,uBAAuB;AACrC"}
@@ -11,11 +11,7 @@ let _appliedParents = null;
11
11
  function enterBulkCommit() {
12
12
  _bulkCommitActive = true;
13
13
  _appliedParents = /* @__PURE__ */ new WeakSet();
14
- try {
15
- setDevValue("__ASKR_FASTLANE_CLEARED_TASKS", globalScheduler.clearPendingSyncTasks?.() ?? 0);
16
- } catch (err) {
17
- if (isDevelopmentEnvironment()) throw err;
18
- }
14
+ setDevValue("__ASKR_FASTLANE_CLEARED_TASKS", 0);
19
15
  }
20
16
  function exitBulkCommit() {
21
17
  _bulkCommitActive = false;
@@ -128,7 +124,7 @@ function commitReorderOnly(instance, result) {
128
124
  if (isDevelopmentEnvironment()) throw e;
129
125
  }
130
126
  });
131
- setDevValue("__FASTLANE_CLEARED_AFTER", globalScheduler.clearPendingSyncTasks?.() ?? 0);
127
+ setDevValue("__FASTLANE_CLEARED_AFTER", 0);
132
128
  if (isDevelopmentEnvironment()) validateFastLaneInvariants(instance, schedBefore);
133
129
  return true;
134
130
  } finally {
@@ -159,23 +155,6 @@ function validateFastLaneInvariants(instance, schedBefore) {
159
155
  console.error("[FASTLANE] enqueue logs", getDevValue("__ENQUEUE_LOGS"));
160
156
  throw new Error("Fast-lane invariant violated: scheduler enqueued leftover work during bulk commit");
161
157
  }
162
- let finalState = globalScheduler.getState();
163
- const executing = globalScheduler.isExecuting();
164
- let outstandingAfter = Math.max(0, finalState.taskCount - (executing ? 1 : 0));
165
- if (outstandingAfter !== 0) {
166
- let attempts = 0;
167
- while (attempts < 5) {
168
- if ((globalScheduler.clearPendingSyncTasks?.() ?? 0) === 0) break;
169
- attempts++;
170
- }
171
- finalState = globalScheduler.getState();
172
- outstandingAfter = Math.max(0, finalState.taskCount - (globalScheduler.isExecuting() ? 1 : 0));
173
- if (outstandingAfter !== 0) {
174
- console.error("[FASTLANE] Post-commit enqueue logs:", getDevValue("__ENQUEUE_LOGS"));
175
- console.error("[FASTLANE] Cleared counts:", getDevValue("__FASTLANE_CLEARED_TASKS"), getDevValue("__FASTLANE_CLEARED_AFTER"));
176
- throw new Error(`Fast-lane invariant violated: scheduler has ${finalState.taskCount} pending task(s) after commit`);
177
- }
178
- }
179
158
  }
180
159
  function tryRuntimeFastLaneSync(instance, result) {
181
160
  if (!classifyUpdate(instance, result).useFastPath) {
@@ -1 +1 @@
1
- {"version":3,"file":"fastlane.js","names":[],"sources":["../../src/runtime/fastlane.ts"],"sourcesContent":["import { isDevelopmentEnvironment } from '../common/env';\nimport { globalScheduler } from './scheduler';\nimport { logger } from '../dev/logger';\nimport type { ComponentInstance } from './component';\nimport { finalizeReadableSubscriptions } from './readable';\nimport {\n getKeyMapForElement,\n isKeyedReorderFastPathEligible,\n populateKeyMapForElement,\n} from '../renderer/keyed';\nimport { Fragment } from '../common/jsx';\nimport { setDevValue, getDevValue, getDevNamespace } from './dev-namespace';\n\nlet _bulkCommitActive = false;\nlet _appliedParents: WeakSet<Element> | null = null;\n\nexport function enterBulkCommit(): void {\n _bulkCommitActive = true;\n // Initialize registry of parents that had fast-path applied during this bulk commit\n _appliedParents = new WeakSet<Element>();\n\n // Clear any previously scheduled synchronous scheduler tasks so they don't\n // retrigger evaluations during the committed fast-path.\n try {\n const cleared = globalScheduler.clearPendingSyncTasks?.() ?? 0;\n setDevValue('__ASKR_FASTLANE_CLEARED_TASKS', cleared);\n } catch (err) {\n if (isDevelopmentEnvironment()) throw err;\n }\n}\n\nexport function exitBulkCommit(): void {\n _bulkCommitActive = false;\n // Clear registry to avoid leaking across commits\n _appliedParents = null;\n}\n\nexport function isBulkCommitActive(): boolean {\n return _bulkCommitActive;\n}\n\n// Mark that a fast-path was applied on a parent element during the active\n// bulk commit. No-op if there is no active bulk commit.\nexport function markFastPathApplied(parent: Element): void {\n if (!_appliedParents) return;\n try {\n _appliedParents.add(parent);\n } catch (e) {\n void e;\n }\n}\n\nexport function isFastPathApplied(parent: Element): boolean {\n return !!(_appliedParents && _appliedParents.has(parent));\n}\n\nfunction finalizeReadSubscriptions(instance: ComponentInstance): void {\n finalizeReadableSubscriptions(instance);\n}\n\n/**\n * Attempt to execute a runtime fast-lane for a single component's synchronous\n * render result. Returns true if the fast-lane was used and commit was done.\n *\n * Preconditions (checked conservatively):\n * - The render result is an intrinsic element root with keyed children\n * - The renderer's fast-path heuristics indicate to use the fast-path\n * - No mount operations are pending on the component instance\n * - No child vnodes are component functions (avoid async/component mounts)\n */\n\n// Helper to unwrap Fragment vnodes to get the first intrinsic element child\nfunction unwrapFragmentForFastPath(vnode: unknown): unknown {\n if (!vnode || typeof vnode !== 'object' || !('type' in vnode)) return vnode;\n const v = vnode as {\n type: unknown;\n children?: unknown;\n props?: { children?: unknown };\n };\n // Check if it's a Fragment\n if (\n typeof v.type === 'symbol' &&\n (v.type === Fragment || String(v.type) === 'Symbol(askr.fragment)')\n ) {\n const children = v.props?.children ?? v.children;\n if (Array.isArray(children) && children.length > 0) {\n // Return the first child that's an intrinsic element\n for (const child of children) {\n if (child && typeof child === 'object' && 'type' in child) {\n const c = child as { type: unknown };\n if (typeof c.type === 'string') {\n return child;\n }\n }\n }\n }\n }\n return vnode;\n}\n\nexport function classifyUpdate(instance: ComponentInstance, result: unknown) {\n // Returns a classification describing whether this update is eligible for\n // the reorder-only fast-lane. The classifier mirrors renderer-level\n // heuristics and performs runtime-level checks (mounts, effects, component\n // children) that the renderer cannot reason about.\n\n // Unwrap Fragment to get the actual element vnode for classification\n const unwrappedResult = unwrapFragmentForFastPath(result);\n\n if (\n !unwrappedResult ||\n typeof unwrappedResult !== 'object' ||\n !('type' in unwrappedResult)\n )\n return { useFastPath: false, reason: 'not-vnode' };\n\n const vnode = unwrappedResult as {\n type: unknown;\n children?: unknown;\n props?: { children?: unknown };\n };\n if (vnode == null || typeof vnode.type !== 'string')\n return { useFastPath: false, reason: 'not-intrinsic' };\n\n const parent = instance.target;\n if (!parent) return { useFastPath: false, reason: 'no-root' };\n\n const firstChild = parent.children[0] as Element | undefined;\n if (!firstChild) return { useFastPath: false, reason: 'no-first-child' };\n if (firstChild.tagName.toLowerCase() !== String(vnode.type).toLowerCase())\n return { useFastPath: false, reason: 'root-tag-mismatch' };\n\n const children = vnode.props?.children ?? vnode.children;\n if (!Array.isArray(children))\n return { useFastPath: false, reason: 'no-children-array' };\n\n // Avoid component child vnodes (they may mount/unmount or trigger async)\n for (const c of children) {\n if (\n typeof c === 'object' &&\n c !== null &&\n 'type' in c &&\n typeof (c as { type?: unknown }).type === 'function'\n ) {\n return { useFastPath: false, reason: 'component-child-present' };\n }\n }\n\n if ((instance.mountOperations?.length ?? 0) > 0)\n return { useFastPath: false, reason: 'pending-mounts' };\n\n // Ask renderer for keyed reorder eligibility (prop differences & heuristics)\n // Ensure a keyed map is available for the first child by populating it proactively.\n try {\n populateKeyMapForElement(firstChild);\n } catch {\n // ignore\n }\n\n const oldKeyMap = getKeyMapForElement(firstChild);\n const decision = isKeyedReorderFastPathEligible(\n firstChild,\n children,\n oldKeyMap\n );\n\n if (!decision.useFastPath || decision.totalKeyed < 128)\n return { ...decision, useFastPath: false, reason: 'renderer-declined' };\n\n return { ...decision, useFastPath: true } as const;\n}\n\nexport function commitReorderOnly(\n instance: ComponentInstance,\n result: unknown\n): boolean {\n // Performs the minimal, synchronous reorder-only commit.\n const evaluate = (\n globalThis as {\n __ASKR_RENDERER?: {\n evaluate?: (node: unknown, target: Element | null) => void;\n };\n }\n ).__ASKR_RENDERER?.evaluate;\n\n if (typeof evaluate !== 'function') {\n logger.warn(\n '[Tempo][FASTPATH][DEV] renderer.evaluate not available; declining fast-lane'\n );\n return false;\n }\n\n const schedBefore = isDevelopmentEnvironment()\n ? globalScheduler.getState()\n : null;\n\n enterBulkCommit();\n\n try {\n globalScheduler.runWithSyncProgress(() => {\n evaluate(result, instance.target);\n\n // Finalize runtime bookkeeping (read subscriptions / tokens)\n try {\n finalizeReadSubscriptions(instance);\n } catch (e) {\n if (isDevelopmentEnvironment()) throw e;\n }\n });\n\n // Clear any synchronous tasks scheduled during the commit\n const clearedAfter = globalScheduler.clearPendingSyncTasks?.() ?? 0;\n setDevValue('__FASTLANE_CLEARED_AFTER', clearedAfter);\n\n // Dev-only invariant checks\n if (isDevelopmentEnvironment()) {\n validateFastLaneInvariants(instance, schedBefore);\n }\n\n return true;\n } finally {\n // Clear bulk commit flag first\n exitBulkCommit();\n }\n // Note: The original code had a check here that was dead code because\n // exitBulkCommit() already ran in the finally block. This comment serves\n // as documentation that we've intentionally removed that unreachable code.\n}\n\n/**\n * Validates fast-lane invariants in dev mode.\n * Extracted to reduce complexity in commitReorderOnly.\n */\nfunction validateFastLaneInvariants(\n instance: ComponentInstance,\n schedBefore: ReturnType<typeof globalScheduler.getState> | null\n): void {\n const commitCount = getDevValue<number>('__LAST_FASTPATH_COMMIT_COUNT') ?? 0;\n const invariants = {\n commitCount,\n mountOps: instance.mountOperations?.length ?? 0,\n cleanupFns: instance.cleanupFns?.length ?? 0,\n };\n setDevValue('__LAST_FASTLANE_INVARIANTS', invariants);\n\n if (commitCount !== 1) {\n console.error(\n '[FASTLANE][INV] commitCount',\n commitCount,\n 'diag',\n getDevNamespace()\n );\n throw new Error(\n 'Fast-lane invariant violated: expected exactly one DOM commit during reorder-only commit'\n );\n }\n\n if (invariants.mountOps > 0) {\n throw new Error(\n 'Fast-lane invariant violated: mount operations were registered during bulk commit'\n );\n }\n\n if (invariants.cleanupFns > 0) {\n throw new Error(\n 'Fast-lane invariant violated: cleanup functions were added during bulk commit'\n );\n }\n\n const schedAfter = globalScheduler.getState();\n if (\n schedBefore &&\n schedAfter &&\n schedAfter.taskCount > schedBefore.taskCount\n ) {\n console.error(\n '[FASTLANE] schedBefore, schedAfter',\n schedBefore,\n schedAfter\n );\n console.error('[FASTLANE] enqueue logs', getDevValue('__ENQUEUE_LOGS'));\n throw new Error(\n 'Fast-lane invariant violated: scheduler enqueued leftover work during bulk commit'\n );\n }\n\n // Final quiescence assertion\n let finalState = globalScheduler.getState();\n const executing = globalScheduler.isExecuting();\n let outstandingAfter = Math.max(\n 0,\n finalState.taskCount - (executing ? 1 : 0)\n );\n\n if (outstandingAfter !== 0) {\n // Attempt to clear newly enqueued synchronous tasks\n let attempts = 0;\n while (attempts < 5) {\n const cleared = globalScheduler.clearPendingSyncTasks?.() ?? 0;\n if (cleared === 0) break;\n attempts++;\n }\n finalState = globalScheduler.getState();\n outstandingAfter = Math.max(\n 0,\n finalState.taskCount - (globalScheduler.isExecuting() ? 1 : 0)\n );\n if (outstandingAfter !== 0) {\n console.error(\n '[FASTLANE] Post-commit enqueue logs:',\n getDevValue('__ENQUEUE_LOGS')\n );\n console.error(\n '[FASTLANE] Cleared counts:',\n getDevValue('__FASTLANE_CLEARED_TASKS'),\n getDevValue('__FASTLANE_CLEARED_AFTER')\n );\n throw new Error(\n `Fast-lane invariant violated: scheduler has ${finalState.taskCount} pending task(s) after commit`\n );\n }\n }\n}\n\nexport function tryRuntimeFastLaneSync(\n instance: ComponentInstance,\n result: unknown\n): boolean {\n const cls = classifyUpdate(instance, result);\n if (!cls.useFastPath) {\n // Clear stale fast-path diagnostics\n setDevValue('__LAST_FASTPATH_STATS', undefined);\n setDevValue('__LAST_FASTPATH_COMMIT_COUNT', 0);\n return false;\n }\n\n try {\n return commitReorderOnly(instance, result);\n } catch (err) {\n // Surface dev-only invariant failures, otherwise decline silently\n if (isDevelopmentEnvironment()) throw err;\n return false;\n }\n}\n\n// Expose fastlane bridge on globalThis for environments/tests\nif (typeof globalThis !== 'undefined') {\n (globalThis as Record<string, unknown>).__ASKR_FASTLANE = {\n isBulkCommitActive,\n enterBulkCommit,\n exitBulkCommit,\n tryRuntimeFastLaneSync,\n markFastPathApplied,\n isFastPathApplied,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"fastlane.js","names":[],"sources":["../../src/runtime/fastlane.ts"],"sourcesContent":["import { isDevelopmentEnvironment } from '../common/env';\nimport { globalScheduler } from './scheduler';\nimport { logger } from '../dev/logger';\nimport type { ComponentInstance } from './component';\nimport { finalizeReadableSubscriptions } from './readable';\nimport {\n getKeyMapForElement,\n isKeyedReorderFastPathEligible,\n populateKeyMapForElement,\n} from '../renderer/keyed';\nimport { Fragment } from '../common/jsx';\nimport { setDevValue, getDevValue, getDevNamespace } from './dev-namespace';\n\nlet _bulkCommitActive = false;\nlet _appliedParents: WeakSet<Element> | null = null;\n\nexport function enterBulkCommit(): void {\n _bulkCommitActive = true;\n // Initialize registry of parents that had fast-path applied during this bulk commit\n _appliedParents = new WeakSet<Element>();\n setDevValue('__ASKR_FASTLANE_CLEARED_TASKS', 0);\n}\n\nexport function exitBulkCommit(): void {\n _bulkCommitActive = false;\n // Clear registry to avoid leaking across commits\n _appliedParents = null;\n}\n\nexport function isBulkCommitActive(): boolean {\n return _bulkCommitActive;\n}\n\n// Mark that a fast-path was applied on a parent element during the active\n// bulk commit. No-op if there is no active bulk commit.\nexport function markFastPathApplied(parent: Element): void {\n if (!_appliedParents) return;\n try {\n _appliedParents.add(parent);\n } catch (e) {\n void e;\n }\n}\n\nexport function isFastPathApplied(parent: Element): boolean {\n return !!(_appliedParents && _appliedParents.has(parent));\n}\n\nfunction finalizeReadSubscriptions(instance: ComponentInstance): void {\n finalizeReadableSubscriptions(instance);\n}\n\n/**\n * Attempt to execute a runtime fast-lane for a single component's synchronous\n * render result. Returns true if the fast-lane was used and commit was done.\n *\n * Preconditions (checked conservatively):\n * - The render result is an intrinsic element root with keyed children\n * - The renderer's fast-path heuristics indicate to use the fast-path\n * - No mount operations are pending on the component instance\n * - No child vnodes are component functions (avoid async/component mounts)\n */\n\n// Helper to unwrap Fragment vnodes to get the first intrinsic element child\nfunction unwrapFragmentForFastPath(vnode: unknown): unknown {\n if (!vnode || typeof vnode !== 'object' || !('type' in vnode)) return vnode;\n const v = vnode as {\n type: unknown;\n children?: unknown;\n props?: { children?: unknown };\n };\n // Check if it's a Fragment\n if (\n typeof v.type === 'symbol' &&\n (v.type === Fragment || String(v.type) === 'Symbol(askr.fragment)')\n ) {\n const children = v.props?.children ?? v.children;\n if (Array.isArray(children) && children.length > 0) {\n // Return the first child that's an intrinsic element\n for (const child of children) {\n if (child && typeof child === 'object' && 'type' in child) {\n const c = child as { type: unknown };\n if (typeof c.type === 'string') {\n return child;\n }\n }\n }\n }\n }\n return vnode;\n}\n\nexport function classifyUpdate(instance: ComponentInstance, result: unknown) {\n // Returns a classification describing whether this update is eligible for\n // the reorder-only fast-lane. The classifier mirrors renderer-level\n // heuristics and performs runtime-level checks (mounts, effects, component\n // children) that the renderer cannot reason about.\n\n // Unwrap Fragment to get the actual element vnode for classification\n const unwrappedResult = unwrapFragmentForFastPath(result);\n\n if (\n !unwrappedResult ||\n typeof unwrappedResult !== 'object' ||\n !('type' in unwrappedResult)\n )\n return { useFastPath: false, reason: 'not-vnode' };\n\n const vnode = unwrappedResult as {\n type: unknown;\n children?: unknown;\n props?: { children?: unknown };\n };\n if (vnode == null || typeof vnode.type !== 'string')\n return { useFastPath: false, reason: 'not-intrinsic' };\n\n const parent = instance.target;\n if (!parent) return { useFastPath: false, reason: 'no-root' };\n\n const firstChild = parent.children[0] as Element | undefined;\n if (!firstChild) return { useFastPath: false, reason: 'no-first-child' };\n if (firstChild.tagName.toLowerCase() !== String(vnode.type).toLowerCase())\n return { useFastPath: false, reason: 'root-tag-mismatch' };\n\n const children = vnode.props?.children ?? vnode.children;\n if (!Array.isArray(children))\n return { useFastPath: false, reason: 'no-children-array' };\n\n // Avoid component child vnodes (they may mount/unmount or trigger async)\n for (const c of children) {\n if (\n typeof c === 'object' &&\n c !== null &&\n 'type' in c &&\n typeof (c as { type?: unknown }).type === 'function'\n ) {\n return { useFastPath: false, reason: 'component-child-present' };\n }\n }\n\n if ((instance.mountOperations?.length ?? 0) > 0)\n return { useFastPath: false, reason: 'pending-mounts' };\n\n // Ask renderer for keyed reorder eligibility (prop differences & heuristics)\n // Ensure a keyed map is available for the first child by populating it proactively.\n try {\n populateKeyMapForElement(firstChild);\n } catch {\n // ignore\n }\n\n const oldKeyMap = getKeyMapForElement(firstChild);\n const decision = isKeyedReorderFastPathEligible(\n firstChild,\n children,\n oldKeyMap\n );\n\n if (!decision.useFastPath || decision.totalKeyed < 128)\n return { ...decision, useFastPath: false, reason: 'renderer-declined' };\n\n return { ...decision, useFastPath: true } as const;\n}\n\nexport function commitReorderOnly(\n instance: ComponentInstance,\n result: unknown\n): boolean {\n // Performs the minimal, synchronous reorder-only commit.\n const evaluate = (\n globalThis as {\n __ASKR_RENDERER?: {\n evaluate?: (node: unknown, target: Element | null) => void;\n };\n }\n ).__ASKR_RENDERER?.evaluate;\n\n if (typeof evaluate !== 'function') {\n logger.warn(\n '[Tempo][FASTPATH][DEV] renderer.evaluate not available; declining fast-lane'\n );\n return false;\n }\n\n const schedBefore = isDevelopmentEnvironment()\n ? globalScheduler.getState()\n : null;\n\n enterBulkCommit();\n\n try {\n globalScheduler.runWithSyncProgress(() => {\n evaluate(result, instance.target);\n\n // Finalize runtime bookkeeping (read subscriptions / tokens)\n try {\n finalizeReadSubscriptions(instance);\n } catch (e) {\n if (isDevelopmentEnvironment()) throw e;\n }\n });\n\n setDevValue('__FASTLANE_CLEARED_AFTER', 0);\n\n // Dev-only invariant checks\n if (isDevelopmentEnvironment()) {\n validateFastLaneInvariants(instance, schedBefore);\n }\n\n return true;\n } finally {\n // Clear bulk commit flag first\n exitBulkCommit();\n }\n // Note: The original code had a check here that was dead code because\n // exitBulkCommit() already ran in the finally block. This comment serves\n // as documentation that we've intentionally removed that unreachable code.\n}\n\n/**\n * Validates fast-lane invariants in dev mode.\n * Extracted to reduce complexity in commitReorderOnly.\n */\nfunction validateFastLaneInvariants(\n instance: ComponentInstance,\n schedBefore: ReturnType<typeof globalScheduler.getState> | null\n): void {\n const commitCount = getDevValue<number>('__LAST_FASTPATH_COMMIT_COUNT') ?? 0;\n const invariants = {\n commitCount,\n mountOps: instance.mountOperations?.length ?? 0,\n cleanupFns: instance.cleanupFns?.length ?? 0,\n };\n setDevValue('__LAST_FASTLANE_INVARIANTS', invariants);\n\n if (commitCount !== 1) {\n console.error(\n '[FASTLANE][INV] commitCount',\n commitCount,\n 'diag',\n getDevNamespace()\n );\n throw new Error(\n 'Fast-lane invariant violated: expected exactly one DOM commit during reorder-only commit'\n );\n }\n\n if (invariants.mountOps > 0) {\n throw new Error(\n 'Fast-lane invariant violated: mount operations were registered during bulk commit'\n );\n }\n\n if (invariants.cleanupFns > 0) {\n throw new Error(\n 'Fast-lane invariant violated: cleanup functions were added during bulk commit'\n );\n }\n\n const schedAfter = globalScheduler.getState();\n if (\n schedBefore &&\n schedAfter &&\n schedAfter.taskCount > schedBefore.taskCount\n ) {\n console.error(\n '[FASTLANE] schedBefore, schedAfter',\n schedBefore,\n schedAfter\n );\n console.error('[FASTLANE] enqueue logs', getDevValue('__ENQUEUE_LOGS'));\n throw new Error(\n 'Fast-lane invariant violated: scheduler enqueued leftover work during bulk commit'\n );\n }\n}\n\nexport function tryRuntimeFastLaneSync(\n instance: ComponentInstance,\n result: unknown\n): boolean {\n const cls = classifyUpdate(instance, result);\n if (!cls.useFastPath) {\n // Clear stale fast-path diagnostics\n setDevValue('__LAST_FASTPATH_STATS', undefined);\n setDevValue('__LAST_FASTPATH_COMMIT_COUNT', 0);\n return false;\n }\n\n try {\n return commitReorderOnly(instance, result);\n } catch (err) {\n // Surface dev-only invariant failures, otherwise decline silently\n if (isDevelopmentEnvironment()) throw err;\n return false;\n }\n}\n\n// Expose fastlane bridge on globalThis for environments/tests\nif (typeof globalThis !== 'undefined') {\n (globalThis as Record<string, unknown>).__ASKR_FASTLANE = {\n isBulkCommitActive,\n enterBulkCommit,\n exitBulkCommit,\n tryRuntimeFastLaneSync,\n markFastPathApplied,\n isFastPathApplied,\n };\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"for-bench.d.ts","names":[],"sources":["../../src/runtime/for-bench.ts"],"mappings":";UASiB,YAAA;EACf,YAAA;EACA,WAAA;EACA,YAAA;EACA,UAAA;EACA,qBAAA;EACA,UAAA;EACA,OAAA;EACA,SAAA;EACA,UAAA;EACA,UAAA;EACA,QAAA;EACA,WAAA;EACA,WAAA;EACA,eAAA;EACA,gBAAA;EACA,oBAAA;EACA,sBAAA;EACA,gBAAA;EACA,gBAAA;EACA,gBAAA;EACA,YAAA;AAAA;AAAA,KAGU,UAAA;AAAA,KA0CP,gBAAA;AAAA,KACA,YAAA;AAAA,iBAmJI,wBAAA,GAAA,CAA4B,KAAA,EAAO,gBAAA,EAAkB,GAAA,QAAW,CAAA,GAAI,CAAA;AAAA,cAoChE,iBAAA;AAAA,cAUA,gBAAA,GAAgB,KAAA,EAlIQ,UAAA,EAAU,KAAA;AAAA,cAsIlC,mBAAA,GAAmB,IAAA;AAAA,cAInB,iBAAA,GAAiB,KAAA,6BAnCI,EAAA;AAAA,cAuCrB,kBAAA,GAAkB,OAAA,EAlFU,YAAA,EAAY,KAAA;AAAA,cAsFxC,oBAAA,SAAoB,wBAAA;AAAA,cAIpB,wBAAA,GAAwB,KAAA,EAnDQ,gBAAA;AAAA,cAuDhC,eAAA,QArCmB,YAAA;AAAA,cAyCnB,iBAAA;AAAA,cAIA,mBAAA"}
1
+ {"version":3,"file":"for-bench.d.ts","names":[],"sources":["../../src/runtime/for-bench.ts"],"mappings":";UASiB,YAAA;EACf,YAAA;EACA,WAAA;EACA,YAAA;EACA,UAAA;EACA,qBAAA;EACA,UAAA;EACA,OAAA;EACA,SAAA;EACA,UAAA;EACA,UAAA;EACA,QAAA;EACA,WAAA;EACA,WAAA;EACA,eAAA;EACA,gBAAA;EACA,oBAAA;EACA,sBAAA;EACA,gBAAA;EACA,gBAAA;EACA,gBAAA;EACA,YAAA;AAAA;AAAA,KAGU,UAAA;AAAA,KA0CP,gBAAA;AAAA,KACA,YAAA;AAAA,iBAmJI,wBAAA,IAA4B,KAAA,EAAO,gBAAA,EAAkB,GAAA,QAAW,CAAA,GAAI,CAAA;AAAA,cAoChE,iBAAA;AAAA,cAUA,gBAAA,GAAgB,KAAA,EAlIQ,UAAU,EAAA,KAAA;AAAA,cAsIlC,mBAAA,GAAmB,IAlFa;AAAA,cAsFhC,iBAAA,GAAiB,KAAA,6BAnCI,EACtB;AAAA,cAsCC,kBAAA,GAAkB,OAAA,EAlFU,YAAY,EAAA,KAAA;AAAA,cAsFxC,oBAAA,SAAoB,wBAE0B;AAAA,cAE9C,wBAAA,GAAwB,KAnDwB,EAAhB,gBAAgB;AAAA,cAuDhD,eAAA,QArCmB,YAuCkB;AAAA,cAErC,iBAAA;AAAA,cAIA,mBAAA"}