debrid-ts 0.0.0-stage → 0.1.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Joshue Abance
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,182 @@
1
- # Temporary Holding Version
1
+ # debrid-ts
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Typed TypeScript clients for debrid services — **Real-Debrid**, **AllDebrid**
4
+ and **Premiumize** — with every documented endpoint as a method, plus one
5
+ provider-agnostic interface so your code can swap providers by changing a
6
+ constructor.
7
+
8
+ - Zero dependencies, ESM only, works anywhere `fetch` exists (Node ≥ 18.17,
9
+ Bun, Deno, browsers, edge runtimes)
10
+ - Full wire types for every endpoint (`Rd*`, `Ad*`, `Pm*`)
11
+ - Normalized `Torrent` / `UserInfo` / `DownloadLink` shapes across providers
12
+ - Consistent errors (`DebridError` with HTTP status and provider error code)
13
+ - Optional request timeout and HTTP 429 retries; injectable `fetch` for tests
14
+
15
+ ```sh
16
+ npm install debrid-ts
17
+ ```
18
+
19
+ ## Quick start
20
+
21
+ ```ts
22
+ import { RealDebrid } from 'debrid-ts'
23
+
24
+ const rd = new RealDebrid(process.env.RD_TOKEN!)
25
+
26
+ const user = await rd.getUser()
27
+ console.log(user.username, user.premium, user.expiresAt)
28
+
29
+ const torrent = await rd.addMagnet('magnet:?xt=urn:btih:...')
30
+ await rd.selectTorrentFiles(torrent.id, 'all') // Real-Debrid only starts after this
31
+ // ... poll rd.getTorrent(torrent.id) until status === 'downloaded' ...
32
+ const links = await rd.getDownloadLinks(torrent.id) // direct, unrestricted URLs
33
+ ```
34
+
35
+ ## One interface, any provider
36
+
37
+ Every client implements `DebridProvider`:
38
+
39
+ ```ts
40
+ import { AllDebrid, Premiumize, RealDebrid, type DebridProvider } from 'debrid-ts'
41
+
42
+ const provider: DebridProvider =
43
+ process.env.PROVIDER === 'ad' ? new AllDebrid(process.env.AD_KEY!)
44
+ : process.env.PROVIDER === 'pm' ? new Premiumize(process.env.PM_KEY!)
45
+ : new RealDebrid(process.env.RD_TOKEN!)
46
+
47
+ if (await provider.isCached(infoHash)) {
48
+ const torrent = await provider.addMagnet(`magnet:?xt=urn:btih:${infoHash}`)
49
+ const links = await provider.getDownloadLinks(torrent.id)
50
+ }
51
+ ```
52
+
53
+ ```ts
54
+ interface DebridProvider {
55
+ readonly name: string
56
+ getUser(): Promise<UserInfo>
57
+ isCached(hashOrMagnet: string): Promise<boolean>
58
+ addMagnet(magnet: string, options?: { host?: string }): Promise<Torrent>
59
+ listTorrents(offset?: number, limit?: number): Promise<Torrent[]>
60
+ getDownloadLinks(torrentId: string): Promise<DownloadLink[]>
61
+ }
62
+ ```
63
+
64
+ ### Provider differences worth knowing
65
+
66
+ | | Real-Debrid | AllDebrid | Premiumize |
67
+ | --- | --- | --- | --- |
68
+ | `isCached()` | **Probe:** adds the magnet, selects all files, checks for `downloaded`, deletes it. An uncached torrent may start for a few seconds. (RD disabled its cache endpoint.) | **Probe:** uploads the magnet, reads `ready`, deletes it. | Real lookup via `/cache/check`, no side effects. |
69
+ | After `addMagnet()` | Call `selectTorrentFiles()` to start. | Starts automatically. | Starts automatically. |
70
+ | `getDownloadLinks()` | Unrestricts each host link (one request per file). | Unlocks each `/f/` file link (one request per file, delayed links are awaited). | Reads the resulting file/folder; links are direct. |
71
+ | `listTorrents()` paging | Server-side. | Client-side slice (API returns all). | Client-side slice (API returns all). |
72
+ | `Torrent.hash` / `bytes` | ✅ | ✅ | Empty — the transfer list has neither. |
73
+
74
+ ## Providers
75
+
76
+ ### Real-Debrid
77
+
78
+ ```ts
79
+ const rd = new RealDebrid(token) // https://real-debrid.com/apitoken, or an OAuth access token
80
+ ```
81
+
82
+ Covers every endpoint in the [API docs](https://api.real-debrid.com/):
83
+ `/disable_access_token`, `/time`, `/user`, `/unrestrict`, `/traffic`,
84
+ `/streaming`, `/downloads`, `/torrents`, `/hosts`, `/settings`. Raw methods
85
+ return wire types (`RdUser`, `RdTorrentInfo`, …).
86
+
87
+ OAuth helpers are static. For scripts and opensource apps (no client secret),
88
+ use the device flow with Real-Debrid's public opensource client id:
89
+
90
+ ```ts
91
+ const device = await RealDebrid.getDeviceCode(undefined, { newCredentials: true })
92
+ console.log(`Open ${device.verification_url} and enter ${device.user_code}`)
93
+
94
+ const { credentials, token } = await RealDebrid.waitForDeviceToken({
95
+ deviceCode: device.device_code,
96
+ expiresIn: device.expires_in,
97
+ interval: device.interval,
98
+ })
99
+ const rd = new RealDebrid(token.access_token)
100
+
101
+ // later, when the access token expires:
102
+ const refreshed = await RealDebrid.refreshToken({
103
+ clientId: credentials.client_id,
104
+ clientSecret: credentials.client_secret,
105
+ refreshToken: token.refresh_token,
106
+ })
107
+ ```
108
+
109
+ Also available: `getAuthorizeUrl()` + `exchangeCode()` (website flow),
110
+ `getDeviceToken()` / `getDeviceCredentials()` (single polls) and
111
+ `getTokenWithPassword()`.
112
+
113
+ ### AllDebrid
114
+
115
+ ```ts
116
+ const ad = new AllDebrid(apiKey) // https://alldebrid.com/apikeys/
117
+ ```
118
+
119
+ Covers every non-deprecated endpoint in the [API docs](https://docs.alldebrid.com/):
120
+ hosts, user, links (unlock, streaming, delayed, redirector), magnets
121
+ (upload, `.torrent` upload, status incl. live mode, files, delete, restart),
122
+ saved/recent links and reseller vouchers. The `{ status, data }` envelope is
123
+ unwrapped for you; `{ status: "error" }` throws `DebridError`.
124
+
125
+ Get an apikey from a user with the PIN flow:
126
+
127
+ ```ts
128
+ const pin = await AllDebrid.getPin()
129
+ console.log(`Open ${pin.user_url}`)
130
+ const apiKey = await AllDebrid.waitForPin(pin)
131
+ ```
132
+
133
+ ### Premiumize
134
+
135
+ ```ts
136
+ const pm = new Premiumize(apiKey) // https://www.premiumize.me/account, or an OAuth access token
137
+ ```
138
+
139
+ Covers every endpoint in the [API docs](https://www.premiumize.me/api):
140
+ `/account`, `/folder` (incl. search and upload), `/item`, `/transfer`,
141
+ `/cache`, `/services`, `/zip`, plus OAuth 2.0 statics (PKCE / auth code via
142
+ `getAuthorizeUrl()` + `exchangeCode()`, device flow via `getDeviceCode()` +
143
+ `waitForDeviceToken()`, and the legacy password grant).
144
+
145
+ ## Options
146
+
147
+ Every client (and every static OAuth helper) accepts:
148
+
149
+ ```ts
150
+ new RealDebrid(token, {
151
+ timeout: 15_000, // per-request timeout in ms (default: none)
152
+ maxRetries: 2, // retry HTTP 429 responses, honoring Retry-After (default: 0)
153
+ fetch: myFetch, // custom fetch (proxies, tests, ...)
154
+ })
155
+ ```
156
+
157
+ ## Errors
158
+
159
+ Every failure — HTTP errors and errors reported inside a 200 envelope — is a
160
+ `DebridError`:
161
+
162
+ ```ts
163
+ import { DebridError } from 'debrid-ts'
164
+
165
+ try {
166
+ await ad.unlockLink(url)
167
+ } catch (error) {
168
+ if (error instanceof DebridError) {
169
+ error.status // HTTP status (200 for envelope errors)
170
+ error.code // provider code: 'bad_token', 'LINK_DOWN', 'not_found', ...
171
+ error.details // raw error payload from the provider
172
+ }
173
+ }
174
+ ```
175
+
176
+ ## Contributing
177
+
178
+ See [CONTRIBUTING.md](./CONTRIBUTING.md).
179
+
180
+ ## License
181
+
182
+ [MIT](./LICENSE)