feat(core): jobs, scheduler, plugin registry, connections

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
This commit is contained in:
Lucas Winther
2026-10-30 20:39:17 +01:00
co-authored by Claude Sonnet 5.5
parent 207c92bb4d
commit 166b8ecb5e
20 changed files with 744 additions and 10 deletions
+1 -2
View File
@@ -4,8 +4,6 @@ import { gql, LISTS_QUERY, PAGE_SIZE, SEARCH_QUERY, USER_BOOKS_QUERY } from "./s
import { mapList, mapUserBook } from "./src/map.ts";
import type { HcList, HcUserBook } from "./src/map.ts";
export { RATE_PER_MINUTE } from "./src/graphql.ts";
async function* pageUserBooks(ctx: PluginContext, where: Record<string, unknown> | null): AsyncGenerator<HcUserBook> {
for (let offset = 0; ; offset += PAGE_SIZE) {
const d = await gql<{ me: { user_books: HcUserBook[] }[] }>(ctx, USER_BOOKS_QUERY, { limit: PAGE_SIZE, offset, where });
@@ -45,6 +43,7 @@ export default definePlugin({
name: "Hardcover",
version: "0.1.0",
sdkVersion: 1,
rateLimit: { perMinute: 50 },
mediaTypes: ["book"],
capabilities: ["pull", "pullChanges", "lookup"],
config: [{ key: "token", label: "Personal access token", type: "secret", required: true }],
-1
View File
@@ -2,7 +2,6 @@ import { HttpError } from "@sttracker/plugin-sdk/http";
import type { PluginContext } from "@sttracker/plugin-sdk/types";
export const ENDPOINT = "https://api.hardcover.app/v1/graphql";
export const RATE_PER_MINUTE = 50;
export const PAGE_SIZE = 100;
const BOOK = `id title release_year contributions { author { name } }`;
+1
View File
@@ -7,6 +7,7 @@ export default definePlugin({
name: "Last.fm",
version: "0.1.0",
sdkVersion: 1,
rateLimit: { perMinute: 240 },
mediaTypes: ["track", "album", "artist"],
capabilities: ["pull", "pullChanges"],
config: [
+1
View File
@@ -7,6 +7,7 @@ export default definePlugin({
name: "ListenBrainz",
version: "0.1.0",
sdkVersion: 1,
rateLimit: { perMinute: 60 },
mediaTypes: ["track", "album", "artist"],
capabilities: ["pull", "pullChanges"],
config: [
+1
View File
@@ -8,6 +8,7 @@ export default definePlugin({
name: "MangaBaka",
version: "0.1.0",
sdkVersion: 1,
rateLimit: { perMinute: 150 },
mediaTypes: ["manga", "comic"],
capabilities: ["pull", "pullChanges", "lookup"],
config: [{ key: "token", label: "API token", type: "secret", required: true, help: "Sent as the x-api-key header." }],
-1
View File
@@ -2,7 +2,6 @@ import type { PluginContext } from "@sttracker/plugin-sdk/types";
export const BASE_URL = "https://api.mangabaka.org";
/** The host builds the HttpClient; it should use this rate for this plugin. */
export const RATE_PER_MINUTE = 150;
export interface ApiSource { id?: number | string | null }
export interface ApiSeries {
+1
View File
@@ -12,6 +12,7 @@ export default definePlugin({
name: "Trakt",
version: "0.1.0",
sdkVersion: 1,
rateLimit: { perMinute: 100 },
mediaTypes: ["movie", "show", "season", "episode"],
capabilities: ["pull", "pullChanges", "lookup"],
config: [
-2
View File
@@ -2,8 +2,6 @@ import { HttpError } from "@sttracker/plugin-sdk/http";
import type { PluginContext } from "@sttracker/plugin-sdk/types";
export const BASE = "https://api.trakt.tv";
/** Rate the host should configure for this plugin's HttpClient. */
export const RATE_PER_MINUTE = 100;
const REFRESH_WINDOW_MS = 24 * 60 * 60 * 1000;
const REDIRECT_URI = "urn:ietf:wg:oauth:2.0:oob";