@itd-api/cache 0.0.1 → 0.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/README.md CHANGED
@@ -3,12 +3,18 @@
3
3
  TTL/LRU-кэш и дедупликация одновременных запросов для
4
4
  [`itd-api`](https://github.com/KiowDev/itd-api).
5
5
 
6
+ [Руководство](https://kiowdev.github.io/itd-api/packages/cache) ·
7
+ [API из TSDoc](https://kiowdev.github.io/itd-api/api/generated/cache/)
8
+
6
9
  ## Установка
7
10
 
8
11
  ```bash
9
12
  npm install itd-api @itd-api/cache
10
13
  ```
11
14
 
15
+ Поддерживается `itd-api >=0.5.0 <1.0.0`: cache использует namespace
16
+ `RequestOptions.extensions` и стабильный `operationId` запроса.
17
+
12
18
  ## Быстрый старт
13
19
 
14
20
  ```ts
@@ -18,7 +24,7 @@ import { ItdClient } from 'itd-api';
18
24
  const itd = new ItdClient({ auth: process.env.ITD_TOKEN });
19
25
  const cached = cache({
20
26
  ttl: 60_000,
21
- routes: ['users.get', 'posts.get', 'posts.list'],
27
+ operations: ['users.get', 'posts.get', 'posts.list'],
22
28
  });
23
29
 
24
30
  itd.use(cached);
@@ -27,16 +33,20 @@ const first = await itd.posts.get(postId); // запрос к API
27
33
  const second = await itd.posts.get(postId); // ответ из кэша
28
34
  ```
29
35
 
30
- Кэшируются только перечисленные маршруты. Query, path и body входят в ключ, поэтому
36
+ Кэшируются только перечисленные операции. Query, path и body входят в ключ, поэтому
31
37
  разные страницы ленты, профили и наборы идентификаторов хранятся отдельно. Одинаковые
32
38
  запросы, запущенные одновременно, выполняют один сетевой вызов.
33
39
 
40
+ Имена в `operations` — стабильные `operationId`, а не HTTP-пути. Поэтому перенос endpoint не ломает
41
+ правила кэша. Низкоуровневый `itd.request()` без явного ID считается операцией `raw`: одно лишь
42
+ совпадение его URL со встроенным resource не включает кэш автоматически.
43
+
34
44
  ## Настройки
35
45
 
36
46
  ```ts
37
47
  const cached = cache({
38
48
  ttl: 60_000,
39
- routes: ['users.get', 'posts.get'],
49
+ operations: ['users.get', 'posts.get'],
40
50
  maxEntries: 500,
41
51
  deduplicate: true,
42
52
  });
@@ -45,7 +55,7 @@ const cached = cache({
45
55
  | Поле | Значение |
46
56
  |---|---|
47
57
  | `ttl` | срок хранения успешного ответа в миллисекундах |
48
- | `routes` | операции, ответы которых нужно кэшировать |
58
+ | `operations` | операции, ответы которых нужно кэшировать |
49
59
  | `maxEntries` | предел LRU-кэша; по умолчанию `500` |
50
60
  | `deduplicate` | объединение одновременных запросов; по умолчанию `true` |
51
61
 
@@ -55,8 +65,8 @@ const cached = cache({
55
65
  ## Управление отдельным запросом
56
66
 
57
67
  ```ts
58
- await itd.posts.get(postId, { cache: 'reload' });
59
- await itd.posts.get(postId, { cache: 'no-store' });
68
+ await itd.posts.get(postId, { extensions: { cache: 'reload' } });
69
+ await itd.posts.get(postId, { extensions: { cache: 'no-store' } });
60
70
  ```
61
71
 
62
72
  - `reload` пропускает готовый ответ, запрашивает новый и заменяет запись;
@@ -68,11 +78,12 @@ await itd.posts.get(postId, { cache: 'no-store' });
68
78
 
69
79
  ## Инвалидация
70
80
 
71
- После успешной мутации плагин удаляет связанные читающие маршруты. Например, реакция на
81
+ После успешной мутации плагин удаляет связанные читающие операции. Например, реакция на
72
82
  пост сбрасывает кэш постов и статистики, но не затрагивает профили, файлы и настройки
73
- платформы. Маршруты с общими данными инвалидируются во всех разделах экземпляра: изменение
74
- поста одним аккаунтом должно быть видно остальным. Персональные настройки, уведомления и
75
- сессии затрагивают только свой раздел.
83
+ платформы. Операции с общими данными инвалидируются во всех аккаунтах экземпляра: изменение
84
+ поста одним аккаунтом должно быть видно остальным. Персональные настройки и уведомления
85
+ инвалидируются у всех копий клиента с тем же пользователем. Изменение сессий сбрасывает все
86
+ варианты `auth.sessions` этого аккаунта, включая варианты других сессий.
76
87
 
77
88
  Известные запросы без зависимостей, включая telemetry и создание жалобы, кэш не меняют.
78
89
 
@@ -85,7 +96,7 @@ cached.invalidate('posts.get', 'posts.list');
85
96
  cached.clear();
86
97
  ```
87
98
 
88
- `invalidate()` удаляет все варианты выбранных маршрутов во всех подключённых клиентах.
99
+ `invalidate()` удаляет все варианты выбранных операций во всех подключённых клиентах.
89
100
  `clear()` очищает всё хранилище. Оба метода защищены от гонки: запрос, начатый до очистки,
90
101
  не запишет устаревший результат после неё.
91
102
 
@@ -102,9 +113,13 @@ detachCache();
102
113
  stream.disconnect();
103
114
  ```
104
115
 
105
- Привязка сразу очищает `notifications.list` и `notifications.count`. Новое уведомление
106
- сбрасывает оба маршрута, событие `unreadCount` счётчик. Другие разделы кэша поток не
107
- изменяет.
116
+ Привязка сразу очищает `notifications.list` и `notifications.count` аккаунта, который
117
+ создал поток. Новое уведомление сбрасывает обе операции во всех копиях клиента с тем же
118
+ пользователем, событие `unreadCount` — их счётчик. Кэш других аккаунтов и остальные операции
119
+ поток не изменяет.
120
+
121
+ У стороннего realtime-объекта без доступных идентификатора пользователя и базового URL
122
+ используется безопасный fallback: операции уведомлений инвалидируются во всех аккаунтах.
108
123
 
109
124
  ## Несколько клиентов
110
125
 
@@ -125,21 +140,26 @@ clientB.use(shared);
125
140
  // либо accounts.use(shared)
126
141
  ```
127
142
 
128
- Каждая установка получает собственный раздел. Ответы и одновременные запросы разных
129
- клиентов не пересекаются: даже публичные профили и посты содержат персонализированные
130
- поля `isLiked`, `isFollowing` и `isReposted`. Инвалидация общей сущности применяется ко
131
- всем разделам, а персонального состояния только к клиенту, который его изменил.
143
+ Копии клиента с одинаковыми базовым URL и пользователем используют общий раздел: готовые
144
+ ответы и одновременные запросы между ними объединяются. Это безопасно для персонализированных
145
+ полей `isLiked`, `isFollowing` и `isReposted`, потому что их значения принадлежат аккаунту,
146
+ а не конкретному access token.
147
+
148
+ Разные пользователи изолированы. Только `auth.sessions` дополнительно разделяется по сессии,
149
+ поскольку ответ отмечает текущую серверную сессию. Если идентификаторов пользователя или
150
+ сессии в токене нет, плагин использует безопасный уникальный раздел установки и ничего между
151
+ копиями не объединяет.
132
152
 
133
- `maxEntries` ограничивает весь экземпляр `shared`, а `clear()`, `invalidate()` и
134
- `attachRealtime()` управляют всеми его разделами. При `setSession()`, входе или выходе
135
- раздел клиента меняется автоматически.
153
+ `maxEntries` ограничивает весь экземпляр `shared`, а `clear()` и `invalidate()` управляют
154
+ всеми его разделами. `attachRealtime()` затрагивает аккаунт создавшего поток клиента.
155
+ Смена сессии сохраняет общий кэш, смена пользователя автоматически выбирает другой раздел.
136
156
 
137
157
  ## Ключ
138
158
 
139
159
  В ключ входят:
140
160
 
141
- - имя маршрута, HTTP-метод и path;
142
- - непрозрачная область клиента и его текущей сессии;
161
+ - имя операции, HTTP-метод и path;
162
+ - базовый URL и идентификатор пользователя; для `auth.sessions` также идентификатор сессии;
143
163
  - `service` или разовый `baseUrl`;
144
164
  - query и JSON-body;
145
165
  - режим `raw`, `skipAuth` и опции других плагинов, влияющие на ответ.
@@ -150,9 +170,9 @@ clientB.use(shared);
150
170
  Ответ хранится как независимая копия: изменение полученного объекта не меняет следующие
151
171
  результаты.
152
172
 
153
- ## Доступные маршруты
173
+ ## Доступные операции
154
174
 
155
- | Раздел | Маршруты |
175
+ | Раздел | Операции |
156
176
  |---|---|
157
177
  | Auth | `auth.sessions` |
158
178
  | Users | `users.me`, `users.get`, `users.checkUsername`, `users.search`, `users.whoToFollow`, `users.topClans`, `users.followers`, `users.following`, `users.blocked`, `users.getPrivacy`, `users.pins`, `users.followStatus` |
@@ -166,14 +186,14 @@ clientB.use(shared);
166
186
  | Verification | `verification.status` |
167
187
  | Platform | `platform.changelog`, `platform.announcements`, `platform.portal`, `platform.status` |
168
188
 
169
- Страницы, загружаемые итераторами, используют маршрут соответствующего списочного метода:
189
+ Страницы, загружаемые итераторами, используют операцию соответствующего списочного метода:
170
190
  `posts.iterate()` — `posts.list`, `users.iterateFollowers()` — `users.followers` и так
171
191
  далее.
172
192
 
173
193
  Каталог доступен программно:
174
194
 
175
195
  ```ts
176
- import { CACHE_ROUTES } from '@itd-api/cache';
196
+ import { CACHE_OPERATIONS } from '@itd-api/cache';
177
197
 
178
- console.log(CACHE_ROUTES.map(({ id }) => id));
198
+ console.log(CACHE_OPERATIONS.map(({ id }) => id));
179
199
  ```