@simpleq/sdk 0.1.0 → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +14 -12
package/README.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# @simpleq/sdk
|
|
2
2
|
|
|
3
|
+
[](https://www.npmjs.com/package/@simpleq/sdk)
|
|
4
|
+
[](https://github.com/simpleqio/simpleq-sdk-typescript/actions/workflows/ci.yml)
|
|
5
|
+
[](./LICENSE)
|
|
6
|
+
|
|
3
7
|
Official Node/TypeScript SDK for [SimpleQ](https://docs.simpleq.io): publish jobs, verify webhook signatures, and run the ack-mode callbacks. ESM + CommonJS, bundled types, zero runtime dependencies. Requires Node 22+. All durations are in **seconds**. The live API contract is machine-readable at [docs.simpleq.io/openapi.json](https://docs.simpleq.io/openapi.json).
|
|
4
8
|
|
|
5
9
|
```bash
|
package/dist/index.cjs
CHANGED
|
@@ -200,7 +200,7 @@ function verifyWebhook(rawBody, signatureHeader, signingSecret) {
|
|
|
200
200
|
var DEFAULT_BASE_URL = "https://api.simpleq.io";
|
|
201
201
|
var DEFAULT_TIMEOUT_SECONDS = 30;
|
|
202
202
|
var DEFAULT_MAX_RETRIES = 2;
|
|
203
|
-
var VERSION = "0.1.
|
|
203
|
+
var VERSION = "0.1.1";
|
|
204
204
|
var SimpleQ = class {
|
|
205
205
|
constructor(options = {}) {
|
|
206
206
|
/** Webhook signature helpers. Usable without an API key (only a `signingSecret` is needed). */
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/webhooks.ts","../src/client.ts"],"names":["createHmac","timingSafeEqual","randomUUID"],"mappings":";;;;;;;;;AAGO,IAAM,YAAA,GAAN,cAA2B,KAAA,CAAM;AAAA,EACtC,YAAY,OAAA,EAAiB;AAC3B,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,KAAK,WAAA,CAAY,IAAA;AAAA,EAC/B;AACF;AAGO,IAAM,sBAAA,GAAN,cAAqC,YAAA,CAAa;AAAC;AAGnD,IAAM,0BAAA,GAAN,cAAyC,YAAA,CAAa;AAAC;AASvD,IAAM,mBAAA,GAAN,MAAM,oBAAA,SAA4B,YAAA,CAAa;AAAA,EAMpD,WAAA,CAAY,YAAqB,OAAA,EAA4D;AAC3F,IAAA,MAAM,MAAA,GAAS,UAAA,IAAc,IAAA,GAAO,CAAA,cAAA,EAAiB,UAAU,CAAA,EAAA,CAAA,GAAO,EAAA;AACtE,IAAA,KAAA,CAAM,OAAA,EAAS,MAAA,IAAU,CAAA,oBAAA,EAAuB,MAAM,CAAA,CAAE,CAAA;AACxD,IAAA,IAAA,CAAK,UAAA,GAAa,UAAA;AAClB,IAAA,IAAA,CAAK,MAAA,GAAS,SAAS,MAAA,IAAU,GAAA;AAAA,EACnC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,OAAO,IAAA,CAAK,GAAA,EAAc,OAAA,EAAuE;AAC/F,IAAA,MAAM,CAAA,GAAI,GAAA;AACV,IAAA,MAAM,MAAA,GACJ,CAAA,EAAG,MAAA,KAAW,GAAA,IAAO,CAAA,EAAG,MAAA,KAAW,GAAA,IAAO,CAAA,EAAG,MAAA,KAAW,GAAA,GAAM,CAAA,CAAE,MAAA,GAAS,GAAA;AAC3E,IAAA,MAAM,UAAA,GAAa,iBAAA,CAAkB,GAAG,CAAA,IAAK,OAAA,EAAS,QAAA;AACtD,IAAA,MAAM,MAAA,GACJ,OAAA,EAAS,MAAA,KAAW,OAAO,CAAA,EAAG,YAAY,QAAA,IAAY,CAAA,CAAE,OAAA,GAAU,CAAA,CAAE,OAAA,GAAU,MAAA,CAAA;AAChF,IAAA,OAAO,IAAI,oBAAA,CAAoB,UAAA,EAAY,EAAE,MAAA,EAAQ,QAAQ,CAAA;AAAA,EAC/D;AACF;AAEA,SAAS,UAAA,CAAW,SAAkB,IAAA,EAAkC;AACtE,EAAA,IAAI,CAAC,OAAA,IAAW,OAAO,OAAA,KAAY,UAAU,OAAO,MAAA;AACpD,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,MAAA,GAAS,OAAA;AACf,EAAA,MAAM,QAAQ,MAAA,CAAO,IAAA,CAAK,aAAa,CAAA,IAAK,OAAO,aAAa,CAAA;AAChE,EAAA,OAAO,OAAO,KAAA,KAAU,QAAA,GAAW,KAAA,GAAQ,MAAA;AAC7C;AAQO,SAAS,kBAAkB,GAAA,EAAkC;AAClE,EAAA,MAAM,CAAA,GAAI,GAAA;AACV,EAAA,MAAM,GAAA,GACJ,UAAA,CAAW,CAAA,EAAG,OAAA,EAAS,aAAa,KAAK,UAAA,CAAW,CAAA,EAAG,QAAA,EAAU,OAAA,EAAS,aAAa,CAAA;AACzF,EAAA,IAAI,GAAA,KAAQ,QAAW,OAAO,MAAA;AAC9B,EAAA,MAAM,OAAA,GAAU,OAAO,GAAG,CAAA;AAC1B,EAAA,OAAO,OAAO,QAAA,CAAS,OAAO,CAAA,IAAK,OAAA,IAAW,IAAI,OAAA,GAAU,MAAA;AAC9D;AAGO,IAAM,QAAA,GAAN,cAAuB,YAAA,CAAa;AAAA,EAIzC,WAAA,CAAY,OAAA,EAAiB,MAAA,EAAgB,IAAA,EAAe;AAC1D,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACd;AACF;AAGO,IAAM,mBAAA,GAAN,cAAkC,QAAA,CAAS;AAAC;AAG5C,IAAM,eAAA,GAAN,cAA8B,QAAA,CAAS;AAAC;AAGxC,IAAM,aAAA,GAAN,cAA4B,QAAA,CAAS;AAAC;AAGtC,IAAM,cAAA,GAAN,cAA6B,QAAA,CAAS;AAAA,EAG3C,WAAA,CAAY,OAAA,EAAiB,MAAA,EAAgB,IAAA,EAAe,UAAA,EAAqB;AAC/E,IAAA,KAAA,CAAM,OAAA,EAAS,QAAQ,IAAI,CAAA;AAC3B,IAAA,IAAA,CAAK,UAAA,GAAa,UAAA;AAAA,EACpB;AACF;AAEA,SAAS,cAAA,CAAe,QAAgB,IAAA,EAAuB;AAC7D,EAAA,IAAI,IAAA,IAAQ,OAAO,IAAA,KAAS,QAAA,IAAY,WAAW,IAAA,EAAM;AACvD,IAAA,MAAM,MAAO,IAAA,CAA4B,KAAA;AACzC,IAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,EAAU,OAAO,GAAA;AACpC,IAAA,IAAI,GAAA,IAAO,OAAO,GAAA,KAAQ,QAAA,SAAiB,CAAA,mBAAA,EAAsB,IAAA,CAAK,SAAA,CAAU,GAAG,CAAC,CAAA,CAAA;AAAA,EACtF;AACA,EAAA,OAAO,2BAA2B,MAAM,CAAA,CAAA,CAAA;AAC1C;AAGO,SAAS,WAAA,CAAY,MAAA,EAAgB,IAAA,EAAe,OAAA,EAA6B;AACtF,EAAA,MAAM,OAAA,GAAU,cAAA,CAAe,MAAA,EAAQ,IAAI,CAAA;AAC3C,EAAA,QAAQ,MAAA;AAAQ,IACd,KAAK,GAAA;AACH,MAAA,OAAO,IAAI,eAAA,CAAgB,OAAA,EAAS,MAAA,EAAQ,IAAI,CAAA;AAAA,IAClD,KAAK,GAAA;AAAA,IACL,KAAK,GAAA;AACH,MAAA,OAAO,IAAI,mBAAA,CAAoB,OAAA,EAAS,MAAA,EAAQ,IAAI,CAAA;AAAA,IACtD,KAAK,GAAA;AACH,MAAA,OAAO,IAAI,aAAA,CAAc,OAAA,EAAS,MAAA,EAAQ,IAAI,CAAA;AAAA,IAChD,KAAK,GAAA,EAAK;AACR,MAAA,MAAM,GAAA,GAAM,OAAA,EAAS,GAAA,CAAI,aAAa,CAAA;AACtC,MAAA,MAAM,UAAA,GAAa,GAAA,IAAO,IAAA,GAAO,MAAA,CAAO,GAAG,CAAA,GAAI,GAAA;AAC/C,MAAA,OAAO,IAAI,cAAA,CAAe,OAAA,EAAS,MAAA,EAAQ,IAAA,EAAM,OAAO,QAAA,CAAS,UAAU,CAAA,GAAI,UAAA,GAAa,MAAS,CAAA;AAAA,IACvG;AAAA,IACA;AACE,MAAA,OAAO,IAAI,QAAA,CAAS,OAAA,EAAS,MAAA,EAAQ,IAAI,CAAA;AAAA;AAE/C;;;ACrHA,IAAM,gBAAA,uBAAuB,GAAA,CAAI,CAAC,KAAK,GAAA,EAAK,GAAA,EAAK,GAAA,EAAK,GAAG,CAAC,CAAA;AAE1D,IAAM,KAAA,GAAQ,CAAC,EAAA,KAA8B,IAAI,OAAA,CAAQ,CAAC,OAAA,KAAY,UAAA,CAAW,OAAA,EAAS,EAAE,CAAC,CAAA;AAG7F,SAAS,UAAU,OAAA,EAAyB;AAC1C,EAAA,MAAM,UAAU,IAAA,CAAK,GAAA,CAAI,GAAA,GAAM,CAAA,IAAK,SAAS,GAAI,CAAA;AACjD,EAAA,OAAO,KAAK,KAAA,CAAM,OAAA,IAAW,MAAM,IAAA,CAAK,MAAA,KAAW,GAAA,CAAI,CAAA;AACzD;AAEO,IAAM,aAAN,MAAiB;AAAA,EACtB,YAA6B,IAAA,EAAyB;AAAzB,IAAA,IAAA,CAAA,IAAA,GAAA,IAAA;AAAA,EAA0B;AAAA,EAEvD,MAAM,QAAW,GAAA,EAAiC;AAChD,IAAA,MAAM,cAAe,GAAA,CAAI,KAAA,IAAS,OAAQ,IAAA,CAAK,IAAA,CAAK,aAAa,CAAA,GAAI,CAAA;AACrE,IAAA,IAAI,SAAA;AAEJ,IAAA,KAAA,IAAS,OAAA,GAAU,CAAA,EAAG,OAAA,GAAU,WAAA,EAAa,OAAA,EAAA,EAAW;AACtD,MAAA,IAAI;AACF,QAAA,OAAO,MAAM,IAAA,CAAK,OAAA,CAAW,GAAG,CAAA;AAAA,MAClC,SAAS,GAAA,EAAK;AACZ,QAAA,SAAA,GAAY,GAAA;AACZ,QAAA,IAAI,CAAC,KAAK,WAAA,CAAY,GAAG,KAAK,OAAA,KAAY,WAAA,GAAc,GAAG,MAAM,GAAA;AACjE,QAAA,MAAM,MAAM,IAAA,CAAK,YAAA,CAAa,GAAG,CAAA,IAAK,SAAA,CAAU,OAAO,CAAC,CAAA;AAAA,MAC1D;AAAA,IACF;AAEA,IAAA,MAAM,qBAAqB,KAAA,GAAQ,SAAA,GAAY,IAAI,YAAA,CAAa,MAAA,CAAO,SAAS,CAAC,CAAA;AAAA,EACnF;AAAA,EAEA,MAAc,QAAW,GAAA,EAAiC;AACxD,IAAA,MAAM,UAAA,GAAa,IAAI,eAAA,EAAgB;AACvC,IAAA,MAAM,KAAA,GAAQ,WAAW,MAAM,UAAA,CAAW,OAAM,EAAG,IAAA,CAAK,KAAK,OAAO,CAAA;AACpE,IAAA,IAAI,GAAA;AACJ,IAAA,IAAI;AACF,MAAA,GAAA,GAAM,MAAM,KAAK,IAAA,CAAK,SAAA,CAAU,KAAK,IAAA,CAAK,OAAA,GAAU,IAAI,IAAA,EAAM;AAAA,QAC5D,QAAQ,GAAA,CAAI,MAAA;AAAA,QACZ,OAAA,EAAS;AAAA,UACP,aAAA,EAAe,CAAA,OAAA,EAAU,IAAA,CAAK,IAAA,CAAK,MAAM,CAAA,CAAA;AAAA,UACzC,cAAA,EAAgB,kBAAA;AAAA,UAChB,YAAA,EAAc,KAAK,IAAA,CAAK,SAAA;AAAA,UACxB,GAAG,GAAA,CAAI;AAAA,SACT;AAAA,QACA,IAAA,EAAM,IAAI,IAAA,KAAS,KAAA,CAAA,GAAY,KAAK,SAAA,CAAU,GAAA,CAAI,IAAI,CAAA,GAAI,KAAA,CAAA;AAAA,QAC1D,QAAQ,UAAA,CAAW;AAAA,OACpB,CAAA;AAAA,IACH,SAAS,GAAA,EAAK;AACZ,MAAA,MAAM,IAAI,sBAAA;AAAA,QACR,CAAA,WAAA,EAAc,GAAA,CAAI,MAAM,CAAA,CAAA,EAAI,GAAA,CAAI,IAAI,CAAA,SAAA,EAAY,GAAA,YAAe,KAAA,GAAQ,GAAA,CAAI,OAAA,GAAU,MAAA,CAAO,GAAG,CAAC,CAAA;AAAA,OAClG;AAAA,IACF,CAAA,SAAE;AACA,MAAA,YAAA,CAAa,KAAK,CAAA;AAAA,IACpB;AAEA,IAAA,IAAI,CAAC,GAAA,CAAI,EAAA,EAAI,MAAM,WAAA,CAAY,GAAA,CAAI,MAAA,EAAQ,MAAM,IAAA,CAAK,SAAA,CAAU,GAAG,CAAA,EAAG,IAAI,OAAO,CAAA;AACjF,IAAA,IAAI,GAAA,CAAI,MAAA,KAAW,GAAA,EAAK,OAAO,MAAA;AAC/B,IAAA,OAAQ,MAAM,IAAA,CAAK,SAAA,CAAU,GAAG,CAAA;AAAA,EAClC;AAAA,EAEA,MAAc,UAAU,GAAA,EAAiC;AACvD,IAAA,MAAM,IAAA,GAAO,MAAM,GAAA,CAAI,IAAA,EAAK;AAC5B,IAAA,IAAI,CAAC,MAAM,OAAO,MAAA;AAClB,IAAA,IAAI;AACF,MAAA,OAAO,IAAA,CAAK,MAAM,IAAI,CAAA;AAAA,IACxB,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,IAAA;AAAA,IACT;AAAA,EACF;AAAA,EAEQ,YAAY,GAAA,EAAuB;AACzC,IAAA,IAAI,GAAA,YAAe,wBAAwB,OAAO,IAAA;AAClD,IAAA,IAAI,eAAe,QAAA,EAAU,OAAO,gBAAA,CAAiB,GAAA,CAAI,IAAI,MAAM,CAAA;AACnE,IAAA,OAAO,KAAA;AAAA,EACT;AAAA,EAEQ,aAAa,GAAA,EAAkC;AACrD,IAAA,OAAO,GAAA,YAAe,kBAAkB,OAAO,GAAA,CAAI,eAAe,QAAA,GAC9D,GAAA,CAAI,aAAa,GAAA,GACjB,MAAA;AAAA,EACN;AACF,CAAA;AC9FO,IAAM,gBAAA,GAAmB;AAEhC,SAAS,SAAS,OAAA,EAA+C;AAC/D,EAAA,IAAI,OAAO,OAAA,KAAY,QAAA,SAAiB,MAAA,CAAO,IAAA,CAAK,SAAS,MAAM,CAAA;AACnE,EAAA,IAAI,MAAA,CAAO,QAAA,CAAS,OAAO,CAAA,EAAG,OAAO,OAAA;AACrC,EAAA,OAAO,MAAA,CAAO,KAAK,OAAO,CAAA;AAC5B;AAEA,SAAS,iBAAA,CAAkB,SAAuC,aAAA,EAA+B;AAC/F,EAAA,OAAO,SAAA,GAAYA,iBAAA,CAAW,QAAA,EAAU,aAAa,CAAA,CAAE,MAAA,CAAO,QAAA,CAAS,OAAO,CAAC,CAAA,CAAE,MAAA,CAAO,KAAK,CAAA;AAC/F;AAQO,SAAS,sBAAA,CACd,OAAA,EACA,eAAA,EACA,aAAA,EACS;AACT,EAAA,IAAI,CAAC,iBAAiB,OAAO,KAAA;AAC7B,EAAA,MAAM,WAAW,MAAA,CAAO,IAAA,CAAK,iBAAA,CAAkB,OAAA,EAAS,aAAa,CAAC,CAAA;AACtE,EAAA,MAAM,QAAA,GAAW,MAAA,CAAO,IAAA,CAAK,eAAe,CAAA;AAE5C,EAAA,IAAI,QAAA,CAAS,MAAA,KAAW,QAAA,CAAS,MAAA,EAAQ,OAAO,KAAA;AAChD,EAAA,OAAOC,sBAAA,CAAgB,UAAU,QAAQ,CAAA;AAC3C;AAQO,SAAS,aAAA,CACd,OAAA,EACA,eAAA,EACA,aAAA,EACgB;AAChB,EAAA,IAAI,CAAC,sBAAA,CAAuB,OAAA,EAAS,eAAA,EAAiB,aAAa,CAAA,EAAG;AACpE,IAAA,MAAM,IAAI,2BAA2B,+CAA+C,CAAA;AAAA,EACtF;AACA,EAAA,MAAM,IAAA,GAAO,OAAO,OAAA,KAAY,QAAA,GAAW,UAAU,QAAA,CAAS,OAAO,CAAA,CAAE,QAAA,CAAS,MAAM,CAAA;AACtF,EAAA,OAAO,IAAA,CAAK,MAAM,IAAI,CAAA;AACxB;;;ACxCA,IAAM,gBAAA,GAAmB,wBAAA;AAEzB,IAAM,uBAAA,GAA0B,EAAA;AAChC,IAAM,mBAAA,GAAsB,CAAA;AAE5B,IAAM,OAAA,GAAU,OAAA;AAGT,IAAM,UAAN,MAAc;AAAA,EASnB,WAAA,CAAY,OAAA,GAA0B,EAAC,EAAG;AAL1C;AAAA,IAAA,IAAA,CAAS,QAAA,GAAW;AAAA,MAClB,sBAAA;AAAA,MACA;AAAA,KACF;AAGE,IAAA,MAAM,MAAA,GAAS,OAAA,CAAQ,MAAA,IAAU,OAAA,CAAQ,GAAA,CAAI,eAAA;AAC7C,IAAA,IAAI,CAAC,MAAA,EAAQ;AACX,MAAA,MAAM,IAAI,aAAa,wEAAwE,CAAA;AAAA,IACjG;AAEA,IAAA,MAAM,SAAA,GAAY,OAAA,CAAQ,KAAA,IAAS,UAAA,CAAW,KAAA;AAC9C,IAAA,IAAI,OAAO,cAAc,UAAA,EAAY;AACnC,MAAA,MAAM,IAAI,aAAa,gEAAgE,CAAA;AAAA,IACzF;AAEA,IAAA,IAAA,CAAK,IAAA,GAAO,IAAI,UAAA,CAAW;AAAA,MACzB,MAAA;AAAA,MACA,UAAU,OAAA,CAAQ,OAAA,IAAW,gBAAA,EAAkB,OAAA,CAAQ,QAAQ,EAAE,CAAA;AAAA,MACjE,OAAA,EAAA,CAAU,OAAA,CAAQ,OAAA,IAAW,uBAAA,IAA2B,GAAA;AAAA,MACxD,UAAA,EAAY,QAAQ,UAAA,IAAc,mBAAA;AAAA,MAClC,SAAA;AAAA,MACA,SAAA,EAAW,gBAAgB,OAAO,CAAA;AAAA,KACnC,CAAA;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,OAAA,CAAQ,SAAA,EAAmB,MAAA,EAAoD;AACnF,IAAA,MAAM,cAAA,GAAiB,MAAA,CAAO,cAAA,IAAkBC,iBAAA,EAAW;AAE3D,IAAA,MAAM,IAAA,GAAgC,EAAE,OAAA,EAAS,MAAA,CAAO,OAAA,EAAQ;AAChE,IAAA,IAAI,cAAA,KAAmB,MAAA,EAAW,IAAA,CAAK,cAAA,GAAiB,cAAA;AACxD,IAAA,IAAI,MAAA,CAAO,KAAA,KAAU,MAAA,EAAW,IAAA,CAAK,QAAQ,MAAA,CAAO,KAAA;AAEpD,IAAA,OAAO,IAAA,CAAK,KAAK,OAAA,CAA4B;AAAA,MAC3C,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,CAAA,WAAA,EAAc,kBAAA,CAAmB,SAAS,CAAC,CAAA,KAAA,CAAA;AAAA,MACjD;AAAA,KACD,CAAA;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,OAAO,KAAA,EAA6B;AACxC,IAAA,OAAO,IAAA,CAAK,KAAK,OAAA,CAAa;AAAA,MAC5B,MAAA,EAAQ,KAAA;AAAA,MACR,IAAA,EAAM,CAAA,SAAA,EAAY,kBAAA,CAAmB,KAAK,CAAC,CAAA;AAAA,KAC5C,CAAA;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,IAAI,KAAA,EAAqC;AAC7C,IAAA,OAAO,IAAA,CAAK,KAAK,OAAA,CAAqB;AAAA,MACpC,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,CAAA,SAAA,EAAY,kBAAA,CAAmB,KAAK,CAAC,CAAA,IAAA,CAAA;AAAA,MAC3C,MAAM;AAAC,KACR,CAAA;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,IAAA,CAAK,KAAA,EAAe,OAAA,GAAuB,EAAC,EAAyB;AACzE,IAAA,OAAO,IAAA,CAAK,KAAK,OAAA,CAAqB;AAAA,MACpC,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,CAAA,SAAA,EAAY,kBAAA,CAAmB,KAAK,CAAC,CAAA,KAAA,CAAA;AAAA,MAC3C,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AAAA;AAAA,EAGA,MAAM,KAAA,CAAM,KAAA,EAAe,OAAA,EAA6C;AACtE,IAAA,MAAM,EAAE,UAAA,EAAW,GAAI,OAAA,IAAW,EAAC;AACnC,IAAA,IAAI,OAAO,UAAA,KAAe,QAAA,IAAY,CAAC,MAAA,CAAO,QAAA,CAAS,UAAU,CAAA,IAAK,UAAA,GAAa,CAAA,IAAK,UAAA,GAAa,IAAA,EAAM;AACzG,MAAA,MAAM,IAAI,eAAA,CAAgB,yEAAA,EAA2E,GAAA,EAAK,MAAS,CAAA;AAAA,IACrH;AACA,IAAA,OAAO,IAAA,CAAK,KAAK,OAAA,CAAqB;AAAA,MACpC,MAAA,EAAQ,MAAA;AAAA,MACR,IAAA,EAAM,CAAA,SAAA,EAAY,kBAAA,CAAmB,KAAK,CAAC,CAAA,MAAA,CAAA;AAAA,MAC3C,IAAA,EAAM;AAAA,KACP,CAAA;AAAA,EACH;AACF","file":"index.cjs","sourcesContent":["// Error and signal types for @simpleq/sdk.\n\n/** Base class for everything thrown by the SDK. Catch this to handle any SimpleQ error. */\nexport class SimpleQError extends Error {\n constructor(message: string) {\n super(message);\n this.name = this.constructor.name;\n }\n}\n\n/** A network failure, timeout, or aborted request — retryable. */\nexport class SimpleQConnectionError extends SimpleQError {}\n\n/** Thrown by `verifyWebhook` when a webhook signature does not verify. */\nexport class SignatureVerificationError extends SimpleQError {}\n\nexport type BackpressureStatus = 429 | 503 | 529;\n\n/**\n * A backpressure signal — not a failure. Throw this from a standard-mode webhook handler to\n * tell the adapter to respond with `429`/`503`/`529` and a `Retry-After`. SimpleQ then holds\n * the job and redelivers it without burning a delivery attempt.\n */\nexport class SimpleQBackpressure extends SimpleQError {\n /** Seconds to hold the job before redelivery. Omit to let SimpleQ pick its fallback. */\n readonly retryAfter?: number;\n /** HTTP status the adapter responds with. Defaults to `503`. */\n readonly status: BackpressureStatus;\n\n constructor(retryAfter?: number, options?: { status?: BackpressureStatus; reason?: string }) {\n const detail = retryAfter != null ? ` (retry after ${retryAfter}s)` : '';\n super(options?.reason ?? `SimpleQ backpressure${detail}`);\n this.retryAfter = retryAfter;\n this.status = options?.status ?? 503;\n }\n\n /**\n * Build a backpressure signal directly from a provider error (Anthropic, OpenAI, any\n * HTTP-shaped error). Reads `err.status` (429/503/529 pass through; anything else maps\n * to 503) and the `Retry-After` header in seconds from `err.headers` or\n * `err.response.headers` (plain object or Headers). When no header is present,\n * `options.fallback` seconds is used; with neither, SimpleQ applies its own 60s hold.\n */\n static from(err: unknown, options?: { fallback?: number; reason?: string }): SimpleQBackpressure {\n const e = err as { status?: unknown; message?: unknown } | null | undefined;\n const status: BackpressureStatus =\n e?.status === 429 || e?.status === 503 || e?.status === 529 ? e.status : 503;\n const retryAfter = retryAfterSeconds(err) ?? options?.fallback;\n const reason =\n options?.reason ?? (typeof e?.message === 'string' && e.message ? e.message : undefined);\n return new SimpleQBackpressure(retryAfter, { status, reason });\n }\n}\n\nfunction readHeader(headers: unknown, name: string): string | undefined {\n if (!headers || typeof headers !== 'object') return undefined;\n if (typeof (headers as Headers).get === 'function') {\n return (headers as Headers).get(name) ?? undefined;\n }\n const record = headers as Record<string, unknown>;\n const value = record[name.toLowerCase()] ?? record['Retry-After'];\n return typeof value === 'string' ? value : undefined;\n}\n\n/**\n * Read the `Retry-After` value, in **seconds**, from a provider error (Anthropic, OpenAI, any\n * HTTP-shaped error). Looks at `err.headers` and `err.response.headers` (plain object or a\n * `Headers` instance). Returns `undefined` when the header is absent or non-numeric (e.g. an\n * HTTP-date). Pair with `simpleq.defer` in ack mode: `defer(id, { retryAfter: retryAfterSeconds(err) ?? 10 })`.\n */\nexport function retryAfterSeconds(err: unknown): number | undefined {\n const e = err as { headers?: unknown; response?: { headers?: unknown } } | null | undefined;\n const raw =\n readHeader(e?.headers, 'retry-after') ?? readHeader(e?.response?.headers, 'retry-after');\n if (raw === undefined) return undefined;\n const seconds = Number(raw);\n return Number.isFinite(seconds) && seconds >= 0 ? seconds : undefined;\n}\n\n/** Any non-2xx response from the SimpleQ API. */\nexport class ApiError extends SimpleQError {\n readonly status: number;\n readonly body: unknown;\n\n constructor(message: string, status: number, body: unknown) {\n super(message);\n this.status = status;\n this.body = body;\n }\n}\n\n/** `401`/`403` — the API key is missing, invalid, or revoked. */\nexport class AuthenticationError extends ApiError {}\n\n/** `400` — request validation failed. `body.error` carries the field-level details. */\nexport class ValidationError extends ApiError {}\n\n/** `404` — the queue or job was not found. */\nexport class NotFoundError extends ApiError {}\n\n/** `429` — rate limited. `retryAfter` is the `Retry-After` header in seconds, if present. */\nexport class RateLimitError extends ApiError {\n readonly retryAfter?: number;\n\n constructor(message: string, status: number, body: unknown, retryAfter?: number) {\n super(message, status, body);\n this.retryAfter = retryAfter;\n }\n}\n\nfunction extractMessage(status: number, body: unknown): string {\n if (body && typeof body === 'object' && 'error' in body) {\n const err = (body as { error: unknown }).error;\n if (typeof err === 'string') return err;\n if (err && typeof err === 'object') return `Validation failed: ${JSON.stringify(err)}`;\n }\n return `SimpleQ API error (HTTP ${status})`;\n}\n\n/** Map an HTTP status + parsed body to the right ApiError subclass. */\nexport function mapApiError(status: number, body: unknown, headers?: Headers): ApiError {\n const message = extractMessage(status, body);\n switch (status) {\n case 400:\n return new ValidationError(message, status, body);\n case 401:\n case 403:\n return new AuthenticationError(message, status, body);\n case 404:\n return new NotFoundError(message, status, body);\n case 429: {\n const raw = headers?.get('retry-after');\n const retryAfter = raw != null ? Number(raw) : NaN;\n return new RateLimitError(message, status, body, Number.isFinite(retryAfter) ? retryAfter : undefined);\n }\n default:\n return new ApiError(message, status, body);\n }\n}\n","// Internal fetch wrapper + retry engine. Not part of the public API.\nimport { ApiError, RateLimitError, SimpleQConnectionError, SimpleQError, mapApiError } from './errors.js';\n\nexport interface HttpClientOptions {\n apiKey: string;\n baseUrl: string;\n timeout: number;\n maxRetries: number;\n fetchImpl: typeof fetch;\n userAgent: string;\n}\n\nexport interface RequestOptions {\n method: string;\n path: string;\n body?: unknown;\n headers?: Record<string, string>;\n /** Retry transient failures (network / 5xx / 429). Default true. */\n retry?: boolean;\n}\n\nconst RETRYABLE_STATUS = new Set([429, 500, 502, 503, 504]);\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n// Exponential backoff (base 250ms, cap 8s) with full jitter.\nfunction backoffMs(attempt: number): number {\n const ceiling = Math.min(250 * 2 ** attempt, 8000);\n return Math.round(ceiling * (0.5 + Math.random() * 0.5));\n}\n\nexport class HttpClient {\n constructor(private readonly opts: HttpClientOptions) {}\n\n async request<T>(req: RequestOptions): Promise<T> {\n const maxAttempts = (req.retry ?? true) ? this.opts.maxRetries + 1 : 1;\n let lastError: unknown;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n return await this.attempt<T>(req);\n } catch (err) {\n lastError = err;\n if (!this.isRetryable(err) || attempt === maxAttempts - 1) throw err;\n await sleep(this.retryAfterMs(err) ?? backoffMs(attempt));\n }\n }\n // Unreachable in practice — the loop either returns or throws.\n throw lastError instanceof Error ? lastError : new SimpleQError(String(lastError));\n }\n\n private async attempt<T>(req: RequestOptions): Promise<T> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.opts.timeout);\n let res: Response;\n try {\n res = await this.opts.fetchImpl(this.opts.baseUrl + req.path, {\n method: req.method,\n headers: {\n Authorization: `Bearer ${this.opts.apiKey}`,\n 'Content-Type': 'application/json',\n 'User-Agent': this.opts.userAgent,\n ...req.headers,\n },\n body: req.body !== undefined ? JSON.stringify(req.body) : undefined,\n signal: controller.signal,\n });\n } catch (err) {\n throw new SimpleQConnectionError(\n `Request to ${req.method} ${req.path} failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n } finally {\n clearTimeout(timer);\n }\n\n if (!res.ok) throw mapApiError(res.status, await this.parseBody(res), res.headers);\n if (res.status === 204) return undefined as T;\n return (await this.parseBody(res)) as T;\n }\n\n private async parseBody(res: Response): Promise<unknown> {\n const text = await res.text();\n if (!text) return undefined;\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n }\n\n private isRetryable(err: unknown): boolean {\n if (err instanceof SimpleQConnectionError) return true;\n if (err instanceof ApiError) return RETRYABLE_STATUS.has(err.status);\n return false;\n }\n\n private retryAfterMs(err: unknown): number | undefined {\n return err instanceof RateLimitError && typeof err.retryAfter === 'number'\n ? err.retryAfter * 1000\n : undefined;\n }\n}\n","// Standalone webhook verification — no API key or client required. Importable as\n// `@simpleq/sdk/webhooks` with only `node:crypto` pulled in.\nimport { createHmac, timingSafeEqual } from 'node:crypto';\nimport { SignatureVerificationError } from './errors.js';\nimport type { WebhookPayload } from './types.js';\n\n/** The header SimpleQ sends with every webhook delivery. */\nexport const SIGNATURE_HEADER = 'x-simpleq-signature';\n\nfunction toBuffer(rawBody: string | Buffer | Uint8Array): Buffer {\n if (typeof rawBody === 'string') return Buffer.from(rawBody, 'utf8');\n if (Buffer.isBuffer(rawBody)) return rawBody;\n return Buffer.from(rawBody);\n}\n\nfunction expectedSignature(rawBody: string | Buffer | Uint8Array, signingSecret: string): string {\n return 'sha256=' + createHmac('sha256', signingSecret).update(toBuffer(rawBody)).digest('hex');\n}\n\n/**\n * Verify the `x-simpleq-signature` header against the raw request body, in constant time.\n * Returns a boolean and never throws — a missing or malformed header simply returns `false`.\n *\n * Always pass the *raw* body bytes (a string or Buffer), never a re-serialized parsed object.\n */\nexport function verifyWebhookSignature(\n rawBody: string | Buffer | Uint8Array,\n signatureHeader: string | null | undefined,\n signingSecret: string,\n): boolean {\n if (!signatureHeader) return false;\n const expected = Buffer.from(expectedSignature(rawBody, signingSecret));\n const received = Buffer.from(signatureHeader);\n // timingSafeEqual throws on differing lengths — guard before the constant-time compare.\n if (expected.length !== received.length) return false;\n return timingSafeEqual(expected, received);\n}\n\n/**\n * Verify the signature and return the parsed, typed webhook envelope (the equivalent of\n * Stripe's `constructEvent`). Throws `SignatureVerificationError` if the signature does\n * not match — the body is only parsed after verification passes, so a tampered payload\n * never reaches `JSON.parse`.\n */\nexport function verifyWebhook(\n rawBody: string | Buffer | Uint8Array,\n signatureHeader: string | null | undefined,\n signingSecret: string,\n): WebhookPayload {\n if (!verifyWebhookSignature(rawBody, signatureHeader, signingSecret)) {\n throw new SignatureVerificationError('SimpleQ webhook signature verification failed');\n }\n const text = typeof rawBody === 'string' ? rawBody : toBuffer(rawBody).toString('utf8');\n return JSON.parse(text) as WebhookPayload;\n}\n","import { randomUUID } from 'node:crypto';\nimport { HttpClient } from './http.js';\nimport { SimpleQError, ValidationError } from './errors.js';\nimport { verifyWebhook, verifyWebhookSignature } from './webhooks.js';\nimport type {\n AckResponse,\n DeferOptions,\n Job,\n NackOptions,\n PublishJobResponse,\n PublishParams,\n SimpleQOptions,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://api.simpleq.io';\n// Customer-facing durations are seconds throughout SimpleQ; convert to ms at the fetch boundary.\nconst DEFAULT_TIMEOUT_SECONDS = 30;\nconst DEFAULT_MAX_RETRIES = 2;\n// Mirrors package.json; surfaced in the User-Agent header.\nconst VERSION = '0.1.0';\n\n/** The SimpleQ client: publish jobs, read job status, and run the ack-mode callbacks. */\nexport class SimpleQ {\n private readonly http: HttpClient;\n\n /** Webhook signature helpers. Usable without an API key (only a `signingSecret` is needed). */\n readonly webhooks = {\n verifyWebhookSignature,\n verifyWebhook,\n };\n\n constructor(options: SimpleQOptions = {}) {\n const apiKey = options.apiKey ?? process.env.SIMPLEQ_API_KEY;\n if (!apiKey) {\n throw new SimpleQError('A SimpleQ API key is required. Pass { apiKey } or set SIMPLEQ_API_KEY.');\n }\n\n const fetchImpl = options.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== 'function') {\n throw new SimpleQError('No fetch implementation found. Use Node 18+ or pass { fetch }.');\n }\n\n this.http = new HttpClient({\n apiKey,\n baseUrl: (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, ''),\n timeout: (options.timeout ?? DEFAULT_TIMEOUT_SECONDS) * 1000,\n maxRetries: options.maxRetries ?? DEFAULT_MAX_RETRIES,\n fetchImpl,\n userAgent: `simpleq-node/${VERSION}`,\n });\n }\n\n /**\n * Publish a job to a queue. Retries transient failures automatically; the idempotency key\n * (yours, or one generated per call when you omit it) is reused across those retries, so a\n * retry can never create a duplicate job. A 200 (idempotent hit) and a 201 (created) are both\n * returned as success.\n */\n async publish(queueName: string, params: PublishParams): Promise<PublishJobResponse> {\n const idempotencyKey = params.idempotencyKey ?? randomUUID();\n\n const body: Record<string, unknown> = { payload: params.payload };\n if (idempotencyKey !== undefined) body.idempotencyKey = idempotencyKey;\n if (params.delay !== undefined) body.delay = params.delay;\n\n return this.http.request<PublishJobResponse>({\n method: 'POST',\n path: `/v1/queues/${encodeURIComponent(queueName)}/jobs`,\n body,\n });\n }\n\n /** Fetch a job's current status and attempt history. */\n async getJob(jobId: string): Promise<Job> {\n return this.http.request<Job>({\n method: 'GET',\n path: `/v1/jobs/${encodeURIComponent(jobId)}`,\n });\n }\n\n /** Ack a job (ack-mode queues): report successful completion. */\n async ack(jobId: string): Promise<AckResponse> {\n return this.http.request<AckResponse>({\n method: 'POST',\n path: `/v1/jobs/${encodeURIComponent(jobId)}/ack`,\n body: {},\n });\n }\n\n /** Nack a job (ack-mode queues): report failure. `retryable: false` dead-letters immediately. */\n async nack(jobId: string, options: NackOptions = {}): Promise<AckResponse> {\n return this.http.request<AckResponse>({\n method: 'POST',\n path: `/v1/jobs/${encodeURIComponent(jobId)}/nack`,\n body: options,\n });\n }\n\n /** Defer a job (ack-mode queues): apply backpressure — held and redelivered, no attempt burned. */\n async defer(jobId: string, options: DeferOptions): Promise<AckResponse> {\n const { retryAfter } = options ?? {};\n if (typeof retryAfter !== 'number' || !Number.isFinite(retryAfter) || retryAfter < 0 || retryAfter > 3600) {\n throw new ValidationError('defer requires retryAfter to be a number of seconds between 0 and 3600.', 400, undefined);\n }\n return this.http.request<AckResponse>({\n method: 'POST',\n path: `/v1/jobs/${encodeURIComponent(jobId)}/defer`,\n body: options,\n });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/http.ts","../src/webhooks.ts","../src/client.ts"],"names":["createHmac","timingSafeEqual","randomUUID"],"mappings":"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","file":"index.cjs","sourcesContent":["// Error and signal types for @simpleq/sdk.\n\n/** Base class for everything thrown by the SDK. Catch this to handle any SimpleQ error. */\nexport class SimpleQError extends Error {\n constructor(message: string) {\n super(message);\n this.name = this.constructor.name;\n }\n}\n\n/** A network failure, timeout, or aborted request — retryable. */\nexport class SimpleQConnectionError extends SimpleQError {}\n\n/** Thrown by `verifyWebhook` when a webhook signature does not verify. */\nexport class SignatureVerificationError extends SimpleQError {}\n\nexport type BackpressureStatus = 429 | 503 | 529;\n\n/**\n * A backpressure signal — not a failure. Throw this from a standard-mode webhook handler to\n * tell the adapter to respond with `429`/`503`/`529` and a `Retry-After`. SimpleQ then holds\n * the job and redelivers it without burning a delivery attempt.\n */\nexport class SimpleQBackpressure extends SimpleQError {\n /** Seconds to hold the job before redelivery. Omit to let SimpleQ pick its fallback. */\n readonly retryAfter?: number;\n /** HTTP status the adapter responds with. Defaults to `503`. */\n readonly status: BackpressureStatus;\n\n constructor(retryAfter?: number, options?: { status?: BackpressureStatus; reason?: string }) {\n const detail = retryAfter != null ? ` (retry after ${retryAfter}s)` : '';\n super(options?.reason ?? `SimpleQ backpressure${detail}`);\n this.retryAfter = retryAfter;\n this.status = options?.status ?? 503;\n }\n\n /**\n * Build a backpressure signal directly from a provider error (Anthropic, OpenAI, any\n * HTTP-shaped error). Reads `err.status` (429/503/529 pass through; anything else maps\n * to 503) and the `Retry-After` header in seconds from `err.headers` or\n * `err.response.headers` (plain object or Headers). When no header is present,\n * `options.fallback` seconds is used; with neither, SimpleQ applies its own 60s hold.\n */\n static from(err: unknown, options?: { fallback?: number; reason?: string }): SimpleQBackpressure {\n const e = err as { status?: unknown; message?: unknown } | null | undefined;\n const status: BackpressureStatus =\n e?.status === 429 || e?.status === 503 || e?.status === 529 ? e.status : 503;\n const retryAfter = retryAfterSeconds(err) ?? options?.fallback;\n const reason =\n options?.reason ?? (typeof e?.message === 'string' && e.message ? e.message : undefined);\n return new SimpleQBackpressure(retryAfter, { status, reason });\n }\n}\n\nfunction readHeader(headers: unknown, name: string): string | undefined {\n if (!headers || typeof headers !== 'object') return undefined;\n if (typeof (headers as Headers).get === 'function') {\n return (headers as Headers).get(name) ?? undefined;\n }\n const record = headers as Record<string, unknown>;\n const value = record[name.toLowerCase()] ?? record['Retry-After'];\n return typeof value === 'string' ? value : undefined;\n}\n\n/**\n * Read the `Retry-After` value, in **seconds**, from a provider error (Anthropic, OpenAI, any\n * HTTP-shaped error). Looks at `err.headers` and `err.response.headers` (plain object or a\n * `Headers` instance). Returns `undefined` when the header is absent or non-numeric (e.g. an\n * HTTP-date). Pair with `simpleq.defer` in ack mode: `defer(id, { retryAfter: retryAfterSeconds(err) ?? 10 })`.\n */\nexport function retryAfterSeconds(err: unknown): number | undefined {\n const e = err as { headers?: unknown; response?: { headers?: unknown } } | null | undefined;\n const raw =\n readHeader(e?.headers, 'retry-after') ?? readHeader(e?.response?.headers, 'retry-after');\n if (raw === undefined) return undefined;\n const seconds = Number(raw);\n return Number.isFinite(seconds) && seconds >= 0 ? seconds : undefined;\n}\n\n/** Any non-2xx response from the SimpleQ API. */\nexport class ApiError extends SimpleQError {\n readonly status: number;\n readonly body: unknown;\n\n constructor(message: string, status: number, body: unknown) {\n super(message);\n this.status = status;\n this.body = body;\n }\n}\n\n/** `401`/`403` — the API key is missing, invalid, or revoked. */\nexport class AuthenticationError extends ApiError {}\n\n/** `400` — request validation failed. `body.error` carries the field-level details. */\nexport class ValidationError extends ApiError {}\n\n/** `404` — the queue or job was not found. */\nexport class NotFoundError extends ApiError {}\n\n/** `429` — rate limited. `retryAfter` is the `Retry-After` header in seconds, if present. */\nexport class RateLimitError extends ApiError {\n readonly retryAfter?: number;\n\n constructor(message: string, status: number, body: unknown, retryAfter?: number) {\n super(message, status, body);\n this.retryAfter = retryAfter;\n }\n}\n\nfunction extractMessage(status: number, body: unknown): string {\n if (body && typeof body === 'object' && 'error' in body) {\n const err = (body as { error: unknown }).error;\n if (typeof err === 'string') return err;\n if (err && typeof err === 'object') return `Validation failed: ${JSON.stringify(err)}`;\n }\n return `SimpleQ API error (HTTP ${status})`;\n}\n\n/** Map an HTTP status + parsed body to the right ApiError subclass. */\nexport function mapApiError(status: number, body: unknown, headers?: Headers): ApiError {\n const message = extractMessage(status, body);\n switch (status) {\n case 400:\n return new ValidationError(message, status, body);\n case 401:\n case 403:\n return new AuthenticationError(message, status, body);\n case 404:\n return new NotFoundError(message, status, body);\n case 429: {\n const raw = headers?.get('retry-after');\n const retryAfter = raw != null ? Number(raw) : NaN;\n return new RateLimitError(message, status, body, Number.isFinite(retryAfter) ? retryAfter : undefined);\n }\n default:\n return new ApiError(message, status, body);\n }\n}\n","// Internal fetch wrapper + retry engine. Not part of the public API.\nimport { ApiError, RateLimitError, SimpleQConnectionError, SimpleQError, mapApiError } from './errors.js';\n\nexport interface HttpClientOptions {\n apiKey: string;\n baseUrl: string;\n timeout: number;\n maxRetries: number;\n fetchImpl: typeof fetch;\n userAgent: string;\n}\n\nexport interface RequestOptions {\n method: string;\n path: string;\n body?: unknown;\n headers?: Record<string, string>;\n /** Retry transient failures (network / 5xx / 429). Default true. */\n retry?: boolean;\n}\n\nconst RETRYABLE_STATUS = new Set([429, 500, 502, 503, 504]);\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n// Exponential backoff (base 250ms, cap 8s) with full jitter.\nfunction backoffMs(attempt: number): number {\n const ceiling = Math.min(250 * 2 ** attempt, 8000);\n return Math.round(ceiling * (0.5 + Math.random() * 0.5));\n}\n\nexport class HttpClient {\n constructor(private readonly opts: HttpClientOptions) {}\n\n async request<T>(req: RequestOptions): Promise<T> {\n const maxAttempts = (req.retry ?? true) ? this.opts.maxRetries + 1 : 1;\n let lastError: unknown;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n return await this.attempt<T>(req);\n } catch (err) {\n lastError = err;\n if (!this.isRetryable(err) || attempt === maxAttempts - 1) throw err;\n await sleep(this.retryAfterMs(err) ?? backoffMs(attempt));\n }\n }\n // Unreachable in practice — the loop either returns or throws.\n throw lastError instanceof Error ? lastError : new SimpleQError(String(lastError));\n }\n\n private async attempt<T>(req: RequestOptions): Promise<T> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.opts.timeout);\n let res: Response;\n try {\n res = await this.opts.fetchImpl(this.opts.baseUrl + req.path, {\n method: req.method,\n headers: {\n Authorization: `Bearer ${this.opts.apiKey}`,\n 'Content-Type': 'application/json',\n 'User-Agent': this.opts.userAgent,\n ...req.headers,\n },\n body: req.body !== undefined ? JSON.stringify(req.body) : undefined,\n signal: controller.signal,\n });\n } catch (err) {\n throw new SimpleQConnectionError(\n `Request to ${req.method} ${req.path} failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n } finally {\n clearTimeout(timer);\n }\n\n if (!res.ok) throw mapApiError(res.status, await this.parseBody(res), res.headers);\n if (res.status === 204) return undefined as T;\n return (await this.parseBody(res)) as T;\n }\n\n private async parseBody(res: Response): Promise<unknown> {\n const text = await res.text();\n if (!text) return undefined;\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n }\n\n private isRetryable(err: unknown): boolean {\n if (err instanceof SimpleQConnectionError) return true;\n if (err instanceof ApiError) return RETRYABLE_STATUS.has(err.status);\n return false;\n }\n\n private retryAfterMs(err: unknown): number | undefined {\n return err instanceof RateLimitError && typeof err.retryAfter === 'number'\n ? err.retryAfter * 1000\n : undefined;\n }\n}\n","// Standalone webhook verification — no API key or client required. Importable as\n// `@simpleq/sdk/webhooks` with only `node:crypto` pulled in.\nimport { createHmac, timingSafeEqual } from 'node:crypto';\nimport { SignatureVerificationError } from './errors.js';\nimport type { WebhookPayload } from './types.js';\n\n/** The header SimpleQ sends with every webhook delivery. */\nexport const SIGNATURE_HEADER = 'x-simpleq-signature';\n\nfunction toBuffer(rawBody: string | Buffer | Uint8Array): Buffer {\n if (typeof rawBody === 'string') return Buffer.from(rawBody, 'utf8');\n if (Buffer.isBuffer(rawBody)) return rawBody;\n return Buffer.from(rawBody);\n}\n\nfunction expectedSignature(rawBody: string | Buffer | Uint8Array, signingSecret: string): string {\n return 'sha256=' + createHmac('sha256', signingSecret).update(toBuffer(rawBody)).digest('hex');\n}\n\n/**\n * Verify the `x-simpleq-signature` header against the raw request body, in constant time.\n * Returns a boolean and never throws — a missing or malformed header simply returns `false`.\n *\n * Always pass the *raw* body bytes (a string or Buffer), never a re-serialized parsed object.\n */\nexport function verifyWebhookSignature(\n rawBody: string | Buffer | Uint8Array,\n signatureHeader: string | null | undefined,\n signingSecret: string,\n): boolean {\n if (!signatureHeader) return false;\n const expected = Buffer.from(expectedSignature(rawBody, signingSecret));\n const received = Buffer.from(signatureHeader);\n // timingSafeEqual throws on differing lengths — guard before the constant-time compare.\n if (expected.length !== received.length) return false;\n return timingSafeEqual(expected, received);\n}\n\n/**\n * Verify the signature and return the parsed, typed webhook envelope (the equivalent of\n * Stripe's `constructEvent`). Throws `SignatureVerificationError` if the signature does\n * not match — the body is only parsed after verification passes, so a tampered payload\n * never reaches `JSON.parse`.\n */\nexport function verifyWebhook(\n rawBody: string | Buffer | Uint8Array,\n signatureHeader: string | null | undefined,\n signingSecret: string,\n): WebhookPayload {\n if (!verifyWebhookSignature(rawBody, signatureHeader, signingSecret)) {\n throw new SignatureVerificationError('SimpleQ webhook signature verification failed');\n }\n const text = typeof rawBody === 'string' ? rawBody : toBuffer(rawBody).toString('utf8');\n return JSON.parse(text) as WebhookPayload;\n}\n","import { randomUUID } from 'node:crypto';\nimport { HttpClient } from './http.js';\nimport { SimpleQError, ValidationError } from './errors.js';\nimport { verifyWebhook, verifyWebhookSignature } from './webhooks.js';\nimport type {\n AckResponse,\n DeferOptions,\n Job,\n NackOptions,\n PublishJobResponse,\n PublishParams,\n SimpleQOptions,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://api.simpleq.io';\n// Customer-facing durations are seconds throughout SimpleQ; convert to ms at the fetch boundary.\nconst DEFAULT_TIMEOUT_SECONDS = 30;\nconst DEFAULT_MAX_RETRIES = 2;\n// Injected from package.json at build time (tsup) and test time (vitest) via `define`, so\n// `npm version` is the single source of truth and the User-Agent header can never drift.\ndeclare const __SDK_VERSION__: string;\nconst VERSION = __SDK_VERSION__;\n\n/** The SimpleQ client: publish jobs, read job status, and run the ack-mode callbacks. */\nexport class SimpleQ {\n private readonly http: HttpClient;\n\n /** Webhook signature helpers. Usable without an API key (only a `signingSecret` is needed). */\n readonly webhooks = {\n verifyWebhookSignature,\n verifyWebhook,\n };\n\n constructor(options: SimpleQOptions = {}) {\n const apiKey = options.apiKey ?? process.env.SIMPLEQ_API_KEY;\n if (!apiKey) {\n throw new SimpleQError('A SimpleQ API key is required. Pass { apiKey } or set SIMPLEQ_API_KEY.');\n }\n\n const fetchImpl = options.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== 'function') {\n throw new SimpleQError('No fetch implementation found. Use Node 18+ or pass { fetch }.');\n }\n\n this.http = new HttpClient({\n apiKey,\n baseUrl: (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, ''),\n timeout: (options.timeout ?? DEFAULT_TIMEOUT_SECONDS) * 1000,\n maxRetries: options.maxRetries ?? DEFAULT_MAX_RETRIES,\n fetchImpl,\n userAgent: `simpleq-node/${VERSION}`,\n });\n }\n\n /**\n * Publish a job to a queue. Retries transient failures automatically; the idempotency key\n * (yours, or one generated per call when you omit it) is reused across those retries, so a\n * retry can never create a duplicate job. A 200 (idempotent hit) and a 201 (created) are both\n * returned as success.\n */\n async publish(queueName: string, params: PublishParams): Promise<PublishJobResponse> {\n const idempotencyKey = params.idempotencyKey ?? randomUUID();\n\n const body: Record<string, unknown> = { payload: params.payload };\n if (idempotencyKey !== undefined) body.idempotencyKey = idempotencyKey;\n if (params.delay !== undefined) body.delay = params.delay;\n\n return this.http.request<PublishJobResponse>({\n method: 'POST',\n path: `/v1/queues/${encodeURIComponent(queueName)}/jobs`,\n body,\n });\n }\n\n /** Fetch a job's current status and attempt history. */\n async getJob(jobId: string): Promise<Job> {\n return this.http.request<Job>({\n method: 'GET',\n path: `/v1/jobs/${encodeURIComponent(jobId)}`,\n });\n }\n\n /** Ack a job (ack-mode queues): report successful completion. */\n async ack(jobId: string): Promise<AckResponse> {\n return this.http.request<AckResponse>({\n method: 'POST',\n path: `/v1/jobs/${encodeURIComponent(jobId)}/ack`,\n body: {},\n });\n }\n\n /** Nack a job (ack-mode queues): report failure. `retryable: false` dead-letters immediately. */\n async nack(jobId: string, options: NackOptions = {}): Promise<AckResponse> {\n return this.http.request<AckResponse>({\n method: 'POST',\n path: `/v1/jobs/${encodeURIComponent(jobId)}/nack`,\n body: options,\n });\n }\n\n /** Defer a job (ack-mode queues): apply backpressure — held and redelivered, no attempt burned. */\n async defer(jobId: string, options: DeferOptions): Promise<AckResponse> {\n const { retryAfter } = options ?? {};\n if (typeof retryAfter !== 'number' || !Number.isFinite(retryAfter) || retryAfter < 0 || retryAfter > 3600) {\n throw new ValidationError('defer requires retryAfter to be a number of seconds between 0 and 3600.', 400, undefined);\n }\n return this.http.request<AckResponse>({\n method: 'POST',\n path: `/v1/jobs/${encodeURIComponent(jobId)}/defer`,\n body: options,\n });\n }\n}\n"]}
|
package/dist/index.js
CHANGED
|
@@ -77,7 +77,7 @@ var HttpClient = class {
|
|
|
77
77
|
var DEFAULT_BASE_URL = "https://api.simpleq.io";
|
|
78
78
|
var DEFAULT_TIMEOUT_SECONDS = 30;
|
|
79
79
|
var DEFAULT_MAX_RETRIES = 2;
|
|
80
|
-
var VERSION = "0.1.
|
|
80
|
+
var VERSION = "0.1.1";
|
|
81
81
|
var SimpleQ = class {
|
|
82
82
|
constructor(options = {}) {
|
|
83
83
|
/** Webhook signature helpers. Usable without an API key (only a `signingSecret` is needed). */
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/http.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// Internal fetch wrapper + retry engine. Not part of the public API.\nimport { ApiError, RateLimitError, SimpleQConnectionError, SimpleQError, mapApiError } from './errors.js';\n\nexport interface HttpClientOptions {\n apiKey: string;\n baseUrl: string;\n timeout: number;\n maxRetries: number;\n fetchImpl: typeof fetch;\n userAgent: string;\n}\n\nexport interface RequestOptions {\n method: string;\n path: string;\n body?: unknown;\n headers?: Record<string, string>;\n /** Retry transient failures (network / 5xx / 429). Default true. */\n retry?: boolean;\n}\n\nconst RETRYABLE_STATUS = new Set([429, 500, 502, 503, 504]);\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n// Exponential backoff (base 250ms, cap 8s) with full jitter.\nfunction backoffMs(attempt: number): number {\n const ceiling = Math.min(250 * 2 ** attempt, 8000);\n return Math.round(ceiling * (0.5 + Math.random() * 0.5));\n}\n\nexport class HttpClient {\n constructor(private readonly opts: HttpClientOptions) {}\n\n async request<T>(req: RequestOptions): Promise<T> {\n const maxAttempts = (req.retry ?? true) ? this.opts.maxRetries + 1 : 1;\n let lastError: unknown;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n return await this.attempt<T>(req);\n } catch (err) {\n lastError = err;\n if (!this.isRetryable(err) || attempt === maxAttempts - 1) throw err;\n await sleep(this.retryAfterMs(err) ?? backoffMs(attempt));\n }\n }\n // Unreachable in practice — the loop either returns or throws.\n throw lastError instanceof Error ? lastError : new SimpleQError(String(lastError));\n }\n\n private async attempt<T>(req: RequestOptions): Promise<T> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.opts.timeout);\n let res: Response;\n try {\n res = await this.opts.fetchImpl(this.opts.baseUrl + req.path, {\n method: req.method,\n headers: {\n Authorization: `Bearer ${this.opts.apiKey}`,\n 'Content-Type': 'application/json',\n 'User-Agent': this.opts.userAgent,\n ...req.headers,\n },\n body: req.body !== undefined ? JSON.stringify(req.body) : undefined,\n signal: controller.signal,\n });\n } catch (err) {\n throw new SimpleQConnectionError(\n `Request to ${req.method} ${req.path} failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n } finally {\n clearTimeout(timer);\n }\n\n if (!res.ok) throw mapApiError(res.status, await this.parseBody(res), res.headers);\n if (res.status === 204) return undefined as T;\n return (await this.parseBody(res)) as T;\n }\n\n private async parseBody(res: Response): Promise<unknown> {\n const text = await res.text();\n if (!text) return undefined;\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n }\n\n private isRetryable(err: unknown): boolean {\n if (err instanceof SimpleQConnectionError) return true;\n if (err instanceof ApiError) return RETRYABLE_STATUS.has(err.status);\n return false;\n }\n\n private retryAfterMs(err: unknown): number | undefined {\n return err instanceof RateLimitError && typeof err.retryAfter === 'number'\n ? err.retryAfter * 1000\n : undefined;\n }\n}\n","import { randomUUID } from 'node:crypto';\nimport { HttpClient } from './http.js';\nimport { SimpleQError, ValidationError } from './errors.js';\nimport { verifyWebhook, verifyWebhookSignature } from './webhooks.js';\nimport type {\n AckResponse,\n DeferOptions,\n Job,\n NackOptions,\n PublishJobResponse,\n PublishParams,\n SimpleQOptions,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://api.simpleq.io';\n// Customer-facing durations are seconds throughout SimpleQ; convert to ms at the fetch boundary.\nconst DEFAULT_TIMEOUT_SECONDS = 30;\nconst DEFAULT_MAX_RETRIES = 2;\n// Mirrors package.json; surfaced in the User-Agent header.\nconst VERSION = '0.1.0';\n\n/** The SimpleQ client: publish jobs, read job status, and run the ack-mode callbacks. */\nexport class SimpleQ {\n private readonly http: HttpClient;\n\n /** Webhook signature helpers. Usable without an API key (only a `signingSecret` is needed). */\n readonly webhooks = {\n verifyWebhookSignature,\n verifyWebhook,\n };\n\n constructor(options: SimpleQOptions = {}) {\n const apiKey = options.apiKey ?? process.env.SIMPLEQ_API_KEY;\n if (!apiKey) {\n throw new SimpleQError('A SimpleQ API key is required. Pass { apiKey } or set SIMPLEQ_API_KEY.');\n }\n\n const fetchImpl = options.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== 'function') {\n throw new SimpleQError('No fetch implementation found. Use Node 18+ or pass { fetch }.');\n }\n\n this.http = new HttpClient({\n apiKey,\n baseUrl: (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, ''),\n timeout: (options.timeout ?? DEFAULT_TIMEOUT_SECONDS) * 1000,\n maxRetries: options.maxRetries ?? DEFAULT_MAX_RETRIES,\n fetchImpl,\n userAgent: `simpleq-node/${VERSION}`,\n });\n }\n\n /**\n * Publish a job to a queue. Retries transient failures automatically; the idempotency key\n * (yours, or one generated per call when you omit it) is reused across those retries, so a\n * retry can never create a duplicate job. A 200 (idempotent hit) and a 201 (created) are both\n * returned as success.\n */\n async publish(queueName: string, params: PublishParams): Promise<PublishJobResponse> {\n const idempotencyKey = params.idempotencyKey ?? randomUUID();\n\n const body: Record<string, unknown> = { payload: params.payload };\n if (idempotencyKey !== undefined) body.idempotencyKey = idempotencyKey;\n if (params.delay !== undefined) body.delay = params.delay;\n\n return this.http.request<PublishJobResponse>({\n method: 'POST',\n path: `/v1/queues/${encodeURIComponent(queueName)}/jobs`,\n body,\n });\n }\n\n /** Fetch a job's current status and attempt history. */\n async getJob(jobId: string): Promise<Job> {\n return this.http.request<Job>({\n method: 'GET',\n path: `/v1/jobs/${encodeURIComponent(jobId)}`,\n });\n }\n\n /** Ack a job (ack-mode queues): report successful completion. */\n async ack(jobId: string): Promise<AckResponse> {\n return this.http.request<AckResponse>({\n method: 'POST',\n path: `/v1/jobs/${encodeURIComponent(jobId)}/ack`,\n body: {},\n });\n }\n\n /** Nack a job (ack-mode queues): report failure. `retryable: false` dead-letters immediately. */\n async nack(jobId: string, options: NackOptions = {}): Promise<AckResponse> {\n return this.http.request<AckResponse>({\n method: 'POST',\n path: `/v1/jobs/${encodeURIComponent(jobId)}/nack`,\n body: options,\n });\n }\n\n /** Defer a job (ack-mode queues): apply backpressure — held and redelivered, no attempt burned. */\n async defer(jobId: string, options: DeferOptions): Promise<AckResponse> {\n const { retryAfter } = options ?? {};\n if (typeof retryAfter !== 'number' || !Number.isFinite(retryAfter) || retryAfter < 0 || retryAfter > 3600) {\n throw new ValidationError('defer requires retryAfter to be a number of seconds between 0 and 3600.', 400, undefined);\n }\n return this.http.request<AckResponse>({\n method: 'POST',\n path: `/v1/jobs/${encodeURIComponent(jobId)}/defer`,\n body: options,\n });\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/http.ts","../src/client.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["// Internal fetch wrapper + retry engine. Not part of the public API.\nimport { ApiError, RateLimitError, SimpleQConnectionError, SimpleQError, mapApiError } from './errors.js';\n\nexport interface HttpClientOptions {\n apiKey: string;\n baseUrl: string;\n timeout: number;\n maxRetries: number;\n fetchImpl: typeof fetch;\n userAgent: string;\n}\n\nexport interface RequestOptions {\n method: string;\n path: string;\n body?: unknown;\n headers?: Record<string, string>;\n /** Retry transient failures (network / 5xx / 429). Default true. */\n retry?: boolean;\n}\n\nconst RETRYABLE_STATUS = new Set([429, 500, 502, 503, 504]);\n\nconst sleep = (ms: number): Promise<void> => new Promise((resolve) => setTimeout(resolve, ms));\n\n// Exponential backoff (base 250ms, cap 8s) with full jitter.\nfunction backoffMs(attempt: number): number {\n const ceiling = Math.min(250 * 2 ** attempt, 8000);\n return Math.round(ceiling * (0.5 + Math.random() * 0.5));\n}\n\nexport class HttpClient {\n constructor(private readonly opts: HttpClientOptions) {}\n\n async request<T>(req: RequestOptions): Promise<T> {\n const maxAttempts = (req.retry ?? true) ? this.opts.maxRetries + 1 : 1;\n let lastError: unknown;\n\n for (let attempt = 0; attempt < maxAttempts; attempt++) {\n try {\n return await this.attempt<T>(req);\n } catch (err) {\n lastError = err;\n if (!this.isRetryable(err) || attempt === maxAttempts - 1) throw err;\n await sleep(this.retryAfterMs(err) ?? backoffMs(attempt));\n }\n }\n // Unreachable in practice — the loop either returns or throws.\n throw lastError instanceof Error ? lastError : new SimpleQError(String(lastError));\n }\n\n private async attempt<T>(req: RequestOptions): Promise<T> {\n const controller = new AbortController();\n const timer = setTimeout(() => controller.abort(), this.opts.timeout);\n let res: Response;\n try {\n res = await this.opts.fetchImpl(this.opts.baseUrl + req.path, {\n method: req.method,\n headers: {\n Authorization: `Bearer ${this.opts.apiKey}`,\n 'Content-Type': 'application/json',\n 'User-Agent': this.opts.userAgent,\n ...req.headers,\n },\n body: req.body !== undefined ? JSON.stringify(req.body) : undefined,\n signal: controller.signal,\n });\n } catch (err) {\n throw new SimpleQConnectionError(\n `Request to ${req.method} ${req.path} failed: ${err instanceof Error ? err.message : String(err)}`,\n );\n } finally {\n clearTimeout(timer);\n }\n\n if (!res.ok) throw mapApiError(res.status, await this.parseBody(res), res.headers);\n if (res.status === 204) return undefined as T;\n return (await this.parseBody(res)) as T;\n }\n\n private async parseBody(res: Response): Promise<unknown> {\n const text = await res.text();\n if (!text) return undefined;\n try {\n return JSON.parse(text);\n } catch {\n return text;\n }\n }\n\n private isRetryable(err: unknown): boolean {\n if (err instanceof SimpleQConnectionError) return true;\n if (err instanceof ApiError) return RETRYABLE_STATUS.has(err.status);\n return false;\n }\n\n private retryAfterMs(err: unknown): number | undefined {\n return err instanceof RateLimitError && typeof err.retryAfter === 'number'\n ? err.retryAfter * 1000\n : undefined;\n }\n}\n","import { randomUUID } from 'node:crypto';\nimport { HttpClient } from './http.js';\nimport { SimpleQError, ValidationError } from './errors.js';\nimport { verifyWebhook, verifyWebhookSignature } from './webhooks.js';\nimport type {\n AckResponse,\n DeferOptions,\n Job,\n NackOptions,\n PublishJobResponse,\n PublishParams,\n SimpleQOptions,\n} from './types.js';\n\nconst DEFAULT_BASE_URL = 'https://api.simpleq.io';\n// Customer-facing durations are seconds throughout SimpleQ; convert to ms at the fetch boundary.\nconst DEFAULT_TIMEOUT_SECONDS = 30;\nconst DEFAULT_MAX_RETRIES = 2;\n// Injected from package.json at build time (tsup) and test time (vitest) via `define`, so\n// `npm version` is the single source of truth and the User-Agent header can never drift.\ndeclare const __SDK_VERSION__: string;\nconst VERSION = __SDK_VERSION__;\n\n/** The SimpleQ client: publish jobs, read job status, and run the ack-mode callbacks. */\nexport class SimpleQ {\n private readonly http: HttpClient;\n\n /** Webhook signature helpers. Usable without an API key (only a `signingSecret` is needed). */\n readonly webhooks = {\n verifyWebhookSignature,\n verifyWebhook,\n };\n\n constructor(options: SimpleQOptions = {}) {\n const apiKey = options.apiKey ?? process.env.SIMPLEQ_API_KEY;\n if (!apiKey) {\n throw new SimpleQError('A SimpleQ API key is required. Pass { apiKey } or set SIMPLEQ_API_KEY.');\n }\n\n const fetchImpl = options.fetch ?? globalThis.fetch;\n if (typeof fetchImpl !== 'function') {\n throw new SimpleQError('No fetch implementation found. Use Node 18+ or pass { fetch }.');\n }\n\n this.http = new HttpClient({\n apiKey,\n baseUrl: (options.baseUrl ?? DEFAULT_BASE_URL).replace(/\\/+$/, ''),\n timeout: (options.timeout ?? DEFAULT_TIMEOUT_SECONDS) * 1000,\n maxRetries: options.maxRetries ?? DEFAULT_MAX_RETRIES,\n fetchImpl,\n userAgent: `simpleq-node/${VERSION}`,\n });\n }\n\n /**\n * Publish a job to a queue. Retries transient failures automatically; the idempotency key\n * (yours, or one generated per call when you omit it) is reused across those retries, so a\n * retry can never create a duplicate job. A 200 (idempotent hit) and a 201 (created) are both\n * returned as success.\n */\n async publish(queueName: string, params: PublishParams): Promise<PublishJobResponse> {\n const idempotencyKey = params.idempotencyKey ?? randomUUID();\n\n const body: Record<string, unknown> = { payload: params.payload };\n if (idempotencyKey !== undefined) body.idempotencyKey = idempotencyKey;\n if (params.delay !== undefined) body.delay = params.delay;\n\n return this.http.request<PublishJobResponse>({\n method: 'POST',\n path: `/v1/queues/${encodeURIComponent(queueName)}/jobs`,\n body,\n });\n }\n\n /** Fetch a job's current status and attempt history. */\n async getJob(jobId: string): Promise<Job> {\n return this.http.request<Job>({\n method: 'GET',\n path: `/v1/jobs/${encodeURIComponent(jobId)}`,\n });\n }\n\n /** Ack a job (ack-mode queues): report successful completion. */\n async ack(jobId: string): Promise<AckResponse> {\n return this.http.request<AckResponse>({\n method: 'POST',\n path: `/v1/jobs/${encodeURIComponent(jobId)}/ack`,\n body: {},\n });\n }\n\n /** Nack a job (ack-mode queues): report failure. `retryable: false` dead-letters immediately. */\n async nack(jobId: string, options: NackOptions = {}): Promise<AckResponse> {\n return this.http.request<AckResponse>({\n method: 'POST',\n path: `/v1/jobs/${encodeURIComponent(jobId)}/nack`,\n body: options,\n });\n }\n\n /** Defer a job (ack-mode queues): apply backpressure — held and redelivered, no attempt burned. */\n async defer(jobId: string, options: DeferOptions): Promise<AckResponse> {\n const { retryAfter } = options ?? {};\n if (typeof retryAfter !== 'number' || !Number.isFinite(retryAfter) || retryAfter < 0 || retryAfter > 3600) {\n throw new ValidationError('defer requires retryAfter to be a number of seconds between 0 and 3600.', 400, undefined);\n }\n return this.http.request<AckResponse>({\n method: 'POST',\n path: `/v1/jobs/${encodeURIComponent(jobId)}/defer`,\n body: options,\n });\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@simpleq/sdk",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.1",
|
|
4
4
|
"description": "Official Node/TypeScript SDK for SimpleQ — publish jobs, verify webhook signatures, and ack/nack/defer deliveries.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "module",
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
"url": "git+https://github.com/simpleqio/simpleq-sdk-typescript.git"
|
|
15
15
|
},
|
|
16
16
|
"bugs": "https://github.com/simpleqio/simpleq-sdk-typescript/issues",
|
|
17
|
+
"packageManager": "pnpm@11.1.2",
|
|
17
18
|
"keywords": [
|
|
18
19
|
"simpleq",
|
|
19
20
|
"queue",
|
|
@@ -75,6 +76,17 @@
|
|
|
75
76
|
},
|
|
76
77
|
"./package.json": "./package.json"
|
|
77
78
|
},
|
|
79
|
+
"scripts": {
|
|
80
|
+
"prepublishOnly": "pnpm run type-check && pnpm run build && pnpm test",
|
|
81
|
+
"build": "tsup && node scripts/audit-dts.mjs",
|
|
82
|
+
"dev": "tsup --watch",
|
|
83
|
+
"type-check": "tsc --noEmit",
|
|
84
|
+
"audit:dts": "node scripts/audit-dts.mjs",
|
|
85
|
+
"test": "vitest run",
|
|
86
|
+
"test:watch": "vitest",
|
|
87
|
+
"clean": "rm -rf dist",
|
|
88
|
+
"check:contract": "node scripts/check-contract.mjs"
|
|
89
|
+
},
|
|
78
90
|
"peerDependencies": {
|
|
79
91
|
"@nestjs/common": "^10.0.0 || ^11.0.0",
|
|
80
92
|
"express": "^4.17.0 || ^5.0.0"
|
|
@@ -98,15 +110,5 @@
|
|
|
98
110
|
"tsup": "^8.3.5",
|
|
99
111
|
"typescript": "^5.7.3",
|
|
100
112
|
"vitest": "^3.0.5"
|
|
101
|
-
},
|
|
102
|
-
"scripts": {
|
|
103
|
-
"build": "tsup && node scripts/audit-dts.mjs",
|
|
104
|
-
"dev": "tsup --watch",
|
|
105
|
-
"type-check": "tsc --noEmit",
|
|
106
|
-
"audit:dts": "node scripts/audit-dts.mjs",
|
|
107
|
-
"test": "vitest run",
|
|
108
|
-
"test:watch": "vitest",
|
|
109
|
-
"clean": "rm -rf dist",
|
|
110
|
-
"check:contract": "node scripts/check-contract.mjs"
|
|
111
113
|
}
|
|
112
|
-
}
|
|
114
|
+
}
|