@ashdev/codex-plugin-sync-anilist 1.10.0 → 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 +44 -6
- package/dist/index.js.map +2 -2
- package/package.json +2 -2
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.
|
|
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.
|
|
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.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.10.0\"\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.
|
|
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.
|
|
43
|
+
"@ashdev/codex-plugin-sdk": "^1.10.2"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@biomejs/biome": "^2.3.13",
|