{"_id":"@carddex/sdk","_rev":"2-7f7dab5f0a588bc22b59d7b7e4b0de7f","name":"@carddex/sdk","dist-tags":{"latest":"0.2.0"},"versions":{"0.1.0":{"name":"@carddex/sdk","version":"0.1.0","keywords":["pokemon","tcg","api","sdk"],"license":"MIT","_id":"@carddex/sdk@0.1.0","maintainers":[{"name":"sirboo","email":"mike@ntmf.eu"}],"dist":{"shasum":"c31d7377076678927e04282dcc702c6f81a31966","tarball":"https://registry.npmjs.org/@carddex/sdk/-/sdk-0.1.0.tgz","fileCount":13,"integrity":"sha512-uAu1av69N6qp6sBuvSv3tYRUZwXZhLYsf0fo6Fii0HpbFOon1zwjDbACnVUXwRjdgMTOHS3gzRkIIFIye99hTQ==","signatures":[{"sig":"MEQCIBlJdVy1LLYbBn7M2wwccDhItrORHXjAJUHUy1c3wq/yAiBTvldW44iFnaOeq8oBtUan3nlss/PBLPKHl6+mrtgv+A==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":26064},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"dc4b1b170e86f337759f197dab54078a2816706c","scripts":{"build":"tsc","prepublishOnly":"npm run build"},"_npmUser":{"name":"sirboo","email":"mike@ntmf.eu"},"_npmVersion":"11.11.1","description":"TypeScript SDK for the CardDex Pokémon TCG API","directories":{},"_nodeVersion":"24.14.0","_hasShrinkwrap":false,"devDependencies":{"typescript":"^5.7.0"},"_npmOperationalInternal":{"tmp":"tmp/sdk_0.1.0_1775379826724_0.09576525220028476","host":"s3://npm-registry-packages-npm-production"}},"0.2.0":{"_id":"@carddex/sdk@0.2.0","bugs":{"url":"https://carddex.dev/docs","email":"api@carddex.dev"},"dist":{"shasum":"60cbee7b3e42593c159fa962f3940b220a50f428","tarball":"https://registry.npmjs.org/@carddex/sdk/-/sdk-0.2.0.tgz","fileCount":9,"integrity":"sha512-jR6TVxIbSCNkFfikWhRZq+3L53szIU0YqpWqTVx25yMV3CLVND6GsbvB+dq9PZ+BvZDHoUXDYBbf4W+vppfwSA==","signatures":[{"sig":"MEYCIQCCcEW/eD/jeoMDGBWerDcXVltmeDgbF8pxtkP0cDGUOQIhAPMO1LGy4um3ebmIyzEoY9hGCcGJqN9rWL8ftQe7s7n6","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIHazt26eJ9+eb8TUZnFRpvaeJsy4kOGb/czKMaYxWyTtAiEA2kUKcYpi+qHqZTa6SufHNungEbTOwOY/oZJD//D4tyA="}],"unpackedSize":141318},"main":"./dist/index.cjs","name":"@carddex/sdk","type":"module","types":"./dist/index.d.ts","author":{"name":"CardDex"},"module":"./dist/index.js","engines":{"node":">=18"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js","require":"./dist/index.cjs"},"./package.json":"./package.json"},"gitHead":"84a017f78989a435c093446b9c0c03cf9358a811","license":"MIT","scripts":{"dev":"tsup --watch","lint":"biome check .","test":"vitest run","build":"tsup","format":"biome check --write .","generate":"node scripts/generate.mjs","typecheck":"tsc --noEmit","test:watch":"vitest"},"version":"0.2.0","_npmUser":{"name":"sirboo","email":"mike@ntmf.eu"},"homepage":"https://carddex.dev/docs","keywords":["pokemon","tcg","trading cards","api","sdk","carddex"],"_npmVersion":"11.16.0","description":"Official TypeScript/JavaScript client for the CardDex Pokémon TCG API","directories":{},"maintainers":[{"name":"sirboo","email":"mike@ntmf.eu"}],"sideEffects":false,"_nodeVersion":"24.18.0","dependencies":{},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.1","vitest":"^4.1.11","typescript":"^5.9.3","openapi-typescript":"^7.9.1"},"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/sdk_0.2.0_1791037062237_0.10618932154358895"}}},"time":{"created":"2026-04-05T09:03:46.668Z","modified":"2026-10-03T14:17:42.513Z","0.1.0":"2026-04-05T09:03:46.883Z","0.2.0":"2026-10-03T14:17:42.339Z"},"license":"MIT","keywords":["pokemon","tcg","trading cards","api","sdk","carddex"],"description":"Official TypeScript/JavaScript client for the CardDex Pokémon TCG API","maintainers":[{"name":"sirboo","email":"mike@ntmf.eu"}],"readme":"# @carddex/sdk\n\nOfficial TypeScript/JavaScript client for the [CardDex](https://carddex.dev) Pokémon TCG API — cards, sets, print variants, sealed products, and price history from Cardmarket (EUR) and TCGplayer (USD).\n\n- Zero runtime dependencies — uses global `fetch`, so it runs unmodified in Node 18+, browsers, Cloudflare Workers, Deno and Bun.\n- Fully typed, ESM + CJS builds, with a shipped `.d.ts`.\n- No codegen step for consumers: types are generated at build time from the CardDex OpenAPI spec and committed.\n\n## Install\n\n```bash\nnpm install @carddex/sdk\n# or\npnpm add @carddex/sdk\n# or\nyarn add @carddex/sdk\n```\n\n## Quickstart\n\n```ts\nimport { CardDex } from '@carddex/sdk';\n\nconst client = new CardDex({ apiKey: process.env.CARDDEX_API_KEY });\n\nconst { data: cards } = await client.cards.list({ name: 'Charizard', sort: 'release_date', order: 'desc' });\n\nconst card = await client.cards.get('sv06-001', { include: ['prices', 'images'] });\n\nconst prices = await client.cards.prices('sv06-001');\n\nconst history = await client.cards.priceHistory('sv06-001', { days: 180, source: ['cardmarket', 'tcgplayer'] });\n```\n\nAn API key is optional. Omit it to call the API anonymously. The SDK sends the key in the `X-API-Key` header.\n\nYou can also sign in with an email link at [carddex.dev/account](https://carddex.dev/account) to see your keys, create up to 2 active keys, and rotate or revoke them.\n### Get a free API key\n\n```ts\nimport { CardDex } from '@carddex/sdk';\n\nconst client = new CardDex();\nconst { api_key } = await client.auth.register('you@example.com', 'My App');\n// Save api_key now — it is shown only once. If you lose it, sign in at https://carddex.dev/account to create a new one or rotate/revoke keys.\n```\n\n## Calling from a browser\n\nPublic read endpoints accept requests from any origin. **Never ship a real API key in public frontend code** — anyone who opens dev tools can read it, and it would be shared by every visitor to your site. Instead:\n\n- Call anonymously from the browser. CardDex allows this at a lower but real rate limit (30 req/min, 5,000 req/day per visitor IP) specifically so a frontend can call it directly, with no key:\n\n  ```ts\n  const client = new CardDex(); // no apiKey — anonymous browser mode\n  ```\n\n- Or proxy through your own backend and attach the key there, server-side.\n\nIf you construct `new CardDex({ apiKey })` in what looks like a browser environment, the SDK logs a one-time `console.warn` as a safety net — it does not block the request.\n\n## Pagination\n\nEvery list endpoint returns `{ data, meta: { total, page, pageSize, totalPages } }`. Each resource that lists something also exposes an `*All` method that returns an async iterator, fetching pages lazily as you consume them:\n\n```ts\nfor await (const card of client.cards.listAll({ set: 'sv06' })) {\n  console.log(card.name);\n}\n\nfor await (const product of client.sealed.listAll({ set_id: 'sv06' })) { ... }\n\nfor await (const card of client.sets.cardsAll('sv06')) { ... }\n```\n\nYou can also use the lower-level `paginate()` helper directly against any page-shaped fetcher:\n\n```ts\nimport { paginate } from '@carddex/sdk';\n\nfor await (const card of paginate((page) => client.cards.list({ set: 'sv06', page }))) { ... }\n```\n\n## Errors\n\nEvery non-2xx response throws a `CardDexError`:\n\n```ts\nimport { CardDex, CardDexError } from '@carddex/sdk';\n\ntry {\n  await client.cards.get('does-not-exist');\n} catch (err) {\n  if (err instanceof CardDexError) {\n    err.status;      // HTTP status, e.g. 404\n    err.code;         // the API's error.code (a number for a real API response; 'NETWORK_ERROR' for a transport failure)\n    err.message;      // the API's error.message\n    err.retryAfter;   // seconds to wait, parsed from Retry-After on a 429 — null otherwise\n    err.rateLimit;    // { limit, dailyLimit, dailyRemaining } parsed from response headers, or null\n    err.isRateLimited; // true for a 429 (either the per-minute or the daily cap)\n  }\n}\n```\n\n## Rate limits & retries\n\nEvery response carries `X-RateLimit-Limit` (per minute), `X-RateLimit-Daily-Limit` and `X-RateLimit-Daily-Remaining` (per UTC day, approximate). A 429 carries `Retry-After` in seconds: `60` for the per-minute limit, or the seconds until 00:00 UTC for the daily one.\n\nAutomatic retry on 429 is **off by default** — the SDK never silently blocks your code. Turn it on when you want it:\n\n```ts\nconst client = new CardDex({ retry: true }); // up to 2 retries, never waiting more than 60s\n\nconst client2 = new CardDex({ retry: { maxRetries: 3, maxWaitSeconds: 30 } });\n```\n\nA `Retry-After` longer than `maxWaitSeconds` is never honoured — the call fails immediately instead of sleeping. This is deliberate: the daily-quota 429's `Retry-After` can be most of a day, and a small SDK default should never block a request for hours. The per-minute 429's `Retry-After: 60` fits comfortably under the default 60s cap, so that case retries; a daily-cap 429 does not, by design.\n\n## Migrating from pokemontcg.io\n\nThe pokemontcg.io v2 compatibility layer is live: an app built on pokemontcg.io v2 can keep its code and stored ids and change its base URL to `https://api.carddex.dev/compat/pokemontcg/v2`. The guide at [carddex.dev/migrate/pokemontcg](https://carddex.dev/migrate/pokemontcg) covers what the layer supports, which official pokemontcg.io SDKs work with it, and the fields that differ.\n\nThis SDK talks to the native `/v1` API, which uses CardDex ids (`sv02-062`) but accepts pokemontcg.io ids as well: `client.cards.get('sv2-62')` returns the same card. The API also returns a `ptcgio_id` field on every card and accepts a `ptcgio_id` filter on the card list; this SDK's types don't include either yet.\n\n## API surface\n\n| Resource | Methods |\n| --- | --- |\n| `client.cards` | `list`, `listAll`, `get`, `random`, `prices`, `priceHistory` |\n| `client.sets` | `list`, `get`, `cards`, `cardsAll`, `neighbors`, `sealed` |\n| `client.sealed` | `list`, `listAll`, `get`, `prices` |\n| `client.prices` | `bulk`, `top`, `trends`, `bargains`, `history` |\n| `client.auth` | `register`, `usage` |\n| `client` | `usage()` (shorthand for `client.auth.usage()`), `health()` |\n\nFull parameter and response types are exported from the package root — see `src/params.ts` and `src/types.ts`, or your editor's autocomplete.\n\n## Development (this monorepo)\n\n```bash\npnpm install\npnpm --filter @carddex/sdk generate   # refresh src/generated/openapi.d.ts from the live OpenAPI spec\npnpm --filter @carddex/sdk build\npnpm --filter @carddex/sdk test\npnpm --filter @carddex/sdk typecheck\npnpm --filter @carddex/sdk lint\n```\n\n`openapi.json` in this package's root is a committed snapshot of `https://api.carddex.dev/openapi.json`. `pnpm generate` refreshes it and regenerates `src/generated/openapi.d.ts` from it; if the fetch fails (offline, no network egress in CI), it regenerates from whatever snapshot is already committed instead of failing outright.\n\nThe OpenAPI spec now documents response body schemas too (`components.schemas`, validated against live API responses by `carddex-api`'s `tests/integration/openapi-contract.test.ts`), so `src/generated/openapi.d.ts` types response bodies precisely rather than as `unknown`. The hand-written interfaces in `src/types.ts` predate that and can stay — they're what this SDK's public API is built on — but new code can also reach into `components[\"schemas\"]` from the generated file directly.\n\n## License\n\nMIT\n","readmeFilename":"README.md","homepage":"https://carddex.dev/docs","author":{"name":"CardDex"},"bugs":{"url":"https://carddex.dev/docs","email":"api@carddex.dev"}}