@itd-api/cache 0.0.2 → 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 +28 -18
- package/dist/index.cjs +790 -696
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +167 -256
- package/dist/index.d.ts +167 -256
- package/dist/index.js +786 -691
- package/dist/index.js.map +1 -1
- package/package.json +11 -10
package/dist/index.cjs
CHANGED
|
@@ -1,728 +1,822 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
// src/errors.ts
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let lru_cache = require("lru-cache");
|
|
3
|
+
//#region src/errors.ts
|
|
4
|
+
/** Ошибка настройки или использования плагина кэша. */
|
|
6
5
|
var CacheError = class extends Error {
|
|
7
|
-
|
|
6
|
+
name = "CacheError";
|
|
8
7
|
};
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
8
|
+
//#endregion
|
|
9
|
+
//#region src/key.ts
|
|
10
|
+
const OMITTED_FIELDS = /* @__PURE__ */ new Set([
|
|
11
|
+
"method",
|
|
12
|
+
"operationId",
|
|
13
|
+
"path",
|
|
14
|
+
"service",
|
|
15
|
+
"baseUrl",
|
|
16
|
+
"query",
|
|
17
|
+
"body",
|
|
18
|
+
"headers",
|
|
19
|
+
"raw",
|
|
20
|
+
"skipAuth",
|
|
21
|
+
"signal",
|
|
22
|
+
"timeout",
|
|
23
|
+
"retry",
|
|
24
|
+
"retrySafety",
|
|
25
|
+
"skipQueue",
|
|
26
|
+
"skipAuthRefresh",
|
|
27
|
+
"extensions"
|
|
27
28
|
]);
|
|
29
|
+
/** Строка query в том же порядке и с теми же правилами, что использует itd-api. */
|
|
28
30
|
function queryKey(query) {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
return search.toString();
|
|
31
|
+
if (!query) return "";
|
|
32
|
+
const search = new URLSearchParams();
|
|
33
|
+
for (const [key, value] of Object.entries(query)) {
|
|
34
|
+
if (value === void 0 || value === null) continue;
|
|
35
|
+
if (Array.isArray(value)) for (const item of value) search.append(key, String(item));
|
|
36
|
+
else search.append(key, String(value));
|
|
37
|
+
}
|
|
38
|
+
return search.toString();
|
|
40
39
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
40
|
+
/**
|
|
41
|
+
* Собирает ключ из значений, влияющих на адрес, тело или разобранный ответ.
|
|
42
|
+
*
|
|
43
|
+
* Заголовки и транспортные опции намеренно не входят. Если тело либо опция другого
|
|
44
|
+
* плагина не сериализуются как JSON, запрос выполняется без кэша.
|
|
45
|
+
*/
|
|
46
|
+
function buildCacheKey(operation, request) {
|
|
47
|
+
const extras = {};
|
|
48
|
+
for (const [key, value] of Object.entries(request)) if (!OMITTED_FIELDS.has(key) && value !== void 0) extras[key] = value;
|
|
49
|
+
const { cache: _cacheMode, ...extensions } = request.extensions ?? {};
|
|
50
|
+
if (Object.keys(extensions).length > 0) extras.extensions = extensions;
|
|
51
|
+
try {
|
|
52
|
+
return JSON.stringify({
|
|
53
|
+
operation,
|
|
54
|
+
method: request.method.toUpperCase(),
|
|
55
|
+
service: request.service ?? null,
|
|
56
|
+
baseUrl: request.baseUrl ?? null,
|
|
57
|
+
path: request.path,
|
|
58
|
+
query: queryKey(request.query),
|
|
59
|
+
body: request.body ?? null,
|
|
60
|
+
raw: request.raw ?? false,
|
|
61
|
+
skipAuth: request.skipAuth ?? null,
|
|
62
|
+
extras
|
|
63
|
+
});
|
|
64
|
+
} catch {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
62
67
|
}
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
68
|
+
//#endregion
|
|
69
|
+
//#region src/operations.ts
|
|
70
|
+
function freezeOperations(operations) {
|
|
71
|
+
for (const operation of operations) Object.freeze(operation);
|
|
72
|
+
return Object.freeze(operations);
|
|
73
|
+
}
|
|
74
|
+
/** Читающие операции, которые можно кэшировать. */
|
|
75
|
+
const CACHE_OPERATIONS = freezeOperations([
|
|
76
|
+
{
|
|
77
|
+
id: "auth.sessions",
|
|
78
|
+
category: "auth"
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
id: "users.me",
|
|
82
|
+
category: "users"
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: "users.checkUsername",
|
|
86
|
+
category: "users"
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
id: "users.search",
|
|
90
|
+
category: "users"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: "users.whoToFollow",
|
|
94
|
+
category: "users"
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
id: "users.topClans",
|
|
98
|
+
category: "users"
|
|
99
|
+
},
|
|
100
|
+
{
|
|
101
|
+
id: "users.followers",
|
|
102
|
+
category: "users"
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
id: "users.following",
|
|
106
|
+
category: "users"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
id: "users.blocked",
|
|
110
|
+
category: "users"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
id: "users.getPrivacy",
|
|
114
|
+
category: "users"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
id: "users.pins",
|
|
118
|
+
category: "users"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
id: "users.followStatus",
|
|
122
|
+
category: "users"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
id: "users.get",
|
|
126
|
+
category: "users"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
id: "posts.list",
|
|
130
|
+
category: "posts"
|
|
131
|
+
},
|
|
132
|
+
{
|
|
133
|
+
id: "posts.likedByUser",
|
|
134
|
+
category: "posts"
|
|
135
|
+
},
|
|
136
|
+
{
|
|
137
|
+
id: "posts.byUser",
|
|
138
|
+
category: "posts"
|
|
139
|
+
},
|
|
140
|
+
{
|
|
141
|
+
id: "posts.comments",
|
|
142
|
+
category: "posts"
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
id: "posts.stats",
|
|
146
|
+
category: "posts"
|
|
147
|
+
},
|
|
148
|
+
{
|
|
149
|
+
id: "posts.get",
|
|
150
|
+
category: "posts"
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
id: "comments.replies",
|
|
154
|
+
category: "comments"
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
id: "notifications.list",
|
|
158
|
+
category: "notifications"
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
id: "notifications.count",
|
|
162
|
+
category: "notifications"
|
|
163
|
+
},
|
|
164
|
+
{
|
|
165
|
+
id: "notifications.getSettings",
|
|
166
|
+
category: "notifications"
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
id: "hashtags.search",
|
|
170
|
+
category: "hashtags"
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
id: "hashtags.trending",
|
|
174
|
+
category: "hashtags"
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
id: "hashtags.posts",
|
|
178
|
+
category: "hashtags"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
id: "search.all",
|
|
182
|
+
category: "search"
|
|
183
|
+
},
|
|
184
|
+
{
|
|
185
|
+
id: "files.get",
|
|
186
|
+
category: "files"
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
id: "subscription.status",
|
|
190
|
+
category: "subscription"
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
id: "subscription.methods",
|
|
194
|
+
category: "subscription"
|
|
195
|
+
},
|
|
196
|
+
{
|
|
197
|
+
id: "verification.status",
|
|
198
|
+
category: "verification"
|
|
199
|
+
},
|
|
200
|
+
{
|
|
201
|
+
id: "platform.changelog",
|
|
202
|
+
category: "platform"
|
|
203
|
+
},
|
|
204
|
+
{
|
|
205
|
+
id: "platform.announcements",
|
|
206
|
+
category: "platform"
|
|
207
|
+
},
|
|
208
|
+
{
|
|
209
|
+
id: "platform.portal",
|
|
210
|
+
category: "platform"
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
id: "platform.status",
|
|
214
|
+
category: "platform"
|
|
215
|
+
}
|
|
216
|
+
]);
|
|
217
|
+
const OPERATIONS = new Map(CACHE_OPERATIONS.map((operation) => [operation.id, operation]));
|
|
218
|
+
/** Проверяет публичное имя кэшируемой операции. */
|
|
219
|
+
function isCacheOperationId(value) {
|
|
220
|
+
return OPERATIONS.has(value);
|
|
221
|
+
}
|
|
222
|
+
/** Находит читающую операцию по стабильному семантическому ID. */
|
|
223
|
+
function cacheOperation(operationId) {
|
|
224
|
+
return OPERATIONS.get(operationId);
|
|
225
|
+
}
|
|
226
|
+
//#endregion
|
|
227
|
+
//#region src/mutations.ts
|
|
228
|
+
const POST_CONTENT = [
|
|
229
|
+
"posts.list",
|
|
230
|
+
"posts.get",
|
|
231
|
+
"posts.byUser",
|
|
232
|
+
"posts.likedByUser",
|
|
233
|
+
"posts.comments",
|
|
234
|
+
"posts.stats",
|
|
235
|
+
"comments.replies",
|
|
236
|
+
"hashtags.search",
|
|
237
|
+
"hashtags.trending",
|
|
238
|
+
"hashtags.posts",
|
|
239
|
+
"search.all",
|
|
240
|
+
"users.me",
|
|
241
|
+
"users.get",
|
|
242
|
+
"users.pins"
|
|
98
243
|
];
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
"users.following",
|
|
108
|
-
"users.blocked",
|
|
109
|
-
"users.getPrivacy",
|
|
110
|
-
"users.pins",
|
|
111
|
-
"users.followStatus",
|
|
112
|
-
"posts.list",
|
|
113
|
-
"posts.get",
|
|
114
|
-
"posts.byUser",
|
|
115
|
-
"posts.likedByUser",
|
|
116
|
-
"posts.comments",
|
|
117
|
-
"comments.replies",
|
|
118
|
-
"hashtags.posts",
|
|
119
|
-
"search.all"
|
|
244
|
+
const POST_REACTIONS = [
|
|
245
|
+
"posts.list",
|
|
246
|
+
"posts.get",
|
|
247
|
+
"posts.byUser",
|
|
248
|
+
"posts.likedByUser",
|
|
249
|
+
"posts.stats",
|
|
250
|
+
"hashtags.posts",
|
|
251
|
+
"search.all"
|
|
120
252
|
];
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
"posts.list",
|
|
130
|
-
"posts.byUser",
|
|
131
|
-
"search.all"
|
|
253
|
+
const COMMENTS = [
|
|
254
|
+
"posts.list",
|
|
255
|
+
"posts.get",
|
|
256
|
+
"posts.comments",
|
|
257
|
+
"posts.stats",
|
|
258
|
+
"comments.replies",
|
|
259
|
+
"hashtags.posts",
|
|
260
|
+
"search.all"
|
|
132
261
|
];
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
262
|
+
const PROFILE = [
|
|
263
|
+
"users.me",
|
|
264
|
+
"users.get",
|
|
265
|
+
"users.checkUsername",
|
|
266
|
+
"users.search",
|
|
267
|
+
"users.whoToFollow",
|
|
268
|
+
"users.topClans",
|
|
269
|
+
"users.followers",
|
|
270
|
+
"users.following",
|
|
271
|
+
"users.blocked",
|
|
272
|
+
"users.getPrivacy",
|
|
273
|
+
"users.pins",
|
|
274
|
+
"users.followStatus",
|
|
275
|
+
"posts.list",
|
|
276
|
+
"posts.get",
|
|
277
|
+
"posts.byUser",
|
|
278
|
+
"posts.likedByUser",
|
|
279
|
+
"posts.comments",
|
|
280
|
+
"comments.replies",
|
|
281
|
+
"hashtags.posts",
|
|
282
|
+
"search.all"
|
|
144
283
|
];
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
284
|
+
const FOLLOWING = [
|
|
285
|
+
"users.me",
|
|
286
|
+
"users.get",
|
|
287
|
+
"users.search",
|
|
288
|
+
"users.whoToFollow",
|
|
289
|
+
"users.followers",
|
|
290
|
+
"users.following",
|
|
291
|
+
"users.followStatus",
|
|
292
|
+
"posts.list",
|
|
293
|
+
"posts.byUser",
|
|
294
|
+
"search.all"
|
|
152
295
|
];
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
296
|
+
const BLOCKS = [
|
|
297
|
+
"users.me",
|
|
298
|
+
"users.get",
|
|
299
|
+
"users.search",
|
|
300
|
+
"users.whoToFollow",
|
|
301
|
+
"users.followers",
|
|
302
|
+
"users.following",
|
|
303
|
+
"users.blocked",
|
|
304
|
+
"users.followStatus",
|
|
305
|
+
"posts.list",
|
|
306
|
+
"search.all"
|
|
156
307
|
];
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
308
|
+
const PINS = [
|
|
309
|
+
"users.me",
|
|
310
|
+
"users.get",
|
|
311
|
+
"users.pins",
|
|
312
|
+
"posts.list",
|
|
313
|
+
"posts.get",
|
|
314
|
+
"posts.byUser"
|
|
160
315
|
];
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
{
|
|
408
|
-
id: "subscription.methods",
|
|
409
|
-
category: "subscription",
|
|
410
|
-
method: "GET",
|
|
411
|
-
path: /^\/api\/v1\/subscription\/methods$/
|
|
412
|
-
},
|
|
413
|
-
{
|
|
414
|
-
id: "verification.status",
|
|
415
|
-
category: "verification",
|
|
416
|
-
method: "GET",
|
|
417
|
-
path: /^\/api\/verification\/status$/
|
|
418
|
-
},
|
|
419
|
-
{
|
|
420
|
-
id: "platform.changelog",
|
|
421
|
-
category: "platform",
|
|
422
|
-
method: "GET",
|
|
423
|
-
path: /^\/api\/platform\/changelog$/
|
|
424
|
-
},
|
|
425
|
-
{
|
|
426
|
-
id: "platform.announcements",
|
|
427
|
-
category: "platform",
|
|
428
|
-
method: "GET",
|
|
429
|
-
path: /^\/api\/platform\/announcements$/
|
|
430
|
-
},
|
|
431
|
-
{ id: "platform.portal", category: "platform", method: "GET", path: /^\/api\/v1\/portal$/ },
|
|
432
|
-
{ id: "platform.status", category: "platform", method: "GET", path: /^\/api\/status$/ }
|
|
316
|
+
const NOTIFICATIONS = ["notifications.list", "notifications.count"];
|
|
317
|
+
const SUBSCRIPTION = ["subscription.status", "subscription.methods"];
|
|
318
|
+
const NOTHING = [];
|
|
319
|
+
/**
|
|
320
|
+
* Известные изменяющие запросы и читающие операции, чьи ответы они могут изменить.
|
|
321
|
+
*
|
|
322
|
+
* Каталог намеренно консервативен: лучше удалить несколько связанных списков, чем оставить
|
|
323
|
+
* персонализированное поле или вложенный объект устаревшим.
|
|
324
|
+
*/
|
|
325
|
+
const CACHE_MUTATIONS = Object.freeze([
|
|
326
|
+
{
|
|
327
|
+
operationId: "auth.refresh",
|
|
328
|
+
invalidates: NOTHING
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
operationId: "auth.resendOtp",
|
|
332
|
+
invalidates: NOTHING
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
operationId: "auth.forgotPassword",
|
|
336
|
+
invalidates: NOTHING
|
|
337
|
+
},
|
|
338
|
+
{
|
|
339
|
+
operationId: "auth.signUp",
|
|
340
|
+
invalidates: "all"
|
|
341
|
+
},
|
|
342
|
+
{
|
|
343
|
+
operationId: "auth.signIn",
|
|
344
|
+
invalidates: "all"
|
|
345
|
+
},
|
|
346
|
+
{
|
|
347
|
+
operationId: "auth.verifyOtp",
|
|
348
|
+
invalidates: "all"
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
operationId: "auth.logout",
|
|
352
|
+
invalidates: "all"
|
|
353
|
+
},
|
|
354
|
+
{
|
|
355
|
+
operationId: "auth.resetPassword",
|
|
356
|
+
invalidates: "all"
|
|
357
|
+
},
|
|
358
|
+
{
|
|
359
|
+
operationId: "auth.changePassword",
|
|
360
|
+
invalidates: "all"
|
|
361
|
+
},
|
|
362
|
+
{
|
|
363
|
+
operationId: "auth.revokeSession",
|
|
364
|
+
invalidates: ["auth.sessions"],
|
|
365
|
+
scope: "account"
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
operationId: "auth.revokeOtherSessions",
|
|
369
|
+
invalidates: ["auth.sessions"],
|
|
370
|
+
scope: "account"
|
|
371
|
+
},
|
|
372
|
+
{
|
|
373
|
+
operationId: "posts.create",
|
|
374
|
+
invalidates: POST_CONTENT
|
|
375
|
+
},
|
|
376
|
+
{
|
|
377
|
+
operationId: "posts.update",
|
|
378
|
+
invalidates: POST_CONTENT
|
|
379
|
+
},
|
|
380
|
+
{
|
|
381
|
+
operationId: "posts.remove",
|
|
382
|
+
invalidates: POST_CONTENT
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
operationId: "posts.restore",
|
|
386
|
+
invalidates: POST_CONTENT
|
|
387
|
+
},
|
|
388
|
+
{
|
|
389
|
+
operationId: "posts.like",
|
|
390
|
+
invalidates: POST_REACTIONS
|
|
391
|
+
},
|
|
392
|
+
{
|
|
393
|
+
operationId: "posts.unlike",
|
|
394
|
+
invalidates: POST_REACTIONS
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
operationId: "posts.repost",
|
|
398
|
+
invalidates: POST_CONTENT
|
|
399
|
+
},
|
|
400
|
+
{
|
|
401
|
+
operationId: "posts.unrepost",
|
|
402
|
+
invalidates: POST_CONTENT
|
|
403
|
+
},
|
|
404
|
+
{
|
|
405
|
+
operationId: "posts.pin",
|
|
406
|
+
invalidates: PINS
|
|
407
|
+
},
|
|
408
|
+
{
|
|
409
|
+
operationId: "posts.unpin",
|
|
410
|
+
invalidates: PINS
|
|
411
|
+
},
|
|
412
|
+
{
|
|
413
|
+
operationId: "posts.vote",
|
|
414
|
+
invalidates: POST_REACTIONS
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
operationId: "posts.comment",
|
|
418
|
+
invalidates: COMMENTS
|
|
419
|
+
},
|
|
420
|
+
{
|
|
421
|
+
operationId: "comments.reply",
|
|
422
|
+
invalidates: COMMENTS
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
operationId: "comments.update",
|
|
426
|
+
invalidates: COMMENTS
|
|
427
|
+
},
|
|
428
|
+
{
|
|
429
|
+
operationId: "comments.remove",
|
|
430
|
+
invalidates: COMMENTS
|
|
431
|
+
},
|
|
432
|
+
{
|
|
433
|
+
operationId: "comments.restore",
|
|
434
|
+
invalidates: COMMENTS
|
|
435
|
+
},
|
|
436
|
+
{
|
|
437
|
+
operationId: "comments.like",
|
|
438
|
+
invalidates: COMMENTS
|
|
439
|
+
},
|
|
440
|
+
{
|
|
441
|
+
operationId: "comments.unlike",
|
|
442
|
+
invalidates: COMMENTS
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
operationId: "users.updateMe",
|
|
446
|
+
invalidates: PROFILE
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
operationId: "users.deactivate",
|
|
450
|
+
invalidates: PROFILE
|
|
451
|
+
},
|
|
452
|
+
{
|
|
453
|
+
operationId: "users.restore",
|
|
454
|
+
invalidates: PROFILE
|
|
455
|
+
},
|
|
456
|
+
{
|
|
457
|
+
operationId: "users.createProfile",
|
|
458
|
+
invalidates: PROFILE
|
|
459
|
+
},
|
|
460
|
+
{
|
|
461
|
+
operationId: "users.follow",
|
|
462
|
+
invalidates: FOLLOWING
|
|
463
|
+
},
|
|
464
|
+
{
|
|
465
|
+
operationId: "users.unfollow",
|
|
466
|
+
invalidates: FOLLOWING
|
|
467
|
+
},
|
|
468
|
+
{
|
|
469
|
+
operationId: "users.block",
|
|
470
|
+
invalidates: BLOCKS
|
|
471
|
+
},
|
|
472
|
+
{
|
|
473
|
+
operationId: "users.unblock",
|
|
474
|
+
invalidates: BLOCKS
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
operationId: "users.updatePrivacy",
|
|
478
|
+
invalidates: [
|
|
479
|
+
"users.me",
|
|
480
|
+
"users.get",
|
|
481
|
+
"users.getPrivacy"
|
|
482
|
+
]
|
|
483
|
+
},
|
|
484
|
+
{
|
|
485
|
+
operationId: "users.setPin",
|
|
486
|
+
invalidates: PINS
|
|
487
|
+
},
|
|
488
|
+
{
|
|
489
|
+
operationId: "users.removePin",
|
|
490
|
+
invalidates: PINS
|
|
491
|
+
},
|
|
492
|
+
{
|
|
493
|
+
operationId: "notifications.markRead",
|
|
494
|
+
invalidates: NOTIFICATIONS,
|
|
495
|
+
scope: "account"
|
|
496
|
+
},
|
|
497
|
+
{
|
|
498
|
+
operationId: "notifications.markReadBatch",
|
|
499
|
+
invalidates: NOTIFICATIONS,
|
|
500
|
+
scope: "account"
|
|
501
|
+
},
|
|
502
|
+
{
|
|
503
|
+
operationId: "notifications.markAllRead",
|
|
504
|
+
invalidates: NOTIFICATIONS,
|
|
505
|
+
scope: "account"
|
|
506
|
+
},
|
|
507
|
+
{
|
|
508
|
+
operationId: "notifications.updateSettings",
|
|
509
|
+
invalidates: ["notifications.getSettings"],
|
|
510
|
+
scope: "account"
|
|
511
|
+
},
|
|
512
|
+
{
|
|
513
|
+
operationId: "files.upload",
|
|
514
|
+
invalidates: NOTHING
|
|
515
|
+
},
|
|
516
|
+
{
|
|
517
|
+
operationId: "files.remove",
|
|
518
|
+
invalidates: ["files.get", ...POST_CONTENT]
|
|
519
|
+
},
|
|
520
|
+
{
|
|
521
|
+
operationId: "verification.submit",
|
|
522
|
+
invalidates: ["verification.status"],
|
|
523
|
+
scope: "account"
|
|
524
|
+
},
|
|
525
|
+
{
|
|
526
|
+
operationId: "subscription.pay",
|
|
527
|
+
invalidates: SUBSCRIPTION,
|
|
528
|
+
scope: "account"
|
|
529
|
+
},
|
|
530
|
+
{
|
|
531
|
+
operationId: "subscription.setAutoRenewal",
|
|
532
|
+
invalidates: SUBSCRIPTION,
|
|
533
|
+
scope: "account"
|
|
534
|
+
},
|
|
535
|
+
{
|
|
536
|
+
operationId: "subscription.bindCard",
|
|
537
|
+
invalidates: SUBSCRIPTION,
|
|
538
|
+
scope: "account"
|
|
539
|
+
},
|
|
540
|
+
{
|
|
541
|
+
operationId: "subscription.setDefaultMethod",
|
|
542
|
+
invalidates: SUBSCRIPTION,
|
|
543
|
+
scope: "account"
|
|
544
|
+
},
|
|
545
|
+
{
|
|
546
|
+
operationId: "subscription.removeMethod",
|
|
547
|
+
invalidates: SUBSCRIPTION,
|
|
548
|
+
scope: "account"
|
|
549
|
+
},
|
|
550
|
+
{
|
|
551
|
+
operationId: "reports.create",
|
|
552
|
+
invalidates: NOTHING
|
|
553
|
+
},
|
|
554
|
+
{
|
|
555
|
+
operationId: "telemetry.dwell",
|
|
556
|
+
invalidates: NOTHING
|
|
557
|
+
},
|
|
558
|
+
{
|
|
559
|
+
operationId: "telemetry.interaction",
|
|
560
|
+
invalidates: NOTHING
|
|
561
|
+
}
|
|
433
562
|
]);
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
563
|
+
for (const mutation of CACHE_MUTATIONS) {
|
|
564
|
+
Object.freeze(mutation.invalidates);
|
|
565
|
+
Object.freeze(mutation);
|
|
437
566
|
}
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
567
|
+
const MUTATIONS = new Map(CACHE_MUTATIONS.map((mutation) => [mutation.operationId, mutation]));
|
|
568
|
+
/** Находит известную мутацию по стабильному семантическому ID. */
|
|
569
|
+
function cacheMutation(operationId) {
|
|
570
|
+
return MUTATIONS.get(operationId);
|
|
441
571
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
572
|
+
//#endregion
|
|
573
|
+
//#region src/plugin.ts
|
|
574
|
+
/** Режимы кэширования отдельного запроса. */
|
|
575
|
+
const CacheModes = Object.freeze({
|
|
576
|
+
/** Отдать свежий кэш, иначе выполнить запрос и сохранить ответ. */
|
|
577
|
+
Default: "default",
|
|
578
|
+
/** Пропустить сохранённое значение, выполнить запрос и перезаписать кэш. */
|
|
579
|
+
Reload: "reload",
|
|
580
|
+
/** Не читать и не писать кэш для этого запроса. */
|
|
581
|
+
NoStore: "no-store"
|
|
451
582
|
});
|
|
452
|
-
|
|
453
|
-
|
|
583
|
+
const DEFAULT_MAX_ENTRIES = 500;
|
|
584
|
+
const CACHE_MODES = new Set(Object.values(CacheModes));
|
|
454
585
|
function assertPositive(value, name, integer = false) {
|
|
455
|
-
|
|
456
|
-
throw new CacheError(
|
|
457
|
-
`${name} \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C ${integer ? "\u0446\u0435\u043B\u044B\u043C " : ""}\u043F\u043E\u043B\u043E\u0436\u0438\u0442\u0435\u043B\u044C\u043D\u044B\u043C \u0447\u0438\u0441\u043B\u043E\u043C, \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u043E: ${value}`
|
|
458
|
-
);
|
|
459
|
-
}
|
|
586
|
+
if (!Number.isFinite(value) || value <= 0 || integer && !Number.isInteger(value)) throw new CacheError(`${name} должен быть ${integer ? "целым " : ""}положительным числом, получено: ${value}`);
|
|
460
587
|
}
|
|
461
588
|
function resolveOptions(options) {
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
throw new CacheError(`cache.deduplicate \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C boolean, \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u043E: ${deduplicate}`);
|
|
481
|
-
}
|
|
482
|
-
return { ttl: options.ttl, routes, maxEntries, deduplicate };
|
|
589
|
+
if (!options || typeof options !== "object") throw new CacheError("cache() принимает объект настроек");
|
|
590
|
+
assertPositive(options.ttl, "cache.ttl");
|
|
591
|
+
if (!Array.isArray(options.operations) || options.operations.length === 0) throw new CacheError("cache.operations должен содержать хотя бы одну операцию");
|
|
592
|
+
const operations = /* @__PURE__ */ new Set();
|
|
593
|
+
for (const operation of options.operations) {
|
|
594
|
+
if (typeof operation !== "string" || !isCacheOperationId(operation)) throw new CacheError(`Неизвестная операция кэша: ${JSON.stringify(operation)}`);
|
|
595
|
+
operations.add(operation);
|
|
596
|
+
}
|
|
597
|
+
const maxEntries = options.maxEntries ?? DEFAULT_MAX_ENTRIES;
|
|
598
|
+
assertPositive(maxEntries, "cache.maxEntries", true);
|
|
599
|
+
const deduplicate = options.deduplicate ?? true;
|
|
600
|
+
if (typeof deduplicate !== "boolean") throw new CacheError(`cache.deduplicate должен быть boolean, получено: ${deduplicate}`);
|
|
601
|
+
return {
|
|
602
|
+
ttl: options.ttl,
|
|
603
|
+
operations,
|
|
604
|
+
maxEntries,
|
|
605
|
+
deduplicate
|
|
606
|
+
};
|
|
483
607
|
}
|
|
484
608
|
function cloneValue(value) {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
609
|
+
try {
|
|
610
|
+
return {
|
|
611
|
+
cacheable: true,
|
|
612
|
+
value: structuredClone(value)
|
|
613
|
+
};
|
|
614
|
+
} catch {
|
|
615
|
+
return {
|
|
616
|
+
cacheable: false,
|
|
617
|
+
value
|
|
618
|
+
};
|
|
619
|
+
}
|
|
490
620
|
}
|
|
491
621
|
function cacheMode(request) {
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
`cache \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C '${CacheModes.Default}', '${CacheModes.Reload}' \u0438\u043B\u0438 '${CacheModes.NoStore}', \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u043E: ${String(mode)}`
|
|
496
|
-
);
|
|
497
|
-
}
|
|
498
|
-
return mode;
|
|
622
|
+
const mode = request.extensions?.cache ?? CacheModes.Default;
|
|
623
|
+
if (!CACHE_MODES.has(mode)) throw new CacheError(`cache должен быть '${CacheModes.Default}', '${CacheModes.Reload}' или '${CacheModes.NoStore}', получено: ${String(mode)}`);
|
|
624
|
+
return mode;
|
|
499
625
|
}
|
|
626
|
+
/** Создаёт TTL/LRU-кэш разобранных ответов itd-api. */
|
|
500
627
|
function cache(options) {
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
clear,
|
|
686
|
-
invalidate,
|
|
687
|
-
attachRealtime(stream) {
|
|
688
|
-
if (!stream || typeof stream.on !== "function") {
|
|
689
|
-
throw new CacheError("attachRealtime() \u043F\u0440\u0438\u043D\u0438\u043C\u0430\u0435\u0442 \u043F\u043E\u0442\u043E\u043A \u0438\u0437 itd.realtime()");
|
|
690
|
-
}
|
|
691
|
-
const invalidateStream = (...routes) => {
|
|
692
|
-
const identity = typeof stream.getAuthIdentity === "function" ? stream.getAuthIdentity() : void 0;
|
|
693
|
-
const streamBaseUrl = typeof stream.baseUrl === "string" && stream.baseUrl.length > 0 ? stream.baseUrl : void 0;
|
|
694
|
-
const legacyScope = typeof stream.getAuthScope === "function" ? stream.getAuthScope() : void 0;
|
|
695
|
-
const accountScope = identity?.userId && streamBaseUrl ? JSON.stringify([streamBaseUrl, identity.userId]) : legacyScope !== void 0 && streamBaseUrl ? JSON.stringify([streamBaseUrl, legacyScope]) : void 0;
|
|
696
|
-
if (accountScope === void 0) invalidate(...routes);
|
|
697
|
-
else invalidateScope(accountScope, routes);
|
|
698
|
-
};
|
|
699
|
-
invalidateStream("notifications.list", "notifications.count");
|
|
700
|
-
const offNotification = stream.on(
|
|
701
|
-
"notification",
|
|
702
|
-
() => invalidateStream("notifications.list", "notifications.count")
|
|
703
|
-
);
|
|
704
|
-
const offUnreadCount = stream.on(
|
|
705
|
-
"unreadCount",
|
|
706
|
-
() => invalidateStream("notifications.count")
|
|
707
|
-
);
|
|
708
|
-
return () => {
|
|
709
|
-
offNotification();
|
|
710
|
-
offUnreadCount();
|
|
711
|
-
};
|
|
712
|
-
},
|
|
713
|
-
install({ use, baseUrl, getAuthIdentity, getAuthScope }) {
|
|
714
|
-
installationSequence += 1;
|
|
715
|
-
use(createTransformer(installationSequence, baseUrl, getAuthIdentity, getAuthScope));
|
|
716
|
-
}
|
|
717
|
-
};
|
|
628
|
+
const config = resolveOptions(options);
|
|
629
|
+
const values = new lru_cache.LRUCache({
|
|
630
|
+
max: config.maxEntries,
|
|
631
|
+
ttl: config.ttl,
|
|
632
|
+
updateAgeOnGet: false,
|
|
633
|
+
allowStale: false
|
|
634
|
+
});
|
|
635
|
+
const pending = /* @__PURE__ */ new Map();
|
|
636
|
+
const operationGenerations = /* @__PURE__ */ new Map();
|
|
637
|
+
const scopeGenerations = /* @__PURE__ */ new Map();
|
|
638
|
+
const scopeOperationGenerations = /* @__PURE__ */ new Map();
|
|
639
|
+
const keyStates = /* @__PURE__ */ new Map();
|
|
640
|
+
let generation = 0;
|
|
641
|
+
let installationSequence = 0;
|
|
642
|
+
const scopeOperationKey = (accountScope, operation) => JSON.stringify([accountScope, operation]);
|
|
643
|
+
const clear = () => {
|
|
644
|
+
generation += 1;
|
|
645
|
+
values.clear();
|
|
646
|
+
pending.clear();
|
|
647
|
+
};
|
|
648
|
+
const invalidate = (...operations) => {
|
|
649
|
+
if (operations.length === 0) return;
|
|
650
|
+
const selected = /* @__PURE__ */ new Set();
|
|
651
|
+
for (const operation of operations) {
|
|
652
|
+
if (!isCacheOperationId(operation)) throw new CacheError(`Неизвестная операция кэша: ${JSON.stringify(operation)}`);
|
|
653
|
+
selected.add(operation);
|
|
654
|
+
operationGenerations.set(operation, (operationGenerations.get(operation) ?? 0) + 1);
|
|
655
|
+
}
|
|
656
|
+
for (const [key, entry] of values.entries()) if (selected.has(entry.operation)) values.delete(key);
|
|
657
|
+
for (const [key, entry] of pending) if (selected.has(entry.operation)) pending.delete(key);
|
|
658
|
+
};
|
|
659
|
+
const clearScope = (accountScope) => {
|
|
660
|
+
scopeGenerations.set(accountScope, (scopeGenerations.get(accountScope) ?? 0) + 1);
|
|
661
|
+
for (const [key, entry] of values.entries()) if (entry.accountScope === accountScope) values.delete(key);
|
|
662
|
+
for (const [key, entry] of pending) if (entry.accountScope === accountScope) pending.delete(key);
|
|
663
|
+
};
|
|
664
|
+
const invalidateScope = (accountScope, operations) => {
|
|
665
|
+
if (operations.length === 0) return;
|
|
666
|
+
const selected = new Set(operations);
|
|
667
|
+
for (const operation of selected) {
|
|
668
|
+
const key = scopeOperationKey(accountScope, operation);
|
|
669
|
+
scopeOperationGenerations.set(key, (scopeOperationGenerations.get(key) ?? 0) + 1);
|
|
670
|
+
}
|
|
671
|
+
for (const [key, entry] of values.entries()) if (entry.accountScope === accountScope && selected.has(entry.operation)) values.delete(key);
|
|
672
|
+
for (const [key, entry] of pending) if (entry.accountScope === accountScope && selected.has(entry.operation)) pending.delete(key);
|
|
673
|
+
};
|
|
674
|
+
const applyMutation = (accountScope, mutation) => {
|
|
675
|
+
if (mutation.invalidates === "all") clearScope(accountScope);
|
|
676
|
+
else if (mutation.scope === "account") invalidateScope(accountScope, mutation.invalidates);
|
|
677
|
+
else invalidate(...mutation.invalidates);
|
|
678
|
+
};
|
|
679
|
+
const createTransformer = (installation, baseUrl, getAuthIdentity, getAuthScope) => {
|
|
680
|
+
const fallbackAuthScope = JSON.stringify([baseUrl, `installation:${installation}`]);
|
|
681
|
+
const resolveIdentity = async () => {
|
|
682
|
+
const identity = await getAuthIdentity?.();
|
|
683
|
+
const accountScope = identity?.userId ? JSON.stringify([baseUrl, identity.userId]) : getAuthScope ? JSON.stringify([baseUrl, getAuthScope()]) : fallbackAuthScope;
|
|
684
|
+
return {
|
|
685
|
+
accountScope,
|
|
686
|
+
sessionScope: identity?.userId && identity.sessionId ? JSON.stringify([
|
|
687
|
+
baseUrl,
|
|
688
|
+
identity.userId,
|
|
689
|
+
identity.sessionId
|
|
690
|
+
]) : JSON.stringify([accountScope, getAuthScope ? getAuthScope() : `installation:${installation}`])
|
|
691
|
+
};
|
|
692
|
+
};
|
|
693
|
+
return async (request, next) => {
|
|
694
|
+
const operation = cacheOperation(request.operationId);
|
|
695
|
+
const method = request.method.toUpperCase();
|
|
696
|
+
if (!(operation !== void 0 || method === "GET" || method === "HEAD")) {
|
|
697
|
+
const mutation = cacheMutation(request.operationId);
|
|
698
|
+
const startedIdentity = mutation ? await resolveIdentity() : void 0;
|
|
699
|
+
const result = await next(request);
|
|
700
|
+
if (mutation && startedIdentity) {
|
|
701
|
+
applyMutation(startedIdentity.accountScope, mutation);
|
|
702
|
+
const currentIdentity = await resolveIdentity();
|
|
703
|
+
if (currentIdentity.accountScope !== startedIdentity.accountScope && (mutation.invalidates === "all" || mutation.scope === "account")) applyMutation(currentIdentity.accountScope, mutation);
|
|
704
|
+
} else clear();
|
|
705
|
+
return result;
|
|
706
|
+
}
|
|
707
|
+
if (!operation || !config.operations.has(operation.id)) return next(request);
|
|
708
|
+
const mode = cacheMode(request);
|
|
709
|
+
if (mode === CacheModes.NoStore) return next(request);
|
|
710
|
+
const unscopedKey = buildCacheKey(operation.id, request);
|
|
711
|
+
if (unscopedKey === void 0) return next(request);
|
|
712
|
+
const identity = await resolveIdentity();
|
|
713
|
+
const scope = operation.id === "auth.sessions" ? identity.sessionScope : identity.accountScope;
|
|
714
|
+
const key = JSON.stringify([scope, unscopedKey]);
|
|
715
|
+
if (mode === CacheModes.Reload) {
|
|
716
|
+
const state = keyStates.get(key) ?? {
|
|
717
|
+
active: 0,
|
|
718
|
+
generation: 0
|
|
719
|
+
};
|
|
720
|
+
state.generation += 1;
|
|
721
|
+
keyStates.set(key, state);
|
|
722
|
+
values.delete(key);
|
|
723
|
+
pending.delete(key);
|
|
724
|
+
}
|
|
725
|
+
if (mode === CacheModes.Default) {
|
|
726
|
+
const hit = values.get(key);
|
|
727
|
+
if (hit) {
|
|
728
|
+
const cloned = cloneValue(hit.value);
|
|
729
|
+
if (cloned.cacheable) return cloned.value;
|
|
730
|
+
values.delete(key);
|
|
731
|
+
}
|
|
732
|
+
const existing = pending.get(key);
|
|
733
|
+
if (config.deduplicate && request.signal === void 0 && request.timeout === void 0 && existing) return cloneValue((await existing.promise).value).value;
|
|
734
|
+
}
|
|
735
|
+
const startedGeneration = generation;
|
|
736
|
+
const startedScopeGeneration = scopeGenerations.get(identity.accountScope) ?? 0;
|
|
737
|
+
const startedOperationGeneration = operationGenerations.get(operation.id) ?? 0;
|
|
738
|
+
const scopedOperationKey = scopeOperationKey(identity.accountScope, operation.id);
|
|
739
|
+
const startedScopeOperationGeneration = scopeOperationGenerations.get(scopedOperationKey) ?? 0;
|
|
740
|
+
const keyState = keyStates.get(key) ?? {
|
|
741
|
+
active: 0,
|
|
742
|
+
generation: 0
|
|
743
|
+
};
|
|
744
|
+
keyState.active += 1;
|
|
745
|
+
keyStates.set(key, keyState);
|
|
746
|
+
const startedKeyGeneration = keyState.generation;
|
|
747
|
+
const load = (async () => {
|
|
748
|
+
try {
|
|
749
|
+
const result = await next(request);
|
|
750
|
+
const stored = cloneValue(result);
|
|
751
|
+
const currentIdentity = await resolveIdentity();
|
|
752
|
+
const currentScope = operation.id === "auth.sessions" ? currentIdentity.sessionScope : currentIdentity.accountScope;
|
|
753
|
+
if (stored.cacheable && currentScope === scope && generation === startedGeneration && (scopeGenerations.get(identity.accountScope) ?? 0) === startedScopeGeneration && (operationGenerations.get(operation.id) ?? 0) === startedOperationGeneration && (scopeOperationGenerations.get(scopedOperationKey) ?? 0) === startedScopeOperationGeneration && keyState.generation === startedKeyGeneration) values.set(key, {
|
|
754
|
+
accountScope: identity.accountScope,
|
|
755
|
+
operation: operation.id,
|
|
756
|
+
value: stored.value
|
|
757
|
+
});
|
|
758
|
+
return {
|
|
759
|
+
cacheable: stored.cacheable,
|
|
760
|
+
value: result
|
|
761
|
+
};
|
|
762
|
+
} finally {
|
|
763
|
+
keyState.active -= 1;
|
|
764
|
+
if (keyState.active === 0 && keyStates.get(key) === keyState) keyStates.delete(key);
|
|
765
|
+
}
|
|
766
|
+
})();
|
|
767
|
+
const mayDeduplicate = mode === CacheModes.Default && config.deduplicate && request.signal === void 0 && request.timeout === void 0;
|
|
768
|
+
const entry = {
|
|
769
|
+
accountScope: identity.accountScope,
|
|
770
|
+
operation: operation.id,
|
|
771
|
+
promise: load
|
|
772
|
+
};
|
|
773
|
+
if (mayDeduplicate) pending.set(key, entry);
|
|
774
|
+
try {
|
|
775
|
+
return (await load).value;
|
|
776
|
+
} finally {
|
|
777
|
+
if (pending.get(key) === entry) pending.delete(key);
|
|
778
|
+
}
|
|
779
|
+
};
|
|
780
|
+
};
|
|
781
|
+
return {
|
|
782
|
+
name: "cache",
|
|
783
|
+
get size() {
|
|
784
|
+
values.purgeStale();
|
|
785
|
+
return values.size;
|
|
786
|
+
},
|
|
787
|
+
clear,
|
|
788
|
+
invalidate,
|
|
789
|
+
attachRealtime(stream) {
|
|
790
|
+
if (!stream || typeof stream.on !== "function") throw new CacheError("attachRealtime() принимает поток из itd.realtime()");
|
|
791
|
+
const invalidateStream = (...operations) => {
|
|
792
|
+
const identity = typeof stream.getAuthIdentity === "function" ? stream.getAuthIdentity() : void 0;
|
|
793
|
+
const streamBaseUrl = typeof stream.baseUrl === "string" && stream.baseUrl.length > 0 ? stream.baseUrl : void 0;
|
|
794
|
+
const legacyScope = typeof stream.getAuthScope === "function" ? stream.getAuthScope() : void 0;
|
|
795
|
+
const accountScope = identity?.userId && streamBaseUrl ? JSON.stringify([streamBaseUrl, identity.userId]) : legacyScope !== void 0 && streamBaseUrl ? JSON.stringify([streamBaseUrl, legacyScope]) : void 0;
|
|
796
|
+
if (accountScope === void 0) invalidate(...operations);
|
|
797
|
+
else invalidateScope(accountScope, operations);
|
|
798
|
+
};
|
|
799
|
+
invalidateStream("notifications.list", "notifications.count");
|
|
800
|
+
const offNotification = stream.on("notification", () => invalidateStream("notifications.list", "notifications.count"));
|
|
801
|
+
const offUnreadCount = stream.on("unreadCount", () => invalidateStream("notifications.count"));
|
|
802
|
+
return () => {
|
|
803
|
+
offNotification();
|
|
804
|
+
offUnreadCount();
|
|
805
|
+
};
|
|
806
|
+
},
|
|
807
|
+
install({ operations, baseUrl, getAuthIdentity, getAuthScope }) {
|
|
808
|
+
installationSequence += 1;
|
|
809
|
+
operations.use(createTransformer(installationSequence, baseUrl, getAuthIdentity, getAuthScope));
|
|
810
|
+
}
|
|
811
|
+
};
|
|
718
812
|
}
|
|
719
|
-
|
|
720
|
-
exports.
|
|
813
|
+
//#endregion
|
|
814
|
+
exports.CACHE_OPERATIONS = CACHE_OPERATIONS;
|
|
721
815
|
exports.CacheError = CacheError;
|
|
722
816
|
exports.CacheModes = CacheModes;
|
|
723
817
|
exports.buildCacheKey = buildCacheKey;
|
|
724
818
|
exports.cache = cache;
|
|
725
|
-
exports.
|
|
726
|
-
exports.
|
|
727
|
-
|
|
819
|
+
exports.cacheOperation = cacheOperation;
|
|
820
|
+
exports.isCacheOperationId = isCacheOperationId;
|
|
821
|
+
|
|
728
822
|
//# sourceMappingURL=index.cjs.map
|