fix(plugins): mangabaka never deletes on upsert without entry
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
ddd938935e
commit
f30c0db2b1
3 files changed
+24
-4
No files matched your search
@@ -13,7 +13,7 @@ export const STATE_MAP: Record<string, Status> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function mapState(s: string | null | undefined): Status {
|
export function mapState(s: string | null | undefined): Status {
|
||||||
return (s != null && STATE_MAP[s]) || "none";
|
return s != null && Object.hasOwn(STATE_MAP, s) ? STATE_MAP[s]! : "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
function hint(e: ApiEntry): WorkHint {
|
function hint(e: ApiEntry): WorkHint {
|
||||||
|
|||||||
@@ -18,8 +18,9 @@ export async function* pullChanges(ctx: PluginContext): AsyncIterable<SourceReco
|
|||||||
for (;;) {
|
for (;;) {
|
||||||
const res = await ctx.http.json<ChangesPage>(`${BASE_URL}/v2/my/library/changes`, { headers, query: { cursor }, signal: ctx.signal });
|
const res = await ctx.http.json<ChangesPage>(`${BASE_URL}/v2/my/library/changes`, { headers, query: { cursor }, signal: ctx.signal });
|
||||||
for (const c of res.data) {
|
for (const c of res.data) {
|
||||||
if (c.type === "delete" || !c.entry) yield* mapDeletion(c.series_id);
|
if (c.type === "delete") yield* mapDeletion(c.series_id);
|
||||||
else yield* mapEntry(c.entry);
|
else if (c.entry) yield* mapEntry(c.entry);
|
||||||
|
else ctx.log(`mangabaka: upsert without entry for series ${c.series_id}, skipped`);
|
||||||
}
|
}
|
||||||
const next = res.next_cursor;
|
const next = res.next_cursor;
|
||||||
if (next) {
|
if (next) {
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { describe, expect, test } from "bun:test";
|
|||||||
import { collect, createFixtureHttp, createTestContext } from "@sttracker/plugin-sdk/testing";
|
import { collect, createFixtureHttp, createTestContext } from "@sttracker/plugin-sdk/testing";
|
||||||
import type { Status } from "@sttracker/plugin-sdk/types";
|
import type { Status } from "@sttracker/plugin-sdk/types";
|
||||||
import plugin from "../index.ts";
|
import plugin from "../index.ts";
|
||||||
import { mapState } from "../src/map.ts";
|
import { mapDeletion, mapState } from "../src/map.ts";
|
||||||
import page1 from "./fixtures/library-page1.json";
|
import page1 from "./fixtures/library-page1.json";
|
||||||
import page2 from "./fixtures/library-page2.json";
|
import page2 from "./fixtures/library-page2.json";
|
||||||
import changes from "./fixtures/changes.json";
|
import changes from "./fixtures/changes.json";
|
||||||
@@ -66,6 +66,25 @@ describe("mangabaka", () => {
|
|||||||
expect(new URL(h.calls[0]!.url).searchParams.get("cursor")).toBe("cur-1");
|
expect(new URL(h.calls[0]!.url).searchParams.get("cursor")).toBe("cur-1");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("upsert without entry is skipped and logged, never deleted", async () => {
|
||||||
|
const logs: string[] = [];
|
||||||
|
const h = createFixtureHttp({ [`GET ${B}/v2/my/library/changes`]: { data: [{ type: "upsert", series_id: 4 }], next_cursor: "c" } });
|
||||||
|
const ctx = createTestContext({ fetch: h.fetch, config: { token: "tok" }, log: (m) => logs.push(m) });
|
||||||
|
const recs = await collect(plugin.pullChanges!(ctx));
|
||||||
|
expect(recs).toEqual([]);
|
||||||
|
expect(logs).toEqual(["mangabaka: upsert without entry for series 4, skipped"]);
|
||||||
|
});
|
||||||
|
|
||||||
|
test("inherited keys are not states", () => expect(mapState("constructor")).toBe("none"));
|
||||||
|
|
||||||
|
test("delete keys are a subset of keys a full pull produced", async () => {
|
||||||
|
const { ctx } = ctxFor({ [`GET ${B}/v1/my/library?page=1`]: page1, [`GET ${B}/v1/my/library?page=2`]: page2 });
|
||||||
|
const pulled = (await collect(plugin.pull!(ctx))).map((r) => r.key);
|
||||||
|
const del = mapDeletion(1).map((r) => r.key);
|
||||||
|
expect(del).toEqual(["series:1", "progress:1"]);
|
||||||
|
for (const k of del) expect(pulled).toContain(k);
|
||||||
|
});
|
||||||
|
|
||||||
test("lookup searches series", async () => {
|
test("lookup searches series", async () => {
|
||||||
const { h, ctx } = ctxFor({ [`GET ${B}/v1/series/search`]: search });
|
const { h, ctx } = ctxFor({ [`GET ${B}/v1/series/search`]: search });
|
||||||
const r = await plugin.lookup!(ctx, { title: "Delta", mediaType: "manga" });
|
const r = await plugin.lookup!(ctx, { title: "Delta", mediaType: "manga" });
|
||||||
|
|||||||
Reference in new issue
Block a user