@pravosleva/reactive-engine 1.5.8-beta → 1.5.10-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -29
- package/dist/decorators/index.d.ts +1 -0
- package/dist/decorators/index.d.ts.map +1 -1
- package/dist/decorators/withStaleWhileRevalidate/index.d.ts +2 -0
- package/dist/decorators/withStaleWhileRevalidate/index.d.ts.map +1 -0
- package/dist/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.cjs +2 -0
- package/dist/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.cjs.map +1 -0
- package/dist/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.d.ts +34 -0
- package/dist/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.d.ts.map +1 -0
- package/dist/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.mjs +22 -0
- package/dist/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.mjs.map +1 -0
- package/dist/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.test.d.ts +2 -0
- package/dist/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.test.d.ts.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.mjs +2 -1
- package/dist/reactive-engine.umd.js +1 -1
- package/dist/rocket-thruster-120x120.svg +1 -0
- package/dist/rocket-thruster.svg +1 -0
- package/package.json +1 -1
- package/dist/vite.svg +0 -1
package/README.md
CHANGED
|
@@ -1,37 +1,48 @@
|
|
|
1
1
|
# 🚀 ReactiveEngine Core Framework
|
|
2
|
-
A lightweight, type-safe reactive engine built with TypeScript, featuring Dependency Injection and seamless React integration.
|
|
3
2
|
|
|
4
|
-
|
|
3
|
+
<div align="center">
|
|
4
|
+
|
|
5
|
+

|
|
6
|
+
|
|
7
|
+
A lightweight, ultra-performance, type-safe reactive engine built with TypeScript, featuring Dependency Injection and seamless multi-framework integration.
|
|
8
|
+
|
|
9
|
+
</div>
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 🗺️ Documentation & Instructions
|
|
5
14
|
- 🇬🇧 [In English](https://pravosleva.pro/reactive-engine/en)
|
|
6
|
-
- 🇷🇺 [
|
|
15
|
+
- 🇷🇺 [Вводная документация на Русском](https://pravosleva.pro/reactive-engine)
|
|
7
16
|
|
|
8
17
|
## 🎯 What Problems This Library Solves
|
|
9
18
|
|
|
10
|
-
When building large-scale
|
|
19
|
+
When building large-scale frontend applications, developers constantly run into architectural bottlenecks imposed by built-in state tools. `@pravosleva/reactive-engine` is designed to elegantly solve the following pain points:
|
|
20
|
+
|
|
21
|
+
### 1. Unnecessary Over-Rendering
|
|
22
|
+
* **The Problem:** React Context API and traditional immutability-based stores (Redux/Zustand) force all components reading from that state slice to re-render whenever even a single deeply nested property changes.
|
|
23
|
+
* **The Solution:** Fine-grained reactivity. Components micro-subscribe only to the specific primitive signals they display. State mutations update strictly the necessary DOM nodes.
|
|
11
24
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
25
|
+
### 2. UI Tearing and Lags in React 18+
|
|
26
|
+
* **The Problem:** Under React Concurrent Mode, standard external state managers can lead to UI tearing, where different parts of the screen temporarily display asynchronous, mismatching data.
|
|
27
|
+
* **The Solution:** The `useReactiveValue` hook is built on top of native `useSyncExternalStore`. This ensures absolute cross-component synchronization, shielding your interface from glitches and tearing.
|
|
15
28
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
29
|
+
### 3. Expensive CPU Re-calculations
|
|
30
|
+
* **The Problem:** Heavy array filtration, sorting, or data analytics functions trigger re-evaluations on every parent re-render or whenever unrelated props shift.
|
|
31
|
+
* **The Solution:** Lazy `Computed` properties with O(1) computation caching. The logic evaluates *only* when its underlying dependency signals change.
|
|
19
32
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
33
|
+
### 4. Network Request Flooding (Race Conditions)
|
|
34
|
+
* **The Problem:** A user rapidly clicking through catalog filters or pagination options spawns cascades of overlapping network requests. An older, slower request might resolve *after* a newer one, overwriting fresh data (Race Condition).
|
|
35
|
+
* **The Solution:** The `Resource` utility automatically orchestrates native `AbortController` instances. Whenever dependency signals change, the previous pending fetch request is instantly cancelled at the browser's system level.
|
|
23
36
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
37
|
+
### 5. Cascading UI Updates (Render Cascades)
|
|
38
|
+
* **The Problem:** Updating 3–4 connected state parameters inside a single event handler prompts 3–4 sequential UI update ticks, clogging the Event Loop.
|
|
39
|
+
* **The Solution:** 100% out-of-the-box automatic batching. The engine bundles all consecutive synchronous and asynchronous modifications into a single microtask, triggering exactly 1 final unified re-render.
|
|
27
40
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
41
|
+
### 6. Memory Leaks in Dynamic Architectures
|
|
42
|
+
* **The Problem:** Dynamically instantiating computed properties (e.g., dynamically filtering an active tab) accumulates abandoned reactive effects in memory that continue to listen to global state updates forever.
|
|
43
|
+
* **The Solution:** Built-in memory cleanup and computation memoization inside the core engine. The library hooks automatically trigger `.destroy()` on component unmount, seamlessly purging dead reactive effects from RAM.
|
|
31
44
|
|
|
32
|
-
|
|
33
|
-
> * *The Problem:* Dynamically instantiating computed properties (e.g., dynamically filtering an active tab) accumulates abandoned reactive effects in memory that continue to listen to global state updates forever.
|
|
34
|
-
> * *The Solution:* Built-in memory cleanup and computation memoization inside the core engine. The library hooks automatically trigger `.destroy()` on component unmount, seamlessly purging dead reactive effects from RAM.
|
|
45
|
+
---
|
|
35
46
|
|
|
36
47
|
## 📦 Installation
|
|
37
48
|
|
|
@@ -41,7 +52,7 @@ Install the package via your favorite package manager:
|
|
|
41
52
|
yarn add @pravosleva/reactive-engine
|
|
42
53
|
```
|
|
43
54
|
|
|
44
|
-
|
|
55
|
+
### `peerDependencies`
|
|
45
56
|
|
|
46
57
|
```json
|
|
47
58
|
{
|
|
@@ -52,7 +63,13 @@ yarn add @pravosleva/reactive-engine
|
|
|
52
63
|
}
|
|
53
64
|
```
|
|
54
65
|
|
|
55
|
-
|
|
66
|
+
---
|
|
67
|
+
|
|
68
|
+
## 💻 Multi-Framework Usage Examples
|
|
69
|
+
|
|
70
|
+
<div>
|
|
71
|
+
<details>
|
|
72
|
+
<summary>React 18+ Integration (Click to expand)</summary>
|
|
56
73
|
|
|
57
74
|
```tsx
|
|
58
75
|
import { AbstractService } from '@pravosleva/reactive-engine'
|
|
@@ -76,7 +93,7 @@ export const Example001 = () => {
|
|
|
76
93
|
<div>
|
|
77
94
|
<div>Signal example</div>
|
|
78
95
|
<code>{counter}</code>
|
|
79
|
-
<div
|
|
96
|
+
<div>
|
|
80
97
|
<button onClick={logic.inc}>+ INC</button>
|
|
81
98
|
</div>
|
|
82
99
|
</div>
|
|
@@ -84,7 +101,12 @@ export const Example001 = () => {
|
|
|
84
101
|
}
|
|
85
102
|
```
|
|
86
103
|
|
|
87
|
-
|
|
104
|
+
</details>
|
|
105
|
+
</div>
|
|
106
|
+
|
|
107
|
+
<div>
|
|
108
|
+
<details>
|
|
109
|
+
<summary>Vue 3 Integration (Click to expand)</summary>
|
|
88
110
|
|
|
89
111
|
```vue
|
|
90
112
|
<script setup lang="ts">
|
|
@@ -117,7 +139,12 @@ const counter = engine.use(logic.counter)
|
|
|
117
139
|
</template>
|
|
118
140
|
```
|
|
119
141
|
|
|
120
|
-
|
|
142
|
+
</details>
|
|
143
|
+
</div>
|
|
144
|
+
|
|
145
|
+
<div>
|
|
146
|
+
<details>
|
|
147
|
+
<summary>Angular 16+ Integration (Click to expand)</summary>
|
|
121
148
|
|
|
122
149
|
```ts
|
|
123
150
|
import { Component } from '@angular/core'
|
|
@@ -150,9 +177,10 @@ class CounterLogic extends AbstractService {
|
|
|
150
177
|
})
|
|
151
178
|
export class AngularCounterComponent {
|
|
152
179
|
private engine = new ReactiveEngine();
|
|
153
|
-
|
|
154
180
|
public logic = this.engine.inject(CounterLogic);
|
|
155
|
-
|
|
156
181
|
public counter = this.engine.use(this.logic.counter);
|
|
157
182
|
}
|
|
158
183
|
```
|
|
184
|
+
|
|
185
|
+
</details>
|
|
186
|
+
</div>
|
|
@@ -4,4 +4,5 @@ export { withLongPolling } from './withLongPolling';
|
|
|
4
4
|
export { withThrottle } from './withThrottle';
|
|
5
5
|
export { withThrottleComputed } from './withThrottleComputed';
|
|
6
6
|
export { withThrottleAndCache } from './withThrottleAndCache';
|
|
7
|
+
export { withStaleWhileRevalidate } from './withStaleWhileRevalidate';
|
|
7
8
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAA;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAA;AAC7C,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAC7D,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAA;AAC7D,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/decorators/withStaleWhileRevalidate/index.ts"],"names":[],"mappings":"AAAA,cAAc,4BAA4B,CAAA"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=(e,t={})=>{let n=t.initialData,r=t.isLogsEnabled??!1;return async(t,i)=>{if(i.aborted){if(n!==void 0)return n;throw i.reason||new DOMException(`The operation was aborted.`,`AbortError`)}try{let r=await e(t,i);return n=r,r}catch(e){let t=e instanceof DOMException&&e.name===`AbortError`;if(n!==void 0)return r&&console.warn(`[ReactiveEngine:Stale] Запрос ${t?`отменен`:`упал с ошибкой`}. Отдаем предыдущее состояние.`,e),n;throw e}}};exports.withStaleWhileRevalidate=e;
|
|
2
|
+
//# sourceMappingURL=withStaleWhileRevalidate.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withStaleWhileRevalidate.cjs","names":[],"sources":["../../../src/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.ts"],"sourcesContent":["interface StaleOptions<T> {\n /**\n * Дефолтное значение, которое вернется при самом первом запросе,\n * если он завершился ошибкой или был отменен.\n */\n initialData?: T;\n isLogsEnabled?: boolean;\n}\n\n/**\n * Декоратор для сохранения предыдущего успешного состояния данных,\n * специально адаптированный для использования совместно с `engine.resource`.\n *\n * Оборачивает асинхронную функцию `fetcher`. Если текущий запрос отменяется\n * (например, через AbortSignal при перетаскивании карты) или завершается ошибкой,\n * декоратор перехватывает исключение и возвращает последнее успешно полученное значение.\n *\n * ### 🧠 Механика Stale-While-Revalidate:\n * 1. **Стабильный кэш последнего состояния:** Декоратор сохраняет в замыкании успешный результат.\n * 2. **Грациозная деградация (Graceful Degradation):** При возникновении `AbortError` (отмена)\n * или любого другого сетевого сбоя, вместо выброса исключения в граф возвращается `stale`-дата.\n * 3. **Бесшовный UX:** Карта или UI-компонент не сбрасывают свое состояние в `null` во время\n * перепривязки сигналов, исключая эффект \"моргания\".\n *\n * @template S Тип входных данных (аргументов) для функции запроса.\n * @template T Тип данных, возвращаемых асинхронным `fetcher`-ом.\n *\n * @param {(source: S, signal: AbortSignal) => Promise<T>} fetcher Оригинальная асинхронная функция запроса.\n * @param {StaleOptions<T>} [options={}] Параметры конфигурации предыдущего состояния.\n *\n * @returns {(source: S, signal: AbortSignal) => Promise<T>} Вовращает обернутую функцию с сохраненной сигнатурой типов.\n */\nexport const withStaleWhileRevalidate = <S, T>(\n fetcher: (source: S, signal: AbortSignal) => Promise<T>,\n options: StaleOptions<T> = {}\n) => {\n // Хранилище для последнего успешного ответа сервера в рамках замыкания декоратора\n let lastValidData: T | undefined = options.initialData\n const isLogsEnabled = options.isLogsEnabled ?? false\n\n return async (source: S, signal: AbortSignal): Promise<T> => {\n // Если запрос отменен еще до старта, сразу возвращаем последнее известное состояние\n if (signal.aborted) {\n if (lastValidData !== undefined) return lastValidData\n throw signal.reason || new DOMException('The operation was aborted.', 'AbortError')\n }\n\n try {\n // Выполняем реальный сетевой запрос\n const freshData = await fetcher(source, signal)\n\n // Запоминаем успешный результат\n lastValidData = freshData\n\n return freshData\n } catch (error) {\n // Если запрос был отменен движком (например, изменился bbox) ИЛИ произошла сетевая ошибка\n const isAbort = error instanceof DOMException && error.name === 'AbortError'\n\n // Если у нас уже есть сохраненные старые данные — отдаем их вместо падения\n if (lastValidData !== undefined) {\n if (isLogsEnabled) {\n // Логируем для трассировки в dev-режиме (опционально)\n console.warn(\n `[ReactiveEngine:Stale] Запрос ${isAbort ? 'отменен' : 'упал с ошибкой'}. Отдаем предыдущее состояние.`,\n error\n )\n }\n return lastValidData\n }\n\n // Если это самый первый запрос и кэш пуст — прокидываем ошибку дальше в граф\n throw error\n }\n }\n}\n"],"mappings":"AAgCA,IAAa,GACX,EACA,EAA2B,CAAC,IACzB,CAEH,IAAI,EAA+B,EAAQ,YACrC,EAAgB,EAAQ,eAAiB,GAE/C,OAAO,MAAO,EAAW,IAAoC,CAE3D,GAAI,EAAO,QAAS,CAClB,GAAI,IAAkB,IAAA,GAAW,OAAO,EACxC,MAAM,EAAO,QAAU,IAAI,aAAa,6BAA8B,YAAY,CACpF,CAEA,GAAI,CAEF,IAAM,EAAY,MAAM,EAAQ,EAAQ,CAAM,EAK9C,MAFA,GAAgB,EAET,CACT,OAAS,EAAO,CAEd,IAAM,EAAU,aAAiB,cAAgB,EAAM,OAAS,aAGhE,GAAI,IAAkB,IAAA,GAQpB,OAPI,GAEF,QAAQ,KACN,iCAAiC,EAAU,UAAY,iBAAiB,gCACxE,CACF,EAEK,EAIT,MAAM,CACR,CACF,CACF"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
interface StaleOptions<T> {
|
|
2
|
+
/**
|
|
3
|
+
* Дефолтное значение, которое вернется при самом первом запросе,
|
|
4
|
+
* если он завершился ошибкой или был отменен.
|
|
5
|
+
*/
|
|
6
|
+
initialData?: T;
|
|
7
|
+
isLogsEnabled?: boolean;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Декоратор для сохранения предыдущего успешного состояния данных,
|
|
11
|
+
* специально адаптированный для использования совместно с `engine.resource`.
|
|
12
|
+
*
|
|
13
|
+
* Оборачивает асинхронную функцию `fetcher`. Если текущий запрос отменяется
|
|
14
|
+
* (например, через AbortSignal при перетаскивании карты) или завершается ошибкой,
|
|
15
|
+
* декоратор перехватывает исключение и возвращает последнее успешно полученное значение.
|
|
16
|
+
*
|
|
17
|
+
* ### 🧠 Механика Stale-While-Revalidate:
|
|
18
|
+
* 1. **Стабильный кэш последнего состояния:** Декоратор сохраняет в замыкании успешный результат.
|
|
19
|
+
* 2. **Грациозная деградация (Graceful Degradation):** При возникновении `AbortError` (отмена)
|
|
20
|
+
* или любого другого сетевого сбоя, вместо выброса исключения в граф возвращается `stale`-дата.
|
|
21
|
+
* 3. **Бесшовный UX:** Карта или UI-компонент не сбрасывают свое состояние в `null` во время
|
|
22
|
+
* перепривязки сигналов, исключая эффект "моргания".
|
|
23
|
+
*
|
|
24
|
+
* @template S Тип входных данных (аргументов) для функции запроса.
|
|
25
|
+
* @template T Тип данных, возвращаемых асинхронным `fetcher`-ом.
|
|
26
|
+
*
|
|
27
|
+
* @param {(source: S, signal: AbortSignal) => Promise<T>} fetcher Оригинальная асинхронная функция запроса.
|
|
28
|
+
* @param {StaleOptions<T>} [options={}] Параметры конфигурации предыдущего состояния.
|
|
29
|
+
*
|
|
30
|
+
* @returns {(source: S, signal: AbortSignal) => Promise<T>} Вовращает обернутую функцию с сохраненной сигнатурой типов.
|
|
31
|
+
*/
|
|
32
|
+
export declare const withStaleWhileRevalidate: <S, T>(fetcher: (source: S, signal: AbortSignal) => Promise<T>, options?: StaleOptions<T>) => (source: S, signal: AbortSignal) => Promise<T>;
|
|
33
|
+
export {};
|
|
34
|
+
//# sourceMappingURL=withStaleWhileRevalidate.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withStaleWhileRevalidate.d.ts","sourceRoot":"","sources":["../../../src/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.ts"],"names":[],"mappings":"AAAA,UAAU,YAAY,CAAC,CAAC;IACtB;;;OAGG;IACH,WAAW,CAAC,EAAE,CAAC,CAAC;IAChB,aAAa,CAAC,EAAE,OAAO,CAAC;CACzB;AAED;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,eAAO,MAAM,wBAAwB,GAAI,CAAC,EAAE,CAAC,EAC3C,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,EACvD,UAAS,YAAY,CAAC,CAAC,CAAM,MAMf,QAAQ,CAAC,EAAE,QAAQ,WAAW,KAAG,OAAO,CAAC,CAAC,CAmCzD,CAAA"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
//#region src/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.ts
|
|
2
|
+
var e = (e, t = {}) => {
|
|
3
|
+
let n = t.initialData, r = t.isLogsEnabled ?? !1;
|
|
4
|
+
return async (t, i) => {
|
|
5
|
+
if (i.aborted) {
|
|
6
|
+
if (n !== void 0) return n;
|
|
7
|
+
throw i.reason || new DOMException("The operation was aborted.", "AbortError");
|
|
8
|
+
}
|
|
9
|
+
try {
|
|
10
|
+
let r = await e(t, i);
|
|
11
|
+
return n = r, r;
|
|
12
|
+
} catch (e) {
|
|
13
|
+
let t = e instanceof DOMException && e.name === "AbortError";
|
|
14
|
+
if (n !== void 0) return r && console.warn(`[ReactiveEngine:Stale] Запрос ${t ? "отменен" : "упал с ошибкой"}. Отдаем предыдущее состояние.`, e), n;
|
|
15
|
+
throw e;
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
//#endregion
|
|
20
|
+
export { e as withStaleWhileRevalidate };
|
|
21
|
+
|
|
22
|
+
//# sourceMappingURL=withStaleWhileRevalidate.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withStaleWhileRevalidate.mjs","names":[],"sources":["../../../src/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.ts"],"sourcesContent":["interface StaleOptions<T> {\n /**\n * Дефолтное значение, которое вернется при самом первом запросе,\n * если он завершился ошибкой или был отменен.\n */\n initialData?: T;\n isLogsEnabled?: boolean;\n}\n\n/**\n * Декоратор для сохранения предыдущего успешного состояния данных,\n * специально адаптированный для использования совместно с `engine.resource`.\n *\n * Оборачивает асинхронную функцию `fetcher`. Если текущий запрос отменяется\n * (например, через AbortSignal при перетаскивании карты) или завершается ошибкой,\n * декоратор перехватывает исключение и возвращает последнее успешно полученное значение.\n *\n * ### 🧠 Механика Stale-While-Revalidate:\n * 1. **Стабильный кэш последнего состояния:** Декоратор сохраняет в замыкании успешный результат.\n * 2. **Грациозная деградация (Graceful Degradation):** При возникновении `AbortError` (отмена)\n * или любого другого сетевого сбоя, вместо выброса исключения в граф возвращается `stale`-дата.\n * 3. **Бесшовный UX:** Карта или UI-компонент не сбрасывают свое состояние в `null` во время\n * перепривязки сигналов, исключая эффект \"моргания\".\n *\n * @template S Тип входных данных (аргументов) для функции запроса.\n * @template T Тип данных, возвращаемых асинхронным `fetcher`-ом.\n *\n * @param {(source: S, signal: AbortSignal) => Promise<T>} fetcher Оригинальная асинхронная функция запроса.\n * @param {StaleOptions<T>} [options={}] Параметры конфигурации предыдущего состояния.\n *\n * @returns {(source: S, signal: AbortSignal) => Promise<T>} Вовращает обернутую функцию с сохраненной сигнатурой типов.\n */\nexport const withStaleWhileRevalidate = <S, T>(\n fetcher: (source: S, signal: AbortSignal) => Promise<T>,\n options: StaleOptions<T> = {}\n) => {\n // Хранилище для последнего успешного ответа сервера в рамках замыкания декоратора\n let lastValidData: T | undefined = options.initialData\n const isLogsEnabled = options.isLogsEnabled ?? false\n\n return async (source: S, signal: AbortSignal): Promise<T> => {\n // Если запрос отменен еще до старта, сразу возвращаем последнее известное состояние\n if (signal.aborted) {\n if (lastValidData !== undefined) return lastValidData\n throw signal.reason || new DOMException('The operation was aborted.', 'AbortError')\n }\n\n try {\n // Выполняем реальный сетевой запрос\n const freshData = await fetcher(source, signal)\n\n // Запоминаем успешный результат\n lastValidData = freshData\n\n return freshData\n } catch (error) {\n // Если запрос был отменен движком (например, изменился bbox) ИЛИ произошла сетевая ошибка\n const isAbort = error instanceof DOMException && error.name === 'AbortError'\n\n // Если у нас уже есть сохраненные старые данные — отдаем их вместо падения\n if (lastValidData !== undefined) {\n if (isLogsEnabled) {\n // Логируем для трассировки в dev-режиме (опционально)\n console.warn(\n `[ReactiveEngine:Stale] Запрос ${isAbort ? 'отменен' : 'упал с ошибкой'}. Отдаем предыдущее состояние.`,\n error\n )\n }\n return lastValidData\n }\n\n // Если это самый первый запрос и кэш пуст — прокидываем ошибку дальше в граф\n throw error\n }\n }\n}\n"],"mappings":";AAgCA,IAAa,KACX,GACA,IAA2B,CAAC,MACzB;CAEH,IAAI,IAA+B,EAAQ,aACrC,IAAgB,EAAQ,iBAAiB;CAE/C,OAAO,OAAO,GAAW,MAAoC;EAE3D,IAAI,EAAO,SAAS;GAClB,IAAI,MAAkB,KAAA,GAAW,OAAO;GACxC,MAAM,EAAO,UAAU,IAAI,aAAa,8BAA8B,YAAY;EACpF;EAEA,IAAI;GAEF,IAAM,IAAY,MAAM,EAAQ,GAAQ,CAAM;GAK9C,OAFA,IAAgB,GAET;EACT,SAAS,GAAO;GAEd,IAAM,IAAU,aAAiB,gBAAgB,EAAM,SAAS;GAGhE,IAAI,MAAkB,KAAA,GAQpB,OAPI,KAEF,QAAQ,KACN,iCAAiC,IAAU,YAAY,iBAAiB,iCACxE,CACF,GAEK;GAIT,MAAM;EACR;CACF;AACF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withStaleWhileRevalidate.test.d.ts","sourceRoot":"","sources":["../../../src/decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.test.ts"],"names":[],"mappings":""}
|
package/dist/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./core.cjs"),t=require("./AbstractService.cjs"),n=require("./BaseREServiceEnhanced.cjs"),r=require("./decorators/withCache/withCache.cjs"),i=require("./decorators/withDebounce/withDebounce.cjs"),a=require("./decorators/withLongPolling/withLongPolling.cjs"),o=require("./decorators/withThrottle/withThrottle.cjs"),s=require("./decorators/withThrottleComputed/withThrottleComputed.cjs"),c=require("./decorators/withThrottleAndCache/withThrottleAndCache.cjs");exports.AbstractService=t.AbstractService,exports.BaseREService=t.BaseREService,exports.BaseREServiceEnhanced=n.BaseREServiceEnhanced,exports.ReactiveEngine=e.ReactiveEngine,exports.withCache=r.withCache,exports.withDebounce=i.withDebounce,exports.withLongPolling=a.withLongPolling,exports.withThrottle=o.withThrottle,exports.withThrottleAndCache=c.withThrottleAndCache,exports.withThrottleComputed=s.withThrottleComputed;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./core.cjs"),t=require("./AbstractService.cjs"),n=require("./BaseREServiceEnhanced.cjs"),r=require("./decorators/withCache/withCache.cjs"),i=require("./decorators/withDebounce/withDebounce.cjs"),a=require("./decorators/withLongPolling/withLongPolling.cjs"),o=require("./decorators/withThrottle/withThrottle.cjs"),s=require("./decorators/withThrottleComputed/withThrottleComputed.cjs"),c=require("./decorators/withThrottleAndCache/withThrottleAndCache.cjs"),l=require("./decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.cjs");exports.AbstractService=t.AbstractService,exports.BaseREService=t.BaseREService,exports.BaseREServiceEnhanced=n.BaseREServiceEnhanced,exports.ReactiveEngine=e.ReactiveEngine,exports.withCache=r.withCache,exports.withDebounce=i.withDebounce,exports.withLongPolling=a.withLongPolling,exports.withStaleWhileRevalidate=l.withStaleWhileRevalidate,exports.withThrottle=o.withThrottle,exports.withThrottleAndCache=c.withThrottleAndCache,exports.withThrottleComputed=s.withThrottleComputed;
|
package/dist/index.mjs
CHANGED
|
@@ -7,4 +7,5 @@ import { withLongPolling as o } from "./decorators/withLongPolling/withLongPolli
|
|
|
7
7
|
import { withThrottle as s } from "./decorators/withThrottle/withThrottle.mjs";
|
|
8
8
|
import { withThrottleComputed as c } from "./decorators/withThrottleComputed/withThrottleComputed.mjs";
|
|
9
9
|
import { withThrottleAndCache as l } from "./decorators/withThrottleAndCache/withThrottleAndCache.mjs";
|
|
10
|
-
|
|
10
|
+
import { withStaleWhileRevalidate as u } from "./decorators/withStaleWhileRevalidate/withStaleWhileRevalidate.mjs";
|
|
11
|
+
export { t as AbstractService, n as BaseREService, r as BaseREServiceEnhanced, e as ReactiveEngine, i as withCache, a as withDebounce, o as withLongPolling, u as withStaleWhileRevalidate, s as withThrottle, l as withThrottleAndCache, c as withThrottleComputed };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="120px" height="120px"><circle cx="256" cy="256" r="256" fill="#000" fill-opacity="1"></circle><g class="" transform="translate(0,0)" style=""><path d="M36.078 16 16 35.55v50.247L87.684 16H36.078zm121.83 0-97.834 95.26c8.838-.48 17.72-.946 27.207-1.367L183.71 16h-25.8zm107.768 0L217.72 62.693c11.73-7.19 24.684-14.537 37.987-21.455 17.973-9.346 36.334-17.656 52.807-23.023 2.466-.804 4.865-1.53 7.234-2.215h-50.072zm105.627 0-4.29 3.432c56.944 23.005 97.62 63.682 120.628 120.627l8.16-10.2C475.674 75.84 440.51 38.356 388.93 16H371.3zm55.894 0C455.86 34.214 478.884 58.318 496 88.027V63.582C484.442 45.14 469.57 29.234 451.488 16h-24.29zm52.176 0A192.31 192.31 0 0 1 496 33.447V16h-16.627zM341.316 30.266c-6.124-.108-15.98 1.4-27.226 5.064-14.994 4.886-32.696 12.84-50.078 21.88a519.558 519.558 0 0 0-18.948 10.384c27.085 5.188 54.39 17.866 79.737 35.3l69.516-49.654c-14.42-8.99-30.465-16.435-48.207-22.35-1.126-.374-2.752-.588-4.794-.624zm68.713 33.87-69.99 49.995a317.653 317.653 0 0 1 28.007 24.895 317.684 317.684 0 0 1 24.902 28.002l49.988-69.986a181.614 181.614 0 0 0-32.91-32.905zm-193.41 18.08c-19.394.162-36.698 5.932-49.39 18.626a58.492 58.492 0 0 0-6.992 8.447c7.737.345 15.336.865 22.698 1.606 8.6-7.025 20.286-10.66 34.26-10.71 9.396-.034 19.82 1.55 31.025 4.802 29.88 8.675 64.076 29.196 94.372 59.492 30.296 30.297 50.82 64.496 59.494 94.374 8.674 29.877 5.474 54.205-8.582 68.26a40.523 40.523 0 0 1-7.076 5.63 234.492 234.492 0 0 1-5.32 22.106c9.518-3 18.04-7.923 25.124-15.006 20.31-20.31 22.893-52.42 13.14-86.01-9.36-32.248-30.12-66.993-60.245-98.2l-.09-.093-.057-.056a307.882 307.882 0 0 0-3.66-3.73h-.002a308.138 308.138 0 0 0-3.726-3.66l-.06-.06a2.16 2.16 0 0 1-.1-.093c-31.205-30.12-65.946-50.88-98.192-60.24-12.596-3.658-24.985-5.58-36.62-5.483zM453.83 112.76l-49.652 69.515c17.437 25.354 30.1 52.67 35.285 79.762a519.383 519.383 0 0 0 10.4-18.974c9.04-17.382 16.992-35.084 21.877-50.078 4.886-14.993 5.94-27.516 4.44-32.017-5.914-17.742-13.36-33.785-22.35-48.207zm-315.766 14.306c-24.424-.103-49.52 1.074-72.78 2.217 7.69 2.09 14.93 3.963 22.872 6.343 29.69 8.9 59.69 19.512 74.75 40.217l12.465 17.137-20.988-2.93c-45.902-6.41-74.37 5.044-101.47 15.693 33.77 7.288 58.506 15.248 87.683 36.73l13.96 10.278-16.44 5.504C78.56 278.195 47.45 315.047 16 357.834v22.143c9.58-5.07 19.283-10.596 29.057-15.934 27.153-14.832 55.85-28.346 85.502-19.572l7.84 2.32-1.56 8.028c-6.803 35.01-28.027 91.445-48.008 141.182h15.455c44.07-50.768 93.33-113.807 108.994-146.596l7.16-14.984 8.644 14.178c5.784 9.484 3.667 19.766.973 31.724-2.694 11.958-7.28 25.69-12.178 39.88-6.224 18.024-12.536 36.71-16.552 52.19 12.538-12.48 25.598-29.23 36.842-46.912 16.8-26.42 29.886-55.1 33.586-72.515l5.015-23.613 11.668 21.134c12.356 22.385 10.967 52.3 6.996 84.723-2.37 19.346-5.82 39.638-8.854 59.653 14.87-22.31 32.57-48.36 48.307-77.36 24.843-45.79 43.262-96.883 34.79-143.876-2.723-15.107-13.146-34.003-28.327-52.83-21.165 6.466-42.44 20.892-62.875 40.822 17.09-29.95 23.5-49.964 37.183-65.225-24.578 10.682-57.176 29.572-91.263 62.765 19.654-25.258 40.095-64.07 53.935-91.478-20.372 15.64-51.45 31.377-71.21 43.81 9.8-15.11 30.47-43.68 36.517-66.957-10.983-4.976-21.758-8.688-31.87-10.765l-.148-.032-.15-.035c-20.223-4.873-46.176-6.523-73.404-6.64zM31.73 138.86 16 154.177V179.3l35.928-34.984c-7.012-1.842-13.946-3.663-20.2-5.455zm82.047 25.04-8.13 7.916a179.563 179.563 0 0 1 21.603-1.504c-4.143-2.217-8.685-4.355-13.473-6.412zM52.14 223.916 16 259.106v50.244l75.926-73.928C79.87 230.577 67.19 227.2 52.14 223.916zM496 287.72 346.97 432.83c-13.02 23.235-27.113 44.683-39.44 63.172h26.163L496 337.965V287.72zm-384.45 72.075c-3.92 0-7.91.426-11.972 1.203L16 442.378V467.5l97.834-95.258c1.202-4.276 2.285-8.36 3.193-12.162a51.858 51.858 0 0 0-5.476-.285zM496 368.81 365.373 496h25.8L496 393.934V368.81zm-295.277 45.924-27.32 26.602c-14.17 18.31-29.498 36.993-44.624 54.664h14.282l44.74-43.56c3.907-12.385 8.606-25.225 12.92-37.706z" fill="#fff" fill-opacity="1"></path></g></svg>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 512px; width: 512px;"><circle cx="256" cy="256" r="256" fill="#000" fill-opacity="1"></circle><g class="" transform="translate(0,0)" style=""><path d="M36.078 16 16 35.55v50.247L87.684 16H36.078zm121.83 0-97.834 95.26c8.838-.48 17.72-.946 27.207-1.367L183.71 16h-25.8zm107.768 0L217.72 62.693c11.73-7.19 24.684-14.537 37.987-21.455 17.973-9.346 36.334-17.656 52.807-23.023 2.466-.804 4.865-1.53 7.234-2.215h-50.072zm105.627 0-4.29 3.432c56.944 23.005 97.62 63.682 120.628 120.627l8.16-10.2C475.674 75.84 440.51 38.356 388.93 16H371.3zm55.894 0C455.86 34.214 478.884 58.318 496 88.027V63.582C484.442 45.14 469.57 29.234 451.488 16h-24.29zm52.176 0A192.31 192.31 0 0 1 496 33.447V16h-16.627zM341.316 30.266c-6.124-.108-15.98 1.4-27.226 5.064-14.994 4.886-32.696 12.84-50.078 21.88a519.558 519.558 0 0 0-18.948 10.384c27.085 5.188 54.39 17.866 79.737 35.3l69.516-49.654c-14.42-8.99-30.465-16.435-48.207-22.35-1.126-.374-2.752-.588-4.794-.624zm68.713 33.87-69.99 49.995a317.653 317.653 0 0 1 28.007 24.895 317.684 317.684 0 0 1 24.902 28.002l49.988-69.986a181.614 181.614 0 0 0-32.91-32.905zm-193.41 18.08c-19.394.162-36.698 5.932-49.39 18.626a58.492 58.492 0 0 0-6.992 8.447c7.737.345 15.336.865 22.698 1.606 8.6-7.025 20.286-10.66 34.26-10.71 9.396-.034 19.82 1.55 31.025 4.802 29.88 8.675 64.076 29.196 94.372 59.492 30.296 30.297 50.82 64.496 59.494 94.374 8.674 29.877 5.474 54.205-8.582 68.26a40.523 40.523 0 0 1-7.076 5.63 234.492 234.492 0 0 1-5.32 22.106c9.518-3 18.04-7.923 25.124-15.006 20.31-20.31 22.893-52.42 13.14-86.01-9.36-32.248-30.12-66.993-60.245-98.2l-.09-.093-.057-.056a307.882 307.882 0 0 0-3.66-3.73h-.002a308.138 308.138 0 0 0-3.726-3.66l-.06-.06a2.16 2.16 0 0 1-.1-.093c-31.205-30.12-65.946-50.88-98.192-60.24-12.596-3.658-24.985-5.58-36.62-5.483zM453.83 112.76l-49.652 69.515c17.437 25.354 30.1 52.67 35.285 79.762a519.383 519.383 0 0 0 10.4-18.974c9.04-17.382 16.992-35.084 21.877-50.078 4.886-14.993 5.94-27.516 4.44-32.017-5.914-17.742-13.36-33.785-22.35-48.207zm-315.766 14.306c-24.424-.103-49.52 1.074-72.78 2.217 7.69 2.09 14.93 3.963 22.872 6.343 29.69 8.9 59.69 19.512 74.75 40.217l12.465 17.137-20.988-2.93c-45.902-6.41-74.37 5.044-101.47 15.693 33.77 7.288 58.506 15.248 87.683 36.73l13.96 10.278-16.44 5.504C78.56 278.195 47.45 315.047 16 357.834v22.143c9.58-5.07 19.283-10.596 29.057-15.934 27.153-14.832 55.85-28.346 85.502-19.572l7.84 2.32-1.56 8.028c-6.803 35.01-28.027 91.445-48.008 141.182h15.455c44.07-50.768 93.33-113.807 108.994-146.596l7.16-14.984 8.644 14.178c5.784 9.484 3.667 19.766.973 31.724-2.694 11.958-7.28 25.69-12.178 39.88-6.224 18.024-12.536 36.71-16.552 52.19 12.538-12.48 25.598-29.23 36.842-46.912 16.8-26.42 29.886-55.1 33.586-72.515l5.015-23.613 11.668 21.134c12.356 22.385 10.967 52.3 6.996 84.723-2.37 19.346-5.82 39.638-8.854 59.653 14.87-22.31 32.57-48.36 48.307-77.36 24.843-45.79 43.262-96.883 34.79-143.876-2.723-15.107-13.146-34.003-28.327-52.83-21.165 6.466-42.44 20.892-62.875 40.822 17.09-29.95 23.5-49.964 37.183-65.225-24.578 10.682-57.176 29.572-91.263 62.765 19.654-25.258 40.095-64.07 53.935-91.478-20.372 15.64-51.45 31.377-71.21 43.81 9.8-15.11 30.47-43.68 36.517-66.957-10.983-4.976-21.758-8.688-31.87-10.765l-.148-.032-.15-.035c-20.223-4.873-46.176-6.523-73.404-6.64zM31.73 138.86 16 154.177V179.3l35.928-34.984c-7.012-1.842-13.946-3.663-20.2-5.455zm82.047 25.04-8.13 7.916a179.563 179.563 0 0 1 21.603-1.504c-4.143-2.217-8.685-4.355-13.473-6.412zM52.14 223.916 16 259.106v50.244l75.926-73.928C79.87 230.577 67.19 227.2 52.14 223.916zM496 287.72 346.97 432.83c-13.02 23.235-27.113 44.683-39.44 63.172h26.163L496 337.965V287.72zm-384.45 72.075c-3.92 0-7.91.426-11.972 1.203L16 442.378V467.5l97.834-95.258c1.202-4.276 2.285-8.36 3.193-12.162a51.858 51.858 0 0 0-5.476-.285zM496 368.81 365.373 496h25.8L496 393.934V368.81zm-295.277 45.924-27.32 26.602c-14.17 18.31-29.498 36.993-44.624 54.664h14.282l44.74-43.56c3.907-12.385 8.606-25.225 12.92-37.706z" fill="#fff" fill-opacity="1"></path></g></svg>
|
package/package.json
CHANGED
package/dist/vite.svg
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>
|