scavio 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/LICENSE +21 -0
- package/README.md +204 -0
- package/dist/index.cjs +363 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +235 -0
- package/dist/index.d.ts +235 -0
- package/dist/index.js +329 -0
- package/dist/index.js.map +1 -0
- package/package.json +64 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,329 @@
|
|
|
1
|
+
// src/errors.ts
|
|
2
|
+
var ScavioError = class extends Error {
|
|
3
|
+
constructor(message) {
|
|
4
|
+
super(message);
|
|
5
|
+
this.name = "ScavioError";
|
|
6
|
+
}
|
|
7
|
+
};
|
|
8
|
+
var MissingAPIKeyError = class extends ScavioError {
|
|
9
|
+
constructor() {
|
|
10
|
+
super(
|
|
11
|
+
"No API key provided. Pass apiKey or set the SCAVIO_API_KEY environment variable. Get your free key at https://dashboard.scavio.dev"
|
|
12
|
+
);
|
|
13
|
+
this.name = "MissingAPIKeyError";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
var InvalidAPIKeyError = class extends ScavioError {
|
|
17
|
+
constructor(message = "Invalid API key") {
|
|
18
|
+
super(message);
|
|
19
|
+
this.name = "InvalidAPIKeyError";
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
var InsufficientCreditsError = class extends ScavioError {
|
|
23
|
+
constructor(message = "Insufficient credits") {
|
|
24
|
+
super(message);
|
|
25
|
+
this.name = "InsufficientCreditsError";
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
var BadRequestError = class extends ScavioError {
|
|
29
|
+
constructor(message = "Bad request") {
|
|
30
|
+
super(message);
|
|
31
|
+
this.name = "BadRequestError";
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
var RateLimitError = class extends ScavioError {
|
|
35
|
+
constructor(message = "Rate limit exceeded") {
|
|
36
|
+
super(message);
|
|
37
|
+
this.name = "RateLimitError";
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
var ScavioAPIError = class extends ScavioError {
|
|
41
|
+
statusCode;
|
|
42
|
+
constructor(statusCode, message) {
|
|
43
|
+
super(`API error ${statusCode}: ${message}`);
|
|
44
|
+
this.name = "ScavioAPIError";
|
|
45
|
+
this.statusCode = statusCode;
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
// src/http.ts
|
|
50
|
+
var BASE_URL = "https://api.scavio.dev";
|
|
51
|
+
var DEFAULT_TIMEOUT = 3e4;
|
|
52
|
+
function buildHeaders(apiKey) {
|
|
53
|
+
return {
|
|
54
|
+
Authorization: `Bearer ${apiKey}`,
|
|
55
|
+
"Content-Type": "application/json",
|
|
56
|
+
"X-Client-Source": "scavio-js"
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
function stripUndefined(obj) {
|
|
60
|
+
const result = {};
|
|
61
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
62
|
+
if (value !== void 0) {
|
|
63
|
+
result[key] = value;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return result;
|
|
67
|
+
}
|
|
68
|
+
function handleError(statusCode, body) {
|
|
69
|
+
let error = body.error ?? "Unknown error";
|
|
70
|
+
if (typeof error === "object" && error !== null && "message" in error) {
|
|
71
|
+
error = error.message;
|
|
72
|
+
}
|
|
73
|
+
const msg = String(error);
|
|
74
|
+
if (statusCode === 400) throw new BadRequestError(msg);
|
|
75
|
+
if (statusCode === 401) throw new InvalidAPIKeyError(msg);
|
|
76
|
+
if (statusCode === 402) throw new InsufficientCreditsError(msg);
|
|
77
|
+
if (statusCode === 429) throw new RateLimitError(msg);
|
|
78
|
+
throw new ScavioAPIError(statusCode, msg);
|
|
79
|
+
}
|
|
80
|
+
async function request(options) {
|
|
81
|
+
await options.rateLimiter.wait();
|
|
82
|
+
const url = `${options.baseUrl}${options.path}`;
|
|
83
|
+
const headers = buildHeaders(options.apiKey);
|
|
84
|
+
const controller = new AbortController();
|
|
85
|
+
const timeoutId = setTimeout(() => controller.abort(), options.timeout);
|
|
86
|
+
try {
|
|
87
|
+
const fetchOptions = {
|
|
88
|
+
method: options.method,
|
|
89
|
+
headers,
|
|
90
|
+
signal: controller.signal
|
|
91
|
+
};
|
|
92
|
+
if (options.method === "POST" && options.body) {
|
|
93
|
+
fetchOptions.body = JSON.stringify(stripUndefined(options.body));
|
|
94
|
+
}
|
|
95
|
+
const response = await fetch(url, fetchOptions);
|
|
96
|
+
if (!response.ok) {
|
|
97
|
+
let body = {};
|
|
98
|
+
try {
|
|
99
|
+
body = await response.json();
|
|
100
|
+
} catch {
|
|
101
|
+
}
|
|
102
|
+
handleError(response.status, body);
|
|
103
|
+
}
|
|
104
|
+
return await response.json();
|
|
105
|
+
} finally {
|
|
106
|
+
clearTimeout(timeoutId);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
// src/rate-limiter.ts
|
|
111
|
+
var RateLimiter = class {
|
|
112
|
+
maxPerSecond;
|
|
113
|
+
timestamps = [];
|
|
114
|
+
pending = Promise.resolve();
|
|
115
|
+
constructor(maxPerSecond) {
|
|
116
|
+
this.maxPerSecond = maxPerSecond;
|
|
117
|
+
}
|
|
118
|
+
async wait() {
|
|
119
|
+
const ticket = this.pending.then(() => this.acquire());
|
|
120
|
+
this.pending = ticket;
|
|
121
|
+
return ticket;
|
|
122
|
+
}
|
|
123
|
+
async acquire() {
|
|
124
|
+
this.cleanup();
|
|
125
|
+
if (this.timestamps.length >= this.maxPerSecond) {
|
|
126
|
+
const sleepMs = 1e3 - (Date.now() - this.timestamps[0]);
|
|
127
|
+
if (sleepMs > 0) {
|
|
128
|
+
await new Promise((resolve) => setTimeout(resolve, sleepMs));
|
|
129
|
+
}
|
|
130
|
+
this.cleanup();
|
|
131
|
+
}
|
|
132
|
+
this.timestamps.push(Date.now());
|
|
133
|
+
}
|
|
134
|
+
cleanup() {
|
|
135
|
+
const now = Date.now();
|
|
136
|
+
while (this.timestamps.length > 0 && now - this.timestamps[0] >= 1e3) {
|
|
137
|
+
this.timestamps.shift();
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
// src/namespaces/amazon.ts
|
|
143
|
+
var AmazonNamespace = class {
|
|
144
|
+
constructor(client) {
|
|
145
|
+
this.client = client;
|
|
146
|
+
}
|
|
147
|
+
client;
|
|
148
|
+
async search(options) {
|
|
149
|
+
return this.client._post("/api/v1/amazon/search", options);
|
|
150
|
+
}
|
|
151
|
+
async product(options) {
|
|
152
|
+
const { asin, ...rest } = options;
|
|
153
|
+
return this.client._post("/api/v1/amazon/product", {
|
|
154
|
+
query: asin,
|
|
155
|
+
...rest
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
|
|
160
|
+
// src/namespaces/google.ts
|
|
161
|
+
var GoogleNamespace = class {
|
|
162
|
+
constructor(client) {
|
|
163
|
+
this.client = client;
|
|
164
|
+
}
|
|
165
|
+
client;
|
|
166
|
+
async search(options) {
|
|
167
|
+
return this.client._post("/api/v1/google", options);
|
|
168
|
+
}
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
// src/namespaces/reddit.ts
|
|
172
|
+
var RedditNamespace = class {
|
|
173
|
+
constructor(client) {
|
|
174
|
+
this.client = client;
|
|
175
|
+
}
|
|
176
|
+
client;
|
|
177
|
+
async search(options) {
|
|
178
|
+
return this.client._post("/api/v1/reddit/search", options);
|
|
179
|
+
}
|
|
180
|
+
async post(options) {
|
|
181
|
+
return this.client._post("/api/v1/reddit/post", options);
|
|
182
|
+
}
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
// src/namespaces/tiktok.ts
|
|
186
|
+
var TikTokNamespace = class {
|
|
187
|
+
constructor(client) {
|
|
188
|
+
this.client = client;
|
|
189
|
+
}
|
|
190
|
+
client;
|
|
191
|
+
async profile(options) {
|
|
192
|
+
return this.client._post("/api/v1/tiktok/profile", options);
|
|
193
|
+
}
|
|
194
|
+
async userPosts(options) {
|
|
195
|
+
return this.client._post("/api/v1/tiktok/user/posts", options);
|
|
196
|
+
}
|
|
197
|
+
async video(options) {
|
|
198
|
+
return this.client._post("/api/v1/tiktok/video", options);
|
|
199
|
+
}
|
|
200
|
+
async videoComments(options) {
|
|
201
|
+
return this.client._post("/api/v1/tiktok/video/comments", options);
|
|
202
|
+
}
|
|
203
|
+
async commentReplies(options) {
|
|
204
|
+
return this.client._post("/api/v1/tiktok/video/comments/replies", options);
|
|
205
|
+
}
|
|
206
|
+
async searchVideos(options) {
|
|
207
|
+
return this.client._post("/api/v1/tiktok/search/videos", options);
|
|
208
|
+
}
|
|
209
|
+
async searchUsers(options) {
|
|
210
|
+
return this.client._post("/api/v1/tiktok/search/users", options);
|
|
211
|
+
}
|
|
212
|
+
async hashtag(options) {
|
|
213
|
+
return this.client._post("/api/v1/tiktok/hashtag", options);
|
|
214
|
+
}
|
|
215
|
+
async hashtagVideos(options) {
|
|
216
|
+
return this.client._post("/api/v1/tiktok/hashtag/videos", options);
|
|
217
|
+
}
|
|
218
|
+
async userFollowers(options) {
|
|
219
|
+
return this.client._post("/api/v1/tiktok/user/followers", options);
|
|
220
|
+
}
|
|
221
|
+
async userFollowings(options) {
|
|
222
|
+
return this.client._post("/api/v1/tiktok/user/followings", options);
|
|
223
|
+
}
|
|
224
|
+
};
|
|
225
|
+
|
|
226
|
+
// src/namespaces/walmart.ts
|
|
227
|
+
var WalmartNamespace = class {
|
|
228
|
+
constructor(client) {
|
|
229
|
+
this.client = client;
|
|
230
|
+
}
|
|
231
|
+
client;
|
|
232
|
+
async search(options) {
|
|
233
|
+
return this.client._post("/api/v1/walmart/search", options);
|
|
234
|
+
}
|
|
235
|
+
async product(options) {
|
|
236
|
+
return this.client._post("/api/v1/walmart/product", options);
|
|
237
|
+
}
|
|
238
|
+
};
|
|
239
|
+
|
|
240
|
+
// src/namespaces/youtube.ts
|
|
241
|
+
var YouTubeNamespace = class {
|
|
242
|
+
constructor(client) {
|
|
243
|
+
this.client = client;
|
|
244
|
+
}
|
|
245
|
+
client;
|
|
246
|
+
async search(options) {
|
|
247
|
+
const { query, ...rest } = options;
|
|
248
|
+
return this.client._post("/api/v1/youtube/search", {
|
|
249
|
+
search: query,
|
|
250
|
+
...rest
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
async metadata(options) {
|
|
254
|
+
return this.client._post("/api/v1/youtube/metadata", options);
|
|
255
|
+
}
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
// src/client.ts
|
|
259
|
+
var Scavio = class {
|
|
260
|
+
google;
|
|
261
|
+
amazon;
|
|
262
|
+
walmart;
|
|
263
|
+
youtube;
|
|
264
|
+
reddit;
|
|
265
|
+
tiktok;
|
|
266
|
+
apiKey;
|
|
267
|
+
baseUrl;
|
|
268
|
+
timeout;
|
|
269
|
+
rateLimiter;
|
|
270
|
+
constructor(config) {
|
|
271
|
+
this.apiKey = config?.apiKey ?? process.env.SCAVIO_API_KEY ?? "";
|
|
272
|
+
if (!this.apiKey) {
|
|
273
|
+
throw new MissingAPIKeyError();
|
|
274
|
+
}
|
|
275
|
+
this.baseUrl = (config?.baseUrl ?? BASE_URL).replace(/\/+$/, "");
|
|
276
|
+
this.timeout = config?.timeout ?? DEFAULT_TIMEOUT;
|
|
277
|
+
const rps = config?.maxRequestsPerSecond ?? 1;
|
|
278
|
+
if (rps < 1 || rps > 10) {
|
|
279
|
+
throw new ScavioError("maxRequestsPerSecond must be between 1 and 10");
|
|
280
|
+
}
|
|
281
|
+
this.rateLimiter = new RateLimiter(rps);
|
|
282
|
+
this.google = new GoogleNamespace(this);
|
|
283
|
+
this.amazon = new AmazonNamespace(this);
|
|
284
|
+
this.walmart = new WalmartNamespace(this);
|
|
285
|
+
this.youtube = new YouTubeNamespace(this);
|
|
286
|
+
this.reddit = new RedditNamespace(this);
|
|
287
|
+
this.tiktok = new TikTokNamespace(this);
|
|
288
|
+
}
|
|
289
|
+
/** @internal */
|
|
290
|
+
async _post(path, body) {
|
|
291
|
+
return request({
|
|
292
|
+
method: "POST",
|
|
293
|
+
path,
|
|
294
|
+
apiKey: this.apiKey,
|
|
295
|
+
baseUrl: this.baseUrl,
|
|
296
|
+
timeout: this.timeout,
|
|
297
|
+
rateLimiter: this.rateLimiter,
|
|
298
|
+
body
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
/** @internal */
|
|
302
|
+
async _get(path) {
|
|
303
|
+
return request({
|
|
304
|
+
method: "GET",
|
|
305
|
+
path,
|
|
306
|
+
apiKey: this.apiKey,
|
|
307
|
+
baseUrl: this.baseUrl,
|
|
308
|
+
timeout: this.timeout,
|
|
309
|
+
rateLimiter: this.rateLimiter
|
|
310
|
+
});
|
|
311
|
+
}
|
|
312
|
+
async search(options) {
|
|
313
|
+
return this.google.search(options);
|
|
314
|
+
}
|
|
315
|
+
async getUsage() {
|
|
316
|
+
return this._get("/api/v1/usage");
|
|
317
|
+
}
|
|
318
|
+
};
|
|
319
|
+
export {
|
|
320
|
+
BadRequestError,
|
|
321
|
+
InsufficientCreditsError,
|
|
322
|
+
InvalidAPIKeyError,
|
|
323
|
+
MissingAPIKeyError,
|
|
324
|
+
RateLimitError,
|
|
325
|
+
Scavio,
|
|
326
|
+
ScavioAPIError,
|
|
327
|
+
ScavioError
|
|
328
|
+
};
|
|
329
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/rate-limiter.ts","../src/namespaces/amazon.ts","../src/namespaces/google.ts","../src/namespaces/reddit.ts","../src/namespaces/tiktok.ts","../src/namespaces/walmart.ts","../src/namespaces/youtube.ts","../src/client.ts"],"sourcesContent":["export class ScavioError extends Error {\n constructor(message: string) {\n super(message);\n this.name = \"ScavioError\";\n }\n}\n\nexport class MissingAPIKeyError extends ScavioError {\n constructor() {\n super(\n \"No API key provided. Pass apiKey or set the SCAVIO_API_KEY \" +\n \"environment variable. Get your free key at https://dashboard.scavio.dev\",\n );\n this.name = \"MissingAPIKeyError\";\n }\n}\n\nexport class InvalidAPIKeyError extends ScavioError {\n constructor(message = \"Invalid API key\") {\n super(message);\n this.name = \"InvalidAPIKeyError\";\n }\n}\n\nexport class InsufficientCreditsError extends ScavioError {\n constructor(message = \"Insufficient credits\") {\n super(message);\n this.name = \"InsufficientCreditsError\";\n }\n}\n\nexport class BadRequestError extends ScavioError {\n constructor(message = \"Bad request\") {\n super(message);\n this.name = \"BadRequestError\";\n }\n}\n\nexport class RateLimitError extends ScavioError {\n constructor(message = \"Rate limit exceeded\") {\n super(message);\n this.name = \"RateLimitError\";\n }\n}\n\nexport class ScavioAPIError extends ScavioError {\n public readonly statusCode: number;\n\n constructor(statusCode: number, message: string) {\n super(`API error ${statusCode}: ${message}`);\n this.name = \"ScavioAPIError\";\n this.statusCode = statusCode;\n }\n}\n","import {\n BadRequestError,\n InsufficientCreditsError,\n InvalidAPIKeyError,\n RateLimitError,\n ScavioAPIError,\n} from \"./errors.js\";\nimport type { RateLimiter } from \"./rate-limiter.js\";\n\nexport const BASE_URL = \"https://api.scavio.dev\";\nexport const DEFAULT_TIMEOUT = 30_000;\n\nfunction buildHeaders(apiKey: string): Record<string, string> {\n return {\n Authorization: `Bearer ${apiKey}`,\n \"Content-Type\": \"application/json\",\n \"X-Client-Source\": \"scavio-js\",\n };\n}\n\nfunction stripUndefined(\n obj: Record<string, unknown>,\n): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj)) {\n if (value !== undefined) {\n result[key] = value;\n }\n }\n return result;\n}\n\nfunction handleError(statusCode: number, body: Record<string, unknown>): never {\n let error = body.error ?? \"Unknown error\";\n if (typeof error === \"object\" && error !== null && \"message\" in error) {\n error = (error as { message: string }).message;\n }\n const msg = String(error);\n\n if (statusCode === 400) throw new BadRequestError(msg);\n if (statusCode === 401) throw new InvalidAPIKeyError(msg);\n if (statusCode === 402) throw new InsufficientCreditsError(msg);\n if (statusCode === 429) throw new RateLimitError(msg);\n throw new ScavioAPIError(statusCode, msg);\n}\n\nexport async function request(options: {\n method: \"GET\" | \"POST\";\n path: string;\n apiKey: string;\n baseUrl: string;\n timeout: number;\n rateLimiter: RateLimiter;\n body?: Record<string, unknown>;\n}): Promise<Record<string, unknown>> {\n await options.rateLimiter.wait();\n\n const url = `${options.baseUrl}${options.path}`;\n const headers = buildHeaders(options.apiKey);\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), options.timeout);\n\n try {\n const fetchOptions: RequestInit = {\n method: options.method,\n headers,\n signal: controller.signal,\n };\n\n if (options.method === \"POST\" && options.body) {\n fetchOptions.body = JSON.stringify(stripUndefined(options.body));\n }\n\n const response = await fetch(url, fetchOptions);\n\n if (!response.ok) {\n let body: Record<string, unknown> = {};\n try {\n body = (await response.json()) as Record<string, unknown>;\n } catch {\n // ignore parse failures\n }\n handleError(response.status, body);\n }\n\n return (await response.json()) as Record<string, unknown>;\n } finally {\n clearTimeout(timeoutId);\n }\n}\n","export class RateLimiter {\n private readonly maxPerSecond: number;\n private readonly timestamps: number[] = [];\n private pending: Promise<void> = Promise.resolve();\n\n constructor(maxPerSecond: number) {\n this.maxPerSecond = maxPerSecond;\n }\n\n async wait(): Promise<void> {\n const ticket = this.pending.then(() => this.acquire());\n this.pending = ticket;\n return ticket;\n }\n\n private async acquire(): Promise<void> {\n this.cleanup();\n if (this.timestamps.length >= this.maxPerSecond) {\n const sleepMs = 1000 - (Date.now() - this.timestamps[0]!);\n if (sleepMs > 0) {\n await new Promise<void>((resolve) => setTimeout(resolve, sleepMs));\n }\n this.cleanup();\n }\n this.timestamps.push(Date.now());\n }\n\n private cleanup(): void {\n const now = Date.now();\n while (this.timestamps.length > 0 && now - this.timestamps[0]! >= 1000) {\n this.timestamps.shift();\n }\n }\n}\n","import type { Scavio } from \"../client.js\";\n\nexport interface AmazonSearchOptions {\n query: string;\n domain?: string;\n country?: string;\n language?: string;\n currency?: string;\n device?: string;\n sort_by?: string;\n start_page?: number;\n pages?: number;\n category_id?: string;\n merchant_id?: string;\n zip_code?: string;\n autoselect_variant?: boolean;\n}\n\nexport interface AmazonProductOptions {\n asin: string;\n domain?: string;\n country?: string;\n language?: string;\n currency?: string;\n device?: string;\n zip_code?: string;\n autoselect_variant?: boolean;\n}\n\nexport class AmazonNamespace {\n constructor(private client: Scavio) {}\n\n async search(\n options: AmazonSearchOptions,\n ): Promise<Record<string, unknown>> {\n return this.client._post(\"/api/v1/amazon/search\", options);\n }\n\n async product(\n options: AmazonProductOptions,\n ): Promise<Record<string, unknown>> {\n const { asin, ...rest } = options;\n return this.client._post(\"/api/v1/amazon/product\", {\n query: asin,\n ...rest,\n });\n }\n}\n","import type { Scavio } from \"../client.js\";\n\nexport interface GoogleSearchOptions {\n query: string;\n country_code?: string;\n language?: string;\n page?: number;\n search_type?: string;\n device?: string;\n nfpr?: boolean;\n light_request?: boolean;\n}\n\nexport class GoogleNamespace {\n constructor(private client: Scavio) {}\n\n async search(options: GoogleSearchOptions): Promise<Record<string, unknown>> {\n return this.client._post(\"/api/v1/google\", options);\n }\n}\n","import type { Scavio } from \"../client.js\";\n\nexport interface RedditSearchOptions {\n query: string;\n type?: string;\n sort?: string;\n cursor?: string;\n}\n\nexport interface RedditPostOptions {\n url: string;\n}\n\nexport class RedditNamespace {\n constructor(private client: Scavio) {}\n\n async search(\n options: RedditSearchOptions,\n ): Promise<Record<string, unknown>> {\n return this.client._post(\"/api/v1/reddit/search\", options);\n }\n\n async post(options: RedditPostOptions): Promise<Record<string, unknown>> {\n return this.client._post(\"/api/v1/reddit/post\", options);\n }\n}\n","import type { Scavio } from \"../client.js\";\n\nexport interface TikTokProfileOptions {\n username?: string;\n sec_user_id?: string;\n}\n\nexport interface TikTokUserPostsOptions {\n sec_user_id: string;\n cursor?: string;\n count?: number;\n sort_type?: string;\n}\n\nexport interface TikTokVideoOptions {\n video_id: string;\n}\n\nexport interface TikTokVideoCommentsOptions {\n video_id: string;\n cursor?: string;\n count?: number;\n}\n\nexport interface TikTokCommentRepliesOptions {\n video_id: string;\n comment_id: string;\n cursor?: string;\n count?: number;\n}\n\nexport interface TikTokSearchVideosOptions {\n keyword: string;\n cursor?: string;\n count?: number;\n sort_type?: string;\n publish_time?: string;\n}\n\nexport interface TikTokSearchUsersOptions {\n keyword: string;\n cursor?: string;\n count?: number;\n}\n\nexport interface TikTokHashtagOptions {\n hashtag_name?: string;\n hashtag_id?: string;\n}\n\nexport interface TikTokHashtagVideosOptions {\n hashtag_id: string;\n cursor?: string;\n count?: number;\n}\n\nexport interface TikTokUserFollowersOptions {\n sec_user_id: string;\n count?: number;\n page_token?: string;\n min_time?: number;\n}\n\nexport interface TikTokUserFollowingsOptions {\n sec_user_id: string;\n count?: number;\n page_token?: string;\n min_time?: number;\n}\n\nexport class TikTokNamespace {\n constructor(private client: Scavio) {}\n\n async profile(\n options: TikTokProfileOptions,\n ): Promise<Record<string, unknown>> {\n return this.client._post(\"/api/v1/tiktok/profile\", options);\n }\n\n async userPosts(\n options: TikTokUserPostsOptions,\n ): Promise<Record<string, unknown>> {\n return this.client._post(\"/api/v1/tiktok/user/posts\", options);\n }\n\n async video(\n options: TikTokVideoOptions,\n ): Promise<Record<string, unknown>> {\n return this.client._post(\"/api/v1/tiktok/video\", options);\n }\n\n async videoComments(\n options: TikTokVideoCommentsOptions,\n ): Promise<Record<string, unknown>> {\n return this.client._post(\"/api/v1/tiktok/video/comments\", options);\n }\n\n async commentReplies(\n options: TikTokCommentRepliesOptions,\n ): Promise<Record<string, unknown>> {\n return this.client._post(\"/api/v1/tiktok/video/comments/replies\", options);\n }\n\n async searchVideos(\n options: TikTokSearchVideosOptions,\n ): Promise<Record<string, unknown>> {\n return this.client._post(\"/api/v1/tiktok/search/videos\", options);\n }\n\n async searchUsers(\n options: TikTokSearchUsersOptions,\n ): Promise<Record<string, unknown>> {\n return this.client._post(\"/api/v1/tiktok/search/users\", options);\n }\n\n async hashtag(\n options: TikTokHashtagOptions,\n ): Promise<Record<string, unknown>> {\n return this.client._post(\"/api/v1/tiktok/hashtag\", options);\n }\n\n async hashtagVideos(\n options: TikTokHashtagVideosOptions,\n ): Promise<Record<string, unknown>> {\n return this.client._post(\"/api/v1/tiktok/hashtag/videos\", options);\n }\n\n async userFollowers(\n options: TikTokUserFollowersOptions,\n ): Promise<Record<string, unknown>> {\n return this.client._post(\"/api/v1/tiktok/user/followers\", options);\n }\n\n async userFollowings(\n options: TikTokUserFollowingsOptions,\n ): Promise<Record<string, unknown>> {\n return this.client._post(\"/api/v1/tiktok/user/followings\", options);\n }\n}\n","import type { Scavio } from \"../client.js\";\n\nexport interface WalmartSearchOptions {\n query: string;\n domain?: string;\n device?: string;\n sort_by?: string;\n start_page?: number;\n min_price?: number;\n max_price?: number;\n fulfillment_speed?: string;\n fulfillment_type?: string;\n delivery_zip?: string;\n store_id?: string;\n}\n\nexport interface WalmartProductOptions {\n product_id: string;\n domain?: string;\n device?: string;\n delivery_zip?: string;\n store_id?: string;\n}\n\nexport class WalmartNamespace {\n constructor(private client: Scavio) {}\n\n async search(\n options: WalmartSearchOptions,\n ): Promise<Record<string, unknown>> {\n return this.client._post(\"/api/v1/walmart/search\", options);\n }\n\n async product(\n options: WalmartProductOptions,\n ): Promise<Record<string, unknown>> {\n return this.client._post(\"/api/v1/walmart/product\", options);\n }\n}\n","import type { Scavio } from \"../client.js\";\n\nexport interface YouTubeSearchOptions {\n query: string;\n upload_date?: string;\n type?: string;\n duration?: string;\n sort_by?: string;\n hd?: boolean;\n subtitles?: boolean;\n creative_commons?: boolean;\n live?: boolean;\n}\n\nexport interface YouTubeMetadataOptions {\n video_id: string;\n}\n\nexport class YouTubeNamespace {\n constructor(private client: Scavio) {}\n\n async search(\n options: YouTubeSearchOptions,\n ): Promise<Record<string, unknown>> {\n const { query, ...rest } = options;\n return this.client._post(\"/api/v1/youtube/search\", {\n search: query,\n ...rest,\n });\n }\n\n async metadata(\n options: YouTubeMetadataOptions,\n ): Promise<Record<string, unknown>> {\n return this.client._post(\"/api/v1/youtube/metadata\", options);\n }\n}\n","import { MissingAPIKeyError, ScavioError } from \"./errors.js\";\nimport { BASE_URL, DEFAULT_TIMEOUT, request } from \"./http.js\";\nimport { RateLimiter } from \"./rate-limiter.js\";\nimport { AmazonNamespace } from \"./namespaces/amazon.js\";\nimport type { GoogleSearchOptions } from \"./namespaces/google.js\";\nimport { GoogleNamespace } from \"./namespaces/google.js\";\nimport { RedditNamespace } from \"./namespaces/reddit.js\";\nimport { TikTokNamespace } from \"./namespaces/tiktok.js\";\nimport { WalmartNamespace } from \"./namespaces/walmart.js\";\nimport { YouTubeNamespace } from \"./namespaces/youtube.js\";\n\nexport interface ScavioConfig {\n apiKey?: string;\n baseUrl?: string;\n timeout?: number;\n maxRequestsPerSecond?: number;\n}\n\nexport class Scavio {\n readonly google: GoogleNamespace;\n readonly amazon: AmazonNamespace;\n readonly walmart: WalmartNamespace;\n readonly youtube: YouTubeNamespace;\n readonly reddit: RedditNamespace;\n readonly tiktok: TikTokNamespace;\n\n private readonly apiKey: string;\n private readonly baseUrl: string;\n private readonly timeout: number;\n private readonly rateLimiter: RateLimiter;\n\n constructor(config?: ScavioConfig) {\n this.apiKey = config?.apiKey ?? process.env.SCAVIO_API_KEY ?? \"\";\n if (!this.apiKey) {\n throw new MissingAPIKeyError();\n }\n\n this.baseUrl = (config?.baseUrl ?? BASE_URL).replace(/\\/+$/, \"\");\n this.timeout = config?.timeout ?? DEFAULT_TIMEOUT;\n\n const rps = config?.maxRequestsPerSecond ?? 1;\n if (rps < 1 || rps > 10) {\n throw new ScavioError(\"maxRequestsPerSecond must be between 1 and 10\");\n }\n this.rateLimiter = new RateLimiter(rps);\n\n this.google = new GoogleNamespace(this);\n this.amazon = new AmazonNamespace(this);\n this.walmart = new WalmartNamespace(this);\n this.youtube = new YouTubeNamespace(this);\n this.reddit = new RedditNamespace(this);\n this.tiktok = new TikTokNamespace(this);\n }\n\n /** @internal */\n async _post(\n path: string,\n body: object,\n ): Promise<Record<string, unknown>> {\n return request({\n method: \"POST\",\n path,\n apiKey: this.apiKey,\n baseUrl: this.baseUrl,\n timeout: this.timeout,\n rateLimiter: this.rateLimiter,\n body: body as Record<string, unknown>,\n });\n }\n\n /** @internal */\n async _get(path: string): Promise<Record<string, unknown>> {\n return request({\n method: \"GET\",\n path,\n apiKey: this.apiKey,\n baseUrl: this.baseUrl,\n timeout: this.timeout,\n rateLimiter: this.rateLimiter,\n });\n }\n\n async search(\n options: GoogleSearchOptions,\n ): Promise<Record<string, unknown>> {\n return this.google.search(options);\n }\n\n async getUsage(): Promise<Record<string, unknown>> {\n return this._get(\"/api/v1/usage\");\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "scavio",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "TypeScript SDK for the Scavio Search API — real-time Google, Amazon, Walmart, YouTube, Reddit, and TikTok data",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.cjs",
|
|
7
|
+
"module": "./dist/index.js",
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"import": {
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"default": "./dist/index.js"
|
|
14
|
+
},
|
|
15
|
+
"require": {
|
|
16
|
+
"types": "./dist/index.d.cts",
|
|
17
|
+
"default": "./dist/index.cjs"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"README.md",
|
|
24
|
+
"LICENSE"
|
|
25
|
+
],
|
|
26
|
+
"scripts": {
|
|
27
|
+
"build": "tsup",
|
|
28
|
+
"dev": "tsup --watch",
|
|
29
|
+
"test": "vitest run",
|
|
30
|
+
"test:watch": "vitest",
|
|
31
|
+
"typecheck": "tsc --noEmit",
|
|
32
|
+
"prepublishOnly": "npm run build"
|
|
33
|
+
},
|
|
34
|
+
"engines": {
|
|
35
|
+
"node": ">=18.0.0"
|
|
36
|
+
},
|
|
37
|
+
"keywords": [
|
|
38
|
+
"search",
|
|
39
|
+
"api",
|
|
40
|
+
"ai",
|
|
41
|
+
"web-search",
|
|
42
|
+
"google-search",
|
|
43
|
+
"amazon",
|
|
44
|
+
"walmart",
|
|
45
|
+
"youtube",
|
|
46
|
+
"reddit",
|
|
47
|
+
"tiktok",
|
|
48
|
+
"serp",
|
|
49
|
+
"scraping"
|
|
50
|
+
],
|
|
51
|
+
"license": "MIT",
|
|
52
|
+
"author": "Scavio <support@scavio.dev>",
|
|
53
|
+
"homepage": "https://scavio.dev",
|
|
54
|
+
"repository": {
|
|
55
|
+
"type": "git",
|
|
56
|
+
"url": "https://github.com/scavio-ai/scavio-js"
|
|
57
|
+
},
|
|
58
|
+
"devDependencies": {
|
|
59
|
+
"@types/node": "^20.0.0",
|
|
60
|
+
"tsup": "^8.0.0",
|
|
61
|
+
"typescript": "^5.5.0",
|
|
62
|
+
"vitest": "^3.0.0"
|
|
63
|
+
}
|
|
64
|
+
}
|