@cyanheads/anime-mcp-server 0.1.1

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.
Files changed (85) hide show
  1. package/AGENTS.md +346 -0
  2. package/CLAUDE.md +346 -0
  3. package/Dockerfile +99 -0
  4. package/LICENSE +201 -0
  5. package/README.md +313 -0
  6. package/changelog/0.1.x/0.1.1.md +42 -0
  7. package/changelog/template.md +127 -0
  8. package/dist/index.d.ts +8 -0
  9. package/dist/index.d.ts.map +1 -0
  10. package/dist/index.js +24 -0
  11. package/dist/index.js.map +1 -0
  12. package/dist/mcp-server/prompts/index.d.ts +7 -0
  13. package/dist/mcp-server/prompts/index.d.ts.map +1 -0
  14. package/dist/mcp-server/prompts/index.js +7 -0
  15. package/dist/mcp-server/prompts/index.js.map +1 -0
  16. package/dist/mcp-server/resources/definitions/anime-media.resource.d.ts +31 -0
  17. package/dist/mcp-server/resources/definitions/anime-media.resource.d.ts.map +1 -0
  18. package/dist/mcp-server/resources/definitions/anime-media.resource.js +100 -0
  19. package/dist/mcp-server/resources/definitions/anime-media.resource.js.map +1 -0
  20. package/dist/mcp-server/resources/index.d.ts +29 -0
  21. package/dist/mcp-server/resources/index.d.ts.map +1 -0
  22. package/dist/mcp-server/resources/index.js +7 -0
  23. package/dist/mcp-server/resources/index.js.map +1 -0
  24. package/dist/mcp-server/tools/definitions/anime-find-characters.tool.d.ts +77 -0
  25. package/dist/mcp-server/tools/definitions/anime-find-characters.tool.d.ts.map +1 -0
  26. package/dist/mcp-server/tools/definitions/anime-find-characters.tool.js +308 -0
  27. package/dist/mcp-server/tools/definitions/anime-find-characters.tool.js.map +1 -0
  28. package/dist/mcp-server/tools/definitions/anime-get-media.tool.d.ts +92 -0
  29. package/dist/mcp-server/tools/definitions/anime-get-media.tool.d.ts.map +1 -0
  30. package/dist/mcp-server/tools/definitions/anime-get-media.tool.js +425 -0
  31. package/dist/mcp-server/tools/definitions/anime-get-media.tool.js.map +1 -0
  32. package/dist/mcp-server/tools/definitions/anime-get-rankings.tool.d.ts +73 -0
  33. package/dist/mcp-server/tools/definitions/anime-get-rankings.tool.d.ts.map +1 -0
  34. package/dist/mcp-server/tools/definitions/anime-get-rankings.tool.js +154 -0
  35. package/dist/mcp-server/tools/definitions/anime-get-rankings.tool.js.map +1 -0
  36. package/dist/mcp-server/tools/definitions/anime-get-recommendations.tool.d.ts +35 -0
  37. package/dist/mcp-server/tools/definitions/anime-get-recommendations.tool.d.ts.map +1 -0
  38. package/dist/mcp-server/tools/definitions/anime-get-recommendations.tool.js +174 -0
  39. package/dist/mcp-server/tools/definitions/anime-get-recommendations.tool.js.map +1 -0
  40. package/dist/mcp-server/tools/definitions/anime-get-relations.tool.d.ts +43 -0
  41. package/dist/mcp-server/tools/definitions/anime-get-relations.tool.d.ts.map +1 -0
  42. package/dist/mcp-server/tools/definitions/anime-get-relations.tool.js +245 -0
  43. package/dist/mcp-server/tools/definitions/anime-get-relations.tool.js.map +1 -0
  44. package/dist/mcp-server/tools/definitions/anime-get-schedule.tool.d.ts +51 -0
  45. package/dist/mcp-server/tools/definitions/anime-get-schedule.tool.d.ts.map +1 -0
  46. package/dist/mcp-server/tools/definitions/anime-get-schedule.tool.js +196 -0
  47. package/dist/mcp-server/tools/definitions/anime-get-schedule.tool.js.map +1 -0
  48. package/dist/mcp-server/tools/definitions/anime-get-studio.tool.d.ts +50 -0
  49. package/dist/mcp-server/tools/definitions/anime-get-studio.tool.d.ts.map +1 -0
  50. package/dist/mcp-server/tools/definitions/anime-get-studio.tool.js +163 -0
  51. package/dist/mcp-server/tools/definitions/anime-get-studio.tool.js.map +1 -0
  52. package/dist/mcp-server/tools/definitions/anime-search-media.tool.d.ts +73 -0
  53. package/dist/mcp-server/tools/definitions/anime-search-media.tool.d.ts.map +1 -0
  54. package/dist/mcp-server/tools/definitions/anime-search-media.tool.js +229 -0
  55. package/dist/mcp-server/tools/definitions/anime-search-media.tool.js.map +1 -0
  56. package/dist/mcp-server/tools/index.d.ts +435 -0
  57. package/dist/mcp-server/tools/index.d.ts.map +1 -0
  58. package/dist/mcp-server/tools/index.js +23 -0
  59. package/dist/mcp-server/tools/index.js.map +1 -0
  60. package/dist/services/anilist/anilist-service.d.ts +90 -0
  61. package/dist/services/anilist/anilist-service.d.ts.map +1 -0
  62. package/dist/services/anilist/anilist-service.js +496 -0
  63. package/dist/services/anilist/anilist-service.js.map +1 -0
  64. package/dist/services/anilist/types.d.ts +255 -0
  65. package/dist/services/anilist/types.d.ts.map +1 -0
  66. package/dist/services/anilist/types.js +6 -0
  67. package/dist/services/anilist/types.js.map +1 -0
  68. package/dist/services/jikan/jikan-service.d.ts +22 -0
  69. package/dist/services/jikan/jikan-service.d.ts.map +1 -0
  70. package/dist/services/jikan/jikan-service.js +89 -0
  71. package/dist/services/jikan/jikan-service.js.map +1 -0
  72. package/dist/services/jikan/types.d.ts +85 -0
  73. package/dist/services/jikan/types.d.ts.map +1 -0
  74. package/dist/services/jikan/types.js +6 -0
  75. package/dist/services/jikan/types.js.map +1 -0
  76. package/dist/services/kitsu/kitsu-service.d.ts +14 -0
  77. package/dist/services/kitsu/kitsu-service.d.ts.map +1 -0
  78. package/dist/services/kitsu/kitsu-service.js +94 -0
  79. package/dist/services/kitsu/kitsu-service.js.map +1 -0
  80. package/dist/services/kitsu/types.d.ts +17 -0
  81. package/dist/services/kitsu/types.d.ts.map +1 -0
  82. package/dist/services/kitsu/types.js +6 -0
  83. package/dist/services/kitsu/types.js.map +1 -0
  84. package/package.json +103 -0
  85. package/server.json +99 -0
@@ -0,0 +1,496 @@
1
+ /**
2
+ * @fileoverview AniList service — GraphQL client wrapping https://graphql.anilist.co.
3
+ * Primary source for all anime/manga data: search, detail, relations, schedule,
4
+ * characters, recommendations, rankings, and studio filmography.
5
+ * @module services/anilist/anilist-service
6
+ */
7
+ import { JsonRpcErrorCode, McpError, serviceUnavailable } from '@cyanheads/mcp-ts-core/errors';
8
+ import { fetchWithTimeout, requestContextService, withRetry } from '@cyanheads/mcp-ts-core/utils';
9
+ // ─── Constants ────────────────────────────────────────────────────────────────
10
+ const ANILIST_URL = 'https://graphql.anilist.co';
11
+ const TIMEOUT_MS = 15_000;
12
+ const REQUEST_CONTEXT = requestContextService.createRequestContext({
13
+ operation: 'anilist-service',
14
+ });
15
+ // ─── Rate-limit state ─────────────────────────────────────────────────────────
16
+ /** Simple in-process rate-limit guard: 30 req / 30s. */
17
+ let _windowStart = 0;
18
+ let _windowCount = 0;
19
+ /**
20
+ * Block if we've hit the AniList rate limit.
21
+ * Waits out the current 30s window before resuming.
22
+ */
23
+ async function checkRateLimit() {
24
+ const now = Date.now();
25
+ if (now - _windowStart > 30_000) {
26
+ _windowStart = now;
27
+ _windowCount = 0;
28
+ }
29
+ _windowCount++;
30
+ if (_windowCount > 29) {
31
+ const wait = 30_000 - (now - _windowStart) + 100;
32
+ await new Promise((r) => setTimeout(r, wait));
33
+ _windowStart = Date.now();
34
+ _windowCount = 1;
35
+ }
36
+ }
37
+ // ─── Core query executor ──────────────────────────────────────────────────────
38
+ /** Execute a GraphQL query against AniList. Returns the `data` payload. */
39
+ async function query(gql, variables) {
40
+ await checkRateLimit();
41
+ return withRetry(async () => {
42
+ const resp = await fetchWithTimeout(ANILIST_URL, TIMEOUT_MS, REQUEST_CONTEXT, {
43
+ method: 'POST',
44
+ headers: { 'Content-Type': 'application/json', Accept: 'application/json' },
45
+ body: JSON.stringify({ query: gql, variables }),
46
+ });
47
+ if (resp.status === 429) {
48
+ // Back off the full 30s window
49
+ await new Promise((r) => setTimeout(r, 30_000));
50
+ throw serviceUnavailable('AniList rate limit exceeded', { status: 429 });
51
+ }
52
+ // AniList sends 404 with data.{entity}: null for nonexistent IDs — read the body
53
+ // before deciding whether to treat it as an error.
54
+ if (!resp.ok && resp.status !== 200 && resp.status !== 404) {
55
+ throw serviceUnavailable(`AniList returned HTTP ${resp.status}`, { status: resp.status });
56
+ }
57
+ const json = (await resp.json());
58
+ // AniList returns HTTP 200 (or 404) even on GraphQL errors.
59
+ // When data is present (e.g. data.Media: null on not-found), return it so
60
+ // callers can check for null and throw the appropriate domain error.
61
+ if (json.errors?.length && !json.data) {
62
+ const firstErr = json.errors[0];
63
+ throw serviceUnavailable(`AniList GraphQL error: ${firstErr?.message ?? 'unknown'}`, {
64
+ status: firstErr?.status,
65
+ });
66
+ }
67
+ return json.data;
68
+ }, {
69
+ maxRetries: 3,
70
+ baseDelayMs: 1000,
71
+ maxDelayMs: 30_000,
72
+ operation: 'anilist-query',
73
+ context: REQUEST_CONTEXT,
74
+ });
75
+ }
76
+ // ─── GraphQL fragments ────────────────────────────────────────────────────────
77
+ const MEDIA_NODE_FRAGMENT = `
78
+ id idMal type format status season seasonYear episodes chapters volumes
79
+ isAdult meanScore
80
+ title { romaji english native }
81
+ coverImage { extraLarge large medium color }
82
+ `;
83
+ const MEDIA_DETAIL_FRAGMENT = `
84
+ ${MEDIA_NODE_FRAGMENT}
85
+ description(asHtml: false)
86
+ source hashtag bannerImage
87
+ averageScore popularity favourites isFavourite
88
+ startDate { year month day }
89
+ endDate { year month day }
90
+ genres
91
+ tags { id name description category rank isGeneralSpoiler isAdult }
92
+ studios { edges { isMain node { id name isAnimationStudio } } }
93
+ externalLinks { id url site siteId type language icon color isDisabled }
94
+ relations { edges { relationType node { ${MEDIA_NODE_FRAGMENT} } } }
95
+ siteUrl
96
+ trailer { id site }
97
+ nextAiringEpisode { airingAt episode timeUntilAiring }
98
+ `;
99
+ // ─── Service methods ──────────────────────────────────────────────────────────
100
+ /** Search anime or manga by various filters. Returns a page of results. */
101
+ export async function searchMedia(params) {
102
+ const gql = `
103
+ query SearchMedia(
104
+ $type: MediaType, $search: String, $genre: String, $tag: String,
105
+ $season: MediaSeason, $seasonYear: Int, $format: MediaFormat,
106
+ $status: MediaStatus, $sort: [MediaSort], $page: Int, $perPage: Int,
107
+ $isAdult: Boolean
108
+ ) {
109
+ Page(page: $page, perPage: $perPage) {
110
+ pageInfo { total currentPage lastPage hasNextPage perPage }
111
+ media(
112
+ type: $type, search: $search, genre: $genre, tag: $tag,
113
+ season: $season, seasonYear: $seasonYear, format: $format,
114
+ status: $status, sort: $sort, isAdult: $isAdult
115
+ ) { ${MEDIA_NODE_FRAGMENT} }
116
+ }
117
+ }
118
+ `;
119
+ const data = await query(gql, {
120
+ type: params.mediaType,
121
+ search: params.query || undefined,
122
+ genre: params.genre || undefined,
123
+ tag: params.tag || undefined,
124
+ season: params.season || undefined,
125
+ seasonYear: params.seasonYear || undefined,
126
+ format: params.format || undefined,
127
+ status: params.status || undefined,
128
+ sort: params.sort || ['SEARCH_MATCH'],
129
+ page: params.page ?? 1,
130
+ perPage: Math.min(params.perPage ?? 20, 50),
131
+ isAdult: params.includeAdult ? undefined : false,
132
+ });
133
+ return data.Page;
134
+ }
135
+ /** Get full detail for one media item by AniList ID. Returns null if not found. */
136
+ export async function getMediaById(id, includeAdult = false) {
137
+ const gql = `
138
+ query GetMedia($id: Int, $isAdult: Boolean) {
139
+ Media(id: $id, isAdult: $isAdult) { ${MEDIA_DETAIL_FRAGMENT} }
140
+ }
141
+ `;
142
+ try {
143
+ const data = await query(gql, {
144
+ id,
145
+ isAdult: includeAdult ? undefined : false,
146
+ });
147
+ return data.Media;
148
+ }
149
+ catch (err) {
150
+ // AniList sends HTTP 404 for nonexistent IDs — fetchWithTimeout converts this to
151
+ // a NotFound McpError before we can read the body. Translate to null so callers
152
+ // can throw the appropriate domain error.
153
+ if (err instanceof McpError && err.code === JsonRpcErrorCode.NotFound)
154
+ return null;
155
+ throw err;
156
+ }
157
+ }
158
+ /** Get relation edges for a media entry (one hop). Returns null if not found. */
159
+ export async function getMediaRelations(id) {
160
+ const gql = `
161
+ query GetRelations($id: Int) {
162
+ Media(id: $id) {
163
+ id
164
+ relations { edges { relationType node { ${MEDIA_NODE_FRAGMENT} } } }
165
+ }
166
+ }
167
+ `;
168
+ try {
169
+ const data = await query(gql, { id });
170
+ return data.Media?.relations.edges ?? null;
171
+ }
172
+ catch (err) {
173
+ if (err instanceof McpError && err.code === JsonRpcErrorCode.NotFound)
174
+ return null;
175
+ throw err;
176
+ }
177
+ }
178
+ /** Get seasonal airing schedule. */
179
+ export async function getSeasonSchedule(params) {
180
+ const gql = `
181
+ query SeasonSchedule(
182
+ $season: MediaSeason!, $seasonYear: Int!, $page: Int, $perPage: Int, $isAdult: Boolean
183
+ ) {
184
+ Page(page: $page, perPage: $perPage) {
185
+ pageInfo { total currentPage lastPage hasNextPage perPage }
186
+ media(
187
+ type: ANIME, season: $season, seasonYear: $seasonYear,
188
+ sort: [POPULARITY_DESC], isAdult: $isAdult
189
+ ) {
190
+ ${MEDIA_NODE_FRAGMENT}
191
+ nextAiringEpisode { airingAt episode timeUntilAiring }
192
+ }
193
+ }
194
+ }
195
+ `;
196
+ const data = await query(gql, {
197
+ season: params.season,
198
+ seasonYear: params.seasonYear,
199
+ page: params.page ?? 1,
200
+ perPage: Math.min(params.perPage ?? 20, 50),
201
+ isAdult: params.includeAdult ? undefined : false,
202
+ });
203
+ return data.Page;
204
+ }
205
+ /** Get upcoming airing episodes within a time window. */
206
+ export async function getUpcomingEpisodes(params) {
207
+ const now = Math.floor(Date.now() / 1000);
208
+ const end = now + (params.daysAhead ?? 7) * 86_400;
209
+ const gql = `
210
+ query UpcomingEpisodes($greaterThan: Int!, $lessThan: Int!, $page: Int, $perPage: Int) {
211
+ Page(page: $page, perPage: $perPage) {
212
+ airingSchedules(airingAt_greater: $greaterThan, airingAt_lesser: $lessThan) {
213
+ id airingAt episode timeUntilAiring
214
+ media { ${MEDIA_NODE_FRAGMENT} }
215
+ }
216
+ }
217
+ }
218
+ `;
219
+ const data = await query(gql, {
220
+ greaterThan: now,
221
+ lessThan: end,
222
+ page: params.page ?? 1,
223
+ perPage: Math.min(params.perPage ?? 50, 50),
224
+ });
225
+ return data.Page.airingSchedules;
226
+ }
227
+ /** Get characters for a media item. */
228
+ export async function getMediaCharacters(params) {
229
+ const gql = `
230
+ query GetCharacters($id: Int!, $language: StaffLanguage, $page: Int, $perPage: Int) {
231
+ Media(id: $id) {
232
+ characters(page: $page, perPage: $perPage, sort: [ROLE, RELEVANCE]) {
233
+ pageInfo { hasNextPage }
234
+ edges {
235
+ role
236
+ node {
237
+ id
238
+ name { full native }
239
+ image { large medium }
240
+ description(asHtml: false)
241
+ siteUrl
242
+ }
243
+ voiceActors(language: $language, sort: [RELEVANCE]) {
244
+ id
245
+ name { full native }
246
+ language
247
+ image { large medium }
248
+ siteUrl
249
+ }
250
+ }
251
+ }
252
+ }
253
+ }
254
+ `;
255
+ try {
256
+ const data = await query(gql, {
257
+ id: params.mediaId,
258
+ language: params.language || undefined,
259
+ page: params.page ?? 1,
260
+ perPage: Math.min(params.perPage ?? 25, 25),
261
+ });
262
+ if (!data.Media)
263
+ return { characters: [], hasNextPage: false };
264
+ return {
265
+ characters: data.Media.characters.edges,
266
+ hasNextPage: data.Media.characters.pageInfo.hasNextPage,
267
+ };
268
+ }
269
+ catch (err) {
270
+ if (err instanceof McpError && err.code === JsonRpcErrorCode.NotFound)
271
+ return { characters: [], hasNextPage: false };
272
+ throw err;
273
+ }
274
+ }
275
+ /** Search for a character by name. */
276
+ export async function searchCharacter(name) {
277
+ const gql = `
278
+ query SearchCharacter($search: String!, $page: Int, $perPage: Int) {
279
+ Character(search: $search) {
280
+ id
281
+ name { full native }
282
+ image { large medium }
283
+ description(asHtml: false)
284
+ siteUrl
285
+ media(page: $page, perPage: $perPage, sort: [POPULARITY_DESC]) {
286
+ pageInfo { hasNextPage currentPage }
287
+ nodes { ${MEDIA_NODE_FRAGMENT} }
288
+ edges {
289
+ characterRole
290
+ voiceActors(sort: [RELEVANCE]) {
291
+ id name { full native } language image { large medium } siteUrl
292
+ }
293
+ }
294
+ }
295
+ }
296
+ }
297
+ `;
298
+ try {
299
+ const data = await query(gql, {
300
+ search: name,
301
+ page: 1,
302
+ perPage: 10,
303
+ });
304
+ return data.Character;
305
+ }
306
+ catch (err) {
307
+ if (err instanceof McpError && err.code === JsonRpcErrorCode.NotFound)
308
+ return null;
309
+ throw err;
310
+ }
311
+ }
312
+ /** Search for a voice actor (staff) by name. */
313
+ export async function searchStaff(name, page = 1, perPage = 10) {
314
+ const gql = `
315
+ query SearchStaff($search: String!, $page: Int, $perPage: Int) {
316
+ Staff(search: $search) {
317
+ id
318
+ name { full native }
319
+ language
320
+ image { large medium }
321
+ description(asHtml: false)
322
+ siteUrl
323
+ characterMedia(page: $page, perPage: $perPage, sort: [POPULARITY_DESC]) {
324
+ pageInfo { hasNextPage currentPage }
325
+ edges {
326
+ characterRole
327
+ node { ${MEDIA_NODE_FRAGMENT} }
328
+ characters { id name { full native } }
329
+ }
330
+ }
331
+ }
332
+ }
333
+ `;
334
+ try {
335
+ const data = await query(gql, {
336
+ search: name,
337
+ page,
338
+ perPage,
339
+ });
340
+ return data.Staff;
341
+ }
342
+ catch (err) {
343
+ if (err instanceof McpError && err.code === JsonRpcErrorCode.NotFound)
344
+ return null;
345
+ throw err;
346
+ }
347
+ }
348
+ /** Get recommendations for a media entry. */
349
+ export async function getRecommendations(params) {
350
+ const gql = `
351
+ query GetRecommendations($id: Int!, $page: Int, $perPage: Int) {
352
+ Media(id: $id) {
353
+ idMal
354
+ recommendations(page: $page, perPage: $perPage, sort: [RATING_DESC]) {
355
+ pageInfo { hasNextPage }
356
+ nodes {
357
+ rating
358
+ mediaRecommendation { ${MEDIA_NODE_FRAGMENT} }
359
+ }
360
+ }
361
+ }
362
+ }
363
+ `;
364
+ try {
365
+ const data = await query(gql, {
366
+ id: params.mediaId,
367
+ page: params.page ?? 1,
368
+ perPage: Math.min(params.perPage ?? 25, 25),
369
+ });
370
+ if (!data.Media)
371
+ return { nodes: [], hasNextPage: false };
372
+ return {
373
+ nodes: data.Media.recommendations.nodes,
374
+ hasNextPage: data.Media.recommendations.pageInfo.hasNextPage,
375
+ };
376
+ }
377
+ catch (err) {
378
+ if (err instanceof McpError && err.code === JsonRpcErrorCode.NotFound)
379
+ return { nodes: [], hasNextPage: false };
380
+ throw err;
381
+ }
382
+ }
383
+ /** Get rankings by mode: top, trending, or seasonal. */
384
+ export async function getRankings(params) {
385
+ let sort;
386
+ let season = params.season;
387
+ let seasonYear = params.seasonYear;
388
+ switch (params.mode) {
389
+ case 'top':
390
+ sort = ['SCORE_DESC'];
391
+ break;
392
+ case 'trending':
393
+ sort = ['TRENDING_DESC'];
394
+ break;
395
+ case 'seasonal':
396
+ sort = ['POPULARITY_DESC'];
397
+ // Default to current season if not specified
398
+ if (!season || !seasonYear) {
399
+ const now = new Date();
400
+ const month = now.getMonth() + 1;
401
+ seasonYear = now.getFullYear();
402
+ if (month <= 3)
403
+ season = 'WINTER';
404
+ else if (month <= 6)
405
+ season = 'SPRING';
406
+ else if (month <= 9)
407
+ season = 'SUMMER';
408
+ else
409
+ season = 'FALL';
410
+ }
411
+ break;
412
+ }
413
+ const gql = `
414
+ query GetRankings(
415
+ $type: MediaType!, $sort: [MediaSort]!, $format: MediaFormat, $genre: String,
416
+ $season: MediaSeason, $seasonYear: Int, $page: Int, $perPage: Int, $isAdult: Boolean
417
+ ) {
418
+ Page(page: $page, perPage: $perPage) {
419
+ pageInfo { total currentPage lastPage hasNextPage perPage }
420
+ media(
421
+ type: $type, sort: $sort, format: $format, genre: $genre,
422
+ season: $season, seasonYear: $seasonYear, isAdult: $isAdult
423
+ ) { ${MEDIA_NODE_FRAGMENT} }
424
+ }
425
+ }
426
+ `;
427
+ const data = await query(gql, {
428
+ type: params.mediaType,
429
+ sort,
430
+ format: params.format || undefined,
431
+ genre: params.genre || undefined,
432
+ season: season || undefined,
433
+ seasonYear: seasonYear || undefined,
434
+ page: params.page ?? 1,
435
+ perPage: Math.min(params.perPage ?? 25, 50),
436
+ isAdult: params.includeAdult ? undefined : false,
437
+ });
438
+ return data.Page;
439
+ }
440
+ /** Look up a studio by name (search) and return its filmography. */
441
+ export async function searchStudio(params) {
442
+ const gql = `
443
+ query SearchStudio($search: String!, $mediaSort: [MediaSort], $page: Int, $perPage: Int) {
444
+ Studio(search: $search) {
445
+ id name isAnimationStudio siteUrl
446
+ media(page: $page, perPage: $perPage, sort: $mediaSort) {
447
+ pageInfo { total currentPage lastPage hasNextPage }
448
+ nodes { ${MEDIA_NODE_FRAGMENT} }
449
+ }
450
+ }
451
+ }
452
+ `;
453
+ try {
454
+ const data = await query(gql, {
455
+ search: params.name,
456
+ mediaSort: params.sort ? [params.sort] : ['POPULARITY_DESC'],
457
+ page: params.page ?? 1,
458
+ perPage: Math.min(params.perPage ?? 25, 50),
459
+ });
460
+ return data.Studio;
461
+ }
462
+ catch (err) {
463
+ if (err instanceof McpError && err.code === JsonRpcErrorCode.NotFound)
464
+ return null;
465
+ throw err;
466
+ }
467
+ }
468
+ /** Get studio by AniList ID. */
469
+ export async function getStudioById(params) {
470
+ const gql = `
471
+ query GetStudio($id: Int!, $mediaSort: [MediaSort], $page: Int, $perPage: Int) {
472
+ Studio(id: $id) {
473
+ id name isAnimationStudio siteUrl
474
+ media(page: $page, perPage: $perPage, sort: $mediaSort) {
475
+ pageInfo { total currentPage lastPage hasNextPage }
476
+ nodes { ${MEDIA_NODE_FRAGMENT} }
477
+ }
478
+ }
479
+ }
480
+ `;
481
+ try {
482
+ const data = await query(gql, {
483
+ id: params.id,
484
+ mediaSort: params.sort ? [params.sort] : ['POPULARITY_DESC'],
485
+ page: params.page ?? 1,
486
+ perPage: Math.min(params.perPage ?? 25, 50),
487
+ });
488
+ return data.Studio;
489
+ }
490
+ catch (err) {
491
+ if (err instanceof McpError && err.code === JsonRpcErrorCode.NotFound)
492
+ return null;
493
+ throw err;
494
+ }
495
+ }
496
+ //# sourceMappingURL=anilist-service.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"anilist-service.js","sourceRoot":"","sources":["../../../src/services/anilist/anilist-service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,kBAAkB,EAAE,MAAM,+BAA+B,CAAC;AAC/F,OAAO,EAAE,gBAAgB,EAAE,qBAAqB,EAAE,SAAS,EAAE,MAAM,8BAA8B,CAAC;AAkBlG,iFAAiF;AAEjF,MAAM,WAAW,GAAG,4BAA4B,CAAC;AACjD,MAAM,UAAU,GAAG,MAAM,CAAC;AAC1B,MAAM,eAAe,GAAG,qBAAqB,CAAC,oBAAoB,CAAC;IACjE,SAAS,EAAE,iBAAiB;CAC7B,CAAC,CAAC;AAEH,iFAAiF;AAEjF,wDAAwD;AACxD,IAAI,YAAY,GAAG,CAAC,CAAC;AACrB,IAAI,YAAY,GAAG,CAAC,CAAC;AAErB;;;GAGG;AACH,KAAK,UAAU,cAAc;IAC3B,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACvB,IAAI,GAAG,GAAG,YAAY,GAAG,MAAM,EAAE,CAAC;QAChC,YAAY,GAAG,GAAG,CAAC;QACnB,YAAY,GAAG,CAAC,CAAC;IACnB,CAAC;IACD,YAAY,EAAE,CAAC;IACf,IAAI,YAAY,GAAG,EAAE,EAAE,CAAC;QACtB,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,GAAG,GAAG,YAAY,CAAC,GAAG,GAAG,CAAC;QACjD,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC;QAC9C,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC1B,YAAY,GAAG,CAAC,CAAC;IACnB,CAAC;AACH,CAAC;AAED,iFAAiF;AAEjF,2EAA2E;AAC3E,KAAK,UAAU,KAAK,CAAI,GAAW,EAAE,SAAkC;IACrE,MAAM,cAAc,EAAE,CAAC;IAEvB,OAAO,SAAS,CACd,KAAK,IAAI,EAAE;QACT,MAAM,IAAI,GAAG,MAAM,gBAAgB,CAAC,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE;YAC5E,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE,MAAM,EAAE,kBAAkB,EAAE;YAC3E,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,CAAC;SAChD,CAAC,CAAC;QAEH,IAAI,IAAI,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACxB,+BAA+B;YAC/B,MAAM,IAAI,OAAO,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC;YAChD,MAAM,kBAAkB,CAAC,6BAA6B,EAAE,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC,CAAC;QAC3E,CAAC;QAED,iFAAiF;QACjF,mDAAmD;QACnD,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,MAAM,KAAK,GAAG,IAAI,IAAI,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YAC3D,MAAM,kBAAkB,CAAC,yBAAyB,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;QAC5F,CAAC;QAED,MAAM,IAAI,GAAG,CAAC,MAAM,IAAI,CAAC,IAAI,EAAE,CAG9B,CAAC;QAEF,4DAA4D;QAC5D,0EAA0E;QAC1E,qEAAqE;QACrE,IAAI,IAAI,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC;YACtC,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;YAChC,MAAM,kBAAkB,CAAC,0BAA0B,QAAQ,EAAE,OAAO,IAAI,SAAS,EAAE,EAAE;gBACnF,MAAM,EAAE,QAAQ,EAAE,MAAM;aACzB,CAAC,CAAC;QACL,CAAC;QAED,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC,EACD;QACE,UAAU,EAAE,CAAC;QACb,WAAW,EAAE,IAAI;QACjB,UAAU,EAAE,MAAM;QAClB,SAAS,EAAE,eAAe;QAC1B,OAAO,EAAE,eAAe;KACzB,CACF,CAAC;AACJ,CAAC;AAED,iFAAiF;AAEjF,MAAM,mBAAmB,GAAG;;;;;CAK3B,CAAC;AAEF,MAAM,qBAAqB,GAAG;IAC1B,mBAAmB;;;;;;;;;;4CAUqB,mBAAmB;;;;CAI9D,CAAC;AAEF,iFAAiF;AAEjF,2EAA2E;AAC3E,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAajC;IACC,MAAM,GAAG,GAAG;;;;;;;;;;;;;cAaA,mBAAmB;;;GAG9B,CAAC;IAEF,MAAM,IAAI,GAAG,MAAM,KAAK,CAAsB,GAAG,EAAE;QACjD,IAAI,EAAE,MAAM,CAAC,SAAS;QACtB,MAAM,EAAE,MAAM,CAAC,KAAK,IAAI,SAAS;QACjC,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,SAAS;QAChC,GAAG,EAAE,MAAM,CAAC,GAAG,IAAI,SAAS;QAC5B,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,SAAS;QAClC,UAAU,EAAE,MAAM,CAAC,UAAU,IAAI,SAAS;QAC1C,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,SAAS;QAClC,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,SAAS;QAClC,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC,cAAc,CAAC;QACrC,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC;QACtB,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE,EAAE,CAAC;QAC3C,OAAO,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK;KACjD,CAAC,CAAC;IAEH,OAAO,IAAI,CAAC,IAAI,CAAC;AACnB,CAAC;AAED,mFAAmF;AACnF,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,EAAU,EAAE,YAAY,GAAG,KAAK;IACjE,MAAM,GAAG,GAAG;;4CAE8B,qBAAqB;;GAE9D,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAgC,GAAG,EAAE;YAC3D,EAAE;YACF,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK;SAC1C,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,iFAAiF;QACjF,gFAAgF;QAChF,0CAA0C;QAC1C,IAAI,GAAG,YAAY,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,gBAAgB,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QACnF,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,EAAU;IAChD,MAAM,GAAG,GAAG;;;;kDAIoC,mBAAmB;;;GAGlE,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAErB,GAAG,EAAE,EAAE,EAAE,EAAE,CAAC,CAAC;QAChB,OAAO,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,KAAK,IAAI,IAAI,CAAC;IAC7C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,gBAAgB,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QACnF,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,oCAAoC;AACpC,MAAM,CAAC,KAAK,UAAU,iBAAiB,CAAC,MAMvC;IACC,MAAM,GAAG,GAAG;;;;;;;;;;YAUF,mBAAmB;;;;;GAK5B,CAAC;IAEF,MAAM,IAAI,GAAG,MAAM,KAAK,CAQrB,GAAG,EAAE;QACN,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,UAAU,EAAE,MAAM,CAAC,UAAU;QAC7B,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC;QACtB,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE,EAAE,CAAC;QAC3C,OAAO,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK;KACjD,CAAC,CAAC;IAEH,OAAO,IAAI,CAAC,IAAI,CAAC;AACnB,CAAC;AAED,yDAAyD;AACzD,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,MAIzC;IACC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;IAC1C,MAAM,GAAG,GAAG,GAAG,GAAG,CAAC,MAAM,CAAC,SAAS,IAAI,CAAC,CAAC,GAAG,MAAM,CAAC;IAEnD,MAAM,GAAG,GAAG;;;;;oBAKM,mBAAmB;;;;GAIpC,CAAC;IAEF,MAAM,IAAI,GAAG,MAAM,KAAK,CAAkD,GAAG,EAAE;QAC7E,WAAW,EAAE,GAAG;QAChB,QAAQ,EAAE,GAAG;QACb,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC;QACtB,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE,EAAE,CAAC;KAC5C,CAAC,CAAC;IAEH,OAAO,IAAI,CAAC,IAAI,CAAC,eAAe,CAAC;AACnC,CAAC;AAED,uCAAuC;AACvC,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAKxC;IACC,MAAM,GAAG,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;GAyBX,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAOrB,GAAG,EAAE;YACN,EAAE,EAAE,MAAM,CAAC,OAAO;YAClB,QAAQ,EAAE,MAAM,CAAC,QAAQ,IAAI,SAAS;YACtC,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC;YACtB,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE,EAAE,CAAC;SAC5C,CAAC,CAAC;QAEH,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;QAE/D,OAAO;YACL,UAAU,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,KAAK;YACvC,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,QAAQ,CAAC,WAAW;SACxD,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,gBAAgB,CAAC,QAAQ;YACnE,OAAO,EAAE,UAAU,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;QAChD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,sCAAsC;AACtC,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY;IAChD,MAAM,GAAG,GAAG;;;;;;;;;;oBAUM,mBAAmB;;;;;;;;;;GAUpC,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAA2C,GAAG,EAAE;YACtE,MAAM,EAAE,IAAI;YACZ,IAAI,EAAE,CAAC;YACP,OAAO,EAAE,EAAE;SACZ,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC;IACxB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,gBAAgB,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QACnF,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,gDAAgD;AAChD,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,IAAY,EACZ,IAAI,GAAG,CAAC,EACR,OAAO,GAAG,EAAE;IAEZ,MAAM,GAAG,GAAG;;;;;;;;;;;;;qBAaO,mBAAmB;;;;;;GAMrC,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAmC,GAAG,EAAE;YAC9D,MAAM,EAAE,IAAI;YACZ,IAAI;YACJ,OAAO;SACR,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,gBAAgB,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QACnF,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,6CAA6C;AAC7C,MAAM,CAAC,KAAK,UAAU,kBAAkB,CAAC,MAIxC;IACC,MAAM,GAAG,GAAG;;;;;;;;oCAQsB,mBAAmB;;;;;GAKpD,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAQrB,GAAG,EAAE;YACN,EAAE,EAAE,MAAM,CAAC,OAAO;YAClB,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC;YACtB,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE,EAAE,CAAC;SAC5C,CAAC,CAAC;QAEH,IAAI,CAAC,IAAI,CAAC,KAAK;YAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;QAE1D,OAAO;YACL,KAAK,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,KAAK;YACvC,WAAW,EAAE,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,QAAQ,CAAC,WAAW;SAC7D,CAAC;IACJ,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,gBAAgB,CAAC,QAAQ;YACnE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,CAAC;QAC3C,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,wDAAwD;AACxD,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAUjC;IACC,IAAI,IAAc,CAAC;IACnB,IAAI,MAAM,GAAuB,MAAM,CAAC,MAAM,CAAC;IAC/C,IAAI,UAAU,GAAuB,MAAM,CAAC,UAAU,CAAC;IAEvD,QAAQ,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,KAAK,KAAK;YACR,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;YACtB,MAAM;QACR,KAAK,UAAU;YACb,IAAI,GAAG,CAAC,eAAe,CAAC,CAAC;YACzB,MAAM;QACR,KAAK,UAAU;YACb,IAAI,GAAG,CAAC,iBAAiB,CAAC,CAAC;YAC3B,6CAA6C;YAC7C,IAAI,CAAC,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;gBAC3B,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC;gBACvB,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,CAAC;gBACjC,UAAU,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC;gBAC/B,IAAI,KAAK,IAAI,CAAC;oBAAE,MAAM,GAAG,QAAQ,CAAC;qBAC7B,IAAI,KAAK,IAAI,CAAC;oBAAE,MAAM,GAAG,QAAQ,CAAC;qBAClC,IAAI,KAAK,IAAI,CAAC;oBAAE,MAAM,GAAG,QAAQ,CAAC;;oBAClC,MAAM,GAAG,MAAM,CAAC;YACvB,CAAC;YACD,MAAM;IACV,CAAC;IAED,MAAM,GAAG,GAAG;;;;;;;;;;cAUA,mBAAmB;;;GAG9B,CAAC;IAEF,MAAM,IAAI,GAAG,MAAM,KAAK,CAAsB,GAAG,EAAE;QACjD,IAAI,EAAE,MAAM,CAAC,SAAS;QACtB,IAAI;QACJ,MAAM,EAAE,MAAM,CAAC,MAAM,IAAI,SAAS;QAClC,KAAK,EAAE,MAAM,CAAC,KAAK,IAAI,SAAS;QAChC,MAAM,EAAE,MAAM,IAAI,SAAS;QAC3B,UAAU,EAAE,UAAU,IAAI,SAAS;QACnC,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC;QACtB,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE,EAAE,CAAC;QAC3C,OAAO,EAAE,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK;KACjD,CAAC,CAAC;IAEH,OAAO,IAAI,CAAC,IAAI,CAAC;AACnB,CAAC;AAED,oEAAoE;AACpE,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,MAKlC;IACC,MAAM,GAAG,GAAG;;;;;;oBAMM,mBAAmB;;;;GAIpC,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAkC,GAAG,EAAE;YAC7D,MAAM,EAAE,MAAM,CAAC,IAAI;YACnB,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC;YAC5D,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC;YACtB,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE,EAAE,CAAC;SAC5C,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,gBAAgB,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QACnF,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,gCAAgC;AAChC,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,MAKnC;IACC,MAAM,GAAG,GAAG;;;;;;oBAMM,mBAAmB;;;;GAIpC,CAAC;IAEF,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,KAAK,CAAkC,GAAG,EAAE;YAC7D,EAAE,EAAE,MAAM,CAAC,EAAE;YACb,SAAS,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,iBAAiB,CAAC;YAC5D,IAAI,EAAE,MAAM,CAAC,IAAI,IAAI,CAAC;YACtB,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,OAAO,IAAI,EAAE,EAAE,EAAE,CAAC;SAC5C,CAAC,CAAC;QACH,OAAO,IAAI,CAAC,MAAM,CAAC;IACrB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,QAAQ,IAAI,GAAG,CAAC,IAAI,KAAK,gBAAgB,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC;QACnF,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC"}