@pravosleva/reactive-engine 2.6.4-alpha.8 → 2.6.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +8 -8
  2. package/dist/core/core.d.ts +160 -0
  3. package/dist/core/core.d.ts.map +1 -1
  4. package/dist/core/core.method.computed.d.ts.map +1 -1
  5. package/dist/core.method.computed.mjs +2 -1
  6. package/dist/core.method.computed.mjs.map +1 -1
  7. package/dist/core.method.resource.mjs +3 -1
  8. package/dist/core.method.resource.mjs.map +1 -1
  9. package/dist/core.mjs.map +1 -1
  10. package/dist/decorators/withValidation/withValidation.d.ts +2 -2
  11. package/dist/decorators/withValidation/withValidation.d.ts.map +1 -1
  12. package/dist/decorators/withValidation/withValidation.mjs +1 -1
  13. package/dist/decorators/withValidation/withValidation.mjs.map +1 -1
  14. package/dist/decorators/withValidation/withValidation.test.d.ts +2 -0
  15. package/dist/decorators/withValidation/withValidation.test.d.ts.map +1 -0
  16. package/dist/index.mjs +2 -2
  17. package/dist/reactive-engine.umd.js +2 -2
  18. package/dist/reactive-engine.umd.js.map +1 -1
  19. package/package.json +8 -11
  20. package/dist/AbstractService.cjs +0 -2
  21. package/dist/AbstractService.cjs.map +0 -1
  22. package/dist/BaseREServiceEnhanced.cjs +0 -2
  23. package/dist/BaseREServiceEnhanced.cjs.map +0 -1
  24. package/dist/angular/core.angular-adapter.cjs +0 -2
  25. package/dist/angular/core.angular-adapter.cjs.map +0 -1
  26. package/dist/angular/index.cjs +0 -2
  27. package/dist/angular/index.cjs.map +0 -1
  28. package/dist/core.autolog.cjs +0 -2
  29. package/dist/core.autolog.cjs.map +0 -1
  30. package/dist/core.automatic.cjs +0 -2
  31. package/dist/core.automatic.cjs.map +0 -1
  32. package/dist/core.cjs +0 -2
  33. package/dist/core.cjs.map +0 -1
  34. package/dist/core.global.cjs +0 -2
  35. package/dist/core.global.cjs.map +0 -1
  36. package/dist/core.logger.cjs +0 -2
  37. package/dist/core.logger.cjs.map +0 -1
  38. package/dist/core.method.computed.cjs +0 -2
  39. package/dist/core.method.computed.cjs.map +0 -1
  40. package/dist/core.method.effect.cjs +0 -2
  41. package/dist/core.method.effect.cjs.map +0 -1
  42. package/dist/core.method.reactive.cjs +0 -2
  43. package/dist/core.method.reactive.cjs.map +0 -1
  44. package/dist/core.method.resource.cjs +0 -2
  45. package/dist/core.method.resource.cjs.map +0 -1
  46. package/dist/core.method.signal.cjs +0 -2
  47. package/dist/core.method.signal.cjs.map +0 -1
  48. package/dist/core.method.untrack.cjs +0 -2
  49. package/dist/core.method.untrack.cjs.map +0 -1
  50. package/dist/decorators/withCache/withCache.cjs +0 -2
  51. package/dist/decorators/withCache/withCache.cjs.map +0 -1
  52. package/dist/decorators/withDebounce/withDebounce.cjs +0 -2
  53. package/dist/decorators/withDebounce/withDebounce.cjs.map +0 -1
  54. package/dist/decorators/withLongPolling/withLongPolling.cjs +0 -2
  55. package/dist/decorators/withLongPolling/withLongPolling.cjs.map +0 -1
  56. package/dist/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.cjs +0 -2
  57. package/dist/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.cjs.map +0 -1
  58. package/dist/decorators/withThrottle/withThrottle.cjs +0 -2
  59. package/dist/decorators/withThrottle/withThrottle.cjs.map +0 -1
  60. package/dist/decorators/withThrottleAndCache/withThrottleAndCache.cjs +0 -2
  61. package/dist/decorators/withThrottleAndCache/withThrottleAndCache.cjs.map +0 -1
  62. package/dist/decorators/withThrottleComputed/withThrottleComputed.cjs +0 -2
  63. package/dist/decorators/withThrottleComputed/withThrottleComputed.cjs.map +0 -1
  64. package/dist/decorators/withValidation/withValidation.cjs +0 -2
  65. package/dist/decorators/withValidation/withValidation.cjs.map +0 -1
  66. package/dist/index.cjs +0 -1
  67. package/dist/index2.cjs +0 -1
  68. package/dist/react/hooks/useReactiveSubscription.cjs +0 -2
  69. package/dist/react/hooks/useReactiveSubscription.cjs.map +0 -1
  70. package/dist/react/hooks/useReactiveValue.cjs +0 -2
  71. package/dist/react/hooks/useReactiveValue.cjs.map +0 -1
  72. package/dist/react/index.cjs +0 -2
  73. package/dist/react/index.cjs.map +0 -1
  74. package/dist/utils/getExtractedValues.cjs +0 -2
  75. package/dist/utils/getExtractedValues.cjs.map +0 -1
  76. package/dist/vue/core.vue-adapter.cjs +0 -2
  77. package/dist/vue/core.vue-adapter.cjs.map +0 -1
  78. package/dist/vue/index.cjs +0 -2
  79. package/dist/vue/index.cjs.map +0 -1
package/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "@pravosleva/reactive-engine",
3
- "version": "2.6.4-alpha.8",
3
+ "version": "2.6.5",
4
4
  "engines": {
5
5
  "node": ">=22.20.0"
6
6
  },
7
7
  "description": "Reactive Engine",
8
- "author": "Den Pol <selection4test@gmail.com> (https://pravosleva.pro)",
8
+ "author": "Den Pol <selection4test@gmail.com> (https://pravosleva.pro/blog)",
9
9
  "homepage": "https://github.com/garage-13/reactive-engine",
10
10
  "repository": {
11
11
  "type": "git",
@@ -20,7 +20,7 @@
20
20
  "state",
21
21
  "manager"
22
22
  ],
23
- "main": "./dist/index.cjs",
23
+ "main": "./dist/index.mjs",
24
24
  "module": "./dist/index.mjs",
25
25
  "types": "./dist/index.d.ts",
26
26
  "unpkg": "./dist/reactive-engine.umd.js",
@@ -29,23 +29,19 @@
29
29
  "exports": {
30
30
  ".": {
31
31
  "types": "./dist/index.d.ts",
32
- "import": "./dist/index.mjs",
33
- "require": "./dist/index.cjs"
32
+ "import": "./dist/index.mjs"
34
33
  },
35
34
  "./react": {
36
35
  "types": "./dist/react/index.d.ts",
37
- "import": "./dist/react/index.mjs",
38
- "require": "./dist/react/index.cjs"
36
+ "import": "./dist/react/index.mjs"
39
37
  },
40
38
  "./vue": {
41
39
  "types": "./dist/vue/index.d.ts",
42
- "import": "./dist/vue/index.mjs",
43
- "require": "./dist/vue/index.cjs"
40
+ "import": "./dist/vue/index.mjs"
44
41
  },
45
42
  "./angular": {
46
43
  "types": "./dist/angular/index.d.ts",
47
- "import": "./dist/angular/index.mjs",
48
- "require": "./dist/angular/index.cjs"
44
+ "import": "./dist/angular/index.mjs"
49
45
  }
50
46
  },
51
47
  "files": [
@@ -126,6 +122,7 @@
126
122
  "pixi.js": "^8.19.0",
127
123
  "react": "^19.2.0",
128
124
  "react-dom": "^19.2.0",
125
+ "rollup-plugin-visualizer": "^7.1.2",
129
126
  "sass-embedded": "^1.100.0",
130
127
  "three": "^0.185.1",
131
128
  "tslib": "^2.8.1",
@@ -1,2 +0,0 @@
1
- var e=class{engine;constructor(e){this.engine=e,this.onInit()}createNumericSignal(e,t){return this.engine.signal(e,{name:t,validate:e=>typeof e==`number`&&!isNaN(e)})}createComputed(e){return this.engine.computed(e)}createSignal(e,t){return this.engine.signal(e,t)}onInit(){}},t=e;exports.AbstractService=e,exports.BaseREService=t;
2
- //# sourceMappingURL=AbstractService.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AbstractService.cjs","names":[],"sources":["../src/core/AbstractService.ts"],"sourcesContent":["import { ReactiveEngineAutomatic } from './core.automatic'\n\nexport abstract class AbstractService {\n constructor(protected engine: ReactiveEngineAutomatic) {\n // Вызываем метод инициализации, который можно переопределить в наследниках\n this.onInit()\n }\n\n // NOTE: Полезные хелперы для сокращения кода\n protected createNumericSignal(val: number, name: string) {\n return this.engine.signal(val, {\n name,\n validate: (v) => typeof v === 'number' && !isNaN(v)\n })\n }\n\n protected createComputed<T>(fn: () => T) {\n return this.engine.computed(fn)\n }\n\n protected createSignal<T>(val: T, name?: string) {\n return this.engine.signal(val, name)\n }\n\n // NOTE: Жизненный цикл: вызывается сразу после создания сервиса.\n // Удобно для инициализации сигналов, которые зависят от engine.\n protected onInit(): void { }\n}\n\nexport const BaseREService = AbstractService\n"],"mappings":"AAEA,IAAsB,EAAtB,KAAsC,CACd,OAAtB,YAAY,EAA2C,CAAjC,KAAA,OAAA,EAEpB,KAAK,OAAO,CACd,CAGA,oBAA8B,EAAa,EAAc,CACvD,OAAO,KAAK,OAAO,OAAO,EAAK,CAC7B,OACA,SAAW,GAAM,OAAO,GAAM,UAAY,CAAC,MAAM,CAAC,CACpD,CAAC,CACH,CAEA,eAA4B,EAAa,CACvC,OAAO,KAAK,OAAO,SAAS,CAAE,CAChC,CAEA,aAA0B,EAAQ,EAAe,CAC/C,OAAO,KAAK,OAAO,OAAO,EAAK,CAAI,CACrC,CAIA,QAAyB,CAAE,CAC7B,EAEa,EAAgB"}
@@ -1,2 +0,0 @@
1
- var e=class{engine;constructor(e){this.engine=e,setTimeout(()=>this.onInit(),0)}onInit(){}};exports.BaseREServiceEnhanced=e;
2
- //# sourceMappingURL=BaseREServiceEnhanced.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BaseREServiceEnhanced.cjs","names":[],"sources":["../src/core/BaseREServiceEnhanced.ts"],"sourcesContent":["import { ReactiveEngineCore } from './core'\n\nexport abstract class BaseREServiceEnhanced {\n constructor(protected engine: ReactiveEngineCore) {\n setTimeout(() => this.onInit(), 0)\n }\n\n protected onInit(): void { }\n}\n"],"mappings":"AAEA,IAAsB,EAAtB,KAA4C,CACpB,OAAtB,YAAY,EAAsC,CAA5B,KAAA,OAAA,EACpB,eAAiB,KAAK,OAAO,EAAG,CAAC,CACnC,CAEA,QAAyB,CAAE,CAC7B"}
@@ -1,2 +0,0 @@
1
- let e=require("@angular/core");function t(t,n){if(typeof t!=`object`||!t)return(0,e.signal)(t).asReadonly();let r=`subscribe`in t&&typeof t.subscribe==`function`,i=(0,e.signal)(r?t.value:t),a=null;if(r)a=t.subscribe(e=>{i.set(e)});else if(`__subscribe`in t&&typeof t.__subscribe==`function`){let e=t;a=e.__subscribe(()=>{i.update(t=>Array.isArray(e)?[...e]:{...e})})}let o=null;try{o=n||(0,e.inject)(e.DestroyRef)}catch{n||console.warn(`[Reactive Engine Angular Adapter] Вызов toAngularSignal осуществлен вне контекста инъекций. Не забудьте передать DestroyRef вторым аргументом для защиты от утечек памяти.`)}return a&&o&&o.onDestroy(()=>{a()}),i.asReadonly()}exports.toAngularSignal=t;
2
- //# sourceMappingURL=core.angular-adapter.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"core.angular-adapter.cjs","names":[],"sources":["../../src/angular/core.angular-adapter.ts"],"sourcesContent":["import { signal, DestroyRef, inject, WritableSignal, Signal as NgSignal } from '@angular/core'\nimport { ISignalLike } from '../core/types'\n\ntype CleanupFn = () => void\n\n/**\n * 🔴 REACTIVE ENGINE ADAPTER FOR ANGULAR (v1.9.0)\n *\n * Нативно интегрирует синхронные и асингулярные графы ядра с Angular Signals.\n * Автоматически отписывается от утечек памяти через DestroyRef контекст инъекций.\n */\n\n/**\n * Функция-адаптер для преобразования реактивных примитивов ядра в Angular Signals.\n * @param item Сигнал, Компьютед или Reactive-Proxy ядра\n * @param injectRef Опциональный DestroyRef (если вызывается вне конструктора/inject-контекста)\n */\nexport function toAngularSignal<T>(\n item: T,\n injectRef?: DestroyRef\n): NgSignal<T extends ISignalLike<infer V> ? V : T> {\n\n if (item === null || item === undefined || typeof item !== 'object') {\n return signal(item as any).asReadonly()\n }\n\n const isSignal = 'subscribe' in item && typeof (item as Record<string, unknown>).subscribe === 'function'\n\n // Инициализируем нативный WritableSignal из Angular стартовым значением из ядра\n const ngSignal: WritableSignal<any> = signal(isSignal ? (item as any).value : item)\n let unsubscribe: CleanupFn | null = null\n\n // =========================================================================\n // СЦЕНАРИЙ 1: Подписка на Сигналы и Вычисляемые свойства (Computed)\n // =========================================================================\n if (isSignal) {\n const signalItem = (item as unknown) as ISignalLike<unknown>\n unsubscribe = signalItem.subscribe((newValue: any) => {\n // Синхронно пушим обновление в Angular Signal\n ngSignal.set(newValue)\n })\n }\n // =========================================================================\n // СЦЕНАРИЙ 2: Подписка на глубокие Proxy-объекты и массивы (reactive)\n // =========================================================================\n else if ('__subscribe' in item && typeof (item as Record<string, unknown>).__subscribe === 'function') {\n const reactiveItem = item as any\n unsubscribe = reactiveItem.__subscribe(() => {\n // Для Proxy-массивов вызываем .update() с поверхностным спредом ссылки,\n // чтобы Change Detection в Angular мгновенно отловил изменения .push()/.splice()\n ngSignal.update((prev) => Array.isArray(reactiveItem) ? [...reactiveItem] : { ...reactiveItem })\n })\n }\n\n // Разрешаем контекст уничтожения для автоматического GC (Garbage Collection)\n let destroyRef: DestroyRef | null = null\n try {\n destroyRef = injectRef || inject(DestroyRef)\n } catch (e) {\n // Вызвано вне контекста инъекций Angular (например, в сырых функциях) и injectRef не передан\n if (!injectRef) {\n console.warn('[Reactive Engine Angular Adapter] Вызов toAngularSignal осуществлен вне контекста инъекций. Не забудьте передать DestroyRef вторым аргументом для защиты от утечек памяти.')\n }\n }\n\n if (unsubscribe && destroyRef) {\n destroyRef.onDestroy(() => {\n unsubscribe!()\n })\n }\n\n // Возвращаем как Readonly Signal, защищая стейт от несанкционированных внешних записей (.set/.update) во вьюхах\n return ngSignal.asReadonly()\n}\n"],"mappings":"+BAiBA,SAAgB,EACd,EACA,EACkD,CAElD,GAA2C,OAAO,GAAS,WAAvD,EACF,OAAA,EAAA,EAAA,OAAA,CAAc,CAAW,CAAC,CAAC,WAAW,EAGxC,IAAM,EAAW,cAAe,GAAQ,OAAQ,EAAiC,WAAc,WAGzF,GAAA,EAAA,EAAA,OAAA,CAAuC,EAAY,EAAa,MAAQ,CAAI,EAC9E,EAAgC,KAKpC,GAAI,EAEF,EAAc,EAAW,UAAW,GAAkB,CAEpD,EAAS,IAAI,CAAQ,CACvB,CAAC,OAKE,GAAI,gBAAiB,GAAQ,OAAQ,EAAiC,aAAgB,WAAY,CACrG,IAAM,EAAe,EACrB,EAAc,EAAa,gBAAkB,CAG3C,EAAS,OAAQ,GAAS,MAAM,QAAQ,CAAY,EAAI,CAAC,GAAG,CAAY,EAAI,CAAE,GAAG,CAAa,CAAC,CACjG,CAAC,CACH,CAGA,IAAI,EAAgC,KACpC,GAAI,CACF,EAAa,IAAA,EAAA,EAAA,OAAA,CAAoB,EAAA,UAAU,CAC7C,MAAY,CAEL,GACH,QAAQ,KAAK,4KAA4K,CAE7L,CASA,OAPI,GAAe,GACjB,EAAW,cAAgB,CACzB,EAAa,CACf,CAAC,EAII,EAAS,WAAW,CAC7B"}
@@ -1,2 +0,0 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("../core.cjs"),t=require("./core.angular-adapter.cjs");require("../index2.cjs");let n=require("@angular/core");var r=class extends e.ReactiveEngine{frameworkPrefix=`angular`;use(e,t){if(e==null)return(0,n.signal)(e).asReadonly();let r=`subscribe`in e&&typeof e.subscribe==`function`,i=()=>r?e.value:e,a=(0,n.signal)(i()),o=!1,s=()=>{o||=(o=!0,a.set(i()),!1)},c=null;if(r?c=e.subscribe(s):`__subscribe`in e&&typeof e.__subscribe==`function`&&(c=e.__subscribe(s)),c){let e=c,r=()=>{try{(0,n.inject)(n.DestroyRef).onDestroy(()=>{e()})}catch{}};t?.injector?(0,n.runInInjectionContext)(t.injector,r):r()}return a.asReadonly()}};exports.ReactiveEngine=r,exports.toAngularSignal=t.toAngularSignal;
2
- //# sourceMappingURL=index.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.cjs","names":[],"sources":["../../src/angular/index.ts"],"sourcesContent":["export { toAngularSignal } from './core.angular-adapter'\n\nimport { signal, inject, DestroyRef, Injector, runInInjectionContext, type Signal } from '@angular/core'\nimport { ReactiveEngineAutomatic } from '../core'\nimport { type CleanupFn } from '../core/types'\n\nexport interface AngularUseOptions {\n /**\n * Кастомный инжектор Angular.\n * Позволяет использовать .use() вне конструктора (например, в асинхронных функциях),\n * если передать текущий Injector вручную.\n */\n injector?: Injector\n}\n\nexport class ReactiveEngine extends ReactiveEngineAutomatic {\n protected override frameworkPrefix = 'angular'\n\n /**\n * Использование реактивного значения (Signal, Computed, Resource или Reactive Proxy) в Angular.\n * Возвращает стандартный неизменяемый Angular Signal.\n */\n public use<T>(\n item: any,\n options?: AngularUseOptions\n ): Signal<any> {\n if (item === null || item === undefined) {\n return signal(item).asReadonly()\n }\n\n const isSignalOrComputed = 'subscribe' in item && typeof item.subscribe === 'function'\n \n const getFreshValue = () => {\n if (isSignalOrComputed) return item.value\n return item\n }\n\n const angularSignal = signal<any>(getFreshValue())\n let isPendingUpdate = false\n\n const triggerUpdate = () => {\n if (isPendingUpdate) return\n isPendingUpdate = true\n \n angularSignal.set(getFreshValue())\n \n // Синхронно разжимаем защёлку, позволяя Angular подхватывать\n // асинхронные хвостовые вызовы (trailing edge) декораторов ядра\n isPendingUpdate = false\n }\n\n let unsubscribe: CleanupFn | null = null\n\n if (isSignalOrComputed) {\n unsubscribe = item.subscribe(triggerUpdate)\n } else if ('__subscribe' in item && typeof item.__subscribe === 'function') {\n unsubscribe = item.__subscribe(triggerUpdate)\n }\n\n if (unsubscribe) {\n const activeUnsub = unsubscribe\n const registerCleanup = () => {\n try {\n const destroyRef = inject(DestroyRef)\n destroyRef.onDestroy(() => {\n activeUnsub()\n })\n } catch (e) {}\n }\n\n if (options?.injector) {\n runInInjectionContext(options.injector, registerCleanup)\n } else {\n registerCleanup()\n }\n }\n\n return angularSignal.asReadonly()\n }\n}\n"],"mappings":"kMAeA,IAAa,EAAb,cAAoC,EAAA,cAAwB,CAC1D,gBAAqC,UAMrC,IACE,EACA,EACa,CACb,GAAI,GAAS,KACX,OAAA,EAAA,EAAA,OAAA,CAAc,CAAI,CAAC,CAAC,WAAW,EAGjC,IAAM,EAAqB,cAAe,GAAQ,OAAO,EAAK,WAAc,WAEtE,MACA,EAA2B,EAAK,MAC7B,EAGH,GAAA,EAAA,EAAA,OAAA,CAA4B,EAAc,CAAC,EAC7C,EAAkB,GAEhB,MAAsB,CACtB,AAOJ,KANA,EAAkB,GAElB,EAAc,IAAI,EAAc,CAAC,EAIf,GACpB,EAEI,EAAgC,KAQpC,GANI,EACF,EAAc,EAAK,UAAU,CAAa,EACjC,gBAAiB,GAAQ,OAAO,EAAK,aAAgB,aAC9D,EAAc,EAAK,YAAY,CAAa,GAG1C,EAAa,CACf,IAAM,EAAc,EACd,MAAwB,CAC5B,GAAI,EAEF,EAAA,EAAA,OAAA,CAD0B,EAAA,UAC1B,CAAA,CAAW,cAAgB,CACzB,EAAY,CACd,CAAC,CACH,MAAY,CAAC,CACf,EAEI,GAAS,UACX,EAAA,EAAA,sBAAA,CAAsB,EAAQ,SAAU,CAAe,EAEvD,EAAgB,CAEpB,CAEA,OAAO,EAAc,WAAW,CAClC,CACF"}
@@ -1,2 +0,0 @@
1
- const e=require("./core.automatic.cjs");var t=class extends e.ReactiveEngineAutomatic{autoLogQueue=[];isHardFlushScheduled=!1;queueLog(e,t,n){this.autoLogQueue.push({type:e,name:t,meta:n,timestamp:Date.now()}),this.isHardFlushScheduled||(this.isHardFlushScheduled=!0,queueMicrotask(()=>this.flushLogs()))}flushLogs(){this.isHardFlushScheduled=!1,this.autoLogQueue.length!==0&&(typeof process<`u`&&process.env.NODE_ENV!==`test`&&(console.group(`📊 [Autolog] Срез транзакций: ${this.autoLogQueue.length} операций`),this.autoLogQueue.forEach(e=>console.log(`[${e.type.toUpperCase()}] ${e.name}`,e.meta||``)),console.groupEnd()),this.autoLogQueue=[])}computed(e,t){let n=this,r=t||`unnamed_computed`,i=super.computed(e,t),a=!1,o={get value(){if(a)return i.value;let e=typeof performance<`u`?performance.now():0,t=i.value;return e&&n.queueLog(`computed`,r,{value:t,duration:`${(performance.now()-e).toFixed(3)}ms`}),t},subscribe:e=>i.subscribe(e),destroy(){a=!0,i.destroy()}};return`_node`in i&&Object.defineProperty(o,"_node",{value:i._node,enumerable:!1}),o}};exports.ReactiveEngineAutolog=t;
2
- //# sourceMappingURL=core.autolog.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"core.autolog.cjs","names":[],"sources":["../src/core/core.autolog.ts"],"sourcesContent":["import { ReactiveEngineAutomatic } from './core.automatic'\nimport { Computed } from './types'\n\n/**\n * 📊 REACTIVE ENGINE AUTOLOG (core.autolog)\n * Расширяет автоматический шедулер. Добавляет Enterprise-логирование,\n * замер производительности и Pull Duration каскадов графа.\n */\nexport class ReactiveEngineAutolog extends ReactiveEngineAutomatic {\n public autoLogQueue: Array<any> = []\n public isHardFlushScheduled = false\n\n public queueLog(type: string, name: string, meta?: any): void {\n this.autoLogQueue.push({ type, name, meta, timestamp: Date.now() })\n if (!this.isHardFlushScheduled) {\n this.isHardFlushScheduled = true\n queueMicrotask(() => this.flushLogs())\n }\n }\n\n public flushLogs(): void {\n this.isHardFlushScheduled = false\n if (this.autoLogQueue.length === 0) return\n if (typeof process !== 'undefined' && process.env.NODE_ENV !== 'test') {\n console.group(`📊 [Autolog] Срез транзакций: ${this.autoLogQueue.length} операций`)\n this.autoLogQueue.forEach(log => console.log(`[${log.type.toUpperCase()}] ${log.name}`, log.meta || ''))\n console.groupEnd()\n }\n this.autoLogQueue = []\n }\n\n public override computed<T>(fn: () => T, signalName?: string): Computed<T> {\n const engine = this\n const name = signalName || 'unnamed_computed'\n const originalComputed = super.computed(fn, signalName)\n let isDestroyed = false\n\n const autologComputedInstance: Computed<T> = {\n get value(): T {\n if (isDestroyed) return originalComputed.value\n const startTime = typeof performance !== 'undefined' ? performance.now() : 0\n const val = originalComputed.value\n\n if (startTime) {\n engine.queueLog('computed', name, { value: val, duration: `${(performance.now() - startTime).toFixed(3)}ms` })\n }\n return val\n },\n subscribe: (cb) => originalComputed.subscribe(cb),\n destroy() {\n isDestroyed = true\n originalComputed.destroy()\n }\n }\n\n if ('_node' in originalComputed) {\n Object.defineProperty(autologComputedInstance, '_node', {\n value: (originalComputed as any)._node,\n enumerable: false\n })\n }\n\n return autologComputedInstance\n }\n}\n"],"mappings":"wCAQA,IAAa,EAAb,cAA2C,EAAA,uBAAwB,CACjE,aAAkC,CAAC,EACnC,qBAA8B,GAE9B,SAAgB,EAAc,EAAc,EAAkB,CAC5D,KAAK,aAAa,KAAK,CAAE,OAAM,OAAM,OAAM,UAAW,KAAK,IAAI,CAAE,CAAC,EAC7D,KAAK,uBACR,KAAK,qBAAuB,GAC5B,mBAAqB,KAAK,UAAU,CAAC,EAEzC,CAEA,WAAyB,CACvB,KAAK,qBAAuB,GACxB,KAAK,aAAa,SAAW,IAC7B,OAAO,QAAY,KAAA,QAAA,IAAA,WAAwC,SAC7D,QAAQ,MAAM,iCAAiC,KAAK,aAAa,OAAO,UAAU,EAClF,KAAK,aAAa,QAAQ,GAAO,QAAQ,IAAI,IAAI,EAAI,KAAK,YAAY,EAAE,IAAI,EAAI,OAAQ,EAAI,MAAQ,EAAE,CAAC,EACvG,QAAQ,SAAS,GAEnB,KAAK,aAAe,CAAC,EACvB,CAEA,SAA4B,EAAa,EAAkC,CACzE,IAAM,EAAS,KACT,EAAO,GAAc,mBACrB,EAAmB,MAAM,SAAS,EAAI,CAAU,EAClD,EAAc,GAEZ,EAAuC,CAC3C,IAAI,OAAW,CACb,GAAI,EAAa,OAAO,EAAiB,MACzC,IAAM,EAAY,OAAO,YAAgB,IAAc,YAAY,IAAI,EAAI,EACrE,EAAM,EAAiB,MAK7B,OAHI,GACF,EAAO,SAAS,WAAY,EAAM,CAAE,MAAO,EAAK,SAAU,IAAI,YAAY,IAAI,EAAI,EAAA,CAAW,QAAQ,CAAC,EAAE,GAAI,CAAC,EAExG,CACT,EACA,UAAY,GAAO,EAAiB,UAAU,CAAE,EAChD,SAAU,CACR,EAAc,GACd,EAAiB,QAAQ,CAC3B,CACF,EASA,MAPI,UAAW,GACb,OAAO,eAAe,EAAyB,QAAS,CACtD,MAAQ,EAAyB,MACjC,WAAY,EACd,CAAC,EAGI,CACT,CACF"}
@@ -1,2 +0,0 @@
1
- const e=require("./core.cjs");var t=class extends e.ReactiveEngine{};exports.ReactiveEngineAutomatic=t;
2
- //# sourceMappingURL=core.automatic.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"core.automatic.cjs","names":[],"sources":["../src/core/core.automatic.ts"],"sourcesContent":["import { ReactiveEngineCore } from './core'\n\nexport class ReactiveEngineAutomatic extends ReactiveEngineCore {}\n"],"mappings":"8BAEA,IAAa,EAAb,cAA6C,EAAA,cAAmB,CAAC"}
package/dist/core.cjs DELETED
@@ -1,2 +0,0 @@
1
- const e=require("./core.method.computed.cjs"),t=require("./core.method.signal.cjs"),n=require("./core.method.untrack.cjs"),r=require("./core.method.reactive.cjs"),i=require("./core.method.effect.cjs"),a=require("./core.logger.cjs"),o=require("./core.method.resource.cjs");var s={signal:`background: #007acc; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`,computed:`background: #42b883; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`,effect:`background: #e01e5a; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`,batch:`background: #7952b3; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`,resource:`background: #d97706; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`,reactive:`background: #007acc; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`},c=null;function l(e){if(e===null)return`null`;if(e===void 0)return`undefined`;if(typeof e==`object`)try{return JSON.stringify(e)}catch{return`[Cyclic Object or Layer]`}return String(e)}function u(e,t,n){c||(c={id:Math.random().toString(36).substring(2,9),pendingLogQueue:[],isFlushing:!1},queueMicrotask(()=>d())),c.pendingLogQueue.push({type:e,label:t,from:n?.from,to:n?.to,payload:n?.payload,timestamp:Date.now()})}function d(){if(!c||c.isFlushing)return;c.isFlushing=!0;let e=c.pendingLogQueue;if(e.length===0){c=null;return}console.groupCollapsed(`%cREACTIVE TRANSACTION%c [id: ${c.id}] (${e.length} operations)`,`background: #7952b3; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`,`color: #888; font-weight: normal;`);for(let t of e){let e=s[t.type],n=t.from!==void 0||t.to!==void 0,r=`%c${t.type.toUpperCase()}%c ${t.label}`;n&&(t.from?r+=` ${l(t.from)} → ${l(t.to)}`:r+=` (${l(t.to)})`),t.payload===void 0?console.log(r,e,`color: inherit;`):(console.groupCollapsed(r,e,`color: inherit;`),console.log(`Payload:`,t.payload),console.groupEnd())}console.groupEnd(),c=null}var f=class{frameworkPrefix=`core`;logger;epoch=0;activeConsumer=null;batchDepth=0;subscriberId=0;pendingEffects=[];maxPendingDepth=0;computedCache=new WeakMap;diRegistry=new Map;diCache=new Map;proxyCache=new WeakMap;proxyTargets=new WeakSet;reactiveSignals=new WeakMap;cycleDetectionStack=new Set;batchedSignals=new Set;activeOwner=null;pendingCleanups=new Set;queueCleanup(e){this.pendingCleanups.add(e)}constructor(e){this.logger=e?.logger||{isEnabled:!1}}scheduleEffect(e){let t=e.depth||0;this.pendingEffects[t]||(this.pendingEffects[t]=new Set),this.pendingEffects[t].add(e),t>this.maxPendingDepth&&(this.maxPendingDepth=t)}queueLog(e,t,n){u(e,t,n)}batch(e){this.batchDepth++;try{return e()}finally{if(this.batchDepth--,this.batchDepth===0){if(this.batchedSignals.size>0){for(let e of this.batchedSignals)e._flushBatch&&e._flushBatch();this.batchedSignals.clear()}this.flushEffects()}}}flushEffects(){if(this.batchDepth>0)return;let e=this.activeConsumer;try{for(let e=0;e<=this.maxPendingDepth;e++){let t=this.pendingEffects[e];if(!t||t.size===0)continue;let n=Array.from(t);t.clear();for(let t of n)if(!t.isDisposed&&t.isDirty){if(t.dependencies&&t.dependencies.size>0){let e=!1;for(let n of t.dependencies){let r=n._node||n;r.type===`computed`&&r.state>0&&r.update&&r.update(),t.depVersions&&t.depVersions.get(n)!==r.version&&(e=!0)}if(!e&&t.dependencies.size>0){t.isDirty=!1;continue}}try{t.run()}catch(t){for(let t=e;t<=this.maxPendingDepth;t++){let e=this.pendingEffects[t];if(e){for(let t of e)t.isDirty=!1;e.clear()}}throw this.maxPendingDepth=0,t}}if(e>0){let t=!1;for(let n=0;n<e;n++)if(this.pendingEffects[n]&&this.pendingEffects[n].size>0){t=!0;break}t&&(e=-1)}}this.maxPendingDepth=0}finally{this.activeConsumer=e}}log(e){!this.logger||!this.logger.isEnabled||a.ReactiveDebounceLogger.processLog(this.logger,u,e)}signal(e,n){return t.createSignal(this,e,n)}computed(t,n){return e.createComputed(this,t,n)}effect(e,t){return i.createEffect(this,e,t)}untrack(e){return n.executeUntrack(this,e)}reactive(e,t){return r.createReactive(this,e,t)}provide(e,t){this.diRegistry.set(e,t),this.diCache.delete(e)}inject(e){if(e==null)throw Error(`[DI Error] Token is empty`);if(this.diCache.has(e))return this.diCache.get(e);if(this.cycleDetectionStack.has(e))throw Error(`[DI Error] Cyclic dependency detected`);this.cycleDetectionStack.add(e);try{if(this.diRegistry.has(e)){let t=this.diRegistry.get(e);if(typeof t==`function`){if(t._isMockFunction){let n=t(this);return n===void 0?t:(this.diCache.set(e,n),n)}let n=t.toString();if(!(n.startsWith(`class `)||n.startsWith(`class{`)||t.prototype&&t.prototype.constructor===t&&!n.startsWith(`function`)&&!n.includes(`=>`))){let n=t(this);return this.diCache.set(e,n),n}return t}return t}if(typeof e==`function`){let t=new e(this);return this.diCache.set(e,t),t}throw Error(`[DI Error] Token not found`)}finally{this.cycleDetectionStack.delete(e)}}delay(e,t){return new Promise((n,r)=>{if(t.aborted)return r(new DOMException(`Aborted`,`AbortError`));let i=setTimeout(()=>{t.removeEventListener(`abort`,a),n()},e),a=()=>{clearTimeout(i),r(new DOMException(`Aborted`,`AbortError`))};t.addEventListener(`abort`,a,{once:!0})})}resource(e,t,n){return o.createResource(this,e,t,n)}};exports.ReactiveEngine=f,exports.ReactiveEngineAutomatic=f,exports.ReactiveEngineCore=f,exports.flushLogs=d,exports.queueLog=u;
2
- //# sourceMappingURL=core.cjs.map
package/dist/core.cjs.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"core.cjs","names":[],"sources":["../src/core/core.ts"],"sourcesContent":["// import { getExtractedValues } from '../utils/getExtractedValues'\nimport { Signal, Computed, IEffect, EngineLoggerOptions, LogEventType, CleanupFn, TransactionContext, LogRecord, SignalOptions, ResourceOptions, ResourceState, Resource } from './types'\nimport { createComputed } from './core.method.computed'\nimport { createSignal } from './core.method.signal'\n// import { executeBatch } from './core.method.batch'\nimport { executeUntrack } from './core.method.untrack'\nimport { createReactive } from './core.method.reactive'\nimport { createEffect } from './core.method.effect'\nimport { ReactiveDebounceLogger } from './core.logger'\nimport { createResource } from './core.method.resource'\n\n// Тип для конструктора класса\ntype Constructor<T> = new (...args: any[]) => T\n// Тип для фабричной функции зависимостей\ntype Factory<T> = (engine: any) => T\n// Универсальный тип токена DI\ntype InjectionToken<T> = Constructor<T> | Factory<T> | symbol | string\n\nconst badgeColors: Record<LogEventType, string> = {\n signal: 'background: #007acc; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;',\n computed: 'background: #42b883; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;',\n effect: 'background: #e01e5a; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;',\n batch: 'background: #7952b3; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;',\n resource: 'background: #d97706; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;',\n reactive: 'background: #007acc; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;'\n}\nlet currentTransaction: TransactionContext | null = null\nfunction safeValueToString(value: unknown): string {\n if (value === null) return 'null'\n if (value === undefined) return 'undefined'\n if (typeof value === 'object') {\n try {\n return JSON.stringify(value)\n } catch (e) {\n return '[Cyclic Object or Layer]'\n }\n }\n return String(value)\n}\nexport function queueLog(type: LogEventType, label: string, details?: { from?: unknown; to?: unknown; payload?: unknown }): void {\n if (!currentTransaction) {\n currentTransaction = { id: Math.random().toString(36).substring(2, 9), pendingLogQueue: [], isFlushing: false }\n queueMicrotask(() => flushLogs())\n }\n currentTransaction.pendingLogQueue.push({ type, label, from: details?.from, to: details?.to, payload: details?.payload, timestamp: Date.now() })\n}\nexport function flushLogs(): void {\n if (!currentTransaction || currentTransaction.isFlushing) return\n currentTransaction.isFlushing = true\n const queue = currentTransaction.pendingLogQueue\n if (queue.length === 0) {\n currentTransaction = null\n return\n }\n console.groupCollapsed(`%cREACTIVE TRANSACTION%c [id: ${currentTransaction.id}] (${queue.length} operations)`, 'background: #7952b3; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;', 'color: #888; font-weight: normal;')\n for (const record of queue) {\n const colorStyle = badgeColors[record.type]\n const hasTransition = record.from !== undefined || record.to !== undefined\n let logMessage = `%c${record.type.toUpperCase()}%c ${record.label}`\n\n if (hasTransition) {\n if (!!record.from)\n logMessage += ` ${safeValueToString(record.from)} → ${safeValueToString(record.to)}`\n else logMessage += ` (${safeValueToString(record.to)})`\n }\n\n if (record.payload !== undefined) {\n console.groupCollapsed(logMessage, colorStyle, 'color: inherit;')\n console.log('Payload:', record.payload)\n console.groupEnd()\n } else {\n console.log(logMessage, colorStyle, 'color: inherit;')\n }\n }\n console.groupEnd()\n currentTransaction = null\n}\nexport class ReactiveEngineCore {\n protected frameworkPrefix = 'core'\n public logger: EngineLoggerOptions\n public epoch = 0\n public activeConsumer: any = null\n public batchDepth = 0\n public subscriberId = 0\n public pendingEffects: Array<Set<any> | undefined> = []\n public maxPendingDepth = 0\n public computedCache = new WeakMap<Function, any>()\n private diRegistry = new Map<unknown, unknown>()\n private diCache = new Map<unknown, unknown>()\n private proxyCache = new WeakMap<object, any>()\n private proxyTargets = new WeakSet<object>()\n private reactiveSignals = new WeakMap<object, Map<string | symbol, any>>()\n private cycleDetectionStack = new Set<unknown>()\n public batchedSignals = new Set<any>()\n public activeOwner: any = null\n // Системная очередь для отложенного батчинга деструкторов\n public pendingCleanups = new Set<() => void>()\n\n // Метод для регистрации отложенной очистки\n public queueCleanup(cleanup: () => void): void {\n this.pendingCleanups.add(cleanup)\n }\n\n constructor(options?: { logger?: EngineLoggerOptions }) {\n this.logger = options?.logger || { isEnabled: false }\n }\n\n public scheduleEffect(effect: any): void {\n const depth = effect.depth || 0\n if (!this.pendingEffects[depth]) {\n this.pendingEffects[depth] = new Set()\n }\n this.pendingEffects[depth]!.add(effect)\n if (depth > this.maxPendingDepth) {\n this.maxPendingDepth = depth\n }\n }\n\n public queueLog(type: LogEventType, label: string, details?: { from?: unknown; to?: unknown; payload?: unknown }): void {\n queueLog(type, label, details)\n }\n\n public batch<T>(fn: () => T): T {\n this.batchDepth++\n try {\n return fn()\n } finally {\n this.batchDepth--\n if (this.batchDepth === 0) {\n if (this.batchedSignals.size > 0) {\n for (const sig of this.batchedSignals) {\n if (sig._flushBatch) sig._flushBatch()\n }\n this.batchedSignals.clear()\n }\n\n this.flushEffects()\n }\n }\n }\n\n public flushEffects(): void {\n if (this.batchDepth > 0) return\n\n const prevConsumer = this.activeConsumer\n\n try {\n for (let depth = 0; depth <= this.maxPendingDepth; depth++) {\n const bucket = this.pendingEffects[depth]\n\n if (!bucket || bucket.size === 0) continue\n\n const effects = Array.from(bucket)\n bucket.clear()\n\n for (const effect of effects) {\n if (effect.isDisposed) continue\n\n // ⚡ ЗOЛОТOЙ СТАНДАРТ ОПТИМИЗАЦИИ (Early Dirty Check Bypass):\n // Переносим проверку грязи в самое начало цикла. Если эффект не был промаркирован\n // как DIRTY волной push-уведомлений, мы мгновенно пропускаем его, полностью\n // избавляя V8 от холостого обхода родителей и тяжелых хэш-поисков depVersions.get(dep).\n if (!effect.isDirty) continue\n\n if (effect.dependencies && effect.dependencies.size > 0) {\n let parentChanged = false\n\n for (const dep of effect.dependencies) {\n const rawNode = dep._node || dep\n\n if (rawNode.type === 'computed' && rawNode.state > 0) {\n if (rawNode.update) rawNode.update()\n }\n\n if (effect.depVersions && effect.depVersions.get(dep) !== rawNode.version) {\n parentChanged = true\n }\n }\n\n if (!parentChanged && effect.dependencies.size > 0) {\n effect.isDirty = false\n continue\n }\n }\n\n try {\n effect.run()\n } catch (err) {\n // ⚡ ФИКС ТЕСТА #177: Если один из эффектов выбросил исключение,\n // принудительно очищаем и гасим флаги грязи (isDirty) у всех оставшихся\n // в очереди эффектов текущего и последующих уровней глубины.\n for (let d = depth; d <= this.maxPendingDepth; d++) {\n const remainingBucket = this.pendingEffects[d]\n if (remainingBucket) {\n for (const remEffect of remainingBucket) {\n remEffect.isDirty = false\n }\n remainingBucket.clear()\n }\n }\n this.maxPendingDepth = 0\n throw err // Прокидываем ошибку дальше по спецификации\n }\n\n }\n\n if (depth > 0) {\n let hasEarlierEffects = false\n for (let i = 0; i < depth; i++) {\n if (this.pendingEffects[i] && this.pendingEffects[i]!.size > 0) {\n hasEarlierEffects = true\n break\n }\n }\n if (hasEarlierEffects) depth = -1\n }\n }\n this.maxPendingDepth = 0\n } finally {\n this.activeConsumer = prevConsumer\n }\n }\n\n // public batch<T>(fn: () => T): T {\n // return executeBatch<T>(this, fn)\n // }\n\n // ⚛️ ФИКС ДЛЯ РЕЛИЗА 2.5.0: Меняем private на public,\n // чтобы изолированные функции-методы имели легальный доступ к регистратору логов\n public log(params: any) {\n if (!this.logger || !this.logger.isEnabled) return\n ReactiveDebounceLogger.processLog(this.logger, queueLog, params)\n }\n\n public signal<T>(initialValue: T, optionsOrName?: string | SignalOptions<T>): Signal<T> {\n return createSignal<T>(this, initialValue, optionsOrName)\n }\n\n public computed<T>(fn: () => T, signalName?: string): Computed<T> {\n // Просто делегируем вызов строго изолированной чистой функции\n return createComputed<T>(this, fn, signalName)\n }\n\n public effect(fn: () => void | CleanupFn, effectName?: string): () => void {\n return createEffect(this, fn, effectName)\n }\n\n public untrack<T>(fn: () => T): T {\n return executeUntrack<T>(this, fn)\n }\n\n public reactive<T extends object>(target: T, name?: string): T {\n return createReactive<T>(this, target, name)\n }\n\n public provide<T>(token: InjectionToken<T>, valueOrFactory: T | Factory<T>): void {\n this.diRegistry.set(token, valueOrFactory)\n this.diCache.delete(token)\n }\n\n public inject<T>(token: InjectionToken<T>): T {\n if (token === undefined || token === null) throw new Error('[DI Error] Token is empty')\n if (this.diCache.has(token)) return this.diCache.get(token) as T\n if (this.cycleDetectionStack.has(token)) throw new Error('[DI Error] Cyclic dependency detected')\n this.cycleDetectionStack.add(token)\n try {\n if (this.diRegistry.has(token)) {\n const entry = this.diRegistry.get(token)\n if (typeof entry === 'function') {\n if ((entry as any)._isMockFunction) {\n const mockRes = (entry as Function)(this)\n if (mockRes !== undefined) {\n this.diCache.set(token, mockRes)\n return mockRes as T\n }\n return entry as unknown as T\n }\n const str = entry.toString()\n const isClass = str.startsWith('class ') || str.startsWith('class{') || (entry.prototype && entry.prototype.constructor === entry && !str.startsWith('function') && !str.includes('=>'))\n if (!isClass) {\n const resolved = (entry as Factory<T>)(this)\n this.diCache.set(token, resolved)\n return resolved\n }\n return entry as unknown as T\n }\n return entry as T\n }\n if (typeof token === 'function') {\n const resolved = new (token as Constructor<T>)(this)\n this.diCache.set(token, resolved)\n return resolved\n }\n throw new Error('[DI Error] Token not found')\n } finally {\n this.cycleDetectionStack.delete(token)\n }\n }\n\n public delay(ms: number, signal: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal.aborted) {\n return reject(new DOMException('Aborted', 'AbortError'))\n }\n\n const timeoutId = setTimeout(() => {\n signal.removeEventListener('abort', onAbort)\n resolve()\n }, ms)\n\n const onAbort = () => {\n clearTimeout(timeoutId)\n reject(new DOMException('Aborted', 'AbortError'))\n }\n\n signal.addEventListener('abort', onAbort, { once: true })\n })\n }\n\n /**\n * Создает умную реактивную декларативную обертку над асинхронными операциями\n * с автоматическим подавлением Race Conditions и встроенным методом .destroy().\n */\n public resource<T, S = void>(\n fetcher: (source: S, signal: AbortSignal) => Promise<T>,\n source?: { value: S },\n optionsOrName?: string | ResourceOptions<T, S>,\n ): Resource<T> {\n // Передаем инстанс движка (this) как IReactiveEngine для соблюдения строгой типизации\n return createResource<T, S>(this, fetcher, source, optionsOrName)\n }\n}\n\nexport { ReactiveEngineCore as ReactiveEngine, ReactiveEngineCore as ReactiveEngineAutomatic }\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- const e=require("./core.cjs");var t=new e.ReactiveEngine({logger:{isEnabled:!1}}),n=(e,n)=>t.signal(e,n),r=(e,n)=>t.computed(e,n),i=(e,n)=>t.effect(e,n),a=e=>t.batch(e),o=e=>t.untrack(e);function s(){t=new e.ReactiveEngine({logger:{isEnabled:!1}})}exports.batch=a,exports.computed=r,exports.effect=i,exports.resetGlobalReactiveEngine=s,exports.signal=n,exports.untrack=o;
2
- //# sourceMappingURL=core.global.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"core.global.cjs","names":[],"sources":["../src/core/core.global.ts"],"sourcesContent":["import { ReactiveEngineCore } from './core'\n\n// Единый глобальный инстанс по умолчанию\nlet globalEngine = new ReactiveEngineCore({ logger: { isEnabled: false } })\n\nexport const signal = <T>(initialValue: T, options?: any) => globalEngine.signal(initialValue, options)\nexport const computed = <T>(fn: () => T, name?: string) => globalEngine.computed(fn, name)\nexport const effect = (fn: () => any, name?: string) => globalEngine.effect(fn, name)\nexport const batch = <T>(fn: () => T): T => globalEngine.batch(fn)\nexport const untrack = <T>(fn: () => T): T => globalEngine.untrack(fn)\n\n/**\n * ⚡ ХУК ДЛЯ БЕНЧМАРКОВ И ТЕСТОВЫХ СРЕД:\n * Позволяет атомарно уничтожить старый граф реактивности и начать с чистого листа,\n * полностью исключая утечки памяти и пересечение эпох между тест-кейсами.\n */\nexport function resetGlobalReactiveEngine(): void {\n // Старый инстанс со всеми WeakMap и StringCache уходит в Garbage Collector\n globalEngine = new ReactiveEngineCore({ logger: { isEnabled: false } })\n}\n"],"mappings":"8BAGA,IAAI,EAAe,IAAI,EAAA,eAAmB,CAAE,OAAQ,CAAE,UAAW,EAAM,CAAE,CAAC,EAE7D,GAAa,EAAiB,IAAkB,EAAa,OAAO,EAAc,CAAO,EACzF,GAAe,EAAa,IAAkB,EAAa,SAAS,EAAI,CAAI,EAC5E,GAAU,EAAe,IAAkB,EAAa,OAAO,EAAI,CAAI,EACvE,EAAY,GAAmB,EAAa,MAAM,CAAE,EACpD,EAAc,GAAmB,EAAa,QAAQ,CAAE,EAOrE,SAAgB,GAAkC,CAEhD,EAAe,IAAI,EAAA,eAAmB,CAAE,OAAQ,CAAE,UAAW,EAAM,CAAE,CAAC,CACxE"}
@@ -1,2 +0,0 @@
1
- var e=class{static churnTracker=new Map;static TIME_WINDOW_MS=1e3;static CHURN_WARNING_THRESHOLD=3;static CHURN_CRITICAL_THRESHOLD=6;static isDeepEqual(e,t){return e===t?!0:typeof e!=`object`||typeof t!=`object`||e===null||t===null?!1:JSON.stringify(e)===JSON.stringify(t)}static analyzeSignalChurn(e){let t=Date.now();this.churnTracker.has(e)||this.churnTracker.set(e,[]);let n=this.churnTracker.get(e),r=t-this.TIME_WINDOW_MS,i=n.filter(e=>e>r);i.push(t);let a=i.length,o=(this.TIME_WINDOW_MS/1e3).toFixed(1);return i.length<=1?(this.churnTracker.delete(e),{marker:`🟢`,info:`[STABLE] (1 изм./${o}s)`}):(this.churnTracker.set(e,i),a>=this.CHURN_CRITICAL_THRESHOLD?{marker:`🔴`,info:`[CRITICAL CHURN] (${a} изм./${o}s) — Нужен debounce!`}:a>=this.CHURN_WARNING_THRESHOLD?{marker:`🟡`,info:`[WARNING CHURN] (${a} изм./${o}s)`}:{marker:`🟢`,info:`[STABLE] (${a} изм./${o}s)`})}static processLog(e,t,n){let{type:r,label:i,details:a,isInternalCoreSignal:o=!1}=n;if(!e.isEnabled||e.filter&&!(e.filter instanceof RegExp?e.filter.test(i):i.includes(e.filter))||o&&!e.isCoreOptimizationDebugEnabled)return;if(a&&`from`in a&&`to`in a&&this.isDeepEqual(a.from,a.to)){if((r===`computed`||r===`resource`)&&e.isCoreOptimizationDebugEnabled){t(r,`🔵 [IDLE] ${i}`,a);return}return}let s=``;if(r===`signal`||r===`resource`||r===`computed`){let e=this.analyzeSignalChurn(i);s=e.marker===`🟢`?` ${e.marker}`:` ${e.marker} ${e.info}`}t(r,`${i}${s}`,a)}};exports.ReactiveDebounceLogger=e;
2
- //# sourceMappingURL=core.logger.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"core.logger.cjs","names":[],"sources":["../src/core/core.logger.ts"],"sourcesContent":["// core.logger.ts\nimport { LogEventType } from \"./types\"\n\ninterface LogDetails {\n from?: unknown;\n to?: unknown;\n payload?: unknown;\n}\n\nexport class ReactiveDebounceLogger {\n private static churnTracker = new Map<string, number[]>()\n\n private static readonly TIME_WINDOW_MS = 1000\n private static readonly CHURN_WARNING_THRESHOLD = 3\n private static readonly CHURN_CRITICAL_THRESHOLD = 6\n\n private static isDeepEqual(a: unknown, b: unknown): boolean {\n if (a === b) return true\n if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) return false\n return JSON.stringify(a) === JSON.stringify(b)\n }\n\n private static analyzeSignalChurn(label: string): { marker: string; info: string } {\n const now = Date.now()\n if (!this.churnTracker.has(label)) {\n this.churnTracker.set(label, [])\n }\n\n const history = this.churnTracker.get(label)!\n const cutoff = now - this.TIME_WINDOW_MS\n // Фильтруем историю\n const activeHistory = history.filter(ts => ts > cutoff)\n activeHistory.push(now)\n\n const updateCount = activeHistory.length\n const intervalSec = (this.TIME_WINDOW_MS / 1000).toFixed(1)\n\n // ⚛️ ФИКС УТЕЧКИ ПАМЯТИ: Если узел стабилен и старых логов нет,\n // удаляем ключ из Map целиком, чтобы не копить мусор\n if (activeHistory.length <= 1) {\n this.churnTracker.delete(label)\n return { marker: '🟢', info: `[STABLE] (1 изм./${intervalSec}s)` }\n } else {\n this.churnTracker.set(label, activeHistory)\n }\n\n if (updateCount >= this.CHURN_CRITICAL_THRESHOLD) {\n return {\n marker: '🔴',\n info: `[CRITICAL CHURN] (${updateCount} изм./${intervalSec}s) — Нужен debounce!`\n }\n }\n\n if (updateCount >= this.CHURN_WARNING_THRESHOLD) {\n return {\n marker: '🟡',\n info: `[WARNING CHURN] (${updateCount} изм./${intervalSec}s)`\n }\n }\n\n return {\n marker: '🟢',\n info: `[STABLE] (${updateCount} изм./${intervalSec}s)`\n }\n }\n\n public static processLog(\n engineLogger: any,\n queueLogFn: Function,\n params: { type: LogEventType; label: string; details?: LogDetails; isInternalCoreSignal?: boolean }\n ) {\n const { type, label, details, isInternalCoreSignal = false } = params\n\n if (!engineLogger.isEnabled) return\n\n // ⚛️ ФИКС #1: Включаем валидацию RegExp фильтра из настроек\n if (engineLogger.filter) {\n const isMatch = engineLogger.filter instanceof RegExp\n ? engineLogger.filter.test(label)\n : label.includes(engineLogger.filter)\n if (!isMatch) return\n }\n\n if (isInternalCoreSignal && !engineLogger.isCoreOptimizationDebugEnabled) return\n\n if (details && 'from' in details && 'to' in details) {\n if (this.isDeepEqual(details.from, details.to)) {\n // ⚛️ ФИКС #2: Разрешаем логам типов 'resource' выводить IDLE транзакции,\n // иначе глубокое равенство объектов состояния блокирует их вывод\n if ((type === 'computed' || type === 'resource') && engineLogger.isCoreOptimizationDebugEnabled) {\n queueLogFn(type, `🔵 [IDLE] ${label}`, details)\n return\n }\n return\n }\n }\n\n let churnInfo = ''\n if (type === 'signal' || type === 'resource' || type === 'computed') {\n const churn = this.analyzeSignalChurn(label)\n churnInfo = churn.marker === '🟢' ? ` ${churn.marker}` : ` ${churn.marker} ${churn.info}`\n }\n\n queueLogFn(type, `${label}${churnInfo}`, details)\n }\n\n}\n"],"mappings":"AASA,IAAa,EAAb,KAAoC,CAClC,OAAe,aAAe,IAAI,IAElC,OAAwB,eAAiB,IACzC,OAAwB,wBAA0B,EAClD,OAAwB,yBAA2B,EAEnD,OAAe,YAAY,EAAY,EAAqB,CAG1D,OAFI,IAAM,EAAU,GAChB,OAAO,GAAM,UAAY,OAAO,GAAM,UAAY,IAAM,MAAQ,IAAM,KAAa,GAChF,KAAK,UAAU,CAAC,IAAM,KAAK,UAAU,CAAC,CAC/C,CAEA,OAAe,mBAAmB,EAAiD,CACjF,IAAM,EAAM,KAAK,IAAI,EAChB,KAAK,aAAa,IAAI,CAAK,GAC9B,KAAK,aAAa,IAAI,EAAO,CAAC,CAAC,EAGjC,IAAM,EAAU,KAAK,aAAa,IAAI,CAAK,EACrC,EAAS,EAAM,KAAK,eAEpB,EAAgB,EAAQ,OAAO,GAAM,EAAK,CAAM,EACtD,EAAc,KAAK,CAAG,EAEtB,IAAM,EAAc,EAAc,OAC5B,GAAe,KAAK,eAAiB,IAAA,CAAM,QAAQ,CAAC,EAyB1D,OArBI,EAAc,QAAU,GAC1B,KAAK,aAAa,OAAO,CAAK,EACvB,CAAE,OAAQ,KAAM,KAAM,oBAAoB,EAAY,GAAI,IAEjE,KAAK,aAAa,IAAI,EAAO,CAAa,EAGxC,GAAe,KAAK,yBACf,CACL,OAAQ,KACR,KAAM,qBAAqB,EAAY,QAAQ,EAAY,qBAC7D,EAGE,GAAe,KAAK,wBACf,CACL,OAAQ,KACR,KAAM,oBAAoB,EAAY,QAAQ,EAAY,GAC5D,EAGK,CACL,OAAQ,KACR,KAAM,aAAa,EAAY,QAAQ,EAAY,GACrD,EACF,CAEA,OAAc,WACZ,EACA,EACA,EACA,CACA,GAAM,CAAE,OAAM,QAAO,UAAS,uBAAuB,IAAU,EAY/D,GAVI,CAAC,EAAa,WAGd,EAAa,QAIX,EAHY,EAAa,kBAAkB,OAC3C,EAAa,OAAO,KAAK,CAAK,EAC9B,EAAM,SAAS,EAAa,MAAM,IAIpC,GAAwB,CAAC,EAAa,+BAAgC,OAE1E,GAAI,GAAW,SAAU,GAAW,OAAQ,GACtC,KAAK,YAAY,EAAQ,KAAM,EAAQ,EAAE,EAAG,CAG9C,IAAK,IAAS,YAAc,IAAS,aAAe,EAAa,+BAAgC,CAC/F,EAAW,EAAM,aAAa,IAAS,CAAO,EAC9C,MACF,CACA,MACF,CAGF,IAAI,EAAY,GAChB,GAAI,IAAS,UAAY,IAAS,YAAc,IAAS,WAAY,CACnE,IAAM,EAAQ,KAAK,mBAAmB,CAAK,EAC3C,EAAY,EAAM,SAAW,KAAO,IAAI,EAAM,SAAW,IAAI,EAAM,OAAO,GAAG,EAAM,MACrF,CAEA,EAAW,EAAM,GAAG,IAAQ,IAAa,CAAO,CAClD,CAEF"}
@@ -1,2 +0,0 @@
1
- function e(e,t,n){let r=e.computedCache.get(t);if(r)return r;let i,a=!0,o=0,s=!1,c=-1,l=2,u=new Set,d=new Map,f=new Set,p=new Set,m=e=>{if(!e)return;let t=e._node||e;if(t.dependencies&&t.dependencies.size>0){for(let n of t.dependencies){let r=n,i=r._node||r;i.subscribers&&(i.subscribers.delete(t),i.subscribers.delete(e),i.subscribers.delete(_),i.type===`computed`&&i.subscribers.size===0&&m(i))}t.dependencies.clear(),t.depVersions&&t.depVersions.clear()}},h=t=>{if(!s||l===2)return t.run();let n=!1;if(u&&u.size>0)for(let t of u){let r=t._node||t;if(r.type===`computed`&&r.state>0&&r.update&&r.verifiedInEpoch!==e.epoch&&r.update(),t.hasBatchValue||d.get(t)!==r.version){n=!0;break}}return n?(c=-1,t.verifiedInEpoch=-1,t.run()):p&&p.size>0&&t.verifiedInEpoch===e.epoch&&e.batchDepth===0&&l===0?!1:a?t.run():(t.verifiedInEpoch!==-1&&t.verifiedInEpoch<e.epoch&&(!p||p.size===0)?t.verifiedInEpoch=-1:t.verifiedInEpoch=e.epoch,l=0,!1)},g=0,_={id:e.subscriberId++,dependencies:u,subscribers:p,ownedEffects:f,depth:1,type:`computed`,fn:t,get version(){return o},get state(){return l},set state(e){l=e},get depVersions(){return d},verifiedInEpoch:-1,update:()=>h(_),run:()=>{if(c===e.epoch&&s&&l===0&&e.batchDepth===0)return!1;let r=e.epoch;if(c=r,_.verifiedInEpoch=r,e.cycleDetectionStack.has(_))throw Error(`[Graph Error] Cyclic dependency detected`);e.cycleDetectionStack.add(_);let p=e.activeConsumer,m=e.activeOwner;e.activeConsumer=_,e.activeOwner=_,g++,_.activeRunId=g;let h=u.size>0?Array.from(u):null;u.clear();try{if(f.size>0){for(let e of f)e&&typeof e.dispose==`function`&&e.dispose();f.clear()}let p=t();if(h!==null){let e=h.length===u.size;for(let t of h){let n=t;if(!e||!u.has(n)){let e=n._node||n;e.subscribers&&e.subscribers.delete(_),d.delete(n)}}}let m=a||!Object.is(i,p);if(m){let t=a?void 0:typeof i==`object`&&i?JSON.parse(JSON.stringify(i)):i;i=p,o++,e.log&&n&&e.log({type:`computed`,label:n,details:{from:t,to:p}})}a=!1,l=0,s=!0;let g=0;for(let e of u){let t=e,n=t._node||t;d.set(t,n.version),n.subscribers&&n.subscribers.add(_),n.depth!==void 0&&n.depth>g&&(g=n.depth)}return _.depth=g+1,e.epoch!==r&&(c=-1,_.verifiedInEpoch=-1,l=2),m}finally{e.activeConsumer=p,e.activeOwner=m,e.cycleDetectionStack.delete(_)}},markDirty:t=>{if(!(l>=t)){l=t;for(let t of p){let n=t._node||t;n.type===`effect`?(n.isDirty=!0,e.scheduleEffect(t)):n.markDirty&&n.markDirty(1)}}}},v={get value(){let t=e.activeConsumer;if(t&&t!==_&&typeof t.dependencies?.add==`function`){p.add(t),t.dependencies.add(_);let e=_.depth||1,n=t._node||t;n.depth!==void 0&&e>=n.depth&&(n.depth=e+1),t.activeRunId!==void 0&&(_._lastSeenInRunId=t.activeRunId)}return h(_),t&&t.depVersions&&t.depVersions.set(v,o),i},get valueWithoutTracking(){return i},get version(){return o},get dependencies(){return u},subscribe(t){let n=this,r={id:e.subscriberId++,isDirty:!0,depth:9999,dependencies:new Set,type:`effect`,run:()=>{if(!r.isDisposed)try{t(n.value)}catch(e){console.error(e)}}};return p.add(r),t(this.value),()=>{r.isDisposed=!0,p.delete(r),r.dependencies.clear()}},subscribeState(e){return v.subscribe(e)},destroy:()=>{m(_),p&&p.clear(),e.computedCache.delete(t),u.clear(),d.clear(),f.clear(),a=!0,l=2,s=!1},__subscribe(t){let n={id:e.subscriberId++,type:`effect`,run:t,isDirty:!1};return p.add(n),()=>{p.delete(n)}}};return v.run=()=>_.run(),e.computedCache.set(t,v),v._node=_,v.subscribers=p,v}exports.createComputed=e;
2
- //# sourceMappingURL=core.method.computed.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"core.method.computed.cjs","names":[],"sources":["../src/core/core.method.computed.ts"],"sourcesContent":["import { Computed, CleanupFn } from './types'\n\nexport function createComputed<T>(\n engine: any,\n fn: () => T,\n signalName?: string\n): Computed<T> {\n // 1. Ультимативный канонический WeakMap путь (строго по ссылке на объект-функцию)\n // Работает со скоростью нативной ссылки в V8, полностью исключая утечки памяти\n const existing = engine.computedCache.get(fn)\n if (existing) return existing as Computed<T>\n\n let value: T\n let isDirty = true\n let version = 0\n let isInitialized = false\n let evaluatedInEpoch = -1\n let state = 2 // 2 = DIRTY, 1 = CHECK, 0 = STABLE\n\n const dependencies = new Set<any>()\n const depVersions = new Map<any, number>()\n const ownedEffects = new Set<any>()\n const subscribers = new Set<any>()\n\n const releaseNode = (node: any): void => {\n if (!node) return\n const actNode = node._node || node\n\n if (actNode.dependencies && actNode.dependencies.size > 0) {\n for (const unknownDep of actNode.dependencies) {\n const dep = unknownDep as any\n const rawDepNode = dep._node || dep\n\n if (rawDepNode.subscribers) {\n rawDepNode.subscribers.delete(actNode)\n rawDepNode.subscribers.delete(node)\n rawDepNode.subscribers.delete(computedNode)\n\n if (rawDepNode.type === 'computed' && rawDepNode.subscribers.size === 0) {\n releaseNode(rawDepNode)\n }\n }\n }\n actNode.dependencies.clear()\n if (actNode.depVersions) actNode.depVersions.clear()\n }\n }\n\n const updateIfNecessary = (node: any): boolean => {\n if (!isInitialized || state === 2) {\n return node.run()\n }\n\n // 1. Сначала честно сканируем родителей по физическим версиям мутаций в V8.\n // Это единственный способ отловить inner write на фазе ленивого pull-запроса,\n // так как вложенный сеттер мог сдвинуть версии сигналов в обход markDirty.\n let hasChangedParent = false\n\n if (dependencies && dependencies.size > 0) {\n for (const dep of dependencies) {\n const rawDep = dep._node || dep\n\n if (rawDep.type === 'computed' && rawDep.state > 0) {\n if (rawDep.update && rawDep.verifiedInEpoch !== engine.epoch) {\n rawDep.update()\n }\n }\n\n if (dep.hasBatchValue || depVersions.get(dep) !== rawDep.version) {\n hasChangedParent = true\n break\n }\n }\n }\n\n // ⚛️ УЛЬТИМАТИВНЫЙ ФИКС ТЕСТOВ #180 и #186:\n // Если обход родителей подтвердил изменение версий из побочного канала (hasChangedParent === true),\n // мы ОБЯЗАНЫ сбросить кэши эпох текущей ноды и пустить её на честный пересчет.\n // При этом мы НЕ выставляем принудительно state = 2, благодаря чему метод run()\n // сможет сравнить результаты через Object.is и легитимно остановить волну (Value-Equality Cut)!\n if (hasChangedParent) {\n evaluatedInEpoch = -1\n node.verifiedInEpoch = -1\n return node.run()\n }\n\n // 2. И только если родители НЕ менялись, мы можем применить быстрый O(1) возврат по эпохам\n if (subscribers && subscribers.size > 0) {\n if (node.verifiedInEpoch === engine.epoch && engine.batchDepth === 0 && state === 0) {\n return false\n }\n }\n\n if (isDirty) {\n return node.run()\n }\n\n // Канонический сброс для unobserved pull-цепочек из тестов матрицы сайта\n if (node.verifiedInEpoch !== -1 && node.verifiedInEpoch < engine.epoch && (!subscribers || subscribers.size === 0)) {\n node.verifiedInEpoch = -1\n } else {\n node.verifiedInEpoch = engine.epoch\n }\n\n state = 0\n return false\n }\n\n let currentRunId = 0\n\n const computedNode: any = {\n id: engine.subscriberId++,\n dependencies,\n subscribers,\n ownedEffects,\n depth: 1,\n type: 'computed',\n fn,\n get version() { return version },\n get state() { return state },\n set state(val: number) { state = val },\n get depVersions() { return depVersions },\n verifiedInEpoch: -1, // Перенесено напрямую на объект ноды для ультимативного O(1)\n update: () => updateIfNecessary(computedNode),\n run: () => {\n // ⚛️ КАНOНИЧЕСКИЙ БЫСТРЫЙ ВЫХOД:\n // Срабатывает только если эпоха стабильна, узел не сброшен в updateIfNecessary\n // и в текущем кадре не происходило inner write мутаций у родителей\n if (evaluatedInEpoch === engine.epoch && isInitialized && state === 0 && engine.batchDepth === 0) {\n return false\n }\n\n // Запоминаем стартовую эпоху до вызова функции пользователя\n const startEpoch = engine.epoch\n evaluatedInEpoch = startEpoch\n computedNode.verifiedInEpoch = startEpoch\n\n if (engine.cycleDetectionStack.has(computedNode)) {\n throw new Error('[Graph Error] Cyclic dependency detected')\n }\n engine.cycleDetectionStack.add(computedNode)\n\n const prevConsumer = engine.activeConsumer\n const prevOwner = engine.activeOwner\n\n engine.activeConsumer = computedNode\n engine.activeOwner = computedNode\n\n currentRunId++\n computedNode.activeRunId = currentRunId\n\n const oldDeps = dependencies.size > 0 ? Array.from(dependencies) : null\n dependencies.clear()\n\n try {\n if (ownedEffects.size > 0) {\n for (const child of ownedEffects) {\n if (child && typeof child.dispose === 'function') {\n child.dispose()\n }\n }\n ownedEffects.clear()\n }\n\n // Выполняем пользовательскую функцию (здесь могут произойти inner writes из тестов #179, #180, #186)\n const newValue = fn()\n\n if (oldDeps !== null) {\n const isSizeIdentical = oldDeps.length === dependencies.size\n for (const unknownDep of oldDeps) {\n const dep = unknownDep as any\n if (!isSizeIdentical || !dependencies.has(dep)) {\n const rawDepNode = dep._node || dep\n if (rawDepNode.subscribers) rawDepNode.subscribers.delete(computedNode)\n depVersions.delete(dep)\n }\n }\n }\n\n const changed = isDirty || !Object.is(value, newValue)\n\n if (changed) {\n const previousValueSnapshot = isDirty ? undefined : (typeof value === 'object' && value !== null ? JSON.parse(JSON.stringify(value)) : value)\n value = newValue\n version++\n\n if (engine.log && signalName) {\n engine.log({\n type: 'computed',\n label: signalName,\n details: { from: previousValueSnapshot, to: newValue }\n })\n }\n }\n\n isDirty = false\n state = 0\n isInitialized = true\n\n let maxDepDepth = 0\n for (const unknownDep of dependencies) {\n const dep = unknownDep as any\n const rawNode = dep._node || dep\n depVersions.set(dep, rawNode.version)\n if (rawNode.subscribers) rawNode.subscribers.add(computedNode)\n if (rawNode.depth !== undefined && rawNode.depth > maxDepDepth) {\n maxDepDepth = rawNode.depth\n }\n }\n\n computedNode.depth = maxDepDepth + 1\n\n // ⚡ ФИКС ДЛЯ INNER WRITES (#179, #180, #186):\n // Если во время исполнения fn() эпоха ядра сдвинулась (был вложенный сеттер),\n // мы обязаны сбросить кэш верификации этой эпохи, чтобы последующие цепочки\n // зависимостей внутри этого же тика пересчитали свои значения нативно.\n if (engine.epoch !== startEpoch) {\n evaluatedInEpoch = -1\n computedNode.verifiedInEpoch = -1\n state = 2 // Переводим в DIRTY для немедленной инвалидации\n }\n\n return changed\n } finally {\n engine.activeConsumer = prevConsumer\n engine.activeOwner = prevOwner\n engine.cycleDetectionStack.delete(computedNode)\n }\n },\n markDirty: (parentState: number) => {\n if (state >= parentState) return\n state = parentState\n\n for (const sub of subscribers) {\n const rawSub = sub._node || sub\n if (rawSub.type === 'effect') {\n rawSub.isDirty = true\n engine.scheduleEffect(sub)\n } else if (rawSub.markDirty) {\n rawSub.markDirty(1)\n }\n }\n }\n }\n\n const computedInstance: Computed<T> = {\n get value() {\n const consumer = engine.activeConsumer\n if (consumer && consumer !== computedNode) {\n if (typeof consumer.dependencies?.add === 'function') {\n subscribers.add(consumer)\n consumer.dependencies.add(computedNode)\n\n const currentDepth = computedNode.depth || 1\n const consumerRaw = consumer._node || consumer\n if (consumerRaw.depth !== undefined && currentDepth >= consumerRaw.depth) {\n consumerRaw.depth = currentDepth + 1\n }\n\n if (consumer.activeRunId !== undefined) {\n computedNode._lastSeenInRunId = consumer.activeRunId\n }\n }\n }\n\n updateIfNecessary(computedNode)\n\n if (consumer && consumer.depVersions) {\n consumer.depVersions.set(computedInstance, version)\n }\n return value\n },\n get valueWithoutTracking() { return value },\n get version() { return version },\n get dependencies() { return dependencies },\n\n subscribe(cb: (val: T) => void): CleanupFn {\n const self = this\n const fakeEffect: any = {\n id: engine.subscriberId++,\n isDirty: true,\n depth: 9999,\n dependencies: new Set(),\n type: 'effect',\n run: () => {\n if (fakeEffect.isDisposed) return\n try { cb(self.value) } catch (err) { console.error(err) }\n }\n }\n subscribers.add(fakeEffect)\n cb(this.value)\n return () => {\n fakeEffect.isDisposed = true\n subscribers.delete(fakeEffect)\n fakeEffect.dependencies.clear()\n }\n },\n subscribeState(cb: () => void): CleanupFn {\n return (computedInstance as any).subscribe(cb)\n },\n destroy: () => {\n releaseNode(computedNode)\n if (subscribers) subscribers.clear()\n engine.computedCache.delete(fn)\n\n dependencies.clear()\n depVersions.clear()\n ownedEffects.clear()\n\n isDirty = true\n state = 2\n isInitialized = false\n },\n __subscribe(cb: () => void): CleanupFn {\n const hookEffect: any = {\n id: engine.subscriberId++,\n type: 'effect',\n run: cb,\n isDirty: false\n }\n subscribers.add(hookEffect)\n return () => {\n subscribers.delete(hookEffect)\n }\n }\n } as any\n\n computedInstance.run = () => computedNode.run()\n engine.computedCache.set(fn, computedInstance)\n\n ;(computedInstance as any)._node = computedNode\n ;(computedInstance as any).subscribers = subscribers\n\n return computedInstance\n}\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- function e(e,t,n){let r=!1,i=!1,a=2,o=new Set,s=new Map,c=new Set,l=()=>{if(c.size>0){let t=e.activeConsumer,n=e.activeOwner;e.activeConsumer=null,e.activeOwner=null;for(let e of c)e.dispose&&e.dispose();c.clear(),e.activeConsumer=t,e.activeOwner=n}if(u.cleanups.size>0){let t=e.activeConsumer;e.activeConsumer=null;for(let e of u.cleanups)try{e()}catch(e){console.error(e)}u.cleanups.clear(),e.activeConsumer=t}},u={id:e.subscriberId++,dependencies:o,ownedEffects:c,cleanups:new Set,type:`effect`,depth:0,label:n,get isDirty(){return a>0},set isDirty(e){e&&(a=2)},get isDisposed(){return r},set isDisposed(e){r=e},get state(){return a},set state(e){a=e},get depVersions(){return s},get _node(){return u},markDirty:()=>{a>=1||(a=1,e.scheduleEffect(u))},run:()=>{if(r||i)return;i=!0,l();let n=e.activeConsumer,c=e.activeOwner;e.activeConsumer=u,e.activeOwner=u;let d=o.size>0?Array.from(o):null;o.clear();try{a=0;let e=t();if(typeof e==`function`&&u.cleanups.add(e),d!==null)for(let e of d){let t=e;if(!o.has(t)){let e=t._node||t;e.subscribers&&e.subscribers.delete(u),s.delete(t)}}let n=0;for(let e of o){let t=e,r=t._node||t;s.set(t,r.version),r.subscribers&&r.subscribers.add(u),r.depth!==void 0&&r.depth>n&&(n=r.depth)}u.depth=n+1}finally{i=!1,e.activeConsumer=n,e.activeOwner=c}},dispose:()=>{if(!r){r=!0,u.isDisposed=!0,l();for(let e of o){let t=e._node||e;t.subscribers&&t.subscribers.delete(u)}o.clear(),s.clear()}}},d=e.activeOwner?e.activeOwner._node||e.activeOwner:null;return d&&d.ownedEffects&&d.ownedEffects.add(u),u.run(),()=>{u.dispose()}}exports.createEffect=e;
2
- //# sourceMappingURL=core.method.effect.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"core.method.effect.cjs","names":[],"sources":["../src/core/core.method.effect.ts"],"sourcesContent":["import { IEffect, EffectFn, CleanupFn } from './types'\n\ninterface ICoreEffectNode extends IEffect {\n dependencies: Set<any>;\n depVersions: Map<any, number>;\n ownedEffects: Set<ICoreEffectNode>;\n type: string;\n depth: number;\n state: number;\n _node: any;\n dispose: () => void;\n}\n\nexport function createEffect(engine: any, fn: EffectFn, effectName?: string): () => void {\n let isDisposed = false\n let isRunning = false\n let state = 2 // 0 = STABLE, 1 = CHECK, 2 = DIRTY\n\n const dependencies = new Set<any>()\n const depVersions = new Map<any, number>()\n const ownedEffects = new Set<ICoreEffectNode>()\n\n const runCleanupPhase = () => {\n // Каскадное уничтожение вложенных детей через быстрый for...of\n if (ownedEffects.size > 0) {\n const prevConsumer = engine.activeConsumer\n const prevOwner = engine.activeOwner\n engine.activeConsumer = null\n engine.activeOwner = null\n\n for (const child of ownedEffects) {\n if (child.dispose) child.dispose()\n }\n ownedEffects.clear()\n\n engine.activeConsumer = prevConsumer\n engine.activeOwner = prevOwner\n }\n\n // Изоляция ошибок в деструкторах пользователя через быстрый for...of\n if (effectNode.cleanups.size > 0) {\n const prevConsumer = engine.activeConsumer\n engine.activeConsumer = null\n\n for (const cleanup of effectNode.cleanups) {\n try {\n cleanup()\n } catch (err) {\n console.error(err)\n }\n }\n\n effectNode.cleanups.clear()\n engine.activeConsumer = prevConsumer\n }\n }\n\n const effectNode: ICoreEffectNode = {\n id: engine.subscriberId++,\n dependencies,\n ownedEffects,\n cleanups: new Set<CleanupFn>(),\n type: 'effect',\n depth: 0,\n label: effectName,\n\n get isDirty(): boolean { return state > 0 },\n set isDirty(val: boolean) { if (val) state = 2 },\n\n get isDisposed(): boolean { return isDisposed },\n set isDisposed(val: boolean) { isDisposed = val },\n\n get state(): number { return state },\n set state(val: number) { state = val },\n get depVersions(): Map<any, number> { return depVersions },\n get _node(): any { return effectNode },\n\n markDirty: () => {\n if (state >= 1) return\n state = 1\n engine.scheduleEffect(effectNode)\n },\n\n run: () => {\n if (isDisposed || isRunning) return\n isRunning = true\n\n runCleanupPhase()\n\n const prevConsumer = engine.activeConsumer\n const prevOwner = engine.activeOwner\n\n engine.activeConsumer = effectNode\n engine.activeOwner = effectNode\n\n const oldDeps = dependencies.size > 0 ? Array.from(dependencies) : null\n dependencies.clear()\n\n try {\n state = 0 // Сбрасываем флаг грязи перед чтением графа\n\n const result = fn()\n if (typeof result === 'function') {\n effectNode.cleanups.add(result)\n }\n\n if (oldDeps !== null) {\n for (const unknownDep of oldDeps) {\n const dep = unknownDep as any\n if (!dependencies.has(dep)) {\n const rawDepNode = dep._node || dep\n if (rawDepNode.subscribers) rawDepNode.subscribers.delete(effectNode)\n depVersions.delete(dep)\n }\n }\n }\n\n let maxDepDepth = 0\n for (const unknownDep of dependencies) {\n const dep = unknownDep as any\n const rawNode = dep._node || dep\n depVersions.set(dep, rawNode.version)\n if (rawNode.subscribers) rawNode.subscribers.add(effectNode)\n if (rawNode.depth !== undefined && rawNode.depth > maxDepDepth) {\n maxDepDepth = rawNode.depth\n }\n }\n effectNode.depth = maxDepDepth + 1\n\n } finally {\n isRunning = false\n engine.activeConsumer = prevConsumer\n engine.activeOwner = prevOwner\n }\n },\n\n dispose: () => {\n if (isDisposed) return\n isDisposed = true\n effectNode.isDisposed = true\n\n runCleanupPhase()\n\n // ⚡ ОПТИМИЗАЦИЯ: Замена .forEach на быстрый for...of при полном уничтожении эффекта\n for (const dep of dependencies) {\n const rawNode = dep._node || dep\n if (rawNode.subscribers) rawNode.subscribers.delete(effectNode)\n }\n dependencies.clear()\n depVersions.clear()\n }\n }\n\n const actualOwnerNode = engine.activeOwner ? (engine.activeOwner._node || engine.activeOwner) : null\n\n if (actualOwnerNode && actualOwnerNode.ownedEffects) {\n actualOwnerNode.ownedEffects.add(effectNode)\n }\n\n effectNode.run()\n\n return () => {\n effectNode.dispose()\n }\n}\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- function e(e,t,n){if(e.proxyTargets.has(t))return t;if(e.proxyCache.has(t))return e.proxyCache.get(t);e.reactiveSignals.has(t)||e.reactiveSignals.set(t,new Map);let r=e.reactiveSignals.get(t),i=new Proxy(t,{get(t,i,a){if(i===`__subscribe`&&Array.isArray(t))return n=>{let i=r.get(`length`);return i||(i=e.signal(t.length),r.set(`length`,i)),i.subscribe(n)};if(Array.isArray(t)&&typeof i==`string`&&[`push`,`pop`,`shift`,`unshift`,`splice`,`sort`,`reverse`].includes(i))return(...n)=>{let o;return e.batch(()=>{o=Reflect.get(t,i).apply(a,n);let e=r.get(`length`);e&&(e.value=t.length),r.forEach((e,n)=>{n!==`length`&&(e.value=Reflect.get(t,n))})}),o};if(typeof i==`symbol`||i===`constructor`||i===`toJSON`)return Reflect.get(t,i,a);let o=r.get(i);if(!o){let a=Reflect.get(t,i);o=e.signal(a),r.set(i,o),typeof a==`object`&&a&&(o._proxyCache=e.reactive(a,n?`${n}.${String(i)}`:String(i)))}return o._proxyCache===void 0?o.value:(o.value,o._proxyCache)},set(t,n,i,a){let o=(e.proxyTargets.has(i),i),s=Reflect.get(t,n);if(s===o&&n!==`length`)return!0;Reflect.set(t,n,o);let c=r.get(n);if(c||(c=e.signal(s),r.set(n,c)),c._proxyCache=void 0,c.value=o,Array.isArray(t)&&n!==`length`){let e=r.get(`length`);e&&(e.value=t.length)}return!0}});return e.proxyCache.set(t,i),e.proxyTargets.add(i),i}exports.createReactive=e;
2
- //# sourceMappingURL=core.method.reactive.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"core.method.reactive.cjs","names":[],"sources":["../src/core/core.method.reactive.ts"],"sourcesContent":["/**\n * * Изолированная фабрика глубоких реактивных Proxy-объектов графа.\n */\nexport function createReactive<T extends object>(\n engine: any,\n target: T,\n name?: string\n): T {\n if (engine.proxyTargets.has(target)) return target as any\n if (engine.proxyCache.has(target)) return engine.proxyCache.get(target) as any\n if (!engine.reactiveSignals.has(target)) engine.reactiveSignals.set(target, new Map())\n const signalsMap = engine.reactiveSignals.get(target)!\n\n const handler: ProxyHandler<T> = {\n get(t: T, prop: string | symbol, receiver: any) {\n if (prop === '__subscribe' && Array.isArray(t)) {\n return (cb: () => void) => {\n let lengthSig = signalsMap.get('length')\n if (!lengthSig) {\n lengthSig = engine.signal(t.length)\n signalsMap.set('length', lengthSig)\n }\n return lengthSig.subscribe(cb)\n }\n }\n\n if (Array.isArray(t) && typeof prop === 'string' && ['push', 'pop', 'shift', 'unshift', 'splice', 'sort', 'reverse'].includes(prop)) {\n return (...args: any[]) => {\n let result: any\n engine.batch(() => {\n result = (Reflect.get(t, prop) as Function).apply(receiver, args)\n\n let lengthSig = signalsMap.get('length')\n if (lengthSig) lengthSig.value = t.length\n\n signalsMap.forEach((sig: any, key: string) => {\n if (key !== 'length') sig.value = Reflect.get(t, key)\n })\n })\n return result\n }\n }\n\n if (typeof prop === 'symbol' || prop === 'constructor' || prop === 'toJSON') return Reflect.get(t, prop, receiver)\n\n let sig = signalsMap.get(prop)\n if (!sig) {\n const rawValue = Reflect.get(t, prop)\n sig = engine.signal(rawValue)\n signalsMap.set(prop, sig)\n\n // ⚡ ЛЕНИВОЕ КЭШИРОВАНИЕ НА ЧТЕНИИ (O(1) Hot Path):\n // Создаем прокси-обертку строго один раз при первом РЕАЛЬНОМ обращении к свойству,\n // а не принудительно при записи.\n if (rawValue !== null && typeof rawValue === 'object') {\n (sig as any)._proxyCache = engine.reactive(rawValue, name ? `${name}.${String(prop)}` : String(prop))\n }\n }\n\n if ((sig as any)._proxyCache !== undefined) {\n sig.value // Честная регистрация ребра для сохранения топологии глубины веток\n return (sig as any)._proxyCache\n }\n\n return sig.value\n },\n\n set(t: T, prop: string | symbol, value: any, receiver: any) {\n const rawValue = engine.proxyTargets.has(value) ? value : value\n const oldValue = Reflect.get(t, prop)\n\n if (oldValue === rawValue && prop !== 'length') return true\n Reflect.set(t, prop, rawValue)\n\n let sig = signalsMap.get(prop)\n if (!sig) {\n sig = engine.signal(oldValue)\n signalsMap.set(prop, sig)\n }\n\n // ⚡ МЕГА-УСКOРЕНИЕ ДЛЯ СЕТТЕРOВ:\n // При записи мы просто СБРАСЫВАЕМ кэш прокси на узле в undefined.\n // Если бенчмарк захочет прочитать это свойство на следующей итерации,\n // ловушка геттера лениво создаст прокси. Если нет — мы сэкономили 100% ресурсов!\n (sig as any)._proxyCache = undefined\n sig.value = rawValue\n\n if (Array.isArray(t) && prop !== 'length') {\n let lengthSig = signalsMap.get('length')\n if (lengthSig) lengthSig.value = t.length\n }\n return true\n }\n }\n\n const proxy = new Proxy(target, handler)\n engine.proxyCache.set(target, proxy)\n engine.proxyTargets.add(proxy)\n return proxy\n}\n"],"mappings":"AAGA,SAAgB,EACd,EACA,EACA,EACG,CACH,GAAI,EAAO,aAAa,IAAI,CAAM,EAAG,OAAO,EAC5C,GAAI,EAAO,WAAW,IAAI,CAAM,EAAG,OAAO,EAAO,WAAW,IAAI,CAAM,EACjE,EAAO,gBAAgB,IAAI,CAAM,GAAG,EAAO,gBAAgB,IAAI,EAAQ,IAAI,GAAK,EACrF,IAAM,EAAa,EAAO,gBAAgB,IAAI,CAAM,EAoF9C,EAAQ,IAAI,MAAM,EAAQ,CAjF9B,IAAI,EAAM,EAAuB,EAAe,CAC9C,GAAI,IAAS,eAAiB,MAAM,QAAQ,CAAC,EAC3C,MAAQ,IAAmB,CACzB,IAAI,EAAY,EAAW,IAAI,QAAQ,EAKvC,OAJK,IACH,EAAY,EAAO,OAAO,EAAE,MAAM,EAClC,EAAW,IAAI,SAAU,CAAS,GAE7B,EAAU,UAAU,CAAE,CAC/B,EAGF,GAAI,MAAM,QAAQ,CAAC,GAAK,OAAO,GAAS,UAAY,CAAC,OAAQ,MAAO,QAAS,UAAW,SAAU,OAAQ,SAAS,CAAC,CAAC,SAAS,CAAI,EAChI,OAAQ,GAAG,IAAgB,CACzB,IAAI,EAWJ,OAVA,EAAO,UAAY,CACjB,EAAU,QAAQ,IAAI,EAAG,CAAI,CAAC,CAAc,MAAM,EAAU,CAAI,EAEhE,IAAI,EAAY,EAAW,IAAI,QAAQ,EACnC,IAAW,EAAU,MAAQ,EAAE,QAEnC,EAAW,SAAS,EAAU,IAAgB,CACxC,IAAQ,WAAU,EAAI,MAAQ,QAAQ,IAAI,EAAG,CAAG,EACtD,CAAC,CACH,CAAC,EACM,CACT,EAGF,GAAI,OAAO,GAAS,UAAY,IAAS,eAAiB,IAAS,SAAU,OAAO,QAAQ,IAAI,EAAG,EAAM,CAAQ,EAEjH,IAAI,EAAM,EAAW,IAAI,CAAI,EAC7B,GAAI,CAAC,EAAK,CACR,IAAM,EAAW,QAAQ,IAAI,EAAG,CAAI,EACpC,EAAM,EAAO,OAAO,CAAQ,EAC5B,EAAW,IAAI,EAAM,CAAG,EAKC,OAAO,GAAa,UAAzC,IACF,EAAa,YAAc,EAAO,SAAS,EAAU,EAAO,GAAG,EAAK,GAAG,OAAO,CAAI,IAAM,OAAO,CAAI,CAAC,EAExG,CAOA,OALK,EAAY,cAAgB,IAAA,GAK1B,EAAI,OAJT,EAAI,MACI,EAAY,YAIxB,EAEA,IAAI,EAAM,EAAuB,EAAY,EAAe,CAC1D,IAAM,GAAW,EAAO,aAAa,IAAI,CAAK,EAAI,GAC5C,EAAW,QAAQ,IAAI,EAAG,CAAI,EAEpC,GAAI,IAAa,GAAY,IAAS,SAAU,MAAO,GACvD,QAAQ,IAAI,EAAG,EAAM,CAAQ,EAE7B,IAAI,EAAM,EAAW,IAAI,CAAI,EAa7B,GAZK,IACH,EAAM,EAAO,OAAO,CAAQ,EAC5B,EAAW,IAAI,EAAM,CAAG,GAO1B,EAAa,YAAc,IAAA,GAC3B,EAAI,MAAQ,EAER,MAAM,QAAQ,CAAC,GAAK,IAAS,SAAU,CACzC,IAAI,EAAY,EAAW,IAAI,QAAQ,EACnC,IAAW,EAAU,MAAQ,EAAE,OACrC,CACA,MAAO,EACT,CAG8B,CAAO,EAGvC,OAFA,EAAO,WAAW,IAAI,EAAQ,CAAK,EACnC,EAAO,aAAa,IAAI,CAAK,EACtB,CACT"}
@@ -1,2 +0,0 @@
1
- const e=require("./utils/getExtractedValues.cjs");function t(t,n,r,i){let a=i&&typeof i==`object`,o=a?i.name||`unnamed_resource`:i||`unnamed_resource`,s=a?i:{},c=s.resetDataOnSourceChange??!0,l=s.responseValidate,u=s.validateBeforeFetch,d=s.retryCount??0,f=s.timeout??5e3,p=Date.now(),m=t.signal({data:null,loading:!0,error:null,isRetrying:!1,attemptIndex:0,retryCount:d,totalElapsedMs:void 0},`[CORE_INTERNAL_SIGNAL=1]:resource:state:${o}`),h=e=>{t.log({type:`resource`,label:o,details:{to:e,from:m.value}}),m.value=e},g=async(r,i,a=!1)=>{if(i.aborted)return;if(p=Date.now(),u){let e=u(r);if(e===!1||typeof e==`string`){if(i.aborted)return;let n=typeof e==`string`?e:`Pre-fetch validation failed for resource`,r=a?null:t.untrack(()=>m.value.data);h({data:r,loading:!1,error:n,isRetrying:!1,attemptIndex:0,retryCount:d,totalElapsedMs:void 0});return}}let s=a&&c?null:t.untrack(()=>m.value.data);h({data:s,loading:!0,error:null,isRetrying:!1,attemptIndex:0,retryCount:d,totalElapsedMs:void 0});for(let a=0;a<=d;a++){if(i.aborted)return;let s=AbortSignal.timeout(f),c=AbortSignal.any([i,s]);try{let e=await n(r,c);if(i.aborted)return;if(s.aborted)throw new DOMException(`The operation timed out.`,`TimeoutError`);if(l){let t=l(e);if(t===!1||typeof t==`string`){if(i.aborted)return;h({data:null,loading:!1,error:typeof t==`string`?t:`Validation failed`,isRetrying:!1,attemptIndex:0,retryCount:d,totalElapsedMs:void 0});return}}if(i.aborted)return;h({data:e,loading:!1,error:null,isRetrying:!1,attemptIndex:0,retryCount:d,totalElapsedMs:void 0});return}catch(n){let r=s.aborted||n.name===`TimeoutError`||n.message?.includes(`timeout`);if(i.aborted&&!r)return;let c=e.getExtractedValues({tested:[n.message],expectedKey:`THROW_CUSTOM_VALIDATION_ERROR_NO_RETRY`,valueType:`number`})?.[0]===`1`||!1,l=c&&e.getExtractedValues({tested:[n.message],expectedKey:`MESSAGE`,valueType:`string`})?.[0]||`Custom validation error`,u=c||n.name===`ValidationError`;if(a===d||u){if(i.aborted)return;let e=Date.now()-p,o=`${r?`Request timed out after ${f}ms (attempt ${a+1}/${d+1})`:c?l:n instanceof Error?n.message:String(n)}.${t.logger.isCoreOptimizationDebugEnabled?` Всего безуспешных попыток с момента изменения исходного сигнала: ${d+1}.`:``}`;h({data:null,loading:!1,error:o,isRetrying:!1,attemptIndex:a+1,retryCount:d,totalElapsedMs:e});return}else{if(i.aborted)return;let e=1e3*2**a;e=Math.min(e,3e5)+Math.random()*200,h({data:m.value.data,loading:!0,error:null,isRetrying:!0,attemptIndex:a+1,retryCount:d}),t.log({type:`resource`,label:`${o}:retry_scheduled`,details:{payload:{attempt:a+1,total:d,nextDelayMs:Math.round(e)}}}),console.warn(`[Resource Retry] "${o}" сбой по ${r?`таймауту`:`ошибке сети`}. Запрос ${a+1} из ${d+1} не удался. Ожидание повтора: ${Math.round(e)}ms`);try{if(await t.delay(e,i),i.aborted)return}catch{return}}}}},_=null,v=t.effect(()=>{let e=r?r.value:void 0,n=new AbortController;return _=n,t.untrack(()=>{g(e,n.signal,!0)}),()=>n.abort()},`[CORE_INTERNAL_SIGNAL=1]:effect`);return{get data(){return m.value.data},get loading(){return m.value.loading},get error(){return m.value.error},get isRetrying(){return m.value.isRetrying},get value(){return m.value},refetch:()=>{_?.abort(),_=new AbortController,g(r?r.value:void 0,_.signal,!1)},subscribe:e=>m.subscribe(e),destroy:()=>{_?.abort(),_=null,typeof v==`function`&&v(),m.destroy&&m.destroy()}}}exports.createResource=t;
2
- //# sourceMappingURL=core.method.resource.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"core.method.resource.cjs","names":[],"sources":["../src/core/core.method.resource.ts"],"sourcesContent":["import { getExtractedValues } from '../utils/getExtractedValues'\nimport { EngineLoggerOptions, Resource, ResourceOptions, ResourceState, Signal } from './types'\n\n// Контракт ядра движка для безопасных вызовов методов с дженериками\ninterface IReactiveEngine {\n signal<V>(initialValue: V, optionsOrName?: any): Signal<V>;\n effect(fn: () => any, name?: string): () => void;\n untrack<V>(fn: () => V): V;\n log(params: any): void;\n delay(ms: number, signal: AbortSignal): Promise<void>;\n logger: EngineLoggerOptions\n}\n\nexport function createResource<T, S = void>(\n engine: IReactiveEngine,\n fetcher: (source: S, signal: AbortSignal) => Promise<T>,\n source?: { value: S },\n optionsOrName?: string | ResourceOptions<T, S>\n): Resource<T> {\n const isOptionsObject = optionsOrName && typeof optionsOrName === 'object'\n const resourceSignalName = isOptionsObject\n ? ((optionsOrName as ResourceOptions<T, S>).name || 'unnamed_resource')\n : (optionsOrName as string) || 'unnamed_resource'\n\n const options: Partial<ResourceOptions<T, S>> = isOptionsObject\n ? (optionsOrName as ResourceOptions<T, S>)\n : {}\n\n const resetDataOnSourceChange = options.resetDataOnSourceChange ?? true\n const responseValidate = options.responseValidate\n const validateBeforeFetch = options.validateBeforeFetch\n const baseDelay = 1000\n const useExponential = true\n const maxRetryDelay = 1000 * 60 * 5\n\n const retryCount = options.retryCount ?? 0\n const timeoutMs = options.timeout ?? 5000\n // Запоминаем точное время старта ВСЕЙ цепочки (включая ретраи и паузы)\n let startTime = Date.now()\n\n const state = engine.signal<ResourceState<T>>(\n {\n data: null,\n loading: true,\n error: null,\n isRetrying: false,\n attemptIndex: 0,\n retryCount,\n totalElapsedMs: undefined // Сбрасываем старый таймер\n },\n `[CORE_INTERNAL_SIGNAL=1]:resource:state:${resourceSignalName}`\n )\n\n const updateResourceState = (nextState: ResourceState<T>) => {\n engine.log({\n type: 'resource',\n label: resourceSignalName,\n details: { to: nextState, from: state.value },\n })\n state.value = nextState\n }\n\n const load = async (sValue: S, effectSignal: AbortSignal, isSourceChange = false) => {\n if (effectSignal.aborted) return\n\n // Фиксируем время старта бизнес-процесса в самом начале метода load\n startTime = Date.now()\n\n if (validateBeforeFetch) {\n const preValidationResult = validateBeforeFetch(sValue)\n if (preValidationResult === false || typeof preValidationResult === 'string') {\n if (effectSignal.aborted) return\n const errorMsg = typeof preValidationResult === 'string'\n ? preValidationResult\n : 'Pre-fetch validation failed for resource'\n\n const currentData = isSourceChange ? null : engine.untrack(() => state.value.data)\n // Явно зачищаем следы старого таймера при ошибке валидации аргументов\n updateResourceState({\n data: currentData,\n loading: false,\n error: errorMsg,\n isRetrying: false,\n attemptIndex: 0,\n retryCount,\n totalElapsedMs: undefined\n })\n return\n }\n }\n\n const shouldClear = isSourceChange && resetDataOnSourceChange\n const currentData = shouldClear ? null : engine.untrack(() => state.value.data)\n\n // Принудительно сбрасываем таймер в undefined перед входом в цикл ретраев\n updateResourceState({\n data: currentData,\n loading: true,\n error: null,\n isRetrying: false,\n attemptIndex: 0,\n retryCount,\n totalElapsedMs: undefined\n })\n\n // 🔄 Контур циклического выполнения попыток (от 0 до retryCount)\n for (let attempt = 0; attempt <= retryCount; attempt++) {\n if (effectSignal.aborted) return\n\n // Создаем персональный сигнал таймаута на эту конкретную попытку\n const timeoutSignal = AbortSignal.timeout(timeoutMs)\n\n // Объединяем управляющий сигнал графа и наш таймаут\n const combinedSignal = AbortSignal.any([effectSignal, timeoutSignal])\n\n try {\n const data = await fetcher(sValue, combinedSignal)\n\n if (effectSignal.aborted) return\n\n // Если фетчер вернул управление, но таймаут успел отработать раньше\n if (timeoutSignal.aborted) {\n throw new DOMException('The operation timed out.', 'TimeoutError')\n }\n\n if (responseValidate) {\n const validationResult = responseValidate(data)\n if (validationResult === false || typeof validationResult === 'string') {\n if (effectSignal.aborted) return\n const errorMsg = typeof validationResult === 'string' ? validationResult : 'Validation failed'\n updateResourceState({\n data: null,\n loading: false,\n error: errorMsg,\n isRetrying: false,\n attemptIndex: 0,\n retryCount,\n totalElapsedMs: undefined\n })\n return\n }\n }\n\n if (effectSignal.aborted) return\n // Успех: сохраняем данные, полностью очищаем ошибки и сквозной таймер\n updateResourceState({\n data,\n loading: false,\n error: null,\n isRetrying: false,\n attemptIndex: 0,\n retryCount,\n totalElapsedMs: undefined\n })\n return\n\n } catch (e: unknown) {\n // 1. Выявляем, произошел ли сбой по таймауту\n const isTimeout = timeoutSignal.aborted ||\n (e as Error).name === 'TimeoutError' ||\n (e as Error).message?.includes('timeout')\n\n // Если это обычная отмена дебаунсом из внешнего контура, мгновенно прекращаем работу\n if (effectSignal.aborted && !isTimeout) return\n\n // 2. Безопасно извлекаем валидационные маркеры до их использования в условиях\n const isCustomValidationError = getExtractedValues({\n tested: [(e as Error).message], expectedKey: 'THROW_CUSTOM_VALIDATION_ERROR_NO_RETRY', valueType: 'number',\n })?.[0] === '1' || false\n\n const __defaultCustomValidationErrorMessage = 'Custom validation error'\n const customValidationErrorMessage: string = isCustomValidationError\n ? (getExtractedValues({\n tested: [(e as Error).message], expectedKey: 'MESSAGE', valueType: 'string',\n })?.[0] || __defaultCustomValidationErrorMessage)\n : __defaultCustomValidationErrorMessage\n\n const isFetchBodyValidationError = isCustomValidationError || (e as Error).name === 'ValidationError'\n\n // Если попытки исчерпаны ИЛИ это валидационная ошибка тела, которая не подлежит повтору\n if (attempt === retryCount || isFetchBodyValidationError) {\n if (effectSignal.aborted) return\n\n // Считаем суммарное время от первого клика/сдвига карты до текущего момента\n const totalElapsedMs = Date.now() - startTime\n\n // Переменная customValidationErrorMessage теперь гарантированно определена выше!\n const baseErrorMsg = isTimeout\n ? `Request timed out after ${timeoutMs}ms (attempt ${attempt + 1}/${retryCount + 1})`\n : isCustomValidationError\n ? customValidationErrorMessage\n : e instanceof Error ? e.message : String(e)\n\n // Формируем детальное сообщение для вывода в UI\n const finalErrorMessage = `${baseErrorMsg}.${engine.logger.isCoreOptimizationDebugEnabled ? ` Всего безуспешных попыток с момента изменения исходного сигнала: ${retryCount + 1}.` : ''}`\n\n updateResourceState({\n data: null,\n loading: false,\n error: finalErrorMessage,\n isRetrying: false,\n attemptIndex: attempt + 1, // Выводим финальное число сделанных попыток\n retryCount,\n totalElapsedMs,\n })\n return\n } else {\n // Инициализируем планирование следующей попытки (Retry Backoff Phase)\n if (effectSignal.aborted) return\n\n let currentDelay = useExponential ? baseDelay * Math.pow(2, attempt) : baseDelay\n currentDelay = Math.min(currentDelay, maxRetryDelay) + Math.random() * 200\n\n updateResourceState({\n data: state.value.data,\n loading: true,\n error: null,\n isRetrying: true,\n attemptIndex: attempt + 1, // Индекс следующей накатываемой попытки для UI (1, 2, 3...)\n retryCount\n })\n\n engine.log({\n type: 'resource',\n label: `${resourceSignalName}:retry_scheduled`,\n details: { payload: { attempt: attempt + 1, total: retryCount, nextDelayMs: Math.round(currentDelay) } }\n })\n\n const logReason = isTimeout ? 'таймауту' : 'ошибке сети'\n // Исправлен счетчик: пишем честный индекс текущего упавшего запроса из общего пула\n console.warn(`[Resource Retry] \"${resourceSignalName}\" сбой по ${logReason}. Запрос ${attempt + 1} из ${retryCount + 1} не удался. Ожидание повтора: ${Math.round(currentDelay)}ms`)\n\n try {\n // Спим перед следующим циклом, уважая отмену внешнего графа\n await engine.delay(currentDelay, effectSignal)\n if (effectSignal.aborted) return\n } catch (delayError) {\n return\n }\n }\n }\n }\n }\n\n let activeEffectController: AbortController | null = null\n\n const disposeInternalEffect = engine.effect(() => {\n const sValue = source ? source.value : undefined as S\n const effectController = new AbortController()\n activeEffectController = effectController\n\n engine.untrack(() => {\n load(sValue as S, effectController.signal, true)\n })\n\n return () => effectController.abort()\n }, '[CORE_INTERNAL_SIGNAL=1]:effect')\n\n return {\n get data() { return state.value.data },\n get loading() { return state.value.loading },\n get error() { return state.value.error },\n get isRetrying() { return state.value.isRetrying },\n get value() { return state.value },\n refetch: () => {\n activeEffectController?.abort()\n activeEffectController = new AbortController()\n load(source ? source.value : undefined as S, activeEffectController.signal, false)\n },\n subscribe: (cb: (val: ResourceState<T>) => void) => state.subscribe(cb),\n destroy: () => {\n activeEffectController?.abort()\n activeEffectController = null\n if (typeof disposeInternalEffect === 'function') {\n disposeInternalEffect()\n }\n if ((state as any).destroy) {\n (state as any).destroy()\n }\n }\n } as any\n}\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- const e=require("./utils/getExtractedValues.cjs");function t(t,n,r){let i=n,a=0,o=typeof r==`string`?r:r?.name,s=!!o&&e.getExtractedValues({tested:[o],expectedKey:`CORE_INTERNAL_SIGNAL`,valueType:`number`})?.[0]===`1`||!1,c=new Set,l=!1,u=n,d={type:`signal`,get version(){return a},subscribers:c},f=()=>{for(let e of c){let n=e._node||e;if(n.type===`effect`)n.isDirty=!0,t.scheduleEffect(e);else if(n.type===`computed`)n.markDirty&&n.markDirty(2);else if(typeof e==`function`)try{e(i)}catch(e){console.error(e)}else if(e&&typeof e.run==`function`)try{e.run()}catch(e){console.error(e)}}},p={get value(){let e=t.activeConsumer;return e&&e.dependencies&&typeof e.dependencies.add==`function`&&(c.add(e),e.dependencies.add(p),e.activeRunId!==void 0&&(p._lastSeenInRunId=e.activeRunId)),i},set value(e){if(Object.is(i,e)&&!(i===e&&typeof i==`object`&&i))return;if(r&&typeof r==`object`&&r.validate){let t=r.validate(e);if(t!==!0){console.error(typeof t==`string`?t:`[Validation Error]`);return}}if(t.batchDepth>0){l||(l=!0,u=i),i=e,t.batchedSignals.add(p);return}let n=i;i=e,a++,t.epoch++,t.log({type:`signal`,label:o||`signal`,details:{from:n,to:e},isInternalCoreSignal:s}),f(),t.batchDepth===0&&t.flushEffects()},get version(){return a},type:`signal`,subscribe(e){return c.add(e),e(i),()=>{c.delete(e)}},_flushBatch:()=>{if(l){if(!Object.is(u,i)||typeof i==`object`&&i){a++,t.epoch++,t.log({type:`signal`,label:o||`signal_batched`,details:{from:u,to:i},isInternalCoreSignal:s});for(let e of c){let n=e._node||e;if(n.type===`effect`)n.isDirty=!0,t.scheduleEffect(e);else if(n.markDirty)n.markDirty(2);else if(typeof e==`function`)try{e(i)}catch(e){console.error(e)}}}l=!1,u=i}},get hasBatchValue(){return l},destroy:()=>{c&&c.clear(),t.batchedSignals&&t.batchedSignals.delete(p),l=!1,i=void 0,u=void 0}};return p._node=d,p.subscribers=c,p}exports.createSignal=t;
2
- //# sourceMappingURL=core.method.signal.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"core.method.signal.cjs","names":[],"sources":["../src/core/core.method.signal.ts"],"sourcesContent":["import { getExtractedValues } from '../utils/getExtractedValues'\nimport { Signal, SignalOptions } from './types'\n\nexport function createSignal<T>(\n engine: any,\n initialValue: T,\n optionsOrName?: SignalOptions<T> | string\n): Signal<T> {\n let value = initialValue\n let version = 0\n let name = typeof optionsOrName === 'string' ? optionsOrName : optionsOrName?.name\n const isInternalCoreSignal = !!name && getExtractedValues({\n tested: [name],\n expectedKey: 'CORE_INTERNAL_SIGNAL',\n valueType: 'number',\n })?.[0] === '1' || false\n const subscribers = new Set<any>()\n\n let hasBatchValue = false\n let batchInitialValue: T = initialValue\n\n const signalNode = {\n type: 'signal',\n get version() { return version },\n subscribers\n }\n\n const notifySubscribers = () => {\n for (const sub of subscribers) {\n const rawSub = sub._node || sub\n if (rawSub.type === 'effect') {\n rawSub.isDirty = true\n engine.scheduleEffect(sub)\n } else if (rawSub.type === 'computed') {\n if (rawSub.markDirty) rawSub.markDirty(2)\n } else {\n if (typeof sub === 'function') {\n try { sub(value) } catch (err) { console.error(err) }\n } else if (sub && typeof sub.run === 'function') {\n try { sub.run() } catch (err) { console.error(err) }\n }\n }\n }\n }\n\n const signalInstance: Signal<T> = {\n get value() {\n // 🛡️ АТОМАРНАЯ ЗАЩИТА: Работаем строго с локально зафиксированной константой consumer\n const consumer = engine.activeConsumer\n if (consumer) {\n if (consumer.dependencies && typeof consumer.dependencies.add === 'function') {\n subscribers.add(consumer)\n consumer.dependencies.add(signalInstance)\n\n if (consumer.activeRunId !== undefined) {\n (signalInstance as any)._lastSeenInRunId = consumer.activeRunId\n }\n }\n }\n return value\n },\n set value(newValue: T) {\n const isObjectKick = value === newValue && value !== null && typeof value === 'object'\n if (Object.is(value, newValue) && !isObjectKick) return\n\n if (optionsOrName && typeof optionsOrName === 'object' && optionsOrName.validate) {\n const validation = optionsOrName.validate(newValue)\n if (validation !== true) {\n console.error(typeof validation === 'string' ? validation : '[Validation Error]')\n return\n }\n }\n\n if (engine.batchDepth > 0) {\n if (!hasBatchValue) {\n hasBatchValue = true\n batchInitialValue = value\n }\n value = newValue\n engine.batchedSignals.add(signalInstance)\n return\n }\n\n const oldValue = value\n value = newValue\n\n version++\n engine.epoch++\n\n engine.log({\n type: 'signal',\n label: name || 'signal',\n details: { from: oldValue, to: newValue },\n isInternalCoreSignal\n })\n\n notifySubscribers()\n if (engine.batchDepth === 0) engine.flushEffects()\n },\n\n get version() { return version },\n type: 'signal',\n\n subscribe(cb: (val: T) => void) {\n subscribers.add(cb)\n cb(value)\n return () => { subscribers.delete(cb) }\n },\n\n _flushBatch: () => {\n if (!hasBatchValue) return\n\n const wasChanged = !Object.is(batchInitialValue, value) || (value !== null && typeof value === 'object')\n\n if (wasChanged) {\n version++\n engine.epoch++\n\n engine.log({\n type: 'signal',\n label: name || 'signal_batched',\n details: { from: batchInitialValue, to: value },\n isInternalCoreSignal\n })\n\n for (const sub of subscribers) {\n const rawSub = sub._node || sub\n if (rawSub.type === 'effect') {\n rawSub.isDirty = true\n engine.scheduleEffect(sub)\n } else if (rawSub.markDirty) {\n rawSub.markDirty(2)\n } else if (typeof sub === 'function') {\n try { sub(value) } catch (err) { console.error(err) }\n }\n }\n }\n\n hasBatchValue = false\n batchInitialValue = value\n },\n\n get hasBatchValue() { return hasBatchValue },\n\n destroy: () => {\n if (subscribers) {\n subscribers.clear()\n }\n if (engine.batchedSignals) {\n engine.batchedSignals.delete(signalInstance)\n }\n hasBatchValue = false\n value = undefined as any\n batchInitialValue = undefined as any\n }\n } as any\n\n ;(signalInstance as any)._node = signalNode\n ;(signalInstance as any).subscribers = subscribers\n return signalInstance\n}\n"],"mappings":"kDAGA,SAAgB,EACd,EACA,EACA,EACW,CACX,IAAI,EAAQ,EACR,EAAU,EACV,EAAO,OAAO,GAAkB,SAAW,EAAgB,GAAe,KACxE,EAAuB,CAAC,CAAC,GAAQ,EAAA,mBAAmB,CACxD,OAAQ,CAAC,CAAI,EACb,YAAa,uBACb,UAAW,QACb,CAAC,CAAC,GAAG,KAAO,KAAO,GACb,EAAc,IAAI,IAEpB,EAAgB,GAChB,EAAuB,EAErB,EAAa,CACjB,KAAM,SACN,IAAI,SAAU,CAAE,OAAO,CAAQ,EAC/B,aACF,EAEM,MAA0B,CAC9B,IAAK,IAAM,KAAO,EAAa,CAC7B,IAAM,EAAS,EAAI,OAAS,EAC5B,GAAI,EAAO,OAAS,SAClB,EAAO,QAAU,GACjB,EAAO,eAAe,CAAG,OACpB,GAAI,EAAO,OAAS,WACrB,EAAO,WAAW,EAAO,UAAU,CAAC,OAExC,GAAI,OAAO,GAAQ,WACjB,GAAI,CAAE,EAAI,CAAK,CAAE,OAAS,EAAK,CAAE,QAAQ,MAAM,CAAG,CAAE,MAC/C,GAAI,GAAO,OAAO,EAAI,KAAQ,WACnC,GAAI,CAAE,EAAI,IAAI,CAAE,OAAS,EAAK,CAAE,QAAQ,MAAM,CAAG,CAAE,CAGzD,CACF,EAEM,EAA4B,CAChC,IAAI,OAAQ,CAEV,IAAM,EAAW,EAAO,eAWxB,OAVI,GACE,EAAS,cAAgB,OAAO,EAAS,aAAa,KAAQ,aAChE,EAAY,IAAI,CAAQ,EACxB,EAAS,aAAa,IAAI,CAAc,EAEpC,EAAS,cAAgB,IAAA,KAC3B,EAAwB,iBAAmB,EAAS,cAInD,CACT,EACA,IAAI,MAAM,EAAa,CAErB,GAAI,OAAO,GAAG,EAAO,CAAQ,GAAK,EADb,IAAU,GAA8B,OAAO,GAAU,UAAnC,GACM,OAEjD,GAAI,GAAiB,OAAO,GAAkB,UAAY,EAAc,SAAU,CAChF,IAAM,EAAa,EAAc,SAAS,CAAQ,EAClD,GAAI,IAAe,GAAM,CACvB,QAAQ,MAAM,OAAO,GAAe,SAAW,EAAa,oBAAoB,EAChF,MACF,CACF,CAEA,GAAI,EAAO,WAAa,EAAG,CACpB,IACH,EAAgB,GAChB,EAAoB,GAEtB,EAAQ,EACR,EAAO,eAAe,IAAI,CAAc,EACxC,MACF,CAEA,IAAM,EAAW,EACjB,EAAQ,EAER,IACA,EAAO,QAEP,EAAO,IAAI,CACT,KAAM,SACN,MAAO,GAAQ,SACf,QAAS,CAAE,KAAM,EAAU,GAAI,CAAS,EACxC,sBACF,CAAC,EAED,EAAkB,EACd,EAAO,aAAe,GAAG,EAAO,aAAa,CACnD,EAEA,IAAI,SAAU,CAAE,OAAO,CAAQ,EAC/B,KAAM,SAEN,UAAU,EAAsB,CAG9B,OAFA,EAAY,IAAI,CAAE,EAClB,EAAG,CAAK,MACK,CAAE,EAAY,OAAO,CAAE,CAAE,CACxC,EAEA,gBAAmB,CACZ,KAIL,IAFmB,CAAC,OAAO,GAAG,EAAmB,CAAK,GAAwB,OAAO,GAAU,UAAnC,EAE5C,CACd,IACA,EAAO,QAEP,EAAO,IAAI,CACT,KAAM,SACN,MAAO,GAAQ,iBACf,QAAS,CAAE,KAAM,EAAmB,GAAI,CAAM,EAC9C,sBACF,CAAC,EAED,IAAK,IAAM,KAAO,EAAa,CAC7B,IAAM,EAAS,EAAI,OAAS,EAC5B,GAAI,EAAO,OAAS,SAClB,EAAO,QAAU,GACjB,EAAO,eAAe,CAAG,OACpB,GAAI,EAAO,UAChB,EAAO,UAAU,CAAC,OACb,GAAI,OAAO,GAAQ,WACxB,GAAI,CAAE,EAAI,CAAK,CAAE,OAAS,EAAK,CAAE,QAAQ,MAAM,CAAG,CAAE,CAExD,CACF,CAEA,EAAgB,GAChB,EAAoB,CAHpB,CAIF,EAEA,IAAI,eAAgB,CAAE,OAAO,CAAc,EAE3C,YAAe,CACT,GACF,EAAY,MAAM,EAEhB,EAAO,gBACT,EAAO,eAAe,OAAO,CAAc,EAE7C,EAAgB,GAChB,EAAQ,IAAA,GACR,EAAoB,IAAA,EACtB,CACF,EAIA,MAFC,GAAwB,MAAQ,EAChC,EAAwB,YAAc,EAChC,CACT"}
@@ -1,2 +0,0 @@
1
- function e(e,t){let n=e.activeConsumer;e.activeConsumer=null;try{return t()}finally{e.activeConsumer=n}}exports.executeUntrack=e;
2
- //# sourceMappingURL=core.method.untrack.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"core.method.untrack.cjs","names":[],"sources":["../src/core/core.method.untrack.ts"],"sourcesContent":["/**\n * Изолированный менеджер контекста untrack реактивного графа.\n * Временно замораживает автоматический сбор зависимостей, подменяя activeConsumer на null.\n */\nexport function executeUntrack<T>(engine: any, fn: () => T): T {\n const prevConsumer = engine.activeConsumer\n engine.activeConsumer = null\n try {\n return fn()\n } finally {\n engine.activeConsumer = prevConsumer\n }\n}\n"],"mappings":"AAIA,SAAgB,EAAkB,EAAa,EAAgB,CAC7D,IAAM,EAAe,EAAO,eAC5B,EAAO,eAAiB,KACxB,GAAI,CACF,OAAO,EAAG,CACZ,QAAU,CACR,EAAO,eAAiB,CAC1B,CACF"}
@@ -1,2 +0,0 @@
1
- var e=(e,t={})=>{let n=t.ttl??300*1e3,r=new Map,i=new Map;return(t,a)=>{let o=typeof t==`object`&&t?JSON.stringify(t):String(t);if(a.aborted)return Promise.reject(a.reason||Error(`Aborted`));let s=Date.now(),c=r.get(o);if(c&&s-c.timestamp<n)return Promise.resolve(c.data);if(i.has(o)){let e=i.get(o);return new Promise((t,n)=>{let r=()=>n(a.reason||Error(`Aborted`));a.addEventListener(`abort`,r),e.then(t).catch(n).finally(()=>a.removeEventListener(`abort`,r))})}let l=e(t,a);return i.set(o,l),new Promise((e,t)=>{let n=()=>{i.delete(o),t(a.reason||Error(`Aborted`))};a.addEventListener(`abort`,n),l.then(t=>{r.set(o,{data:t,timestamp:Date.now()}),e(t)}).catch(e=>{t(e)}).finally(()=>{i.delete(o),a.removeEventListener(`abort`,n)})})}};exports.withCache=e;
2
- //# sourceMappingURL=withCache.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"withCache.cjs","names":[],"sources":["../../../src/decorators/withCache/withCache.ts"],"sourcesContent":["import { CacheOptions, CacheEntry } from './types'\n\n/**\n * 📦 DECORATOR: withCache (v1.9.0)\n *\n * Продвинутый декоратор кэширования асинхронных фабрик и фетчеров.\n * Нативно предотвращает Race Conditions и дублирование параллельных запросов (Request Collapsing).\n */\nexport const withCache = <S, T>(\n fetcher: (source: S, signal: AbortSignal) => Promise<T>,\n options: CacheOptions = {}\n) => {\n const ttl = options.ttl ?? 5 * 60 * 1000 // Дефолтный TTL: 5 минут\n\n // Хранилище готовых данных\n const dataCache = new Map<string, CacheEntry<T>>()\n // Хранилище активных Promise для склеивания параллельного спама!\n const activePromises = new Map<string, Promise<T>>()\n\n return (source: S, signal: AbortSignal): Promise<T> => {\n // 1. Генерируем детерминированный ключ кэша\n const cacheKey = typeof source === 'object' && source !== null\n ? JSON.stringify(source)\n : String(source)\n\n // Если AbortSignal уже отменен на старте — мгновенно прерываем цепочку\n if (signal.aborted) {\n return Promise.reject(signal.reason || new Error('Aborted'))\n }\n\n const now = Date.now()\n const cached = dataCache.get(cacheKey)\n\n // 2. СЦЕНАРИЙ А: Есть валидный, не устаревший кэш данных\n if (cached && (now - cached.timestamp < ttl)) {\n return Promise.resolve(cached.data)\n }\n\n // 3. СЦЕНАРИЙ Б: Запрос с таким ключом ПРЯМО СЕЙЧАС идет в сеть (Request Collapsing)\n // Вместо запуска второго фетчера, отдаем тот же самый Promise текущего такта!\n if (activePromises.has(cacheKey)) {\n const existingPromise = activePromises.get(cacheKey)!\n\n // Навешиваем слушатель отмены текущего сигнала на общий Promise\n return new Promise<T>((resolve, reject) => {\n const onAbort = () => reject(signal.reason || new Error('Aborted'))\n signal.addEventListener('abort', onAbort)\n\n existingPromise\n .then(resolve)\n .catch(reject)\n .finally(() => signal.removeEventListener('abort', onAbort))\n })\n }\n\n // 4. СЦЕНАРИЙ В: Кэша нет или он устарел — инициируем новую транзакцию\n const promise = fetcher(source, signal)\n activePromises.set(cacheKey, promise)\n\n const executionPromise = new Promise<T>((resolve, reject) => {\n const onAbort = () => {\n activePromises.delete(cacheKey)\n reject(signal.reason || new Error('Aborted'))\n }\n signal.addEventListener('abort', onAbort)\n\n promise\n .then((freshData) => {\n // Сохраняем завершенные данные и метку времени в кэш\n dataCache.set(cacheKey, {\n data: freshData,\n timestamp: Date.now()\n })\n resolve(freshData)\n })\n .catch((err) => {\n reject(err)\n })\n .finally(() => {\n // Чистим активный промис, открывая дорогу для последующих TTL-обновлений\n activePromises.delete(cacheKey)\n signal.removeEventListener('abort', onAbort)\n })\n })\n\n return executionPromise\n }\n}\n"],"mappings":"AAQA,IAAa,GACX,EACA,EAAwB,CAAC,IACtB,CACH,IAAM,EAAM,EAAQ,KAAO,IAAS,IAG9B,EAAY,IAAI,IAEhB,EAAiB,IAAI,IAE3B,OAAQ,EAAW,IAAoC,CAErD,IAAM,EAAW,OAAO,GAAW,UAAY,EAC3C,KAAK,UAAU,CAAM,EACrB,OAAO,CAAM,EAGjB,GAAI,EAAO,QACT,OAAO,QAAQ,OAAO,EAAO,QAAc,MAAM,SAAS,CAAC,EAG7D,IAAM,EAAM,KAAK,IAAI,EACf,EAAS,EAAU,IAAI,CAAQ,EAGrC,GAAI,GAAW,EAAM,EAAO,UAAY,EACtC,OAAO,QAAQ,QAAQ,EAAO,IAAI,EAKpC,GAAI,EAAe,IAAI,CAAQ,EAAG,CAChC,IAAM,EAAkB,EAAe,IAAI,CAAQ,EAGnD,OAAO,IAAI,SAAY,EAAS,IAAW,CACzC,IAAM,MAAgB,EAAO,EAAO,QAAc,MAAM,SAAS,CAAC,EAClE,EAAO,iBAAiB,QAAS,CAAO,EAExC,EACG,KAAK,CAAO,CAAC,CACb,MAAM,CAAM,CAAC,CACb,YAAc,EAAO,oBAAoB,QAAS,CAAO,CAAC,CAC/D,CAAC,CACH,CAGA,IAAM,EAAU,EAAQ,EAAQ,CAAM,EA6BtC,OA5BA,EAAe,IAAI,EAAU,CAAO,EA4B7B,IA1BsB,SAAY,EAAS,IAAW,CAC3D,IAAM,MAAgB,CACpB,EAAe,OAAO,CAAQ,EAC9B,EAAO,EAAO,QAAc,MAAM,SAAS,CAAC,CAC9C,EACA,EAAO,iBAAiB,QAAS,CAAO,EAExC,EACG,KAAM,GAAc,CAEnB,EAAU,IAAI,EAAU,CACtB,KAAM,EACN,UAAW,KAAK,IAAI,CACtB,CAAC,EACD,EAAQ,CAAS,CACnB,CAAC,CAAC,CACD,MAAO,GAAQ,CACd,EAAO,CAAG,CACZ,CAAC,CAAC,CACD,YAAc,CAEb,EAAe,OAAO,CAAQ,EAC9B,EAAO,oBAAoB,QAAS,CAAO,CAC7C,CAAC,CACL,CAEO,CACT,CACF"}
@@ -1,2 +0,0 @@
1
- var e=(e,t={})=>{let n=t.delay??300,r=null,i=null;return(t,a)=>(r&&clearTimeout(r),i&&i(new DOMException(`Aborted due to debounce`,`AbortError`)),new Promise((o,s)=>{i=s;let c=()=>{r&&clearTimeout(r),s(new DOMException(`Aborted by resource signal`,`AbortError`))};if(a.aborted)return c();a.addEventListener(`abort`,c),r=setTimeout(async()=>{a.removeEventListener(`abort`,c),i=null,r=null;try{o(await e(t,a))}catch(e){s(e)}},n)}))};exports.withDebounce=e;
2
- //# sourceMappingURL=withDebounce.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"withDebounce.cjs","names":[],"sources":["../../../src/decorators/withDebounce/withDebounce.ts"],"sourcesContent":["interface DebounceOptions {\n /** Задержка в миллисекундах. По умолчанию 300 мс */\n delay?: number;\n}\n\n/**\n * Декоратор для создания дебаунсящего (отложенного) загрузчика данных, специально\n * адаптированный для использования совместно с `engine.resource`.\n *\n * Откладывает выполнение асинхронной функции `fetcher` на заданную задержку `options.delay`.\n * Если в течение этого интервала происходит новый вызов (например, пользователь продолжает вводить текст),\n * таймер сбрасывается, а предыдущий ожидающий промис принудительно отклоняется. В итоге выполняется\n * только один запрос — после того, как поток вызовов затихнет.\n *\n * ### 🧠 Механика управления промисами (Контур Debounce):\n * 1. **Сброс дребезга:** При каждом вызове функции проверяется наличие активного таймера. Если он есть,\n * `clearTimeout` мгновенно останавливает его.\n * 2. **Каскадное отклонение:** Ссылка на метод `reject` каждого создаваемого промиса сохраняется в `rejectPrevious`.\n * При поступлении нового запроса предыдущий промис не остается «зависшим», а принудительно переходит\n * в состояние `rejected` с ошибкой `AbortError`. Это сигнализирует ядру, что данные устарели.\n * 3. **Чистый запуск:** Оригинальный `fetcher` вызывается только тогда, когда таймер успешно дотикал до конца,\n * не будучи прерванным.\n *\n * @template S Тип входных данных (аргументов) для функции запроса.\n * @template T Тип данных, возвращаемых асинхронным `fetcher`-ом (разрешенное значение промиса).\n *\n * @param {(source: S, signal: AbortSignal) => Promise<T>} fetcher Оригинальная асинхронная функция запроса, принимающая параметры и сигнал отмены.\n * @param {DebounceOptions} [options={}] Параметры конфигурации дебаунса.\n * @param {number} [options.delay=300] Время ожидания в миллисекундах с момента последнего вызова до фактического старта запроса.\n *\n * @returns {(source: S, signal: AbortSignal) => Promise<T>} Возвращает обернутую дебаунс-функцию, возвращающую `Promise<T>` и полностью сохраняющую исходную сигнатуру типов.\n *\n * @example\n * ```typescript\n * import { withDebounce } from '@pravosleva/reactive-engine';\n *\n * const searchProducts = async (query: string, signal: AbortSignal) => {\n * const res = await fetch(`/api/products?search=${encodeURIComponent(query)}`, { signal });\n * return res.json();\n * };\n *\n * // Запрос уйдет только через 400мс после того, как пользователь перестанет нажимать клавиши\n * const debouncedFetch = withDebounce(searchProducts, { delay: 400 });\n *\n * // Интеграция с фабрикой ресурсов вашего реактивного ядра\n * const productSearchResource = engine.resource(\n * fetcher: debouncedFetch,\n * source: () => searchInputValue.value // Следит за сигналом строки ввода\n * );\n * ```\n *\n * @abstract\n * ### 🚨 Сквозная интеграция с AbortSignal и менеджмент памяти\n * Декоратор непрерывно отслеживает состояние нативного `AbortSignal`, передаваемого движком (например, при размонтировании UI-виджета):\n * - Если сигнал переходит в состояние `aborted` во время отсчета таймаута дебаунса, таймер сбрасывается,\n * а промис мгновенно отклоняется.\n * - При успешном выполнении таймера слушатель `abort` своевременно удаляется через `removeEventListener`,\n * исключая накопление холостых подписок.\n * - Все внутренние ссылки на методы разрешения промисов (`rejectPrevious`, `timeoutId`) принудительно зануляются (`null`),\n * очищая замыкания от застрявших в памяти объектов и защищая Node.js/браузер от утечек.\n */\nexport const withDebounce = <S, T>(\n fetcher: (source: S, signal: AbortSignal) => Promise<T>,\n options: DebounceOptions = {}\n) => {\n const delay = options.delay ?? 300\n\n // Храним ссылку на активный таймер текущего ожидания\n let timeoutId: ReturnType<typeof setTimeout> | null = null\n // Храним функцию отмены для предыдущего неоконченного промиса ожидания\n let rejectPrevious: ((reason: any) => void) | null = null\n\n return (source: S, signal: AbortSignal): Promise<T> => {\n // 1. Если уже идет ожидание другого запроса — отменяем его промис и очищаем таймер\n if (timeoutId) {\n clearTimeout(timeoutId)\n }\n if (rejectPrevious) {\n // Бросаем DOMException, имитируя нативную отмену fetch, чтобы движок понял, что запрос прерван\n rejectPrevious(new DOMException('Aborted due to debounce', 'AbortError'))\n }\n\n return new Promise<T>((resolve, reject) => {\n // Сохраняем ссылку на reject текущего промиса, чтобы его мог отменить следующий вызов\n rejectPrevious = reject\n\n // 2. Слушаем нативный AbortSignal от движка (например, если компонент размонтировался во время дебаунса)\n const onAbort = () => {\n if (timeoutId) clearTimeout(timeoutId)\n reject(new DOMException('Aborted by resource signal', 'AbortError'))\n }\n\n if (signal.aborted) {\n return onAbort()\n }\n signal.addEventListener('abort', onAbort)\n\n // 3. Взводим отложенный таймер выполнения\n timeoutId = setTimeout(async () => {\n // Убираем слушатель, так как таймаут успешно дождался конца\n signal.removeEventListener('abort', onAbort)\n rejectPrevious = null\n timeoutId = null\n\n try {\n // 4. Запускаем оригинальный fetcher\n const data = await fetcher(source, signal)\n resolve(data)\n } catch (error) {\n reject(error)\n }\n }, delay)\n })\n }\n}\n"],"mappings":"AA6DA,IAAa,GACX,EACA,EAA2B,CAAC,IACzB,CACH,IAAM,EAAQ,EAAQ,OAAS,IAG3B,EAAkD,KAElD,EAAiD,KAErD,OAAQ,EAAW,KAEb,GACF,aAAa,CAAS,EAEpB,GAEF,EAAe,IAAI,aAAa,0BAA2B,YAAY,CAAC,EAGnE,IAAI,SAAY,EAAS,IAAW,CAEzC,EAAiB,EAGjB,IAAM,MAAgB,CAChB,GAAW,aAAa,CAAS,EACrC,EAAO,IAAI,aAAa,6BAA8B,YAAY,CAAC,CACrE,EAEA,GAAI,EAAO,QACT,OAAO,EAAQ,EAEjB,EAAO,iBAAiB,QAAS,CAAO,EAGxC,EAAY,WAAW,SAAY,CAEjC,EAAO,oBAAoB,QAAS,CAAO,EAC3C,EAAiB,KACjB,EAAY,KAEZ,GAAI,CAGF,EAAQ,MADW,EAAQ,EAAQ,CAAM,CAC7B,CACd,OAAS,EAAO,CACd,EAAO,CAAK,CACd,CACF,EAAG,CAAK,CACV,CAAC,EAEL"}
@@ -1,2 +0,0 @@
1
- var e=(e,t)=>{let{onNextTick:n,onError:r,externalSignal:i,delay:a=500,errorInitialDelay:o=2e3,errorMaxDelay:s=8e3}=t,c=o,l=0;return(t,u)=>{let d=++l;return new Promise((f,p)=>{let m=async()=>{if(u.aborted||i?.aborted){p(new DOMException(`Aborted by long polling lifecycle`,`AbortError`));return}try{let r=await e(t,u);if(c=o,u.aborted||i?.aborted){p(new DOMException(`Aborted by long polling lifecycle`,`AbortError`));return}f(r),setTimeout(()=>{d===l&&!u.aborted&&!i?.aborted&&n?.()},a)}catch(e){if(e instanceof DOMException&&e.name===`AbortError`){p(e);return}p(e);let t=c;typeof r==`function`&&r(t,()=>{d===l&&(c=Math.min(c*2,s))}),setTimeout(()=>{d===l&&!u.aborted&&!i?.aborted&&n?.()},t)}},h=()=>{p(new DOMException(`Aborted by lifecycle event`,`AbortError`))};if(u.addEventListener(`abort`,h),i&&i.addEventListener(`abort`,h),u.aborted||i?.aborted)return h();m()})}};exports.withLongPolling=e;
2
- //# sourceMappingURL=withLongPolling.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"withLongPolling.cjs","names":[],"sources":["../../../src/decorators/withLongPolling/withLongPolling.ts"],"sourcesContent":["interface LongPollingOptions {\n /** Коллбэк для инкремента реактивного тика (перехода на следующую итерацию поллинга) */\n onNextTick: () => void;\n\n /**\n * Коллбэк, вызываемый при возникновении сетевой ошибки.\n * Позволяет внешней системе узнать о сбое и текущем времени ожидания до следующей попытки.\n *\n * @param {number} delayMs - Текущая задержка Exponential Backoff в миллисекундах перед следующим запросом.\n * @param {() => void} onRetryScheduled - Коллбэк-триггер. Должен быть вызван один раз, чтобы\n * просигнализировать декоратору, что шаг зафиксирован и задержка для следующей ошибки может быть увеличена.\n */\n onError: (delayMs: number, onRetryScheduled: () => void) => void;\n\n /** Пауза перед открытием следующего соединения в миллисекундах. По умолчанию 500 мс */\n delay?: number;\n /** Стартовая задержка Exponential Backoff в миллисекундах. По умолчанию 2000 мс */\n errorInitialDelay?: number;\n /** Потолок задержки Exponential Backoff в миллисекундах. По умолчанию 8000 мс */\n errorMaxDelay?: number;\n /** Внешний сигнал для жесткой остановки рекурсивных таймаутов */\n externalSignal?: AbortSignal;\n}\n\n/**\n * Адаптированный декоратор для реализации паттерна Long Polling (длинные опросы),\n * спроектированный специально для интеграции с подсистемой `engine.resource`.\n *\n * Превращает разовый асинхронный запрос данных в непрерывный контролируемый конвейер\n * циклического опроса сервера с поддержкой экспоненциального отката при ошибках\n * (Exponential Backoff) и защитой от пересечения параллельных сессий.\n *\n * ### 🧠 Архитектура конвейера опроса:\n * 1. **Контроль сессионных токенов:** Каждый новый вызов функции инкрементирует `currentSessionToken`.\n * Если предыдущий запрос завершится позже, таймер следующего шага не взведется, так как\n * идентификаторы сессий (`activeSessionId === currentSessionToken`) не совпадут. Это полностью исключает утечки и гонки ответов.\n * 2. **Экспоненциальный откат (Exponential Backoff):** При успешном запросе интервал между циклами равен `options.delay`.\n * В случае падения сетевого запроса, время ожидания перед следующим опросом прогрессивно удваивается,\n * начиная с `errorInitialDelay` вплоть до достижения лимита `errorMaxDelay`, чтобы не спамить упавший бэкенд.\n * 3. **Двойной контур отмены:** Поддерживает как локальный `AbortSignal` от ресурса, так и глобальный `externalSignal`\n * (например, для остановки всех фоновых процессов при закрытии приложения).\n *\n * @template S Тип входных данных (аргументов) для функции запроса.\n * @template T Тип данных, возвращаемых асинхронным `fetcher`-ом (разрешенное значение промиса).\n *\n * @param {(source: S, signal: AbortSignal) => Promise<T>} fetcher Асинхронная функция-загрузчик (например, fetch-запрос к эндпоинту уведомлений).\n * @param {LongPollingOptions} options Конфигурация параметров и коллбэков длинных опросов.\n * @param {() => void} options.onNextTick Коллбэк-триггер, вызываемый для перезапуска цикла опроса (в контексте ядра обычно мутирует или инвалидирует `source` ресурса).\n * @param {(currentDelay: number, increaseDelay: () => void) => void} [options.onError] Коллбэк, вызываемый при ошибке сети. Позволяет логировать сбои и управлять шагом экспоненциального отката через запуск функции `increaseDelay()`.\n * @param {AbortSignal} [options.externalSignal] Внешний сигнал отмены для принудительной остановки поллинга извне (независимо от жизненного цикла ресурса).\n * @param {number} [options.delay=500] Базовая задержка в миллисекундах между успешным ответом сервера и началом следующего запроса.\n * @param {number} [options.errorInitialDelay=2000] Стартовая задержка в миллисекундах при возникновении первой ошибки.\n * @param {number} [options.errorMaxDelay=8000] Максимально возможный интервал задержки в миллисекундах при череде последовательных ошибок.\n *\n * @returns {(source: S, signal: AbortSignal) => Promise<T>} Возвращает обернутую циклическую функцию, возвращающую `Promise<T>`.\n *\n * @example\n * ```typescript\n * import { withLongPolling } from '@pravosleva/reactive-engine';\n *\n * // 1. Настраиваем функцию опроса новостной ленты\n * const pollingFetch = withLongPolling(\n * async (userId: string, signal) => {\n * const res = await fetch(`/api/notifications?uid=${userId}`, { signal });\n * return res.json();\n * },\n * {\n * delay: 1000,\n * errorInitialDelay: 2000,\n * errorMaxDelay: 10000,\n * onNextTick: () => {\n * // Инвалидируем или триггерим обновление ресурса в ядре\n * notificationResource.refresh();\n * },\n * onError: (delay, increaseDelay) => {\n * console.warn(`Ошибка сети. Следующая попытка через ${delay}мс`);\n * increaseDelay(); // Удваиваем интервал до следующего тика\n * }\n * }\n * );\n *\n * // 2. Передаем декоратор в подсистему ресурсов ядра\n * const notificationResource = engine.resource(\n * fetcher: pollingFetch,\n * source: () => currentUserId.value\n * );\n * ```\n *\n * @abstract\n * ### 🚨 Поведение при отмене и очистка слушателей\n * При срабатывании любого из сигналов отмены (`signal` или `externalSignal` переходит в состояние `aborted`):\n * - Текущий ожидающий промис немедленно отклоняется с системным исключением `AbortError`.\n * - Цикл поллинга блокируется и полностью прекращает планирование будущих макрозадач `setTimeout`.\n * - Все подписки на события `'abort'` корректно удаляются, предотвращая скрытые утечки памяти в Node.js / браузере.\n */\nexport const withLongPolling = <S, T>(\n fetcher: (source: S, signal: AbortSignal) => Promise<T>,\n options: LongPollingOptions\n) => {\n const {\n onNextTick,\n onError,\n externalSignal,\n delay = 500,\n errorInitialDelay = 2000,\n errorMaxDelay = 8000\n } = options\n\n let currentErrorDelay = errorInitialDelay\n let currentSessionToken = 0\n\n return (source: S, signal: AbortSignal): Promise<T> => {\n const activeSessionId = ++currentSessionToken\n\n return new Promise<T>((resolve, reject) => {\n\n const poll = async () => {\n if (signal.aborted || externalSignal?.aborted) {\n reject(new DOMException('Aborted by long polling lifecycle', 'AbortError'))\n return\n }\n\n try {\n const data = await fetcher(source, signal)\n currentErrorDelay = errorInitialDelay\n\n if (signal.aborted || externalSignal?.aborted) {\n reject(new DOMException('Aborted by long polling lifecycle', 'AbortError'))\n return\n }\n\n resolve(data)\n\n setTimeout(() => {\n if (activeSessionId === currentSessionToken && !signal.aborted && !externalSignal?.aborted) {\n onNextTick?.()\n }\n }, delay)\n\n } catch (error) {\n if (error instanceof DOMException && error.name === 'AbortError') {\n reject(error)\n return\n }\n\n reject(error)\n const delayDuration = currentErrorDelay\n\n if (typeof onError === 'function') onError(delayDuration, () => {\n if (activeSessionId === currentSessionToken) {\n currentErrorDelay = Math.min(currentErrorDelay * 2, errorMaxDelay)\n }\n })\n\n setTimeout(() => {\n if (activeSessionId === currentSessionToken && !signal.aborted && !externalSignal?.aborted) {\n onNextTick?.()\n }\n }, delayDuration)\n }\n }\n\n const forceKillTimer = () => {\n reject(new DOMException('Aborted by lifecycle event', 'AbortError'))\n }\n\n signal.addEventListener('abort', forceKillTimer)\n if (externalSignal) {\n externalSignal.addEventListener('abort', forceKillTimer)\n }\n\n if (signal.aborted || externalSignal?.aborted) {\n return forceKillTimer()\n }\n\n poll()\n })\n }\n}\n"],"mappings":"AA+FA,IAAa,GACX,EACA,IACG,CACH,GAAM,CACJ,aACA,UACA,iBACA,QAAQ,IACR,oBAAoB,IACpB,gBAAgB,KACd,EAEA,EAAoB,EACpB,EAAsB,EAE1B,OAAQ,EAAW,IAAoC,CACrD,IAAM,EAAkB,EAAE,EAE1B,OAAO,IAAI,SAAY,EAAS,IAAW,CAEzC,IAAM,EAAO,SAAY,CACvB,GAAI,EAAO,SAAW,GAAgB,QAAS,CAC7C,EAAO,IAAI,aAAa,oCAAqC,YAAY,CAAC,EAC1E,MACF,CAEA,GAAI,CACF,IAAM,EAAO,MAAM,EAAQ,EAAQ,CAAM,EAGzC,GAFA,EAAoB,EAEhB,EAAO,SAAW,GAAgB,QAAS,CAC7C,EAAO,IAAI,aAAa,oCAAqC,YAAY,CAAC,EAC1E,MACF,CAEA,EAAQ,CAAI,EAEZ,eAAiB,CACX,IAAoB,GAAuB,CAAC,EAAO,SAAW,CAAC,GAAgB,SACjF,IAAa,CAEjB,EAAG,CAAK,CAEV,OAAS,EAAO,CACd,GAAI,aAAiB,cAAgB,EAAM,OAAS,aAAc,CAChE,EAAO,CAAK,EACZ,MACF,CAEA,EAAO,CAAK,EACZ,IAAM,EAAgB,EAElB,OAAO,GAAY,YAAY,EAAQ,MAAqB,CAC1D,IAAoB,IACtB,EAAoB,KAAK,IAAI,EAAoB,EAAG,CAAa,EAErE,CAAC,EAED,eAAiB,CACX,IAAoB,GAAuB,CAAC,EAAO,SAAW,CAAC,GAAgB,SACjF,IAAa,CAEjB,EAAG,CAAa,CAClB,CACF,EAEM,MAAuB,CAC3B,EAAO,IAAI,aAAa,6BAA8B,YAAY,CAAC,CACrE,EAOA,GALA,EAAO,iBAAiB,QAAS,CAAc,EAC3C,GACF,EAAe,iBAAiB,QAAS,CAAc,EAGrD,EAAO,SAAW,GAAgB,QACpC,OAAO,EAAe,EAGxB,EAAK,CACP,CAAC,CACH,CACF"}
@@ -1,2 +0,0 @@
1
- var e=(e,t={})=>{let n=new Map,r=t.isLogsEnabled??!1,i=t.ttl,a=t.maxSize,o=a!==void 0&&a>0,s=e=>{try{return JSON.stringify(e)}catch{return String(e)}};return async(t,c)=>{let l=s(t),u=n.get(l);u&&o&&(n.delete(l),n.set(l,u));let d=()=>u?i===void 0?!0:Date.now()-u.savedTime<i:!1;if(c.aborted){if(d()&&u)return u.data;throw c.reason||new DOMException(`The operation was aborted.`,`AbortError`)}try{let i=await e(t,c);if(o&&n.size>=a&&!n.has(l)){let e=n.keys().next().value;e!==void 0&&(n.delete(e),r&&console.warn(`[ReactiveEngine:Stale] Кэш переполнен. Удален старый ключ: ${e}`))}return n.set(l,{data:i,savedTime:Date.now()}),i}catch(e){if(d()&&u)return r&&console.warn(`[ReactiveEngine:Stale] Запрос ${l} упал. Отдаем кэш.`,e),u.data;throw e}}};exports.withStaleWhileRevalidate=e;
2
- //# sourceMappingURL=withStaleWhileRevalidate.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"withStaleWhileRevalidate.cjs","names":[],"sources":["../../../src/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.ts"],"sourcesContent":["export interface StaleOptions<T> {\n ttl?: number;\n isLogsEnabled?: boolean;\n maxSize?: number;\n}\n\nexport const withStaleWhileRevalidate = <S, T>(\n fetcher: (source: S, signal: AbortSignal) => Promise<T>,\n options: StaleOptions<T> = {}\n) => {\n const cacheMap = new Map<string, { data: T; savedTime: number }>()\n const isLogsEnabled = options.isLogsEnabled ?? false\n const ttl = options.ttl\n const maxSize = options.maxSize\n\n // Кэшируем флаг, чтобы не проверять \"undefined\" в горячем цикле\n const hasMaxLimit = maxSize !== undefined && maxSize > 0\n\n const getCacheKey = (source: S): string => {\n try { return JSON.stringify(source) } catch (e) { return String(source) }\n }\n\n return async (source: S, signal: AbortSignal): Promise<T> => {\n const cacheKey = getCacheKey(source)\n let cachedRecord = cacheMap.get(cacheKey)\n\n // ⚡ ОПТИМИЗАЦИЯ #1 (Fast Path): Перестраиваем Map только если включено ограничение памяти\n if (cachedRecord && hasMaxLimit) {\n cacheMap.delete(cacheKey)\n cacheMap.set(cacheKey, cachedRecord)\n }\n\n const isCacheValid = (): boolean => {\n if (!cachedRecord) return false\n if (ttl === undefined) return true\n return Date.now() - cachedRecord.savedTime < ttl\n }\n\n if (signal.aborted) {\n if (isCacheValid() && cachedRecord) return cachedRecord.data\n throw signal.reason || new DOMException('The operation was aborted.', 'AbortError')\n }\n\n try {\n const freshData = await fetcher(source, signal)\n\n // ⚡ ОПТИМИЗАЦИЯ #2: Итератор `.keys()` вызывается СТРОГО при реальном переполнении\n if (hasMaxLimit && cacheMap.size >= maxSize && !cacheMap.has(cacheKey)) {\n const oldestKey = cacheMap.keys().next().value\n if (oldestKey !== undefined) {\n cacheMap.delete(oldestKey)\n if (isLogsEnabled) {\n console.warn(`[ReactiveEngine:Stale] Кэш переполнен. Удален старый ключ: ${oldestKey}`)\n }\n }\n }\n\n cacheMap.set(cacheKey, {\n data: freshData,\n savedTime: Date.now()\n })\n\n return freshData\n } catch (error) {\n if (isCacheValid() && cachedRecord) {\n if (isLogsEnabled) {\n console.warn(`[ReactiveEngine:Stale] Запрос ${cacheKey} упал. Отдаем кэш.`, error)\n }\n return cachedRecord.data\n }\n\n throw error\n }\n }\n}\n"],"mappings":"AAMA,IAAa,GACX,EACA,EAA2B,CAAC,IACzB,CACH,IAAM,EAAW,IAAI,IACf,EAAgB,EAAQ,eAAiB,GACzC,EAAM,EAAQ,IACd,EAAU,EAAQ,QAGlB,EAAc,IAAY,IAAA,IAAa,EAAU,EAEjD,EAAe,GAAsB,CACzC,GAAI,CAAE,OAAO,KAAK,UAAU,CAAM,CAAE,MAAY,CAAE,OAAO,OAAO,CAAM,CAAE,CAC1E,EAEA,OAAO,MAAO,EAAW,IAAoC,CAC3D,IAAM,EAAW,EAAY,CAAM,EAC/B,EAAe,EAAS,IAAI,CAAQ,EAGpC,GAAgB,IAClB,EAAS,OAAO,CAAQ,EACxB,EAAS,IAAI,EAAU,CAAY,GAGrC,IAAM,MACC,EACD,IAAQ,IAAA,GAAkB,GACvB,KAAK,IAAI,EAAI,EAAa,UAAY,EAFnB,GAK5B,GAAI,EAAO,QAAS,CAClB,GAAI,EAAa,GAAK,EAAc,OAAO,EAAa,KACxD,MAAM,EAAO,QAAU,IAAI,aAAa,6BAA8B,YAAY,CACpF,CAEA,GAAI,CACF,IAAM,EAAY,MAAM,EAAQ,EAAQ,CAAM,EAG9C,GAAI,GAAe,EAAS,MAAQ,GAAW,CAAC,EAAS,IAAI,CAAQ,EAAG,CACtE,IAAM,EAAY,EAAS,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,MACrC,IAAc,IAAA,KAChB,EAAS,OAAO,CAAS,EACrB,GACF,QAAQ,KAAK,8DAA8D,GAAW,EAG5F,CAOA,OALA,EAAS,IAAI,EAAU,CACrB,KAAM,EACN,UAAW,KAAK,IAAI,CACtB,CAAC,EAEM,CACT,OAAS,EAAO,CACd,GAAI,EAAa,GAAK,EAIpB,OAHI,GACF,QAAQ,KAAK,iCAAiC,EAAS,oBAAqB,CAAK,EAE5E,EAAa,KAGtB,MAAM,CACR,CACF,CACF"}
@@ -1,2 +0,0 @@
1
- var e=(e,t={})=>{let n=t.limit??300,r=0,i=null,a=null,o=null,s=null,c=null;return(t,l)=>{let u=Date.now(),d=n-(u-r),f=()=>{i&&=(clearTimeout(i),null),s&&=(s(new DOMException(`Aborted by resource signal during throttle`,`AbortError`)),o=null,null)};return d<=0?(i&&=(clearTimeout(i),null),s&&=(s(new DOMException(`Aborted due to newer direct throttle execution`,`AbortError`)),o=null,null),r=u,e(t,l)):(s&&s(new DOMException(`Aborted due to newer throttled value`,`AbortError`)),new Promise((n,u)=>{if(a=t,o=n,s=u,c=l,l.aborted)return f();l.addEventListener(`abort`,f),i||=setTimeout(async()=>{i=null;let t=a,n=o,l=s,u=c;a=null,o=null,s=null,c=null,u.removeEventListener(`abort`,f);try{r=Date.now(),n(await e(t,u))}catch(e){l(e)}},d)}))}};exports.withThrottle=e;
2
- //# sourceMappingURL=withThrottle.cjs.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"withThrottle.cjs","names":[],"sources":["../../../src/decorators/withThrottle/withThrottle.ts"],"sourcesContent":["interface ThrottleOptions {\n /** Интервал троттлинга в миллисекундах. По умолчанию 300 мс */\n limit?: number;\n}\n\n/**\n * Декоратор для создания дросселирующего (throttled) загрузчика данных, специально\n * адаптированный для использования совместно с `engine.resource`.\n *\n * Ограничивает частоту вызовов асинхронной функции `fetcher`, гарантируя выполнение\n * первого запроса мгновенно (Leading edge), а самого последнего запроса — на хвосте\n * временного интервала (Trailing edge) с автоматической отменой всех промежуточных вызовов.\n *\n * ### 🧠 Механика обработки вызовов (Две фазы):\n * 1. **Прямое выполнение (Leading edge):** Если окно блокировки закрыто (`remainingTime <= 0`),\n * запрос пробрасывается к исходному `fetcher` немедленно. Время последнего выполнения фиксируется.\n * 2. **Отложенное выполнение (Trailing edge):** Если вызов происходит внутри активного окна блокировки,\n * его параметры (`source`, `signal`, `resolve`, `reject`) запоминаются, перезаписывая предыдущие.\n * По истечении таймера выполнится только самый актуальный (последний) запрос.\n * Все промежуточные «перезаписанные» промисы отклоняются с ошибкой `AbortError`.\n *\n * @template S Тип входных данных (аргументов) для функции запроса.\n * @template T Тип данных, возвращаемых асинхронным `fetcher`-ом (разрешенное значение промиса).\n *\n * @param {(source: S, signal: AbortSignal) => Promise<T>} fetcher Оригинальная асинхронная функция запроса, принимающая параметры и сигнал отмены.\n * @param {ThrottleOptions} [options={}] Параметры конфигурации троттлинга.\n * @param {number} [options.limit=300] Минимальный интервал времени в миллисекундах между последовательными прямыми вызовами.\n *\n * @returns {(source: S, signal: AbortSignal) => Promise<T>} Возвращает обернутую функцию, возвращающую `Promise<T>` и полностью сохраняющую исходную сигнатуру типов.\n *\n * @example\n * ```typescript\n * import { withThrottle } from '@pravosleva/reactive-engine';\n *\n * const fetchUserData = async (userId: string, signal: AbortSignal) => {\n * const res = await fetch(`/api/users/${userId}`, { signal });\n * return res.json();\n * };\n *\n * // Ограничиваем частоту запросов профиля до 1 раза в 400мс\n * const throttledFetch = withThrottle(fetchUserData, { limit: 400 });\n *\n * // Интеграция с подсистемой ресурсов вашего ядра\n * const userResource = engine.resource(\n * fetcher: throttledFetch,\n * source: () => currentUserId.value\n * );\n * ```\n *\n * @abstract\n * ### 🚨 Интеграция с AbortSignal и защита от утечек памяти\n * Декоратор подписывается на событие отмены `abort` переданного сигнала. Если внешний ресурс\n * размонтируется или перезапрашивает данные в процессе ожидания внутри окна троттлинга:\n * - Активный таймер `setTimeout` незамедлительно сбрасывается.\n * - Ожидающий хвостовой промис переходит в состояние `rejected` с системной ошибкой `AbortError`.\n * - Все внутренние ссылки на контекст промиса (`resolve`, `reject`, `source`) принудительно зануляются (`null`),\n * освобождая память от скрытых замыканий и предотвращая появление эффекта «зависших» запросов.\n */\nexport const withThrottle = <S, T>(\n fetcher: (source: S, signal: AbortSignal) => Promise<T>,\n options: ThrottleOptions = {}\n) => {\n const limit = options.limit ?? 300\n\n let lastExecutionTime = 0\n let throttleTimeoutId: ReturnType<typeof setTimeout> | null = null\n\n // Храним параметры последнего \"заблокированного\" вызова, чтобы выполнить его на хвосте\n let lastSavedSource: S | null = null\n let lastSavedResolve: ((value: T | PromiseLike<T>) => void) | null = null\n let lastSavedReject: ((reason: any) => void) | null = null\n let lastSavedSignal: AbortSignal | null = null\n\n return (source: S, signal: AbortSignal): Promise<T> => {\n const now = Date.now()\n const remainingTime = limit - (now - lastExecutionTime)\n\n // Слушатель для мгновенной отмены ожидания, если ресурс размонтировался во время блокировки\n const onAbort = () => {\n if (throttleTimeoutId) {\n clearTimeout(throttleTimeoutId)\n throttleTimeoutId = null\n }\n if (lastSavedReject) {\n lastSavedReject(new DOMException('Aborted by resource signal during throttle', 'AbortError'))\n lastSavedResolve = null\n lastSavedReject = null\n }\n }\n\n // СЦЕНАРИЙ 1: Интервал блокировки истек — выполняем запрос мгновенно (Leading edge)\n if (remainingTime <= 0) {\n // Если висел отложенный хвостовой вызов, отменяем его, так как пришел более свежий прямой запрос\n if (throttleTimeoutId) {\n clearTimeout(throttleTimeoutId)\n throttleTimeoutId = null\n }\n if (lastSavedReject) {\n lastSavedReject(new DOMException('Aborted due to newer direct throttle execution', 'AbortError'))\n lastSavedResolve = null\n lastSavedReject = null\n }\n\n lastExecutionTime = now\n return fetcher(source, signal)\n }\n\n // СЦЕНАРИЙ 2: Мы находимся внутри интервала блокировки.\n // Запоминаем текущие параметры как самые актуальные для выполнения на хвосте (Trailing edge).\n if (lastSavedReject) {\n // Отклоняем предыдущий сохраненный хвостовой промис, так как данные уже устарели\n lastSavedReject(new DOMException('Aborted due to newer throttled value', 'AbortError'))\n }\n\n return new Promise<T>((resolve, reject) => {\n lastSavedSource = source\n lastSavedResolve = resolve\n lastSavedReject = reject\n lastSavedSignal = signal\n\n if (signal.aborted) {\n return onAbort()\n }\n signal.addEventListener('abort', onAbort)\n\n // Если таймер хвостового вызова еще не запущен, взводим его на остаток времени блокировки\n if (!throttleTimeoutId) {\n throttleTimeoutId = setTimeout(async () => {\n throttleTimeoutId = null\n\n const savedSource = lastSavedSource!\n const savedResolve = lastSavedResolve!\n const savedReject = lastSavedReject!\n const savedSignal = lastSavedSignal!\n\n // Очищаем ссылки перед асинхронным вызовом\n lastSavedSource = null\n lastSavedResolve = null\n lastSavedReject = null\n lastSavedSignal = null\n savedSignal.removeEventListener('abort', onAbort)\n\n try {\n lastExecutionTime = Date.now()\n const data = await fetcher(savedSource, savedSignal)\n savedResolve(data)\n } catch (error) {\n savedReject(error)\n }\n }, remainingTime)\n }\n })\n }\n}\n"],"mappings":"AA0DA,IAAa,GACX,EACA,EAA2B,CAAC,IACzB,CACH,IAAM,EAAQ,EAAQ,OAAS,IAE3B,EAAoB,EACpB,EAA0D,KAG1D,EAA4B,KAC5B,EAAiE,KACjE,EAAkD,KAClD,EAAsC,KAE1C,OAAQ,EAAW,IAAoC,CACrD,IAAM,EAAM,KAAK,IAAI,EACf,EAAgB,GAAS,EAAM,GAG/B,MAAgB,CACpB,AAEE,KADA,aAAa,CAAiB,EACV,MAEtB,AAGE,KAFA,EAAgB,IAAI,aAAa,6CAA8C,YAAY,CAAC,EAC5F,EAAmB,KACD,KAEtB,EA0BA,OAvBI,GAAiB,GAEnB,AAEE,KADA,aAAa,CAAiB,EACV,MAEtB,AAGE,KAFA,EAAgB,IAAI,aAAa,iDAAkD,YAAY,CAAC,EAChG,EAAmB,KACD,MAGpB,EAAoB,EACb,EAAQ,EAAQ,CAAM,IAK3B,GAEF,EAAgB,IAAI,aAAa,uCAAwC,YAAY,CAAC,EAGjF,IAAI,SAAY,EAAS,IAAW,CAMzC,GALA,EAAkB,EAClB,EAAmB,EACnB,EAAkB,EAClB,EAAkB,EAEd,EAAO,QACT,OAAO,EAAQ,EAEjB,EAAO,iBAAiB,QAAS,CAAO,EAGxC,AACE,IAAoB,WAAW,SAAY,CACzC,EAAoB,KAEpB,IAAM,EAAc,EACd,EAAe,EACf,EAAc,EACd,EAAc,EAGpB,EAAkB,KAClB,EAAmB,KACnB,EAAkB,KAClB,EAAkB,KAClB,EAAY,oBAAoB,QAAS,CAAO,EAEhD,GAAI,CACF,EAAoB,KAAK,IAAI,EAE7B,EAAa,MADM,EAAQ,EAAa,CAAW,CAClC,CACnB,OAAS,EAAO,CACd,EAAY,CAAK,CACnB,CACF,EAAG,CAAa,CAEpB,CAAC,EACH,CACF"}
@@ -1,2 +0,0 @@
1
- var e=(e,t={})=>{let n=t.limit??300,r=t.ttl??300*1e3,i=0,a=null,o=null,s=null,c=null,l=null,u=new Map,d=e=>typeof e==`object`&&e?JSON.stringify(e):String(e);return(t,f)=>{let p=Date.now(),m=n-(p-i);d(t);let h=()=>{a&&=(clearTimeout(a),null),c&&=(c(new DOMException(`Aborted by resource signal during throttle`,`AbortError`)),s=null,null)},g=async(t,n)=>{let i=Date.now(),a=d(t),o=u.get(a);if(o&&i-o.timestamp<r)return o.data;let s=await e(t,n);return u.set(a,{data:s,timestamp:Date.now()}),s};return m<=0?(a&&=(clearTimeout(a),null),c&&=(c(new DOMException(`Aborted due to newer direct execution`,`AbortError`)),s=null,null),i=p,g(t,f)):(c&&c(new DOMException(`Aborted due to newer throttled value`,`AbortError`)),new Promise((e,n)=>{if(o=t,s=e,c=n,l=f,f.aborted)return h();f.addEventListener(`abort`,h),a||=setTimeout(async()=>{a=null;let e=o,t=s,n=c,r=l;o=null,s=null,c=null,l=null,r.removeEventListener(`abort`,h);try{i=Date.now(),t(await g(e,r))}catch(e){n(e)}},m)}))}};exports.withThrottleAndCache=e;
2
- //# sourceMappingURL=withThrottleAndCache.cjs.map