@ashdev/codex-plugin-sync-anilist 1.10.1 → 1.10.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -530,7 +530,9 @@ var UPDATE_ENTRY_MUTATION = `
530
530
  $progressVolumes: Int,
531
531
  $startedAt: FuzzyDateInput,
532
532
  $completedAt: FuzzyDateInput,
533
- $notes: String
533
+ $notes: String,
534
+ $private: Boolean,
535
+ $hiddenFromStatusLists: Boolean
534
536
  ) {
535
537
  SaveMediaListEntry(
536
538
  mediaId: $mediaId,
@@ -540,7 +542,9 @@ var UPDATE_ENTRY_MUTATION = `
540
542
  progressVolumes: $progressVolumes,
541
543
  startedAt: $startedAt,
542
544
  completedAt: $completedAt,
543
- notes: $notes
545
+ notes: $notes,
546
+ private: $private,
547
+ hiddenFromStatusLists: $hiddenFromStatusLists
544
548
  ) {
545
549
  id
546
550
  mediaId
@@ -741,7 +745,7 @@ function convertScoreFromAnilist(score, format) {
741
745
  // package.json
742
746
  var package_default = {
743
747
  name: "@ashdev/codex-plugin-sync-anilist",
744
- version: "1.10.1",
748
+ version: "1.10.2",
745
749
  description: "AniList reading progress sync plugin for Codex",
746
750
  main: "dist/index.js",
747
751
  bin: "dist/index.js",
@@ -781,7 +785,7 @@ var package_default = {
781
785
  node: ">=22.0.0"
782
786
  },
783
787
  dependencies: {
784
- "@ashdev/codex-plugin-sdk": "^1.10.1"
788
+ "@ashdev/codex-plugin-sdk": "^1.10.2"
785
789
  },
786
790
  devDependencies: {
787
791
  "@biomejs/biome": "^2.3.13",
@@ -849,6 +853,22 @@ var manifest = {
849
853
  type: "boolean",
850
854
  required: false,
851
855
  default: false
856
+ },
857
+ {
858
+ key: "private",
859
+ label: "Private Mode",
860
+ description: "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).",
861
+ type: "boolean",
862
+ required: false,
863
+ default: true
864
+ },
865
+ {
866
+ key: "hiddenFromStatusLists",
867
+ label: "Hide from Status Lists",
868
+ description: "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.",
869
+ type: "boolean",
870
+ required: false,
871
+ default: false
852
872
  }
853
873
  ]
854
874
  },
@@ -872,6 +892,8 @@ var progressUnit = "volumes";
872
892
  var pauseAfterDays = 0;
873
893
  var dropAfterDays = 0;
874
894
  var searchFallback = false;
895
+ var privateMode = true;
896
+ var hiddenFromStatusLists = false;
875
897
  function setClient(c) {
876
898
  client = c;
877
899
  }
@@ -881,6 +903,12 @@ function setViewerId(id) {
881
903
  function setSearchFallback(enabled) {
882
904
  searchFallback = enabled;
883
905
  }
906
+ function setPrivateMode(enabled) {
907
+ privateMode = enabled;
908
+ }
909
+ function setHiddenFromStatusLists(enabled) {
910
+ hiddenFromStatusLists = enabled;
911
+ }
884
912
  function applyStaleness(status, latestUpdatedAt, pauseDays, dropDays, now) {
885
913
  if (status !== "reading") return status;
886
914
  if (pauseDays === 0 && dropDays === 0) return status;
@@ -963,7 +991,9 @@ var provider = {
963
991
  }
964
992
  const saveParams = {
965
993
  mediaId,
966
- status: syncStatusToAnilist(effectiveStatus)
994
+ status: syncStatusToAnilist(effectiveStatus),
995
+ private: privateMode,
996
+ hiddenFromStatusLists
967
997
  };
968
998
  const count = entry.progress?.volumes ?? entry.progress?.chapters;
969
999
  if (count !== void 0) {
@@ -1078,8 +1108,14 @@ createSyncPlugin({
1078
1108
  if (typeof uc.searchFallback === "boolean") {
1079
1109
  searchFallback = uc.searchFallback;
1080
1110
  }
1111
+ if (typeof uc.private === "boolean") {
1112
+ privateMode = uc.private;
1113
+ }
1114
+ if (typeof uc.hiddenFromStatusLists === "boolean") {
1115
+ hiddenFromStatusLists = uc.hiddenFromStatusLists;
1116
+ }
1081
1117
  logger.info(
1082
- `Plugin config: progressUnit=${progressUnit}, pauseAfterDays=${pauseAfterDays}, dropAfterDays=${dropAfterDays}, searchFallback=${searchFallback}`
1118
+ `Plugin config: progressUnit=${progressUnit}, pauseAfterDays=${pauseAfterDays}, dropAfterDays=${dropAfterDays}, searchFallback=${searchFallback}, private=${privateMode}, hiddenFromStatusLists=${hiddenFromStatusLists}`
1083
1119
  );
1084
1120
  }
1085
1121
  }
@@ -1089,6 +1125,8 @@ export {
1089
1125
  applyStaleness,
1090
1126
  provider,
1091
1127
  setClient,
1128
+ setHiddenFromStatusLists,
1129
+ setPrivateMode,
1092
1130
  setSearchFallback,
1093
1131
  setViewerId
1094
1132
  };
package/dist/index.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
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", "../node_modules/@ashdev/codex-plugin-sdk/src/types/manifest.ts", "../src/anilist.ts", "../package.json", "../src/manifest.ts", "../src/index.ts"],
4
- "sourcesContent": [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 ) {\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 ) {\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 }): 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.10.1\",\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.10.1\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.3.13\",\n \"@types/node\": \"^22.0.0\",\n \"esbuild\": \"^0.24.0\",\n \"typescript\": \"^5.7.0\",\n \"vitest\": \"^3.0.0\"\n }\n}\n", "import { EXTERNAL_ID_SOURCE_ANILIST, type PluginManifest } from \"@ashdev/codex-plugin-sdk\";\nimport packageJson from \"../package.json\" with { type: \"json\" };\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 },\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;\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// =============================================================================\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 } = {\n mediaId,\n status: syncStatusToAnilist(effectiveStatus),\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 logger.info(\n `Plugin config: progressUnit=${progressUnit}, pauseAfterDays=${pauseAfterDays}, dropAfterDays=${dropAfterDays}, searchFallback=${searchFallback}`,\n );\n }\n },\n});\n\nlogger.info(\"AniList sync plugin started\");\n"],
5
- "mappings": "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",
4
+ "sourcesContent": [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.10.2\",\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.10.2\"\n },\n \"devDependencies\": {\n \"@biomejs/biome\": \"^2.3.13\",\n \"@types/node\": \"^22.0.0\",\n \"esbuild\": \"^0.24.0\",\n \"typescript\": \"^5.7.0\",\n \"vitest\": \"^3.0.0\"\n }\n}\n", "import { EXTERNAL_ID_SOURCE_ANILIST, type PluginManifest } from \"@ashdev/codex-plugin-sdk\";\nimport packageJson from \"../package.json\" with { type: \"json\" };\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": "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",
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.10.1",
3
+ "version": "1.10.2",
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.10.1"
43
+ "@ashdev/codex-plugin-sdk": "^1.10.2"
44
44
  },
45
45
  "devDependencies": {
46
46
  "@biomejs/biome": "^2.3.13",