style: add prettier and format codebase
This commit is contained in:
parent
bf459740fe
commit
2f58ac7bf8
18 changed files with 151 additions and 70 deletions
7
.prettierrc
Normal file
7
.prettierrc
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
{
|
||||||
|
"semi": true,
|
||||||
|
"singleQuote": false,
|
||||||
|
"trailingComma": "all",
|
||||||
|
"tabWidth": 2,
|
||||||
|
"printWidth": 80
|
||||||
|
}
|
||||||
40
README.md
40
README.md
|
|
@ -12,29 +12,29 @@ No API key required.
|
||||||
|
|
||||||
## Available Tools
|
## Available Tools
|
||||||
|
|
||||||
| Tool | Description |
|
| Tool | Description |
|
||||||
|------|-------------|
|
| --------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| `search_content` | Search movies/shows with filters (query, type, genre, year, rating, quality, language, sort). Returns content with torrents and magnet links. |
|
| `search_content` | Search movies/shows with filters (query, type, genre, year, rating, quality, language, sort). Returns content with torrents and magnet links. |
|
||||||
| `get_popular` | Get popular content ranked by user clicks |
|
| `get_popular` | Get popular content ranked by user clicks |
|
||||||
| `get_recent` | Get recently added content |
|
| `get_recent` | Get recently added content |
|
||||||
| `get_watch_providers` | Streaming availability by country (Netflix, Disney+, etc.) |
|
| `get_watch_providers` | Streaming availability by country (Netflix, Disney+, etc.) |
|
||||||
| `get_credits` | Cast and director for a title |
|
| `get_credits` | Cast and director for a title |
|
||||||
| `get_torrent_url` | Get .torrent file download URL from info hash |
|
| `get_torrent_url` | Get .torrent file download URL from info hash |
|
||||||
|
|
||||||
## Resources
|
## Resources
|
||||||
|
|
||||||
| URI | Description |
|
| URI | Description |
|
||||||
|-----|-------------|
|
| --------------------- | ----------------------------------------------------- |
|
||||||
| `torrentclaw://stats` | Catalog statistics (content/torrent counts by source) |
|
| `torrentclaw://stats` | Catalog statistics (content/torrent counts by source) |
|
||||||
|
|
||||||
## Prompts
|
## Prompts
|
||||||
|
|
||||||
| Prompt | Description |
|
| Prompt | Description |
|
||||||
|--------|-------------|
|
| ---------------- | -------------------------------------------------------- |
|
||||||
| `search_movie` | Search for a movie by title and get torrents + streaming |
|
| `search_movie` | Search for a movie by title and get torrents + streaming |
|
||||||
| `search_show` | Search for a TV show by title and get torrents |
|
| `search_show` | Search for a TV show by title and get torrents |
|
||||||
| `whats_new` | Discover recently added movies and TV shows |
|
| `whats_new` | Discover recently added movies and TV shows |
|
||||||
| `where_to_watch` | Find where to stream, rent, or buy a title |
|
| `where_to_watch` | Find where to stream, rent, or buy a title |
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
|
|
@ -89,10 +89,10 @@ Point to your own TorrentClaw instance:
|
||||||
|
|
||||||
## Environment Variables
|
## Environment Variables
|
||||||
|
|
||||||
| Variable | Default | Description |
|
| Variable | Default | Description |
|
||||||
|----------|---------|-------------|
|
| --------------------------- | ------------------------- | ---------------------------------------------------------------------- |
|
||||||
| `TORRENTCLAW_API_URL` | `https://torrentclaw.com` | Base URL of the TorrentClaw API |
|
| `TORRENTCLAW_API_URL` | `https://torrentclaw.com` | Base URL of the TorrentClaw API |
|
||||||
| `TORRENTCLAW_ALLOW_PRIVATE` | `false` | Set to `true` to allow private/localhost URLs (for self-hosted setups) |
|
| `TORRENTCLAW_ALLOW_PRIVATE` | `false` | Set to `true` to allow private/localhost URLs (for self-hosted setups) |
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|
||||||
|
|
|
||||||
17
package-lock.json
generated
17
package-lock.json
generated
|
|
@ -18,6 +18,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^22.0.0",
|
"@types/node": "^22.0.0",
|
||||||
"@vitest/coverage-v8": "^4.0.18",
|
"@vitest/coverage-v8": "^4.0.18",
|
||||||
|
"prettier": "^3.8.1",
|
||||||
"tsx": "^4.19.0",
|
"tsx": "^4.19.0",
|
||||||
"typescript": "^5.7.0",
|
"typescript": "^5.7.0",
|
||||||
"vitest": "^4.0.0"
|
"vitest": "^4.0.0"
|
||||||
|
|
@ -2231,6 +2232,22 @@
|
||||||
"node": "^10 || ^12 || >=14"
|
"node": "^10 || ^12 || >=14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/prettier": {
|
||||||
|
"version": "3.8.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz",
|
||||||
|
"integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"prettier": "bin/prettier.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=14"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/prettier/prettier?sponsor=1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/proxy-addr": {
|
"node_modules/proxy-addr": {
|
||||||
"version": "2.0.7",
|
"version": "2.0.7",
|
||||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,7 @@
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/node": "^22.0.0",
|
"@types/node": "^22.0.0",
|
||||||
"@vitest/coverage-v8": "^4.0.18",
|
"@vitest/coverage-v8": "^4.0.18",
|
||||||
|
"prettier": "^3.8.1",
|
||||||
"tsx": "^4.19.0",
|
"tsx": "^4.19.0",
|
||||||
"typescript": "^5.7.0",
|
"typescript": "^5.7.0",
|
||||||
"vitest": "^4.0.0"
|
"vitest": "^4.0.0"
|
||||||
|
|
|
||||||
|
|
@ -91,9 +91,7 @@ function formatResult(
|
||||||
`Stream: ${r.streaming.flatrate.map((p) => p.name).join(", ")}`,
|
`Stream: ${r.streaming.flatrate.map((p) => p.name).join(", ")}`,
|
||||||
);
|
);
|
||||||
if (r.streaming.free.length > 0)
|
if (r.streaming.free.length > 0)
|
||||||
providers.push(
|
providers.push(`Free: ${r.streaming.free.map((p) => p.name).join(", ")}`);
|
||||||
`Free: ${r.streaming.free.map((p) => p.name).join(", ")}`,
|
|
||||||
);
|
|
||||||
if (providers.length > 0) lines.push(` ${providers.join(" | ")}`);
|
if (providers.length > 0) lines.push(` ${providers.join(" | ")}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,7 +128,8 @@ export function formatPopularResults(data: PopularResponse): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
const header = `Popular content (${data.total} total, page ${data.page}):`;
|
const header = `Popular content (${data.total} total, page ${data.page}):`;
|
||||||
const hint = "(Use search_content with a title to get torrents and full details)";
|
const hint =
|
||||||
|
"(Use search_content with a title to get torrents and full details)";
|
||||||
const items = data.items.map((item, i) => formatPopularItem(item, i + 1));
|
const items = data.items.map((item, i) => formatPopularItem(item, i + 1));
|
||||||
return [header, hint, "", ...items].join("\n");
|
return [header, hint, "", ...items].join("\n");
|
||||||
}
|
}
|
||||||
|
|
@ -152,7 +151,8 @@ export function formatRecentResults(data: RecentResponse): string {
|
||||||
}
|
}
|
||||||
|
|
||||||
const header = `Recently added content (${data.total} total, page ${data.page}):`;
|
const header = `Recently added content (${data.total} total, page ${data.page}):`;
|
||||||
const hint = "(Use search_content with a title to get torrents and full details)";
|
const hint =
|
||||||
|
"(Use search_content with a title to get torrents and full details)";
|
||||||
const items = data.items.map((item, i) => formatRecentItem(item, i + 1));
|
const items = data.items.map((item, i) => formatRecentItem(item, i + 1));
|
||||||
return [header, hint, "", ...items].join("\n");
|
return [header, hint, "", ...items].join("\n");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,7 @@ export function formatWatchProviders(data: WatchProvidersResponse): string {
|
||||||
].filter(Boolean) as string[];
|
].filter(Boolean) as string[];
|
||||||
|
|
||||||
if (sections.length === 0) {
|
if (sections.length === 0) {
|
||||||
lines.push(
|
lines.push(` No watch providers found in ${data.country}.`);
|
||||||
` No watch providers found in ${data.country}.`,
|
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
lines.push(...sections);
|
lines.push(...sections);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,7 @@ export function registerGetPopular(
|
||||||
},
|
},
|
||||||
async (params) => {
|
async (params) => {
|
||||||
try {
|
try {
|
||||||
const data = await client.getPopular(
|
const data = await client.getPopular(params.limit ?? 10, params.page);
|
||||||
params.limit ?? 10,
|
|
||||||
params.page,
|
|
||||||
);
|
|
||||||
return {
|
return {
|
||||||
content: [{ type: "text", text: formatPopularResults(data) }],
|
content: [{ type: "text", text: formatPopularResults(data) }],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -28,10 +28,7 @@ export function registerGetRecent(
|
||||||
},
|
},
|
||||||
async (params) => {
|
async (params) => {
|
||||||
try {
|
try {
|
||||||
const data = await client.getRecent(
|
const data = await client.getRecent(params.limit ?? 10, params.page);
|
||||||
params.limit ?? 10,
|
|
||||||
params.page,
|
|
||||||
);
|
|
||||||
return {
|
return {
|
||||||
content: [{ type: "text", text: formatRecentResults(data) }],
|
content: [{ type: "text", text: formatRecentResults(data) }],
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -27,9 +27,7 @@ export function registerGetWatchProviders(
|
||||||
"Must be uppercase 2-letter ISO 3166-1 country code",
|
"Must be uppercase 2-letter ISO 3166-1 country code",
|
||||||
)
|
)
|
||||||
.default("US")
|
.default("US")
|
||||||
.describe(
|
.describe("ISO 3166-1 country code (e.g. US, ES, GB, DE). Default: US"),
|
||||||
"ISO 3166-1 country code (e.g. US, ES, GB, DE). Default: US",
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
async (params) => {
|
async (params) => {
|
||||||
try {
|
try {
|
||||||
|
|
|
||||||
|
|
@ -98,7 +98,9 @@ describe("TorrentClawClient", () => {
|
||||||
|
|
||||||
it("constructs torrent download URL", () => {
|
it("constructs torrent download URL", () => {
|
||||||
const client = new TorrentClawClient();
|
const client = new TorrentClawClient();
|
||||||
const url = client.getTorrentDownloadUrl("aaf1e71c0a0e3b1c0f1a2b3c4d5e6f7a8b9c0d1e");
|
const url = client.getTorrentDownloadUrl(
|
||||||
|
"aaf1e71c0a0e3b1c0f1a2b3c4d5e6f7a8b9c0d1e",
|
||||||
|
);
|
||||||
expect(url).toBe(
|
expect(url).toBe(
|
||||||
"https://torrentclaw.com/api/v1/torrent/aaf1e71c0a0e3b1c0f1a2b3c4d5e6f7a8b9c0d1e",
|
"https://torrentclaw.com/api/v1/torrent/aaf1e71c0a0e3b1c0f1a2b3c4d5e6f7a8b9c0d1e",
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -110,10 +110,13 @@ describe("TorrentClawClient cache integration", () => {
|
||||||
(globalThis.fetch as ReturnType<typeof vi.fn>)
|
(globalThis.fetch as ReturnType<typeof vi.fn>)
|
||||||
.mockResolvedValueOnce(new Response("Server error", { status: 500 }))
|
.mockResolvedValueOnce(new Response("Server error", { status: 500 }))
|
||||||
.mockResolvedValueOnce(
|
.mockResolvedValueOnce(
|
||||||
new Response(JSON.stringify({ total: 0, page: 1, pageSize: 10, results: [] }), {
|
new Response(
|
||||||
status: 200,
|
JSON.stringify({ total: 0, page: 1, pageSize: 10, results: [] }),
|
||||||
headers: { "Content-Type": "application/json" },
|
{
|
||||||
}),
|
status: 200,
|
||||||
|
headers: { "Content-Type": "application/json" },
|
||||||
|
},
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
const client = new TorrentClawClient();
|
const client = new TorrentClawClient();
|
||||||
|
|
|
||||||
|
|
@ -56,15 +56,11 @@ describe("validateApiUrl", () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
it("rejects 0.0.0.0", () => {
|
it("rejects 0.0.0.0", () => {
|
||||||
expect(() => validateApiUrl("http://0.0.0.0")).toThrow(
|
expect(() => validateApiUrl("http://0.0.0.0")).toThrow("private/reserved");
|
||||||
"private/reserved",
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("rejects 10.x.x.x range", () => {
|
it("rejects 10.x.x.x range", () => {
|
||||||
expect(() => validateApiUrl("http://10.0.0.1")).toThrow(
|
expect(() => validateApiUrl("http://10.0.0.1")).toThrow("private/reserved");
|
||||||
"private/reserved",
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("rejects 172.16-31.x.x range", () => {
|
it("rejects 172.16-31.x.x range", () => {
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,8 @@ describe("formatSearchResults", () => {
|
||||||
title: "Inception",
|
title: "Inception",
|
||||||
titleOriginal: "Inception",
|
titleOriginal: "Inception",
|
||||||
year: 2010,
|
year: 2010,
|
||||||
overview: "A thief who steals corporate secrets through dream-sharing technology.",
|
overview:
|
||||||
|
"A thief who steals corporate secrets through dream-sharing technology.",
|
||||||
posterUrl: "https://image.tmdb.org/t/p/w500/poster.jpg",
|
posterUrl: "https://image.tmdb.org/t/p/w500/poster.jpg",
|
||||||
backdropUrl: null,
|
backdropUrl: null,
|
||||||
genres: ["Action", "Science Fiction"],
|
genres: ["Action", "Science Fiction"],
|
||||||
|
|
@ -52,7 +53,8 @@ describe("formatSearchResults", () => {
|
||||||
sizeBytes: "2147483648",
|
sizeBytes: "2147483648",
|
||||||
seeders: 847,
|
seeders: 847,
|
||||||
leechers: 23,
|
leechers: 23,
|
||||||
magnetUrl: "magnet:?xt=urn:btih:aaf1e71c0a0e3b1c0f1a2b3c4d5e6f7a8b9c0d1e",
|
magnetUrl:
|
||||||
|
"magnet:?xt=urn:btih:aaf1e71c0a0e3b1c0f1a2b3c4d5e6f7a8b9c0d1e",
|
||||||
source: "yts",
|
source: "yts",
|
||||||
qualityScore: 85,
|
qualityScore: 85,
|
||||||
uploadedAt: "2024-03-15T12:00:00Z",
|
uploadedAt: "2024-03-15T12:00:00Z",
|
||||||
|
|
@ -561,7 +563,12 @@ describe("formatSearchResults", () => {
|
||||||
|
|
||||||
describe("formatPopularResults", () => {
|
describe("formatPopularResults", () => {
|
||||||
it("formats empty results", () => {
|
it("formats empty results", () => {
|
||||||
const response: PopularResponse = { items: [], total: 0, page: 1, pageSize: 10 };
|
const response: PopularResponse = {
|
||||||
|
items: [],
|
||||||
|
total: 0,
|
||||||
|
page: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
};
|
||||||
expect(formatPopularResults(response)).toContain("No popular content");
|
expect(formatPopularResults(response)).toContain("No popular content");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -593,7 +600,12 @@ describe("formatPopularResults", () => {
|
||||||
|
|
||||||
describe("formatRecentResults", () => {
|
describe("formatRecentResults", () => {
|
||||||
it("formats empty results", () => {
|
it("formats empty results", () => {
|
||||||
const response: RecentResponse = { items: [], total: 0, page: 1, pageSize: 10 };
|
const response: RecentResponse = {
|
||||||
|
items: [],
|
||||||
|
total: 0,
|
||||||
|
page: 1,
|
||||||
|
pageSize: 10,
|
||||||
|
};
|
||||||
expect(formatRecentResults(response)).toContain("No recent content");
|
expect(formatRecentResults(response)).toContain("No recent content");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -9,14 +9,38 @@ describe("formatWatchProviders", () => {
|
||||||
country: "ES",
|
country: "ES",
|
||||||
providers: {
|
providers: {
|
||||||
flatrate: [
|
flatrate: [
|
||||||
{ providerId: 8, name: "Netflix", logo: null, link: null, displayPriority: 1 },
|
{
|
||||||
{ providerId: 337, name: "Disney+", logo: null, link: null, displayPriority: 2 },
|
providerId: 8,
|
||||||
|
name: "Netflix",
|
||||||
|
logo: null,
|
||||||
|
link: null,
|
||||||
|
displayPriority: 1,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
providerId: 337,
|
||||||
|
name: "Disney+",
|
||||||
|
logo: null,
|
||||||
|
link: null,
|
||||||
|
displayPriority: 2,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
rent: [
|
rent: [
|
||||||
{ providerId: 2, name: "Apple TV", logo: null, link: null, displayPriority: 1 },
|
{
|
||||||
|
providerId: 2,
|
||||||
|
name: "Apple TV",
|
||||||
|
logo: null,
|
||||||
|
link: null,
|
||||||
|
displayPriority: 1,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
buy: [
|
buy: [
|
||||||
{ providerId: 3, name: "Google Play", logo: null, link: null, displayPriority: 1 },
|
{
|
||||||
|
providerId: 3,
|
||||||
|
name: "Google Play",
|
||||||
|
logo: null,
|
||||||
|
link: null,
|
||||||
|
displayPriority: 1,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
free: [],
|
free: [],
|
||||||
},
|
},
|
||||||
|
|
@ -66,8 +90,20 @@ describe("formatWatchProviders", () => {
|
||||||
country: "GB",
|
country: "GB",
|
||||||
providers: {
|
providers: {
|
||||||
flatrate: [
|
flatrate: [
|
||||||
{ providerId: 2, name: "Second", logo: null, link: null, displayPriority: 20 },
|
{
|
||||||
{ providerId: 1, name: "First", logo: null, link: null, displayPriority: 1 },
|
providerId: 2,
|
||||||
|
name: "Second",
|
||||||
|
logo: null,
|
||||||
|
link: null,
|
||||||
|
displayPriority: 20,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
providerId: 1,
|
||||||
|
name: "First",
|
||||||
|
logo: null,
|
||||||
|
link: null,
|
||||||
|
displayPriority: 1,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
rent: [],
|
rent: [],
|
||||||
buy: [],
|
buy: [],
|
||||||
|
|
@ -89,7 +125,13 @@ describe("formatWatchProviders", () => {
|
||||||
rent: [],
|
rent: [],
|
||||||
buy: [],
|
buy: [],
|
||||||
free: [
|
free: [
|
||||||
{ providerId: 100, name: "Tubi", logo: null, link: null, displayPriority: 1 },
|
{
|
||||||
|
providerId: 100,
|
||||||
|
name: "Tubi",
|
||||||
|
logo: null,
|
||||||
|
link: null,
|
||||||
|
displayPriority: 1,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
attribution: "JustWatch",
|
attribution: "JustWatch",
|
||||||
|
|
|
||||||
|
|
@ -2,9 +2,9 @@ import { describe, it, expect, vi } from "vitest";
|
||||||
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
||||||
import { registerPrompts } from "../src/prompts.js";
|
import { registerPrompts } from "../src/prompts.js";
|
||||||
|
|
||||||
type PromptHandler = (
|
type PromptHandler = (params: Record<string, string>) => {
|
||||||
params: Record<string, string>,
|
messages: { role: string; content: { type: string; text: string } }[];
|
||||||
) => { messages: { role: string; content: { type: string; text: string } }[] };
|
};
|
||||||
|
|
||||||
describe("registerPrompts", () => {
|
describe("registerPrompts", () => {
|
||||||
function createMockServer() {
|
function createMockServer() {
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,9 @@ describe("get_credits tool", () => {
|
||||||
|
|
||||||
it("returns isError on ApiError", async () => {
|
it("returns isError on ApiError", async () => {
|
||||||
const client = createMockClient({
|
const client = createMockClient({
|
||||||
getCredits: vi.fn().mockRejectedValue(new ApiError(503, "TMDB unavailable")),
|
getCredits: vi
|
||||||
|
.fn()
|
||||||
|
.mockRejectedValue(new ApiError(503, "TMDB unavailable")),
|
||||||
});
|
});
|
||||||
const { server, getToolHandler } = createMockServer();
|
const { server, getToolHandler } = createMockServer();
|
||||||
registerGetCredits(server, client);
|
registerGetCredits(server, client);
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,7 @@ function createMockClient(overrides: Partial<TorrentClawClient> = {}) {
|
||||||
getTorrentDownloadUrl: vi
|
getTorrentDownloadUrl: vi
|
||||||
.fn()
|
.fn()
|
||||||
.mockImplementation(
|
.mockImplementation(
|
||||||
(hash: string) =>
|
(hash: string) => `https://torrentclaw.com/api/v1/torrent/${hash}`,
|
||||||
`https://torrentclaw.com/api/v1/torrent/${hash}`,
|
|
||||||
),
|
),
|
||||||
...overrides,
|
...overrides,
|
||||||
} as unknown as TorrentClawClient;
|
} as unknown as TorrentClawClient;
|
||||||
|
|
|
||||||
|
|
@ -24,7 +24,13 @@ describe("get_watch_providers tool", () => {
|
||||||
country: "ES",
|
country: "ES",
|
||||||
providers: {
|
providers: {
|
||||||
flatrate: [
|
flatrate: [
|
||||||
{ providerId: 8, name: "Netflix", logo: null, link: null, displayPriority: 1 },
|
{
|
||||||
|
providerId: 8,
|
||||||
|
name: "Netflix",
|
||||||
|
logo: null,
|
||||||
|
link: null,
|
||||||
|
displayPriority: 1,
|
||||||
|
},
|
||||||
],
|
],
|
||||||
rent: [],
|
rent: [],
|
||||||
buy: [],
|
buy: [],
|
||||||
|
|
@ -64,7 +70,9 @@ describe("get_watch_providers tool", () => {
|
||||||
|
|
||||||
it("returns isError on ApiError", async () => {
|
it("returns isError on ApiError", async () => {
|
||||||
const client = createMockClient({
|
const client = createMockClient({
|
||||||
getWatchProviders: vi.fn().mockRejectedValue(new ApiError(404, "Not found")),
|
getWatchProviders: vi
|
||||||
|
.fn()
|
||||||
|
.mockRejectedValue(new ApiError(404, "Not found")),
|
||||||
});
|
});
|
||||||
const { server, getToolHandler } = createMockServer();
|
const { server, getToolHandler } = createMockServer();
|
||||||
registerGetWatchProviders(server, client);
|
registerGetWatchProviders(server, client);
|
||||||
|
|
@ -78,7 +86,9 @@ describe("get_watch_providers tool", () => {
|
||||||
|
|
||||||
it("returns isError on generic error", async () => {
|
it("returns isError on generic error", async () => {
|
||||||
const client = createMockClient({
|
const client = createMockClient({
|
||||||
getWatchProviders: vi.fn().mockRejectedValue(new Error("Connection refused")),
|
getWatchProviders: vi
|
||||||
|
.fn()
|
||||||
|
.mockRejectedValue(new Error("Connection refused")),
|
||||||
});
|
});
|
||||||
const { server, getToolHandler } = createMockServer();
|
const { server, getToolHandler } = createMockServer();
|
||||||
registerGetWatchProviders(server, client);
|
registerGetWatchProviders(server, client);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue