@pravosleva/reactive-engine 1.5.5-beta → 1.5.7-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/dist/decorators/index.d.ts +6 -6
- package/dist/decorators/index.d.ts.map +1 -1
- package/dist/decorators/withCache/withCache.cjs +2 -0
- package/dist/decorators/withCache/withCache.cjs.map +1 -0
- package/dist/decorators/withCache/withCache.mjs +17 -0
- package/dist/decorators/withCache/withCache.mjs.map +1 -0
- package/dist/decorators/withDebounce/withDebounce.cjs +2 -0
- package/dist/decorators/withDebounce/withDebounce.cjs.map +1 -0
- package/dist/decorators/withDebounce/withDebounce.mjs +23 -0
- package/dist/decorators/withDebounce/withDebounce.mjs.map +1 -0
- package/dist/decorators/withLongPolling/withLongPolling.cjs +2 -0
- package/dist/decorators/withLongPolling/withLongPolling.cjs.map +1 -0
- package/dist/decorators/withLongPolling/withLongPolling.mjs +45 -0
- package/dist/decorators/withLongPolling/withLongPolling.mjs.map +1 -0
- package/dist/decorators/withThrottle/withThrottle.cjs +2 -0
- package/dist/decorators/withThrottle/withThrottle.cjs.map +1 -0
- package/dist/decorators/withThrottle/withThrottle.mjs +26 -0
- package/dist/decorators/withThrottle/withThrottle.mjs.map +1 -0
- package/dist/decorators/withThrottleAndCache/withThrottleAndCache.cjs +2 -0
- package/dist/decorators/withThrottleAndCache/withThrottleAndCache.cjs.map +1 -0
- package/dist/decorators/withThrottleAndCache/withThrottleAndCache.mjs +36 -0
- package/dist/decorators/withThrottleAndCache/withThrottleAndCache.mjs.map +1 -0
- package/dist/decorators/withThrottleComputed/withThrottleComputed.cjs +2 -0
- package/dist/decorators/withThrottleComputed/withThrottleComputed.cjs.map +1 -0
- package/dist/decorators/withThrottleComputed/withThrottleComputed.mjs +29 -0
- package/dist/decorators/withThrottleComputed/withThrottleComputed.mjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.d.ts +3 -2
- package/dist/index.mjs +7 -1
- package/dist/reactive-engine.umd.js +11 -0
- package/dist/vue/composables/index.d.ts +2 -0
- package/dist/vue/composables/index.d.ts.map +1 -0
- package/dist/vue/composables/useReactiveValue.cjs +2 -0
- package/dist/vue/composables/useReactiveValue.cjs.map +1 -0
- package/dist/vue/composables/useReactiveValue.d.ts +53 -0
- package/dist/vue/composables/useReactiveValue.d.ts.map +1 -0
- package/dist/vue/composables/useReactiveValue.mjs +14 -0
- package/dist/vue/composables/useReactiveValue.mjs.map +1 -0
- package/dist/vue/composables/useReactiveValue.test.d.ts +2 -0
- package/dist/vue/composables/useReactiveValue.test.d.ts.map +1 -0
- package/dist/vue/index.cjs +1 -1
- package/dist/vue/index.d.ts +1 -0
- package/dist/vue/index.d.ts.map +1 -1
- package/dist/vue/index.mjs +2 -1
- package/package.json +1 -1
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export
|
|
2
|
-
export
|
|
3
|
-
export
|
|
4
|
-
export
|
|
5
|
-
export
|
|
6
|
-
export
|
|
1
|
+
export { withCache } from './withCache';
|
|
2
|
+
export { withDebounce } from './withDebounce';
|
|
3
|
+
export { withLongPolling } from './withLongPolling';
|
|
4
|
+
export { withThrottle } from './withThrottle';
|
|
5
|
+
export { withThrottleComputed } from './withThrottleComputed';
|
|
6
|
+
export { withThrottleAndCache } from './withThrottleAndCache';
|
|
7
7
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/decorators/index.ts"],"names":[],"mappings":"AAAA,
|
|
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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=(e,t={})=>{let n=t.ttl??300*1e3,r=new Map;return async(t,i)=>{let a=typeof t==`object`&&t?JSON.stringify(t):String(t),o=Date.now(),s=r.get(a);if(s&&o-s.timestamp<n)return s.data;let c=await e(t,i);return r.set(a,{data:c,timestamp:Date.now()}),c}};exports.withCache=e;
|
|
2
|
+
//# sourceMappingURL=withCache.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withCache.cjs","names":[],"sources":["../../../src/decorators/withCache/withCache.ts"],"sourcesContent":["interface CacheEntry<T> {\n data: T;\n timestamp: number;\n}\n\ninterface CacheOptions {\n /** Время жизни кэша в миллисекундах. По умолчанию 5 минут (300000 мс) */\n ttl?: number;\n}\n\n/**\n * Декоратор для создания кэширующего fetcher-а для engine.resource\n * @param fetcher Оригинальная асинхронная функция запроса\n * @param options Настройки кэширования\n * @source\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 const cache = new Map<string, CacheEntry<T>>()\n\n return async (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 const now = Date.now()\n const cached = cache.get(cacheKey)\n\n // 2. Проверяем, есть ли валидный (не устаревший) кэш\n if (cached && (now - cached.timestamp < ttl)) {\n return cached.data\n }\n\n // 3. Если кэша нет или он устарел — делаем реальный сетевой запрос\n const freshData = await fetcher(source, signal)\n\n // 4. Сохраняем свежие данные и метку времени в кэш\n cache.set(cacheKey, {\n data: freshData,\n timestamp: Date.now() // берем актуальное время после завершения запроса\n })\n\n return freshData\n }\n}\n"],"mappings":"AAgBA,IAAa,GACX,EACA,EAAwB,CAAC,IACtB,CACH,IAAM,EAAM,EAAQ,KAAO,IAAS,IAC9B,EAAQ,IAAI,IAElB,OAAO,MAAO,EAAW,IAAoC,CAE3D,IAAM,EAAW,OAAO,GAAW,UAAY,EAC3C,KAAK,UAAU,CAAM,EACrB,OAAO,CAAM,EAEX,EAAM,KAAK,IAAI,EACf,EAAS,EAAM,IAAI,CAAQ,EAGjC,GAAI,GAAW,EAAM,EAAO,UAAY,EACtC,OAAO,EAAO,KAIhB,IAAM,EAAY,MAAM,EAAQ,EAAQ,CAAM,EAQ9C,OALA,EAAM,IAAI,EAAU,CAClB,KAAM,EACN,UAAW,KAAK,IAAI,CACtB,CAAC,EAEM,CACT,CACF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/decorators/withCache/withCache.ts
|
|
2
|
+
var e = (e, t = {}) => {
|
|
3
|
+
let n = t.ttl ?? 300 * 1e3, r = /* @__PURE__ */ new Map();
|
|
4
|
+
return async (t, i) => {
|
|
5
|
+
let a = typeof t == "object" && t ? JSON.stringify(t) : String(t), o = Date.now(), s = r.get(a);
|
|
6
|
+
if (s && o - s.timestamp < n) return s.data;
|
|
7
|
+
let c = await e(t, i);
|
|
8
|
+
return r.set(a, {
|
|
9
|
+
data: c,
|
|
10
|
+
timestamp: Date.now()
|
|
11
|
+
}), c;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
//#endregion
|
|
15
|
+
export { e as withCache };
|
|
16
|
+
|
|
17
|
+
//# sourceMappingURL=withCache.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withCache.mjs","names":[],"sources":["../../../src/decorators/withCache/withCache.ts"],"sourcesContent":["interface CacheEntry<T> {\n data: T;\n timestamp: number;\n}\n\ninterface CacheOptions {\n /** Время жизни кэша в миллисекундах. По умолчанию 5 минут (300000 мс) */\n ttl?: number;\n}\n\n/**\n * Декоратор для создания кэширующего fetcher-а для engine.resource\n * @param fetcher Оригинальная асинхронная функция запроса\n * @param options Настройки кэширования\n * @source\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 const cache = new Map<string, CacheEntry<T>>()\n\n return async (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 const now = Date.now()\n const cached = cache.get(cacheKey)\n\n // 2. Проверяем, есть ли валидный (не устаревший) кэш\n if (cached && (now - cached.timestamp < ttl)) {\n return cached.data\n }\n\n // 3. Если кэша нет или он устарел — делаем реальный сетевой запрос\n const freshData = await fetcher(source, signal)\n\n // 4. Сохраняем свежие данные и метку времени в кэш\n cache.set(cacheKey, {\n data: freshData,\n timestamp: Date.now() // берем актуальное время после завершения запроса\n })\n\n return freshData\n }\n}\n"],"mappings":";AAgBA,IAAa,KACX,GACA,IAAwB,CAAC,MACtB;CACH,IAAM,IAAM,EAAQ,OAAO,MAAS,KAC9B,oBAAQ,IAAI,IAA2B;CAE7C,OAAO,OAAO,GAAW,MAAoC;EAE3D,IAAM,IAAW,OAAO,KAAW,YAAY,IAC3C,KAAK,UAAU,CAAM,IACrB,OAAO,CAAM,GAEX,IAAM,KAAK,IAAI,GACf,IAAS,EAAM,IAAI,CAAQ;EAGjC,IAAI,KAAW,IAAM,EAAO,YAAY,GACtC,OAAO,EAAO;EAIhB,IAAM,IAAY,MAAM,EAAQ,GAAQ,CAAM;EAQ9C,OALA,EAAM,IAAI,GAAU;GAClB,MAAM;GACN,WAAW,KAAK,IAAI;EACtB,CAAC,GAEM;CACT;AACF"}
|
|
@@ -0,0 +1,2 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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 * Декоратор для создания дебаунсящего fetcher-а для engine.resource\n * @param fetcher Оригинальная асинхронная функция запроса\n * @param options Настройки дебаунса\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":"AAUA,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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
//#region src/decorators/withDebounce/withDebounce.ts
|
|
2
|
+
var e = (e, t = {}) => {
|
|
3
|
+
let n = t.delay ?? 300, r = null, i = null;
|
|
4
|
+
return (t, a) => (r && clearTimeout(r), i && i(new DOMException("Aborted due to debounce", "AbortError")), new Promise((o, s) => {
|
|
5
|
+
i = s;
|
|
6
|
+
let c = () => {
|
|
7
|
+
r && clearTimeout(r), s(new DOMException("Aborted by resource signal", "AbortError"));
|
|
8
|
+
};
|
|
9
|
+
if (a.aborted) return c();
|
|
10
|
+
a.addEventListener("abort", c), r = setTimeout(async () => {
|
|
11
|
+
a.removeEventListener("abort", c), i = null, r = null;
|
|
12
|
+
try {
|
|
13
|
+
o(await e(t, a));
|
|
14
|
+
} catch (e) {
|
|
15
|
+
s(e);
|
|
16
|
+
}
|
|
17
|
+
}, n);
|
|
18
|
+
}));
|
|
19
|
+
};
|
|
20
|
+
//#endregion
|
|
21
|
+
export { e as withDebounce };
|
|
22
|
+
|
|
23
|
+
//# sourceMappingURL=withDebounce.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withDebounce.mjs","names":[],"sources":["../../../src/decorators/withDebounce/withDebounce.ts"],"sourcesContent":["interface DebounceOptions {\n /** Задержка в миллисекундах. По умолчанию 300 мс */\n delay?: number;\n}\n\n/**\n * Декоратор для создания дебаунсящего fetcher-а для engine.resource\n * @param fetcher Оригинальная асинхронная функция запроса\n * @param options Настройки дебаунса\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":";AAUA,IAAa,KACX,GACA,IAA2B,CAAC,MACzB;CACH,IAAM,IAAQ,EAAQ,SAAS,KAG3B,IAAkD,MAElD,IAAiD;CAErD,QAAQ,GAAW,OAEb,KACF,aAAa,CAAS,GAEpB,KAEF,EAAe,IAAI,aAAa,2BAA2B,YAAY,CAAC,GAGnE,IAAI,SAAY,GAAS,MAAW;EAEzC,IAAiB;EAGjB,IAAM,UAAgB;GAEpB,AADI,KAAW,aAAa,CAAS,GACrC,EAAO,IAAI,aAAa,8BAA8B,YAAY,CAAC;EACrE;EAEA,IAAI,EAAO,SACT,OAAO,EAAQ;EAKjB,AAHA,EAAO,iBAAiB,SAAS,CAAO,GAGxC,IAAY,WAAW,YAAY;GAIjC,AAFA,EAAO,oBAAoB,SAAS,CAAO,GAC3C,IAAiB,MACjB,IAAY;GAEZ,IAAI;IAGF,EAAQ,MADW,EAAQ,GAAQ,CAAM,CAC7B;GACd,SAAS,GAAO;IACd,EAAO,CAAK;GACd;EACF,GAAG,CAAK;CACV,CAAC;AAEL"}
|
|
@@ -0,0 +1,2 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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 * Адаптированный декоратор лонг-поллинга для engine.resource.\n * Принимает строго два аргумента: асинхронную функцию и конфиг-объект.\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":"AA4BA,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"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
//#region src/decorators/withLongPolling/withLongPolling.ts
|
|
2
|
+
var e = (e, t) => {
|
|
3
|
+
let { onNextTick: n, onError: r, externalSignal: i, delay: a = 500, errorInitialDelay: o = 2e3, errorMaxDelay: s = 8e3 } = t, c = o, l = 0;
|
|
4
|
+
return (t, u) => {
|
|
5
|
+
let d = ++l;
|
|
6
|
+
return new Promise((f, p) => {
|
|
7
|
+
let m = async () => {
|
|
8
|
+
if (u.aborted || i?.aborted) {
|
|
9
|
+
p(new DOMException("Aborted by long polling lifecycle", "AbortError"));
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
try {
|
|
13
|
+
let r = await e(t, u);
|
|
14
|
+
if (c = o, u.aborted || i?.aborted) {
|
|
15
|
+
p(new DOMException("Aborted by long polling lifecycle", "AbortError"));
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
f(r), setTimeout(() => {
|
|
19
|
+
d === l && !u.aborted && !i?.aborted && n?.();
|
|
20
|
+
}, a);
|
|
21
|
+
} catch (e) {
|
|
22
|
+
if (e instanceof DOMException && e.name === "AbortError") {
|
|
23
|
+
p(e);
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
p(e);
|
|
27
|
+
let t = c;
|
|
28
|
+
typeof r == "function" && r(t, () => {
|
|
29
|
+
d === l && (c = Math.min(c * 2, s));
|
|
30
|
+
}), setTimeout(() => {
|
|
31
|
+
d === l && !u.aborted && !i?.aborted && n?.();
|
|
32
|
+
}, t);
|
|
33
|
+
}
|
|
34
|
+
}, h = () => {
|
|
35
|
+
p(new DOMException("Aborted by lifecycle event", "AbortError"));
|
|
36
|
+
};
|
|
37
|
+
if (u.addEventListener("abort", h), i && i.addEventListener("abort", h), u.aborted || i?.aborted) return h();
|
|
38
|
+
m();
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
//#endregion
|
|
43
|
+
export { e as withLongPolling };
|
|
44
|
+
|
|
45
|
+
//# sourceMappingURL=withLongPolling.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withLongPolling.mjs","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 * Адаптированный декоратор лонг-поллинга для engine.resource.\n * Принимает строго два аргумента: асинхронную функцию и конфиг-объект.\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":";AA4BA,IAAa,KACX,GACA,MACG;CACH,IAAM,EACJ,eACA,YACA,mBACA,WAAQ,KACR,uBAAoB,KACpB,mBAAgB,QACd,GAEA,IAAoB,GACpB,IAAsB;CAE1B,QAAQ,GAAW,MAAoC;EACrD,IAAM,IAAkB,EAAE;EAE1B,OAAO,IAAI,SAAY,GAAS,MAAW;GAEzC,IAAM,IAAO,YAAY;IACvB,IAAI,EAAO,WAAW,GAAgB,SAAS;KAC7C,EAAO,IAAI,aAAa,qCAAqC,YAAY,CAAC;KAC1E;IACF;IAEA,IAAI;KACF,IAAM,IAAO,MAAM,EAAQ,GAAQ,CAAM;KAGzC,IAFA,IAAoB,GAEhB,EAAO,WAAW,GAAgB,SAAS;MAC7C,EAAO,IAAI,aAAa,qCAAqC,YAAY,CAAC;MAC1E;KACF;KAIA,AAFA,EAAQ,CAAI,GAEZ,iBAAiB;MACf,AAAI,MAAoB,KAAuB,CAAC,EAAO,WAAW,CAAC,GAAgB,WACjF,IAAa;KAEjB,GAAG,CAAK;IAEV,SAAS,GAAO;KACd,IAAI,aAAiB,gBAAgB,EAAM,SAAS,cAAc;MAChE,EAAO,CAAK;MACZ;KACF;KAEA,EAAO,CAAK;KACZ,IAAM,IAAgB;KAQtB,AANI,OAAO,KAAY,cAAY,EAAQ,SAAqB;MAC9D,AAAI,MAAoB,MACtB,IAAoB,KAAK,IAAI,IAAoB,GAAG,CAAa;KAErE,CAAC,GAED,iBAAiB;MACf,AAAI,MAAoB,KAAuB,CAAC,EAAO,WAAW,CAAC,GAAgB,WACjF,IAAa;KAEjB,GAAG,CAAa;IAClB;GACF,GAEM,UAAuB;IAC3B,EAAO,IAAI,aAAa,8BAA8B,YAAY,CAAC;GACrE;GAOA,IALA,EAAO,iBAAiB,SAAS,CAAc,GAC3C,KACF,EAAe,iBAAiB,SAAS,CAAc,GAGrD,EAAO,WAAW,GAAgB,SACpC,OAAO,EAAe;GAGxB,EAAK;EACP,CAAC;CACH;AACF"}
|
|
@@ -0,0 +1,2 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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 * Декоратор для создания троттлящего fetcher-а для engine.resource\n * @param fetcher Оригинальная асинхронная функция запроса\n * @param options Настройки троттлинга\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":"AAUA,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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/decorators/withThrottle/withThrottle.ts
|
|
2
|
+
var e = (e, t = {}) => {
|
|
3
|
+
let n = t.limit ?? 300, r = 0, i = null, a = null, o = null, s = null, c = null;
|
|
4
|
+
return (t, l) => {
|
|
5
|
+
let u = Date.now(), d = n - (u - r), f = () => {
|
|
6
|
+
i &&= (clearTimeout(i), null), s &&= (s(new DOMException("Aborted by resource signal during throttle", "AbortError")), o = null, null);
|
|
7
|
+
};
|
|
8
|
+
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) => {
|
|
9
|
+
if (a = t, o = n, s = u, c = l, l.aborted) return f();
|
|
10
|
+
l.addEventListener("abort", f), i ||= setTimeout(async () => {
|
|
11
|
+
i = null;
|
|
12
|
+
let t = a, n = o, l = s, u = c;
|
|
13
|
+
a = null, o = null, s = null, c = null, u.removeEventListener("abort", f);
|
|
14
|
+
try {
|
|
15
|
+
r = Date.now(), n(await e(t, u));
|
|
16
|
+
} catch (e) {
|
|
17
|
+
l(e);
|
|
18
|
+
}
|
|
19
|
+
}, d);
|
|
20
|
+
}));
|
|
21
|
+
};
|
|
22
|
+
};
|
|
23
|
+
//#endregion
|
|
24
|
+
export { e as withThrottle };
|
|
25
|
+
|
|
26
|
+
//# sourceMappingURL=withThrottle.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withThrottle.mjs","names":[],"sources":["../../../src/decorators/withThrottle/withThrottle.ts"],"sourcesContent":["interface ThrottleOptions {\n /** Интервал троттлинга в миллисекундах. По умолчанию 300 мс */\n limit?: number;\n}\n\n/**\n * Декоратор для создания троттлящего fetcher-а для engine.resource\n * @param fetcher Оригинальная асинхронная функция запроса\n * @param options Настройки троттлинга\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":";AAUA,IAAa,KACX,GACA,IAA2B,CAAC,MACzB;CACH,IAAM,IAAQ,EAAQ,SAAS,KAE3B,IAAoB,GACpB,IAA0D,MAG1D,IAA4B,MAC5B,IAAiE,MACjE,IAAkD,MAClD,IAAsC;CAE1C,QAAQ,GAAW,MAAoC;EACrD,IAAM,IAAM,KAAK,IAAI,GACf,IAAgB,KAAS,IAAM,IAG/B,UAAgB;GAKpB,AAJA,AAEE,OADA,aAAa,CAAiB,GACV,OAEtB,AAGE,OAFA,EAAgB,IAAI,aAAa,8CAA8C,YAAY,CAAC,GAC5F,IAAmB,MACD;EAEtB;EA0BA,OAvBI,KAAiB,KAEnB,AAEE,OADA,aAAa,CAAiB,GACV,OAEtB,AAGE,OAFA,EAAgB,IAAI,aAAa,kDAAkD,YAAY,CAAC,GAChG,IAAmB,MACD,OAGpB,IAAoB,GACb,EAAQ,GAAQ,CAAM,MAK3B,KAEF,EAAgB,IAAI,aAAa,wCAAwC,YAAY,CAAC,GAGjF,IAAI,SAAY,GAAS,MAAW;GAMzC,IALA,IAAkB,GAClB,IAAmB,GACnB,IAAkB,GAClB,IAAkB,GAEd,EAAO,SACT,OAAO,EAAQ;GAKjB,AAHA,EAAO,iBAAiB,SAAS,CAAO,GAGxC,AACE,MAAoB,WAAW,YAAY;IACzC,IAAoB;IAEpB,IAAM,IAAc,GACd,IAAe,GACf,IAAc,GACd,IAAc;IAOpB,AAJA,IAAkB,MAClB,IAAmB,MACnB,IAAkB,MAClB,IAAkB,MAClB,EAAY,oBAAoB,SAAS,CAAO;IAEhD,IAAI;KAGF,AAFA,IAAoB,KAAK,IAAI,GAE7B,EAAa,MADM,EAAQ,GAAa,CAAW,CAClC;IACnB,SAAS,GAAO;KACd,EAAY,CAAK;IACnB;GACF,GAAG,CAAa;EAEpB,CAAC;CACH;AACF"}
|
|
@@ -0,0 +1,2 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withThrottleAndCache.cjs","names":[],"sources":["../../../src/decorators/withThrottleAndCache/withThrottleAndCache.ts"],"sourcesContent":["interface ThrottleAndCacheOptions {\n /** Интервал троттлинга в миллисекундах. По умолчанию 300 мс */\n limit?: number;\n /** Время жизни кэша в миллисекундах. По умолчанию 5 минут (300000 мс) */\n ttl?: number;\n}\n\ninterface CacheEntry<T> {\n data: T;\n timestamp: number;\n}\n\n/**\n * Комбинированный декоратор: сначала применяет троттлинг к частоте вызовов,\n * а затем проверяет кэш перед отправкой реального fetcher-запроса.\n */\nexport const withThrottleAndCache = <S, T>(\n fetcher: (source: S, signal: AbortSignal) => Promise<T>,\n options: ThrottleAndCacheOptions = {}\n) => {\n const limit = options.limit ?? 300\n const ttl = options.ttl ?? 5 * 60 * 1000\n\n // Инфраструктура троттлинга\n let lastExecutionTime = 0\n let throttleTimeoutId: ReturnType<typeof setTimeout> | null = null\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 // Инфраструктура кэширования\n const cache = new Map<string, CacheEntry<T>>()\n\n // Внутренний хелпер для генерации ключа кэша\n const getCacheKey = (source: S): string => {\n return typeof source === 'object' && source !== null\n ? JSON.stringify(source)\n : String(source)\n }\n\n return (source: S, signal: AbortSignal): Promise<T> => {\n const now = Date.now()\n const remainingTime = limit - (now - lastExecutionTime)\n const cacheKey = getCacheKey(source)\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 // --- ФУНКЦИЯ ВЫПОЛНЕНИЯ ЗАПРОСА С УЧЕТОМ КЭША ---\n const executeWithCache = async (src: S, sig: AbortSignal): Promise<T> => {\n const currentNow = Date.now()\n const currentKey = getCacheKey(src)\n const cached = cache.get(currentKey)\n\n // Проверяем оперативную память на валидность кэша\n if (cached && currentNow - cached.timestamp < ttl) {\n return cached.data\n }\n\n // Если кэша нет — делаем реальный запрос\n const freshData = await fetcher(src, sig)\n\n // Сохраняем в кэш\n cache.set(currentKey, {\n data: freshData,\n timestamp: Date.now(),\n })\n\n return freshData\n }\n\n // --- ВЕТКА 1: Leading edge (Окно блокировки закрыто, выполняем сразу) ---\n if (remainingTime <= 0) {\n if (throttleTimeoutId) {\n clearTimeout(throttleTimeoutId)\n throttleTimeoutId = null\n }\n if (lastSavedReject) {\n lastSavedReject(new DOMException('Aborted due to newer direct execution', 'AbortError'))\n lastSavedResolve = null\n lastSavedReject = null\n }\n\n lastExecutionTime = now\n return executeWithCache(source, signal)\n }\n\n // --- ВЕТКА 2: Trailing edge (Внутри окна блокировки, перезаписываем хвост) ---\n if (lastSavedReject) {\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 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 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 executeWithCache(savedSource, savedSignal)\n savedResolve(data)\n } catch (error) {\n savedReject(error)\n }\n }, remainingTime)\n }\n })\n }\n}\n"],"mappings":"AAgBA,IAAa,GACX,EACA,EAAmC,CAAC,IACjC,CACH,IAAM,EAAQ,EAAQ,OAAS,IACzB,EAAM,EAAQ,KAAO,IAAS,IAGhC,EAAoB,EACpB,EAA0D,KAC1D,EAA4B,KAC5B,EAAiE,KACjE,EAAkD,KAClD,EAAsC,KAGpC,EAAQ,IAAI,IAGZ,EAAe,GACZ,OAAO,GAAW,UAAY,EACjC,KAAK,UAAU,CAAM,EACrB,OAAO,CAAM,EAGnB,OAAQ,EAAW,IAAoC,CACrD,IAAM,EAAM,KAAK,IAAI,EACf,EAAgB,GAAS,EAAM,GACpB,EAAY,CAAM,EAEnC,IAAM,MAAgB,CACpB,AAEE,KADA,aAAa,CAAiB,EACV,MAEtB,AAGE,KAFA,EAAgB,IAAI,aAAa,6CAA8C,YAAY,CAAC,EAC5F,EAAmB,KACD,KAEtB,EAGM,EAAmB,MAAO,EAAQ,IAAiC,CACvE,IAAM,EAAa,KAAK,IAAI,EACtB,EAAa,EAAY,CAAG,EAC5B,EAAS,EAAM,IAAI,CAAU,EAGnC,GAAI,GAAU,EAAa,EAAO,UAAY,EAC5C,OAAO,EAAO,KAIhB,IAAM,EAAY,MAAM,EAAQ,EAAK,CAAG,EAQxC,OALA,EAAM,IAAI,EAAY,CACpB,KAAM,EACN,UAAW,KAAK,IAAI,CACtB,CAAC,EAEM,CACT,EAuBA,OApBI,GAAiB,GACnB,AAEE,KADA,aAAa,CAAiB,EACV,MAEtB,AAGE,KAFA,EAAgB,IAAI,aAAa,wCAAyC,YAAY,CAAC,EACvF,EAAmB,KACD,MAGpB,EAAoB,EACb,EAAiB,EAAQ,CAAM,IAIpC,GACF,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,EAExC,AACE,IAAoB,WAAW,SAAY,CACzC,EAAoB,KAEpB,IAAM,EAAc,EACd,EAAe,EACf,EAAc,EACd,EAAc,EAEpB,EAAkB,KAClB,EAAmB,KACnB,EAAkB,KAClB,EAAkB,KAClB,EAAY,oBAAoB,QAAS,CAAO,EAEhD,GAAI,CACF,EAAoB,KAAK,IAAI,EAE7B,EAAa,MADM,EAAiB,EAAa,CAAW,CAC3C,CACnB,OAAS,EAAO,CACd,EAAY,CAAK,CACnB,CACF,EAAG,CAAa,CAEpB,CAAC,EACH,CACF"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
//#region src/decorators/withThrottleAndCache/withThrottleAndCache.ts
|
|
2
|
+
var e = (e, t = {}) => {
|
|
3
|
+
let n = t.limit ?? 300, r = t.ttl ?? 300 * 1e3, i = 0, a = null, o = null, s = null, c = null, l = null, u = /* @__PURE__ */ new Map(), d = (e) => typeof e == "object" && e ? JSON.stringify(e) : String(e);
|
|
4
|
+
return (t, f) => {
|
|
5
|
+
let p = Date.now(), m = n - (p - i);
|
|
6
|
+
d(t);
|
|
7
|
+
let h = () => {
|
|
8
|
+
a &&= (clearTimeout(a), null), c &&= (c(new DOMException("Aborted by resource signal during throttle", "AbortError")), s = null, null);
|
|
9
|
+
}, g = async (t, n) => {
|
|
10
|
+
let i = Date.now(), a = d(t), o = u.get(a);
|
|
11
|
+
if (o && i - o.timestamp < r) return o.data;
|
|
12
|
+
let s = await e(t, n);
|
|
13
|
+
return u.set(a, {
|
|
14
|
+
data: s,
|
|
15
|
+
timestamp: Date.now()
|
|
16
|
+
}), s;
|
|
17
|
+
};
|
|
18
|
+
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) => {
|
|
19
|
+
if (o = t, s = e, c = n, l = f, f.aborted) return h();
|
|
20
|
+
f.addEventListener("abort", h), a ||= setTimeout(async () => {
|
|
21
|
+
a = null;
|
|
22
|
+
let e = o, t = s, n = c, r = l;
|
|
23
|
+
o = null, s = null, c = null, l = null, r.removeEventListener("abort", h);
|
|
24
|
+
try {
|
|
25
|
+
i = Date.now(), t(await g(e, r));
|
|
26
|
+
} catch (e) {
|
|
27
|
+
n(e);
|
|
28
|
+
}
|
|
29
|
+
}, m);
|
|
30
|
+
}));
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
//#endregion
|
|
34
|
+
export { e as withThrottleAndCache };
|
|
35
|
+
|
|
36
|
+
//# sourceMappingURL=withThrottleAndCache.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withThrottleAndCache.mjs","names":[],"sources":["../../../src/decorators/withThrottleAndCache/withThrottleAndCache.ts"],"sourcesContent":["interface ThrottleAndCacheOptions {\n /** Интервал троттлинга в миллисекундах. По умолчанию 300 мс */\n limit?: number;\n /** Время жизни кэша в миллисекундах. По умолчанию 5 минут (300000 мс) */\n ttl?: number;\n}\n\ninterface CacheEntry<T> {\n data: T;\n timestamp: number;\n}\n\n/**\n * Комбинированный декоратор: сначала применяет троттлинг к частоте вызовов,\n * а затем проверяет кэш перед отправкой реального fetcher-запроса.\n */\nexport const withThrottleAndCache = <S, T>(\n fetcher: (source: S, signal: AbortSignal) => Promise<T>,\n options: ThrottleAndCacheOptions = {}\n) => {\n const limit = options.limit ?? 300\n const ttl = options.ttl ?? 5 * 60 * 1000\n\n // Инфраструктура троттлинга\n let lastExecutionTime = 0\n let throttleTimeoutId: ReturnType<typeof setTimeout> | null = null\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 // Инфраструктура кэширования\n const cache = new Map<string, CacheEntry<T>>()\n\n // Внутренний хелпер для генерации ключа кэша\n const getCacheKey = (source: S): string => {\n return typeof source === 'object' && source !== null\n ? JSON.stringify(source)\n : String(source)\n }\n\n return (source: S, signal: AbortSignal): Promise<T> => {\n const now = Date.now()\n const remainingTime = limit - (now - lastExecutionTime)\n const cacheKey = getCacheKey(source)\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 // --- ФУНКЦИЯ ВЫПОЛНЕНИЯ ЗАПРОСА С УЧЕТОМ КЭША ---\n const executeWithCache = async (src: S, sig: AbortSignal): Promise<T> => {\n const currentNow = Date.now()\n const currentKey = getCacheKey(src)\n const cached = cache.get(currentKey)\n\n // Проверяем оперативную память на валидность кэша\n if (cached && currentNow - cached.timestamp < ttl) {\n return cached.data\n }\n\n // Если кэша нет — делаем реальный запрос\n const freshData = await fetcher(src, sig)\n\n // Сохраняем в кэш\n cache.set(currentKey, {\n data: freshData,\n timestamp: Date.now(),\n })\n\n return freshData\n }\n\n // --- ВЕТКА 1: Leading edge (Окно блокировки закрыто, выполняем сразу) ---\n if (remainingTime <= 0) {\n if (throttleTimeoutId) {\n clearTimeout(throttleTimeoutId)\n throttleTimeoutId = null\n }\n if (lastSavedReject) {\n lastSavedReject(new DOMException('Aborted due to newer direct execution', 'AbortError'))\n lastSavedResolve = null\n lastSavedReject = null\n }\n\n lastExecutionTime = now\n return executeWithCache(source, signal)\n }\n\n // --- ВЕТКА 2: Trailing edge (Внутри окна блокировки, перезаписываем хвост) ---\n if (lastSavedReject) {\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 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 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 executeWithCache(savedSource, savedSignal)\n savedResolve(data)\n } catch (error) {\n savedReject(error)\n }\n }, remainingTime)\n }\n })\n }\n}\n"],"mappings":";AAgBA,IAAa,KACX,GACA,IAAmC,CAAC,MACjC;CACH,IAAM,IAAQ,EAAQ,SAAS,KACzB,IAAM,EAAQ,OAAO,MAAS,KAGhC,IAAoB,GACpB,IAA0D,MAC1D,IAA4B,MAC5B,IAAiE,MACjE,IAAkD,MAClD,IAAsC,MAGpC,oBAAQ,IAAI,IAA2B,GAGvC,KAAe,MACZ,OAAO,KAAW,YAAY,IACjC,KAAK,UAAU,CAAM,IACrB,OAAO,CAAM;CAGnB,QAAQ,GAAW,MAAoC;EACrD,IAAM,IAAM,KAAK,IAAI,GACf,IAAgB,KAAS,IAAM;EACpB,EAAY,CAAM;EAEnC,IAAM,UAAgB;GAKpB,AAJA,AAEE,OADA,aAAa,CAAiB,GACV,OAEtB,AAGE,OAFA,EAAgB,IAAI,aAAa,8CAA8C,YAAY,CAAC,GAC5F,IAAmB,MACD;EAEtB,GAGM,IAAmB,OAAO,GAAQ,MAAiC;GACvE,IAAM,IAAa,KAAK,IAAI,GACtB,IAAa,EAAY,CAAG,GAC5B,IAAS,EAAM,IAAI,CAAU;GAGnC,IAAI,KAAU,IAAa,EAAO,YAAY,GAC5C,OAAO,EAAO;GAIhB,IAAM,IAAY,MAAM,EAAQ,GAAK,CAAG;GAQxC,OALA,EAAM,IAAI,GAAY;IACpB,MAAM;IACN,WAAW,KAAK,IAAI;GACtB,CAAC,GAEM;EACT;EAuBA,OApBI,KAAiB,KACnB,AAEE,OADA,aAAa,CAAiB,GACV,OAEtB,AAGE,OAFA,EAAgB,IAAI,aAAa,yCAAyC,YAAY,CAAC,GACvF,IAAmB,MACD,OAGpB,IAAoB,GACb,EAAiB,GAAQ,CAAM,MAIpC,KACF,EAAgB,IAAI,aAAa,wCAAwC,YAAY,CAAC,GAGjF,IAAI,SAAY,GAAS,MAAW;GAMzC,IALA,IAAkB,GAClB,IAAmB,GACnB,IAAkB,GAClB,IAAkB,GAEd,EAAO,SACT,OAAO,EAAQ;GAIjB,AAFA,EAAO,iBAAiB,SAAS,CAAO,GAExC,AACE,MAAoB,WAAW,YAAY;IACzC,IAAoB;IAEpB,IAAM,IAAc,GACd,IAAe,GACf,IAAc,GACd,IAAc;IAMpB,AAJA,IAAkB,MAClB,IAAmB,MACnB,IAAkB,MAClB,IAAkB,MAClB,EAAY,oBAAoB,SAAS,CAAO;IAEhD,IAAI;KAGF,AAFA,IAAoB,KAAK,IAAI,GAE7B,EAAa,MADM,EAAiB,GAAa,CAAW,CAC3C;IACnB,SAAS,GAAO;KACd,EAAY,CAAK;IACnB;GACF,GAAG,CAAa;EAEpB,CAAC;CACH;AACF"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var e=(e,t,n,r)=>{let i=r||`throttled_computed:unnamed`,a=n.limit,o=t(),s=e.signal(o,`signal:internal:${i}`),c=0,l=null,u=null,d=!1,f=!0,p=e=>{s.value=e,c=Date.now(),d=!1,l=null};return e.effect(()=>{let e=t();if(f){f=!1;return}let n=c===0?a:Date.now()-c;n>=a?(l&&=(clearTimeout(l),null),p(e)):(u=e,d=!0,l||=setTimeout(()=>{d&&p(u)},a-n))},`effect:throttle-scheduler:${i}`),{get value(){return s.value},subscribe:e=>s.subscribe(e),destroy:()=>{l&&clearTimeout(l)}}};exports.withThrottleComputed=e;
|
|
2
|
+
//# sourceMappingURL=withThrottleComputed.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withThrottleComputed.cjs","names":[],"sources":["../../../src/decorators/withThrottleComputed/withThrottleComputed.ts"],"sourcesContent":["import { ReactiveEngine } from '../../core/core'\n\ninterface ThrottleComputedOptions {\n limit: number;\n}\n\nexport const withThrottleComputed = <T>(\n engine: ReactiveEngine,\n getter: () => T,\n options: ThrottleComputedOptions,\n signalName?: string\n) => {\n const name = signalName || 'throttled_computed:unnamed'\n const limit = options.limit\n\n const initialValue = getter()\n const throttledSignal = engine.signal<T>(initialValue, `signal:internal:${name}`)\n\n // ИСПОЛЬЗУЕМ СТАНДАРТНЫЙ ТАЙМЕР ДЛЯ СИНХРOНИЗАЦИИ С ТЕСТАМИ\n let lastRunTime = 0\n let timeoutId: any = null\n let pendingValue: T | null = null\n let hasPending = false\n\n let isFirstEffectRun = true\n\n const updateSignal = (value: T) => {\n throttledSignal.value = value\n lastRunTime = Date.now() // Перешли на Date.now() для 100% поддержки FakeTimers\n hasPending = false\n timeoutId = null\n }\n\n engine.effect(() => {\n const freshValue = getter() // Собираем зависимости нативно\n\n if (isFirstEffectRun) {\n isFirstEffectRun = false\n return\n }\n\n const now = Date.now()\n\n // Если lastRunTime === 0 — это самое первое реальное изменение, пушим его сразу\n const timePassed = lastRunTime === 0 ? limit : (now - lastRunTime)\n\n if (timePassed >= limit) {\n if (timeoutId) {\n clearTimeout(timeoutId)\n timeoutId = null\n }\n updateSignal(freshValue)\n } else {\n pendingValue = freshValue\n hasPending = true\n\n if (!timeoutId) {\n timeoutId = setTimeout(() => {\n if (hasPending) {\n updateSignal(pendingValue as T)\n }\n }, limit - timePassed)\n }\n }\n }, `effect:throttle-scheduler:${name}`)\n\n const destroy = () => {\n if (timeoutId) {\n clearTimeout(timeoutId)\n }\n }\n\n return {\n get value(): T {\n return throttledSignal.value\n },\n subscribe: (cb: (val: T) => void) => throttledSignal.subscribe(cb),\n destroy\n }\n}\n"],"mappings":"AAMA,IAAa,GACX,EACA,EACA,EACA,IACG,CACH,IAAM,EAAO,GAAc,6BACrB,EAAQ,EAAQ,MAEhB,EAAe,EAAO,EACtB,EAAkB,EAAO,OAAU,EAAc,mBAAmB,GAAM,EAG5E,EAAc,EACd,EAAiB,KACjB,EAAyB,KACzB,EAAa,GAEb,EAAmB,GAEjB,EAAgB,GAAa,CACjC,EAAgB,MAAQ,EACxB,EAAc,KAAK,IAAI,EACvB,EAAa,GACb,EAAY,IACd,EAyCA,OAvCA,EAAO,WAAa,CAClB,IAAM,EAAa,EAAO,EAE1B,GAAI,EAAkB,CACpB,EAAmB,GACnB,MACF,CAKA,IAAM,EAAa,IAAgB,EAAI,EAH3B,KAAK,IAG+B,EAAM,EAElD,GAAc,GAChB,AAEE,KADA,aAAa,CAAS,EACV,MAEd,EAAa,CAAU,IAEvB,EAAe,EACf,EAAa,GAEb,AACE,IAAY,eAAiB,CACvB,GACF,EAAa,CAAiB,CAElC,EAAG,EAAQ,CAAU,EAG3B,EAAG,6BAA6B,GAAM,EAQ/B,CACL,IAAI,OAAW,CACb,OAAO,EAAgB,KACzB,EACA,UAAY,GAAyB,EAAgB,UAAU,CAAE,EACjE,YAXoB,CAChB,GACF,aAAa,CAAS,CAE1B,CAQA,CACF"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
//#region src/decorators/withThrottleComputed/withThrottleComputed.ts
|
|
2
|
+
var e = (e, t, n, r) => {
|
|
3
|
+
let i = r || "throttled_computed:unnamed", a = n.limit, o = t(), s = e.signal(o, `signal:internal:${i}`), c = 0, l = null, u = null, d = !1, f = !0, p = (e) => {
|
|
4
|
+
s.value = e, c = Date.now(), d = !1, l = null;
|
|
5
|
+
};
|
|
6
|
+
return e.effect(() => {
|
|
7
|
+
let e = t();
|
|
8
|
+
if (f) {
|
|
9
|
+
f = !1;
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
let n = c === 0 ? a : Date.now() - c;
|
|
13
|
+
n >= a ? (l &&= (clearTimeout(l), null), p(e)) : (u = e, d = !0, l ||= setTimeout(() => {
|
|
14
|
+
d && p(u);
|
|
15
|
+
}, a - n));
|
|
16
|
+
}, `effect:throttle-scheduler:${i}`), {
|
|
17
|
+
get value() {
|
|
18
|
+
return s.value;
|
|
19
|
+
},
|
|
20
|
+
subscribe: (e) => s.subscribe(e),
|
|
21
|
+
destroy: () => {
|
|
22
|
+
l && clearTimeout(l);
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
};
|
|
26
|
+
//#endregion
|
|
27
|
+
export { e as withThrottleComputed };
|
|
28
|
+
|
|
29
|
+
//# sourceMappingURL=withThrottleComputed.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"withThrottleComputed.mjs","names":[],"sources":["../../../src/decorators/withThrottleComputed/withThrottleComputed.ts"],"sourcesContent":["import { ReactiveEngine } from '../../core/core'\n\ninterface ThrottleComputedOptions {\n limit: number;\n}\n\nexport const withThrottleComputed = <T>(\n engine: ReactiveEngine,\n getter: () => T,\n options: ThrottleComputedOptions,\n signalName?: string\n) => {\n const name = signalName || 'throttled_computed:unnamed'\n const limit = options.limit\n\n const initialValue = getter()\n const throttledSignal = engine.signal<T>(initialValue, `signal:internal:${name}`)\n\n // ИСПОЛЬЗУЕМ СТАНДАРТНЫЙ ТАЙМЕР ДЛЯ СИНХРOНИЗАЦИИ С ТЕСТАМИ\n let lastRunTime = 0\n let timeoutId: any = null\n let pendingValue: T | null = null\n let hasPending = false\n\n let isFirstEffectRun = true\n\n const updateSignal = (value: T) => {\n throttledSignal.value = value\n lastRunTime = Date.now() // Перешли на Date.now() для 100% поддержки FakeTimers\n hasPending = false\n timeoutId = null\n }\n\n engine.effect(() => {\n const freshValue = getter() // Собираем зависимости нативно\n\n if (isFirstEffectRun) {\n isFirstEffectRun = false\n return\n }\n\n const now = Date.now()\n\n // Если lastRunTime === 0 — это самое первое реальное изменение, пушим его сразу\n const timePassed = lastRunTime === 0 ? limit : (now - lastRunTime)\n\n if (timePassed >= limit) {\n if (timeoutId) {\n clearTimeout(timeoutId)\n timeoutId = null\n }\n updateSignal(freshValue)\n } else {\n pendingValue = freshValue\n hasPending = true\n\n if (!timeoutId) {\n timeoutId = setTimeout(() => {\n if (hasPending) {\n updateSignal(pendingValue as T)\n }\n }, limit - timePassed)\n }\n }\n }, `effect:throttle-scheduler:${name}`)\n\n const destroy = () => {\n if (timeoutId) {\n clearTimeout(timeoutId)\n }\n }\n\n return {\n get value(): T {\n return throttledSignal.value\n },\n subscribe: (cb: (val: T) => void) => throttledSignal.subscribe(cb),\n destroy\n }\n}\n"],"mappings":";AAMA,IAAa,KACX,GACA,GACA,GACA,MACG;CACH,IAAM,IAAO,KAAc,8BACrB,IAAQ,EAAQ,OAEhB,IAAe,EAAO,GACtB,IAAkB,EAAO,OAAU,GAAc,mBAAmB,GAAM,GAG5E,IAAc,GACd,IAAiB,MACjB,IAAyB,MACzB,IAAa,IAEb,IAAmB,IAEjB,KAAgB,MAAa;EAIjC,AAHA,EAAgB,QAAQ,GACxB,IAAc,KAAK,IAAI,GACvB,IAAa,IACb,IAAY;CACd;CAyCA,OAvCA,EAAO,aAAa;EAClB,IAAM,IAAa,EAAO;EAE1B,IAAI,GAAkB;GACpB,IAAmB;GACnB;EACF;EAKA,IAAM,IAAa,MAAgB,IAAI,IAH3B,KAAK,IAG+B,IAAM;EAEtD,AAAI,KAAc,KAChB,AAEE,OADA,aAAa,CAAS,GACV,OAEd,EAAa,CAAU,MAEvB,IAAe,GACf,IAAa,IAEb,AACE,MAAY,iBAAiB;GAC3B,AAAI,KACF,EAAa,CAAiB;EAElC,GAAG,IAAQ,CAAU;CAG3B,GAAG,6BAA6B,GAAM,GAQ/B;EACL,IAAI,QAAW;GACb,OAAO,EAAgB;EACzB;EACA,YAAY,MAAyB,EAAgB,UAAU,CAAE;EACjE,eAXoB;GACpB,AAAI,KACF,aAAa,CAAS;EAE1B;CAQA;AACF"}
|
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");exports.AbstractService=t.AbstractService,exports.BaseREService=t.BaseREService,exports.BaseREServiceEnhanced=n.BaseREServiceEnhanced,exports.ReactiveEngine=e.ReactiveEngine;
|
|
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;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export * from './core
|
|
2
|
-
export
|
|
1
|
+
export * from './core';
|
|
2
|
+
export * from './decorators';
|
|
3
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.mjs
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { ReactiveEngine as e } from "./core.mjs";
|
|
2
2
|
import { AbstractService as t, BaseREService as n } from "./AbstractService.mjs";
|
|
3
3
|
import { BaseREServiceEnhanced as r } from "./BaseREServiceEnhanced.mjs";
|
|
4
|
-
|
|
4
|
+
import { withCache as i } from "./decorators/withCache/withCache.mjs";
|
|
5
|
+
import { withDebounce as a } from "./decorators/withDebounce/withDebounce.mjs";
|
|
6
|
+
import { withLongPolling as o } from "./decorators/withLongPolling/withLongPolling.mjs";
|
|
7
|
+
import { withThrottle as s } from "./decorators/withThrottle/withThrottle.mjs";
|
|
8
|
+
import { withThrottleComputed as c } from "./decorators/withThrottleComputed/withThrottleComputed.mjs";
|
|
9
|
+
import { withThrottleAndCache as l } from "./decorators/withThrottleAndCache/withThrottleAndCache.mjs";
|
|
10
|
+
export { t as AbstractService, n as BaseREService, r as BaseREServiceEnhanced, e as ReactiveEngine, i as withCache, a as withDebounce, o as withLongPolling, s as withThrottle, l as withThrottleAndCache, c as withThrottleComputed };
|
|
@@ -1,2 +1,13 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* @pravosleva/reactive-engine v1.5.7-beta
|
|
3
|
+
* High-performance transactional reactive engine with microtask batching.
|
|
4
|
+
*
|
|
5
|
+
* @license MIT
|
|
6
|
+
* @author pravosleva <selection4test@google.com>
|
|
7
|
+
* @homepage https://pravosleva.pro/reactive-engine
|
|
8
|
+
*
|
|
9
|
+
* @contact Telegram Channel: https://t.me/bash_exp_ru/3393
|
|
10
|
+
* @contact Developer Telegram: https://t.me/pravosleva
|
|
11
|
+
*/
|
|
1
12
|
(function(e,t){typeof exports==`object`&&typeof module<`u`?t(exports):typeof define==`function`&&define.amd?define([`exports`],t):(e=typeof globalThis<`u`?globalThis:e||self,t(e.ReactiveEngineLib={}))})(this,function(e){Object.defineProperty(e,Symbol.toStringTag,{value:`Module`});var t=({tested:e,expectedKey:t,valueType:n})=>{let r=[];if(!e||!Array.isArray(e))return r;for(let i=0,a=e.length;i<a;i++){let a=e[i];if(typeof a!=`string`)continue;let o;switch(n){case`number`:o=RegExp(`\\[${t}=(?<value>\\d+)\\]`,`g`);break;default:o=RegExp(`\\[${t}=(?<value>.*?)\\]`,`g`);break}for(let e of a.matchAll(o))e?.groups&&r.push(e.groups.value)}return r},n=class{frameworkPrefix=`core`;activeEffect=null;isBatching=!1;pendingEffects=new Set;services=new Map;factories=new Map;proxyCache=new WeakMap;allEffects=new Set;loggerOptions;pendingLogQueue=[];lastTransactionDuration=null;signalMutationCounts=new Map;lastComputedDurations=new Map;effectExecutionCounts=new Map;batchTickCounts=0;constructor(e){this.loggerOptions=e?.logger}log(e,n,r){if(!this.loggerOptions?.isEnabled)return;if(!this.loggerOptions?.isCoreOptimizationDebugEnabled){let e=t({expectedKey:`CORE_INTERNAL_SIGNAL`,tested:[n],valueType:`number`})?.[0]===`1`,r=t({expectedKey:`CORE_INTERNAL_EFFECT`,tested:[n],valueType:`number`})?.[0]===`1`;if(e||r)return}if(this.loggerOptions.filter&&!(this.loggerOptions.filter instanceof RegExp?this.loggerOptions.filter:new RegExp(this.loggerOptions.filter.replace(/^\/|\/$/g,``))).test(n))return;let i={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;`},a=``,o=`color: #aaa; font-weight: normal;`;switch(e){case`signal`:{let s=t({tested:[n],expectedKey:`CORE_INTERNAL_SIGNAL`,valueType:`number`})?.[0]===`1`,c=n,l=(this.signalMutationCounts.get(c)||0)+1;this.signalMutationCounts.set(c,l);let u=r,d=u.subscribers&&u.subscribers.length>0?u.subscribers.every(e=>e?t({tested:[e],expectedKey:`IS_OPTIMIZED`,valueType:`number`})?.[0]===`1`:!1):!1,f=l>50,p=s?`COMPUTED_INTERNAL`:`SIGNAL`;a=` 🔄 Изменений ${s?`кэша`:`сигнала`}: ${l}${f?` ⚠️ (high noise — обнаружен дребезг/спам значений!)`:``}`,f&&(o=`color: orange; font-weight: bold;`,d||(r.__performance_advice__={issue:`Сигнал [${c}] обновляется слишком часто (${l} раз за такт). Это приводит к избыточным ререндерам UI.`,solution:`Оберните чтение этого сигнала в декоратор сжатия потока данных 'withThrottleComputed'`,example:`public throttled = withThrottleComputed(this.engine, () => this.yourSignalName.value, { limit: 300 });`})),console.groupCollapsed(`%c${p}%c [${c}]%c${a}`,s?`background: #42b883; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`:i[e],`color: #aaa; font-weight: bold;`,o),console.log(`Данные (Payload):`,r),this.loggerOptions.traceTime&&typeof performance<`u`&&console.log(`Тайминг рантайма:`,`${performance.now().toFixed(2)} ms`),console.groupEnd();return}case`computed`:{let e=r;if(e&&`to`in e){let t=e.to;a=` 🧮 Значение: ${typeof t==`object`&&t?`{...}`:String(t)}`}else if(e&&`duration`in e){let t=parseFloat(e.duration);if(!isNaN(t)){let r=this.lastComputedDurations.get(n);if(r!==void 0&&r>0){let n=(t-r)/r*100;n>5?(a=` 🔴 Замедление: +${n.toFixed(1)}% (${e.duration})`,o=`color: #e01e5a; font-weight: bold;`):n<-5?(a=` 🟢 Ускорение: ${n.toFixed(1)}% (${e.duration})`,o=`color: #42b883; font-weight: bold;`):(a=` 🟢 Стабильно (${e.duration})`,o=`color: #42b883; font-weight: bold;`)}else a=` ⚪ Первый расчет (${e.duration})`;this.lastComputedDurations.set(n,t)}}break}case`effect`:{let e=(this.effectExecutionCounts.get(n)||0)+1;this.effectExecutionCounts.set(n,e);let t=e>30,i=r;a=` 🟢 Стабильно${i&&`duration`in i?` (${i.duration})`:``} | 🚀 Вызовов: ${e}${t?` ⚠️ (heavy re-renders)`:``}`,o=`color: #42b883; font-weight: bold;`,t&&(o=`color: #ff4a4a; font-weight: bold;`);break}case`batch`:this.batchTickCounts+=1,a=` 📦 Номер транзакции: #${this.batchTickCounts}`;break;case`resource`:{let e=r;if(e.loading)a=` ⏳ ЗАГРУЗКА (fetching...)`,o=`color: #d97706; font-weight: bold;`;else if(e.error)a=` 🔴 ОШИБКА: ${e.error.message||`Unknown Error`}`,o=`color: #ff4a4a; font-weight: bold;`;else{let t=e.data;a=` 🟢 УСПЕХ (data: ${typeof t==`object`&&t?`{...}`:String(t)})`,o=`color: #42b883; font-weight: bold;`}break}default:break}console.groupCollapsed(`%c${e.toUpperCase()}%c [${n}]%c${a}`,i[e],`color: #aaa; font-weight: bold;`,o),console.log(`Данные (Payload):`,r),this.loggerOptions.traceTime&&typeof performance<`u`&&console.log(`Тайминг рантайма:`,`${performance.now().toFixed(2)} ms`),console.groupEnd()}onSignalChange;provide(e,t){typeof t==`function`&&!t.prototype?this.factories.set(e,t):this.services.set(e,t)}inject(e){if(!e)throw Error(`[DI Error]: Вы пытаетесь внедрить пустой токен (undefined/null). Проверьте импорты.`);let t=e;if(this.services.has(t))return this.services.get(t);try{let n=this.factories.get(t);if(n){let e=n(this);return this.services.set(t,e),e}if(typeof e==`function`&&e.prototype){let n=new e(this);return this.services.set(t,n),n}throw Error(`Service not found: ${String(e)}`)}catch(t){throw Error(`[DI Error]: Не удалось создать сервис ${String(e)}. Ошибка: ${t?.message||`No e?.message`}`)}}queueLog(e,t,n){this.loggerOptions?.isEnabled&&this.pendingLogQueue.push({type:e,name:t,detail:n})}flushLogs(){if(!this.loggerOptions?.isEnabled||this.pendingLogQueue.length===0)return;let e=typeof performance<`u`?performance.now():0,t=this.pendingLogQueue;if(this.loggerOptions.filter)try{let e;if(this.loggerOptions.filter instanceof RegExp)e=this.loggerOptions.filter;else{let t=this.loggerOptions.filter.replace(/^\/|\/$/g,``);e=new RegExp(t)}t=t.filter(t=>e.test(t.name))}catch(e){console.warn(`[Logger Error]: Некорректный паттерн фильтрации логов`,e)}if(t.length===0){this.pendingLogQueue=[];return}let n=``,r=``,i=`color: #aaa; font-weight: normal;`;if(this.loggerOptions.traceTime&&e){let t=performance.now()-e;if(n=` | Duration: ${t.toFixed(3)} ms`,this.lastTransactionDuration!==null&&this.lastTransactionDuration>0){let e=(t-this.lastTransactionDuration)/this.lastTransactionDuration*100;e>.1?(r=` 🔴 +${e.toFixed(1)}%`,i=`color: #e01e5a; font-weight: bold;`):e<-.1?(r=` 🟢 ${e.toFixed(1)}%`,i=`color: #42b883; font-weight: bold;`):(r=` 🟢 stable`,i=`color: #42b883; font-weight: bold;`)}else r=` ⚪ first`;this.lastTransactionDuration=t}console.groupCollapsed(`%cREACTIVE TRANSACTION${this.loggerOptions.instanceName?` ${this.loggerOptions.instanceName}`:``}%c Microtask Tick (Size: ${t.length}${n})%c${r}`,`background: #7952b3; color: #fff; padding: 2px 6px; border-radius: 4px; font-weight: bold;`,`color: #aaa; font-weight: normal;`,i),t.forEach(e=>{this.log(e.type,e.name,e.detail)}),this.loggerOptions.traceTime&&typeof performance<`u`&&console.log(`%c[Execution Timestamp]: ${performance.now().toFixed(2)} ms`,`color: #7952b3; font-weight: bold;`),console.groupEnd(),this.pendingLogQueue=[]}signal(e,t){let n=this,r=e,i=new Set,a=typeof t==`string`?{name:t}:t||{},o=a.name||`unnamed_signal`;return{get value(){if(n.activeEffect){let e=n.activeEffect;i.has(e)||(i.add(e),e.cleanups.add(()=>{i.delete(e)}))}return r},set value(e){if(r===e)return;if(a.validate){let t=a.validate(e);if(t===!1||typeof t==`string`){let n=typeof t==`string`?t:`[Validation Error]: Некорректное значение для сигнала "${o}"`;console.error(`%c${n}`,`color: orange; font-weight: bold;`,{received:e,current:r});return}}let t=r;r=e,n.onSignalChange?.(o,e,t);let s=Array.from(i).map(e=>e.label||`unnamed_effect`);n.queueLog?.(`signal`,o,{from:t,to:e,subscribersCount:i.size,subscribers:s}),i.forEach(e=>n.pendingEffects.add(e)),n.isBatching||(n.isBatching=!0,queueMicrotask(()=>{for(let e of n.pendingEffects)n.pendingEffects.delete(e),e.run();n.isBatching=!1,n.flushLogs?.()}))},subscribe(e){return n.effect(()=>{e(this.value)},`${n.frameworkPrefix}:use:${o}`)}}}effect(e,t){let n=this,r=!0,i={label:t,cleanups:new Set,run(){this.cleanups.forEach(e=>e()),this.cleanups.clear();let t=n.activeEffect;n.activeEffect=this;let i=performance.now();n.safeRun(this,()=>{let t=e();typeof t==`function`&&this.cleanups.add(t)}),n.activeEffect=t;let a=performance.now()-i;if(!r&&n.loggerOptions?.isEnabled){let e=n.loggerOptions.filter;(!e||e instanceof RegExp&&this.label&&e.test(this.label))&&typeof n.queueLog==`function`&&n.queueLog(`effect`,this.label||`unnamed-efect-0`,{name:this.label||`unnamed-efect-0`,type:`effect`,detail:{status:`stable`,duration:`${a.toFixed(3)}ms`,timestamp:i}})}r=!1}};return this.allEffects.add(i),i.run(),()=>{i.cleanups.forEach(e=>e()),n.pendingEffects.delete(i),n.allEffects.delete(i)}}computedCache=new Map;cleanupRegistry=new FinalizationRegistry(e=>{e()});computed(e,t){if(this.computedCache.has(e)){let t=this.computedCache.get(e)?.deref();if(t)return t}let n=this,r=t||`unnamed_computed`,i=this.signal(void 0,`[CORE_INTERNAL_SIGNAL=1]:${r}`),a=!0,o,s=this.effect(()=>{o=e(),a=!1;let t=typeof performance<`u`&&performance.now()?`0.010ms`:`N/A`;typeof n.queueLog==`function`&&n.queueLog(`computed`,r,{value:o,duration:t}),i.value=o},`[CORE_INTERNAL_EFFECT=1]:${r}`),c=Array.from(this.allEffects)[this.allEffects.size-1],l=()=>{s(),c&&n.allEffects.delete(c),n.computedCache.delete(e)},u={get value(){return a&&(o=e(),a=!1,i.value=o),i.value},subscribe:e=>i.subscribe(e),destroy(){l()}};return this.cleanupRegistry.register(u,l),this.computedCache.set(e,new WeakRef(u)),u}reactive(e,t=`reactive`){if(this.proxyCache.has(e))return this.proxyCache.get(e);let n=this,r=new Map,i=new Proxy(e,{get(e,i,a){n.activeEffect&&(r.has(i)||r.set(i,new Set),r.get(i).add(n.activeEffect));let o=Reflect.get(e,i,a);return typeof o==`object`&&o?n.reactive(o,`${t}.${String(i)}`):o},set(e,i,a,o){let s=Reflect.get(e,i,o);return s===a||s!==a&&(Reflect.set(e,i,a,o),n.onSignalChange?.(`${t}.${String(i)}`,a,s),r.get(i)?.forEach(e=>n.isBatching?n.pendingEffects.add(e):e.run())),!0}});return this.proxyCache.set(e,i),i}batch(e){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,n,r){let i=r&&typeof r==`object`,a=i?r.name:r||`unnamed_resource`,o=i?r:{},s=o.resetDataOnSourceChange??!0,c=o.responseValidate,l=o.validateBeforeFetch,u=o.retryCount??0,d=o.retryDelay??1e3,f=o.isExponentialBackoffEnabled??!1,p=o.maxRetryDelay??3e4,m=o.timeout,h=this.signal({data:null,loading:!0,error:null,isRetrying:!1},`[CORE_INTERNAL_SIGNAL=1]:resource:state:${a}`),g=e=>{h.value=e,typeof this.queueLog==`function`&&this.queueLog(`resource`,a,{loading:e.loading,data:e.data,error:e.error,isRetrying:e.isRetrying})},_=async(n,r,i=!1)=>{if(r.aborted)return;if(l){let e=l(n);if(e===!1||typeof e==`string`){if(r.aborted)return;let t=typeof e==`string`?e:`Pre-fetch validation failed for resource`,n=i?null:this.untrack(()=>h.value.data);g({data:n,loading:!1,error:Error(t),isRetrying:!1});return}}let o=i&&s?null:this.untrack(()=>h.value.data);g({data:o,loading:!0,error:null,isRetrying:!1});for(let i=0;i<=u;i++){if(r.aborted)return;let o=r;try{if(m&&m>0){let e=AbortSignal.timeout(m);o=AbortSignal.any([r,e])}let t=await e(n,o);if(r.aborted)return;if(o.aborted)throw new DOMException(`The operation timed out.`,`TimeoutError`);if(c){let e=c(t);if(e===!1||typeof e==`string`){if(r.aborted)return;g({data:null,loading:!1,error:Error(typeof e==`string`?e:`Validation failed`),isRetrying:!1});return}}if(r.aborted)return;g({data:t,loading:!1,error:null,isRetrying:!1});return}catch(e){if(r.aborted||e.name===`AbortError`&&r.aborted)return;let n=e.name===`TimeoutError`||e.name===`AbortError`||e.message?.includes(`timeout`),o=t({tested:[e.message],expectedKey:`THROW_CUSTOM_VALIDATION_ERROR_NO_RETRY`,valueType:`number`})?.[0]===`1`||!1,s=o&&t({tested:[e.message],expectedKey:`MESSAGE`,valueType:`string`})?.[0]||`Custom validation error`,c=o||e.name===`ValidationError`;if(i===u||c){if(r.aborted)return;let t=n?Error(`Request timed out after ${m}ms`,{cause:e}):o?Error(s,{cause:e}):e;g({data:null,loading:!1,error:t,isRetrying:!1});return}else{if(r.aborted)return;let e=f?d*2**i:d;e=Math.min(e,p);let t=Math.random()*200;e+=t,g({data:h.value.data,loading:!0,error:null,isRetrying:!0}),console.warn(`[Resource Retry] "${a}" сбой по ${n?`таймауту`:`ошибке сети`}. Попытка ${i+1}/${u+1}...`);try{if(await this.delay(e,r),r.aborted)return}catch{return}}}}},v=null;return this.effect(()=>{let e=n?n.value:void 0,t=new AbortController;return v=t,this.untrack(()=>{_(e,t.signal,!0)}),()=>t.abort()},`[dev]`),{get data(){return h.value.data},get loading(){return h.value.loading},get error(){return h.value.error},get isRetrying(){return h.value.isRetrying},get value(){return h.value},refetch:()=>{v?.abort(),v=new AbortController,_(n?n.value:void 0,v.signal,!1)},subscribe:e=>h.subscribe(e)}}untrack(e){let t=this.activeEffect;this.activeEffect=null;try{return e()}finally{this.activeEffect=t}}safeRun(e,t){try{t()}catch(e){console.error(`%c[Reactive Error] %cОшибка в эффекте/computed:`,`color: white; background: red; padding: 2px 4px; border-radius: 3px;`,`font-weight: bold;`,e)}}},r=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(){}},i=r,a=class{engine;constructor(e){this.engine=e,setTimeout(()=>this.onInit(),0)}onInit(){}};e.AbstractService=r,e.BaseREService=i,e.BaseREServiceEnhanced=a,e.ReactiveEngine=n});
|
|
2
13
|
//# sourceMappingURL=reactive-engine.umd.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/vue/composables/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAA"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
let e=require("vue");function t(t){let n=(0,e.shallowRef)(t.value),r=typeof window>`u`||typeof process<`u`&&process.server,i=(0,e.getCurrentInstance)()||(0,e.getCurrentScope)();if(r||!i)return n;let a=t.subscribe(t=>{n.value=t,(0,e.triggerRef)(n)});return(0,e.getCurrentInstance)()?(0,e.onUnmounted)(a):(0,e.getCurrentScope)()&&(0,e.onScopeDispose)(a),n}exports.useReactiveValue=t;
|
|
2
|
+
//# sourceMappingURL=useReactiveValue.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useReactiveValue.cjs","names":[],"sources":["../../../src/vue/composables/useReactiveValue.ts"],"sourcesContent":["import { shallowRef, onUnmounted, getCurrentInstance, getCurrentScope, onScopeDispose, triggerRef, type ShallowRef } from 'vue'\n\ntype CleanupFn = () => void\ninterface ReactiveItem<T> {\n value: T\n subscribe: (cb: (v: T) => void) => CleanupFn\n}\n\n/**\n * Хук-композибл для бесшовной интеграции примитивов реактивного ядра с системой рендеринга Vue 3.\n * Нативно поддерживает как атомарные сигналы (`signal`), так и ленивые вычисляемые свойства (`computed`).\n *\n * @template T Тип данных, содержащихся внутри реактивного элемента.\n *\n * @param {Object} item Реактивный примитив ядра, на который необходимо подписаться.\n * @param {T} item.value Текущее значение элемента.\n * @param {(cb: (v: T) => void) => () => void} item.subscribe Метод ядра для оформления подписки на изменения.\n *\n * @returns {ShallowRef<T>} Возвращает стандартную для Vue 3 переменную типа `ShallowRef`.\n * При мутации данных в ядре автоматически вызывается `triggerRef`, инициируя точечный перерасчет шаблона.\n *\n * @example\n * ```vue\n * <script setup>\n * import { useEngine } from '~/composables/useEngine';\n * import { useReactiveValue } from '@pravosleva/reactive-engine/vue';\n *\n * const engine = useEngine();\n * const counterSignal = engine.signal(0, 'ui:counter');\n *\n * // countState теперь обычный Vue Ref, но связанный с ядром данных\n * const countState = useReactiveValue(counterSignal);\n * </script>\n *\n * <template>\n * <button @click=\"counterSignal.value++\">Кликнули: {{ countState }}</button>\n * </template>\n * ```\n *\n * @abstract\n * ### 🚨 Поведение в SSR и Универсальном рендеринге (Nuxt 3 / Nitro)\n * Композибл полностью безопасен для работы на стороне сервера (Node.js). Благодаря внутренним\n * проверкам окружения, на этапе серверного пре-рендеринга он переходит в **пассивный режим**:\n * - Выполняется только однократное чтение `.value` для сборки начального HTML-кода страницы.\n * - Активные подписки и замыкания **не регистрируются**, что полностью предотвращает утечки памяти на сервере.\n * - Исключает появление ошибок несовпадения разметки (`Hydration Mismatch`) при гидратации в браузере.\n *\n * ### 🧹 Управление памятью на клиенте\n * В браузере композибл самостоятельно управляет своим жизненным циклом:\n * - Если вызван внутри компонента, подписка автоматически аннулируется на хуке `onUnmounted`.\n * - Если вызван внутри независимого контекста эффектов, отписка произойдет через `onScopeDispose`.\n */\nexport function useReactiveValue<T>(item: ReactiveItem<T>): ShallowRef<T> {\n const state = shallowRef(item.value)\n\n // SSR: Если мы на сервере Node.js (нет window) или вне контекста Vue —\n // просто возвращаем пассивный ref, не создавая подписку!\n const isServer = typeof window === 'undefined' || (typeof process !== 'undefined' && process.server)\n const hasInstance = getCurrentInstance() || getCurrentScope()\n\n if (isServer || !hasInstance) {\n return state // Пассивный режим однократного чтения для HTML-рендеринга\n }\n\n const unsubscribe = item.subscribe((newValue) => {\n state.value = newValue\n triggerRef(state)\n })\n\n if (getCurrentInstance()) {\n onUnmounted(unsubscribe)\n } else if (getCurrentScope()) {\n onScopeDispose(unsubscribe)\n }\n\n return state\n}\n"],"mappings":"qBAoDA,SAAgB,EAAoB,EAAsC,CACxE,IAAM,GAAA,EAAA,EAAA,WAAA,CAAmB,EAAK,KAAK,EAI7B,EAAW,OAAO,OAAW,KAAgB,OAAO,QAAY,KAAe,QAAQ,OACvF,GAAA,EAAA,EAAA,mBAAA,CAAiC,IAAA,EAAA,EAAA,gBAAA,CAAqB,EAE5D,GAAI,GAAY,CAAC,EACf,OAAO,EAGT,IAAM,EAAc,EAAK,UAAW,GAAa,CAC/C,EAAM,MAAQ,GACd,EAAA,EAAA,WAAA,CAAW,CAAK,CAClB,CAAC,EAQD,OANA,EAAA,EAAA,mBAAA,CAAuB,GACrB,EAAA,EAAA,YAAA,CAAY,CAAW,GAClB,EAAA,EAAA,gBAAA,CAAoB,IACzB,EAAA,EAAA,eAAA,CAAe,CAAW,EAGrB,CACT"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { ShallowRef } from 'vue';
|
|
2
|
+
type CleanupFn = () => void;
|
|
3
|
+
interface ReactiveItem<T> {
|
|
4
|
+
value: T;
|
|
5
|
+
subscribe: (cb: (v: T) => void) => CleanupFn;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Хук-композибл для бесшовной интеграции примитивов реактивного ядра с системой рендеринга Vue 3.
|
|
9
|
+
* Нативно поддерживает как атомарные сигналы (`signal`), так и ленивые вычисляемые свойства (`computed`).
|
|
10
|
+
*
|
|
11
|
+
* @template T Тип данных, содержащихся внутри реактивного элемента.
|
|
12
|
+
*
|
|
13
|
+
* @param {Object} item Реактивный примитив ядра, на который необходимо подписаться.
|
|
14
|
+
* @param {T} item.value Текущее значение элемента.
|
|
15
|
+
* @param {(cb: (v: T) => void) => () => void} item.subscribe Метод ядра для оформления подписки на изменения.
|
|
16
|
+
*
|
|
17
|
+
* @returns {ShallowRef<T>} Возвращает стандартную для Vue 3 переменную типа `ShallowRef`.
|
|
18
|
+
* При мутации данных в ядре автоматически вызывается `triggerRef`, инициируя точечный перерасчет шаблона.
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* ```vue
|
|
22
|
+
* <script setup>
|
|
23
|
+
* import { useEngine } from '~/composables/useEngine';
|
|
24
|
+
* import { useReactiveValue } from '@pravosleva/reactive-engine/vue';
|
|
25
|
+
*
|
|
26
|
+
* const engine = useEngine();
|
|
27
|
+
* const counterSignal = engine.signal(0, 'ui:counter');
|
|
28
|
+
*
|
|
29
|
+
* // countState теперь обычный Vue Ref, но связанный с ядром данных
|
|
30
|
+
* const countState = useReactiveValue(counterSignal);
|
|
31
|
+
* </script>
|
|
32
|
+
*
|
|
33
|
+
* <template>
|
|
34
|
+
* <button @click="counterSignal.value++">Кликнули: {{ countState }}</button>
|
|
35
|
+
* </template>
|
|
36
|
+
* ```
|
|
37
|
+
*
|
|
38
|
+
* @abstract
|
|
39
|
+
* ### 🚨 Поведение в SSR и Универсальном рендеринге (Nuxt 3 / Nitro)
|
|
40
|
+
* Композибл полностью безопасен для работы на стороне сервера (Node.js). Благодаря внутренним
|
|
41
|
+
* проверкам окружения, на этапе серверного пре-рендеринга он переходит в **пассивный режим**:
|
|
42
|
+
* - Выполняется только однократное чтение `.value` для сборки начального HTML-кода страницы.
|
|
43
|
+
* - Активные подписки и замыкания **не регистрируются**, что полностью предотвращает утечки памяти на сервере.
|
|
44
|
+
* - Исключает появление ошибок несовпадения разметки (`Hydration Mismatch`) при гидратации в браузере.
|
|
45
|
+
*
|
|
46
|
+
* ### 🧹 Управление памятью на клиенте
|
|
47
|
+
* В браузере композибл самостоятельно управляет своим жизненным циклом:
|
|
48
|
+
* - Если вызван внутри компонента, подписка автоматически аннулируется на хуке `onUnmounted`.
|
|
49
|
+
* - Если вызван внутри независимого контекста эффектов, отписка произойдет через `onScopeDispose`.
|
|
50
|
+
*/
|
|
51
|
+
export declare function useReactiveValue<T>(item: ReactiveItem<T>): ShallowRef<T>;
|
|
52
|
+
export {};
|
|
53
|
+
//# sourceMappingURL=useReactiveValue.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useReactiveValue.d.ts","sourceRoot":"","sources":["../../../src/vue/composables/useReactiveValue.ts"],"names":[],"mappings":"AAAA,OAAO,EAA4F,KAAK,UAAU,EAAE,MAAM,KAAK,CAAA;AAE/H,KAAK,SAAS,GAAG,MAAM,IAAI,CAAA;AAC3B,UAAU,YAAY,CAAC,CAAC;IACtB,KAAK,EAAE,CAAC,CAAA;IACR,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,CAAC,KAAK,IAAI,KAAK,SAAS,CAAA;CAC7C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA2CG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,CAwBxE"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { getCurrentInstance as e, getCurrentScope as t, onScopeDispose as n, onUnmounted as r, shallowRef as i, triggerRef as a } from "vue";
|
|
2
|
+
//#region src/vue/composables/useReactiveValue.ts
|
|
3
|
+
function o(o) {
|
|
4
|
+
let s = i(o.value), c = typeof window > "u" || typeof process < "u" && process.server, l = e() || t();
|
|
5
|
+
if (c || !l) return s;
|
|
6
|
+
let u = o.subscribe((e) => {
|
|
7
|
+
s.value = e, a(s);
|
|
8
|
+
});
|
|
9
|
+
return e() ? r(u) : t() && n(u), s;
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { o as useReactiveValue };
|
|
13
|
+
|
|
14
|
+
//# sourceMappingURL=useReactiveValue.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useReactiveValue.mjs","names":[],"sources":["../../../src/vue/composables/useReactiveValue.ts"],"sourcesContent":["import { shallowRef, onUnmounted, getCurrentInstance, getCurrentScope, onScopeDispose, triggerRef, type ShallowRef } from 'vue'\n\ntype CleanupFn = () => void\ninterface ReactiveItem<T> {\n value: T\n subscribe: (cb: (v: T) => void) => CleanupFn\n}\n\n/**\n * Хук-композибл для бесшовной интеграции примитивов реактивного ядра с системой рендеринга Vue 3.\n * Нативно поддерживает как атомарные сигналы (`signal`), так и ленивые вычисляемые свойства (`computed`).\n *\n * @template T Тип данных, содержащихся внутри реактивного элемента.\n *\n * @param {Object} item Реактивный примитив ядра, на который необходимо подписаться.\n * @param {T} item.value Текущее значение элемента.\n * @param {(cb: (v: T) => void) => () => void} item.subscribe Метод ядра для оформления подписки на изменения.\n *\n * @returns {ShallowRef<T>} Возвращает стандартную для Vue 3 переменную типа `ShallowRef`.\n * При мутации данных в ядре автоматически вызывается `triggerRef`, инициируя точечный перерасчет шаблона.\n *\n * @example\n * ```vue\n * <script setup>\n * import { useEngine } from '~/composables/useEngine';\n * import { useReactiveValue } from '@pravosleva/reactive-engine/vue';\n *\n * const engine = useEngine();\n * const counterSignal = engine.signal(0, 'ui:counter');\n *\n * // countState теперь обычный Vue Ref, но связанный с ядром данных\n * const countState = useReactiveValue(counterSignal);\n * </script>\n *\n * <template>\n * <button @click=\"counterSignal.value++\">Кликнули: {{ countState }}</button>\n * </template>\n * ```\n *\n * @abstract\n * ### 🚨 Поведение в SSR и Универсальном рендеринге (Nuxt 3 / Nitro)\n * Композибл полностью безопасен для работы на стороне сервера (Node.js). Благодаря внутренним\n * проверкам окружения, на этапе серверного пре-рендеринга он переходит в **пассивный режим**:\n * - Выполняется только однократное чтение `.value` для сборки начального HTML-кода страницы.\n * - Активные подписки и замыкания **не регистрируются**, что полностью предотвращает утечки памяти на сервере.\n * - Исключает появление ошибок несовпадения разметки (`Hydration Mismatch`) при гидратации в браузере.\n *\n * ### 🧹 Управление памятью на клиенте\n * В браузере композибл самостоятельно управляет своим жизненным циклом:\n * - Если вызван внутри компонента, подписка автоматически аннулируется на хуке `onUnmounted`.\n * - Если вызван внутри независимого контекста эффектов, отписка произойдет через `onScopeDispose`.\n */\nexport function useReactiveValue<T>(item: ReactiveItem<T>): ShallowRef<T> {\n const state = shallowRef(item.value)\n\n // SSR: Если мы на сервере Node.js (нет window) или вне контекста Vue —\n // просто возвращаем пассивный ref, не создавая подписку!\n const isServer = typeof window === 'undefined' || (typeof process !== 'undefined' && process.server)\n const hasInstance = getCurrentInstance() || getCurrentScope()\n\n if (isServer || !hasInstance) {\n return state // Пассивный режим однократного чтения для HTML-рендеринга\n }\n\n const unsubscribe = item.subscribe((newValue) => {\n state.value = newValue\n triggerRef(state)\n })\n\n if (getCurrentInstance()) {\n onUnmounted(unsubscribe)\n } else if (getCurrentScope()) {\n onScopeDispose(unsubscribe)\n }\n\n return state\n}\n"],"mappings":";;AAoDA,SAAgB,EAAoB,GAAsC;CACxE,IAAM,IAAQ,EAAW,EAAK,KAAK,GAI7B,IAAW,OAAO,SAAW,OAAgB,OAAO,UAAY,OAAe,QAAQ,QACvF,IAAc,EAAmB,KAAK,EAAgB;CAE5D,IAAI,KAAY,CAAC,GACf,OAAO;CAGT,IAAM,IAAc,EAAK,WAAW,MAAa;EAE/C,AADA,EAAM,QAAQ,GACd,EAAW,CAAK;CAClB,CAAC;CAQD,OANI,EAAmB,IACrB,EAAY,CAAW,IACd,EAAgB,KACzB,EAAe,CAAW,GAGrB;AACT"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useReactiveValue.test.d.ts","sourceRoot":"","sources":["../../../src/vue/composables/useReactiveValue.test.ts"],"names":[],"mappings":""}
|
package/dist/vue/index.cjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./ReactiveEngine4Vue.cjs");exports.ReactiveEngine=e.ReactiveEngine4Vue;
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./ReactiveEngine4Vue.cjs"),t=require("./composables/useReactiveValue.cjs");exports.ReactiveEngine=e.ReactiveEngine4Vue,exports.useReactiveValue=t.useReactiveValue;
|
package/dist/vue/index.d.ts
CHANGED
package/dist/vue/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vue/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,IAAI,cAAc,EAAE,MAAM,sBAAsB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/vue/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,IAAI,cAAc,EAAE,MAAM,sBAAsB,CAAA;AAE3E,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAA"}
|
package/dist/vue/index.mjs
CHANGED