@fictjs/runtime 0.5.1 → 0.5.2

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 (48) hide show
  1. package/dist/advanced.cjs +9 -9
  2. package/dist/advanced.js +4 -4
  3. package/dist/{chunk-AR6NSCZM.js → chunk-4NUHM77Z.js} +3 -3
  4. package/dist/{chunk-RY5CY4CI.js → chunk-D2IWOO4X.js} +2 -2
  5. package/dist/{chunk-LFMXNQZC.cjs → chunk-KNGHYGK4.cjs} +17 -17
  6. package/dist/{chunk-LFMXNQZC.cjs.map → chunk-KNGHYGK4.cjs.map} +1 -1
  7. package/dist/{chunk-7BO6P2KP.js → chunk-LRFMCJY3.js} +84 -1
  8. package/dist/chunk-LRFMCJY3.js.map +1 -0
  9. package/dist/{chunk-4ZPZM5IG.cjs → chunk-QB2UD62G.cjs} +8 -8
  10. package/dist/{chunk-4ZPZM5IG.cjs.map → chunk-QB2UD62G.cjs.map} +1 -1
  11. package/dist/{chunk-5OYBRKE4.js → chunk-SLFAEVKJ.js} +3 -3
  12. package/dist/{chunk-WJHXPF7M.cjs → chunk-Z6M3HKLG.cjs} +156 -156
  13. package/dist/{chunk-WJHXPF7M.cjs.map → chunk-Z6M3HKLG.cjs.map} +1 -1
  14. package/dist/{chunk-6RCEIWZL.cjs → chunk-ZR435MDC.cjs} +85 -2
  15. package/dist/chunk-ZR435MDC.cjs.map +1 -0
  16. package/dist/index.cjs +95 -45
  17. package/dist/index.cjs.map +1 -1
  18. package/dist/index.dev.js +87 -7
  19. package/dist/index.dev.js.map +1 -1
  20. package/dist/index.js +60 -10
  21. package/dist/index.js.map +1 -1
  22. package/dist/internal.cjs +51 -41
  23. package/dist/internal.cjs.map +1 -1
  24. package/dist/internal.d.cts +11 -2
  25. package/dist/internal.d.ts +11 -2
  26. package/dist/internal.js +13 -3
  27. package/dist/internal.js.map +1 -1
  28. package/dist/jsx-dev-runtime.d.cts +671 -0
  29. package/dist/jsx-dev-runtime.d.ts +671 -0
  30. package/dist/loader.cjs +60 -8
  31. package/dist/loader.cjs.map +1 -1
  32. package/dist/loader.d.cts +1 -1
  33. package/dist/loader.d.ts +1 -1
  34. package/dist/loader.js +53 -1
  35. package/dist/loader.js.map +1 -1
  36. package/dist/{resume-Dx8_l72o.d.ts → resume-CqeQ3v_q.d.ts} +5 -1
  37. package/dist/{resume-BrAkmSTY.d.cts → resume-i-A3EFox.d.cts} +5 -1
  38. package/package.json +1 -1
  39. package/src/internal.ts +4 -0
  40. package/src/loader.ts +58 -0
  41. package/src/resume.ts +55 -0
  42. package/src/ssr-stream.ts +38 -0
  43. package/src/suspense.ts +62 -7
  44. package/dist/chunk-6RCEIWZL.cjs.map +0 -1
  45. package/dist/chunk-7BO6P2KP.js.map +0 -1
  46. /package/dist/{chunk-AR6NSCZM.js.map → chunk-4NUHM77Z.js.map} +0 -0
  47. /package/dist/{chunk-RY5CY4CI.js.map → chunk-D2IWOO4X.js.map} +0 -0
  48. /package/dist/{chunk-5OYBRKE4.js.map → chunk-SLFAEVKJ.js.map} +0 -0
package/src/resume.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type { HookContext } from './hooks'
2
2
  import { createSignal, isSignal } from './signal'
3
+ import { __fictGetCurrentSSRBoundary } from './ssr-stream'
3
4
  import { createStore, isStoreProxy, unwrapStore } from './store'
4
5
 
5
6
  // ============================================================================
@@ -43,6 +44,7 @@ export interface ScopeRecord {
43
44
  id: string
44
45
  ctx: HookContext
45
46
  host: Element
47
+ boundaryId?: string
46
48
  type?: string
47
49
  props?: Record<string, unknown>
48
50
  }
@@ -52,6 +54,7 @@ let resumableEnabled = false
52
54
  let hydrating = false
53
55
  let scopeCounter = 0
54
56
  let scopeRegistry = new Map<string, ScopeRecord>()
57
+ let boundaryScopes = new Map<string, Set<string>>()
55
58
  let snapshotState: SSRState | null = null
56
59
  const resumedScopes = new Map<
57
60
  string,
@@ -62,12 +65,14 @@ export function __fictEnableSSR(): void {
62
65
  ssrEnabled = true
63
66
  scopeCounter = 0
64
67
  scopeRegistry = new Map()
68
+ boundaryScopes = new Map()
65
69
  resumedScopes.clear()
66
70
  snapshotState = null
67
71
  }
68
72
 
69
73
  export function __fictDisableSSR(): void {
70
74
  ssrEnabled = false
75
+ boundaryScopes = new Map()
71
76
  }
72
77
 
73
78
  export function __fictEnableResumable(): void {
@@ -124,6 +129,16 @@ export function __fictRegisterScope(
124
129
  if (props !== undefined) {
125
130
  record.props = props
126
131
  }
132
+ const boundaryId = __fictGetCurrentSSRBoundary()
133
+ if (boundaryId) {
134
+ record.boundaryId = boundaryId
135
+ let scopes = boundaryScopes.get(boundaryId)
136
+ if (!scopes) {
137
+ scopes = new Set()
138
+ boundaryScopes.set(boundaryId, scopes)
139
+ }
140
+ scopes.add(id)
141
+ }
127
142
  scopeRegistry.set(id, record)
128
143
  return id
129
144
  }
@@ -132,6 +147,12 @@ export function __fictGetScopeRegistry(): Map<string, ScopeRecord> {
132
147
  return scopeRegistry
133
148
  }
134
149
 
150
+ export function __fictGetScopesForBoundary(boundaryId: string): string[] {
151
+ const scopes = boundaryScopes.get(boundaryId)
152
+ if (!scopes) return []
153
+ return Array.from(scopes)
154
+ }
155
+
135
156
  export function __fictSerializeSSRState(): SSRState {
136
157
  const scopes: Record<string, ScopeSnapshot> = {}
137
158
 
@@ -155,6 +176,31 @@ export function __fictSerializeSSRState(): SSRState {
155
176
  return { scopes }
156
177
  }
157
178
 
179
+ export function __fictSerializeSSRStateForScopes(scopeIds: Iterable<string>): SSRState {
180
+ const scopes: Record<string, ScopeSnapshot> = {}
181
+
182
+ for (const id of scopeIds) {
183
+ const record = scopeRegistry.get(id)
184
+ if (!record) continue
185
+ const snapshot: ScopeSnapshot = {
186
+ id,
187
+ slots: serializeSlots(record.ctx),
188
+ }
189
+ if (record.type !== undefined) {
190
+ snapshot.t = record.type
191
+ }
192
+ if (record.props !== undefined) {
193
+ snapshot.props = record.props
194
+ }
195
+ if (record.ctx.slotMap !== undefined) {
196
+ snapshot.vars = record.ctx.slotMap
197
+ }
198
+ scopes[id] = snapshot
199
+ }
200
+
201
+ return { scopes }
202
+ }
203
+
158
204
  export function __fictSetSSRState(state: SSRState | null): void {
159
205
  snapshotState = state
160
206
  if (!state) {
@@ -162,6 +208,15 @@ export function __fictSetSSRState(state: SSRState | null): void {
162
208
  }
163
209
  }
164
210
 
211
+ export function __fictMergeSSRState(state: SSRState | null): void {
212
+ if (!state) return
213
+ if (!snapshotState) {
214
+ snapshotState = { scopes: { ...state.scopes } }
215
+ return
216
+ }
217
+ Object.assign(snapshotState.scopes, state.scopes)
218
+ }
219
+
165
220
  export function __fictGetSSRScope(id: string): ScopeSnapshot | undefined {
166
221
  return snapshotState?.scopes[id]
167
222
  }
@@ -0,0 +1,38 @@
1
+ export interface SSRStreamHooks {
2
+ registerBoundary?: (start: Comment, end: Comment) => string | null
3
+ boundaryPending?: (id: string) => void
4
+ boundaryResolved?: (id: string) => void
5
+ onError?: (error: unknown, boundaryId?: string) => void
6
+ }
7
+
8
+ let ssrStreamHooks: SSRStreamHooks | null = null
9
+ const boundaryStack: string[] = []
10
+
11
+ export function __fictSetSSRStreamHooks(hooks: SSRStreamHooks | null): void {
12
+ ssrStreamHooks = hooks
13
+ if (!hooks) {
14
+ boundaryStack.length = 0
15
+ }
16
+ }
17
+
18
+ export function __fictGetSSRStreamHooks(): SSRStreamHooks | null {
19
+ return ssrStreamHooks
20
+ }
21
+
22
+ export function __fictPushSSRBoundary(id: string): void {
23
+ boundaryStack.push(id)
24
+ }
25
+
26
+ export function __fictPopSSRBoundary(expected?: string): void {
27
+ if (boundaryStack.length === 0) return
28
+ const top = boundaryStack[boundaryStack.length - 1]
29
+ if (expected && top !== expected) {
30
+ boundaryStack.pop()
31
+ return
32
+ }
33
+ boundaryStack.pop()
34
+ }
35
+
36
+ export function __fictGetCurrentSSRBoundary(): string | null {
37
+ return boundaryStack.length > 0 ? boundaryStack[boundaryStack.length - 1]! : null
38
+ }
package/src/suspense.ts CHANGED
@@ -12,6 +12,7 @@ import {
12
12
  } from './lifecycle'
13
13
  import { insertNodesBefore, removeNodes, toNodeArray } from './node-ops'
14
14
  import { createSignal } from './signal'
15
+ import { __fictGetSSRStreamHooks, __fictPopSSRBoundary, __fictPushSSRBoundary } from './ssr-stream'
15
16
  import type { BaseProps, FictNode, SuspenseToken } from './types'
16
17
 
17
18
  export interface SuspenseProps extends BaseProps {
@@ -49,6 +50,7 @@ const isThenable = (value: unknown): value is PromiseLike<unknown> =>
49
50
  typeof (value as PromiseLike<unknown>).then === 'function'
50
51
 
51
52
  export function Suspense(props: SuspenseProps): FictNode {
53
+ const streamHooks = __fictGetSSRStreamHooks()
52
54
  const pending = createSignal(0)
53
55
  let resolvedOnce = false
54
56
  let epoch = 0
@@ -76,7 +78,12 @@ export function Suspense(props: SuspenseProps): FictNode {
76
78
  const root = createRootContext(hostRoot)
77
79
  const prev = pushRoot(root)
78
80
  let nodes: Node[] = []
81
+ let boundaryPushed = false
79
82
  try {
83
+ if (streamBoundaryId) {
84
+ __fictPushSSRBoundary(streamBoundaryId)
85
+ boundaryPushed = true
86
+ }
80
87
  const output = createElement(view)
81
88
  nodes = toNodeArray(output)
82
89
  // Suspended view: child threw a suspense token and was handled upstream.
@@ -90,9 +97,9 @@ export function Suspense(props: SuspenseProps): FictNode {
90
97
  destroyRoot(root)
91
98
  return
92
99
  }
93
- const parentNode = marker.parentNode as (ParentNode & Node) | null
100
+ const parentNode = endMarker.parentNode as (ParentNode & Node) | null
94
101
  if (parentNode) {
95
- insertNodesBefore(parentNode, nodes, marker)
102
+ insertNodesBefore(parentNode, nodes, endMarker)
96
103
  }
97
104
  } catch (err) {
98
105
  popRoot(prev)
@@ -101,6 +108,10 @@ export function Suspense(props: SuspenseProps): FictNode {
101
108
  throw err
102
109
  }
103
110
  return
111
+ } finally {
112
+ if (boundaryPushed) {
113
+ __fictPopSSRBoundary(streamBoundaryId ?? undefined)
114
+ }
104
115
  }
105
116
  popRoot(prev)
106
117
  flushOnMount(root)
@@ -113,10 +124,22 @@ export function Suspense(props: SuspenseProps): FictNode {
113
124
  }
114
125
 
115
126
  const fragment = document.createDocumentFragment()
116
- const marker = document.createComment('fict:suspense')
117
- fragment.appendChild(marker)
127
+ const startMarker = document.createComment('fict:suspense-start')
128
+ const endMarker = document.createComment('fict:suspense-end')
129
+ fragment.appendChild(startMarker)
130
+ fragment.appendChild(endMarker)
118
131
  let cleanup: (() => void) | undefined
119
132
  let activeNodes: Node[] = []
133
+ let streamBoundaryId: string | null = null
134
+ let streamPending = false
135
+
136
+ if (streamHooks?.registerBoundary) {
137
+ streamBoundaryId = streamHooks.registerBoundary(startMarker, endMarker) ?? null
138
+ if (streamBoundaryId) {
139
+ startMarker.data = `fict:suspense-start:${streamBoundaryId}`
140
+ endMarker.data = `fict:suspense-end:${streamBoundaryId}`
141
+ }
142
+ }
120
143
 
121
144
  const onResolveMaybe = () => {
122
145
  if (!resolvedOnce) {
@@ -127,6 +150,10 @@ export function Suspense(props: SuspenseProps): FictNode {
127
150
 
128
151
  registerSuspenseHandler(token => {
129
152
  const tokenEpoch = epoch
153
+ if (!streamPending && streamBoundaryId && streamHooks?.boundaryPending) {
154
+ streamPending = true
155
+ streamHooks.boundaryPending(streamBoundaryId)
156
+ }
130
157
  pending(pending() + 1)
131
158
  // Directly render fallback instead of using switchView to avoid
132
159
  // triggering the effect which would cause duplicate renders
@@ -155,6 +182,10 @@ export function Suspense(props: SuspenseProps): FictNode {
155
182
  if (newPending === 0) {
156
183
  // Directly render children instead of using switchView
157
184
  renderView(props.children ?? null)
185
+ if (streamPending && streamBoundaryId && streamHooks?.boundaryResolved) {
186
+ streamPending = false
187
+ streamHooks.boundaryResolved(streamBoundaryId)
188
+ }
158
189
  onResolveMaybe()
159
190
  }
160
191
  },
@@ -165,9 +196,29 @@ export function Suspense(props: SuspenseProps): FictNode {
165
196
  }
166
197
  const newPending = Math.max(0, pending() - 1)
167
198
  pending(newPending)
168
- props.onReject?.(err)
169
- if (!handleError(err, { source: 'render' }, hostRoot)) {
170
- throw err
199
+ let rejectionError = err
200
+ try {
201
+ props.onReject?.(err)
202
+ } catch (callbackError) {
203
+ rejectionError = callbackError
204
+ }
205
+
206
+ const handled = handleError(rejectionError, { source: 'render' }, hostRoot)
207
+ if (!handled) {
208
+ if (streamHooks?.onError) {
209
+ streamHooks.onError(rejectionError, streamBoundaryId ?? undefined)
210
+ return
211
+ }
212
+ throw rejectionError
213
+ }
214
+ if (
215
+ newPending === 0 &&
216
+ streamPending &&
217
+ streamBoundaryId &&
218
+ streamHooks?.boundaryResolved
219
+ ) {
220
+ streamPending = false
221
+ streamHooks.boundaryResolved(streamBoundaryId)
171
222
  }
172
223
  },
173
224
  )
@@ -195,6 +246,10 @@ export function Suspense(props: SuspenseProps): FictNode {
195
246
  pending(0)
196
247
  // Directly render children instead of using switchView
197
248
  renderView(props.children ?? null)
249
+ if (streamPending && streamBoundaryId && streamHooks?.boundaryResolved) {
250
+ streamPending = false
251
+ streamHooks.boundaryResolved(streamBoundaryId)
252
+ }
198
253
  }
199
254
  })
200
255
  }
@@ -1 +0,0 @@
1
- {"version":3,"sources":["/home/runner/work/fict/fict/packages/runtime/dist/chunk-6RCEIWZL.cjs","../src/delegated-events.ts","../src/constants.ts","../src/devtools.ts","../src/cycle-guard.ts","../src/lifecycle.ts","../src/effect.ts","../src/hooks.ts","../src/signal.ts","../src/memo.ts","../src/store.ts","../src/resume.ts"],"names":["isDev"],"mappings":"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AAA;AACI,QAAA;AACJ,MAAA;AACkB,QAAA;AAClB,MAAA;AACoB,QAAA;AACpB,MAAA;AACmC,QAAA;AAC9B,MAAA;AAC8B,QAAA;AACpB,QAAA;AACuB,QAAA;AAChB,UAAA;AACX,UAAA;AACG,UAAA;AACX,UAAA;AACuC,YAAA;AACA,YAAA;AAC3C,UAAA;AACF,QAAA;AACO,QAAA;AACT,MAAA;AACU,MAAA;AACqB,QAAA;AACX,QAAA;AACuB,QAAA;AACW,UAAA;AACpD,QAAA;AACO,QAAA;AACT,MAAA;AACK,MAAA;AACoB,QAAA;AAC3B,IAAA;AACF,EAAA;AAG0B,EAAA;AACA,IAAA;AACN,IAAA;AACqB,IAAA;AACiB,MAAA;AACxD,IAAA;AACO,IAAA;AACT,EAAA;AAGsC,EAAA;AACpB,EAAA;AACoB,EAAA;AAC8C,IAAA;AACpF,EAAA;AACO,EAAA;AACT;AXovD4D;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA","file":"/home/runner/work/fict/fict/packages/runtime/dist/chunk-6RCEIWZL.cjs","sourcesContent":[null,"export const DelegatedEventNames = [\n 'beforeinput',\n 'click',\n 'dblclick',\n 'contextmenu',\n 'focusin',\n 'focusout',\n 'input',\n 'keydown',\n 'keyup',\n 'mousedown',\n 'mousemove',\n 'mouseout',\n 'mouseover',\n 'mouseup',\n 'pointerdown',\n 'pointermove',\n 'pointerout',\n 'pointerover',\n 'pointerup',\n 'touchend',\n 'touchmove',\n 'touchstart',\n] as const\n","/**\n * Fict DOM Constants\n *\n * Property constants and configurations for DOM attribute handling.\n * Borrowed from dom-expressions for comprehensive DOM support.\n */\n\nimport { DelegatedEventNames } from './delegated-events'\n\n// Detect dev mode at runtime:\n// 1. Check __DEV__ global (set by bundlers via define, e.g., Vite plugin sets this)\n// 2. Check process.env.NODE_ENV (Node.js)\n// Note: We cannot use import.meta.env here because import.meta is ES module syntax\n// and will cause syntax errors when the code is bundled to CJS format.\nconst isDev =\n typeof __DEV__ !== 'undefined'\n ? __DEV__\n : typeof process === 'undefined' || process.env?.NODE_ENV !== 'production'\n\n// ============================================================================\n// Boolean Attributes\n// ============================================================================\n\n/**\n * Complete list of boolean attributes (lowercase)\n * These attributes are set as empty strings when true, removed when false\n */\nconst booleans = isDev\n ? [\n 'allowfullscreen',\n 'async',\n 'alpha', // HTMLInputElement\n 'autofocus', // HTMLElement prop\n 'autoplay',\n 'checked',\n 'controls',\n 'default',\n 'disabled',\n 'formnovalidate',\n 'hidden', // HTMLElement prop\n 'indeterminate',\n 'inert', // HTMLElement prop\n 'ismap',\n 'loop',\n 'multiple',\n 'muted',\n 'nomodule',\n 'novalidate',\n 'open',\n 'playsinline',\n 'readonly',\n 'required',\n 'reversed',\n 'seamless', // HTMLIframeElement - non-standard\n 'selected',\n // Experimental attributes\n 'adauctionheaders',\n 'browsingtopics',\n 'credentialless',\n 'defaultchecked',\n 'defaultmuted',\n 'defaultselected',\n 'defer',\n 'disablepictureinpicture',\n 'disableremoteplayback',\n 'preservespitch',\n 'shadowrootclonable',\n 'shadowrootcustomelementregistry',\n 'shadowrootdelegatesfocus',\n 'shadowrootserializable',\n 'sharedstoragewritable',\n ]\n : []\n\nexport const BooleanAttributes = new Set<string>(booleans)\n\n// ============================================================================\n// Properties Set\n// ============================================================================\n\n/**\n * Properties that should be set via DOM property (not attribute)\n * Includes camelCase versions of boolean attributes\n */\nconst properties = isDev\n ? [\n // Core properties\n 'className',\n 'value',\n\n // CamelCase booleans\n 'readOnly',\n 'noValidate',\n 'formNoValidate',\n 'isMap',\n 'noModule',\n 'playsInline',\n\n // Experimental (camelCase)\n 'adAuctionHeaders',\n 'allowFullscreen',\n 'browsingTopics',\n 'defaultChecked',\n 'defaultMuted',\n 'defaultSelected',\n 'disablePictureInPicture',\n 'disableRemotePlayback',\n 'preservesPitch',\n 'shadowRootClonable',\n 'shadowRootCustomElementRegistry',\n 'shadowRootDelegatesFocus',\n 'shadowRootSerializable',\n 'sharedStorageWritable',\n\n // All lowercase booleans\n ...booleans,\n ]\n : []\n\nexport const Properties = new Set<string>(properties)\n\n// ============================================================================\n// Child Properties\n// ============================================================================\n\n/**\n * Properties that represent children/content\n */\nexport const ChildProperties = new Set<string>([\n 'innerHTML',\n 'textContent',\n 'innerText',\n 'children',\n])\n\n// ============================================================================\n// Property Aliases\n// ============================================================================\n\n/**\n * React compatibility aliases (className -> class)\n */\nexport const Aliases: Record<string, string> = {\n className: 'class',\n htmlFor: 'for',\n}\n\n/**\n * Element-specific property aliases\n * Maps lowercase attribute names to their camelCase property equivalents\n * Only for specific elements that have these properties\n */\nconst PropAliases: Record<string, string | { $: string; [tagName: string]: string | number }> =\n isDev\n ? {\n // Direct mapping\n class: 'className',\n\n // Element-specific mappings\n novalidate: {\n $: 'noValidate',\n FORM: 1,\n },\n formnovalidate: {\n $: 'formNoValidate',\n BUTTON: 1,\n INPUT: 1,\n },\n ismap: {\n $: 'isMap',\n IMG: 1,\n },\n nomodule: {\n $: 'noModule',\n SCRIPT: 1,\n },\n playsinline: {\n $: 'playsInline',\n VIDEO: 1,\n },\n readonly: {\n $: 'readOnly',\n INPUT: 1,\n TEXTAREA: 1,\n },\n\n // Experimental element-specific\n adauctionheaders: {\n $: 'adAuctionHeaders',\n IFRAME: 1,\n },\n allowfullscreen: {\n $: 'allowFullscreen',\n IFRAME: 1,\n },\n browsingtopics: {\n $: 'browsingTopics',\n IMG: 1,\n },\n defaultchecked: {\n $: 'defaultChecked',\n INPUT: 1,\n },\n defaultmuted: {\n $: 'defaultMuted',\n AUDIO: 1,\n VIDEO: 1,\n },\n defaultselected: {\n $: 'defaultSelected',\n OPTION: 1,\n },\n disablepictureinpicture: {\n $: 'disablePictureInPicture',\n VIDEO: 1,\n },\n disableremoteplayback: {\n $: 'disableRemotePlayback',\n AUDIO: 1,\n VIDEO: 1,\n },\n preservespitch: {\n $: 'preservesPitch',\n AUDIO: 1,\n VIDEO: 1,\n },\n shadowrootclonable: {\n $: 'shadowRootClonable',\n TEMPLATE: 1,\n },\n shadowrootdelegatesfocus: {\n $: 'shadowRootDelegatesFocus',\n TEMPLATE: 1,\n },\n shadowrootserializable: {\n $: 'shadowRootSerializable',\n TEMPLATE: 1,\n },\n sharedstoragewritable: {\n $: 'sharedStorageWritable',\n IFRAME: 1,\n IMG: 1,\n },\n }\n : {}\n\n/**\n * Get the property alias for a given attribute and tag name\n */\nexport function getPropAlias(prop: string, tagName: string): string | undefined {\n if (!isDev) return undefined\n const a = PropAliases[prop]\n if (typeof a === 'object') {\n return a[tagName] ? a['$'] : undefined\n }\n return a\n}\n\n// ============================================================================\n// Event Delegation\n// ============================================================================\n\n/**\n * Symbol for storing delegated events on the document\n */\nexport const $$EVENTS = '_$FICT_DELEGATE'\n\n/**\n * Events that should use event delegation for performance\n * These events bubble and are commonly used across many elements\n * Note: This must match the compiler's DelegatedEvents set\n */\nexport const DelegatedEvents = new Set<string>(DelegatedEventNames)\n\n// ============================================================================\n// SVG Support\n// ============================================================================\n\n/**\n * SVG element names (excluding common ones that overlap with HTML)\n */\nconst svgElements = isDev\n ? [\n 'altGlyph',\n 'altGlyphDef',\n 'altGlyphItem',\n 'animate',\n 'animateColor',\n 'animateMotion',\n 'animateTransform',\n 'circle',\n 'clipPath',\n 'color-profile',\n 'cursor',\n 'defs',\n 'desc',\n 'ellipse',\n 'feBlend',\n 'feColorMatrix',\n 'feComponentTransfer',\n 'feComposite',\n 'feConvolveMatrix',\n 'feDiffuseLighting',\n 'feDisplacementMap',\n 'feDistantLight',\n 'feDropShadow',\n 'feFlood',\n 'feFuncA',\n 'feFuncB',\n 'feFuncG',\n 'feFuncR',\n 'feGaussianBlur',\n 'feImage',\n 'feMerge',\n 'feMergeNode',\n 'feMorphology',\n 'feOffset',\n 'fePointLight',\n 'feSpecularLighting',\n 'feSpotLight',\n 'feTile',\n 'feTurbulence',\n 'filter',\n 'font',\n 'font-face',\n 'font-face-format',\n 'font-face-name',\n 'font-face-src',\n 'font-face-uri',\n 'foreignObject',\n 'g',\n 'glyph',\n 'glyphRef',\n 'hkern',\n 'image',\n 'line',\n 'linearGradient',\n 'marker',\n 'mask',\n 'metadata',\n 'missing-glyph',\n 'mpath',\n 'path',\n 'pattern',\n 'polygon',\n 'polyline',\n 'radialGradient',\n 'rect',\n 'set',\n 'stop',\n 'svg',\n 'switch',\n 'symbol',\n 'text',\n 'textPath',\n 'tref',\n 'tspan',\n 'use',\n 'view',\n 'vkern',\n ]\n : []\n\nexport const SVGElements = new Set<string>(svgElements)\n\n/**\n * SVG attribute namespaces\n */\nexport const SVGNamespace: Record<string, string> = {\n xlink: 'http://www.w3.org/1999/xlink',\n xml: 'http://www.w3.org/XML/1998/namespace',\n}\n\n// ============================================================================\n// Unitless CSS Properties\n// ============================================================================\n\n/**\n * CSS properties that don't need a unit (like 'px')\n */\nconst unitlessList = isDev\n ? [\n 'animationIterationCount',\n 'animation-iteration-count',\n 'borderImageOutset',\n 'border-image-outset',\n 'borderImageSlice',\n 'border-image-slice',\n 'borderImageWidth',\n 'border-image-width',\n 'boxFlex',\n 'box-flex',\n 'boxFlexGroup',\n 'box-flex-group',\n 'boxOrdinalGroup',\n 'box-ordinal-group',\n 'columnCount',\n 'column-count',\n 'columns',\n 'flex',\n 'flexGrow',\n 'flex-grow',\n 'flexPositive',\n 'flex-positive',\n 'flexShrink',\n 'flex-shrink',\n 'flexNegative',\n 'flex-negative',\n 'flexOrder',\n 'flex-order',\n 'gridRow',\n 'grid-row',\n 'gridRowEnd',\n 'grid-row-end',\n 'gridRowSpan',\n 'grid-row-span',\n 'gridRowStart',\n 'grid-row-start',\n 'gridColumn',\n 'grid-column',\n 'gridColumnEnd',\n 'grid-column-end',\n 'gridColumnSpan',\n 'grid-column-span',\n 'gridColumnStart',\n 'grid-column-start',\n 'fontWeight',\n 'font-weight',\n 'lineClamp',\n 'line-clamp',\n 'lineHeight',\n 'line-height',\n 'opacity',\n 'order',\n 'orphans',\n 'tabSize',\n 'tab-size',\n 'widows',\n 'zIndex',\n 'z-index',\n 'zoom',\n 'fillOpacity',\n 'fill-opacity',\n 'floodOpacity',\n 'flood-opacity',\n 'stopOpacity',\n 'stop-opacity',\n 'strokeDasharray',\n 'stroke-dasharray',\n 'strokeDashoffset',\n 'stroke-dashoffset',\n 'strokeMiterlimit',\n 'stroke-miterlimit',\n 'strokeOpacity',\n 'stroke-opacity',\n 'strokeWidth',\n 'stroke-width',\n ]\n : ['opacity', 'zIndex']\n\nexport const UnitlessStyles = new Set<string>(unitlessList)\n","export interface FictDevtoolsHook {\n registerSignal: (\n id: number,\n value: unknown,\n options?: { name?: string; source?: string; ownerId?: number },\n ) => void\n updateSignal: (id: number, value: unknown) => void\n registerComputed: (\n id: number,\n value: unknown,\n options?: { name?: string; source?: string; ownerId?: number; hasValue?: boolean },\n ) => void\n updateComputed: (id: number, value: unknown) => void\n registerEffect: (id: number, options?: { ownerId?: number; source?: string }) => void\n effectRun: (id: number) => void\n /** Track a dependency relationship between subscriber and dependency */\n trackDependency?: (subscriberId: number, dependencyId: number) => void\n /** Remove a dependency relationship when unlinked */\n untrackDependency?: (subscriberId: number, dependencyId: number) => void\n cycleDetected?: (payload: { reason: string; detail?: Record<string, unknown> }) => void\n\n // Component lifecycle\n registerComponent?: (id: number, name: string, parentId?: number, source?: any) => void\n componentMount?: (id: number, elements?: HTMLElement[]) => void\n componentUnmount?: (id: number) => void\n componentRender?: (id: number) => void\n}\n\nfunction getGlobalHook(): FictDevtoolsHook | undefined {\n if (typeof globalThis === 'undefined') return undefined\n return (globalThis as typeof globalThis & { __FICT_DEVTOOLS_HOOK__?: FictDevtoolsHook })\n .__FICT_DEVTOOLS_HOOK__\n}\n\nexport function getDevtoolsHook(): FictDevtoolsHook | undefined {\n return getGlobalHook()\n}\n","import { getDevtoolsHook } from './devtools'\n\nconst isDev =\n typeof __DEV__ !== 'undefined'\n ? __DEV__\n : typeof process === 'undefined' || process.env?.NODE_ENV !== 'production'\n\nexport interface CycleProtectionOptions {\n /** Enable cycle protection guards (defaults to dev-only) */\n enabled?: boolean\n maxFlushCyclesPerMicrotask?: number\n maxEffectRunsPerFlush?: number\n windowSize?: number\n highUsageRatio?: number\n maxRootReentrantDepth?: number\n enableWindowWarning?: boolean\n devMode?: boolean\n /** Enable backoff warnings at 50% and 75% of limits */\n enableBackoffWarning?: boolean\n /** Ratio at which to show first backoff warning (default 0.5) */\n backoffWarningRatio?: number\n}\n\ninterface CycleWindowEntry {\n used: number\n budget: number\n}\n\nlet setCycleProtectionOptions: (opts: CycleProtectionOptions) => void = () => {}\nlet resetCycleProtectionStateForTests: () => void = () => {}\nlet beginFlushGuard: () => void = () => {}\nlet beforeEffectRunGuard: () => boolean = () => true\nlet endFlushGuard: () => void = () => {}\nlet enterRootGuard: (root: object) => boolean = () => true\nlet exitRootGuard: (root: object) => void = () => {}\n\nconst defaultOptions = {\n enabled: isDev,\n maxFlushCyclesPerMicrotask: 10_000,\n maxEffectRunsPerFlush: 20_000,\n windowSize: 5,\n highUsageRatio: 0.8,\n maxRootReentrantDepth: 10,\n enableWindowWarning: true,\n devMode: isDev,\n // Backoff warning options\n enableBackoffWarning: isDev,\n backoffWarningRatio: 0.5,\n}\n\nlet enabled = defaultOptions.enabled\nlet options: Required<CycleProtectionOptions> = {\n ...defaultOptions,\n} as Required<CycleProtectionOptions>\n\nlet effectRunsThisFlush = 0\nlet windowUsage: CycleWindowEntry[] = []\nlet rootDepth = new WeakMap<object, number>()\nlet flushWarned = false\nlet rootWarned = false\nlet windowWarned = false\n// Backoff warning state\nlet backoffWarned50 = false\nlet backoffWarned75 = false\n\nsetCycleProtectionOptions = opts => {\n if (typeof opts.enabled === 'boolean') {\n enabled = opts.enabled\n }\n options = { ...options, ...opts }\n}\n\nresetCycleProtectionStateForTests = () => {\n options = { ...defaultOptions } as Required<CycleProtectionOptions>\n enabled = defaultOptions.enabled\n effectRunsThisFlush = 0\n windowUsage = []\n rootDepth = new WeakMap<object, number>()\n flushWarned = false\n rootWarned = false\n windowWarned = false\n // Reset backoff state\n backoffWarned50 = false\n backoffWarned75 = false\n}\n\nbeginFlushGuard = () => {\n if (!enabled) return\n effectRunsThisFlush = 0\n flushWarned = false\n windowWarned = false\n // Reset backoff state for new flush\n backoffWarned50 = false\n backoffWarned75 = false\n}\n\nbeforeEffectRunGuard = () => {\n if (!enabled) return true\n const next = ++effectRunsThisFlush\n const limit = Math.min(options.maxFlushCyclesPerMicrotask, options.maxEffectRunsPerFlush)\n\n // Backoff warnings at 50% and 75% of limit\n if (options.enableBackoffWarning && isDev) {\n const ratio = next / limit\n const backoffRatio = options.backoffWarningRatio ?? 0.5\n\n if (!backoffWarned50 && ratio >= backoffRatio && ratio < backoffRatio + 0.25) {\n backoffWarned50 = true\n console.warn(\n `[fict] cycle guard: approaching effect limit (${Math.round(ratio * 100)}% of budget used)\\n` +\n ` - Current: ${next} effects, Limit: ${limit}\\n` +\n ` - Tip: Check for effects that trigger other effects in a loop.\\n` +\n ` - Common causes: signal updates inside effects that read and write the same signal.`,\n )\n } else if (!backoffWarned75 && ratio >= backoffRatio + 0.25 && ratio < 1) {\n backoffWarned75 = true\n console.warn(\n `[fict] cycle guard: nearing effect limit (${Math.round(ratio * 100)}% of budget used)\\n` +\n ` - Current: ${next} effects, Limit: ${limit}\\n` +\n ` - Warning: Consider breaking the reactive dependency cycle.\\n` +\n ` - Debug: Use browser devtools to identify the recursive effect chain.`,\n )\n }\n }\n\n if (next > limit) {\n const message = `[fict] cycle protection triggered: flush-budget-exceeded`\n if (options.devMode) {\n throw new Error(\n message +\n `\\n - Effect runs: ${next}, Limit: ${limit}` +\n `\\n - This indicates a reactive cycle where effects keep triggering each other.` +\n `\\n - Check for patterns like: createEffect(() => { signal(); signal(newValue); })`,\n )\n }\n if (!flushWarned) {\n flushWarned = true\n console.warn(message, { effectRuns: next, limit })\n }\n return false\n }\n return true\n}\n\nendFlushGuard = () => {\n if (!enabled) return\n recordWindowUsage(effectRunsThisFlush, options.maxFlushCyclesPerMicrotask)\n effectRunsThisFlush = 0\n}\n\nenterRootGuard = root => {\n if (!enabled) return true\n const depth = (rootDepth.get(root) ?? 0) + 1\n if (depth > options.maxRootReentrantDepth) {\n const message = `[fict] cycle protection triggered: root-reentry`\n if (options.devMode) {\n throw new Error(\n message +\n `\\n - Re-entry depth: ${depth}, Max allowed: ${options.maxRootReentrantDepth}` +\n `\\n - This indicates recursive render() or component initialization.` +\n `\\n - Check for components that trigger re-renders during their own render phase.`,\n )\n }\n if (!rootWarned) {\n rootWarned = true\n console.warn(message, { depth, maxAllowed: options.maxRootReentrantDepth })\n }\n return false\n }\n rootDepth.set(root, depth)\n return true\n}\n\nexitRootGuard = root => {\n if (!enabled) return\n const depth = rootDepth.get(root)\n if (depth === undefined) return\n if (depth <= 1) {\n rootDepth.delete(root)\n } else {\n rootDepth.set(root, depth - 1)\n }\n}\n\nconst recordWindowUsage = (used: number, budget: number): void => {\n if (!options.enableWindowWarning) return\n const entry = { used, budget }\n windowUsage.push(entry)\n if (windowUsage.length > options.windowSize) {\n windowUsage.shift()\n }\n if (windowWarned) return\n if (\n windowUsage.length >= options.windowSize &&\n windowUsage.every(item => item.budget > 0 && item.used / item.budget >= options.highUsageRatio)\n ) {\n windowWarned = true\n reportCycle('high-usage-window', {\n windowSize: options.windowSize,\n ratio: options.highUsageRatio,\n })\n }\n}\n\nconst reportCycle = (\n reason: string,\n detail: Record<string, unknown> | undefined = undefined,\n): void => {\n const hook = getDevtoolsHook()\n hook?.cycleDetected?.(detail ? { reason, detail } : { reason })\n console.warn(`[fict] cycle protection triggered: ${reason}`, detail ?? '')\n}\n\nexport {\n setCycleProtectionOptions,\n resetCycleProtectionStateForTests,\n beginFlushGuard,\n beforeEffectRunGuard,\n endFlushGuard,\n enterRootGuard,\n exitRootGuard,\n}\n","import { enterRootGuard, exitRootGuard } from './cycle-guard'\nimport type { Cleanup, ErrorInfo, SuspenseToken } from './types'\n\nconst isDev =\n typeof __DEV__ !== 'undefined'\n ? __DEV__\n : typeof process === 'undefined' || process.env?.NODE_ENV !== 'production'\n\ntype LifecycleFn = () => void | Cleanup\n\nexport interface RootContext {\n parent?: RootContext | undefined\n onMountCallbacks?: LifecycleFn[]\n cleanups: Cleanup[]\n destroyCallbacks: Cleanup[]\n errorHandlers?: ErrorHandler[]\n suspenseHandlers?: SuspenseHandler[]\n suspended?: boolean\n}\n\nexport interface CreateRootOptions {\n inherit?: boolean\n}\n\ntype ErrorHandler = (err: unknown, info?: ErrorInfo) => boolean | void\ntype SuspenseHandler = (token: SuspenseToken | PromiseLike<unknown>) => boolean | void\n\nlet currentRoot: RootContext | undefined\nlet currentEffectCleanups: Cleanup[] | undefined\nconst globalErrorHandlers = new WeakMap<RootContext, ErrorHandler[]>()\nconst globalSuspenseHandlers = new WeakMap<RootContext, SuspenseHandler[]>()\n\nexport function createRootContext(parent?: RootContext): RootContext {\n return { parent, cleanups: [], destroyCallbacks: [], suspended: false }\n}\n\nexport function pushRoot(root: RootContext): RootContext | undefined {\n if (!enterRootGuard(root)) {\n return currentRoot\n }\n const prev = currentRoot\n currentRoot = root\n return prev\n}\n\nexport function getCurrentRoot(): RootContext | undefined {\n return currentRoot\n}\n\nexport function popRoot(prev: RootContext | undefined): void {\n if (currentRoot) {\n exitRootGuard(currentRoot)\n }\n currentRoot = prev\n}\n\nexport function onMount(fn: LifecycleFn): void {\n if (currentRoot) {\n ;(currentRoot.onMountCallbacks ||= []).push(fn)\n return\n }\n runLifecycle(fn)\n}\n\nexport function onDestroy(fn: LifecycleFn): void {\n if (currentRoot) {\n currentRoot.destroyCallbacks.push(() => runLifecycle(fn))\n return\n }\n runLifecycle(fn)\n}\n\nexport function onCleanup(fn: Cleanup): void {\n registerEffectCleanup(fn)\n}\n\nexport function flushOnMount(root: RootContext): void {\n const cbs = root.onMountCallbacks\n if (!cbs || cbs.length === 0) return\n // Temporarily restore root context so onCleanup calls inside\n // mount callbacks register correctly\n const prevRoot = currentRoot\n currentRoot = root\n try {\n for (let i = 0; i < cbs.length; i++) {\n const cleanup = cbs[i]!()\n if (typeof cleanup === 'function') {\n root.cleanups.push(cleanup)\n }\n }\n } finally {\n currentRoot = prevRoot\n cbs.length = 0\n }\n}\n\nexport function registerRootCleanup(fn: Cleanup): void {\n if (currentRoot) {\n currentRoot.cleanups.push(fn)\n }\n}\n\nexport function clearRoot(root: RootContext): void {\n runCleanupList(root.cleanups)\n if (root.onMountCallbacks) {\n root.onMountCallbacks.length = 0\n }\n}\n\nexport function destroyRoot(root: RootContext): void {\n clearRoot(root)\n runCleanupList(root.destroyCallbacks)\n if (root.errorHandlers) {\n root.errorHandlers.length = 0\n }\n if (globalErrorHandlers.has(root)) {\n globalErrorHandlers.delete(root)\n }\n if (root.suspenseHandlers) {\n root.suspenseHandlers.length = 0\n }\n if (globalSuspenseHandlers.has(root)) {\n globalSuspenseHandlers.delete(root)\n }\n}\n\nexport function createRoot<T>(\n fn: () => T,\n options?: CreateRootOptions,\n): { dispose: () => void; value: T } {\n const parent = options?.inherit ? currentRoot : undefined\n const root = createRootContext(parent)\n const prev = pushRoot(root)\n let value: T\n try {\n value = fn()\n } finally {\n popRoot(prev)\n }\n flushOnMount(root)\n return {\n dispose: () => destroyRoot(root),\n value,\n }\n}\n\nexport function withEffectCleanups<T>(bucket: Cleanup[], fn: () => T): T {\n const prev = currentEffectCleanups\n currentEffectCleanups = bucket\n try {\n return fn()\n } finally {\n currentEffectCleanups = prev\n }\n}\n\nexport function registerEffectCleanup(fn: Cleanup): void {\n if (currentEffectCleanups) {\n currentEffectCleanups.push(fn)\n } else {\n registerRootCleanup(fn)\n }\n}\n\nexport function runCleanupList(list: Cleanup[]): void {\n let error: unknown\n for (let i = list.length - 1; i >= 0; i--) {\n try {\n const cleanup = list[i]\n if (cleanup) cleanup()\n } catch (err) {\n if (error === undefined) {\n error = err\n }\n }\n }\n list.length = 0\n if (error !== undefined) {\n if (!handleError(error, { source: 'cleanup' })) {\n throw error\n }\n }\n}\n\nfunction runLifecycle(fn: LifecycleFn): void {\n const cleanup = fn()\n if (typeof cleanup === 'function') {\n cleanup()\n }\n}\n\nexport function registerErrorHandler(fn: ErrorHandler): void {\n if (!currentRoot) {\n const message = isDev\n ? 'registerErrorHandler must be called within a root'\n : 'FICT:E_ROOT_HANDLER'\n throw new Error(message)\n }\n if (!currentRoot.errorHandlers) {\n currentRoot.errorHandlers = []\n }\n currentRoot.errorHandlers.push(fn)\n const existing = globalErrorHandlers.get(currentRoot)\n if (existing) {\n existing.push(fn)\n } else {\n globalErrorHandlers.set(currentRoot, [fn])\n }\n}\n\nexport function registerSuspenseHandler(fn: SuspenseHandler): void {\n if (!currentRoot) {\n const message = isDev\n ? 'registerSuspenseHandler must be called within a root'\n : 'FICT:E_ROOT_SUSPENSE'\n throw new Error(message)\n }\n if (!currentRoot.suspenseHandlers) {\n currentRoot.suspenseHandlers = []\n }\n currentRoot.suspenseHandlers.push(fn)\n const existing = globalSuspenseHandlers.get(currentRoot)\n if (existing) {\n existing.push(fn)\n } else {\n globalSuspenseHandlers.set(currentRoot, [fn])\n }\n}\n\nexport function handleError(err: unknown, info?: ErrorInfo, startRoot?: RootContext): boolean {\n let root: RootContext | undefined = startRoot ?? currentRoot\n let error = err\n while (root) {\n const handlers = root.errorHandlers\n if (handlers && handlers.length) {\n for (let i = handlers.length - 1; i >= 0; i--) {\n const handler = handlers[i]!\n try {\n const handled = handler(error, info)\n if (handled !== false) {\n return true\n }\n } catch (nextErr) {\n error = nextErr\n }\n }\n }\n root = root.parent\n }\n const globalForRoot = startRoot\n ? globalErrorHandlers.get(startRoot)\n : currentRoot\n ? globalErrorHandlers.get(currentRoot)\n : undefined\n if (globalForRoot && globalForRoot.length) {\n for (let i = globalForRoot.length - 1; i >= 0; i--) {\n const handler = globalForRoot[i]!\n try {\n const handled = handler(error, info)\n if (handled !== false) {\n return true\n }\n } catch (nextErr) {\n error = nextErr\n }\n }\n }\n // The caller (e.g., runCleanupList) can decide whether to rethrow.\n // This makes the API consistent: handleError always returns a boolean\n // indicating whether the error was handled.\n return false\n}\n\nexport function handleSuspend(\n token: SuspenseToken | PromiseLike<unknown>,\n startRoot?: RootContext,\n): boolean {\n let root: RootContext | undefined = startRoot ?? currentRoot\n const originRoot = root // Preserve reference to set suspended flag on success\n while (root) {\n const handlers = root.suspenseHandlers\n if (handlers && handlers.length) {\n for (let i = handlers.length - 1; i >= 0; i--) {\n const handler = handlers[i]!\n const handled = handler(token)\n if (handled !== false) {\n // Only set suspended = true when a handler actually handles the token\n if (originRoot) originRoot.suspended = true\n return true\n }\n }\n }\n root = root.parent\n }\n const globalForRoot =\n startRoot && globalSuspenseHandlers.get(startRoot)\n ? globalSuspenseHandlers.get(startRoot)\n : currentRoot\n ? globalSuspenseHandlers.get(currentRoot)\n : undefined\n if (globalForRoot && globalForRoot.length) {\n for (let i = globalForRoot.length - 1; i >= 0; i--) {\n const handler = globalForRoot[i]!\n const handled = handler(token)\n if (handled !== false) {\n // Only set suspended = true when a handler actually handles the token\n if (originRoot) originRoot.suspended = true\n return true\n }\n }\n }\n return false\n}\n","import {\n getCurrentRoot,\n handleError,\n handleSuspend,\n registerRootCleanup,\n runCleanupList,\n withEffectCleanups,\n} from './lifecycle'\nimport { effectWithCleanup } from './signal'\nimport type { Cleanup } from './types'\n\n/**\n * Effect callback run synchronously; async callbacks are not tracked after the first await.\n * TypeScript will reject `async () => {}` here—split async work or read signals before awaiting.\n */\nexport type Effect = () => void | Cleanup\n\nexport function createEffect(fn: Effect): () => void {\n let cleanups: Cleanup[] = []\n const rootForError = getCurrentRoot()\n\n // Cleanup runner - called by runEffect BEFORE signal values are committed\n const doCleanup = () => {\n runCleanupList(cleanups)\n cleanups = []\n }\n\n const run = () => {\n // Note: cleanups are now run by signal.ts runEffect before this function is called\n const bucket: Cleanup[] = []\n withEffectCleanups(bucket, () => {\n try {\n const maybeCleanup = fn()\n if (typeof maybeCleanup === 'function') {\n bucket.push(maybeCleanup)\n }\n } catch (err) {\n if (handleSuspend(err as any, rootForError)) {\n return\n }\n if (handleError(err, { source: 'effect' }, rootForError)) {\n return\n }\n throw err\n }\n })\n cleanups = bucket\n }\n\n const disposeEffect = effectWithCleanup(run, doCleanup, rootForError)\n const teardown = () => {\n runCleanupList(cleanups)\n disposeEffect()\n }\n\n registerRootCleanup(teardown)\n\n return teardown\n}\n\nexport const $effect = createEffect\n\nexport function createRenderEffect(fn: Effect): () => void {\n let cleanup: Cleanup | undefined\n const rootForError = getCurrentRoot()\n\n // Cleanup runner - called by runEffect BEFORE signal values are committed\n const doCleanup = () => {\n if (cleanup) {\n cleanup()\n cleanup = undefined\n }\n }\n\n const run = () => {\n // Note: cleanups are now run by signal.ts runEffect before this function is called\n try {\n const maybeCleanup = fn()\n if (typeof maybeCleanup === 'function') {\n cleanup = maybeCleanup\n }\n } catch (err) {\n if (handleSuspend(err as any, rootForError)) {\n return\n }\n const handled = handleError(err, { source: 'effect' }, rootForError)\n if (handled) {\n return\n }\n throw err\n }\n }\n\n const disposeEffect = effectWithCleanup(run, doCleanup, rootForError)\n const teardown = () => {\n if (cleanup) {\n cleanup()\n cleanup = undefined\n }\n disposeEffect()\n }\n\n registerRootCleanup(teardown)\n\n return teardown\n}\n","import { createEffect } from './effect'\nimport { createMemo } from './memo'\nimport {\n createSignal,\n type SignalAccessor,\n type ComputedAccessor,\n type MemoOptions,\n type SignalOptions,\n} from './signal'\n\nconst isDev =\n typeof __DEV__ !== 'undefined'\n ? __DEV__\n : typeof process === 'undefined' || process.env?.NODE_ENV !== 'production'\n\nexport interface HookContext {\n slots: unknown[]\n cursor: number\n rendering?: boolean\n componentId?: number\n parentId?: number\n scopeId?: string\n scopeType?: string\n slotMap?: Record<string, number>\n}\n\nconst ctxStack: HookContext[] = []\nlet preparedContext: HookContext | null = null\n\nfunction assertRenderContext(ctx: HookContext, hookName: string): void {\n if (!ctx.rendering) {\n const message = isDev\n ? `${hookName} can only be used during render execution`\n : 'FICT:E_HOOK_RENDER'\n throw new Error(message)\n }\n}\n\nexport function __fictUseContext(): HookContext {\n if (ctxStack.length === 0) {\n // fix: Don't silently create context when called outside render.\n // This would cause a memory leak and undefined behavior.\n const message = isDev\n ? 'Invalid hook call: hooks can only be used while rendering a component. ' +\n 'Make sure you are not calling hooks in event handlers or outside of components.'\n : 'FICT:E_HOOK_OUTSIDE_RENDER'\n throw new Error(message)\n }\n const ctx = ctxStack[ctxStack.length - 1]!\n // fix: Only reset cursor when starting a new render, not during an existing render.\n // This allows custom hooks to share the same hook slot sequence as the calling component,\n // similar to React's \"rules of hooks\" where hooks are called in consistent order.\n if (!ctx.rendering) {\n ctx.cursor = 0\n ctx.rendering = true\n }\n return ctx\n}\n\nexport function __fictPushContext(): HookContext {\n const ctx: HookContext = preparedContext ?? { slots: [], cursor: 0 }\n preparedContext = null\n ctxStack.push(ctx)\n return ctx\n}\n\nexport function __fictPrepareContext(ctx: HookContext): void {\n preparedContext = ctx\n}\n\nexport function __fictGetCurrentComponentId(): number | undefined {\n return ctxStack[ctxStack.length - 1]?.componentId\n}\n\nexport function __fictPopContext(): void {\n // fix: Reset rendering flag when popping to avoid state leakage\n const ctx = ctxStack.pop()\n if (ctx) ctx.rendering = false\n}\n\nexport function __fictResetContext(): void {\n ctxStack.length = 0\n}\n\nexport function __fictUseSignal<T>(\n ctx: HookContext,\n initial: T,\n optionsOrSlot?: number | SignalOptions<T>,\n slot?: number,\n): SignalAccessor<T> {\n assertRenderContext(ctx, '__fictUseSignal')\n const options = typeof optionsOrSlot === 'number' ? undefined : optionsOrSlot\n const resolvedSlot = typeof optionsOrSlot === 'number' ? optionsOrSlot : slot\n const index = resolvedSlot ?? ctx.cursor++\n if (!ctx.slots[index]) {\n ctx.slots[index] = createSignal(initial, options)\n }\n if (options?.name) {\n if (!ctx.slotMap) ctx.slotMap = {}\n ctx.slotMap[options.name] = index\n }\n return ctx.slots[index] as SignalAccessor<T>\n}\n\nexport function __fictUseMemo<T>(\n ctx: HookContext,\n fn: () => T,\n optionsOrSlot?: number | MemoOptions<T>,\n slot?: number,\n): ComputedAccessor<T> {\n assertRenderContext(ctx, '__fictUseMemo')\n const options = typeof optionsOrSlot === 'number' ? undefined : optionsOrSlot\n const resolvedSlot = typeof optionsOrSlot === 'number' ? optionsOrSlot : slot\n const index = resolvedSlot ?? ctx.cursor++\n if (!ctx.slots[index]) {\n ctx.slots[index] = createMemo(fn, options)\n }\n return ctx.slots[index] as ComputedAccessor<T>\n}\n\nexport function __fictUseEffect(ctx: HookContext, fn: () => void, slot?: number): void {\n // fix: When a slot number is provided, we trust the compiler has allocated this slot.\n // This allows effects inside conditional callbacks to work even outside render context.\n // The slot number proves this is a known, statically-allocated effect location.\n if (slot !== undefined) {\n if (ctx.slots[slot]) {\n // Effect already exists, nothing to do\n return\n }\n // Create the effect even outside render context - the slot number proves validity\n ctx.slots[slot] = createEffect(fn)\n return\n }\n\n // For cursor-based allocation (no slot number), we need render context\n assertRenderContext(ctx, '__fictUseEffect')\n const index = ctx.cursor++\n if (!ctx.slots[index]) {\n ctx.slots[index] = createEffect(fn)\n }\n}\n\nexport function __fictRender<T>(ctx: HookContext, fn: () => T): T {\n ctxStack.push(ctx)\n ctx.cursor = 0\n ctx.rendering = true\n try {\n return fn()\n } finally {\n ctx.rendering = false\n ctxStack.pop()\n }\n}\n","import { beginFlushGuard, beforeEffectRunGuard, endFlushGuard } from './cycle-guard'\nimport { getDevtoolsHook } from './devtools'\nimport { __fictGetCurrentComponentId } from './hooks'\nimport {\n getCurrentRoot,\n handleError,\n handleSuspend,\n registerRootCleanup,\n type RootContext,\n} from './lifecycle'\nimport type { SuspenseToken } from './types'\n\nconst isDev =\n typeof __DEV__ !== 'undefined'\n ? __DEV__\n : typeof process === 'undefined' || process.env?.NODE_ENV !== 'production'\n\n// ============================================================================\n// Type Definitions\n// ============================================================================\n\n/**\n * Reactive node that can be either a signal, computed, effect, or effect scope\n */\nexport type ReactiveNode =\n | SignalNode<unknown>\n | ComputedNode<unknown>\n | EffectNode\n | EffectScopeNode\n | SubscriberNode\n\n/**\n * Link between a dependency and a subscriber in the reactive graph\n */\nexport interface Link {\n /** Version/cycle when this link was created */\n version: number\n /** The dependency being tracked */\n dep: ReactiveNode\n /** The subscriber tracking this dependency */\n sub: ReactiveNode\n /** Previous dependency link in the subscriber's dependency list */\n prevDep: Link | undefined\n /** Next dependency link in the subscriber's dependency list */\n nextDep: Link | undefined\n /** Previous subscriber link in the dependency's subscriber list */\n prevSub: Link | undefined\n /** Next subscriber link in the dependency's subscriber list */\n nextSub: Link | undefined\n}\n\n/**\n * Stack frame for traversing the reactive graph\n */\nexport interface StackFrame {\n /** The link value at this stack level */\n value: Link | undefined\n /** Previous stack frame */\n prev: StackFrame | undefined\n}\n\n/**\n * Base interface for all reactive nodes\n */\nexport interface BaseNode {\n /** First subscriber link */\n subs: Link | undefined\n /** Last subscriber link */\n subsTail: Link | undefined\n /** Reactive flags (Mutable, Watching, Running, etc.) */\n flags: number\n}\n\n/**\n * Options for creating a signal\n */\nexport interface SignalOptions<T> {\n /** Custom equality check */\n equals?: false | ((prev: T, next: T) => boolean)\n /** Debug name */\n name?: string\n /** Source location */\n devToolsSource?: string\n}\n\n/**\n * Options for creating a memo\n */\nexport interface MemoOptions<T> {\n /** Custom equality check */\n equals?: false | ((prev: T, next: T) => boolean)\n /** Debug name */\n name?: string\n /** Source location */\n devToolsSource?: string\n}\n\n/**\n * Signal node - mutable reactive value\n */\nexport interface SignalNode<T = unknown> extends BaseNode {\n /** Current committed value */\n currentValue: T\n /** Pending value to be committed */\n pendingValue: T\n /** Previous committed value (for cleanup reads) */\n prevValue?: T\n /** Flush id when prevValue was recorded */\n prevFlushId?: number\n /** Signals don't have dependencies */\n deps?: undefined\n depsTail?: undefined\n getter?: undefined\n /** DevTools ID */\n __id?: number | undefined\n /** Equality check */\n equals?: false | ((prev: T, next: T) => boolean)\n /** Debug name */\n name?: string\n /** Source location */\n devToolsSource?: string\n}\n\n/**\n * Computed node - derived reactive value\n */\nexport interface ComputedNode<T = unknown> extends BaseNode {\n /** Current computed value */\n value: T\n /** Previous computed value (for cleanup reads) */\n prevValue?: T\n /** Flush id when prevValue was recorded */\n prevFlushId?: number\n /** First dependency link */\n deps: Link | undefined\n /** Last dependency link */\n depsTail: Link | undefined\n /** Getter function to compute the value */\n getter: (oldValue: T | undefined) => T\n /** DevTools ID */\n __id?: number | undefined\n /** Equality check */\n equals?: false | ((prev: T, next: T) => boolean)\n /** Debug name */\n name?: string\n /** Source location */\n devToolsSource?: string\n}\n\n/**\n * Effect node - side effect that runs when dependencies change\n */\nexport interface EffectNode extends BaseNode {\n /** Effect function to execute */\n fn: () => void\n /** First dependency link */\n deps: Link | undefined\n /** Last dependency link */\n depsTail: Link | undefined\n /** Optional cleanup runner to be called before checkDirty */\n runCleanup?: () => void\n /** Root context for error/suspense handling */\n root?: RootContext\n /** Devtools ID */\n __id?: number | undefined\n}\n\n/**\n * Effect scope node - manages multiple effects\n */\nexport interface EffectScopeNode extends BaseNode {\n /** First dependency link */\n deps: Link | undefined\n /** Last dependency link */\n depsTail: Link | undefined\n}\n\n/**\n * Subscriber node used in trigger\n */\nexport interface SubscriberNode {\n /** First dependency link */\n deps: Link | undefined\n /** Last dependency link */\n depsTail: Link | undefined\n /** Reactive flags */\n flags: number\n subs?: undefined\n subsTail?: undefined\n}\n\n/**\n * Signal accessor - function to get/set signal value\n */\nexport interface SignalAccessor<T> {\n (): T\n (value: T): void\n}\n\n/**\n * Computed accessor - function to get computed value\n */\nexport type ComputedAccessor<T> = () => T\n\n/**\n * Effect disposer - function to dispose an effect\n */\nexport type EffectDisposer = () => void\n\n/**\n * Effect scope disposer - function to dispose an effect scope\n */\nexport type EffectScopeDisposer = () => void\n\n/**\n * Options for creating a custom reactive system\n */\nexport interface ReactiveSystemOptions {\n /** Update function for reactive nodes */\n update: (node: ReactiveNode) => boolean\n /** Notify function when a subscriber needs to be notified */\n notify: (sub: ReactiveNode) => void\n /** Callback when a dependency becomes unwatched */\n unwatched: (dep: ReactiveNode) => void\n}\n\n/**\n * Custom reactive system methods\n */\nexport interface ReactiveSystem {\n /** Link a dependency to a subscriber */\n link: typeof link\n /** Unlink a dependency from a subscriber */\n unlink: (lnk: Link, sub?: ReactiveNode) => Link | undefined\n /** Propagate changes through the reactive graph */\n propagate: (firstLink: Link) => void\n /** Check if a node is dirty */\n checkDirty: (firstLink: Link, sub: ReactiveNode) => boolean\n /** Shallow propagate changes */\n shallowPropagate: (firstLink: Link) => void\n}\n\n// ============================================================================\n// Flags\n// ============================================================================\nconst Mutable = 1\nconst Watching = 2\nconst Running = 4\nconst Recursed = 8\nconst Dirty = 16\nconst Pending = 32\n// Pre-computed combinations\nconst MutableDirty = 17\nconst MutablePending = 33\nconst MutableRunning = 5\nconst WatchingRunning = 6\n// Global state\nlet cycle = 0\nlet batchDepth = 0\nlet activeSub: ReactiveNode | undefined\nlet flushScheduled = false\nlet currentFlushId = 0\nlet activeCleanupFlushId = 0\n// Dual-priority queue for scheduler\nconst highPriorityQueue: EffectNode[] = []\nconst lowPriorityQueue: EffectNode[] = []\nlet isInTransition = false\nconst enqueueMicrotask =\n typeof queueMicrotask === 'function'\n ? queueMicrotask\n : (fn: () => void) => {\n Promise.resolve().then(fn)\n }\n// Flag to indicate cleanup is running - signal reads should return currentValue without updating\nlet inCleanup = false\n// This ensures type detection works correctly even after minification\nconst SIGNAL_MARKER = Symbol.for('fict:signal')\nconst COMPUTED_MARKER = Symbol.for('fict:computed')\nconst EFFECT_MARKER = Symbol.for('fict:effect')\nconst EFFECT_SCOPE_MARKER = Symbol.for('fict:effectScope')\nexport const ReactiveFlags = {\n None: 0,\n Mutable,\n Watching,\n RecursedCheck: Running,\n Recursed,\n Dirty,\n Pending,\n}\n// ============================================================================\n// createReactiveSystem - Support for custom systems\n// ============================================================================\n/**\n * Create a custom reactive system with custom update, notify, and unwatched handlers\n * @param options - Reactive system options\n * @returns Custom reactive system methods\n */\nexport function createReactiveSystem({\n update,\n notify: notifyFn,\n unwatched: unwatchedFn,\n}: ReactiveSystemOptions): ReactiveSystem {\n function customPropagate(firstLink: Link): void {\n let link = firstLink\n let next = link.nextSub\n let stack: StackFrame | undefined\n\n top: for (;;) {\n const sub = link.sub\n let flags = sub.flags\n\n if (!(flags & 60)) {\n sub.flags = flags | Pending\n } else if (!(flags & 12)) {\n flags = 0\n } else if (!(flags & Running)) {\n sub.flags = (flags & ~Recursed) | Pending\n } else if (!(flags & 48)) {\n let vlink = sub.depsTail\n let valid = false\n while (vlink !== undefined) {\n if (vlink === link) {\n valid = true\n break\n }\n vlink = vlink.prevDep\n }\n if (valid) {\n sub.flags = flags | 40\n flags &= Mutable\n } else {\n flags = 0\n }\n } else {\n flags = 0\n }\n\n if (flags & Watching) notifyFn(sub)\n\n if (flags & Mutable) {\n const subSubs = sub.subs\n if (subSubs !== undefined) {\n const nextSub = subSubs.nextSub\n if (nextSub !== undefined) {\n stack = { value: next, prev: stack }\n next = nextSub\n }\n link = subSubs\n continue\n }\n }\n\n if (next !== undefined) {\n link = next\n next = link.nextSub\n continue\n }\n\n while (stack !== undefined) {\n link = stack.value!\n stack = stack.prev\n if (link !== undefined) {\n next = link.nextSub\n continue top\n }\n }\n break\n }\n }\n function customCheckDirty(firstLink: Link, sub: ReactiveNode): boolean {\n let link = firstLink\n let stack: StackFrame | undefined\n let checkDepth = 0\n let dirty = false\n\n top: for (;;) {\n const dep = link.dep\n const depFlags = dep.flags\n\n if (sub.flags & Dirty) {\n dirty = true\n } else if ((depFlags & MutableDirty) === MutableDirty) {\n if (update(dep)) {\n const subs = dep.subs\n if (subs !== undefined && subs.nextSub !== undefined) {\n customShallowPropagate(subs)\n }\n dirty = true\n }\n } else if ((depFlags & MutablePending) === MutablePending) {\n if (!dep.deps) {\n const nextDep = link.nextDep\n if (nextDep !== undefined) {\n link = nextDep\n continue\n }\n } else {\n if (link.nextSub !== undefined || link.prevSub !== undefined) {\n stack = { value: link, prev: stack }\n }\n link = dep.deps\n sub = dep\n ++checkDepth\n continue\n }\n }\n\n if (!dirty) {\n const nextDep = link.nextDep\n if (nextDep !== undefined) {\n link = nextDep\n continue\n }\n }\n\n while (checkDepth-- > 0) {\n const firstSub = sub.subs!\n const hasMultipleSubs = firstSub.nextSub !== undefined\n\n if (hasMultipleSubs) {\n link = stack!.value!\n stack = stack!.prev\n } else link = firstSub\n\n if (dirty) {\n if (update(sub)) {\n if (hasMultipleSubs) customShallowPropagate(firstSub)\n sub = link.sub\n continue\n }\n dirty = false\n } else {\n sub.flags &= ~Pending\n }\n\n sub = link.sub\n const nextDep = link.nextDep\n if (nextDep !== undefined) {\n link = nextDep\n continue top\n }\n }\n\n return dirty\n }\n }\n function customShallowPropagate(firstLink: Link): void {\n let link: Link | undefined = firstLink\n do {\n const sub = link.sub\n const flags = sub.flags\n if ((flags & 48) === Pending) {\n sub.flags = flags | Dirty\n if ((flags & 6) === Watching) notifyFn(sub)\n }\n link = link.nextSub\n } while (link !== undefined)\n }\n function customUnlink(lnk: Link, sub: ReactiveNode = lnk.sub): Link | undefined {\n const dep = lnk.dep\n const prevDep = lnk.prevDep\n const nextDep = lnk.nextDep\n const nextSub = lnk.nextSub\n const prevSub = lnk.prevSub\n\n if (nextDep !== undefined) nextDep.prevDep = prevDep\n else sub.depsTail = prevDep\n if (prevDep !== undefined) prevDep.nextDep = nextDep\n else sub.deps = nextDep\n\n if (nextSub !== undefined) nextSub.prevSub = prevSub\n else dep.subsTail = prevSub\n if (prevSub !== undefined) prevSub.nextSub = nextSub\n else if ((dep.subs = nextSub) === undefined) unwatchedFn(dep)\n\n return nextDep\n }\n return {\n link,\n unlink: customUnlink,\n propagate: customPropagate,\n checkDirty: customCheckDirty,\n shallowPropagate: customShallowPropagate,\n }\n}\n// ============================================================================\n// Core functions\n// ============================================================================\n/**\n * Create a link between a dependency and a subscriber\n * @param dep - The dependency node\n * @param sub - The subscriber node\n * @param version - The cycle version\n */\nfunction link(dep: ReactiveNode, sub: ReactiveNode, version: number): void {\n const prevDep = sub.depsTail\n if (prevDep !== undefined && prevDep.dep === dep) return\n\n const nextDep = prevDep !== undefined ? prevDep.nextDep : sub.deps\n if (nextDep !== undefined && nextDep.dep === dep) {\n nextDep.version = version\n sub.depsTail = nextDep\n return\n }\n\n const prevSub = dep.subsTail\n if (prevSub !== undefined && prevSub.version === version && prevSub.sub === sub) return\n\n const newLink = { version, dep, sub, prevDep, nextDep, prevSub, nextSub: undefined }\n sub.depsTail = newLink\n dep.subsTail = newLink\n\n if (nextDep !== undefined) nextDep.prevDep = newLink\n if (prevDep !== undefined) prevDep.nextDep = newLink\n else sub.deps = newLink\n if (prevSub !== undefined) prevSub.nextSub = newLink\n else dep.subs = newLink\n\n // Track dependency for devtools\n if (isDev) trackDependencyDevtools(dep, sub)\n}\n/**\n * Remove a link between a dependency and a subscriber\n * @param lnk - The link to remove\n * @param sub - The subscriber node (defaults to lnk.sub)\n * @returns The next dependency link\n */\nfunction unlink(lnk: Link, sub: ReactiveNode = lnk.sub): Link | undefined {\n const dep = lnk.dep\n const prevDep = lnk.prevDep\n const nextDep = lnk.nextDep\n const nextSub = lnk.nextSub\n const prevSub = lnk.prevSub\n\n if (nextDep !== undefined) nextDep.prevDep = prevDep\n else sub.depsTail = prevDep\n if (prevDep !== undefined) prevDep.nextDep = nextDep\n else sub.deps = nextDep\n\n if (nextSub !== undefined) nextSub.prevSub = prevSub\n else dep.subsTail = prevSub\n if (prevSub !== undefined) prevSub.nextSub = nextSub\n else if ((dep.subs = nextSub) === undefined) unwatched(dep)\n\n // Notify devtools that dependency edge is removed\n if (isDev) untrackDependencyDevtools(dep, sub)\n\n return nextDep\n}\n/**\n * Handle when a dependency becomes unwatched\n * @param dep - The dependency node\n */\nfunction unwatched(dep: ReactiveNode): void {\n if (!(dep.flags & Mutable)) {\n disposeNode(dep)\n } else if ('getter' in dep && dep.getter !== undefined) {\n dep.depsTail = undefined\n dep.flags = MutableDirty\n purgeDeps(dep)\n }\n}\n/**\n * Propagate changes through the reactive graph\n * @param firstLink - The first link to propagate from\n */\nfunction propagate(firstLink: Link): void {\n let link = firstLink\n let next = link.nextSub\n let stack: StackFrame | undefined\n\n top: for (;;) {\n const sub = link.sub\n let flags = sub.flags\n\n if (!(flags & 60)) {\n sub.flags = flags | Pending\n } else if (!(flags & 12)) {\n flags = 0\n } else if (!(flags & Running)) {\n sub.flags = (flags & ~Recursed) | Pending\n } else if (!(flags & 48)) {\n let vlink = sub.depsTail\n let valid = false\n while (vlink !== undefined) {\n if (vlink === link) {\n valid = true\n break\n }\n vlink = vlink.prevDep\n }\n if (valid) {\n sub.flags = flags | 40\n flags &= Mutable\n } else {\n flags = 0\n }\n } else {\n flags = 0\n }\n\n if (flags & Watching) notify(sub)\n\n if (flags & Mutable) {\n const subSubs = sub.subs\n if (subSubs !== undefined) {\n const nextSub = subSubs.nextSub\n if (nextSub !== undefined) {\n stack = { value: next, prev: stack }\n next = nextSub\n }\n link = subSubs\n continue\n }\n }\n\n if (next !== undefined) {\n link = next\n next = link.nextSub\n continue\n }\n\n while (stack !== undefined) {\n link = stack.value!\n stack = stack.prev\n if (link !== undefined) {\n next = link.nextSub\n continue top\n }\n }\n break\n }\n}\n/**\n * Check if a node is dirty by traversing its dependencies\n * @param firstLink - The first link to check\n * @param sub - The subscriber node\n * @returns True if the node is dirty\n */\nfunction checkDirty(firstLink: Link, sub: ReactiveNode): boolean {\n let link = firstLink\n let stack: StackFrame | undefined\n let checkDepth = 0\n let dirty = false\n\n top: for (;;) {\n const dep = link.dep\n const depFlags = dep.flags\n\n if (sub.flags & Dirty) {\n dirty = true\n } else if ((depFlags & MutableDirty) === MutableDirty) {\n if (update(dep)) {\n const subs = dep.subs\n if (subs !== undefined && subs.nextSub !== undefined) shallowPropagate(subs)\n dirty = true\n }\n } else if ((depFlags & MutablePending) === MutablePending) {\n if (!dep.deps) {\n // No dependencies to check, skip this node\n const nextDep = link.nextDep\n if (nextDep !== undefined) {\n link = nextDep\n continue\n }\n } else {\n if (link.nextSub !== undefined || link.prevSub !== undefined) {\n stack = { value: link, prev: stack }\n }\n link = dep.deps\n sub = dep\n ++checkDepth\n continue\n }\n }\n\n if (!dirty) {\n const nextDep = link.nextDep\n if (nextDep !== undefined) {\n link = nextDep\n continue\n }\n }\n\n while (checkDepth-- > 0) {\n const firstSub = sub.subs!\n const hasMultipleSubs = firstSub.nextSub !== undefined\n\n if (hasMultipleSubs) {\n link = stack!.value!\n stack = stack!.prev\n } else {\n link = firstSub\n }\n\n if (dirty) {\n if (update(sub)) {\n if (hasMultipleSubs) shallowPropagate(firstSub)\n sub = link.sub\n continue\n }\n dirty = false\n } else {\n sub.flags &= ~Pending\n }\n\n sub = link.sub\n const nextDep = link.nextDep\n if (nextDep !== undefined) {\n link = nextDep\n continue top\n }\n }\n\n return dirty\n }\n}\n/**\n * Shallow propagate changes without traversing deeply\n * @param firstLink - The first link to propagate from\n */\nfunction shallowPropagate(firstLink: Link): void {\n let link: Link | undefined = firstLink\n do {\n const sub = link.sub\n const flags = sub.flags\n if ((flags & 48) === Pending) {\n sub.flags = flags | Dirty\n if ((flags & 6) === Watching) notify(sub)\n }\n link = link.nextSub\n } while (link !== undefined)\n}\n/**\n * Update a reactive node (signal or computed)\n * @param node - The node to update\n * @returns True if the value changed\n */\nfunction update(node: ReactiveNode): boolean {\n return 'getter' in node && node.getter !== undefined\n ? updateComputed(node as ComputedNode)\n : updateSignal(node as SignalNode)\n}\n\nfunction valuesDiffer<T>(\n node: { equals?: false | ((prev: T, next: T) => boolean) },\n prev: T,\n next: T,\n): boolean {\n if (node.equals === false) return true\n if (typeof node.equals === 'function') return !node.equals(prev, next)\n return prev !== next\n}\n/**\n * Notify an effect and add it to the queue\n * @param effect - The effect to notify\n */\nfunction notify(effect: ReactiveNode): void {\n effect.flags &= ~Watching\n const effects: EffectNode[] = []\n\n for (;;) {\n effects.push(effect as EffectNode)\n const nextLink = effect.subs\n if (nextLink === undefined) break\n effect = nextLink.sub\n if (effect === undefined || !(effect.flags & Watching)) break\n effect.flags &= ~Watching\n }\n\n // Route effects to appropriate queue based on transition context\n const targetQueue = isInTransition ? lowPriorityQueue : highPriorityQueue\n for (let i = effects.length - 1; i >= 0; i--) {\n targetQueue.push(effects[i]!)\n }\n}\n/**\n * Purge all dependencies from a subscriber\n * @param sub - The subscriber node\n */\nfunction purgeDeps(sub: ReactiveNode): void {\n const depsTail = sub.depsTail\n let dep = depsTail !== undefined ? depsTail.nextDep : sub.deps\n while (dep !== undefined) dep = unlink(dep, sub)\n}\n/**\n * Dispose a reactive node\n * @param node - The node to dispose\n */\nfunction disposeNode(node: ReactiveNode): void {\n node.depsTail = undefined\n node.flags = 0\n purgeDeps(node)\n let sub = node.subs\n while (sub !== undefined) {\n const next = sub.nextSub\n unlink(sub)\n sub = next\n }\n}\n/**\n * Update a signal node\n * @param s - The signal node\n * @returns True if the value changed\n */\nfunction updateSignal(s: SignalNode): boolean {\n s.flags = Mutable\n const current = s.currentValue\n const pending = s.pendingValue\n if (valuesDiffer(s, current, pending)) {\n s.prevValue = current\n s.prevFlushId = currentFlushId\n s.currentValue = pending\n return true\n }\n return false\n}\n/**\n * Update a computed node\n * @param c - The computed node\n * @returns True if the value changed\n */\nfunction updateComputed<T>(c: ComputedNode<T>): boolean {\n ++cycle\n const oldValue = c.value\n c.depsTail = undefined\n c.flags = MutableRunning\n const prevSub = activeSub\n activeSub = c\n\n try {\n const newValue = c.getter(oldValue)\n activeSub = prevSub\n c.flags &= ~Running\n purgeDeps(c)\n if (valuesDiffer(c, oldValue, newValue)) {\n c.prevValue = oldValue\n c.prevFlushId = currentFlushId\n c.value = newValue\n if (isDev) updateComputedDevtools(c, newValue)\n return true\n }\n return false\n } catch (e) {\n activeSub = prevSub\n c.flags &= ~Running\n throw e\n }\n}\n/**\n * Run an effect\n * @param e - The effect node\n */\nfunction runEffect(e: EffectNode): void {\n const flags = e.flags\n const runCleanup = () => {\n if (!e.runCleanup) return\n inCleanup = true\n activeCleanupFlushId = currentFlushId\n try {\n e.runCleanup()\n } finally {\n activeCleanupFlushId = 0\n inCleanup = false\n }\n }\n if (flags & Dirty) {\n // Run cleanup before re-run; values are still the previous commit.\n runCleanup()\n ++cycle\n if (isDev) effectRunDevtools(e)\n e.depsTail = undefined\n e.flags = WatchingRunning\n const prevSub = activeSub\n activeSub = e\n try {\n e.fn()\n activeSub = prevSub\n e.flags = Watching\n purgeDeps(e)\n } catch (err) {\n activeSub = prevSub\n e.flags = Watching\n throw err\n }\n } else if (flags & Pending && e.deps) {\n let isDirty = false\n try {\n isDirty = checkDirty(e.deps, e)\n } catch (err) {\n if (handleSuspend(err as SuspenseToken, e.root)) {\n if (e.flags !== 0) {\n e.flags = Watching\n }\n return\n }\n if (handleError(err, { source: 'effect' }, e.root)) {\n if (e.flags !== 0) {\n e.flags = Watching\n }\n return\n }\n throw err\n }\n if (isDirty) {\n // Only run cleanup if the effect will actually re-run.\n // Cleanup reads should observe previous values for this flush.\n runCleanup()\n ++cycle\n if (isDev) effectRunDevtools(e)\n e.depsTail = undefined\n e.flags = WatchingRunning\n const prevSub = activeSub\n activeSub = e\n try {\n e.fn()\n activeSub = prevSub\n e.flags = Watching\n purgeDeps(e)\n } catch (err) {\n activeSub = prevSub\n e.flags = Watching\n throw err\n }\n } else {\n e.flags = Watching\n }\n } else {\n e.flags = Watching\n }\n}\n/**\n * Schedule a flush in a microtask to coalesce synchronous writes\n */\nexport function scheduleFlush(): void {\n const hasWork = highPriorityQueue.length > 0 || lowPriorityQueue.length > 0\n if (flushScheduled || !hasWork) return\n if (batchDepth > 0) return\n flushScheduled = true\n enqueueMicrotask(() => {\n flush()\n })\n}\n/**\n * Flush all queued effects with priority-based scheduling\n * High priority effects execute first; low priority can be interrupted\n */\nfunction flush(): void {\n beginFlushGuard()\n if (batchDepth > 0) {\n // If batching is active, defer until the batch completes\n scheduleFlush()\n endFlushGuard()\n return\n }\n const hasWork = highPriorityQueue.length > 0 || lowPriorityQueue.length > 0\n if (!hasWork) {\n flushScheduled = false\n endFlushGuard()\n return\n }\n currentFlushId++\n flushScheduled = false\n\n // 1. Process all high-priority effects first\n let highIndex = 0\n while (highIndex < highPriorityQueue.length) {\n const e = highPriorityQueue[highIndex]!\n if (!beforeEffectRunGuard()) {\n // fix: When cycle guard fails, drop the current queues to avoid microtask spin.\n // Dev mode will throw inside beforeEffectRunGuard; this branch is for prod warnings.\n for (let i = 0; i < highPriorityQueue.length; i++) {\n const queued = highPriorityQueue[i]\n if (queued && queued.flags !== 0) {\n queued.flags = Watching\n }\n }\n for (let i = 0; i < lowPriorityQueue.length; i++) {\n const queued = lowPriorityQueue[i]\n if (queued && queued.flags !== 0) {\n queued.flags = Watching\n }\n }\n highPriorityQueue.length = 0\n lowPriorityQueue.length = 0\n flushScheduled = false\n endFlushGuard()\n return\n }\n highIndex++\n runEffect(e)\n }\n highPriorityQueue.length = 0\n\n // 2. Process low-priority effects, interruptible by high priority\n let lowIndex = 0\n while (lowIndex < lowPriorityQueue.length) {\n // Check if high priority work arrived during low priority execution\n if (highPriorityQueue.length > 0) {\n if (lowIndex > 0) {\n lowPriorityQueue.copyWithin(0, lowIndex)\n lowPriorityQueue.length -= lowIndex\n }\n scheduleFlush()\n endFlushGuard()\n return\n }\n const e = lowPriorityQueue[lowIndex]!\n if (!beforeEffectRunGuard()) {\n // fix: When cycle guard fails, drop the current queues to avoid microtask spin.\n // Dev mode will throw inside beforeEffectRunGuard; this branch is for prod warnings.\n for (let i = 0; i < highPriorityQueue.length; i++) {\n const queued = highPriorityQueue[i]\n if (queued && queued.flags !== 0) {\n queued.flags = Watching\n }\n }\n for (let i = 0; i < lowPriorityQueue.length; i++) {\n const queued = lowPriorityQueue[i]\n if (queued && queued.flags !== 0) {\n queued.flags = Watching\n }\n }\n highPriorityQueue.length = 0\n lowPriorityQueue.length = 0\n flushScheduled = false\n endFlushGuard()\n return\n }\n lowIndex++\n runEffect(e)\n }\n lowPriorityQueue.length = 0\n\n endFlushGuard()\n}\n// ============================================================================\n// Signal - Inline optimized version\n// ============================================================================\n/**\n * Create a reactive signal\n * @param initialValue - The initial value\n * @returns A signal accessor function\n */\nexport function signal<T>(initialValue: T, options?: SignalOptions<T>): SignalAccessor<T> {\n const s: SignalNode<T> = {\n currentValue: initialValue,\n pendingValue: initialValue,\n subs: undefined,\n subsTail: undefined,\n flags: Mutable,\n __id: undefined as number | undefined,\n ...(options?.equals !== undefined ? { equals: options.equals } : {}),\n ...(options?.name !== undefined ? { name: options.name } : {}),\n ...(options?.devToolsSource !== undefined ? { devToolsSource: options.devToolsSource } : {}),\n }\n if (isDev) registerSignalDevtools(s)\n const accessor = signalOper.bind(s as any) as SignalAccessor<T> & Record<symbol, boolean>\n accessor[SIGNAL_MARKER] = true\n return accessor as SignalAccessor<T>\n}\nfunction signalOper<T>(this: SignalNode<T>, value?: T): T | void {\n if (arguments.length > 0) {\n const next = value as T\n const prev = this.pendingValue\n if (valuesDiffer(this, prev as T, next)) {\n this.pendingValue = next\n this.flags = MutableDirty\n if (isDev) updateSignalDevtools(this, next)\n const subs = this.subs\n if (subs !== undefined) {\n propagate(subs)\n if (!batchDepth) scheduleFlush()\n }\n }\n return\n }\n\n const flags = this.flags\n // During cleanup, don't update signal - return currentValue as-is\n if (flags & Dirty && !inCleanup) {\n if (updateSignal(this as any)) {\n const subs = this.subs\n if (subs !== undefined) shallowPropagate(subs)\n }\n }\n if (inCleanup) {\n if (this.prevFlushId === activeCleanupFlushId) {\n return this.prevValue as T\n }\n return this.currentValue\n }\n\n let sub = activeSub\n while (sub !== undefined) {\n if (sub.flags & 3) {\n link(this as any, sub, cycle)\n break\n }\n const subSubs = sub.subs\n sub = subSubs !== undefined ? subSubs.sub : undefined\n }\n\n return this.currentValue\n}\n// ============================================================================\n// Computed\n// ============================================================================\n/**\n * Create a computed reactive value\n * @param getter - The getter function\n * @param options - Computed options\n * @returns A computed accessor function\n */\nexport function computed<T>(\n getter: (oldValue?: T) => T,\n options?: MemoOptions<T>,\n): ComputedAccessor<T> {\n const c: ComputedNode<T> = {\n value: undefined as unknown as T,\n subs: undefined,\n subsTail: undefined,\n deps: undefined,\n depsTail: undefined,\n flags: 0,\n getter,\n __id: undefined as number | undefined,\n ...(options?.equals !== undefined ? { equals: options.equals } : {}),\n ...(options?.name !== undefined ? { name: options.name } : {}),\n ...(options?.devToolsSource !== undefined ? { devToolsSource: options.devToolsSource } : {}),\n }\n if (isDev) registerComputedDevtools(c)\n const bound = (computedOper as (this: ComputedNode<T>) => T).bind(\n c as any,\n ) as ComputedAccessor<T> & Record<symbol, boolean>\n bound[COMPUTED_MARKER] = true\n return bound as ComputedAccessor<T>\n}\nfunction computedOper<T>(this: ComputedNode<T>): T {\n // fix: During cleanup, return previous value for this flush without triggering updates.\n // This ensures cleanup functions observe the pre-commit state for this effect.\n if (inCleanup) {\n if (this.prevFlushId === activeCleanupFlushId) {\n return this.prevValue as T\n }\n return this.value\n }\n\n const flags = this.flags\n\n if (flags & Dirty) {\n if (updateComputed(this)) {\n const subs = this.subs\n if (subs !== undefined) shallowPropagate(subs)\n }\n } else if (flags & Pending) {\n if (this.deps && checkDirty(this.deps, this)) {\n if (updateComputed(this)) {\n const subs = this.subs\n if (subs !== undefined) shallowPropagate(subs)\n }\n } else {\n this.flags = flags & ~Pending\n }\n } else if (!flags) {\n this.flags = MutableRunning\n const prevSub = setActiveSub(this)\n try {\n this.value = this.getter(undefined)\n if (isDev) updateComputedDevtools(this, this.value)\n } finally {\n setActiveSub(prevSub)\n this.flags &= ~Running\n }\n }\n\n if (activeSub !== undefined) link(this, activeSub, cycle)\n return this.value\n}\n// ============================================================================\n// Effect\n// ============================================================================\n/**\n * Create a reactive effect\n * @param fn - The effect function\n * @returns An effect disposer function\n */\nexport function effect(fn: () => void): EffectDisposer {\n const e: EffectNode = {\n fn,\n subs: undefined,\n subsTail: undefined,\n deps: undefined,\n depsTail: undefined,\n flags: WatchingRunning,\n __id: undefined as number | undefined,\n }\n const root = getCurrentRoot()\n if (root) {\n e.root = root\n }\n\n if (isDev) registerEffectDevtools(e)\n\n const prevSub = activeSub\n if (prevSub !== undefined) link(e, prevSub, 0)\n activeSub = e\n\n try {\n if (isDev) effectRunDevtools(e)\n fn()\n } finally {\n activeSub = prevSub\n e.flags &= ~Running\n }\n\n const disposer = effectOper.bind(e) as EffectDisposer & Record<symbol, boolean>\n disposer[EFFECT_MARKER] = true\n return disposer as EffectDisposer\n}\n\n/**\n * Create a reactive effect with a custom cleanup runner\n * The cleanup runner is called BEFORE signal values are committed, allowing\n * cleanup functions to access the previous values of signals.\n * @param fn - The effect function\n * @param cleanupRunner - Function to run cleanups before signal value commit\n * @param root - Root context for error/suspense handling (defaults to current root)\n * @returns An effect disposer function\n */\nexport function effectWithCleanup(\n fn: () => void,\n cleanupRunner: () => void,\n root?: RootContext,\n): EffectDisposer {\n const e: EffectNode = {\n fn,\n subs: undefined,\n subsTail: undefined,\n deps: undefined,\n depsTail: undefined,\n flags: WatchingRunning,\n runCleanup: cleanupRunner,\n __id: undefined as number | undefined,\n }\n const resolvedRoot = root ?? getCurrentRoot()\n if (resolvedRoot) {\n e.root = resolvedRoot\n }\n\n if (isDev) registerEffectDevtools(e)\n\n const prevSub = activeSub\n if (prevSub !== undefined) link(e, prevSub, 0)\n activeSub = e\n\n try {\n if (isDev) effectRunDevtools(e)\n fn()\n } finally {\n activeSub = prevSub\n e.flags &= ~Running\n }\n\n const disposer = effectOper.bind(e) as EffectDisposer & Record<symbol, boolean>\n disposer[EFFECT_MARKER] = true\n return disposer as EffectDisposer\n}\n\nfunction effectOper(this: EffectNode): void {\n disposeNode(this)\n}\n// ============================================================================\n// Effect Scope\n// ============================================================================\n/**\n * Create a reactive effect scope\n * @param fn - The scope function\n * @returns An effect scope disposer function\n */\nexport function effectScope(fn: () => void): EffectScopeDisposer {\n const e = { deps: undefined, depsTail: undefined, subs: undefined, subsTail: undefined, flags: 0 }\n\n const prevSub = activeSub\n if (prevSub !== undefined) link(e, prevSub, 0)\n activeSub = e\n\n try {\n fn()\n } finally {\n activeSub = prevSub\n }\n\n const disposer = effectScopeOper.bind(e) as EffectScopeDisposer & Record<symbol, boolean>\n disposer[EFFECT_SCOPE_MARKER] = true\n return disposer as EffectScopeDisposer\n}\nfunction effectScopeOper(this: EffectScopeNode): void {\n disposeNode(this)\n}\n// ============================================================================\n// Trigger\n// ============================================================================\n/**\n * Trigger a reactive computation without creating a persistent subscription\n * @param fn - The function to run\n */\nexport function trigger(fn: () => void): void {\n const sub: SubscriberNode = { deps: undefined, depsTail: undefined, flags: Watching }\n const prevSub = activeSub\n activeSub = sub as ReactiveNode\n\n try {\n fn()\n } finally {\n activeSub = prevSub\n let lnk = sub.deps\n while (lnk !== undefined) {\n const dep = lnk.dep\n lnk = unlink(lnk, sub)\n const subs = dep.subs\n if (subs !== undefined) {\n sub.flags = 0\n propagate(subs)\n shallowPropagate(subs)\n }\n }\n if (!batchDepth) scheduleFlush()\n }\n}\n// ============================================================================\n// Batch processing & Utility API\n// ============================================================================\n/**\n * Start a batch of updates\n */\nexport function startBatch(): void {\n ++batchDepth\n}\n/**\n * End a batch of updates and flush effects\n */\nexport function endBatch(): void {\n if (--batchDepth === 0) flush()\n}\n/**\n * Execute a function in a batch\n * @param fn - The function to execute\n * @returns The return value of the function\n */\nexport function batch<T>(fn: () => T): T {\n ++batchDepth\n let result!: T\n let error: unknown\n try {\n result = fn()\n } catch (e) {\n error = e\n } finally {\n --batchDepth\n if (batchDepth === 0) {\n try {\n flush()\n } catch (flushErr) {\n if (error === undefined) {\n error = flushErr\n }\n }\n }\n }\n if (error !== undefined) {\n throw error\n }\n return result\n}\n/**\n * Get the current active subscriber\n * @returns The active subscriber or undefined\n */\nexport function getActiveSub(): ReactiveNode | undefined {\n return activeSub\n}\n/**\n * Set the active subscriber\n * @param sub - The new active subscriber\n * @returns The previous active subscriber\n */\nexport function setActiveSub(sub: ReactiveNode | undefined): ReactiveNode | undefined {\n const prev = activeSub\n activeSub = sub\n return prev\n}\n/**\n * Get the current batch depth\n * @returns The current batch depth\n */\nexport function getBatchDepth(): number {\n return batchDepth\n}\n/**\n * Reset all global reactive state for test isolation.\n * ONLY use this in test setup/teardown - never in production code.\n * This clears effect queues, resets batch depth, and clears pending flushes.\n */\nexport function __resetReactiveState(): void {\n highPriorityQueue.length = 0\n lowPriorityQueue.length = 0\n batchDepth = 0\n activeSub = undefined\n flushScheduled = false\n isInTransition = false\n inCleanup = false\n cycle = 0\n currentFlushId = 0\n activeCleanupFlushId = 0\n}\n/**\n * Execute a function without tracking dependencies\n * @param fn - The function to execute\n * @returns The return value of the function\n */\nexport function untrack<T>(fn: () => T): T {\n const prev = activeSub\n activeSub = undefined\n try {\n return fn()\n } finally {\n activeSub = prev\n }\n}\n/**\n * Peek at a reactive value without tracking it as a dependency\n * @param accessor - The accessor function\n * @returns The value\n */\nexport function peek<T>(accessor: () => T): T {\n return untrack(accessor)\n}\n// This ensures correct detection even after minification\n/**\n * Check if a function is a signal accessor\n * @param fn - The function to check\n * @returns True if the function is a signal accessor\n */\nexport function isSignal(fn: unknown): fn is SignalAccessor<unknown> {\n return (\n typeof fn === 'function' && (fn as unknown as Record<symbol, boolean>)[SIGNAL_MARKER] === true\n )\n}\n/**\n * Check if a function is a computed accessor\n * @param fn - The function to check\n * @returns True if the function is a computed accessor\n */\nexport function isComputed(fn: unknown): fn is ComputedAccessor<unknown> {\n return (\n typeof fn === 'function' && (fn as unknown as Record<symbol, boolean>)[COMPUTED_MARKER] === true\n )\n}\n/**\n * Check if a function is an effect disposer\n * @param fn - The function to check\n * @returns True if the function is an effect disposer\n */\nexport function isEffect(fn: unknown): fn is EffectDisposer {\n return (\n typeof fn === 'function' && (fn as unknown as Record<symbol, boolean>)[EFFECT_MARKER] === true\n )\n}\n/**\n * Check if a function is an effect scope disposer\n * @param fn - The function to check\n * @returns True if the function is an effect scope disposer\n */\nexport function isEffectScope(fn: unknown): fn is EffectScopeDisposer {\n return (\n typeof fn === 'function' &&\n (fn as unknown as Record<symbol, boolean>)[EFFECT_SCOPE_MARKER] === true\n )\n}\n// ============================================================================\n// Transition Context (for priority scheduling)\n// ============================================================================\n/**\n * Set the transition context\n * @param value - Whether we're inside a transition\n * @returns The previous transition context value\n */\nexport function setTransitionContext(value: boolean): boolean {\n const prev = isInTransition\n isInTransition = value\n return prev\n}\n/**\n * Get the current transition context\n * @returns True if currently inside a transition\n */\nexport function getTransitionContext(): boolean {\n return isInTransition\n}\n// Export aliases for API compatibility\nexport { signal as createSignal }\nexport type { SignalAccessor as Signal }\n\nexport { flush, link, unlink, propagate, checkDirty, shallowPropagate }\nexport default {\n signal,\n computed,\n effect,\n effectScope,\n trigger,\n batch,\n startBatch,\n endBatch,\n flush,\n untrack,\n peek,\n isSignal,\n isComputed,\n isEffect,\n isEffectScope,\n getActiveSub,\n setActiveSub,\n getBatchDepth,\n link,\n unlink,\n propagate,\n checkDirty,\n shallowPropagate,\n createReactiveSystem,\n ReactiveFlags,\n}\nexport const $state = signal as <T>(value: T) => T\n\ninterface DevtoolsIdentifiable {\n __id?: number\n}\n\nlet registerSignalDevtools: <T>(node: SignalNode<T>) => number | undefined = () => undefined\nlet updateSignalDevtools: <T>(node: SignalNode<T>, value: unknown) => void = () => {}\nlet registerComputedDevtools: <T>(node: ComputedNode<T>) => number | undefined = () => undefined\nlet updateComputedDevtools: <T>(node: ComputedNode<T>, value: unknown) => void = () => {}\nlet registerEffectDevtools: (node: EffectNode) => number | undefined = () => undefined\nlet effectRunDevtools: (node: EffectNode) => void = () => {}\nlet trackDependencyDevtools: (dep: ReactiveNode, sub: ReactiveNode) => void = () => {}\nlet untrackDependencyDevtools: (dep: ReactiveNode, sub: ReactiveNode) => void = () => {}\n\nif (isDev) {\n // Unified ID counter for all reactive nodes (signal/computed/effect)\n // to prevent ID collisions when storing in single devtools maps\n let nextDevtoolsId = 0\n\n registerSignalDevtools = node => {\n const hook = getDevtoolsHook()\n if (!hook) return undefined\n const id = ++nextDevtoolsId\n const options: { name?: string; source?: string } = {}\n if (node.name !== undefined) options.name = node.name\n if (node.devToolsSource !== undefined) options.source = node.devToolsSource\n const ownerId = __fictGetCurrentComponentId()\n if (ownerId !== undefined) (options as any).ownerId = ownerId\n hook.registerSignal(id, node.currentValue, options)\n ;(node as SignalNode & DevtoolsIdentifiable).__id = id\n return id\n }\n\n updateSignalDevtools = (node, value) => {\n const hook = getDevtoolsHook()\n if (!hook) return\n const id = (node as SignalNode & DevtoolsIdentifiable).__id\n if (id) hook.updateSignal(id, value)\n }\n\n registerComputedDevtools = node => {\n const hook = getDevtoolsHook()\n if (!hook) return undefined\n const id = ++nextDevtoolsId\n const options: { name?: string; source?: string } = {}\n if (node.name !== undefined) options.name = node.name\n if (node.devToolsSource !== undefined) options.source = node.devToolsSource\n const ownerId = __fictGetCurrentComponentId()\n if (ownerId !== undefined) (options as any).ownerId = ownerId\n ;(options as any).hasValue = false\n hook.registerComputed(id, node.value, options)\n ;(node as ComputedNode & DevtoolsIdentifiable).__id = id\n return id\n }\n\n updateComputedDevtools = (node, value) => {\n const hook = getDevtoolsHook()\n if (!hook) return\n const id = (node as ComputedNode & DevtoolsIdentifiable).__id\n if (id) hook.updateComputed(id, value)\n }\n\n registerEffectDevtools = node => {\n const hook = getDevtoolsHook()\n if (!hook) return undefined\n const id = ++nextDevtoolsId\n const ownerId = __fictGetCurrentComponentId()\n hook.registerEffect(id, ownerId !== undefined ? { ownerId } : undefined)\n ;(node as EffectNode & DevtoolsIdentifiable).__id = id\n return id\n }\n\n effectRunDevtools = node => {\n const hook = getDevtoolsHook()\n if (!hook) return\n const id = (node as EffectNode & DevtoolsIdentifiable).__id\n if (id) hook.effectRun(id)\n }\n\n trackDependencyDevtools = (dep, sub) => {\n const hook = getDevtoolsHook()\n if (!hook?.trackDependency) return\n const depId = (dep as ReactiveNode & DevtoolsIdentifiable).__id\n const subId = (sub as ReactiveNode & DevtoolsIdentifiable).__id\n if (depId && subId) hook.trackDependency(subId, depId)\n }\n\n untrackDependencyDevtools = (dep, sub) => {\n const hook = getDevtoolsHook()\n if (!hook?.untrackDependency) return\n const depId = (dep as ReactiveNode & DevtoolsIdentifiable).__id\n const subId = (sub as ReactiveNode & DevtoolsIdentifiable).__id\n if (depId && subId) hook.untrackDependency(subId, depId)\n }\n}\n\n// ============================================================================\n// Selector\n// ============================================================================\n/**\n * Create a selector signal that efficiently updates only when the selected key matches.\n * Useful for large lists where only one item is selected.\n *\n * @param source - The source signal returning the current key\n * @param equalityFn - Optional equality function\n * @returns A selector function that takes a key and returns a boolean signal accessor\n */\nexport function createSelector<T>(\n source: () => T,\n equalityFn: (a: T, b: T) => boolean = (a, b) => a === b,\n): (key: T) => boolean {\n let current = source()\n const observers = new Map<T, SignalAccessor<boolean>>()\n\n const dispose = effect(() => {\n const next = source()\n if (equalityFn(current, next)) return\n\n const prevSig = observers.get(current)\n if (prevSig) prevSig(false)\n\n const nextSig = observers.get(next)\n if (nextSig) nextSig(true)\n\n current = next\n })\n registerRootCleanup(() => {\n dispose()\n observers.clear()\n })\n\n return (key: T) => {\n let sig = observers.get(key)\n if (!sig) {\n sig = signal(equalityFn(key, current))\n observers.set(key, sig)\n registerRootCleanup(() => observers.delete(key))\n }\n return sig()\n }\n}\n","import { computed, type Signal, type MemoOptions } from './signal'\n\nexport type Memo<T> = () => T\n\nexport function createMemo<T>(fn: () => T, options?: MemoOptions<T>): Memo<T> {\n return computed(fn, options)\n}\n\nexport function fromSignal<T>(signal: Signal<T>): Memo<T> {\n return () => signal()\n}\n\nexport const $memo = createMemo\n","import { signal, batch, type SignalAccessor } from './signal'\n\nconst PROXY = Symbol('fict:store-proxy')\nconst TARGET = Symbol('fict:store-target')\nconst ITERATE_KEY = Symbol('fict:iterate')\n\n// ============================================================================\n// Store (Deep Proxy)\n// ============================================================================\n\nexport type Store<T> = T\n\n/**\n * Create a Store: a reactive proxy that allows fine-grained access and mutation.\n *\n * @param initialValue - The initial state object\n * @returns [store, setStore]\n */\nexport function createStore<T extends object>(\n initialValue: T,\n): [Store<T>, (fn: (state: T) => void | T) => void] {\n const unwrapped = unwrap(initialValue)\n const wrapped = wrap(unwrapped)\n\n function setStore(fn: (state: T) => void | T) {\n batch(() => {\n const result = fn(wrapped)\n if (result !== undefined) {\n reconcile(wrapped, result)\n }\n })\n }\n\n return [wrapped, setStore]\n}\n\n// Map of target object -> Proxy\nconst proxyCache = new WeakMap<object, unknown>()\n// Map of target object -> Map<key, Signal>\nconst signalCache = new WeakMap<object, Map<string | symbol, SignalAccessor<unknown>>>()\n\nfunction wrap<T>(value: T): T {\n if (value === null || typeof value !== 'object') return value\n if (Reflect.get(value, PROXY)) return value\n\n if (proxyCache.has(value)) return proxyCache.get(value) as T\n\n const handler: ProxyHandler<object> = {\n get(target, prop, receiver) {\n if (prop === PROXY) return true\n if (prop === TARGET) return target\n\n const value = Reflect.get(target, prop, receiver)\n\n // Track property access\n track(target, prop)\n\n // Recursively wrap objects\n return wrap(value)\n },\n has(target, prop) {\n const result = Reflect.has(target, prop)\n track(target, prop)\n return result\n },\n ownKeys(target) {\n track(target, ITERATE_KEY)\n return Reflect.ownKeys(target)\n },\n getOwnPropertyDescriptor(target, prop) {\n track(target, prop)\n return Reflect.getOwnPropertyDescriptor(target, prop)\n },\n set(target, prop, value, receiver) {\n if (prop === PROXY || prop === TARGET) return false\n\n const isArrayLength = Array.isArray(target) && prop === 'length'\n const oldLength = isArrayLength ? target.length : undefined\n const hadKey = Object.prototype.hasOwnProperty.call(target, prop)\n const oldValue = Reflect.get(target, prop, receiver)\n if (oldValue === value) return true\n\n const result = Reflect.set(target, prop, value, receiver)\n if (result) {\n trigger(target, prop)\n if (!hadKey) {\n trigger(target, ITERATE_KEY)\n }\n if (isArrayLength) {\n const nextLength = target.length\n if (typeof oldLength === 'number' && nextLength < oldLength) {\n const signals = signalCache.get(target)\n if (signals) {\n for (const key of signals.keys()) {\n if (typeof key !== 'string') continue\n const index = Number(key)\n if (!Number.isInteger(index) || String(index) !== key) continue\n if (index >= nextLength && index < oldLength) {\n trigger(target, key)\n }\n }\n }\n }\n trigger(target, ITERATE_KEY)\n }\n }\n return result\n },\n deleteProperty(target, prop) {\n const hadKey = Object.prototype.hasOwnProperty.call(target, prop)\n const result = Reflect.deleteProperty(target, prop)\n if (result) {\n trigger(target, prop)\n if (hadKey) {\n trigger(target, ITERATE_KEY)\n }\n }\n return result\n },\n }\n\n const proxy = new Proxy(value, handler)\n proxyCache.set(value, proxy)\n return proxy as T\n}\n\nfunction unwrap<T>(value: T): T {\n if (value && typeof value === 'object' && Reflect.get(value, PROXY)) {\n return Reflect.get(value, TARGET) as T\n }\n return value\n}\n\nexport function isStoreProxy(value: unknown): boolean {\n return !!(value && typeof value === 'object' && Reflect.get(value as object, PROXY))\n}\n\nexport function unwrapStore<T>(value: T): T {\n return unwrap(value)\n}\n\nfunction track(target: object, prop: string | symbol) {\n let signals = signalCache.get(target)\n if (!signals) {\n signals = new Map()\n signalCache.set(target, signals)\n }\n\n let s = signals.get(prop)\n if (!s) {\n const initial =\n prop === ITERATE_KEY ? (Reflect.ownKeys(target).length as number) : getLastValue(target, prop)\n s = signal(initial)\n signals.set(prop, s)\n }\n s() // subscribe\n}\n\nfunction trigger(target: object, prop: string | symbol) {\n const signals = signalCache.get(target)\n if (signals) {\n const s = signals.get(prop)\n if (s) {\n if (prop === ITERATE_KEY) {\n s(Reflect.ownKeys(target).length)\n } else {\n s(getLastValue(target, prop)) // notify with new value\n }\n }\n }\n}\n\nfunction getLastValue(target: object, prop: string | symbol) {\n return Reflect.get(target, prop)\n}\n\n/**\n * Reconcile a store path with a new value (shallow merge/diff)\n */\nfunction reconcile(target: object, value: unknown) {\n if (target === value) return\n if (value === null || typeof value !== 'object') {\n throw new Error(\n `[Fict] Cannot replace store with primitive value: ${String(\n value,\n )}. setStore should return an object/array to merge.`,\n )\n }\n\n const realTarget = unwrap(target)\n const realValue = unwrap(value)\n\n const keys = new Set([...Object.keys(realTarget), ...Object.keys(realValue)])\n for (const key of keys) {\n const rTarget = realTarget as Record<string, unknown>\n const rValue = realValue as Record<string, unknown>\n\n if (rValue[key] === undefined && rTarget[key] !== undefined) {\n // deleted\n delete (target as Record<string, unknown>)[key] // Triggers proxy trap\n } else if (rTarget[key] !== rValue[key]) {\n ;(target as Record<string, unknown>)[key] = rValue[key] // Triggers proxy trap\n }\n }\n\n // Fix array length if needed\n if (Array.isArray(target) && Array.isArray(realValue) && target.length !== realValue.length) {\n target.length = realValue.length\n }\n}\n\n// ============================================================================\n// Diffing Signal (for List Items)\n// ============================================================================\n\n/**\n * Creates a signal that returns a Stable Proxy.\n * Updates to the signal (via set) will diff the new value against the old value\n * and trigger property-specific updates.\n */\nexport function createDiffingSignal<T extends object>(initialValue: T) {\n let currentValue = unwrap(initialValue)\n const signals = new Map<string | symbol, SignalAccessor<unknown>>()\n let iterateSignal: SignalAccessor<number> | undefined\n\n const getPropSignal = (prop: string | symbol) => {\n let s = signals.get(prop)\n if (!s) {\n s = signal(Reflect.get(currentValue as object, prop))\n signals.set(prop, s)\n }\n return s\n }\n\n const trackIterate = () => {\n if (!iterateSignal) {\n iterateSignal = signal(Reflect.ownKeys(currentValue).length)\n }\n iterateSignal()\n }\n\n const updateIterate = (value: T) => {\n if (iterateSignal) {\n iterateSignal(Reflect.ownKeys(value).length)\n }\n }\n\n // The stable proxy we return\n const proxy = new Proxy({} as T, {\n get(_, prop) {\n if (prop === PROXY) return true\n if (prop === TARGET) return currentValue\n\n // Subscribe to property\n const s = getPropSignal(prop)\n return s()\n },\n ownKeys() {\n trackIterate()\n return Reflect.ownKeys(currentValue)\n },\n has(target, prop) {\n getPropSignal(prop)()\n return Reflect.has(currentValue, prop)\n },\n getOwnPropertyDescriptor(target, prop) {\n getPropSignal(prop)()\n return Reflect.getOwnPropertyDescriptor(currentValue, prop)\n },\n })\n\n const read = () => proxy\n\n const write = (newValue: T) => {\n const next = unwrap(newValue)\n const prev = currentValue\n currentValue = next\n\n if (prev === next) {\n // Same ref update: re-evaluate all tracked signals\n // This is necessary for in-place mutations\n for (const [prop, s] of signals) {\n const newVal = Reflect.get(next as object, prop)\n s(newVal)\n }\n updateIterate(next)\n return\n }\n\n // Diff logic\n // We only trigger signals for properties that exist in our cache (tracked)\n // and have changed.\n for (const [prop, s] of signals) {\n const oldVal = Reflect.get(prev as object, prop)\n const newVal = Reflect.get(next as object, prop)\n if (oldVal !== newVal) {\n s(newVal)\n }\n }\n updateIterate(next)\n\n // Note: If new properties appeared that weren't tracked, we don't care\n // because no one is listening.\n // If we assume shape stability (Keyed List), this is efficient.\n }\n\n return [read, write] as const\n}\n","import type { HookContext } from './hooks'\nimport { createSignal, isSignal } from './signal'\nimport { createStore, isStoreProxy, unwrapStore } from './store'\n\n// ============================================================================\n// Serialization Types\n// ============================================================================\n\n/**\n * Type markers for serialized values.\n * These allow us to preserve type information through JSON serialization.\n */\ntype SerializedMarker =\n | { __t: 'd'; v: number } // Date (as timestamp)\n | { __t: 'm'; v: [unknown, unknown][] } // Map (as entries array)\n | { __t: 's'; v: unknown[] } // Set (as array)\n | { __t: 'r'; v: { s: string; f: string } } // RegExp (source + flags)\n | { __t: 'u' } // undefined\n | { __t: 'n' } // NaN\n | { __t: '+i' } // Infinity\n | { __t: '-i' } // -Infinity\n | { __t: 'b'; v: string } // BigInt (as string)\n | { __t: 'ref'; v: string } // Circular reference (path)\n\nexport type SlotSnapshot =\n | [index: number, type: 'sig', value: unknown]\n | [index: number, type: 'store', value: unknown]\n | [index: number, type: 'raw', value: unknown]\n\nexport interface ScopeSnapshot {\n id: string\n t?: string\n slots: SlotSnapshot[]\n props?: Record<string, unknown>\n vars?: Record<string, number>\n}\n\nexport interface SSRState {\n scopes: Record<string, ScopeSnapshot>\n}\n\nexport interface ScopeRecord {\n id: string\n ctx: HookContext\n host: Element\n type?: string\n props?: Record<string, unknown>\n}\n\nlet ssrEnabled = false\nlet resumableEnabled = false\nlet hydrating = false\nlet scopeCounter = 0\nlet scopeRegistry = new Map<string, ScopeRecord>()\nlet snapshotState: SSRState | null = null\nconst resumedScopes = new Map<\n string,\n { ctx: HookContext; host: Element; props?: Record<string, unknown> }\n>()\n\nexport function __fictEnableSSR(): void {\n ssrEnabled = true\n scopeCounter = 0\n scopeRegistry = new Map()\n resumedScopes.clear()\n snapshotState = null\n}\n\nexport function __fictDisableSSR(): void {\n ssrEnabled = false\n}\n\nexport function __fictEnableResumable(): void {\n resumableEnabled = true\n}\n\nexport function __fictDisableResumable(): void {\n resumableEnabled = false\n resumedScopes.clear()\n}\n\nexport function __fictIsResumable(): boolean {\n return ssrEnabled || resumableEnabled\n}\n\nexport function __fictIsSSR(): boolean {\n return ssrEnabled\n}\n\nexport function __fictEnterHydration(): void {\n hydrating = true\n}\n\nexport function __fictExitHydration(): void {\n hydrating = false\n}\n\nexport function __fictIsHydrating(): boolean {\n return hydrating\n}\n\nexport function __fictRegisterScope(\n ctx: HookContext,\n host: Element,\n type?: string,\n props?: Record<string, unknown>,\n): string {\n if (!__fictIsResumable()) return ''\n\n const id = `s${++scopeCounter}`\n ctx.scopeId = id\n if (type !== undefined) {\n ctx.scopeType = type\n }\n host.setAttribute('data-fict-s', id)\n if (type) {\n host.setAttribute('data-fict-t', type)\n }\n\n const record: ScopeRecord = { id, ctx, host }\n if (type !== undefined) {\n record.type = type\n }\n if (props !== undefined) {\n record.props = props\n }\n scopeRegistry.set(id, record)\n return id\n}\n\nexport function __fictGetScopeRegistry(): Map<string, ScopeRecord> {\n return scopeRegistry\n}\n\nexport function __fictSerializeSSRState(): SSRState {\n const scopes: Record<string, ScopeSnapshot> = {}\n\n for (const [id, record] of scopeRegistry.entries()) {\n const snapshot: ScopeSnapshot = {\n id,\n slots: serializeSlots(record.ctx),\n }\n if (record.type !== undefined) {\n snapshot.t = record.type\n }\n if (record.props !== undefined) {\n snapshot.props = record.props\n }\n if (record.ctx.slotMap !== undefined) {\n snapshot.vars = record.ctx.slotMap\n }\n scopes[id] = snapshot\n }\n\n return { scopes }\n}\n\nexport function __fictSetSSRState(state: SSRState | null): void {\n snapshotState = state\n if (!state) {\n resumedScopes.clear()\n }\n}\n\nexport function __fictGetSSRScope(id: string): ScopeSnapshot | undefined {\n return snapshotState?.scopes[id]\n}\n\nexport function __fictEnsureScope(\n scopeId: string,\n host: Element,\n snapshot?: ScopeSnapshot,\n): HookContext {\n const existing = resumedScopes.get(scopeId)\n if (existing) return existing.ctx\n\n const ctx = createContextFromSnapshot(snapshot)\n ctx.scopeId = scopeId\n if (snapshot?.t !== undefined) {\n ctx.scopeType = snapshot.t\n }\n const entry: { ctx: HookContext; host: Element; props?: Record<string, unknown> } = { ctx, host }\n if (snapshot?.props !== undefined) {\n entry.props = snapshot.props\n }\n resumedScopes.set(scopeId, entry)\n return ctx\n}\n\nexport function __fictUseLexicalScope(scopeId: string, names: string[]): unknown[] {\n const record = resumedScopes.get(scopeId)\n if (!record) {\n throw new Error(`[fict] Missing resumed scope for ${scopeId}`)\n }\n const ctx = record.ctx\n const map = ctx.slotMap ?? {}\n return names.map(name => ctx.slots[map[name] ?? -1])\n}\n\nexport function __fictGetScopeProps(scopeId: string): Record<string, unknown> | undefined {\n return resumedScopes.get(scopeId)?.props\n}\n\nexport function __fictQrl(moduleId: string, exportName: string): string {\n const manifest = (globalThis as Record<string, unknown>).__FICT_MANIFEST__ as\n | Record<string, string>\n | undefined\n\n // Check manifest first (production builds)\n if (manifest?.[moduleId]) {\n return `${manifest[moduleId]}#${exportName}`\n }\n\n // Handle file:// URLs for Vite dev mode SSR\n if (moduleId.startsWith('file://')) {\n const filePath = moduleId.slice(7) // Remove 'file://'\n\n // Check for configured SSR base path (project root)\n const ssrBase = (globalThis as Record<string, unknown>).__FICT_SSR_BASE__ as string | undefined\n if (ssrBase) {\n // Strip base to get relative path (e.g., /src/App.tsx)\n if (filePath.startsWith(ssrBase)) {\n const relativePath = filePath.slice(ssrBase.length)\n return `${relativePath}#${exportName}`\n }\n }\n\n // Fallback: use Vite's /@fs/ convention for direct file system access\n return `/@fs${filePath}#${exportName}`\n }\n\n return `${moduleId}#${exportName}`\n}\n\n// Registry for resume functions to prevent tree-shaking\nconst resumeFunctionRegistry = new Map<string, (...args: unknown[]) => unknown>()\n\n/**\n * Register a resume function to prevent it from being tree-shaken.\n * This is called at module load time by compiled component code.\n */\nexport function __fictRegisterResume(name: string, fn: (...args: unknown[]) => unknown): void {\n resumeFunctionRegistry.set(name, fn)\n}\n\n/**\n * Get a registered resume function by name.\n * Used by the loader to find resume functions.\n */\nexport function __fictGetResume(name: string): ((...args: unknown[]) => unknown) | undefined {\n return resumeFunctionRegistry.get(name)\n}\n\nfunction serializeSlots(ctx: HookContext): SlotSnapshot[] {\n const slots: SlotSnapshot[] = []\n const values = ctx.slots ?? []\n // Share the 'seen' map across all slots to handle cross-slot circular references\n const seen = new Map<object, string>()\n\n for (let i = 0; i < values.length; i++) {\n const value = values[i]\n // Note: we don't skip undefined anymore since we can serialize it\n if (value === undefined) {\n slots.push([i, 'raw', serializeValue(undefined, seen, `$[${i}]`)])\n continue\n }\n\n if (isSignal(value)) {\n try {\n const raw = (value as () => unknown)()\n slots.push([i, 'sig', serializeValue(raw, seen, `$[${i}]`)])\n } catch {\n // ignore signal read errors during SSR\n }\n continue\n }\n\n if (isStoreProxy(value)) {\n const raw = unwrapStore(value)\n slots.push([i, 'store', serializeValue(raw, seen, `$[${i}]`)])\n continue\n }\n\n // Fallback: serialize raw slot value with complex type support\n slots.push([i, 'raw', serializeValue(value, seen, `$[${i}]`)])\n }\n\n return slots\n}\n\nfunction createContextFromSnapshot(snapshot?: ScopeSnapshot): HookContext {\n const ctx: HookContext = { slots: [], cursor: 0 }\n if (!snapshot) return ctx\n\n for (const slot of snapshot.slots) {\n const [index, type, value] = slot\n if (type === 'sig') {\n ctx.slots[index] = createSignal(deserializeValue(value))\n } else if (type === 'store') {\n ctx.slots[index] = createStore(deserializeValue(value) as object)[0]\n } else {\n ctx.slots[index] = deserializeValue(value)\n }\n }\n if (snapshot.vars) {\n ctx.slotMap = { ...snapshot.vars }\n }\n\n return ctx\n}\n\n// ============================================================================\n// Value Serialization - Complex Type Support\n// ============================================================================\n\n/**\n * Check if value has a serialization marker\n */\nfunction isSerializedMarker(value: unknown): value is SerializedMarker {\n return (\n typeof value === 'object' &&\n value !== null &&\n '__t' in value &&\n typeof (value as SerializedMarker).__t === 'string'\n )\n}\n\n/**\n * Serialize a value with support for complex types.\n * Handles: Date, Map, Set, RegExp, undefined, NaN, Infinity, -Infinity, BigInt, circular references\n */\nexport function serializeValue(\n value: unknown,\n seen = new Map<object, string>(),\n path = '$',\n): unknown {\n // Handle primitives that JSON can't represent correctly\n if (value === undefined) {\n return { __t: 'u' } as SerializedMarker\n }\n\n if (typeof value === 'number') {\n if (Number.isNaN(value)) {\n return { __t: 'n' } as SerializedMarker\n }\n if (value === Infinity) {\n return { __t: '+i' } as SerializedMarker\n }\n if (value === -Infinity) {\n return { __t: '-i' } as SerializedMarker\n }\n return value\n }\n\n if (typeof value === 'bigint') {\n return { __t: 'b', v: value.toString() } as SerializedMarker\n }\n\n // Primitives that JSON handles correctly\n if (value === null || typeof value === 'boolean' || typeof value === 'string') {\n return value\n }\n\n // Handle functions - can't serialize, skip\n if (typeof value === 'function') {\n return undefined\n }\n\n // Handle objects - check for circular references first\n if (typeof value === 'object') {\n // Check for circular reference\n if (seen.has(value)) {\n return { __t: 'ref', v: seen.get(value)! } as SerializedMarker\n }\n\n // Date\n if (value instanceof Date) {\n return { __t: 'd', v: value.getTime() } as SerializedMarker\n }\n\n // RegExp\n if (value instanceof RegExp) {\n return { __t: 'r', v: { s: value.source, f: value.flags } } as SerializedMarker\n }\n\n // Map\n if (value instanceof Map) {\n seen.set(value, path)\n const entries: [unknown, unknown][] = []\n let i = 0\n for (const [k, v] of value) {\n entries.push([\n serializeValue(k, seen, `${path}.k${i}`),\n serializeValue(v, seen, `${path}.v${i}`),\n ])\n i++\n }\n return { __t: 'm', v: entries } as SerializedMarker\n }\n\n // Set\n if (value instanceof Set) {\n seen.set(value, path)\n const items: unknown[] = []\n let i = 0\n for (const item of value) {\n items.push(serializeValue(item, seen, `${path}[${i}]`))\n i++\n }\n return { __t: 's', v: items } as SerializedMarker\n }\n\n // Array\n if (Array.isArray(value)) {\n seen.set(value, path)\n return value.map((item, i) => serializeValue(item, seen, `${path}[${i}]`))\n }\n\n // Plain object\n seen.set(value, path)\n const result: Record<string, unknown> = {}\n for (const key of Object.keys(value)) {\n const serialized = serializeValue(\n (value as Record<string, unknown>)[key],\n seen,\n `${path}.${key}`,\n )\n if (serialized !== undefined) {\n result[key] = serialized\n }\n }\n return result\n }\n\n return value\n}\n\n/**\n * Deserialize a value, restoring complex types from their serialized form.\n */\nexport function deserializeValue(\n value: unknown,\n refs = new Map<string, unknown>(),\n path = '$',\n): unknown {\n // Handle null\n if (value === null) {\n return null\n }\n\n // Handle primitives\n if (typeof value !== 'object') {\n return value\n }\n\n // Check for serialization markers\n if (isSerializedMarker(value)) {\n switch (value.__t) {\n case 'u':\n return undefined\n case 'n':\n return NaN\n case '+i':\n return Infinity\n case '-i':\n return -Infinity\n case 'b':\n return BigInt(value.v)\n case 'd':\n return new Date(value.v)\n case 'r':\n return new RegExp(value.v.s, value.v.f)\n case 'm': {\n const map = new Map<unknown, unknown>()\n refs.set(path, map)\n for (let i = 0; i < value.v.length; i++) {\n const entry = value.v[i]\n if (!entry) continue\n const [k, v] = entry\n map.set(\n deserializeValue(k, refs, `${path}.k${i}`),\n deserializeValue(v, refs, `${path}.v${i}`),\n )\n }\n return map\n }\n case 's': {\n const set = new Set<unknown>()\n refs.set(path, set)\n for (let i = 0; i < value.v.length; i++) {\n set.add(deserializeValue(value.v[i], refs, `${path}[${i}]`))\n }\n return set\n }\n case 'ref':\n return refs.get(value.v)\n }\n }\n\n // Handle arrays\n if (Array.isArray(value)) {\n const arr: unknown[] = []\n refs.set(path, arr)\n for (let i = 0; i < value.length; i++) {\n arr.push(deserializeValue(value[i], refs, `${path}[${i}]`))\n }\n return arr\n }\n\n // Handle plain objects\n const obj: Record<string, unknown> = {}\n refs.set(path, obj)\n for (const key of Object.keys(value)) {\n obj[key] = deserializeValue((value as Record<string, unknown>)[key], refs, `${path}.${key}`)\n }\n return obj\n}\n"]}