@adbjs/sdk 1.0.0 → 2.0.0

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.cjs CHANGED
@@ -159,11 +159,11 @@ var LinkResource = class extends BaseResource {
159
159
  *
160
160
  * @example
161
161
  * ```ts
162
- * const info = await client.link.infos('https://example.com/file.zip')
163
- * console.log(info)
162
+ * const data = await client.link.infos('https://example.com/file.zip')
163
+ * console.log(data.infos)
164
164
  *
165
165
  * // With password
166
- * const protectedInfo = await client.link.infos(
166
+ * const protectedData = await client.link.infos(
167
167
  * 'https://example.com/protected.zip',
168
168
  * 'mypassword'
169
169
  * )
@@ -172,12 +172,7 @@ var LinkResource = class extends BaseResource {
172
172
  async infos(links, password) {
173
173
  const linksArray = Array.isArray(links) ? links : [links];
174
174
  const params = password ? { password } : void 0;
175
- const data = await this.post(
176
- "/link/infos",
177
- { "link[]": linksArray },
178
- params
179
- );
180
- return data?.infos;
175
+ return this.post("/link/infos", { "link[]": linksArray }, params);
181
176
  }
182
177
  /**
183
178
  * Extract links from redirectors/link protectors
@@ -186,14 +181,14 @@ var LinkResource = class extends BaseResource {
186
181
  *
187
182
  * @example
188
183
  * ```ts
189
- * const links = await client.link.redirector('https://linkprotector.com/abc123')
184
+ * const data = await client.link.redirector('https://linkprotector.com/abc123')
185
+ * console.log(data.links)
190
186
  * ```
191
187
  */
192
188
  async redirector(link) {
193
- const data = await this.post("/link/redirector", {
189
+ return this.post("/link/redirector", {
194
190
  link
195
191
  });
196
- return data?.links;
197
192
  }
198
193
  /**
199
194
  * Unlock a download link
@@ -363,16 +358,38 @@ var MagnetResource = class extends BaseResource {
363
358
  return this.post("/magnet/status", body);
364
359
  }
365
360
  /**
366
- * Get magnet status using live mode for reduced bandwidth consumption
361
+ * Get magnet status using live mode for bandwidth-optimized delta synchronization
362
+ *
363
+ * Live mode is designed for monitoring multiple magnets efficiently by only transmitting
364
+ * changes between polling intervals, drastically reducing bandwidth usage for dashboards
365
+ * and real-time monitoring applications.
366
+ *
367
+ * ## How it works
368
+ *
369
+ * 1. **Session initialization**: Generate a random session ID and start with counter = 0
370
+ * 2. **First call (fullsync)**: Returns ALL magnets with `fullsync: true`
371
+ * 3. **Update counter**: Use the `counter` value returned by the API for the next call
372
+ * 4. **Subsequent calls (delta)**: Returns ONLY magnets that changed since last call
373
+ * 5. **Repeat**: Keep calling with updated counter to receive only deltas
374
+ *
375
+ * ## When to use
376
+ *
377
+ * - ✅ Monitoring multiple active magnets simultaneously
378
+ * - ✅ Building real-time dashboards
379
+ * - ✅ High-frequency polling scenarios (every few seconds)
380
+ * - ❌ Watching a single specific magnet (use `watch()` instead)
367
381
  *
368
- * Live mode uses delta synchronization - only changes since the last call are transmitted.
369
- * On the first call (counter=0), all data is returned with `fullsync: true`.
370
- * Subsequent calls return only modifications.
382
+ * ## Important notes
371
383
  *
372
- * @param options - Live mode options
373
- * @param options.session - Session ID (generate once per session and reuse)
374
- * @param options.counter - Synchronization counter (start at 0, use returned counter for next call)
375
- * @param id - Optional magnet ID to filter a specific magnet
384
+ * - **Don't use the `id` parameter**: Passing an ID defeats the purpose of live mode
385
+ * as it disables delta sync and behaves like a regular `status()` call
386
+ * - **Session persistence**: Keep the same session ID for the entire monitoring session
387
+ * - **Counter tracking**: Always update the counter with the value returned by the API
388
+ * - **Empty deltas**: When no magnets changed, `magnets` will be an empty array
389
+ *
390
+ * @param options - Live mode session options
391
+ * @param options.session - Unique session ID (generate once: `Math.floor(Math.random() * 1000000)`)
392
+ * @param options.counter - Sync counter (start at 0, then use value from previous API response)
376
393
  *
377
394
  * @example
378
395
  * ```ts
@@ -380,34 +397,64 @@ var MagnetResource = class extends BaseResource {
380
397
  * const session = Math.floor(Math.random() * 1000000)
381
398
  * let counter = 0
382
399
  *
383
- * // First call - full sync
400
+ * // First call - returns all magnets (fullsync: true)
384
401
  * const firstCall = await client.magnet.statusLive({ session, counter })
385
402
  * console.log('Full sync:', firstCall.fullsync) // true
386
- * console.log('All magnets:', firstCall.magnets)
387
- *
388
- * // Update counter with value returned by API
389
- * counter = firstCall.counter
403
+ * console.log('All magnets:', firstCall.magnets) // Array of all magnets
404
+ * counter = firstCall.counter // Update counter for next call
390
405
  *
391
- * // Second call - only changes
406
+ * // Second call - returns only magnets that changed
407
+ * await new Promise(resolve => setTimeout(resolve, 3000)) // Wait 3 seconds
392
408
  * const secondCall = await client.magnet.statusLive({ session, counter })
393
- * console.log('Delta sync:', secondCall.magnets) // Only modified magnets
409
+ * console.log('Delta sync:', secondCall.magnets) // Only changed magnets
410
+ * counter = secondCall.counter
411
+ *
412
+ * // Example: Monitor all magnets until none are active
413
+ * const activeMagnets = new Map()
414
+ *
415
+ * while (true) {
416
+ * const response = await client.magnet.statusLive({ session, counter })
417
+ * counter = response.counter ?? counter
418
+ *
419
+ * // Update our local state with changes
420
+ * if (response.fullsync) {
421
+ * activeMagnets.clear()
422
+ * response.magnets?.forEach(m => activeMagnets.set(m.id, m))
423
+ * } else {
424
+ * response.magnets?.forEach(m => {
425
+ * if (m.status === 'Ready' || m.status === 'Error' || m.status === 'Expired') {
426
+ * activeMagnets.delete(m.id)
427
+ * } else {
428
+ * activeMagnets.set(m.id, m)
429
+ * }
430
+ * })
431
+ * }
432
+ *
433
+ * // Display current state
434
+ * console.log(`Active downloads: ${activeMagnets.size}`)
435
+ * activeMagnets.forEach(m => {
436
+ * console.log(` ${m.filename}: ${m.status} - ${m.downloaded}/${m.size} bytes`)
437
+ * })
438
+ *
439
+ * // Stop when no more active magnets
440
+ * if (activeMagnets.size === 0) {
441
+ * console.log('All downloads completed!')
442
+ * break
443
+ * }
394
444
  *
395
- * // Filter specific magnet in live mode
396
- * const magnetLive = await client.magnet.statusLive({ session, counter }, 123)
445
+ * await new Promise(resolve => setTimeout(resolve, 3000))
446
+ * }
397
447
  * ```
398
448
  *
399
449
  * @remarks
400
- * This is ideal for real-time dashboards or frequent polling scenarios
401
- * as it significantly reduces bandwidth usage by transmitting only changes.
450
+ * This method is ideal for scenarios where you're monitoring multiple magnets and want
451
+ * to minimize bandwidth. For simple single-magnet monitoring, use `watch()` instead.
402
452
  */
403
- async statusLive(options, id) {
453
+ async statusLive(options) {
404
454
  const body = {
405
455
  session: options.session,
406
456
  counter: options.counter
407
457
  };
408
- if (id !== void 0) {
409
- body.id = id;
410
- }
411
458
  return this.post("/magnet/status", body);
412
459
  }
413
460
  /**
@@ -452,9 +499,9 @@ var MagnetResource = class extends BaseResource {
452
499
  *
453
500
  * @example
454
501
  * ```ts
455
- * const files = await client.magnet.files(123)
456
- * files?.forEach(file => {
457
- * console.log(file.filename, file.link)
502
+ * const data = await client.magnet.files(123)
503
+ * data?.magnets?.forEach(magnet => {
504
+ * console.log(magnet.filename, magnet.files)
458
505
  * })
459
506
  * ```
460
507
  *
@@ -468,56 +515,40 @@ var MagnetResource = class extends BaseResource {
468
515
  for (const id of idsArray) {
469
516
  formData.append("id[]", String(id));
470
517
  }
471
- const data = await this.postFormData("/magnet/files", formData);
472
- return data?.magnets;
518
+ return this.postFormData("/magnet/files", formData);
473
519
  }
474
520
  /**
475
521
  * Watch a magnet's status with automatic polling
476
522
  *
523
+ * This is a simple helper that polls the status of a specific magnet until it reaches
524
+ * a target status (default: 'Ready'). For advanced use cases with multiple magnets
525
+ * or bandwidth optimization, use `statusLive()` directly instead.
526
+ *
477
527
  * @param id - The magnet ID to watch
478
528
  * @param options - Watch options
479
529
  * @param options.interval - Polling interval in milliseconds (default: 3000)
480
530
  * @param options.maxAttempts - Maximum polling attempts, 0 for infinite (default: 0)
481
531
  * @param options.onUpdate - Callback called on each status update
482
532
  * @param options.stopOnStatus - Stop when magnet reaches this status (default: 'Ready')
483
- * @param options.useLiveMode - Use live mode for reduced bandwidth (default: false)
484
533
  *
485
534
  * @example
486
535
  * ```ts
487
- * // Standard mode
488
536
  * await client.magnet.watch(123, {
489
537
  * onUpdate: (status) => console.log('Status:', status.magnets[0]?.status),
490
538
  * stopOnStatus: 'Ready'
491
539
  * })
492
- *
493
- * // Live mode for reduced bandwidth
494
- * await client.magnet.watch(123, {
495
- * useLiveMode: true,
496
- * interval: 2000,
497
- * onUpdate: (status) => console.log('Update:', status)
498
- * })
499
540
  * ```
541
+ *
542
+ * @remarks
543
+ * For monitoring multiple magnets efficiently, use `statusLive()` directly.
544
+ * See the `statusLive()` documentation for details on delta synchronization.
500
545
  */
501
546
  async watch(id, options = {}) {
502
- const {
503
- interval = 3e3,
504
- maxAttempts = 0,
505
- onUpdate,
506
- stopOnStatus = "Ready",
507
- useLiveMode = false
508
- } = options;
547
+ const { interval = 3e3, maxAttempts = 0, onUpdate, stopOnStatus = "Ready" } = options;
509
548
  let attempt = 0;
510
- let session;
511
- let counter = 0;
512
- if (useLiveMode) {
513
- session = Math.floor(Math.random() * 1e6);
514
- }
515
549
  while (maxAttempts === 0 || attempt < maxAttempts) {
516
550
  attempt++;
517
- const status = useLiveMode && session !== void 0 ? await this.statusLive({ session, counter }, id) : await this.status(id);
518
- if (useLiveMode && status?.counter !== void 0) {
519
- counter = status.counter;
520
- }
551
+ const status = await this.status(id);
521
552
  onUpdate?.(status);
522
553
  const magnet = status?.magnets?.[0];
523
554
  if (magnet?.status === stopOnStatus) {
@@ -643,13 +674,12 @@ var UserResource = class extends BaseResource {
643
674
  *
644
675
  * @example
645
676
  * ```ts
646
- * const user = await client.user.getInfo()
647
- * console.log(user.username, user.isPremium)
677
+ * const data = await client.user.getInfo()
678
+ * console.log(data.user.username, data.user.isPremium)
648
679
  * ```
649
680
  */
650
681
  async getInfo() {
651
- const data = await this.get("/user");
652
- return data?.user;
682
+ return this.get("/user");
653
683
  }
654
684
  /**
655
685
  * Get available hosts for the current user based on their subscription
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/base-resource.ts","../src/resources/host.ts","../src/resources/link.ts","../src/resources/magnet.ts","../src/resources/pin.ts","../src/resources/user.ts","../src/resources/voucher.ts","../src/client.ts"],"names":["wretch"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { ApiError } from './types.js'\n\n/**\n * Base error class for AllDebrid SDK errors\n */\nexport class AllDebridError extends Error {\n public readonly code: string\n public readonly isAllDebridError = true\n\n constructor(code: string, message: string) {\n super(message)\n this.name = 'AllDebridError'\n this.code = code\n\n // Maintains proper stack trace for where our error was thrown (only available on V8)\n if ('captureStackTrace' in Error && typeof (Error as any).captureStackTrace === 'function') {\n ;(Error as any).captureStackTrace(this, AllDebridError)\n }\n }\n\n /**\n * Create an AllDebridError from an API error response\n */\n static fromApiError(error: ApiError): AllDebridError {\n return new AllDebridError(error.code, error.message)\n }\n}\n\n/**\n * Authentication related errors\n */\nexport class AuthenticationError extends AllDebridError {\n constructor(code: string, message: string) {\n super(code, message)\n this.name = 'AuthenticationError'\n }\n}\n\n/**\n * Link processing errors\n */\nexport class LinkError extends AllDebridError {\n constructor(code: string, message: string) {\n super(code, message)\n this.name = 'LinkError'\n }\n}\n\n/**\n * Magnet/Torrent related errors\n */\nexport class MagnetError extends AllDebridError {\n constructor(code: string, message: string) {\n super(code, message)\n this.name = 'MagnetError'\n }\n}\n\n/**\n * Network/HTTP errors\n */\nexport class NetworkError extends AllDebridError {\n constructor(\n message: string,\n public readonly statusCode?: number,\n ) {\n super('NETWORK_ERROR', message)\n this.name = 'NetworkError'\n }\n}\n\n/**\n * Helper to determine error type from error code\n */\nexport function createTypedError(code: string, message: string): AllDebridError {\n if (code.startsWith('AUTH_')) {\n return new AuthenticationError(code, message)\n }\n if (\n code.startsWith('LINK_') ||\n code.startsWith('REDIRECTOR_') ||\n code.startsWith('STREAM_') ||\n code.startsWith('DELAYED_')\n ) {\n return new LinkError(code, message)\n }\n if (code.startsWith('MAGNET_')) {\n return new MagnetError(code, message)\n }\n return new AllDebridError(code, message)\n}\n","import type { AllDebridClient } from './client.js'\nimport type { ExtractData } from './types.js'\n\n/**\n * Base class for all resources\n * Provides access to HTTP methods\n * @internal\n */\nexport abstract class BaseResource {\n constructor(protected readonly client: AllDebridClient) {}\n\n /**\n * Make a GET request\n * @template T - The generated response type (e.g., GetLinkUnlockResponse)\n * @param path - API endpoint path\n * @param params - Optional query parameters\n * @returns The extracted data from the response (without the { status, data } wrapper)\n */\n protected async get<T>(path: string, params?: Record<string, unknown>): Promise<ExtractData<T>> {\n return this.client.get<T>(path, params)\n }\n\n /**\n * Make a POST request\n * @template T - The generated response type\n * @param path - API endpoint path\n * @param body - Request body\n * @param params - Optional query parameters\n * @returns The extracted data from the response (without the { status, data } wrapper)\n */\n protected async post<T>(\n path: string,\n body?: unknown,\n params?: Record<string, unknown>,\n ): Promise<ExtractData<T>> {\n return this.client.post<T>(path, body, params)\n }\n\n /**\n * Make a POST request with FormData (multipart/form-data)\n * @template T - The generated response type\n * @param path - API endpoint path\n * @param formData - Form data to send\n * @param params - Optional query parameters\n * @returns The extracted data from the response (without the { status, data } wrapper)\n */\n protected async postFormData<T>(\n path: string,\n formData: FormData,\n params?: Record<string, unknown>,\n ): Promise<ExtractData<T>> {\n return this.client.postFormData<T>(path, formData, params)\n }\n}\n","import type {\n GetHostDomainsResponse,\n GetHostPriorityResponse,\n GetHostsResponse,\n} from '../generated/types.gen.js'\nimport { BaseResource } from '../base-resource.js'\n\n/**\n * Host resource for getting information about supported hosts\n */\nexport class HostResource extends BaseResource {\n /**\n * Get list of all supported hosts with their information\n *\n * @param hostOnly - If true, only return hosts (exclude streams and redirectors)\n *\n * @example\n * ```ts\n * const hosts = await client.host.list()\n * console.log(hosts.hosts) // All supported file hosts\n * console.log(hosts.streams) // Streaming hosts\n * console.log(hosts.redirectors) // Link redirectors\n * ```\n */\n async list(hostOnly?: boolean) {\n const params = hostOnly ? { hostOnly: '1' } : undefined\n return this.get<GetHostsResponse>('/hosts', params)\n }\n\n /**\n * Get array of all supported domain names\n *\n * @example\n * ```ts\n * const domains = await client.host.domains()\n * console.log(domains) // ['rapidgator.net', 'uploaded.net', ...]\n * ```\n */\n async domains() {\n return this.get<GetHostDomainsResponse>('/hosts/domains')\n }\n\n /**\n * Get hosts ordered by restriction level (priority list)\n *\n * @example\n * ```ts\n * const priority = await client.host.priority()\n * console.log(priority.hosts) // Ordered list with restriction levels\n * ```\n */\n async priority() {\n return this.get<GetHostPriorityResponse>('/hosts/priority')\n }\n}\n","import type {\n GetDelayedStatusResponse,\n GetLinkInfosResponse,\n GetRedirectorLinksResponse,\n GetStreamingLinkResponse,\n UnlockLinkResponse,\n} from '../generated/types.gen.js'\nimport { BaseResource } from '../base-resource.js'\n\n/**\n * Options for polling delayed link generation\n */\nexport interface PollOptions {\n /**\n * Polling interval in milliseconds\n * @default 2000\n */\n interval?: number\n\n /**\n * Maximum number of polling attempts\n * @default 30\n */\n maxAttempts?: number\n\n /**\n * Callback called on each polling attempt\n */\n onPoll?: (attempt: number) => void\n}\n\n/**\n * Link resource for unlocking and managing download links\n */\nexport class LinkResource extends BaseResource {\n /**\n * Get information about one or more links\n *\n * @param links - Single link or array of links to get info for\n * @param password - Optional password for password-protected links\n *\n * @example\n * ```ts\n * const info = await client.link.infos('https://example.com/file.zip')\n * console.log(info)\n *\n * // With password\n * const protectedInfo = await client.link.infos(\n * 'https://example.com/protected.zip',\n * 'mypassword'\n * )\n * ```\n */\n async infos(links: string | string[], password?: string) {\n const linksArray = Array.isArray(links) ? links : [links]\n const params = password ? { password } : undefined\n const data = await this.post<GetLinkInfosResponse>(\n '/link/infos',\n { 'link[]': linksArray },\n params,\n )\n return data?.infos\n }\n\n /**\n * Extract links from redirectors/link protectors\n *\n * @param link - The redirector link to extract from\n *\n * @example\n * ```ts\n * const links = await client.link.redirector('https://linkprotector.com/abc123')\n * ```\n */\n async redirector(link: string) {\n const data = await this.post<GetRedirectorLinksResponse>('/link/redirector', {\n link,\n })\n return data?.links\n }\n\n /**\n * Unlock a download link\n *\n * @param link - The link to unlock\n * @param password - Optional password for password-protected links\n *\n * @example\n * ```ts\n * const result = await client.link.unlock('https://example.com/file.zip')\n * if (result.link) {\n * console.log('Direct link:', result.link)\n * } else if (result.delayed) {\n * // Handle delayed generation\n * const delayedResult = await client.link.delayed(result.delayed)\n * }\n *\n * // With password\n * const protectedResult = await client.link.unlock(\n * 'https://example.com/protected.zip',\n * 'mypassword'\n * )\n * ```\n */\n async unlock(link: string, password?: string) {\n const params = password ? { password } : undefined\n return this.post<UnlockLinkResponse>('/link/unlock', { link }, params)\n }\n\n /**\n * Unlock a link and automatically poll if delayed\n * Note: The API response format doesn't include a delayed field in the current OpenAPI spec.\n * This method will be updated once the delayed mechanism is documented.\n *\n * @param link - The link to unlock\n * @param _options - Polling options (currently unused)\n *\n * @example\n * ```ts\n * const result = await client.link.unlockWithPolling('https://example.com/file.zip')\n * console.log('Direct link:', result.link)\n * ```\n */\n async unlockWithPolling(link: string, _options: PollOptions = {}) {\n // For now, just unlock without polling\n // TODO: Implement polling once delayed field is added to API response\n return this.unlock(link)\n }\n\n /**\n * Get streaming options for a generated link\n *\n * @param id - The generated link ID or streaming ID\n *\n * @example\n * ```ts\n * const streams = await client.link.streaming('abc123')\n * ```\n */\n async streaming(id: string, stream: string) {\n return this.post<GetStreamingLinkResponse>('/link/streaming', {\n id,\n stream,\n })\n }\n\n /**\n * Get the status/result of a delayed link generation\n *\n * @param id - The delayed generation ID\n *\n * @example\n * ```ts\n * const result = await client.link.delayed('delayed_id_123')\n * ```\n */\n async delayed(id: number) {\n return this.post<GetDelayedStatusResponse>('/link/delayed', {\n id,\n })\n }\n}\n","import type {\n DeleteMagnetResponse,\n GetMagnetFilesResponse,\n GetMagnetStatusResponse,\n RestartMagnetResponse,\n UploadMagnetsResponse,\n UploadTorrentFileResponse,\n} from '../generated/types.gen.js'\nimport { BaseResource } from '../base-resource.js'\n\n/**\n * Options for live mode status polling\n */\nexport interface LiveStatusOptions {\n /**\n * Session ID - Generate a random number and keep it consistent for the entire session\n * @example Math.floor(Math.random() * 1000000)\n */\n session: number\n\n /**\n * Counter for synchronization - Start at 0 and increment with each call\n * The API will return the next counter value to use\n */\n counter: number\n}\n\n/**\n * Options for watching magnet status\n */\nexport interface WatchOptions {\n /**\n * Polling interval in milliseconds\n * @default 3000\n */\n interval?: number\n\n /**\n * Maximum number of polling attempts (0 = infinite)\n * @default 0\n */\n maxAttempts?: number\n\n /**\n * Callback called on each status update\n */\n onUpdate?: (status: any) => void\n\n /**\n * Stop watching when magnet reaches this status\n * @default 'Ready'\n */\n stopOnStatus?: string\n\n /**\n * Use live mode for reduced bandwidth (delta sync)\n * When enabled, only changes are transmitted instead of full status\n * @default false\n */\n useLiveMode?: boolean\n}\n\n/**\n * Magnet/Torrent resource for managing torrent downloads\n */\nexport class MagnetResource extends BaseResource {\n /**\n * Upload magnets by URI or hash\n *\n * @param magnets - Single magnet URI/hash or array of magnets\n *\n * @example\n * ```ts\n * const result = await client.magnet.upload('magnet:?xt=urn:btih:...')\n * console.log('Magnet ID:', result.magnets[0].id)\n * ```\n */\n async upload(magnets: string | string[]) {\n const magnetsArray = Array.isArray(magnets) ? magnets : [magnets]\n return this.post<UploadMagnetsResponse>('/magnet/upload', {\n magnets: magnetsArray,\n })\n }\n\n /**\n * Upload a torrent file\n *\n * @param file - The torrent file (Blob or File)\n * @param filename - Optional filename (defaults to 'torrent.torrent' for Blob, or file.name for File)\n *\n * @example\n * ```ts\n * const file = new File([buffer], 'torrent.torrent')\n * const result = await client.magnet.uploadFile(file)\n *\n * // Or with a Blob and custom filename\n * const blob = new Blob([buffer])\n * const result = await client.magnet.uploadFile(blob, 'my-torrent.torrent')\n * ```\n */\n async uploadFile(file: Blob | File, filename?: string) {\n const formData = new FormData()\n\n // Determine the filename to use\n const actualFilename = filename || (file instanceof File ? file.name : 'torrent.torrent')\n\n // Append with explicit filename\n formData.append('files[]', file, actualFilename)\n\n return this.postFormData<UploadTorrentFileResponse>('/magnet/upload/file', formData)\n }\n\n /**\n * Get the status of a specific magnet by ID\n *\n * @param id - Magnet ID to get status for\n *\n * @example\n * ```ts\n * const status = await client.magnet.status(123)\n * console.log(status.magnets[0]?.status) // 'Downloading', 'Ready', etc.\n * ```\n *\n * @remarks\n * This endpoint uses AllDebrid API v4.1 (POST method)\n * Migrated from v4 GET endpoint which was deprecated on 2024-10-16\n */\n async status(id: number) {\n const data = await this.post<GetMagnetStatusResponse>('/magnet/status', { id })\n\n // Fix: AllDebrid API returns an object instead of array when filtering by ID\n // This is an API inconsistency, so we normalize it to always return an array\n if (data?.magnets && !Array.isArray(data.magnets)) {\n return {\n ...data,\n magnets: [data.magnets],\n }\n }\n\n return data\n }\n\n /**\n * Get list of magnets with optional status filter\n *\n * @param statusFilter - Optional filter by status: 'active', 'ready', 'expired', or 'error'\n *\n * @example\n * ```ts\n * // Get all magnets\n * const allMagnets = await client.magnet.statusList()\n *\n * // Get only active magnets\n * const activeMagnets = await client.magnet.statusList('active')\n *\n * // Get only ready magnets\n * const readyMagnets = await client.magnet.statusList('ready')\n * ```\n *\n * @remarks\n * This endpoint uses AllDebrid API v4.1 (POST method)\n */\n async statusList(statusFilter?: 'active' | 'ready' | 'expired' | 'error') {\n const body = statusFilter ? { status: statusFilter } : undefined\n return this.post<GetMagnetStatusResponse>('/magnet/status', body)\n }\n\n /**\n * Get magnet status using live mode for reduced bandwidth consumption\n *\n * Live mode uses delta synchronization - only changes since the last call are transmitted.\n * On the first call (counter=0), all data is returned with `fullsync: true`.\n * Subsequent calls return only modifications.\n *\n * @param options - Live mode options\n * @param options.session - Session ID (generate once per session and reuse)\n * @param options.counter - Synchronization counter (start at 0, use returned counter for next call)\n * @param id - Optional magnet ID to filter a specific magnet\n *\n * @example\n * ```ts\n * // Initialize session\n * const session = Math.floor(Math.random() * 1000000)\n * let counter = 0\n *\n * // First call - full sync\n * const firstCall = await client.magnet.statusLive({ session, counter })\n * console.log('Full sync:', firstCall.fullsync) // true\n * console.log('All magnets:', firstCall.magnets)\n *\n * // Update counter with value returned by API\n * counter = firstCall.counter\n *\n * // Second call - only changes\n * const secondCall = await client.magnet.statusLive({ session, counter })\n * console.log('Delta sync:', secondCall.magnets) // Only modified magnets\n *\n * // Filter specific magnet in live mode\n * const magnetLive = await client.magnet.statusLive({ session, counter }, 123)\n * ```\n *\n * @remarks\n * This is ideal for real-time dashboards or frequent polling scenarios\n * as it significantly reduces bandwidth usage by transmitting only changes.\n */\n async statusLive(options: LiveStatusOptions, id?: number) {\n const body: any = {\n session: options.session,\n counter: options.counter,\n }\n\n if (id !== undefined) {\n body.id = id\n }\n\n return this.post<GetMagnetStatusResponse>('/magnet/status', body)\n }\n\n /**\n * Delete a magnet\n *\n * @param id - The magnet ID to delete\n *\n * @example\n * ```ts\n * await client.magnet.delete(123)\n * ```\n */\n async delete(id: number) {\n return this.post<DeleteMagnetResponse>('/magnet/delete', {\n id,\n })\n }\n\n /**\n * Restart one or more failed magnets\n *\n * @param ids - Single magnet ID or array of magnet IDs to restart (numbers)\n *\n * @example\n * ```ts\n * // Restart single magnet\n * await client.magnet.restart(123)\n *\n * // Restart multiple magnets\n * await client.magnet.restart([123, 456])\n * ```\n */\n async restart(ids: number | number[]) {\n const idsArray = Array.isArray(ids) ? ids : [ids]\n return this.post<RestartMagnetResponse>('/magnet/restart', {\n ids: idsArray,\n })\n }\n\n /**\n * Get files for a completed magnet\n *\n * @param ids - The magnet ID or IDs to get files for\n *\n * @example\n * ```ts\n * const files = await client.magnet.files(123)\n * files?.forEach(file => {\n * console.log(file.filename, file.link)\n * })\n * ```\n *\n * @remarks\n * Files are now retrieved separately from magnet status (since v4.1)\n * Only available for magnets with status 'Ready'\n */\n async files(ids: number | number[]) {\n const formData = new FormData()\n const idsArray = Array.isArray(ids) ? ids : [ids]\n for (const id of idsArray) {\n formData.append('id[]', String(id))\n }\n const data = await this.postFormData<GetMagnetFilesResponse>('/magnet/files', formData)\n return data?.magnets\n }\n\n /**\n * Watch a magnet's status with automatic polling\n *\n * @param id - The magnet ID to watch\n * @param options - Watch options\n * @param options.interval - Polling interval in milliseconds (default: 3000)\n * @param options.maxAttempts - Maximum polling attempts, 0 for infinite (default: 0)\n * @param options.onUpdate - Callback called on each status update\n * @param options.stopOnStatus - Stop when magnet reaches this status (default: 'Ready')\n * @param options.useLiveMode - Use live mode for reduced bandwidth (default: false)\n *\n * @example\n * ```ts\n * // Standard mode\n * await client.magnet.watch(123, {\n * onUpdate: (status) => console.log('Status:', status.magnets[0]?.status),\n * stopOnStatus: 'Ready'\n * })\n *\n * // Live mode for reduced bandwidth\n * await client.magnet.watch(123, {\n * useLiveMode: true,\n * interval: 2000,\n * onUpdate: (status) => console.log('Update:', status)\n * })\n * ```\n */\n async watch(id: number, options: WatchOptions = {}) {\n const {\n interval = 3000,\n maxAttempts = 0,\n onUpdate,\n stopOnStatus = 'Ready',\n useLiveMode = false,\n } = options\n\n let attempt = 0\n\n // Live mode session state\n let session: number | undefined\n let counter = 0\n\n if (useLiveMode) {\n session = Math.floor(Math.random() * 1000000)\n }\n\n while (maxAttempts === 0 || attempt < maxAttempts) {\n attempt++\n\n // Use appropriate status method based on mode\n const status =\n useLiveMode && session !== undefined\n ? await this.statusLive({ session, counter }, id)\n : await this.status(id)\n\n // Update counter for next live mode call\n if (useLiveMode && status?.counter !== undefined) {\n counter = status.counter\n }\n\n onUpdate?.(status)\n\n // Check if we should stop (magnets is an array)\n const magnet = status?.magnets?.[0]\n if (magnet?.status === stopOnStatus) {\n return status\n }\n\n // Wait before next attempt\n await new Promise((resolve) => setTimeout(resolve, interval))\n }\n\n throw new Error(\n `Watch timeout: magnet did not reach '${stopOnStatus}' status after ${maxAttempts} attempts`,\n )\n }\n}\n","import type { CheckPinResponse, GetPinResponse } from '../generated/types.gen.js'\nimport { BaseResource } from '../base-resource.js'\n\n/**\n * Pin resource for PIN-based authentication flow\n *\n * The PIN flow allows users to authenticate without directly providing their API key.\n * This is useful for applications where you want users to authorize access through\n * the AllDebrid website.\n */\nexport class PinResource extends BaseResource {\n /**\n * Generate a new PIN code for authentication\n *\n * This initiates the PIN authentication flow. The user should visit the\n * returned URL to authorize the application.\n *\n * @example\n * ```ts\n * const pinData = await client.pin.generate()\n * console.log('Visit:', pinData.user_url)\n * console.log('PIN:', pinData.pin)\n *\n * // Poll the check endpoint until user authorizes\n * const auth = await client.pin.check(pinData.check, pinData.pin)\n * if (auth.activated) {\n * console.log('API Key:', auth.apikey)\n * }\n * ```\n *\n * @returns PIN code and authorization URL\n */\n async generate() {\n return super.get<GetPinResponse>('/pin/get')\n }\n\n /**\n * Check the status of a PIN authentication\n *\n * Poll this endpoint to check if the user has authorized the application.\n * Once authorized, the response will include the API key.\n *\n * @param check - Check ID from /pin/get\n * @param pin - PIN code from /pin/get\n *\n * @example\n * ```ts\n * const pinData = await client.pin.generate()\n *\n * // Poll every few seconds until activated\n * const checkStatus = async () => {\n * const result = await client.pin.check(pinData.check, pinData.pin)\n * if (result?.activated && result?.apikey) {\n * console.log('Authorized! API Key:', result.apikey)\n * return result.apikey\n * }\n * // Wait and try again\n * await new Promise(resolve => setTimeout(resolve, 3000))\n * return checkStatus()\n * }\n *\n * const apikey = await checkStatus()\n * ```\n *\n * @returns Authorization status and API key (if activated)\n */\n async check(check: string, pin: string) {\n return super.get<CheckPinResponse>('/pin/check', { check, pin })\n }\n\n /**\n * Helper method to wait for PIN authorization with automatic polling\n *\n * This method handles the polling logic for you, making it easier to\n * implement the PIN authentication flow.\n *\n * @param check - Check ID from /pin/get\n * @param pin - PIN code from /pin/get\n * @param options - Polling options\n * @param options.timeout - Maximum time to wait in milliseconds (default: 600000 = 10 minutes)\n * @param options.interval - Polling interval in milliseconds (default: 3000 = 3 seconds)\n *\n * @example\n * ```ts\n * const pinData = await client.pin.generate()\n * console.log('Visit:', pinData.user_url)\n *\n * try {\n * const apikey = await client.pin.waitForAuth(pinData.check, pinData.pin, {\n * timeout: 600000, // 10 minutes\n * interval: 3000, // Check every 3 seconds\n * })\n * console.log('Authorized! API Key:', apikey)\n * } catch (error) {\n * console.error('Authorization timed out or failed')\n * }\n * ```\n *\n * @returns The API key once authorized\n * @throws Error if timeout is reached or authorization fails\n */\n async waitForAuth(\n check: string,\n pin: string,\n options: {\n /** Maximum time to wait in milliseconds (default: 600000 = 10 minutes) */\n timeout?: number\n /** Polling interval in milliseconds (default: 3000 = 3 seconds) */\n interval?: number\n } = {},\n ): Promise<string> {\n const timeout = options.timeout ?? 600000 // 10 minutes default\n const interval = options.interval ?? 3000 // 3 seconds default\n const startTime = Date.now()\n\n while (Date.now() - startTime < timeout) {\n const result = await this.check(check, pin)\n\n if (result?.activated && result?.apikey) {\n return result.apikey\n }\n\n // Wait before next poll\n await new Promise((resolve) => setTimeout(resolve, interval))\n }\n\n throw new Error('PIN authorization timeout - user did not authorize within the time limit')\n }\n}\n","import type {\n ClearNotificationResponse,\n DeleteHistoryResponse,\n DeleteSavedLinksResponse,\n GetHistoryResponse,\n GetSavedLinksResponse,\n GetUserHostsResponse,\n GetUserResponse,\n GetVerifStatusResponse,\n ResendVerifResponse,\n SaveLinksResponse,\n} from '../generated/types.gen.js'\nimport { BaseResource } from '../base-resource.js'\n\n/**\n * User resource for managing user account information\n */\nexport class UserResource extends BaseResource {\n /**\n * Get user profile information including premium status and quotas\n *\n * @example\n * ```ts\n * const user = await client.user.getInfo()\n * console.log(user.username, user.isPremium)\n * ```\n */\n async getInfo() {\n const data = await this.get<GetUserResponse>('/user')\n return data?.user\n }\n\n /**\n * Get available hosts for the current user based on their subscription\n *\n * @param hostOnly - If true, only return hosts data (exclude streams and redirectors)\n *\n * @example\n * ```ts\n * const hosts = await client.user.getHosts()\n * console.log(Object.keys(hosts.hosts))\n * ```\n */\n async getHosts(hostOnly?: boolean) {\n const params = hostOnly ? { hostOnly: '1' } : undefined\n return this.get<GetUserHostsResponse>('/user/hosts', params)\n }\n\n /**\n * Clear a specific notification by code\n *\n * @param code - The notification code to clear\n *\n * @example\n * ```ts\n * await client.user.clearNotification('SOME_NOTIF_CODE')\n * ```\n */\n async clearNotification(code: string) {\n await this.post<ClearNotificationResponse>('/user/notification/clear', { code })\n }\n\n // ============================================\n // Saved Links Management\n // ============================================\n\n /**\n * Get all saved links\n *\n * @example\n * ```ts\n * const savedLinks = await client.user.getLinks()\n * console.log(savedLinks.links)\n * ```\n */\n async getLinks() {\n return this.get<GetSavedLinksResponse>('/user/links')\n }\n\n /**\n * Save one or multiple links for later use\n *\n * Supports batch operations - you can save multiple links in a single request.\n *\n * @param links - Single link or array of links to save\n *\n * @example\n * ```ts\n * // Save single link\n * await client.user.saveLink('https://example.com/file.zip')\n *\n * // Save multiple links at once\n * await client.user.saveLink([\n * 'https://example.com/file1.zip',\n * 'https://example.com/file2.zip',\n * 'https://example.com/file3.zip'\n * ])\n * ```\n */\n async saveLink(links: string | string[]) {\n const linksArray = Array.isArray(links) ? links : [links]\n const formData = new FormData()\n\n // API expects links[] array format\n for (const link of linksArray) {\n formData.append('links[]', link)\n }\n\n return this.postFormData<SaveLinksResponse>('/user/links/save', formData)\n }\n\n /**\n * Delete one or multiple saved links\n *\n * Supports batch operations - you can delete multiple links in a single request.\n *\n * @param links - Single link or array of links to delete (can be saved link IDs or URLs)\n *\n * @example\n * ```ts\n * // Delete single link\n * await client.user.deleteLink('saved-link-id')\n *\n * // Delete multiple links at once\n * await client.user.deleteLink([\n * 'saved-link-id-1',\n * 'saved-link-id-2',\n * 'saved-link-id-3'\n * ])\n * ```\n */\n async deleteLink(links: string | string[]) {\n const linksArray = Array.isArray(links) ? links : [links]\n const formData = new FormData()\n\n // API expects links[] array format\n for (const link of linksArray) {\n formData.append('links[]', link)\n }\n\n return this.postFormData<DeleteSavedLinksResponse>('/user/links/delete', formData)\n }\n\n // ============================================\n // History Management\n // ============================================\n\n /**\n * Get user history (if enabled in account settings)\n *\n * @example\n * ```ts\n * const history = await client.user.getHistory()\n * console.log(history.links)\n * ```\n */\n async getHistory() {\n return this.get<GetHistoryResponse>('/user/history')\n }\n\n /**\n * Clear user history\n *\n * @example\n * ```ts\n * await client.user.clearHistory()\n * ```\n */\n async clearHistory() {\n return this.post<DeleteHistoryResponse>('/user/history/delete')\n }\n\n // ============================================\n // Email Verification\n // ============================================\n\n /**\n * Check email verification status\n *\n * @param token - Verification token\n *\n * @example\n * ```ts\n * const status = await client.user.getVerificationStatus('verification-token')\n * console.log(status.verif) // 'waiting', 'allowed', or 'denied'\n * ```\n */\n async getVerificationStatus(token: string) {\n return this.post<GetVerifStatusResponse>('/user/verif', undefined, { token })\n }\n\n /**\n * Resend verification email\n *\n * @param token - Verification token\n *\n * @example\n * ```ts\n * await client.user.resendVerification('verification-token')\n * ```\n */\n async resendVerification(token: string) {\n return this.post<ResendVerifResponse>('/user/verif/resend', undefined, { token })\n }\n}\n","import type {\n GenerateVouchersResponse,\n GetAvailableVouchersResponse,\n GetVoucherBalanceResponse,\n} from '../generated/types.gen.js'\nimport { BaseResource } from '../base-resource.js'\n\n/**\n * Voucher resource for reseller voucher management\n *\n * Note: These endpoints are only available for reseller accounts.\n */\nexport class VoucherResource extends BaseResource {\n /**\n * Get voucher balance for reseller accounts\n *\n * This endpoint allows resellers to check their remaining voucher balance.\n * Only available for accounts with reseller privileges.\n *\n * @example\n * ```ts\n * const balance = await client.voucher.getBalance()\n * console.log('Remaining balance:', balance.balance, '€')\n * ```\n *\n * @returns Voucher balance information\n */\n async getBalance() {\n return this.get<GetVoucherBalanceResponse>('/voucher/balance')\n }\n\n /**\n * Retrieve existing vouchers from reseller inventory\n *\n * This endpoint retrieves vouchers that were previously generated\n * and are available in your inventory.\n *\n * @param quantity - Optional number of vouchers to retrieve\n *\n * @example\n * ```ts\n * // Get all available vouchers\n * const allVouchers = await client.voucher.getVouchers()\n * console.log('Vouchers:', allVouchers?.codes)\n *\n * // Get specific quantity\n * const fiveVouchers = await client.voucher.getVouchers(5)\n * ```\n *\n * @returns List of voucher codes\n */\n async getVouchers(quantity?: number) {\n const params = quantity ? { quantity } : undefined\n return this.get<GetAvailableVouchersResponse>('/voucher/get', params)\n }\n\n /**\n * Generate new vouchers (deducts from reseller balance)\n *\n * This endpoint creates new vouchers and deducts the cost from your\n * reseller account balance.\n *\n * @param quantity - Number of vouchers to generate\n * @param duration - Voucher duration in days\n *\n * @example\n * ```ts\n * // Generate 10 vouchers valid for 30 days\n * const vouchers = await client.voucher.generateVouchers(10, 30)\n * console.log('Generated vouchers:', vouchers?.codes)\n *\n * // Generate 5 vouchers valid for 7 days\n * const weekVouchers = await client.voucher.generateVouchers(5, 7)\n * ```\n *\n * @returns List of newly generated voucher codes\n */\n async generateVouchers(quantity: number, duration: number) {\n return this.post<GenerateVouchersResponse>('/voucher/generate', {\n quantity,\n duration,\n })\n }\n}\n","import type { PingResponse } from './generated/types.gen.js'\nimport type { AllDebridConfig, ApiResponse, ExtractData } from './types.js'\nimport wretch from 'wretch'\nimport { createTypedError, NetworkError } from './errors.js'\nimport { HostResource } from './resources/host.js'\nimport { LinkResource } from './resources/link.js'\nimport { MagnetResource } from './resources/magnet.js'\nimport { PinResource } from './resources/pin.js'\nimport { UserResource } from './resources/user.js'\nimport { VoucherResource } from './resources/voucher.js'\n\nconst DEFAULT_BASE_URL = 'https://api.alldebrid.com/v4.1'\nconst DEFAULT_AGENT = '@alldebrid/sdk'\nconst DEFAULT_TIMEOUT = 30000\nconst DEFAULT_MAX_RETRIES = 3\n\n/**\n * Main AllDebrid client class\n */\nexport class AllDebridClient {\n private readonly config: Required<AllDebridConfig>\n\n /**\n * User resource for managing user account\n */\n public readonly user: UserResource\n\n /**\n * Link resource for unlocking and managing download links\n */\n public readonly link: LinkResource\n\n /**\n * Magnet resource for managing torrents\n */\n public readonly magnet: MagnetResource\n\n /**\n * Host resource for getting information about supported hosts\n */\n public readonly host: HostResource\n\n /**\n * Pin resource for PIN-based authentication\n */\n public readonly pin: PinResource\n\n /**\n * Voucher resource for reseller voucher management\n */\n public readonly voucher: VoucherResource\n\n constructor(config: AllDebridConfig) {\n // Merge config with defaults\n this.config = {\n apiKey: config.apiKey,\n agent: config.agent ?? DEFAULT_AGENT,\n baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,\n timeout: config.timeout ?? DEFAULT_TIMEOUT,\n retry: config.retry ?? true,\n maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,\n }\n\n // Initialize resources\n this.user = new UserResource(this)\n this.link = new LinkResource(this)\n this.magnet = new MagnetResource(this)\n this.host = new HostResource(this)\n this.pin = new PinResource(this)\n this.voucher = new VoucherResource(this)\n }\n\n /**\n * Build query string from params\n */\n private buildUrl(path: string, params?: Record<string, unknown>): string {\n const allParams = {\n agent: this.config.agent,\n ...params,\n }\n\n const query = new URLSearchParams()\n for (const [key, value] of Object.entries(allParams)) {\n if (value !== undefined && value !== null) {\n if (Array.isArray(value)) {\n value.forEach((v) => query.append(`${key}[]`, String(v)))\n } else {\n query.append(key, String(value))\n }\n }\n }\n\n const queryString = query.toString()\n return queryString ? `${path}?${queryString}` : path\n }\n\n /**\n * Make a GET request\n * @template T - The generated response type (e.g., GetLinkUnlockResponse)\n * @param path - API endpoint path\n * @param params - Optional query parameters\n * @returns The extracted data from the response (without the { status, data } wrapper)\n * @internal\n */\n async get<T>(path: string, params?: Record<string, unknown>): Promise<ExtractData<T>> {\n try {\n const url = this.buildUrl(path, params)\n const json = await wretch(this.config.baseUrl)\n .auth(`Bearer ${this.config.apiKey}`)\n .url(url)\n .get()\n .json<ApiResponse<unknown>>()\n\n // Handle error responses\n if (json.status === 'error' && json.error) {\n throw createTypedError(json.error.code, json.error.message)\n }\n\n return json.data as ExtractData<T>\n } catch (error: any) {\n // Handle HTTP errors\n if (error.status === 401) {\n throw createTypedError('AUTH_BAD_APIKEY', 'Invalid API key or unauthorized access')\n }\n if (error.status === 403) {\n throw createTypedError('AUTH_BLOCKED', 'Access forbidden')\n }\n if (error.status === 429) {\n throw createTypedError('RATE_LIMITED', 'Too many requests')\n }\n\n // Re-throw if already our error type\n if (error.isAllDebridError) {\n throw error\n }\n\n // Wrap in NetworkError\n throw new NetworkError(error.message || 'Network error occurred', error.status)\n }\n }\n\n /**\n * Make a POST request with application/x-www-form-urlencoded\n * @template T - The generated response type\n * @param path - API endpoint path\n * @param body - Request body (will be converted to URLSearchParams)\n * @param params - Optional query parameters\n * @returns The extracted data from the response (without the { status, data } wrapper)\n * @internal\n */\n async post<T>(\n path: string,\n body?: unknown,\n params?: Record<string, unknown>,\n ): Promise<ExtractData<T>> {\n try {\n const url = this.buildUrl(path, params)\n\n // Convert body to URLSearchParams for application/x-www-form-urlencoded\n const formData = new URLSearchParams()\n if (body && typeof body === 'object') {\n for (const [key, value] of Object.entries(body)) {\n if (value !== undefined && value !== null) {\n if (Array.isArray(value)) {\n // Handle arrays (e.g., link[] for multiple links)\n value.forEach((v) => formData.append(key, String(v)))\n } else {\n formData.append(key, String(value))\n }\n }\n }\n }\n\n const json = await wretch(this.config.baseUrl)\n .auth(`Bearer ${this.config.apiKey}`)\n .url(url)\n .body(formData)\n .post()\n .json<ApiResponse<unknown>>()\n\n // Handle error responses\n if (json.status === 'error' && json.error) {\n throw createTypedError(json.error.code, json.error.message)\n }\n\n return json.data as ExtractData<T>\n } catch (error: any) {\n // Handle HTTP errors\n if (error.status === 401) {\n throw createTypedError('AUTH_BAD_APIKEY', 'Invalid API key or unauthorized access')\n }\n if (error.status === 403) {\n throw createTypedError('AUTH_BLOCKED', 'Access forbidden')\n }\n if (error.status === 429) {\n throw createTypedError('RATE_LIMITED', 'Too many requests')\n }\n\n // Re-throw if already our error type\n if (error.isAllDebridError) {\n throw error\n }\n\n // Wrap in NetworkError\n throw new NetworkError(error.message || 'Network error occurred', error.status)\n }\n }\n\n /**\n * Make a POST request with FormData (multipart/form-data)\n * @template T - The generated response type\n * @param path - API endpoint path\n * @param formData - Form data to send\n * @param params - Optional query parameters\n * @returns The extracted data from the response (without the { status, data } wrapper)\n * @internal\n */\n async postFormData<T>(\n path: string,\n formData: FormData,\n params?: Record<string, unknown>,\n ): Promise<ExtractData<T>> {\n try {\n const url = this.buildUrl(path, params)\n const json = await wretch(this.config.baseUrl)\n .auth(`Bearer ${this.config.apiKey}`)\n .url(url)\n .body(formData)\n .post()\n .json<ApiResponse<unknown>>()\n\n // Handle error responses\n if (json.status === 'error' && json.error) {\n throw createTypedError(json.error.code, json.error.message)\n }\n\n return json.data as ExtractData<T>\n } catch (error: any) {\n // Handle HTTP errors\n if (error.status === 401) {\n throw createTypedError('AUTH_BAD_APIKEY', 'Invalid API key or unauthorized access')\n }\n if (error.status === 403) {\n throw createTypedError('AUTH_BLOCKED', 'Access forbidden')\n }\n if (error.status === 429) {\n throw createTypedError('RATE_LIMITED', 'Too many requests')\n }\n\n // Re-throw if already our error type\n if (error.isAllDebridError) {\n throw error\n }\n\n // Wrap in NetworkError\n throw new NetworkError(error.message || 'Network error occurred', error.status)\n }\n }\n\n /**\n * Test the API connection\n *\n * This endpoint doesn't require authentication and can be used to verify\n * that the AllDebrid API is reachable.\n *\n * @example\n * ```ts\n * const result = await client.ping()\n * console.log(result.ping) // 'pong'\n * ```\n *\n * @returns Ping response with 'pong' message\n */\n async ping() {\n return this.get<PingResponse>('/ping')\n }\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/base-resource.ts","../src/resources/host.ts","../src/resources/link.ts","../src/resources/magnet.ts","../src/resources/pin.ts","../src/resources/user.ts","../src/resources/voucher.ts","../src/client.ts"],"names":["wretch"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { ApiError } from './types.js'\n\n/**\n * Base error class for AllDebrid SDK errors\n */\nexport class AllDebridError extends Error {\n public readonly code: string\n public readonly isAllDebridError = true\n\n constructor(code: string, message: string) {\n super(message)\n this.name = 'AllDebridError'\n this.code = code\n\n // Maintains proper stack trace for where our error was thrown (only available on V8)\n if ('captureStackTrace' in Error && typeof (Error as any).captureStackTrace === 'function') {\n ;(Error as any).captureStackTrace(this, AllDebridError)\n }\n }\n\n /**\n * Create an AllDebridError from an API error response\n */\n static fromApiError(error: ApiError): AllDebridError {\n return new AllDebridError(error.code, error.message)\n }\n}\n\n/**\n * Authentication related errors\n */\nexport class AuthenticationError extends AllDebridError {\n constructor(code: string, message: string) {\n super(code, message)\n this.name = 'AuthenticationError'\n }\n}\n\n/**\n * Link processing errors\n */\nexport class LinkError extends AllDebridError {\n constructor(code: string, message: string) {\n super(code, message)\n this.name = 'LinkError'\n }\n}\n\n/**\n * Magnet/Torrent related errors\n */\nexport class MagnetError extends AllDebridError {\n constructor(code: string, message: string) {\n super(code, message)\n this.name = 'MagnetError'\n }\n}\n\n/**\n * Network/HTTP errors\n */\nexport class NetworkError extends AllDebridError {\n constructor(\n message: string,\n public readonly statusCode?: number,\n ) {\n super('NETWORK_ERROR', message)\n this.name = 'NetworkError'\n }\n}\n\n/**\n * Helper to determine error type from error code\n */\nexport function createTypedError(code: string, message: string): AllDebridError {\n if (code.startsWith('AUTH_')) {\n return new AuthenticationError(code, message)\n }\n if (\n code.startsWith('LINK_') ||\n code.startsWith('REDIRECTOR_') ||\n code.startsWith('STREAM_') ||\n code.startsWith('DELAYED_')\n ) {\n return new LinkError(code, message)\n }\n if (code.startsWith('MAGNET_')) {\n return new MagnetError(code, message)\n }\n return new AllDebridError(code, message)\n}\n","import type { AllDebridClient } from './client.js'\nimport type { ExtractData } from './types.js'\n\n/**\n * Base class for all resources\n * Provides access to HTTP methods\n * @internal\n */\nexport abstract class BaseResource {\n constructor(protected readonly client: AllDebridClient) {}\n\n /**\n * Make a GET request\n * @template T - The generated response type (e.g., GetLinkUnlockResponse)\n * @param path - API endpoint path\n * @param params - Optional query parameters\n * @returns The extracted data from the response (without the { status, data } wrapper)\n */\n protected async get<T>(path: string, params?: Record<string, unknown>): Promise<ExtractData<T>> {\n return this.client.get<T>(path, params)\n }\n\n /**\n * Make a POST request\n * @template T - The generated response type\n * @param path - API endpoint path\n * @param body - Request body\n * @param params - Optional query parameters\n * @returns The extracted data from the response (without the { status, data } wrapper)\n */\n protected async post<T>(\n path: string,\n body?: unknown,\n params?: Record<string, unknown>,\n ): Promise<ExtractData<T>> {\n return this.client.post<T>(path, body, params)\n }\n\n /**\n * Make a POST request with FormData (multipart/form-data)\n * @template T - The generated response type\n * @param path - API endpoint path\n * @param formData - Form data to send\n * @param params - Optional query parameters\n * @returns The extracted data from the response (without the { status, data } wrapper)\n */\n protected async postFormData<T>(\n path: string,\n formData: FormData,\n params?: Record<string, unknown>,\n ): Promise<ExtractData<T>> {\n return this.client.postFormData<T>(path, formData, params)\n }\n}\n","import type {\n GetHostDomainsResponse,\n GetHostPriorityResponse,\n GetHostsResponse,\n} from '../generated/types.gen.js'\nimport { BaseResource } from '../base-resource.js'\n\n/**\n * Host resource for getting information about supported hosts\n */\nexport class HostResource extends BaseResource {\n /**\n * Get list of all supported hosts with their information\n *\n * @param hostOnly - If true, only return hosts (exclude streams and redirectors)\n *\n * @example\n * ```ts\n * const hosts = await client.host.list()\n * console.log(hosts.hosts) // All supported file hosts\n * console.log(hosts.streams) // Streaming hosts\n * console.log(hosts.redirectors) // Link redirectors\n * ```\n */\n async list(hostOnly?: boolean) {\n const params = hostOnly ? { hostOnly: '1' } : undefined\n return this.get<GetHostsResponse>('/hosts', params)\n }\n\n /**\n * Get array of all supported domain names\n *\n * @example\n * ```ts\n * const domains = await client.host.domains()\n * console.log(domains) // ['rapidgator.net', 'uploaded.net', ...]\n * ```\n */\n async domains() {\n return this.get<GetHostDomainsResponse>('/hosts/domains')\n }\n\n /**\n * Get hosts ordered by restriction level (priority list)\n *\n * @example\n * ```ts\n * const priority = await client.host.priority()\n * console.log(priority.hosts) // Ordered list with restriction levels\n * ```\n */\n async priority() {\n return this.get<GetHostPriorityResponse>('/hosts/priority')\n }\n}\n","import type {\n GetDelayedStatusResponse,\n GetLinkInfosResponse,\n GetRedirectorLinksResponse,\n GetStreamingLinkResponse,\n UnlockLinkResponse,\n} from '../generated/types.gen.js'\nimport { BaseResource } from '../base-resource.js'\n\n/**\n * Options for polling delayed link generation\n */\nexport interface PollOptions {\n /**\n * Polling interval in milliseconds\n * @default 2000\n */\n interval?: number\n\n /**\n * Maximum number of polling attempts\n * @default 30\n */\n maxAttempts?: number\n\n /**\n * Callback called on each polling attempt\n */\n onPoll?: (attempt: number) => void\n}\n\n/**\n * Link resource for unlocking and managing download links\n */\nexport class LinkResource extends BaseResource {\n /**\n * Get information about one or more links\n *\n * @param links - Single link or array of links to get info for\n * @param password - Optional password for password-protected links\n *\n * @example\n * ```ts\n * const data = await client.link.infos('https://example.com/file.zip')\n * console.log(data.infos)\n *\n * // With password\n * const protectedData = await client.link.infos(\n * 'https://example.com/protected.zip',\n * 'mypassword'\n * )\n * ```\n */\n async infos(links: string | string[], password?: string) {\n const linksArray = Array.isArray(links) ? links : [links]\n const params = password ? { password } : undefined\n return this.post<GetLinkInfosResponse>('/link/infos', { 'link[]': linksArray }, params)\n }\n\n /**\n * Extract links from redirectors/link protectors\n *\n * @param link - The redirector link to extract from\n *\n * @example\n * ```ts\n * const data = await client.link.redirector('https://linkprotector.com/abc123')\n * console.log(data.links)\n * ```\n */\n async redirector(link: string) {\n return this.post<GetRedirectorLinksResponse>('/link/redirector', {\n link,\n })\n }\n\n /**\n * Unlock a download link\n *\n * @param link - The link to unlock\n * @param password - Optional password for password-protected links\n *\n * @example\n * ```ts\n * const result = await client.link.unlock('https://example.com/file.zip')\n * if (result.link) {\n * console.log('Direct link:', result.link)\n * } else if (result.delayed) {\n * // Handle delayed generation\n * const delayedResult = await client.link.delayed(result.delayed)\n * }\n *\n * // With password\n * const protectedResult = await client.link.unlock(\n * 'https://example.com/protected.zip',\n * 'mypassword'\n * )\n * ```\n */\n async unlock(link: string, password?: string) {\n const params = password ? { password } : undefined\n return this.post<UnlockLinkResponse>('/link/unlock', { link }, params)\n }\n\n /**\n * Unlock a link and automatically poll if delayed\n * Note: The API response format doesn't include a delayed field in the current OpenAPI spec.\n * This method will be updated once the delayed mechanism is documented.\n *\n * @param link - The link to unlock\n * @param _options - Polling options (currently unused)\n *\n * @example\n * ```ts\n * const result = await client.link.unlockWithPolling('https://example.com/file.zip')\n * console.log('Direct link:', result.link)\n * ```\n */\n async unlockWithPolling(link: string, _options: PollOptions = {}) {\n // For now, just unlock without polling\n // TODO: Implement polling once delayed field is added to API response\n return this.unlock(link)\n }\n\n /**\n * Get streaming options for a generated link\n *\n * @param id - The generated link ID or streaming ID\n *\n * @example\n * ```ts\n * const streams = await client.link.streaming('abc123')\n * ```\n */\n async streaming(id: string, stream: string) {\n return this.post<GetStreamingLinkResponse>('/link/streaming', {\n id,\n stream,\n })\n }\n\n /**\n * Get the status/result of a delayed link generation\n *\n * @param id - The delayed generation ID\n *\n * @example\n * ```ts\n * const result = await client.link.delayed('delayed_id_123')\n * ```\n */\n async delayed(id: number) {\n return this.post<GetDelayedStatusResponse>('/link/delayed', {\n id,\n })\n }\n}\n","import type {\n DeleteMagnetResponse,\n GetMagnetFilesResponse,\n GetMagnetStatusResponse,\n RestartMagnetResponse,\n UploadMagnetsResponse,\n UploadTorrentFileResponse,\n} from '../generated/types.gen.js'\nimport { BaseResource } from '../base-resource.js'\n\n/**\n * Options for live mode status polling\n */\nexport interface LiveStatusOptions {\n /**\n * Session ID - Generate a random number and keep it consistent for the entire session\n * @example Math.floor(Math.random() * 1000000)\n */\n session: number\n\n /**\n * Counter for synchronization - Start at 0 and increment with each call\n * The API will return the next counter value to use\n */\n counter: number\n}\n\n/**\n * Options for watching magnet status\n */\nexport interface WatchOptions {\n /**\n * Polling interval in milliseconds\n * @default 3000\n */\n interval?: number\n\n /**\n * Maximum number of polling attempts (0 = infinite)\n * @default 0\n */\n maxAttempts?: number\n\n /**\n * Callback called on each status update\n */\n onUpdate?: (status: any) => void\n\n /**\n * Stop watching when magnet reaches this status\n * @default 'Ready'\n */\n stopOnStatus?: string\n}\n\n/**\n * Magnet/Torrent resource for managing torrent downloads\n */\nexport class MagnetResource extends BaseResource {\n /**\n * Upload magnets by URI or hash\n *\n * @param magnets - Single magnet URI/hash or array of magnets\n *\n * @example\n * ```ts\n * const result = await client.magnet.upload('magnet:?xt=urn:btih:...')\n * console.log('Magnet ID:', result.magnets[0].id)\n * ```\n */\n async upload(magnets: string | string[]) {\n const magnetsArray = Array.isArray(magnets) ? magnets : [magnets]\n return this.post<UploadMagnetsResponse>('/magnet/upload', {\n magnets: magnetsArray,\n })\n }\n\n /**\n * Upload a torrent file\n *\n * @param file - The torrent file (Blob or File)\n * @param filename - Optional filename (defaults to 'torrent.torrent' for Blob, or file.name for File)\n *\n * @example\n * ```ts\n * const file = new File([buffer], 'torrent.torrent')\n * const result = await client.magnet.uploadFile(file)\n *\n * // Or with a Blob and custom filename\n * const blob = new Blob([buffer])\n * const result = await client.magnet.uploadFile(blob, 'my-torrent.torrent')\n * ```\n */\n async uploadFile(file: Blob | File, filename?: string) {\n const formData = new FormData()\n\n // Determine the filename to use\n const actualFilename = filename || (file instanceof File ? file.name : 'torrent.torrent')\n\n // Append with explicit filename\n formData.append('files[]', file, actualFilename)\n\n return this.postFormData<UploadTorrentFileResponse>('/magnet/upload/file', formData)\n }\n\n /**\n * Get the status of a specific magnet by ID\n *\n * @param id - Magnet ID to get status for\n *\n * @example\n * ```ts\n * const status = await client.magnet.status(123)\n * console.log(status.magnets[0]?.status) // 'Downloading', 'Ready', etc.\n * ```\n *\n * @remarks\n * This endpoint uses AllDebrid API v4.1 (POST method)\n * Migrated from v4 GET endpoint which was deprecated on 2024-10-16\n */\n async status(id: number) {\n const data = await this.post<GetMagnetStatusResponse>('/magnet/status', { id })\n\n // Fix: AllDebrid API returns an object instead of array when filtering by ID\n // This is an API inconsistency, so we normalize it to always return an array\n if (data?.magnets && !Array.isArray(data.magnets)) {\n return {\n ...data,\n magnets: [data.magnets],\n }\n }\n\n return data\n }\n\n /**\n * Get list of magnets with optional status filter\n *\n * @param statusFilter - Optional filter by status: 'active', 'ready', 'expired', or 'error'\n *\n * @example\n * ```ts\n * // Get all magnets\n * const allMagnets = await client.magnet.statusList()\n *\n * // Get only active magnets\n * const activeMagnets = await client.magnet.statusList('active')\n *\n * // Get only ready magnets\n * const readyMagnets = await client.magnet.statusList('ready')\n * ```\n *\n * @remarks\n * This endpoint uses AllDebrid API v4.1 (POST method)\n */\n async statusList(statusFilter?: 'active' | 'ready' | 'expired' | 'error') {\n const body = statusFilter ? { status: statusFilter } : undefined\n return this.post<GetMagnetStatusResponse>('/magnet/status', body)\n }\n\n /**\n * Get magnet status using live mode for bandwidth-optimized delta synchronization\n *\n * Live mode is designed for monitoring multiple magnets efficiently by only transmitting\n * changes between polling intervals, drastically reducing bandwidth usage for dashboards\n * and real-time monitoring applications.\n *\n * ## How it works\n *\n * 1. **Session initialization**: Generate a random session ID and start with counter = 0\n * 2. **First call (fullsync)**: Returns ALL magnets with `fullsync: true`\n * 3. **Update counter**: Use the `counter` value returned by the API for the next call\n * 4. **Subsequent calls (delta)**: Returns ONLY magnets that changed since last call\n * 5. **Repeat**: Keep calling with updated counter to receive only deltas\n *\n * ## When to use\n *\n * - ✅ Monitoring multiple active magnets simultaneously\n * - ✅ Building real-time dashboards\n * - ✅ High-frequency polling scenarios (every few seconds)\n * - ❌ Watching a single specific magnet (use `watch()` instead)\n *\n * ## Important notes\n *\n * - **Don't use the `id` parameter**: Passing an ID defeats the purpose of live mode\n * as it disables delta sync and behaves like a regular `status()` call\n * - **Session persistence**: Keep the same session ID for the entire monitoring session\n * - **Counter tracking**: Always update the counter with the value returned by the API\n * - **Empty deltas**: When no magnets changed, `magnets` will be an empty array\n *\n * @param options - Live mode session options\n * @param options.session - Unique session ID (generate once: `Math.floor(Math.random() * 1000000)`)\n * @param options.counter - Sync counter (start at 0, then use value from previous API response)\n *\n * @example\n * ```ts\n * // Initialize session\n * const session = Math.floor(Math.random() * 1000000)\n * let counter = 0\n *\n * // First call - returns all magnets (fullsync: true)\n * const firstCall = await client.magnet.statusLive({ session, counter })\n * console.log('Full sync:', firstCall.fullsync) // true\n * console.log('All magnets:', firstCall.magnets) // Array of all magnets\n * counter = firstCall.counter // Update counter for next call\n *\n * // Second call - returns only magnets that changed\n * await new Promise(resolve => setTimeout(resolve, 3000)) // Wait 3 seconds\n * const secondCall = await client.magnet.statusLive({ session, counter })\n * console.log('Delta sync:', secondCall.magnets) // Only changed magnets\n * counter = secondCall.counter\n *\n * // Example: Monitor all magnets until none are active\n * const activeMagnets = new Map()\n *\n * while (true) {\n * const response = await client.magnet.statusLive({ session, counter })\n * counter = response.counter ?? counter\n *\n * // Update our local state with changes\n * if (response.fullsync) {\n * activeMagnets.clear()\n * response.magnets?.forEach(m => activeMagnets.set(m.id, m))\n * } else {\n * response.magnets?.forEach(m => {\n * if (m.status === 'Ready' || m.status === 'Error' || m.status === 'Expired') {\n * activeMagnets.delete(m.id)\n * } else {\n * activeMagnets.set(m.id, m)\n * }\n * })\n * }\n *\n * // Display current state\n * console.log(`Active downloads: ${activeMagnets.size}`)\n * activeMagnets.forEach(m => {\n * console.log(` ${m.filename}: ${m.status} - ${m.downloaded}/${m.size} bytes`)\n * })\n *\n * // Stop when no more active magnets\n * if (activeMagnets.size === 0) {\n * console.log('All downloads completed!')\n * break\n * }\n *\n * await new Promise(resolve => setTimeout(resolve, 3000))\n * }\n * ```\n *\n * @remarks\n * This method is ideal for scenarios where you're monitoring multiple magnets and want\n * to minimize bandwidth. For simple single-magnet monitoring, use `watch()` instead.\n */\n async statusLive(options: LiveStatusOptions) {\n const body: any = {\n session: options.session,\n counter: options.counter,\n }\n\n return this.post<GetMagnetStatusResponse>('/magnet/status', body)\n }\n\n /**\n * Delete a magnet\n *\n * @param id - The magnet ID to delete\n *\n * @example\n * ```ts\n * await client.magnet.delete(123)\n * ```\n */\n async delete(id: number) {\n return this.post<DeleteMagnetResponse>('/magnet/delete', {\n id,\n })\n }\n\n /**\n * Restart one or more failed magnets\n *\n * @param ids - Single magnet ID or array of magnet IDs to restart (numbers)\n *\n * @example\n * ```ts\n * // Restart single magnet\n * await client.magnet.restart(123)\n *\n * // Restart multiple magnets\n * await client.magnet.restart([123, 456])\n * ```\n */\n async restart(ids: number | number[]) {\n const idsArray = Array.isArray(ids) ? ids : [ids]\n return this.post<RestartMagnetResponse>('/magnet/restart', {\n ids: idsArray,\n })\n }\n\n /**\n * Get files for a completed magnet\n *\n * @param ids - The magnet ID or IDs to get files for\n *\n * @example\n * ```ts\n * const data = await client.magnet.files(123)\n * data?.magnets?.forEach(magnet => {\n * console.log(magnet.filename, magnet.files)\n * })\n * ```\n *\n * @remarks\n * Files are now retrieved separately from magnet status (since v4.1)\n * Only available for magnets with status 'Ready'\n */\n async files(ids: number | number[]) {\n const formData = new FormData()\n const idsArray = Array.isArray(ids) ? ids : [ids]\n for (const id of idsArray) {\n formData.append('id[]', String(id))\n }\n return this.postFormData<GetMagnetFilesResponse>('/magnet/files', formData)\n }\n\n /**\n * Watch a magnet's status with automatic polling\n *\n * This is a simple helper that polls the status of a specific magnet until it reaches\n * a target status (default: 'Ready'). For advanced use cases with multiple magnets\n * or bandwidth optimization, use `statusLive()` directly instead.\n *\n * @param id - The magnet ID to watch\n * @param options - Watch options\n * @param options.interval - Polling interval in milliseconds (default: 3000)\n * @param options.maxAttempts - Maximum polling attempts, 0 for infinite (default: 0)\n * @param options.onUpdate - Callback called on each status update\n * @param options.stopOnStatus - Stop when magnet reaches this status (default: 'Ready')\n *\n * @example\n * ```ts\n * await client.magnet.watch(123, {\n * onUpdate: (status) => console.log('Status:', status.magnets[0]?.status),\n * stopOnStatus: 'Ready'\n * })\n * ```\n *\n * @remarks\n * For monitoring multiple magnets efficiently, use `statusLive()` directly.\n * See the `statusLive()` documentation for details on delta synchronization.\n */\n async watch(id: number, options: WatchOptions = {}) {\n const { interval = 3000, maxAttempts = 0, onUpdate, stopOnStatus = 'Ready' } = options\n\n let attempt = 0\n\n while (maxAttempts === 0 || attempt < maxAttempts) {\n attempt++\n\n const status = await this.status(id)\n\n onUpdate?.(status)\n\n // Check if we should stop (magnets is normalized to an array with one element)\n const magnet = status?.magnets?.[0]\n if (magnet?.status === stopOnStatus) {\n return status\n }\n\n // Wait before next attempt\n await new Promise((resolve) => setTimeout(resolve, interval))\n }\n\n throw new Error(\n `Watch timeout: magnet did not reach '${stopOnStatus}' status after ${maxAttempts} attempts`,\n )\n }\n}\n","import type { CheckPinResponse, GetPinResponse } from '../generated/types.gen.js'\nimport { BaseResource } from '../base-resource.js'\n\n/**\n * Pin resource for PIN-based authentication flow\n *\n * The PIN flow allows users to authenticate without directly providing their API key.\n * This is useful for applications where you want users to authorize access through\n * the AllDebrid website.\n */\nexport class PinResource extends BaseResource {\n /**\n * Generate a new PIN code for authentication\n *\n * This initiates the PIN authentication flow. The user should visit the\n * returned URL to authorize the application.\n *\n * @example\n * ```ts\n * const pinData = await client.pin.generate()\n * console.log('Visit:', pinData.user_url)\n * console.log('PIN:', pinData.pin)\n *\n * // Poll the check endpoint until user authorizes\n * const auth = await client.pin.check(pinData.check, pinData.pin)\n * if (auth.activated) {\n * console.log('API Key:', auth.apikey)\n * }\n * ```\n *\n * @returns PIN code and authorization URL\n */\n async generate() {\n return super.get<GetPinResponse>('/pin/get')\n }\n\n /**\n * Check the status of a PIN authentication\n *\n * Poll this endpoint to check if the user has authorized the application.\n * Once authorized, the response will include the API key.\n *\n * @param check - Check ID from /pin/get\n * @param pin - PIN code from /pin/get\n *\n * @example\n * ```ts\n * const pinData = await client.pin.generate()\n *\n * // Poll every few seconds until activated\n * const checkStatus = async () => {\n * const result = await client.pin.check(pinData.check, pinData.pin)\n * if (result?.activated && result?.apikey) {\n * console.log('Authorized! API Key:', result.apikey)\n * return result.apikey\n * }\n * // Wait and try again\n * await new Promise(resolve => setTimeout(resolve, 3000))\n * return checkStatus()\n * }\n *\n * const apikey = await checkStatus()\n * ```\n *\n * @returns Authorization status and API key (if activated)\n */\n async check(check: string, pin: string) {\n return super.get<CheckPinResponse>('/pin/check', { check, pin })\n }\n\n /**\n * Helper method to wait for PIN authorization with automatic polling\n *\n * This method handles the polling logic for you, making it easier to\n * implement the PIN authentication flow.\n *\n * @param check - Check ID from /pin/get\n * @param pin - PIN code from /pin/get\n * @param options - Polling options\n * @param options.timeout - Maximum time to wait in milliseconds (default: 600000 = 10 minutes)\n * @param options.interval - Polling interval in milliseconds (default: 3000 = 3 seconds)\n *\n * @example\n * ```ts\n * const pinData = await client.pin.generate()\n * console.log('Visit:', pinData.user_url)\n *\n * try {\n * const apikey = await client.pin.waitForAuth(pinData.check, pinData.pin, {\n * timeout: 600000, // 10 minutes\n * interval: 3000, // Check every 3 seconds\n * })\n * console.log('Authorized! API Key:', apikey)\n * } catch (error) {\n * console.error('Authorization timed out or failed')\n * }\n * ```\n *\n * @returns The API key once authorized\n * @throws Error if timeout is reached or authorization fails\n */\n async waitForAuth(\n check: string,\n pin: string,\n options: {\n /** Maximum time to wait in milliseconds (default: 600000 = 10 minutes) */\n timeout?: number\n /** Polling interval in milliseconds (default: 3000 = 3 seconds) */\n interval?: number\n } = {},\n ): Promise<string> {\n const timeout = options.timeout ?? 600000 // 10 minutes default\n const interval = options.interval ?? 3000 // 3 seconds default\n const startTime = Date.now()\n\n while (Date.now() - startTime < timeout) {\n const result = await this.check(check, pin)\n\n if (result?.activated && result?.apikey) {\n return result.apikey\n }\n\n // Wait before next poll\n await new Promise((resolve) => setTimeout(resolve, interval))\n }\n\n throw new Error('PIN authorization timeout - user did not authorize within the time limit')\n }\n}\n","import type {\n ClearNotificationResponse,\n DeleteHistoryResponse,\n DeleteSavedLinksResponse,\n GetHistoryResponse,\n GetSavedLinksResponse,\n GetUserHostsResponse,\n GetUserResponse,\n GetVerifStatusResponse,\n ResendVerifResponse,\n SaveLinksResponse,\n} from '../generated/types.gen.js'\nimport { BaseResource } from '../base-resource.js'\n\n/**\n * User resource for managing user account information\n */\nexport class UserResource extends BaseResource {\n /**\n * Get user profile information including premium status and quotas\n *\n * @example\n * ```ts\n * const data = await client.user.getInfo()\n * console.log(data.user.username, data.user.isPremium)\n * ```\n */\n async getInfo() {\n return this.get<GetUserResponse>('/user')\n }\n\n /**\n * Get available hosts for the current user based on their subscription\n *\n * @param hostOnly - If true, only return hosts data (exclude streams and redirectors)\n *\n * @example\n * ```ts\n * const hosts = await client.user.getHosts()\n * console.log(Object.keys(hosts.hosts))\n * ```\n */\n async getHosts(hostOnly?: boolean) {\n const params = hostOnly ? { hostOnly: '1' } : undefined\n return this.get<GetUserHostsResponse>('/user/hosts', params)\n }\n\n /**\n * Clear a specific notification by code\n *\n * @param code - The notification code to clear\n *\n * @example\n * ```ts\n * await client.user.clearNotification('SOME_NOTIF_CODE')\n * ```\n */\n async clearNotification(code: string) {\n await this.post<ClearNotificationResponse>('/user/notification/clear', { code })\n }\n\n // ============================================\n // Saved Links Management\n // ============================================\n\n /**\n * Get all saved links\n *\n * @example\n * ```ts\n * const savedLinks = await client.user.getLinks()\n * console.log(savedLinks.links)\n * ```\n */\n async getLinks() {\n return this.get<GetSavedLinksResponse>('/user/links')\n }\n\n /**\n * Save one or multiple links for later use\n *\n * Supports batch operations - you can save multiple links in a single request.\n *\n * @param links - Single link or array of links to save\n *\n * @example\n * ```ts\n * // Save single link\n * await client.user.saveLink('https://example.com/file.zip')\n *\n * // Save multiple links at once\n * await client.user.saveLink([\n * 'https://example.com/file1.zip',\n * 'https://example.com/file2.zip',\n * 'https://example.com/file3.zip'\n * ])\n * ```\n */\n async saveLink(links: string | string[]) {\n const linksArray = Array.isArray(links) ? links : [links]\n const formData = new FormData()\n\n // API expects links[] array format\n for (const link of linksArray) {\n formData.append('links[]', link)\n }\n\n return this.postFormData<SaveLinksResponse>('/user/links/save', formData)\n }\n\n /**\n * Delete one or multiple saved links\n *\n * Supports batch operations - you can delete multiple links in a single request.\n *\n * @param links - Single link or array of links to delete (can be saved link IDs or URLs)\n *\n * @example\n * ```ts\n * // Delete single link\n * await client.user.deleteLink('saved-link-id')\n *\n * // Delete multiple links at once\n * await client.user.deleteLink([\n * 'saved-link-id-1',\n * 'saved-link-id-2',\n * 'saved-link-id-3'\n * ])\n * ```\n */\n async deleteLink(links: string | string[]) {\n const linksArray = Array.isArray(links) ? links : [links]\n const formData = new FormData()\n\n // API expects links[] array format\n for (const link of linksArray) {\n formData.append('links[]', link)\n }\n\n return this.postFormData<DeleteSavedLinksResponse>('/user/links/delete', formData)\n }\n\n // ============================================\n // History Management\n // ============================================\n\n /**\n * Get user history (if enabled in account settings)\n *\n * @example\n * ```ts\n * const history = await client.user.getHistory()\n * console.log(history.links)\n * ```\n */\n async getHistory() {\n return this.get<GetHistoryResponse>('/user/history')\n }\n\n /**\n * Clear user history\n *\n * @example\n * ```ts\n * await client.user.clearHistory()\n * ```\n */\n async clearHistory() {\n return this.post<DeleteHistoryResponse>('/user/history/delete')\n }\n\n // ============================================\n // Email Verification\n // ============================================\n\n /**\n * Check email verification status\n *\n * @param token - Verification token\n *\n * @example\n * ```ts\n * const status = await client.user.getVerificationStatus('verification-token')\n * console.log(status.verif) // 'waiting', 'allowed', or 'denied'\n * ```\n */\n async getVerificationStatus(token: string) {\n return this.post<GetVerifStatusResponse>('/user/verif', undefined, { token })\n }\n\n /**\n * Resend verification email\n *\n * @param token - Verification token\n *\n * @example\n * ```ts\n * await client.user.resendVerification('verification-token')\n * ```\n */\n async resendVerification(token: string) {\n return this.post<ResendVerifResponse>('/user/verif/resend', undefined, { token })\n }\n}\n","import type {\n GenerateVouchersResponse,\n GetAvailableVouchersResponse,\n GetVoucherBalanceResponse,\n} from '../generated/types.gen.js'\nimport { BaseResource } from '../base-resource.js'\n\n/**\n * Voucher resource for reseller voucher management\n *\n * Note: These endpoints are only available for reseller accounts.\n */\nexport class VoucherResource extends BaseResource {\n /**\n * Get voucher balance for reseller accounts\n *\n * This endpoint allows resellers to check their remaining voucher balance.\n * Only available for accounts with reseller privileges.\n *\n * @example\n * ```ts\n * const balance = await client.voucher.getBalance()\n * console.log('Remaining balance:', balance.balance, '€')\n * ```\n *\n * @returns Voucher balance information\n */\n async getBalance() {\n return this.get<GetVoucherBalanceResponse>('/voucher/balance')\n }\n\n /**\n * Retrieve existing vouchers from reseller inventory\n *\n * This endpoint retrieves vouchers that were previously generated\n * and are available in your inventory.\n *\n * @param quantity - Optional number of vouchers to retrieve\n *\n * @example\n * ```ts\n * // Get all available vouchers\n * const allVouchers = await client.voucher.getVouchers()\n * console.log('Vouchers:', allVouchers?.codes)\n *\n * // Get specific quantity\n * const fiveVouchers = await client.voucher.getVouchers(5)\n * ```\n *\n * @returns List of voucher codes\n */\n async getVouchers(quantity?: number) {\n const params = quantity ? { quantity } : undefined\n return this.get<GetAvailableVouchersResponse>('/voucher/get', params)\n }\n\n /**\n * Generate new vouchers (deducts from reseller balance)\n *\n * This endpoint creates new vouchers and deducts the cost from your\n * reseller account balance.\n *\n * @param quantity - Number of vouchers to generate\n * @param duration - Voucher duration in days\n *\n * @example\n * ```ts\n * // Generate 10 vouchers valid for 30 days\n * const vouchers = await client.voucher.generateVouchers(10, 30)\n * console.log('Generated vouchers:', vouchers?.codes)\n *\n * // Generate 5 vouchers valid for 7 days\n * const weekVouchers = await client.voucher.generateVouchers(5, 7)\n * ```\n *\n * @returns List of newly generated voucher codes\n */\n async generateVouchers(quantity: number, duration: number) {\n return this.post<GenerateVouchersResponse>('/voucher/generate', {\n quantity,\n duration,\n })\n }\n}\n","import type { PingResponse } from './generated/types.gen.js'\nimport type { AllDebridConfig, ApiResponse, ExtractData } from './types.js'\nimport wretch from 'wretch'\nimport { createTypedError, NetworkError } from './errors.js'\nimport { HostResource } from './resources/host.js'\nimport { LinkResource } from './resources/link.js'\nimport { MagnetResource } from './resources/magnet.js'\nimport { PinResource } from './resources/pin.js'\nimport { UserResource } from './resources/user.js'\nimport { VoucherResource } from './resources/voucher.js'\n\nconst DEFAULT_BASE_URL = 'https://api.alldebrid.com/v4.1'\nconst DEFAULT_AGENT = '@alldebrid/sdk'\nconst DEFAULT_TIMEOUT = 30000\nconst DEFAULT_MAX_RETRIES = 3\n\n/**\n * Main AllDebrid client class\n */\nexport class AllDebridClient {\n private readonly config: Required<AllDebridConfig>\n\n /**\n * User resource for managing user account\n */\n public readonly user: UserResource\n\n /**\n * Link resource for unlocking and managing download links\n */\n public readonly link: LinkResource\n\n /**\n * Magnet resource for managing torrents\n */\n public readonly magnet: MagnetResource\n\n /**\n * Host resource for getting information about supported hosts\n */\n public readonly host: HostResource\n\n /**\n * Pin resource for PIN-based authentication\n */\n public readonly pin: PinResource\n\n /**\n * Voucher resource for reseller voucher management\n */\n public readonly voucher: VoucherResource\n\n constructor(config: AllDebridConfig) {\n // Merge config with defaults\n this.config = {\n apiKey: config.apiKey,\n agent: config.agent ?? DEFAULT_AGENT,\n baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,\n timeout: config.timeout ?? DEFAULT_TIMEOUT,\n retry: config.retry ?? true,\n maxRetries: config.maxRetries ?? DEFAULT_MAX_RETRIES,\n }\n\n // Initialize resources\n this.user = new UserResource(this)\n this.link = new LinkResource(this)\n this.magnet = new MagnetResource(this)\n this.host = new HostResource(this)\n this.pin = new PinResource(this)\n this.voucher = new VoucherResource(this)\n }\n\n /**\n * Build query string from params\n */\n private buildUrl(path: string, params?: Record<string, unknown>): string {\n const allParams = {\n agent: this.config.agent,\n ...params,\n }\n\n const query = new URLSearchParams()\n for (const [key, value] of Object.entries(allParams)) {\n if (value !== undefined && value !== null) {\n if (Array.isArray(value)) {\n value.forEach((v) => query.append(`${key}[]`, String(v)))\n } else {\n query.append(key, String(value))\n }\n }\n }\n\n const queryString = query.toString()\n return queryString ? `${path}?${queryString}` : path\n }\n\n /**\n * Make a GET request\n * @template T - The generated response type (e.g., GetLinkUnlockResponse)\n * @param path - API endpoint path\n * @param params - Optional query parameters\n * @returns The extracted data from the response (without the { status, data } wrapper)\n * @internal\n */\n async get<T>(path: string, params?: Record<string, unknown>): Promise<ExtractData<T>> {\n try {\n const url = this.buildUrl(path, params)\n const json = await wretch(this.config.baseUrl)\n .auth(`Bearer ${this.config.apiKey}`)\n .url(url)\n .get()\n .json<ApiResponse<unknown>>()\n\n // Handle error responses\n if (json.status === 'error' && json.error) {\n throw createTypedError(json.error.code, json.error.message)\n }\n\n return json.data as ExtractData<T>\n } catch (error: any) {\n // Handle HTTP errors\n if (error.status === 401) {\n throw createTypedError('AUTH_BAD_APIKEY', 'Invalid API key or unauthorized access')\n }\n if (error.status === 403) {\n throw createTypedError('AUTH_BLOCKED', 'Access forbidden')\n }\n if (error.status === 429) {\n throw createTypedError('RATE_LIMITED', 'Too many requests')\n }\n\n // Re-throw if already our error type\n if (error.isAllDebridError) {\n throw error\n }\n\n // Wrap in NetworkError\n throw new NetworkError(error.message || 'Network error occurred', error.status)\n }\n }\n\n /**\n * Make a POST request with application/x-www-form-urlencoded\n * @template T - The generated response type\n * @param path - API endpoint path\n * @param body - Request body (will be converted to URLSearchParams)\n * @param params - Optional query parameters\n * @returns The extracted data from the response (without the { status, data } wrapper)\n * @internal\n */\n async post<T>(\n path: string,\n body?: unknown,\n params?: Record<string, unknown>,\n ): Promise<ExtractData<T>> {\n try {\n const url = this.buildUrl(path, params)\n\n // Convert body to URLSearchParams for application/x-www-form-urlencoded\n const formData = new URLSearchParams()\n if (body && typeof body === 'object') {\n for (const [key, value] of Object.entries(body)) {\n if (value !== undefined && value !== null) {\n if (Array.isArray(value)) {\n // Handle arrays (e.g., link[] for multiple links)\n value.forEach((v) => formData.append(key, String(v)))\n } else {\n formData.append(key, String(value))\n }\n }\n }\n }\n\n const json = await wretch(this.config.baseUrl)\n .auth(`Bearer ${this.config.apiKey}`)\n .url(url)\n .body(formData)\n .post()\n .json<ApiResponse<unknown>>()\n\n // Handle error responses\n if (json.status === 'error' && json.error) {\n throw createTypedError(json.error.code, json.error.message)\n }\n\n return json.data as ExtractData<T>\n } catch (error: any) {\n // Handle HTTP errors\n if (error.status === 401) {\n throw createTypedError('AUTH_BAD_APIKEY', 'Invalid API key or unauthorized access')\n }\n if (error.status === 403) {\n throw createTypedError('AUTH_BLOCKED', 'Access forbidden')\n }\n if (error.status === 429) {\n throw createTypedError('RATE_LIMITED', 'Too many requests')\n }\n\n // Re-throw if already our error type\n if (error.isAllDebridError) {\n throw error\n }\n\n // Wrap in NetworkError\n throw new NetworkError(error.message || 'Network error occurred', error.status)\n }\n }\n\n /**\n * Make a POST request with FormData (multipart/form-data)\n * @template T - The generated response type\n * @param path - API endpoint path\n * @param formData - Form data to send\n * @param params - Optional query parameters\n * @returns The extracted data from the response (without the { status, data } wrapper)\n * @internal\n */\n async postFormData<T>(\n path: string,\n formData: FormData,\n params?: Record<string, unknown>,\n ): Promise<ExtractData<T>> {\n try {\n const url = this.buildUrl(path, params)\n const json = await wretch(this.config.baseUrl)\n .auth(`Bearer ${this.config.apiKey}`)\n .url(url)\n .body(formData)\n .post()\n .json<ApiResponse<unknown>>()\n\n // Handle error responses\n if (json.status === 'error' && json.error) {\n throw createTypedError(json.error.code, json.error.message)\n }\n\n return json.data as ExtractData<T>\n } catch (error: any) {\n // Handle HTTP errors\n if (error.status === 401) {\n throw createTypedError('AUTH_BAD_APIKEY', 'Invalid API key or unauthorized access')\n }\n if (error.status === 403) {\n throw createTypedError('AUTH_BLOCKED', 'Access forbidden')\n }\n if (error.status === 429) {\n throw createTypedError('RATE_LIMITED', 'Too many requests')\n }\n\n // Re-throw if already our error type\n if (error.isAllDebridError) {\n throw error\n }\n\n // Wrap in NetworkError\n throw new NetworkError(error.message || 'Network error occurred', error.status)\n }\n }\n\n /**\n * Test the API connection\n *\n * This endpoint doesn't require authentication and can be used to verify\n * that the AllDebrid API is reachable.\n *\n * @example\n * ```ts\n * const result = await client.ping()\n * console.log(result.ping) // 'pong'\n * ```\n *\n * @returns Ping response with 'pong' message\n */\n async ping() {\n return this.get<PingResponse>('/ping')\n }\n}\n"]}