@hyperttp/cache 1.0.22 → 1.1.0
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/LICENSE +21 -0
- package/README.md +133 -0
- package/package.json +4 -3
- package/plugin.d.ts +9 -3
- package/plugin.d.ts.map +1 -1
- package/plugin.js +126 -49
- package/plugin.js.map +1 -1
- package/types/cache.d.ts +1 -1
- package/types/cache.d.ts.map +1 -1
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 IT IF OR
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
# hyperttp-cache
|
|
2
|
+
|
|
3
|
+
> English | [Русский](https://github.com/IT-IF-OR/hyperttp-cache/tree/main/lang/ru)
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 🌐 Language
|
|
8
|
+
|
|
9
|
+
- 🇺🇸 English
|
|
10
|
+
- 🇷🇺 [Русский](https://github.com/IT-IF-OR/hyperttp-cache/tree/main/lang/ru)
|
|
11
|
+
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
Сверхбыстрый, изоморфный плагин кэширования и дедупликации параллельных запросов для высокопроизводительного
|
|
15
|
+
HTTP-клиента `Hyperttp`. Оптимизирован для рантаймов **Bun** и **Node.js**.
|
|
16
|
+
|
|
17
|
+
Плагин бесшовно встраивается в плоский конвейер жизненного цикла `HyperCore`, защищая сервер от лавинообразной
|
|
18
|
+
нагрузки (**Cache Stampede Protection**) и предоставляя умное in-memory хранилище на базе стратегии
|
|
19
|
+
**LRU (Least Recently Used)**.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 🔥 Ключевые фичи
|
|
24
|
+
|
|
25
|
+
- 🧠 **LRU-стратегия с поддержкой TTL:** Автоматическое вытеснение старых записей при достижении лимита. При каждом
|
|
26
|
+
`GET`-запросе возраст записи сбрасывается (`updateAgeOnGet: true`), удерживая горячие данные в памяти.
|
|
27
|
+
- 🚀 **In-Flight Deduplication:** Веерные параллельные запросы на один и тот же URL группируются в один сетевой
|
|
28
|
+
hot path. Ответ клонируется и раздается всем подписчикам одновременно.
|
|
29
|
+
- 🔄 **HTTP Revalidation:** Полная поддержка проверок свежести по `ETag` (`If-None-Match`) и `Last-Modified`
|
|
30
|
+
(`If-Modified-Since`). Автоматически гидрирует пустые `304` ответы актуальным телом из памяти.
|
|
31
|
+
- 🛡️ **Безопасность при сбоях:** При возникновении сетевых ошибок пул ожидания мгновенно разрывается (`onError`),
|
|
32
|
+
разблокируя повторные попытки запросов.
|
|
33
|
+
- 📊 **Расширение Ядра:** Автоматически инжектирует методы управления кэшем (`clearCache`) и добавляет метрику
|
|
34
|
+
`cacheSize` в системную статистику `getStats()`.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## 📦 Установка
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
bun add hyperttp-cache
|
|
42
|
+
# или
|
|
43
|
+
npm install hyperttp-cache
|
|
44
|
+
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## 🚀 Быстрый старт
|
|
50
|
+
|
|
51
|
+
Просто импортируйте фабрику `withCache` и передайте её в массив плагинов вашего клиента. Настройки кэша
|
|
52
|
+
передаются в глобальный конфиг.
|
|
53
|
+
|
|
54
|
+
```typescript
|
|
55
|
+
import { createClient } from "@hyperttp/core";
|
|
56
|
+
import { withCache } from "hyperttp-cache";
|
|
57
|
+
|
|
58
|
+
const client = createClient({
|
|
59
|
+
plugins: [withCache()],
|
|
60
|
+
cache: {
|
|
61
|
+
enabled: true,
|
|
62
|
+
ttl: 60_000, // 1 минута (по умолчанию 300_000 мс)
|
|
63
|
+
maxSize: 1000, // Лимит в 1000 элементов (по умолчанию 500)
|
|
64
|
+
methods: ["GET"], // HTTP-методы, разрешенные для кэширования
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// 1. Первый запрос уходит в сеть и наполняет кэш
|
|
69
|
+
const res1 = await client.get("/api/data");
|
|
70
|
+
|
|
71
|
+
// 2. Второй последующий запрос вернет изолированный клон из кэша
|
|
72
|
+
const res2 = await client.get("/api/data");
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
---
|
|
76
|
+
|
|
77
|
+
## ⚙️ Параметры конфигурации (`CacheManagerOptions`)
|
|
78
|
+
|
|
79
|
+
Конфигурация плагина полностью типизирована и расширяет интерфейс настроек клиента:
|
|
80
|
+
|
|
81
|
+
| Параметр | Тип | По умолчанию | Описание |
|
|
82
|
+
| --------------- | ---------- | ----------------- | ---------------------------------------------------------------- |
|
|
83
|
+
| `cache.enabled` | `boolean` | `false` | Флаг активации/деактивации слоя кэширования. |
|
|
84
|
+
| `cache.ttl` | `number` | `300_000` (5 мин) | Время жизни записи в кэше (в миллисекундах). |
|
|
85
|
+
| `cache.maxSize` | `number` | `500` | Максимальное количество записей в LRU-кэше до начала вытеснения. |
|
|
86
|
+
| `cache.methods` | `Method[]` | `["GET"]` | Массив HTTP-методов, для которых разрешено кэширование ответов. |
|
|
87
|
+
|
|
88
|
+
---
|
|
89
|
+
|
|
90
|
+
## 🛠️ API Расширения Ядра
|
|
91
|
+
|
|
92
|
+
Плагин расширяет глобальные интерфейсы декларации типов `@hyperttp/types`. Вам становятся доступны следующие
|
|
93
|
+
методы прямо из инстанса ядра:
|
|
94
|
+
|
|
95
|
+
### Очистка кэша
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
// Очистить кэш полностью
|
|
99
|
+
client.clearCache();
|
|
100
|
+
|
|
101
|
+
// Удалить конкретный URL из кэша
|
|
102
|
+
client.clearCache("/api/data");
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### Телеметрия
|
|
106
|
+
|
|
107
|
+
Если ваше ядро поддерживает метод `getStats()`, плагин автоматически подмешает туда текущий размер кэша:
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
const stats = client.getStats();
|
|
111
|
+
console.log(stats.cacheSize); // Выведет текущее количество записей в LRU-хранилище
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
## 📐 Архитектура жизненного цикла
|
|
117
|
+
|
|
118
|
+
Плагин использует атомарные независимые хуки вместо тяжелых middleware-оберток:
|
|
119
|
+
|
|
120
|
+
1. **`onRequest`**: Проверяет наличие точного совпадения в `CacheManager`. Если запись свежая и не требует
|
|
121
|
+
проверки сервера — возвращает её клон, завершая цепочку. Если идет активный запрос к этому же URL — подписывается
|
|
122
|
+
на его `Promise`. Если запись требует валидации, подмешает заголовки `If-None-Match` / `If-Modified-Since`.
|
|
123
|
+
2. **`onResponse`**: Перехватывает успешные ответы. Превращает пустой `304 Not Modified` обратно в полноценный
|
|
124
|
+
`200 OK`, восстанавливая данные из локальной памяти. Записывает новые `200` ответы с валидными ETag. Разрешает
|
|
125
|
+
(resolves) ожидания всех `In-Flight` подписчиков.
|
|
126
|
+
3. **`onError`**: В случае сетевого сбоя вычищает карту активных задач, чтобы не заблокировать последующие
|
|
127
|
+
повторные вызовы к упавшему эндпоинту.
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
## 📄 Лицензия
|
|
132
|
+
|
|
133
|
+
MIT
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperttp/cache",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"description": "High-performance LRU caching plugin for Hyperttp client",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./index.js",
|
|
@@ -15,10 +15,11 @@
|
|
|
15
15
|
"url": "git+https://github.com/IT-IF-OR/hyperttp-cache.git"
|
|
16
16
|
},
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"
|
|
18
|
+
"@hyperttp/types": "^0.1.1",
|
|
19
|
+
"lru-cache": "^11.5.1"
|
|
19
20
|
},
|
|
20
21
|
"peerDependencies": {
|
|
21
|
-
"@hyperttp/core": "^1.
|
|
22
|
+
"@hyperttp/core": "^1.2.0"
|
|
22
23
|
},
|
|
23
24
|
"private": false
|
|
24
25
|
}
|
package/plugin.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { HyperPlugin } from "@hyperttp/
|
|
1
|
+
import type { HyperPlugin } from "@hyperttp/types";
|
|
2
2
|
import type { CacheManagerOptions } from "./types/cache.js";
|
|
3
3
|
import { CacheManager } from "./utils/CacheManager.js";
|
|
4
|
-
declare module "@hyperttp/
|
|
4
|
+
declare module "@hyperttp/types" {
|
|
5
5
|
interface PluginContext {
|
|
6
6
|
cache?: CacheManager;
|
|
7
7
|
}
|
|
@@ -10,9 +10,15 @@ declare module "@hyperttp/core" {
|
|
|
10
10
|
enabled: boolean;
|
|
11
11
|
};
|
|
12
12
|
}
|
|
13
|
-
interface
|
|
13
|
+
interface IHyperCore {
|
|
14
14
|
clearCache(key?: string): void;
|
|
15
|
+
getStats?(): Record<string, any>;
|
|
15
16
|
}
|
|
16
17
|
}
|
|
18
|
+
/**
|
|
19
|
+
* @ru Фабрика плагина кэширования и дедупликации конкурентных запросов для HyperCore.
|
|
20
|
+
* @en Cache management and concurrent request deduplication plugin factory for HyperCore.
|
|
21
|
+
* @returns Модуль расширения ядра в рамках линейного жизненного цикла. / Configured extension plugin container.
|
|
22
|
+
*/
|
|
17
23
|
export declare function withCache(): HyperPlugin;
|
|
18
24
|
//# sourceMappingURL=plugin.d.ts.map
|
package/plugin.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,WAAW,EAKZ,MAAM,iBAAiB,CAAC;AAEzB,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAEvD,OAAO,QAAQ,iBAAiB,CAAC;IAC/B,UAAU,aAAa;QACrB,KAAK,CAAC,EAAE,YAAY,CAAC;KACtB;IACD,UAAU,wBAAwB;QAChC,KAAK,CAAC,EAAE,mBAAmB,GAAG;YAC5B,OAAO,EAAE,OAAO,CAAC;SAClB,CAAC;KACH;IACD,UAAU,UAAU;QAClB,UAAU,CAAC,GAAG,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;QAC/B,QAAQ,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;KAClC;CACF;AAaD;;;;GAIG;AACH,wBAAgB,SAAS,IAAI,WAAW,CA+LvC"}
|
package/plugin.js
CHANGED
|
@@ -1,12 +1,44 @@
|
|
|
1
1
|
import { CacheManager } from "./utils/CacheManager.js";
|
|
2
|
+
/**
|
|
3
|
+
* @ru Фабрика плагина кэширования и дедупликации конкурентных запросов для HyperCore.
|
|
4
|
+
* @en Cache management and concurrent request deduplication plugin factory for HyperCore.
|
|
5
|
+
* @returns Модуль расширения ядра в рамках линейного жизненного цикла. / Configured extension plugin container.
|
|
6
|
+
*/
|
|
2
7
|
export function withCache() {
|
|
8
|
+
/**
|
|
9
|
+
* @private
|
|
10
|
+
* @ru Изолированный инстанс менеджера кэша для текущего клиента.
|
|
11
|
+
* @en Isolated cache manager orchestration instance allocated for the target client.
|
|
12
|
+
*/
|
|
3
13
|
let cache;
|
|
14
|
+
/**
|
|
15
|
+
* @private
|
|
16
|
+
* @ru Список HTTP-методов, для которых разрешено кэширование ответов.
|
|
17
|
+
* @en Set of HTTP request methods authorized for downstream response caching.
|
|
18
|
+
*/
|
|
4
19
|
let allowedMethods;
|
|
20
|
+
/**
|
|
21
|
+
* @private
|
|
22
|
+
* @ru Карта активных сетевых запросов для предотвращения каскадного заваливания бэкенда (Cache Stampede).
|
|
23
|
+
* @en Registry of concurrent requests in execution to prevent backend server breakdown (Cache Stampede).
|
|
24
|
+
*/
|
|
5
25
|
const inFlight = new Map();
|
|
6
26
|
return {
|
|
7
27
|
name: "hyperttp-cache",
|
|
8
|
-
|
|
9
|
-
|
|
28
|
+
/**
|
|
29
|
+
* @ru Динамическая проверка необходимости активации кэширования на основе переданных опций.
|
|
30
|
+
* @en Dynamic check evaluating if the caching plugin layer should be appended based on client runtime options.
|
|
31
|
+
* @param config - Глобальная конфигурация инстанса клиента. / Global active client lifecycle options.
|
|
32
|
+
* @returns Индикатор необходимости сборки плагина. / Lifecycle activation indicator status.
|
|
33
|
+
*/
|
|
34
|
+
enabled: (config) => {
|
|
35
|
+
return !!config.cache?.enabled;
|
|
36
|
+
},
|
|
37
|
+
/**
|
|
38
|
+
* @ru Однократный хук инициализации. Настраивает менеджер кэша и внедряет методы отладки/очистки в ядро.
|
|
39
|
+
* @en One-time setup context hook. Orchestrates the cache manager and extends telemetry/purge interfaces inside the core.
|
|
40
|
+
* @param ctx - Общий контекст окружения плагина. / Shared plugin execution context metadata.
|
|
41
|
+
*/
|
|
10
42
|
setup(ctx) {
|
|
11
43
|
const { core, config } = ctx;
|
|
12
44
|
cache = new CacheManager(config?.cache);
|
|
@@ -27,54 +59,99 @@ export function withCache() {
|
|
|
27
59
|
return key ? cache.delete(key) : cache.clear();
|
|
28
60
|
};
|
|
29
61
|
},
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
62
|
+
/**
|
|
63
|
+
* @ru Перехватчик фазы отправки запроса. Проверяет локальные кэш-хиты и координирует пулинг конкурентных задач.
|
|
64
|
+
* @en Request phase interceptor. Evaluates local cache hits, appends conditional headers, or hooks into active in-flight targets.
|
|
65
|
+
* @param req - Сконфигурированный внутренний объект запроса. / Contextual internal request parameters.
|
|
66
|
+
* @param ctx - Общий контекст окружения плагина. / Shared plugin execution context metadata.
|
|
67
|
+
* @returns Мгновенный изолированный ответ из кэша, обертку гонки или void для продолжения сетевого цикла. / Short-circuit response clone, matching follower promise tracker, or void execution.
|
|
68
|
+
*/
|
|
69
|
+
onRequest(req,
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
71
|
+
_ctx) {
|
|
72
|
+
const method = req.method.toUpperCase();
|
|
73
|
+
if (!allowedMethods.has(method)) {
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
const cacheKey = req.url;
|
|
77
|
+
const cachedEntry = cache.getWithMetadata(cacheKey);
|
|
78
|
+
if (cachedEntry !== undefined &&
|
|
79
|
+
!cachedEntry.etag &&
|
|
80
|
+
!cachedEntry.lastModified) {
|
|
81
|
+
return cachedEntry.data.clone();
|
|
82
|
+
}
|
|
83
|
+
// Частичный кэш-хит, подмешиваем заголовки проверки свежести
|
|
84
|
+
if (cachedEntry !== undefined) {
|
|
85
|
+
req.headers = { ...req.headers };
|
|
86
|
+
if (cachedEntry.etag)
|
|
87
|
+
req.headers["if-none-match"] = cachedEntry.etag;
|
|
88
|
+
if (cachedEntry.lastModified)
|
|
89
|
+
req.headers["if-modified-since"] = cachedEntry.lastModified;
|
|
90
|
+
}
|
|
91
|
+
const currentInFlight = inFlight.get(cacheKey);
|
|
92
|
+
if (currentInFlight) {
|
|
93
|
+
return currentInFlight.promise.then((res) => res.clone());
|
|
94
|
+
}
|
|
95
|
+
let resolveFn;
|
|
96
|
+
let rejectFn;
|
|
97
|
+
const promise = new Promise((res, rej) => {
|
|
98
|
+
resolveFn = res;
|
|
99
|
+
rejectFn = rej;
|
|
100
|
+
});
|
|
101
|
+
promise.catch(() => { });
|
|
102
|
+
inFlight.set(cacheKey, { promise, resolve: resolveFn, reject: rejectFn });
|
|
103
|
+
},
|
|
104
|
+
/**
|
|
105
|
+
* @ru Перехватчик фазы получения ответа. Обновляет хранилище или трансформирует статус 304 в полные данные из кэша.
|
|
106
|
+
* @en Response phase interceptor. Saves raw outputs to the storage layer or re-hydrates empty 304 responses with cached data bodies.
|
|
107
|
+
*/
|
|
108
|
+
onResponse(res, req,
|
|
109
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
110
|
+
_ctx) {
|
|
111
|
+
const cacheKey = req.url;
|
|
112
|
+
const trigger = inFlight.get(cacheKey);
|
|
113
|
+
if (!trigger) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
inFlight.delete(cacheKey);
|
|
117
|
+
const cachedEntry = cache.getWithMetadata(cacheKey);
|
|
118
|
+
if (res.status === 304 && cachedEntry !== undefined) {
|
|
119
|
+
const clonedCache = cachedEntry.data.clone();
|
|
120
|
+
Object.assign(res, clonedCache);
|
|
121
|
+
res.status = clonedCache.status ?? 200;
|
|
122
|
+
trigger.resolve(clonedCache);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (res.status >= 200 && res.status < 300) {
|
|
126
|
+
const valueToCache = res.clone();
|
|
127
|
+
const headers = res.headers;
|
|
128
|
+
const etag = headers?.["etag"] || headers?.["ETag"];
|
|
129
|
+
const lastModified = headers?.["last-modified"] || headers?.["Last-Modified"];
|
|
130
|
+
cache.setWithMetadata(cacheKey, valueToCache, {
|
|
131
|
+
etag: typeof etag === "string" ? etag : undefined,
|
|
132
|
+
lastModified: typeof lastModified === "string" ? lastModified : undefined,
|
|
74
133
|
});
|
|
75
|
-
|
|
76
|
-
return
|
|
77
|
-
}
|
|
134
|
+
trigger.resolve(res.clone());
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
trigger.resolve(res.clone());
|
|
138
|
+
},
|
|
139
|
+
/**
|
|
140
|
+
* @ru Перехватчик фазы критических сбоев. Разрывает пул ожидания дедупликации, транслируя ошибку всем подписчикам.
|
|
141
|
+
* @en Error phase interceptor. Purges matching metadata maps and forwards pipeline processing exceptions to all waiting threads.
|
|
142
|
+
* @param err - Специфичный объект ошибки сетевого клиента. / Normalized client-level error framework tracking details.
|
|
143
|
+
* @param req - Сконфигурированный внутренний объект запроса. / Contextual internal request parameters.
|
|
144
|
+
* @param ctx - Общий контекст окружения плагина. / Shared plugin execution context metadata.
|
|
145
|
+
*/
|
|
146
|
+
onError(err, req,
|
|
147
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
148
|
+
_ctx) {
|
|
149
|
+
const cacheKey = req.url;
|
|
150
|
+
const trigger = inFlight.get(cacheKey);
|
|
151
|
+
if (trigger) {
|
|
152
|
+
inFlight.delete(cacheKey);
|
|
153
|
+
trigger.reject(err);
|
|
154
|
+
}
|
|
78
155
|
},
|
|
79
156
|
};
|
|
80
157
|
}
|
package/plugin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"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"}
|
package/types/cache.d.ts
CHANGED
package/types/cache.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/types/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"cache.d.ts","sourceRoot":"","sources":["../../src/types/cache.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,MAAM,WAAW,UAAU,CAAC,CAAC;IAC3B,IAAI,EAAE,CAAC,CAAC;IACR,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,mBAAmB;IAClC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB;;;OAGG;IACH,OAAO,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC7B"}
|