serpkite 0.5.0 → 0.6.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 CHANGED
@@ -87,7 +87,7 @@ vertical-specific extras and `meta` (`request_id`, `credits_used`, `cached`, `la
87
87
  | `news(params)` | `POST /v1/news` | `SearchParams` | `NewsResponse` |
88
88
  | `maps(params)` | `POST /v1/maps` | `SearchParams` (+ `ll`: `"@lat,lng,14z"`) | `PlacesResponse` |
89
89
  | `places(params)` | `POST /v1/places` | `SearchParams` | `PlacesResponse` |
90
- | `place(params)` | `POST /v1/place` | `PlaceParams` (`place_id` \| `cid` \| `fid`, `country`, `language`) | `PlacesResponse` (one place: `weekly_hours`, `photos`, `timezone`, …; empty when the id is unknown) |
90
+ | `place(params)` | `POST /v1/place` | `PlaceParams` (`place_id` \| `cid` \| `fid` \| `oid` (Yandex Maps), `country`, `language`) | `PlacesResponse` (one place: `weekly_hours`, `photos`, `timezone`, …; empty when the id is unknown) |
91
91
  | `reviews(params)` | `POST /v1/reviews` | `ReviewsParams` (`place_id` \| `cid` \| `fid`, `sort`, `page_token`, `num` ≤ 50) | `ReviewsResponse` (+ `next_page_token`) |
92
92
  | `shopping(params)` | `POST /v1/shopping` | `SearchParams` | `ShoppingResponse` |
93
93
  | `scholar(params)` | `POST /v1/scholar` | `SearchParams` | `ScholarResponse` |
package/dist/index.cjs CHANGED
@@ -50,7 +50,7 @@ function errorFromResponse(status, headers, body) {
50
50
  }
51
51
 
52
52
  // src/client.ts
53
- var VERSION = "0.5.0";
53
+ var VERSION = "0.6.0";
54
54
  var DEFAULT_BASE_URL = "https://api.serpkite.com";
55
55
  var TASK_DONE = /* @__PURE__ */ new Set(["completed", "failed", "canceled"]);
56
56
  var SerpKite = class {
@@ -98,12 +98,16 @@ var SerpKite = class {
98
98
  videos = this.#vertical("/v1/videos");
99
99
  /** Google News. */
100
100
  news = this.#vertical("/v1/news");
101
- /** Google Maps search (places with coordinates). Accepts `ll` ("@lat,lng,14z"). */
101
+ /**
102
+ * Google Maps search (places with coordinates). Accepts `ll` ("@lat,lng,14z"). With
103
+ * `engine: "yandex"` (where enabled) the places come from Yandex Maps and carry an `oid`.
104
+ */
102
105
  maps = this.#vertical("/v1/maps");
103
106
  /** Google local results. */
104
107
  places = this.#vertical("/v1/places");
105
108
  /**
106
- * Details of one place by `place_id`, `cid` or `fid`: address, country, time zone, hours
109
+ * Details of one place by `place_id`, `cid` or `fid`, or by a Yandex Maps `oid` (implies
110
+ * `engine: "yandex"`): address, country, time zone, hours
107
111
  * (`opening_hours` text and structured `weekly_hours`), phones, description and photos.
108
112
  * `results` holds the place, or is empty (not charged) when no place has that id. 1 credit.
109
113
  */
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/util.ts","../src/webhooks.ts"],"names":[],"mappings":";;;AAKO,IAAM,aAAA,GAAN,cAA4B,KAAA,CAAM;AAAA;AAAA,EAE9B,MAAA;AAAA;AAAA,EAEA,IAAA;AAAA;AAAA,EAEA,SAAA;AAAA;AAAA,EAEA,OAAA;AAAA,EAET,YACE,MAAA,EACA,IAAA,EACA,OAAA,EACA,SAAA,EACA,SACA,OAAA,EACA;AACA,IAAA,KAAA,CAAM,SAAS,OAAO,CAAA;AACtB,IAAA,IAAA,CAAK,IAAA,GAAO,eAAA;AACZ,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,YAAY,SAAA,IAAa,MAAA;AAC9B,IAAA,IAAA,CAAK,OAAA,GAAU,OAAA;AAAA,EACjB;AACF;AAEA,IAAM,aAAA,GAAwC;AAAA,EAC5C,GAAA,EAAK,iBAAA;AAAA,EACL,GAAA,EAAK,cAAA;AAAA,EACL,GAAA,EAAK,sBAAA;AAAA,EACL,GAAA,EAAK,WAAA;AAAA,EACL,GAAA,EAAK,WAAA;AAAA,EACL,GAAA,EAAK,cAAA;AAAA;AAAA;AAAA,EAGL,GAAA,EAAK,gBAAA;AAAA,EACL,GAAA,EAAK,aAAA;AAAA,EACL,GAAA,EAAK;AACP,CAAA;AAGO,SAAS,iBAAA,CAAkB,MAAA,EAAgB,OAAA,EAAkB,IAAA,EAA6B;AAC/F,EAAA,IAAI,OAAO,aAAA,CAAc,MAAM,CAAA,KAAM,MAAA,IAAU,MAAM,cAAA,GAAiB,YAAA,CAAA;AACtE,EAAA,IAAI,OAAA,GAAU,KAAK,IAAA,EAAK,CAAE,MAAM,CAAA,EAAG,GAAG,CAAA,IAAK,CAAA,KAAA,EAAQ,MAAM,CAAA,CAAA;AACzD,EAAA,IAAI,SAAA,GAAY,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA,IAAK,MAAA;AAC/C,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,IAAA,CAAK,KAAA,CAAM,IAAI,CAAA;AAG9B,IAAA,MAAM,IAAI,MAAA,EAAQ,KAAA;AAClB,IAAA,IAAI,CAAA,IAAK,OAAO,CAAA,KAAM,QAAA,EAAU;AAC9B,MAAA,IAAI,OAAO,CAAA,CAAE,IAAA,KAAS,YAAY,CAAA,CAAE,IAAA,SAAa,CAAA,CAAE,IAAA;AACnD,MAAA,IAAI,OAAO,CAAA,CAAE,OAAA,KAAY,YAAY,CAAA,CAAE,OAAA,YAAmB,CAAA,CAAE,OAAA;AAC5D,MAAA,IAAI,OAAO,CAAA,CAAE,UAAA,KAAe,YAAY,CAAA,CAAE,UAAA,cAAwB,CAAA,CAAE,UAAA;AAAA,IACtE;AAAA,EACF,CAAA,CAAA,MAAQ;AAAA,EAER;AACA,EAAA,OAAO,IAAI,aAAA,CAAc,MAAA,EAAQ,IAAA,EAAM,OAAA,EAAS,WAAW,OAAO,CAAA;AACpE;;;ACvBO,IAAM,OAAA,GAAU;AAChB,IAAM,gBAAA,GAAmB;AA6EhC,IAAM,4BAAY,IAAI,GAAA,CAAI,CAAC,WAAA,EAAa,QAAA,EAAU,UAAU,CAAC,CAAA;AAWtD,IAAM,WAAN,MAAe;AAAA,EACX,OAAA;AAAA,EACA,SAAA;AAAA,EACA,UAAA;AAAA,EACA,YAAA;AAAA,EACA,OAAA;AAAA,EACA,MAAA;AAAA,EACA,QAAA;AAAA,EAET,WAAA,CAAY,OAAA,GAA2B,EAAC,EAAG;AACzC,IAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,MAAA,IAAU,GAAA,CAAI,kBAAkB,CAAA;AACvD,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,MAAM,IAAI,aAAA;AAAA,QACR,CAAA;AAAA,QACA,iBAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF;AACA,IAAA,IAAA,CAAK,OAAA,GAAU,MAAA;AACf,IAAA,IAAA,CAAK,WAAW,OAAA,CAAQ,OAAA,IAAW,GAAA,CAAI,mBAAmB,KAAK,gBAAA,EAAkB,OAAA;AAAA,MAC/E,MAAA;AAAA,MACA;AAAA,KACF;AACA,IAAA,IAAA,CAAK,SAAA,GAAY,QAAQ,SAAA,IAAa,GAAA;AACtC,IAAA,IAAA,CAAK,aAAa,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,OAAA,CAAQ,cAAc,CAAC,CAAA;AACrD,IAAA,IAAA,CAAK,YAAA,GAAe,QAAQ,YAAA,IAAgB,GAAA;AAC5C,IAAA,MAAM,CAAA,GAAI,OAAA,CAAQ,KAAA,IAAS,UAAA,CAAW,KAAA;AACtC,IAAA,IAAI,OAAO,MAAM,UAAA,EAAY;AAC3B,MAAA,MAAM,IAAI,aAAA;AAAA,QACR,CAAA;AAAA,QACA,eAAA;AAAA,QACA;AAAA,OACF;AAAA,IACF;AACA,IAAA,IAAA,CAAK,MAAA,GAAS,CAAA;AACd,IAAA,IAAA,CAAK,QAAA,GAAW,EAAE,GAAG,OAAA,CAAQ,OAAA,EAAQ;AAAA,EACvC;AAAA;AAAA;AAAA,EAKS,MAAA,GAAS,IAAA,CAAK,SAAA,CAAwC,YAAY,CAAA;AAAA;AAAA,EAElE,MAAA,GAAS,IAAA,CAAK,SAAA,CAAwC,YAAY,CAAA;AAAA;AAAA,EAElE,MAAA,GAAS,IAAA,CAAK,SAAA,CAAwC,YAAY,CAAA;AAAA;AAAA,EAElE,IAAA,GAAO,IAAA,CAAK,SAAA,CAAsC,UAAU,CAAA;AAAA;AAAA,EAE5D,IAAA,GAAO,IAAA,CAAK,SAAA,CAAwC,UAAU,CAAA;AAAA;AAAA,EAE9D,MAAA,GAAS,IAAA,CAAK,SAAA,CAAwC,YAAY,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMlE,KAAA,GAAQ,IAAA,CAAK,SAAA,CAAuC,WAAW,CAAA;AAAA;AAAA,EAE/D,OAAA,GAAU,IAAA,CAAK,SAAA,CAA0C,aAAa,CAAA;AAAA;AAAA,EAEtE,QAAA,GAAW,IAAA,CAAK,SAAA,CAA0C,cAAc,CAAA;AAAA;AAAA,EAExE,OAAA,GAAU,IAAA,CAAK,SAAA,CAAyC,aAAa,CAAA;AAAA;AAAA,EAErE,OAAA,GAAU,IAAA,CAAK,SAAA,CAAyC,aAAa,CAAA;AAAA;AAAA,EAErE,YAAA,GAAe,IAAA,CAAK,SAAA,CAA8C,kBAAkB,CAAA;AAAA;AAAA,EAEpF,OAAA,GAAU,IAAA,CAAK,SAAA,CAA0C,aAAa,CAAA;AAAA;AAAA,EAG/E,IAAA,CAAK,QAAoB,OAAA,EAAiD;AACxE,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,EAAE,MAAA,EAAQ,MAAA,EAAQ,MAAM,UAAA,EAAY,IAAA,EAAM,MAAA,EAAQ,OAAA,EAAS,CAAA;AAAA,EACjF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,OAAA,CAAQ,QAAuB,OAAA,EAAoD;AAGjF,IAAA,MAAM,IAAA,GAAA,CAAA,CAAS,MAAA,CAAO,OAAA,IAAW,EAAA,IAAM,EAAA,IAAM,GAAA;AAC7C,IAAA,OAAO,KAAK,OAAA,CAAQ;AAAA,MAClB,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,aAAA;AAAA,MACN,IAAA,EAAM,MAAA;AAAA,MACN,OAAA,EAAS;AAAA,QACP,GAAG,OAAA;AAAA,QACH,SAAA,EAAW,OAAA,EAAS,SAAA,KAAc,IAAA,CAAK,SAAA,GAAY,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,IAAA,CAAK,SAAA,EAAW,IAAI,CAAA,GAAI,CAAA;AAAA,OAC1F;AAAA,MACA,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,GAAA,CAAI,QAAmB,OAAA,EAAgD;AACrE,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,EAAE,MAAA,EAAQ,MAAA,EAAQ,MAAM,SAAA,EAAW,IAAA,EAAM,MAAA,EAAQ,OAAA,EAAS,CAAA;AAAA,EAChF;AAAA;AAAA,EAGA,QAAQ,OAAA,EAA4C;AAClD,IAAA,OAAO,IAAA,CAAK,QAAQ,EAAE,MAAA,EAAQ,OAAO,IAAA,EAAM,aAAA,EAAe,SAAS,CAAA;AAAA,EACrE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,KAAA,CAAM,QAAqB,OAAA,EAAgD;AACzE,IAAA,OAAO,KAAK,OAAA,CAAQ;AAAA,MAClB,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,WAAA;AAAA,MACN,IAAA,EAAM,MAAA;AAAA,MACN,OAAA;AAAA,MACA,KAAA,EAAO;AAAA,KACR,CAAA;AAAA,EACH;AAAA;AAAA,EAGA,QAAA,CAAS,IAAY,OAAA,EAA8C;AACjE,IAAA,OAAO,IAAA,CAAK,OAAA,CAAQ,EAAE,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAM,CAAA,UAAA,EAAa,kBAAA,CAAmB,EAAE,CAAC,CAAA,CAAA,EAAI,OAAA,EAAS,CAAA;AAAA,EAC7F;AAAA;AAAA,EAGA,WAAA,CAAY,IAAY,OAAA,EAAuD;AAC7E,IAAA,OAAO,KAAK,OAAA,CAAQ;AAAA,MAClB,MAAA,EAAQ,QAAA;AAAA,MACR,IAAA,EAAM,CAAA,UAAA,EAAa,kBAAA,CAAmB,EAAE,CAAC,CAAA,CAAA;AAAA,MACzC;AAAA,KACD,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,YAAA,CACJ,QAAA,EACA,OAAA,GAAuB,EAAC,EACJ;AACpB,IAAA,OAAO,IAAA,CAAK,SAAA,CAAU,MAAA,CAAO,QAAQ,GAAG,CAAC,EAAA,KAAO,IAAA,CAAK,QAAA,CAAS,IAAI,EAAE,MAAA,EAAQ,OAAA,CAAQ,MAAA,EAAQ,CAAA,EAAG;AAAA,MAC7F,GAAG,OAAA;AAAA,MACH,SAAA,EAAW,QAAQ,SAAA,IAAa;AAAA,KACjC,CAAA;AAAA,EACH;AAAA;AAAA,EAIS,QAAA,GAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAYlB,MAAA,EAAQ,CAAC,MAAA,EAA6B,OAAA,KACpC,KAAK,OAAA,CAAQ;AAAA,MACX,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,cAAA;AAAA,MACN,IAAA,EAAM,MAAA;AAAA,MACN,OAAA;AAAA,MACA,KAAA,EAAO;AAAA,KACR,CAAA;AAAA;AAAA,IAGH,IAAA,EAAM,CAAC,OAAA,KACL,IAAA,CAAK,OAAA,CAAQ,EAAE,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAM,cAAA,EAAgB,OAAA,EAAS,CAAA;AAAA,IAE/D,KAAK,CAAC,EAAA,EAAY,OAAA,KAChB,IAAA,CAAK,QAAQ,EAAE,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAM,gBAAgB,kBAAA,CAAmB,EAAE,CAAC,CAAA,CAAA,EAAI,SAAS,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IASzF,QAAQ,CAAC,EAAA,EAAY,MAAA,EAA6B,OAAA,KAChD,KAAK,OAAA,CAAQ;AAAA,MACX,MAAA,EAAQ,OAAA;AAAA,MACR,IAAA,EAAM,CAAA,aAAA,EAAgB,kBAAA,CAAmB,EAAE,CAAC,CAAA,CAAA;AAAA,MAC5C,IAAA,EAAM,MAAA;AAAA,MACN;AAAA,KACD,CAAA;AAAA,IAEH,MAAA,EAAQ,OAAO,EAAA,EAAY,OAAA,KAA4C;AACrE,MAAA,MAAM,KAAK,OAAA,CAAQ;AAAA,QACjB,MAAA,EAAQ,QAAA;AAAA,QACR,IAAA,EAAM,CAAA,aAAA,EAAgB,kBAAA,CAAmB,EAAE,CAAC,CAAA,CAAA;AAAA,QAC5C;AAAA,OACD,CAAA;AAAA,IACH,CAAA;AAAA;AAAA;AAAA,IAIA,GAAA,EAAK,CAAC,EAAA,EAAY,OAAA,KAChB,KAAK,OAAA,CAAQ;AAAA,MACX,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,CAAA,aAAA,EAAgB,kBAAA,CAAmB,EAAE,CAAC,CAAA,IAAA,CAAA;AAAA,MAC5C,OAAA;AAAA,MACA,KAAA,EAAO;AAAA,KACR,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOH,IAAA,EAAM,CACJ,EAAA,EACA,MAAA,GAA4B,EAAC,EAC7B,OAAA,KAEA,KAAK,OAAA,CAAQ;AAAA,MACX,MAAA,EAAQ,KAAA;AAAA,MACR,IAAA,EAAM,gBAAgB,kBAAA,CAAmB,EAAE,CAAC,CAAA,KAAA,EAAQ,KAAA,CAAM,MAAM,CAAC,CAAA,CAAA;AAAA,MACjE;AAAA,KACD,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAUH,QAAA,EAAU,CACR,EAAA,EACA,MAAA,GAA4B,EAAC,EAC7B,OAAA,KAC8B,IAAA,CAAK,SAAA,CAAU,EAAA,EAAI,MAAA,EAAQ,OAAO;AAAA,GACpE;AAAA;AAAA,EAIS,OAAA,GAAU;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAQjB,MAAA,EAAQ,CACN,MAAA,EACA,OAAA,GAA8B,EAAC,KACE;AACjC,MAAA,MAAM,EAAE,cAAA,EAAgB,GAAG,IAAA,EAAK,GAAI,OAAA;AACpC,MAAA,OAAO,KAAK,OAAA,CAAQ;AAAA,QAClB,MAAA,EAAQ,MAAA;AAAA,QACR,IAAA,EAAM,aAAA;AAAA,QACN,IAAA,EAAM,MAAA;AAAA,QACN,OAAA,EAAS,cAAA,GACL,EAAE,GAAG,IAAA,EAAM,OAAA,EAAS,EAAE,GAAG,IAAA,CAAK,OAAA,EAAS,iBAAA,EAAmB,cAAA,IAAiB,GAC3E,IAAA;AAAA,QACJ,KAAA,EAAO,iBAAiB,KAAA,GAAQ;AAAA,OACjC,CAAA;AAAA,IACH,CAAA;AAAA;AAAA,IAGA,KAAK,CAAC,EAAA,EAAY,OAAA,KAChB,IAAA,CAAK,QAAQ,EAAE,MAAA,EAAQ,KAAA,EAAO,IAAA,EAAM,eAAe,kBAAA,CAAmB,EAAE,CAAC,CAAA,CAAA,EAAI,SAAS,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAOxF,IAAA,EAAM,CAAC,SAAA,EAAkD,OAAA,GAAuB,EAAC,KAC/E,IAAA,CAAK,KAAA,CAAM,SAAA,EAAW,OAAO;AAAA,GACjC;AAAA;AAAA,EAIA,OAAO,SAAA,CACL,EAAA,EACA,MAAA,EACA,OAAA,EAC4B;AAC5B,IAAA,IAAI,SAAS,MAAA,CAAO,MAAA;AACpB,IAAA,WAAS;AACP,MAAA,MAAM,IAAA,GAAO,MAAM,IAAA,CAAK,QAAA,CAAS,IAAA,CAAK,EAAA,EAAI,EAAE,GAAG,MAAA,EAAQ,MAAA,EAAO,EAAG,OAAO,CAAA;AACxE,MAAA,OAAO,IAAA,CAAK,OAAA;AACZ,MAAA,IAAI,CAAC,IAAA,CAAK,WAAA,IAAe,IAAA,CAAK,OAAA,CAAQ,WAAW,CAAA,EAAG;AACpD,MAAA,MAAA,GAAS,IAAA,CAAK,WAAA;AAAA,IAChB;AAAA,EACF;AAAA,EAEA,MAAM,SAAA,CACJ,EAAA,EACA,GAAA,EACA,CAAA,EACY;AACZ,IAAA,MAAM,SAAA,GAAY,EAAE,SAAA,IAAa,GAAA;AACjC,IAAA,MAAM,WAAA,GAAc,EAAE,iBAAA,IAAqB,GAAA;AAC3C,IAAA,IAAI,QAAA,GAAW,EAAE,cAAA,IAAkB,GAAA;AACnC,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA;AAC9B,IAAA,WAAS;AACP,MAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,EAAE,CAAA;AACzB,MAAA,IAAI,SAAA,CAAU,GAAA,CAAI,IAAA,CAAK,MAAM,GAAG,OAAO,IAAA;AACvC,MAAA,MAAM,IAAA,GAAO,QAAA,GAAW,IAAA,CAAK,GAAA,EAAI;AACjC,MAAA,IAAI,QAAQ,CAAA,EAAG;AACb,QAAA,MAAM,IAAI,aAAA;AAAA,UACR,CAAA;AAAA,UACA,SAAA;AAAA,UACA,QAAQ,EAAE,CAAA,OAAA,EAAU,IAAA,CAAK,MAAM,UAAU,SAAS,CAAA,GAAA;AAAA,SACpD;AAAA,MACF;AACA,MAAA,MAAM,MAAM,IAAA,CAAK,GAAA,CAAI,UAAU,IAAI,CAAA,EAAG,EAAE,MAAM,CAAA;AAC9C,MAAA,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,QAAA,GAAW,GAAA,EAAK,WAAW,CAAA;AAAA,IACjD;AAAA,EACF;AAAA,EAEA,UAAgB,IAAA,EAAoC;AAClD,IAAA,QAAQ,CAAC,MAAA,EAAW,OAAA,KAClB,IAAA,CAAK,OAAA,CAAQ,EAAE,MAAA,EAAQ,MAAA,EAAQ,IAAA,EAAM,IAAA,EAAM,MAAA,EAAQ,OAAA,EAAS,CAAA;AAAA,EAChE;AAAA,EAEA,MAAM,KAAA,CAAM,SAAA,EAAkD,CAAA,EAAgC;AAC5F,IAAA,IAAI,EAAA;AACJ,IAAA,IAAI,OAAO,cAAc,QAAA,EAAU;AACjC,MAAA,EAAA,GAAK,SAAA;AAAA,IACP,WAAW,SAAA,IAAa,IAAA,IAAQ,aAAa,OAAO,SAAA,CAAU,OAAO,QAAA,EAAU;AAC7E,MAAA,EAAA,GAAK,SAAA,CAAU,EAAA;AAAA,IACjB,CAAA,MAAA,IAAW,aAAa,OAAA,IAAW,SAAA,IAAa,UAAU,KAAA,IAAS,EAAE,QAAQ,SAAA,CAAA,EAAY;AACvF,MAAA,MAAM,IAAI,SAAA,CAAU,KAAA;AACpB,MAAA,MAAM,IAAI,aAAA;AAAA,QACR,GAAA;AAAA,QACA,EAAE,IAAA,IAAQ,iBAAA;AAAA,QACV,EAAE,OAAA,IAAW,4BAAA;AAAA,QACb,CAAA,CAAE;AAAA,OACJ;AAAA,IACF;AACA,IAAA,IAAI,CAAC,EAAA,EAAI;AACP,MAAA,MAAM,IAAI,aAAA,CAAc,CAAA,EAAG,iBAAA,EAAmB,+BAA+B,CAAA;AAAA,IAC/E;AACA,IAAA,MAAM,SAAA,GAAY,EAAE,SAAA,IAAa,GAAA;AACjC,IAAA,MAAM,WAAA,GAAc,EAAE,iBAAA,IAAqB,GAAA;AAC3C,IAAA,IAAI,QAAA,GAAW,EAAE,cAAA,IAAkB,GAAA;AACnC,IAAA,MAAM,QAAA,GAAW,IAAA,CAAK,GAAA,EAAI,GAAI,SAAA;AAC9B,IAAA,WAAS;AACP,MAAA,MAAM,KAAA,GAAQ,MAAM,IAAA,CAAK,OAAA,CAAQ,GAAA,CAAI,IAAI,EAAE,MAAA,EAAQ,CAAA,CAAE,MAAA,EAAQ,CAAA;AAC7D,MAAA,IAAI,MAAM,MAAA,KAAW,MAAA,IAAU,KAAA,CAAM,MAAA,KAAW,UAAU,OAAO,KAAA;AACjE,MAAA,MAAM,IAAA,GAAO,QAAA,GAAW,IAAA,CAAK,GAAA,EAAI;AACjC,MAAA,IAAI,QAAQ,CAAA,EAAG;AACb,QAAA,MAAM,IAAI,aAAA;AAAA,UACR,CAAA;AAAA,UACA,SAAA;AAAA,UACA,SAAS,EAAE,CAAA,OAAA,EAAU,KAAA,CAAM,MAAM,UAAU,SAAS,CAAA,GAAA;AAAA,SACtD;AAAA,MACF;AACA,MAAA,MAAM,MAAM,IAAA,CAAK,GAAA,CAAI,UAAU,IAAI,CAAA,EAAG,EAAE,MAAM,CAAA;AAC9C,MAAA,QAAA,GAAW,IAAA,CAAK,GAAA,CAAI,QAAA,GAAW,GAAA,EAAK,WAAW,CAAA;AAAA,IACjD;AAAA,EACF;AAAA;AAAA,EAGA,MAAM,QAAW,IAAA,EAAwB;AACvC,IAAA,MAAM,EAAE,MAAA,EAAQ,IAAA,EAAM,MAAM,OAAA,GAAU,IAAG,GAAI,IAAA;AAC7C,IAAA,MAAM,aAAa,IAAA,CAAK,GAAA,CAAI,GAAG,OAAA,CAAQ,UAAA,IAAc,KAAK,UAAU,CAAA;AACpE,IAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,SAAA,IAAa,IAAA,CAAK,SAAA;AAC5C,IAAA,MAAM,OAAA,GAAkC;AAAA,MACtC,MAAA,EAAQ,uCAAA;AAAA,MACR,aAAA,EAAe,CAAA,OAAA,EAAU,IAAA,CAAK,OAAO,CAAA,CAAA;AAAA,MACrC,GAAG,IAAA,CAAK,QAAA;AAAA,MACR,GAAG,OAAA,CAAQ;AAAA,KACb;AACA,IAAA,IAAI,IAAA,KAAS,MAAA,EAAW,OAAA,CAAQ,cAAc,CAAA,GAAI,kBAAA;AAElD,IAAA,IAAI,CAAC,SAAA,EAAU,UAAW,YAAY,CAAA,GAAI,uBAAuB,OAAO,CAAA,CAAA;AACxE,IAAA,MAAM,IAAA,GAAoB;AAAA,MACxB,MAAA;AAAA,MACA,OAAA;AAAA,MACA,MAAM,IAAA,KAAS,MAAA,GAAY,MAAA,GAAY,IAAA,CAAK,UAAU,IAAI;AAAA,KAC5D;AAEA,IAAA,KAAA,IAAS,OAAA,GAAU,KAAK,OAAA,EAAA,EAAW;AACjC,MAAA,MAAM,WAAW,OAAA,GAAU,UAAA;AAC3B,MAAA,IAAI,GAAA;AACJ,MAAA,MAAM,EAAE,QAAQ,OAAA,EAAS,QAAA,KAAa,WAAA,CAAY,OAAA,CAAQ,QAAQ,SAAS,CAAA;AAC3E,MAAA,IAAI;AACF,QAAA,GAAA,GAAM,MAAM,IAAA,CAAK,MAAA,CAAO,IAAA,CAAK,OAAA,GAAU,MAAM,EAAE,GAAG,IAAA,EAAM,MAAA,EAAQ,CAAA;AAAA,MAClE,SAAS,GAAA,EAAK;AACZ,QAAA,OAAA,EAAQ;AACR,QAAA,IAAI,OAAA,CAAQ,MAAA,EAAQ,OAAA,EAAS,MAAM,GAAA;AACnC,QAAA,MAAM,IAAA,GAAO,QAAA,EAAS,GAAI,SAAA,GAAY,kBAAA;AACtC,QAAA,IAAI,QAAA,IAAY,IAAA,CAAK,KAAA,KAAU,YAAA,EAAc;AAC3C,UAAA,MAAM,MAAM,IAAA,CAAK,QAAA,CAAS,OAAO,CAAA,EAAG,QAAQ,MAAM,CAAA;AAClD,UAAA;AAAA,QACF;AACA,QAAA,MAAM,GAAA,GAAM,QAAA,EAAS,GACjB,CAAA,wBAAA,EAA2B,SAAS,CAAA,GAAA,CAAA,GACpC,CAAA,gBAAA,EAAmB,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAC,CAAA,CAAA;AACvE,QAAA,MAAM,IAAI,aAAA,CAAc,CAAA,EAAG,IAAA,EAAM,GAAA,EAAK,QAAW,MAAA,EAAW,EAAE,KAAA,EAAO,GAAA,EAAK,CAAA;AAAA,MAC5E;AAEA,MAAA,IAAI,IAAA;AACJ,MAAA,IAAI;AACF,QAAA,IAAA,GAAO,MAAM,IAAI,IAAA,EAAK;AAAA,MACxB,SAAS,GAAA,EAAK;AACZ,QAAA,OAAA,EAAQ;AACR,QAAA,IAAI,OAAA,CAAQ,MAAA,EAAQ,OAAA,EAAS,MAAM,GAAA;AACnC,QAAA,IAAI,QAAA,IAAY,IAAA,CAAK,KAAA,KAAU,YAAA,EAAc;AAC3C,UAAA,MAAM,MAAM,IAAA,CAAK,QAAA,CAAS,OAAO,CAAA,EAAG,QAAQ,MAAM,CAAA;AAClD,UAAA;AAAA,QACF;AACA,QAAA,MAAM,IAAA,GAAO,QAAA,EAAS,GAAI,SAAA,GAAY,kBAAA;AACtC,QAAA,MAAM,IAAI,aAAA;AAAA,UACR,CAAA;AAAA,UACA,IAAA;AAAA,UACA,kCAAA;AAAA,UACA,MAAA;AAAA,UACA,GAAA,CAAI,OAAA;AAAA,UACJ;AAAA,YACE,KAAA,EAAO;AAAA;AACT,SACF;AAAA,MACF;AACA,MAAA,OAAA,EAAQ;AAER,MAAA,IAAI,CAAC,IAAI,EAAA,EAAI;AACX,QAAA,MAAM,SAAA,GAAY,IAAI,MAAA,KAAW,GAAA,IAAQ,IAAI,MAAA,IAAU,GAAA,IAAO,KAAK,KAAA,KAAU,YAAA;AAC7E,QAAA,IAAI,YAAY,SAAA,EAAW;AACzB,UAAA,MAAM,KAAA,CAAM,KAAK,WAAA,CAAY,OAAA,EAAS,IAAI,OAAO,CAAA,EAAG,QAAQ,MAAM,CAAA;AAClE,UAAA;AAAA,QACF;AACA,QAAA,MAAM,iBAAA,CAAkB,GAAA,CAAI,MAAA,EAAQ,GAAA,CAAI,SAAS,IAAI,CAAA;AAAA,MACvD;AAEA,MAAA,OAAA,CAAQ,UAAA,GAAa,YAAA,CAAa,GAAG,CAAC,CAAA;AACtC,MAAA,MAAM,IAAA,GAAO,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA,IAAK,EAAA;AAChD,MAAA,IAAI,IAAA,CAAK,QAAA,CAAS,MAAM,CAAA,EAAG;AACzB,QAAA,IAAI;AACF,UAAA,OAAO,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,QACxB,SAAS,GAAA,EAAK;AACZ,UAAA,MAAM,IAAI,aAAA;AAAA,YACR,GAAA,CAAI,MAAA;AAAA,YACJ,kBAAA;AAAA,YACA,4BAAA;AAAA,YACA,GAAA,CAAI,OAAA,CAAQ,GAAA,CAAI,cAAc,CAAA,IAAK,MAAA;AAAA,YACnC,GAAA,CAAI,OAAA;AAAA,YACJ,EAAE,OAAO,GAAA;AAAI,WACf;AAAA,QACF;AAAA,MACF;AACA,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAAA,EAEA,SAAS,OAAA,EAAyB;AAChC,IAAA,MAAM,OAAO,IAAA,CAAK,GAAA,CAAI,KAAK,YAAA,GAAe,CAAA,IAAK,SAAS,GAAK,CAAA;AAC7D,IAAA,OAAO,IAAA,GAAO,CAAA,GAAI,IAAA,CAAK,MAAA,MAAY,IAAA,GAAO,CAAA,CAAA;AAAA,EAC5C;AAAA,EAEA,WAAA,CAAY,SAAiB,OAAA,EAA0B;AACrD,IAAA,MAAM,KAAA,GAAQ,eAAA,CAAgB,OAAA,CAAQ,GAAA,CAAI,aAAa,CAAC,CAAA;AACxD,IAAA,OAAO,KAAA,KAAU,SAAY,IAAA,CAAK,QAAA,CAAS,OAAO,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,KAAA,EAAO,GAAM,CAAA;AAAA,EAC9E;AACF;AAKA,SAAS,MAAM,MAAA,EAAuE;AACpF,EAAA,MAAM,CAAA,GAAI,IAAI,eAAA,EAAgB;AAC9B,EAAA,KAAA,MAAW,CAAC,CAAA,EAAG,CAAC,KAAK,MAAA,CAAO,OAAA,CAAQ,MAAM,CAAA,EAAG;AAC3C,IAAA,IAAI,CAAA,KAAM,UAAa,CAAA,KAAM,IAAA,IAAQ,GAAA,CAAI,CAAA,EAAG,MAAA,CAAO,CAAC,CAAC,CAAA;AAAA,EACvD;AACA,EAAA,MAAM,CAAA,GAAI,EAAE,QAAA,EAAS;AACrB,EAAA,OAAO,CAAA,GAAI,CAAA,CAAA,EAAI,CAAC,CAAA,CAAA,GAAK,EAAA;AACvB;AAEA,SAAS,OAAO,QAAA,EAA2C;AACzD,EAAA,MAAM,EAAA,GAAK,OAAO,QAAA,KAAa,QAAA,GAAW,WAAW,QAAA,EAAU,EAAA;AAC/D,EAAA,IAAI,CAAC,EAAA,EAAI,MAAM,IAAI,aAAA,CAAc,CAAA,EAAG,mBAAmB,uBAAuB,CAAA;AAC9E,EAAA,OAAO,EAAA;AACT;AAGO,SAAS,gBAAgB,CAAA,EAAsC;AACpE,EAAA,IAAI,CAAC,GAAG,OAAO,MAAA;AACf,EAAA,MAAM,IAAA,GAAO,OAAO,CAAC,CAAA;AACrB,EAAA,IAAI,MAAA,CAAO,SAAS,IAAI,CAAA,SAAU,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,GAAO,GAAI,CAAA;AACzD,EAAA,MAAM,EAAA,GAAK,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA;AACvB,EAAA,OAAO,MAAA,CAAO,KAAA,CAAM,EAAE,CAAA,GAAI,MAAA,GAAY,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,EAAA,GAAK,IAAA,CAAK,GAAA,EAAK,CAAA;AACnE;AAEA,SAAS,aAAa,GAAA,EAA6B;AACjD,EAAA,MAAM,IAAI,GAAA,CAAI,OAAA;AACd,EAAA,MAAM,GAAA,GAAM,CAAC,IAAA,KAAiB;AAC5B,IAAA,MAAM,CAAA,GAAI,CAAA,CAAE,GAAA,CAAI,IAAI,CAAA;AACpB,IAAA,IAAI,CAAA,KAAM,IAAA,IAAQ,CAAA,KAAM,EAAA,EAAI,OAAO,MAAA;AACnC,IAAA,MAAM,CAAA,GAAI,OAAO,CAAC,CAAA;AAClB,IAAA,OAAO,MAAA,CAAO,QAAA,CAAS,CAAC,CAAA,GAAI,CAAA,GAAI,MAAA;AAAA,EAClC,CAAA;AACA,EAAA,MAAM,KAAA,GAAQ,CAAA,CAAE,GAAA,CAAI,SAAS,GAAG,WAAA,EAAY;AAC5C,EAAA,OAAO;AAAA,IACL,QAAQ,GAAA,CAAI,MAAA;AAAA,IACZ,OAAA,EAAS,CAAA;AAAA,IACT,SAAA,EAAW,CAAA,CAAE,GAAA,CAAI,cAAc,CAAA,IAAK,MAAA;AAAA,IACpC,WAAA,EAAa,IAAI,gBAAgB,CAAA;AAAA,IACjC,gBAAA,EAAkB,IAAI,qBAAqB,CAAA;AAAA,IAC3C,OAAA,EAAS,IAAI,YAAY,CAAA;AAAA,IACzB,KAAA,EAAO,KAAA,KAAU,KAAA,IAAS,KAAA,KAAU,SAAS,KAAA,GAAQ,MAAA;AAAA,IACrD,SAAA,EAAW,IAAI,cAAc,CAAA;AAAA,IAC7B,cAAA,EAAgB,IAAI,mBAAmB;AAAA,GACzC;AACF;AAEA,SAAS,WAAA,CAAY,OAAgC,EAAA,EAAY;AAC/D,EAAA,MAAM,IAAA,GAAO,IAAI,eAAA,EAAgB;AACjC,EAAA,IAAI,QAAA,GAAW,KAAA;AACf,EAAA,MAAM,OAAA,GAAU,MAAM,IAAA,CAAK,KAAA,CAAM,OAAO,MAAM,CAAA;AAC9C,EAAA,IAAI,KAAA,EAAO,OAAA,EAAS,IAAA,CAAK,KAAA,CAAM,MAAM,MAAM,CAAA;AAAA,cAC/B,gBAAA,CAAiB,OAAA,EAAS,SAAS,EAAE,IAAA,EAAM,MAAM,CAAA;AAC7D,EAAA,MAAM,KAAA,GACJ,KAAK,CAAA,IAAK,MAAA,CAAO,SAAS,EAAE,CAAA,GACxB,WAAW,MAAM;AACf,IAAA,QAAA,GAAW,IAAA;AACX,IAAA,IAAA,CAAK,KAAA,CAAM,IAAI,aAAA,CAAc,CAAA,EAAG,WAAW,CAAA,wBAAA,EAA2B,EAAE,KAAK,CAAC,CAAA;AAAA,EAChF,CAAA,EAAG,EAAE,CAAA,GACL,MAAA;AACN,EAAA,OAAO;AAAA,IACL,QAAQ,IAAA,CAAK,MAAA;AAAA,IACb,UAAU,MAAM,QAAA;AAAA,IAChB,SAAS,MAAM;AACb,MAAA,IAAI,KAAA,KAAU,MAAA,EAAW,YAAA,CAAa,KAAK,CAAA;AAC3C,MAAA,KAAA,EAAO,mBAAA,CAAoB,SAAS,OAAO,CAAA;AAAA,IAC7C;AAAA,GACF;AACF;AAEA,SAAS,KAAA,CAAM,IAAY,MAAA,EAAqC;AAC9D,EAAA,OAAO,IAAI,OAAA,CAAQ,CAAC,OAAA,EAAS,MAAA,KAAW;AACtC,IAAA,IAAI,MAAA,EAAQ,OAAA,EAAS,OAAO,MAAA,CAAO,OAAO,MAAM,CAAA;AAChD,IAAA,MAAM,CAAA,GAAI,WAAW,MAAM;AACzB,MAAA,MAAA,EAAQ,mBAAA,CAAoB,SAAS,OAAO,CAAA;AAC5C,MAAA,OAAA,EAAQ;AAAA,IACV,GAAG,EAAE,CAAA;AACL,IAAA,MAAM,UAAU,MAAM;AACpB,MAAA,YAAA,CAAa,CAAC,CAAA;AACd,MAAA,MAAA,CAAO,QAAQ,MAAM,CAAA;AAAA,IACvB,CAAA;AACA,IAAA,MAAA,EAAQ,iBAAiB,OAAA,EAAS,OAAA,EAAS,EAAE,IAAA,EAAM,MAAM,CAAA;AAAA,EAC3D,CAAC,CAAA;AACH;AAQA,SAAS,IAAI,IAAA,EAAkC;AAC7C,EAAA,MAAM,CAAA,GAAI,UAAA;AACV,EAAA,IAAI;AACF,IAAA,MAAM,CAAA,GAAI,CAAA,CAAE,OAAA,EAAS,GAAA,GAAM,IAAI,CAAA;AAC/B,IAAA,IAAI,GAAG,OAAO,CAAA;AAAA,EAChB,CAAA,CAAA,MAAQ;AAAA,EAER;AACA,EAAA,IAAI;AACF,IAAA,OAAO,CAAA,CAAE,IAAA,EAAM,GAAA,EAAK,GAAA,GAAM,IAAI,CAAA,IAAK,KAAA,CAAA;AAAA,EACrC,CAAA,CAAA,MAAQ;AAEN,IAAA,OAAO,MAAA;AAAA,EACT;AACF;AAEA,SAAS,SAAA,GAAqB;AAC5B,EAAA,OAAO,OAAQ,WAAuB,QAAA,KAAa,WAAA;AACrD;;;ACltBO,SAAS,aAAa,KAAA,EAAoD;AAC/E,EAAA,OAAO,EAAE,IAAA,IAAQ,KAAA,IAAS,OAAO,KAAA,CAAM,EAAA,KAAO,QAAA,CAAA,IAAa,OAAA,IAAW,KAAA,IAAS,CAAC,CAAC,KAAA,CAAM,KAAA;AACzF;;;ACQA,SAAS,MAAA,CAAO,SAAuB,IAAA,EAAkC;AACvE,EAAA,IAAI,OAAQ,OAAA,CAAoB,GAAA,KAAQ,UAAA,EAAY;AAClD,IAAA,OAAQ,OAAA,CAAoB,GAAA,CAAI,IAAI,CAAA,IAAK,MAAA;AAAA,EAC3C;AACA,EAAA,MAAM,GAAA,GAAM,OAAA;AACZ,EAAA,MAAM,GAAA,GAAM,MAAA,CAAO,IAAA,CAAK,GAAG,CAAA,CAAE,IAAA,CAAK,CAAC,CAAA,KAAM,CAAA,CAAE,WAAA,EAAY,KAAM,IAAA,CAAK,aAAa,CAAA;AAC/E,EAAA,MAAM,CAAA,GAAI,GAAA,KAAQ,MAAA,GAAY,MAAA,GAAY,IAAI,GAAG,CAAA;AACjD,EAAA,OAAO,MAAM,OAAA,CAAQ,CAAC,CAAA,GAAI,CAAA,CAAE,CAAC,CAAA,GAAI,CAAA;AACnC;AAaA,eAAsB,cACpB,MAAA,EACA,OAAA,EACA,OAAA,EACA,OAAA,GAAgC,EAAC,EACf;AAClB,EAAA,MAAM,SAAA,GAAY,MAAA,CAAO,OAAA,EAAS,sBAAsB,CAAA;AACxD,EAAA,MAAM,EAAA,GAAK,MAAA,CAAO,OAAA,EAAS,sBAAsB,CAAA;AACjD,EAAA,IAAI,CAAC,MAAA,IAAU,CAAC,SAAA,EAAW,WAAW,KAAK,CAAA,IAAK,CAAC,EAAA,IAAM,CAAC,OAAA,CAAQ,IAAA,CAAK,EAAE,GAAG,OAAO,KAAA;AACjF,EAAA,MAAM,GAAA,GAAM,QAAQ,GAAA,IAAO,IAAA,CAAK,MAAM,IAAA,CAAK,GAAA,KAAQ,GAAI,CAAA;AACvD,EAAA,IAAI,IAAA,CAAK,GAAA,CAAI,GAAA,GAAM,MAAA,CAAO,EAAE,CAAC,CAAA,IAAK,OAAA,CAAQ,gBAAA,IAAoB,GAAA,CAAA,EAAM,OAAO,KAAA;AAE3E,EAAA,MAAM,GAAA,GAAM,IAAI,WAAA,EAAY;AAC5B,EAAA,MAAM,OAAO,OAAO,OAAA,KAAY,WAAW,GAAA,CAAI,MAAA,CAAO,OAAO,CAAA,GAAI,OAAA;AACjE,EAAA,MAAM,MAAA,GAAS,GAAA,CAAI,MAAA,CAAO,CAAA,EAAG,EAAE,CAAA,CAAA,CAAG,CAAA;AAClC,EAAA,MAAM,MAAM,IAAI,UAAA,CAAW,MAAA,CAAO,MAAA,GAAS,KAAK,MAAM,CAAA;AACtD,EAAA,GAAA,CAAI,IAAI,MAAM,CAAA;AACd,EAAA,GAAA,CAAI,GAAA,CAAI,IAAA,EAAM,MAAA,CAAO,MAAM,CAAA;AAC3B,EAAA,MAAM,GAAA,GAAM,MAAM,MAAA,CAAO,MAAA,CAAO,SAAA;AAAA,IAC9B,KAAA;AAAA,IACA,GAAA,CAAI,OAAO,MAAM,CAAA;AAAA,IACjB,EAAE,IAAA,EAAM,MAAA,EAAQ,IAAA,EAAM,SAAA,EAAU;AAAA,IAChC,KAAA;AAAA,IACA,CAAC,MAAM;AAAA,GACT;AACA,EAAA,MAAM,GAAA,GAAM,IAAI,UAAA,CAAW,MAAM,MAAA,CAAO,OAAO,IAAA,CAAK,MAAA,EAAQ,GAAA,EAAK,GAAG,CAAC,CAAA;AACrE,EAAA,MAAM,OAAO,KAAA,CAAM,IAAA,CAAK,GAAA,EAAK,CAAC,MAAM,CAAA,CAAE,QAAA,CAAS,EAAE,CAAA,CAAE,SAAS,CAAA,EAAG,GAAG,CAAC,CAAA,CAAE,KAAK,EAAE,CAAA;AAC5E,EAAA,MAAM,GAAA,GAAM,SAAA,CAAU,KAAA,CAAM,CAAC,EAAE,WAAA,EAAY;AAC3C,EAAA,IAAI,GAAA,CAAI,MAAA,KAAW,IAAA,CAAK,MAAA,EAAQ,OAAO,KAAA;AACvC,EAAA,IAAI,IAAA,GAAO,CAAA;AACX,EAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,MAAA,EAAQ,CAAA,EAAA,EAAK,IAAA,IAAQ,IAAA,CAAK,UAAA,CAAW,CAAC,CAAA,GAAI,GAAA,CAAI,WAAW,CAAC,CAAA;AACnF,EAAA,OAAO,IAAA,KAAS,CAAA;AAClB;AAgBA,eAAsB,aACpB,MAAA,EACA,OAAA,EACA,OAAA,EACA,OAAA,GAAgC,EAAC,EACV;AACvB,EAAA,IAAI,CAAE,MAAM,aAAA,CAAc,QAAQ,OAAA,EAAS,OAAA,EAAS,OAAO,CAAA,EAAI;AAC7D,IAAA,MAAM,IAAI,aAAA,CAAc,GAAA,EAAK,mBAAA,EAAqB,2CAA2C,CAAA;AAAA,EAC/F;AACA,EAAA,MAAM,IAAA,GAAO,OAAO,OAAA,KAAY,QAAA,GAAW,UAAU,IAAI,WAAA,EAAY,CAAE,MAAA,CAAO,OAAO,CAAA;AACrF,EAAA,IAAI,IAAA;AACJ,EAAA,IAAI;AACF,IAAA,IAAA,GAAO,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,EACxB,SAAS,GAAA,EAAK;AACZ,IAAA,MAAM,IAAI,aAAA;AAAA,MACR,GAAA;AAAA,MACA,iBAAA;AAAA,MACA,0BAAA;AAAA,MACA,MAAA;AAAA,MACA,MAAA;AAAA,MACA;AAAA,QACE,KAAA,EAAO;AAAA;AACT,KACF;AAAA,EACF;AACA,EAAA,MAAM,IAAA,GACJ,MAAA,CAAO,OAAA,EAAS,kBAAkB,CAAA,KACjC,OAAO,IAAA,EAAM,KAAA,KAAU,QAAA,GAAW,IAAA,CAAK,KAAA,GAAQ,iBAAA,CAAA;AAClD,EAAA,OAAO,EAAE,IAAA,EAAM,UAAA,EAAY,OAAO,OAAA,EAAS,qBAAqB,GAAG,IAAA,EAAK;AAC1E","file":"index.cjs","sourcesContent":["/**\n * Every failure thrown by the SDK. API errors carry the fields of the\n * `{\"error\":{\"code\",\"message\",\"request_id\"}}` envelope; network failures and\n * timeouts use `status: 0` with code `connection_error` or `timeout`.\n */\nexport class SerpKiteError extends Error {\n /** HTTP status, or 0 when no response was received. */\n readonly status: number;\n /** Machine-readable code, e.g. `unauthorized`, `insufficient_credits`, `rate_limited`. */\n readonly code: string;\n /** `X-Request-Id` of the failed request, when the API returned one. */\n readonly requestId: string | undefined;\n /** Response headers, when the API responded. */\n readonly headers: Headers | undefined;\n\n constructor(\n status: number,\n code: string,\n message: string,\n requestId?: string,\n headers?: Headers,\n options?: { cause?: unknown },\n ) {\n super(message, options);\n this.name = \"SerpKiteError\";\n this.status = status;\n this.code = code;\n this.requestId = requestId || undefined;\n this.headers = headers;\n }\n}\n\nconst fallbackCodes: Record<number, string> = {\n 400: \"invalid_request\",\n 401: \"unauthorized\",\n 402: \"insufficient_credits\",\n 403: \"forbidden\",\n 404: \"not_found\",\n 429: \"rate_limited\",\n // The API sends upstream failures as 503 with a JSON body; a bare 502/504\n // comes from a proxy (Cloudflare replaces origin 502/504 bodies).\n 502: \"upstream_error\",\n 503: \"unavailable\",\n 504: \"upstream_timeout\",\n};\n\n/** Builds a SerpKiteError from a non-2xx response body (JSON envelope or anything else). */\nexport function errorFromResponse(status: number, headers: Headers, body: string): SerpKiteError {\n let code = fallbackCodes[status] ?? (status >= 500 ? \"server_error\" : \"http_error\");\n let message = body.trim().slice(0, 500) || `HTTP ${status}`;\n let requestId = headers.get(\"x-request-id\") ?? undefined;\n try {\n const parsed = JSON.parse(body) as {\n error?: { code?: unknown; message?: unknown; request_id?: unknown };\n };\n const e = parsed?.error;\n if (e && typeof e === \"object\") {\n if (typeof e.code === \"string\" && e.code) code = e.code;\n if (typeof e.message === \"string\" && e.message) message = e.message;\n if (typeof e.request_id === \"string\" && e.request_id) requestId = e.request_id;\n }\n } catch {\n // Not JSON: keep the text body as the message.\n }\n return new SerpKiteError(status, code, message, requestId, headers);\n}\n","import { errorFromResponse, SerpKiteError } from \"./errors\";\nimport type {\n Account,\n AutocompleteResponse,\n Batch,\n BatchCreateEntry,\n BatchCreateParams,\n BatchCreateResponse,\n CompactResponse,\n CrawlParams,\n CrawlTask,\n ExtractParams,\n ExtractResponse,\n ImagesResponse,\n MapParams,\n MapResponse,\n Monitor,\n MonitorCreateParams,\n MonitorList,\n MonitorRun,\n MonitorRunList,\n MonitorRunsParams,\n MonitorUpdateParams,\n NewsResponse,\n PatentsResponse,\n PlaceParams,\n PlacesResponse,\n RankParams,\n RankResponse,\n ReviewsParams,\n ReviewsResponse,\n ScholarResponse,\n SearchParams,\n SearchResponse,\n ShoppingResponse,\n TaskCancelResponse,\n TaskCreated,\n VideosResponse,\n WebpageParams,\n WebpageResponse,\n} from \"./types\";\n\nexport const VERSION = \"0.5.0\";\nexport const DEFAULT_BASE_URL = \"https://api.serpkite.com\";\n\nexport interface SerpKiteOptions {\n /** API key (`skt_live_…`). Defaults to the `SERPKITE_API_KEY` environment variable. */\n apiKey?: string;\n /** Defaults to `SERPKITE_BASE_URL` or https://api.serpkite.com. */\n baseUrl?: string;\n /** Per-attempt timeout in milliseconds. Default 60000. */\n timeoutMs?: number;\n /** Retries after the first attempt on 429, 5xx and network errors. Default 2. */\n maxRetries?: number;\n /** Base delay of the exponential backoff in milliseconds. Default 500. */\n retryDelayMs?: number;\n /** Custom fetch implementation. Defaults to the global `fetch`. */\n fetch?: typeof fetch;\n /** Extra headers sent with every request. */\n headers?: Record<string, string>;\n}\n\n/** Billing and tracing details from the response headers. */\nexport interface ResponseInfo {\n status: number;\n headers: Headers;\n requestId: string | undefined;\n creditsUsed: number | undefined;\n creditsRemaining: number | undefined;\n costUsd: number | undefined;\n /** `HIT` when served from cache (`max_age`), else `MISS`. */\n cache: \"HIT\" | \"MISS\" | undefined;\n latencyMs: number | undefined;\n tokensEstimate: number | undefined;\n}\n\nexport interface RequestOptions {\n signal?: AbortSignal;\n /** Overrides the client's per-attempt timeout. */\n timeoutMs?: number;\n /** Overrides the client's retry count. */\n maxRetries?: number;\n headers?: Record<string, string>;\n /** Called with the final response's headers (credits used/remaining, cache, request id). */\n onResponse?: (info: ResponseInfo) => void;\n}\n\nexport interface BatchCreateOptions extends RequestOptions {\n /**\n * Sent as `Idempotency-Key` (1-255 printable ASCII characters, e.g. a UUID).\n * For 24 hours a retry with the same key and body returns the first response\n * instead of queueing and billing the jobs again.\n */\n idempotencyKey?: string;\n}\n\nexport interface WaitOptions {\n /**\n * Give up after this many milliseconds. Default 600000 (10 minutes) for batches and\n * 2100000 (35 minutes) for `waitForCrawl`: a crawl runs for up to 30 minutes.\n */\n timeoutMs?: number;\n /** First delay between polls. Default 1000. Grows 1.5× per poll. */\n pollIntervalMs?: number;\n /** Upper bound of the delay between polls. Default 10000. */\n maxPollIntervalMs?: number;\n signal?: AbortSignal;\n}\n\n/** A vertical whose return type follows `format`: `\"markdown\"` → string, `\"compact\"` → CompactResponse. */\nexport interface VerticalMethod<P, R> {\n (params: P & { format: \"markdown\" }, options?: RequestOptions): Promise<string>;\n (params: P & { format: \"compact\" }, options?: RequestOptions): Promise<CompactResponse>;\n (params: P & { format?: \"json\" }, options?: RequestOptions): Promise<R>;\n (params: P, options?: RequestOptions): Promise<R | CompactResponse | string>;\n}\n\ntype Method = \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\";\n\n/** Task states after which `waitForCrawl` returns. */\nconst TASK_DONE = new Set([\"completed\", \"failed\", \"canceled\"]);\n\ninterface Call {\n method: Method;\n path: string;\n body?: unknown;\n options?: RequestOptions;\n /** Which failures are safe to retry. `all` = 429, 5xx and network errors. */\n retry?: \"all\" | \"rate_limit\";\n}\n\nexport class SerpKite {\n readonly baseUrl: string;\n readonly timeoutMs: number;\n readonly maxRetries: number;\n readonly retryDelayMs: number;\n readonly #apiKey: string;\n readonly #fetch: typeof fetch;\n readonly #headers: Record<string, string>;\n\n constructor(options: SerpKiteOptions = {}) {\n const apiKey = options.apiKey ?? env(\"SERPKITE_API_KEY\");\n if (!apiKey) {\n throw new SerpKiteError(\n 0,\n \"missing_api_key\",\n \"No API key: pass { apiKey } or set the SERPKITE_API_KEY environment variable\",\n );\n }\n this.#apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? env(\"SERPKITE_BASE_URL\") ?? DEFAULT_BASE_URL).replace(\n /\\/+$/,\n \"\",\n );\n this.timeoutMs = options.timeoutMs ?? 60_000;\n this.maxRetries = Math.max(0, options.maxRetries ?? 2);\n this.retryDelayMs = options.retryDelayMs ?? 500;\n const f = options.fetch ?? globalThis.fetch;\n if (typeof f !== \"function\") {\n throw new SerpKiteError(\n 0,\n \"missing_fetch\",\n \"No global fetch: pass { fetch } (Node 18+ has one)\",\n );\n }\n this.#fetch = f;\n this.#headers = { ...options.headers };\n }\n\n // ── Verticals ─────────────────────────────────────────────────────────\n\n /** Google web search: organic results, answer box, knowledge graph, people also ask… */\n readonly search = this.#vertical<SearchParams, SearchResponse>(\"/v1/search\");\n /** Google Images. */\n readonly images = this.#vertical<SearchParams, ImagesResponse>(\"/v1/images\");\n /** Google Videos. */\n readonly videos = this.#vertical<SearchParams, VideosResponse>(\"/v1/videos\");\n /** Google News. */\n readonly news = this.#vertical<SearchParams, NewsResponse>(\"/v1/news\");\n /** Google Maps search (places with coordinates). Accepts `ll` (\"@lat,lng,14z\"). */\n readonly maps = this.#vertical<SearchParams, PlacesResponse>(\"/v1/maps\");\n /** Google local results. */\n readonly places = this.#vertical<SearchParams, PlacesResponse>(\"/v1/places\");\n /**\n * Details of one place by `place_id`, `cid` or `fid`: address, country, time zone, hours\n * (`opening_hours` text and structured `weekly_hours`), phones, description and photos.\n * `results` holds the place, or is empty (not charged) when no place has that id. 1 credit.\n */\n readonly place = this.#vertical<PlaceParams, PlacesResponse>(\"/v1/place\");\n /** Reviews of a place by `place_id`, `cid` or `fid`. Page with `page_token` = `next_page_token`. */\n readonly reviews = this.#vertical<ReviewsParams, ReviewsResponse>(\"/v1/reviews\");\n /** Google Shopping. */\n readonly shopping = this.#vertical<SearchParams, ShoppingResponse>(\"/v1/shopping\");\n /** Google Scholar. */\n readonly scholar = this.#vertical<SearchParams, ScholarResponse>(\"/v1/scholar\");\n /** Google Patents. */\n readonly patents = this.#vertical<SearchParams, PatentsResponse>(\"/v1/patents\");\n /** Google autocomplete suggestions. */\n readonly autocomplete = this.#vertical<SearchParams, AutocompleteResponse>(\"/v1/autocomplete\");\n /** Fetch any public URL as clean Markdown plus metadata. */\n readonly webpage = this.#vertical<WebpageParams, WebpageResponse>(\"/v1/webpage\");\n\n /** Position of `domain` for keyword `q` in the top `num` results (default 100). */\n rank(params: RankParams, options?: RequestOptions): Promise<RankResponse> {\n return this.request({ method: \"POST\", path: \"/v1/rank\", body: params, options });\n }\n\n /**\n * Read up to 20 URLs (HTML or PDF) as Markdown, text or HTML in one call, with optional\n * query-ranked `highlights` (BM25), `include_links` and `include_images`. 1 credit per URL\n * that comes back (0.5 from cache); URLs that fail are listed in `failed` and cost nothing.\n */\n extract(params: ExtractParams, options?: RequestOptions): Promise<ExtractResponse> {\n // Billed per page even when the response is lost: retried only on 429,\n // and the HTTP timeout covers the server's deadline (timeout, default 50 s) + 15 s.\n const wait = ((params.timeout ?? 50) + 15) * 1000;\n return this.request({\n method: \"POST\",\n path: \"/v1/extract\",\n body: params,\n options: {\n ...options,\n timeoutMs: options?.timeoutMs ?? (this.timeoutMs > 0 ? Math.max(this.timeoutMs, wait) : 0),\n },\n retry: \"rate_limit\",\n });\n }\n\n /**\n * The URLs of a site from its sitemaps (XML, RSS/Atom, gzip, plain text) and start page,\n * canonicalised and deduplicated, optionally ranked by `search`. `include_paths` /\n * `exclude_paths` (regular expressions on the URL path) and `ignore_query_parameters`\n * narrow the list. 1 credit; free when nothing is found.\n */\n map(params: MapParams, options?: RequestOptions): Promise<MapResponse> {\n return this.request({ method: \"POST\", path: \"/v1/map\", body: params, options });\n }\n\n /** Balance, limits and this month's usage for the key's account. */\n account(options?: RequestOptions): Promise<Account> {\n return this.request({ method: \"GET\", path: \"/v1/account\", options });\n }\n\n // ── Async tasks: crawl ────────────────────────────────────────────────\n\n /**\n * Starts an async crawl of one site and returns the queued task (`202`). 1 credit per page\n * read (0.5 from cache); `limit` credits (up to 1000 pages, `max_depth` up to 10) are\n * reserved up front and the rest refunded. `sitemap` (`include` default, `only`, `skip`)\n * seeds the crawl with sitemap URLs; `query` reads the most relevant pages first. robots.txt\n * and Crawl-delay are honoured; `result.stats.stopped` says why the crawl ended (`done`,\n * `limit`, `time_limit`, `size_limit`, `too_many_failures`, `canceled`).\n * Only retried on 429, so a lost response never starts (and reserves) a second crawl.\n */\n crawl(params: CrawlParams, options?: RequestOptions): Promise<TaskCreated> {\n return this.request({\n method: \"POST\",\n path: \"/v1/crawl\",\n body: params,\n options,\n retry: \"rate_limit\",\n });\n }\n\n /** Polls a crawl (results are kept for 24 hours). */\n getCrawl(id: string, options?: RequestOptions): Promise<CrawlTask> {\n return this.request({ method: \"GET\", path: `/v1/crawl/${encodeURIComponent(id)}`, options });\n }\n\n /** Cancels a crawl: refunded if still queued, else stops at the next checkpoint. */\n cancelCrawl(id: string, options?: RequestOptions): Promise<TaskCancelResponse> {\n return this.request({\n method: \"DELETE\",\n path: `/v1/crawl/${encodeURIComponent(id)}`,\n options,\n });\n }\n\n /**\n * Polls until the crawl is `completed`, `failed` or `canceled` and returns it (a failed\n * task is returned, not thrown; check `status` and `error`). Accepts an id or the task\n * returned by `crawl`.\n */\n async waitForCrawl(\n idOrTask: string | { id: string },\n options: WaitOptions = {},\n ): Promise<CrawlTask> {\n return this.#waitTask(taskId(idOrTask), (id) => this.getCrawl(id, { signal: options.signal }), {\n ...options,\n timeoutMs: options.timeoutMs ?? 2_100_000,\n });\n }\n\n // ── Monitors ──────────────────────────────────────────────────────────\n\n readonly monitors = {\n /**\n * Saves a `search` or `news` request (`q`) that runs on a schedule (hourly to monthly) and\n * POSTs results it hasn't seen before to `webhook_url` (`monitor.results`). With\n * `endpoint: \"webpage\"` and a `url` it checks that page each interval (1 credit per check)\n * and reports it (`MonitorPageChange`) when its content changes. `metadata` (your JSON\n * object, at most 2 KB) is echoed on the monitor and in its webhooks. Without a\n * `webhook_url`, read new results from `monitors.runs`. `active: false`\n * creates it paused. A monitor pauses itself after 10 failed runs in a row\n * (`last_status: \"paused\"`); `update(id, { active: true })` resumes it. Each run costs\n * what its search costs. Only retried on 429.\n */\n create: (params: MonitorCreateParams, options?: RequestOptions): Promise<Monitor> =>\n this.request({\n method: \"POST\",\n path: \"/v1/monitors\",\n body: params,\n options,\n retry: \"rate_limit\",\n }),\n\n /** The account's monitors. */\n list: (options?: RequestOptions): Promise<MonitorList> =>\n this.request({ method: \"GET\", path: \"/v1/monitors\", options }),\n\n get: (id: string, options?: RequestOptions): Promise<Monitor> =>\n this.request({ method: \"GET\", path: `/v1/monitors/${encodeURIComponent(id)}`, options }),\n\n /**\n * Changes `name`, `interval` / `interval_seconds`, `webhook_url` (`\"\"` removes it),\n * `active` (`true` resumes a paused monitor), `metadata` (an object replaces it, `null`\n * clears it) or the saved request (`endpoint`, `q`, `url`, `country`, `num`, domains,\n * `engine`…). Switching `endpoint` between a search and `webpage` drops the other kind's\n * fields. A changed search reports every result as new on the next run.\n */\n update: (id: string, params: MonitorUpdateParams, options?: RequestOptions): Promise<Monitor> =>\n this.request({\n method: \"PATCH\",\n path: `/v1/monitors/${encodeURIComponent(id)}`,\n body: params,\n options,\n }),\n\n delete: async (id: string, options?: RequestOptions): Promise<void> => {\n await this.request({\n method: \"DELETE\",\n path: `/v1/monitors/${encodeURIComponent(id)}`,\n options,\n });\n },\n\n /** Runs an active monitor at the next scheduler poll (within about 30 seconds).\n * Paused monitors return 409; update(id, { active: true }) resumes and schedules them. */\n run: (id: string, options?: RequestOptions): Promise<Monitor> =>\n this.request({\n method: \"POST\",\n path: `/v1/monitors/${encodeURIComponent(id)}/run`,\n options,\n retry: \"rate_limit\",\n }),\n\n /**\n * One page of the monitor's run history, newest first (`limit` 1-100, default 20). Each\n * run carries its new results for 24 hours. Pass `next_before` as `before` for the next\n * page; it is null on the last one.\n */\n runs: (\n id: string,\n params: MonitorRunsParams = {},\n options?: RequestOptions,\n ): Promise<MonitorRunList> =>\n this.request({\n method: \"GET\",\n path: `/v1/monitors/${encodeURIComponent(id)}/runs${query(params)}`,\n options,\n }),\n\n /**\n * Iterates over every run of the monitor, newest first, fetching pages of `limit` as\n * needed (starting at `before` when given).\n *\n * ```ts\n * for await (const run of sk.monitors.iterRuns(\"m1\")) console.log(run.new_results);\n * ```\n */\n iterRuns: (\n id: string,\n params: MonitorRunsParams = {},\n options?: RequestOptions,\n ): AsyncIterable<MonitorRun> => this.#iterRuns(id, params, options),\n };\n\n // ── Batches ───────────────────────────────────────────────────────────\n\n readonly batches = {\n /**\n * Queue 1-100 requests for one endpoint at half price. Returns one entry per\n * request, in order: a queued `Batch` or an error object. Without an\n * `idempotencyKey` it is only retried on 429, so a lost response never queues\n * (and bills) the same requests twice. With one, 5xx and network errors are\n * retried too: the server replays the first response for the same key and body.\n */\n create: (\n params: BatchCreateParams,\n options: BatchCreateOptions = {},\n ): Promise<BatchCreateResponse> => {\n const { idempotencyKey, ...rest } = options;\n return this.request({\n method: \"POST\",\n path: \"/v1/batches\",\n body: params,\n options: idempotencyKey\n ? { ...rest, headers: { ...rest.headers, \"Idempotency-Key\": idempotencyKey } }\n : rest,\n retry: idempotencyKey ? \"all\" : \"rate_limit\",\n });\n },\n\n /** Poll one batch job. */\n get: (id: string, options?: RequestOptions): Promise<Batch> =>\n this.request({ method: \"GET\", path: `/v1/batches/${encodeURIComponent(id)}`, options }),\n\n /**\n * Poll until the job is `done` or `failed` and return it (a failed job is\n * returned, not thrown; check `status` and `error`). Accepts an id or an\n * entry from `create`; an entry that failed to queue throws its error.\n */\n wait: (idOrEntry: string | BatchCreateEntry | undefined, options: WaitOptions = {}) =>\n this.#wait(idOrEntry, options),\n };\n\n // ── Plumbing ──────────────────────────────────────────────────────────\n\n async *#iterRuns(\n id: string,\n params: MonitorRunsParams,\n options?: RequestOptions,\n ): AsyncGenerator<MonitorRun> {\n let before = params.before;\n for (;;) {\n const page = await this.monitors.runs(id, { ...params, before }, options);\n yield* page.results;\n if (!page.next_before || page.results.length === 0) return;\n before = page.next_before;\n }\n }\n\n async #waitTask<T extends { status: string }>(\n id: string,\n get: (id: string) => Promise<T>,\n o: WaitOptions,\n ): Promise<T> {\n const timeoutMs = o.timeoutMs ?? 600_000;\n const maxInterval = o.maxPollIntervalMs ?? 10_000;\n let interval = o.pollIntervalMs ?? 1_000;\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n const task = await get(id);\n if (TASK_DONE.has(task.status)) return task;\n const left = deadline - Date.now();\n if (left <= 0) {\n throw new SerpKiteError(\n 0,\n \"timeout\",\n `task ${id} still ${task.status} after ${timeoutMs} ms`,\n );\n }\n await sleep(Math.min(interval, left), o.signal);\n interval = Math.min(interval * 1.5, maxInterval);\n }\n }\n\n #vertical<P, R>(path: string): VerticalMethod<P, R> {\n return ((params: P, options?: RequestOptions) =>\n this.request({ method: \"POST\", path, body: params, options })) as VerticalMethod<P, R>;\n }\n\n async #wait(idOrEntry: string | BatchCreateEntry | undefined, o: WaitOptions): Promise<Batch> {\n let id: string | undefined;\n if (typeof idOrEntry === \"string\") {\n id = idOrEntry;\n } else if (idOrEntry && \"id\" in idOrEntry && typeof idOrEntry.id === \"string\") {\n id = idOrEntry.id;\n } else if (idOrEntry && \"error\" in idOrEntry && idOrEntry.error && !(\"id\" in idOrEntry)) {\n const e = idOrEntry.error as { code?: string; message?: string; request_id?: string };\n throw new SerpKiteError(\n 400,\n e.code ?? \"invalid_request\",\n e.message ?? \"batch entry was not queued\",\n e.request_id,\n );\n }\n if (!id) {\n throw new SerpKiteError(0, \"invalid_request\", \"batches.wait needs a batch id\");\n }\n const timeoutMs = o.timeoutMs ?? 600_000;\n const maxInterval = o.maxPollIntervalMs ?? 10_000;\n let interval = o.pollIntervalMs ?? 1_000;\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n const batch = await this.batches.get(id, { signal: o.signal });\n if (batch.status === \"done\" || batch.status === \"failed\") return batch;\n const left = deadline - Date.now();\n if (left <= 0) {\n throw new SerpKiteError(\n 0,\n \"timeout\",\n `batch ${id} still ${batch.status} after ${timeoutMs} ms`,\n );\n }\n await sleep(Math.min(interval, left), o.signal);\n interval = Math.min(interval * 1.5, maxInterval);\n }\n }\n\n /** Low-level request: JSON body in, parsed JSON (or text for non-JSON responses) out. */\n async request<T>(call: Call): Promise<T> {\n const { method, path, body, options = {} } = call;\n const maxRetries = Math.max(0, options.maxRetries ?? this.maxRetries);\n const timeoutMs = options.timeoutMs ?? this.timeoutMs;\n const headers: Record<string, string> = {\n Accept: \"application/json, text/markdown;q=0.9\",\n Authorization: `Bearer ${this.#apiKey}`,\n ...this.#headers,\n ...options.headers,\n };\n if (body !== undefined) headers[\"Content-Type\"] = \"application/json\";\n // Browsers would turn a custom User-Agent into a CORS preflight header.\n if (!isBrowser()) headers[\"User-Agent\"] = `serpkite-typescript/${VERSION}`;\n const init: RequestInit = {\n method,\n headers,\n body: body === undefined ? undefined : JSON.stringify(body),\n };\n\n for (let attempt = 0; ; attempt++) {\n const canRetry = attempt < maxRetries;\n let res: Response;\n const { signal, cleanup, timedOut } = withTimeout(options.signal, timeoutMs);\n try {\n res = await this.#fetch(this.baseUrl + path, { ...init, signal });\n } catch (err) {\n cleanup();\n if (options.signal?.aborted) throw err;\n const code = timedOut() ? \"timeout\" : \"connection_error\";\n if (canRetry && call.retry !== \"rate_limit\") {\n await sleep(this.#backoff(attempt), options.signal);\n continue;\n }\n const msg = timedOut()\n ? `request timed out after ${timeoutMs} ms`\n : `request failed: ${err instanceof Error ? err.message : String(err)}`;\n throw new SerpKiteError(0, code, msg, undefined, undefined, { cause: err });\n }\n\n let text: string;\n try {\n text = await res.text();\n } catch (err) {\n cleanup();\n if (options.signal?.aborted) throw err;\n if (canRetry && call.retry !== \"rate_limit\") {\n await sleep(this.#backoff(attempt), options.signal);\n continue;\n }\n const code = timedOut() ? \"timeout\" : \"connection_error\";\n throw new SerpKiteError(\n 0,\n code,\n \"failed to read the response body\",\n undefined,\n res.headers,\n {\n cause: err,\n },\n );\n }\n cleanup();\n\n if (!res.ok) {\n const retryable = res.status === 429 || (res.status >= 500 && call.retry !== \"rate_limit\");\n if (canRetry && retryable) {\n await sleep(this.#retryDelay(attempt, res.headers), options.signal);\n continue;\n }\n throw errorFromResponse(res.status, res.headers, text);\n }\n\n options.onResponse?.(responseInfo(res));\n const type = res.headers.get(\"content-type\") ?? \"\";\n if (type.includes(\"json\")) {\n try {\n return JSON.parse(text) as T;\n } catch (err) {\n throw new SerpKiteError(\n res.status,\n \"invalid_response\",\n \"response is not valid JSON\",\n res.headers.get(\"x-request-id\") ?? undefined,\n res.headers,\n { cause: err },\n );\n }\n }\n return text as T;\n }\n }\n\n #backoff(attempt: number): number {\n const base = Math.min(this.retryDelayMs * 2 ** attempt, 8_000);\n return base / 2 + Math.random() * (base / 2);\n }\n\n #retryDelay(attempt: number, headers: Headers): number {\n const after = parseRetryAfter(headers.get(\"retry-after\"));\n return after === undefined ? this.#backoff(attempt) : Math.min(after, 60_000);\n }\n}\n\n// ── helpers ─────────────────────────────────────────────────────────────\n\n/** Builds `?a=1&b=2` from the defined values (empty string when there are none). */\nfunction query(params: Record<string, string | number | boolean | undefined>): string {\n const q = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== null) q.set(k, String(v));\n }\n const s = q.toString();\n return s ? `?${s}` : \"\";\n}\n\nfunction taskId(idOrTask: string | { id: string }): string {\n const id = typeof idOrTask === \"string\" ? idOrTask : idOrTask?.id;\n if (!id) throw new SerpKiteError(0, \"invalid_request\", \"a task id is required\");\n return id;\n}\n\n/** Parses Retry-After (seconds or an HTTP date) into milliseconds. */\nexport function parseRetryAfter(v: string | null): number | undefined {\n if (!v) return undefined;\n const secs = Number(v);\n if (Number.isFinite(secs)) return Math.max(0, secs * 1000);\n const at = Date.parse(v);\n return Number.isNaN(at) ? undefined : Math.max(0, at - Date.now());\n}\n\nfunction responseInfo(res: Response): ResponseInfo {\n const h = res.headers;\n const num = (name: string) => {\n const v = h.get(name);\n if (v === null || v === \"\") return undefined;\n const n = Number(v);\n return Number.isFinite(n) ? n : undefined;\n };\n const cache = h.get(\"x-cache\")?.toUpperCase();\n return {\n status: res.status,\n headers: h,\n requestId: h.get(\"x-request-id\") ?? undefined,\n creditsUsed: num(\"x-credits-used\"),\n creditsRemaining: num(\"x-credits-remaining\"),\n costUsd: num(\"x-cost-usd\"),\n cache: cache === \"HIT\" || cache === \"MISS\" ? cache : undefined,\n latencyMs: num(\"x-latency-ms\"),\n tokensEstimate: num(\"x-tokens-estimate\"),\n };\n}\n\nfunction withTimeout(outer: AbortSignal | undefined, ms: number) {\n const ctrl = new AbortController();\n let timedOut = false;\n const onAbort = () => ctrl.abort(outer?.reason);\n if (outer?.aborted) ctrl.abort(outer.reason);\n else outer?.addEventListener(\"abort\", onAbort, { once: true });\n const timer =\n ms > 0 && Number.isFinite(ms)\n ? setTimeout(() => {\n timedOut = true;\n ctrl.abort(new SerpKiteError(0, \"timeout\", `request timed out after ${ms} ms`));\n }, ms)\n : undefined;\n return {\n signal: ctrl.signal,\n timedOut: () => timedOut,\n cleanup: () => {\n if (timer !== undefined) clearTimeout(timer);\n outer?.removeEventListener(\"abort\", onAbort);\n },\n };\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(signal.reason);\n const t = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(t);\n reject(signal?.reason);\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\ntype EnvHost = {\n process?: { env?: Record<string, string | undefined> };\n Deno?: { env?: { get?: (name: string) => string | undefined } };\n document?: unknown;\n};\n\nfunction env(name: string): string | undefined {\n const g = globalThis as EnvHost;\n try {\n const v = g.process?.env?.[name];\n if (v) return v;\n } catch {\n // process.env may be a throwing proxy on some edge runtimes.\n }\n try {\n return g.Deno?.env?.get?.(name) || undefined;\n } catch {\n // Deno without --allow-env.\n return undefined;\n }\n}\n\nfunction isBrowser(): boolean {\n return typeof (globalThis as EnvHost).document !== \"undefined\";\n}\n","import type { BatchCreateEntry, BatchCreateError } from \"./types\";\n\n/** True when a `batches.create` entry was rejected instead of queued. */\nexport function isBatchError(entry: BatchCreateEntry): entry is BatchCreateError {\n return !(\"id\" in entry && typeof entry.id === \"string\") && \"error\" in entry && !!entry.error;\n}\n","import { SerpKiteError } from \"./errors\";\nimport type { WebhookEvent } from \"./types\";\n\n/** Options for {@link verifyWebhook}. */\nexport interface VerifyWebhookOptions {\n /** Reject deliveries whose timestamp is further than this from now. Default 300. */\n toleranceSeconds?: number;\n /** Current time in Unix seconds (tests). */\n now?: number;\n}\n\ntype HeaderSource = Headers | Record<string, string | string[] | undefined>;\n\nfunction header(headers: HeaderSource, name: string): string | undefined {\n if (typeof (headers as Headers).get === \"function\") {\n return (headers as Headers).get(name) ?? undefined;\n }\n const rec = headers as Record<string, string | string[] | undefined>;\n const key = Object.keys(rec).find((k) => k.toLowerCase() === name.toLowerCase());\n const v = key === undefined ? undefined : rec[key];\n return Array.isArray(v) ? v[0] : v;\n}\n\n/**\n * Checks a webhook delivery (any event: `batch.completed`, `crawl.completed`,\n * `monitor.results`): `X-SerpKite-Signature` must be\n * `v1=<hex HMAC-SHA256(secret, \"<X-SerpKite-Timestamp>.<raw body>\")>` and the\n * timestamp recent. Pass the raw request body exactly as received (not\n * re-serialised JSON). Uses Web Crypto (Node 18+, Deno, Bun, browsers).\n *\n * ```ts\n * const ok = await verifyWebhook(process.env.SERPKITE_WEBHOOK_SECRET!, rawBody, req.headers);\n * ```\n */\nexport async function verifyWebhook(\n secret: string,\n payload: string | Uint8Array,\n headers: HeaderSource,\n options: VerifyWebhookOptions = {},\n): Promise<boolean> {\n const signature = header(headers, \"x-serpkite-signature\");\n const ts = header(headers, \"x-serpkite-timestamp\");\n if (!secret || !signature?.startsWith(\"v1=\") || !ts || !/^\\d+$/.test(ts)) return false;\n const now = options.now ?? Math.floor(Date.now() / 1000);\n if (Math.abs(now - Number(ts)) > (options.toleranceSeconds ?? 300)) return false;\n\n const enc = new TextEncoder();\n const body = typeof payload === \"string\" ? enc.encode(payload) : payload;\n const prefix = enc.encode(`${ts}.`);\n const msg = new Uint8Array(prefix.length + body.length);\n msg.set(prefix);\n msg.set(body, prefix.length);\n const key = await crypto.subtle.importKey(\n \"raw\",\n enc.encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n const mac = new Uint8Array(await crypto.subtle.sign(\"HMAC\", key, msg));\n const want = Array.from(mac, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n const got = signature.slice(3).toLowerCase();\n if (got.length !== want.length) return false;\n let diff = 0;\n for (let i = 0; i < want.length; i++) diff |= want.charCodeAt(i) ^ got.charCodeAt(i);\n return diff === 0;\n}\n\n/**\n * Verifies a delivery (see {@link verifyWebhook}) and returns it typed by its\n * `X-SerpKite-Event` header. `deliveryId` is `X-SerpKite-Delivery` (for\n * `monitor.results` it equals `data.run_id`): use it to deduplicate retries. A\n * `crawl.completed` result over 4 MB arrives as `result: null` with\n * `result_omitted: true`; fetch it from `data.poll_url`. Throws a\n * `SerpKiteError` with code `invalid_signature` when the signature or timestamp\n * doesn't check out.\n *\n * ```ts\n * const ev = await parseWebhook(secret, rawBody, req.headers);\n * if (ev.type === \"monitor.results\") console.log(ev.data.new_results.length);\n * ```\n */\nexport async function parseWebhook(\n secret: string,\n payload: string | Uint8Array,\n headers: HeaderSource,\n options: VerifyWebhookOptions = {},\n): Promise<WebhookEvent> {\n if (!(await verifyWebhook(secret, payload, headers, options))) {\n throw new SerpKiteError(400, \"invalid_signature\", \"webhook signature or timestamp is invalid\");\n }\n const text = typeof payload === \"string\" ? payload : new TextDecoder().decode(payload);\n let data: { event?: unknown };\n try {\n data = JSON.parse(text);\n } catch (err) {\n throw new SerpKiteError(\n 400,\n \"invalid_payload\",\n \"webhook body is not JSON\",\n undefined,\n undefined,\n {\n cause: err,\n },\n );\n }\n const type =\n header(headers, \"x-serpkite-event\") ??\n (typeof data?.event === \"string\" ? data.event : \"batch.completed\");\n return { type, deliveryId: header(headers, \"x-serpkite-delivery\"), data } as WebhookEvent;\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/util.ts","../src/webhooks.ts"],"names":[],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Every failure thrown by the SDK. API errors carry the fields of the\n * `{\"error\":{\"code\",\"message\",\"request_id\"}}` envelope; network failures and\n * timeouts use `status: 0` with code `connection_error` or `timeout`.\n */\nexport class SerpKiteError extends Error {\n /** HTTP status, or 0 when no response was received. */\n readonly status: number;\n /** Machine-readable code, e.g. `unauthorized`, `insufficient_credits`, `rate_limited`. */\n readonly code: string;\n /** `X-Request-Id` of the failed request, when the API returned one. */\n readonly requestId: string | undefined;\n /** Response headers, when the API responded. */\n readonly headers: Headers | undefined;\n\n constructor(\n status: number,\n code: string,\n message: string,\n requestId?: string,\n headers?: Headers,\n options?: { cause?: unknown },\n ) {\n super(message, options);\n this.name = \"SerpKiteError\";\n this.status = status;\n this.code = code;\n this.requestId = requestId || undefined;\n this.headers = headers;\n }\n}\n\nconst fallbackCodes: Record<number, string> = {\n 400: \"invalid_request\",\n 401: \"unauthorized\",\n 402: \"insufficient_credits\",\n 403: \"forbidden\",\n 404: \"not_found\",\n 429: \"rate_limited\",\n // The API sends upstream failures as 503 with a JSON body; a bare 502/504\n // comes from a proxy (Cloudflare replaces origin 502/504 bodies).\n 502: \"upstream_error\",\n 503: \"unavailable\",\n 504: \"upstream_timeout\",\n};\n\n/** Builds a SerpKiteError from a non-2xx response body (JSON envelope or anything else). */\nexport function errorFromResponse(status: number, headers: Headers, body: string): SerpKiteError {\n let code = fallbackCodes[status] ?? (status >= 500 ? \"server_error\" : \"http_error\");\n let message = body.trim().slice(0, 500) || `HTTP ${status}`;\n let requestId = headers.get(\"x-request-id\") ?? undefined;\n try {\n const parsed = JSON.parse(body) as {\n error?: { code?: unknown; message?: unknown; request_id?: unknown };\n };\n const e = parsed?.error;\n if (e && typeof e === \"object\") {\n if (typeof e.code === \"string\" && e.code) code = e.code;\n if (typeof e.message === \"string\" && e.message) message = e.message;\n if (typeof e.request_id === \"string\" && e.request_id) requestId = e.request_id;\n }\n } catch {\n // Not JSON: keep the text body as the message.\n }\n return new SerpKiteError(status, code, message, requestId, headers);\n}\n","import { errorFromResponse, SerpKiteError } from \"./errors\";\nimport type {\n Account,\n AutocompleteResponse,\n Batch,\n BatchCreateEntry,\n BatchCreateParams,\n BatchCreateResponse,\n CompactResponse,\n CrawlParams,\n CrawlTask,\n ExtractParams,\n ExtractResponse,\n ImagesResponse,\n MapParams,\n MapResponse,\n Monitor,\n MonitorCreateParams,\n MonitorList,\n MonitorRun,\n MonitorRunList,\n MonitorRunsParams,\n MonitorUpdateParams,\n NewsResponse,\n PatentsResponse,\n PlaceParams,\n PlacesResponse,\n RankParams,\n RankResponse,\n ReviewsParams,\n ReviewsResponse,\n ScholarResponse,\n SearchParams,\n SearchResponse,\n ShoppingResponse,\n TaskCancelResponse,\n TaskCreated,\n VideosResponse,\n WebpageParams,\n WebpageResponse,\n} from \"./types\";\n\nexport const VERSION = \"0.6.0\";\nexport const DEFAULT_BASE_URL = \"https://api.serpkite.com\";\n\nexport interface SerpKiteOptions {\n /** API key (`skt_live_…`). Defaults to the `SERPKITE_API_KEY` environment variable. */\n apiKey?: string;\n /** Defaults to `SERPKITE_BASE_URL` or https://api.serpkite.com. */\n baseUrl?: string;\n /** Per-attempt timeout in milliseconds. Default 60000. */\n timeoutMs?: number;\n /** Retries after the first attempt on 429, 5xx and network errors. Default 2. */\n maxRetries?: number;\n /** Base delay of the exponential backoff in milliseconds. Default 500. */\n retryDelayMs?: number;\n /** Custom fetch implementation. Defaults to the global `fetch`. */\n fetch?: typeof fetch;\n /** Extra headers sent with every request. */\n headers?: Record<string, string>;\n}\n\n/** Billing and tracing details from the response headers. */\nexport interface ResponseInfo {\n status: number;\n headers: Headers;\n requestId: string | undefined;\n creditsUsed: number | undefined;\n creditsRemaining: number | undefined;\n costUsd: number | undefined;\n /** `HIT` when served from cache (`max_age`), else `MISS`. */\n cache: \"HIT\" | \"MISS\" | undefined;\n latencyMs: number | undefined;\n tokensEstimate: number | undefined;\n}\n\nexport interface RequestOptions {\n signal?: AbortSignal;\n /** Overrides the client's per-attempt timeout. */\n timeoutMs?: number;\n /** Overrides the client's retry count. */\n maxRetries?: number;\n headers?: Record<string, string>;\n /** Called with the final response's headers (credits used/remaining, cache, request id). */\n onResponse?: (info: ResponseInfo) => void;\n}\n\nexport interface BatchCreateOptions extends RequestOptions {\n /**\n * Sent as `Idempotency-Key` (1-255 printable ASCII characters, e.g. a UUID).\n * For 24 hours a retry with the same key and body returns the first response\n * instead of queueing and billing the jobs again.\n */\n idempotencyKey?: string;\n}\n\nexport interface WaitOptions {\n /**\n * Give up after this many milliseconds. Default 600000 (10 minutes) for batches and\n * 2100000 (35 minutes) for `waitForCrawl`: a crawl runs for up to 30 minutes.\n */\n timeoutMs?: number;\n /** First delay between polls. Default 1000. Grows 1.5× per poll. */\n pollIntervalMs?: number;\n /** Upper bound of the delay between polls. Default 10000. */\n maxPollIntervalMs?: number;\n signal?: AbortSignal;\n}\n\n/** A vertical whose return type follows `format`: `\"markdown\"` → string, `\"compact\"` → CompactResponse. */\nexport interface VerticalMethod<P, R> {\n (params: P & { format: \"markdown\" }, options?: RequestOptions): Promise<string>;\n (params: P & { format: \"compact\" }, options?: RequestOptions): Promise<CompactResponse>;\n (params: P & { format?: \"json\" }, options?: RequestOptions): Promise<R>;\n (params: P, options?: RequestOptions): Promise<R | CompactResponse | string>;\n}\n\ntype Method = \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\";\n\n/** Task states after which `waitForCrawl` returns. */\nconst TASK_DONE = new Set([\"completed\", \"failed\", \"canceled\"]);\n\ninterface Call {\n method: Method;\n path: string;\n body?: unknown;\n options?: RequestOptions;\n /** Which failures are safe to retry. `all` = 429, 5xx and network errors. */\n retry?: \"all\" | \"rate_limit\";\n}\n\nexport class SerpKite {\n readonly baseUrl: string;\n readonly timeoutMs: number;\n readonly maxRetries: number;\n readonly retryDelayMs: number;\n readonly #apiKey: string;\n readonly #fetch: typeof fetch;\n readonly #headers: Record<string, string>;\n\n constructor(options: SerpKiteOptions = {}) {\n const apiKey = options.apiKey ?? env(\"SERPKITE_API_KEY\");\n if (!apiKey) {\n throw new SerpKiteError(\n 0,\n \"missing_api_key\",\n \"No API key: pass { apiKey } or set the SERPKITE_API_KEY environment variable\",\n );\n }\n this.#apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? env(\"SERPKITE_BASE_URL\") ?? DEFAULT_BASE_URL).replace(\n /\\/+$/,\n \"\",\n );\n this.timeoutMs = options.timeoutMs ?? 60_000;\n this.maxRetries = Math.max(0, options.maxRetries ?? 2);\n this.retryDelayMs = options.retryDelayMs ?? 500;\n const f = options.fetch ?? globalThis.fetch;\n if (typeof f !== \"function\") {\n throw new SerpKiteError(\n 0,\n \"missing_fetch\",\n \"No global fetch: pass { fetch } (Node 18+ has one)\",\n );\n }\n this.#fetch = f;\n this.#headers = { ...options.headers };\n }\n\n // ── Verticals ─────────────────────────────────────────────────────────\n\n /** Google web search: organic results, answer box, knowledge graph, people also ask… */\n readonly search = this.#vertical<SearchParams, SearchResponse>(\"/v1/search\");\n /** Google Images. */\n readonly images = this.#vertical<SearchParams, ImagesResponse>(\"/v1/images\");\n /** Google Videos. */\n readonly videos = this.#vertical<SearchParams, VideosResponse>(\"/v1/videos\");\n /** Google News. */\n readonly news = this.#vertical<SearchParams, NewsResponse>(\"/v1/news\");\n /**\n * Google Maps search (places with coordinates). Accepts `ll` (\"@lat,lng,14z\"). With\n * `engine: \"yandex\"` (where enabled) the places come from Yandex Maps and carry an `oid`.\n */\n readonly maps = this.#vertical<SearchParams, PlacesResponse>(\"/v1/maps\");\n /** Google local results. */\n readonly places = this.#vertical<SearchParams, PlacesResponse>(\"/v1/places\");\n /**\n * Details of one place by `place_id`, `cid` or `fid`, or by a Yandex Maps `oid` (implies\n * `engine: \"yandex\"`): address, country, time zone, hours\n * (`opening_hours` text and structured `weekly_hours`), phones, description and photos.\n * `results` holds the place, or is empty (not charged) when no place has that id. 1 credit.\n */\n readonly place = this.#vertical<PlaceParams, PlacesResponse>(\"/v1/place\");\n /** Reviews of a place by `place_id`, `cid` or `fid`. Page with `page_token` = `next_page_token`. */\n readonly reviews = this.#vertical<ReviewsParams, ReviewsResponse>(\"/v1/reviews\");\n /** Google Shopping. */\n readonly shopping = this.#vertical<SearchParams, ShoppingResponse>(\"/v1/shopping\");\n /** Google Scholar. */\n readonly scholar = this.#vertical<SearchParams, ScholarResponse>(\"/v1/scholar\");\n /** Google Patents. */\n readonly patents = this.#vertical<SearchParams, PatentsResponse>(\"/v1/patents\");\n /** Google autocomplete suggestions. */\n readonly autocomplete = this.#vertical<SearchParams, AutocompleteResponse>(\"/v1/autocomplete\");\n /** Fetch any public URL as clean Markdown plus metadata. */\n readonly webpage = this.#vertical<WebpageParams, WebpageResponse>(\"/v1/webpage\");\n\n /** Position of `domain` for keyword `q` in the top `num` results (default 100). */\n rank(params: RankParams, options?: RequestOptions): Promise<RankResponse> {\n return this.request({ method: \"POST\", path: \"/v1/rank\", body: params, options });\n }\n\n /**\n * Read up to 20 URLs (HTML or PDF) as Markdown, text or HTML in one call, with optional\n * query-ranked `highlights` (BM25), `include_links` and `include_images`. 1 credit per URL\n * that comes back (0.5 from cache); URLs that fail are listed in `failed` and cost nothing.\n */\n extract(params: ExtractParams, options?: RequestOptions): Promise<ExtractResponse> {\n // Billed per page even when the response is lost: retried only on 429,\n // and the HTTP timeout covers the server's deadline (timeout, default 50 s) + 15 s.\n const wait = ((params.timeout ?? 50) + 15) * 1000;\n return this.request({\n method: \"POST\",\n path: \"/v1/extract\",\n body: params,\n options: {\n ...options,\n timeoutMs: options?.timeoutMs ?? (this.timeoutMs > 0 ? Math.max(this.timeoutMs, wait) : 0),\n },\n retry: \"rate_limit\",\n });\n }\n\n /**\n * The URLs of a site from its sitemaps (XML, RSS/Atom, gzip, plain text) and start page,\n * canonicalised and deduplicated, optionally ranked by `search`. `include_paths` /\n * `exclude_paths` (regular expressions on the URL path) and `ignore_query_parameters`\n * narrow the list. 1 credit; free when nothing is found.\n */\n map(params: MapParams, options?: RequestOptions): Promise<MapResponse> {\n return this.request({ method: \"POST\", path: \"/v1/map\", body: params, options });\n }\n\n /** Balance, limits and this month's usage for the key's account. */\n account(options?: RequestOptions): Promise<Account> {\n return this.request({ method: \"GET\", path: \"/v1/account\", options });\n }\n\n // ── Async tasks: crawl ────────────────────────────────────────────────\n\n /**\n * Starts an async crawl of one site and returns the queued task (`202`). 1 credit per page\n * read (0.5 from cache); `limit` credits (up to 1000 pages, `max_depth` up to 10) are\n * reserved up front and the rest refunded. `sitemap` (`include` default, `only`, `skip`)\n * seeds the crawl with sitemap URLs; `query` reads the most relevant pages first. robots.txt\n * and Crawl-delay are honoured; `result.stats.stopped` says why the crawl ended (`done`,\n * `limit`, `time_limit`, `size_limit`, `too_many_failures`, `canceled`).\n * Only retried on 429, so a lost response never starts (and reserves) a second crawl.\n */\n crawl(params: CrawlParams, options?: RequestOptions): Promise<TaskCreated> {\n return this.request({\n method: \"POST\",\n path: \"/v1/crawl\",\n body: params,\n options,\n retry: \"rate_limit\",\n });\n }\n\n /** Polls a crawl (results are kept for 24 hours). */\n getCrawl(id: string, options?: RequestOptions): Promise<CrawlTask> {\n return this.request({ method: \"GET\", path: `/v1/crawl/${encodeURIComponent(id)}`, options });\n }\n\n /** Cancels a crawl: refunded if still queued, else stops at the next checkpoint. */\n cancelCrawl(id: string, options?: RequestOptions): Promise<TaskCancelResponse> {\n return this.request({\n method: \"DELETE\",\n path: `/v1/crawl/${encodeURIComponent(id)}`,\n options,\n });\n }\n\n /**\n * Polls until the crawl is `completed`, `failed` or `canceled` and returns it (a failed\n * task is returned, not thrown; check `status` and `error`). Accepts an id or the task\n * returned by `crawl`.\n */\n async waitForCrawl(\n idOrTask: string | { id: string },\n options: WaitOptions = {},\n ): Promise<CrawlTask> {\n return this.#waitTask(taskId(idOrTask), (id) => this.getCrawl(id, { signal: options.signal }), {\n ...options,\n timeoutMs: options.timeoutMs ?? 2_100_000,\n });\n }\n\n // ── Monitors ──────────────────────────────────────────────────────────\n\n readonly monitors = {\n /**\n * Saves a `search` or `news` request (`q`) that runs on a schedule (hourly to monthly) and\n * POSTs results it hasn't seen before to `webhook_url` (`monitor.results`). With\n * `endpoint: \"webpage\"` and a `url` it checks that page each interval (1 credit per check)\n * and reports it (`MonitorPageChange`) when its content changes. `metadata` (your JSON\n * object, at most 2 KB) is echoed on the monitor and in its webhooks. Without a\n * `webhook_url`, read new results from `monitors.runs`. `active: false`\n * creates it paused. A monitor pauses itself after 10 failed runs in a row\n * (`last_status: \"paused\"`); `update(id, { active: true })` resumes it. Each run costs\n * what its search costs. Only retried on 429.\n */\n create: (params: MonitorCreateParams, options?: RequestOptions): Promise<Monitor> =>\n this.request({\n method: \"POST\",\n path: \"/v1/monitors\",\n body: params,\n options,\n retry: \"rate_limit\",\n }),\n\n /** The account's monitors. */\n list: (options?: RequestOptions): Promise<MonitorList> =>\n this.request({ method: \"GET\", path: \"/v1/monitors\", options }),\n\n get: (id: string, options?: RequestOptions): Promise<Monitor> =>\n this.request({ method: \"GET\", path: `/v1/monitors/${encodeURIComponent(id)}`, options }),\n\n /**\n * Changes `name`, `interval` / `interval_seconds`, `webhook_url` (`\"\"` removes it),\n * `active` (`true` resumes a paused monitor), `metadata` (an object replaces it, `null`\n * clears it) or the saved request (`endpoint`, `q`, `url`, `country`, `num`, domains,\n * `engine`…). Switching `endpoint` between a search and `webpage` drops the other kind's\n * fields. A changed search reports every result as new on the next run.\n */\n update: (id: string, params: MonitorUpdateParams, options?: RequestOptions): Promise<Monitor> =>\n this.request({\n method: \"PATCH\",\n path: `/v1/monitors/${encodeURIComponent(id)}`,\n body: params,\n options,\n }),\n\n delete: async (id: string, options?: RequestOptions): Promise<void> => {\n await this.request({\n method: \"DELETE\",\n path: `/v1/monitors/${encodeURIComponent(id)}`,\n options,\n });\n },\n\n /** Runs an active monitor at the next scheduler poll (within about 30 seconds).\n * Paused monitors return 409; update(id, { active: true }) resumes and schedules them. */\n run: (id: string, options?: RequestOptions): Promise<Monitor> =>\n this.request({\n method: \"POST\",\n path: `/v1/monitors/${encodeURIComponent(id)}/run`,\n options,\n retry: \"rate_limit\",\n }),\n\n /**\n * One page of the monitor's run history, newest first (`limit` 1-100, default 20). Each\n * run carries its new results for 24 hours. Pass `next_before` as `before` for the next\n * page; it is null on the last one.\n */\n runs: (\n id: string,\n params: MonitorRunsParams = {},\n options?: RequestOptions,\n ): Promise<MonitorRunList> =>\n this.request({\n method: \"GET\",\n path: `/v1/monitors/${encodeURIComponent(id)}/runs${query(params)}`,\n options,\n }),\n\n /**\n * Iterates over every run of the monitor, newest first, fetching pages of `limit` as\n * needed (starting at `before` when given).\n *\n * ```ts\n * for await (const run of sk.monitors.iterRuns(\"m1\")) console.log(run.new_results);\n * ```\n */\n iterRuns: (\n id: string,\n params: MonitorRunsParams = {},\n options?: RequestOptions,\n ): AsyncIterable<MonitorRun> => this.#iterRuns(id, params, options),\n };\n\n // ── Batches ───────────────────────────────────────────────────────────\n\n readonly batches = {\n /**\n * Queue 1-100 requests for one endpoint at half price. Returns one entry per\n * request, in order: a queued `Batch` or an error object. Without an\n * `idempotencyKey` it is only retried on 429, so a lost response never queues\n * (and bills) the same requests twice. With one, 5xx and network errors are\n * retried too: the server replays the first response for the same key and body.\n */\n create: (\n params: BatchCreateParams,\n options: BatchCreateOptions = {},\n ): Promise<BatchCreateResponse> => {\n const { idempotencyKey, ...rest } = options;\n return this.request({\n method: \"POST\",\n path: \"/v1/batches\",\n body: params,\n options: idempotencyKey\n ? { ...rest, headers: { ...rest.headers, \"Idempotency-Key\": idempotencyKey } }\n : rest,\n retry: idempotencyKey ? \"all\" : \"rate_limit\",\n });\n },\n\n /** Poll one batch job. */\n get: (id: string, options?: RequestOptions): Promise<Batch> =>\n this.request({ method: \"GET\", path: `/v1/batches/${encodeURIComponent(id)}`, options }),\n\n /**\n * Poll until the job is `done` or `failed` and return it (a failed job is\n * returned, not thrown; check `status` and `error`). Accepts an id or an\n * entry from `create`; an entry that failed to queue throws its error.\n */\n wait: (idOrEntry: string | BatchCreateEntry | undefined, options: WaitOptions = {}) =>\n this.#wait(idOrEntry, options),\n };\n\n // ── Plumbing ──────────────────────────────────────────────────────────\n\n async *#iterRuns(\n id: string,\n params: MonitorRunsParams,\n options?: RequestOptions,\n ): AsyncGenerator<MonitorRun> {\n let before = params.before;\n for (;;) {\n const page = await this.monitors.runs(id, { ...params, before }, options);\n yield* page.results;\n if (!page.next_before || page.results.length === 0) return;\n before = page.next_before;\n }\n }\n\n async #waitTask<T extends { status: string }>(\n id: string,\n get: (id: string) => Promise<T>,\n o: WaitOptions,\n ): Promise<T> {\n const timeoutMs = o.timeoutMs ?? 600_000;\n const maxInterval = o.maxPollIntervalMs ?? 10_000;\n let interval = o.pollIntervalMs ?? 1_000;\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n const task = await get(id);\n if (TASK_DONE.has(task.status)) return task;\n const left = deadline - Date.now();\n if (left <= 0) {\n throw new SerpKiteError(\n 0,\n \"timeout\",\n `task ${id} still ${task.status} after ${timeoutMs} ms`,\n );\n }\n await sleep(Math.min(interval, left), o.signal);\n interval = Math.min(interval * 1.5, maxInterval);\n }\n }\n\n #vertical<P, R>(path: string): VerticalMethod<P, R> {\n return ((params: P, options?: RequestOptions) =>\n this.request({ method: \"POST\", path, body: params, options })) as VerticalMethod<P, R>;\n }\n\n async #wait(idOrEntry: string | BatchCreateEntry | undefined, o: WaitOptions): Promise<Batch> {\n let id: string | undefined;\n if (typeof idOrEntry === \"string\") {\n id = idOrEntry;\n } else if (idOrEntry && \"id\" in idOrEntry && typeof idOrEntry.id === \"string\") {\n id = idOrEntry.id;\n } else if (idOrEntry && \"error\" in idOrEntry && idOrEntry.error && !(\"id\" in idOrEntry)) {\n const e = idOrEntry.error as { code?: string; message?: string; request_id?: string };\n throw new SerpKiteError(\n 400,\n e.code ?? \"invalid_request\",\n e.message ?? \"batch entry was not queued\",\n e.request_id,\n );\n }\n if (!id) {\n throw new SerpKiteError(0, \"invalid_request\", \"batches.wait needs a batch id\");\n }\n const timeoutMs = o.timeoutMs ?? 600_000;\n const maxInterval = o.maxPollIntervalMs ?? 10_000;\n let interval = o.pollIntervalMs ?? 1_000;\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n const batch = await this.batches.get(id, { signal: o.signal });\n if (batch.status === \"done\" || batch.status === \"failed\") return batch;\n const left = deadline - Date.now();\n if (left <= 0) {\n throw new SerpKiteError(\n 0,\n \"timeout\",\n `batch ${id} still ${batch.status} after ${timeoutMs} ms`,\n );\n }\n await sleep(Math.min(interval, left), o.signal);\n interval = Math.min(interval * 1.5, maxInterval);\n }\n }\n\n /** Low-level request: JSON body in, parsed JSON (or text for non-JSON responses) out. */\n async request<T>(call: Call): Promise<T> {\n const { method, path, body, options = {} } = call;\n const maxRetries = Math.max(0, options.maxRetries ?? this.maxRetries);\n const timeoutMs = options.timeoutMs ?? this.timeoutMs;\n const headers: Record<string, string> = {\n Accept: \"application/json, text/markdown;q=0.9\",\n Authorization: `Bearer ${this.#apiKey}`,\n ...this.#headers,\n ...options.headers,\n };\n if (body !== undefined) headers[\"Content-Type\"] = \"application/json\";\n // Browsers would turn a custom User-Agent into a CORS preflight header.\n if (!isBrowser()) headers[\"User-Agent\"] = `serpkite-typescript/${VERSION}`;\n const init: RequestInit = {\n method,\n headers,\n body: body === undefined ? undefined : JSON.stringify(body),\n };\n\n for (let attempt = 0; ; attempt++) {\n const canRetry = attempt < maxRetries;\n let res: Response;\n const { signal, cleanup, timedOut } = withTimeout(options.signal, timeoutMs);\n try {\n res = await this.#fetch(this.baseUrl + path, { ...init, signal });\n } catch (err) {\n cleanup();\n if (options.signal?.aborted) throw err;\n const code = timedOut() ? \"timeout\" : \"connection_error\";\n if (canRetry && call.retry !== \"rate_limit\") {\n await sleep(this.#backoff(attempt), options.signal);\n continue;\n }\n const msg = timedOut()\n ? `request timed out after ${timeoutMs} ms`\n : `request failed: ${err instanceof Error ? err.message : String(err)}`;\n throw new SerpKiteError(0, code, msg, undefined, undefined, { cause: err });\n }\n\n let text: string;\n try {\n text = await res.text();\n } catch (err) {\n cleanup();\n if (options.signal?.aborted) throw err;\n if (canRetry && call.retry !== \"rate_limit\") {\n await sleep(this.#backoff(attempt), options.signal);\n continue;\n }\n const code = timedOut() ? \"timeout\" : \"connection_error\";\n throw new SerpKiteError(\n 0,\n code,\n \"failed to read the response body\",\n undefined,\n res.headers,\n {\n cause: err,\n },\n );\n }\n cleanup();\n\n if (!res.ok) {\n const retryable = res.status === 429 || (res.status >= 500 && call.retry !== \"rate_limit\");\n if (canRetry && retryable) {\n await sleep(this.#retryDelay(attempt, res.headers), options.signal);\n continue;\n }\n throw errorFromResponse(res.status, res.headers, text);\n }\n\n options.onResponse?.(responseInfo(res));\n const type = res.headers.get(\"content-type\") ?? \"\";\n if (type.includes(\"json\")) {\n try {\n return JSON.parse(text) as T;\n } catch (err) {\n throw new SerpKiteError(\n res.status,\n \"invalid_response\",\n \"response is not valid JSON\",\n res.headers.get(\"x-request-id\") ?? undefined,\n res.headers,\n { cause: err },\n );\n }\n }\n return text as T;\n }\n }\n\n #backoff(attempt: number): number {\n const base = Math.min(this.retryDelayMs * 2 ** attempt, 8_000);\n return base / 2 + Math.random() * (base / 2);\n }\n\n #retryDelay(attempt: number, headers: Headers): number {\n const after = parseRetryAfter(headers.get(\"retry-after\"));\n return after === undefined ? this.#backoff(attempt) : Math.min(after, 60_000);\n }\n}\n\n// ── helpers ─────────────────────────────────────────────────────────────\n\n/** Builds `?a=1&b=2` from the defined values (empty string when there are none). */\nfunction query(params: Record<string, string | number | boolean | undefined>): string {\n const q = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== null) q.set(k, String(v));\n }\n const s = q.toString();\n return s ? `?${s}` : \"\";\n}\n\nfunction taskId(idOrTask: string | { id: string }): string {\n const id = typeof idOrTask === \"string\" ? idOrTask : idOrTask?.id;\n if (!id) throw new SerpKiteError(0, \"invalid_request\", \"a task id is required\");\n return id;\n}\n\n/** Parses Retry-After (seconds or an HTTP date) into milliseconds. */\nexport function parseRetryAfter(v: string | null): number | undefined {\n if (!v) return undefined;\n const secs = Number(v);\n if (Number.isFinite(secs)) return Math.max(0, secs * 1000);\n const at = Date.parse(v);\n return Number.isNaN(at) ? undefined : Math.max(0, at - Date.now());\n}\n\nfunction responseInfo(res: Response): ResponseInfo {\n const h = res.headers;\n const num = (name: string) => {\n const v = h.get(name);\n if (v === null || v === \"\") return undefined;\n const n = Number(v);\n return Number.isFinite(n) ? n : undefined;\n };\n const cache = h.get(\"x-cache\")?.toUpperCase();\n return {\n status: res.status,\n headers: h,\n requestId: h.get(\"x-request-id\") ?? undefined,\n creditsUsed: num(\"x-credits-used\"),\n creditsRemaining: num(\"x-credits-remaining\"),\n costUsd: num(\"x-cost-usd\"),\n cache: cache === \"HIT\" || cache === \"MISS\" ? cache : undefined,\n latencyMs: num(\"x-latency-ms\"),\n tokensEstimate: num(\"x-tokens-estimate\"),\n };\n}\n\nfunction withTimeout(outer: AbortSignal | undefined, ms: number) {\n const ctrl = new AbortController();\n let timedOut = false;\n const onAbort = () => ctrl.abort(outer?.reason);\n if (outer?.aborted) ctrl.abort(outer.reason);\n else outer?.addEventListener(\"abort\", onAbort, { once: true });\n const timer =\n ms > 0 && Number.isFinite(ms)\n ? setTimeout(() => {\n timedOut = true;\n ctrl.abort(new SerpKiteError(0, \"timeout\", `request timed out after ${ms} ms`));\n }, ms)\n : undefined;\n return {\n signal: ctrl.signal,\n timedOut: () => timedOut,\n cleanup: () => {\n if (timer !== undefined) clearTimeout(timer);\n outer?.removeEventListener(\"abort\", onAbort);\n },\n };\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(signal.reason);\n const t = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(t);\n reject(signal?.reason);\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\ntype EnvHost = {\n process?: { env?: Record<string, string | undefined> };\n Deno?: { env?: { get?: (name: string) => string | undefined } };\n document?: unknown;\n};\n\nfunction env(name: string): string | undefined {\n const g = globalThis as EnvHost;\n try {\n const v = g.process?.env?.[name];\n if (v) return v;\n } catch {\n // process.env may be a throwing proxy on some edge runtimes.\n }\n try {\n return g.Deno?.env?.get?.(name) || undefined;\n } catch {\n // Deno without --allow-env.\n return undefined;\n }\n}\n\nfunction isBrowser(): boolean {\n return typeof (globalThis as EnvHost).document !== \"undefined\";\n}\n","import type { BatchCreateEntry, BatchCreateError } from \"./types\";\n\n/** True when a `batches.create` entry was rejected instead of queued. */\nexport function isBatchError(entry: BatchCreateEntry): entry is BatchCreateError {\n return !(\"id\" in entry && typeof entry.id === \"string\") && \"error\" in entry && !!entry.error;\n}\n","import { SerpKiteError } from \"./errors\";\nimport type { WebhookEvent } from \"./types\";\n\n/** Options for {@link verifyWebhook}. */\nexport interface VerifyWebhookOptions {\n /** Reject deliveries whose timestamp is further than this from now. Default 300. */\n toleranceSeconds?: number;\n /** Current time in Unix seconds (tests). */\n now?: number;\n}\n\ntype HeaderSource = Headers | Record<string, string | string[] | undefined>;\n\nfunction header(headers: HeaderSource, name: string): string | undefined {\n if (typeof (headers as Headers).get === \"function\") {\n return (headers as Headers).get(name) ?? undefined;\n }\n const rec = headers as Record<string, string | string[] | undefined>;\n const key = Object.keys(rec).find((k) => k.toLowerCase() === name.toLowerCase());\n const v = key === undefined ? undefined : rec[key];\n return Array.isArray(v) ? v[0] : v;\n}\n\n/**\n * Checks a webhook delivery (any event: `batch.completed`, `crawl.completed`,\n * `monitor.results`): `X-SerpKite-Signature` must be\n * `v1=<hex HMAC-SHA256(secret, \"<X-SerpKite-Timestamp>.<raw body>\")>` and the\n * timestamp recent. Pass the raw request body exactly as received (not\n * re-serialised JSON). Uses Web Crypto (Node 18+, Deno, Bun, browsers).\n *\n * ```ts\n * const ok = await verifyWebhook(process.env.SERPKITE_WEBHOOK_SECRET!, rawBody, req.headers);\n * ```\n */\nexport async function verifyWebhook(\n secret: string,\n payload: string | Uint8Array,\n headers: HeaderSource,\n options: VerifyWebhookOptions = {},\n): Promise<boolean> {\n const signature = header(headers, \"x-serpkite-signature\");\n const ts = header(headers, \"x-serpkite-timestamp\");\n if (!secret || !signature?.startsWith(\"v1=\") || !ts || !/^\\d+$/.test(ts)) return false;\n const now = options.now ?? Math.floor(Date.now() / 1000);\n if (Math.abs(now - Number(ts)) > (options.toleranceSeconds ?? 300)) return false;\n\n const enc = new TextEncoder();\n const body = typeof payload === \"string\" ? enc.encode(payload) : payload;\n const prefix = enc.encode(`${ts}.`);\n const msg = new Uint8Array(prefix.length + body.length);\n msg.set(prefix);\n msg.set(body, prefix.length);\n const key = await crypto.subtle.importKey(\n \"raw\",\n enc.encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n const mac = new Uint8Array(await crypto.subtle.sign(\"HMAC\", key, msg));\n const want = Array.from(mac, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n const got = signature.slice(3).toLowerCase();\n if (got.length !== want.length) return false;\n let diff = 0;\n for (let i = 0; i < want.length; i++) diff |= want.charCodeAt(i) ^ got.charCodeAt(i);\n return diff === 0;\n}\n\n/**\n * Verifies a delivery (see {@link verifyWebhook}) and returns it typed by its\n * `X-SerpKite-Event` header. `deliveryId` is `X-SerpKite-Delivery` (for\n * `monitor.results` it equals `data.run_id`): use it to deduplicate retries. A\n * `crawl.completed` result over 4 MB arrives as `result: null` with\n * `result_omitted: true`; fetch it from `data.poll_url`. Throws a\n * `SerpKiteError` with code `invalid_signature` when the signature or timestamp\n * doesn't check out.\n *\n * ```ts\n * const ev = await parseWebhook(secret, rawBody, req.headers);\n * if (ev.type === \"monitor.results\") console.log(ev.data.new_results.length);\n * ```\n */\nexport async function parseWebhook(\n secret: string,\n payload: string | Uint8Array,\n headers: HeaderSource,\n options: VerifyWebhookOptions = {},\n): Promise<WebhookEvent> {\n if (!(await verifyWebhook(secret, payload, headers, options))) {\n throw new SerpKiteError(400, \"invalid_signature\", \"webhook signature or timestamp is invalid\");\n }\n const text = typeof payload === \"string\" ? payload : new TextDecoder().decode(payload);\n let data: { event?: unknown };\n try {\n data = JSON.parse(text);\n } catch (err) {\n throw new SerpKiteError(\n 400,\n \"invalid_payload\",\n \"webhook body is not JSON\",\n undefined,\n undefined,\n {\n cause: err,\n },\n );\n }\n const type =\n header(headers, \"x-serpkite-event\") ??\n (typeof data?.event === \"string\" ? data.event : \"batch.completed\");\n return { type, deliveryId: header(headers, \"x-serpkite-delivery\"), data } as WebhookEvent;\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -166,6 +166,13 @@ interface paths {
166
166
  * (or `uule`) searches the named place. Without either, Google picks the area from the
167
167
  * query (an exact name or address) or from where the request comes from, so local queries
168
168
  * such as "coffee" need `location` or `ll`.
169
+ *
170
+ * **Yandex Maps:** with `engine=yandex` (where the deployment enables it) the results come
171
+ * from Yandex Maps, which covers Russia and the CIS in depth. They have the same fields,
172
+ * with the Yandex organisation id in `oid` (for `/v1/place`) and `yandex_maps_url` instead
173
+ * of Google's identifiers; categories, addresses and hours follow `language` (`ru` for
174
+ * Russian). Pass `ll` or a `location` (a city, appended to the query); `uule` and `tbs`
175
+ * are refused.
169
176
  */
170
177
  post: operations["maps"];
171
178
  delete?: never;
@@ -204,11 +211,16 @@ interface paths {
204
211
  get?: never;
205
212
  put?: never;
206
213
  /**
207
- * Details of one place (by `place_id`, `cid` or `fid`); 1 credit
214
+ * Details of one place (by `place_id`, `cid`, `fid` or Yandex `oid`); 1 credit
208
215
  * @description The full Google Maps listing of one place: address, country, coordinates, time zone,
209
216
  * categories, opening hours (as text and as structured `weekly_hours`), website, phone,
210
217
  * rating, description and photos, in `language`. `results` holds the place, or is empty
211
218
  * (not charged) when no place has that identifier.
219
+ *
220
+ * With `oid` (a Yandex Maps organisation id, e.g. from an `engine=yandex` maps result or
221
+ * `yandex.ru/maps/org/<name>/<oid>/`) the listing comes from Yandex Maps, where the
222
+ * deployment enables it: `oid` implies `engine=yandex` and can't be combined with Google's
223
+ * identifiers. Closed listings (temporarily or permanently) carry no hours.
212
224
  */
213
225
  post: operations["place"];
214
226
  delete?: never;
@@ -893,7 +905,7 @@ interface components {
893
905
  fields?: string;
894
906
  max_age?: number;
895
907
  };
896
- /** @description One of place_id, cid or fid is required (place_id wins, then fid, then cid) */
908
+ /** @description One of place_id, cid or fid (Google; place_id wins, then fid, then cid) or oid (Yandex Maps) is required */
897
909
  PlaceRequest: {
898
910
  /** @description Google place id ("ChIJ…"), e.g. `place_id` of a /v1/maps result */
899
911
  place_id?: string;
@@ -901,6 +913,11 @@ interface components {
901
913
  cid?: string;
902
914
  /** @description Feature id "0x…:0x…" (`fid` of a result) */
903
915
  fid?: string;
916
+ /**
917
+ * @description Yandex Maps organisation id (`oid` of an `engine=yandex` maps result). Implies `engine=yandex`; not with place_id, cid or fid
918
+ * @example 1045821788
919
+ */
920
+ oid?: string;
904
921
  /**
905
922
  * @description Country code (ISO 3166-1 alpha-2); Google's regional view of the listing
906
923
  * @default us
@@ -1257,8 +1274,8 @@ interface components {
1257
1274
  * @description A search provider (docs/providers). Which verticals each serves depends on the deployment.
1258
1275
  * @enum {string}
1259
1276
  */
1260
- Provider: "google" | "brave" | "bing" | "yahoo" | "duckduckgo" | "mojeek" | "wikipedia";
1261
- /** @description Which search providers may answer. `google` (the default) is Google only; within Google, SerpKite always fails over across its own proxy pools. `auto` allows falling back to other enabled providers, in route order, when Google is blocked or times out. A single other provider (`brave`) or a list (`["google","brave"]`, or `google,brave` in a query string) restricts the request to those providers. `meta.engine` always names the provider that answered and credits follow that provider's price. A key with "Allow fallback to other search engines" on treats a request without `engine` as `auto`. `consensus` (`/v1/search` only; 400 elsewhere, and it can't be combined with other names) queries several independent search indexes in parallel (at most one Bing-backed provider, so Yahoo or DuckDuckGo never count as agreeing with Bing), merges the results by URL and ranks them by how many providers returned each one. Each result lists its `sources`; `meta.engine` is `consensus` and `meta.route` lists every provider attempt. It stops once `num` unique results are in hand or after a few seconds, and costs the sum of one page at each provider that returned results (providers that failed, came back empty or were never started are free). */
1277
+ Provider: "google" | "brave" | "bing" | "yahoo" | "duckduckgo" | "mojeek" | "wikipedia" | "yandex";
1278
+ /** @description Which search providers may answer. `google` (the default) is Google only; within Google, SerpKite always fails over across its own proxy pools. `auto` allows falling back to other enabled providers, in route order, when Google is blocked or times out. A single other provider (`brave`) or a list (`["google","brave"]`, or `google,brave` in a query string) restricts the request to those providers. `meta.engine` always names the provider that answered and credits follow that provider's price. A key with "Allow fallback to other search engines" on treats a request without `engine` as `auto`. `consensus` (`/v1/search` only; 400 elsewhere, and it can't be combined with other names) queries several independent search indexes in parallel (at most one Bing-backed provider, so Yahoo or DuckDuckGo never count as agreeing with Bing), merges the results by URL and ranks them by how many providers returned each one. Each result lists its `sources`; `meta.engine` is `consensus` and `meta.route` lists every provider attempt. It stops once `num` unique results are in hand or after a few seconds, and costs the sum of one page at each provider that returned results (providers that failed, came back empty or were never started are free). `yandex` serves `/v1/maps`, `/v1/places` and `/v1/place` from Yandex Maps where the deployment enables it (otherwise a 503 `unavailable`, not charged); with `auto` it is the last fallback there. */
1262
1279
  EngineParam: string | components["schemas"]["Provider"][];
1263
1280
  /** @description One provider attempt behind this answer. Proxy pools are internal and never listed. */
1264
1281
  RouteStep: {
@@ -1321,6 +1338,7 @@ interface components {
1321
1338
  place_id?: string;
1322
1339
  cid?: string;
1323
1340
  fid?: string;
1341
+ oid?: string;
1324
1342
  sort?: string;
1325
1343
  include_content?: number;
1326
1344
  format?: string;
@@ -1479,7 +1497,7 @@ interface components {
1479
1497
  phone_number?: string;
1480
1498
  /** @example +44 20 7232 3010 */
1481
1499
  international_phone_number?: string;
1482
- /** @description Hours as Google displays them, keyed by English weekday (Monday … Sunday), in `language`, e.g. {"Monday": "7:30 am–6 pm", "Sunday": "Closed"} */
1500
+ /** @description Hours as the provider displays them, keyed by English weekday (Monday … Sunday), in `language`, e.g. {"Monday": "7:30 am–6 pm", "Sunday": "Closed"}; Yandex Maps: 24-hour times ("08:00–22:00"), "Closed"/"выходной", "Open 24 hours"/"круглосуточно" */
1483
1501
  opening_hours?: {
1484
1502
  [key: string]: string;
1485
1503
  };
@@ -1488,7 +1506,7 @@ interface components {
1488
1506
  country?: string;
1489
1507
  /** @description IANA time zone of the place (Europe/Moscow) */
1490
1508
  timezone?: string;
1491
- /** @description Google's short description of the place, or the owner's, when Google shows one */
1509
+ /** @description Google's short description of the place, or the owner's, when Google shows one; Yandex Maps' summary of the place when it has one */
1492
1510
  description?: string;
1493
1511
  /** @description Photos of the place (/v1/place; up to 10). The URLs are public and can be fetched server-side without cookies */
1494
1512
  photos?: components["schemas"]["PlacePhoto"][];
@@ -1498,12 +1516,17 @@ interface components {
1498
1516
  place_id?: string;
1499
1517
  cid?: string;
1500
1518
  fid?: string;
1519
+ /** @description Yandex Maps organisation id (engine=yandex), for /v1/place */
1520
+ oid?: string;
1521
+ /** @description The place on Yandex Maps (engine=yandex): https://yandex.ru/maps/org/<oid>/ */
1522
+ yandex_maps_url?: string;
1501
1523
  };
1502
1524
  /**
1503
- * @description Opening hours per weekday, from Google's listing, as local times (`timezone`) in 24-hour HH:MM.
1525
+ * @description Opening hours per weekday, from the provider's listing, as local times (`timezone`) in 24-hour HH:MM.
1504
1526
  * A day that is closed is an empty list; a day open 24 hours is `[{"open": "00:00", "close": "24:00"}]`;
1505
1527
  * a day with a break has several intervals. `close` is "24:00" at midnight, and an interval that
1506
- * ends after midnight has `next_day: true` (e.g. 17:30–03:00). Days Google doesn't list are absent.
1528
+ * ends after midnight has `next_day: true` (e.g. 17:30–03:00). Days Google doesn't list are absent;
1529
+ * Yandex Maps lists all seven or none.
1507
1530
  */
1508
1531
  WeeklyHours: {
1509
1532
  monday?: components["schemas"]["HoursIntervals"];
@@ -3420,7 +3443,10 @@ type SearchParams = Omit<Schemas["SearchRequest"], "engine"> & {
3420
3443
  engine?: Engine;
3421
3444
  };
3422
3445
  type ReviewsParams = Schemas["ReviewsRequest"];
3423
- /** Parameters of `place`: one of `place_id`, `cid` or `fid` (place_id wins, then fid, then cid). */
3446
+ /**
3447
+ * Parameters of `place`: one of `place_id`, `cid` or `fid` (Google; place_id wins, then fid,
3448
+ * then cid), or `oid` (a Yandex Maps organisation id, which implies `engine: "yandex"`).
3449
+ */
3424
3450
  type PlaceParams = Omit<Schemas["PlaceRequest"], "engine"> & {
3425
3451
  /** Search providers allowed to answer. Default `"google"`. See {@link Engine}. */
3426
3452
  engine?: Engine;
@@ -3630,7 +3656,7 @@ type WebhookEvent = {
3630
3656
  data: MonitorResultsEvent;
3631
3657
  };
3632
3658
 
3633
- declare const VERSION = "0.5.0";
3659
+ declare const VERSION = "0.6.0";
3634
3660
  declare const DEFAULT_BASE_URL = "https://api.serpkite.com";
3635
3661
  interface SerpKiteOptions {
3636
3662
  /** API key (`skt_live_…`). Defaults to the `SERPKITE_API_KEY` environment variable. */
@@ -3751,7 +3777,10 @@ declare class SerpKite {
3751
3777
  results: components["schemas"]["NewsResult"][];
3752
3778
  meta: components["schemas"]["Meta"];
3753
3779
  }>;
3754
- /** Google Maps search (places with coordinates). Accepts `ll` ("@lat,lng,14z"). */
3780
+ /**
3781
+ * Google Maps search (places with coordinates). Accepts `ll` ("@lat,lng,14z"). With
3782
+ * `engine: "yandex"` (where enabled) the places come from Yandex Maps and carry an `oid`.
3783
+ */
3755
3784
  readonly maps: VerticalMethod<SearchParams, {
3756
3785
  request: components["schemas"]["RequestEcho"];
3757
3786
  results: components["schemas"]["PlaceResult"][];
@@ -3764,7 +3793,8 @@ declare class SerpKite {
3764
3793
  meta: components["schemas"]["Meta"];
3765
3794
  }>;
3766
3795
  /**
3767
- * Details of one place by `place_id`, `cid` or `fid`: address, country, time zone, hours
3796
+ * Details of one place by `place_id`, `cid` or `fid`, or by a Yandex Maps `oid` (implies
3797
+ * `engine: "yandex"`): address, country, time zone, hours
3768
3798
  * (`opening_hours` text and structured `weekly_hours`), phones, description and photos.
3769
3799
  * `results` holds the place, or is empty (not charged) when no place has that id. 1 credit.
3770
3800
  */
package/dist/index.d.ts CHANGED
@@ -166,6 +166,13 @@ interface paths {
166
166
  * (or `uule`) searches the named place. Without either, Google picks the area from the
167
167
  * query (an exact name or address) or from where the request comes from, so local queries
168
168
  * such as "coffee" need `location` or `ll`.
169
+ *
170
+ * **Yandex Maps:** with `engine=yandex` (where the deployment enables it) the results come
171
+ * from Yandex Maps, which covers Russia and the CIS in depth. They have the same fields,
172
+ * with the Yandex organisation id in `oid` (for `/v1/place`) and `yandex_maps_url` instead
173
+ * of Google's identifiers; categories, addresses and hours follow `language` (`ru` for
174
+ * Russian). Pass `ll` or a `location` (a city, appended to the query); `uule` and `tbs`
175
+ * are refused.
169
176
  */
170
177
  post: operations["maps"];
171
178
  delete?: never;
@@ -204,11 +211,16 @@ interface paths {
204
211
  get?: never;
205
212
  put?: never;
206
213
  /**
207
- * Details of one place (by `place_id`, `cid` or `fid`); 1 credit
214
+ * Details of one place (by `place_id`, `cid`, `fid` or Yandex `oid`); 1 credit
208
215
  * @description The full Google Maps listing of one place: address, country, coordinates, time zone,
209
216
  * categories, opening hours (as text and as structured `weekly_hours`), website, phone,
210
217
  * rating, description and photos, in `language`. `results` holds the place, or is empty
211
218
  * (not charged) when no place has that identifier.
219
+ *
220
+ * With `oid` (a Yandex Maps organisation id, e.g. from an `engine=yandex` maps result or
221
+ * `yandex.ru/maps/org/<name>/<oid>/`) the listing comes from Yandex Maps, where the
222
+ * deployment enables it: `oid` implies `engine=yandex` and can't be combined with Google's
223
+ * identifiers. Closed listings (temporarily or permanently) carry no hours.
212
224
  */
213
225
  post: operations["place"];
214
226
  delete?: never;
@@ -893,7 +905,7 @@ interface components {
893
905
  fields?: string;
894
906
  max_age?: number;
895
907
  };
896
- /** @description One of place_id, cid or fid is required (place_id wins, then fid, then cid) */
908
+ /** @description One of place_id, cid or fid (Google; place_id wins, then fid, then cid) or oid (Yandex Maps) is required */
897
909
  PlaceRequest: {
898
910
  /** @description Google place id ("ChIJ…"), e.g. `place_id` of a /v1/maps result */
899
911
  place_id?: string;
@@ -901,6 +913,11 @@ interface components {
901
913
  cid?: string;
902
914
  /** @description Feature id "0x…:0x…" (`fid` of a result) */
903
915
  fid?: string;
916
+ /**
917
+ * @description Yandex Maps organisation id (`oid` of an `engine=yandex` maps result). Implies `engine=yandex`; not with place_id, cid or fid
918
+ * @example 1045821788
919
+ */
920
+ oid?: string;
904
921
  /**
905
922
  * @description Country code (ISO 3166-1 alpha-2); Google's regional view of the listing
906
923
  * @default us
@@ -1257,8 +1274,8 @@ interface components {
1257
1274
  * @description A search provider (docs/providers). Which verticals each serves depends on the deployment.
1258
1275
  * @enum {string}
1259
1276
  */
1260
- Provider: "google" | "brave" | "bing" | "yahoo" | "duckduckgo" | "mojeek" | "wikipedia";
1261
- /** @description Which search providers may answer. `google` (the default) is Google only; within Google, SerpKite always fails over across its own proxy pools. `auto` allows falling back to other enabled providers, in route order, when Google is blocked or times out. A single other provider (`brave`) or a list (`["google","brave"]`, or `google,brave` in a query string) restricts the request to those providers. `meta.engine` always names the provider that answered and credits follow that provider's price. A key with "Allow fallback to other search engines" on treats a request without `engine` as `auto`. `consensus` (`/v1/search` only; 400 elsewhere, and it can't be combined with other names) queries several independent search indexes in parallel (at most one Bing-backed provider, so Yahoo or DuckDuckGo never count as agreeing with Bing), merges the results by URL and ranks them by how many providers returned each one. Each result lists its `sources`; `meta.engine` is `consensus` and `meta.route` lists every provider attempt. It stops once `num` unique results are in hand or after a few seconds, and costs the sum of one page at each provider that returned results (providers that failed, came back empty or were never started are free). */
1277
+ Provider: "google" | "brave" | "bing" | "yahoo" | "duckduckgo" | "mojeek" | "wikipedia" | "yandex";
1278
+ /** @description Which search providers may answer. `google` (the default) is Google only; within Google, SerpKite always fails over across its own proxy pools. `auto` allows falling back to other enabled providers, in route order, when Google is blocked or times out. A single other provider (`brave`) or a list (`["google","brave"]`, or `google,brave` in a query string) restricts the request to those providers. `meta.engine` always names the provider that answered and credits follow that provider's price. A key with "Allow fallback to other search engines" on treats a request without `engine` as `auto`. `consensus` (`/v1/search` only; 400 elsewhere, and it can't be combined with other names) queries several independent search indexes in parallel (at most one Bing-backed provider, so Yahoo or DuckDuckGo never count as agreeing with Bing), merges the results by URL and ranks them by how many providers returned each one. Each result lists its `sources`; `meta.engine` is `consensus` and `meta.route` lists every provider attempt. It stops once `num` unique results are in hand or after a few seconds, and costs the sum of one page at each provider that returned results (providers that failed, came back empty or were never started are free). `yandex` serves `/v1/maps`, `/v1/places` and `/v1/place` from Yandex Maps where the deployment enables it (otherwise a 503 `unavailable`, not charged); with `auto` it is the last fallback there. */
1262
1279
  EngineParam: string | components["schemas"]["Provider"][];
1263
1280
  /** @description One provider attempt behind this answer. Proxy pools are internal and never listed. */
1264
1281
  RouteStep: {
@@ -1321,6 +1338,7 @@ interface components {
1321
1338
  place_id?: string;
1322
1339
  cid?: string;
1323
1340
  fid?: string;
1341
+ oid?: string;
1324
1342
  sort?: string;
1325
1343
  include_content?: number;
1326
1344
  format?: string;
@@ -1479,7 +1497,7 @@ interface components {
1479
1497
  phone_number?: string;
1480
1498
  /** @example +44 20 7232 3010 */
1481
1499
  international_phone_number?: string;
1482
- /** @description Hours as Google displays them, keyed by English weekday (Monday … Sunday), in `language`, e.g. {"Monday": "7:30 am–6 pm", "Sunday": "Closed"} */
1500
+ /** @description Hours as the provider displays them, keyed by English weekday (Monday … Sunday), in `language`, e.g. {"Monday": "7:30 am–6 pm", "Sunday": "Closed"}; Yandex Maps: 24-hour times ("08:00–22:00"), "Closed"/"выходной", "Open 24 hours"/"круглосуточно" */
1483
1501
  opening_hours?: {
1484
1502
  [key: string]: string;
1485
1503
  };
@@ -1488,7 +1506,7 @@ interface components {
1488
1506
  country?: string;
1489
1507
  /** @description IANA time zone of the place (Europe/Moscow) */
1490
1508
  timezone?: string;
1491
- /** @description Google's short description of the place, or the owner's, when Google shows one */
1509
+ /** @description Google's short description of the place, or the owner's, when Google shows one; Yandex Maps' summary of the place when it has one */
1492
1510
  description?: string;
1493
1511
  /** @description Photos of the place (/v1/place; up to 10). The URLs are public and can be fetched server-side without cookies */
1494
1512
  photos?: components["schemas"]["PlacePhoto"][];
@@ -1498,12 +1516,17 @@ interface components {
1498
1516
  place_id?: string;
1499
1517
  cid?: string;
1500
1518
  fid?: string;
1519
+ /** @description Yandex Maps organisation id (engine=yandex), for /v1/place */
1520
+ oid?: string;
1521
+ /** @description The place on Yandex Maps (engine=yandex): https://yandex.ru/maps/org/<oid>/ */
1522
+ yandex_maps_url?: string;
1501
1523
  };
1502
1524
  /**
1503
- * @description Opening hours per weekday, from Google's listing, as local times (`timezone`) in 24-hour HH:MM.
1525
+ * @description Opening hours per weekday, from the provider's listing, as local times (`timezone`) in 24-hour HH:MM.
1504
1526
  * A day that is closed is an empty list; a day open 24 hours is `[{"open": "00:00", "close": "24:00"}]`;
1505
1527
  * a day with a break has several intervals. `close` is "24:00" at midnight, and an interval that
1506
- * ends after midnight has `next_day: true` (e.g. 17:30–03:00). Days Google doesn't list are absent.
1528
+ * ends after midnight has `next_day: true` (e.g. 17:30–03:00). Days Google doesn't list are absent;
1529
+ * Yandex Maps lists all seven or none.
1507
1530
  */
1508
1531
  WeeklyHours: {
1509
1532
  monday?: components["schemas"]["HoursIntervals"];
@@ -3420,7 +3443,10 @@ type SearchParams = Omit<Schemas["SearchRequest"], "engine"> & {
3420
3443
  engine?: Engine;
3421
3444
  };
3422
3445
  type ReviewsParams = Schemas["ReviewsRequest"];
3423
- /** Parameters of `place`: one of `place_id`, `cid` or `fid` (place_id wins, then fid, then cid). */
3446
+ /**
3447
+ * Parameters of `place`: one of `place_id`, `cid` or `fid` (Google; place_id wins, then fid,
3448
+ * then cid), or `oid` (a Yandex Maps organisation id, which implies `engine: "yandex"`).
3449
+ */
3424
3450
  type PlaceParams = Omit<Schemas["PlaceRequest"], "engine"> & {
3425
3451
  /** Search providers allowed to answer. Default `"google"`. See {@link Engine}. */
3426
3452
  engine?: Engine;
@@ -3630,7 +3656,7 @@ type WebhookEvent = {
3630
3656
  data: MonitorResultsEvent;
3631
3657
  };
3632
3658
 
3633
- declare const VERSION = "0.5.0";
3659
+ declare const VERSION = "0.6.0";
3634
3660
  declare const DEFAULT_BASE_URL = "https://api.serpkite.com";
3635
3661
  interface SerpKiteOptions {
3636
3662
  /** API key (`skt_live_…`). Defaults to the `SERPKITE_API_KEY` environment variable. */
@@ -3751,7 +3777,10 @@ declare class SerpKite {
3751
3777
  results: components["schemas"]["NewsResult"][];
3752
3778
  meta: components["schemas"]["Meta"];
3753
3779
  }>;
3754
- /** Google Maps search (places with coordinates). Accepts `ll` ("@lat,lng,14z"). */
3780
+ /**
3781
+ * Google Maps search (places with coordinates). Accepts `ll` ("@lat,lng,14z"). With
3782
+ * `engine: "yandex"` (where enabled) the places come from Yandex Maps and carry an `oid`.
3783
+ */
3755
3784
  readonly maps: VerticalMethod<SearchParams, {
3756
3785
  request: components["schemas"]["RequestEcho"];
3757
3786
  results: components["schemas"]["PlaceResult"][];
@@ -3764,7 +3793,8 @@ declare class SerpKite {
3764
3793
  meta: components["schemas"]["Meta"];
3765
3794
  }>;
3766
3795
  /**
3767
- * Details of one place by `place_id`, `cid` or `fid`: address, country, time zone, hours
3796
+ * Details of one place by `place_id`, `cid` or `fid`, or by a Yandex Maps `oid` (implies
3797
+ * `engine: "yandex"`): address, country, time zone, hours
3768
3798
  * (`opening_hours` text and structured `weekly_hours`), phones, description and photos.
3769
3799
  * `results` holds the place, or is empty (not charged) when no place has that id. 1 credit.
3770
3800
  */
package/dist/index.js CHANGED
@@ -48,7 +48,7 @@ function errorFromResponse(status, headers, body) {
48
48
  }
49
49
 
50
50
  // src/client.ts
51
- var VERSION = "0.5.0";
51
+ var VERSION = "0.6.0";
52
52
  var DEFAULT_BASE_URL = "https://api.serpkite.com";
53
53
  var TASK_DONE = /* @__PURE__ */ new Set(["completed", "failed", "canceled"]);
54
54
  var SerpKite = class {
@@ -96,12 +96,16 @@ var SerpKite = class {
96
96
  videos = this.#vertical("/v1/videos");
97
97
  /** Google News. */
98
98
  news = this.#vertical("/v1/news");
99
- /** Google Maps search (places with coordinates). Accepts `ll` ("@lat,lng,14z"). */
99
+ /**
100
+ * Google Maps search (places with coordinates). Accepts `ll` ("@lat,lng,14z"). With
101
+ * `engine: "yandex"` (where enabled) the places come from Yandex Maps and carry an `oid`.
102
+ */
100
103
  maps = this.#vertical("/v1/maps");
101
104
  /** Google local results. */
102
105
  places = this.#vertical("/v1/places");
103
106
  /**
104
- * Details of one place by `place_id`, `cid` or `fid`: address, country, time zone, hours
107
+ * Details of one place by `place_id`, `cid` or `fid`, or by a Yandex Maps `oid` (implies
108
+ * `engine: "yandex"`): address, country, time zone, hours
105
109
  * (`opening_hours` text and structured `weekly_hours`), phones, description and photos.
106
110
  * `results` holds the place, or is empty (not charged) when no place has that id. 1 credit.
107
111
  */
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/util.ts","../src/webhooks.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Every failure thrown by the SDK. API errors carry the fields of the\n * `{\"error\":{\"code\",\"message\",\"request_id\"}}` envelope; network failures and\n * timeouts use `status: 0` with code `connection_error` or `timeout`.\n */\nexport class SerpKiteError extends Error {\n /** HTTP status, or 0 when no response was received. */\n readonly status: number;\n /** Machine-readable code, e.g. `unauthorized`, `insufficient_credits`, `rate_limited`. */\n readonly code: string;\n /** `X-Request-Id` of the failed request, when the API returned one. */\n readonly requestId: string | undefined;\n /** Response headers, when the API responded. */\n readonly headers: Headers | undefined;\n\n constructor(\n status: number,\n code: string,\n message: string,\n requestId?: string,\n headers?: Headers,\n options?: { cause?: unknown },\n ) {\n super(message, options);\n this.name = \"SerpKiteError\";\n this.status = status;\n this.code = code;\n this.requestId = requestId || undefined;\n this.headers = headers;\n }\n}\n\nconst fallbackCodes: Record<number, string> = {\n 400: \"invalid_request\",\n 401: \"unauthorized\",\n 402: \"insufficient_credits\",\n 403: \"forbidden\",\n 404: \"not_found\",\n 429: \"rate_limited\",\n // The API sends upstream failures as 503 with a JSON body; a bare 502/504\n // comes from a proxy (Cloudflare replaces origin 502/504 bodies).\n 502: \"upstream_error\",\n 503: \"unavailable\",\n 504: \"upstream_timeout\",\n};\n\n/** Builds a SerpKiteError from a non-2xx response body (JSON envelope or anything else). */\nexport function errorFromResponse(status: number, headers: Headers, body: string): SerpKiteError {\n let code = fallbackCodes[status] ?? (status >= 500 ? \"server_error\" : \"http_error\");\n let message = body.trim().slice(0, 500) || `HTTP ${status}`;\n let requestId = headers.get(\"x-request-id\") ?? undefined;\n try {\n const parsed = JSON.parse(body) as {\n error?: { code?: unknown; message?: unknown; request_id?: unknown };\n };\n const e = parsed?.error;\n if (e && typeof e === \"object\") {\n if (typeof e.code === \"string\" && e.code) code = e.code;\n if (typeof e.message === \"string\" && e.message) message = e.message;\n if (typeof e.request_id === \"string\" && e.request_id) requestId = e.request_id;\n }\n } catch {\n // Not JSON: keep the text body as the message.\n }\n return new SerpKiteError(status, code, message, requestId, headers);\n}\n","import { errorFromResponse, SerpKiteError } from \"./errors\";\nimport type {\n Account,\n AutocompleteResponse,\n Batch,\n BatchCreateEntry,\n BatchCreateParams,\n BatchCreateResponse,\n CompactResponse,\n CrawlParams,\n CrawlTask,\n ExtractParams,\n ExtractResponse,\n ImagesResponse,\n MapParams,\n MapResponse,\n Monitor,\n MonitorCreateParams,\n MonitorList,\n MonitorRun,\n MonitorRunList,\n MonitorRunsParams,\n MonitorUpdateParams,\n NewsResponse,\n PatentsResponse,\n PlaceParams,\n PlacesResponse,\n RankParams,\n RankResponse,\n ReviewsParams,\n ReviewsResponse,\n ScholarResponse,\n SearchParams,\n SearchResponse,\n ShoppingResponse,\n TaskCancelResponse,\n TaskCreated,\n VideosResponse,\n WebpageParams,\n WebpageResponse,\n} from \"./types\";\n\nexport const VERSION = \"0.5.0\";\nexport const DEFAULT_BASE_URL = \"https://api.serpkite.com\";\n\nexport interface SerpKiteOptions {\n /** API key (`skt_live_…`). Defaults to the `SERPKITE_API_KEY` environment variable. */\n apiKey?: string;\n /** Defaults to `SERPKITE_BASE_URL` or https://api.serpkite.com. */\n baseUrl?: string;\n /** Per-attempt timeout in milliseconds. Default 60000. */\n timeoutMs?: number;\n /** Retries after the first attempt on 429, 5xx and network errors. Default 2. */\n maxRetries?: number;\n /** Base delay of the exponential backoff in milliseconds. Default 500. */\n retryDelayMs?: number;\n /** Custom fetch implementation. Defaults to the global `fetch`. */\n fetch?: typeof fetch;\n /** Extra headers sent with every request. */\n headers?: Record<string, string>;\n}\n\n/** Billing and tracing details from the response headers. */\nexport interface ResponseInfo {\n status: number;\n headers: Headers;\n requestId: string | undefined;\n creditsUsed: number | undefined;\n creditsRemaining: number | undefined;\n costUsd: number | undefined;\n /** `HIT` when served from cache (`max_age`), else `MISS`. */\n cache: \"HIT\" | \"MISS\" | undefined;\n latencyMs: number | undefined;\n tokensEstimate: number | undefined;\n}\n\nexport interface RequestOptions {\n signal?: AbortSignal;\n /** Overrides the client's per-attempt timeout. */\n timeoutMs?: number;\n /** Overrides the client's retry count. */\n maxRetries?: number;\n headers?: Record<string, string>;\n /** Called with the final response's headers (credits used/remaining, cache, request id). */\n onResponse?: (info: ResponseInfo) => void;\n}\n\nexport interface BatchCreateOptions extends RequestOptions {\n /**\n * Sent as `Idempotency-Key` (1-255 printable ASCII characters, e.g. a UUID).\n * For 24 hours a retry with the same key and body returns the first response\n * instead of queueing and billing the jobs again.\n */\n idempotencyKey?: string;\n}\n\nexport interface WaitOptions {\n /**\n * Give up after this many milliseconds. Default 600000 (10 minutes) for batches and\n * 2100000 (35 minutes) for `waitForCrawl`: a crawl runs for up to 30 minutes.\n */\n timeoutMs?: number;\n /** First delay between polls. Default 1000. Grows 1.5× per poll. */\n pollIntervalMs?: number;\n /** Upper bound of the delay between polls. Default 10000. */\n maxPollIntervalMs?: number;\n signal?: AbortSignal;\n}\n\n/** A vertical whose return type follows `format`: `\"markdown\"` → string, `\"compact\"` → CompactResponse. */\nexport interface VerticalMethod<P, R> {\n (params: P & { format: \"markdown\" }, options?: RequestOptions): Promise<string>;\n (params: P & { format: \"compact\" }, options?: RequestOptions): Promise<CompactResponse>;\n (params: P & { format?: \"json\" }, options?: RequestOptions): Promise<R>;\n (params: P, options?: RequestOptions): Promise<R | CompactResponse | string>;\n}\n\ntype Method = \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\";\n\n/** Task states after which `waitForCrawl` returns. */\nconst TASK_DONE = new Set([\"completed\", \"failed\", \"canceled\"]);\n\ninterface Call {\n method: Method;\n path: string;\n body?: unknown;\n options?: RequestOptions;\n /** Which failures are safe to retry. `all` = 429, 5xx and network errors. */\n retry?: \"all\" | \"rate_limit\";\n}\n\nexport class SerpKite {\n readonly baseUrl: string;\n readonly timeoutMs: number;\n readonly maxRetries: number;\n readonly retryDelayMs: number;\n readonly #apiKey: string;\n readonly #fetch: typeof fetch;\n readonly #headers: Record<string, string>;\n\n constructor(options: SerpKiteOptions = {}) {\n const apiKey = options.apiKey ?? env(\"SERPKITE_API_KEY\");\n if (!apiKey) {\n throw new SerpKiteError(\n 0,\n \"missing_api_key\",\n \"No API key: pass { apiKey } or set the SERPKITE_API_KEY environment variable\",\n );\n }\n this.#apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? env(\"SERPKITE_BASE_URL\") ?? DEFAULT_BASE_URL).replace(\n /\\/+$/,\n \"\",\n );\n this.timeoutMs = options.timeoutMs ?? 60_000;\n this.maxRetries = Math.max(0, options.maxRetries ?? 2);\n this.retryDelayMs = options.retryDelayMs ?? 500;\n const f = options.fetch ?? globalThis.fetch;\n if (typeof f !== \"function\") {\n throw new SerpKiteError(\n 0,\n \"missing_fetch\",\n \"No global fetch: pass { fetch } (Node 18+ has one)\",\n );\n }\n this.#fetch = f;\n this.#headers = { ...options.headers };\n }\n\n // ── Verticals ─────────────────────────────────────────────────────────\n\n /** Google web search: organic results, answer box, knowledge graph, people also ask… */\n readonly search = this.#vertical<SearchParams, SearchResponse>(\"/v1/search\");\n /** Google Images. */\n readonly images = this.#vertical<SearchParams, ImagesResponse>(\"/v1/images\");\n /** Google Videos. */\n readonly videos = this.#vertical<SearchParams, VideosResponse>(\"/v1/videos\");\n /** Google News. */\n readonly news = this.#vertical<SearchParams, NewsResponse>(\"/v1/news\");\n /** Google Maps search (places with coordinates). Accepts `ll` (\"@lat,lng,14z\"). */\n readonly maps = this.#vertical<SearchParams, PlacesResponse>(\"/v1/maps\");\n /** Google local results. */\n readonly places = this.#vertical<SearchParams, PlacesResponse>(\"/v1/places\");\n /**\n * Details of one place by `place_id`, `cid` or `fid`: address, country, time zone, hours\n * (`opening_hours` text and structured `weekly_hours`), phones, description and photos.\n * `results` holds the place, or is empty (not charged) when no place has that id. 1 credit.\n */\n readonly place = this.#vertical<PlaceParams, PlacesResponse>(\"/v1/place\");\n /** Reviews of a place by `place_id`, `cid` or `fid`. Page with `page_token` = `next_page_token`. */\n readonly reviews = this.#vertical<ReviewsParams, ReviewsResponse>(\"/v1/reviews\");\n /** Google Shopping. */\n readonly shopping = this.#vertical<SearchParams, ShoppingResponse>(\"/v1/shopping\");\n /** Google Scholar. */\n readonly scholar = this.#vertical<SearchParams, ScholarResponse>(\"/v1/scholar\");\n /** Google Patents. */\n readonly patents = this.#vertical<SearchParams, PatentsResponse>(\"/v1/patents\");\n /** Google autocomplete suggestions. */\n readonly autocomplete = this.#vertical<SearchParams, AutocompleteResponse>(\"/v1/autocomplete\");\n /** Fetch any public URL as clean Markdown plus metadata. */\n readonly webpage = this.#vertical<WebpageParams, WebpageResponse>(\"/v1/webpage\");\n\n /** Position of `domain` for keyword `q` in the top `num` results (default 100). */\n rank(params: RankParams, options?: RequestOptions): Promise<RankResponse> {\n return this.request({ method: \"POST\", path: \"/v1/rank\", body: params, options });\n }\n\n /**\n * Read up to 20 URLs (HTML or PDF) as Markdown, text or HTML in one call, with optional\n * query-ranked `highlights` (BM25), `include_links` and `include_images`. 1 credit per URL\n * that comes back (0.5 from cache); URLs that fail are listed in `failed` and cost nothing.\n */\n extract(params: ExtractParams, options?: RequestOptions): Promise<ExtractResponse> {\n // Billed per page even when the response is lost: retried only on 429,\n // and the HTTP timeout covers the server's deadline (timeout, default 50 s) + 15 s.\n const wait = ((params.timeout ?? 50) + 15) * 1000;\n return this.request({\n method: \"POST\",\n path: \"/v1/extract\",\n body: params,\n options: {\n ...options,\n timeoutMs: options?.timeoutMs ?? (this.timeoutMs > 0 ? Math.max(this.timeoutMs, wait) : 0),\n },\n retry: \"rate_limit\",\n });\n }\n\n /**\n * The URLs of a site from its sitemaps (XML, RSS/Atom, gzip, plain text) and start page,\n * canonicalised and deduplicated, optionally ranked by `search`. `include_paths` /\n * `exclude_paths` (regular expressions on the URL path) and `ignore_query_parameters`\n * narrow the list. 1 credit; free when nothing is found.\n */\n map(params: MapParams, options?: RequestOptions): Promise<MapResponse> {\n return this.request({ method: \"POST\", path: \"/v1/map\", body: params, options });\n }\n\n /** Balance, limits and this month's usage for the key's account. */\n account(options?: RequestOptions): Promise<Account> {\n return this.request({ method: \"GET\", path: \"/v1/account\", options });\n }\n\n // ── Async tasks: crawl ────────────────────────────────────────────────\n\n /**\n * Starts an async crawl of one site and returns the queued task (`202`). 1 credit per page\n * read (0.5 from cache); `limit` credits (up to 1000 pages, `max_depth` up to 10) are\n * reserved up front and the rest refunded. `sitemap` (`include` default, `only`, `skip`)\n * seeds the crawl with sitemap URLs; `query` reads the most relevant pages first. robots.txt\n * and Crawl-delay are honoured; `result.stats.stopped` says why the crawl ended (`done`,\n * `limit`, `time_limit`, `size_limit`, `too_many_failures`, `canceled`).\n * Only retried on 429, so a lost response never starts (and reserves) a second crawl.\n */\n crawl(params: CrawlParams, options?: RequestOptions): Promise<TaskCreated> {\n return this.request({\n method: \"POST\",\n path: \"/v1/crawl\",\n body: params,\n options,\n retry: \"rate_limit\",\n });\n }\n\n /** Polls a crawl (results are kept for 24 hours). */\n getCrawl(id: string, options?: RequestOptions): Promise<CrawlTask> {\n return this.request({ method: \"GET\", path: `/v1/crawl/${encodeURIComponent(id)}`, options });\n }\n\n /** Cancels a crawl: refunded if still queued, else stops at the next checkpoint. */\n cancelCrawl(id: string, options?: RequestOptions): Promise<TaskCancelResponse> {\n return this.request({\n method: \"DELETE\",\n path: `/v1/crawl/${encodeURIComponent(id)}`,\n options,\n });\n }\n\n /**\n * Polls until the crawl is `completed`, `failed` or `canceled` and returns it (a failed\n * task is returned, not thrown; check `status` and `error`). Accepts an id or the task\n * returned by `crawl`.\n */\n async waitForCrawl(\n idOrTask: string | { id: string },\n options: WaitOptions = {},\n ): Promise<CrawlTask> {\n return this.#waitTask(taskId(idOrTask), (id) => this.getCrawl(id, { signal: options.signal }), {\n ...options,\n timeoutMs: options.timeoutMs ?? 2_100_000,\n });\n }\n\n // ── Monitors ──────────────────────────────────────────────────────────\n\n readonly monitors = {\n /**\n * Saves a `search` or `news` request (`q`) that runs on a schedule (hourly to monthly) and\n * POSTs results it hasn't seen before to `webhook_url` (`monitor.results`). With\n * `endpoint: \"webpage\"` and a `url` it checks that page each interval (1 credit per check)\n * and reports it (`MonitorPageChange`) when its content changes. `metadata` (your JSON\n * object, at most 2 KB) is echoed on the monitor and in its webhooks. Without a\n * `webhook_url`, read new results from `monitors.runs`. `active: false`\n * creates it paused. A monitor pauses itself after 10 failed runs in a row\n * (`last_status: \"paused\"`); `update(id, { active: true })` resumes it. Each run costs\n * what its search costs. Only retried on 429.\n */\n create: (params: MonitorCreateParams, options?: RequestOptions): Promise<Monitor> =>\n this.request({\n method: \"POST\",\n path: \"/v1/monitors\",\n body: params,\n options,\n retry: \"rate_limit\",\n }),\n\n /** The account's monitors. */\n list: (options?: RequestOptions): Promise<MonitorList> =>\n this.request({ method: \"GET\", path: \"/v1/monitors\", options }),\n\n get: (id: string, options?: RequestOptions): Promise<Monitor> =>\n this.request({ method: \"GET\", path: `/v1/monitors/${encodeURIComponent(id)}`, options }),\n\n /**\n * Changes `name`, `interval` / `interval_seconds`, `webhook_url` (`\"\"` removes it),\n * `active` (`true` resumes a paused monitor), `metadata` (an object replaces it, `null`\n * clears it) or the saved request (`endpoint`, `q`, `url`, `country`, `num`, domains,\n * `engine`…). Switching `endpoint` between a search and `webpage` drops the other kind's\n * fields. A changed search reports every result as new on the next run.\n */\n update: (id: string, params: MonitorUpdateParams, options?: RequestOptions): Promise<Monitor> =>\n this.request({\n method: \"PATCH\",\n path: `/v1/monitors/${encodeURIComponent(id)}`,\n body: params,\n options,\n }),\n\n delete: async (id: string, options?: RequestOptions): Promise<void> => {\n await this.request({\n method: \"DELETE\",\n path: `/v1/monitors/${encodeURIComponent(id)}`,\n options,\n });\n },\n\n /** Runs an active monitor at the next scheduler poll (within about 30 seconds).\n * Paused monitors return 409; update(id, { active: true }) resumes and schedules them. */\n run: (id: string, options?: RequestOptions): Promise<Monitor> =>\n this.request({\n method: \"POST\",\n path: `/v1/monitors/${encodeURIComponent(id)}/run`,\n options,\n retry: \"rate_limit\",\n }),\n\n /**\n * One page of the monitor's run history, newest first (`limit` 1-100, default 20). Each\n * run carries its new results for 24 hours. Pass `next_before` as `before` for the next\n * page; it is null on the last one.\n */\n runs: (\n id: string,\n params: MonitorRunsParams = {},\n options?: RequestOptions,\n ): Promise<MonitorRunList> =>\n this.request({\n method: \"GET\",\n path: `/v1/monitors/${encodeURIComponent(id)}/runs${query(params)}`,\n options,\n }),\n\n /**\n * Iterates over every run of the monitor, newest first, fetching pages of `limit` as\n * needed (starting at `before` when given).\n *\n * ```ts\n * for await (const run of sk.monitors.iterRuns(\"m1\")) console.log(run.new_results);\n * ```\n */\n iterRuns: (\n id: string,\n params: MonitorRunsParams = {},\n options?: RequestOptions,\n ): AsyncIterable<MonitorRun> => this.#iterRuns(id, params, options),\n };\n\n // ── Batches ───────────────────────────────────────────────────────────\n\n readonly batches = {\n /**\n * Queue 1-100 requests for one endpoint at half price. Returns one entry per\n * request, in order: a queued `Batch` or an error object. Without an\n * `idempotencyKey` it is only retried on 429, so a lost response never queues\n * (and bills) the same requests twice. With one, 5xx and network errors are\n * retried too: the server replays the first response for the same key and body.\n */\n create: (\n params: BatchCreateParams,\n options: BatchCreateOptions = {},\n ): Promise<BatchCreateResponse> => {\n const { idempotencyKey, ...rest } = options;\n return this.request({\n method: \"POST\",\n path: \"/v1/batches\",\n body: params,\n options: idempotencyKey\n ? { ...rest, headers: { ...rest.headers, \"Idempotency-Key\": idempotencyKey } }\n : rest,\n retry: idempotencyKey ? \"all\" : \"rate_limit\",\n });\n },\n\n /** Poll one batch job. */\n get: (id: string, options?: RequestOptions): Promise<Batch> =>\n this.request({ method: \"GET\", path: `/v1/batches/${encodeURIComponent(id)}`, options }),\n\n /**\n * Poll until the job is `done` or `failed` and return it (a failed job is\n * returned, not thrown; check `status` and `error`). Accepts an id or an\n * entry from `create`; an entry that failed to queue throws its error.\n */\n wait: (idOrEntry: string | BatchCreateEntry | undefined, options: WaitOptions = {}) =>\n this.#wait(idOrEntry, options),\n };\n\n // ── Plumbing ──────────────────────────────────────────────────────────\n\n async *#iterRuns(\n id: string,\n params: MonitorRunsParams,\n options?: RequestOptions,\n ): AsyncGenerator<MonitorRun> {\n let before = params.before;\n for (;;) {\n const page = await this.monitors.runs(id, { ...params, before }, options);\n yield* page.results;\n if (!page.next_before || page.results.length === 0) return;\n before = page.next_before;\n }\n }\n\n async #waitTask<T extends { status: string }>(\n id: string,\n get: (id: string) => Promise<T>,\n o: WaitOptions,\n ): Promise<T> {\n const timeoutMs = o.timeoutMs ?? 600_000;\n const maxInterval = o.maxPollIntervalMs ?? 10_000;\n let interval = o.pollIntervalMs ?? 1_000;\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n const task = await get(id);\n if (TASK_DONE.has(task.status)) return task;\n const left = deadline - Date.now();\n if (left <= 0) {\n throw new SerpKiteError(\n 0,\n \"timeout\",\n `task ${id} still ${task.status} after ${timeoutMs} ms`,\n );\n }\n await sleep(Math.min(interval, left), o.signal);\n interval = Math.min(interval * 1.5, maxInterval);\n }\n }\n\n #vertical<P, R>(path: string): VerticalMethod<P, R> {\n return ((params: P, options?: RequestOptions) =>\n this.request({ method: \"POST\", path, body: params, options })) as VerticalMethod<P, R>;\n }\n\n async #wait(idOrEntry: string | BatchCreateEntry | undefined, o: WaitOptions): Promise<Batch> {\n let id: string | undefined;\n if (typeof idOrEntry === \"string\") {\n id = idOrEntry;\n } else if (idOrEntry && \"id\" in idOrEntry && typeof idOrEntry.id === \"string\") {\n id = idOrEntry.id;\n } else if (idOrEntry && \"error\" in idOrEntry && idOrEntry.error && !(\"id\" in idOrEntry)) {\n const e = idOrEntry.error as { code?: string; message?: string; request_id?: string };\n throw new SerpKiteError(\n 400,\n e.code ?? \"invalid_request\",\n e.message ?? \"batch entry was not queued\",\n e.request_id,\n );\n }\n if (!id) {\n throw new SerpKiteError(0, \"invalid_request\", \"batches.wait needs a batch id\");\n }\n const timeoutMs = o.timeoutMs ?? 600_000;\n const maxInterval = o.maxPollIntervalMs ?? 10_000;\n let interval = o.pollIntervalMs ?? 1_000;\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n const batch = await this.batches.get(id, { signal: o.signal });\n if (batch.status === \"done\" || batch.status === \"failed\") return batch;\n const left = deadline - Date.now();\n if (left <= 0) {\n throw new SerpKiteError(\n 0,\n \"timeout\",\n `batch ${id} still ${batch.status} after ${timeoutMs} ms`,\n );\n }\n await sleep(Math.min(interval, left), o.signal);\n interval = Math.min(interval * 1.5, maxInterval);\n }\n }\n\n /** Low-level request: JSON body in, parsed JSON (or text for non-JSON responses) out. */\n async request<T>(call: Call): Promise<T> {\n const { method, path, body, options = {} } = call;\n const maxRetries = Math.max(0, options.maxRetries ?? this.maxRetries);\n const timeoutMs = options.timeoutMs ?? this.timeoutMs;\n const headers: Record<string, string> = {\n Accept: \"application/json, text/markdown;q=0.9\",\n Authorization: `Bearer ${this.#apiKey}`,\n ...this.#headers,\n ...options.headers,\n };\n if (body !== undefined) headers[\"Content-Type\"] = \"application/json\";\n // Browsers would turn a custom User-Agent into a CORS preflight header.\n if (!isBrowser()) headers[\"User-Agent\"] = `serpkite-typescript/${VERSION}`;\n const init: RequestInit = {\n method,\n headers,\n body: body === undefined ? undefined : JSON.stringify(body),\n };\n\n for (let attempt = 0; ; attempt++) {\n const canRetry = attempt < maxRetries;\n let res: Response;\n const { signal, cleanup, timedOut } = withTimeout(options.signal, timeoutMs);\n try {\n res = await this.#fetch(this.baseUrl + path, { ...init, signal });\n } catch (err) {\n cleanup();\n if (options.signal?.aborted) throw err;\n const code = timedOut() ? \"timeout\" : \"connection_error\";\n if (canRetry && call.retry !== \"rate_limit\") {\n await sleep(this.#backoff(attempt), options.signal);\n continue;\n }\n const msg = timedOut()\n ? `request timed out after ${timeoutMs} ms`\n : `request failed: ${err instanceof Error ? err.message : String(err)}`;\n throw new SerpKiteError(0, code, msg, undefined, undefined, { cause: err });\n }\n\n let text: string;\n try {\n text = await res.text();\n } catch (err) {\n cleanup();\n if (options.signal?.aborted) throw err;\n if (canRetry && call.retry !== \"rate_limit\") {\n await sleep(this.#backoff(attempt), options.signal);\n continue;\n }\n const code = timedOut() ? \"timeout\" : \"connection_error\";\n throw new SerpKiteError(\n 0,\n code,\n \"failed to read the response body\",\n undefined,\n res.headers,\n {\n cause: err,\n },\n );\n }\n cleanup();\n\n if (!res.ok) {\n const retryable = res.status === 429 || (res.status >= 500 && call.retry !== \"rate_limit\");\n if (canRetry && retryable) {\n await sleep(this.#retryDelay(attempt, res.headers), options.signal);\n continue;\n }\n throw errorFromResponse(res.status, res.headers, text);\n }\n\n options.onResponse?.(responseInfo(res));\n const type = res.headers.get(\"content-type\") ?? \"\";\n if (type.includes(\"json\")) {\n try {\n return JSON.parse(text) as T;\n } catch (err) {\n throw new SerpKiteError(\n res.status,\n \"invalid_response\",\n \"response is not valid JSON\",\n res.headers.get(\"x-request-id\") ?? undefined,\n res.headers,\n { cause: err },\n );\n }\n }\n return text as T;\n }\n }\n\n #backoff(attempt: number): number {\n const base = Math.min(this.retryDelayMs * 2 ** attempt, 8_000);\n return base / 2 + Math.random() * (base / 2);\n }\n\n #retryDelay(attempt: number, headers: Headers): number {\n const after = parseRetryAfter(headers.get(\"retry-after\"));\n return after === undefined ? this.#backoff(attempt) : Math.min(after, 60_000);\n }\n}\n\n// ── helpers ─────────────────────────────────────────────────────────────\n\n/** Builds `?a=1&b=2` from the defined values (empty string when there are none). */\nfunction query(params: Record<string, string | number | boolean | undefined>): string {\n const q = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== null) q.set(k, String(v));\n }\n const s = q.toString();\n return s ? `?${s}` : \"\";\n}\n\nfunction taskId(idOrTask: string | { id: string }): string {\n const id = typeof idOrTask === \"string\" ? idOrTask : idOrTask?.id;\n if (!id) throw new SerpKiteError(0, \"invalid_request\", \"a task id is required\");\n return id;\n}\n\n/** Parses Retry-After (seconds or an HTTP date) into milliseconds. */\nexport function parseRetryAfter(v: string | null): number | undefined {\n if (!v) return undefined;\n const secs = Number(v);\n if (Number.isFinite(secs)) return Math.max(0, secs * 1000);\n const at = Date.parse(v);\n return Number.isNaN(at) ? undefined : Math.max(0, at - Date.now());\n}\n\nfunction responseInfo(res: Response): ResponseInfo {\n const h = res.headers;\n const num = (name: string) => {\n const v = h.get(name);\n if (v === null || v === \"\") return undefined;\n const n = Number(v);\n return Number.isFinite(n) ? n : undefined;\n };\n const cache = h.get(\"x-cache\")?.toUpperCase();\n return {\n status: res.status,\n headers: h,\n requestId: h.get(\"x-request-id\") ?? undefined,\n creditsUsed: num(\"x-credits-used\"),\n creditsRemaining: num(\"x-credits-remaining\"),\n costUsd: num(\"x-cost-usd\"),\n cache: cache === \"HIT\" || cache === \"MISS\" ? cache : undefined,\n latencyMs: num(\"x-latency-ms\"),\n tokensEstimate: num(\"x-tokens-estimate\"),\n };\n}\n\nfunction withTimeout(outer: AbortSignal | undefined, ms: number) {\n const ctrl = new AbortController();\n let timedOut = false;\n const onAbort = () => ctrl.abort(outer?.reason);\n if (outer?.aborted) ctrl.abort(outer.reason);\n else outer?.addEventListener(\"abort\", onAbort, { once: true });\n const timer =\n ms > 0 && Number.isFinite(ms)\n ? setTimeout(() => {\n timedOut = true;\n ctrl.abort(new SerpKiteError(0, \"timeout\", `request timed out after ${ms} ms`));\n }, ms)\n : undefined;\n return {\n signal: ctrl.signal,\n timedOut: () => timedOut,\n cleanup: () => {\n if (timer !== undefined) clearTimeout(timer);\n outer?.removeEventListener(\"abort\", onAbort);\n },\n };\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(signal.reason);\n const t = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(t);\n reject(signal?.reason);\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\ntype EnvHost = {\n process?: { env?: Record<string, string | undefined> };\n Deno?: { env?: { get?: (name: string) => string | undefined } };\n document?: unknown;\n};\n\nfunction env(name: string): string | undefined {\n const g = globalThis as EnvHost;\n try {\n const v = g.process?.env?.[name];\n if (v) return v;\n } catch {\n // process.env may be a throwing proxy on some edge runtimes.\n }\n try {\n return g.Deno?.env?.get?.(name) || undefined;\n } catch {\n // Deno without --allow-env.\n return undefined;\n }\n}\n\nfunction isBrowser(): boolean {\n return typeof (globalThis as EnvHost).document !== \"undefined\";\n}\n","import type { BatchCreateEntry, BatchCreateError } from \"./types\";\n\n/** True when a `batches.create` entry was rejected instead of queued. */\nexport function isBatchError(entry: BatchCreateEntry): entry is BatchCreateError {\n return !(\"id\" in entry && typeof entry.id === \"string\") && \"error\" in entry && !!entry.error;\n}\n","import { SerpKiteError } from \"./errors\";\nimport type { WebhookEvent } from \"./types\";\n\n/** Options for {@link verifyWebhook}. */\nexport interface VerifyWebhookOptions {\n /** Reject deliveries whose timestamp is further than this from now. Default 300. */\n toleranceSeconds?: number;\n /** Current time in Unix seconds (tests). */\n now?: number;\n}\n\ntype HeaderSource = Headers | Record<string, string | string[] | undefined>;\n\nfunction header(headers: HeaderSource, name: string): string | undefined {\n if (typeof (headers as Headers).get === \"function\") {\n return (headers as Headers).get(name) ?? undefined;\n }\n const rec = headers as Record<string, string | string[] | undefined>;\n const key = Object.keys(rec).find((k) => k.toLowerCase() === name.toLowerCase());\n const v = key === undefined ? undefined : rec[key];\n return Array.isArray(v) ? v[0] : v;\n}\n\n/**\n * Checks a webhook delivery (any event: `batch.completed`, `crawl.completed`,\n * `monitor.results`): `X-SerpKite-Signature` must be\n * `v1=<hex HMAC-SHA256(secret, \"<X-SerpKite-Timestamp>.<raw body>\")>` and the\n * timestamp recent. Pass the raw request body exactly as received (not\n * re-serialised JSON). Uses Web Crypto (Node 18+, Deno, Bun, browsers).\n *\n * ```ts\n * const ok = await verifyWebhook(process.env.SERPKITE_WEBHOOK_SECRET!, rawBody, req.headers);\n * ```\n */\nexport async function verifyWebhook(\n secret: string,\n payload: string | Uint8Array,\n headers: HeaderSource,\n options: VerifyWebhookOptions = {},\n): Promise<boolean> {\n const signature = header(headers, \"x-serpkite-signature\");\n const ts = header(headers, \"x-serpkite-timestamp\");\n if (!secret || !signature?.startsWith(\"v1=\") || !ts || !/^\\d+$/.test(ts)) return false;\n const now = options.now ?? Math.floor(Date.now() / 1000);\n if (Math.abs(now - Number(ts)) > (options.toleranceSeconds ?? 300)) return false;\n\n const enc = new TextEncoder();\n const body = typeof payload === \"string\" ? enc.encode(payload) : payload;\n const prefix = enc.encode(`${ts}.`);\n const msg = new Uint8Array(prefix.length + body.length);\n msg.set(prefix);\n msg.set(body, prefix.length);\n const key = await crypto.subtle.importKey(\n \"raw\",\n enc.encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n const mac = new Uint8Array(await crypto.subtle.sign(\"HMAC\", key, msg));\n const want = Array.from(mac, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n const got = signature.slice(3).toLowerCase();\n if (got.length !== want.length) return false;\n let diff = 0;\n for (let i = 0; i < want.length; i++) diff |= want.charCodeAt(i) ^ got.charCodeAt(i);\n return diff === 0;\n}\n\n/**\n * Verifies a delivery (see {@link verifyWebhook}) and returns it typed by its\n * `X-SerpKite-Event` header. `deliveryId` is `X-SerpKite-Delivery` (for\n * `monitor.results` it equals `data.run_id`): use it to deduplicate retries. A\n * `crawl.completed` result over 4 MB arrives as `result: null` with\n * `result_omitted: true`; fetch it from `data.poll_url`. Throws a\n * `SerpKiteError` with code `invalid_signature` when the signature or timestamp\n * doesn't check out.\n *\n * ```ts\n * const ev = await parseWebhook(secret, rawBody, req.headers);\n * if (ev.type === \"monitor.results\") console.log(ev.data.new_results.length);\n * ```\n */\nexport async function parseWebhook(\n secret: string,\n payload: string | Uint8Array,\n headers: HeaderSource,\n options: VerifyWebhookOptions = {},\n): Promise<WebhookEvent> {\n if (!(await verifyWebhook(secret, payload, headers, options))) {\n throw new SerpKiteError(400, \"invalid_signature\", \"webhook signature or timestamp is invalid\");\n }\n const text = typeof payload === \"string\" ? payload : new TextDecoder().decode(payload);\n let data: { event?: unknown };\n try {\n data = JSON.parse(text);\n } catch (err) {\n throw new SerpKiteError(\n 400,\n \"invalid_payload\",\n \"webhook body is not JSON\",\n undefined,\n undefined,\n {\n cause: err,\n },\n );\n }\n const type =\n header(headers, \"x-serpkite-event\") ??\n (typeof data?.event === \"string\" ? data.event : \"batch.completed\");\n return { type, deliveryId: header(headers, \"x-serpkite-delivery\"), data } as WebhookEvent;\n}\n"]}
1
+ {"version":3,"sources":["../src/errors.ts","../src/client.ts","../src/util.ts","../src/webhooks.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Every failure thrown by the SDK. API errors carry the fields of the\n * `{\"error\":{\"code\",\"message\",\"request_id\"}}` envelope; network failures and\n * timeouts use `status: 0` with code `connection_error` or `timeout`.\n */\nexport class SerpKiteError extends Error {\n /** HTTP status, or 0 when no response was received. */\n readonly status: number;\n /** Machine-readable code, e.g. `unauthorized`, `insufficient_credits`, `rate_limited`. */\n readonly code: string;\n /** `X-Request-Id` of the failed request, when the API returned one. */\n readonly requestId: string | undefined;\n /** Response headers, when the API responded. */\n readonly headers: Headers | undefined;\n\n constructor(\n status: number,\n code: string,\n message: string,\n requestId?: string,\n headers?: Headers,\n options?: { cause?: unknown },\n ) {\n super(message, options);\n this.name = \"SerpKiteError\";\n this.status = status;\n this.code = code;\n this.requestId = requestId || undefined;\n this.headers = headers;\n }\n}\n\nconst fallbackCodes: Record<number, string> = {\n 400: \"invalid_request\",\n 401: \"unauthorized\",\n 402: \"insufficient_credits\",\n 403: \"forbidden\",\n 404: \"not_found\",\n 429: \"rate_limited\",\n // The API sends upstream failures as 503 with a JSON body; a bare 502/504\n // comes from a proxy (Cloudflare replaces origin 502/504 bodies).\n 502: \"upstream_error\",\n 503: \"unavailable\",\n 504: \"upstream_timeout\",\n};\n\n/** Builds a SerpKiteError from a non-2xx response body (JSON envelope or anything else). */\nexport function errorFromResponse(status: number, headers: Headers, body: string): SerpKiteError {\n let code = fallbackCodes[status] ?? (status >= 500 ? \"server_error\" : \"http_error\");\n let message = body.trim().slice(0, 500) || `HTTP ${status}`;\n let requestId = headers.get(\"x-request-id\") ?? undefined;\n try {\n const parsed = JSON.parse(body) as {\n error?: { code?: unknown; message?: unknown; request_id?: unknown };\n };\n const e = parsed?.error;\n if (e && typeof e === \"object\") {\n if (typeof e.code === \"string\" && e.code) code = e.code;\n if (typeof e.message === \"string\" && e.message) message = e.message;\n if (typeof e.request_id === \"string\" && e.request_id) requestId = e.request_id;\n }\n } catch {\n // Not JSON: keep the text body as the message.\n }\n return new SerpKiteError(status, code, message, requestId, headers);\n}\n","import { errorFromResponse, SerpKiteError } from \"./errors\";\nimport type {\n Account,\n AutocompleteResponse,\n Batch,\n BatchCreateEntry,\n BatchCreateParams,\n BatchCreateResponse,\n CompactResponse,\n CrawlParams,\n CrawlTask,\n ExtractParams,\n ExtractResponse,\n ImagesResponse,\n MapParams,\n MapResponse,\n Monitor,\n MonitorCreateParams,\n MonitorList,\n MonitorRun,\n MonitorRunList,\n MonitorRunsParams,\n MonitorUpdateParams,\n NewsResponse,\n PatentsResponse,\n PlaceParams,\n PlacesResponse,\n RankParams,\n RankResponse,\n ReviewsParams,\n ReviewsResponse,\n ScholarResponse,\n SearchParams,\n SearchResponse,\n ShoppingResponse,\n TaskCancelResponse,\n TaskCreated,\n VideosResponse,\n WebpageParams,\n WebpageResponse,\n} from \"./types\";\n\nexport const VERSION = \"0.6.0\";\nexport const DEFAULT_BASE_URL = \"https://api.serpkite.com\";\n\nexport interface SerpKiteOptions {\n /** API key (`skt_live_…`). Defaults to the `SERPKITE_API_KEY` environment variable. */\n apiKey?: string;\n /** Defaults to `SERPKITE_BASE_URL` or https://api.serpkite.com. */\n baseUrl?: string;\n /** Per-attempt timeout in milliseconds. Default 60000. */\n timeoutMs?: number;\n /** Retries after the first attempt on 429, 5xx and network errors. Default 2. */\n maxRetries?: number;\n /** Base delay of the exponential backoff in milliseconds. Default 500. */\n retryDelayMs?: number;\n /** Custom fetch implementation. Defaults to the global `fetch`. */\n fetch?: typeof fetch;\n /** Extra headers sent with every request. */\n headers?: Record<string, string>;\n}\n\n/** Billing and tracing details from the response headers. */\nexport interface ResponseInfo {\n status: number;\n headers: Headers;\n requestId: string | undefined;\n creditsUsed: number | undefined;\n creditsRemaining: number | undefined;\n costUsd: number | undefined;\n /** `HIT` when served from cache (`max_age`), else `MISS`. */\n cache: \"HIT\" | \"MISS\" | undefined;\n latencyMs: number | undefined;\n tokensEstimate: number | undefined;\n}\n\nexport interface RequestOptions {\n signal?: AbortSignal;\n /** Overrides the client's per-attempt timeout. */\n timeoutMs?: number;\n /** Overrides the client's retry count. */\n maxRetries?: number;\n headers?: Record<string, string>;\n /** Called with the final response's headers (credits used/remaining, cache, request id). */\n onResponse?: (info: ResponseInfo) => void;\n}\n\nexport interface BatchCreateOptions extends RequestOptions {\n /**\n * Sent as `Idempotency-Key` (1-255 printable ASCII characters, e.g. a UUID).\n * For 24 hours a retry with the same key and body returns the first response\n * instead of queueing and billing the jobs again.\n */\n idempotencyKey?: string;\n}\n\nexport interface WaitOptions {\n /**\n * Give up after this many milliseconds. Default 600000 (10 minutes) for batches and\n * 2100000 (35 minutes) for `waitForCrawl`: a crawl runs for up to 30 minutes.\n */\n timeoutMs?: number;\n /** First delay between polls. Default 1000. Grows 1.5× per poll. */\n pollIntervalMs?: number;\n /** Upper bound of the delay between polls. Default 10000. */\n maxPollIntervalMs?: number;\n signal?: AbortSignal;\n}\n\n/** A vertical whose return type follows `format`: `\"markdown\"` → string, `\"compact\"` → CompactResponse. */\nexport interface VerticalMethod<P, R> {\n (params: P & { format: \"markdown\" }, options?: RequestOptions): Promise<string>;\n (params: P & { format: \"compact\" }, options?: RequestOptions): Promise<CompactResponse>;\n (params: P & { format?: \"json\" }, options?: RequestOptions): Promise<R>;\n (params: P, options?: RequestOptions): Promise<R | CompactResponse | string>;\n}\n\ntype Method = \"GET\" | \"POST\" | \"PATCH\" | \"DELETE\";\n\n/** Task states after which `waitForCrawl` returns. */\nconst TASK_DONE = new Set([\"completed\", \"failed\", \"canceled\"]);\n\ninterface Call {\n method: Method;\n path: string;\n body?: unknown;\n options?: RequestOptions;\n /** Which failures are safe to retry. `all` = 429, 5xx and network errors. */\n retry?: \"all\" | \"rate_limit\";\n}\n\nexport class SerpKite {\n readonly baseUrl: string;\n readonly timeoutMs: number;\n readonly maxRetries: number;\n readonly retryDelayMs: number;\n readonly #apiKey: string;\n readonly #fetch: typeof fetch;\n readonly #headers: Record<string, string>;\n\n constructor(options: SerpKiteOptions = {}) {\n const apiKey = options.apiKey ?? env(\"SERPKITE_API_KEY\");\n if (!apiKey) {\n throw new SerpKiteError(\n 0,\n \"missing_api_key\",\n \"No API key: pass { apiKey } or set the SERPKITE_API_KEY environment variable\",\n );\n }\n this.#apiKey = apiKey;\n this.baseUrl = (options.baseUrl ?? env(\"SERPKITE_BASE_URL\") ?? DEFAULT_BASE_URL).replace(\n /\\/+$/,\n \"\",\n );\n this.timeoutMs = options.timeoutMs ?? 60_000;\n this.maxRetries = Math.max(0, options.maxRetries ?? 2);\n this.retryDelayMs = options.retryDelayMs ?? 500;\n const f = options.fetch ?? globalThis.fetch;\n if (typeof f !== \"function\") {\n throw new SerpKiteError(\n 0,\n \"missing_fetch\",\n \"No global fetch: pass { fetch } (Node 18+ has one)\",\n );\n }\n this.#fetch = f;\n this.#headers = { ...options.headers };\n }\n\n // ── Verticals ─────────────────────────────────────────────────────────\n\n /** Google web search: organic results, answer box, knowledge graph, people also ask… */\n readonly search = this.#vertical<SearchParams, SearchResponse>(\"/v1/search\");\n /** Google Images. */\n readonly images = this.#vertical<SearchParams, ImagesResponse>(\"/v1/images\");\n /** Google Videos. */\n readonly videos = this.#vertical<SearchParams, VideosResponse>(\"/v1/videos\");\n /** Google News. */\n readonly news = this.#vertical<SearchParams, NewsResponse>(\"/v1/news\");\n /**\n * Google Maps search (places with coordinates). Accepts `ll` (\"@lat,lng,14z\"). With\n * `engine: \"yandex\"` (where enabled) the places come from Yandex Maps and carry an `oid`.\n */\n readonly maps = this.#vertical<SearchParams, PlacesResponse>(\"/v1/maps\");\n /** Google local results. */\n readonly places = this.#vertical<SearchParams, PlacesResponse>(\"/v1/places\");\n /**\n * Details of one place by `place_id`, `cid` or `fid`, or by a Yandex Maps `oid` (implies\n * `engine: \"yandex\"`): address, country, time zone, hours\n * (`opening_hours` text and structured `weekly_hours`), phones, description and photos.\n * `results` holds the place, or is empty (not charged) when no place has that id. 1 credit.\n */\n readonly place = this.#vertical<PlaceParams, PlacesResponse>(\"/v1/place\");\n /** Reviews of a place by `place_id`, `cid` or `fid`. Page with `page_token` = `next_page_token`. */\n readonly reviews = this.#vertical<ReviewsParams, ReviewsResponse>(\"/v1/reviews\");\n /** Google Shopping. */\n readonly shopping = this.#vertical<SearchParams, ShoppingResponse>(\"/v1/shopping\");\n /** Google Scholar. */\n readonly scholar = this.#vertical<SearchParams, ScholarResponse>(\"/v1/scholar\");\n /** Google Patents. */\n readonly patents = this.#vertical<SearchParams, PatentsResponse>(\"/v1/patents\");\n /** Google autocomplete suggestions. */\n readonly autocomplete = this.#vertical<SearchParams, AutocompleteResponse>(\"/v1/autocomplete\");\n /** Fetch any public URL as clean Markdown plus metadata. */\n readonly webpage = this.#vertical<WebpageParams, WebpageResponse>(\"/v1/webpage\");\n\n /** Position of `domain` for keyword `q` in the top `num` results (default 100). */\n rank(params: RankParams, options?: RequestOptions): Promise<RankResponse> {\n return this.request({ method: \"POST\", path: \"/v1/rank\", body: params, options });\n }\n\n /**\n * Read up to 20 URLs (HTML or PDF) as Markdown, text or HTML in one call, with optional\n * query-ranked `highlights` (BM25), `include_links` and `include_images`. 1 credit per URL\n * that comes back (0.5 from cache); URLs that fail are listed in `failed` and cost nothing.\n */\n extract(params: ExtractParams, options?: RequestOptions): Promise<ExtractResponse> {\n // Billed per page even when the response is lost: retried only on 429,\n // and the HTTP timeout covers the server's deadline (timeout, default 50 s) + 15 s.\n const wait = ((params.timeout ?? 50) + 15) * 1000;\n return this.request({\n method: \"POST\",\n path: \"/v1/extract\",\n body: params,\n options: {\n ...options,\n timeoutMs: options?.timeoutMs ?? (this.timeoutMs > 0 ? Math.max(this.timeoutMs, wait) : 0),\n },\n retry: \"rate_limit\",\n });\n }\n\n /**\n * The URLs of a site from its sitemaps (XML, RSS/Atom, gzip, plain text) and start page,\n * canonicalised and deduplicated, optionally ranked by `search`. `include_paths` /\n * `exclude_paths` (regular expressions on the URL path) and `ignore_query_parameters`\n * narrow the list. 1 credit; free when nothing is found.\n */\n map(params: MapParams, options?: RequestOptions): Promise<MapResponse> {\n return this.request({ method: \"POST\", path: \"/v1/map\", body: params, options });\n }\n\n /** Balance, limits and this month's usage for the key's account. */\n account(options?: RequestOptions): Promise<Account> {\n return this.request({ method: \"GET\", path: \"/v1/account\", options });\n }\n\n // ── Async tasks: crawl ────────────────────────────────────────────────\n\n /**\n * Starts an async crawl of one site and returns the queued task (`202`). 1 credit per page\n * read (0.5 from cache); `limit` credits (up to 1000 pages, `max_depth` up to 10) are\n * reserved up front and the rest refunded. `sitemap` (`include` default, `only`, `skip`)\n * seeds the crawl with sitemap URLs; `query` reads the most relevant pages first. robots.txt\n * and Crawl-delay are honoured; `result.stats.stopped` says why the crawl ended (`done`,\n * `limit`, `time_limit`, `size_limit`, `too_many_failures`, `canceled`).\n * Only retried on 429, so a lost response never starts (and reserves) a second crawl.\n */\n crawl(params: CrawlParams, options?: RequestOptions): Promise<TaskCreated> {\n return this.request({\n method: \"POST\",\n path: \"/v1/crawl\",\n body: params,\n options,\n retry: \"rate_limit\",\n });\n }\n\n /** Polls a crawl (results are kept for 24 hours). */\n getCrawl(id: string, options?: RequestOptions): Promise<CrawlTask> {\n return this.request({ method: \"GET\", path: `/v1/crawl/${encodeURIComponent(id)}`, options });\n }\n\n /** Cancels a crawl: refunded if still queued, else stops at the next checkpoint. */\n cancelCrawl(id: string, options?: RequestOptions): Promise<TaskCancelResponse> {\n return this.request({\n method: \"DELETE\",\n path: `/v1/crawl/${encodeURIComponent(id)}`,\n options,\n });\n }\n\n /**\n * Polls until the crawl is `completed`, `failed` or `canceled` and returns it (a failed\n * task is returned, not thrown; check `status` and `error`). Accepts an id or the task\n * returned by `crawl`.\n */\n async waitForCrawl(\n idOrTask: string | { id: string },\n options: WaitOptions = {},\n ): Promise<CrawlTask> {\n return this.#waitTask(taskId(idOrTask), (id) => this.getCrawl(id, { signal: options.signal }), {\n ...options,\n timeoutMs: options.timeoutMs ?? 2_100_000,\n });\n }\n\n // ── Monitors ──────────────────────────────────────────────────────────\n\n readonly monitors = {\n /**\n * Saves a `search` or `news` request (`q`) that runs on a schedule (hourly to monthly) and\n * POSTs results it hasn't seen before to `webhook_url` (`monitor.results`). With\n * `endpoint: \"webpage\"` and a `url` it checks that page each interval (1 credit per check)\n * and reports it (`MonitorPageChange`) when its content changes. `metadata` (your JSON\n * object, at most 2 KB) is echoed on the monitor and in its webhooks. Without a\n * `webhook_url`, read new results from `monitors.runs`. `active: false`\n * creates it paused. A monitor pauses itself after 10 failed runs in a row\n * (`last_status: \"paused\"`); `update(id, { active: true })` resumes it. Each run costs\n * what its search costs. Only retried on 429.\n */\n create: (params: MonitorCreateParams, options?: RequestOptions): Promise<Monitor> =>\n this.request({\n method: \"POST\",\n path: \"/v1/monitors\",\n body: params,\n options,\n retry: \"rate_limit\",\n }),\n\n /** The account's monitors. */\n list: (options?: RequestOptions): Promise<MonitorList> =>\n this.request({ method: \"GET\", path: \"/v1/monitors\", options }),\n\n get: (id: string, options?: RequestOptions): Promise<Monitor> =>\n this.request({ method: \"GET\", path: `/v1/monitors/${encodeURIComponent(id)}`, options }),\n\n /**\n * Changes `name`, `interval` / `interval_seconds`, `webhook_url` (`\"\"` removes it),\n * `active` (`true` resumes a paused monitor), `metadata` (an object replaces it, `null`\n * clears it) or the saved request (`endpoint`, `q`, `url`, `country`, `num`, domains,\n * `engine`…). Switching `endpoint` between a search and `webpage` drops the other kind's\n * fields. A changed search reports every result as new on the next run.\n */\n update: (id: string, params: MonitorUpdateParams, options?: RequestOptions): Promise<Monitor> =>\n this.request({\n method: \"PATCH\",\n path: `/v1/monitors/${encodeURIComponent(id)}`,\n body: params,\n options,\n }),\n\n delete: async (id: string, options?: RequestOptions): Promise<void> => {\n await this.request({\n method: \"DELETE\",\n path: `/v1/monitors/${encodeURIComponent(id)}`,\n options,\n });\n },\n\n /** Runs an active monitor at the next scheduler poll (within about 30 seconds).\n * Paused monitors return 409; update(id, { active: true }) resumes and schedules them. */\n run: (id: string, options?: RequestOptions): Promise<Monitor> =>\n this.request({\n method: \"POST\",\n path: `/v1/monitors/${encodeURIComponent(id)}/run`,\n options,\n retry: \"rate_limit\",\n }),\n\n /**\n * One page of the monitor's run history, newest first (`limit` 1-100, default 20). Each\n * run carries its new results for 24 hours. Pass `next_before` as `before` for the next\n * page; it is null on the last one.\n */\n runs: (\n id: string,\n params: MonitorRunsParams = {},\n options?: RequestOptions,\n ): Promise<MonitorRunList> =>\n this.request({\n method: \"GET\",\n path: `/v1/monitors/${encodeURIComponent(id)}/runs${query(params)}`,\n options,\n }),\n\n /**\n * Iterates over every run of the monitor, newest first, fetching pages of `limit` as\n * needed (starting at `before` when given).\n *\n * ```ts\n * for await (const run of sk.monitors.iterRuns(\"m1\")) console.log(run.new_results);\n * ```\n */\n iterRuns: (\n id: string,\n params: MonitorRunsParams = {},\n options?: RequestOptions,\n ): AsyncIterable<MonitorRun> => this.#iterRuns(id, params, options),\n };\n\n // ── Batches ───────────────────────────────────────────────────────────\n\n readonly batches = {\n /**\n * Queue 1-100 requests for one endpoint at half price. Returns one entry per\n * request, in order: a queued `Batch` or an error object. Without an\n * `idempotencyKey` it is only retried on 429, so a lost response never queues\n * (and bills) the same requests twice. With one, 5xx and network errors are\n * retried too: the server replays the first response for the same key and body.\n */\n create: (\n params: BatchCreateParams,\n options: BatchCreateOptions = {},\n ): Promise<BatchCreateResponse> => {\n const { idempotencyKey, ...rest } = options;\n return this.request({\n method: \"POST\",\n path: \"/v1/batches\",\n body: params,\n options: idempotencyKey\n ? { ...rest, headers: { ...rest.headers, \"Idempotency-Key\": idempotencyKey } }\n : rest,\n retry: idempotencyKey ? \"all\" : \"rate_limit\",\n });\n },\n\n /** Poll one batch job. */\n get: (id: string, options?: RequestOptions): Promise<Batch> =>\n this.request({ method: \"GET\", path: `/v1/batches/${encodeURIComponent(id)}`, options }),\n\n /**\n * Poll until the job is `done` or `failed` and return it (a failed job is\n * returned, not thrown; check `status` and `error`). Accepts an id or an\n * entry from `create`; an entry that failed to queue throws its error.\n */\n wait: (idOrEntry: string | BatchCreateEntry | undefined, options: WaitOptions = {}) =>\n this.#wait(idOrEntry, options),\n };\n\n // ── Plumbing ──────────────────────────────────────────────────────────\n\n async *#iterRuns(\n id: string,\n params: MonitorRunsParams,\n options?: RequestOptions,\n ): AsyncGenerator<MonitorRun> {\n let before = params.before;\n for (;;) {\n const page = await this.monitors.runs(id, { ...params, before }, options);\n yield* page.results;\n if (!page.next_before || page.results.length === 0) return;\n before = page.next_before;\n }\n }\n\n async #waitTask<T extends { status: string }>(\n id: string,\n get: (id: string) => Promise<T>,\n o: WaitOptions,\n ): Promise<T> {\n const timeoutMs = o.timeoutMs ?? 600_000;\n const maxInterval = o.maxPollIntervalMs ?? 10_000;\n let interval = o.pollIntervalMs ?? 1_000;\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n const task = await get(id);\n if (TASK_DONE.has(task.status)) return task;\n const left = deadline - Date.now();\n if (left <= 0) {\n throw new SerpKiteError(\n 0,\n \"timeout\",\n `task ${id} still ${task.status} after ${timeoutMs} ms`,\n );\n }\n await sleep(Math.min(interval, left), o.signal);\n interval = Math.min(interval * 1.5, maxInterval);\n }\n }\n\n #vertical<P, R>(path: string): VerticalMethod<P, R> {\n return ((params: P, options?: RequestOptions) =>\n this.request({ method: \"POST\", path, body: params, options })) as VerticalMethod<P, R>;\n }\n\n async #wait(idOrEntry: string | BatchCreateEntry | undefined, o: WaitOptions): Promise<Batch> {\n let id: string | undefined;\n if (typeof idOrEntry === \"string\") {\n id = idOrEntry;\n } else if (idOrEntry && \"id\" in idOrEntry && typeof idOrEntry.id === \"string\") {\n id = idOrEntry.id;\n } else if (idOrEntry && \"error\" in idOrEntry && idOrEntry.error && !(\"id\" in idOrEntry)) {\n const e = idOrEntry.error as { code?: string; message?: string; request_id?: string };\n throw new SerpKiteError(\n 400,\n e.code ?? \"invalid_request\",\n e.message ?? \"batch entry was not queued\",\n e.request_id,\n );\n }\n if (!id) {\n throw new SerpKiteError(0, \"invalid_request\", \"batches.wait needs a batch id\");\n }\n const timeoutMs = o.timeoutMs ?? 600_000;\n const maxInterval = o.maxPollIntervalMs ?? 10_000;\n let interval = o.pollIntervalMs ?? 1_000;\n const deadline = Date.now() + timeoutMs;\n for (;;) {\n const batch = await this.batches.get(id, { signal: o.signal });\n if (batch.status === \"done\" || batch.status === \"failed\") return batch;\n const left = deadline - Date.now();\n if (left <= 0) {\n throw new SerpKiteError(\n 0,\n \"timeout\",\n `batch ${id} still ${batch.status} after ${timeoutMs} ms`,\n );\n }\n await sleep(Math.min(interval, left), o.signal);\n interval = Math.min(interval * 1.5, maxInterval);\n }\n }\n\n /** Low-level request: JSON body in, parsed JSON (or text for non-JSON responses) out. */\n async request<T>(call: Call): Promise<T> {\n const { method, path, body, options = {} } = call;\n const maxRetries = Math.max(0, options.maxRetries ?? this.maxRetries);\n const timeoutMs = options.timeoutMs ?? this.timeoutMs;\n const headers: Record<string, string> = {\n Accept: \"application/json, text/markdown;q=0.9\",\n Authorization: `Bearer ${this.#apiKey}`,\n ...this.#headers,\n ...options.headers,\n };\n if (body !== undefined) headers[\"Content-Type\"] = \"application/json\";\n // Browsers would turn a custom User-Agent into a CORS preflight header.\n if (!isBrowser()) headers[\"User-Agent\"] = `serpkite-typescript/${VERSION}`;\n const init: RequestInit = {\n method,\n headers,\n body: body === undefined ? undefined : JSON.stringify(body),\n };\n\n for (let attempt = 0; ; attempt++) {\n const canRetry = attempt < maxRetries;\n let res: Response;\n const { signal, cleanup, timedOut } = withTimeout(options.signal, timeoutMs);\n try {\n res = await this.#fetch(this.baseUrl + path, { ...init, signal });\n } catch (err) {\n cleanup();\n if (options.signal?.aborted) throw err;\n const code = timedOut() ? \"timeout\" : \"connection_error\";\n if (canRetry && call.retry !== \"rate_limit\") {\n await sleep(this.#backoff(attempt), options.signal);\n continue;\n }\n const msg = timedOut()\n ? `request timed out after ${timeoutMs} ms`\n : `request failed: ${err instanceof Error ? err.message : String(err)}`;\n throw new SerpKiteError(0, code, msg, undefined, undefined, { cause: err });\n }\n\n let text: string;\n try {\n text = await res.text();\n } catch (err) {\n cleanup();\n if (options.signal?.aborted) throw err;\n if (canRetry && call.retry !== \"rate_limit\") {\n await sleep(this.#backoff(attempt), options.signal);\n continue;\n }\n const code = timedOut() ? \"timeout\" : \"connection_error\";\n throw new SerpKiteError(\n 0,\n code,\n \"failed to read the response body\",\n undefined,\n res.headers,\n {\n cause: err,\n },\n );\n }\n cleanup();\n\n if (!res.ok) {\n const retryable = res.status === 429 || (res.status >= 500 && call.retry !== \"rate_limit\");\n if (canRetry && retryable) {\n await sleep(this.#retryDelay(attempt, res.headers), options.signal);\n continue;\n }\n throw errorFromResponse(res.status, res.headers, text);\n }\n\n options.onResponse?.(responseInfo(res));\n const type = res.headers.get(\"content-type\") ?? \"\";\n if (type.includes(\"json\")) {\n try {\n return JSON.parse(text) as T;\n } catch (err) {\n throw new SerpKiteError(\n res.status,\n \"invalid_response\",\n \"response is not valid JSON\",\n res.headers.get(\"x-request-id\") ?? undefined,\n res.headers,\n { cause: err },\n );\n }\n }\n return text as T;\n }\n }\n\n #backoff(attempt: number): number {\n const base = Math.min(this.retryDelayMs * 2 ** attempt, 8_000);\n return base / 2 + Math.random() * (base / 2);\n }\n\n #retryDelay(attempt: number, headers: Headers): number {\n const after = parseRetryAfter(headers.get(\"retry-after\"));\n return after === undefined ? this.#backoff(attempt) : Math.min(after, 60_000);\n }\n}\n\n// ── helpers ─────────────────────────────────────────────────────────────\n\n/** Builds `?a=1&b=2` from the defined values (empty string when there are none). */\nfunction query(params: Record<string, string | number | boolean | undefined>): string {\n const q = new URLSearchParams();\n for (const [k, v] of Object.entries(params)) {\n if (v !== undefined && v !== null) q.set(k, String(v));\n }\n const s = q.toString();\n return s ? `?${s}` : \"\";\n}\n\nfunction taskId(idOrTask: string | { id: string }): string {\n const id = typeof idOrTask === \"string\" ? idOrTask : idOrTask?.id;\n if (!id) throw new SerpKiteError(0, \"invalid_request\", \"a task id is required\");\n return id;\n}\n\n/** Parses Retry-After (seconds or an HTTP date) into milliseconds. */\nexport function parseRetryAfter(v: string | null): number | undefined {\n if (!v) return undefined;\n const secs = Number(v);\n if (Number.isFinite(secs)) return Math.max(0, secs * 1000);\n const at = Date.parse(v);\n return Number.isNaN(at) ? undefined : Math.max(0, at - Date.now());\n}\n\nfunction responseInfo(res: Response): ResponseInfo {\n const h = res.headers;\n const num = (name: string) => {\n const v = h.get(name);\n if (v === null || v === \"\") return undefined;\n const n = Number(v);\n return Number.isFinite(n) ? n : undefined;\n };\n const cache = h.get(\"x-cache\")?.toUpperCase();\n return {\n status: res.status,\n headers: h,\n requestId: h.get(\"x-request-id\") ?? undefined,\n creditsUsed: num(\"x-credits-used\"),\n creditsRemaining: num(\"x-credits-remaining\"),\n costUsd: num(\"x-cost-usd\"),\n cache: cache === \"HIT\" || cache === \"MISS\" ? cache : undefined,\n latencyMs: num(\"x-latency-ms\"),\n tokensEstimate: num(\"x-tokens-estimate\"),\n };\n}\n\nfunction withTimeout(outer: AbortSignal | undefined, ms: number) {\n const ctrl = new AbortController();\n let timedOut = false;\n const onAbort = () => ctrl.abort(outer?.reason);\n if (outer?.aborted) ctrl.abort(outer.reason);\n else outer?.addEventListener(\"abort\", onAbort, { once: true });\n const timer =\n ms > 0 && Number.isFinite(ms)\n ? setTimeout(() => {\n timedOut = true;\n ctrl.abort(new SerpKiteError(0, \"timeout\", `request timed out after ${ms} ms`));\n }, ms)\n : undefined;\n return {\n signal: ctrl.signal,\n timedOut: () => timedOut,\n cleanup: () => {\n if (timer !== undefined) clearTimeout(timer);\n outer?.removeEventListener(\"abort\", onAbort);\n },\n };\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) return reject(signal.reason);\n const t = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n const onAbort = () => {\n clearTimeout(t);\n reject(signal?.reason);\n };\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\ntype EnvHost = {\n process?: { env?: Record<string, string | undefined> };\n Deno?: { env?: { get?: (name: string) => string | undefined } };\n document?: unknown;\n};\n\nfunction env(name: string): string | undefined {\n const g = globalThis as EnvHost;\n try {\n const v = g.process?.env?.[name];\n if (v) return v;\n } catch {\n // process.env may be a throwing proxy on some edge runtimes.\n }\n try {\n return g.Deno?.env?.get?.(name) || undefined;\n } catch {\n // Deno without --allow-env.\n return undefined;\n }\n}\n\nfunction isBrowser(): boolean {\n return typeof (globalThis as EnvHost).document !== \"undefined\";\n}\n","import type { BatchCreateEntry, BatchCreateError } from \"./types\";\n\n/** True when a `batches.create` entry was rejected instead of queued. */\nexport function isBatchError(entry: BatchCreateEntry): entry is BatchCreateError {\n return !(\"id\" in entry && typeof entry.id === \"string\") && \"error\" in entry && !!entry.error;\n}\n","import { SerpKiteError } from \"./errors\";\nimport type { WebhookEvent } from \"./types\";\n\n/** Options for {@link verifyWebhook}. */\nexport interface VerifyWebhookOptions {\n /** Reject deliveries whose timestamp is further than this from now. Default 300. */\n toleranceSeconds?: number;\n /** Current time in Unix seconds (tests). */\n now?: number;\n}\n\ntype HeaderSource = Headers | Record<string, string | string[] | undefined>;\n\nfunction header(headers: HeaderSource, name: string): string | undefined {\n if (typeof (headers as Headers).get === \"function\") {\n return (headers as Headers).get(name) ?? undefined;\n }\n const rec = headers as Record<string, string | string[] | undefined>;\n const key = Object.keys(rec).find((k) => k.toLowerCase() === name.toLowerCase());\n const v = key === undefined ? undefined : rec[key];\n return Array.isArray(v) ? v[0] : v;\n}\n\n/**\n * Checks a webhook delivery (any event: `batch.completed`, `crawl.completed`,\n * `monitor.results`): `X-SerpKite-Signature` must be\n * `v1=<hex HMAC-SHA256(secret, \"<X-SerpKite-Timestamp>.<raw body>\")>` and the\n * timestamp recent. Pass the raw request body exactly as received (not\n * re-serialised JSON). Uses Web Crypto (Node 18+, Deno, Bun, browsers).\n *\n * ```ts\n * const ok = await verifyWebhook(process.env.SERPKITE_WEBHOOK_SECRET!, rawBody, req.headers);\n * ```\n */\nexport async function verifyWebhook(\n secret: string,\n payload: string | Uint8Array,\n headers: HeaderSource,\n options: VerifyWebhookOptions = {},\n): Promise<boolean> {\n const signature = header(headers, \"x-serpkite-signature\");\n const ts = header(headers, \"x-serpkite-timestamp\");\n if (!secret || !signature?.startsWith(\"v1=\") || !ts || !/^\\d+$/.test(ts)) return false;\n const now = options.now ?? Math.floor(Date.now() / 1000);\n if (Math.abs(now - Number(ts)) > (options.toleranceSeconds ?? 300)) return false;\n\n const enc = new TextEncoder();\n const body = typeof payload === \"string\" ? enc.encode(payload) : payload;\n const prefix = enc.encode(`${ts}.`);\n const msg = new Uint8Array(prefix.length + body.length);\n msg.set(prefix);\n msg.set(body, prefix.length);\n const key = await crypto.subtle.importKey(\n \"raw\",\n enc.encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n const mac = new Uint8Array(await crypto.subtle.sign(\"HMAC\", key, msg));\n const want = Array.from(mac, (b) => b.toString(16).padStart(2, \"0\")).join(\"\");\n const got = signature.slice(3).toLowerCase();\n if (got.length !== want.length) return false;\n let diff = 0;\n for (let i = 0; i < want.length; i++) diff |= want.charCodeAt(i) ^ got.charCodeAt(i);\n return diff === 0;\n}\n\n/**\n * Verifies a delivery (see {@link verifyWebhook}) and returns it typed by its\n * `X-SerpKite-Event` header. `deliveryId` is `X-SerpKite-Delivery` (for\n * `monitor.results` it equals `data.run_id`): use it to deduplicate retries. A\n * `crawl.completed` result over 4 MB arrives as `result: null` with\n * `result_omitted: true`; fetch it from `data.poll_url`. Throws a\n * `SerpKiteError` with code `invalid_signature` when the signature or timestamp\n * doesn't check out.\n *\n * ```ts\n * const ev = await parseWebhook(secret, rawBody, req.headers);\n * if (ev.type === \"monitor.results\") console.log(ev.data.new_results.length);\n * ```\n */\nexport async function parseWebhook(\n secret: string,\n payload: string | Uint8Array,\n headers: HeaderSource,\n options: VerifyWebhookOptions = {},\n): Promise<WebhookEvent> {\n if (!(await verifyWebhook(secret, payload, headers, options))) {\n throw new SerpKiteError(400, \"invalid_signature\", \"webhook signature or timestamp is invalid\");\n }\n const text = typeof payload === \"string\" ? payload : new TextDecoder().decode(payload);\n let data: { event?: unknown };\n try {\n data = JSON.parse(text);\n } catch (err) {\n throw new SerpKiteError(\n 400,\n \"invalid_payload\",\n \"webhook body is not JSON\",\n undefined,\n undefined,\n {\n cause: err,\n },\n );\n }\n const type =\n header(headers, \"x-serpkite-event\") ??\n (typeof data?.event === \"string\" ? data.event : \"batch.completed\");\n return { type, deliveryId: header(headers, \"x-serpkite-delivery\"), data } as WebhookEvent;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "serpkite",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "Official TypeScript/JavaScript SDK for SerpKite, the Google search API built for AI agents: clean JSON or Markdown results.",
5
5
  "license": "MIT",
6
6
  "author": "SerpKite",