@itd-api/cache 0.0.1 → 0.0.2

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/index.js CHANGED
@@ -172,7 +172,7 @@ var CACHE_MUTATIONS = Object.freeze([
172
172
  method: "DELETE",
173
173
  path: /^\/api\/v1\/auth\/sessions(?:\/[^/]+)?$/,
174
174
  invalidates: ["auth.sessions"],
175
- scope: "installation"
175
+ scope: "account"
176
176
  },
177
177
  // Посты и комментарии.
178
178
  { method: "POST", path: /^\/api\/posts$/, invalidates: POST_CONTENT },
@@ -214,13 +214,13 @@ var CACHE_MUTATIONS = Object.freeze([
214
214
  method: "POST",
215
215
  path: /^\/api\/notifications\/(?:[^/]+\/read|read-batch|read-all)$/,
216
216
  invalidates: NOTIFICATIONS,
217
- scope: "installation"
217
+ scope: "account"
218
218
  },
219
219
  {
220
220
  method: "PUT",
221
221
  path: /^\/api\/notifications\/settings$/,
222
222
  invalidates: ["notifications.getSettings"],
223
- scope: "installation"
223
+ scope: "account"
224
224
  },
225
225
  // Файлы и настройки аккаунта.
226
226
  { method: "POST", path: /^\/api\/files\/upload$/, invalidates: NOTHING },
@@ -233,37 +233,37 @@ var CACHE_MUTATIONS = Object.freeze([
233
233
  method: "POST",
234
234
  path: /^\/api\/verification\/submit$/,
235
235
  invalidates: ["verification.status"],
236
- scope: "installation"
236
+ scope: "account"
237
237
  },
238
238
  {
239
239
  method: "POST",
240
240
  path: /^\/api\/v1\/subscription\/pay$/,
241
241
  invalidates: SUBSCRIPTION,
242
- scope: "installation"
242
+ scope: "account"
243
243
  },
244
244
  {
245
245
  method: "POST",
246
246
  path: /^\/api\/v1\/subscription\/auto-renewal$/,
247
247
  invalidates: SUBSCRIPTION,
248
- scope: "installation"
248
+ scope: "account"
249
249
  },
250
250
  {
251
251
  method: "POST",
252
252
  path: /^\/api\/v1\/subscription\/bind-card$/,
253
253
  invalidates: SUBSCRIPTION,
254
- scope: "installation"
254
+ scope: "account"
255
255
  },
256
256
  {
257
257
  method: "POST",
258
258
  path: /^\/api\/v1\/subscription\/methods\/[^/]+\/default$/,
259
259
  invalidates: SUBSCRIPTION,
260
- scope: "installation"
260
+ scope: "account"
261
261
  },
262
262
  {
263
263
  method: "DELETE",
264
264
  path: /^\/api\/v1\/subscription\/methods\/[^/]+$/,
265
265
  invalidates: SUBSCRIPTION,
266
- scope: "installation"
266
+ scope: "account"
267
267
  },
268
268
  // Эти запросы не меняют ни один доступный для кэширования ответ.
269
269
  { method: "POST", path: /^\/api\/reports$/, invalidates: NOTHING },
@@ -439,8 +439,16 @@ function cacheRoute(method, path) {
439
439
  }
440
440
 
441
441
  // src/plugin.ts
442
+ var CacheModes = Object.freeze({
443
+ /** Отдать свежий кэш, иначе выполнить запрос и сохранить ответ. */
444
+ Default: "default",
445
+ /** Пропустить сохранённое значение, выполнить запрос и перезаписать кэш. */
446
+ Reload: "reload",
447
+ /** Не читать и не писать кэш для этого запроса. */
448
+ NoStore: "no-store"
449
+ });
442
450
  var DEFAULT_MAX_ENTRIES = 500;
443
- var CACHE_MODES = /* @__PURE__ */ new Set(["default", "reload", "no-store"]);
451
+ var CACHE_MODES = new Set(Object.values(CacheModes));
444
452
  function assertPositive(value, name, integer = false) {
445
453
  if (!Number.isFinite(value) || value <= 0 || integer && !Number.isInteger(value)) {
446
454
  throw new CacheError(
@@ -479,10 +487,10 @@ function cloneValue(value) {
479
487
  }
480
488
  }
481
489
  function cacheMode(request) {
482
- const mode = request.cache ?? "default";
490
+ const mode = request.cache ?? CacheModes.Default;
483
491
  if (!CACHE_MODES.has(mode)) {
484
492
  throw new CacheError(
485
- `cache \u0434\u043E\u043B\u0436\u0435\u043D \u0431\u044B\u0442\u044C 'default', 'reload' \u0438\u043B\u0438 'no-store', \u043F\u043E\u043B\u0443\u0447\u0435\u043D\u043E: ${String(mode)}`
493
+ `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)}`
486
494
  );
487
495
  }
488
496
  return mode;
@@ -497,12 +505,12 @@ function cache(options) {
497
505
  });
498
506
  const pending = /* @__PURE__ */ new Map();
499
507
  const routeGenerations = /* @__PURE__ */ new Map();
500
- const installationGenerations = /* @__PURE__ */ new Map();
501
- const installationRouteGenerations = /* @__PURE__ */ new Map();
508
+ const scopeGenerations = /* @__PURE__ */ new Map();
509
+ const scopeRouteGenerations = /* @__PURE__ */ new Map();
502
510
  const keyStates = /* @__PURE__ */ new Map();
503
511
  let generation = 0;
504
512
  let installationSequence = 0;
505
- const installationRouteKey = (installation, route) => `${installation}:${route}`;
513
+ const scopeRouteKey = (accountScope, route) => JSON.stringify([accountScope, route]);
506
514
  const clear = () => {
507
515
  generation += 1;
508
516
  values.clear();
@@ -525,47 +533,48 @@ function cache(options) {
525
533
  if (selected.has(entry.route)) pending.delete(key);
526
534
  }
527
535
  };
528
- const clearInstallation = (installation) => {
529
- installationGenerations.set(installation, (installationGenerations.get(installation) ?? 0) + 1);
536
+ const clearScope = (accountScope) => {
537
+ scopeGenerations.set(accountScope, (scopeGenerations.get(accountScope) ?? 0) + 1);
530
538
  for (const [key, entry] of values.entries()) {
531
- if (entry.installation === installation) values.delete(key);
539
+ if (entry.accountScope === accountScope) values.delete(key);
532
540
  }
533
541
  for (const [key, entry] of pending) {
534
- if (entry.installation === installation) pending.delete(key);
542
+ if (entry.accountScope === accountScope) pending.delete(key);
535
543
  }
536
544
  };
537
- const invalidateInstallation = (installation, routes) => {
545
+ const invalidateScope = (accountScope, routes) => {
538
546
  if (routes.length === 0) return;
539
547
  const selected = new Set(routes);
540
548
  for (const route of selected) {
541
- const key = installationRouteKey(installation, route);
542
- installationRouteGenerations.set(key, (installationRouteGenerations.get(key) ?? 0) + 1);
549
+ const key = scopeRouteKey(accountScope, route);
550
+ scopeRouteGenerations.set(key, (scopeRouteGenerations.get(key) ?? 0) + 1);
543
551
  }
544
552
  for (const [key, entry] of values.entries()) {
545
- if (entry.installation === installation && selected.has(entry.route)) values.delete(key);
553
+ if (entry.accountScope === accountScope && selected.has(entry.route)) values.delete(key);
546
554
  }
547
555
  for (const [key, entry] of pending) {
548
- if (entry.installation === installation && selected.has(entry.route)) pending.delete(key);
556
+ if (entry.accountScope === accountScope && selected.has(entry.route)) pending.delete(key);
549
557
  }
550
558
  };
551
- const applyMutation = (installation, mutation) => {
559
+ const applyMutation = (accountScope, mutation) => {
552
560
  if (mutation.invalidates === "all") {
553
- clearInstallation(installation);
554
- } else if (mutation.scope === "installation") {
555
- invalidateInstallation(installation, mutation.invalidates);
561
+ clearScope(accountScope);
562
+ } else if (mutation.scope === "account") {
563
+ invalidateScope(accountScope, mutation.invalidates);
556
564
  } else {
557
565
  invalidate(...mutation.invalidates);
558
566
  }
559
567
  };
560
- const createTransformer = (installation, getAuthScope) => {
561
- let observedAuthScope;
562
- const resolveScope = () => {
563
- const authScope = getAuthScope ? getAuthScope() : "default";
564
- if (observedAuthScope !== void 0 && observedAuthScope !== authScope) {
565
- clearInstallation(installation);
566
- }
567
- observedAuthScope = authScope;
568
- return JSON.stringify([installation, authScope]);
568
+ const createTransformer = (installation, baseUrl, getAuthIdentity, getAuthScope) => {
569
+ const fallbackAuthScope = JSON.stringify([baseUrl, `installation:${installation}`]);
570
+ const resolveIdentity = async () => {
571
+ const identity = await getAuthIdentity?.();
572
+ const accountScope = identity?.userId ? JSON.stringify([baseUrl, identity.userId]) : getAuthScope ? JSON.stringify([baseUrl, getAuthScope()]) : fallbackAuthScope;
573
+ const sessionScope = identity?.userId && identity.sessionId ? JSON.stringify([baseUrl, identity.userId, identity.sessionId]) : JSON.stringify([
574
+ accountScope,
575
+ getAuthScope ? getAuthScope() : `installation:${installation}`
576
+ ]);
577
+ return { accountScope, sessionScope };
569
578
  };
570
579
  return async (rawRequest, next) => {
571
580
  const request = rawRequest;
@@ -573,27 +582,39 @@ function cache(options) {
573
582
  const method = request.method.toUpperCase();
574
583
  const isRead = route !== void 0 || method === "GET" || method === "HEAD";
575
584
  if (!isRead) {
576
- const result = await next(request);
577
585
  const mutation = cacheMutation(method, request.path);
578
- if (mutation) applyMutation(installation, mutation);
579
- else clear();
586
+ const startedIdentity = mutation ? await resolveIdentity() : void 0;
587
+ const result = await next(request);
588
+ if (mutation && startedIdentity) {
589
+ applyMutation(startedIdentity.accountScope, mutation);
590
+ const currentIdentity = await resolveIdentity();
591
+ if (currentIdentity.accountScope !== startedIdentity.accountScope && (mutation.invalidates === "all" || mutation.scope === "account")) {
592
+ applyMutation(currentIdentity.accountScope, mutation);
593
+ }
594
+ } else {
595
+ clear();
596
+ }
580
597
  return result;
581
598
  }
582
599
  if (!route || !config.routes.has(route.id)) return next(request);
583
600
  const mode = cacheMode(request);
584
- if (mode === "no-store") return next(request);
601
+ if (mode === CacheModes.NoStore) return next(request);
585
602
  const unscopedKey = buildCacheKey(route.id, request);
586
603
  if (unscopedKey === void 0) return next(request);
587
- const scope = resolveScope();
604
+ const identity = await resolveIdentity();
605
+ const scope = route.id === "auth.sessions" ? identity.sessionScope : identity.accountScope;
588
606
  const key = JSON.stringify([scope, unscopedKey]);
589
- if (mode === "reload") {
590
- const state = keyStates.get(key) ?? { active: 0, generation: 0 };
607
+ if (mode === CacheModes.Reload) {
608
+ const state = keyStates.get(key) ?? {
609
+ active: 0,
610
+ generation: 0
611
+ };
591
612
  state.generation += 1;
592
613
  keyStates.set(key, state);
593
614
  values.delete(key);
594
615
  pending.delete(key);
595
616
  }
596
- if (mode === "default") {
617
+ if (mode === CacheModes.Default) {
597
618
  const hit = values.get(key);
598
619
  if (hit) {
599
620
  const cloned = cloneValue(hit.value);
@@ -607,11 +628,14 @@ function cache(options) {
607
628
  }
608
629
  }
609
630
  const startedGeneration = generation;
610
- const startedInstallationGeneration = installationGenerations.get(installation) ?? 0;
631
+ const startedScopeGeneration = scopeGenerations.get(identity.accountScope) ?? 0;
611
632
  const startedRouteGeneration = routeGenerations.get(route.id) ?? 0;
612
- const scopedRouteKey = installationRouteKey(installation, route.id);
613
- const startedInstallationRouteGeneration = installationRouteGenerations.get(scopedRouteKey) ?? 0;
614
- const keyState = keyStates.get(key) ?? { active: 0, generation: 0 };
633
+ const scopedRouteKey = scopeRouteKey(identity.accountScope, route.id);
634
+ const startedScopeRouteGeneration = scopeRouteGenerations.get(scopedRouteKey) ?? 0;
635
+ const keyState = keyStates.get(key) ?? {
636
+ active: 0,
637
+ generation: 0
638
+ };
615
639
  keyState.active += 1;
616
640
  keyStates.set(key, keyState);
617
641
  const startedKeyGeneration = keyState.generation;
@@ -619,9 +643,14 @@ function cache(options) {
619
643
  try {
620
644
  const result = await next(request);
621
645
  const stored = cloneValue(result);
622
- const currentScope = resolveScope();
623
- if (stored.cacheable && currentScope === scope && generation === startedGeneration && (installationGenerations.get(installation) ?? 0) === startedInstallationGeneration && (routeGenerations.get(route.id) ?? 0) === startedRouteGeneration && (installationRouteGenerations.get(scopedRouteKey) ?? 0) === startedInstallationRouteGeneration && keyState.generation === startedKeyGeneration) {
624
- values.set(key, { installation, route: route.id, value: stored.value });
646
+ const currentIdentity = await resolveIdentity();
647
+ const currentScope = route.id === "auth.sessions" ? currentIdentity.sessionScope : currentIdentity.accountScope;
648
+ if (stored.cacheable && currentScope === scope && generation === startedGeneration && (scopeGenerations.get(identity.accountScope) ?? 0) === startedScopeGeneration && (routeGenerations.get(route.id) ?? 0) === startedRouteGeneration && (scopeRouteGenerations.get(scopedRouteKey) ?? 0) === startedScopeRouteGeneration && keyState.generation === startedKeyGeneration) {
649
+ values.set(key, {
650
+ accountScope: identity.accountScope,
651
+ route: route.id,
652
+ value: stored.value
653
+ });
625
654
  }
626
655
  return { cacheable: stored.cacheable, value: result };
627
656
  } finally {
@@ -629,8 +658,12 @@ function cache(options) {
629
658
  if (keyState.active === 0 && keyStates.get(key) === keyState) keyStates.delete(key);
630
659
  }
631
660
  })();
632
- const mayDeduplicate = mode === "default" && config.deduplicate && request.signal === void 0 && request.timeout === void 0;
633
- const entry = { installation, route: route.id, promise: load };
661
+ const mayDeduplicate = mode === CacheModes.Default && config.deduplicate && request.signal === void 0 && request.timeout === void 0;
662
+ const entry = {
663
+ accountScope: identity.accountScope,
664
+ route: route.id,
665
+ promise: load
666
+ };
634
667
  if (mayDeduplicate) pending.set(key, entry);
635
668
  try {
636
669
  const loaded = await load;
@@ -653,24 +686,35 @@ function cache(options) {
653
686
  if (!stream || typeof stream.on !== "function") {
654
687
  throw new CacheError("attachRealtime() \u043F\u0440\u0438\u043D\u0438\u043C\u0430\u0435\u0442 \u043F\u043E\u0442\u043E\u043A \u0438\u0437 itd.realtime()");
655
688
  }
656
- invalidate("notifications.list", "notifications.count");
689
+ const invalidateStream = (...routes) => {
690
+ const identity = typeof stream.getAuthIdentity === "function" ? stream.getAuthIdentity() : void 0;
691
+ const streamBaseUrl = typeof stream.baseUrl === "string" && stream.baseUrl.length > 0 ? stream.baseUrl : void 0;
692
+ const legacyScope = typeof stream.getAuthScope === "function" ? stream.getAuthScope() : void 0;
693
+ const accountScope = identity?.userId && streamBaseUrl ? JSON.stringify([streamBaseUrl, identity.userId]) : legacyScope !== void 0 && streamBaseUrl ? JSON.stringify([streamBaseUrl, legacyScope]) : void 0;
694
+ if (accountScope === void 0) invalidate(...routes);
695
+ else invalidateScope(accountScope, routes);
696
+ };
697
+ invalidateStream("notifications.list", "notifications.count");
657
698
  const offNotification = stream.on(
658
699
  "notification",
659
- () => invalidate("notifications.list", "notifications.count")
700
+ () => invalidateStream("notifications.list", "notifications.count")
701
+ );
702
+ const offUnreadCount = stream.on(
703
+ "unreadCount",
704
+ () => invalidateStream("notifications.count")
660
705
  );
661
- const offUnreadCount = stream.on("unreadCount", () => invalidate("notifications.count"));
662
706
  return () => {
663
707
  offNotification();
664
708
  offUnreadCount();
665
709
  };
666
710
  },
667
- install({ use, getAuthScope }) {
711
+ install({ use, baseUrl, getAuthIdentity, getAuthScope }) {
668
712
  installationSequence += 1;
669
- use(createTransformer(installationSequence, getAuthScope));
713
+ use(createTransformer(installationSequence, baseUrl, getAuthIdentity, getAuthScope));
670
714
  }
671
715
  };
672
716
  }
673
717
 
674
- export { CACHE_ROUTES, CacheError, buildCacheKey, cache, cacheRoute, isCacheRouteId };
718
+ export { CACHE_ROUTES, CacheError, CacheModes, buildCacheKey, cache, cacheRoute, isCacheRouteId };
675
719
  //# sourceMappingURL=index.js.map
676
720
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/key.ts","../src/mutations.ts","../src/routes.ts","../src/plugin.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/** Ошибка настройки или использования плагина кэша. */\nexport class CacheError extends Error {\n override readonly name = 'CacheError';\n}\n","import type { RawRequestOptions } from 'itd-api';\nimport type { CacheRouteId } from './routes.js';\n\nconst OMITTED_FIELDS = new Set([\n 'method',\n 'path',\n 'service',\n 'baseUrl',\n 'query',\n 'body',\n 'headers',\n 'raw',\n 'skipAuth',\n 'signal',\n 'timeout',\n 'retry',\n 'skipQueue',\n 'skipAuthRefresh',\n 'cache',\n]);\n\n/** Строка query в том же порядке и с теми же правилами, что использует itd-api. */\nfunction queryKey(query: RawRequestOptions['query']): string {\n if (!query) return '';\n\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) continue;\n\n if (Array.isArray(value)) {\n for (const item of value) search.append(key, String(item));\n } else {\n search.append(key, String(value));\n }\n }\n\n return search.toString();\n}\n\n/**\n * Собирает ключ из значений, влияющих на адрес, тело или разобранный ответ.\n *\n * Заголовки и транспортные опции намеренно не входят. Если тело либо опция другого\n * плагина не сериализуются как JSON, запрос выполняется без кэша.\n */\nexport function buildCacheKey(route: CacheRouteId, request: RawRequestOptions): string | undefined {\n const extras: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(request)) {\n if (!OMITTED_FIELDS.has(key) && value !== undefined) extras[key] = value;\n }\n\n try {\n return JSON.stringify({\n route,\n method: request.method.toUpperCase(),\n service: request.service ?? null,\n baseUrl: request.baseUrl ?? null,\n path: request.path,\n query: queryKey(request.query),\n body: request.body ?? null,\n raw: request.raw ?? false,\n skipAuth: request.skipAuth ?? null,\n extras,\n });\n } catch {\n return undefined;\n }\n}\n","import type { CacheRouteId } from './routes.js';\n\nexport type MutationInvalidation = readonly CacheRouteId[] | 'all';\n\nexport interface CacheMutation {\n method: string;\n path: RegExp;\n invalidates: MutationInvalidation;\n /** По умолчанию зависимые маршруты удаляются у всех установок общего экземпляра. */\n scope?: 'installation' | undefined;\n}\n\nconst POST_CONTENT = [\n 'posts.list',\n 'posts.get',\n 'posts.byUser',\n 'posts.likedByUser',\n 'posts.comments',\n 'posts.stats',\n 'comments.replies',\n 'hashtags.search',\n 'hashtags.trending',\n 'hashtags.posts',\n 'search.all',\n 'users.me',\n 'users.get',\n 'users.pins',\n] as const satisfies readonly CacheRouteId[];\n\nconst POST_REACTIONS = [\n 'posts.list',\n 'posts.get',\n 'posts.byUser',\n 'posts.likedByUser',\n 'posts.stats',\n 'hashtags.posts',\n 'search.all',\n] as const satisfies readonly CacheRouteId[];\n\nconst COMMENTS = [\n 'posts.list',\n 'posts.get',\n 'posts.comments',\n 'posts.stats',\n 'comments.replies',\n 'hashtags.posts',\n 'search.all',\n] as const satisfies readonly CacheRouteId[];\n\nconst PROFILE = [\n 'users.me',\n 'users.get',\n 'users.checkUsername',\n 'users.search',\n 'users.whoToFollow',\n 'users.topClans',\n 'users.followers',\n 'users.following',\n 'users.blocked',\n 'users.getPrivacy',\n 'users.pins',\n 'users.followStatus',\n 'posts.list',\n 'posts.get',\n 'posts.byUser',\n 'posts.likedByUser',\n 'posts.comments',\n 'comments.replies',\n 'hashtags.posts',\n 'search.all',\n] as const satisfies readonly CacheRouteId[];\n\nconst FOLLOWING = [\n 'users.me',\n 'users.get',\n 'users.search',\n 'users.whoToFollow',\n 'users.followers',\n 'users.following',\n 'users.followStatus',\n 'posts.list',\n 'posts.byUser',\n 'search.all',\n] as const satisfies readonly CacheRouteId[];\n\nconst BLOCKS = [\n 'users.me',\n 'users.get',\n 'users.search',\n 'users.whoToFollow',\n 'users.followers',\n 'users.following',\n 'users.blocked',\n 'users.followStatus',\n 'posts.list',\n 'search.all',\n] as const satisfies readonly CacheRouteId[];\n\nconst PINS = [\n 'users.me',\n 'users.get',\n 'users.pins',\n 'posts.list',\n 'posts.get',\n 'posts.byUser',\n] as const satisfies readonly CacheRouteId[];\n\nconst NOTIFICATIONS = [\n 'notifications.list',\n 'notifications.count',\n] as const satisfies readonly CacheRouteId[];\n\nconst SUBSCRIPTION = [\n 'subscription.status',\n 'subscription.methods',\n] as const satisfies readonly CacheRouteId[];\n\nconst NOTHING = [] as const satisfies readonly CacheRouteId[];\n\n/**\n * Известные изменяющие запросы и читающие маршруты, чьи ответы они могут изменить.\n *\n * Каталог намеренно консервативен: лучше удалить несколько связанных списков, чем оставить\n * персонализированное поле или вложенный объект устаревшим.\n */\nconst CACHE_MUTATIONS = Object.freeze([\n // Авторизация и сессии.\n { method: 'POST', path: /^\\/api\\/v1\\/auth\\/refresh$/, invalidates: NOTHING },\n { method: 'POST', path: /^\\/api\\/v1\\/auth\\/resend-otp$/, invalidates: NOTHING },\n { method: 'POST', path: /^\\/api\\/v1\\/auth\\/forgot-password$/, invalidates: NOTHING },\n { method: 'POST', path: /^\\/api\\/v1\\/auth\\/sign-up$/, invalidates: 'all' },\n { method: 'POST', path: /^\\/api\\/v1\\/auth\\/sign-in$/, invalidates: 'all' },\n { method: 'POST', path: /^\\/api\\/v1\\/auth\\/verify-otp$/, invalidates: 'all' },\n { method: 'POST', path: /^\\/api\\/v1\\/auth\\/logout$/, invalidates: 'all' },\n { method: 'POST', path: /^\\/api\\/v1\\/auth\\/reset-password$/, invalidates: 'all' },\n { method: 'POST', path: /^\\/api\\/v1\\/auth\\/change-password$/, invalidates: 'all' },\n {\n method: 'DELETE',\n path: /^\\/api\\/v1\\/auth\\/sessions(?:\\/[^/]+)?$/,\n invalidates: ['auth.sessions'],\n scope: 'installation',\n },\n\n // Посты и комментарии.\n { method: 'POST', path: /^\\/api\\/posts$/, invalidates: POST_CONTENT },\n { method: 'PUT', path: /^\\/api\\/posts\\/[^/]+$/, invalidates: POST_CONTENT },\n { method: 'DELETE', path: /^\\/api\\/posts\\/[^/]+$/, invalidates: POST_CONTENT },\n { method: 'POST', path: /^\\/api\\/posts\\/[^/]+\\/restore$/, invalidates: POST_CONTENT },\n { method: 'POST', path: /^\\/api\\/posts\\/[^/]+\\/like$/, invalidates: POST_REACTIONS },\n { method: 'DELETE', path: /^\\/api\\/posts\\/[^/]+\\/like$/, invalidates: POST_REACTIONS },\n { method: 'POST', path: /^\\/api\\/posts\\/[^/]+\\/repost$/, invalidates: POST_CONTENT },\n { method: 'DELETE', path: /^\\/api\\/posts\\/[^/]+\\/repost$/, invalidates: POST_CONTENT },\n { method: 'POST', path: /^\\/api\\/posts\\/[^/]+\\/pin$/, invalidates: PINS },\n { method: 'DELETE', path: /^\\/api\\/posts\\/[^/]+\\/pin$/, invalidates: PINS },\n { method: 'POST', path: /^\\/api\\/posts\\/[^/]+\\/poll\\/vote$/, invalidates: POST_REACTIONS },\n { method: 'POST', path: /^\\/api\\/posts\\/[^/]+\\/comments$/, invalidates: COMMENTS },\n { method: 'POST', path: /^\\/api\\/comments\\/[^/]+\\/replies$/, invalidates: COMMENTS },\n { method: 'PATCH', path: /^\\/api\\/comments\\/[^/]+$/, invalidates: COMMENTS },\n { method: 'DELETE', path: /^\\/api\\/comments\\/[^/]+$/, invalidates: COMMENTS },\n { method: 'POST', path: /^\\/api\\/comments\\/[^/]+\\/restore$/, invalidates: COMMENTS },\n { method: 'POST', path: /^\\/api\\/comments\\/[^/]+\\/like$/, invalidates: COMMENTS },\n { method: 'DELETE', path: /^\\/api\\/comments\\/[^/]+\\/like$/, invalidates: COMMENTS },\n\n // Профиль и связи между пользователями.\n { method: 'PUT', path: /^\\/api\\/users\\/me$/, invalidates: PROFILE },\n { method: 'DELETE', path: /^\\/api\\/users\\/me$/, invalidates: PROFILE },\n { method: 'POST', path: /^\\/api\\/users\\/me\\/restore$/, invalidates: PROFILE },\n { method: 'POST', path: /^\\/api\\/users\\/profile$/, invalidates: PROFILE },\n { method: 'POST', path: /^\\/api\\/users\\/[^/]+\\/follow$/, invalidates: FOLLOWING },\n { method: 'DELETE', path: /^\\/api\\/users\\/[^/]+\\/follow$/, invalidates: FOLLOWING },\n { method: 'POST', path: /^\\/api\\/users\\/[^/]+\\/block$/, invalidates: BLOCKS },\n { method: 'DELETE', path: /^\\/api\\/users\\/[^/]+\\/block$/, invalidates: BLOCKS },\n {\n method: 'PUT',\n path: /^\\/api\\/users\\/me\\/privacy$/,\n invalidates: ['users.me', 'users.get', 'users.getPrivacy'],\n },\n { method: 'PUT', path: /^\\/api\\/users\\/me\\/pin$/, invalidates: PINS },\n { method: 'DELETE', path: /^\\/api\\/users\\/me\\/pin$/, invalidates: PINS },\n\n // Уведомления.\n {\n method: 'POST',\n path: /^\\/api\\/notifications\\/(?:[^/]+\\/read|read-batch|read-all)$/,\n invalidates: NOTIFICATIONS,\n scope: 'installation',\n },\n {\n method: 'PUT',\n path: /^\\/api\\/notifications\\/settings$/,\n invalidates: ['notifications.getSettings'],\n scope: 'installation',\n },\n\n // Файлы и настройки аккаунта.\n { method: 'POST', path: /^\\/api\\/files\\/upload$/, invalidates: NOTHING },\n {\n method: 'DELETE',\n path: /^\\/api\\/files\\/[^/]+$/,\n invalidates: ['files.get', ...POST_CONTENT],\n },\n {\n method: 'POST',\n path: /^\\/api\\/verification\\/submit$/,\n invalidates: ['verification.status'],\n scope: 'installation',\n },\n {\n method: 'POST',\n path: /^\\/api\\/v1\\/subscription\\/pay$/,\n invalidates: SUBSCRIPTION,\n scope: 'installation',\n },\n {\n method: 'POST',\n path: /^\\/api\\/v1\\/subscription\\/auto-renewal$/,\n invalidates: SUBSCRIPTION,\n scope: 'installation',\n },\n {\n method: 'POST',\n path: /^\\/api\\/v1\\/subscription\\/bind-card$/,\n invalidates: SUBSCRIPTION,\n scope: 'installation',\n },\n {\n method: 'POST',\n path: /^\\/api\\/v1\\/subscription\\/methods\\/[^/]+\\/default$/,\n invalidates: SUBSCRIPTION,\n scope: 'installation',\n },\n {\n method: 'DELETE',\n path: /^\\/api\\/v1\\/subscription\\/methods\\/[^/]+$/,\n invalidates: SUBSCRIPTION,\n scope: 'installation',\n },\n\n // Эти запросы не меняют ни один доступный для кэширования ответ.\n { method: 'POST', path: /^\\/api\\/reports$/, invalidates: NOTHING },\n { method: 'POST', path: /^\\/api\\/v1\\/[ix]$/, invalidates: NOTHING },\n] as const satisfies readonly CacheMutation[]);\n\n/** Находит известную мутацию по HTTP-методу и пути. */\nexport function cacheMutation(method: string, path: string): CacheMutation | undefined {\n const normalized = method.toUpperCase();\n return CACHE_MUTATIONS.find(\n (mutation) => mutation.method === normalized && mutation.path.test(path),\n );\n}\n","/** Описание читающего маршрута itd-api. */\nexport interface CacheRoute {\n /** Публичное имя для настройки плагина. */\n id: string;\n /** Раздел клиента. */\n category: string;\n /** HTTP-метод маршрута. */\n method: string;\n /** Путь без query и базового URL. */\n path: RegExp;\n}\n\n/**\n * Читающие маршруты, которые можно кэшировать.\n *\n * Порядок значим: точные служебные пути стоят перед динамическими маршрутами.\n */\nexport const CACHE_ROUTES = Object.freeze([\n { id: 'auth.sessions', category: 'auth', method: 'GET', path: /^\\/api\\/v1\\/auth\\/sessions$/ },\n\n { id: 'users.me', category: 'users', method: 'GET', path: /^\\/api\\/users\\/me$/ },\n {\n id: 'users.checkUsername',\n category: 'users',\n method: 'GET',\n path: /^\\/api\\/users\\/check-username$/,\n },\n { id: 'users.search', category: 'users', method: 'GET', path: /^\\/api\\/users\\/search$/ },\n {\n id: 'users.whoToFollow',\n category: 'users',\n method: 'GET',\n path: /^\\/api\\/users\\/suggestions\\/who-to-follow$/,\n },\n {\n id: 'users.topClans',\n category: 'users',\n method: 'GET',\n path: /^\\/api\\/users\\/stats\\/top-clans$/,\n },\n {\n id: 'users.followers',\n category: 'users',\n method: 'GET',\n path: /^\\/api\\/users\\/[^/]+\\/followers$/,\n },\n {\n id: 'users.following',\n category: 'users',\n method: 'GET',\n path: /^\\/api\\/users\\/[^/]+\\/following$/,\n },\n {\n id: 'users.blocked',\n category: 'users',\n method: 'GET',\n path: /^\\/api\\/users\\/me\\/blocked$/,\n },\n {\n id: 'users.getPrivacy',\n category: 'users',\n method: 'GET',\n path: /^\\/api\\/users\\/me\\/privacy$/,\n },\n { id: 'users.pins', category: 'users', method: 'GET', path: /^\\/api\\/users\\/me\\/pins$/ },\n {\n id: 'users.followStatus',\n category: 'users',\n method: 'POST',\n path: /^\\/api\\/users\\/follow-status$/,\n },\n { id: 'users.get', category: 'users', method: 'GET', path: /^\\/api\\/users\\/[^/]+$/ },\n\n { id: 'posts.list', category: 'posts', method: 'GET', path: /^\\/api\\/posts$/ },\n {\n id: 'posts.likedByUser',\n category: 'posts',\n method: 'GET',\n path: /^\\/api\\/posts\\/user\\/[^/]+\\/liked$/,\n },\n {\n id: 'posts.byUser',\n category: 'posts',\n method: 'GET',\n path: /^\\/api\\/posts\\/user\\/[^/]+$/,\n },\n {\n id: 'posts.comments',\n category: 'posts',\n method: 'GET',\n path: /^\\/api\\/posts\\/[^/]+\\/comments$/,\n },\n { id: 'posts.stats', category: 'posts', method: 'POST', path: /^\\/api\\/posts\\/stats$/ },\n { id: 'posts.get', category: 'posts', method: 'GET', path: /^\\/api\\/posts\\/[^/]+$/ },\n\n {\n id: 'comments.replies',\n category: 'comments',\n method: 'GET',\n path: /^\\/api\\/comments\\/[^/]+\\/replies$/,\n },\n\n {\n id: 'notifications.list',\n category: 'notifications',\n method: 'GET',\n path: /^\\/api\\/notifications\\/$/,\n },\n {\n id: 'notifications.count',\n category: 'notifications',\n method: 'GET',\n path: /^\\/api\\/notifications\\/count$/,\n },\n {\n id: 'notifications.getSettings',\n category: 'notifications',\n method: 'GET',\n path: /^\\/api\\/notifications\\/settings$/,\n },\n\n {\n id: 'hashtags.search',\n category: 'hashtags',\n method: 'GET',\n path: /^\\/api\\/hashtags$/,\n },\n {\n id: 'hashtags.trending',\n category: 'hashtags',\n method: 'GET',\n path: /^\\/api\\/hashtags\\/trending$/,\n },\n {\n id: 'hashtags.posts',\n category: 'hashtags',\n method: 'GET',\n path: /^\\/api\\/hashtags\\/[^/]+\\/posts$/,\n },\n\n { id: 'search.all', category: 'search', method: 'GET', path: /^\\/api\\/search$/ },\n { id: 'files.get', category: 'files', method: 'GET', path: /^\\/api\\/files\\/[^/]+$/ },\n\n {\n id: 'subscription.status',\n category: 'subscription',\n method: 'GET',\n path: /^\\/api\\/v1\\/subscription\\/$/,\n },\n {\n id: 'subscription.methods',\n category: 'subscription',\n method: 'GET',\n path: /^\\/api\\/v1\\/subscription\\/methods$/,\n },\n {\n id: 'verification.status',\n category: 'verification',\n method: 'GET',\n path: /^\\/api\\/verification\\/status$/,\n },\n\n {\n id: 'platform.changelog',\n category: 'platform',\n method: 'GET',\n path: /^\\/api\\/platform\\/changelog$/,\n },\n {\n id: 'platform.announcements',\n category: 'platform',\n method: 'GET',\n path: /^\\/api\\/platform\\/announcements$/,\n },\n { id: 'platform.portal', category: 'platform', method: 'GET', path: /^\\/api\\/v1\\/portal$/ },\n { id: 'platform.status', category: 'platform', method: 'GET', path: /^\\/api\\/status$/ },\n] as const satisfies readonly CacheRoute[]);\n\n/** Имя маршрута, доступное в `cache({ routes: … })`. */\nexport type CacheRouteId = (typeof CACHE_ROUTES)[number]['id'];\n\n/** Раздел маршрута. */\nexport type CacheRouteCategory = (typeof CACHE_ROUTES)[number]['category'];\n\nconst ROUTE_IDS: ReadonlySet<string> = new Set(CACHE_ROUTES.map((route) => route.id));\n\n/** Проверяет публичное имя маршрута. */\nexport function isCacheRouteId(value: string): value is CacheRouteId {\n return ROUTE_IDS.has(value);\n}\n\n/** Находит читающий маршрут по HTTP-методу и пути. */\nexport function cacheRoute(\n method: string,\n path: string,\n): (typeof CACHE_ROUTES)[number] | undefined {\n const normalized = method.toUpperCase();\n return CACHE_ROUTES.find((route) => route.method === normalized && route.path.test(path));\n}\n","import type { ItdPlugin, ItdRealtime, RawRequestOptions, Transformer, Unsubscribe } from 'itd-api';\nimport { LRUCache } from 'lru-cache';\nimport { CacheError } from './errors.js';\nimport { buildCacheKey } from './key.js';\nimport { type CacheMutation, cacheMutation } from './mutations.js';\nimport { type CacheRouteId, cacheRoute, isCacheRouteId } from './routes.js';\n\n/** Поведение кэша для отдельного запроса. */\nexport type CacheMode = 'default' | 'reload' | 'no-store';\n\n/** Настройки плагина. */\nexport interface CacheOptions {\n /** Сколько миллисекунд хранить успешный ответ. */\n ttl: number;\n /** Какие операции itd-api кэшировать. */\n routes: readonly CacheRouteId[];\n /** Максимальное количество ответов. По умолчанию 500. */\n maxEntries?: number | undefined;\n /** Объединять ли одновременные одинаковые запросы. По умолчанию `true`. */\n deduplicate?: boolean | undefined;\n}\n\n/** Плагин и управление созданным им хранилищем. */\nexport interface CachePlugin extends ItdPlugin {\n /** Количество готовых ответов во всех разделах кэша. */\n readonly size: number;\n /** Удаляет все ответы и не даёт выполняющимся запросам вернуть устаревший результат. */\n clear(): void;\n /** Удаляет все варианты названных маршрутов во всех подключённых клиентах. */\n invalidate(...routes: CacheRouteId[]): void;\n /**\n * Очищает список и счётчик уведомлений по событиям realtime.\n *\n * Сразу удаляет прежние значения и возвращает функцию отписки.\n */\n attachRealtime(stream: ItdRealtime): Unsubscribe;\n}\n\ninterface CacheEntry {\n installation: number;\n route: CacheRouteId;\n value: unknown;\n}\n\ninterface LoadedValue {\n cacheable: boolean;\n value: unknown;\n}\n\ninterface PendingEntry {\n installation: number;\n route: CacheRouteId;\n promise: Promise<LoadedValue>;\n}\n\ninterface KeyState {\n active: number;\n generation: number;\n}\n\ntype CacheRequest = RawRequestOptions & { cache?: CacheMode | undefined };\n\nconst DEFAULT_MAX_ENTRIES = 500;\nconst CACHE_MODES: ReadonlySet<string> = new Set(['default', 'reload', 'no-store']);\n\nfunction assertPositive(value: number, name: string, integer = false): void {\n if (!Number.isFinite(value) || value <= 0 || (integer && !Number.isInteger(value))) {\n throw new CacheError(\n `${name} должен быть ${integer ? 'целым ' : ''}положительным числом, получено: ${value}`,\n );\n }\n}\n\nfunction resolveOptions(options: CacheOptions): {\n ttl: number;\n routes: ReadonlySet<CacheRouteId>;\n maxEntries: number;\n deduplicate: boolean;\n} {\n if (!options || typeof options !== 'object') {\n throw new CacheError('cache() принимает объект настроек');\n }\n\n assertPositive(options.ttl, 'cache.ttl');\n\n if (!Array.isArray(options.routes) || options.routes.length === 0) {\n throw new CacheError('cache.routes должен содержать хотя бы один маршрут');\n }\n\n const routes = new Set<CacheRouteId>();\n for (const route of options.routes as readonly string[]) {\n if (typeof route !== 'string' || !isCacheRouteId(route)) {\n throw new CacheError(`Неизвестный маршрут кэша: ${JSON.stringify(route)}`);\n }\n routes.add(route);\n }\n\n const maxEntries = options.maxEntries ?? DEFAULT_MAX_ENTRIES;\n assertPositive(maxEntries, 'cache.maxEntries', true);\n\n const deduplicate = options.deduplicate ?? true;\n if (typeof deduplicate !== 'boolean') {\n throw new CacheError(`cache.deduplicate должен быть boolean, получено: ${deduplicate}`);\n }\n\n return { ttl: options.ttl, routes, maxEntries, deduplicate };\n}\n\nfunction cloneValue(value: unknown): LoadedValue {\n try {\n return { cacheable: true, value: structuredClone(value) };\n } catch {\n return { cacheable: false, value };\n }\n}\n\nfunction cacheMode(request: CacheRequest): CacheMode {\n const mode = request.cache ?? 'default';\n if (!CACHE_MODES.has(mode)) {\n throw new CacheError(\n `cache должен быть 'default', 'reload' или 'no-store', получено: ${String(mode)}`,\n );\n }\n return mode;\n}\n\n/** Создаёт TTL/LRU-кэш разобранных ответов itd-api. */\nexport function cache(options: CacheOptions): CachePlugin {\n const config = resolveOptions(options);\n const values = new LRUCache<string, CacheEntry>({\n max: config.maxEntries,\n ttl: config.ttl,\n updateAgeOnGet: false,\n allowStale: false,\n });\n const pending = new Map<string, PendingEntry>();\n const routeGenerations = new Map<CacheRouteId, number>();\n const installationGenerations = new Map<number, number>();\n const installationRouteGenerations = new Map<string, number>();\n const keyStates = new Map<string, KeyState>();\n let generation = 0;\n let installationSequence = 0;\n\n const installationRouteKey = (installation: number, route: CacheRouteId): string =>\n `${installation}:${route}`;\n\n const clear = (): void => {\n generation += 1;\n values.clear();\n pending.clear();\n };\n\n const invalidate = (...routes: CacheRouteId[]): void => {\n if (routes.length === 0) return;\n\n const selected = new Set<CacheRouteId>();\n for (const route of routes as readonly string[]) {\n if (!isCacheRouteId(route)) {\n throw new CacheError(`Неизвестный маршрут кэша: ${JSON.stringify(route)}`);\n }\n selected.add(route);\n routeGenerations.set(route, (routeGenerations.get(route) ?? 0) + 1);\n }\n\n for (const [key, entry] of values.entries()) {\n if (selected.has(entry.route)) values.delete(key);\n }\n for (const [key, entry] of pending) {\n if (selected.has(entry.route)) pending.delete(key);\n }\n };\n\n const clearInstallation = (installation: number): void => {\n installationGenerations.set(installation, (installationGenerations.get(installation) ?? 0) + 1);\n\n for (const [key, entry] of values.entries()) {\n if (entry.installation === installation) values.delete(key);\n }\n for (const [key, entry] of pending) {\n if (entry.installation === installation) pending.delete(key);\n }\n };\n\n const invalidateInstallation = (installation: number, routes: readonly CacheRouteId[]): void => {\n if (routes.length === 0) return;\n\n const selected = new Set(routes);\n for (const route of selected) {\n const key = installationRouteKey(installation, route);\n installationRouteGenerations.set(key, (installationRouteGenerations.get(key) ?? 0) + 1);\n }\n\n for (const [key, entry] of values.entries()) {\n if (entry.installation === installation && selected.has(entry.route)) values.delete(key);\n }\n for (const [key, entry] of pending) {\n if (entry.installation === installation && selected.has(entry.route)) pending.delete(key);\n }\n };\n\n const applyMutation = (installation: number, mutation: CacheMutation): void => {\n if (mutation.invalidates === 'all') {\n clearInstallation(installation);\n } else if (mutation.scope === 'installation') {\n invalidateInstallation(installation, mutation.invalidates);\n } else {\n invalidate(...mutation.invalidates);\n }\n };\n\n const createTransformer = (\n installation: number,\n getAuthScope: (() => string) | undefined,\n ): Transformer => {\n let observedAuthScope: string | undefined;\n\n const resolveScope = (): string => {\n const authScope = getAuthScope ? getAuthScope() : 'default';\n if (observedAuthScope !== undefined && observedAuthScope !== authScope) {\n clearInstallation(installation);\n }\n observedAuthScope = authScope;\n return JSON.stringify([installation, authScope]);\n };\n\n return async (rawRequest, next) => {\n const request = rawRequest as CacheRequest;\n const route = cacheRoute(request.method, request.path);\n const method = request.method.toUpperCase();\n const isRead = route !== undefined || method === 'GET' || method === 'HEAD';\n\n if (!isRead) {\n const result = await next(request);\n const mutation = cacheMutation(method, request.path);\n if (mutation) applyMutation(installation, mutation);\n else clear();\n return result;\n }\n\n if (!route || !config.routes.has(route.id)) return next(request);\n\n const mode = cacheMode(request);\n if (mode === 'no-store') return next(request);\n\n const unscopedKey = buildCacheKey(route.id, request);\n if (unscopedKey === undefined) return next(request);\n\n const scope = resolveScope();\n const key = JSON.stringify([scope, unscopedKey]);\n\n if (mode === 'reload') {\n // Прежняя загрузка только этого ключа не должна перезаписать принудительное обновление.\n const state = keyStates.get(key) ?? { active: 0, generation: 0 };\n state.generation += 1;\n keyStates.set(key, state);\n values.delete(key);\n pending.delete(key);\n }\n\n if (mode === 'default') {\n const hit = values.get(key);\n if (hit) {\n const cloned = cloneValue(hit.value);\n if (cloned.cacheable) return cloned.value;\n values.delete(key);\n }\n\n const existing = pending.get(key);\n if (\n config.deduplicate &&\n request.signal === undefined &&\n request.timeout === undefined &&\n existing\n ) {\n const loaded = await existing.promise;\n return cloneValue(loaded.value).value;\n }\n }\n\n const startedGeneration = generation;\n const startedInstallationGeneration = installationGenerations.get(installation) ?? 0;\n const startedRouteGeneration = routeGenerations.get(route.id) ?? 0;\n const scopedRouteKey = installationRouteKey(installation, route.id);\n const startedInstallationRouteGeneration =\n installationRouteGenerations.get(scopedRouteKey) ?? 0;\n const keyState = keyStates.get(key) ?? { active: 0, generation: 0 };\n keyState.active += 1;\n keyStates.set(key, keyState);\n const startedKeyGeneration = keyState.generation;\n const load = (async (): Promise<LoadedValue> => {\n try {\n const result = await next(request);\n const stored = cloneValue(result);\n const currentScope = resolveScope();\n\n if (\n stored.cacheable &&\n currentScope === scope &&\n generation === startedGeneration &&\n (installationGenerations.get(installation) ?? 0) === startedInstallationGeneration &&\n (routeGenerations.get(route.id) ?? 0) === startedRouteGeneration &&\n (installationRouteGenerations.get(scopedRouteKey) ?? 0) ===\n startedInstallationRouteGeneration &&\n keyState.generation === startedKeyGeneration\n ) {\n values.set(key, { installation, route: route.id, value: stored.value });\n }\n\n // Снимок уже отделён для кэша; инициатор получает независимый исходный ответ сети.\n return { cacheable: stored.cacheable, value: result };\n } finally {\n keyState.active -= 1;\n if (keyState.active === 0 && keyStates.get(key) === keyState) keyStates.delete(key);\n }\n })();\n\n const mayDeduplicate =\n mode === 'default' &&\n config.deduplicate &&\n request.signal === undefined &&\n request.timeout === undefined;\n const entry: PendingEntry = { installation, route: route.id, promise: load };\n if (mayDeduplicate) pending.set(key, entry);\n\n try {\n const loaded = await load;\n return loaded.value;\n } finally {\n if (pending.get(key) === entry) pending.delete(key);\n }\n };\n };\n\n return {\n name: 'cache',\n optionKeys: ['cache'],\n get size() {\n values.purgeStale();\n return values.size;\n },\n clear,\n invalidate,\n attachRealtime(stream) {\n if (!stream || typeof stream.on !== 'function') {\n throw new CacheError('attachRealtime() принимает поток из itd.realtime()');\n }\n\n invalidate('notifications.list', 'notifications.count');\n const offNotification = stream.on('notification', () =>\n invalidate('notifications.list', 'notifications.count'),\n );\n const offUnreadCount = stream.on('unreadCount', () => invalidate('notifications.count'));\n\n return () => {\n offNotification();\n offUnreadCount();\n };\n },\n install({ use, getAuthScope }) {\n installationSequence += 1;\n use(createTransformer(installationSequence, getAuthScope));\n },\n };\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/key.ts","../src/mutations.ts","../src/routes.ts","../src/plugin.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/** Ошибка настройки или использования плагина кэша. */\nexport class CacheError extends Error {\n override readonly name = 'CacheError';\n}\n","import type { RawRequestOptions } from 'itd-api';\nimport type { CacheRouteId } from './routes.js';\n\nconst OMITTED_FIELDS = new Set([\n 'method',\n 'path',\n 'service',\n 'baseUrl',\n 'query',\n 'body',\n 'headers',\n 'raw',\n 'skipAuth',\n 'signal',\n 'timeout',\n 'retry',\n 'skipQueue',\n 'skipAuthRefresh',\n 'cache',\n]);\n\n/** Строка query в том же порядке и с теми же правилами, что использует itd-api. */\nfunction queryKey(query: RawRequestOptions['query']): string {\n if (!query) return '';\n\n const search = new URLSearchParams();\n for (const [key, value] of Object.entries(query)) {\n if (value === undefined || value === null) continue;\n\n if (Array.isArray(value)) {\n for (const item of value) search.append(key, String(item));\n } else {\n search.append(key, String(value));\n }\n }\n\n return search.toString();\n}\n\n/**\n * Собирает ключ из значений, влияющих на адрес, тело или разобранный ответ.\n *\n * Заголовки и транспортные опции намеренно не входят. Если тело либо опция другого\n * плагина не сериализуются как JSON, запрос выполняется без кэша.\n */\nexport function buildCacheKey(route: CacheRouteId, request: RawRequestOptions): string | undefined {\n const extras: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(request)) {\n if (!OMITTED_FIELDS.has(key) && value !== undefined) extras[key] = value;\n }\n\n try {\n return JSON.stringify({\n route,\n method: request.method.toUpperCase(),\n service: request.service ?? null,\n baseUrl: request.baseUrl ?? null,\n path: request.path,\n query: queryKey(request.query),\n body: request.body ?? null,\n raw: request.raw ?? false,\n skipAuth: request.skipAuth ?? null,\n extras,\n });\n } catch {\n return undefined;\n }\n}\n","import type { CacheRouteId } from './routes.js';\n\nexport type MutationInvalidation = readonly CacheRouteId[] | 'all';\n\nexport interface CacheMutation {\n method: string;\n path: RegExp;\n invalidates: MutationInvalidation;\n /** По умолчанию зависимые маршруты удаляются у всех аккаунтов общего экземпляра. */\n scope?: 'account' | undefined;\n}\n\nconst POST_CONTENT = [\n 'posts.list',\n 'posts.get',\n 'posts.byUser',\n 'posts.likedByUser',\n 'posts.comments',\n 'posts.stats',\n 'comments.replies',\n 'hashtags.search',\n 'hashtags.trending',\n 'hashtags.posts',\n 'search.all',\n 'users.me',\n 'users.get',\n 'users.pins',\n] as const satisfies readonly CacheRouteId[];\n\nconst POST_REACTIONS = [\n 'posts.list',\n 'posts.get',\n 'posts.byUser',\n 'posts.likedByUser',\n 'posts.stats',\n 'hashtags.posts',\n 'search.all',\n] as const satisfies readonly CacheRouteId[];\n\nconst COMMENTS = [\n 'posts.list',\n 'posts.get',\n 'posts.comments',\n 'posts.stats',\n 'comments.replies',\n 'hashtags.posts',\n 'search.all',\n] as const satisfies readonly CacheRouteId[];\n\nconst PROFILE = [\n 'users.me',\n 'users.get',\n 'users.checkUsername',\n 'users.search',\n 'users.whoToFollow',\n 'users.topClans',\n 'users.followers',\n 'users.following',\n 'users.blocked',\n 'users.getPrivacy',\n 'users.pins',\n 'users.followStatus',\n 'posts.list',\n 'posts.get',\n 'posts.byUser',\n 'posts.likedByUser',\n 'posts.comments',\n 'comments.replies',\n 'hashtags.posts',\n 'search.all',\n] as const satisfies readonly CacheRouteId[];\n\nconst FOLLOWING = [\n 'users.me',\n 'users.get',\n 'users.search',\n 'users.whoToFollow',\n 'users.followers',\n 'users.following',\n 'users.followStatus',\n 'posts.list',\n 'posts.byUser',\n 'search.all',\n] as const satisfies readonly CacheRouteId[];\n\nconst BLOCKS = [\n 'users.me',\n 'users.get',\n 'users.search',\n 'users.whoToFollow',\n 'users.followers',\n 'users.following',\n 'users.blocked',\n 'users.followStatus',\n 'posts.list',\n 'search.all',\n] as const satisfies readonly CacheRouteId[];\n\nconst PINS = [\n 'users.me',\n 'users.get',\n 'users.pins',\n 'posts.list',\n 'posts.get',\n 'posts.byUser',\n] as const satisfies readonly CacheRouteId[];\n\nconst NOTIFICATIONS = [\n 'notifications.list',\n 'notifications.count',\n] as const satisfies readonly CacheRouteId[];\n\nconst SUBSCRIPTION = [\n 'subscription.status',\n 'subscription.methods',\n] as const satisfies readonly CacheRouteId[];\n\nconst NOTHING = [] as const satisfies readonly CacheRouteId[];\n\n/**\n * Известные изменяющие запросы и читающие маршруты, чьи ответы они могут изменить.\n *\n * Каталог намеренно консервативен: лучше удалить несколько связанных списков, чем оставить\n * персонализированное поле или вложенный объект устаревшим.\n */\nconst CACHE_MUTATIONS = Object.freeze([\n // Авторизация и сессии.\n { method: 'POST', path: /^\\/api\\/v1\\/auth\\/refresh$/, invalidates: NOTHING },\n { method: 'POST', path: /^\\/api\\/v1\\/auth\\/resend-otp$/, invalidates: NOTHING },\n { method: 'POST', path: /^\\/api\\/v1\\/auth\\/forgot-password$/, invalidates: NOTHING },\n { method: 'POST', path: /^\\/api\\/v1\\/auth\\/sign-up$/, invalidates: 'all' },\n { method: 'POST', path: /^\\/api\\/v1\\/auth\\/sign-in$/, invalidates: 'all' },\n { method: 'POST', path: /^\\/api\\/v1\\/auth\\/verify-otp$/, invalidates: 'all' },\n { method: 'POST', path: /^\\/api\\/v1\\/auth\\/logout$/, invalidates: 'all' },\n { method: 'POST', path: /^\\/api\\/v1\\/auth\\/reset-password$/, invalidates: 'all' },\n { method: 'POST', path: /^\\/api\\/v1\\/auth\\/change-password$/, invalidates: 'all' },\n {\n method: 'DELETE',\n path: /^\\/api\\/v1\\/auth\\/sessions(?:\\/[^/]+)?$/,\n invalidates: ['auth.sessions'],\n scope: 'account',\n },\n\n // Посты и комментарии.\n { method: 'POST', path: /^\\/api\\/posts$/, invalidates: POST_CONTENT },\n { method: 'PUT', path: /^\\/api\\/posts\\/[^/]+$/, invalidates: POST_CONTENT },\n { method: 'DELETE', path: /^\\/api\\/posts\\/[^/]+$/, invalidates: POST_CONTENT },\n { method: 'POST', path: /^\\/api\\/posts\\/[^/]+\\/restore$/, invalidates: POST_CONTENT },\n { method: 'POST', path: /^\\/api\\/posts\\/[^/]+\\/like$/, invalidates: POST_REACTIONS },\n { method: 'DELETE', path: /^\\/api\\/posts\\/[^/]+\\/like$/, invalidates: POST_REACTIONS },\n { method: 'POST', path: /^\\/api\\/posts\\/[^/]+\\/repost$/, invalidates: POST_CONTENT },\n { method: 'DELETE', path: /^\\/api\\/posts\\/[^/]+\\/repost$/, invalidates: POST_CONTENT },\n { method: 'POST', path: /^\\/api\\/posts\\/[^/]+\\/pin$/, invalidates: PINS },\n { method: 'DELETE', path: /^\\/api\\/posts\\/[^/]+\\/pin$/, invalidates: PINS },\n { method: 'POST', path: /^\\/api\\/posts\\/[^/]+\\/poll\\/vote$/, invalidates: POST_REACTIONS },\n { method: 'POST', path: /^\\/api\\/posts\\/[^/]+\\/comments$/, invalidates: COMMENTS },\n { method: 'POST', path: /^\\/api\\/comments\\/[^/]+\\/replies$/, invalidates: COMMENTS },\n { method: 'PATCH', path: /^\\/api\\/comments\\/[^/]+$/, invalidates: COMMENTS },\n { method: 'DELETE', path: /^\\/api\\/comments\\/[^/]+$/, invalidates: COMMENTS },\n { method: 'POST', path: /^\\/api\\/comments\\/[^/]+\\/restore$/, invalidates: COMMENTS },\n { method: 'POST', path: /^\\/api\\/comments\\/[^/]+\\/like$/, invalidates: COMMENTS },\n { method: 'DELETE', path: /^\\/api\\/comments\\/[^/]+\\/like$/, invalidates: COMMENTS },\n\n // Профиль и связи между пользователями.\n { method: 'PUT', path: /^\\/api\\/users\\/me$/, invalidates: PROFILE },\n { method: 'DELETE', path: /^\\/api\\/users\\/me$/, invalidates: PROFILE },\n { method: 'POST', path: /^\\/api\\/users\\/me\\/restore$/, invalidates: PROFILE },\n { method: 'POST', path: /^\\/api\\/users\\/profile$/, invalidates: PROFILE },\n { method: 'POST', path: /^\\/api\\/users\\/[^/]+\\/follow$/, invalidates: FOLLOWING },\n { method: 'DELETE', path: /^\\/api\\/users\\/[^/]+\\/follow$/, invalidates: FOLLOWING },\n { method: 'POST', path: /^\\/api\\/users\\/[^/]+\\/block$/, invalidates: BLOCKS },\n { method: 'DELETE', path: /^\\/api\\/users\\/[^/]+\\/block$/, invalidates: BLOCKS },\n {\n method: 'PUT',\n path: /^\\/api\\/users\\/me\\/privacy$/,\n invalidates: ['users.me', 'users.get', 'users.getPrivacy'],\n },\n { method: 'PUT', path: /^\\/api\\/users\\/me\\/pin$/, invalidates: PINS },\n { method: 'DELETE', path: /^\\/api\\/users\\/me\\/pin$/, invalidates: PINS },\n\n // Уведомления.\n {\n method: 'POST',\n path: /^\\/api\\/notifications\\/(?:[^/]+\\/read|read-batch|read-all)$/,\n invalidates: NOTIFICATIONS,\n scope: 'account',\n },\n {\n method: 'PUT',\n path: /^\\/api\\/notifications\\/settings$/,\n invalidates: ['notifications.getSettings'],\n scope: 'account',\n },\n\n // Файлы и настройки аккаунта.\n { method: 'POST', path: /^\\/api\\/files\\/upload$/, invalidates: NOTHING },\n {\n method: 'DELETE',\n path: /^\\/api\\/files\\/[^/]+$/,\n invalidates: ['files.get', ...POST_CONTENT],\n },\n {\n method: 'POST',\n path: /^\\/api\\/verification\\/submit$/,\n invalidates: ['verification.status'],\n scope: 'account',\n },\n {\n method: 'POST',\n path: /^\\/api\\/v1\\/subscription\\/pay$/,\n invalidates: SUBSCRIPTION,\n scope: 'account',\n },\n {\n method: 'POST',\n path: /^\\/api\\/v1\\/subscription\\/auto-renewal$/,\n invalidates: SUBSCRIPTION,\n scope: 'account',\n },\n {\n method: 'POST',\n path: /^\\/api\\/v1\\/subscription\\/bind-card$/,\n invalidates: SUBSCRIPTION,\n scope: 'account',\n },\n {\n method: 'POST',\n path: /^\\/api\\/v1\\/subscription\\/methods\\/[^/]+\\/default$/,\n invalidates: SUBSCRIPTION,\n scope: 'account',\n },\n {\n method: 'DELETE',\n path: /^\\/api\\/v1\\/subscription\\/methods\\/[^/]+$/,\n invalidates: SUBSCRIPTION,\n scope: 'account',\n },\n\n // Эти запросы не меняют ни один доступный для кэширования ответ.\n { method: 'POST', path: /^\\/api\\/reports$/, invalidates: NOTHING },\n { method: 'POST', path: /^\\/api\\/v1\\/[ix]$/, invalidates: NOTHING },\n] as const satisfies readonly CacheMutation[]);\n\n/** Находит известную мутацию по HTTP-методу и пути. */\nexport function cacheMutation(method: string, path: string): CacheMutation | undefined {\n const normalized = method.toUpperCase();\n return CACHE_MUTATIONS.find(\n (mutation) => mutation.method === normalized && mutation.path.test(path),\n );\n}\n","/** Описание читающего маршрута itd-api. */\nexport interface CacheRoute {\n /** Публичное имя для настройки плагина. */\n id: string;\n /** Раздел клиента. */\n category: string;\n /** HTTP-метод маршрута. */\n method: string;\n /** Путь без query и базового URL. */\n path: RegExp;\n}\n\n/**\n * Читающие маршруты, которые можно кэшировать.\n *\n * Порядок значим: точные служебные пути стоят перед динамическими маршрутами.\n */\nexport const CACHE_ROUTES = Object.freeze([\n { id: 'auth.sessions', category: 'auth', method: 'GET', path: /^\\/api\\/v1\\/auth\\/sessions$/ },\n\n { id: 'users.me', category: 'users', method: 'GET', path: /^\\/api\\/users\\/me$/ },\n {\n id: 'users.checkUsername',\n category: 'users',\n method: 'GET',\n path: /^\\/api\\/users\\/check-username$/,\n },\n { id: 'users.search', category: 'users', method: 'GET', path: /^\\/api\\/users\\/search$/ },\n {\n id: 'users.whoToFollow',\n category: 'users',\n method: 'GET',\n path: /^\\/api\\/users\\/suggestions\\/who-to-follow$/,\n },\n {\n id: 'users.topClans',\n category: 'users',\n method: 'GET',\n path: /^\\/api\\/users\\/stats\\/top-clans$/,\n },\n {\n id: 'users.followers',\n category: 'users',\n method: 'GET',\n path: /^\\/api\\/users\\/[^/]+\\/followers$/,\n },\n {\n id: 'users.following',\n category: 'users',\n method: 'GET',\n path: /^\\/api\\/users\\/[^/]+\\/following$/,\n },\n {\n id: 'users.blocked',\n category: 'users',\n method: 'GET',\n path: /^\\/api\\/users\\/me\\/blocked$/,\n },\n {\n id: 'users.getPrivacy',\n category: 'users',\n method: 'GET',\n path: /^\\/api\\/users\\/me\\/privacy$/,\n },\n { id: 'users.pins', category: 'users', method: 'GET', path: /^\\/api\\/users\\/me\\/pins$/ },\n {\n id: 'users.followStatus',\n category: 'users',\n method: 'POST',\n path: /^\\/api\\/users\\/follow-status$/,\n },\n { id: 'users.get', category: 'users', method: 'GET', path: /^\\/api\\/users\\/[^/]+$/ },\n\n { id: 'posts.list', category: 'posts', method: 'GET', path: /^\\/api\\/posts$/ },\n {\n id: 'posts.likedByUser',\n category: 'posts',\n method: 'GET',\n path: /^\\/api\\/posts\\/user\\/[^/]+\\/liked$/,\n },\n {\n id: 'posts.byUser',\n category: 'posts',\n method: 'GET',\n path: /^\\/api\\/posts\\/user\\/[^/]+$/,\n },\n {\n id: 'posts.comments',\n category: 'posts',\n method: 'GET',\n path: /^\\/api\\/posts\\/[^/]+\\/comments$/,\n },\n { id: 'posts.stats', category: 'posts', method: 'POST', path: /^\\/api\\/posts\\/stats$/ },\n { id: 'posts.get', category: 'posts', method: 'GET', path: /^\\/api\\/posts\\/[^/]+$/ },\n\n {\n id: 'comments.replies',\n category: 'comments',\n method: 'GET',\n path: /^\\/api\\/comments\\/[^/]+\\/replies$/,\n },\n\n {\n id: 'notifications.list',\n category: 'notifications',\n method: 'GET',\n path: /^\\/api\\/notifications\\/$/,\n },\n {\n id: 'notifications.count',\n category: 'notifications',\n method: 'GET',\n path: /^\\/api\\/notifications\\/count$/,\n },\n {\n id: 'notifications.getSettings',\n category: 'notifications',\n method: 'GET',\n path: /^\\/api\\/notifications\\/settings$/,\n },\n\n {\n id: 'hashtags.search',\n category: 'hashtags',\n method: 'GET',\n path: /^\\/api\\/hashtags$/,\n },\n {\n id: 'hashtags.trending',\n category: 'hashtags',\n method: 'GET',\n path: /^\\/api\\/hashtags\\/trending$/,\n },\n {\n id: 'hashtags.posts',\n category: 'hashtags',\n method: 'GET',\n path: /^\\/api\\/hashtags\\/[^/]+\\/posts$/,\n },\n\n { id: 'search.all', category: 'search', method: 'GET', path: /^\\/api\\/search$/ },\n { id: 'files.get', category: 'files', method: 'GET', path: /^\\/api\\/files\\/[^/]+$/ },\n\n {\n id: 'subscription.status',\n category: 'subscription',\n method: 'GET',\n path: /^\\/api\\/v1\\/subscription\\/$/,\n },\n {\n id: 'subscription.methods',\n category: 'subscription',\n method: 'GET',\n path: /^\\/api\\/v1\\/subscription\\/methods$/,\n },\n {\n id: 'verification.status',\n category: 'verification',\n method: 'GET',\n path: /^\\/api\\/verification\\/status$/,\n },\n\n {\n id: 'platform.changelog',\n category: 'platform',\n method: 'GET',\n path: /^\\/api\\/platform\\/changelog$/,\n },\n {\n id: 'platform.announcements',\n category: 'platform',\n method: 'GET',\n path: /^\\/api\\/platform\\/announcements$/,\n },\n { id: 'platform.portal', category: 'platform', method: 'GET', path: /^\\/api\\/v1\\/portal$/ },\n { id: 'platform.status', category: 'platform', method: 'GET', path: /^\\/api\\/status$/ },\n] as const satisfies readonly CacheRoute[]);\n\n/** Имя маршрута, доступное в `cache({ routes: … })`. */\nexport type CacheRouteId = (typeof CACHE_ROUTES)[number]['id'];\n\n/** Раздел маршрута. */\nexport type CacheRouteCategory = (typeof CACHE_ROUTES)[number]['category'];\n\nconst ROUTE_IDS: ReadonlySet<string> = new Set(CACHE_ROUTES.map((route) => route.id));\n\n/** Проверяет публичное имя маршрута. */\nexport function isCacheRouteId(value: string): value is CacheRouteId {\n return ROUTE_IDS.has(value);\n}\n\n/** Находит читающий маршрут по HTTP-методу и пути. */\nexport function cacheRoute(\n method: string,\n path: string,\n): (typeof CACHE_ROUTES)[number] | undefined {\n const normalized = method.toUpperCase();\n return CACHE_ROUTES.find((route) => route.method === normalized && route.path.test(path));\n}\n","import type {\n AuthIdentity,\n ItdPlugin,\n ItdRealtime,\n RawRequestOptions,\n Transformer,\n Unsubscribe,\n} from 'itd-api';\nimport { LRUCache } from 'lru-cache';\nimport { CacheError } from './errors.js';\nimport { buildCacheKey } from './key.js';\nimport { type CacheMutation, cacheMutation } from './mutations.js';\nimport { type CacheRouteId, cacheRoute, isCacheRouteId } from './routes.js';\n\n/** Режимы кэширования отдельного запроса. */\nexport const CacheModes = Object.freeze({\n /** Отдать свежий кэш, иначе выполнить запрос и сохранить ответ. */\n Default: 'default',\n /** Пропустить сохранённое значение, выполнить запрос и перезаписать кэш. */\n Reload: 'reload',\n /** Не читать и не писать кэш для этого запроса. */\n NoStore: 'no-store',\n} as const);\n\n/** Поведение кэша для отдельного запроса. */\nexport type CacheMode = (typeof CacheModes)[keyof typeof CacheModes];\n\n/** Настройки плагина. */\nexport interface CacheOptions {\n /** Сколько миллисекунд хранить успешный ответ. */\n ttl: number;\n /** Какие операции itd-api кэшировать. */\n routes: readonly CacheRouteId[];\n /** Максимальное количество ответов. По умолчанию 500. */\n maxEntries?: number | undefined;\n /** Объединять ли одновременные одинаковые запросы. По умолчанию `true`. */\n deduplicate?: boolean | undefined;\n}\n\n/** Плагин и управление созданным им хранилищем. */\nexport interface CachePlugin extends ItdPlugin {\n /** Количество готовых ответов во всех разделах кэша. */\n readonly size: number;\n /** Удаляет все ответы и не даёт выполняющимся запросам вернуть устаревший результат. */\n clear(): void;\n /** Удаляет все варианты названных маршрутов во всех подключённых клиентах. */\n invalidate(...routes: CacheRouteId[]): void;\n /**\n * Очищает список и счётчик уведомлений по событиям realtime.\n *\n * Сразу удаляет прежние значения и возвращает функцию отписки.\n */\n attachRealtime(stream: ItdRealtime): Unsubscribe;\n}\n\ninterface CacheEntry {\n accountScope: string;\n route: CacheRouteId;\n value: unknown;\n}\n\ninterface LoadedValue {\n cacheable: boolean;\n value: unknown;\n}\n\ninterface CacheIdentity {\n accountScope: string;\n sessionScope: string;\n}\n\ninterface PendingEntry {\n accountScope: string;\n route: CacheRouteId;\n promise: Promise<LoadedValue>;\n}\n\ninterface KeyState {\n active: number;\n generation: number;\n}\n\ntype CacheRequest = RawRequestOptions & { cache?: CacheMode | undefined };\n\nconst DEFAULT_MAX_ENTRIES = 500;\nconst CACHE_MODES: ReadonlySet<string> = new Set(Object.values(CacheModes));\n\nfunction assertPositive(value: number, name: string, integer = false): void {\n if (!Number.isFinite(value) || value <= 0 || (integer && !Number.isInteger(value))) {\n throw new CacheError(\n `${name} должен быть ${integer ? 'целым ' : ''}положительным числом, получено: ${value}`,\n );\n }\n}\n\nfunction resolveOptions(options: CacheOptions): {\n ttl: number;\n routes: ReadonlySet<CacheRouteId>;\n maxEntries: number;\n deduplicate: boolean;\n} {\n if (!options || typeof options !== 'object') {\n throw new CacheError('cache() принимает объект настроек');\n }\n\n assertPositive(options.ttl, 'cache.ttl');\n\n if (!Array.isArray(options.routes) || options.routes.length === 0) {\n throw new CacheError('cache.routes должен содержать хотя бы один маршрут');\n }\n\n const routes = new Set<CacheRouteId>();\n for (const route of options.routes as readonly string[]) {\n if (typeof route !== 'string' || !isCacheRouteId(route)) {\n throw new CacheError(`Неизвестный маршрут кэша: ${JSON.stringify(route)}`);\n }\n routes.add(route);\n }\n\n const maxEntries = options.maxEntries ?? DEFAULT_MAX_ENTRIES;\n assertPositive(maxEntries, 'cache.maxEntries', true);\n\n const deduplicate = options.deduplicate ?? true;\n if (typeof deduplicate !== 'boolean') {\n throw new CacheError(`cache.deduplicate должен быть boolean, получено: ${deduplicate}`);\n }\n\n return { ttl: options.ttl, routes, maxEntries, deduplicate };\n}\n\nfunction cloneValue(value: unknown): LoadedValue {\n try {\n return { cacheable: true, value: structuredClone(value) };\n } catch {\n return { cacheable: false, value };\n }\n}\n\nfunction cacheMode(request: CacheRequest): CacheMode {\n const mode = request.cache ?? CacheModes.Default;\n if (!CACHE_MODES.has(mode)) {\n throw new CacheError(\n `cache должен быть '${CacheModes.Default}', '${CacheModes.Reload}' или '${CacheModes.NoStore}', получено: ${String(mode)}`,\n );\n }\n return mode;\n}\n\n/** Создаёт TTL/LRU-кэш разобранных ответов itd-api. */\nexport function cache(options: CacheOptions): CachePlugin {\n const config = resolveOptions(options);\n const values = new LRUCache<string, CacheEntry>({\n max: config.maxEntries,\n ttl: config.ttl,\n updateAgeOnGet: false,\n allowStale: false,\n });\n const pending = new Map<string, PendingEntry>();\n const routeGenerations = new Map<CacheRouteId, number>();\n const scopeGenerations = new Map<string, number>();\n const scopeRouteGenerations = new Map<string, number>();\n const keyStates = new Map<string, KeyState>();\n let generation = 0;\n let installationSequence = 0;\n\n const scopeRouteKey = (accountScope: string, route: CacheRouteId): string =>\n JSON.stringify([accountScope, route]);\n\n const clear = (): void => {\n generation += 1;\n values.clear();\n pending.clear();\n };\n\n const invalidate = (...routes: CacheRouteId[]): void => {\n if (routes.length === 0) return;\n\n const selected = new Set<CacheRouteId>();\n for (const route of routes as readonly string[]) {\n if (!isCacheRouteId(route)) {\n throw new CacheError(`Неизвестный маршрут кэша: ${JSON.stringify(route)}`);\n }\n selected.add(route);\n routeGenerations.set(route, (routeGenerations.get(route) ?? 0) + 1);\n }\n\n for (const [key, entry] of values.entries()) {\n if (selected.has(entry.route)) values.delete(key);\n }\n for (const [key, entry] of pending) {\n if (selected.has(entry.route)) pending.delete(key);\n }\n };\n\n const clearScope = (accountScope: string): void => {\n scopeGenerations.set(accountScope, (scopeGenerations.get(accountScope) ?? 0) + 1);\n\n for (const [key, entry] of values.entries()) {\n if (entry.accountScope === accountScope) values.delete(key);\n }\n for (const [key, entry] of pending) {\n if (entry.accountScope === accountScope) pending.delete(key);\n }\n };\n\n const invalidateScope = (accountScope: string, routes: readonly CacheRouteId[]): void => {\n if (routes.length === 0) return;\n\n const selected = new Set(routes);\n for (const route of selected) {\n const key = scopeRouteKey(accountScope, route);\n scopeRouteGenerations.set(key, (scopeRouteGenerations.get(key) ?? 0) + 1);\n }\n\n for (const [key, entry] of values.entries()) {\n if (entry.accountScope === accountScope && selected.has(entry.route)) values.delete(key);\n }\n for (const [key, entry] of pending) {\n if (entry.accountScope === accountScope && selected.has(entry.route)) pending.delete(key);\n }\n };\n\n const applyMutation = (accountScope: string, mutation: CacheMutation): void => {\n if (mutation.invalidates === 'all') {\n clearScope(accountScope);\n } else if (mutation.scope === 'account') {\n invalidateScope(accountScope, mutation.invalidates);\n } else {\n invalidate(...mutation.invalidates);\n }\n };\n\n const createTransformer = (\n installation: number,\n baseUrl: string,\n getAuthIdentity: (() => Promise<AuthIdentity>) | undefined,\n getAuthScope: (() => string) | undefined,\n ): Transformer => {\n const fallbackAuthScope = JSON.stringify([baseUrl, `installation:${installation}`]);\n\n const resolveIdentity = async (): Promise<CacheIdentity> => {\n const identity = await getAuthIdentity?.();\n const accountScope = identity?.userId\n ? JSON.stringify([baseUrl, identity.userId])\n : getAuthScope\n ? JSON.stringify([baseUrl, getAuthScope()])\n : fallbackAuthScope;\n const sessionScope =\n identity?.userId && identity.sessionId\n ? JSON.stringify([baseUrl, identity.userId, identity.sessionId])\n : JSON.stringify([\n accountScope,\n getAuthScope ? getAuthScope() : `installation:${installation}`,\n ]);\n return { accountScope, sessionScope };\n };\n\n return async (rawRequest, next) => {\n const request = rawRequest as CacheRequest;\n const route = cacheRoute(request.method, request.path);\n const method = request.method.toUpperCase();\n const isRead = route !== undefined || method === 'GET' || method === 'HEAD';\n\n if (!isRead) {\n const mutation = cacheMutation(method, request.path);\n const startedIdentity = mutation ? await resolveIdentity() : undefined;\n const result = await next(request);\n if (mutation && startedIdentity) {\n applyMutation(startedIdentity.accountScope, mutation);\n const currentIdentity = await resolveIdentity();\n if (\n currentIdentity.accountScope !== startedIdentity.accountScope &&\n (mutation.invalidates === 'all' || mutation.scope === 'account')\n ) {\n applyMutation(currentIdentity.accountScope, mutation);\n }\n } else {\n clear();\n }\n return result;\n }\n\n if (!route || !config.routes.has(route.id)) return next(request);\n\n const mode = cacheMode(request);\n if (mode === CacheModes.NoStore) return next(request);\n\n const unscopedKey = buildCacheKey(route.id, request);\n if (unscopedKey === undefined) return next(request);\n\n const identity = await resolveIdentity();\n const scope = route.id === 'auth.sessions' ? identity.sessionScope : identity.accountScope;\n const key = JSON.stringify([scope, unscopedKey]);\n\n if (mode === CacheModes.Reload) {\n // Прежняя загрузка только этого ключа не должна перезаписать принудительное обновление.\n const state = keyStates.get(key) ?? {\n active: 0,\n generation: 0,\n };\n state.generation += 1;\n keyStates.set(key, state);\n values.delete(key);\n pending.delete(key);\n }\n\n if (mode === CacheModes.Default) {\n const hit = values.get(key);\n if (hit) {\n const cloned = cloneValue(hit.value);\n if (cloned.cacheable) return cloned.value;\n values.delete(key);\n }\n\n const existing = pending.get(key);\n if (\n config.deduplicate &&\n request.signal === undefined &&\n request.timeout === undefined &&\n existing\n ) {\n const loaded = await existing.promise;\n return cloneValue(loaded.value).value;\n }\n }\n\n const startedGeneration = generation;\n const startedScopeGeneration = scopeGenerations.get(identity.accountScope) ?? 0;\n const startedRouteGeneration = routeGenerations.get(route.id) ?? 0;\n const scopedRouteKey = scopeRouteKey(identity.accountScope, route.id);\n const startedScopeRouteGeneration = scopeRouteGenerations.get(scopedRouteKey) ?? 0;\n const keyState = keyStates.get(key) ?? {\n active: 0,\n generation: 0,\n };\n keyState.active += 1;\n keyStates.set(key, keyState);\n const startedKeyGeneration = keyState.generation;\n const load = (async (): Promise<LoadedValue> => {\n try {\n const result = await next(request);\n const stored = cloneValue(result);\n const currentIdentity = await resolveIdentity();\n const currentScope =\n route.id === 'auth.sessions'\n ? currentIdentity.sessionScope\n : currentIdentity.accountScope;\n\n if (\n stored.cacheable &&\n currentScope === scope &&\n generation === startedGeneration &&\n (scopeGenerations.get(identity.accountScope) ?? 0) === startedScopeGeneration &&\n (routeGenerations.get(route.id) ?? 0) === startedRouteGeneration &&\n (scopeRouteGenerations.get(scopedRouteKey) ?? 0) === startedScopeRouteGeneration &&\n keyState.generation === startedKeyGeneration\n ) {\n values.set(key, {\n accountScope: identity.accountScope,\n route: route.id,\n value: stored.value,\n });\n }\n\n // Снимок уже отделён для кэша; инициатор получает независимый исходный ответ сети.\n return { cacheable: stored.cacheable, value: result };\n } finally {\n keyState.active -= 1;\n if (keyState.active === 0 && keyStates.get(key) === keyState) keyStates.delete(key);\n }\n })();\n\n const mayDeduplicate =\n mode === CacheModes.Default &&\n config.deduplicate &&\n request.signal === undefined &&\n request.timeout === undefined;\n const entry: PendingEntry = {\n accountScope: identity.accountScope,\n route: route.id,\n promise: load,\n };\n if (mayDeduplicate) pending.set(key, entry);\n\n try {\n const loaded = await load;\n return loaded.value;\n } finally {\n if (pending.get(key) === entry) pending.delete(key);\n }\n };\n };\n\n return {\n name: 'cache',\n optionKeys: ['cache'],\n get size() {\n values.purgeStale();\n return values.size;\n },\n clear,\n invalidate,\n attachRealtime(stream) {\n if (!stream || typeof stream.on !== 'function') {\n throw new CacheError('attachRealtime() принимает поток из itd.realtime()');\n }\n\n const invalidateStream = (...routes: CacheRouteId[]): void => {\n const identity =\n typeof stream.getAuthIdentity === 'function' ? stream.getAuthIdentity() : undefined;\n const streamBaseUrl =\n typeof stream.baseUrl === 'string' && stream.baseUrl.length > 0\n ? stream.baseUrl\n : undefined;\n const legacyScope =\n typeof stream.getAuthScope === 'function' ? stream.getAuthScope() : undefined;\n const accountScope =\n identity?.userId && streamBaseUrl\n ? JSON.stringify([streamBaseUrl, identity.userId])\n : legacyScope !== undefined && streamBaseUrl\n ? JSON.stringify([streamBaseUrl, legacyScope])\n : undefined;\n if (accountScope === undefined) invalidate(...routes);\n else invalidateScope(accountScope, routes);\n };\n\n invalidateStream('notifications.list', 'notifications.count');\n const offNotification = stream.on('notification', () =>\n invalidateStream('notifications.list', 'notifications.count'),\n );\n const offUnreadCount = stream.on('unreadCount', () =>\n invalidateStream('notifications.count'),\n );\n\n return () => {\n offNotification();\n offUnreadCount();\n };\n },\n install({ use, baseUrl, getAuthIdentity, getAuthScope }) {\n installationSequence += 1;\n use(createTransformer(installationSequence, baseUrl, getAuthIdentity, getAuthScope));\n },\n };\n}\n"]}