stophy 1.0.1 → 1.0.2

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
@@ -143,20 +132,14 @@ function bindSurface(call) {
143
132
  youtube: {
144
133
  search: post("/v1/youtube/search", call),
145
134
  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
- }),
135
+ comments: post("/v1/youtube/comments", call),
150
136
  channel: post("/v1/youtube/channel", call),
151
- playlist: post("/v1/youtube/playlist", call),
152
- suggest: post("/v1/youtube/suggest", call)
137
+ playlist: post("/v1/youtube/playlist", call)
153
138
  },
139
+ transcript: post("/v1/transcript", call),
154
140
  reddit: {
155
141
  search: post("/v1/reddit/search", call),
156
142
  post: post("/v1/reddit/post", call),
157
- comments: {
158
- more: post("/v1/reddit/comments/more", call)
159
- },
160
143
  subreddit: post("/v1/reddit/subreddit", call),
161
144
  user: post("/v1/reddit/user", call),
162
145
  domain: post("/v1/reddit/domain", call)
@@ -168,59 +151,34 @@ function bindSurface(call) {
168
151
  },
169
152
  instagram: {
170
153
  profile: post("/v1/instagram/profile", call),
171
- posts: post("/v1/instagram/posts", call),
172
154
  post: post("/v1/instagram/post", call),
173
- url: post("/v1/instagram/url", call),
174
155
  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
- })
156
+ comments: post("/v1/instagram/comments", call)
179
157
  },
180
158
  tiktok: {
181
159
  profile: post("/v1/tiktok/profile", call),
182
160
  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
161
  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
- }
162
+ comments: post("/v1/tiktok/comments", call),
163
+ search: post("/v1/tiktok/search", call)
195
164
  },
196
165
  bluesky: {
197
166
  profile: post("/v1/bluesky/profile", call),
198
- posts: post("/v1/bluesky/posts", call),
199
167
  post: post("/v1/bluesky/post", call),
200
168
  followers: post("/v1/bluesky/followers", call)
201
169
  },
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
170
  threads: {
209
171
  profile: post("/v1/threads/profile", call),
210
- posts: post("/v1/threads/posts", call),
211
172
  post: post("/v1/threads/post", call),
212
173
  search: post("/v1/threads/search", call)
213
174
  },
214
175
  telegram: {
215
- channel: post("/v1/telegram/channel", call),
216
176
  posts: post("/v1/telegram/posts", call),
217
177
  post: post("/v1/telegram/post", call)
218
178
  },
219
179
  meta: {
220
180
  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)
181
+ page: post("/v1/meta/ads/page", call)
224
182
  }
225
183
  },
226
184
  linkedin: {
@@ -228,82 +186,40 @@ function bindSurface(call) {
228
186
  search: postOptional("/v1/linkedin/jobs/search", call),
229
187
  job: post("/v1/linkedin/jobs/job", call)
230
188
  },
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
- }),
189
+ company: post("/v1/linkedin/company", call),
238
190
  profile: post("/v1/linkedin/profile", call),
239
191
  posts: postOptional("/v1/linkedin/posts", call)
240
192
  },
241
193
  zillow: {
242
- search: postOptional("/v1/zillow/search", call),
194
+ search: post("/v1/zillow/search", call),
243
195
  property: post("/v1/zillow/property", call)
244
196
  },
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
197
  upwork: {
260
198
  search: postOptional("/v1/upwork/search", call),
261
199
  job: post("/v1/upwork/job", call)
262
200
  },
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)
201
+ google: {
202
+ trends: Object.assign(post("/v1/google/trends", call), {
203
+ related: post("/v1/google/trends/related", call),
204
+ trending: postOptional("/v1/google/trends/trending", call)
205
+ })
268
206
  },
269
207
  site: {
270
- map: post("/v1/site/map", call),
271
208
  seo: post("/v1/site/seo", call)
272
209
  },
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
210
  email: {
279
- check: post("/v1/email/check", call)
211
+ check: post("/v1/email/check", call),
212
+ find: post("/v1/email/find", call)
280
213
  },
281
214
  crypto: {
282
215
  coins: postOptional("/v1/crypto/coins", call),
283
216
  coin: post("/v1/crypto/coin", call),
284
217
  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
218
  dex: {
290
219
  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)
220
+ token: post("/v1/crypto/dex/token", call)
299
221
  },
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
- }
222
+ wallet: post("/v1/crypto/wallet", call)
307
223
  },
308
224
  indeed: {
309
225
  search: postOptional("/v1/indeed/search", call),
@@ -317,6 +233,11 @@ function bindSurface(call) {
317
233
  googletravel: {
318
234
  flights: post("/v1/googletravel/flights", call)
319
235
  },
236
+ amazon: {
237
+ search: postOptional("/v1/amazon/search", call),
238
+ product: post("/v1/amazon/product", call),
239
+ bestsellers: post("/v1/amazon/bestsellers", call)
240
+ },
320
241
  shopify: {
321
242
  products: post("/v1/shopify/products", call),
322
243
  collections: post("/v1/shopify/collections", call),
@@ -347,14 +268,6 @@ function bindSurface(call) {
347
268
  calendar: post("/v1/airbnb/calendar", call),
348
269
  reviews: post("/v1/airbnb/reviews", call)
349
270
  },
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
271
  rightmove: {
359
272
  search: post("/v1/rightmove/search", call),
360
273
  property: post("/v1/rightmove/property", call)
@@ -367,54 +280,28 @@ function bindSurface(call) {
367
280
  search: post("/v1/pinterest/search", call),
368
281
  pin: post("/v1/pinterest/pin", call),
369
282
  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
- }
283
+ user: post("/v1/pinterest/user", call)
375
284
  },
376
285
  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)
286
+ post: post("/v1/x/post", call)
383
287
  },
384
288
  finance: {
385
289
  quote: post("/v1/finance/quote", call),
386
290
  history: post("/v1/finance/history", call),
387
291
  search: post("/v1/finance/search", call),
388
- profile: post("/v1/finance/profile", call)
292
+ stock: post("/v1/finance/stock", call)
389
293
  },
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)
294
+ ads: {
295
+ search: post("/v1/ads/search", call),
296
+ ad: post("/v1/ads/ad", call),
297
+ advertisers: post("/v1/ads/advertisers", call)
409
298
  },
410
- quora: {
411
- question: post("/v1/quora/question", call)
412
- }
299
+ suggest: post("/v1/suggest", call)
413
300
  };
414
301
  }
415
302
 
416
303
  // package.json
417
- var version = "1.0.1";
304
+ var version = "1.0.2";
418
305
 
419
306
  // src/transport.ts
420
307
  var DEFAULT_BASE_URL = "https://api.stophy.dev";
@@ -431,7 +318,6 @@ function createCaller(options) {
431
318
  timeoutMs: options.timeoutMs ?? DEFAULT_TIMEOUT_MS
432
319
  };
433
320
  return async (spec) => {
434
- const markdown = spec.options?.format === "markdown";
435
321
  const headers = new Headers(options.headers);
436
322
  if (typeof document === "undefined" && !headers.has("user-agent")) {
437
323
  headers.set("user-agent", USER_AGENT);
@@ -439,7 +325,7 @@ function createCaller(options) {
439
325
  if (options.apiKey) {
440
326
  headers.set("authorization", `Bearer ${options.apiKey}`);
441
327
  }
442
- headers.set("accept", markdown ? "text/markdown" : "application/json");
328
+ headers.set("accept", "application/json");
443
329
  if (spec.body !== void 0)
444
330
  headers.set("content-type", "application/json");
445
331
  const url = withQuery(`${baseUrl}${spec.path}`, spec.query);
@@ -452,13 +338,12 @@ function createCaller(options) {
452
338
  body: spec.body === void 0 ? void 0 : JSON.stringify(spec.body),
453
339
  signal
454
340
  }),
455
- markdown,
456
341
  spec.options?.signal,
457
342
  retry
458
343
  );
459
344
  };
460
345
  }
461
- async function send(baseFetch, url, init, markdown, signal, retry) {
346
+ async function send(baseFetch, url, init, signal, retry) {
462
347
  for (let n = 0; ; n += 1) {
463
348
  const deadline = withDeadline(signal, retry.timeoutMs);
464
349
  let waitMs;
@@ -479,7 +364,7 @@ async function send(baseFetch, url, init, markdown, signal, retry) {
479
364
  }
480
365
  waitMs = seconds === void 0 ? backoffMs(n, retry.initialDelayMs) : seconds * 1e3;
481
366
  } else {
482
- return await readBody(response, markdown);
367
+ return await readBody(response);
483
368
  }
484
369
  } finally {
485
370
  deadline.clear();
@@ -509,10 +394,9 @@ function withDeadline(signal, timeoutMs) {
509
394
  }
510
395
  };
511
396
  }
512
- async function readBody(response, markdown) {
397
+ async function readBody(response) {
513
398
  if (!response.ok) throw await errorFrom(response);
514
399
  const text = await response.text();
515
- if (markdown) return text;
516
400
  if (!text) {
517
401
  throw failed(response, "Stophy returned an empty response", {});
518
402
  }