stophy 0.3.0 → 1.0.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/README.md +84 -84
- package/dist/index.cjs +558 -334
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22667 -1403
- package/dist/index.d.ts +22667 -1403
- package/dist/index.js +558 -334
- package/dist/index.js.map +1 -1
- package/package.json +18 -10
package/dist/index.js
CHANGED
|
@@ -1,331 +1,596 @@
|
|
|
1
|
-
import { createClient, createConfig } from '@hey-api/client-fetch';
|
|
2
|
-
|
|
3
|
-
// src/generated/client.gen.ts
|
|
4
|
-
var client = createClient(
|
|
5
|
-
createConfig({
|
|
6
|
-
baseUrl: "https://api.stophy.dev"
|
|
7
|
-
})
|
|
8
|
-
);
|
|
9
|
-
|
|
10
|
-
// src/generated/sdk.gen.ts
|
|
11
|
-
var searchVideos = (options) => {
|
|
12
|
-
return (options.client ?? client).post({
|
|
13
|
-
security: [
|
|
14
|
-
{
|
|
15
|
-
scheme: "bearer",
|
|
16
|
-
type: "http"
|
|
17
|
-
}
|
|
18
|
-
],
|
|
19
|
-
url: "/v1/search",
|
|
20
|
-
...options,
|
|
21
|
-
headers: {
|
|
22
|
-
"Content-Type": "application/json",
|
|
23
|
-
...options?.headers
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
};
|
|
27
|
-
var getVideo = (options) => {
|
|
28
|
-
return (options.client ?? client).post({
|
|
29
|
-
security: [
|
|
30
|
-
{
|
|
31
|
-
scheme: "bearer",
|
|
32
|
-
type: "http"
|
|
33
|
-
}
|
|
34
|
-
],
|
|
35
|
-
url: "/v1/video",
|
|
36
|
-
...options,
|
|
37
|
-
headers: {
|
|
38
|
-
"Content-Type": "application/json",
|
|
39
|
-
...options?.headers
|
|
40
|
-
}
|
|
41
|
-
});
|
|
42
|
-
};
|
|
43
|
-
var getChannel = (options) => {
|
|
44
|
-
return (options.client ?? client).post({
|
|
45
|
-
security: [
|
|
46
|
-
{
|
|
47
|
-
scheme: "bearer",
|
|
48
|
-
type: "http"
|
|
49
|
-
}
|
|
50
|
-
],
|
|
51
|
-
url: "/v1/channel",
|
|
52
|
-
...options,
|
|
53
|
-
headers: {
|
|
54
|
-
"Content-Type": "application/json",
|
|
55
|
-
...options?.headers
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
};
|
|
59
|
-
var getPlaylist = (options) => {
|
|
60
|
-
return (options.client ?? client).post({
|
|
61
|
-
security: [
|
|
62
|
-
{
|
|
63
|
-
scheme: "bearer",
|
|
64
|
-
type: "http"
|
|
65
|
-
}
|
|
66
|
-
],
|
|
67
|
-
url: "/v1/playlist",
|
|
68
|
-
...options,
|
|
69
|
-
headers: {
|
|
70
|
-
"Content-Type": "application/json",
|
|
71
|
-
...options?.headers
|
|
72
|
-
}
|
|
73
|
-
});
|
|
74
|
-
};
|
|
75
|
-
var getSuggestions = (options) => {
|
|
76
|
-
return (options.client ?? client).post({
|
|
77
|
-
security: [
|
|
78
|
-
{
|
|
79
|
-
scheme: "bearer",
|
|
80
|
-
type: "http"
|
|
81
|
-
}
|
|
82
|
-
],
|
|
83
|
-
url: "/v1/suggest",
|
|
84
|
-
...options,
|
|
85
|
-
headers: {
|
|
86
|
-
"Content-Type": "application/json",
|
|
87
|
-
...options?.headers
|
|
88
|
-
}
|
|
89
|
-
});
|
|
90
|
-
};
|
|
91
|
-
var youtubeMusic = (options) => {
|
|
92
|
-
return (options.client ?? client).post({
|
|
93
|
-
security: [
|
|
94
|
-
{
|
|
95
|
-
scheme: "bearer",
|
|
96
|
-
type: "http"
|
|
97
|
-
}
|
|
98
|
-
],
|
|
99
|
-
url: "/v1/music",
|
|
100
|
-
...options,
|
|
101
|
-
headers: {
|
|
102
|
-
"Content-Type": "application/json",
|
|
103
|
-
...options?.headers
|
|
104
|
-
}
|
|
105
|
-
});
|
|
106
|
-
};
|
|
107
|
-
var youtubeKids = (options) => {
|
|
108
|
-
return (options.client ?? client).post({
|
|
109
|
-
security: [
|
|
110
|
-
{
|
|
111
|
-
scheme: "bearer",
|
|
112
|
-
type: "http"
|
|
113
|
-
}
|
|
114
|
-
],
|
|
115
|
-
url: "/v1/kids",
|
|
116
|
-
...options,
|
|
117
|
-
headers: {
|
|
118
|
-
"Content-Type": "application/json",
|
|
119
|
-
...options?.headers
|
|
120
|
-
}
|
|
121
|
-
});
|
|
122
|
-
};
|
|
123
|
-
var getCredits = (options) => {
|
|
124
|
-
return (options?.client ?? client).get({
|
|
125
|
-
security: [
|
|
126
|
-
{
|
|
127
|
-
scheme: "bearer",
|
|
128
|
-
type: "http"
|
|
129
|
-
}
|
|
130
|
-
],
|
|
131
|
-
url: "/v1/credits",
|
|
132
|
-
...options
|
|
133
|
-
});
|
|
134
|
-
};
|
|
135
|
-
var getUsage = (options) => {
|
|
136
|
-
return (options?.client ?? client).get({
|
|
137
|
-
security: [
|
|
138
|
-
{
|
|
139
|
-
scheme: "bearer",
|
|
140
|
-
type: "http"
|
|
141
|
-
}
|
|
142
|
-
],
|
|
143
|
-
url: "/v1/usage",
|
|
144
|
-
...options
|
|
145
|
-
});
|
|
146
|
-
};
|
|
147
|
-
var getLogs = (options) => {
|
|
148
|
-
return (options?.client ?? client).get({
|
|
149
|
-
security: [
|
|
150
|
-
{
|
|
151
|
-
scheme: "bearer",
|
|
152
|
-
type: "http"
|
|
153
|
-
}
|
|
154
|
-
],
|
|
155
|
-
url: "/v1/logs",
|
|
156
|
-
...options
|
|
157
|
-
});
|
|
158
|
-
};
|
|
159
|
-
|
|
160
1
|
// src/errors.ts
|
|
161
2
|
var StophyError = class extends Error {
|
|
162
3
|
code;
|
|
4
|
+
retryable;
|
|
5
|
+
retryAfterSeconds;
|
|
163
6
|
status;
|
|
164
7
|
requestId;
|
|
165
|
-
details;
|
|
166
8
|
constructor(message, options) {
|
|
167
9
|
super(message);
|
|
168
10
|
this.name = "StophyError";
|
|
169
11
|
this.status = options.status;
|
|
170
12
|
this.code = options.code;
|
|
13
|
+
this.retryable = options.retryable;
|
|
14
|
+
this.retryAfterSeconds = options.retryAfterSeconds;
|
|
171
15
|
this.requestId = options.requestId;
|
|
172
|
-
this.details = options.details;
|
|
173
16
|
}
|
|
174
17
|
};
|
|
175
18
|
|
|
176
|
-
// src/
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
options.maxRetries ?? 2,
|
|
189
|
-
options.retryInitialDelayMs ?? 500
|
|
190
|
-
)
|
|
191
|
-
})
|
|
19
|
+
// src/account.ts
|
|
20
|
+
function usage(call) {
|
|
21
|
+
return call({ method: "GET", path: "/v1/usage" }).then(parseUsage);
|
|
22
|
+
}
|
|
23
|
+
function logs(call, query) {
|
|
24
|
+
const params = {};
|
|
25
|
+
if (query?.apiKeyId !== void 0) params.apiKeyId = query.apiKeyId;
|
|
26
|
+
if (query?.days !== void 0) params.days = query.days;
|
|
27
|
+
if (query?.endpoint !== void 0) params.endpoint = query.endpoint;
|
|
28
|
+
if (query?.page !== void 0) params.page = query.page;
|
|
29
|
+
return call({ method: "GET", path: "/v1/logs", query: params }).then(
|
|
30
|
+
parseLogs
|
|
192
31
|
);
|
|
193
32
|
}
|
|
194
|
-
function
|
|
195
|
-
if (
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
33
|
+
function parseUsage(value) {
|
|
34
|
+
if (!isRecord(value)) return unexpected("usage");
|
|
35
|
+
const balanceMicros = numberField(value, "balanceMicros");
|
|
36
|
+
const creditsUsed = numberField(value, "creditsUsed");
|
|
37
|
+
const requestCount = numberField(value, "requestCount");
|
|
38
|
+
return { balanceMicros, creditsUsed, requestCount };
|
|
39
|
+
}
|
|
40
|
+
function parseLogs(value) {
|
|
41
|
+
if (!isRecord(value) || !Array.isArray(value.logs) || !Array.isArray(value.endpoints)) {
|
|
42
|
+
return unexpected("logs");
|
|
43
|
+
}
|
|
44
|
+
return {
|
|
45
|
+
endpoints: value.endpoints.map((item) => {
|
|
46
|
+
if (typeof item !== "string") return unexpected("logs.endpoints");
|
|
47
|
+
return item;
|
|
48
|
+
}),
|
|
49
|
+
logs: value.logs.map(parseLog),
|
|
50
|
+
page: numberField(value, "page"),
|
|
51
|
+
pageSize: numberField(value, "pageSize"),
|
|
52
|
+
total: numberField(value, "total"),
|
|
53
|
+
totalPages: numberField(value, "totalPages")
|
|
213
54
|
};
|
|
214
55
|
}
|
|
215
|
-
function
|
|
216
|
-
|
|
217
|
-
return
|
|
56
|
+
function parseLog(value) {
|
|
57
|
+
if (!isRecord(value)) return unexpected("logs.logs");
|
|
58
|
+
return {
|
|
59
|
+
apiKeyId: stringOrNull(value, "apiKeyId"),
|
|
60
|
+
apiKeyName: stringOrNull(value, "apiKeyName"),
|
|
61
|
+
createdAt: stringField(value, "createdAt"),
|
|
62
|
+
credits: numberField(value, "credits"),
|
|
63
|
+
durationMs: numberOrNull(value, "durationMs"),
|
|
64
|
+
endpoint: stringField(value, "endpoint"),
|
|
65
|
+
id: stringField(value, "id"),
|
|
66
|
+
method: stringField(value, "method"),
|
|
67
|
+
response: stringField(value, "response"),
|
|
68
|
+
status: numberField(value, "status")
|
|
69
|
+
};
|
|
218
70
|
}
|
|
219
|
-
function
|
|
220
|
-
const
|
|
221
|
-
if (
|
|
222
|
-
|
|
223
|
-
if (!Number.isNaN(seconds)) return seconds * 1e3;
|
|
224
|
-
const date = Date.parse(header);
|
|
225
|
-
return Number.isNaN(date) ? null : Math.max(0, date - Date.now());
|
|
71
|
+
function numberField(record, field) {
|
|
72
|
+
const value = record[field];
|
|
73
|
+
if (typeof value !== "number") return unexpected(field);
|
|
74
|
+
return value;
|
|
226
75
|
}
|
|
227
|
-
function
|
|
228
|
-
|
|
76
|
+
function numberOrNull(record, field) {
|
|
77
|
+
const value = record[field];
|
|
78
|
+
if (value === null) return null;
|
|
79
|
+
if (typeof value !== "number") return unexpected(field);
|
|
80
|
+
return value;
|
|
229
81
|
}
|
|
230
|
-
function
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
throw new StophyError(
|
|
235
|
-
error.error ?? `Stophy request failed with status ${result.response.status}`,
|
|
236
|
-
{
|
|
237
|
-
status: result.response.status,
|
|
238
|
-
code: error.code,
|
|
239
|
-
requestId: result.response.headers.get("x-request-id") ?? void 0,
|
|
240
|
-
details: error.details
|
|
241
|
-
}
|
|
242
|
-
);
|
|
82
|
+
function stringField(record, field) {
|
|
83
|
+
const value = record[field];
|
|
84
|
+
if (typeof value !== "string") return unexpected(field);
|
|
85
|
+
return value;
|
|
243
86
|
}
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
87
|
+
function stringOrNull(record, field) {
|
|
88
|
+
const value = record[field];
|
|
89
|
+
if (value === null) return null;
|
|
90
|
+
if (typeof value !== "string") return unexpected(field);
|
|
91
|
+
return value;
|
|
248
92
|
}
|
|
249
|
-
function
|
|
250
|
-
|
|
93
|
+
function unexpected(field) {
|
|
94
|
+
throw new StophyError(`Stophy returned an unexpected ${field}`, {
|
|
95
|
+
status: 200,
|
|
96
|
+
retryable: false
|
|
97
|
+
});
|
|
251
98
|
}
|
|
252
|
-
function
|
|
253
|
-
return
|
|
99
|
+
function isRecord(value) {
|
|
100
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
254
101
|
}
|
|
255
102
|
|
|
256
|
-
// src/
|
|
257
|
-
function
|
|
258
|
-
|
|
259
|
-
|
|
103
|
+
// src/bind.ts
|
|
104
|
+
function post(path, call) {
|
|
105
|
+
function run(body, options) {
|
|
106
|
+
return call({ method: "POST", path, body, options });
|
|
107
|
+
}
|
|
108
|
+
return run;
|
|
260
109
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
110
|
+
function postOptional(path, call) {
|
|
111
|
+
function run(body, options) {
|
|
112
|
+
if (isMarkdownOptions(body) && options === void 0) {
|
|
113
|
+
return call({ method: "POST", path, body: {}, options: body });
|
|
114
|
+
}
|
|
115
|
+
return call({ method: "POST", path, body: body ?? {}, options });
|
|
116
|
+
}
|
|
117
|
+
return run;
|
|
118
|
+
}
|
|
119
|
+
function get(path, call) {
|
|
120
|
+
function run(options) {
|
|
121
|
+
return call({ method: "GET", path, options });
|
|
122
|
+
}
|
|
123
|
+
return run;
|
|
124
|
+
}
|
|
125
|
+
function isMarkdownOptions(value) {
|
|
126
|
+
if (typeof value !== "object" || value === null) return false;
|
|
127
|
+
return "format" in value && value.format === "markdown";
|
|
265
128
|
}
|
|
266
129
|
|
|
267
|
-
// src/
|
|
268
|
-
function
|
|
269
|
-
return
|
|
130
|
+
// src/generated/surface.gen.ts
|
|
131
|
+
function bindSurface(call) {
|
|
132
|
+
return {
|
|
133
|
+
endpoints: get("/v1/endpoints", call),
|
|
134
|
+
web: {
|
|
135
|
+
search: post("/v1/web/search", call),
|
|
136
|
+
news: postOptional("/v1/web/news", call),
|
|
137
|
+
contacts: post("/v1/web/contacts", call)
|
|
138
|
+
},
|
|
139
|
+
youtube: {
|
|
140
|
+
search: post("/v1/youtube/search", call),
|
|
141
|
+
video: post("/v1/youtube/video", call),
|
|
142
|
+
transcript: post("/v1/youtube/transcript", call),
|
|
143
|
+
comments: Object.assign(post("/v1/youtube/comments", call), {
|
|
144
|
+
replies: post("/v1/youtube/comments/replies", call)
|
|
145
|
+
}),
|
|
146
|
+
channel: post("/v1/youtube/channel", call),
|
|
147
|
+
playlist: post("/v1/youtube/playlist", call),
|
|
148
|
+
suggest: post("/v1/youtube/suggest", call)
|
|
149
|
+
},
|
|
150
|
+
reddit: {
|
|
151
|
+
search: post("/v1/reddit/search", call),
|
|
152
|
+
post: post("/v1/reddit/post", call),
|
|
153
|
+
comments: {
|
|
154
|
+
more: post("/v1/reddit/comments/more", call)
|
|
155
|
+
},
|
|
156
|
+
subreddit: post("/v1/reddit/subreddit", call),
|
|
157
|
+
user: post("/v1/reddit/user", call),
|
|
158
|
+
domain: post("/v1/reddit/domain", call)
|
|
159
|
+
},
|
|
160
|
+
maps: {
|
|
161
|
+
search: post("/v1/maps/search", call),
|
|
162
|
+
place: post("/v1/maps/place", call),
|
|
163
|
+
reviews: post("/v1/maps/reviews", call)
|
|
164
|
+
},
|
|
165
|
+
instagram: {
|
|
166
|
+
profile: post("/v1/instagram/profile", call),
|
|
167
|
+
posts: post("/v1/instagram/posts", call),
|
|
168
|
+
post: post("/v1/instagram/post", call),
|
|
169
|
+
url: post("/v1/instagram/url", call),
|
|
170
|
+
search: post("/v1/instagram/search", call),
|
|
171
|
+
transcript: post("/v1/instagram/transcript", call),
|
|
172
|
+
comments: Object.assign(post("/v1/instagram/comments", call), {
|
|
173
|
+
replies: post("/v1/instagram/comments/replies", call)
|
|
174
|
+
})
|
|
175
|
+
},
|
|
176
|
+
tiktok: {
|
|
177
|
+
profile: post("/v1/tiktok/profile", call),
|
|
178
|
+
video: post("/v1/tiktok/video", call),
|
|
179
|
+
url: post("/v1/tiktok/url", call),
|
|
180
|
+
transcript: post("/v1/tiktok/transcript", call),
|
|
181
|
+
posts: post("/v1/tiktok/posts", call),
|
|
182
|
+
hashtag: post("/v1/tiktok/hashtag", call),
|
|
183
|
+
comments: Object.assign(post("/v1/tiktok/comments", call), {
|
|
184
|
+
replies: post("/v1/tiktok/comments/replies", call)
|
|
185
|
+
}),
|
|
186
|
+
search: post("/v1/tiktok/search", call),
|
|
187
|
+
ads: {
|
|
188
|
+
search: postOptional("/v1/tiktok/ads/search", call),
|
|
189
|
+
ad: post("/v1/tiktok/ads/ad", call)
|
|
190
|
+
}
|
|
191
|
+
},
|
|
192
|
+
bluesky: {
|
|
193
|
+
profile: post("/v1/bluesky/profile", call),
|
|
194
|
+
posts: post("/v1/bluesky/posts", call),
|
|
195
|
+
post: post("/v1/bluesky/post", call),
|
|
196
|
+
followers: post("/v1/bluesky/followers", call)
|
|
197
|
+
},
|
|
198
|
+
mastodon: {
|
|
199
|
+
profile: post("/v1/mastodon/profile", call),
|
|
200
|
+
posts: post("/v1/mastodon/posts", call),
|
|
201
|
+
post: post("/v1/mastodon/post", call),
|
|
202
|
+
hashtag: post("/v1/mastodon/hashtag", call)
|
|
203
|
+
},
|
|
204
|
+
threads: {
|
|
205
|
+
profile: post("/v1/threads/profile", call),
|
|
206
|
+
posts: post("/v1/threads/posts", call),
|
|
207
|
+
post: post("/v1/threads/post", call),
|
|
208
|
+
search: post("/v1/threads/search", call)
|
|
209
|
+
},
|
|
210
|
+
telegram: {
|
|
211
|
+
channel: post("/v1/telegram/channel", call),
|
|
212
|
+
posts: post("/v1/telegram/posts", call),
|
|
213
|
+
post: post("/v1/telegram/post", call)
|
|
214
|
+
},
|
|
215
|
+
meta: {
|
|
216
|
+
ads: {
|
|
217
|
+
search: post("/v1/meta/ads/search", call),
|
|
218
|
+
page: post("/v1/meta/ads/page", call),
|
|
219
|
+
ad: post("/v1/meta/ads/ad", call)
|
|
220
|
+
}
|
|
221
|
+
},
|
|
222
|
+
linkedin: {
|
|
223
|
+
jobs: {
|
|
224
|
+
search: postOptional("/v1/linkedin/jobs/search", call),
|
|
225
|
+
job: post("/v1/linkedin/jobs/job", call)
|
|
226
|
+
},
|
|
227
|
+
ads: {
|
|
228
|
+
search: postOptional("/v1/linkedin/ads/search", call),
|
|
229
|
+
ad: post("/v1/linkedin/ads/ad", call)
|
|
230
|
+
},
|
|
231
|
+
company: Object.assign(post("/v1/linkedin/company", call), {
|
|
232
|
+
posts: post("/v1/linkedin/company/posts", call)
|
|
233
|
+
}),
|
|
234
|
+
profile: post("/v1/linkedin/profile", call),
|
|
235
|
+
posts: postOptional("/v1/linkedin/posts", call)
|
|
236
|
+
},
|
|
237
|
+
zillow: {
|
|
238
|
+
search: postOptional("/v1/zillow/search", call),
|
|
239
|
+
property: post("/v1/zillow/property", call)
|
|
240
|
+
},
|
|
241
|
+
google: {
|
|
242
|
+
ads: {
|
|
243
|
+
advertisers: post("/v1/google/ads/advertisers", call),
|
|
244
|
+
search: postOptional("/v1/google/ads/search", call),
|
|
245
|
+
ad: post("/v1/google/ads/ad", call)
|
|
246
|
+
},
|
|
247
|
+
suggest: post("/v1/google/suggest", call),
|
|
248
|
+
trends: {
|
|
249
|
+
interest: post("/v1/google/trends/interest", call),
|
|
250
|
+
regions: post("/v1/google/trends/regions", call),
|
|
251
|
+
related: post("/v1/google/trends/related", call),
|
|
252
|
+
trending: postOptional("/v1/google/trends/trending", call)
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
upwork: {
|
|
256
|
+
search: postOptional("/v1/upwork/search", call),
|
|
257
|
+
job: post("/v1/upwork/job", call)
|
|
258
|
+
},
|
|
259
|
+
amazon: {
|
|
260
|
+
suggest: post("/v1/amazon/suggest", call),
|
|
261
|
+
search: postOptional("/v1/amazon/search", call),
|
|
262
|
+
product: post("/v1/amazon/product", call),
|
|
263
|
+
bestsellers: post("/v1/amazon/bestsellers", call)
|
|
264
|
+
},
|
|
265
|
+
site: {
|
|
266
|
+
map: post("/v1/site/map", call),
|
|
267
|
+
seo: post("/v1/site/seo", call)
|
|
268
|
+
},
|
|
269
|
+
domain: {
|
|
270
|
+
whois: post("/v1/domain/whois", call),
|
|
271
|
+
dns: post("/v1/domain/dns", call),
|
|
272
|
+
tech: post("/v1/domain/tech", call)
|
|
273
|
+
},
|
|
274
|
+
email: {
|
|
275
|
+
check: post("/v1/email/check", call)
|
|
276
|
+
},
|
|
277
|
+
crypto: {
|
|
278
|
+
coins: postOptional("/v1/crypto/coins", call),
|
|
279
|
+
coin: post("/v1/crypto/coin", call),
|
|
280
|
+
history: post("/v1/crypto/history", call),
|
|
281
|
+
trending: postOptional("/v1/crypto/trending", call),
|
|
282
|
+
categories: postOptional("/v1/crypto/categories", call),
|
|
283
|
+
movers: postOptional("/v1/crypto/movers", call),
|
|
284
|
+
new: postOptional("/v1/crypto/new", call),
|
|
285
|
+
dex: {
|
|
286
|
+
search: post("/v1/crypto/dex/search", call),
|
|
287
|
+
pairs: post("/v1/crypto/dex/pairs", call),
|
|
288
|
+
token: post("/v1/crypto/dex/token", call),
|
|
289
|
+
new: postOptional("/v1/crypto/dex/new", call)
|
|
290
|
+
},
|
|
291
|
+
pump: {
|
|
292
|
+
coins: postOptional("/v1/crypto/pump/coins", call),
|
|
293
|
+
coin: post("/v1/crypto/pump/coin", call),
|
|
294
|
+
trades: post("/v1/crypto/pump/trades", call)
|
|
295
|
+
},
|
|
296
|
+
wallet: post("/v1/crypto/wallet", call),
|
|
297
|
+
token: {
|
|
298
|
+
holders: post("/v1/crypto/token/holders", call)
|
|
299
|
+
},
|
|
300
|
+
binance: {
|
|
301
|
+
announcements: postOptional("/v1/crypto/binance/announcements", call)
|
|
302
|
+
}
|
|
303
|
+
},
|
|
304
|
+
indeed: {
|
|
305
|
+
search: postOptional("/v1/indeed/search", call),
|
|
306
|
+
job: post("/v1/indeed/job", call)
|
|
307
|
+
},
|
|
308
|
+
tripadvisor: {
|
|
309
|
+
search: post("/v1/tripadvisor/search", call),
|
|
310
|
+
place: post("/v1/tripadvisor/place", call),
|
|
311
|
+
reviews: post("/v1/tripadvisor/reviews", call)
|
|
312
|
+
},
|
|
313
|
+
googletravel: {
|
|
314
|
+
flights: post("/v1/googletravel/flights", call)
|
|
315
|
+
},
|
|
316
|
+
shopify: {
|
|
317
|
+
products: post("/v1/shopify/products", call),
|
|
318
|
+
collections: post("/v1/shopify/collections", call),
|
|
319
|
+
store: post("/v1/shopify/store", call)
|
|
320
|
+
},
|
|
321
|
+
walmart: {
|
|
322
|
+
search: post("/v1/walmart/search", call),
|
|
323
|
+
product: post("/v1/walmart/product", call)
|
|
324
|
+
},
|
|
325
|
+
aliexpress: {
|
|
326
|
+
search: post("/v1/aliexpress/search", call),
|
|
327
|
+
product: post("/v1/aliexpress/product", call)
|
|
328
|
+
},
|
|
329
|
+
appstore: {
|
|
330
|
+
app: post("/v1/appstore/app", call),
|
|
331
|
+
search: post("/v1/appstore/search", call),
|
|
332
|
+
reviews: post("/v1/appstore/reviews", call),
|
|
333
|
+
top: postOptional("/v1/appstore/top", call)
|
|
334
|
+
},
|
|
335
|
+
googleplay: {
|
|
336
|
+
app: post("/v1/googleplay/app", call),
|
|
337
|
+
search: post("/v1/googleplay/search", call),
|
|
338
|
+
reviews: post("/v1/googleplay/reviews", call)
|
|
339
|
+
},
|
|
340
|
+
airbnb: {
|
|
341
|
+
search: post("/v1/airbnb/search", call),
|
|
342
|
+
listing: post("/v1/airbnb/listing", call),
|
|
343
|
+
calendar: post("/v1/airbnb/calendar", call),
|
|
344
|
+
reviews: post("/v1/airbnb/reviews", call)
|
|
345
|
+
},
|
|
346
|
+
redfin: {
|
|
347
|
+
search: post("/v1/redfin/search", call),
|
|
348
|
+
property: post("/v1/redfin/property", call)
|
|
349
|
+
},
|
|
350
|
+
realtor: {
|
|
351
|
+
search: post("/v1/realtor/search", call),
|
|
352
|
+
property: post("/v1/realtor/property", call)
|
|
353
|
+
},
|
|
354
|
+
rightmove: {
|
|
355
|
+
search: post("/v1/rightmove/search", call),
|
|
356
|
+
property: post("/v1/rightmove/property", call)
|
|
357
|
+
},
|
|
358
|
+
immoscout: {
|
|
359
|
+
search: post("/v1/immoscout/search", call),
|
|
360
|
+
listing: post("/v1/immoscout/listing", call)
|
|
361
|
+
},
|
|
362
|
+
pinterest: {
|
|
363
|
+
search: post("/v1/pinterest/search", call),
|
|
364
|
+
pin: post("/v1/pinterest/pin", call),
|
|
365
|
+
board: post("/v1/pinterest/board", call),
|
|
366
|
+
user: post("/v1/pinterest/user", call),
|
|
367
|
+
ads: {
|
|
368
|
+
search: post("/v1/pinterest/ads/search", call),
|
|
369
|
+
ad: post("/v1/pinterest/ads/ad", call)
|
|
370
|
+
}
|
|
371
|
+
},
|
|
372
|
+
x: {
|
|
373
|
+
tweet: post("/v1/x/tweet", call)
|
|
374
|
+
},
|
|
375
|
+
kick: {
|
|
376
|
+
channel: post("/v1/kick/channel", call),
|
|
377
|
+
videos: post("/v1/kick/videos", call),
|
|
378
|
+
clips: post("/v1/kick/clips", call)
|
|
379
|
+
},
|
|
380
|
+
finance: {
|
|
381
|
+
quote: post("/v1/finance/quote", call),
|
|
382
|
+
history: post("/v1/finance/history", call),
|
|
383
|
+
search: post("/v1/finance/search", call),
|
|
384
|
+
profile: post("/v1/finance/profile", call)
|
|
385
|
+
},
|
|
386
|
+
microsoft: {
|
|
387
|
+
ads: {
|
|
388
|
+
search: postOptional("/v1/microsoft/ads/search", call),
|
|
389
|
+
ad: post("/v1/microsoft/ads/ad", call),
|
|
390
|
+
advertisers: post("/v1/microsoft/ads/advertisers", call)
|
|
391
|
+
}
|
|
392
|
+
},
|
|
393
|
+
snapchat: {
|
|
394
|
+
profile: post("/v1/snapchat/profile", call),
|
|
395
|
+
ads: {
|
|
396
|
+
search: post("/v1/snapchat/ads/search", call),
|
|
397
|
+
ad: post("/v1/snapchat/ads/ad", call)
|
|
398
|
+
}
|
|
399
|
+
},
|
|
400
|
+
tumblr: {
|
|
401
|
+
blog: post("/v1/tumblr/blog", call),
|
|
402
|
+
posts: post("/v1/tumblr/posts", call),
|
|
403
|
+
post: post("/v1/tumblr/post", call),
|
|
404
|
+
search: post("/v1/tumblr/search", call)
|
|
405
|
+
},
|
|
406
|
+
quora: {
|
|
407
|
+
question: post("/v1/quora/question", call)
|
|
408
|
+
}
|
|
409
|
+
};
|
|
270
410
|
}
|
|
271
411
|
|
|
272
|
-
//
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
412
|
+
// package.json
|
|
413
|
+
var version = "1.0.1";
|
|
414
|
+
|
|
415
|
+
// src/transport.ts
|
|
416
|
+
var DEFAULT_BASE_URL = "https://api.stophy.dev";
|
|
417
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
418
|
+
var MAX_RETRY_WAIT_SECONDS = 60;
|
|
419
|
+
var RETRYABLE_STATUS = /* @__PURE__ */ new Set([429, 500, 502, 503, 504]);
|
|
420
|
+
var USER_AGENT = `stophy-typescript/${version}`;
|
|
421
|
+
function createCaller(options) {
|
|
422
|
+
const baseFetch = options.fetch ?? globalThis.fetch;
|
|
423
|
+
const baseUrl = (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\/$/, "");
|
|
424
|
+
const retry = {
|
|
425
|
+
maxRetries: options.maxRetries ?? 2,
|
|
426
|
+
initialDelayMs: options.retryInitialDelayMs ?? 500,
|
|
427
|
+
timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS
|
|
428
|
+
};
|
|
429
|
+
return async (spec) => {
|
|
430
|
+
const markdown = spec.options?.format === "markdown";
|
|
431
|
+
const headers = new Headers(options.headers);
|
|
432
|
+
if (typeof document === "undefined" && !headers.has("user-agent")) {
|
|
433
|
+
headers.set("user-agent", USER_AGENT);
|
|
434
|
+
}
|
|
435
|
+
if (options.apiKey) {
|
|
436
|
+
headers.set("authorization", `Bearer ${options.apiKey}`);
|
|
437
|
+
}
|
|
438
|
+
headers.set("accept", markdown ? "text/markdown" : "application/json");
|
|
439
|
+
if (spec.body !== void 0)
|
|
440
|
+
headers.set("content-type", "application/json");
|
|
441
|
+
const url = withQuery(`${baseUrl}${spec.path}`, spec.query);
|
|
442
|
+
return send(
|
|
443
|
+
baseFetch,
|
|
444
|
+
url,
|
|
445
|
+
(signal) => ({
|
|
446
|
+
method: spec.method,
|
|
447
|
+
headers,
|
|
448
|
+
body: spec.body === void 0 ? void 0 : JSON.stringify(spec.body),
|
|
449
|
+
signal
|
|
450
|
+
}),
|
|
451
|
+
markdown,
|
|
452
|
+
spec.options?.signal,
|
|
453
|
+
retry
|
|
454
|
+
);
|
|
455
|
+
};
|
|
456
|
+
}
|
|
457
|
+
async function send(baseFetch, url, init, markdown, signal, retry) {
|
|
458
|
+
for (let n = 0; ; n += 1) {
|
|
459
|
+
const deadline = withDeadline(signal, retry.timeoutMs);
|
|
460
|
+
let waitMs;
|
|
461
|
+
try {
|
|
462
|
+
const response = await baseFetch(url, init(deadline.signal)).catch(
|
|
463
|
+
(error) => {
|
|
464
|
+
if (deadline.signal.aborted || n >= retry.maxRetries) throw error;
|
|
465
|
+
return void 0;
|
|
466
|
+
}
|
|
467
|
+
);
|
|
468
|
+
if (response === void 0) {
|
|
469
|
+
waitMs = backoffMs(n, retry.initialDelayMs);
|
|
470
|
+
} else if (n < retry.maxRetries && RETRYABLE_STATUS.has(response.status)) {
|
|
471
|
+
const error = await errorFrom(response);
|
|
472
|
+
const seconds = error.retryAfterSeconds;
|
|
473
|
+
if (seconds !== void 0 && seconds > MAX_RETRY_WAIT_SECONDS) {
|
|
474
|
+
throw error;
|
|
475
|
+
}
|
|
476
|
+
waitMs = seconds === void 0 ? backoffMs(n, retry.initialDelayMs) : seconds * 1e3;
|
|
477
|
+
} else {
|
|
478
|
+
return await readBody(response, markdown);
|
|
479
|
+
}
|
|
480
|
+
} finally {
|
|
481
|
+
deadline.clear();
|
|
482
|
+
}
|
|
483
|
+
await sleep(waitMs);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
function withDeadline(signal, timeoutMs) {
|
|
487
|
+
const controller = new AbortController();
|
|
488
|
+
const abort = () => controller.abort(signal?.reason);
|
|
489
|
+
if (signal?.aborted) abort();
|
|
490
|
+
else signal?.addEventListener("abort", abort, { once: true });
|
|
491
|
+
const timer = setTimeout(
|
|
492
|
+
() => controller.abort(
|
|
493
|
+
new DOMException(
|
|
494
|
+
`Stophy request timed out after ${timeoutMs} ms`,
|
|
495
|
+
"TimeoutError"
|
|
496
|
+
)
|
|
497
|
+
),
|
|
498
|
+
timeoutMs
|
|
277
499
|
);
|
|
500
|
+
return {
|
|
501
|
+
signal: controller.signal,
|
|
502
|
+
clear: () => {
|
|
503
|
+
clearTimeout(timer);
|
|
504
|
+
signal?.removeEventListener("abort", abort);
|
|
505
|
+
}
|
|
506
|
+
};
|
|
278
507
|
}
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
if (
|
|
283
|
-
|
|
508
|
+
async function readBody(response, markdown) {
|
|
509
|
+
if (!response.ok) throw await errorFrom(response);
|
|
510
|
+
const text = await response.text();
|
|
511
|
+
if (markdown) return text;
|
|
512
|
+
if (!text) {
|
|
513
|
+
throw failed(response, "Stophy returned an empty response", {});
|
|
514
|
+
}
|
|
515
|
+
try {
|
|
516
|
+
return JSON.parse(text);
|
|
517
|
+
} catch {
|
|
518
|
+
throw failed(response, "Stophy returned a non-JSON response", {});
|
|
284
519
|
}
|
|
285
|
-
const body = typeof queryOrBody === "string" ? { q: queryOrBody, ...options } : queryOrBody;
|
|
286
|
-
return searchVideos({ client: client2, body }).then(unwrap);
|
|
287
520
|
}
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
if (
|
|
292
|
-
|
|
521
|
+
async function errorFrom(response) {
|
|
522
|
+
const text = await response.text();
|
|
523
|
+
let body;
|
|
524
|
+
if (text) {
|
|
525
|
+
try {
|
|
526
|
+
body = JSON.parse(text);
|
|
527
|
+
} catch {
|
|
528
|
+
body = void 0;
|
|
529
|
+
}
|
|
293
530
|
}
|
|
294
|
-
const
|
|
295
|
-
|
|
296
|
-
|
|
531
|
+
const error = readError(body);
|
|
532
|
+
const retryAfterSeconds = error.retryAfterSeconds ?? headerRetryAfter(response);
|
|
533
|
+
return failed(
|
|
534
|
+
response,
|
|
535
|
+
error.message ?? `Stophy request failed with status ${response.status}`,
|
|
536
|
+
{
|
|
537
|
+
code: error.code,
|
|
538
|
+
retryable: error.retryable ?? RETRYABLE_STATUS.has(response.status),
|
|
539
|
+
retryAfterSeconds,
|
|
540
|
+
requestId: error.requestId ?? headerRequestId(response)
|
|
541
|
+
}
|
|
297
542
|
);
|
|
298
543
|
}
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
544
|
+
function failed(response, message, options) {
|
|
545
|
+
return new StophyError(message, {
|
|
546
|
+
status: response.status,
|
|
547
|
+
code: options.code,
|
|
548
|
+
retryable: options.retryable ?? false,
|
|
549
|
+
retryAfterSeconds: options.retryAfterSeconds,
|
|
550
|
+
requestId: options.requestId ?? headerRequestId(response)
|
|
551
|
+
});
|
|
303
552
|
}
|
|
304
|
-
function
|
|
305
|
-
|
|
553
|
+
function readError(body) {
|
|
554
|
+
if (!isRecord2(body) || !isRecord2(body.error)) return {};
|
|
555
|
+
const error = body.error;
|
|
556
|
+
return {
|
|
557
|
+
code: typeof error.code === "string" ? error.code : void 0,
|
|
558
|
+
message: typeof error.message === "string" ? error.message : void 0,
|
|
559
|
+
retryable: typeof error.retryable === "boolean" ? error.retryable : void 0,
|
|
560
|
+
retryAfterSeconds: typeof error.retryAfterSeconds === "number" ? error.retryAfterSeconds : void 0,
|
|
561
|
+
requestId: typeof error.requestId === "string" ? error.requestId : void 0
|
|
562
|
+
};
|
|
306
563
|
}
|
|
307
|
-
function
|
|
308
|
-
return
|
|
564
|
+
function isRecord2(value) {
|
|
565
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
309
566
|
}
|
|
310
|
-
function
|
|
311
|
-
return
|
|
312
|
-
type: "comments",
|
|
313
|
-
videoUrl,
|
|
314
|
-
...options
|
|
315
|
-
});
|
|
567
|
+
function headerRequestId(response) {
|
|
568
|
+
return response.headers.get("x-request-id") ?? void 0;
|
|
316
569
|
}
|
|
317
|
-
function
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
570
|
+
function headerRetryAfter(response) {
|
|
571
|
+
const header = response.headers.get("retry-after");
|
|
572
|
+
if (!header) return void 0;
|
|
573
|
+
const seconds = Number(header);
|
|
574
|
+
if (Number.isFinite(seconds)) return seconds;
|
|
575
|
+
const date = Date.parse(header);
|
|
576
|
+
if (Number.isNaN(date)) return void 0;
|
|
577
|
+
return Math.max(0, Math.ceil((date - Date.now()) / 1e3));
|
|
322
578
|
}
|
|
323
|
-
function
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
}
|
|
579
|
+
function withQuery(url, query) {
|
|
580
|
+
if (!query) return url;
|
|
581
|
+
const params = new URLSearchParams();
|
|
582
|
+
for (const [key, value] of Object.entries(query)) {
|
|
583
|
+
if (value !== void 0) params.set(key, String(value));
|
|
584
|
+
}
|
|
585
|
+
const text = params.toString();
|
|
586
|
+
return text ? `${url}?${text}` : url;
|
|
587
|
+
}
|
|
588
|
+
function backoffMs(attempt, base) {
|
|
589
|
+
const window = base * 2 ** attempt;
|
|
590
|
+
return window / 2 + Math.random() * (window / 2);
|
|
591
|
+
}
|
|
592
|
+
function sleep(ms) {
|
|
593
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
329
594
|
}
|
|
330
595
|
|
|
331
596
|
// src/client.ts
|
|
@@ -333,65 +598,24 @@ function env(name) {
|
|
|
333
598
|
return typeof process === "undefined" ? void 0 : process.env[name];
|
|
334
599
|
}
|
|
335
600
|
var Stophy = class {
|
|
336
|
-
|
|
601
|
+
#call;
|
|
337
602
|
constructor(input = {}) {
|
|
338
603
|
const options = typeof input === "string" ? { apiKey: input } : input;
|
|
339
604
|
const apiKey = options.apiKey?.trim() || env("STOPHY_API_KEY")?.trim();
|
|
340
|
-
|
|
341
|
-
throw new Error(
|
|
342
|
-
"Stophy: provide `apiKey` or set the STOPHY_API_KEY environment variable."
|
|
343
|
-
);
|
|
344
|
-
}
|
|
345
|
-
this.client = createTransport({
|
|
605
|
+
this.#call = createCaller({
|
|
346
606
|
...options,
|
|
347
607
|
apiKey,
|
|
348
608
|
baseUrl: options.baseUrl ?? env("STOPHY_BASE_URL")
|
|
349
609
|
});
|
|
610
|
+
Object.assign(this, bindSurface(this.#call));
|
|
350
611
|
}
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
videoDetails(videoUrl) {
|
|
355
|
-
return videoDetails(this.client, videoUrl);
|
|
356
|
-
}
|
|
357
|
-
transcript(videoUrl, options) {
|
|
358
|
-
return transcript(this.client, videoUrl, options);
|
|
359
|
-
}
|
|
360
|
-
comments(videoUrl, options) {
|
|
361
|
-
return comments(this.client, videoUrl, options);
|
|
362
|
-
}
|
|
363
|
-
replies(continuationToken) {
|
|
364
|
-
return replies(this.client, continuationToken);
|
|
365
|
-
}
|
|
366
|
-
liveChat(videoUrl, options) {
|
|
367
|
-
return liveChat(this.client, videoUrl, options);
|
|
368
|
-
}
|
|
369
|
-
async search(queryOrBody, options) {
|
|
370
|
-
return search(this.client, queryOrBody, options);
|
|
371
|
-
}
|
|
372
|
-
async channel(urlOrBody, options) {
|
|
373
|
-
return channel(this.client, urlOrBody, options);
|
|
374
|
-
}
|
|
375
|
-
async playlist(urlOrBody, options) {
|
|
376
|
-
return playlist(this.client, urlOrBody, options);
|
|
377
|
-
}
|
|
378
|
-
async suggest(queryOrOptions, options) {
|
|
379
|
-
return suggest(this.client, queryOrOptions, options);
|
|
380
|
-
}
|
|
381
|
-
music(body) {
|
|
382
|
-
return music(this.client, body);
|
|
383
|
-
}
|
|
384
|
-
kids(body) {
|
|
385
|
-
return kids(this.client, body);
|
|
386
|
-
}
|
|
387
|
-
credits() {
|
|
388
|
-
return credits(this.client);
|
|
612
|
+
/** Current balance and lifetime usage. Requires an API key. */
|
|
613
|
+
usage() {
|
|
614
|
+
return usage(this.#call);
|
|
389
615
|
}
|
|
616
|
+
/** Recent metered requests. Requires an API key. */
|
|
390
617
|
logs(query) {
|
|
391
|
-
return logs(this
|
|
392
|
-
}
|
|
393
|
-
usage(query) {
|
|
394
|
-
return usage(this.client, query);
|
|
618
|
+
return logs(this.#call, query);
|
|
395
619
|
}
|
|
396
620
|
};
|
|
397
621
|
|