@rawcast/sdk 0.1.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 ADDED
@@ -0,0 +1,654 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropNames = Object.getOwnPropertyNames;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ function __accessProp(key) {
6
+ return this[key];
7
+ }
8
+ var __toCommonJS = (from) => {
9
+ var entry = (__moduleCache ??= new WeakMap).get(from), desc;
10
+ if (entry)
11
+ return entry;
12
+ entry = __defProp({}, "__esModule", { value: true });
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (var key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(entry, key))
16
+ __defProp(entry, key, {
17
+ get: __accessProp.bind(from, key),
18
+ enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
19
+ });
20
+ }
21
+ __moduleCache.set(from, entry);
22
+ return entry;
23
+ };
24
+ var __moduleCache;
25
+ var __returnValue = (v) => v;
26
+ function __exportSetter(name, newValue) {
27
+ this[name] = __returnValue.bind(null, newValue);
28
+ }
29
+ var __export = (target, all) => {
30
+ for (var name in all)
31
+ __defProp(target, name, {
32
+ get: all[name],
33
+ enumerable: true,
34
+ configurable: true,
35
+ set: __exportSetter.bind(all, name)
36
+ });
37
+ };
38
+
39
+ // src/index.ts
40
+ var exports_src = {};
41
+ __export(exports_src, {
42
+ HealthResource: () => HealthResource,
43
+ HttpTransport: () => HttpTransport,
44
+ MetadataResource: () => MetadataResource,
45
+ MoviesResource: () => MoviesResource,
46
+ Rawcast: () => Rawcast,
47
+ RawcastAuthenticationError: () => RawcastAuthenticationError,
48
+ RawcastError: () => RawcastError,
49
+ RawcastForbiddenError: () => RawcastForbiddenError,
50
+ RawcastNotFoundError: () => RawcastNotFoundError,
51
+ RawcastRateLimitError: () => RawcastRateLimitError,
52
+ RawcastTimeoutError: () => RawcastTimeoutError,
53
+ RawcastUpstreamError: () => RawcastUpstreamError,
54
+ ResolveResource: () => ResolveResource,
55
+ SourcesResponse: () => SourcesResponse,
56
+ SubtitlesResource: () => SubtitlesResource,
57
+ TvResource: () => TvResource,
58
+ default: () => src_default
59
+ });
60
+ module.exports = __toCommonJS(exports_src);
61
+
62
+ // src/resources/health.ts
63
+ class HealthResource {
64
+ transport;
65
+ constructor(transport) {
66
+ this.transport = transport;
67
+ }
68
+ async check() {
69
+ return this.transport.request("health");
70
+ }
71
+ async providers() {
72
+ return this.transport.request("health/providers");
73
+ }
74
+ }
75
+
76
+ // src/resources/metadata.ts
77
+ class MetadataResource {
78
+ transport;
79
+ constructor(transport) {
80
+ this.transport = transport;
81
+ }
82
+ async getMovie(tmdbId, options = {}) {
83
+ const id = String(tmdbId).trim();
84
+ const query = new URLSearchParams;
85
+ if (options.lang)
86
+ query.set("lang", options.lang);
87
+ const qs = query.toString() ? `?${query.toString()}` : "";
88
+ return this.transport.request(`meta/movie/${id}${qs}`);
89
+ }
90
+ async getTv(tmdbId, options = {}) {
91
+ const id = String(tmdbId).trim();
92
+ const query = new URLSearchParams;
93
+ if (options.season !== undefined)
94
+ query.set("season", String(options.season));
95
+ if (options.lang)
96
+ query.set("lang", options.lang);
97
+ const qs = query.toString() ? `?${query.toString()}` : "";
98
+ return this.transport.request(`meta/tv/${id}${qs}`);
99
+ }
100
+ }
101
+
102
+ // src/response.ts
103
+ var QUALITY_WEIGHTS = {
104
+ "4k": 6,
105
+ "2160p": 6,
106
+ "1080p": 5,
107
+ "720p": 4,
108
+ "480p": 3,
109
+ "360p": 2,
110
+ auto: 1,
111
+ "Auto (Adaptive)": 1
112
+ };
113
+
114
+ class SourcesResponse {
115
+ servers;
116
+ subtitles;
117
+ constructor(data) {
118
+ this.servers = Array.isArray(data.servers) ? data.servers : [];
119
+ this.subtitles = Array.isArray(data.subtitles) ? data.subtitles : [];
120
+ }
121
+ get allStreams() {
122
+ return this.servers.flatMap((server) => server.streams);
123
+ }
124
+ get hlsStreams() {
125
+ return this.servers.filter((s) => s.format === "hls").flatMap((s) => s.streams);
126
+ }
127
+ get dashStreams() {
128
+ return this.servers.filter((s) => s.format === "dash").flatMap((s) => s.streams);
129
+ }
130
+ get mp4Streams() {
131
+ return this.servers.filter((s) => s.format === "mp4").flatMap((s) => s.streams);
132
+ }
133
+ bestStream(options = {}) {
134
+ const {
135
+ preferFormat = "hls",
136
+ maxQuality,
137
+ preferredAudio = "English",
138
+ requireDownload = false
139
+ } = options;
140
+ let candidateStreams = [];
141
+ for (const server of this.servers) {
142
+ for (const stream of server.streams) {
143
+ if (requireDownload && !stream.download && !stream.downloadUrl) {
144
+ continue;
145
+ }
146
+ candidateStreams.push({
147
+ stream,
148
+ format: server.format
149
+ });
150
+ }
151
+ }
152
+ if (candidateStreams.length === 0) {
153
+ return null;
154
+ }
155
+ if (maxQuality) {
156
+ const maxWeight = QUALITY_WEIGHTS[maxQuality.toLowerCase()] ?? 99;
157
+ candidateStreams = candidateStreams.filter((item) => {
158
+ const itemWeight = QUALITY_WEIGHTS[item.stream.quality.toLowerCase()] ?? 1;
159
+ return itemWeight <= maxWeight;
160
+ });
161
+ }
162
+ if (candidateStreams.length === 0) {
163
+ return this.allStreams[0] ?? null;
164
+ }
165
+ candidateStreams.sort((a, b) => {
166
+ const formatScoreA = a.format === preferFormat ? 10 : 0;
167
+ const formatScoreB = b.format === preferFormat ? 10 : 0;
168
+ if (formatScoreA !== formatScoreB) {
169
+ return formatScoreB - formatScoreA;
170
+ }
171
+ const audioMatchA = (a.stream.audio || "").toLowerCase().includes(preferredAudio.toLowerCase()) ? 5 : 0;
172
+ const audioMatchB = (b.stream.audio || "").toLowerCase().includes(preferredAudio.toLowerCase()) ? 5 : 0;
173
+ if (audioMatchA !== audioMatchB) {
174
+ return audioMatchB - audioMatchA;
175
+ }
176
+ const qA = QUALITY_WEIGHTS[a.stream.quality.toLowerCase()] ?? 1;
177
+ const qB = QUALITY_WEIGHTS[b.stream.quality.toLowerCase()] ?? 1;
178
+ return qB - qA;
179
+ });
180
+ return candidateStreams[0].stream;
181
+ }
182
+ subtitlesByLang(languageOrCode) {
183
+ const q = languageOrCode.trim().toLowerCase();
184
+ return this.subtitles.filter((sub) => {
185
+ const lang = (sub.language || "").toLowerCase();
186
+ const label = (sub.label || "").toLowerCase();
187
+ const id = (sub.id || "").toLowerCase();
188
+ return lang === q || label.includes(q) || id.includes(q);
189
+ });
190
+ }
191
+ }
192
+
193
+ // src/resources/movies.ts
194
+ class MoviesResource {
195
+ transport;
196
+ constructor(transport) {
197
+ this.transport = transport;
198
+ }
199
+ async getSources(tmdbId, options = {}) {
200
+ const id = String(tmdbId).trim();
201
+ const query = new URLSearchParams;
202
+ if (options.lang)
203
+ query.set("lang", options.lang);
204
+ if (options.title)
205
+ query.set("title", options.title);
206
+ const qs = query.toString() ? `?${query.toString()}` : "";
207
+ const raw = await this.transport.request(`sources/movie/${id}${qs}`);
208
+ return new SourcesResponse(raw);
209
+ }
210
+ async getDownload(tmdbId, options = {}) {
211
+ const id = String(tmdbId).trim();
212
+ const query = new URLSearchParams;
213
+ if (options.quality)
214
+ query.set("quality", options.quality);
215
+ if (options.lang)
216
+ query.set("lang", options.lang);
217
+ if (options.title)
218
+ query.set("title", options.title);
219
+ query.set("redirect", "false");
220
+ return this.transport.request(`download/movie/${id}?${query.toString()}`);
221
+ }
222
+ }
223
+
224
+ // src/errors.ts
225
+ class RawcastError extends Error {
226
+ code;
227
+ statusCode;
228
+ responseBody;
229
+ constructor(message, code = "RC_UNKNOWN_ERROR", statusCode, responseBody) {
230
+ super(message);
231
+ this.name = "RawcastError";
232
+ this.code = code;
233
+ this.statusCode = statusCode;
234
+ this.responseBody = responseBody;
235
+ Object.setPrototypeOf(this, new.target.prototype);
236
+ }
237
+ }
238
+
239
+ class RawcastAuthenticationError extends RawcastError {
240
+ constructor(message = "API key is missing or invalid.", responseBody) {
241
+ super(message, "RC_UNAUTHORIZED", 401, responseBody);
242
+ this.name = "RawcastAuthenticationError";
243
+ }
244
+ }
245
+
246
+ class RawcastForbiddenError extends RawcastError {
247
+ constructor(message = "Account lacks permission or email is not verified.", code = "RC_FORBIDDEN", responseBody) {
248
+ super(message, code, 403, responseBody);
249
+ this.name = "RawcastForbiddenError";
250
+ }
251
+ }
252
+
253
+ class RawcastNotFoundError extends RawcastError {
254
+ constructor(message = "Resource or media streams not found.", code = "RC_NOT_FOUND", responseBody) {
255
+ super(message, code, 404, responseBody);
256
+ this.name = "RawcastNotFoundError";
257
+ }
258
+ }
259
+
260
+ class RawcastRateLimitError extends RawcastError {
261
+ retryAfterSeconds;
262
+ limit;
263
+ remaining;
264
+ reset;
265
+ constructor(message = "Rate limit or monthly quota exceeded.", options) {
266
+ super(message, "RC_RATE_LIMIT", 429, options?.responseBody);
267
+ this.name = "RawcastRateLimitError";
268
+ this.retryAfterSeconds = options?.retryAfterSeconds;
269
+ this.limit = options?.limit;
270
+ this.remaining = options?.remaining;
271
+ this.reset = options?.reset;
272
+ }
273
+ }
274
+
275
+ class RawcastUpstreamError extends RawcastError {
276
+ constructor(message = "Upstream scraper or provider error.", statusCode = 502, responseBody) {
277
+ super(message, "RC_UPSTREAM_ERROR", statusCode, responseBody);
278
+ this.name = "RawcastUpstreamError";
279
+ }
280
+ }
281
+
282
+ class RawcastTimeoutError extends RawcastError {
283
+ constructor(timeoutMs) {
284
+ super(`Request timed out after ${timeoutMs}ms.`, "RC_TIMEOUT");
285
+ this.name = "RawcastTimeoutError";
286
+ }
287
+ }
288
+
289
+ // src/resources/resolve.ts
290
+ class ResolveResource {
291
+ transport;
292
+ constructor(transport) {
293
+ this.transport = transport;
294
+ }
295
+ getStreamUrl(token, options = {}) {
296
+ const base = this.transport.getBaseUrl().replace(/\/+$/, "");
297
+ const query = new URLSearchParams;
298
+ if (options.download)
299
+ query.set("download", "1");
300
+ if (options.title)
301
+ query.set("title", options.title);
302
+ const qs = query.toString() ? `?${query.toString()}` : "";
303
+ return `${base}/resolve/${encodeURIComponent(token)}${qs}`;
304
+ }
305
+ getDownloadUrl(token, options = {}) {
306
+ const base = this.transport.getBaseUrl().replace(/\/+$/, "");
307
+ const query = new URLSearchParams;
308
+ if (options.title)
309
+ query.set("title", options.title);
310
+ const qs = query.toString() ? `?${query.toString()}` : "";
311
+ return `${base}/download/${encodeURIComponent(token)}${qs}`;
312
+ }
313
+ getHlsManifestUrl(token) {
314
+ const base = this.transport.getBaseUrl().replace(/\/+$/, "");
315
+ return `${base}/stream/hls/${encodeURIComponent(token)}/manifest.m3u8`;
316
+ }
317
+ async resolveDirect(token, options = {}) {
318
+ const url = this.getStreamUrl(token, options);
319
+ const fetchFn = this.transport.getFetch();
320
+ const response = await fetchFn(url, {
321
+ method: "GET",
322
+ redirect: "manual",
323
+ headers: {
324
+ "X-API-Key": this.transport.getApiKey()
325
+ }
326
+ });
327
+ if (response.status >= 300 && response.status < 400) {
328
+ const location = response.headers.get("location");
329
+ if (location)
330
+ return location;
331
+ }
332
+ if (response.status === 404) {
333
+ throw new RawcastNotFoundError("Stream token is invalid or has expired", "RC_NOT_FOUND");
334
+ }
335
+ if (response.url && response.url !== url) {
336
+ return response.url;
337
+ }
338
+ throw new Error(`Failed to resolve upstream redirect for token (HTTP status: ${response.status})`);
339
+ }
340
+ }
341
+
342
+ // src/resources/subtitles.ts
343
+ class SubtitlesResource {
344
+ transport;
345
+ constructor(transport) {
346
+ this.transport = transport;
347
+ }
348
+ async getMovie(tmdbId, options = {}) {
349
+ const id = String(tmdbId).trim();
350
+ const query = new URLSearchParams;
351
+ if (options.lang)
352
+ query.set("lang", options.lang);
353
+ const qs = query.toString() ? `?${query.toString()}` : "";
354
+ return this.transport.request(`subtitles/movie/${id}${qs}`);
355
+ }
356
+ async getTv(tmdbIdOrOptions, season, episode, options = {}) {
357
+ let id;
358
+ let s;
359
+ let ep;
360
+ let lang;
361
+ if (typeof tmdbIdOrOptions === "object") {
362
+ id = String(tmdbIdOrOptions.tmdbId).trim();
363
+ s = tmdbIdOrOptions.season;
364
+ ep = tmdbIdOrOptions.episode;
365
+ lang = tmdbIdOrOptions.lang;
366
+ } else {
367
+ id = String(tmdbIdOrOptions).trim();
368
+ if (season === undefined || episode === undefined) {
369
+ throw new Error("Missing season or episode. Usage: rawcast.subtitles.getTv(tmdbId, season, episode, options?)");
370
+ }
371
+ s = season;
372
+ ep = episode;
373
+ lang = options.lang;
374
+ }
375
+ const query = new URLSearchParams;
376
+ if (lang)
377
+ query.set("lang", lang);
378
+ const qs = query.toString() ? `?${query.toString()}` : "";
379
+ return this.transport.request(`subtitles/tv/${id}/${s}/${ep}${qs}`);
380
+ }
381
+ getVttUrl(rawSubtitleUrl) {
382
+ const base = this.transport.getBaseUrl().replace(/\/+$/, "");
383
+ return `${base}/subtitles/vtt?url=${encodeURIComponent(rawSubtitleUrl)}`;
384
+ }
385
+ async fetchVtt(rawSubtitleUrl) {
386
+ const query = new URLSearchParams({ url: rawSubtitleUrl });
387
+ const response = await this.transport.rawFetch(`subtitles/vtt?${query.toString()}`);
388
+ return response.text();
389
+ }
390
+ }
391
+
392
+ // src/resources/tv.ts
393
+ class TvResource {
394
+ transport;
395
+ constructor(transport) {
396
+ this.transport = transport;
397
+ }
398
+ async getSources(tmdbIdOrOptions, season, episode, options = {}) {
399
+ let id;
400
+ let s;
401
+ let ep;
402
+ let lang;
403
+ let title;
404
+ if (typeof tmdbIdOrOptions === "object") {
405
+ id = String(tmdbIdOrOptions.tmdbId).trim();
406
+ s = tmdbIdOrOptions.season;
407
+ ep = tmdbIdOrOptions.episode;
408
+ lang = tmdbIdOrOptions.lang ?? tmdbIdOrOptions.preferredLang;
409
+ title = tmdbIdOrOptions.title;
410
+ } else {
411
+ id = String(tmdbIdOrOptions).trim();
412
+ if (season === undefined || episode === undefined) {
413
+ throw new Error("Missing season or episode. Usage: rawcast.tv.getSources(tmdbId, season, episode, options?)");
414
+ }
415
+ s = season;
416
+ ep = episode;
417
+ lang = options.lang ?? options.preferredLang;
418
+ title = options.title;
419
+ }
420
+ const query = new URLSearchParams;
421
+ if (lang)
422
+ query.set("lang", lang);
423
+ if (title)
424
+ query.set("title", title);
425
+ const qs = query.toString() ? `?${query.toString()}` : "";
426
+ const raw = await this.transport.request(`sources/tv/${id}/${s}/${ep}${qs}`);
427
+ return new SourcesResponse(raw);
428
+ }
429
+ async getDownload(tmdbIdOrOptions, season, episode, options = {}) {
430
+ let id;
431
+ let s;
432
+ let ep;
433
+ let quality;
434
+ let lang;
435
+ let title;
436
+ if (typeof tmdbIdOrOptions === "object") {
437
+ id = String(tmdbIdOrOptions.tmdbId ?? "").trim();
438
+ s = tmdbIdOrOptions.season;
439
+ ep = tmdbIdOrOptions.episode;
440
+ quality = tmdbIdOrOptions.quality;
441
+ lang = tmdbIdOrOptions.lang;
442
+ title = tmdbIdOrOptions.title;
443
+ } else {
444
+ id = String(tmdbIdOrOptions).trim();
445
+ if (season === undefined || episode === undefined) {
446
+ throw new Error("Missing season or episode. Usage: rawcast.tv.getDownload(tmdbId, season, episode, options?)");
447
+ }
448
+ s = season;
449
+ ep = episode;
450
+ quality = options.quality;
451
+ lang = options.lang;
452
+ title = options.title;
453
+ }
454
+ const query = new URLSearchParams;
455
+ if (quality)
456
+ query.set("quality", quality);
457
+ if (lang)
458
+ query.set("lang", lang);
459
+ if (title)
460
+ query.set("title", title);
461
+ query.set("redirect", "false");
462
+ return this.transport.request(`download/tv/${id}/${s}/${ep}?${query.toString()}`);
463
+ }
464
+ }
465
+
466
+ // src/transport.ts
467
+ class HttpTransport {
468
+ baseUrl;
469
+ apiKey;
470
+ timeoutMs;
471
+ maxRetries;
472
+ fetchFn;
473
+ quota = {
474
+ limit: null,
475
+ remaining: null,
476
+ reset: null,
477
+ lastUpdated: null
478
+ };
479
+ constructor(options) {
480
+ if (!options.apiKey || !options.apiKey.trim()) {
481
+ throw new RawcastAuthenticationError("Rawcast API key is required. Pass apiKey or set process.env.RAWCAST_API_KEY.");
482
+ }
483
+ this.apiKey = options.apiKey.trim();
484
+ this.baseUrl = (options.baseUrl || "https://zeroms.space/v1").replace(/\/+$/, "");
485
+ this.timeoutMs = options.timeoutMs ?? 25000;
486
+ this.maxRetries = Math.max(0, options.maxRetries ?? 2);
487
+ this.fetchFn = options.fetch ?? globalThis.fetch;
488
+ if (!this.fetchFn) {
489
+ throw new RawcastError("Global fetch is not available. Please provide a custom fetch implementation or upgrade Node/runtime.");
490
+ }
491
+ }
492
+ updateQuotaHeaders(headers) {
493
+ const limit = headers.get("x-ratelimit-limit");
494
+ const remaining = headers.get("x-ratelimit-remaining");
495
+ const reset = headers.get("x-ratelimit-reset");
496
+ if (limit !== null || remaining !== null || reset !== null) {
497
+ this.quota.limit = limit !== null ? Number.parseInt(limit, 10) : this.quota.limit;
498
+ this.quota.remaining = remaining !== null ? Number.parseInt(remaining, 10) : this.quota.remaining;
499
+ this.quota.reset = reset !== null ? Number.parseInt(reset, 10) : this.quota.reset;
500
+ this.quota.lastUpdated = Date.now();
501
+ }
502
+ }
503
+ async sleep(ms) {
504
+ return new Promise((resolve) => setTimeout(resolve, ms));
505
+ }
506
+ getBaseUrl() {
507
+ return this.baseUrl;
508
+ }
509
+ getApiKey() {
510
+ return this.apiKey;
511
+ }
512
+ getFetch() {
513
+ return this.fetchFn;
514
+ }
515
+ async rawFetch(endpoint, options = {}) {
516
+ const url = endpoint.startsWith("http") ? endpoint : `${this.baseUrl}/${endpoint.replace(/^\/+/, "")}`;
517
+ const headers = new Headers(options.headers || {});
518
+ if (!options.skipAuth) {
519
+ headers.set("X-API-Key", this.apiKey);
520
+ }
521
+ return this.fetchFn(url, {
522
+ ...options,
523
+ headers
524
+ });
525
+ }
526
+ async request(endpoint, options = {}) {
527
+ const url = endpoint.startsWith("http") ? endpoint : `${this.baseUrl}/${endpoint.replace(/^\/+/, "")}`;
528
+ const timeout = options.timeoutMs ?? this.timeoutMs;
529
+ let attempt = 0;
530
+ while (attempt <= this.maxRetries) {
531
+ attempt++;
532
+ const controller = new AbortController;
533
+ const timer = setTimeout(() => controller.abort(), timeout);
534
+ const headers = new Headers(options.headers || {});
535
+ if (!options.skipAuth) {
536
+ headers.set("X-API-Key", this.apiKey);
537
+ }
538
+ headers.set("Accept", "application/json, text/plain, */*");
539
+ try {
540
+ const response = await this.fetchFn(url, {
541
+ ...options,
542
+ headers,
543
+ signal: controller.signal
544
+ });
545
+ clearTimeout(timer);
546
+ this.updateQuotaHeaders(response.headers);
547
+ if (response.ok) {
548
+ if (response.status === 204) {
549
+ return;
550
+ }
551
+ const contentType = response.headers.get("content-type") || "";
552
+ if (contentType.includes("application/json")) {
553
+ return await response.json();
554
+ }
555
+ return await response.text();
556
+ }
557
+ let errorBody;
558
+ try {
559
+ errorBody = await response.json();
560
+ } catch {
561
+ try {
562
+ errorBody = await response.text();
563
+ } catch {}
564
+ }
565
+ const errorMessage = typeof errorBody === "object" && errorBody !== null && "error" in errorBody ? errorBody.error.message || response.statusText : typeof errorBody === "string" && errorBody ? errorBody : response.statusText;
566
+ if (response.status === 429) {
567
+ const retryAfterHeader = response.headers.get("retry-after");
568
+ const retryAfterSeconds = retryAfterHeader ? Number.parseFloat(retryAfterHeader) : 1;
569
+ if (attempt <= this.maxRetries) {
570
+ const sleepMs = Math.min(Math.max(retryAfterSeconds * 1000, 500), 1e4);
571
+ await this.sleep(sleepMs);
572
+ continue;
573
+ }
574
+ throw new RawcastRateLimitError(errorMessage, {
575
+ retryAfterSeconds,
576
+ limit: this.quota.limit ?? undefined,
577
+ remaining: this.quota.remaining ?? undefined,
578
+ reset: this.quota.reset ?? undefined,
579
+ responseBody: errorBody
580
+ });
581
+ }
582
+ if ([502, 503, 504].includes(response.status) && attempt <= this.maxRetries) {
583
+ const backoff = Math.min(400 * 2 ** (attempt - 1), 5000);
584
+ await this.sleep(backoff);
585
+ continue;
586
+ }
587
+ switch (response.status) {
588
+ case 401:
589
+ throw new RawcastAuthenticationError(errorMessage, errorBody);
590
+ case 403:
591
+ throw new RawcastForbiddenError(errorMessage, "RC_FORBIDDEN", errorBody);
592
+ case 404:
593
+ throw new RawcastNotFoundError(errorMessage, "RC_NOT_FOUND", errorBody);
594
+ case 502:
595
+ case 503:
596
+ case 504:
597
+ throw new RawcastUpstreamError(errorMessage, response.status, errorBody);
598
+ default:
599
+ throw new RawcastError(errorMessage, "RC_API_ERROR", response.status, errorBody);
600
+ }
601
+ } catch (err) {
602
+ clearTimeout(timer);
603
+ if (err instanceof RawcastError) {
604
+ throw err;
605
+ }
606
+ if (err instanceof Error && err.name === "AbortError") {
607
+ throw new RawcastTimeoutError(timeout);
608
+ }
609
+ if (attempt <= this.maxRetries) {
610
+ await this.sleep(500 * attempt);
611
+ continue;
612
+ }
613
+ throw new RawcastError(err instanceof Error ? err.message : "Network request failed", "RC_NETWORK_ERROR");
614
+ }
615
+ }
616
+ throw new RawcastError("Request failed after maximum retries exceeded.");
617
+ }
618
+ }
619
+
620
+ // src/client.ts
621
+ class Rawcast {
622
+ transport;
623
+ movies;
624
+ tv;
625
+ subtitles;
626
+ metadata;
627
+ meta;
628
+ resolve;
629
+ health;
630
+ constructor(optionsOrApiKey) {
631
+ let options;
632
+ if (typeof optionsOrApiKey === "string") {
633
+ options = { apiKey: optionsOrApiKey };
634
+ } else if (typeof optionsOrApiKey === "object" && optionsOrApiKey !== null) {
635
+ options = optionsOrApiKey;
636
+ } else {
637
+ const envKey = typeof process !== "undefined" && process.env ? process.env.RAWCAST_API_KEY : undefined;
638
+ options = { apiKey: envKey ?? "" };
639
+ }
640
+ this.transport = new HttpTransport(options);
641
+ this.movies = new MoviesResource(this.transport);
642
+ this.tv = new TvResource(this.transport);
643
+ this.subtitles = new SubtitlesResource(this.transport);
644
+ this.metadata = new MetadataResource(this.transport);
645
+ this.meta = this.metadata;
646
+ this.resolve = new ResolveResource(this.transport);
647
+ this.health = new HealthResource(this.transport);
648
+ }
649
+ get quota() {
650
+ return this.transport.quota;
651
+ }
652
+ }
653
+ // src/index.ts
654
+ var src_default = Rawcast;
@@ -0,0 +1,14 @@
1
+ import { Rawcast } from './client';
2
+ export { Rawcast };
3
+ export default Rawcast;
4
+ export { SourcesResponse } from './response';
5
+ export { HttpTransport } from './transport';
6
+ export { RawcastError, RawcastAuthenticationError, RawcastForbiddenError, RawcastNotFoundError, RawcastRateLimitError, RawcastUpstreamError, RawcastTimeoutError, } from './errors';
7
+ export { MoviesResource } from './resources/movies';
8
+ export { TvResource } from './resources/tv';
9
+ export { SubtitlesResource } from './resources/subtitles';
10
+ export { MetadataResource } from './resources/metadata';
11
+ export { ResolveResource } from './resources/resolve';
12
+ export { HealthResource } from './resources/health';
13
+ export type { RawcastOptions, QuotaState, GetMovieSourcesOptions, GetTvSourcesOptions, GetMovieDownloadOptions, GetTvDownloadOptions, DownloadResult, GetSubtitlesOptions, GetTvSubtitlesOptions, GetTvMetadataOptions, BestStreamOptions, HealthStatus, ProviderHealthDashboard, MovieMetadata, TvMetadata, TvEpisodeMetadata, TvSeasonInfo, ServerGroup, StreamItem, SubtitleTrack, MediaDownloadResult, DownloadOption, } from './types';
14
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAEnC,OAAO,EAAE,OAAO,EAAE,CAAC;AACnB,eAAe,OAAO,CAAC;AAEvB,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAE5C,OAAO,EACL,YAAY,EACZ,0BAA0B,EAC1B,qBAAqB,EACrB,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,EACpB,mBAAmB,GACpB,MAAM,UAAU,CAAC;AAElB,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AACxD,OAAO,EAAE,eAAe,EAAE,MAAM,qBAAqB,CAAC;AACtD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAEpD,YAAY,EACV,cAAc,EACd,UAAU,EACV,sBAAsB,EACtB,mBAAmB,EACnB,uBAAuB,EACvB,oBAAoB,EACpB,cAAc,EACd,mBAAmB,EACnB,qBAAqB,EACrB,oBAAoB,EACpB,iBAAiB,EACjB,YAAY,EACZ,uBAAuB,EAEvB,aAAa,EACb,UAAU,EACV,iBAAiB,EACjB,YAAY,EACZ,WAAW,EACX,UAAU,EACV,aAAa,EACb,mBAAmB,EACnB,cAAc,GACf,MAAM,SAAS,CAAC"}