fict 0.2.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chunk-QPBAYI4X.js → chunk-T5BGEI6S.js} +15 -2
- package/dist/chunk-T5BGEI6S.js.map +1 -0
- package/dist/index.cjs +13 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/plus.cjs +13 -0
- package/dist/plus.cjs.map +1 -1
- package/dist/plus.js +1 -1
- package/dist/slim.cjs +14 -0
- package/dist/slim.cjs.map +1 -0
- package/dist/slim.d.cts +21 -0
- package/dist/slim.d.ts +21 -0
- package/dist/slim.js +11 -0
- package/dist/slim.js.map +1 -0
- package/package.json +8 -3
- package/src/slim.ts +25 -0
- package/src/store.ts +13 -1
- package/dist/chunk-QPBAYI4X.js.map +0 -1
|
@@ -59,6 +59,7 @@ function $store(initialValue) {
|
|
|
59
59
|
return currentValue;
|
|
60
60
|
},
|
|
61
61
|
set(target, prop, newValue, receiver) {
|
|
62
|
+
const oldLength = Array.isArray(target) && prop === "length" ? target.length : void 0;
|
|
62
63
|
const oldValue = Reflect.get(target, prop, receiver);
|
|
63
64
|
const hadKey = Object.prototype.hasOwnProperty.call(target, prop);
|
|
64
65
|
if (oldValue === newValue && hadKey) {
|
|
@@ -83,6 +84,18 @@ function $store(initialValue) {
|
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
86
|
if (Array.isArray(target) && prop === "length") {
|
|
87
|
+
const nextLength = target.length;
|
|
88
|
+
if (typeof oldLength === "number" && nextLength < oldLength) {
|
|
89
|
+
const signals2 = SIGNAL_CACHE.get(target);
|
|
90
|
+
if (signals2) {
|
|
91
|
+
for (let i = nextLength; i < oldLength; i += 1) {
|
|
92
|
+
const key = String(i);
|
|
93
|
+
if (signals2[key]) {
|
|
94
|
+
signals2[key](void 0);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
}
|
|
86
99
|
triggerIteration(target);
|
|
87
100
|
}
|
|
88
101
|
return result;
|
|
@@ -117,5 +130,5 @@ function $store(initialValue) {
|
|
|
117
130
|
}
|
|
118
131
|
|
|
119
132
|
export { $store };
|
|
120
|
-
//# sourceMappingURL=chunk-
|
|
121
|
-
//# sourceMappingURL=chunk-
|
|
133
|
+
//# sourceMappingURL=chunk-T5BGEI6S.js.map
|
|
134
|
+
//# sourceMappingURL=chunk-T5BGEI6S.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/store.ts"],"names":["signals"],"mappings":";;;AA4BA,IAAM,WAAA,uBAAkB,OAAA,EAAyB;AAGjD,IAAM,YAAA,uBAAmB,OAAA,EAA0D;AAGnF,IAAM,kBAAA,uBAAyB,OAAA,EAAwD;AAGvF,IAAM,WAAA,GAAc,OAAO,SAAS,CAAA;AAMpC,SAAS,SAAA,CAAU,QAAgB,IAAA,EAAwC;AACzE,EAAA,IAAI,OAAA,GAAU,YAAA,CAAa,GAAA,CAAI,MAAM,CAAA;AACrC,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,OAAA,GAAU,EAAC;AACX,IAAA,YAAA,CAAa,GAAA,CAAI,QAAQ,OAAO,CAAA;AAAA,EAClC;AACA,EAAA,IAAI,CAAC,OAAA,CAAQ,IAAI,CAAA,EAAG;AAClB,IAAA,MAAM,OAAA,GAAU,IAAA,KAAS,WAAA,GAAc,CAAA,GAAK,OAA2B,IAAI,CAAA;AAC3E,IAAA,OAAA,CAAQ,IAAI,CAAA,GAAI,YAAA,CAAa,OAAO,CAAA;AAAA,EACtC;AACA,EAAA,OAAO,QAAQ,IAAI,CAAA;AACrB;AAMA,SAAS,iBAAiB,MAAA,EAAsB;AAC9C,EAAA,MAAM,OAAA,GAAU,YAAA,CAAa,GAAA,CAAI,MAAM,CAAA;AACvC,EAAA,IAAI,OAAA,IAAW,OAAA,CAAQ,WAAW,CAAA,EAAG;AACnC,IAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,WAAW,CAAA,EAAE;AACrC,IAAA,OAAA,CAAQ,WAAW,CAAA,CAAE,OAAA,GAAU,CAAC,CAAA;AAAA,EAClC;AACF;AA+BO,SAAS,OAAyB,YAAA,EAAoB;AAC3D,EAAA,IAAI,OAAO,YAAA,KAAiB,QAAA,IAAY,YAAA,KAAiB,IAAA,EAAM;AAC7D,IAAA,OAAO,YAAA;AAAA,EACT;AAEA,EAAA,IAAI,WAAA,CAAY,GAAA,CAAI,YAAY,CAAA,EAAG;AACjC,IAAA,OAAO,WAAA,CAAY,IAAI,YAAY,CAAA;AAAA,EACrC;AAEA,EAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,CAAM,YAAA,EAAc;AAAA,IACpC,GAAA,CAAI,MAAA,EAAQ,IAAA,EAAM,QAAA,EAAU;AAG1B,MAAA,MAAM,MAAA,GAAS,SAAA,CAAU,MAAA,EAAQ,IAAI,CAAA;AACrC,MAAA,MAAM,eAAe,MAAA,EAAO;AAE5B,MAAA,MAAM,eAAe,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,IAAA,EAAM,YAAY,KAAK,CAAA;AAChE,MAAA,IAAI,iBAAiB,YAAA,EAAc;AAIjC,QAAA,MAAA,CAAO,YAAY,CAAA;AAAA,MACrB;AAEA,MAAA,IAAI,OAAO,iBAAiB,UAAA,EAAY;AACtC,QAAA,IAAI,YAAA,GAAe,kBAAA,CAAmB,GAAA,CAAI,MAAM,CAAA;AAChD,QAAA,IAAI,CAAC,YAAA,EAAc;AACjB,UAAA,YAAA,uBAAmB,GAAA,EAAI;AACvB,UAAA,kBAAA,CAAmB,GAAA,CAAI,QAAQ,YAAY,CAAA;AAAA,QAC7C;AACA,QAAA,MAAM,MAAA,GAAS,YAAA,CAAa,GAAA,CAAI,IAAI,CAAA;AACpC,QAAA,IAAI,MAAA,IAAU,MAAA,CAAO,GAAA,KAAQ,YAAA,EAAc;AACzC,UAAA,OAAO,MAAA,CAAO,KAAA;AAAA,QAChB;AAEA,QAAA,MAAM,KAAA,GAAS,YAAA,CAAuB,IAAA,CAAK,QAAA,IAAY,KAAK,CAAA;AAC5D,QAAA,YAAA,CAAa,IAAI,IAAA,EAAM,EAAE,GAAA,EAAK,YAAA,EAAuB,OAAO,CAAA;AAC5D,QAAA,OAAO,KAAA;AAAA,MACT;AAGA,MAAA,IAAI,OAAO,YAAA,KAAiB,QAAA,IAAY,YAAA,KAAiB,IAAA,EAAM;AAC7D,QAAA,OAAO,OAAO,YAAuC,CAAA;AAAA,MACvD;AAGA,MAAA,OAAO,YAAA;AAAA,IACT,CAAA;AAAA,IAEA,GAAA,CAAI,MAAA,EAAQ,IAAA,EAAM,QAAA,EAAU,QAAA,EAAU;AACpC,MAAA,MAAM,SAAA,GAAY,MAAM,OAAA,CAAQ,MAAM,KAAK,IAAA,KAAS,QAAA,GAAW,OAAO,MAAA,GAAS,MAAA;AAC/E,MAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,MAAM,QAAQ,CAAA;AACnD,MAAA,MAAM,SAAS,MAAA,CAAO,SAAA,CAAU,cAAA,CAAe,IAAA,CAAK,QAAQ,IAAI,CAAA;AAGhE,MAAA,IAAI,QAAA,KAAa,YAAY,MAAA,EAAQ;AACnC,QAAA,OAAO,IAAA;AAAA,MACT;AAEA,MAAA,MAAM,SAAS,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,IAAA,EAAM,UAAU,QAAQ,CAAA;AAG3D,MAAA,MAAM,YAAA,GAAe,kBAAA,CAAmB,GAAA,CAAI,MAAM,CAAA;AAClD,MAAA,IAAI,YAAA,IAAgB,YAAA,CAAa,GAAA,CAAI,IAAI,CAAA,EAAG;AAC1C,QAAA,YAAA,CAAa,OAAO,IAAI,CAAA;AAAA,MAC1B;AAGA,MAAA,MAAM,OAAA,GAAU,YAAA,CAAa,GAAA,CAAI,MAAM,CAAA;AACvC,MAAA,IAAI,OAAA,IAAW,OAAA,CAAQ,IAAI,CAAA,EAAG;AAC5B,QAAA,OAAA,CAAQ,IAAI,EAAE,QAAQ,CAAA;AAAA,MACxB;AAGA,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,gBAAA,CAAiB,MAAM,CAAA;AAAA,MACzB;AAIA,MAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,IAAK,SAAS,QAAA,EAAU;AAC9C,QAAA,MAAMA,QAAAA,GAAU,YAAA,CAAa,GAAA,CAAI,MAAM,CAAA;AACvC,QAAA,IAAIA,QAAAA,IAAWA,SAAQ,MAAA,EAAQ;AAC7B,UAAAA,QAAAA,CAAQ,MAAA,CAAO,MAAA,CAAO,MAAM,CAAA;AAAA,QAC9B;AAAA,MACF;AAGA,MAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,IAAK,SAAS,QAAA,EAAU;AAC9C,QAAA,MAAM,aAAa,MAAA,CAAO,MAAA;AAC1B,QAAA,IAAI,OAAO,SAAA,KAAc,QAAA,IAAY,UAAA,GAAa,SAAA,EAAW;AAC3D,UAAA,MAAMA,QAAAA,GAAU,YAAA,CAAa,GAAA,CAAI,MAAM,CAAA;AACvC,UAAA,IAAIA,QAAAA,EAAS;AACX,YAAA,KAAA,IAAS,CAAA,GAAI,UAAA,EAAY,CAAA,GAAI,SAAA,EAAW,KAAK,CAAA,EAAG;AAC9C,cAAA,MAAM,GAAA,GAAM,OAAO,CAAC,CAAA;AACpB,cAAA,IAAIA,QAAAA,CAAQ,GAAG,CAAA,EAAG;AAChB,gBAAAA,QAAAA,CAAQ,GAAG,CAAA,CAAE,MAAS,CAAA;AAAA,cACxB;AAAA,YACF;AAAA,UACF;AAAA,QACF;AACA,QAAA,gBAAA,CAAiB,MAAM,CAAA;AAAA,MACzB;AAEA,MAAA,OAAO,MAAA;AAAA,IACT,CAAA;AAAA,IAEA,cAAA,CAAe,QAAQ,IAAA,EAAM;AAC3B,MAAA,MAAM,SAAS,MAAA,CAAO,SAAA,CAAU,cAAA,CAAe,IAAA,CAAK,QAAQ,IAAI,CAAA;AAChE,MAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,cAAA,CAAe,MAAA,EAAQ,IAAI,CAAA;AAElD,MAAA,IAAI,UAAU,MAAA,EAAQ;AACpB,QAAA,MAAM,OAAA,GAAU,YAAA,CAAa,GAAA,CAAI,MAAM,CAAA;AACvC,QAAA,IAAI,OAAA,IAAW,OAAA,CAAQ,IAAI,CAAA,EAAG;AAC5B,UAAA,OAAA,CAAQ,IAAI,EAAE,MAAS,CAAA;AAAA,QACzB;AAGA,QAAA,MAAM,YAAA,GAAe,kBAAA,CAAmB,GAAA,CAAI,MAAM,CAAA;AAClD,QAAA,IAAI,YAAA,IAAgB,YAAA,CAAa,GAAA,CAAI,IAAI,CAAA,EAAG;AAC1C,UAAA,YAAA,CAAa,OAAO,IAAI,CAAA;AAAA,QAC1B;AAEA,QAAA,gBAAA,CAAiB,MAAM,CAAA;AAAA,MACzB;AAEA,MAAA,OAAO,MAAA;AAAA,IACT,CAAA;AAAA,IAEA,QAAQ,MAAA,EAAQ;AACd,MAAA,SAAA,CAAU,MAAA,EAAQ,WAAW,CAAA,EAAE;AAC/B,MAAA,OAAO,OAAA,CAAQ,QAAQ,MAAM,CAAA;AAAA,IAC/B,CAAA;AAAA,IAEA,GAAA,CAAI,QAAQ,IAAA,EAAM;AAChB,MAAA,SAAA,CAAU,MAAA,EAAQ,IAAI,CAAA,EAAE;AACxB,MAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,IAAI,CAAA;AAAA,IACjC;AAAA,GACD,CAAA;AAED,EAAA,WAAA,CAAY,GAAA,CAAI,cAAc,KAAK,CAAA;AACnC,EAAA,OAAO,KAAA;AACT","file":"chunk-T5BGEI6S.js","sourcesContent":["/**\n * @fileoverview Deep reactive store implementation for Fict.\n *\n * $store creates a deeply reactive proxy that tracks property access at the path level.\n * Unlike $state (which is shallow), $store allows direct mutation of nested properties.\n *\n * @example\n * ```typescript\n * const user = $store({ name: 'Alice', address: { city: 'London' } })\n * user.address.city = 'Paris' // Fine-grained reactive update\n * ```\n */\n\nimport { createSignal, type Signal } from '@fictjs/runtime/advanced'\n\n/** Function type for bound methods */\ntype AnyFn = (...args: unknown[]) => unknown\n\n/** Cache entry for bound methods to preserve identity */\ninterface BoundMethodEntry {\n ref: AnyFn\n bound: AnyFn\n}\n\n/** Type for objects with indexable properties */\ntype IndexableObject = Record<string | symbol, unknown>\n\n/** Cache of proxied objects to avoid duplicate proxies */\nconst PROXY_CACHE = new WeakMap<object, unknown>()\n\n/** Cache of signals per object property */\nconst SIGNAL_CACHE = new WeakMap<object, Record<string | symbol, Signal<unknown>>>()\n\n/** Cache of bound methods to preserve function identity across reads */\nconst BOUND_METHOD_CACHE = new WeakMap<object, Map<string | symbol, BoundMethodEntry>>()\n\n/** Special key for tracking iteration (Object.keys, for-in, etc.) */\nconst ITERATE_KEY = Symbol('iterate')\n\n/**\n * Get or create a signal for a specific property on a target object.\n * @internal\n */\nfunction getSignal(target: object, prop: string | symbol): Signal<unknown> {\n let signals = SIGNAL_CACHE.get(target)\n if (!signals) {\n signals = {}\n SIGNAL_CACHE.set(target, signals)\n }\n if (!signals[prop]) {\n const initial = prop === ITERATE_KEY ? 0 : (target as IndexableObject)[prop]\n signals[prop] = createSignal(initial)\n }\n return signals[prop]\n}\n\n/**\n * Trigger iteration signal to notify consumers that keys have changed.\n * @internal\n */\nfunction triggerIteration(target: object): void {\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals[ITERATE_KEY]) {\n const current = signals[ITERATE_KEY]() as number\n signals[ITERATE_KEY](current + 1)\n }\n}\n\n/**\n * Create a deep reactive store using Proxy.\n *\n * Unlike `$state` (which is shallow and compiler-transformed), `$store` provides:\n * - **Deep reactivity**: Nested objects are automatically wrapped in proxies\n * - **Direct mutation**: Modify properties directly without spread operators\n * - **Path-level tracking**: Only components reading changed paths re-render\n *\n * @param initialValue - The initial object to make reactive\n * @returns A reactive proxy of the object\n *\n * @example\n * ```tsx\n * import { $store } from 'fict'\n *\n * const form = $store({\n * user: { name: '', email: '' },\n * settings: { theme: 'light' }\n * })\n *\n * // Direct mutation works\n * form.user.name = 'Alice'\n *\n * // In JSX - only updates when form.user.name changes\n * <input value={form.user.name} />\n * ```\n *\n * @public\n */\nexport function $store<T extends object>(initialValue: T): T {\n if (typeof initialValue !== 'object' || initialValue === null) {\n return initialValue\n }\n\n if (PROXY_CACHE.has(initialValue)) {\n return PROXY_CACHE.get(initialValue) as T\n }\n\n const proxy = new Proxy(initialValue, {\n get(target, prop, receiver) {\n // Always touch the signal so reference changes to this property are tracked,\n // even if the value is an object we proxy further.\n const signal = getSignal(target, prop)\n const trackedValue = signal()\n\n const currentValue = Reflect.get(target, prop, receiver ?? proxy)\n if (currentValue !== trackedValue) {\n // If the value has changed (e.g. via direct mutation of the underlying object not via proxy),\n // we update the signal to keep it in sync.\n // Note: This is a bit of a heuristic. Ideally all mutations go through proxy.\n signal(currentValue)\n }\n\n if (typeof currentValue === 'function') {\n let boundMethods = BOUND_METHOD_CACHE.get(target)\n if (!boundMethods) {\n boundMethods = new Map()\n BOUND_METHOD_CACHE.set(target, boundMethods)\n }\n const cached = boundMethods.get(prop)\n if (cached && cached.ref === currentValue) {\n return cached.bound\n }\n\n const bound = (currentValue as AnyFn).bind(receiver ?? proxy)\n boundMethods.set(prop, { ref: currentValue as AnyFn, bound })\n return bound\n }\n\n // If the value is an object/array, we recursively wrap it in a store\n if (typeof currentValue === 'object' && currentValue !== null) {\n return $store(currentValue as Record<string, unknown>)\n }\n\n // For primitives (and functions), we return the signal value (which tracks the read)\n return currentValue\n },\n\n set(target, prop, newValue, receiver) {\n const oldLength = Array.isArray(target) && prop === 'length' ? target.length : undefined\n const oldValue = Reflect.get(target, prop, receiver)\n const hadKey = Object.prototype.hasOwnProperty.call(target, prop)\n\n // If value hasn't changed, do nothing\n if (oldValue === newValue && hadKey) {\n return true\n }\n\n const result = Reflect.set(target, prop, newValue, receiver)\n\n // IMPORTANT: Clear bound method cache BEFORE updating the signal\n const boundMethods = BOUND_METHOD_CACHE.get(target)\n if (boundMethods && boundMethods.has(prop)) {\n boundMethods.delete(prop)\n }\n\n // Update the signal if it exists\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals[prop]) {\n signals[prop](newValue)\n }\n\n // If new property, trigger iteration update\n if (!hadKey) {\n triggerIteration(target)\n }\n\n // Ensure array length subscribers are notified even if the native push/pop\n // doesn't trigger a separate set trap for \"length\" (defensive).\n if (Array.isArray(target) && prop !== 'length') {\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals.length) {\n signals.length(target.length)\n }\n }\n\n // If it's an array and length changed implicitly, we might need to handle it.\n if (Array.isArray(target) && prop === 'length') {\n const nextLength = target.length\n if (typeof oldLength === 'number' && nextLength < oldLength) {\n const signals = SIGNAL_CACHE.get(target)\n if (signals) {\n for (let i = nextLength; i < oldLength; i += 1) {\n const key = String(i)\n if (signals[key]) {\n signals[key](undefined)\n }\n }\n }\n }\n triggerIteration(target)\n }\n\n return result\n },\n\n deleteProperty(target, prop) {\n const hadKey = Object.prototype.hasOwnProperty.call(target, prop)\n const result = Reflect.deleteProperty(target, prop)\n\n if (result && hadKey) {\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals[prop]) {\n signals[prop](undefined)\n }\n\n // Clear bound method cache\n const boundMethods = BOUND_METHOD_CACHE.get(target)\n if (boundMethods && boundMethods.has(prop)) {\n boundMethods.delete(prop)\n }\n\n triggerIteration(target)\n }\n\n return result\n },\n\n ownKeys(target) {\n getSignal(target, ITERATE_KEY)()\n return Reflect.ownKeys(target)\n },\n\n has(target, prop) {\n getSignal(target, prop)()\n return Reflect.has(target, prop)\n },\n })\n\n PROXY_CACHE.set(initialValue, proxy)\n return proxy\n}\n"]}
|
package/dist/index.cjs
CHANGED
|
@@ -62,6 +62,7 @@ function $store(initialValue) {
|
|
|
62
62
|
return currentValue;
|
|
63
63
|
},
|
|
64
64
|
set(target, prop, newValue, receiver) {
|
|
65
|
+
const oldLength = Array.isArray(target) && prop === "length" ? target.length : void 0;
|
|
65
66
|
const oldValue = Reflect.get(target, prop, receiver);
|
|
66
67
|
const hadKey = Object.prototype.hasOwnProperty.call(target, prop);
|
|
67
68
|
if (oldValue === newValue && hadKey) {
|
|
@@ -86,6 +87,18 @@ function $store(initialValue) {
|
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
if (Array.isArray(target) && prop === "length") {
|
|
90
|
+
const nextLength = target.length;
|
|
91
|
+
if (typeof oldLength === "number" && nextLength < oldLength) {
|
|
92
|
+
const signals2 = SIGNAL_CACHE.get(target);
|
|
93
|
+
if (signals2) {
|
|
94
|
+
for (let i = nextLength; i < oldLength; i += 1) {
|
|
95
|
+
const key = String(i);
|
|
96
|
+
if (signals2[key]) {
|
|
97
|
+
signals2[key](void 0);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
89
102
|
triggerIteration(target);
|
|
90
103
|
}
|
|
91
104
|
return result;
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/store.ts","../src/index.ts"],"names":["createSignal","signals"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @fileoverview Deep reactive store implementation for Fict.\n *\n * $store creates a deeply reactive proxy that tracks property access at the path level.\n * Unlike $state (which is shallow), $store allows direct mutation of nested properties.\n *\n * @example\n * ```typescript\n * const user = $store({ name: 'Alice', address: { city: 'London' } })\n * user.address.city = 'Paris' // Fine-grained reactive update\n * ```\n */\n\nimport { createSignal, type Signal } from '@fictjs/runtime/advanced'\n\n/** Function type for bound methods */\ntype AnyFn = (...args: unknown[]) => unknown\n\n/** Cache entry for bound methods to preserve identity */\ninterface BoundMethodEntry {\n ref: AnyFn\n bound: AnyFn\n}\n\n/** Type for objects with indexable properties */\ntype IndexableObject = Record<string | symbol, unknown>\n\n/** Cache of proxied objects to avoid duplicate proxies */\nconst PROXY_CACHE = new WeakMap<object, unknown>()\n\n/** Cache of signals per object property */\nconst SIGNAL_CACHE = new WeakMap<object, Record<string | symbol, Signal<unknown>>>()\n\n/** Cache of bound methods to preserve function identity across reads */\nconst BOUND_METHOD_CACHE = new WeakMap<object, Map<string | symbol, BoundMethodEntry>>()\n\n/** Special key for tracking iteration (Object.keys, for-in, etc.) */\nconst ITERATE_KEY = Symbol('iterate')\n\n/**\n * Get or create a signal for a specific property on a target object.\n * @internal\n */\nfunction getSignal(target: object, prop: string | symbol): Signal<unknown> {\n let signals = SIGNAL_CACHE.get(target)\n if (!signals) {\n signals = {}\n SIGNAL_CACHE.set(target, signals)\n }\n if (!signals[prop]) {\n const initial = prop === ITERATE_KEY ? 0 : (target as IndexableObject)[prop]\n signals[prop] = createSignal(initial)\n }\n return signals[prop]\n}\n\n/**\n * Trigger iteration signal to notify consumers that keys have changed.\n * @internal\n */\nfunction triggerIteration(target: object): void {\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals[ITERATE_KEY]) {\n const current = signals[ITERATE_KEY]() as number\n signals[ITERATE_KEY](current + 1)\n }\n}\n\n/**\n * Create a deep reactive store using Proxy.\n *\n * Unlike `$state` (which is shallow and compiler-transformed), `$store` provides:\n * - **Deep reactivity**: Nested objects are automatically wrapped in proxies\n * - **Direct mutation**: Modify properties directly without spread operators\n * - **Path-level tracking**: Only components reading changed paths re-render\n *\n * @param initialValue - The initial object to make reactive\n * @returns A reactive proxy of the object\n *\n * @example\n * ```tsx\n * import { $store } from 'fict'\n *\n * const form = $store({\n * user: { name: '', email: '' },\n * settings: { theme: 'light' }\n * })\n *\n * // Direct mutation works\n * form.user.name = 'Alice'\n *\n * // In JSX - only updates when form.user.name changes\n * <input value={form.user.name} />\n * ```\n *\n * @public\n */\nexport function $store<T extends object>(initialValue: T): T {\n if (typeof initialValue !== 'object' || initialValue === null) {\n return initialValue\n }\n\n if (PROXY_CACHE.has(initialValue)) {\n return PROXY_CACHE.get(initialValue) as T\n }\n\n const proxy = new Proxy(initialValue, {\n get(target, prop, receiver) {\n // Always touch the signal so reference changes to this property are tracked,\n // even if the value is an object we proxy further.\n const signal = getSignal(target, prop)\n const trackedValue = signal()\n\n const currentValue = Reflect.get(target, prop, receiver ?? proxy)\n if (currentValue !== trackedValue) {\n // If the value has changed (e.g. via direct mutation of the underlying object not via proxy),\n // we update the signal to keep it in sync.\n // Note: This is a bit of a heuristic. Ideally all mutations go through proxy.\n signal(currentValue)\n }\n\n if (typeof currentValue === 'function') {\n let boundMethods = BOUND_METHOD_CACHE.get(target)\n if (!boundMethods) {\n boundMethods = new Map()\n BOUND_METHOD_CACHE.set(target, boundMethods)\n }\n const cached = boundMethods.get(prop)\n if (cached && cached.ref === currentValue) {\n return cached.bound\n }\n\n const bound = (currentValue as AnyFn).bind(receiver ?? proxy)\n boundMethods.set(prop, { ref: currentValue as AnyFn, bound })\n return bound\n }\n\n // If the value is an object/array, we recursively wrap it in a store\n if (typeof currentValue === 'object' && currentValue !== null) {\n return $store(currentValue as Record<string, unknown>)\n }\n\n // For primitives (and functions), we return the signal value (which tracks the read)\n return currentValue\n },\n\n set(target, prop, newValue, receiver) {\n const oldValue = Reflect.get(target, prop, receiver)\n const hadKey = Object.prototype.hasOwnProperty.call(target, prop)\n\n // If value hasn't changed, do nothing\n if (oldValue === newValue && hadKey) {\n return true\n }\n\n const result = Reflect.set(target, prop, newValue, receiver)\n\n // IMPORTANT: Clear bound method cache BEFORE updating the signal\n const boundMethods = BOUND_METHOD_CACHE.get(target)\n if (boundMethods && boundMethods.has(prop)) {\n boundMethods.delete(prop)\n }\n\n // Update the signal if it exists\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals[prop]) {\n signals[prop](newValue)\n }\n\n // If new property, trigger iteration update\n if (!hadKey) {\n triggerIteration(target)\n }\n\n // Ensure array length subscribers are notified even if the native push/pop\n // doesn't trigger a separate set trap for \"length\" (defensive).\n if (Array.isArray(target) && prop !== 'length') {\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals.length) {\n signals.length(target.length)\n }\n }\n\n // If it's an array and length changed implicitly, we might need to handle it.\n // But usually 'length' is set explicitly or handled by the runtime.\n if (Array.isArray(target) && prop === 'length') {\n triggerIteration(target)\n }\n\n return result\n },\n\n deleteProperty(target, prop) {\n const hadKey = Object.prototype.hasOwnProperty.call(target, prop)\n const result = Reflect.deleteProperty(target, prop)\n\n if (result && hadKey) {\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals[prop]) {\n signals[prop](undefined)\n }\n\n // Clear bound method cache\n const boundMethods = BOUND_METHOD_CACHE.get(target)\n if (boundMethods && boundMethods.has(prop)) {\n boundMethods.delete(prop)\n }\n\n triggerIteration(target)\n }\n\n return result\n },\n\n ownKeys(target) {\n getSignal(target, ITERATE_KEY)()\n return Reflect.ownKeys(target)\n },\n\n has(target, prop) {\n getSignal(target, prop)()\n return Reflect.has(target, prop)\n },\n })\n\n PROXY_CACHE.set(initialValue, proxy)\n return proxy\n}\n","/**\n * @fileoverview Fict Framework - Complete API\n *\n * This is the main entry point for the Fict framework.\n *\n * ## Recommended Import Pattern (v1.0+)\n *\n * ```typescript\n * // Core public API (most users need only this)\n * // Use $state in components (compiler-transformed)\n * // Use $store for cross-component shared state\n * import { $store, render } from 'fict'\n *\n * // Async utilities\n * import { resource, lazy } from 'fict/plus'\n *\n * // Advanced APIs (escape hatches, library authors)\n * import { createSignal, createContext, createScope } from 'fict/advanced'\n * ```\n *\n * ## State Management Guide\n *\n * | Use Case | API |\n * |----------|-----|\n * | Component-local state | `$state` (compiler-transformed) |\n * | Derived values / side effects | JS + auto-derived + `$effect` |\n * | Cross-component (large objects, deep mutation) | `$store` |\n * | Cross-component (scalar/lightweight, library-level) | `createSignal` (advanced) |\n * | Cross-component (subtree scope, SSR isolation) | `Context` (advanced) |\n *\n * @public\n * @packageDocumentation\n */\n\n// Re-export everything from runtime\nexport * from '@fictjs/runtime'\n\n// Re-export commonly used advanced APIs for convenience\nexport { createSelector, createScope, runInScope } from '@fictjs/runtime/advanced'\n\n// ============================================================================\n// Convenience Aliases\n// ============================================================================\n\n/**\n * Alias for createMemo.\n * Creates a memoized value that only recomputes when dependencies change.\n *\n * @example\n * ```tsx\n * const fullName = $memo(() => firstName + ' ' + lastName)\n * ```\n *\n * @public\n */\nexport { createMemo as $memo } from '@fictjs/runtime'\n\n// ============================================================================\n// Deep Reactive Store (Proxy-based)\n// ============================================================================\n\n/**\n * Create a deep reactive store using Proxy.\n * Unlike createStore, $store allows direct mutation.\n *\n * @example\n * ```tsx\n * const user = $store({ name: 'Alice', address: { city: 'Beijing' } })\n * user.name = 'Bob' // Reactive update\n * user.address.city = 'Shanghai' // Deep reactive\n * ```\n *\n * @public\n */\nexport { $store } from './store'\n\n// ============================================================================\n// Compiler Macros (transformed at compile time)\n// ============================================================================\n\n/**\n * Compiler macro for reactive state.\n * This is transformed at compile time and should never be called at runtime.\n *\n * @example\n * ```tsx\n * let count = $state(0)\n * count++ // Reactive update\n * ```\n *\n * @public\n */\nexport function $state<T>(_initialValue: T): T {\n // This function is never called at runtime - the compiler transforms it\n throw new Error('$state() is a compiler macro and should be transformed at compile time')\n}\n\n/**\n * Compiler macro for reactive effects.\n * This is transformed at compile time and should never be called at runtime.\n *\n * @example\n * ```tsx\n * $effect(() => {\n * console.log('count changed:', count)\n * })\n * ```\n *\n * @public\n */\nexport function $effect(_fn: () => void | (() => void)): void {\n // This function is never called at runtime - the compiler transforms it\n throw new Error('$effect() is a compiler macro and should be transformed at compile time')\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/store.ts","../src/index.ts"],"names":["createSignal","signals"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * @fileoverview Deep reactive store implementation for Fict.\n *\n * $store creates a deeply reactive proxy that tracks property access at the path level.\n * Unlike $state (which is shallow), $store allows direct mutation of nested properties.\n *\n * @example\n * ```typescript\n * const user = $store({ name: 'Alice', address: { city: 'London' } })\n * user.address.city = 'Paris' // Fine-grained reactive update\n * ```\n */\n\nimport { createSignal, type Signal } from '@fictjs/runtime/advanced'\n\n/** Function type for bound methods */\ntype AnyFn = (...args: unknown[]) => unknown\n\n/** Cache entry for bound methods to preserve identity */\ninterface BoundMethodEntry {\n ref: AnyFn\n bound: AnyFn\n}\n\n/** Type for objects with indexable properties */\ntype IndexableObject = Record<string | symbol, unknown>\n\n/** Cache of proxied objects to avoid duplicate proxies */\nconst PROXY_CACHE = new WeakMap<object, unknown>()\n\n/** Cache of signals per object property */\nconst SIGNAL_CACHE = new WeakMap<object, Record<string | symbol, Signal<unknown>>>()\n\n/** Cache of bound methods to preserve function identity across reads */\nconst BOUND_METHOD_CACHE = new WeakMap<object, Map<string | symbol, BoundMethodEntry>>()\n\n/** Special key for tracking iteration (Object.keys, for-in, etc.) */\nconst ITERATE_KEY = Symbol('iterate')\n\n/**\n * Get or create a signal for a specific property on a target object.\n * @internal\n */\nfunction getSignal(target: object, prop: string | symbol): Signal<unknown> {\n let signals = SIGNAL_CACHE.get(target)\n if (!signals) {\n signals = {}\n SIGNAL_CACHE.set(target, signals)\n }\n if (!signals[prop]) {\n const initial = prop === ITERATE_KEY ? 0 : (target as IndexableObject)[prop]\n signals[prop] = createSignal(initial)\n }\n return signals[prop]\n}\n\n/**\n * Trigger iteration signal to notify consumers that keys have changed.\n * @internal\n */\nfunction triggerIteration(target: object): void {\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals[ITERATE_KEY]) {\n const current = signals[ITERATE_KEY]() as number\n signals[ITERATE_KEY](current + 1)\n }\n}\n\n/**\n * Create a deep reactive store using Proxy.\n *\n * Unlike `$state` (which is shallow and compiler-transformed), `$store` provides:\n * - **Deep reactivity**: Nested objects are automatically wrapped in proxies\n * - **Direct mutation**: Modify properties directly without spread operators\n * - **Path-level tracking**: Only components reading changed paths re-render\n *\n * @param initialValue - The initial object to make reactive\n * @returns A reactive proxy of the object\n *\n * @example\n * ```tsx\n * import { $store } from 'fict'\n *\n * const form = $store({\n * user: { name: '', email: '' },\n * settings: { theme: 'light' }\n * })\n *\n * // Direct mutation works\n * form.user.name = 'Alice'\n *\n * // In JSX - only updates when form.user.name changes\n * <input value={form.user.name} />\n * ```\n *\n * @public\n */\nexport function $store<T extends object>(initialValue: T): T {\n if (typeof initialValue !== 'object' || initialValue === null) {\n return initialValue\n }\n\n if (PROXY_CACHE.has(initialValue)) {\n return PROXY_CACHE.get(initialValue) as T\n }\n\n const proxy = new Proxy(initialValue, {\n get(target, prop, receiver) {\n // Always touch the signal so reference changes to this property are tracked,\n // even if the value is an object we proxy further.\n const signal = getSignal(target, prop)\n const trackedValue = signal()\n\n const currentValue = Reflect.get(target, prop, receiver ?? proxy)\n if (currentValue !== trackedValue) {\n // If the value has changed (e.g. via direct mutation of the underlying object not via proxy),\n // we update the signal to keep it in sync.\n // Note: This is a bit of a heuristic. Ideally all mutations go through proxy.\n signal(currentValue)\n }\n\n if (typeof currentValue === 'function') {\n let boundMethods = BOUND_METHOD_CACHE.get(target)\n if (!boundMethods) {\n boundMethods = new Map()\n BOUND_METHOD_CACHE.set(target, boundMethods)\n }\n const cached = boundMethods.get(prop)\n if (cached && cached.ref === currentValue) {\n return cached.bound\n }\n\n const bound = (currentValue as AnyFn).bind(receiver ?? proxy)\n boundMethods.set(prop, { ref: currentValue as AnyFn, bound })\n return bound\n }\n\n // If the value is an object/array, we recursively wrap it in a store\n if (typeof currentValue === 'object' && currentValue !== null) {\n return $store(currentValue as Record<string, unknown>)\n }\n\n // For primitives (and functions), we return the signal value (which tracks the read)\n return currentValue\n },\n\n set(target, prop, newValue, receiver) {\n const oldLength = Array.isArray(target) && prop === 'length' ? target.length : undefined\n const oldValue = Reflect.get(target, prop, receiver)\n const hadKey = Object.prototype.hasOwnProperty.call(target, prop)\n\n // If value hasn't changed, do nothing\n if (oldValue === newValue && hadKey) {\n return true\n }\n\n const result = Reflect.set(target, prop, newValue, receiver)\n\n // IMPORTANT: Clear bound method cache BEFORE updating the signal\n const boundMethods = BOUND_METHOD_CACHE.get(target)\n if (boundMethods && boundMethods.has(prop)) {\n boundMethods.delete(prop)\n }\n\n // Update the signal if it exists\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals[prop]) {\n signals[prop](newValue)\n }\n\n // If new property, trigger iteration update\n if (!hadKey) {\n triggerIteration(target)\n }\n\n // Ensure array length subscribers are notified even if the native push/pop\n // doesn't trigger a separate set trap for \"length\" (defensive).\n if (Array.isArray(target) && prop !== 'length') {\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals.length) {\n signals.length(target.length)\n }\n }\n\n // If it's an array and length changed implicitly, we might need to handle it.\n if (Array.isArray(target) && prop === 'length') {\n const nextLength = target.length\n if (typeof oldLength === 'number' && nextLength < oldLength) {\n const signals = SIGNAL_CACHE.get(target)\n if (signals) {\n for (let i = nextLength; i < oldLength; i += 1) {\n const key = String(i)\n if (signals[key]) {\n signals[key](undefined)\n }\n }\n }\n }\n triggerIteration(target)\n }\n\n return result\n },\n\n deleteProperty(target, prop) {\n const hadKey = Object.prototype.hasOwnProperty.call(target, prop)\n const result = Reflect.deleteProperty(target, prop)\n\n if (result && hadKey) {\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals[prop]) {\n signals[prop](undefined)\n }\n\n // Clear bound method cache\n const boundMethods = BOUND_METHOD_CACHE.get(target)\n if (boundMethods && boundMethods.has(prop)) {\n boundMethods.delete(prop)\n }\n\n triggerIteration(target)\n }\n\n return result\n },\n\n ownKeys(target) {\n getSignal(target, ITERATE_KEY)()\n return Reflect.ownKeys(target)\n },\n\n has(target, prop) {\n getSignal(target, prop)()\n return Reflect.has(target, prop)\n },\n })\n\n PROXY_CACHE.set(initialValue, proxy)\n return proxy\n}\n","/**\n * @fileoverview Fict Framework - Complete API\n *\n * This is the main entry point for the Fict framework.\n *\n * ## Recommended Import Pattern (v1.0+)\n *\n * ```typescript\n * // Core public API (most users need only this)\n * // Use $state in components (compiler-transformed)\n * // Use $store for cross-component shared state\n * import { $store, render } from 'fict'\n *\n * // Async utilities\n * import { resource, lazy } from 'fict/plus'\n *\n * // Advanced APIs (escape hatches, library authors)\n * import { createSignal, createContext, createScope } from 'fict/advanced'\n * ```\n *\n * ## State Management Guide\n *\n * | Use Case | API |\n * |----------|-----|\n * | Component-local state | `$state` (compiler-transformed) |\n * | Derived values / side effects | JS + auto-derived + `$effect` |\n * | Cross-component (large objects, deep mutation) | `$store` |\n * | Cross-component (scalar/lightweight, library-level) | `createSignal` (advanced) |\n * | Cross-component (subtree scope, SSR isolation) | `Context` (advanced) |\n *\n * @public\n * @packageDocumentation\n */\n\n// Re-export everything from runtime\nexport * from '@fictjs/runtime'\n\n// Re-export commonly used advanced APIs for convenience\nexport { createSelector, createScope, runInScope } from '@fictjs/runtime/advanced'\n\n// ============================================================================\n// Convenience Aliases\n// ============================================================================\n\n/**\n * Alias for createMemo.\n * Creates a memoized value that only recomputes when dependencies change.\n *\n * @example\n * ```tsx\n * const fullName = $memo(() => firstName + ' ' + lastName)\n * ```\n *\n * @public\n */\nexport { createMemo as $memo } from '@fictjs/runtime'\n\n// ============================================================================\n// Deep Reactive Store (Proxy-based)\n// ============================================================================\n\n/**\n * Create a deep reactive store using Proxy.\n * Unlike createStore, $store allows direct mutation.\n *\n * @example\n * ```tsx\n * const user = $store({ name: 'Alice', address: { city: 'Beijing' } })\n * user.name = 'Bob' // Reactive update\n * user.address.city = 'Shanghai' // Deep reactive\n * ```\n *\n * @public\n */\nexport { $store } from './store'\n\n// ============================================================================\n// Compiler Macros (transformed at compile time)\n// ============================================================================\n\n/**\n * Compiler macro for reactive state.\n * This is transformed at compile time and should never be called at runtime.\n *\n * @example\n * ```tsx\n * let count = $state(0)\n * count++ // Reactive update\n * ```\n *\n * @public\n */\nexport function $state<T>(_initialValue: T): T {\n // This function is never called at runtime - the compiler transforms it\n throw new Error('$state() is a compiler macro and should be transformed at compile time')\n}\n\n/**\n * Compiler macro for reactive effects.\n * This is transformed at compile time and should never be called at runtime.\n *\n * @example\n * ```tsx\n * $effect(() => {\n * console.log('count changed:', count)\n * })\n * ```\n *\n * @public\n */\nexport function $effect(_fn: () => void | (() => void)): void {\n // This function is never called at runtime - the compiler transforms it\n throw new Error('$effect() is a compiler macro and should be transformed at compile time')\n}\n"]}
|
package/dist/index.js
CHANGED
package/dist/plus.cjs
CHANGED
|
@@ -62,6 +62,7 @@ function $store(initialValue) {
|
|
|
62
62
|
return currentValue;
|
|
63
63
|
},
|
|
64
64
|
set(target, prop, newValue, receiver) {
|
|
65
|
+
const oldLength = Array.isArray(target) && prop === "length" ? target.length : void 0;
|
|
65
66
|
const oldValue = Reflect.get(target, prop, receiver);
|
|
66
67
|
const hadKey = Object.prototype.hasOwnProperty.call(target, prop);
|
|
67
68
|
if (oldValue === newValue && hadKey) {
|
|
@@ -86,6 +87,18 @@ function $store(initialValue) {
|
|
|
86
87
|
}
|
|
87
88
|
}
|
|
88
89
|
if (Array.isArray(target) && prop === "length") {
|
|
90
|
+
const nextLength = target.length;
|
|
91
|
+
if (typeof oldLength === "number" && nextLength < oldLength) {
|
|
92
|
+
const signals2 = SIGNAL_CACHE.get(target);
|
|
93
|
+
if (signals2) {
|
|
94
|
+
for (let i = nextLength; i < oldLength; i += 1) {
|
|
95
|
+
const key = String(i);
|
|
96
|
+
if (signals2[key]) {
|
|
97
|
+
signals2[key](void 0);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
89
102
|
triggerIteration(target);
|
|
90
103
|
}
|
|
91
104
|
return result;
|
package/dist/plus.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/store.ts","../src/resource.ts","../src/lazy.ts"],"names":["createSignal","signals","createSuspenseToken","onCleanup","entry","createEffect"],"mappings":"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","file":"plus.cjs","sourcesContent":["/**\n * @fileoverview Deep reactive store implementation for Fict.\n *\n * $store creates a deeply reactive proxy that tracks property access at the path level.\n * Unlike $state (which is shallow), $store allows direct mutation of nested properties.\n *\n * @example\n * ```typescript\n * const user = $store({ name: 'Alice', address: { city: 'London' } })\n * user.address.city = 'Paris' // Fine-grained reactive update\n * ```\n */\n\nimport { createSignal, type Signal } from '@fictjs/runtime/advanced'\n\n/** Function type for bound methods */\ntype AnyFn = (...args: unknown[]) => unknown\n\n/** Cache entry for bound methods to preserve identity */\ninterface BoundMethodEntry {\n ref: AnyFn\n bound: AnyFn\n}\n\n/** Type for objects with indexable properties */\ntype IndexableObject = Record<string | symbol, unknown>\n\n/** Cache of proxied objects to avoid duplicate proxies */\nconst PROXY_CACHE = new WeakMap<object, unknown>()\n\n/** Cache of signals per object property */\nconst SIGNAL_CACHE = new WeakMap<object, Record<string | symbol, Signal<unknown>>>()\n\n/** Cache of bound methods to preserve function identity across reads */\nconst BOUND_METHOD_CACHE = new WeakMap<object, Map<string | symbol, BoundMethodEntry>>()\n\n/** Special key for tracking iteration (Object.keys, for-in, etc.) */\nconst ITERATE_KEY = Symbol('iterate')\n\n/**\n * Get or create a signal for a specific property on a target object.\n * @internal\n */\nfunction getSignal(target: object, prop: string | symbol): Signal<unknown> {\n let signals = SIGNAL_CACHE.get(target)\n if (!signals) {\n signals = {}\n SIGNAL_CACHE.set(target, signals)\n }\n if (!signals[prop]) {\n const initial = prop === ITERATE_KEY ? 0 : (target as IndexableObject)[prop]\n signals[prop] = createSignal(initial)\n }\n return signals[prop]\n}\n\n/**\n * Trigger iteration signal to notify consumers that keys have changed.\n * @internal\n */\nfunction triggerIteration(target: object): void {\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals[ITERATE_KEY]) {\n const current = signals[ITERATE_KEY]() as number\n signals[ITERATE_KEY](current + 1)\n }\n}\n\n/**\n * Create a deep reactive store using Proxy.\n *\n * Unlike `$state` (which is shallow and compiler-transformed), `$store` provides:\n * - **Deep reactivity**: Nested objects are automatically wrapped in proxies\n * - **Direct mutation**: Modify properties directly without spread operators\n * - **Path-level tracking**: Only components reading changed paths re-render\n *\n * @param initialValue - The initial object to make reactive\n * @returns A reactive proxy of the object\n *\n * @example\n * ```tsx\n * import { $store } from 'fict'\n *\n * const form = $store({\n * user: { name: '', email: '' },\n * settings: { theme: 'light' }\n * })\n *\n * // Direct mutation works\n * form.user.name = 'Alice'\n *\n * // In JSX - only updates when form.user.name changes\n * <input value={form.user.name} />\n * ```\n *\n * @public\n */\nexport function $store<T extends object>(initialValue: T): T {\n if (typeof initialValue !== 'object' || initialValue === null) {\n return initialValue\n }\n\n if (PROXY_CACHE.has(initialValue)) {\n return PROXY_CACHE.get(initialValue) as T\n }\n\n const proxy = new Proxy(initialValue, {\n get(target, prop, receiver) {\n // Always touch the signal so reference changes to this property are tracked,\n // even if the value is an object we proxy further.\n const signal = getSignal(target, prop)\n const trackedValue = signal()\n\n const currentValue = Reflect.get(target, prop, receiver ?? proxy)\n if (currentValue !== trackedValue) {\n // If the value has changed (e.g. via direct mutation of the underlying object not via proxy),\n // we update the signal to keep it in sync.\n // Note: This is a bit of a heuristic. Ideally all mutations go through proxy.\n signal(currentValue)\n }\n\n if (typeof currentValue === 'function') {\n let boundMethods = BOUND_METHOD_CACHE.get(target)\n if (!boundMethods) {\n boundMethods = new Map()\n BOUND_METHOD_CACHE.set(target, boundMethods)\n }\n const cached = boundMethods.get(prop)\n if (cached && cached.ref === currentValue) {\n return cached.bound\n }\n\n const bound = (currentValue as AnyFn).bind(receiver ?? proxy)\n boundMethods.set(prop, { ref: currentValue as AnyFn, bound })\n return bound\n }\n\n // If the value is an object/array, we recursively wrap it in a store\n if (typeof currentValue === 'object' && currentValue !== null) {\n return $store(currentValue as Record<string, unknown>)\n }\n\n // For primitives (and functions), we return the signal value (which tracks the read)\n return currentValue\n },\n\n set(target, prop, newValue, receiver) {\n const oldValue = Reflect.get(target, prop, receiver)\n const hadKey = Object.prototype.hasOwnProperty.call(target, prop)\n\n // If value hasn't changed, do nothing\n if (oldValue === newValue && hadKey) {\n return true\n }\n\n const result = Reflect.set(target, prop, newValue, receiver)\n\n // IMPORTANT: Clear bound method cache BEFORE updating the signal\n const boundMethods = BOUND_METHOD_CACHE.get(target)\n if (boundMethods && boundMethods.has(prop)) {\n boundMethods.delete(prop)\n }\n\n // Update the signal if it exists\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals[prop]) {\n signals[prop](newValue)\n }\n\n // If new property, trigger iteration update\n if (!hadKey) {\n triggerIteration(target)\n }\n\n // Ensure array length subscribers are notified even if the native push/pop\n // doesn't trigger a separate set trap for \"length\" (defensive).\n if (Array.isArray(target) && prop !== 'length') {\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals.length) {\n signals.length(target.length)\n }\n }\n\n // If it's an array and length changed implicitly, we might need to handle it.\n // But usually 'length' is set explicitly or handled by the runtime.\n if (Array.isArray(target) && prop === 'length') {\n triggerIteration(target)\n }\n\n return result\n },\n\n deleteProperty(target, prop) {\n const hadKey = Object.prototype.hasOwnProperty.call(target, prop)\n const result = Reflect.deleteProperty(target, prop)\n\n if (result && hadKey) {\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals[prop]) {\n signals[prop](undefined)\n }\n\n // Clear bound method cache\n const boundMethods = BOUND_METHOD_CACHE.get(target)\n if (boundMethods && boundMethods.has(prop)) {\n boundMethods.delete(prop)\n }\n\n triggerIteration(target)\n }\n\n return result\n },\n\n ownKeys(target) {\n getSignal(target, ITERATE_KEY)()\n return Reflect.ownKeys(target)\n },\n\n has(target, prop) {\n getSignal(target, prop)()\n return Reflect.has(target, prop)\n },\n })\n\n PROXY_CACHE.set(initialValue, proxy)\n return proxy\n}\n","/**\n * @fileoverview Async data fetching with caching and Suspense support.\n *\n * The `resource` function creates a reactive data fetcher that:\n * - Automatically cancels in-flight requests when args change\n * - Supports Suspense for loading states\n * - Provides caching with TTL and stale-while-revalidate\n * - Handles errors gracefully\n */\n\nimport { createEffect, onCleanup, createSuspenseToken } from '@fictjs/runtime'\nimport { createSignal } from '@fictjs/runtime/advanced'\n\n/**\n * The result of reading a resource.\n *\n * @typeParam T - The type of data returned by the fetcher\n */\nexport interface ResourceResult<T> {\n /** The fetched data, or undefined if not yet loaded or on error */\n readonly data: T | undefined\n /** Whether the resource is currently loading (initial fetch or refetch) */\n readonly loading: boolean\n /**\n * Any error that occurred during fetching.\n * Type is unknown since errors can be any value in JavaScript.\n */\n readonly error: unknown\n /** Manually trigger a refetch of the resource */\n refresh: () => void\n}\n\n/**\n * Cache configuration options for a resource.\n */\nexport interface ResourceCacheOptions {\n /**\n * Caching mode:\n * - `'memory'`: Cache responses in memory (default)\n * - `'none'`: No caching, always refetch\n * @default 'memory'\n */\n mode?: 'memory' | 'none'\n\n /**\n * Time-to-live in milliseconds before cached data is considered stale.\n * @default Infinity\n */\n ttlMs?: number\n\n /**\n * If true, return stale cached data immediately while refetching in background.\n * @default false\n */\n staleWhileRevalidate?: boolean\n\n /**\n * If true, cache error responses as well.\n * @default false\n */\n cacheErrors?: boolean\n}\n\n/**\n * Configuration options for creating a resource.\n *\n * @typeParam T - The type of data returned by the fetcher\n * @typeParam Args - The type of arguments passed to the fetcher\n */\nexport interface ResourceOptions<T, Args> {\n /**\n * Custom cache key. Can be a static value or a function that computes\n * the key from the args. If not provided, args are used as the key.\n */\n key?: unknown | ((args: Args) => unknown)\n\n /**\n * The fetcher function that performs the async data retrieval.\n * Receives an AbortController signal for cancellation support.\n */\n fetch: (ctx: { signal: AbortSignal }, args: Args) => Promise<T>\n\n /**\n * If true, the resource will throw a Suspense token while loading,\n * enabling React-like Suspense boundaries.\n * @default false\n */\n suspense?: boolean\n\n /**\n * Cache configuration options.\n */\n cache?: ResourceCacheOptions\n\n /**\n * A value or reactive getter that, when changed, resets the resource.\n * Useful for clearing cache when certain conditions change.\n */\n reset?: unknown | (() => unknown)\n}\n\n/**\n * Return type of the resource factory.\n *\n * @typeParam T - The type of data returned by the fetcher\n * @typeParam Args - The type of arguments passed to the fetcher\n */\nexport interface Resource<T, Args> {\n /**\n * Read the resource data, triggering a fetch if needed.\n * Can accept static args or a reactive getter.\n *\n * @param argsAccessor - Arguments or a getter returning arguments\n */\n read(argsAccessor: (() => Args) | Args): ResourceResult<T>\n\n /**\n * Invalidate cached data, causing the next read to refetch.\n *\n * @param key - Optional specific key to invalidate. If omitted, invalidates all.\n */\n invalidate(key?: unknown): void\n\n /**\n * Prefetch data without reading it. Useful for eager loading.\n *\n * @param args - Arguments to pass to the fetcher\n * @param keyOverride - Optional cache key override\n */\n prefetch(args: Args, keyOverride?: unknown): void\n}\n\n/**\n * Resource status values for tracking fetch lifecycle.\n * @internal\n */\nexport type ResourceStatus = 'idle' | 'pending' | 'success' | 'error'\n\n/**\n * Internal cache entry for a resource.\n * Tracks the reactive state and metadata for a single cached fetch.\n *\n * @typeParam T - The type of data returned by the fetcher\n * @typeParam Args - The type of arguments passed to the fetcher\n * @internal\n */\ninterface ResourceEntry<T, Args> {\n /** Reactive signal for the fetched data */\n data: ReturnType<typeof createSignal<T | undefined>>\n /** Reactive signal for loading state */\n loading: ReturnType<typeof createSignal<boolean>>\n /** Reactive signal for error state */\n error: ReturnType<typeof createSignal<unknown>>\n /** Version counter for invalidation */\n version: ReturnType<typeof createSignal<number>>\n /** Suspense token when using suspense mode */\n pendingToken: ReturnType<typeof createSuspenseToken> | null\n /** Last used arguments for change detection */\n lastArgs: Args | undefined\n /** Last seen version for change detection */\n lastVersion: number\n /** Last reset token value for change detection */\n lastReset: unknown\n /** Whether we have a valid cached value */\n hasValue: boolean\n /** Current fetch status */\n status: ResourceStatus\n /** Generation counter to handle race conditions */\n generation: number\n /** Timestamp when the cached value expires */\n expiresAt: number | undefined\n /** Currently in-flight fetch promise */\n inFlight: Promise<void> | undefined\n /** AbortController for cancelling in-flight requests */\n controller: AbortController | undefined\n}\n\nconst defaultCacheOptions: Required<ResourceCacheOptions> = {\n mode: 'memory',\n ttlMs: Number.POSITIVE_INFINITY,\n staleWhileRevalidate: false,\n cacheErrors: false,\n}\n\n/**\n * Create a reactive async data resource.\n *\n * Resources handle async data fetching with automatic caching, cancellation,\n * and optional Suspense integration.\n *\n * @param optionsOrFetcher - A fetcher function or full configuration object\n * @returns A resource factory with read, invalidate, and prefetch methods\n *\n * @example\n * ```tsx\n * import { resource } from 'fict'\n *\n * // Simple fetcher\n * const userResource = resource(\n * ({ signal }, userId: string) =>\n * fetch(`/api/users/${userId}`, { signal }).then(r => r.json())\n * )\n *\n * // With full options\n * const postsResource = resource({\n * fetch: ({ signal }, userId: string) =>\n * fetch(`/api/users/${userId}/posts`, { signal }).then(r => r.json()),\n * suspense: true,\n * cache: {\n * ttlMs: 60_000,\n * staleWhileRevalidate: true,\n * },\n * })\n *\n * // Usage in component\n * function UserProfile({ userId }: { userId: string }) {\n * const { data, loading, error, refresh } = userResource.read(() => userId)\n *\n * if (loading) return <Spinner />\n * if (error) return <ErrorMessage error={error} />\n * return <div>{data.name}</div>\n * }\n * ```\n *\n * @public\n */\nexport function resource<T, Args = void>(\n optionsOrFetcher:\n | ((ctx: { signal: AbortSignal }, args: Args) => Promise<T>)\n | ResourceOptions<T, Args>,\n): Resource<T, Args> {\n const fetcher = typeof optionsOrFetcher === 'function' ? optionsOrFetcher : optionsOrFetcher.fetch\n const useSuspense = typeof optionsOrFetcher === 'object' && !!optionsOrFetcher.suspense\n const cacheOptions: ResourceCacheOptions =\n typeof optionsOrFetcher === 'object' ? (optionsOrFetcher.cache ?? {}) : {}\n const resolvedCacheOptions = { ...defaultCacheOptions, ...cacheOptions }\n const cache = new Map<unknown, ResourceEntry<T, Args>>()\n\n const readArgs = (argsAccessor: (() => Args) | Args): Args =>\n typeof argsAccessor === 'function' ? (argsAccessor as () => Args)() : argsAccessor\n\n const computeKey = (argsAccessor: (() => Args) | Args): unknown => {\n const argsValue = readArgs(argsAccessor)\n if (typeof optionsOrFetcher === 'object' && optionsOrFetcher.key !== undefined) {\n const key = optionsOrFetcher.key\n return typeof key === 'function' ? (key as (args: Args) => unknown)(argsValue) : key\n }\n return argsValue\n }\n\n const readResetToken = (): unknown => {\n if (typeof optionsOrFetcher !== 'object') return undefined\n const reset = optionsOrFetcher.reset\n if (typeof reset === 'function' && (reset as () => unknown).length === 0) {\n return (reset as () => unknown)()\n }\n return reset\n }\n\n const ensureEntry = (key: unknown): ResourceEntry<T, Args> => {\n let state = cache.get(key)\n if (!state) {\n state = {\n data: createSignal<T | undefined>(undefined),\n loading: createSignal<boolean>(false),\n error: createSignal<unknown>(undefined),\n version: createSignal(0),\n pendingToken: null,\n lastArgs: undefined,\n lastVersion: -1,\n lastReset: undefined,\n hasValue: false,\n status: 'idle',\n generation: 0,\n expiresAt: undefined,\n inFlight: undefined,\n controller: undefined,\n }\n cache.set(key, state)\n }\n return state!\n }\n\n const isExpired = (entry: ResourceEntry<T, Args>): boolean => {\n if (resolvedCacheOptions.mode === 'none') return true\n if (!Number.isFinite(resolvedCacheOptions.ttlMs)) return false\n if (entry.expiresAt === undefined) return false\n return entry.expiresAt < Date.now()\n }\n\n const markExpiry = (entry: ResourceEntry<T, Args>) => {\n if (resolvedCacheOptions.mode === 'none') {\n entry.expiresAt = Date.now() - 1\n return\n }\n entry.expiresAt = Number.isFinite(resolvedCacheOptions.ttlMs)\n ? Date.now() + resolvedCacheOptions.ttlMs\n : undefined\n }\n\n const startFetch = (\n entry: ResourceEntry<T, Args>,\n key: unknown,\n args: Args,\n isRevalidating = false,\n ) => {\n entry.controller?.abort()\n entry.inFlight = undefined\n const controller = new AbortController()\n entry.controller = controller\n entry.status = 'pending'\n // For stale-while-revalidate: don't show loading if we already have data to display\n if (!isRevalidating) {\n entry.loading(true)\n }\n entry.error(undefined)\n entry.generation += 1\n const currentGen = entry.generation\n\n const shouldSuspend = useSuspense && !entry.hasValue\n entry.pendingToken = shouldSuspend ? createSuspenseToken() : null\n\n const fetchPromise = fetcher({ signal: controller.signal }, args)\n .then(res => {\n if (controller.signal.aborted || entry.generation !== currentGen) return\n entry.data(res)\n entry.hasValue = true\n entry.status = 'success'\n entry.loading(false)\n markExpiry(entry)\n if (entry.pendingToken) {\n entry.pendingToken.resolve()\n entry.pendingToken = null\n }\n })\n .catch(err => {\n if (controller.signal.aborted || entry.generation !== currentGen) return\n entry.error(err)\n entry.status = 'error'\n entry.loading(false)\n if (resolvedCacheOptions.cacheErrors) {\n markExpiry(entry)\n } else {\n entry.expiresAt = Date.now() - 1\n entry.hasValue = false\n }\n if (entry.pendingToken) {\n entry.pendingToken.reject(err)\n entry.pendingToken = null\n }\n })\n .finally(() => {\n entry.inFlight = undefined\n entry.controller = undefined\n })\n\n entry.inFlight = fetchPromise\n\n onCleanup(() => {\n if (resolvedCacheOptions.mode === 'none') {\n controller.abort()\n cache.delete(key)\n }\n })\n }\n\n const invalidate = (key?: unknown) => {\n if (key === undefined) {\n cache.forEach(entry => {\n entry.controller?.abort()\n entry.version(entry.version() + 1)\n entry.expiresAt = Date.now() - 1\n })\n cache.clear()\n return\n }\n const entry = cache.get(key)\n if (entry) {\n entry.controller?.abort()\n entry.version(entry.version() + 1)\n entry.expiresAt = Date.now() - 1\n cache.delete(key)\n }\n }\n\n const prefetch = (args: Args, keyOverride?: unknown) => {\n const key = keyOverride ?? computeKey(args)\n const entry = ensureEntry(key)\n const usableData = entry.hasValue && !isExpired(entry)\n if (!usableData) {\n entry.lastArgs = args\n entry.lastVersion = entry.version()\n startFetch(entry, key, args)\n }\n }\n\n return {\n read(argsAccessor: (() => Args) | Args): ResourceResult<T> {\n const entryRef = createSignal<ResourceEntry<T, Args> | null>(null)\n\n createEffect(() => {\n const key = computeKey(argsAccessor)\n const entry = ensureEntry(key)\n entryRef(entry)\n const args = readArgs(argsAccessor)\n const currentVersion = entry.version()\n const expired = isExpired(entry)\n const argsChanged = entry.lastArgs !== args\n const versionChanged = entry.lastVersion !== currentVersion\n const resetToken = readResetToken()\n const resetChanged = entry.lastReset !== resetToken\n // For stale-while-revalidate: if we have cached data, don't treat expired as requiring immediate refetch\n // We'll handle the revalidation separately to show stale data without loading state\n const canUseStaleData =\n resolvedCacheOptions.staleWhileRevalidate && entry.hasValue && expired\n const shouldRefetch =\n (expired && !canUseStaleData) ||\n argsChanged ||\n versionChanged ||\n resetChanged ||\n (entry.status === 'error' && !resolvedCacheOptions.cacheErrors)\n\n entry.lastArgs = args\n entry.lastVersion = currentVersion\n entry.lastReset = resetToken\n\n if (shouldRefetch) {\n if (entry.inFlight && (argsChanged || versionChanged)) {\n entry.controller?.abort()\n entry.inFlight = undefined\n }\n if (resetChanged) {\n entry.hasValue = false\n entry.expiresAt = Date.now() - 1\n }\n startFetch(entry, key, args as Args)\n } else if (canUseStaleData && entry.inFlight === undefined) {\n // stale-while-revalidate: return stale data immediately, refresh in background\n // Pass isRevalidating=true to avoid showing loading state\n startFetch(entry, key, args as Args, true)\n }\n })\n\n return {\n get data() {\n const entry = entryRef()\n if (!entry) return undefined\n if (useSuspense && entry.pendingToken) {\n throw entry.pendingToken.token\n }\n return entry.data()\n },\n get loading() {\n const entry = entryRef()\n return entry ? entry.loading() : false\n },\n get error() {\n const entry = entryRef()\n return entry ? entry.error() : undefined\n },\n refresh: () => {\n const entry = entryRef()\n if (entry) entry.version(entry.version() + 1)\n },\n }\n },\n invalidate,\n prefetch,\n }\n}\n","/**\n * @fileoverview Lazy component loading with Suspense support.\n *\n * Creates a component that loads its implementation asynchronously,\n * suspending rendering until the module is loaded.\n */\n\nimport { createSuspenseToken } from '@fictjs/runtime'\nimport type { Component } from '@fictjs/runtime'\n\n/** Module shape expected from dynamic imports */\nexport interface LazyModule<TProps extends Record<string, unknown>> {\n default: Component<TProps>\n}\n\n/** Options for lazy loading behavior */\nexport interface LazyOptions {\n /**\n * Maximum number of retry attempts on load failure.\n * Set to 0 to disable retries (default behavior).\n * @default 0\n */\n maxRetries?: number\n\n /**\n * Delay in milliseconds between retry attempts.\n * Uses exponential backoff: delay * 2^(attempt - 1)\n * @default 1000\n */\n retryDelay?: number\n}\n\n/** Extended component with retry capability */\nexport interface LazyComponent<TProps extends Record<string, unknown>> extends Component<TProps> {\n /**\n * Reset the lazy component state, allowing it to retry loading.\n * Useful when used with ErrorBoundary reset functionality.\n */\n reset: () => void\n\n /**\n * Preload the component without rendering it.\n * Returns a promise that resolves when the component is loaded.\n */\n preload: () => Promise<void>\n}\n\n/**\n * Create a lazy component that suspends while loading.\n *\n * @param loader - Function that returns a promise resolving to the component module\n * @param options - Optional configuration for retry behavior\n * @returns A component that suspends during loading and supports retry on failure\n *\n * @example\n * ```tsx\n * import { lazy, Suspense } from 'fict'\n *\n * // Basic usage\n * const LazyChart = lazy(() => import('./Chart'))\n *\n * // With retry options\n * const LazyDashboard = lazy(() => import('./Dashboard'), {\n * maxRetries: 3,\n * retryDelay: 1000\n * })\n *\n * function App() {\n * return (\n * <Suspense fallback={<Loading />}>\n * <LazyChart />\n * </Suspense>\n * )\n * }\n *\n * // Reset on error (with ErrorBoundary)\n * <ErrorBoundary fallback={(err, reset) => (\n * <button onClick={() => { LazyChart.reset(); reset(); }}>Retry</button>\n * )}>\n * <LazyChart />\n * </ErrorBoundary>\n * ```\n *\n * @public\n */\nexport function lazy<TProps extends Record<string, unknown> = Record<string, unknown>>(\n loader: () => Promise<LazyModule<TProps> | { default: Component<TProps> }>,\n options: LazyOptions = {},\n): LazyComponent<TProps> {\n const { maxRetries = 0, retryDelay = 1000 } = options\n\n let loaded: Component<TProps> | null = null\n let loadError: unknown = null\n let loadingPromise: Promise<unknown> | null = null\n let pendingToken: ReturnType<typeof createSuspenseToken> | null = null\n let retryCount = 0\n\n const attemptLoad = (): Promise<void> => {\n return loader()\n .then(mod => {\n loaded = (mod as LazyModule<TProps>).default\n loadError = null\n retryCount = 0\n pendingToken?.resolve()\n })\n .catch((err: unknown) => {\n if (retryCount < maxRetries) {\n retryCount++\n const delay = retryDelay * Math.pow(2, retryCount - 1)\n return new Promise<void>(resolve => {\n setTimeout(() => {\n resolve(attemptLoad())\n }, delay)\n })\n }\n loadError = err\n pendingToken?.reject(err)\n return undefined\n })\n .finally(() => {\n loadingPromise = null\n pendingToken = null\n })\n }\n\n const component = ((props: TProps) => {\n if (loaded) {\n return loaded(props)\n }\n if (loadError) {\n throw loadError\n }\n if (!loadingPromise) {\n pendingToken = createSuspenseToken()\n loadingPromise = attemptLoad()\n }\n if (pendingToken) {\n throw pendingToken.token\n }\n // Should never hit if pendingToken exists, but fallback for type safety.\n throw new Error('Lazy component failed to start loading')\n }) as LazyComponent<TProps>\n\n /**\n * Reset the lazy component state, clearing any cached error.\n * Call this before triggering a re-render to retry loading.\n */\n component.reset = () => {\n loadError = null\n loadingPromise = null\n pendingToken = null\n retryCount = 0\n // Note: we don't clear `loaded` - if it was successfully loaded, keep it\n }\n\n /**\n * Preload the component without rendering.\n * Useful for eager loading on route prefetch.\n */\n component.preload = (): Promise<void> => {\n if (loaded) {\n return Promise.resolve()\n }\n if (loadingPromise) {\n return loadingPromise as Promise<void>\n }\n pendingToken = createSuspenseToken()\n loadingPromise = attemptLoad()\n return loadingPromise as Promise<void>\n }\n\n return component\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/store.ts","../src/resource.ts","../src/lazy.ts"],"names":["createSignal","signals","createSuspenseToken","onCleanup","entry","createEffect"],"mappings":";;;;;;AA4BA,IAAM,WAAA,uBAAkB,OAAA,EAAyB;AAGjD,IAAM,YAAA,uBAAmB,OAAA,EAA0D;AAGnF,IAAM,kBAAA,uBAAyB,OAAA,EAAwD;AAGvF,IAAM,WAAA,GAAc,OAAO,SAAS,CAAA;AAMpC,SAAS,SAAA,CAAU,QAAgB,IAAA,EAAwC;AACzE,EAAA,IAAI,OAAA,GAAU,YAAA,CAAa,GAAA,CAAI,MAAM,CAAA;AACrC,EAAA,IAAI,CAAC,OAAA,EAAS;AACZ,IAAA,OAAA,GAAU,EAAC;AACX,IAAA,YAAA,CAAa,GAAA,CAAI,QAAQ,OAAO,CAAA;AAAA,EAClC;AACA,EAAA,IAAI,CAAC,OAAA,CAAQ,IAAI,CAAA,EAAG;AAClB,IAAA,MAAM,OAAA,GAAU,IAAA,KAAS,WAAA,GAAc,CAAA,GAAK,OAA2B,IAAI,CAAA;AAC3E,IAAA,OAAA,CAAQ,IAAI,CAAA,GAAIA,qBAAA,CAAa,OAAO,CAAA;AAAA,EACtC;AACA,EAAA,OAAO,QAAQ,IAAI,CAAA;AACrB;AAMA,SAAS,iBAAiB,MAAA,EAAsB;AAC9C,EAAA,MAAM,OAAA,GAAU,YAAA,CAAa,GAAA,CAAI,MAAM,CAAA;AACvC,EAAA,IAAI,OAAA,IAAW,OAAA,CAAQ,WAAW,CAAA,EAAG;AACnC,IAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,WAAW,CAAA,EAAE;AACrC,IAAA,OAAA,CAAQ,WAAW,CAAA,CAAE,OAAA,GAAU,CAAC,CAAA;AAAA,EAClC;AACF;AA+BO,SAAS,OAAyB,YAAA,EAAoB;AAC3D,EAAA,IAAI,OAAO,YAAA,KAAiB,QAAA,IAAY,YAAA,KAAiB,IAAA,EAAM;AAC7D,IAAA,OAAO,YAAA;AAAA,EACT;AAEA,EAAA,IAAI,WAAA,CAAY,GAAA,CAAI,YAAY,CAAA,EAAG;AACjC,IAAA,OAAO,WAAA,CAAY,IAAI,YAAY,CAAA;AAAA,EACrC;AAEA,EAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,CAAM,YAAA,EAAc;AAAA,IACpC,GAAA,CAAI,MAAA,EAAQ,IAAA,EAAM,QAAA,EAAU;AAG1B,MAAA,MAAM,MAAA,GAAS,SAAA,CAAU,MAAA,EAAQ,IAAI,CAAA;AACrC,MAAA,MAAM,eAAe,MAAA,EAAO;AAE5B,MAAA,MAAM,eAAe,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,IAAA,EAAM,YAAY,KAAK,CAAA;AAChE,MAAA,IAAI,iBAAiB,YAAA,EAAc;AAIjC,QAAA,MAAA,CAAO,YAAY,CAAA;AAAA,MACrB;AAEA,MAAA,IAAI,OAAO,iBAAiB,UAAA,EAAY;AACtC,QAAA,IAAI,YAAA,GAAe,kBAAA,CAAmB,GAAA,CAAI,MAAM,CAAA;AAChD,QAAA,IAAI,CAAC,YAAA,EAAc;AACjB,UAAA,YAAA,uBAAmB,GAAA,EAAI;AACvB,UAAA,kBAAA,CAAmB,GAAA,CAAI,QAAQ,YAAY,CAAA;AAAA,QAC7C;AACA,QAAA,MAAM,MAAA,GAAS,YAAA,CAAa,GAAA,CAAI,IAAI,CAAA;AACpC,QAAA,IAAI,MAAA,IAAU,MAAA,CAAO,GAAA,KAAQ,YAAA,EAAc;AACzC,UAAA,OAAO,MAAA,CAAO,KAAA;AAAA,QAChB;AAEA,QAAA,MAAM,KAAA,GAAS,YAAA,CAAuB,IAAA,CAAK,QAAA,IAAY,KAAK,CAAA;AAC5D,QAAA,YAAA,CAAa,IAAI,IAAA,EAAM,EAAE,GAAA,EAAK,YAAA,EAAuB,OAAO,CAAA;AAC5D,QAAA,OAAO,KAAA;AAAA,MACT;AAGA,MAAA,IAAI,OAAO,YAAA,KAAiB,QAAA,IAAY,YAAA,KAAiB,IAAA,EAAM;AAC7D,QAAA,OAAO,OAAO,YAAuC,CAAA;AAAA,MACvD;AAGA,MAAA,OAAO,YAAA;AAAA,IACT,CAAA;AAAA,IAEA,GAAA,CAAI,MAAA,EAAQ,IAAA,EAAM,QAAA,EAAU,QAAA,EAAU;AACpC,MAAA,MAAM,SAAA,GAAY,MAAM,OAAA,CAAQ,MAAM,KAAK,IAAA,KAAS,QAAA,GAAW,OAAO,MAAA,GAAS,MAAA;AAC/E,MAAA,MAAM,QAAA,GAAW,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,MAAM,QAAQ,CAAA;AACnD,MAAA,MAAM,SAAS,MAAA,CAAO,SAAA,CAAU,cAAA,CAAe,IAAA,CAAK,QAAQ,IAAI,CAAA;AAGhE,MAAA,IAAI,QAAA,KAAa,YAAY,MAAA,EAAQ;AACnC,QAAA,OAAO,IAAA;AAAA,MACT;AAEA,MAAA,MAAM,SAAS,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,IAAA,EAAM,UAAU,QAAQ,CAAA;AAG3D,MAAA,MAAM,YAAA,GAAe,kBAAA,CAAmB,GAAA,CAAI,MAAM,CAAA;AAClD,MAAA,IAAI,YAAA,IAAgB,YAAA,CAAa,GAAA,CAAI,IAAI,CAAA,EAAG;AAC1C,QAAA,YAAA,CAAa,OAAO,IAAI,CAAA;AAAA,MAC1B;AAGA,MAAA,MAAM,OAAA,GAAU,YAAA,CAAa,GAAA,CAAI,MAAM,CAAA;AACvC,MAAA,IAAI,OAAA,IAAW,OAAA,CAAQ,IAAI,CAAA,EAAG;AAC5B,QAAA,OAAA,CAAQ,IAAI,EAAE,QAAQ,CAAA;AAAA,MACxB;AAGA,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA,gBAAA,CAAiB,MAAM,CAAA;AAAA,MACzB;AAIA,MAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,IAAK,SAAS,QAAA,EAAU;AAC9C,QAAA,MAAMC,QAAAA,GAAU,YAAA,CAAa,GAAA,CAAI,MAAM,CAAA;AACvC,QAAA,IAAIA,QAAAA,IAAWA,SAAQ,MAAA,EAAQ;AAC7B,UAAAA,QAAAA,CAAQ,MAAA,CAAO,MAAA,CAAO,MAAM,CAAA;AAAA,QAC9B;AAAA,MACF;AAGA,MAAA,IAAI,KAAA,CAAM,OAAA,CAAQ,MAAM,CAAA,IAAK,SAAS,QAAA,EAAU;AAC9C,QAAA,MAAM,aAAa,MAAA,CAAO,MAAA;AAC1B,QAAA,IAAI,OAAO,SAAA,KAAc,QAAA,IAAY,UAAA,GAAa,SAAA,EAAW;AAC3D,UAAA,MAAMA,QAAAA,GAAU,YAAA,CAAa,GAAA,CAAI,MAAM,CAAA;AACvC,UAAA,IAAIA,QAAAA,EAAS;AACX,YAAA,KAAA,IAAS,CAAA,GAAI,UAAA,EAAY,CAAA,GAAI,SAAA,EAAW,KAAK,CAAA,EAAG;AAC9C,cAAA,MAAM,GAAA,GAAM,OAAO,CAAC,CAAA;AACpB,cAAA,IAAIA,QAAAA,CAAQ,GAAG,CAAA,EAAG;AAChB,gBAAAA,QAAAA,CAAQ,GAAG,CAAA,CAAE,MAAS,CAAA;AAAA,cACxB;AAAA,YACF;AAAA,UACF;AAAA,QACF;AACA,QAAA,gBAAA,CAAiB,MAAM,CAAA;AAAA,MACzB;AAEA,MAAA,OAAO,MAAA;AAAA,IACT,CAAA;AAAA,IAEA,cAAA,CAAe,QAAQ,IAAA,EAAM;AAC3B,MAAA,MAAM,SAAS,MAAA,CAAO,SAAA,CAAU,cAAA,CAAe,IAAA,CAAK,QAAQ,IAAI,CAAA;AAChE,MAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,cAAA,CAAe,MAAA,EAAQ,IAAI,CAAA;AAElD,MAAA,IAAI,UAAU,MAAA,EAAQ;AACpB,QAAA,MAAM,OAAA,GAAU,YAAA,CAAa,GAAA,CAAI,MAAM,CAAA;AACvC,QAAA,IAAI,OAAA,IAAW,OAAA,CAAQ,IAAI,CAAA,EAAG;AAC5B,UAAA,OAAA,CAAQ,IAAI,EAAE,MAAS,CAAA;AAAA,QACzB;AAGA,QAAA,MAAM,YAAA,GAAe,kBAAA,CAAmB,GAAA,CAAI,MAAM,CAAA;AAClD,QAAA,IAAI,YAAA,IAAgB,YAAA,CAAa,GAAA,CAAI,IAAI,CAAA,EAAG;AAC1C,UAAA,YAAA,CAAa,OAAO,IAAI,CAAA;AAAA,QAC1B;AAEA,QAAA,gBAAA,CAAiB,MAAM,CAAA;AAAA,MACzB;AAEA,MAAA,OAAO,MAAA;AAAA,IACT,CAAA;AAAA,IAEA,QAAQ,MAAA,EAAQ;AACd,MAAA,SAAA,CAAU,MAAA,EAAQ,WAAW,CAAA,EAAE;AAC/B,MAAA,OAAO,OAAA,CAAQ,QAAQ,MAAM,CAAA;AAAA,IAC/B,CAAA;AAAA,IAEA,GAAA,CAAI,QAAQ,IAAA,EAAM;AAChB,MAAA,SAAA,CAAU,MAAA,EAAQ,IAAI,CAAA,EAAE;AACxB,MAAA,OAAO,OAAA,CAAQ,GAAA,CAAI,MAAA,EAAQ,IAAI,CAAA;AAAA,IACjC;AAAA,GACD,CAAA;AAED,EAAA,WAAA,CAAY,GAAA,CAAI,cAAc,KAAK,CAAA;AACnC,EAAA,OAAO,KAAA;AACT;AC9DA,IAAM,mBAAA,GAAsD;AAAA,EAC1D,IAAA,EAAM,QAAA;AAAA,EACN,OAAO,MAAA,CAAO,iBAAA;AAAA,EACd,oBAAA,EAAsB,KAAA;AAAA,EACtB,WAAA,EAAa;AACf,CAAA;AA4CO,SAAS,SACd,gBAAA,EAGmB;AACnB,EAAA,MAAM,OAAA,GAAU,OAAO,gBAAA,KAAqB,UAAA,GAAa,mBAAmB,gBAAA,CAAiB,KAAA;AAC7F,EAAA,MAAM,cAAc,OAAO,gBAAA,KAAqB,QAAA,IAAY,CAAC,CAAC,gBAAA,CAAiB,QAAA;AAC/E,EAAA,MAAM,YAAA,GACJ,OAAO,gBAAA,KAAqB,QAAA,GAAY,iBAAiB,KAAA,IAAS,KAAM,EAAC;AAC3E,EAAA,MAAM,oBAAA,GAAuB,EAAE,GAAG,mBAAA,EAAqB,GAAG,YAAA,EAAa;AACvE,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAqC;AAEvD,EAAA,MAAM,WAAW,CAAC,YAAA,KAChB,OAAO,YAAA,KAAiB,UAAA,GAAc,cAA4B,GAAI,YAAA;AAExE,EAAA,MAAM,UAAA,GAAa,CAAC,YAAA,KAA+C;AACjE,IAAA,MAAM,SAAA,GAAY,SAAS,YAAY,CAAA;AACvC,IAAA,IAAI,OAAO,gBAAA,KAAqB,QAAA,IAAY,gBAAA,CAAiB,QAAQ,MAAA,EAAW;AAC9E,MAAA,MAAM,MAAM,gBAAA,CAAiB,GAAA;AAC7B,MAAA,OAAO,OAAO,GAAA,KAAQ,UAAA,GAAc,GAAA,CAAgC,SAAS,CAAA,GAAI,GAAA;AAAA,IACnF;AACA,IAAA,OAAO,SAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,iBAAiB,MAAe;AACpC,IAAA,IAAI,OAAO,gBAAA,KAAqB,QAAA,EAAU,OAAO,MAAA;AACjD,IAAA,MAAM,QAAQ,gBAAA,CAAiB,KAAA;AAC/B,IAAA,IAAI,OAAO,KAAA,KAAU,UAAA,IAAe,KAAA,CAAwB,WAAW,CAAA,EAAG;AACxE,MAAA,OAAQ,KAAA,EAAwB;AAAA,IAClC;AACA,IAAA,OAAO,KAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,WAAA,GAAc,CAAC,GAAA,KAAyC;AAC5D,IAAA,IAAI,KAAA,GAAQ,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AACzB,IAAA,IAAI,CAAC,KAAA,EAAO;AACV,MAAA,KAAA,GAAQ;AAAA,QACN,IAAA,EAAMD,sBAA4B,MAAS,CAAA;AAAA,QAC3C,OAAA,EAASA,sBAAsB,KAAK,CAAA;AAAA,QACpC,KAAA,EAAOA,sBAAsB,MAAS,CAAA;AAAA,QACtC,OAAA,EAASA,sBAAa,CAAC,CAAA;AAAA,QACvB,YAAA,EAAc,IAAA;AAAA,QACd,QAAA,EAAU,MAAA;AAAA,QACV,WAAA,EAAa,EAAA;AAAA,QACb,SAAA,EAAW,MAAA;AAAA,QACX,QAAA,EAAU,KAAA;AAAA,QACV,MAAA,EAAQ,MAAA;AAAA,QACR,UAAA,EAAY,CAAA;AAAA,QACZ,SAAA,EAAW,MAAA;AAAA,QACX,QAAA,EAAU,MAAA;AAAA,QACV,UAAA,EAAY;AAAA,OACd;AACA,MAAA,KAAA,CAAM,GAAA,CAAI,KAAK,KAAK,CAAA;AAAA,IACtB;AACA,IAAA,OAAO,KAAA;AAAA,EACT,CAAA;AAEA,EAAA,MAAM,SAAA,GAAY,CAAC,KAAA,KAA2C;AAC5D,IAAA,IAAI,oBAAA,CAAqB,IAAA,KAAS,MAAA,EAAQ,OAAO,IAAA;AACjD,IAAA,IAAI,CAAC,MAAA,CAAO,QAAA,CAAS,oBAAA,CAAqB,KAAK,GAAG,OAAO,KAAA;AACzD,IAAA,IAAI,KAAA,CAAM,SAAA,KAAc,MAAA,EAAW,OAAO,KAAA;AAC1C,IAAA,OAAO,KAAA,CAAM,SAAA,GAAY,IAAA,CAAK,GAAA,EAAI;AAAA,EACpC,CAAA;AAEA,EAAA,MAAM,UAAA,GAAa,CAAC,KAAA,KAAkC;AACpD,IAAA,IAAI,oBAAA,CAAqB,SAAS,MAAA,EAAQ;AACxC,MAAA,KAAA,CAAM,SAAA,GAAY,IAAA,CAAK,GAAA,EAAI,GAAI,CAAA;AAC/B,MAAA;AAAA,IACF;AACA,IAAA,KAAA,CAAM,SAAA,GAAY,MAAA,CAAO,QAAA,CAAS,oBAAA,CAAqB,KAAK,IACxD,IAAA,CAAK,GAAA,EAAI,GAAI,oBAAA,CAAqB,KAAA,GAClC,MAAA;AAAA,EACN,CAAA;AAEA,EAAA,MAAM,aAAa,CACjB,KAAA,EACA,GAAA,EACA,IAAA,EACA,iBAAiB,KAAA,KACd;AACH,IAAA,KAAA,CAAM,YAAY,KAAA,EAAM;AACxB,IAAA,KAAA,CAAM,QAAA,GAAW,MAAA;AACjB,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,KAAA,CAAM,UAAA,GAAa,UAAA;AACnB,IAAA,KAAA,CAAM,MAAA,GAAS,SAAA;AAEf,IAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,MAAA,KAAA,CAAM,QAAQ,IAAI,CAAA;AAAA,IACpB;AACA,IAAA,KAAA,CAAM,MAAM,MAAS,CAAA;AACrB,IAAA,KAAA,CAAM,UAAA,IAAc,CAAA;AACpB,IAAA,MAAM,aAAa,KAAA,CAAM,UAAA;AAEzB,IAAA,MAAM,aAAA,GAAgB,WAAA,IAAe,CAAC,KAAA,CAAM,QAAA;AAC5C,IAAA,KAAA,CAAM,YAAA,GAAe,aAAA,GAAgBE,2BAAA,EAAoB,GAAI,IAAA;AAE7D,IAAA,MAAM,YAAA,GAAe,OAAA,CAAQ,EAAE,MAAA,EAAQ,UAAA,CAAW,QAAO,EAAG,IAAI,CAAA,CAC7D,IAAA,CAAK,CAAA,GAAA,KAAO;AACX,MAAA,IAAI,UAAA,CAAW,MAAA,CAAO,OAAA,IAAW,KAAA,CAAM,eAAe,UAAA,EAAY;AAClE,MAAA,KAAA,CAAM,KAAK,GAAG,CAAA;AACd,MAAA,KAAA,CAAM,QAAA,GAAW,IAAA;AACjB,MAAA,KAAA,CAAM,MAAA,GAAS,SAAA;AACf,MAAA,KAAA,CAAM,QAAQ,KAAK,CAAA;AACnB,MAAA,UAAA,CAAW,KAAK,CAAA;AAChB,MAAA,IAAI,MAAM,YAAA,EAAc;AACtB,QAAA,KAAA,CAAM,aAAa,OAAA,EAAQ;AAC3B,QAAA,KAAA,CAAM,YAAA,GAAe,IAAA;AAAA,MACvB;AAAA,IACF,CAAC,CAAA,CACA,KAAA,CAAM,CAAA,GAAA,KAAO;AACZ,MAAA,IAAI,UAAA,CAAW,MAAA,CAAO,OAAA,IAAW,KAAA,CAAM,eAAe,UAAA,EAAY;AAClE,MAAA,KAAA,CAAM,MAAM,GAAG,CAAA;AACf,MAAA,KAAA,CAAM,MAAA,GAAS,OAAA;AACf,MAAA,KAAA,CAAM,QAAQ,KAAK,CAAA;AACnB,MAAA,IAAI,qBAAqB,WAAA,EAAa;AACpC,QAAA,UAAA,CAAW,KAAK,CAAA;AAAA,MAClB,CAAA,MAAO;AACL,QAAA,KAAA,CAAM,SAAA,GAAY,IAAA,CAAK,GAAA,EAAI,GAAI,CAAA;AAC/B,QAAA,KAAA,CAAM,QAAA,GAAW,KAAA;AAAA,MACnB;AACA,MAAA,IAAI,MAAM,YAAA,EAAc;AACtB,QAAA,KAAA,CAAM,YAAA,CAAa,OAAO,GAAG,CAAA;AAC7B,QAAA,KAAA,CAAM,YAAA,GAAe,IAAA;AAAA,MACvB;AAAA,IACF,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACb,MAAA,KAAA,CAAM,QAAA,GAAW,MAAA;AACjB,MAAA,KAAA,CAAM,UAAA,GAAa,MAAA;AAAA,IACrB,CAAC,CAAA;AAEH,IAAA,KAAA,CAAM,QAAA,GAAW,YAAA;AAEjB,IAAAC,iBAAA,CAAU,MAAM;AACd,MAAA,IAAI,oBAAA,CAAqB,SAAS,MAAA,EAAQ;AACxC,QAAA,UAAA,CAAW,KAAA,EAAM;AACjB,QAAA,KAAA,CAAM,OAAO,GAAG,CAAA;AAAA,MAClB;AAAA,IACF,CAAC,CAAA;AAAA,EACH,CAAA;AAEA,EAAA,MAAM,UAAA,GAAa,CAAC,GAAA,KAAkB;AACpC,IAAA,IAAI,QAAQ,MAAA,EAAW;AACrB,MAAA,KAAA,CAAM,OAAA,CAAQ,CAAAC,MAAAA,KAAS;AACrB,QAAAA,MAAAA,CAAM,YAAY,KAAA,EAAM;AACxB,QAAAA,MAAAA,CAAM,OAAA,CAAQA,MAAAA,CAAM,OAAA,KAAY,CAAC,CAAA;AACjC,QAAAA,MAAAA,CAAM,SAAA,GAAY,IAAA,CAAK,GAAA,EAAI,GAAI,CAAA;AAAA,MACjC,CAAC,CAAA;AACD,MAAA,KAAA,CAAM,KAAA,EAAM;AACZ,MAAA;AAAA,IACF;AACA,IAAA,MAAM,KAAA,GAAQ,KAAA,CAAM,GAAA,CAAI,GAAG,CAAA;AAC3B,IAAA,IAAI,KAAA,EAAO;AACT,MAAA,KAAA,CAAM,YAAY,KAAA,EAAM;AACxB,MAAA,KAAA,CAAM,OAAA,CAAQ,KAAA,CAAM,OAAA,EAAQ,GAAI,CAAC,CAAA;AACjC,MAAA,KAAA,CAAM,SAAA,GAAY,IAAA,CAAK,GAAA,EAAI,GAAI,CAAA;AAC/B,MAAA,KAAA,CAAM,OAAO,GAAG,CAAA;AAAA,IAClB;AAAA,EACF,CAAA;AAEA,EAAA,MAAM,QAAA,GAAW,CAAC,IAAA,EAAY,WAAA,KAA0B;AACtD,IAAA,MAAM,GAAA,GAAM,WAAA,IAAe,UAAA,CAAW,IAAI,CAAA;AAC1C,IAAA,MAAM,KAAA,GAAQ,YAAY,GAAG,CAAA;AAC7B,IAAA,MAAM,UAAA,GAAa,KAAA,CAAM,QAAA,IAAY,CAAC,UAAU,KAAK,CAAA;AACrD,IAAA,IAAI,CAAC,UAAA,EAAY;AACf,MAAA,KAAA,CAAM,QAAA,GAAW,IAAA;AACjB,MAAA,KAAA,CAAM,WAAA,GAAc,MAAM,OAAA,EAAQ;AAClC,MAAA,UAAA,CAAW,KAAA,EAAO,KAAK,IAAI,CAAA;AAAA,IAC7B;AAAA,EACF,CAAA;AAEA,EAAA,OAAO;AAAA,IACL,KAAK,YAAA,EAAsD;AACzD,MAAA,MAAM,QAAA,GAAWJ,sBAA4C,IAAI,CAAA;AAEjE,MAAAK,oBAAA,CAAa,MAAM;AACjB,QAAA,MAAM,GAAA,GAAM,WAAW,YAAY,CAAA;AACnC,QAAA,MAAM,KAAA,GAAQ,YAAY,GAAG,CAAA;AAC7B,QAAA,QAAA,CAAS,KAAK,CAAA;AACd,QAAA,MAAM,IAAA,GAAO,SAAS,YAAY,CAAA;AAClC,QAAA,MAAM,cAAA,GAAiB,MAAM,OAAA,EAAQ;AACrC,QAAA,MAAM,OAAA,GAAU,UAAU,KAAK,CAAA;AAC/B,QAAA,MAAM,WAAA,GAAc,MAAM,QAAA,KAAa,IAAA;AACvC,QAAA,MAAM,cAAA,GAAiB,MAAM,WAAA,KAAgB,cAAA;AAC7C,QAAA,MAAM,aAAa,cAAA,EAAe;AAClC,QAAA,MAAM,YAAA,GAAe,MAAM,SAAA,KAAc,UAAA;AAGzC,QAAA,MAAM,eAAA,GACJ,oBAAA,CAAqB,oBAAA,IAAwB,KAAA,CAAM,QAAA,IAAY,OAAA;AACjE,QAAA,MAAM,aAAA,GACH,OAAA,IAAW,CAAC,eAAA,IACb,WAAA,IACA,cAAA,IACA,YAAA,IACC,KAAA,CAAM,MAAA,KAAW,OAAA,IAAW,CAAC,oBAAA,CAAqB,WAAA;AAErD,QAAA,KAAA,CAAM,QAAA,GAAW,IAAA;AACjB,QAAA,KAAA,CAAM,WAAA,GAAc,cAAA;AACpB,QAAA,KAAA,CAAM,SAAA,GAAY,UAAA;AAElB,QAAA,IAAI,aAAA,EAAe;AACjB,UAAA,IAAI,KAAA,CAAM,QAAA,KAAa,WAAA,IAAe,cAAA,CAAA,EAAiB;AACrD,YAAA,KAAA,CAAM,YAAY,KAAA,EAAM;AACxB,YAAA,KAAA,CAAM,QAAA,GAAW,MAAA;AAAA,UACnB;AACA,UAAA,IAAI,YAAA,EAAc;AAChB,YAAA,KAAA,CAAM,QAAA,GAAW,KAAA;AACjB,YAAA,KAAA,CAAM,SAAA,GAAY,IAAA,CAAK,GAAA,EAAI,GAAI,CAAA;AAAA,UACjC;AACA,UAAA,UAAA,CAAW,KAAA,EAAO,KAAK,IAAY,CAAA;AAAA,QACrC,CAAA,MAAA,IAAW,eAAA,IAAmB,KAAA,CAAM,QAAA,KAAa,MAAA,EAAW;AAG1D,UAAA,UAAA,CAAW,KAAA,EAAO,GAAA,EAAK,IAAA,EAAc,IAAI,CAAA;AAAA,QAC3C;AAAA,MACF,CAAC,CAAA;AAED,MAAA,OAAO;AAAA,QACL,IAAI,IAAA,GAAO;AACT,UAAA,MAAM,QAAQ,QAAA,EAAS;AACvB,UAAA,IAAI,CAAC,OAAO,OAAO,MAAA;AACnB,UAAA,IAAI,WAAA,IAAe,MAAM,YAAA,EAAc;AACrC,YAAA,MAAM,MAAM,YAAA,CAAa,KAAA;AAAA,UAC3B;AACA,UAAA,OAAO,MAAM,IAAA,EAAK;AAAA,QACpB,CAAA;AAAA,QACA,IAAI,OAAA,GAAU;AACZ,UAAA,MAAM,QAAQ,QAAA,EAAS;AACvB,UAAA,OAAO,KAAA,GAAQ,KAAA,CAAM,OAAA,EAAQ,GAAI,KAAA;AAAA,QACnC,CAAA;AAAA,QACA,IAAI,KAAA,GAAQ;AACV,UAAA,MAAM,QAAQ,QAAA,EAAS;AACvB,UAAA,OAAO,KAAA,GAAQ,KAAA,CAAM,KAAA,EAAM,GAAI,MAAA;AAAA,QACjC,CAAA;AAAA,QACA,SAAS,MAAM;AACb,UAAA,MAAM,QAAQ,QAAA,EAAS;AACvB,UAAA,IAAI,OAAO,KAAA,CAAM,OAAA,CAAQ,KAAA,CAAM,OAAA,KAAY,CAAC,CAAA;AAAA,QAC9C;AAAA,OACF;AAAA,IACF,CAAA;AAAA,IACA,UAAA;AAAA,IACA;AAAA,GACF;AACF;AChYO,SAAS,IAAA,CACd,MAAA,EACA,OAAA,GAAuB,EAAC,EACD;AACvB,EAAA,MAAM,EAAE,UAAA,GAAa,CAAA,EAAG,UAAA,GAAa,KAAK,GAAI,OAAA;AAE9C,EAAA,IAAI,MAAA,GAAmC,IAAA;AACvC,EAAA,IAAI,SAAA,GAAqB,IAAA;AACzB,EAAA,IAAI,cAAA,GAA0C,IAAA;AAC9C,EAAA,IAAI,YAAA,GAA8D,IAAA;AAClE,EAAA,IAAI,UAAA,GAAa,CAAA;AAEjB,EAAA,MAAM,cAAc,MAAqB;AACvC,IAAA,OAAO,MAAA,EAAO,CACX,IAAA,CAAK,CAAA,GAAA,KAAO;AACX,MAAA,MAAA,GAAU,GAAA,CAA2B,OAAA;AACrC,MAAA,SAAA,GAAY,IAAA;AACZ,MAAA,UAAA,GAAa,CAAA;AACb,MAAA,YAAA,EAAc,OAAA,EAAQ;AAAA,IACxB,CAAC,CAAA,CACA,KAAA,CAAM,CAAC,GAAA,KAAiB;AACvB,MAAA,IAAI,aAAa,UAAA,EAAY;AAC3B,QAAA,UAAA,EAAA;AACA,QAAA,MAAM,QAAQ,UAAA,GAAa,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,aAAa,CAAC,CAAA;AACrD,QAAA,OAAO,IAAI,QAAc,CAAA,OAAA,KAAW;AAClC,UAAA,UAAA,CAAW,MAAM;AACf,YAAA,OAAA,CAAQ,aAAa,CAAA;AAAA,UACvB,GAAG,KAAK,CAAA;AAAA,QACV,CAAC,CAAA;AAAA,MACH;AACA,MAAA,SAAA,GAAY,GAAA;AACZ,MAAA,YAAA,EAAc,OAAO,GAAG,CAAA;AACxB,MAAA,OAAO,MAAA;AAAA,IACT,CAAC,CAAA,CACA,OAAA,CAAQ,MAAM;AACb,MAAA,cAAA,GAAiB,IAAA;AACjB,MAAA,YAAA,GAAe,IAAA;AAAA,IACjB,CAAC,CAAA;AAAA,EACL,CAAA;AAEA,EAAA,MAAM,SAAA,IAAa,CAAC,KAAA,KAAkB;AACpC,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,OAAO,OAAO,KAAK,CAAA;AAAA,IACrB;AACA,IAAA,IAAI,SAAA,EAAW;AACb,MAAA,MAAM,SAAA;AAAA,IACR;AACA,IAAA,IAAI,CAAC,cAAA,EAAgB;AACnB,MAAA,YAAA,GAAeH,2BAAAA,EAAoB;AACnC,MAAA,cAAA,GAAiB,WAAA,EAAY;AAAA,IAC/B;AACA,IAAA,IAAI,YAAA,EAAc;AAChB,MAAA,MAAM,YAAA,CAAa,KAAA;AAAA,IACrB;AAEA,IAAA,MAAM,IAAI,MAAM,wCAAwC,CAAA;AAAA,EAC1D,CAAA,CAAA;AAMA,EAAA,SAAA,CAAU,QAAQ,MAAM;AACtB,IAAA,SAAA,GAAY,IAAA;AACZ,IAAA,cAAA,GAAiB,IAAA;AACjB,IAAA,YAAA,GAAe,IAAA;AACf,IAAA,UAAA,GAAa,CAAA;AAAA,EAEf,CAAA;AAMA,EAAA,SAAA,CAAU,UAAU,MAAqB;AACvC,IAAA,IAAI,MAAA,EAAQ;AACV,MAAA,OAAO,QAAQ,OAAA,EAAQ;AAAA,IACzB;AACA,IAAA,IAAI,cAAA,EAAgB;AAClB,MAAA,OAAO,cAAA;AAAA,IACT;AACA,IAAA,YAAA,GAAeA,2BAAAA,EAAoB;AACnC,IAAA,cAAA,GAAiB,WAAA,EAAY;AAC7B,IAAA,OAAO,cAAA;AAAA,EACT,CAAA;AAEA,EAAA,OAAO,SAAA;AACT","file":"plus.cjs","sourcesContent":["/**\n * @fileoverview Deep reactive store implementation for Fict.\n *\n * $store creates a deeply reactive proxy that tracks property access at the path level.\n * Unlike $state (which is shallow), $store allows direct mutation of nested properties.\n *\n * @example\n * ```typescript\n * const user = $store({ name: 'Alice', address: { city: 'London' } })\n * user.address.city = 'Paris' // Fine-grained reactive update\n * ```\n */\n\nimport { createSignal, type Signal } from '@fictjs/runtime/advanced'\n\n/** Function type for bound methods */\ntype AnyFn = (...args: unknown[]) => unknown\n\n/** Cache entry for bound methods to preserve identity */\ninterface BoundMethodEntry {\n ref: AnyFn\n bound: AnyFn\n}\n\n/** Type for objects with indexable properties */\ntype IndexableObject = Record<string | symbol, unknown>\n\n/** Cache of proxied objects to avoid duplicate proxies */\nconst PROXY_CACHE = new WeakMap<object, unknown>()\n\n/** Cache of signals per object property */\nconst SIGNAL_CACHE = new WeakMap<object, Record<string | symbol, Signal<unknown>>>()\n\n/** Cache of bound methods to preserve function identity across reads */\nconst BOUND_METHOD_CACHE = new WeakMap<object, Map<string | symbol, BoundMethodEntry>>()\n\n/** Special key for tracking iteration (Object.keys, for-in, etc.) */\nconst ITERATE_KEY = Symbol('iterate')\n\n/**\n * Get or create a signal for a specific property on a target object.\n * @internal\n */\nfunction getSignal(target: object, prop: string | symbol): Signal<unknown> {\n let signals = SIGNAL_CACHE.get(target)\n if (!signals) {\n signals = {}\n SIGNAL_CACHE.set(target, signals)\n }\n if (!signals[prop]) {\n const initial = prop === ITERATE_KEY ? 0 : (target as IndexableObject)[prop]\n signals[prop] = createSignal(initial)\n }\n return signals[prop]\n}\n\n/**\n * Trigger iteration signal to notify consumers that keys have changed.\n * @internal\n */\nfunction triggerIteration(target: object): void {\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals[ITERATE_KEY]) {\n const current = signals[ITERATE_KEY]() as number\n signals[ITERATE_KEY](current + 1)\n }\n}\n\n/**\n * Create a deep reactive store using Proxy.\n *\n * Unlike `$state` (which is shallow and compiler-transformed), `$store` provides:\n * - **Deep reactivity**: Nested objects are automatically wrapped in proxies\n * - **Direct mutation**: Modify properties directly without spread operators\n * - **Path-level tracking**: Only components reading changed paths re-render\n *\n * @param initialValue - The initial object to make reactive\n * @returns A reactive proxy of the object\n *\n * @example\n * ```tsx\n * import { $store } from 'fict'\n *\n * const form = $store({\n * user: { name: '', email: '' },\n * settings: { theme: 'light' }\n * })\n *\n * // Direct mutation works\n * form.user.name = 'Alice'\n *\n * // In JSX - only updates when form.user.name changes\n * <input value={form.user.name} />\n * ```\n *\n * @public\n */\nexport function $store<T extends object>(initialValue: T): T {\n if (typeof initialValue !== 'object' || initialValue === null) {\n return initialValue\n }\n\n if (PROXY_CACHE.has(initialValue)) {\n return PROXY_CACHE.get(initialValue) as T\n }\n\n const proxy = new Proxy(initialValue, {\n get(target, prop, receiver) {\n // Always touch the signal so reference changes to this property are tracked,\n // even if the value is an object we proxy further.\n const signal = getSignal(target, prop)\n const trackedValue = signal()\n\n const currentValue = Reflect.get(target, prop, receiver ?? proxy)\n if (currentValue !== trackedValue) {\n // If the value has changed (e.g. via direct mutation of the underlying object not via proxy),\n // we update the signal to keep it in sync.\n // Note: This is a bit of a heuristic. Ideally all mutations go through proxy.\n signal(currentValue)\n }\n\n if (typeof currentValue === 'function') {\n let boundMethods = BOUND_METHOD_CACHE.get(target)\n if (!boundMethods) {\n boundMethods = new Map()\n BOUND_METHOD_CACHE.set(target, boundMethods)\n }\n const cached = boundMethods.get(prop)\n if (cached && cached.ref === currentValue) {\n return cached.bound\n }\n\n const bound = (currentValue as AnyFn).bind(receiver ?? proxy)\n boundMethods.set(prop, { ref: currentValue as AnyFn, bound })\n return bound\n }\n\n // If the value is an object/array, we recursively wrap it in a store\n if (typeof currentValue === 'object' && currentValue !== null) {\n return $store(currentValue as Record<string, unknown>)\n }\n\n // For primitives (and functions), we return the signal value (which tracks the read)\n return currentValue\n },\n\n set(target, prop, newValue, receiver) {\n const oldLength = Array.isArray(target) && prop === 'length' ? target.length : undefined\n const oldValue = Reflect.get(target, prop, receiver)\n const hadKey = Object.prototype.hasOwnProperty.call(target, prop)\n\n // If value hasn't changed, do nothing\n if (oldValue === newValue && hadKey) {\n return true\n }\n\n const result = Reflect.set(target, prop, newValue, receiver)\n\n // IMPORTANT: Clear bound method cache BEFORE updating the signal\n const boundMethods = BOUND_METHOD_CACHE.get(target)\n if (boundMethods && boundMethods.has(prop)) {\n boundMethods.delete(prop)\n }\n\n // Update the signal if it exists\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals[prop]) {\n signals[prop](newValue)\n }\n\n // If new property, trigger iteration update\n if (!hadKey) {\n triggerIteration(target)\n }\n\n // Ensure array length subscribers are notified even if the native push/pop\n // doesn't trigger a separate set trap for \"length\" (defensive).\n if (Array.isArray(target) && prop !== 'length') {\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals.length) {\n signals.length(target.length)\n }\n }\n\n // If it's an array and length changed implicitly, we might need to handle it.\n if (Array.isArray(target) && prop === 'length') {\n const nextLength = target.length\n if (typeof oldLength === 'number' && nextLength < oldLength) {\n const signals = SIGNAL_CACHE.get(target)\n if (signals) {\n for (let i = nextLength; i < oldLength; i += 1) {\n const key = String(i)\n if (signals[key]) {\n signals[key](undefined)\n }\n }\n }\n }\n triggerIteration(target)\n }\n\n return result\n },\n\n deleteProperty(target, prop) {\n const hadKey = Object.prototype.hasOwnProperty.call(target, prop)\n const result = Reflect.deleteProperty(target, prop)\n\n if (result && hadKey) {\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals[prop]) {\n signals[prop](undefined)\n }\n\n // Clear bound method cache\n const boundMethods = BOUND_METHOD_CACHE.get(target)\n if (boundMethods && boundMethods.has(prop)) {\n boundMethods.delete(prop)\n }\n\n triggerIteration(target)\n }\n\n return result\n },\n\n ownKeys(target) {\n getSignal(target, ITERATE_KEY)()\n return Reflect.ownKeys(target)\n },\n\n has(target, prop) {\n getSignal(target, prop)()\n return Reflect.has(target, prop)\n },\n })\n\n PROXY_CACHE.set(initialValue, proxy)\n return proxy\n}\n","/**\n * @fileoverview Async data fetching with caching and Suspense support.\n *\n * The `resource` function creates a reactive data fetcher that:\n * - Automatically cancels in-flight requests when args change\n * - Supports Suspense for loading states\n * - Provides caching with TTL and stale-while-revalidate\n * - Handles errors gracefully\n */\n\nimport { createEffect, onCleanup, createSuspenseToken } from '@fictjs/runtime'\nimport { createSignal } from '@fictjs/runtime/advanced'\n\n/**\n * The result of reading a resource.\n *\n * @typeParam T - The type of data returned by the fetcher\n */\nexport interface ResourceResult<T> {\n /** The fetched data, or undefined if not yet loaded or on error */\n readonly data: T | undefined\n /** Whether the resource is currently loading (initial fetch or refetch) */\n readonly loading: boolean\n /**\n * Any error that occurred during fetching.\n * Type is unknown since errors can be any value in JavaScript.\n */\n readonly error: unknown\n /** Manually trigger a refetch of the resource */\n refresh: () => void\n}\n\n/**\n * Cache configuration options for a resource.\n */\nexport interface ResourceCacheOptions {\n /**\n * Caching mode:\n * - `'memory'`: Cache responses in memory (default)\n * - `'none'`: No caching, always refetch\n * @default 'memory'\n */\n mode?: 'memory' | 'none'\n\n /**\n * Time-to-live in milliseconds before cached data is considered stale.\n * @default Infinity\n */\n ttlMs?: number\n\n /**\n * If true, return stale cached data immediately while refetching in background.\n * @default false\n */\n staleWhileRevalidate?: boolean\n\n /**\n * If true, cache error responses as well.\n * @default false\n */\n cacheErrors?: boolean\n}\n\n/**\n * Configuration options for creating a resource.\n *\n * @typeParam T - The type of data returned by the fetcher\n * @typeParam Args - The type of arguments passed to the fetcher\n */\nexport interface ResourceOptions<T, Args> {\n /**\n * Custom cache key. Can be a static value or a function that computes\n * the key from the args. If not provided, args are used as the key.\n */\n key?: unknown | ((args: Args) => unknown)\n\n /**\n * The fetcher function that performs the async data retrieval.\n * Receives an AbortController signal for cancellation support.\n */\n fetch: (ctx: { signal: AbortSignal }, args: Args) => Promise<T>\n\n /**\n * If true, the resource will throw a Suspense token while loading,\n * enabling React-like Suspense boundaries.\n * @default false\n */\n suspense?: boolean\n\n /**\n * Cache configuration options.\n */\n cache?: ResourceCacheOptions\n\n /**\n * A value or reactive getter that, when changed, resets the resource.\n * Useful for clearing cache when certain conditions change.\n */\n reset?: unknown | (() => unknown)\n}\n\n/**\n * Return type of the resource factory.\n *\n * @typeParam T - The type of data returned by the fetcher\n * @typeParam Args - The type of arguments passed to the fetcher\n */\nexport interface Resource<T, Args> {\n /**\n * Read the resource data, triggering a fetch if needed.\n * Can accept static args or a reactive getter.\n *\n * @param argsAccessor - Arguments or a getter returning arguments\n */\n read(argsAccessor: (() => Args) | Args): ResourceResult<T>\n\n /**\n * Invalidate cached data, causing the next read to refetch.\n *\n * @param key - Optional specific key to invalidate. If omitted, invalidates all.\n */\n invalidate(key?: unknown): void\n\n /**\n * Prefetch data without reading it. Useful for eager loading.\n *\n * @param args - Arguments to pass to the fetcher\n * @param keyOverride - Optional cache key override\n */\n prefetch(args: Args, keyOverride?: unknown): void\n}\n\n/**\n * Resource status values for tracking fetch lifecycle.\n * @internal\n */\nexport type ResourceStatus = 'idle' | 'pending' | 'success' | 'error'\n\n/**\n * Internal cache entry for a resource.\n * Tracks the reactive state and metadata for a single cached fetch.\n *\n * @typeParam T - The type of data returned by the fetcher\n * @typeParam Args - The type of arguments passed to the fetcher\n * @internal\n */\ninterface ResourceEntry<T, Args> {\n /** Reactive signal for the fetched data */\n data: ReturnType<typeof createSignal<T | undefined>>\n /** Reactive signal for loading state */\n loading: ReturnType<typeof createSignal<boolean>>\n /** Reactive signal for error state */\n error: ReturnType<typeof createSignal<unknown>>\n /** Version counter for invalidation */\n version: ReturnType<typeof createSignal<number>>\n /** Suspense token when using suspense mode */\n pendingToken: ReturnType<typeof createSuspenseToken> | null\n /** Last used arguments for change detection */\n lastArgs: Args | undefined\n /** Last seen version for change detection */\n lastVersion: number\n /** Last reset token value for change detection */\n lastReset: unknown\n /** Whether we have a valid cached value */\n hasValue: boolean\n /** Current fetch status */\n status: ResourceStatus\n /** Generation counter to handle race conditions */\n generation: number\n /** Timestamp when the cached value expires */\n expiresAt: number | undefined\n /** Currently in-flight fetch promise */\n inFlight: Promise<void> | undefined\n /** AbortController for cancelling in-flight requests */\n controller: AbortController | undefined\n}\n\nconst defaultCacheOptions: Required<ResourceCacheOptions> = {\n mode: 'memory',\n ttlMs: Number.POSITIVE_INFINITY,\n staleWhileRevalidate: false,\n cacheErrors: false,\n}\n\n/**\n * Create a reactive async data resource.\n *\n * Resources handle async data fetching with automatic caching, cancellation,\n * and optional Suspense integration.\n *\n * @param optionsOrFetcher - A fetcher function or full configuration object\n * @returns A resource factory with read, invalidate, and prefetch methods\n *\n * @example\n * ```tsx\n * import { resource } from 'fict'\n *\n * // Simple fetcher\n * const userResource = resource(\n * ({ signal }, userId: string) =>\n * fetch(`/api/users/${userId}`, { signal }).then(r => r.json())\n * )\n *\n * // With full options\n * const postsResource = resource({\n * fetch: ({ signal }, userId: string) =>\n * fetch(`/api/users/${userId}/posts`, { signal }).then(r => r.json()),\n * suspense: true,\n * cache: {\n * ttlMs: 60_000,\n * staleWhileRevalidate: true,\n * },\n * })\n *\n * // Usage in component\n * function UserProfile({ userId }: { userId: string }) {\n * const { data, loading, error, refresh } = userResource.read(() => userId)\n *\n * if (loading) return <Spinner />\n * if (error) return <ErrorMessage error={error} />\n * return <div>{data.name}</div>\n * }\n * ```\n *\n * @public\n */\nexport function resource<T, Args = void>(\n optionsOrFetcher:\n | ((ctx: { signal: AbortSignal }, args: Args) => Promise<T>)\n | ResourceOptions<T, Args>,\n): Resource<T, Args> {\n const fetcher = typeof optionsOrFetcher === 'function' ? optionsOrFetcher : optionsOrFetcher.fetch\n const useSuspense = typeof optionsOrFetcher === 'object' && !!optionsOrFetcher.suspense\n const cacheOptions: ResourceCacheOptions =\n typeof optionsOrFetcher === 'object' ? (optionsOrFetcher.cache ?? {}) : {}\n const resolvedCacheOptions = { ...defaultCacheOptions, ...cacheOptions }\n const cache = new Map<unknown, ResourceEntry<T, Args>>()\n\n const readArgs = (argsAccessor: (() => Args) | Args): Args =>\n typeof argsAccessor === 'function' ? (argsAccessor as () => Args)() : argsAccessor\n\n const computeKey = (argsAccessor: (() => Args) | Args): unknown => {\n const argsValue = readArgs(argsAccessor)\n if (typeof optionsOrFetcher === 'object' && optionsOrFetcher.key !== undefined) {\n const key = optionsOrFetcher.key\n return typeof key === 'function' ? (key as (args: Args) => unknown)(argsValue) : key\n }\n return argsValue\n }\n\n const readResetToken = (): unknown => {\n if (typeof optionsOrFetcher !== 'object') return undefined\n const reset = optionsOrFetcher.reset\n if (typeof reset === 'function' && (reset as () => unknown).length === 0) {\n return (reset as () => unknown)()\n }\n return reset\n }\n\n const ensureEntry = (key: unknown): ResourceEntry<T, Args> => {\n let state = cache.get(key)\n if (!state) {\n state = {\n data: createSignal<T | undefined>(undefined),\n loading: createSignal<boolean>(false),\n error: createSignal<unknown>(undefined),\n version: createSignal(0),\n pendingToken: null,\n lastArgs: undefined,\n lastVersion: -1,\n lastReset: undefined,\n hasValue: false,\n status: 'idle',\n generation: 0,\n expiresAt: undefined,\n inFlight: undefined,\n controller: undefined,\n }\n cache.set(key, state)\n }\n return state!\n }\n\n const isExpired = (entry: ResourceEntry<T, Args>): boolean => {\n if (resolvedCacheOptions.mode === 'none') return true\n if (!Number.isFinite(resolvedCacheOptions.ttlMs)) return false\n if (entry.expiresAt === undefined) return false\n return entry.expiresAt < Date.now()\n }\n\n const markExpiry = (entry: ResourceEntry<T, Args>) => {\n if (resolvedCacheOptions.mode === 'none') {\n entry.expiresAt = Date.now() - 1\n return\n }\n entry.expiresAt = Number.isFinite(resolvedCacheOptions.ttlMs)\n ? Date.now() + resolvedCacheOptions.ttlMs\n : undefined\n }\n\n const startFetch = (\n entry: ResourceEntry<T, Args>,\n key: unknown,\n args: Args,\n isRevalidating = false,\n ) => {\n entry.controller?.abort()\n entry.inFlight = undefined\n const controller = new AbortController()\n entry.controller = controller\n entry.status = 'pending'\n // For stale-while-revalidate: don't show loading if we already have data to display\n if (!isRevalidating) {\n entry.loading(true)\n }\n entry.error(undefined)\n entry.generation += 1\n const currentGen = entry.generation\n\n const shouldSuspend = useSuspense && !entry.hasValue\n entry.pendingToken = shouldSuspend ? createSuspenseToken() : null\n\n const fetchPromise = fetcher({ signal: controller.signal }, args)\n .then(res => {\n if (controller.signal.aborted || entry.generation !== currentGen) return\n entry.data(res)\n entry.hasValue = true\n entry.status = 'success'\n entry.loading(false)\n markExpiry(entry)\n if (entry.pendingToken) {\n entry.pendingToken.resolve()\n entry.pendingToken = null\n }\n })\n .catch(err => {\n if (controller.signal.aborted || entry.generation !== currentGen) return\n entry.error(err)\n entry.status = 'error'\n entry.loading(false)\n if (resolvedCacheOptions.cacheErrors) {\n markExpiry(entry)\n } else {\n entry.expiresAt = Date.now() - 1\n entry.hasValue = false\n }\n if (entry.pendingToken) {\n entry.pendingToken.reject(err)\n entry.pendingToken = null\n }\n })\n .finally(() => {\n entry.inFlight = undefined\n entry.controller = undefined\n })\n\n entry.inFlight = fetchPromise\n\n onCleanup(() => {\n if (resolvedCacheOptions.mode === 'none') {\n controller.abort()\n cache.delete(key)\n }\n })\n }\n\n const invalidate = (key?: unknown) => {\n if (key === undefined) {\n cache.forEach(entry => {\n entry.controller?.abort()\n entry.version(entry.version() + 1)\n entry.expiresAt = Date.now() - 1\n })\n cache.clear()\n return\n }\n const entry = cache.get(key)\n if (entry) {\n entry.controller?.abort()\n entry.version(entry.version() + 1)\n entry.expiresAt = Date.now() - 1\n cache.delete(key)\n }\n }\n\n const prefetch = (args: Args, keyOverride?: unknown) => {\n const key = keyOverride ?? computeKey(args)\n const entry = ensureEntry(key)\n const usableData = entry.hasValue && !isExpired(entry)\n if (!usableData) {\n entry.lastArgs = args\n entry.lastVersion = entry.version()\n startFetch(entry, key, args)\n }\n }\n\n return {\n read(argsAccessor: (() => Args) | Args): ResourceResult<T> {\n const entryRef = createSignal<ResourceEntry<T, Args> | null>(null)\n\n createEffect(() => {\n const key = computeKey(argsAccessor)\n const entry = ensureEntry(key)\n entryRef(entry)\n const args = readArgs(argsAccessor)\n const currentVersion = entry.version()\n const expired = isExpired(entry)\n const argsChanged = entry.lastArgs !== args\n const versionChanged = entry.lastVersion !== currentVersion\n const resetToken = readResetToken()\n const resetChanged = entry.lastReset !== resetToken\n // For stale-while-revalidate: if we have cached data, don't treat expired as requiring immediate refetch\n // We'll handle the revalidation separately to show stale data without loading state\n const canUseStaleData =\n resolvedCacheOptions.staleWhileRevalidate && entry.hasValue && expired\n const shouldRefetch =\n (expired && !canUseStaleData) ||\n argsChanged ||\n versionChanged ||\n resetChanged ||\n (entry.status === 'error' && !resolvedCacheOptions.cacheErrors)\n\n entry.lastArgs = args\n entry.lastVersion = currentVersion\n entry.lastReset = resetToken\n\n if (shouldRefetch) {\n if (entry.inFlight && (argsChanged || versionChanged)) {\n entry.controller?.abort()\n entry.inFlight = undefined\n }\n if (resetChanged) {\n entry.hasValue = false\n entry.expiresAt = Date.now() - 1\n }\n startFetch(entry, key, args as Args)\n } else if (canUseStaleData && entry.inFlight === undefined) {\n // stale-while-revalidate: return stale data immediately, refresh in background\n // Pass isRevalidating=true to avoid showing loading state\n startFetch(entry, key, args as Args, true)\n }\n })\n\n return {\n get data() {\n const entry = entryRef()\n if (!entry) return undefined\n if (useSuspense && entry.pendingToken) {\n throw entry.pendingToken.token\n }\n return entry.data()\n },\n get loading() {\n const entry = entryRef()\n return entry ? entry.loading() : false\n },\n get error() {\n const entry = entryRef()\n return entry ? entry.error() : undefined\n },\n refresh: () => {\n const entry = entryRef()\n if (entry) entry.version(entry.version() + 1)\n },\n }\n },\n invalidate,\n prefetch,\n }\n}\n","/**\n * @fileoverview Lazy component loading with Suspense support.\n *\n * Creates a component that loads its implementation asynchronously,\n * suspending rendering until the module is loaded.\n */\n\nimport { createSuspenseToken } from '@fictjs/runtime'\nimport type { Component } from '@fictjs/runtime'\n\n/** Module shape expected from dynamic imports */\nexport interface LazyModule<TProps extends Record<string, unknown>> {\n default: Component<TProps>\n}\n\n/** Options for lazy loading behavior */\nexport interface LazyOptions {\n /**\n * Maximum number of retry attempts on load failure.\n * Set to 0 to disable retries (default behavior).\n * @default 0\n */\n maxRetries?: number\n\n /**\n * Delay in milliseconds between retry attempts.\n * Uses exponential backoff: delay * 2^(attempt - 1)\n * @default 1000\n */\n retryDelay?: number\n}\n\n/** Extended component with retry capability */\nexport interface LazyComponent<TProps extends Record<string, unknown>> extends Component<TProps> {\n /**\n * Reset the lazy component state, allowing it to retry loading.\n * Useful when used with ErrorBoundary reset functionality.\n */\n reset: () => void\n\n /**\n * Preload the component without rendering it.\n * Returns a promise that resolves when the component is loaded.\n */\n preload: () => Promise<void>\n}\n\n/**\n * Create a lazy component that suspends while loading.\n *\n * @param loader - Function that returns a promise resolving to the component module\n * @param options - Optional configuration for retry behavior\n * @returns A component that suspends during loading and supports retry on failure\n *\n * @example\n * ```tsx\n * import { lazy, Suspense } from 'fict'\n *\n * // Basic usage\n * const LazyChart = lazy(() => import('./Chart'))\n *\n * // With retry options\n * const LazyDashboard = lazy(() => import('./Dashboard'), {\n * maxRetries: 3,\n * retryDelay: 1000\n * })\n *\n * function App() {\n * return (\n * <Suspense fallback={<Loading />}>\n * <LazyChart />\n * </Suspense>\n * )\n * }\n *\n * // Reset on error (with ErrorBoundary)\n * <ErrorBoundary fallback={(err, reset) => (\n * <button onClick={() => { LazyChart.reset(); reset(); }}>Retry</button>\n * )}>\n * <LazyChart />\n * </ErrorBoundary>\n * ```\n *\n * @public\n */\nexport function lazy<TProps extends Record<string, unknown> = Record<string, unknown>>(\n loader: () => Promise<LazyModule<TProps> | { default: Component<TProps> }>,\n options: LazyOptions = {},\n): LazyComponent<TProps> {\n const { maxRetries = 0, retryDelay = 1000 } = options\n\n let loaded: Component<TProps> | null = null\n let loadError: unknown = null\n let loadingPromise: Promise<unknown> | null = null\n let pendingToken: ReturnType<typeof createSuspenseToken> | null = null\n let retryCount = 0\n\n const attemptLoad = (): Promise<void> => {\n return loader()\n .then(mod => {\n loaded = (mod as LazyModule<TProps>).default\n loadError = null\n retryCount = 0\n pendingToken?.resolve()\n })\n .catch((err: unknown) => {\n if (retryCount < maxRetries) {\n retryCount++\n const delay = retryDelay * Math.pow(2, retryCount - 1)\n return new Promise<void>(resolve => {\n setTimeout(() => {\n resolve(attemptLoad())\n }, delay)\n })\n }\n loadError = err\n pendingToken?.reject(err)\n return undefined\n })\n .finally(() => {\n loadingPromise = null\n pendingToken = null\n })\n }\n\n const component = ((props: TProps) => {\n if (loaded) {\n return loaded(props)\n }\n if (loadError) {\n throw loadError\n }\n if (!loadingPromise) {\n pendingToken = createSuspenseToken()\n loadingPromise = attemptLoad()\n }\n if (pendingToken) {\n throw pendingToken.token\n }\n // Should never hit if pendingToken exists, but fallback for type safety.\n throw new Error('Lazy component failed to start loading')\n }) as LazyComponent<TProps>\n\n /**\n * Reset the lazy component state, clearing any cached error.\n * Call this before triggering a re-render to retry loading.\n */\n component.reset = () => {\n loadError = null\n loadingPromise = null\n pendingToken = null\n retryCount = 0\n // Note: we don't clear `loaded` - if it was successfully loaded, keep it\n }\n\n /**\n * Preload the component without rendering.\n * Useful for eager loading on route prefetch.\n */\n component.preload = (): Promise<void> => {\n if (loaded) {\n return Promise.resolve()\n }\n if (loadingPromise) {\n return loadingPromise as Promise<void>\n }\n pendingToken = createSuspenseToken()\n loadingPromise = attemptLoad()\n return loadingPromise as Promise<void>\n }\n\n return component\n}\n"]}
|
package/dist/plus.js
CHANGED
package/dist/slim.cjs
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
// src/slim.ts
|
|
4
|
+
function $state(_initialValue) {
|
|
5
|
+
throw new Error("$state() is a compiler macro and should be transformed at compile time");
|
|
6
|
+
}
|
|
7
|
+
function $effect(_fn) {
|
|
8
|
+
throw new Error("$effect() is a compiler macro and should be transformed at compile time");
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
exports.$effect = $effect;
|
|
12
|
+
exports.$state = $state;
|
|
13
|
+
//# sourceMappingURL=slim.cjs.map
|
|
14
|
+
//# sourceMappingURL=slim.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/slim.ts"],"names":[],"mappings":";;;AAcO,SAAS,OAAU,aAAA,EAAqB;AAC7C,EAAA,MAAM,IAAI,MAAM,wEAAwE,CAAA;AAC1F;AAMO,SAAS,QAAQ,GAAA,EAAsC;AAC5D,EAAA,MAAM,IAAI,MAAM,yEAAyE,CAAA;AAC3F","file":"slim.cjs","sourcesContent":["/**\n * @fileoverview Fict Slim entrypoint\n *\n * Exposes compiler macros only. Intended for users who want the smallest\n * runtime surface and rely on the compiler to erase macro calls.\n *\n * @public\n * @packageDocumentation\n */\n\n/**\n * Compiler macro for reactive state.\n * This is transformed at compile time and should never be called at runtime.\n */\nexport function $state<T>(_initialValue: T): T {\n throw new Error('$state() is a compiler macro and should be transformed at compile time')\n}\n\n/**\n * Compiler macro for reactive effects.\n * This is transformed at compile time and should never be called at runtime.\n */\nexport function $effect(_fn: () => void | (() => void)): void {\n throw new Error('$effect() is a compiler macro and should be transformed at compile time')\n}\n"]}
|
package/dist/slim.d.cts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Fict Slim entrypoint
|
|
3
|
+
*
|
|
4
|
+
* Exposes compiler macros only. Intended for users who want the smallest
|
|
5
|
+
* runtime surface and rely on the compiler to erase macro calls.
|
|
6
|
+
*
|
|
7
|
+
* @public
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Compiler macro for reactive state.
|
|
12
|
+
* This is transformed at compile time and should never be called at runtime.
|
|
13
|
+
*/
|
|
14
|
+
declare function $state<T>(_initialValue: T): T;
|
|
15
|
+
/**
|
|
16
|
+
* Compiler macro for reactive effects.
|
|
17
|
+
* This is transformed at compile time and should never be called at runtime.
|
|
18
|
+
*/
|
|
19
|
+
declare function $effect(_fn: () => void | (() => void)): void;
|
|
20
|
+
|
|
21
|
+
export { $effect, $state };
|
package/dist/slim.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Fict Slim entrypoint
|
|
3
|
+
*
|
|
4
|
+
* Exposes compiler macros only. Intended for users who want the smallest
|
|
5
|
+
* runtime surface and rely on the compiler to erase macro calls.
|
|
6
|
+
*
|
|
7
|
+
* @public
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* Compiler macro for reactive state.
|
|
12
|
+
* This is transformed at compile time and should never be called at runtime.
|
|
13
|
+
*/
|
|
14
|
+
declare function $state<T>(_initialValue: T): T;
|
|
15
|
+
/**
|
|
16
|
+
* Compiler macro for reactive effects.
|
|
17
|
+
* This is transformed at compile time and should never be called at runtime.
|
|
18
|
+
*/
|
|
19
|
+
declare function $effect(_fn: () => void | (() => void)): void;
|
|
20
|
+
|
|
21
|
+
export { $effect, $state };
|
package/dist/slim.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
// src/slim.ts
|
|
2
|
+
function $state(_initialValue) {
|
|
3
|
+
throw new Error("$state() is a compiler macro and should be transformed at compile time");
|
|
4
|
+
}
|
|
5
|
+
function $effect(_fn) {
|
|
6
|
+
throw new Error("$effect() is a compiler macro and should be transformed at compile time");
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export { $effect, $state };
|
|
10
|
+
//# sourceMappingURL=slim.js.map
|
|
11
|
+
//# sourceMappingURL=slim.js.map
|
package/dist/slim.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/slim.ts"],"names":[],"mappings":";AAcO,SAAS,OAAU,aAAA,EAAqB;AAC7C,EAAA,MAAM,IAAI,MAAM,wEAAwE,CAAA;AAC1F;AAMO,SAAS,QAAQ,GAAA,EAAsC;AAC5D,EAAA,MAAM,IAAI,MAAM,yEAAyE,CAAA;AAC3F","file":"slim.js","sourcesContent":["/**\n * @fileoverview Fict Slim entrypoint\n *\n * Exposes compiler macros only. Intended for users who want the smallest\n * runtime surface and rely on the compiler to erase macro calls.\n *\n * @public\n * @packageDocumentation\n */\n\n/**\n * Compiler macro for reactive state.\n * This is transformed at compile time and should never be called at runtime.\n */\nexport function $state<T>(_initialValue: T): T {\n throw new Error('$state() is a compiler macro and should be transformed at compile time')\n}\n\n/**\n * Compiler macro for reactive effects.\n * This is transformed at compile time and should never be called at runtime.\n */\nexport function $effect(_fn: () => void | (() => void)): void {\n throw new Error('$effect() is a compiler macro and should be transformed at compile time')\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "fict",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Main package for the Fict framework",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
@@ -48,6 +48,11 @@
|
|
|
48
48
|
"types": "./dist/advanced.d.ts",
|
|
49
49
|
"import": "./dist/advanced.js",
|
|
50
50
|
"require": "./dist/advanced.cjs"
|
|
51
|
+
},
|
|
52
|
+
"./slim": {
|
|
53
|
+
"types": "./dist/slim.d.ts",
|
|
54
|
+
"import": "./dist/slim.js",
|
|
55
|
+
"require": "./dist/slim.cjs"
|
|
51
56
|
}
|
|
52
57
|
},
|
|
53
58
|
"sideEffects": false,
|
|
@@ -56,12 +61,12 @@
|
|
|
56
61
|
"src"
|
|
57
62
|
],
|
|
58
63
|
"dependencies": {
|
|
59
|
-
"@fictjs/runtime": "0.2.
|
|
64
|
+
"@fictjs/runtime": "0.2.1"
|
|
60
65
|
},
|
|
61
66
|
"devDependencies": {
|
|
62
67
|
"tsup": "^8.5.1",
|
|
63
68
|
"vite": "^7.3.0",
|
|
64
|
-
"@fictjs/vite-plugin": "0.2.
|
|
69
|
+
"@fictjs/vite-plugin": "0.2.1"
|
|
65
70
|
},
|
|
66
71
|
"scripts": {
|
|
67
72
|
"build": "tsup",
|
package/src/slim.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Fict Slim entrypoint
|
|
3
|
+
*
|
|
4
|
+
* Exposes compiler macros only. Intended for users who want the smallest
|
|
5
|
+
* runtime surface and rely on the compiler to erase macro calls.
|
|
6
|
+
*
|
|
7
|
+
* @public
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Compiler macro for reactive state.
|
|
13
|
+
* This is transformed at compile time and should never be called at runtime.
|
|
14
|
+
*/
|
|
15
|
+
export function $state<T>(_initialValue: T): T {
|
|
16
|
+
throw new Error('$state() is a compiler macro and should be transformed at compile time')
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Compiler macro for reactive effects.
|
|
21
|
+
* This is transformed at compile time and should never be called at runtime.
|
|
22
|
+
*/
|
|
23
|
+
export function $effect(_fn: () => void | (() => void)): void {
|
|
24
|
+
throw new Error('$effect() is a compiler macro and should be transformed at compile time')
|
|
25
|
+
}
|
package/src/store.ts
CHANGED
|
@@ -145,6 +145,7 @@ export function $store<T extends object>(initialValue: T): T {
|
|
|
145
145
|
},
|
|
146
146
|
|
|
147
147
|
set(target, prop, newValue, receiver) {
|
|
148
|
+
const oldLength = Array.isArray(target) && prop === 'length' ? target.length : undefined
|
|
148
149
|
const oldValue = Reflect.get(target, prop, receiver)
|
|
149
150
|
const hadKey = Object.prototype.hasOwnProperty.call(target, prop)
|
|
150
151
|
|
|
@@ -182,8 +183,19 @@ export function $store<T extends object>(initialValue: T): T {
|
|
|
182
183
|
}
|
|
183
184
|
|
|
184
185
|
// If it's an array and length changed implicitly, we might need to handle it.
|
|
185
|
-
// But usually 'length' is set explicitly or handled by the runtime.
|
|
186
186
|
if (Array.isArray(target) && prop === 'length') {
|
|
187
|
+
const nextLength = target.length
|
|
188
|
+
if (typeof oldLength === 'number' && nextLength < oldLength) {
|
|
189
|
+
const signals = SIGNAL_CACHE.get(target)
|
|
190
|
+
if (signals) {
|
|
191
|
+
for (let i = nextLength; i < oldLength; i += 1) {
|
|
192
|
+
const key = String(i)
|
|
193
|
+
if (signals[key]) {
|
|
194
|
+
signals[key](undefined)
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
187
199
|
triggerIteration(target)
|
|
188
200
|
}
|
|
189
201
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/store.ts"],"names":["signals"],"mappings":"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","file":"chunk-QPBAYI4X.js","sourcesContent":["/**\n * @fileoverview Deep reactive store implementation for Fict.\n *\n * $store creates a deeply reactive proxy that tracks property access at the path level.\n * Unlike $state (which is shallow), $store allows direct mutation of nested properties.\n *\n * @example\n * ```typescript\n * const user = $store({ name: 'Alice', address: { city: 'London' } })\n * user.address.city = 'Paris' // Fine-grained reactive update\n * ```\n */\n\nimport { createSignal, type Signal } from '@fictjs/runtime/advanced'\n\n/** Function type for bound methods */\ntype AnyFn = (...args: unknown[]) => unknown\n\n/** Cache entry for bound methods to preserve identity */\ninterface BoundMethodEntry {\n ref: AnyFn\n bound: AnyFn\n}\n\n/** Type for objects with indexable properties */\ntype IndexableObject = Record<string | symbol, unknown>\n\n/** Cache of proxied objects to avoid duplicate proxies */\nconst PROXY_CACHE = new WeakMap<object, unknown>()\n\n/** Cache of signals per object property */\nconst SIGNAL_CACHE = new WeakMap<object, Record<string | symbol, Signal<unknown>>>()\n\n/** Cache of bound methods to preserve function identity across reads */\nconst BOUND_METHOD_CACHE = new WeakMap<object, Map<string | symbol, BoundMethodEntry>>()\n\n/** Special key for tracking iteration (Object.keys, for-in, etc.) */\nconst ITERATE_KEY = Symbol('iterate')\n\n/**\n * Get or create a signal for a specific property on a target object.\n * @internal\n */\nfunction getSignal(target: object, prop: string | symbol): Signal<unknown> {\n let signals = SIGNAL_CACHE.get(target)\n if (!signals) {\n signals = {}\n SIGNAL_CACHE.set(target, signals)\n }\n if (!signals[prop]) {\n const initial = prop === ITERATE_KEY ? 0 : (target as IndexableObject)[prop]\n signals[prop] = createSignal(initial)\n }\n return signals[prop]\n}\n\n/**\n * Trigger iteration signal to notify consumers that keys have changed.\n * @internal\n */\nfunction triggerIteration(target: object): void {\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals[ITERATE_KEY]) {\n const current = signals[ITERATE_KEY]() as number\n signals[ITERATE_KEY](current + 1)\n }\n}\n\n/**\n * Create a deep reactive store using Proxy.\n *\n * Unlike `$state` (which is shallow and compiler-transformed), `$store` provides:\n * - **Deep reactivity**: Nested objects are automatically wrapped in proxies\n * - **Direct mutation**: Modify properties directly without spread operators\n * - **Path-level tracking**: Only components reading changed paths re-render\n *\n * @param initialValue - The initial object to make reactive\n * @returns A reactive proxy of the object\n *\n * @example\n * ```tsx\n * import { $store } from 'fict'\n *\n * const form = $store({\n * user: { name: '', email: '' },\n * settings: { theme: 'light' }\n * })\n *\n * // Direct mutation works\n * form.user.name = 'Alice'\n *\n * // In JSX - only updates when form.user.name changes\n * <input value={form.user.name} />\n * ```\n *\n * @public\n */\nexport function $store<T extends object>(initialValue: T): T {\n if (typeof initialValue !== 'object' || initialValue === null) {\n return initialValue\n }\n\n if (PROXY_CACHE.has(initialValue)) {\n return PROXY_CACHE.get(initialValue) as T\n }\n\n const proxy = new Proxy(initialValue, {\n get(target, prop, receiver) {\n // Always touch the signal so reference changes to this property are tracked,\n // even if the value is an object we proxy further.\n const signal = getSignal(target, prop)\n const trackedValue = signal()\n\n const currentValue = Reflect.get(target, prop, receiver ?? proxy)\n if (currentValue !== trackedValue) {\n // If the value has changed (e.g. via direct mutation of the underlying object not via proxy),\n // we update the signal to keep it in sync.\n // Note: This is a bit of a heuristic. Ideally all mutations go through proxy.\n signal(currentValue)\n }\n\n if (typeof currentValue === 'function') {\n let boundMethods = BOUND_METHOD_CACHE.get(target)\n if (!boundMethods) {\n boundMethods = new Map()\n BOUND_METHOD_CACHE.set(target, boundMethods)\n }\n const cached = boundMethods.get(prop)\n if (cached && cached.ref === currentValue) {\n return cached.bound\n }\n\n const bound = (currentValue as AnyFn).bind(receiver ?? proxy)\n boundMethods.set(prop, { ref: currentValue as AnyFn, bound })\n return bound\n }\n\n // If the value is an object/array, we recursively wrap it in a store\n if (typeof currentValue === 'object' && currentValue !== null) {\n return $store(currentValue as Record<string, unknown>)\n }\n\n // For primitives (and functions), we return the signal value (which tracks the read)\n return currentValue\n },\n\n set(target, prop, newValue, receiver) {\n const oldValue = Reflect.get(target, prop, receiver)\n const hadKey = Object.prototype.hasOwnProperty.call(target, prop)\n\n // If value hasn't changed, do nothing\n if (oldValue === newValue && hadKey) {\n return true\n }\n\n const result = Reflect.set(target, prop, newValue, receiver)\n\n // IMPORTANT: Clear bound method cache BEFORE updating the signal\n const boundMethods = BOUND_METHOD_CACHE.get(target)\n if (boundMethods && boundMethods.has(prop)) {\n boundMethods.delete(prop)\n }\n\n // Update the signal if it exists\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals[prop]) {\n signals[prop](newValue)\n }\n\n // If new property, trigger iteration update\n if (!hadKey) {\n triggerIteration(target)\n }\n\n // Ensure array length subscribers are notified even if the native push/pop\n // doesn't trigger a separate set trap for \"length\" (defensive).\n if (Array.isArray(target) && prop !== 'length') {\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals.length) {\n signals.length(target.length)\n }\n }\n\n // If it's an array and length changed implicitly, we might need to handle it.\n // But usually 'length' is set explicitly or handled by the runtime.\n if (Array.isArray(target) && prop === 'length') {\n triggerIteration(target)\n }\n\n return result\n },\n\n deleteProperty(target, prop) {\n const hadKey = Object.prototype.hasOwnProperty.call(target, prop)\n const result = Reflect.deleteProperty(target, prop)\n\n if (result && hadKey) {\n const signals = SIGNAL_CACHE.get(target)\n if (signals && signals[prop]) {\n signals[prop](undefined)\n }\n\n // Clear bound method cache\n const boundMethods = BOUND_METHOD_CACHE.get(target)\n if (boundMethods && boundMethods.has(prop)) {\n boundMethods.delete(prop)\n }\n\n triggerIteration(target)\n }\n\n return result\n },\n\n ownKeys(target) {\n getSignal(target, ITERATE_KEY)()\n return Reflect.ownKeys(target)\n },\n\n has(target, prop) {\n getSignal(target, prop)()\n return Reflect.has(target, prop)\n },\n })\n\n PROXY_CACHE.set(initialValue, proxy)\n return proxy\n}\n"]}
|