stophy 1.0.1 → 1.0.3

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 CHANGED
@@ -17,7 +17,7 @@ const result = await new Stophy().web.search({ query: "bun runtime" });
17
17
  console.log(result.data.results);
18
18
  ```
19
19
 
20
- Web search, YouTube search, and YouTube transcripts work without a key, with a small free allowance. Every other method throws a `StophyError` with the code `unauthorized`.
20
+ Web search, YouTube search, and transcripts work without a key, with a small free allowance. Every other method throws a `StophyError` with the code `unauthorized`.
21
21
 
22
22
  ## Use an API key
23
23
 
@@ -32,42 +32,38 @@ console.log(videos.data.results);
32
32
 
33
33
  `new Stophy("st_...")` works too.
34
34
 
35
- Methods follow the source and the command: `stophy.maps.search(...)`, `stophy.reddit.subreddit(...)`, `stophy.youtube.comments.replies(...)`. Each result has `data`, `creditsUsed`, and `requestId`.
35
+ Methods follow the source and the command: `stophy.maps.search(...)`, `stophy.reddit.subreddit(...)`, `stophy.ads.search({ network: "meta", ... })`. Endpoints with a single name are methods on the client: `stophy.transcript(...)`, `stophy.suggest(...)`.
36
+
37
+ Every response is `{ success, data, creditsUsed, requestId }`. `data` is one flat object. Lists are in `data.results`.
36
38
 
37
39
  ## More sources
38
40
 
39
- A YouTube transcript, Reddit posts, Google Maps reviews and an Amazon product:
41
+ A transcript, Reddit posts, Google Maps reviews, an Amazon product and Meta ads:
40
42
 
41
43
  ```ts
42
44
  const stophy = new Stophy({ apiKey: "st_..." });
43
45
 
44
- const transcript = await stophy.youtube.transcript({ video: "dQw4w9WgXcQ", includeTimestamps: true });
46
+ const transcript = await stophy.transcript({ video: "https://youtu.be/dQw4w9WgXcQ", includeTimestamps: true });
45
47
  console.log(transcript.data.text, transcript.data.segments);
46
48
 
47
49
  const posts = await stophy.reddit.search({ query: "bun runtime", sort: "top", within: "month" });
48
50
  console.log(posts.data.results);
49
51
 
50
- const places = await stophy.maps.search({ query: "coffee", near: "Austin, TX", limit: 5 });
51
- const placeId = places.data.places[0]?.id;
52
+ const places = await stophy.maps.search({ query: "coffee", location: "Austin, TX", limit: 5 });
53
+ const placeId = places.data.results[0]?.placeId;
52
54
  if (placeId) {
53
55
  const reviews = await stophy.maps.reviews({ place: placeId, limit: 20 });
54
- console.log(reviews.data.reviews);
56
+ console.log(reviews.data.results);
55
57
  }
56
58
 
57
59
  const product = await stophy.amazon.product({ product: "B08N5WRWNW", country: "us" });
58
- console.log(product.data.product.title, product.data.product.price);
59
- ```
60
+ console.log(product.data.title, product.data.price);
60
61
 
61
- ## Get markdown for a model
62
-
63
- ```ts
64
- const markdown = await stophy.youtube.search(
65
- { query: "bun runtime", limit: 5 },
66
- { format: "markdown" },
67
- );
62
+ const ads = await stophy.ads.search({ network: "meta", query: "running shoes" });
63
+ console.log(ads.data.results);
68
64
  ```
69
65
 
70
- With `format: "markdown"`, the method returns a string.
66
+ Some endpoints cover several sources. Pick one with a field: `network` for `ads.*`, `source` for `suggest`, `by` for `google.trends`. The types follow the choice.
71
67
 
72
68
  ## Get the next page
73
69
 
package/dist/index.cjs CHANGED
@@ -106,29 +106,18 @@ function isRecord(value) {
106
106
 
107
107
  // src/bind.ts
108
108
  function post(path, call) {
109
- function run(body, options) {
110
- return call({ method: "POST", path, body, options });
111
- }
112
- return run;
109
+ return (body, options) => call({ method: "POST", path, body, options });
113
110
  }
114
111
  function postOptional(path, call) {
115
- function run(body, options) {
116
- if (isMarkdownOptions(body) && options === void 0) {
117
- return call({ method: "POST", path, body: {}, options: body });
118
- }
119
- return call({ method: "POST", path, body: body ?? {}, options });
120
- }
121
- return run;
112
+ return (body, options) => call({
113
+ method: "POST",
114
+ path,
115
+ body: body ?? {},
116
+ options
117
+ });
122
118
  }
123
119
  function get(path, call) {
124
- function run(options) {
125
- return call({ method: "GET", path, options });
126
- }
127
- return run;
128
- }
129
- function isMarkdownOptions(value) {
130
- if (typeof value !== "object" || value === null) return false;
131
- return "format" in value && value.format === "markdown";
120
+ return (options) => call({ method: "GET", path, options });
132
121
  }
133
122
 
134
123
  // src/generated/surface.gen.ts
@@ -137,26 +126,19 @@ function bindSurface(call) {
137
126
  endpoints: get("/v1/endpoints", call),
138
127
  web: {
139
128
  search: post("/v1/web/search", call),
140
- news: postOptional("/v1/web/news", call),
141
- contacts: post("/v1/web/contacts", call)
129
+ news: postOptional("/v1/web/news", call)
142
130
  },
143
131
  youtube: {
144
132
  search: post("/v1/youtube/search", call),
145
133
  video: post("/v1/youtube/video", call),
146
- transcript: post("/v1/youtube/transcript", call),
147
- comments: Object.assign(post("/v1/youtube/comments", call), {
148
- replies: post("/v1/youtube/comments/replies", call)
149
- }),
134
+ comments: post("/v1/youtube/comments", call),
150
135
  channel: post("/v1/youtube/channel", call),
151
- playlist: post("/v1/youtube/playlist", call),
152
- suggest: post("/v1/youtube/suggest", call)
136
+ playlist: post("/v1/youtube/playlist", call)
153
137
  },
138
+ transcript: post("/v1/transcript", call),
154
139
  reddit: {
155
140
  search: post("/v1/reddit/search", call),
156
141
  post: post("/v1/reddit/post", call),
157
- comments: {
158
- more: post("/v1/reddit/comments/more", call)
159
- },
160
142
  subreddit: post("/v1/reddit/subreddit", call),
161
143
  user: post("/v1/reddit/user", call),
162
144
  domain: post("/v1/reddit/domain", call)
@@ -168,59 +150,34 @@ function bindSurface(call) {
168
150
  },
169
151
  instagram: {
170
152
  profile: post("/v1/instagram/profile", call),
171
- posts: post("/v1/instagram/posts", call),
172
153
  post: post("/v1/instagram/post", call),
173
- url: post("/v1/instagram/url", call),
174
154
  search: post("/v1/instagram/search", call),
175
- transcript: post("/v1/instagram/transcript", call),
176
- comments: Object.assign(post("/v1/instagram/comments", call), {
177
- replies: post("/v1/instagram/comments/replies", call)
178
- })
155
+ comments: post("/v1/instagram/comments", call)
179
156
  },
180
157
  tiktok: {
181
158
  profile: post("/v1/tiktok/profile", call),
182
159
  video: post("/v1/tiktok/video", call),
183
- url: post("/v1/tiktok/url", call),
184
- transcript: post("/v1/tiktok/transcript", call),
185
- posts: post("/v1/tiktok/posts", call),
186
160
  hashtag: post("/v1/tiktok/hashtag", call),
187
- comments: Object.assign(post("/v1/tiktok/comments", call), {
188
- replies: post("/v1/tiktok/comments/replies", call)
189
- }),
190
- search: post("/v1/tiktok/search", call),
191
- ads: {
192
- search: postOptional("/v1/tiktok/ads/search", call),
193
- ad: post("/v1/tiktok/ads/ad", call)
194
- }
161
+ comments: post("/v1/tiktok/comments", call),
162
+ search: post("/v1/tiktok/search", call)
195
163
  },
196
164
  bluesky: {
197
165
  profile: post("/v1/bluesky/profile", call),
198
- posts: post("/v1/bluesky/posts", call),
199
166
  post: post("/v1/bluesky/post", call),
200
167
  followers: post("/v1/bluesky/followers", call)
201
168
  },
202
- mastodon: {
203
- profile: post("/v1/mastodon/profile", call),
204
- posts: post("/v1/mastodon/posts", call),
205
- post: post("/v1/mastodon/post", call),
206
- hashtag: post("/v1/mastodon/hashtag", call)
207
- },
208
169
  threads: {
209
170
  profile: post("/v1/threads/profile", call),
210
- posts: post("/v1/threads/posts", call),
211
171
  post: post("/v1/threads/post", call),
212
172
  search: post("/v1/threads/search", call)
213
173
  },
214
174
  telegram: {
215
- channel: post("/v1/telegram/channel", call),
216
175
  posts: post("/v1/telegram/posts", call),
217
176
  post: post("/v1/telegram/post", call)
218
177
  },
219
178
  meta: {
220
179
  ads: {
221
- search: post("/v1/meta/ads/search", call),
222
- page: post("/v1/meta/ads/page", call),
223
- ad: post("/v1/meta/ads/ad", call)
180
+ page: post("/v1/meta/ads/page", call)
224
181
  }
225
182
  },
226
183
  linkedin: {
@@ -228,82 +185,40 @@ function bindSurface(call) {
228
185
  search: postOptional("/v1/linkedin/jobs/search", call),
229
186
  job: post("/v1/linkedin/jobs/job", call)
230
187
  },
231
- ads: {
232
- search: postOptional("/v1/linkedin/ads/search", call),
233
- ad: post("/v1/linkedin/ads/ad", call)
234
- },
235
- company: Object.assign(post("/v1/linkedin/company", call), {
236
- posts: post("/v1/linkedin/company/posts", call)
237
- }),
188
+ company: post("/v1/linkedin/company", call),
238
189
  profile: post("/v1/linkedin/profile", call),
239
190
  posts: postOptional("/v1/linkedin/posts", call)
240
191
  },
241
192
  zillow: {
242
- search: postOptional("/v1/zillow/search", call),
193
+ search: post("/v1/zillow/search", call),
243
194
  property: post("/v1/zillow/property", call)
244
195
  },
245
- google: {
246
- ads: {
247
- advertisers: post("/v1/google/ads/advertisers", call),
248
- search: postOptional("/v1/google/ads/search", call),
249
- ad: post("/v1/google/ads/ad", call)
250
- },
251
- suggest: post("/v1/google/suggest", call),
252
- trends: {
253
- interest: post("/v1/google/trends/interest", call),
254
- regions: post("/v1/google/trends/regions", call),
255
- related: post("/v1/google/trends/related", call),
256
- trending: postOptional("/v1/google/trends/trending", call)
257
- }
258
- },
259
196
  upwork: {
260
197
  search: postOptional("/v1/upwork/search", call),
261
198
  job: post("/v1/upwork/job", call)
262
199
  },
263
- amazon: {
264
- suggest: post("/v1/amazon/suggest", call),
265
- search: postOptional("/v1/amazon/search", call),
266
- product: post("/v1/amazon/product", call),
267
- bestsellers: post("/v1/amazon/bestsellers", call)
200
+ google: {
201
+ trends: Object.assign(post("/v1/google/trends", call), {
202
+ related: post("/v1/google/trends/related", call),
203
+ trending: postOptional("/v1/google/trends/trending", call)
204
+ })
268
205
  },
269
206
  site: {
270
- map: post("/v1/site/map", call),
271
207
  seo: post("/v1/site/seo", call)
272
208
  },
273
- domain: {
274
- whois: post("/v1/domain/whois", call),
275
- dns: post("/v1/domain/dns", call),
276
- tech: post("/v1/domain/tech", call)
277
- },
278
209
  email: {
279
- check: post("/v1/email/check", call)
210
+ verify: post("/v1/email/verify", call),
211
+ find: post("/v1/email/find", call)
280
212
  },
281
213
  crypto: {
282
214
  coins: postOptional("/v1/crypto/coins", call),
283
215
  coin: post("/v1/crypto/coin", call),
284
216
  history: post("/v1/crypto/history", call),
285
- trending: postOptional("/v1/crypto/trending", call),
286
- categories: postOptional("/v1/crypto/categories", call),
287
- movers: postOptional("/v1/crypto/movers", call),
288
- new: postOptional("/v1/crypto/new", call),
289
217
  dex: {
290
218
  search: post("/v1/crypto/dex/search", call),
291
- pairs: post("/v1/crypto/dex/pairs", call),
292
- token: post("/v1/crypto/dex/token", call),
293
- new: postOptional("/v1/crypto/dex/new", call)
294
- },
295
- pump: {
296
- coins: postOptional("/v1/crypto/pump/coins", call),
297
- coin: post("/v1/crypto/pump/coin", call),
298
- trades: post("/v1/crypto/pump/trades", call)
219
+ token: post("/v1/crypto/dex/token", call)
299
220
  },
300
- wallet: post("/v1/crypto/wallet", call),
301
- token: {
302
- holders: post("/v1/crypto/token/holders", call)
303
- },
304
- binance: {
305
- announcements: postOptional("/v1/crypto/binance/announcements", call)
306
- }
221
+ wallet: post("/v1/crypto/wallet", call)
307
222
  },
308
223
  indeed: {
309
224
  search: postOptional("/v1/indeed/search", call),
@@ -317,6 +232,11 @@ function bindSurface(call) {
317
232
  googletravel: {
318
233
  flights: post("/v1/googletravel/flights", call)
319
234
  },
235
+ amazon: {
236
+ search: postOptional("/v1/amazon/search", call),
237
+ product: post("/v1/amazon/product", call),
238
+ bestsellers: post("/v1/amazon/bestsellers", call)
239
+ },
320
240
  shopify: {
321
241
  products: post("/v1/shopify/products", call),
322
242
  collections: post("/v1/shopify/collections", call),
@@ -347,14 +267,6 @@ function bindSurface(call) {
347
267
  calendar: post("/v1/airbnb/calendar", call),
348
268
  reviews: post("/v1/airbnb/reviews", call)
349
269
  },
350
- redfin: {
351
- search: post("/v1/redfin/search", call),
352
- property: post("/v1/redfin/property", call)
353
- },
354
- realtor: {
355
- search: post("/v1/realtor/search", call),
356
- property: post("/v1/realtor/property", call)
357
- },
358
270
  rightmove: {
359
271
  search: post("/v1/rightmove/search", call),
360
272
  property: post("/v1/rightmove/property", call)
@@ -367,54 +279,28 @@ function bindSurface(call) {
367
279
  search: post("/v1/pinterest/search", call),
368
280
  pin: post("/v1/pinterest/pin", call),
369
281
  board: post("/v1/pinterest/board", call),
370
- user: post("/v1/pinterest/user", call),
371
- ads: {
372
- search: post("/v1/pinterest/ads/search", call),
373
- ad: post("/v1/pinterest/ads/ad", call)
374
- }
282
+ user: post("/v1/pinterest/user", call)
375
283
  },
376
284
  x: {
377
- tweet: post("/v1/x/tweet", call)
378
- },
379
- kick: {
380
- channel: post("/v1/kick/channel", call),
381
- videos: post("/v1/kick/videos", call),
382
- clips: post("/v1/kick/clips", call)
285
+ post: post("/v1/x/post", call)
383
286
  },
384
287
  finance: {
385
288
  quote: post("/v1/finance/quote", call),
386
289
  history: post("/v1/finance/history", call),
387
290
  search: post("/v1/finance/search", call),
388
- profile: post("/v1/finance/profile", call)
291
+ stock: post("/v1/finance/stock", call)
389
292
  },
390
- microsoft: {
391
- ads: {
392
- search: postOptional("/v1/microsoft/ads/search", call),
393
- ad: post("/v1/microsoft/ads/ad", call),
394
- advertisers: post("/v1/microsoft/ads/advertisers", call)
395
- }
396
- },
397
- snapchat: {
398
- profile: post("/v1/snapchat/profile", call),
399
- ads: {
400
- search: post("/v1/snapchat/ads/search", call),
401
- ad: post("/v1/snapchat/ads/ad", call)
402
- }
403
- },
404
- tumblr: {
405
- blog: post("/v1/tumblr/blog", call),
406
- posts: post("/v1/tumblr/posts", call),
407
- post: post("/v1/tumblr/post", call),
408
- search: post("/v1/tumblr/search", call)
293
+ ads: {
294
+ search: post("/v1/ads/search", call),
295
+ ad: post("/v1/ads/ad", call),
296
+ advertisers: post("/v1/ads/advertisers", call)
409
297
  },
410
- quora: {
411
- question: post("/v1/quora/question", call)
412
- }
298
+ suggest: post("/v1/suggest", call)
413
299
  };
414
300
  }
415
301
 
416
302
  // package.json
417
- var version = "1.0.1";
303
+ var version = "1.0.3";
418
304
 
419
305
  // src/transport.ts
420
306
  var DEFAULT_BASE_URL = "https://api.stophy.dev";
@@ -431,7 +317,6 @@ function createCaller(options) {
431
317
  timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS
432
318
  };
433
319
  return async (spec) => {
434
- const markdown = spec.options?.format === "markdown";
435
320
  const headers = new Headers(options.headers);
436
321
  if (typeof document === "undefined" && !headers.has("user-agent")) {
437
322
  headers.set("user-agent", USER_AGENT);
@@ -439,7 +324,7 @@ function createCaller(options) {
439
324
  if (options.apiKey) {
440
325
  headers.set("authorization", `Bearer ${options.apiKey}`);
441
326
  }
442
- headers.set("accept", markdown ? "text/markdown" : "application/json");
327
+ headers.set("accept", "application/json");
443
328
  if (spec.body !== void 0)
444
329
  headers.set("content-type", "application/json");
445
330
  const url = withQuery(`${baseUrl}${spec.path}`, spec.query);
@@ -452,13 +337,12 @@ function createCaller(options) {
452
337
  body: spec.body === void 0 ? void 0 : JSON.stringify(spec.body),
453
338
  signal
454
339
  }),
455
- markdown,
456
340
  spec.options?.signal,
457
341
  retry
458
342
  );
459
343
  };
460
344
  }
461
- async function send(baseFetch, url, init, markdown, signal, retry) {
345
+ async function send(baseFetch, url, init, signal, retry) {
462
346
  for (let n = 0; ; n += 1) {
463
347
  const deadline = withDeadline(signal, retry.timeoutMs);
464
348
  let waitMs;
@@ -479,7 +363,7 @@ async function send(baseFetch, url, init, markdown, signal, retry) {
479
363
  }
480
364
  waitMs = seconds === void 0 ? backoffMs(n, retry.initialDelayMs) : seconds * 1e3;
481
365
  } else {
482
- return await readBody(response, markdown);
366
+ return await readBody(response);
483
367
  }
484
368
  } finally {
485
369
  deadline.clear();
@@ -509,10 +393,9 @@ function withDeadline(signal, timeoutMs) {
509
393
  }
510
394
  };
511
395
  }
512
- async function readBody(response, markdown) {
396
+ async function readBody(response) {
513
397
  if (!response.ok) throw await errorFrom(response);
514
398
  const text = await response.text();
515
- if (markdown) return text;
516
399
  if (!text) {
517
400
  throw failed(response, "Stophy returned an empty response", {});
518
401
  }