ani-client 2.1.0 → 2.1.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/README.md +134 -60
- package/dist/index.d.mts +60 -1
- package/dist/index.d.ts +60 -1
- package/dist/index.js +236 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +236 -14
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -124,6 +124,174 @@ function sortObjectKeys(obj) {
|
|
|
124
124
|
return sorted;
|
|
125
125
|
}
|
|
126
126
|
|
|
127
|
+
// src/cache/normalized.ts
|
|
128
|
+
var NormalizedCache = class {
|
|
129
|
+
ttl;
|
|
130
|
+
maxSize;
|
|
131
|
+
enabled;
|
|
132
|
+
swrMs;
|
|
133
|
+
queryStore = /* @__PURE__ */ new Map();
|
|
134
|
+
entityStore = /* @__PURE__ */ new Map();
|
|
135
|
+
_hits = 0;
|
|
136
|
+
_misses = 0;
|
|
137
|
+
_stales = 0;
|
|
138
|
+
constructor(options = {}) {
|
|
139
|
+
this.ttl = options.ttl ?? 24 * 60 * 60 * 1e3;
|
|
140
|
+
this.maxSize = options.maxSize ?? 500;
|
|
141
|
+
this.enabled = options.enabled ?? true;
|
|
142
|
+
this.swrMs = options.staleWhileRevalidateMs ?? 0;
|
|
143
|
+
}
|
|
144
|
+
static key(query, variables) {
|
|
145
|
+
const normalized = normalizeQuery(query);
|
|
146
|
+
return `${normalized}|${JSON.stringify(sortObjectKeys(variables))}`;
|
|
147
|
+
}
|
|
148
|
+
/** Normalizes a GraphQL response, extracting entities and returning a tree of references. */
|
|
149
|
+
normalize(data, seen = /* @__PURE__ */ new WeakSet()) {
|
|
150
|
+
if (Array.isArray(data)) {
|
|
151
|
+
if (seen.has(data)) return null;
|
|
152
|
+
seen.add(data);
|
|
153
|
+
return data.map((item) => this.normalize(item, seen));
|
|
154
|
+
}
|
|
155
|
+
if (data !== null && typeof data === "object") {
|
|
156
|
+
if (seen.has(data)) return null;
|
|
157
|
+
seen.add(data);
|
|
158
|
+
const obj = data;
|
|
159
|
+
if (typeof obj.__typename === "string" && (typeof obj.id === "number" || typeof obj.id === "string")) {
|
|
160
|
+
const ref = `${obj.__typename}:${obj.id}`;
|
|
161
|
+
const normalizedObj = {};
|
|
162
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
163
|
+
normalizedObj[k] = this.normalize(v, seen);
|
|
164
|
+
}
|
|
165
|
+
const existing = this.entityStore.get(ref) || {};
|
|
166
|
+
this.entityStore.set(ref, { ...existing, ...normalizedObj });
|
|
167
|
+
return { __ref: ref };
|
|
168
|
+
}
|
|
169
|
+
const result = {};
|
|
170
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
171
|
+
result[k] = this.normalize(v, seen);
|
|
172
|
+
}
|
|
173
|
+
return result;
|
|
174
|
+
}
|
|
175
|
+
return data;
|
|
176
|
+
}
|
|
177
|
+
/** Reconstructs a GraphQL response from references. */
|
|
178
|
+
denormalize(data, seen = /* @__PURE__ */ new Set()) {
|
|
179
|
+
if (Array.isArray(data)) {
|
|
180
|
+
return data.map((item) => this.denormalize(item, seen));
|
|
181
|
+
}
|
|
182
|
+
if (data !== null && typeof data === "object") {
|
|
183
|
+
const obj = data;
|
|
184
|
+
if (typeof obj.__ref === "string") {
|
|
185
|
+
const ref = obj.__ref;
|
|
186
|
+
if (seen.has(ref)) {
|
|
187
|
+
return { __ref: ref };
|
|
188
|
+
}
|
|
189
|
+
seen.add(ref);
|
|
190
|
+
const entity = this.entityStore.get(ref);
|
|
191
|
+
if (!entity) return void 0;
|
|
192
|
+
const result2 = this.denormalize(entity, seen);
|
|
193
|
+
seen.delete(ref);
|
|
194
|
+
return result2;
|
|
195
|
+
}
|
|
196
|
+
const result = {};
|
|
197
|
+
for (const [k, v] of Object.entries(obj)) {
|
|
198
|
+
const denormalized = this.denormalize(v, seen);
|
|
199
|
+
if (denormalized === void 0) return void 0;
|
|
200
|
+
result[k] = denormalized;
|
|
201
|
+
}
|
|
202
|
+
return result;
|
|
203
|
+
}
|
|
204
|
+
return data;
|
|
205
|
+
}
|
|
206
|
+
getWithMeta(key) {
|
|
207
|
+
if (!this.enabled) return void 0;
|
|
208
|
+
const entry = this.queryStore.get(key);
|
|
209
|
+
if (!entry) {
|
|
210
|
+
this._misses++;
|
|
211
|
+
return void 0;
|
|
212
|
+
}
|
|
213
|
+
const now = Date.now();
|
|
214
|
+
let isStale = false;
|
|
215
|
+
if (now > entry.expiresAt) {
|
|
216
|
+
if (this.swrMs > 0 && now <= entry.expiresAt + this.swrMs) {
|
|
217
|
+
isStale = true;
|
|
218
|
+
} else {
|
|
219
|
+
this.queryStore.delete(key);
|
|
220
|
+
this._misses++;
|
|
221
|
+
return void 0;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
const denormalized = this.denormalize(entry.data);
|
|
225
|
+
if (denormalized === void 0) {
|
|
226
|
+
this.queryStore.delete(key);
|
|
227
|
+
this._misses++;
|
|
228
|
+
return void 0;
|
|
229
|
+
}
|
|
230
|
+
this.queryStore.delete(key);
|
|
231
|
+
this.queryStore.set(key, entry);
|
|
232
|
+
if (isStale) {
|
|
233
|
+
this._stales++;
|
|
234
|
+
} else {
|
|
235
|
+
this._hits++;
|
|
236
|
+
}
|
|
237
|
+
return { data: denormalized, stale: isStale };
|
|
238
|
+
}
|
|
239
|
+
get(key) {
|
|
240
|
+
const res = this.getWithMeta(key);
|
|
241
|
+
return res ? res.data : void 0;
|
|
242
|
+
}
|
|
243
|
+
set(key, data) {
|
|
244
|
+
if (!this.enabled) return;
|
|
245
|
+
const normalizedData = this.normalize(data);
|
|
246
|
+
this.queryStore.delete(key);
|
|
247
|
+
if (this.maxSize > 0 && this.queryStore.size >= this.maxSize) {
|
|
248
|
+
const firstKey = this.queryStore.keys().next().value;
|
|
249
|
+
if (firstKey !== void 0) this.queryStore.delete(firstKey);
|
|
250
|
+
}
|
|
251
|
+
this.queryStore.set(key, { data: normalizedData, expiresAt: Date.now() + this.ttl });
|
|
252
|
+
}
|
|
253
|
+
delete(key) {
|
|
254
|
+
return this.queryStore.delete(key);
|
|
255
|
+
}
|
|
256
|
+
clear() {
|
|
257
|
+
this.queryStore.clear();
|
|
258
|
+
this.entityStore.clear();
|
|
259
|
+
this._hits = 0;
|
|
260
|
+
this._misses = 0;
|
|
261
|
+
this._stales = 0;
|
|
262
|
+
}
|
|
263
|
+
get size() {
|
|
264
|
+
return this.queryStore.size;
|
|
265
|
+
}
|
|
266
|
+
keys() {
|
|
267
|
+
return [...this.queryStore.keys()];
|
|
268
|
+
}
|
|
269
|
+
invalidate(pattern) {
|
|
270
|
+
const test = typeof pattern === "string" ? (key) => key.includes(pattern) : (key) => pattern.test(key);
|
|
271
|
+
const toDelete = [];
|
|
272
|
+
for (const key of this.queryStore.keys()) {
|
|
273
|
+
if (test(key)) toDelete.push(key);
|
|
274
|
+
}
|
|
275
|
+
for (const key of toDelete) this.queryStore.delete(key);
|
|
276
|
+
return toDelete.length;
|
|
277
|
+
}
|
|
278
|
+
get stats() {
|
|
279
|
+
const total = this._hits + this._misses + this._stales;
|
|
280
|
+
return {
|
|
281
|
+
hits: this._hits,
|
|
282
|
+
misses: this._misses,
|
|
283
|
+
stales: this._stales,
|
|
284
|
+
hitRate: total === 0 ? Number.NaN : this._hits / total,
|
|
285
|
+
entitiesCount: this.entityStore.size
|
|
286
|
+
};
|
|
287
|
+
}
|
|
288
|
+
resetStats() {
|
|
289
|
+
this._hits = 0;
|
|
290
|
+
this._misses = 0;
|
|
291
|
+
this._stales = 0;
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
|
|
127
295
|
// src/cache/index.ts
|
|
128
296
|
var ONE_DAY_MS = 24 * 60 * 60 * 1e3;
|
|
129
297
|
var MemoryCache = class {
|
|
@@ -151,7 +319,10 @@ var MemoryCache = class {
|
|
|
151
319
|
* With stale-while-revalidate enabled, returns stale data within the grace window
|
|
152
320
|
* and flags it so the caller can refresh in the background.
|
|
153
321
|
*/
|
|
154
|
-
|
|
322
|
+
/**
|
|
323
|
+
* Retrieve a cached value and its stale status.
|
|
324
|
+
*/
|
|
325
|
+
getWithMeta(key) {
|
|
155
326
|
if (!this.enabled) return void 0;
|
|
156
327
|
const entry = this.store.get(key);
|
|
157
328
|
if (!entry) {
|
|
@@ -164,7 +335,7 @@ var MemoryCache = class {
|
|
|
164
335
|
this.store.delete(key);
|
|
165
336
|
this.store.set(key, entry);
|
|
166
337
|
this._stales++;
|
|
167
|
-
return entry.data;
|
|
338
|
+
return { data: entry.data, stale: true };
|
|
168
339
|
}
|
|
169
340
|
this.store.delete(key);
|
|
170
341
|
this._misses++;
|
|
@@ -173,7 +344,11 @@ var MemoryCache = class {
|
|
|
173
344
|
this.store.delete(key);
|
|
174
345
|
this.store.set(key, entry);
|
|
175
346
|
this._hits++;
|
|
176
|
-
return entry.data;
|
|
347
|
+
return { data: entry.data, stale: false };
|
|
348
|
+
}
|
|
349
|
+
get(key) {
|
|
350
|
+
const res = this.getWithMeta(key);
|
|
351
|
+
return res ? res.data : void 0;
|
|
177
352
|
}
|
|
178
353
|
/** Store a value in the cache. */
|
|
179
354
|
set(key, data) {
|
|
@@ -351,7 +526,7 @@ var AniListError = class _AniListError extends Error {
|
|
|
351
526
|
this.status = status;
|
|
352
527
|
this.errors = errors;
|
|
353
528
|
Object.setPrototypeOf(this, _AniListError.prototype);
|
|
354
|
-
if (Error
|
|
529
|
+
if ("captureStackTrace" in Error) {
|
|
355
530
|
Error.captureStackTrace(this, _AniListError);
|
|
356
531
|
}
|
|
357
532
|
}
|
|
@@ -359,6 +534,7 @@ var AniListError = class _AniListError extends Error {
|
|
|
359
534
|
|
|
360
535
|
// src/queries/fragments.ts
|
|
361
536
|
var MEDIA_FIELDS_LIGHT = `
|
|
537
|
+
__typename
|
|
362
538
|
id
|
|
363
539
|
idMal
|
|
364
540
|
title { romaji english native userPreferred }
|
|
@@ -385,6 +561,7 @@ var MEDIA_FIELDS_LIGHT = `
|
|
|
385
561
|
}
|
|
386
562
|
`;
|
|
387
563
|
var MEDIA_FIELDS_BASE = `
|
|
564
|
+
__typename
|
|
388
565
|
id
|
|
389
566
|
idMal
|
|
390
567
|
title { romaji english native userPreferred }
|
|
@@ -431,6 +608,7 @@ var RELATIONS_FIELDS = `
|
|
|
431
608
|
edges {
|
|
432
609
|
relationType(version: 2)
|
|
433
610
|
node {
|
|
611
|
+
__typename
|
|
434
612
|
id
|
|
435
613
|
title { romaji english native userPreferred }
|
|
436
614
|
type
|
|
@@ -461,25 +639,33 @@ var RELATIONS_FIELDS = `
|
|
|
461
639
|
}
|
|
462
640
|
`;
|
|
463
641
|
var MEDIA_RECOMMENDATION_FIELDS = `
|
|
642
|
+
__typename
|
|
464
643
|
id
|
|
465
644
|
rating
|
|
466
645
|
mediaRecommendation {
|
|
646
|
+
__typename
|
|
467
647
|
id
|
|
468
648
|
title { romaji english native userPreferred }
|
|
469
649
|
type
|
|
470
650
|
format
|
|
471
|
-
coverImage { large medium }
|
|
651
|
+
coverImage { extraLarge large medium color }
|
|
472
652
|
averageScore
|
|
473
653
|
meanScore
|
|
474
654
|
episodes
|
|
475
655
|
chapters
|
|
476
656
|
volumes
|
|
477
|
-
nextAiringEpisode
|
|
657
|
+
nextAiringEpisode {
|
|
658
|
+
id
|
|
659
|
+
airingAt
|
|
660
|
+
episode
|
|
661
|
+
mediaId
|
|
662
|
+
timeUntilAiring
|
|
663
|
+
}
|
|
478
664
|
season
|
|
479
665
|
seasonYear
|
|
480
|
-
startDate
|
|
481
|
-
|
|
482
|
-
studios
|
|
666
|
+
startDate { year month day }
|
|
667
|
+
endDate { year month day }
|
|
668
|
+
studios { nodes { id name isAnimationStudio siteUrl } }
|
|
483
669
|
genres
|
|
484
670
|
siteUrl
|
|
485
671
|
}
|
|
@@ -489,6 +675,7 @@ var MEDIA_FIELDS = `
|
|
|
489
675
|
${RELATIONS_FIELDS}
|
|
490
676
|
`;
|
|
491
677
|
var CHARACTER_FIELDS_COMPACT = `
|
|
678
|
+
__typename
|
|
492
679
|
id
|
|
493
680
|
name { first middle last full native alternative }
|
|
494
681
|
image { large medium }
|
|
@@ -503,6 +690,7 @@ var CHARACTER_FIELDS_COMPACT = `
|
|
|
503
690
|
var CHARACTER_MEDIA_NODES = `
|
|
504
691
|
media(perPage: 10) {
|
|
505
692
|
nodes {
|
|
693
|
+
__typename
|
|
506
694
|
id
|
|
507
695
|
title { romaji english native userPreferred }
|
|
508
696
|
type
|
|
@@ -512,6 +700,7 @@ var CHARACTER_MEDIA_NODES = `
|
|
|
512
700
|
}
|
|
513
701
|
`;
|
|
514
702
|
var VOICE_ACTOR_FIELDS_COMPACT = `
|
|
703
|
+
__typename
|
|
515
704
|
id
|
|
516
705
|
name { first middle last full native userPreferred }
|
|
517
706
|
languageV2
|
|
@@ -527,6 +716,7 @@ var CHARACTER_MEDIA_EDGES_WITH_VA = `
|
|
|
527
716
|
${VOICE_ACTOR_FIELDS_COMPACT}
|
|
528
717
|
}
|
|
529
718
|
node {
|
|
719
|
+
__typename
|
|
530
720
|
id
|
|
531
721
|
title { romaji english native userPreferred }
|
|
532
722
|
type
|
|
@@ -545,6 +735,7 @@ var CHARACTER_FIELDS_WITH_VA = `
|
|
|
545
735
|
${CHARACTER_MEDIA_EDGES_WITH_VA}
|
|
546
736
|
`;
|
|
547
737
|
var STAFF_FIELDS = `
|
|
738
|
+
__typename
|
|
548
739
|
id
|
|
549
740
|
name { first middle last full native }
|
|
550
741
|
language
|
|
@@ -564,6 +755,7 @@ var STAFF_FIELDS = `
|
|
|
564
755
|
var STAFF_MEDIA_FIELDS = `
|
|
565
756
|
staffMedia(perPage: $perPage, sort: [POPULARITY_DESC]) {
|
|
566
757
|
nodes {
|
|
758
|
+
__typename
|
|
567
759
|
id
|
|
568
760
|
title { romaji english native userPreferred }
|
|
569
761
|
type
|
|
@@ -602,6 +794,7 @@ var STAFF_MEDIA_FIELDS = `
|
|
|
602
794
|
}
|
|
603
795
|
`;
|
|
604
796
|
var USER_FIELDS = `
|
|
797
|
+
__typename
|
|
605
798
|
id
|
|
606
799
|
name
|
|
607
800
|
about(asHtml: false)
|
|
@@ -622,6 +815,7 @@ var USER_FAVORITES_FIELDS = `
|
|
|
622
815
|
favourites {
|
|
623
816
|
anime(perPage: 25) {
|
|
624
817
|
nodes {
|
|
818
|
+
__typename
|
|
625
819
|
id
|
|
626
820
|
title { romaji english native userPreferred }
|
|
627
821
|
coverImage { large medium }
|
|
@@ -632,6 +826,7 @@ var USER_FAVORITES_FIELDS = `
|
|
|
632
826
|
}
|
|
633
827
|
manga(perPage: 25) {
|
|
634
828
|
nodes {
|
|
829
|
+
__typename
|
|
635
830
|
id
|
|
636
831
|
title { romaji english native userPreferred }
|
|
637
832
|
coverImage { large medium }
|
|
@@ -642,6 +837,7 @@ var USER_FAVORITES_FIELDS = `
|
|
|
642
837
|
}
|
|
643
838
|
characters(perPage: 25) {
|
|
644
839
|
nodes {
|
|
840
|
+
__typename
|
|
645
841
|
id
|
|
646
842
|
name { full native }
|
|
647
843
|
image { large medium }
|
|
@@ -650,6 +846,7 @@ var USER_FAVORITES_FIELDS = `
|
|
|
650
846
|
}
|
|
651
847
|
staff(perPage: 25) {
|
|
652
848
|
nodes {
|
|
849
|
+
__typename
|
|
653
850
|
id
|
|
654
851
|
name { full native }
|
|
655
852
|
image { large medium }
|
|
@@ -658,6 +855,7 @@ var USER_FAVORITES_FIELDS = `
|
|
|
658
855
|
}
|
|
659
856
|
studios(perPage: 25) {
|
|
660
857
|
nodes {
|
|
858
|
+
__typename
|
|
661
859
|
id
|
|
662
860
|
name
|
|
663
861
|
siteUrl
|
|
@@ -666,6 +864,7 @@ var USER_FAVORITES_FIELDS = `
|
|
|
666
864
|
}
|
|
667
865
|
`;
|
|
668
866
|
var MEDIA_LIST_FIELDS = `
|
|
867
|
+
__typename
|
|
669
868
|
id
|
|
670
869
|
mediaId
|
|
671
870
|
status
|
|
@@ -685,6 +884,7 @@ var MEDIA_LIST_FIELDS = `
|
|
|
685
884
|
}
|
|
686
885
|
`;
|
|
687
886
|
var STUDIO_FIELDS = `
|
|
887
|
+
__typename
|
|
688
888
|
id
|
|
689
889
|
name
|
|
690
890
|
isAnimationStudio
|
|
@@ -693,6 +893,7 @@ var STUDIO_FIELDS = `
|
|
|
693
893
|
media(page: 1, perPage: 25, sort: POPULARITY_DESC) {
|
|
694
894
|
pageInfo { total perPage currentPage lastPage hasNextPage }
|
|
695
895
|
nodes {
|
|
896
|
+
__typename
|
|
696
897
|
id
|
|
697
898
|
title { romaji english native userPreferred }
|
|
698
899
|
type
|
|
@@ -703,6 +904,7 @@ var STUDIO_FIELDS = `
|
|
|
703
904
|
}
|
|
704
905
|
`;
|
|
705
906
|
var THREAD_FIELDS = `
|
|
907
|
+
__typename
|
|
706
908
|
id
|
|
707
909
|
title
|
|
708
910
|
body(asHtml: false)
|
|
@@ -719,20 +921,24 @@ var THREAD_FIELDS = `
|
|
|
719
921
|
updatedAt
|
|
720
922
|
siteUrl
|
|
721
923
|
user {
|
|
924
|
+
__typename
|
|
722
925
|
id
|
|
723
926
|
name
|
|
724
927
|
avatar { large medium }
|
|
725
928
|
}
|
|
726
929
|
replyUser {
|
|
930
|
+
__typename
|
|
727
931
|
id
|
|
728
932
|
name
|
|
729
933
|
avatar { large medium }
|
|
730
934
|
}
|
|
731
935
|
categories {
|
|
936
|
+
__typename
|
|
732
937
|
id
|
|
733
938
|
name
|
|
734
939
|
}
|
|
735
940
|
mediaCategories {
|
|
941
|
+
__typename
|
|
736
942
|
id
|
|
737
943
|
title { romaji english native userPreferred }
|
|
738
944
|
type
|
|
@@ -740,6 +946,7 @@ var THREAD_FIELDS = `
|
|
|
740
946
|
siteUrl
|
|
741
947
|
}
|
|
742
948
|
likes {
|
|
949
|
+
__typename
|
|
743
950
|
id
|
|
744
951
|
name
|
|
745
952
|
}
|
|
@@ -841,7 +1048,7 @@ query (
|
|
|
841
1048
|
timeUntilAiring
|
|
842
1049
|
episode
|
|
843
1050
|
mediaId
|
|
844
|
-
media
|
|
1051
|
+
media {
|
|
845
1052
|
${MEDIA_FIELDS_BASE}
|
|
846
1053
|
}
|
|
847
1054
|
}
|
|
@@ -2117,7 +2324,7 @@ function mapFavorites(fav) {
|
|
|
2117
2324
|
|
|
2118
2325
|
// src/client/index.ts
|
|
2119
2326
|
var DEFAULT_API_URL = "https://graphql.anilist.co";
|
|
2120
|
-
var LIB_VERSION = "2.1.
|
|
2327
|
+
var LIB_VERSION = "2.1.2" ;
|
|
2121
2328
|
var AniListClient = class {
|
|
2122
2329
|
apiUrl;
|
|
2123
2330
|
headers;
|
|
@@ -2162,10 +2369,25 @@ var AniListClient = class {
|
|
|
2162
2369
|
/** @internal */
|
|
2163
2370
|
async request(query, variables = {}) {
|
|
2164
2371
|
const cacheKey = MemoryCache.key(query, variables);
|
|
2165
|
-
|
|
2372
|
+
let cached;
|
|
2373
|
+
let isStale = false;
|
|
2374
|
+
if (this.cacheAdapter.getWithMeta) {
|
|
2375
|
+
const res = await this.cacheAdapter.getWithMeta(cacheKey);
|
|
2376
|
+
if (res) {
|
|
2377
|
+
cached = res.data;
|
|
2378
|
+
isStale = res.stale;
|
|
2379
|
+
}
|
|
2380
|
+
} else {
|
|
2381
|
+
cached = await this.cacheAdapter.get(cacheKey);
|
|
2382
|
+
}
|
|
2166
2383
|
if (cached !== void 0) {
|
|
2384
|
+
if (isStale) {
|
|
2385
|
+
this.executeRequest(query, variables, cacheKey).catch((err) => {
|
|
2386
|
+
this.logger?.error("Background revalidation failed", { error: err.message, cacheKey });
|
|
2387
|
+
});
|
|
2388
|
+
}
|
|
2167
2389
|
this.hooks.onCacheHit?.(cacheKey);
|
|
2168
|
-
this.logger?.debug("Cache hit", { cacheKey });
|
|
2390
|
+
this.logger?.debug("Cache hit", { cacheKey, isStale });
|
|
2169
2391
|
const meta = { durationMs: 0, fromCache: true };
|
|
2170
2392
|
this._lastRequestMeta = meta;
|
|
2171
2393
|
this.hooks.onResponse?.(query, 0, true);
|
|
@@ -2555,6 +2777,7 @@ exports.MediaSource = MediaSource;
|
|
|
2555
2777
|
exports.MediaStatus = MediaStatus;
|
|
2556
2778
|
exports.MediaType = MediaType;
|
|
2557
2779
|
exports.MemoryCache = MemoryCache;
|
|
2780
|
+
exports.NormalizedCache = NormalizedCache;
|
|
2558
2781
|
exports.RateLimiter = RateLimiter;
|
|
2559
2782
|
exports.RecommendationSort = RecommendationSort;
|
|
2560
2783
|
exports.RedisCache = RedisCache;
|