@ashdev/codex-plugin-sync-anilist 1.18.0 → 1.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -71,6 +71,122 @@ var ApiError = class extends PluginError {
71
71
  }
72
72
  };
73
73
 
74
+ // node_modules/@ashdev/codex-plugin-sdk/dist/request-context.js
75
+ import { AsyncLocalStorage } from "node:async_hooks";
76
+ var store = new AsyncLocalStorage();
77
+ function runWithParentRequestId(forwardRequestId, fn) {
78
+ return store.run(forwardRequestId, fn);
79
+ }
80
+ function currentParentRequestId() {
81
+ return store.getStore();
82
+ }
83
+
84
+ // node_modules/@ashdev/codex-plugin-sdk/dist/host-rpc.js
85
+ var HostRpcError = class extends Error {
86
+ code;
87
+ data;
88
+ constructor(message, code, data) {
89
+ super(message);
90
+ this.code = code;
91
+ this.data = data;
92
+ this.name = "HostRpcError";
93
+ }
94
+ };
95
+ var HostRpcClient = class {
96
+ // Start the counter high so it can't collide with PluginStorage's id space.
97
+ // `Number.MAX_SAFE_INTEGER` is far above this, so we have plenty of room
98
+ // before wrapping (and we never expect a single plugin lifetime to issue
99
+ // more than ~9 quintillion calls).
100
+ nextId = 1e9;
101
+ pendingRequests = /* @__PURE__ */ new Map();
102
+ writeFn;
103
+ /**
104
+ * @param writeFn - Optional custom write function (defaults to
105
+ * `process.stdout.write`). Useful for testing.
106
+ */
107
+ constructor(writeFn) {
108
+ this.writeFn = writeFn ?? ((line) => {
109
+ process.stdout.write(line);
110
+ });
111
+ }
112
+ /**
113
+ * Send a JSON-RPC request to the host and resolve with the result.
114
+ *
115
+ * @param method - JSON-RPC method name (e.g. `"releases/list_tracked"`).
116
+ * @param params - Method-specific params. Pass `undefined` when the method
117
+ * takes no params.
118
+ */
119
+ async call(method, params) {
120
+ const id = this.nextId++;
121
+ const parent = currentParentRequestId();
122
+ const request = {
123
+ jsonrpc: "2.0",
124
+ id,
125
+ method,
126
+ params,
127
+ ...parent !== void 0 ? { parentRequestId: parent } : {}
128
+ };
129
+ return new Promise((resolve, reject) => {
130
+ this.pendingRequests.set(id, {
131
+ resolve: (v) => resolve(v),
132
+ reject
133
+ });
134
+ try {
135
+ this.writeFn(`${JSON.stringify(request)}
136
+ `);
137
+ } catch (err) {
138
+ this.pendingRequests.delete(id);
139
+ const message = err instanceof Error ? err.message : "Unknown write error";
140
+ reject(new HostRpcError(`Failed to send request: ${message}`, -1));
141
+ }
142
+ });
143
+ }
144
+ /**
145
+ * Process an incoming JSON-RPC response line. Returns `true` if this
146
+ * client owned the response id and resolved it, `false` otherwise (so
147
+ * other clients can try).
148
+ *
149
+ * Called by the plugin server's main loop on every response.
150
+ */
151
+ handleResponse(line) {
152
+ const trimmed = line.trim();
153
+ if (!trimmed)
154
+ return false;
155
+ let parsed;
156
+ try {
157
+ parsed = JSON.parse(trimmed);
158
+ } catch {
159
+ return false;
160
+ }
161
+ const obj = parsed;
162
+ if (obj.method !== void 0)
163
+ return false;
164
+ const rawId = obj.id;
165
+ if (typeof rawId !== "number")
166
+ return false;
167
+ if (!this.pendingRequests.has(rawId))
168
+ return false;
169
+ const pending = this.pendingRequests.get(rawId);
170
+ if (!pending)
171
+ return false;
172
+ this.pendingRequests.delete(rawId);
173
+ if ("error" in obj && obj.error) {
174
+ const err = obj.error;
175
+ pending.reject(new HostRpcError(err.message, err.code, err.data));
176
+ } else {
177
+ pending.resolve(obj.result);
178
+ }
179
+ return true;
180
+ }
181
+ /** Reject all pending requests (e.g. on shutdown). */
182
+ cancelAll() {
183
+ for (const [, pending] of this.pendingRequests) {
184
+ pending.reject(new HostRpcError("Host RPC client stopped", -1));
185
+ }
186
+ this.pendingRequests.clear();
187
+ }
188
+ };
189
+
74
190
  // node_modules/@ashdev/codex-plugin-sdk/dist/logger.js
75
191
  var LOG_LEVELS = {
76
192
  debug: 0,
@@ -288,17 +404,19 @@ function createPluginServer(options) {
288
404
  const logger2 = createLogger({ name: manifest2.name, level: logLevel });
289
405
  const prefix = label ? `${label} plugin` : "plugin";
290
406
  const storage = new PluginStorage();
407
+ const hostRpc = new HostRpcClient();
291
408
  logger2.info(`Starting ${prefix}: ${manifest2.displayName} v${manifest2.version}`);
292
409
  const rl = createInterface({
293
410
  input: process.stdin,
294
411
  terminal: false
295
412
  });
296
413
  rl.on("line", (line) => {
297
- void handleLine(line, manifest2, onInitialize, router, logger2, storage);
414
+ void handleLine(line, manifest2, onInitialize, router, logger2, storage, hostRpc);
298
415
  });
299
416
  rl.on("close", () => {
300
417
  logger2.info("stdin closed, shutting down");
301
418
  storage.cancelAll();
419
+ hostRpc.cancelAll();
302
420
  process.exit(0);
303
421
  });
304
422
  process.on("uncaughtException", (error) => {
@@ -316,7 +434,7 @@ function isJsonRpcResponse(obj) {
316
434
  return false;
317
435
  return "result" in obj || "error" in obj;
318
436
  }
319
- async function handleLine(line, manifest2, onInitialize, router, logger2, storage) {
437
+ async function handleLine(line, manifest2, onInitialize, router, logger2, storage, hostRpc) {
320
438
  const trimmed = line.trim();
321
439
  if (!trimmed)
322
440
  return;
@@ -326,8 +444,10 @@ async function handleLine(line, manifest2, onInitialize, router, logger2, storag
326
444
  } catch {
327
445
  }
328
446
  if (parsed && isJsonRpcResponse(parsed)) {
329
- logger2.debug("Routing storage response", { id: parsed.id });
330
- storage.handleResponse(trimmed);
447
+ logger2.debug("Routing reverse-RPC response", { id: parsed.id });
448
+ if (!hostRpc.handleResponse(trimmed)) {
449
+ storage.handleResponse(trimmed);
450
+ }
331
451
  return;
332
452
  }
333
453
  let id = null;
@@ -335,7 +455,7 @@ async function handleLine(line, manifest2, onInitialize, router, logger2, storag
335
455
  const request = parsed ?? JSON.parse(trimmed);
336
456
  id = request.id;
337
457
  logger2.debug(`Received request: ${request.method}`, { id: request.id });
338
- const response = await handleRequest(request, manifest2, onInitialize, router, logger2, storage);
458
+ const response = await runWithParentRequestId(request.id, () => handleRequest(request, manifest2, onInitialize, router, logger2, storage, hostRpc));
339
459
  if (response !== null) {
340
460
  writeResponse(response);
341
461
  }
@@ -369,12 +489,13 @@ async function handleLine(line, manifest2, onInitialize, router, logger2, storag
369
489
  }
370
490
  }
371
491
  }
372
- async function handleRequest(request, manifest2, onInitialize, router, logger2, storage) {
492
+ async function handleRequest(request, manifest2, onInitialize, router, logger2, storage, hostRpc) {
373
493
  const { method, params, id } = request;
374
494
  switch (method) {
375
495
  case "initialize": {
376
496
  const initParams = params ?? {};
377
497
  initParams.storage = storage;
498
+ initParams.hostRpc = hostRpc;
378
499
  if (onInitialize) {
379
500
  await onInitialize(initParams);
380
501
  }
@@ -385,6 +506,7 @@ async function handleRequest(request, manifest2, onInitialize, router, logger2,
385
506
  case "shutdown": {
386
507
  logger2.info("Shutdown requested");
387
508
  storage.cancelAll();
509
+ hostRpc.cancelAll();
388
510
  const response2 = { jsonrpc: "2.0", id, result: null };
389
511
  process.stdout.write(`${JSON.stringify(response2)}
390
512
  `, () => {
@@ -742,7 +864,7 @@ function convertScoreFromAnilist(score, format) {
742
864
  // package.json
743
865
  var package_default = {
744
866
  name: "@ashdev/codex-plugin-sync-anilist",
745
- version: "1.18.0",
867
+ version: "1.19.0",
746
868
  description: "AniList reading progress sync plugin for Codex",
747
869
  main: "dist/index.js",
748
870
  bin: "dist/index.js",
@@ -782,7 +904,7 @@ var package_default = {
782
904
  node: ">=22.0.0"
783
905
  },
784
906
  dependencies: {
785
- "@ashdev/codex-plugin-sdk": "^1.18.0"
907
+ "@ashdev/codex-plugin-sdk": "^1.19.0"
786
908
  },
787
909
  devDependencies: {
788
910
  "@biomejs/biome": "^2.4.4",
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../node_modules/@ashdev/codex-plugin-sdk/src/types/rpc.ts", "../node_modules/@ashdev/codex-plugin-sdk/src/errors.ts", "../node_modules/@ashdev/codex-plugin-sdk/src/logger.ts", "../node_modules/@ashdev/codex-plugin-sdk/src/server.ts", "../node_modules/@ashdev/codex-plugin-sdk/src/storage.ts", "../src/anilist.ts", "../package.json", "../src/manifest.ts", "../src/index.ts"],
4
- "sourcesContent": [null, null, null, null, null, "/**\n * AniList GraphQL API client\n *\n * Provides typed access to AniList's GraphQL API for reading progress sync.\n * See: https://anilist.gitbook.io/anilist-apiv2-docs/\n */\n\nimport { ApiError, AuthError, RateLimitError } from \"@ashdev/codex-plugin-sdk\";\n\nconst ANILIST_API_URL = \"https://graphql.anilist.co\";\n\n// =============================================================================\n// GraphQL Queries\n// =============================================================================\n\nconst VIEWER_QUERY = `\n query {\n Viewer {\n id\n name\n avatar {\n large\n medium\n }\n siteUrl\n options {\n displayAdultContent\n }\n mediaListOptions {\n scoreFormat\n }\n }\n }\n`;\n\nconst MANGA_LIST_QUERY = `\n query ($userId: Int!, $page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n pageInfo {\n total\n currentPage\n lastPage\n hasNextPage\n }\n mediaList(userId: $userId, type: MANGA, sort: UPDATED_TIME_DESC) {\n id\n mediaId\n status\n score\n progress\n progressVolumes\n startedAt {\n year\n month\n day\n }\n completedAt {\n year\n month\n day\n }\n notes\n updatedAt\n media {\n id\n title {\n romaji\n english\n native\n }\n siteUrl\n }\n }\n }\n }\n`;\n\n/** Search for a manga by title to find its AniList ID */\nconst SEARCH_MANGA_QUERY = `\n query ($search: String!) {\n Media(search: $search, type: MANGA) {\n id\n title {\n romaji\n english\n }\n }\n }\n`;\n\nconst UPDATE_ENTRY_MUTATION = `\n mutation (\n $mediaId: Int!,\n $status: MediaListStatus,\n $score: Float,\n $progress: Int,\n $progressVolumes: Int,\n $startedAt: FuzzyDateInput,\n $completedAt: FuzzyDateInput,\n $notes: String,\n $private: Boolean,\n $hiddenFromStatusLists: Boolean\n ) {\n SaveMediaListEntry(\n mediaId: $mediaId,\n status: $status,\n score: $score,\n progress: $progress,\n progressVolumes: $progressVolumes,\n startedAt: $startedAt,\n completedAt: $completedAt,\n notes: $notes,\n private: $private,\n hiddenFromStatusLists: $hiddenFromStatusLists\n ) {\n id\n mediaId\n status\n score\n progress\n progressVolumes\n }\n }\n`;\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface AniListViewer {\n id: number;\n name: string;\n avatar: { large?: string; medium?: string };\n siteUrl: string;\n options: { displayAdultContent: boolean };\n mediaListOptions: { scoreFormat: string };\n}\n\nexport interface AniListSearchResult {\n id: number;\n title: { romaji?: string; english?: string };\n}\n\nexport interface AniListFuzzyDate {\n year?: number | null;\n month?: number | null;\n day?: number | null;\n}\n\nexport interface AniListMediaListEntry {\n id: number;\n mediaId: number;\n status: string;\n score: number;\n progress: number;\n progressVolumes: number;\n startedAt: AniListFuzzyDate;\n completedAt: AniListFuzzyDate;\n notes: string | null;\n updatedAt: number;\n media: {\n id: number;\n title: { romaji?: string; english?: string; native?: string };\n siteUrl: string;\n };\n}\n\nexport interface AniListPageInfo {\n total: number;\n currentPage: number;\n lastPage: number;\n hasNextPage: boolean;\n}\n\nexport interface AniListSaveResult {\n id: number;\n mediaId: number;\n status: string;\n score: number;\n progress: number;\n progressVolumes: number;\n}\n\n// =============================================================================\n// Client\n// =============================================================================\n\nexport class AniListClient {\n private accessToken: string;\n\n constructor(accessToken: string) {\n this.accessToken = accessToken;\n }\n\n /**\n * Execute a GraphQL query against the AniList API.\n * On rate limit (429), waits the requested duration and retries once.\n */\n private async query<T>(queryStr: string, variables?: Record<string, unknown>): Promise<T> {\n return this.executeQuery<T>(queryStr, variables, true);\n }\n\n private async executeQuery<T>(\n queryStr: string,\n variables: Record<string, unknown> | undefined,\n allowRetry: boolean,\n ): Promise<T> {\n let response: Response;\n try {\n response = await fetch(ANILIST_API_URL, {\n method: \"POST\",\n signal: AbortSignal.timeout(30_000),\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n Authorization: `Bearer ${this.accessToken}`,\n },\n body: JSON.stringify({ query: queryStr, variables }),\n });\n } catch (error) {\n if (error instanceof DOMException && error.name === \"TimeoutError\") {\n throw new ApiError(\"AniList API request timed out after 30 seconds\");\n }\n throw error;\n }\n\n if (response.status === 401) {\n throw new AuthError(\"AniList access token is invalid or expired\");\n }\n\n if (response.status === 429) {\n const retryAfter = response.headers.get(\"Retry-After\");\n const retrySeconds = retryAfter ? Number.parseInt(retryAfter, 10) : 60;\n const waitSeconds = Number.isNaN(retrySeconds) ? 60 : retrySeconds;\n\n if (allowRetry) {\n await new Promise((resolve) => setTimeout(resolve, waitSeconds * 1000));\n return this.executeQuery<T>(queryStr, variables, false);\n }\n\n throw new RateLimitError(waitSeconds, \"AniList rate limit exceeded\");\n }\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n throw new ApiError(\n `AniList API error: ${response.status} ${response.statusText}${body ? ` - ${body}` : \"\"}`,\n );\n }\n\n const json = (await response.json()) as { data?: T; errors?: Array<{ message: string }> };\n\n if (json.errors?.length) {\n const message = json.errors.map((e) => e.message).join(\"; \");\n throw new ApiError(`AniList GraphQL error: ${message}`);\n }\n\n if (!json.data) {\n throw new ApiError(\"AniList returned empty data\");\n }\n\n return json.data;\n }\n\n /**\n * Get the authenticated user's info\n */\n async getViewer(): Promise<AniListViewer> {\n const data = await this.query<{ Viewer: AniListViewer }>(VIEWER_QUERY);\n return data.Viewer;\n }\n\n /**\n * Get the user's manga list (paginated)\n */\n async getMangaList(\n userId: number,\n page = 1,\n perPage = 50,\n ): Promise<{ pageInfo: AniListPageInfo; entries: AniListMediaListEntry[] }> {\n const variables: Record<string, unknown> = { userId, page, perPage };\n\n const data = await this.query<{\n Page: {\n pageInfo: AniListPageInfo;\n mediaList: AniListMediaListEntry[];\n };\n }>(MANGA_LIST_QUERY, variables);\n\n return {\n pageInfo: data.Page.pageInfo,\n entries: data.Page.mediaList,\n };\n }\n\n /**\n * Update or create a manga list entry\n */\n async saveEntry(variables: {\n mediaId: number;\n status?: string;\n score?: number;\n progress?: number;\n progressVolumes?: number;\n startedAt?: AniListFuzzyDate;\n completedAt?: AniListFuzzyDate;\n notes?: string;\n private?: boolean;\n hiddenFromStatusLists?: boolean;\n }): Promise<AniListSaveResult> {\n const data = await this.query<{ SaveMediaListEntry: AniListSaveResult }>(\n UPDATE_ENTRY_MUTATION,\n variables,\n );\n return data.SaveMediaListEntry;\n }\n\n /**\n * Search for a manga by title and return its AniList ID.\n * Returns null if no result found or an error occurs.\n */\n async searchManga(title: string): Promise<AniListSearchResult | null> {\n try {\n const data = await this.query<{ Media: AniListSearchResult | null }>(SEARCH_MANGA_QUERY, {\n search: title,\n });\n return data.Media;\n } catch {\n return null;\n }\n }\n}\n\n// =============================================================================\n// Status Mapping\n// =============================================================================\n\n/**\n * Map AniList MediaListStatus to Codex SyncReadingStatus\n */\nexport function anilistStatusToSync(\n status: string,\n): \"reading\" | \"completed\" | \"on_hold\" | \"dropped\" | \"plan_to_read\" {\n switch (status) {\n case \"CURRENT\":\n case \"REPEATING\":\n return \"reading\";\n case \"COMPLETED\":\n return \"completed\";\n case \"PAUSED\":\n return \"on_hold\";\n case \"DROPPED\":\n return \"dropped\";\n case \"PLANNING\":\n return \"plan_to_read\";\n default:\n return \"reading\";\n }\n}\n\n/**\n * Map Codex SyncReadingStatus to AniList MediaListStatus\n */\nexport function syncStatusToAnilist(\n status: string,\n): \"CURRENT\" | \"COMPLETED\" | \"PAUSED\" | \"DROPPED\" | \"PLANNING\" {\n switch (status) {\n case \"reading\":\n return \"CURRENT\";\n case \"completed\":\n return \"COMPLETED\";\n case \"on_hold\":\n return \"PAUSED\";\n case \"dropped\":\n return \"DROPPED\";\n case \"plan_to_read\":\n return \"PLANNING\";\n default:\n return \"CURRENT\";\n }\n}\n\n/**\n * Convert AniList FuzzyDate to ISO 8601 string\n */\nexport function fuzzyDateToIso(date: AniListFuzzyDate | null | undefined): string | undefined {\n if (!date?.year) return undefined;\n const month = date.month ? String(date.month).padStart(2, \"0\") : \"01\";\n const day = date.day ? String(date.day).padStart(2, \"0\") : \"01\";\n return `${date.year}-${month}-${day}T00:00:00Z`;\n}\n\n/**\n * Convert ISO 8601 string to AniList FuzzyDate\n */\nexport function isoToFuzzyDate(iso: string | undefined): AniListFuzzyDate | undefined {\n if (!iso) return undefined;\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return undefined;\n return {\n year: d.getUTCFullYear(),\n month: d.getUTCMonth() + 1,\n day: d.getUTCDate(),\n };\n}\n\n// =============================================================================\n// Score Conversion\n// =============================================================================\n\n/**\n * Convert a score from Codex's 1-100 scale to AniList's format\n */\nexport function convertScoreToAnilist(score: number, format: string): number {\n switch (format) {\n case \"POINT_100\":\n return Math.round(score);\n case \"POINT_10_DECIMAL\":\n return score / 10;\n case \"POINT_10\":\n return Math.round(score / 10);\n case \"POINT_5\":\n return Math.round(score / 20);\n case \"POINT_3\":\n if (score >= 70) return 3;\n if (score >= 40) return 2;\n return 1;\n default:\n return Math.round(score / 10);\n }\n}\n\n/**\n * Convert a score from AniList's format to Codex's 1-100 scale\n */\nexport function convertScoreFromAnilist(score: number, format: string): number {\n switch (format) {\n case \"POINT_100\":\n return score;\n case \"POINT_10_DECIMAL\":\n return score * 10;\n case \"POINT_10\":\n return score * 10;\n case \"POINT_5\":\n return score * 20;\n case \"POINT_3\":\n return Math.round(score * 33.3);\n default:\n return score * 10;\n }\n}\n", "{\n \"name\": \"@ashdev/codex-plugin-sync-anilist\",\n \"version\": \"1.18.0\",\n \"description\": \"AniList reading progress sync plugin for Codex\",\n \"main\": \"dist/index.js\",\n \"bin\": \"dist/index.js\",\n \"type\": \"module\",\n \"files\": [\n \"dist\",\n \"README.md\"\n ],\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/AshDevFr/codex.git\",\n \"directory\": \"plugins/sync-anilist\"\n },\n \"scripts\": {\n \"build\": \"esbuild src/index.ts --bundle --platform=node --target=node22 --format=esm --outfile=dist/index.js --sourcemap --banner:js='#!/usr/bin/env node'\",\n \"dev\": \"npm run build -- --watch\",\n \"clean\": \"rm -rf dist\",\n \"start\": \"node dist/index.js\",\n \"lint\": \"biome check .\",\n \"lint:fix\": \"biome check --write .\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run --passWithNoTests\",\n \"test:watch\": \"vitest\",\n \"prepublishOnly\": \"npm run lint && npm run build\"\n },\n \"keywords\": [\n \"codex\",\n \"plugin\",\n \"anilist\",\n \"sync\",\n \"manga\",\n \"reading-progress\"\n ],\n \"author\": \"Codex\",\n \"license\": \"MIT\",\n \"engines\": {\n \"node\": \">=22.0.0\"\n },\n \"dependencies\": {\n \"@ashdev/codex-plugin-sdk\": \"^1.18.0\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.4.4\",\n \"@types/node\": \"^22.0.0\",\n \"esbuild\": \"^0.27.3\",\n \"typescript\": \"^5.9.3\",\n \"vitest\": \"^4.0.18\"\n }\n}\n", "import type { PluginManifest } from \"@ashdev/codex-plugin-sdk\";\nimport packageJson from \"../package.json\" with { type: \"json\" };\n\n/** Canonical external ID source for AniList (`api:<service>` convention) */\nconst EXTERNAL_ID_SOURCE_ANILIST = \"api:anilist\" as const;\n\nexport const manifest = {\n name: \"sync-anilist\",\n displayName: \"AniList Sync\",\n version: packageJson.version,\n description:\n \"Sync manga reading progress between Codex and AniList. Supports push/pull of reading status, chapters read, scores, and dates.\",\n author: \"Codex\",\n homepage: \"https://github.com/AshDevFr/codex\",\n protocolVersion: \"1.0\",\n capabilities: {\n userReadSync: true,\n externalIdSource: EXTERNAL_ID_SOURCE_ANILIST,\n },\n requiredCredentials: [\n {\n key: \"access_token\",\n label: \"AniList Access Token\",\n description: \"OAuth access token for AniList API\",\n type: \"password\" as const,\n required: true,\n sensitive: true,\n },\n ],\n userConfigSchema: {\n description: \"AniList-specific sync settings\",\n fields: [\n {\n key: \"progressUnit\",\n label: \"Progress Unit\",\n description:\n \"What each book in Codex represents in AniList. Use 'volumes' for manga volumes, 'chapters' for individual chapters\",\n type: \"string\" as const,\n required: false,\n default: \"volumes\",\n },\n {\n key: \"pauseAfterDays\",\n label: \"Auto-Pause After Days\",\n description:\n \"Automatically set in-progress series to Paused on AniList if no reading activity in this many days. Set to 0 to disable.\",\n type: \"number\" as const,\n required: false,\n default: 0,\n },\n {\n key: \"dropAfterDays\",\n label: \"Auto-Drop After Days\",\n description:\n \"Automatically set in-progress series to Dropped on AniList if no reading activity in this many days. Set to 0 to disable. When both pause and drop are set, the shorter threshold fires first.\",\n type: \"number\" as const,\n required: false,\n default: 0,\n },\n {\n key: \"searchFallback\",\n label: \"Search Fallback\",\n description:\n \"When a series has no AniList ID, search by title to find a match and sync progress. Disable for strict matching only.\",\n type: \"boolean\" as const,\n required: false,\n default: false,\n },\n {\n key: \"private\",\n label: \"Private Mode\",\n description:\n \"When enabled, all manga list entries synced from Codex will be marked as private on AniList, visible only to you. When disabled, entries follow AniList's default visibility (public).\",\n type: \"boolean\" as const,\n required: false,\n default: true,\n },\n {\n key: \"hiddenFromStatusLists\",\n label: \"Hide from Status Lists\",\n description:\n \"When enabled, synced entries will be hidden from your standard AniList status lists (Currently Reading, Completed, etc.) but will still appear in custom lists. Has no effect when Private Mode is enabled.\",\n type: \"boolean\" as const,\n required: false,\n default: false,\n },\n ],\n },\n oauth: {\n authorizationUrl: \"https://anilist.co/api/v2/oauth/authorize\",\n tokenUrl: \"https://anilist.co/api/v2/oauth/token\",\n scopes: [],\n pkce: false,\n },\n userDescription: \"Sync manga reading progress between Codex and AniList\",\n adminSetupInstructions:\n \"To enable OAuth login, create an AniList API client at https://anilist.co/settings/developer. Set the redirect URL to {your-codex-url}/api/v1/user/plugins/oauth/callback. Enter the Client ID below. Without OAuth configured, users can still connect by pasting a personal access token.\",\n userSetupInstructions:\n \"Connect your AniList account via OAuth, or paste a personal access token. To generate a token, visit https://anilist.co/settings/developer, create a client with redirect URL https://anilist.co/api/v2/oauth/pin, then authorize it to receive your token.\",\n} as const satisfies PluginManifest & {\n capabilities: { userReadSync: true };\n};\n", "/**\n * AniList Sync Plugin for Codex\n *\n * Syncs manga reading progress between Codex and AniList.\n * Communicates via JSON-RPC over stdio using the Codex plugin SDK.\n *\n * Capabilities:\n * - Push reading progress from Codex to AniList\n * - Pull reading progress from AniList to Codex\n * - Get user info from AniList\n * - Status reporting for sync state\n */\n\nimport {\n createLogger,\n createSyncPlugin,\n type ExternalUserInfo,\n type InitializeParams,\n type SyncEntry,\n type SyncEntryResult,\n type SyncProvider,\n type SyncPullRequest,\n type SyncPullResponse,\n type SyncPushRequest,\n type SyncPushResponse,\n type SyncStatusResponse,\n} from \"@ashdev/codex-plugin-sdk\";\nimport {\n AniListClient,\n type AniListFuzzyDate,\n anilistStatusToSync,\n convertScoreFromAnilist,\n convertScoreToAnilist,\n fuzzyDateToIso,\n isoToFuzzyDate,\n syncStatusToAnilist,\n} from \"./anilist.js\";\nimport { manifest } from \"./manifest.js\";\n\nconst logger = createLogger({ name: \"sync-anilist\", level: \"debug\" });\n\n// Plugin state (set during initialization)\nlet client: AniListClient | null = null;\nlet viewerId: number | null = null;\nlet scoreFormat = \"POINT_10\";\n\n// Plugin-specific config (from userConfig, set during initialization)\nlet progressUnit: \"volumes\" | \"chapters\" = \"volumes\";\nlet pauseAfterDays = 0;\nlet dropAfterDays = 0;\nlet searchFallback = false;\nlet privateMode = true;\nlet hiddenFromStatusLists = false;\n\n/** Set the AniList client (exported for testing) */\nexport function setClient(c: AniListClient | null): void {\n client = c;\n}\n\n/** Set the viewer ID (exported for testing) */\nexport function setViewerId(id: number | null): void {\n viewerId = id;\n}\n\n/** Set the searchFallback flag (exported for testing) */\nexport function setSearchFallback(enabled: boolean): void {\n searchFallback = enabled;\n}\n\n/** Set the privateMode flag (exported for testing) */\nexport function setPrivateMode(enabled: boolean): void {\n privateMode = enabled;\n}\n\n/** Set the hiddenFromStatusLists flag (exported for testing) */\nexport function setHiddenFromStatusLists(enabled: boolean): void {\n hiddenFromStatusLists = enabled;\n}\n\n// =============================================================================\n// Staleness Logic\n// =============================================================================\n\n/**\n * Apply auto-pause/auto-drop for stale in-progress entries.\n *\n * Only applies to \"reading\" entries. Drop takes priority over pause\n * when both thresholds are met. A threshold of 0 means disabled.\n */\nexport function applyStaleness(\n status: SyncEntry[\"status\"],\n latestUpdatedAt: string | undefined,\n pauseDays: number,\n dropDays: number,\n now?: number,\n): SyncEntry[\"status\"] {\n if (status !== \"reading\") return status;\n if (pauseDays === 0 && dropDays === 0) return status;\n if (!latestUpdatedAt) return status;\n\n const lastActivity = new Date(latestUpdatedAt).getTime();\n if (Number.isNaN(lastActivity)) return status;\n\n const currentTime = now ?? Date.now();\n const daysInactive = Math.max(0, (currentTime - lastActivity) / (1000 * 60 * 60 * 24));\n\n // Drop takes priority (stronger action)\n if (dropDays > 0 && daysInactive >= dropDays) {\n return \"dropped\";\n }\n if (pauseDays > 0 && daysInactive >= pauseDays) {\n return \"on_hold\";\n }\n\n return status;\n}\n\n// =============================================================================\n// Sync Provider Implementation\n// =============================================================================\n\n/** Exported for testing */\nexport const provider: SyncProvider = {\n async getUserInfo(): Promise<ExternalUserInfo> {\n if (!client) {\n throw new Error(\"Plugin not initialized - no AniList client\");\n }\n\n const viewer = await client.getViewer();\n viewerId = viewer.id;\n scoreFormat = viewer.mediaListOptions.scoreFormat;\n\n logger.info(`Authenticated as ${viewer.name} (id: ${viewer.id}, scoreFormat: ${scoreFormat})`);\n\n return {\n externalId: String(viewer.id),\n username: viewer.name,\n avatarUrl: viewer.avatar.large || viewer.avatar.medium,\n profileUrl: viewer.siteUrl,\n };\n },\n\n async pushProgress(params: SyncPushRequest): Promise<SyncPushResponse> {\n if (!client || viewerId === null) {\n throw new Error(\"Plugin not initialized - call getUserInfo first\");\n }\n\n // Pre-fetch existing media IDs to distinguish \"created\" vs \"updated\"\n const existingMediaIds = new Set<number>();\n let page = 1;\n let hasMore = true;\n while (hasMore) {\n const result = await client.getMangaList(viewerId, page, 50);\n for (const entry of result.entries) {\n existingMediaIds.add(entry.mediaId);\n }\n hasMore = result.pageInfo.hasNextPage;\n page++;\n }\n\n const success: SyncEntryResult[] = [];\n const failed: SyncEntryResult[] = [];\n\n for (const entry of params.entries) {\n try {\n let mediaId = Number.parseInt(entry.externalId, 10);\n if (Number.isNaN(mediaId)) {\n // Try search fallback if enabled and entry has a title\n if (searchFallback && entry.title) {\n const result = await client.searchManga(entry.title);\n if (result) {\n mediaId = result.id;\n logger.info(`Search fallback resolved \"${entry.title}\" \u2192 AniList ID ${mediaId}`);\n }\n }\n\n if (Number.isNaN(mediaId)) {\n failed.push({\n externalId: entry.externalId,\n status: \"failed\",\n error: searchFallback\n ? `No AniList match found for \"${entry.title || entry.externalId}\"`\n : `Invalid media ID: ${entry.externalId}`,\n });\n continue;\n }\n }\n\n // Apply staleness logic: auto-pause or auto-drop stale in-progress entries\n const effectiveStatus = applyStaleness(\n entry.status,\n entry.latestUpdatedAt,\n pauseAfterDays,\n dropAfterDays,\n );\n if (effectiveStatus !== entry.status) {\n logger.debug(\n `Entry ${entry.externalId}: auto-${effectiveStatus === \"dropped\" ? \"dropped\" : \"paused\"} (was ${entry.status})`,\n );\n }\n\n const saveParams: {\n mediaId: number;\n status?: string;\n score?: number;\n progress?: number;\n progressVolumes?: number;\n startedAt?: AniListFuzzyDate;\n completedAt?: AniListFuzzyDate;\n notes?: string;\n private?: boolean;\n hiddenFromStatusLists?: boolean;\n } = {\n mediaId,\n status: syncStatusToAnilist(effectiveStatus),\n private: privateMode,\n hiddenFromStatusLists,\n };\n\n // Map progress using the configured progressUnit.\n // Server always sends books-read as `volumes`. Based on\n // progressUnit, we map to AniList's `progress` (chapters)\n // or `progressVolumes` (volumes) field.\n const count = entry.progress?.volumes ?? entry.progress?.chapters;\n if (count !== undefined) {\n if (progressUnit === \"chapters\") {\n saveParams.progress = count;\n } else {\n saveParams.progressVolumes = count;\n }\n }\n\n // Map score (convert from 1-100 scale to AniList format)\n if (entry.score !== undefined) {\n saveParams.score = convertScoreToAnilist(entry.score, scoreFormat);\n }\n\n // Map dates\n if (entry.startedAt) {\n saveParams.startedAt = isoToFuzzyDate(entry.startedAt);\n }\n if (entry.completedAt) {\n saveParams.completedAt = isoToFuzzyDate(entry.completedAt);\n }\n\n // Map notes\n if (entry.notes !== undefined) {\n saveParams.notes = entry.notes;\n }\n\n const resolvedExternalId = String(mediaId);\n const existed = existingMediaIds.has(mediaId);\n const result = await client.saveEntry(saveParams);\n logger.debug(`Pushed entry ${resolvedExternalId}: status=${result.status}`);\n\n // Track newly created entries for subsequent pushes in the same batch\n existingMediaIds.add(mediaId);\n\n success.push({\n externalId: resolvedExternalId,\n status: existed ? \"updated\" : \"created\",\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Unknown error\";\n logger.error(`Failed to push entry ${entry.externalId}: ${message}`);\n failed.push({\n externalId: entry.externalId,\n status: \"failed\",\n error: message,\n });\n }\n }\n\n return { success, failed };\n },\n\n async pullProgress(params: SyncPullRequest): Promise<SyncPullResponse> {\n if (!client || viewerId === null) {\n throw new Error(\"Plugin not initialized - call getUserInfo first\");\n }\n\n // Parse pagination cursor (page number)\n const page = params.cursor ? Number.parseInt(params.cursor, 10) : 1;\n const perPage = params.limit ? Math.min(params.limit, 50) : 50;\n\n const result = await client.getMangaList(viewerId, page, perPage);\n\n const entries: SyncEntry[] = result.entries.map((entry) => ({\n externalId: String(entry.mediaId),\n status: anilistStatusToSync(entry.status),\n progress: {\n chapters: entry.progress || undefined,\n volumes: entry.progressVolumes || undefined,\n },\n score: entry.score > 0 ? convertScoreFromAnilist(entry.score, scoreFormat) : undefined,\n startedAt: fuzzyDateToIso(entry.startedAt),\n completedAt: fuzzyDateToIso(entry.completedAt),\n notes: entry.notes || undefined,\n }));\n\n logger.info(\n `Pulled ${entries.length} entries (page ${result.pageInfo.currentPage}/${result.pageInfo.lastPage})`,\n );\n\n return {\n entries,\n nextCursor: result.pageInfo.hasNextPage ? String(result.pageInfo.currentPage + 1) : undefined,\n hasMore: result.pageInfo.hasNextPage,\n };\n },\n\n async status(): Promise<SyncStatusResponse> {\n if (!client || viewerId === null) {\n return {\n pendingPush: 0,\n pendingPull: 0,\n conflicts: 0,\n };\n }\n\n // Get total count from AniList\n const result = await client.getMangaList(viewerId, 1, 1);\n\n return {\n externalCount: result.pageInfo.total,\n pendingPush: 0,\n pendingPull: 0,\n conflicts: 0,\n };\n },\n};\n\n// =============================================================================\n// Plugin Initialization\n// =============================================================================\n\ncreateSyncPlugin({\n manifest,\n provider,\n logLevel: \"debug\",\n onInitialize(params: InitializeParams) {\n // Get access token from credentials\n const accessToken = params.credentials?.access_token;\n if (accessToken) {\n client = new AniListClient(accessToken);\n logger.info(\"AniList client initialized with access token\");\n } else {\n logger.warn(\"No access token provided - sync operations will fail\");\n }\n\n // Read plugin-specific config from userConfig\n const uc = params.userConfig;\n if (uc) {\n const unit = uc.progressUnit;\n if (unit === \"chapters\" || unit === \"volumes\") {\n progressUnit = unit;\n }\n if (typeof uc.pauseAfterDays === \"number\" && uc.pauseAfterDays >= 0) {\n pauseAfterDays = uc.pauseAfterDays;\n }\n if (typeof uc.dropAfterDays === \"number\" && uc.dropAfterDays >= 0) {\n dropAfterDays = uc.dropAfterDays;\n }\n if (typeof uc.searchFallback === \"boolean\") {\n searchFallback = uc.searchFallback;\n }\n if (typeof uc.private === \"boolean\") {\n privateMode = uc.private;\n }\n if (typeof uc.hiddenFromStatusLists === \"boolean\") {\n hiddenFromStatusLists = uc.hiddenFromStatusLists;\n }\n logger.info(\n `Plugin config: progressUnit=${progressUnit}, pauseAfterDays=${pauseAfterDays}, dropAfterDays=${dropAfterDays}, searchFallback=${searchFallback}, private=${privateMode}, hiddenFromStatusLists=${hiddenFromStatusLists}`,\n );\n }\n },\n});\n\nlogger.info(\"AniList sync plugin started\");\n"],
5
- "mappings": ";;;AAkCO,IAAM,uBAAuB;;EAElC,aAAa;;EAEb,iBAAiB;;EAEjB,kBAAkB;;EAElB,gBAAgB;;EAEhB,gBAAgB;;AAMX,IAAM,qBAAqB;;EAEhC,cAAc;;EAEd,WAAW;;EAEX,aAAa;;EAEb,WAAW;;EAEX,cAAc;;;;ACnDV,IAAgB,cAAhB,cAAoC,MAAK;EAEpC;EAET,YAAY,SAAiB,MAAc;AACzC,UAAM,OAAO;AACb,SAAK,OAAO,KAAK,YAAY;AAC7B,SAAK,OAAO;EACd;;;;EAKA,iBAAc;AACZ,WAAO;MACL,MAAM,KAAK;MACX,SAAS,KAAK;MACd,MAAM,KAAK;;EAEf;;AAMI,IAAO,iBAAP,cAA8B,YAAW;EACpC,OAAO,mBAAmB;;EAE1B;EAET,YAAY,mBAA2B,SAAgB;AACrD,UAAM,WAAW,6BAA6B,iBAAiB,KAAK;MAClE;KACD;AACD,SAAK,oBAAoB;EAC3B;;AAaI,IAAO,YAAP,cAAyB,YAAW;EAC/B,OAAO,mBAAmB;EAEnC,YAAY,SAAgB;AAC1B,UAAM,WAAW,uBAAuB;EAC1C;;AAMI,IAAO,WAAP,cAAwB,YAAW;EAC9B,OAAO,mBAAmB;EAC1B;EAET,YAAY,SAAiB,YAAmB;AAC9C,UAAM,SAAS,eAAe,SAAY,EAAE,WAAU,IAAK,MAAS;AACpE,SAAK,aAAa;EACpB;;;;AClEF,IAAM,aAAuC;EAC3C,OAAO;EACP,MAAM;EACN,MAAM;EACN,OAAO;;AAeH,IAAO,SAAP,MAAa;EACA;EACA;EACA;EAEjB,YAAY,SAAsB;AAChC,SAAK,OAAO,QAAQ;AACpB,SAAK,WAAW,WAAW,QAAQ,SAAS,MAAM;AAClD,SAAK,aAAa,QAAQ,cAAc;EAC1C;EAEQ,UAAU,OAAe;AAC/B,WAAO,WAAW,KAAK,KAAK,KAAK;EACnC;EAEQ,OAAO,OAAiB,SAAiB,MAAc;AAC7D,UAAM,QAAkB,CAAA;AAExB,QAAI,KAAK,YAAY;AACnB,YAAM,MAAK,oBAAI,KAAI,GAAG,YAAW,CAAE;IACrC;AAEA,UAAM,KAAK,IAAI,MAAM,YAAW,CAAE,GAAG;AACrC,UAAM,KAAK,IAAI,KAAK,IAAI,GAAG;AAC3B,UAAM,KAAK,OAAO;AAElB,QAAI,SAAS,QAAW;AACtB,UAAI,gBAAgB,OAAO;AACzB,cAAM,KAAK,KAAK,KAAK,OAAO,EAAE;AAC9B,YAAI,KAAK,OAAO;AACd,gBAAM,KAAK;EAAK,KAAK,KAAK,EAAE;QAC9B;MACF,WAAW,OAAO,SAAS,UAAU;AACnC,cAAM,KAAK,KAAK,KAAK,UAAU,IAAI,CAAC,EAAE;MACxC,OAAO;AACL,cAAM,KAAK,KAAK,OAAO,IAAI,CAAC,EAAE;MAChC;IACF;AAEA,WAAO,MAAM,KAAK,GAAG;EACvB;EAEQ,IAAI,OAAiB,SAAiB,MAAc;AAC1D,QAAI,KAAK,UAAU,KAAK,GAAG;AAEzB,cAAQ,OAAO,MAAM,GAAG,KAAK,OAAO,OAAO,SAAS,IAAI,CAAC;CAAI;IAC/D;EACF;EAEA,MAAM,SAAiB,MAAc;AACnC,SAAK,IAAI,SAAS,SAAS,IAAI;EACjC;EAEA,KAAK,SAAiB,MAAc;AAClC,SAAK,IAAI,QAAQ,SAAS,IAAI;EAChC;EAEA,KAAK,SAAiB,MAAc;AAClC,SAAK,IAAI,QAAQ,SAAS,IAAI;EAChC;EAEA,MAAM,SAAiB,MAAc;AACnC,SAAK,IAAI,SAAS,SAAS,IAAI;EACjC;;AAMI,SAAU,aAAa,SAAsB;AACjD,SAAO,IAAI,OAAO,OAAO;AAC3B;;;ACvFA,SAAS,uBAAuB;;;AC8E1B,IAAO,eAAP,cAA4B,MAAK;EAGnB;EACA;EAHlB,YACE,SACgB,MACA,MAAc;AAE9B,UAAM,OAAO;AAHG,SAAA,OAAA;AACA,SAAA,OAAA;AAGhB,SAAK,OAAO;EACd;;AAiBI,IAAO,gBAAP,MAAoB;EAChB,SAAS;EACT,kBAAkB,oBAAI,IAAG;EAOzB;;;;;;;EAQR,YAAY,SAAiB;AAC3B,SAAK,UACH,YACC,CAAC,SAAgB;AAChB,cAAQ,OAAO,MAAM,IAAI;IAC3B;EACJ;;;;;;;EAQA,MAAM,IAAI,KAAW;AACnB,WAAQ,MAAM,KAAK,YAAY,eAAe,EAAE,IAAG,CAAE;EACvD;;;;;;;;;EAUA,MAAM,IAAI,KAAa,MAAe,WAAkB;AACtD,UAAM,SAAkC,EAAE,KAAK,KAAI;AACnD,QAAI,cAAc,QAAW;AAC3B,aAAO,YAAY;IACrB;AACA,WAAQ,MAAM,KAAK,YAAY,eAAe,MAAM;EACtD;;;;;;;EAQA,MAAM,OAAO,KAAW;AACtB,WAAQ,MAAM,KAAK,YAAY,kBAAkB,EAAE,IAAG,CAAE;EAC1D;;;;;;EAOA,MAAM,OAAI;AACR,WAAQ,MAAM,KAAK,YAAY,gBAAgB,CAAA,CAAE;EACnD;;;;;;EAOA,MAAM,QAAK;AACT,WAAQ,MAAM,KAAK,YAAY,iBAAiB,CAAA,CAAE;EACpD;;;;;;;EAQA,eAAe,MAAY;AACzB,UAAM,UAAU,KAAK,KAAI;AACzB,QAAI,CAAC;AAAS;AAEd,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,MAAM,OAAO;IAC7B,QAAQ;AAEN;IACF;AAEA,UAAM,MAAM;AAGZ,QAAI,IAAI,WAAW,QAAW;AAE5B;IACF;AAEA,UAAM,KAAK,IAAI;AACf,QAAI,OAAO,UAAa,OAAO;AAAM;AAErC,UAAM,UAAU,KAAK,gBAAgB,IAAI,EAAqB;AAC9D,QAAI,CAAC;AAAS;AAEd,SAAK,gBAAgB,OAAO,EAAqB;AAEjD,QAAI,WAAW,OAAO,IAAI,OAAO;AAC/B,YAAM,MAAM,IAAI;AAChB,cAAQ,OAAO,IAAI,aAAa,IAAI,SAAS,IAAI,MAAM,IAAI,IAAI,CAAC;IAClE,OAAO;AACL,cAAQ,QAAQ,IAAI,MAAM;IAC5B;EACF;;;;EAKA,YAAS;AACP,eAAW,CAAC,EAAE,OAAO,KAAK,KAAK,iBAAiB;AAC9C,cAAQ,OAAO,IAAI,aAAa,0BAA0B,EAAE,CAAC;IAC/D;AACA,SAAK,gBAAgB,MAAK;EAC5B;;;;EAMQ,YAAY,QAAgB,QAAe;AACjD,UAAM,KAAK,KAAK;AAEhB,UAAM,UAA0B;MAC9B,SAAS;MACT;MACA;MACA;;AAGF,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAU;AACrC,WAAK,gBAAgB,IAAI,IAAI,EAAE,SAAS,OAAM,CAAE;AAEhD,UAAI;AACF,aAAK,QAAQ,GAAG,KAAK,UAAU,OAAO,CAAC;CAAI;MAC7C,SAAS,KAAK;AACZ,aAAK,gBAAgB,OAAO,EAAE;AAC9B,cAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,eAAO,IAAI,aAAa,2BAA2B,OAAO,IAAI,EAAE,CAAC;MACnE;IACF,CAAC;EACH;;;;AD9EF,SAAS,mBAAmB,SAA4B;AACtD,QAAM,EAAE,UAAAA,WAAU,cAAc,WAAW,QAAQ,OAAO,OAAM,IAAK;AACrE,QAAMC,UAAS,aAAa,EAAE,MAAMD,UAAS,MAAM,OAAO,SAAQ,CAAE;AACpE,QAAM,SAAS,QAAQ,GAAG,KAAK,YAAY;AAC3C,QAAM,UAAU,IAAI,cAAa;AAEjC,EAAAC,QAAO,KAAK,YAAY,MAAM,KAAKD,UAAS,WAAW,KAAKA,UAAS,OAAO,EAAE;AAE9E,QAAM,KAAK,gBAAgB;IACzB,OAAO,QAAQ;IACf,UAAU;GACX;AAED,KAAG,GAAG,QAAQ,CAAC,SAAQ;AACrB,SAAK,WAAW,MAAMA,WAAU,cAAc,QAAQC,SAAQ,OAAO;EACvE,CAAC;AAED,KAAG,GAAG,SAAS,MAAK;AAClB,IAAAA,QAAO,KAAK,6BAA6B;AACzC,YAAQ,UAAS;AACjB,YAAQ,KAAK,CAAC;EAChB,CAAC;AAED,UAAQ,GAAG,qBAAqB,CAAC,UAAS;AACxC,IAAAA,QAAO,MAAM,sBAAsB,KAAK;AACxC,YAAQ,KAAK,CAAC;EAChB,CAAC;AAED,UAAQ,GAAG,sBAAsB,CAAC,WAAU;AAC1C,IAAAA,QAAO,MAAM,uBAAuB,MAAM;EAC5C,CAAC;AACH;AAQA,SAAS,kBAAkB,KAA4B;AACrD,MAAI,IAAI,WAAW;AAAW,WAAO;AACrC,MAAI,IAAI,OAAO,UAAa,IAAI,OAAO;AAAM,WAAO;AACpD,SAAO,YAAY,OAAO,WAAW;AACvC;AAEA,eAAe,WACb,MACAD,WACA,cACA,QACAC,SACA,SAAsB;AAEtB,QAAM,UAAU,KAAK,KAAI;AACzB,MAAI,CAAC;AAAS;AAKd,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,OAAO;EAC7B,QAAQ;EAER;AAEA,MAAI,UAAU,kBAAkB,MAAM,GAAG;AACvC,IAAAA,QAAO,MAAM,4BAA4B,EAAE,IAAI,OAAO,GAAE,CAAE;AAC1D,YAAQ,eAAe,OAAO;AAC9B;EACF;AAEA,MAAI,KAA6B;AAEjC,MAAI;AACF,UAAM,UAAW,UAAU,KAAK,MAAM,OAAO;AAC7C,SAAK,QAAQ;AAEb,IAAAA,QAAO,MAAM,qBAAqB,QAAQ,MAAM,IAAI,EAAE,IAAI,QAAQ,GAAE,CAAE;AAEtE,UAAM,WAAW,MAAM,cAAc,SAASD,WAAU,cAAc,QAAQC,SAAQ,OAAO;AAC7F,QAAI,aAAa,MAAM;AACrB,oBAAc,QAAQ;IACxB;EACF,SAAS,OAAO;AACd,QAAI,iBAAiB,aAAa;AAChC,oBAAc;QACZ,SAAS;QACT,IAAI;QACJ,OAAO;UACL,MAAM,qBAAqB;UAC3B,SAAS;;OAEZ;IACH,WAAW,iBAAiB,aAAa;AACvC,oBAAc;QACZ,SAAS;QACT;QACA,OAAO,MAAM,eAAc;OAC5B;IACH,OAAO;AACL,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,MAAAA,QAAO,MAAM,kBAAkB,KAAK;AACpC,oBAAc;QACZ,SAAS;QACT;QACA,OAAO;UACL,MAAM,qBAAqB;UAC3B;;OAEH;IACH;EACF;AACF;AAEA,eAAe,cACb,SACAD,WACA,cACA,QACAC,SACA,SAAsB;AAEtB,QAAM,EAAE,QAAQ,QAAQ,GAAE,IAAK;AAG/B,UAAQ,QAAQ;IACd,KAAK,cAAc;AACjB,YAAM,aAAc,UAAU,CAAA;AAE9B,iBAAW,UAAU;AACrB,UAAI,cAAc;AAChB,cAAM,aAAa,UAAU;MAC/B;AACA,aAAO,EAAE,SAAS,OAAO,IAAI,QAAQD,UAAQ;IAC/C;IAEA,KAAK;AACH,aAAO,EAAE,SAAS,OAAO,IAAI,QAAQ,OAAM;IAE7C,KAAK,YAAY;AACf,MAAAC,QAAO,KAAK,oBAAoB;AAChC,cAAQ,UAAS;AACjB,YAAMC,YAA4B,EAAE,SAAS,OAAO,IAAI,QAAQ,KAAI;AACpE,cAAQ,OAAO,MAAM,GAAG,KAAK,UAAUA,SAAQ,CAAC;GAAM,MAAK;AACzD,gBAAQ,KAAK,CAAC;MAChB,CAAC;AAED,aAAO;IACT;EACF;AAGA,QAAM,WAAW,MAAM,OAAO,QAAQ,QAAQ,EAAE;AAChD,MAAI,aAAa,MAAM;AACrB,WAAO;EACT;AAGA,SAAO;IACL,SAAS;IACT;IACA,OAAO;MACL,MAAM,qBAAqB;MAC3B,SAAS,qBAAqB,MAAM;;;AAG1C;AAEA,SAAS,cAAc,UAAyB;AAC9C,UAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,QAAQ,CAAC;CAAI;AACtD;AAMA,SAAS,eAAe,IAA4B,SAAe;AACjE,SAAO;IACL,SAAS;IACT;IACA,OAAO;MACL,MAAM,qBAAqB;MAC3B;;;AAGN;AAEA,SAAS,QAAQ,IAA4B,QAAe;AAC1D,SAAO,EAAE,SAAS,OAAO,IAAI,OAAM;AACrC;AAsMM,SAAU,iBAAiB,SAA0B;AACzD,QAAM,EAAE,UAAAC,WAAU,UAAAC,WAAU,cAAc,SAAQ,IAAK;AAEvD,QAAM,SAAuB,OAAO,QAAQ,QAAQ,OAAM;AACxD,YAAQ,QAAQ;MACd,KAAK;AACH,eAAO,QAAQ,IAAI,MAAMA,UAAS,YAAW,CAAE;MACjD,KAAK;AACH,eAAO,QAAQ,IAAI,MAAMA,UAAS,aAAa,MAAyB,CAAC;MAC3E,KAAK;AACH,eAAO,QAAQ,IAAI,MAAMA,UAAS,aAAa,MAAyB,CAAC;MAC3E,KAAK,eAAe;AAClB,YAAI,CAACA,UAAS;AAAQ,iBAAO,eAAe,IAAI,0CAA0C;AAC1F,eAAO,QAAQ,IAAI,MAAMA,UAAS,OAAM,CAAE;MAC5C;MACA;AACE,eAAO;IACX;EACF;AAEA,qBAAmB,EAAE,UAAAD,WAAU,cAAc,UAAU,OAAO,QAAQ,OAAM,CAAE;AAChF;;;AEjlBA,IAAM,kBAAkB;AAMxB,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBrB,IAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2CzB,IAAM,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAY3B,IAAM,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiGvB,IAAM,gBAAN,MAAoB;AAAA,EACjB;AAAA,EAER,YAAY,aAAqB;AAC/B,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,MAAS,UAAkB,WAAiD;AACxF,WAAO,KAAK,aAAgB,UAAU,WAAW,IAAI;AAAA,EACvD;AAAA,EAEA,MAAc,aACZ,UACA,WACA,YACY;AACZ,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,MAAM,iBAAiB;AAAA,QACtC,QAAQ;AAAA,QACR,QAAQ,YAAY,QAAQ,GAAM;AAAA,QAClC,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,QAAQ;AAAA,UACR,eAAe,UAAU,KAAK,WAAW;AAAA,QAC3C;AAAA,QACA,MAAM,KAAK,UAAU,EAAE,OAAO,UAAU,UAAU,CAAC;AAAA,MACrD,CAAC;AAAA,IACH,SAAS,OAAO;AACd,UAAI,iBAAiB,gBAAgB,MAAM,SAAS,gBAAgB;AAClE,cAAM,IAAI,SAAS,gDAAgD;AAAA,MACrE;AACA,YAAM;AAAA,IACR;AAEA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,UAAU,4CAA4C;AAAA,IAClE;AAEA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,aAAa,SAAS,QAAQ,IAAI,aAAa;AACrD,YAAM,eAAe,aAAa,OAAO,SAAS,YAAY,EAAE,IAAI;AACpE,YAAM,cAAc,OAAO,MAAM,YAAY,IAAI,KAAK;AAEtD,UAAI,YAAY;AACd,cAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,cAAc,GAAI,CAAC;AACtE,eAAO,KAAK,aAAgB,UAAU,WAAW,KAAK;AAAA,MACxD;AAEA,YAAM,IAAI,eAAe,aAAa,6BAA6B;AAAA,IACrE;AAEA,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,OAAO,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,EAAE;AACjD,YAAM,IAAI;AAAA,QACR,sBAAsB,SAAS,MAAM,IAAI,SAAS,UAAU,GAAG,OAAO,MAAM,IAAI,KAAK,EAAE;AAAA,MACzF;AAAA,IACF;AAEA,UAAM,OAAQ,MAAM,SAAS,KAAK;AAElC,QAAI,KAAK,QAAQ,QAAQ;AACvB,YAAM,UAAU,KAAK,OAAO,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,IAAI;AAC3D,YAAM,IAAI,SAAS,0BAA0B,OAAO,EAAE;AAAA,IACxD;AAEA,QAAI,CAAC,KAAK,MAAM;AACd,YAAM,IAAI,SAAS,6BAA6B;AAAA,IAClD;AAEA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAoC;AACxC,UAAM,OAAO,MAAM,KAAK,MAAiC,YAAY;AACrE,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aACJ,QACA,OAAO,GACP,UAAU,IACgE;AAC1E,UAAM,YAAqC,EAAE,QAAQ,MAAM,QAAQ;AAEnE,UAAM,OAAO,MAAM,KAAK,MAKrB,kBAAkB,SAAS;AAE9B,WAAO;AAAA,MACL,UAAU,KAAK,KAAK;AAAA,MACpB,SAAS,KAAK,KAAK;AAAA,IACrB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAU,WAWe;AAC7B,UAAM,OAAO,MAAM,KAAK;AAAA,MACtB;AAAA,MACA;AAAA,IACF;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YAAY,OAAoD;AACpE,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,MAA6C,oBAAoB;AAAA,QACvF,QAAQ;AAAA,MACV,CAAC;AACD,aAAO,KAAK;AAAA,IACd,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;AASO,SAAS,oBACd,QACkE;AAClE,UAAQ,QAAQ;AAAA,IACd,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAKO,SAAS,oBACd,QAC6D;AAC7D,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAKO,SAAS,eAAe,MAA+D;AAC5F,MAAI,CAAC,MAAM,KAAM,QAAO;AACxB,QAAM,QAAQ,KAAK,QAAQ,OAAO,KAAK,KAAK,EAAE,SAAS,GAAG,GAAG,IAAI;AACjE,QAAM,MAAM,KAAK,MAAM,OAAO,KAAK,GAAG,EAAE,SAAS,GAAG,GAAG,IAAI;AAC3D,SAAO,GAAG,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG;AACrC;AAKO,SAAS,eAAe,KAAuD;AACpF,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,IAAI,IAAI,KAAK,GAAG;AACtB,MAAI,OAAO,MAAM,EAAE,QAAQ,CAAC,EAAG,QAAO;AACtC,SAAO;AAAA,IACL,MAAM,EAAE,eAAe;AAAA,IACvB,OAAO,EAAE,YAAY,IAAI;AAAA,IACzB,KAAK,EAAE,WAAW;AAAA,EACpB;AACF;AASO,SAAS,sBAAsB,OAAe,QAAwB;AAC3E,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO,KAAK,MAAM,KAAK;AAAA,IACzB,KAAK;AACH,aAAO,QAAQ;AAAA,IACjB,KAAK;AACH,aAAO,KAAK,MAAM,QAAQ,EAAE;AAAA,IAC9B,KAAK;AACH,aAAO,KAAK,MAAM,QAAQ,EAAE;AAAA,IAC9B,KAAK;AACH,UAAI,SAAS,GAAI,QAAO;AACxB,UAAI,SAAS,GAAI,QAAO;AACxB,aAAO;AAAA,IACT;AACE,aAAO,KAAK,MAAM,QAAQ,EAAE;AAAA,EAChC;AACF;AAKO,SAAS,wBAAwB,OAAe,QAAwB;AAC7E,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,QAAQ;AAAA,IACjB,KAAK;AACH,aAAO,QAAQ;AAAA,IACjB,KAAK;AACH,aAAO,QAAQ;AAAA,IACjB,KAAK;AACH,aAAO,KAAK,MAAM,QAAQ,IAAI;AAAA,IAChC;AACE,aAAO,QAAQ;AAAA,EACnB;AACF;;;AClcA;AAAA,EACE,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,aAAe;AAAA,EACf,MAAQ;AAAA,EACR,KAAO;AAAA,EACP,MAAQ;AAAA,EACR,OAAS;AAAA,IACP;AAAA,IACA;AAAA,EACF;AAAA,EACA,YAAc;AAAA,IACZ,MAAQ;AAAA,IACR,KAAO;AAAA,IACP,WAAa;AAAA,EACf;AAAA,EACA,SAAW;AAAA,IACT,OAAS;AAAA,IACT,KAAO;AAAA,IACP,OAAS;AAAA,IACT,OAAS;AAAA,IACT,MAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAa;AAAA,IACb,MAAQ;AAAA,IACR,cAAc;AAAA,IACd,gBAAkB;AAAA,EACpB;AAAA,EACA,UAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,QAAU;AAAA,EACV,SAAW;AAAA,EACX,SAAW;AAAA,IACT,MAAQ;AAAA,EACV;AAAA,EACA,cAAgB;AAAA,IACd,4BAA4B;AAAA,EAC9B;AAAA,EACA,iBAAmB;AAAA,IACjB,kBAAkB;AAAA,IAClB,eAAe;AAAA,IACf,SAAW;AAAA,IACX,YAAc;AAAA,IACd,QAAU;AAAA,EACZ;AACF;;;AC/CA,IAAM,6BAA6B;AAE5B,IAAM,WAAW;AAAA,EACtB,MAAM;AAAA,EACN,aAAa;AAAA,EACb,SAAS,gBAAY;AAAA,EACrB,aACE;AAAA,EACF,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,iBAAiB;AAAA,EACjB,cAAc;AAAA,IACZ,cAAc;AAAA,IACd,kBAAkB;AAAA,EACpB;AAAA,EACA,qBAAqB;AAAA,IACnB;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,aAAa;AAAA,MACb,MAAM;AAAA,MACN,UAAU;AAAA,MACV,WAAW;AAAA,IACb;AAAA,EACF;AAAA,EACA,kBAAkB;AAAA,IAChB,aAAa;AAAA,IACb,QAAQ;AAAA,MACN;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,aACE;AAAA,QACF,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS;AAAA,MACX;AAAA,MACA;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,aACE;AAAA,QACF,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS;AAAA,MACX;AAAA,MACA;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,aACE;AAAA,QACF,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS;AAAA,MACX;AAAA,MACA;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,aACE;AAAA,QACF,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS;AAAA,MACX;AAAA,MACA;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,aACE;AAAA,QACF,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS;AAAA,MACX;AAAA,MACA;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,aACE;AAAA,QACF,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACL,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,QAAQ,CAAC;AAAA,IACT,MAAM;AAAA,EACR;AAAA,EACA,iBAAiB;AAAA,EACjB,wBACE;AAAA,EACF,uBACE;AACJ;;;AC5DA,IAAM,SAAS,aAAa,EAAE,MAAM,gBAAgB,OAAO,QAAQ,CAAC;AAGpE,IAAI,SAA+B;AACnC,IAAI,WAA0B;AAC9B,IAAI,cAAc;AAGlB,IAAI,eAAuC;AAC3C,IAAI,iBAAiB;AACrB,IAAI,gBAAgB;AACpB,IAAI,iBAAiB;AACrB,IAAI,cAAc;AAClB,IAAI,wBAAwB;AAGrB,SAAS,UAAU,GAA+B;AACvD,WAAS;AACX;AAGO,SAAS,YAAY,IAAyB;AACnD,aAAW;AACb;AAGO,SAAS,kBAAkB,SAAwB;AACxD,mBAAiB;AACnB;AAGO,SAAS,eAAe,SAAwB;AACrD,gBAAc;AAChB;AAGO,SAAS,yBAAyB,SAAwB;AAC/D,0BAAwB;AAC1B;AAYO,SAAS,eACd,QACA,iBACA,WACA,UACA,KACqB;AACrB,MAAI,WAAW,UAAW,QAAO;AACjC,MAAI,cAAc,KAAK,aAAa,EAAG,QAAO;AAC9C,MAAI,CAAC,gBAAiB,QAAO;AAE7B,QAAM,eAAe,IAAI,KAAK,eAAe,EAAE,QAAQ;AACvD,MAAI,OAAO,MAAM,YAAY,EAAG,QAAO;AAEvC,QAAM,cAAc,OAAO,KAAK,IAAI;AACpC,QAAM,eAAe,KAAK,IAAI,IAAI,cAAc,iBAAiB,MAAO,KAAK,KAAK,GAAG;AAGrF,MAAI,WAAW,KAAK,gBAAgB,UAAU;AAC5C,WAAO;AAAA,EACT;AACA,MAAI,YAAY,KAAK,gBAAgB,WAAW;AAC9C,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAOO,IAAM,WAAyB;AAAA,EACpC,MAAM,cAAyC;AAC7C,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AAEA,UAAM,SAAS,MAAM,OAAO,UAAU;AACtC,eAAW,OAAO;AAClB,kBAAc,OAAO,iBAAiB;AAEtC,WAAO,KAAK,oBAAoB,OAAO,IAAI,SAAS,OAAO,EAAE,kBAAkB,WAAW,GAAG;AAE7F,WAAO;AAAA,MACL,YAAY,OAAO,OAAO,EAAE;AAAA,MAC5B,UAAU,OAAO;AAAA,MACjB,WAAW,OAAO,OAAO,SAAS,OAAO,OAAO;AAAA,MAChD,YAAY,OAAO;AAAA,IACrB;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,QAAoD;AACrE,QAAI,CAAC,UAAU,aAAa,MAAM;AAChC,YAAM,IAAI,MAAM,iDAAiD;AAAA,IACnE;AAGA,UAAM,mBAAmB,oBAAI,IAAY;AACzC,QAAI,OAAO;AACX,QAAI,UAAU;AACd,WAAO,SAAS;AACd,YAAM,SAAS,MAAM,OAAO,aAAa,UAAU,MAAM,EAAE;AAC3D,iBAAW,SAAS,OAAO,SAAS;AAClC,yBAAiB,IAAI,MAAM,OAAO;AAAA,MACpC;AACA,gBAAU,OAAO,SAAS;AAC1B;AAAA,IACF;AAEA,UAAME,WAA6B,CAAC;AACpC,UAAM,SAA4B,CAAC;AAEnC,eAAW,SAAS,OAAO,SAAS;AAClC,UAAI;AACF,YAAI,UAAU,OAAO,SAAS,MAAM,YAAY,EAAE;AAClD,YAAI,OAAO,MAAM,OAAO,GAAG;AAEzB,cAAI,kBAAkB,MAAM,OAAO;AACjC,kBAAMC,UAAS,MAAM,OAAO,YAAY,MAAM,KAAK;AACnD,gBAAIA,SAAQ;AACV,wBAAUA,QAAO;AACjB,qBAAO,KAAK,6BAA6B,MAAM,KAAK,uBAAkB,OAAO,EAAE;AAAA,YACjF;AAAA,UACF;AAEA,cAAI,OAAO,MAAM,OAAO,GAAG;AACzB,mBAAO,KAAK;AAAA,cACV,YAAY,MAAM;AAAA,cAClB,QAAQ;AAAA,cACR,OAAO,iBACH,+BAA+B,MAAM,SAAS,MAAM,UAAU,MAC9D,qBAAqB,MAAM,UAAU;AAAA,YAC3C,CAAC;AACD;AAAA,UACF;AAAA,QACF;AAGA,cAAM,kBAAkB;AAAA,UACtB,MAAM;AAAA,UACN,MAAM;AAAA,UACN;AAAA,UACA;AAAA,QACF;AACA,YAAI,oBAAoB,MAAM,QAAQ;AACpC,iBAAO;AAAA,YACL,SAAS,MAAM,UAAU,UAAU,oBAAoB,YAAY,YAAY,QAAQ,SAAS,MAAM,MAAM;AAAA,UAC9G;AAAA,QACF;AAEA,cAAM,aAWF;AAAA,UACF;AAAA,UACA,QAAQ,oBAAoB,eAAe;AAAA,UAC3C,SAAS;AAAA,UACT;AAAA,QACF;AAMA,cAAM,QAAQ,MAAM,UAAU,WAAW,MAAM,UAAU;AACzD,YAAI,UAAU,QAAW;AACvB,cAAI,iBAAiB,YAAY;AAC/B,uBAAW,WAAW;AAAA,UACxB,OAAO;AACL,uBAAW,kBAAkB;AAAA,UAC/B;AAAA,QACF;AAGA,YAAI,MAAM,UAAU,QAAW;AAC7B,qBAAW,QAAQ,sBAAsB,MAAM,OAAO,WAAW;AAAA,QACnE;AAGA,YAAI,MAAM,WAAW;AACnB,qBAAW,YAAY,eAAe,MAAM,SAAS;AAAA,QACvD;AACA,YAAI,MAAM,aAAa;AACrB,qBAAW,cAAc,eAAe,MAAM,WAAW;AAAA,QAC3D;AAGA,YAAI,MAAM,UAAU,QAAW;AAC7B,qBAAW,QAAQ,MAAM;AAAA,QAC3B;AAEA,cAAM,qBAAqB,OAAO,OAAO;AACzC,cAAM,UAAU,iBAAiB,IAAI,OAAO;AAC5C,cAAM,SAAS,MAAM,OAAO,UAAU,UAAU;AAChD,eAAO,MAAM,gBAAgB,kBAAkB,YAAY,OAAO,MAAM,EAAE;AAG1E,yBAAiB,IAAI,OAAO;AAE5B,QAAAD,SAAQ,KAAK;AAAA,UACX,YAAY;AAAA,UACZ,QAAQ,UAAU,YAAY;AAAA,QAChC,CAAC;AAAA,MACH,SAAS,OAAO;AACd,cAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,eAAO,MAAM,wBAAwB,MAAM,UAAU,KAAK,OAAO,EAAE;AACnE,eAAO,KAAK;AAAA,UACV,YAAY,MAAM;AAAA,UAClB,QAAQ;AAAA,UACR,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO,EAAE,SAAAA,UAAS,OAAO;AAAA,EAC3B;AAAA,EAEA,MAAM,aAAa,QAAoD;AACrE,QAAI,CAAC,UAAU,aAAa,MAAM;AAChC,YAAM,IAAI,MAAM,iDAAiD;AAAA,IACnE;AAGA,UAAM,OAAO,OAAO,SAAS,OAAO,SAAS,OAAO,QAAQ,EAAE,IAAI;AAClE,UAAM,UAAU,OAAO,QAAQ,KAAK,IAAI,OAAO,OAAO,EAAE,IAAI;AAE5D,UAAM,SAAS,MAAM,OAAO,aAAa,UAAU,MAAM,OAAO;AAEhE,UAAM,UAAuB,OAAO,QAAQ,IAAI,CAAC,WAAW;AAAA,MAC1D,YAAY,OAAO,MAAM,OAAO;AAAA,MAChC,QAAQ,oBAAoB,MAAM,MAAM;AAAA,MACxC,UAAU;AAAA,QACR,UAAU,MAAM,YAAY;AAAA,QAC5B,SAAS,MAAM,mBAAmB;AAAA,MACpC;AAAA,MACA,OAAO,MAAM,QAAQ,IAAI,wBAAwB,MAAM,OAAO,WAAW,IAAI;AAAA,MAC7E,WAAW,eAAe,MAAM,SAAS;AAAA,MACzC,aAAa,eAAe,MAAM,WAAW;AAAA,MAC7C,OAAO,MAAM,SAAS;AAAA,IACxB,EAAE;AAEF,WAAO;AAAA,MACL,UAAU,QAAQ,MAAM,kBAAkB,OAAO,SAAS,WAAW,IAAI,OAAO,SAAS,QAAQ;AAAA,IACnG;AAEA,WAAO;AAAA,MACL;AAAA,MACA,YAAY,OAAO,SAAS,cAAc,OAAO,OAAO,SAAS,cAAc,CAAC,IAAI;AAAA,MACpF,SAAS,OAAO,SAAS;AAAA,IAC3B;AAAA,EACF;AAAA,EAEA,MAAM,SAAsC;AAC1C,QAAI,CAAC,UAAU,aAAa,MAAM;AAChC,aAAO;AAAA,QACL,aAAa;AAAA,QACb,aAAa;AAAA,QACb,WAAW;AAAA,MACb;AAAA,IACF;AAGA,UAAM,SAAS,MAAM,OAAO,aAAa,UAAU,GAAG,CAAC;AAEvD,WAAO;AAAA,MACL,eAAe,OAAO,SAAS;AAAA,MAC/B,aAAa;AAAA,MACb,aAAa;AAAA,MACb,WAAW;AAAA,IACb;AAAA,EACF;AACF;AAMA,iBAAiB;AAAA,EACf;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,aAAa,QAA0B;AAErC,UAAM,cAAc,OAAO,aAAa;AACxC,QAAI,aAAa;AACf,eAAS,IAAI,cAAc,WAAW;AACtC,aAAO,KAAK,8CAA8C;AAAA,IAC5D,OAAO;AACL,aAAO,KAAK,sDAAsD;AAAA,IACpE;AAGA,UAAM,KAAK,OAAO;AAClB,QAAI,IAAI;AACN,YAAM,OAAO,GAAG;AAChB,UAAI,SAAS,cAAc,SAAS,WAAW;AAC7C,uBAAe;AAAA,MACjB;AACA,UAAI,OAAO,GAAG,mBAAmB,YAAY,GAAG,kBAAkB,GAAG;AACnE,yBAAiB,GAAG;AAAA,MACtB;AACA,UAAI,OAAO,GAAG,kBAAkB,YAAY,GAAG,iBAAiB,GAAG;AACjE,wBAAgB,GAAG;AAAA,MACrB;AACA,UAAI,OAAO,GAAG,mBAAmB,WAAW;AAC1C,yBAAiB,GAAG;AAAA,MACtB;AACA,UAAI,OAAO,GAAG,YAAY,WAAW;AACnC,sBAAc,GAAG;AAAA,MACnB;AACA,UAAI,OAAO,GAAG,0BAA0B,WAAW;AACjD,gCAAwB,GAAG;AAAA,MAC7B;AACA,aAAO;AAAA,QACL,+BAA+B,YAAY,oBAAoB,cAAc,mBAAmB,aAAa,oBAAoB,cAAc,aAAa,WAAW,2BAA2B,qBAAqB;AAAA,MACzN;AAAA,IACF;AAAA,EACF;AACF,CAAC;AAED,OAAO,KAAK,6BAA6B;",
3
+ "sources": ["../node_modules/@ashdev/codex-plugin-sdk/src/types/rpc.ts", "../node_modules/@ashdev/codex-plugin-sdk/src/errors.ts", "../node_modules/@ashdev/codex-plugin-sdk/src/request-context.ts", "../node_modules/@ashdev/codex-plugin-sdk/src/host-rpc.ts", "../node_modules/@ashdev/codex-plugin-sdk/src/logger.ts", "../node_modules/@ashdev/codex-plugin-sdk/src/server.ts", "../node_modules/@ashdev/codex-plugin-sdk/src/storage.ts", "../src/anilist.ts", "../package.json", "../src/manifest.ts", "../src/index.ts"],
4
+ "sourcesContent": [null, null, null, null, null, null, null, "/**\n * AniList GraphQL API client\n *\n * Provides typed access to AniList's GraphQL API for reading progress sync.\n * See: https://anilist.gitbook.io/anilist-apiv2-docs/\n */\n\nimport { ApiError, AuthError, RateLimitError } from \"@ashdev/codex-plugin-sdk\";\n\nconst ANILIST_API_URL = \"https://graphql.anilist.co\";\n\n// =============================================================================\n// GraphQL Queries\n// =============================================================================\n\nconst VIEWER_QUERY = `\n query {\n Viewer {\n id\n name\n avatar {\n large\n medium\n }\n siteUrl\n options {\n displayAdultContent\n }\n mediaListOptions {\n scoreFormat\n }\n }\n }\n`;\n\nconst MANGA_LIST_QUERY = `\n query ($userId: Int!, $page: Int, $perPage: Int) {\n Page(page: $page, perPage: $perPage) {\n pageInfo {\n total\n currentPage\n lastPage\n hasNextPage\n }\n mediaList(userId: $userId, type: MANGA, sort: UPDATED_TIME_DESC) {\n id\n mediaId\n status\n score\n progress\n progressVolumes\n startedAt {\n year\n month\n day\n }\n completedAt {\n year\n month\n day\n }\n notes\n updatedAt\n media {\n id\n title {\n romaji\n english\n native\n }\n siteUrl\n }\n }\n }\n }\n`;\n\n/** Search for a manga by title to find its AniList ID */\nconst SEARCH_MANGA_QUERY = `\n query ($search: String!) {\n Media(search: $search, type: MANGA) {\n id\n title {\n romaji\n english\n }\n }\n }\n`;\n\nconst UPDATE_ENTRY_MUTATION = `\n mutation (\n $mediaId: Int!,\n $status: MediaListStatus,\n $score: Float,\n $progress: Int,\n $progressVolumes: Int,\n $startedAt: FuzzyDateInput,\n $completedAt: FuzzyDateInput,\n $notes: String,\n $private: Boolean,\n $hiddenFromStatusLists: Boolean\n ) {\n SaveMediaListEntry(\n mediaId: $mediaId,\n status: $status,\n score: $score,\n progress: $progress,\n progressVolumes: $progressVolumes,\n startedAt: $startedAt,\n completedAt: $completedAt,\n notes: $notes,\n private: $private,\n hiddenFromStatusLists: $hiddenFromStatusLists\n ) {\n id\n mediaId\n status\n score\n progress\n progressVolumes\n }\n }\n`;\n\n// =============================================================================\n// Types\n// =============================================================================\n\nexport interface AniListViewer {\n id: number;\n name: string;\n avatar: { large?: string; medium?: string };\n siteUrl: string;\n options: { displayAdultContent: boolean };\n mediaListOptions: { scoreFormat: string };\n}\n\nexport interface AniListSearchResult {\n id: number;\n title: { romaji?: string; english?: string };\n}\n\nexport interface AniListFuzzyDate {\n year?: number | null;\n month?: number | null;\n day?: number | null;\n}\n\nexport interface AniListMediaListEntry {\n id: number;\n mediaId: number;\n status: string;\n score: number;\n progress: number;\n progressVolumes: number;\n startedAt: AniListFuzzyDate;\n completedAt: AniListFuzzyDate;\n notes: string | null;\n updatedAt: number;\n media: {\n id: number;\n title: { romaji?: string; english?: string; native?: string };\n siteUrl: string;\n };\n}\n\nexport interface AniListPageInfo {\n total: number;\n currentPage: number;\n lastPage: number;\n hasNextPage: boolean;\n}\n\nexport interface AniListSaveResult {\n id: number;\n mediaId: number;\n status: string;\n score: number;\n progress: number;\n progressVolumes: number;\n}\n\n// =============================================================================\n// Client\n// =============================================================================\n\nexport class AniListClient {\n private accessToken: string;\n\n constructor(accessToken: string) {\n this.accessToken = accessToken;\n }\n\n /**\n * Execute a GraphQL query against the AniList API.\n * On rate limit (429), waits the requested duration and retries once.\n */\n private async query<T>(queryStr: string, variables?: Record<string, unknown>): Promise<T> {\n return this.executeQuery<T>(queryStr, variables, true);\n }\n\n private async executeQuery<T>(\n queryStr: string,\n variables: Record<string, unknown> | undefined,\n allowRetry: boolean,\n ): Promise<T> {\n let response: Response;\n try {\n response = await fetch(ANILIST_API_URL, {\n method: \"POST\",\n signal: AbortSignal.timeout(30_000),\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n Authorization: `Bearer ${this.accessToken}`,\n },\n body: JSON.stringify({ query: queryStr, variables }),\n });\n } catch (error) {\n if (error instanceof DOMException && error.name === \"TimeoutError\") {\n throw new ApiError(\"AniList API request timed out after 30 seconds\");\n }\n throw error;\n }\n\n if (response.status === 401) {\n throw new AuthError(\"AniList access token is invalid or expired\");\n }\n\n if (response.status === 429) {\n const retryAfter = response.headers.get(\"Retry-After\");\n const retrySeconds = retryAfter ? Number.parseInt(retryAfter, 10) : 60;\n const waitSeconds = Number.isNaN(retrySeconds) ? 60 : retrySeconds;\n\n if (allowRetry) {\n await new Promise((resolve) => setTimeout(resolve, waitSeconds * 1000));\n return this.executeQuery<T>(queryStr, variables, false);\n }\n\n throw new RateLimitError(waitSeconds, \"AniList rate limit exceeded\");\n }\n\n if (!response.ok) {\n const body = await response.text().catch(() => \"\");\n throw new ApiError(\n `AniList API error: ${response.status} ${response.statusText}${body ? ` - ${body}` : \"\"}`,\n );\n }\n\n const json = (await response.json()) as { data?: T; errors?: Array<{ message: string }> };\n\n if (json.errors?.length) {\n const message = json.errors.map((e) => e.message).join(\"; \");\n throw new ApiError(`AniList GraphQL error: ${message}`);\n }\n\n if (!json.data) {\n throw new ApiError(\"AniList returned empty data\");\n }\n\n return json.data;\n }\n\n /**\n * Get the authenticated user's info\n */\n async getViewer(): Promise<AniListViewer> {\n const data = await this.query<{ Viewer: AniListViewer }>(VIEWER_QUERY);\n return data.Viewer;\n }\n\n /**\n * Get the user's manga list (paginated)\n */\n async getMangaList(\n userId: number,\n page = 1,\n perPage = 50,\n ): Promise<{ pageInfo: AniListPageInfo; entries: AniListMediaListEntry[] }> {\n const variables: Record<string, unknown> = { userId, page, perPage };\n\n const data = await this.query<{\n Page: {\n pageInfo: AniListPageInfo;\n mediaList: AniListMediaListEntry[];\n };\n }>(MANGA_LIST_QUERY, variables);\n\n return {\n pageInfo: data.Page.pageInfo,\n entries: data.Page.mediaList,\n };\n }\n\n /**\n * Update or create a manga list entry\n */\n async saveEntry(variables: {\n mediaId: number;\n status?: string;\n score?: number;\n progress?: number;\n progressVolumes?: number;\n startedAt?: AniListFuzzyDate;\n completedAt?: AniListFuzzyDate;\n notes?: string;\n private?: boolean;\n hiddenFromStatusLists?: boolean;\n }): Promise<AniListSaveResult> {\n const data = await this.query<{ SaveMediaListEntry: AniListSaveResult }>(\n UPDATE_ENTRY_MUTATION,\n variables,\n );\n return data.SaveMediaListEntry;\n }\n\n /**\n * Search for a manga by title and return its AniList ID.\n * Returns null if no result found or an error occurs.\n */\n async searchManga(title: string): Promise<AniListSearchResult | null> {\n try {\n const data = await this.query<{ Media: AniListSearchResult | null }>(SEARCH_MANGA_QUERY, {\n search: title,\n });\n return data.Media;\n } catch {\n return null;\n }\n }\n}\n\n// =============================================================================\n// Status Mapping\n// =============================================================================\n\n/**\n * Map AniList MediaListStatus to Codex SyncReadingStatus\n */\nexport function anilistStatusToSync(\n status: string,\n): \"reading\" | \"completed\" | \"on_hold\" | \"dropped\" | \"plan_to_read\" {\n switch (status) {\n case \"CURRENT\":\n case \"REPEATING\":\n return \"reading\";\n case \"COMPLETED\":\n return \"completed\";\n case \"PAUSED\":\n return \"on_hold\";\n case \"DROPPED\":\n return \"dropped\";\n case \"PLANNING\":\n return \"plan_to_read\";\n default:\n return \"reading\";\n }\n}\n\n/**\n * Map Codex SyncReadingStatus to AniList MediaListStatus\n */\nexport function syncStatusToAnilist(\n status: string,\n): \"CURRENT\" | \"COMPLETED\" | \"PAUSED\" | \"DROPPED\" | \"PLANNING\" {\n switch (status) {\n case \"reading\":\n return \"CURRENT\";\n case \"completed\":\n return \"COMPLETED\";\n case \"on_hold\":\n return \"PAUSED\";\n case \"dropped\":\n return \"DROPPED\";\n case \"plan_to_read\":\n return \"PLANNING\";\n default:\n return \"CURRENT\";\n }\n}\n\n/**\n * Convert AniList FuzzyDate to ISO 8601 string\n */\nexport function fuzzyDateToIso(date: AniListFuzzyDate | null | undefined): string | undefined {\n if (!date?.year) return undefined;\n const month = date.month ? String(date.month).padStart(2, \"0\") : \"01\";\n const day = date.day ? String(date.day).padStart(2, \"0\") : \"01\";\n return `${date.year}-${month}-${day}T00:00:00Z`;\n}\n\n/**\n * Convert ISO 8601 string to AniList FuzzyDate\n */\nexport function isoToFuzzyDate(iso: string | undefined): AniListFuzzyDate | undefined {\n if (!iso) return undefined;\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return undefined;\n return {\n year: d.getUTCFullYear(),\n month: d.getUTCMonth() + 1,\n day: d.getUTCDate(),\n };\n}\n\n// =============================================================================\n// Score Conversion\n// =============================================================================\n\n/**\n * Convert a score from Codex's 1-100 scale to AniList's format\n */\nexport function convertScoreToAnilist(score: number, format: string): number {\n switch (format) {\n case \"POINT_100\":\n return Math.round(score);\n case \"POINT_10_DECIMAL\":\n return score / 10;\n case \"POINT_10\":\n return Math.round(score / 10);\n case \"POINT_5\":\n return Math.round(score / 20);\n case \"POINT_3\":\n if (score >= 70) return 3;\n if (score >= 40) return 2;\n return 1;\n default:\n return Math.round(score / 10);\n }\n}\n\n/**\n * Convert a score from AniList's format to Codex's 1-100 scale\n */\nexport function convertScoreFromAnilist(score: number, format: string): number {\n switch (format) {\n case \"POINT_100\":\n return score;\n case \"POINT_10_DECIMAL\":\n return score * 10;\n case \"POINT_10\":\n return score * 10;\n case \"POINT_5\":\n return score * 20;\n case \"POINT_3\":\n return Math.round(score * 33.3);\n default:\n return score * 10;\n }\n}\n", "{\n \"name\": \"@ashdev/codex-plugin-sync-anilist\",\n \"version\": \"1.19.0\",\n \"description\": \"AniList reading progress sync plugin for Codex\",\n \"main\": \"dist/index.js\",\n \"bin\": \"dist/index.js\",\n \"type\": \"module\",\n \"files\": [\n \"dist\",\n \"README.md\"\n ],\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"https://github.com/AshDevFr/codex.git\",\n \"directory\": \"plugins/sync-anilist\"\n },\n \"scripts\": {\n \"build\": \"esbuild src/index.ts --bundle --platform=node --target=node22 --format=esm --outfile=dist/index.js --sourcemap --banner:js='#!/usr/bin/env node'\",\n \"dev\": \"npm run build -- --watch\",\n \"clean\": \"rm -rf dist\",\n \"start\": \"node dist/index.js\",\n \"lint\": \"biome check .\",\n \"lint:fix\": \"biome check --write .\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run --passWithNoTests\",\n \"test:watch\": \"vitest\",\n \"prepublishOnly\": \"npm run lint && npm run build\"\n },\n \"keywords\": [\n \"codex\",\n \"plugin\",\n \"anilist\",\n \"sync\",\n \"manga\",\n \"reading-progress\"\n ],\n \"author\": \"Codex\",\n \"license\": \"MIT\",\n \"engines\": {\n \"node\": \">=22.0.0\"\n },\n \"dependencies\": {\n \"@ashdev/codex-plugin-sdk\": \"^1.19.0\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.4.4\",\n \"@types/node\": \"^22.0.0\",\n \"esbuild\": \"^0.27.3\",\n \"typescript\": \"^5.9.3\",\n \"vitest\": \"^4.0.18\"\n }\n}\n", "import type { PluginManifest } from \"@ashdev/codex-plugin-sdk\";\nimport packageJson from \"../package.json\" with { type: \"json\" };\n\n/** Canonical external ID source for AniList (`api:<service>` convention) */\nconst EXTERNAL_ID_SOURCE_ANILIST = \"api:anilist\" as const;\n\nexport const manifest = {\n name: \"sync-anilist\",\n displayName: \"AniList Sync\",\n version: packageJson.version,\n description:\n \"Sync manga reading progress between Codex and AniList. Supports push/pull of reading status, chapters read, scores, and dates.\",\n author: \"Codex\",\n homepage: \"https://github.com/AshDevFr/codex\",\n protocolVersion: \"1.0\",\n capabilities: {\n userReadSync: true,\n externalIdSource: EXTERNAL_ID_SOURCE_ANILIST,\n },\n requiredCredentials: [\n {\n key: \"access_token\",\n label: \"AniList Access Token\",\n description: \"OAuth access token for AniList API\",\n type: \"password\" as const,\n required: true,\n sensitive: true,\n },\n ],\n userConfigSchema: {\n description: \"AniList-specific sync settings\",\n fields: [\n {\n key: \"progressUnit\",\n label: \"Progress Unit\",\n description:\n \"What each book in Codex represents in AniList. Use 'volumes' for manga volumes, 'chapters' for individual chapters\",\n type: \"string\" as const,\n required: false,\n default: \"volumes\",\n },\n {\n key: \"pauseAfterDays\",\n label: \"Auto-Pause After Days\",\n description:\n \"Automatically set in-progress series to Paused on AniList if no reading activity in this many days. Set to 0 to disable.\",\n type: \"number\" as const,\n required: false,\n default: 0,\n },\n {\n key: \"dropAfterDays\",\n label: \"Auto-Drop After Days\",\n description:\n \"Automatically set in-progress series to Dropped on AniList if no reading activity in this many days. Set to 0 to disable. When both pause and drop are set, the shorter threshold fires first.\",\n type: \"number\" as const,\n required: false,\n default: 0,\n },\n {\n key: \"searchFallback\",\n label: \"Search Fallback\",\n description:\n \"When a series has no AniList ID, search by title to find a match and sync progress. Disable for strict matching only.\",\n type: \"boolean\" as const,\n required: false,\n default: false,\n },\n {\n key: \"private\",\n label: \"Private Mode\",\n description:\n \"When enabled, all manga list entries synced from Codex will be marked as private on AniList, visible only to you. When disabled, entries follow AniList's default visibility (public).\",\n type: \"boolean\" as const,\n required: false,\n default: true,\n },\n {\n key: \"hiddenFromStatusLists\",\n label: \"Hide from Status Lists\",\n description:\n \"When enabled, synced entries will be hidden from your standard AniList status lists (Currently Reading, Completed, etc.) but will still appear in custom lists. Has no effect when Private Mode is enabled.\",\n type: \"boolean\" as const,\n required: false,\n default: false,\n },\n ],\n },\n oauth: {\n authorizationUrl: \"https://anilist.co/api/v2/oauth/authorize\",\n tokenUrl: \"https://anilist.co/api/v2/oauth/token\",\n scopes: [],\n pkce: false,\n },\n userDescription: \"Sync manga reading progress between Codex and AniList\",\n adminSetupInstructions:\n \"To enable OAuth login, create an AniList API client at https://anilist.co/settings/developer. Set the redirect URL to {your-codex-url}/api/v1/user/plugins/oauth/callback. Enter the Client ID below. Without OAuth configured, users can still connect by pasting a personal access token.\",\n userSetupInstructions:\n \"Connect your AniList account via OAuth, or paste a personal access token. To generate a token, visit https://anilist.co/settings/developer, create a client with redirect URL https://anilist.co/api/v2/oauth/pin, then authorize it to receive your token.\",\n} as const satisfies PluginManifest & {\n capabilities: { userReadSync: true };\n};\n", "/**\n * AniList Sync Plugin for Codex\n *\n * Syncs manga reading progress between Codex and AniList.\n * Communicates via JSON-RPC over stdio using the Codex plugin SDK.\n *\n * Capabilities:\n * - Push reading progress from Codex to AniList\n * - Pull reading progress from AniList to Codex\n * - Get user info from AniList\n * - Status reporting for sync state\n */\n\nimport {\n createLogger,\n createSyncPlugin,\n type ExternalUserInfo,\n type InitializeParams,\n type SyncEntry,\n type SyncEntryResult,\n type SyncProvider,\n type SyncPullRequest,\n type SyncPullResponse,\n type SyncPushRequest,\n type SyncPushResponse,\n type SyncStatusResponse,\n} from \"@ashdev/codex-plugin-sdk\";\nimport {\n AniListClient,\n type AniListFuzzyDate,\n anilistStatusToSync,\n convertScoreFromAnilist,\n convertScoreToAnilist,\n fuzzyDateToIso,\n isoToFuzzyDate,\n syncStatusToAnilist,\n} from \"./anilist.js\";\nimport { manifest } from \"./manifest.js\";\n\nconst logger = createLogger({ name: \"sync-anilist\", level: \"debug\" });\n\n// Plugin state (set during initialization)\nlet client: AniListClient | null = null;\nlet viewerId: number | null = null;\nlet scoreFormat = \"POINT_10\";\n\n// Plugin-specific config (from userConfig, set during initialization)\nlet progressUnit: \"volumes\" | \"chapters\" = \"volumes\";\nlet pauseAfterDays = 0;\nlet dropAfterDays = 0;\nlet searchFallback = false;\nlet privateMode = true;\nlet hiddenFromStatusLists = false;\n\n/** Set the AniList client (exported for testing) */\nexport function setClient(c: AniListClient | null): void {\n client = c;\n}\n\n/** Set the viewer ID (exported for testing) */\nexport function setViewerId(id: number | null): void {\n viewerId = id;\n}\n\n/** Set the searchFallback flag (exported for testing) */\nexport function setSearchFallback(enabled: boolean): void {\n searchFallback = enabled;\n}\n\n/** Set the privateMode flag (exported for testing) */\nexport function setPrivateMode(enabled: boolean): void {\n privateMode = enabled;\n}\n\n/** Set the hiddenFromStatusLists flag (exported for testing) */\nexport function setHiddenFromStatusLists(enabled: boolean): void {\n hiddenFromStatusLists = enabled;\n}\n\n// =============================================================================\n// Staleness Logic\n// =============================================================================\n\n/**\n * Apply auto-pause/auto-drop for stale in-progress entries.\n *\n * Only applies to \"reading\" entries. Drop takes priority over pause\n * when both thresholds are met. A threshold of 0 means disabled.\n */\nexport function applyStaleness(\n status: SyncEntry[\"status\"],\n latestUpdatedAt: string | undefined,\n pauseDays: number,\n dropDays: number,\n now?: number,\n): SyncEntry[\"status\"] {\n if (status !== \"reading\") return status;\n if (pauseDays === 0 && dropDays === 0) return status;\n if (!latestUpdatedAt) return status;\n\n const lastActivity = new Date(latestUpdatedAt).getTime();\n if (Number.isNaN(lastActivity)) return status;\n\n const currentTime = now ?? Date.now();\n const daysInactive = Math.max(0, (currentTime - lastActivity) / (1000 * 60 * 60 * 24));\n\n // Drop takes priority (stronger action)\n if (dropDays > 0 && daysInactive >= dropDays) {\n return \"dropped\";\n }\n if (pauseDays > 0 && daysInactive >= pauseDays) {\n return \"on_hold\";\n }\n\n return status;\n}\n\n// =============================================================================\n// Sync Provider Implementation\n// =============================================================================\n\n/** Exported for testing */\nexport const provider: SyncProvider = {\n async getUserInfo(): Promise<ExternalUserInfo> {\n if (!client) {\n throw new Error(\"Plugin not initialized - no AniList client\");\n }\n\n const viewer = await client.getViewer();\n viewerId = viewer.id;\n scoreFormat = viewer.mediaListOptions.scoreFormat;\n\n logger.info(`Authenticated as ${viewer.name} (id: ${viewer.id}, scoreFormat: ${scoreFormat})`);\n\n return {\n externalId: String(viewer.id),\n username: viewer.name,\n avatarUrl: viewer.avatar.large || viewer.avatar.medium,\n profileUrl: viewer.siteUrl,\n };\n },\n\n async pushProgress(params: SyncPushRequest): Promise<SyncPushResponse> {\n if (!client || viewerId === null) {\n throw new Error(\"Plugin not initialized - call getUserInfo first\");\n }\n\n // Pre-fetch existing media IDs to distinguish \"created\" vs \"updated\"\n const existingMediaIds = new Set<number>();\n let page = 1;\n let hasMore = true;\n while (hasMore) {\n const result = await client.getMangaList(viewerId, page, 50);\n for (const entry of result.entries) {\n existingMediaIds.add(entry.mediaId);\n }\n hasMore = result.pageInfo.hasNextPage;\n page++;\n }\n\n const success: SyncEntryResult[] = [];\n const failed: SyncEntryResult[] = [];\n\n for (const entry of params.entries) {\n try {\n let mediaId = Number.parseInt(entry.externalId, 10);\n if (Number.isNaN(mediaId)) {\n // Try search fallback if enabled and entry has a title\n if (searchFallback && entry.title) {\n const result = await client.searchManga(entry.title);\n if (result) {\n mediaId = result.id;\n logger.info(`Search fallback resolved \"${entry.title}\" \u2192 AniList ID ${mediaId}`);\n }\n }\n\n if (Number.isNaN(mediaId)) {\n failed.push({\n externalId: entry.externalId,\n status: \"failed\",\n error: searchFallback\n ? `No AniList match found for \"${entry.title || entry.externalId}\"`\n : `Invalid media ID: ${entry.externalId}`,\n });\n continue;\n }\n }\n\n // Apply staleness logic: auto-pause or auto-drop stale in-progress entries\n const effectiveStatus = applyStaleness(\n entry.status,\n entry.latestUpdatedAt,\n pauseAfterDays,\n dropAfterDays,\n );\n if (effectiveStatus !== entry.status) {\n logger.debug(\n `Entry ${entry.externalId}: auto-${effectiveStatus === \"dropped\" ? \"dropped\" : \"paused\"} (was ${entry.status})`,\n );\n }\n\n const saveParams: {\n mediaId: number;\n status?: string;\n score?: number;\n progress?: number;\n progressVolumes?: number;\n startedAt?: AniListFuzzyDate;\n completedAt?: AniListFuzzyDate;\n notes?: string;\n private?: boolean;\n hiddenFromStatusLists?: boolean;\n } = {\n mediaId,\n status: syncStatusToAnilist(effectiveStatus),\n private: privateMode,\n hiddenFromStatusLists,\n };\n\n // Map progress using the configured progressUnit.\n // Server always sends books-read as `volumes`. Based on\n // progressUnit, we map to AniList's `progress` (chapters)\n // or `progressVolumes` (volumes) field.\n const count = entry.progress?.volumes ?? entry.progress?.chapters;\n if (count !== undefined) {\n if (progressUnit === \"chapters\") {\n saveParams.progress = count;\n } else {\n saveParams.progressVolumes = count;\n }\n }\n\n // Map score (convert from 1-100 scale to AniList format)\n if (entry.score !== undefined) {\n saveParams.score = convertScoreToAnilist(entry.score, scoreFormat);\n }\n\n // Map dates\n if (entry.startedAt) {\n saveParams.startedAt = isoToFuzzyDate(entry.startedAt);\n }\n if (entry.completedAt) {\n saveParams.completedAt = isoToFuzzyDate(entry.completedAt);\n }\n\n // Map notes\n if (entry.notes !== undefined) {\n saveParams.notes = entry.notes;\n }\n\n const resolvedExternalId = String(mediaId);\n const existed = existingMediaIds.has(mediaId);\n const result = await client.saveEntry(saveParams);\n logger.debug(`Pushed entry ${resolvedExternalId}: status=${result.status}`);\n\n // Track newly created entries for subsequent pushes in the same batch\n existingMediaIds.add(mediaId);\n\n success.push({\n externalId: resolvedExternalId,\n status: existed ? \"updated\" : \"created\",\n });\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Unknown error\";\n logger.error(`Failed to push entry ${entry.externalId}: ${message}`);\n failed.push({\n externalId: entry.externalId,\n status: \"failed\",\n error: message,\n });\n }\n }\n\n return { success, failed };\n },\n\n async pullProgress(params: SyncPullRequest): Promise<SyncPullResponse> {\n if (!client || viewerId === null) {\n throw new Error(\"Plugin not initialized - call getUserInfo first\");\n }\n\n // Parse pagination cursor (page number)\n const page = params.cursor ? Number.parseInt(params.cursor, 10) : 1;\n const perPage = params.limit ? Math.min(params.limit, 50) : 50;\n\n const result = await client.getMangaList(viewerId, page, perPage);\n\n const entries: SyncEntry[] = result.entries.map((entry) => ({\n externalId: String(entry.mediaId),\n status: anilistStatusToSync(entry.status),\n progress: {\n chapters: entry.progress || undefined,\n volumes: entry.progressVolumes || undefined,\n },\n score: entry.score > 0 ? convertScoreFromAnilist(entry.score, scoreFormat) : undefined,\n startedAt: fuzzyDateToIso(entry.startedAt),\n completedAt: fuzzyDateToIso(entry.completedAt),\n notes: entry.notes || undefined,\n }));\n\n logger.info(\n `Pulled ${entries.length} entries (page ${result.pageInfo.currentPage}/${result.pageInfo.lastPage})`,\n );\n\n return {\n entries,\n nextCursor: result.pageInfo.hasNextPage ? String(result.pageInfo.currentPage + 1) : undefined,\n hasMore: result.pageInfo.hasNextPage,\n };\n },\n\n async status(): Promise<SyncStatusResponse> {\n if (!client || viewerId === null) {\n return {\n pendingPush: 0,\n pendingPull: 0,\n conflicts: 0,\n };\n }\n\n // Get total count from AniList\n const result = await client.getMangaList(viewerId, 1, 1);\n\n return {\n externalCount: result.pageInfo.total,\n pendingPush: 0,\n pendingPull: 0,\n conflicts: 0,\n };\n },\n};\n\n// =============================================================================\n// Plugin Initialization\n// =============================================================================\n\ncreateSyncPlugin({\n manifest,\n provider,\n logLevel: \"debug\",\n onInitialize(params: InitializeParams) {\n // Get access token from credentials\n const accessToken = params.credentials?.access_token;\n if (accessToken) {\n client = new AniListClient(accessToken);\n logger.info(\"AniList client initialized with access token\");\n } else {\n logger.warn(\"No access token provided - sync operations will fail\");\n }\n\n // Read plugin-specific config from userConfig\n const uc = params.userConfig;\n if (uc) {\n const unit = uc.progressUnit;\n if (unit === \"chapters\" || unit === \"volumes\") {\n progressUnit = unit;\n }\n if (typeof uc.pauseAfterDays === \"number\" && uc.pauseAfterDays >= 0) {\n pauseAfterDays = uc.pauseAfterDays;\n }\n if (typeof uc.dropAfterDays === \"number\" && uc.dropAfterDays >= 0) {\n dropAfterDays = uc.dropAfterDays;\n }\n if (typeof uc.searchFallback === \"boolean\") {\n searchFallback = uc.searchFallback;\n }\n if (typeof uc.private === \"boolean\") {\n privateMode = uc.private;\n }\n if (typeof uc.hiddenFromStatusLists === \"boolean\") {\n hiddenFromStatusLists = uc.hiddenFromStatusLists;\n }\n logger.info(\n `Plugin config: progressUnit=${progressUnit}, pauseAfterDays=${pauseAfterDays}, dropAfterDays=${dropAfterDays}, searchFallback=${searchFallback}, private=${privateMode}, hiddenFromStatusLists=${hiddenFromStatusLists}`,\n );\n }\n },\n});\n\nlogger.info(\"AniList sync plugin started\");\n"],
5
+ "mappings": ";;;AA2CO,IAAM,uBAAuB;;EAElC,aAAa;;EAEb,iBAAiB;;EAEjB,kBAAkB;;EAElB,gBAAgB;;EAEhB,gBAAgB;;AAMX,IAAM,qBAAqB;;EAEhC,cAAc;;EAEd,WAAW;;EAEX,aAAa;;EAEb,WAAW;;EAEX,cAAc;;;;AC5DV,IAAgB,cAAhB,cAAoC,MAAK;EAEpC;EAET,YAAY,SAAiB,MAAc;AACzC,UAAM,OAAO;AACb,SAAK,OAAO,KAAK,YAAY;AAC7B,SAAK,OAAO;EACd;;;;EAKA,iBAAc;AACZ,WAAO;MACL,MAAM,KAAK;MACX,SAAS,KAAK;MACd,MAAM,KAAK;;EAEf;;AAMI,IAAO,iBAAP,cAA8B,YAAW;EACpC,OAAO,mBAAmB;;EAE1B;EAET,YAAY,mBAA2B,SAAgB;AACrD,UAAM,WAAW,6BAA6B,iBAAiB,KAAK;MAClE;KACD;AACD,SAAK,oBAAoB;EAC3B;;AAaI,IAAO,YAAP,cAAyB,YAAW;EAC/B,OAAO,mBAAmB;EAEnC,YAAY,SAAgB;AAC1B,UAAM,WAAW,uBAAuB;EAC1C;;AAMI,IAAO,WAAP,cAAwB,YAAW;EAC9B,OAAO,mBAAmB;EAC1B;EAET,YAAY,SAAiB,YAAmB;AAC9C,UAAM,SAAS,eAAe,SAAY,EAAE,WAAU,IAAK,MAAS;AACpE,SAAK,aAAa;EACpB;;;;ACxDF,SAAS,yBAAyB;AAElC,IAAM,QAAQ,IAAI,kBAAiB;AAO7B,SAAU,uBACd,kBACA,IAAoB;AAEpB,SAAO,MAAM,IAAI,kBAAkB,EAAE;AACvC;AAQM,SAAU,yBAAsB;AACpC,SAAO,MAAM,SAAQ;AACvB;;;ACZM,IAAO,eAAP,cAA4B,MAAK;EAGnB;EACA;EAHlB,YACE,SACgB,MACA,MAAc;AAE9B,UAAM,OAAO;AAHG,SAAA,OAAA;AACA,SAAA,OAAA;AAGhB,SAAK,OAAO;EACd;;AAOI,IAAO,gBAAP,MAAoB;;;;;EAKhB,SAAS;EACT,kBAAkB,oBAAI,IAAG;EAOzB;;;;;EAMR,YAAY,SAAiB;AAC3B,SAAK,UACH,YACC,CAAC,SAAgB;AAChB,cAAQ,OAAO,MAAM,IAAI;IAC3B;EACJ;;;;;;;;EASA,MAAM,KAAkB,QAAgB,QAAgB;AACtD,UAAM,KAAK,KAAK;AAKhB,UAAM,SAAS,uBAAsB;AACrC,UAAM,UAA0B;MAC9B,SAAS;MACT;MACA;MACA;MACA,GAAI,WAAW,SAAY,EAAE,iBAAiB,OAAM,IAAK,CAAA;;AAG3D,WAAO,IAAI,QAAW,CAAC,SAAS,WAAU;AACxC,WAAK,gBAAgB,IAAI,IAAI;QAC3B,SAAS,CAAC,MAAM,QAAQ,CAAM;QAC9B;OACD;AACD,UAAI;AACF,aAAK,QAAQ,GAAG,KAAK,UAAU,OAAO,CAAC;CAAI;MAC7C,SAAS,KAAK;AACZ,aAAK,gBAAgB,OAAO,EAAE;AAC9B,cAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,eAAO,IAAI,aAAa,2BAA2B,OAAO,IAAI,EAAE,CAAC;MACnE;IACF,CAAC;EACH;;;;;;;;EASA,eAAe,MAAY;AACzB,UAAM,UAAU,KAAK,KAAI;AACzB,QAAI,CAAC;AAAS,aAAO;AAErB,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,MAAM,OAAO;IAC7B,QAAQ;AACN,aAAO;IACT;AAEA,UAAM,MAAM;AACZ,QAAI,IAAI,WAAW;AAAW,aAAO;AACrC,UAAM,QAAQ,IAAI;AAClB,QAAI,OAAO,UAAU;AAAU,aAAO;AACtC,QAAI,CAAC,KAAK,gBAAgB,IAAI,KAAK;AAAG,aAAO;AAE7C,UAAM,UAAU,KAAK,gBAAgB,IAAI,KAAK;AAC9C,QAAI,CAAC;AAAS,aAAO;AACrB,SAAK,gBAAgB,OAAO,KAAK;AAEjC,QAAI,WAAW,OAAO,IAAI,OAAO;AAC/B,YAAM,MAAM,IAAI;AAChB,cAAQ,OAAO,IAAI,aAAa,IAAI,SAAS,IAAI,MAAM,IAAI,IAAI,CAAC;IAClE,OAAO;AACL,cAAQ,QAAQ,IAAI,MAAM;IAC5B;AACA,WAAO;EACT;;EAGA,YAAS;AACP,eAAW,CAAC,EAAE,OAAO,KAAK,KAAK,iBAAiB;AAC9C,cAAQ,OAAO,IAAI,aAAa,2BAA2B,EAAE,CAAC;IAChE;AACA,SAAK,gBAAgB,MAAK;EAC5B;;;;AChJF,IAAM,aAAuC;EAC3C,OAAO;EACP,MAAM;EACN,MAAM;EACN,OAAO;;AAeH,IAAO,SAAP,MAAa;EACA;EACA;EACA;EAEjB,YAAY,SAAsB;AAChC,SAAK,OAAO,QAAQ;AACpB,SAAK,WAAW,WAAW,QAAQ,SAAS,MAAM;AAClD,SAAK,aAAa,QAAQ,cAAc;EAC1C;EAEQ,UAAU,OAAe;AAC/B,WAAO,WAAW,KAAK,KAAK,KAAK;EACnC;EAEQ,OAAO,OAAiB,SAAiB,MAAc;AAC7D,UAAM,QAAkB,CAAA;AAExB,QAAI,KAAK,YAAY;AACnB,YAAM,MAAK,oBAAI,KAAI,GAAG,YAAW,CAAE;IACrC;AAEA,UAAM,KAAK,IAAI,MAAM,YAAW,CAAE,GAAG;AACrC,UAAM,KAAK,IAAI,KAAK,IAAI,GAAG;AAC3B,UAAM,KAAK,OAAO;AAElB,QAAI,SAAS,QAAW;AACtB,UAAI,gBAAgB,OAAO;AACzB,cAAM,KAAK,KAAK,KAAK,OAAO,EAAE;AAC9B,YAAI,KAAK,OAAO;AACd,gBAAM,KAAK;EAAK,KAAK,KAAK,EAAE;QAC9B;MACF,WAAW,OAAO,SAAS,UAAU;AACnC,cAAM,KAAK,KAAK,KAAK,UAAU,IAAI,CAAC,EAAE;MACxC,OAAO;AACL,cAAM,KAAK,KAAK,OAAO,IAAI,CAAC,EAAE;MAChC;IACF;AAEA,WAAO,MAAM,KAAK,GAAG;EACvB;EAEQ,IAAI,OAAiB,SAAiB,MAAc;AAC1D,QAAI,KAAK,UAAU,KAAK,GAAG;AAEzB,cAAQ,OAAO,MAAM,GAAG,KAAK,OAAO,OAAO,SAAS,IAAI,CAAC;CAAI;IAC/D;EACF;EAEA,MAAM,SAAiB,MAAc;AACnC,SAAK,IAAI,SAAS,SAAS,IAAI;EACjC;EAEA,KAAK,SAAiB,MAAc;AAClC,SAAK,IAAI,QAAQ,SAAS,IAAI;EAChC;EAEA,KAAK,SAAiB,MAAc;AAClC,SAAK,IAAI,QAAQ,SAAS,IAAI;EAChC;EAEA,MAAM,SAAiB,MAAc;AACnC,SAAK,IAAI,SAAS,SAAS,IAAI;EACjC;;AAMI,SAAU,aAAa,SAAsB;AACjD,SAAO,IAAI,OAAO,OAAO;AAC3B;;;ACvFA,SAAS,uBAAuB;;;AC8E1B,IAAO,eAAP,cAA4B,MAAK;EAGnB;EACA;EAHlB,YACE,SACgB,MACA,MAAc;AAE9B,UAAM,OAAO;AAHG,SAAA,OAAA;AACA,SAAA,OAAA;AAGhB,SAAK,OAAO;EACd;;AAiBI,IAAO,gBAAP,MAAoB;EAChB,SAAS;EACT,kBAAkB,oBAAI,IAAG;EAOzB;;;;;;;EAQR,YAAY,SAAiB;AAC3B,SAAK,UACH,YACC,CAAC,SAAgB;AAChB,cAAQ,OAAO,MAAM,IAAI;IAC3B;EACJ;;;;;;;EAQA,MAAM,IAAI,KAAW;AACnB,WAAQ,MAAM,KAAK,YAAY,eAAe,EAAE,IAAG,CAAE;EACvD;;;;;;;;;EAUA,MAAM,IAAI,KAAa,MAAe,WAAkB;AACtD,UAAM,SAAkC,EAAE,KAAK,KAAI;AACnD,QAAI,cAAc,QAAW;AAC3B,aAAO,YAAY;IACrB;AACA,WAAQ,MAAM,KAAK,YAAY,eAAe,MAAM;EACtD;;;;;;;EAQA,MAAM,OAAO,KAAW;AACtB,WAAQ,MAAM,KAAK,YAAY,kBAAkB,EAAE,IAAG,CAAE;EAC1D;;;;;;EAOA,MAAM,OAAI;AACR,WAAQ,MAAM,KAAK,YAAY,gBAAgB,CAAA,CAAE;EACnD;;;;;;EAOA,MAAM,QAAK;AACT,WAAQ,MAAM,KAAK,YAAY,iBAAiB,CAAA,CAAE;EACpD;;;;;;;EAQA,eAAe,MAAY;AACzB,UAAM,UAAU,KAAK,KAAI;AACzB,QAAI,CAAC;AAAS;AAEd,QAAI;AACJ,QAAI;AACF,eAAS,KAAK,MAAM,OAAO;IAC7B,QAAQ;AAEN;IACF;AAEA,UAAM,MAAM;AAGZ,QAAI,IAAI,WAAW,QAAW;AAE5B;IACF;AAEA,UAAM,KAAK,IAAI;AACf,QAAI,OAAO,UAAa,OAAO;AAAM;AAErC,UAAM,UAAU,KAAK,gBAAgB,IAAI,EAAqB;AAC9D,QAAI,CAAC;AAAS;AAEd,SAAK,gBAAgB,OAAO,EAAqB;AAEjD,QAAI,WAAW,OAAO,IAAI,OAAO;AAC/B,YAAM,MAAM,IAAI;AAChB,cAAQ,OAAO,IAAI,aAAa,IAAI,SAAS,IAAI,MAAM,IAAI,IAAI,CAAC;IAClE,OAAO;AACL,cAAQ,QAAQ,IAAI,MAAM;IAC5B;EACF;;;;EAKA,YAAS;AACP,eAAW,CAAC,EAAE,OAAO,KAAK,KAAK,iBAAiB;AAC9C,cAAQ,OAAO,IAAI,aAAa,0BAA0B,EAAE,CAAC;IAC/D;AACA,SAAK,gBAAgB,MAAK;EAC5B;;;;EAMQ,YAAY,QAAgB,QAAe;AACjD,UAAM,KAAK,KAAK;AAEhB,UAAM,UAA0B;MAC9B,SAAS;MACT;MACA;MACA;;AAGF,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAU;AACrC,WAAK,gBAAgB,IAAI,IAAI,EAAE,SAAS,OAAM,CAAE;AAEhD,UAAI;AACF,aAAK,QAAQ,GAAG,KAAK,UAAU,OAAO,CAAC;CAAI;MAC7C,SAAS,KAAK;AACZ,aAAK,gBAAgB,OAAO,EAAE;AAC9B,cAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,eAAO,IAAI,aAAa,2BAA2B,OAAO,IAAI,EAAE,CAAC;MACnE;IACF,CAAC;EACH;;;;ADjEF,SAAS,mBAAmB,SAA4B;AACtD,QAAM,EAAE,UAAAA,WAAU,cAAc,WAAW,QAAQ,OAAO,OAAM,IAAK;AACrE,QAAMC,UAAS,aAAa,EAAE,MAAMD,UAAS,MAAM,OAAO,SAAQ,CAAE;AACpE,QAAM,SAAS,QAAQ,GAAG,KAAK,YAAY;AAC3C,QAAM,UAAU,IAAI,cAAa;AACjC,QAAM,UAAU,IAAI,cAAa;AAEjC,EAAAC,QAAO,KAAK,YAAY,MAAM,KAAKD,UAAS,WAAW,KAAKA,UAAS,OAAO,EAAE;AAE9E,QAAM,KAAK,gBAAgB;IACzB,OAAO,QAAQ;IACf,UAAU;GACX;AAED,KAAG,GAAG,QAAQ,CAAC,SAAQ;AACrB,SAAK,WAAW,MAAMA,WAAU,cAAc,QAAQC,SAAQ,SAAS,OAAO;EAChF,CAAC;AAED,KAAG,GAAG,SAAS,MAAK;AAClB,IAAAA,QAAO,KAAK,6BAA6B;AACzC,YAAQ,UAAS;AACjB,YAAQ,UAAS;AACjB,YAAQ,KAAK,CAAC;EAChB,CAAC;AAED,UAAQ,GAAG,qBAAqB,CAAC,UAAS;AACxC,IAAAA,QAAO,MAAM,sBAAsB,KAAK;AACxC,YAAQ,KAAK,CAAC;EAChB,CAAC;AAED,UAAQ,GAAG,sBAAsB,CAAC,WAAU;AAC1C,IAAAA,QAAO,MAAM,uBAAuB,MAAM;EAC5C,CAAC;AACH;AAQA,SAAS,kBAAkB,KAA4B;AACrD,MAAI,IAAI,WAAW;AAAW,WAAO;AACrC,MAAI,IAAI,OAAO,UAAa,IAAI,OAAO;AAAM,WAAO;AACpD,SAAO,YAAY,OAAO,WAAW;AACvC;AAEA,eAAe,WACb,MACAD,WACA,cACA,QACAC,SACA,SACA,SAAsB;AAEtB,QAAM,UAAU,KAAK,KAAI;AACzB,MAAI,CAAC;AAAS;AAMd,MAAI;AACJ,MAAI;AACF,aAAS,KAAK,MAAM,OAAO;EAC7B,QAAQ;EAER;AAEA,MAAI,UAAU,kBAAkB,MAAM,GAAG;AACvC,IAAAA,QAAO,MAAM,gCAAgC,EAAE,IAAI,OAAO,GAAE,CAAE;AAC9D,QAAI,CAAC,QAAQ,eAAe,OAAO,GAAG;AACpC,cAAQ,eAAe,OAAO;IAChC;AACA;EACF;AAEA,MAAI,KAA6B;AAEjC,MAAI;AACF,UAAM,UAAW,UAAU,KAAK,MAAM,OAAO;AAC7C,SAAK,QAAQ;AAEb,IAAAA,QAAO,MAAM,qBAAqB,QAAQ,MAAM,IAAI,EAAE,IAAI,QAAQ,GAAE,CAAE;AAMtE,UAAM,WAAW,MAAM,uBAAuB,QAAQ,IAAI,MACxD,cAAc,SAASD,WAAU,cAAc,QAAQC,SAAQ,SAAS,OAAO,CAAC;AAElF,QAAI,aAAa,MAAM;AACrB,oBAAc,QAAQ;IACxB;EACF,SAAS,OAAO;AACd,QAAI,iBAAiB,aAAa;AAChC,oBAAc;QACZ,SAAS;QACT,IAAI;QACJ,OAAO;UACL,MAAM,qBAAqB;UAC3B,SAAS;;OAEZ;IACH,WAAW,iBAAiB,aAAa;AACvC,oBAAc;QACZ,SAAS;QACT;QACA,OAAO,MAAM,eAAc;OAC5B;IACH,OAAO;AACL,YAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,MAAAA,QAAO,MAAM,kBAAkB,KAAK;AACpC,oBAAc;QACZ,SAAS;QACT;QACA,OAAO;UACL,MAAM,qBAAqB;UAC3B;;OAEH;IACH;EACF;AACF;AAEA,eAAe,cACb,SACAD,WACA,cACA,QACAC,SACA,SACA,SAAsB;AAEtB,QAAM,EAAE,QAAQ,QAAQ,GAAE,IAAK;AAG/B,UAAQ,QAAQ;IACd,KAAK,cAAc;AACjB,YAAM,aAAc,UAAU,CAAA;AAG9B,iBAAW,UAAU;AACrB,iBAAW,UAAU;AACrB,UAAI,cAAc;AAChB,cAAM,aAAa,UAAU;MAC/B;AACA,aAAO,EAAE,SAAS,OAAO,IAAI,QAAQD,UAAQ;IAC/C;IAEA,KAAK;AACH,aAAO,EAAE,SAAS,OAAO,IAAI,QAAQ,OAAM;IAE7C,KAAK,YAAY;AACf,MAAAC,QAAO,KAAK,oBAAoB;AAChC,cAAQ,UAAS;AACjB,cAAQ,UAAS;AACjB,YAAMC,YAA4B,EAAE,SAAS,OAAO,IAAI,QAAQ,KAAI;AACpE,cAAQ,OAAO,MAAM,GAAG,KAAK,UAAUA,SAAQ,CAAC;GAAM,MAAK;AACzD,gBAAQ,KAAK,CAAC;MAChB,CAAC;AAED,aAAO;IACT;EACF;AAGA,QAAM,WAAW,MAAM,OAAO,QAAQ,QAAQ,EAAE;AAChD,MAAI,aAAa,MAAM;AACrB,WAAO;EACT;AAGA,SAAO;IACL,SAAS;IACT;IACA,OAAO;MACL,MAAM,qBAAqB;MAC3B,SAAS,qBAAqB,MAAM;;;AAG1C;AAEA,SAAS,cAAc,UAAyB;AAC9C,UAAQ,OAAO,MAAM,GAAG,KAAK,UAAU,QAAQ,CAAC;CAAI;AACtD;AAMA,SAAS,eAAe,IAA4B,SAAe;AACjE,SAAO;IACL,SAAS;IACT;IACA,OAAO;MACL,MAAM,qBAAqB;MAC3B;;;AAGN;AAEA,SAAS,QAAQ,IAA4B,QAAe;AAC1D,SAAO,EAAE,SAAS,OAAO,IAAI,OAAM;AACrC;AAsMM,SAAU,iBAAiB,SAA0B;AACzD,QAAM,EAAE,UAAAC,WAAU,UAAAC,WAAU,cAAc,SAAQ,IAAK;AAEvD,QAAM,SAAuB,OAAO,QAAQ,QAAQ,OAAM;AACxD,YAAQ,QAAQ;MACd,KAAK;AACH,eAAO,QAAQ,IAAI,MAAMA,UAAS,YAAW,CAAE;MACjD,KAAK;AACH,eAAO,QAAQ,IAAI,MAAMA,UAAS,aAAa,MAAyB,CAAC;MAC3E,KAAK;AACH,eAAO,QAAQ,IAAI,MAAMA,UAAS,aAAa,MAAyB,CAAC;MAC3E,KAAK,eAAe;AAClB,YAAI,CAACA,UAAS;AAAQ,iBAAO,eAAe,IAAI,0CAA0C;AAC1F,eAAO,QAAQ,IAAI,MAAMA,UAAS,OAAM,CAAE;MAC5C;MACA;AACE,eAAO;IACX;EACF;AAEA,qBAAmB,EAAE,UAAAD,WAAU,cAAc,UAAU,OAAO,QAAQ,OAAM,CAAE;AAChF;;;AE9mBA,IAAM,kBAAkB;AAMxB,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAoBrB,IAAM,mBAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA2CzB,IAAM,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAY3B,IAAM,wBAAwB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiGvB,IAAM,gBAAN,MAAoB;AAAA,EACjB;AAAA,EAER,YAAY,aAAqB;AAC/B,SAAK,cAAc;AAAA,EACrB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAc,MAAS,UAAkB,WAAiD;AACxF,WAAO,KAAK,aAAgB,UAAU,WAAW,IAAI;AAAA,EACvD;AAAA,EAEA,MAAc,aACZ,UACA,WACA,YACY;AACZ,QAAI;AACJ,QAAI;AACF,iBAAW,MAAM,MAAM,iBAAiB;AAAA,QACtC,QAAQ;AAAA,QACR,QAAQ,YAAY,QAAQ,GAAM;AAAA,QAClC,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,QAAQ;AAAA,UACR,eAAe,UAAU,KAAK,WAAW;AAAA,QAC3C;AAAA,QACA,MAAM,KAAK,UAAU,EAAE,OAAO,UAAU,UAAU,CAAC;AAAA,MACrD,CAAC;AAAA,IACH,SAAS,OAAO;AACd,UAAI,iBAAiB,gBAAgB,MAAM,SAAS,gBAAgB;AAClE,cAAM,IAAI,SAAS,gDAAgD;AAAA,MACrE;AACA,YAAM;AAAA,IACR;AAEA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,IAAI,UAAU,4CAA4C;AAAA,IAClE;AAEA,QAAI,SAAS,WAAW,KAAK;AAC3B,YAAM,aAAa,SAAS,QAAQ,IAAI,aAAa;AACrD,YAAM,eAAe,aAAa,OAAO,SAAS,YAAY,EAAE,IAAI;AACpE,YAAM,cAAc,OAAO,MAAM,YAAY,IAAI,KAAK;AAEtD,UAAI,YAAY;AACd,cAAM,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,cAAc,GAAI,CAAC;AACtE,eAAO,KAAK,aAAgB,UAAU,WAAW,KAAK;AAAA,MACxD;AAEA,YAAM,IAAI,eAAe,aAAa,6BAA6B;AAAA,IACrE;AAEA,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,OAAO,MAAM,SAAS,KAAK,EAAE,MAAM,MAAM,EAAE;AACjD,YAAM,IAAI;AAAA,QACR,sBAAsB,SAAS,MAAM,IAAI,SAAS,UAAU,GAAG,OAAO,MAAM,IAAI,KAAK,EAAE;AAAA,MACzF;AAAA,IACF;AAEA,UAAM,OAAQ,MAAM,SAAS,KAAK;AAElC,QAAI,KAAK,QAAQ,QAAQ;AACvB,YAAM,UAAU,KAAK,OAAO,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,IAAI;AAC3D,YAAM,IAAI,SAAS,0BAA0B,OAAO,EAAE;AAAA,IACxD;AAEA,QAAI,CAAC,KAAK,MAAM;AACd,YAAM,IAAI,SAAS,6BAA6B;AAAA,IAClD;AAEA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,YAAoC;AACxC,UAAM,OAAO,MAAM,KAAK,MAAiC,YAAY;AACrE,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,aACJ,QACA,OAAO,GACP,UAAU,IACgE;AAC1E,UAAM,YAAqC,EAAE,QAAQ,MAAM,QAAQ;AAEnE,UAAM,OAAO,MAAM,KAAK,MAKrB,kBAAkB,SAAS;AAE9B,WAAO;AAAA,MACL,UAAU,KAAK,KAAK;AAAA,MACpB,SAAS,KAAK,KAAK;AAAA,IACrB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,UAAU,WAWe;AAC7B,UAAM,OAAO,MAAM,KAAK;AAAA,MACtB;AAAA,MACA;AAAA,IACF;AACA,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MAAM,YAAY,OAAoD;AACpE,QAAI;AACF,YAAM,OAAO,MAAM,KAAK,MAA6C,oBAAoB;AAAA,QACvF,QAAQ;AAAA,MACV,CAAC;AACD,aAAO,KAAK;AAAA,IACd,QAAQ;AACN,aAAO;AAAA,IACT;AAAA,EACF;AACF;AASO,SAAS,oBACd,QACkE;AAClE,UAAQ,QAAQ;AAAA,IACd,KAAK;AAAA,IACL,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAKO,SAAS,oBACd,QAC6D;AAC7D,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO;AAAA,IACT;AACE,aAAO;AAAA,EACX;AACF;AAKO,SAAS,eAAe,MAA+D;AAC5F,MAAI,CAAC,MAAM,KAAM,QAAO;AACxB,QAAM,QAAQ,KAAK,QAAQ,OAAO,KAAK,KAAK,EAAE,SAAS,GAAG,GAAG,IAAI;AACjE,QAAM,MAAM,KAAK,MAAM,OAAO,KAAK,GAAG,EAAE,SAAS,GAAG,GAAG,IAAI;AAC3D,SAAO,GAAG,KAAK,IAAI,IAAI,KAAK,IAAI,GAAG;AACrC;AAKO,SAAS,eAAe,KAAuD;AACpF,MAAI,CAAC,IAAK,QAAO;AACjB,QAAM,IAAI,IAAI,KAAK,GAAG;AACtB,MAAI,OAAO,MAAM,EAAE,QAAQ,CAAC,EAAG,QAAO;AACtC,SAAO;AAAA,IACL,MAAM,EAAE,eAAe;AAAA,IACvB,OAAO,EAAE,YAAY,IAAI;AAAA,IACzB,KAAK,EAAE,WAAW;AAAA,EACpB;AACF;AASO,SAAS,sBAAsB,OAAe,QAAwB;AAC3E,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO,KAAK,MAAM,KAAK;AAAA,IACzB,KAAK;AACH,aAAO,QAAQ;AAAA,IACjB,KAAK;AACH,aAAO,KAAK,MAAM,QAAQ,EAAE;AAAA,IAC9B,KAAK;AACH,aAAO,KAAK,MAAM,QAAQ,EAAE;AAAA,IAC9B,KAAK;AACH,UAAI,SAAS,GAAI,QAAO;AACxB,UAAI,SAAS,GAAI,QAAO;AACxB,aAAO;AAAA,IACT;AACE,aAAO,KAAK,MAAM,QAAQ,EAAE;AAAA,EAChC;AACF;AAKO,SAAS,wBAAwB,OAAe,QAAwB;AAC7E,UAAQ,QAAQ;AAAA,IACd,KAAK;AACH,aAAO;AAAA,IACT,KAAK;AACH,aAAO,QAAQ;AAAA,IACjB,KAAK;AACH,aAAO,QAAQ;AAAA,IACjB,KAAK;AACH,aAAO,QAAQ;AAAA,IACjB,KAAK;AACH,aAAO,KAAK,MAAM,QAAQ,IAAI;AAAA,IAChC;AACE,aAAO,QAAQ;AAAA,EACnB;AACF;;;AClcA;AAAA,EACE,MAAQ;AAAA,EACR,SAAW;AAAA,EACX,aAAe;AAAA,EACf,MAAQ;AAAA,EACR,KAAO;AAAA,EACP,MAAQ;AAAA,EACR,OAAS;AAAA,IACP;AAAA,IACA;AAAA,EACF;AAAA,EACA,YAAc;AAAA,IACZ,MAAQ;AAAA,IACR,KAAO;AAAA,IACP,WAAa;AAAA,EACf;AAAA,EACA,SAAW;AAAA,IACT,OAAS;AAAA,IACT,KAAO;AAAA,IACP,OAAS;AAAA,IACT,OAAS;AAAA,IACT,MAAQ;AAAA,IACR,YAAY;AAAA,IACZ,WAAa;AAAA,IACb,MAAQ;AAAA,IACR,cAAc;AAAA,IACd,gBAAkB;AAAA,EACpB;AAAA,EACA,UAAY;AAAA,IACV;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF;AAAA,EACA,QAAU;AAAA,EACV,SAAW;AAAA,EACX,SAAW;AAAA,IACT,MAAQ;AAAA,EACV;AAAA,EACA,cAAgB;AAAA,IACd,4BAA4B;AAAA,EAC9B;AAAA,EACA,iBAAmB;AAAA,IACjB,kBAAkB;AAAA,IAClB,eAAe;AAAA,IACf,SAAW;AAAA,IACX,YAAc;AAAA,IACd,QAAU;AAAA,EACZ;AACF;;;AC/CA,IAAM,6BAA6B;AAE5B,IAAM,WAAW;AAAA,EACtB,MAAM;AAAA,EACN,aAAa;AAAA,EACb,SAAS,gBAAY;AAAA,EACrB,aACE;AAAA,EACF,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,iBAAiB;AAAA,EACjB,cAAc;AAAA,IACZ,cAAc;AAAA,IACd,kBAAkB;AAAA,EACpB;AAAA,EACA,qBAAqB;AAAA,IACnB;AAAA,MACE,KAAK;AAAA,MACL,OAAO;AAAA,MACP,aAAa;AAAA,MACb,MAAM;AAAA,MACN,UAAU;AAAA,MACV,WAAW;AAAA,IACb;AAAA,EACF;AAAA,EACA,kBAAkB;AAAA,IAChB,aAAa;AAAA,IACb,QAAQ;AAAA,MACN;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,aACE;AAAA,QACF,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS;AAAA,MACX;AAAA,MACA;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,aACE;AAAA,QACF,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS;AAAA,MACX;AAAA,MACA;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,aACE;AAAA,QACF,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS;AAAA,MACX;AAAA,MACA;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,aACE;AAAA,QACF,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS;AAAA,MACX;AAAA,MACA;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,aACE;AAAA,QACF,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS;AAAA,MACX;AAAA,MACA;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,aACE;AAAA,QACF,MAAM;AAAA,QACN,UAAU;AAAA,QACV,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF;AAAA,EACA,OAAO;AAAA,IACL,kBAAkB;AAAA,IAClB,UAAU;AAAA,IACV,QAAQ,CAAC;AAAA,IACT,MAAM;AAAA,EACR;AAAA,EACA,iBAAiB;AAAA,EACjB,wBACE;AAAA,EACF,uBACE;AACJ;;;AC5DA,IAAM,SAAS,aAAa,EAAE,MAAM,gBAAgB,OAAO,QAAQ,CAAC;AAGpE,IAAI,SAA+B;AACnC,IAAI,WAA0B;AAC9B,IAAI,cAAc;AAGlB,IAAI,eAAuC;AAC3C,IAAI,iBAAiB;AACrB,IAAI,gBAAgB;AACpB,IAAI,iBAAiB;AACrB,IAAI,cAAc;AAClB,IAAI,wBAAwB;AAGrB,SAAS,UAAU,GAA+B;AACvD,WAAS;AACX;AAGO,SAAS,YAAY,IAAyB;AACnD,aAAW;AACb;AAGO,SAAS,kBAAkB,SAAwB;AACxD,mBAAiB;AACnB;AAGO,SAAS,eAAe,SAAwB;AACrD,gBAAc;AAChB;AAGO,SAAS,yBAAyB,SAAwB;AAC/D,0BAAwB;AAC1B;AAYO,SAAS,eACd,QACA,iBACA,WACA,UACA,KACqB;AACrB,MAAI,WAAW,UAAW,QAAO;AACjC,MAAI,cAAc,KAAK,aAAa,EAAG,QAAO;AAC9C,MAAI,CAAC,gBAAiB,QAAO;AAE7B,QAAM,eAAe,IAAI,KAAK,eAAe,EAAE,QAAQ;AACvD,MAAI,OAAO,MAAM,YAAY,EAAG,QAAO;AAEvC,QAAM,cAAc,OAAO,KAAK,IAAI;AACpC,QAAM,eAAe,KAAK,IAAI,IAAI,cAAc,iBAAiB,MAAO,KAAK,KAAK,GAAG;AAGrF,MAAI,WAAW,KAAK,gBAAgB,UAAU;AAC5C,WAAO;AAAA,EACT;AACA,MAAI,YAAY,KAAK,gBAAgB,WAAW;AAC9C,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAOO,IAAM,WAAyB;AAAA,EACpC,MAAM,cAAyC;AAC7C,QAAI,CAAC,QAAQ;AACX,YAAM,IAAI,MAAM,4CAA4C;AAAA,IAC9D;AAEA,UAAM,SAAS,MAAM,OAAO,UAAU;AACtC,eAAW,OAAO;AAClB,kBAAc,OAAO,iBAAiB;AAEtC,WAAO,KAAK,oBAAoB,OAAO,IAAI,SAAS,OAAO,EAAE,kBAAkB,WAAW,GAAG;AAE7F,WAAO;AAAA,MACL,YAAY,OAAO,OAAO,EAAE;AAAA,MAC5B,UAAU,OAAO;AAAA,MACjB,WAAW,OAAO,OAAO,SAAS,OAAO,OAAO;AAAA,MAChD,YAAY,OAAO;AAAA,IACrB;AAAA,EACF;AAAA,EAEA,MAAM,aAAa,QAAoD;AACrE,QAAI,CAAC,UAAU,aAAa,MAAM;AAChC,YAAM,IAAI,MAAM,iDAAiD;AAAA,IACnE;AAGA,UAAM,mBAAmB,oBAAI,IAAY;AACzC,QAAI,OAAO;AACX,QAAI,UAAU;AACd,WAAO,SAAS;AACd,YAAM,SAAS,MAAM,OAAO,aAAa,UAAU,MAAM,EAAE;AAC3D,iBAAW,SAAS,OAAO,SAAS;AAClC,yBAAiB,IAAI,MAAM,OAAO;AAAA,MACpC;AACA,gBAAU,OAAO,SAAS;AAC1B;AAAA,IACF;AAEA,UAAME,WAA6B,CAAC;AACpC,UAAM,SAA4B,CAAC;AAEnC,eAAW,SAAS,OAAO,SAAS;AAClC,UAAI;AACF,YAAI,UAAU,OAAO,SAAS,MAAM,YAAY,EAAE;AAClD,YAAI,OAAO,MAAM,OAAO,GAAG;AAEzB,cAAI,kBAAkB,MAAM,OAAO;AACjC,kBAAMC,UAAS,MAAM,OAAO,YAAY,MAAM,KAAK;AACnD,gBAAIA,SAAQ;AACV,wBAAUA,QAAO;AACjB,qBAAO,KAAK,6BAA6B,MAAM,KAAK,uBAAkB,OAAO,EAAE;AAAA,YACjF;AAAA,UACF;AAEA,cAAI,OAAO,MAAM,OAAO,GAAG;AACzB,mBAAO,KAAK;AAAA,cACV,YAAY,MAAM;AAAA,cAClB,QAAQ;AAAA,cACR,OAAO,iBACH,+BAA+B,MAAM,SAAS,MAAM,UAAU,MAC9D,qBAAqB,MAAM,UAAU;AAAA,YAC3C,CAAC;AACD;AAAA,UACF;AAAA,QACF;AAGA,cAAM,kBAAkB;AAAA,UACtB,MAAM;AAAA,UACN,MAAM;AAAA,UACN;AAAA,UACA;AAAA,QACF;AACA,YAAI,oBAAoB,MAAM,QAAQ;AACpC,iBAAO;AAAA,YACL,SAAS,MAAM,UAAU,UAAU,oBAAoB,YAAY,YAAY,QAAQ,SAAS,MAAM,MAAM;AAAA,UAC9G;AAAA,QACF;AAEA,cAAM,aAWF;AAAA,UACF;AAAA,UACA,QAAQ,oBAAoB,eAAe;AAAA,UAC3C,SAAS;AAAA,UACT;AAAA,QACF;AAMA,cAAM,QAAQ,MAAM,UAAU,WAAW,MAAM,UAAU;AACzD,YAAI,UAAU,QAAW;AACvB,cAAI,iBAAiB,YAAY;AAC/B,uBAAW,WAAW;AAAA,UACxB,OAAO;AACL,uBAAW,kBAAkB;AAAA,UAC/B;AAAA,QACF;AAGA,YAAI,MAAM,UAAU,QAAW;AAC7B,qBAAW,QAAQ,sBAAsB,MAAM,OAAO,WAAW;AAAA,QACnE;AAGA,YAAI,MAAM,WAAW;AACnB,qBAAW,YAAY,eAAe,MAAM,SAAS;AAAA,QACvD;AACA,YAAI,MAAM,aAAa;AACrB,qBAAW,cAAc,eAAe,MAAM,WAAW;AAAA,QAC3D;AAGA,YAAI,MAAM,UAAU,QAAW;AAC7B,qBAAW,QAAQ,MAAM;AAAA,QAC3B;AAEA,cAAM,qBAAqB,OAAO,OAAO;AACzC,cAAM,UAAU,iBAAiB,IAAI,OAAO;AAC5C,cAAM,SAAS,MAAM,OAAO,UAAU,UAAU;AAChD,eAAO,MAAM,gBAAgB,kBAAkB,YAAY,OAAO,MAAM,EAAE;AAG1E,yBAAiB,IAAI,OAAO;AAE5B,QAAAD,SAAQ,KAAK;AAAA,UACX,YAAY;AAAA,UACZ,QAAQ,UAAU,YAAY;AAAA,QAChC,CAAC;AAAA,MACH,SAAS,OAAO;AACd,cAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,eAAO,MAAM,wBAAwB,MAAM,UAAU,KAAK,OAAO,EAAE;AACnE,eAAO,KAAK;AAAA,UACV,YAAY,MAAM;AAAA,UAClB,QAAQ;AAAA,UACR,OAAO;AAAA,QACT,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO,EAAE,SAAAA,UAAS,OAAO;AAAA,EAC3B;AAAA,EAEA,MAAM,aAAa,QAAoD;AACrE,QAAI,CAAC,UAAU,aAAa,MAAM;AAChC,YAAM,IAAI,MAAM,iDAAiD;AAAA,IACnE;AAGA,UAAM,OAAO,OAAO,SAAS,OAAO,SAAS,OAAO,QAAQ,EAAE,IAAI;AAClE,UAAM,UAAU,OAAO,QAAQ,KAAK,IAAI,OAAO,OAAO,EAAE,IAAI;AAE5D,UAAM,SAAS,MAAM,OAAO,aAAa,UAAU,MAAM,OAAO;AAEhE,UAAM,UAAuB,OAAO,QAAQ,IAAI,CAAC,WAAW;AAAA,MAC1D,YAAY,OAAO,MAAM,OAAO;AAAA,MAChC,QAAQ,oBAAoB,MAAM,MAAM;AAAA,MACxC,UAAU;AAAA,QACR,UAAU,MAAM,YAAY;AAAA,QAC5B,SAAS,MAAM,mBAAmB;AAAA,MACpC;AAAA,MACA,OAAO,MAAM,QAAQ,IAAI,wBAAwB,MAAM,OAAO,WAAW,IAAI;AAAA,MAC7E,WAAW,eAAe,MAAM,SAAS;AAAA,MACzC,aAAa,eAAe,MAAM,WAAW;AAAA,MAC7C,OAAO,MAAM,SAAS;AAAA,IACxB,EAAE;AAEF,WAAO;AAAA,MACL,UAAU,QAAQ,MAAM,kBAAkB,OAAO,SAAS,WAAW,IAAI,OAAO,SAAS,QAAQ;AAAA,IACnG;AAEA,WAAO;AAAA,MACL;AAAA,MACA,YAAY,OAAO,SAAS,cAAc,OAAO,OAAO,SAAS,cAAc,CAAC,IAAI;AAAA,MACpF,SAAS,OAAO,SAAS;AAAA,IAC3B;AAAA,EACF;AAAA,EAEA,MAAM,SAAsC;AAC1C,QAAI,CAAC,UAAU,aAAa,MAAM;AAChC,aAAO;AAAA,QACL,aAAa;AAAA,QACb,aAAa;AAAA,QACb,WAAW;AAAA,MACb;AAAA,IACF;AAGA,UAAM,SAAS,MAAM,OAAO,aAAa,UAAU,GAAG,CAAC;AAEvD,WAAO;AAAA,MACL,eAAe,OAAO,SAAS;AAAA,MAC/B,aAAa;AAAA,MACb,aAAa;AAAA,MACb,WAAW;AAAA,IACb;AAAA,EACF;AACF;AAMA,iBAAiB;AAAA,EACf;AAAA,EACA;AAAA,EACA,UAAU;AAAA,EACV,aAAa,QAA0B;AAErC,UAAM,cAAc,OAAO,aAAa;AACxC,QAAI,aAAa;AACf,eAAS,IAAI,cAAc,WAAW;AACtC,aAAO,KAAK,8CAA8C;AAAA,IAC5D,OAAO;AACL,aAAO,KAAK,sDAAsD;AAAA,IACpE;AAGA,UAAM,KAAK,OAAO;AAClB,QAAI,IAAI;AACN,YAAM,OAAO,GAAG;AAChB,UAAI,SAAS,cAAc,SAAS,WAAW;AAC7C,uBAAe;AAAA,MACjB;AACA,UAAI,OAAO,GAAG,mBAAmB,YAAY,GAAG,kBAAkB,GAAG;AACnE,yBAAiB,GAAG;AAAA,MACtB;AACA,UAAI,OAAO,GAAG,kBAAkB,YAAY,GAAG,iBAAiB,GAAG;AACjE,wBAAgB,GAAG;AAAA,MACrB;AACA,UAAI,OAAO,GAAG,mBAAmB,WAAW;AAC1C,yBAAiB,GAAG;AAAA,MACtB;AACA,UAAI,OAAO,GAAG,YAAY,WAAW;AACnC,sBAAc,GAAG;AAAA,MACnB;AACA,UAAI,OAAO,GAAG,0BAA0B,WAAW;AACjD,gCAAwB,GAAG;AAAA,MAC7B;AACA,aAAO;AAAA,QACL,+BAA+B,YAAY,oBAAoB,cAAc,mBAAmB,aAAa,oBAAoB,cAAc,aAAa,WAAW,2BAA2B,qBAAqB;AAAA,MACzN;AAAA,IACF;AAAA,EACF;AACF,CAAC;AAED,OAAO,KAAK,6BAA6B;",
6
6
  "names": ["manifest", "logger", "response", "manifest", "provider", "success", "result"]
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ashdev/codex-plugin-sync-anilist",
3
- "version": "1.18.0",
3
+ "version": "1.19.0",
4
4
  "description": "AniList reading progress sync plugin for Codex",
5
5
  "main": "dist/index.js",
6
6
  "bin": "dist/index.js",
@@ -40,7 +40,7 @@
40
40
  "node": ">=22.0.0"
41
41
  },
42
42
  "dependencies": {
43
- "@ashdev/codex-plugin-sdk": "^1.18.0"
43
+ "@ashdev/codex-plugin-sdk": "^1.19.0"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@biomejs/biome": "^2.4.4",