stophy 0.2.1 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +59 -69
- package/dist/index.cjs +562 -282
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +22754 -664
- package/dist/index.d.ts +22754 -664
- package/dist/index.js +562 -282
- package/dist/index.js.map +1 -1
- package/package.json +13 -10
package/dist/index.js
CHANGED
|
@@ -1,341 +1,621 @@
|
|
|
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 getVideo = (options) => {
|
|
12
|
-
return (options.client ?? client).post({
|
|
13
|
-
security: [
|
|
14
|
-
{
|
|
15
|
-
scheme: "bearer",
|
|
16
|
-
type: "http"
|
|
17
|
-
}
|
|
18
|
-
],
|
|
19
|
-
url: "/v1/video",
|
|
20
|
-
...options,
|
|
21
|
-
headers: {
|
|
22
|
-
"Content-Type": "application/json",
|
|
23
|
-
...options?.headers
|
|
24
|
-
}
|
|
25
|
-
});
|
|
26
|
-
};
|
|
27
|
-
var searchVideos = (options) => {
|
|
28
|
-
return (options.client ?? client).post({
|
|
29
|
-
security: [
|
|
30
|
-
{
|
|
31
|
-
scheme: "bearer",
|
|
32
|
-
type: "http"
|
|
33
|
-
}
|
|
34
|
-
],
|
|
35
|
-
url: "/v1/search",
|
|
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).get({
|
|
77
|
-
security: [
|
|
78
|
-
{
|
|
79
|
-
scheme: "bearer",
|
|
80
|
-
type: "http"
|
|
81
|
-
}
|
|
82
|
-
],
|
|
83
|
-
url: "/v1/suggest",
|
|
84
|
-
...options
|
|
85
|
-
});
|
|
86
|
-
};
|
|
87
|
-
var getCredits = (options) => {
|
|
88
|
-
return (options?.client ?? client).get({
|
|
89
|
-
security: [
|
|
90
|
-
{
|
|
91
|
-
scheme: "bearer",
|
|
92
|
-
type: "http"
|
|
93
|
-
}
|
|
94
|
-
],
|
|
95
|
-
url: "/v1/credits",
|
|
96
|
-
...options
|
|
97
|
-
});
|
|
98
|
-
};
|
|
99
|
-
var getLogs = (options) => {
|
|
100
|
-
return (options?.client ?? client).get({
|
|
101
|
-
security: [
|
|
102
|
-
{
|
|
103
|
-
scheme: "bearer",
|
|
104
|
-
type: "http"
|
|
105
|
-
}
|
|
106
|
-
],
|
|
107
|
-
url: "/v1/logs",
|
|
108
|
-
...options
|
|
109
|
-
});
|
|
110
|
-
};
|
|
111
|
-
var getUsage = (options) => {
|
|
112
|
-
return (options?.client ?? client).get({
|
|
113
|
-
security: [
|
|
114
|
-
{
|
|
115
|
-
scheme: "bearer",
|
|
116
|
-
type: "http"
|
|
117
|
-
}
|
|
118
|
-
],
|
|
119
|
-
url: "/v1/usage",
|
|
120
|
-
...options
|
|
121
|
-
});
|
|
122
|
-
};
|
|
123
|
-
|
|
124
1
|
// src/errors.ts
|
|
125
2
|
var StophyError = class extends Error {
|
|
126
3
|
code;
|
|
4
|
+
retryable;
|
|
5
|
+
retryAfterSeconds;
|
|
127
6
|
status;
|
|
128
7
|
requestId;
|
|
129
|
-
details;
|
|
130
8
|
constructor(message, options) {
|
|
131
9
|
super(message);
|
|
132
10
|
this.name = "StophyError";
|
|
133
11
|
this.status = options.status;
|
|
134
12
|
this.code = options.code;
|
|
13
|
+
this.retryable = options.retryable;
|
|
14
|
+
this.retryAfterSeconds = options.retryAfterSeconds;
|
|
135
15
|
this.requestId = options.requestId;
|
|
136
|
-
this.details = options.details;
|
|
137
16
|
}
|
|
138
17
|
};
|
|
139
18
|
|
|
140
|
-
// src/
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
options.maxRetries ?? 2,
|
|
153
|
-
options.retryInitialDelayMs ?? 500
|
|
154
|
-
)
|
|
155
|
-
})
|
|
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
|
|
156
31
|
);
|
|
157
32
|
}
|
|
158
|
-
function
|
|
159
|
-
if (
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
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")
|
|
177
54
|
};
|
|
178
55
|
}
|
|
179
|
-
function
|
|
180
|
-
|
|
181
|
-
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
|
+
};
|
|
182
70
|
}
|
|
183
|
-
function
|
|
184
|
-
const
|
|
185
|
-
if (
|
|
186
|
-
|
|
187
|
-
if (!Number.isNaN(seconds)) return seconds * 1e3;
|
|
188
|
-
const date = Date.parse(header);
|
|
189
|
-
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;
|
|
190
75
|
}
|
|
191
|
-
function
|
|
192
|
-
|
|
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;
|
|
193
81
|
}
|
|
194
|
-
function
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
throw new StophyError(
|
|
199
|
-
error.error ?? `Stophy request failed with status ${result.response.status}`,
|
|
200
|
-
{
|
|
201
|
-
status: result.response.status,
|
|
202
|
-
code: error.code,
|
|
203
|
-
requestId: result.response.headers.get("x-request-id") ?? void 0,
|
|
204
|
-
details: error.details
|
|
205
|
-
}
|
|
206
|
-
);
|
|
82
|
+
function stringField(record, field) {
|
|
83
|
+
const value = record[field];
|
|
84
|
+
if (typeof value !== "string") return unexpected(field);
|
|
85
|
+
return value;
|
|
207
86
|
}
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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;
|
|
212
92
|
}
|
|
213
|
-
function
|
|
214
|
-
|
|
93
|
+
function unexpected(field) {
|
|
94
|
+
throw new StophyError(`Stophy returned an unexpected ${field}`, {
|
|
95
|
+
status: 200,
|
|
96
|
+
retryable: false
|
|
97
|
+
});
|
|
215
98
|
}
|
|
216
|
-
function
|
|
217
|
-
return
|
|
99
|
+
function isRecord(value) {
|
|
100
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
218
101
|
}
|
|
219
102
|
|
|
220
|
-
// src/
|
|
221
|
-
function
|
|
222
|
-
|
|
223
|
-
|
|
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;
|
|
224
109
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
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;
|
|
230
118
|
}
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
if (typeof queryOrBody === "string" && !queryOrBody.trim()) {
|
|
235
|
-
throw new Error("query cannot be empty");
|
|
119
|
+
function get(path, call) {
|
|
120
|
+
function run(options) {
|
|
121
|
+
return call({ method: "GET", path, options });
|
|
236
122
|
}
|
|
237
|
-
|
|
238
|
-
|
|
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";
|
|
239
128
|
}
|
|
240
129
|
|
|
241
|
-
// src/
|
|
242
|
-
function
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
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
|
+
};
|
|
248
410
|
}
|
|
249
411
|
|
|
250
|
-
//
|
|
251
|
-
|
|
252
|
-
|
|
412
|
+
// package.json
|
|
413
|
+
var version = "1.0.0";
|
|
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
|
+
};
|
|
253
456
|
}
|
|
254
|
-
function
|
|
255
|
-
|
|
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
|
+
}
|
|
256
485
|
}
|
|
257
|
-
function
|
|
258
|
-
|
|
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
|
|
499
|
+
);
|
|
500
|
+
return {
|
|
501
|
+
signal: controller.signal,
|
|
502
|
+
clear: () => {
|
|
503
|
+
clearTimeout(timer);
|
|
504
|
+
signal?.removeEventListener("abort", abort);
|
|
505
|
+
}
|
|
506
|
+
};
|
|
259
507
|
}
|
|
260
|
-
function
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
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", {});
|
|
519
|
+
}
|
|
266
520
|
}
|
|
267
|
-
function
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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
|
+
}
|
|
530
|
+
}
|
|
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
|
+
}
|
|
542
|
+
);
|
|
272
543
|
}
|
|
273
|
-
function
|
|
274
|
-
return
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
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)
|
|
278
551
|
});
|
|
279
552
|
}
|
|
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
|
+
};
|
|
563
|
+
}
|
|
564
|
+
function isRecord2(value) {
|
|
565
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
566
|
+
}
|
|
567
|
+
function headerRequestId(response) {
|
|
568
|
+
return response.headers.get("x-request-id") ?? void 0;
|
|
569
|
+
}
|
|
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));
|
|
578
|
+
}
|
|
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));
|
|
594
|
+
}
|
|
280
595
|
|
|
281
596
|
// src/client.ts
|
|
282
597
|
function env(name) {
|
|
283
598
|
return typeof process === "undefined" ? void 0 : process.env[name];
|
|
284
599
|
}
|
|
285
600
|
var Stophy = class {
|
|
286
|
-
|
|
601
|
+
#call;
|
|
287
602
|
constructor(input = {}) {
|
|
288
603
|
const options = typeof input === "string" ? { apiKey: input } : input;
|
|
289
604
|
const apiKey = options.apiKey?.trim() || env("STOPHY_API_KEY")?.trim();
|
|
290
|
-
|
|
291
|
-
throw new Error(
|
|
292
|
-
"Stophy: provide `apiKey` or set the STOPHY_API_KEY environment variable."
|
|
293
|
-
);
|
|
294
|
-
}
|
|
295
|
-
this.client = createTransport({
|
|
605
|
+
this.#call = createCaller({
|
|
296
606
|
...options,
|
|
297
607
|
apiKey,
|
|
298
608
|
baseUrl: options.baseUrl ?? env("STOPHY_BASE_URL")
|
|
299
609
|
});
|
|
610
|
+
Object.assign(this, bindSurface(this.#call));
|
|
300
611
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
videoDetails(videoUrl) {
|
|
305
|
-
return videoDetails(this.client, videoUrl);
|
|
306
|
-
}
|
|
307
|
-
transcript(videoUrl) {
|
|
308
|
-
return transcript(this.client, videoUrl);
|
|
309
|
-
}
|
|
310
|
-
comments(videoUrl, options) {
|
|
311
|
-
return comments(this.client, videoUrl, options);
|
|
312
|
-
}
|
|
313
|
-
replies(continuationToken) {
|
|
314
|
-
return replies(this.client, continuationToken);
|
|
315
|
-
}
|
|
316
|
-
liveChat(videoUrl, options) {
|
|
317
|
-
return liveChat(this.client, videoUrl, options);
|
|
318
|
-
}
|
|
319
|
-
async search(queryOrBody, options) {
|
|
320
|
-
return search(this.client, queryOrBody, options);
|
|
321
|
-
}
|
|
322
|
-
async channel(urlOrBody, options) {
|
|
323
|
-
return channel(this.client, urlOrBody, options);
|
|
324
|
-
}
|
|
325
|
-
async playlist(urlOrBody, options) {
|
|
326
|
-
return playlist(this.client, urlOrBody, options);
|
|
327
|
-
}
|
|
328
|
-
async suggest(queryOrOptions, options) {
|
|
329
|
-
return suggest(this.client, queryOrOptions, options);
|
|
330
|
-
}
|
|
331
|
-
credits() {
|
|
332
|
-
return credits(this.client);
|
|
612
|
+
/** Current balance and lifetime usage. Requires an API key. */
|
|
613
|
+
usage() {
|
|
614
|
+
return usage(this.#call);
|
|
333
615
|
}
|
|
616
|
+
/** Recent metered requests. Requires an API key. */
|
|
334
617
|
logs(query) {
|
|
335
|
-
return logs(this
|
|
336
|
-
}
|
|
337
|
-
usage(query) {
|
|
338
|
-
return usage(this.client, query);
|
|
618
|
+
return logs(this.#call, query);
|
|
339
619
|
}
|
|
340
620
|
};
|
|
341
621
|
|