@rotorsoft/act-http 1.8.2 → 1.8.4

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.
Files changed (53) hide show
  1. package/README.md +31 -11
  2. package/dist/.tsbuildinfo +1 -1
  3. package/dist/@types/api/idempotency.d.ts +10 -3
  4. package/dist/@types/api/idempotency.d.ts.map +1 -1
  5. package/dist/@types/api/sse-wiring.d.ts.map +1 -1
  6. package/dist/@types/receiver/express/index.d.ts +17 -1
  7. package/dist/@types/receiver/express/index.d.ts.map +1 -1
  8. package/dist/@types/receiver/fastify/index.d.ts +17 -2
  9. package/dist/@types/receiver/fastify/index.d.ts.map +1 -1
  10. package/dist/@types/receiver/finalize.d.ts +34 -0
  11. package/dist/@types/receiver/finalize.d.ts.map +1 -0
  12. package/dist/@types/receiver/hono/index.d.ts +15 -0
  13. package/dist/@types/receiver/hono/index.d.ts.map +1 -1
  14. package/dist/@types/receiver/start.d.ts.map +1 -1
  15. package/dist/@types/receiver/trpc/index.d.ts.map +1 -1
  16. package/dist/api/index.cjs +11 -3
  17. package/dist/api/index.cjs.map +1 -1
  18. package/dist/api/index.js +1 -1
  19. package/dist/{chunk-K4HAOBRF.js → chunk-6YOMQRZO.js} +23 -5
  20. package/dist/chunk-6YOMQRZO.js.map +1 -0
  21. package/dist/{chunk-AV57CGSG.js → chunk-FIYLGJAE.js} +12 -4
  22. package/dist/chunk-FIYLGJAE.js.map +1 -0
  23. package/dist/{chunk-4CGAUB5H.js → chunk-NXSPB2NW.js} +20 -2
  24. package/dist/chunk-NXSPB2NW.js.map +1 -0
  25. package/dist/hono/index.cjs +11 -3
  26. package/dist/hono/index.cjs.map +1 -1
  27. package/dist/hono/index.js +1 -1
  28. package/dist/receiver/express/index.cjs +25 -1
  29. package/dist/receiver/express/index.cjs.map +1 -1
  30. package/dist/receiver/express/index.js +11 -3
  31. package/dist/receiver/express/index.js.map +1 -1
  32. package/dist/receiver/fastify/index.cjs +28 -1
  33. package/dist/receiver/fastify/index.cjs.map +1 -1
  34. package/dist/receiver/fastify/index.js +14 -3
  35. package/dist/receiver/fastify/index.js.map +1 -1
  36. package/dist/receiver/hono/index.cjs +36 -2
  37. package/dist/receiver/hono/index.cjs.map +1 -1
  38. package/dist/receiver/hono/index.js +2 -2
  39. package/dist/receiver/index.cjs +38 -2
  40. package/dist/receiver/index.cjs.map +1 -1
  41. package/dist/receiver/index.js +4 -2
  42. package/dist/receiver/index.js.map +1 -1
  43. package/dist/receiver/trpc/index.cjs +45 -6
  44. package/dist/receiver/trpc/index.cjs.map +1 -1
  45. package/dist/receiver/trpc/index.js +31 -8
  46. package/dist/receiver/trpc/index.js.map +1 -1
  47. package/dist/trpc/index.cjs +11 -3
  48. package/dist/trpc/index.cjs.map +1 -1
  49. package/dist/trpc/index.js +1 -1
  50. package/package.json +2 -2
  51. package/dist/chunk-4CGAUB5H.js.map +0 -1
  52. package/dist/chunk-AV57CGSG.js.map +0 -1
  53. package/dist/chunk-K4HAOBRF.js.map +0 -1
@@ -23,9 +23,16 @@ export type IdempotencyResult<T> = {
23
23
  };
24
24
  /**
25
25
  * Wrap an action handler so the framework honors `Idempotency-Key`
26
- * dedup. Acquires the key via {@link IdempotencyStore.claim}, runs
27
- * the handler exactly when the claim was fresh, and skips the
28
- * handler entirely on a duplicate.
26
+ * dedup. Acquires the key via {@link IdempotencyStore.claim} (a
27
+ * *tentative* reservation), runs the handler exactly when the claim
28
+ * was fresh, and skips the handler entirely on a duplicate.
29
+ *
30
+ * The claim is finalized two-phase: on handler success the key is
31
+ * {@link IdempotencyStore.commit committed} so later retries dedup;
32
+ * on handler failure it is {@link IdempotencyStore.release released}
33
+ * and the rejection re-thrown, so the sender's retry re-processes
34
+ * instead of the delivery being permanently dropped. The tentative
35
+ * claim still dedups a concurrent duplicate mid-flight.
29
36
  *
30
37
  * Reuses the contract `@rotorsoft/act-ops/idempotency` already
31
38
  * defines for the receiver-side `Idempotency-Key` story. A single
@@ -1 +1 @@
1
- {"version":3,"file":"idempotency.d.ts","sourceRoot":"","sources":["../../../src/api/idempotency.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAEvE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAC3B;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,CAAC,CAAA;CAAE,GAC7B;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,CAAC;AAEtB;;;;;;;;;;GAUG;AACH,wBAAsB,eAAe,CAAC,CAAC,EACrC,KAAK,EAAE,gBAAgB,EACvB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACxB,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAM/B"}
1
+ {"version":3,"file":"idempotency.d.ts","sourceRoot":"","sources":["../../../src/api/idempotency.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAEvE;;;;;;;;;;;;;;;GAeG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,IAC3B;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,CAAC,CAAA;CAAE,GAC7B;IAAE,OAAO,EAAE,IAAI,CAAA;CAAE,CAAC;AAEtB;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAsB,eAAe,CAAC,CAAC,EACrC,KAAK,EAAE,gBAAgB,EACvB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GACxB,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,CAAC,CAc/B"}
@@ -1 +1 @@
1
- {"version":3,"file":"sse-wiring.d.ts","sourceRoot":"","sources":["../../../src/api/sse-wiring.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB;;;;;OAKG;IAEH,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACxC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC;;;;;;;OAOG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAC;IACnD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAE/C;;;GAGG;AACH,eAAO,MAAM,wBAAwB,QAAS,CAAC;AAuB/C;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,UAAU,GAAG,SAAS,CAU/D;AAED;;;;;;;;;GASG;AACH,qBAAa,oBAAoB;IAC/B,SAAgB,KAAK,EAAE,MAAM,CAAC;IAC9B,OAAO,CAAC,KAAK,CAAK;gBAEN,KAAK,EAAE,MAAM;IAIzB;;;;OAIG;IACH,OAAO,IAAI,OAAO;IAMlB;;;;OAIG;IACH,OAAO,IAAI,IAAI;IAIf,qDAAqD;IACrD,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAE7E;AAED;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,CAAC,CAAC,IAC9B;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GAC5C;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAEvD;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,IAAI,OAAO,CAAC;IACnB,OAAO,IAAI,IAAI,CAAC;CACjB,CAAC;AAEF;;;;;;;;;;GAUG;AAEH,wBAAuB,kBAAkB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,GAAG,EACtE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC5B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,aAAa,GAAG,SAAS,EACrC,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,eAAe,CAAC,EAAE,MAAM,KAAK,GAC5B,cAAc,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAgCzC"}
1
+ {"version":3,"file":"sse-wiring.d.ts","sourceRoot":"","sources":["../../../src/api/sse-wiring.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEtD;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB;;;;;OAKG;IAEH,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC,GAAG,CAAC,CAAC;IACxC;;;;;;;;;;OAUG;IACH,QAAQ,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC;IACjC;;;;;;;OAOG;IACH,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAC;CAC/B,CAAC;AAEF;;;;;;GAMG;AACH,MAAM,MAAM,SAAS,GAAG;IACtB,QAAQ,CAAC,OAAO,EAAE,gBAAgB,CAAC,cAAc,CAAC,CAAC;IACnD,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,MAAM,CAAC;AAE/C;;;GAGG;AACH,eAAO,MAAM,wBAAwB,QAAS,CAAC;AAyB/C;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,UAAU,GAAG,SAAS,CAU/D;AAED;;;;;;;;;GASG;AACH,qBAAa,oBAAoB;IAC/B,SAAgB,KAAK,EAAE,MAAM,CAAC;IAC9B,OAAO,CAAC,KAAK,CAAK;gBAEN,KAAK,EAAE,MAAM;IAIzB;;;;OAIG;IACH,OAAO,IAAI,OAAO;IAMlB;;;;OAIG;IACH,OAAO,IAAI,IAAI;IAIf,qDAAqD;IACrD,IAAI,IAAI,IAAI,MAAM,CAEjB;CACF;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAAE,EAAE,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,CAE7E;AAED;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,CAAC,CAAC,IAC9B;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAA;CAAE,GAC5C;IAAE,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAC;IAAC,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CAAE,CAAC;AAEvD;;;;;;;;GAQG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,OAAO,IAAI,OAAO,CAAC;IACnB,OAAO,IAAI,IAAI,CAAC;CACjB,CAAC;AAEF;;;;;;;;;;GAUG;AAEH,wBAAuB,kBAAkB,CAAC,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAA;CAAE,GAAG,GAAG,EACtE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,EAC5B,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,aAAa,GAAG,SAAS,EACrC,MAAM,EAAE,WAAW,GAAG,SAAS,EAC/B,eAAe,CAAC,EAAE,MAAM,KAAK,GAC5B,cAAc,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC,CAgCzC"}
@@ -32,7 +32,17 @@
32
32
  * On failure: responds with the framework-idiomatic JSON shape
33
33
  * `{ error: <reason> }` at status 400 (missing-key) or 401
34
34
  * (verification failures), and does not call `next()`. On success:
35
- * attaches `req.idempotency = { key, deduped }` and calls `next()`.
35
+ * attaches `req.idempotency = { key, deduped, commit, release }` and
36
+ * calls `next()`.
37
+ *
38
+ * **Two-phase dedup**: the claim is *tentative*. Express runs the
39
+ * middleware to completion before the route handler, so — unlike the
40
+ * Hono adapter — it can't observe the handler's outcome to finalize
41
+ * automatically. The route handler **must** call
42
+ * `req.idempotency.commit()` on success or `req.idempotency.release()`
43
+ * on a transient failure. Skipping both leaves the claim tentative:
44
+ * it dedups concurrent duplicates but expires on TTL, so the delivery
45
+ * is never permanently lost — it just isn't durably deduped either.
36
46
  *
37
47
  * **Raw body requirement**: when `secret` is configured, mount
38
48
  * `express.raw({ type: "application/json" })` (or whatever
@@ -42,6 +52,12 @@
42
52
  */
43
53
  import type { RequestHandler } from "express";
44
54
  import { type CheckWebhookOptions } from "../check.js";
55
+ import { type Finalizers } from "../finalize.js";
56
+ /** Shape attached to `req.idempotency` by the Express adapter. */
57
+ export type ExpressIdempotency = {
58
+ key: string;
59
+ deduped: boolean;
60
+ } & Finalizers;
45
61
  /**
46
62
  * Build an Express middleware that verifies the request signature
47
63
  * (when `secret` is set), enforces `Idempotency-Key`, and claims the
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/receiver/express/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,OAAO,KAAK,EAAyB,cAAc,EAAY,MAAM,SAAS,CAAC;AAC/E,OAAO,EAAE,KAAK,mBAAmB,EAAgB,MAAM,aAAa,CAAC;AAErE;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,mBAAmB,GAC3B,cAAc,CAwBhB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/receiver/express/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmDG;AACH,OAAO,KAAK,EAAyB,cAAc,EAAY,MAAM,SAAS,CAAC;AAC/E,OAAO,EAAE,KAAK,mBAAmB,EAAgB,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,KAAK,UAAU,EAAmB,MAAM,gBAAgB,CAAC;AAElE,kEAAkE;AAClE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;CAClB,GAAG,UAAU,CAAC;AAEf;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,mBAAmB,GAC3B,cAAc,CA6BhB"}
@@ -33,8 +33,17 @@
33
33
  *
34
34
  * On failure: replies with `{ error: <reason> }` at status 400
35
35
  * (missing-key) or 401 (verification failures). On success: attaches
36
- * `request.idempotency = { key, deduped }` and lets the route handler
37
- * run.
36
+ * `request.idempotency = { key, deduped, commit, release }` and lets
37
+ * the route handler run.
38
+ *
39
+ * **Two-phase dedup**: the claim is *tentative*. A Fastify
40
+ * `preHandler` runs to completion before the route handler, so — like
41
+ * the Express adapter — it can't finalize automatically. The route
42
+ * handler **must** call `request.idempotency.commit()` on success or
43
+ * `request.idempotency.release()` on a transient failure. Skipping
44
+ * both leaves the claim tentative: it dedups concurrent duplicates but
45
+ * expires on TTL, so a delivery is never permanently lost — it just
46
+ * isn't durably deduped either.
38
47
  *
39
48
  * **Raw body requirement**: when `secret` is configured, register a
40
49
  * content-type parser that preserves the raw body string. Fastify's
@@ -45,6 +54,12 @@
45
54
  */
46
55
  import type { FastifyReply, FastifyRequest } from "fastify";
47
56
  import { type CheckWebhookOptions } from "../check.js";
57
+ import { type Finalizers } from "../finalize.js";
58
+ /** Shape attached to `request.idempotency` by the Fastify adapter. */
59
+ export type FastifyIdempotency = {
60
+ key: string;
61
+ deduped: boolean;
62
+ } & Finalizers;
48
63
  /**
49
64
  * Build a Fastify `preHandler` hook that verifies the request
50
65
  * signature (when `secret` is set), enforces `Idempotency-Key`, and
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/receiver/fastify/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,KAAK,mBAAmB,EAAgB,MAAM,aAAa,CAAC;AAOrE;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,mBAAmB,GAC3B,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CAkBjE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/receiver/fastify/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqDG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAC5D,OAAO,EAAE,KAAK,mBAAmB,EAAgB,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,KAAK,UAAU,EAAmB,MAAM,gBAAgB,CAAC;AAElE,sEAAsE;AACtE,MAAM,MAAM,kBAAkB,GAAG;IAC/B,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;CAClB,GAAG,UAAU,CAAC;AAOf;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,mBAAmB,GAC3B,CAAC,OAAO,EAAE,cAAc,EAAE,KAAK,EAAE,YAAY,KAAK,OAAO,CAAC,IAAI,CAAC,CA4BjE"}
@@ -0,0 +1,34 @@
1
+ import type { IdempotencyStore } from "@rotorsoft/act-ops/idempotency";
2
+ /**
3
+ * The two-phase finalizers a receiver adapter binds to a single
4
+ * inbound delivery. The claim `checkWebhook` makes is *tentative*;
5
+ * exactly one of these promotes or drops it once the business handler
6
+ * resolves its outcome.
7
+ */
8
+ export type Finalizers = {
9
+ /**
10
+ * Promote the tentative claim to a durable record so every later
11
+ * retry of this key dedups. Call on handler success.
12
+ */
13
+ commit: () => void | Promise<void>;
14
+ /**
15
+ * Drop the tentative claim so the sender's retry re-processes.
16
+ * Call on transient handler failure.
17
+ */
18
+ release: () => void | Promise<void>;
19
+ };
20
+ /**
21
+ * Build the {@link Finalizers} for one delivery.
22
+ *
23
+ * Guarantees:
24
+ *
25
+ * - **Deduped deliveries are inert.** When `deduped` is `true` the key
26
+ * was already committed by an earlier delivery; both finalizers are
27
+ * no-ops so a duplicate can never release someone else's committed
28
+ * claim.
29
+ * - **Finalize-once.** After the first `commit` or `release` fires,
30
+ * further calls are no-ops — an adapter that both auto-finalizes and
31
+ * lets the operator call `commit()`/`release()` can't double-fire.
32
+ */
33
+ export declare function make_finalizers(store: IdempotencyStore, key: string, deduped: boolean): Finalizers;
34
+ //# sourceMappingURL=finalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"finalize.d.ts","sourceRoot":"","sources":["../../../src/receiver/finalize.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAEvE;;;;;GAKG;AACH,MAAM,MAAM,UAAU,GAAG;IACvB;;;OAGG;IACH,MAAM,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACnC;;;OAGG;IACH,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrC,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,gBAAgB,EACvB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,OAAO,GACf,UAAU,CAcZ"}
@@ -31,6 +31,14 @@
31
31
  * success: stashes `c.set("idempotency", { key, deduped })` and
32
32
  * continues with `await next()`.
33
33
  *
34
+ * **Two-phase dedup**: the claim `checkWebhook` makes is *tentative*.
35
+ * Because Hono middleware wraps the downstream chain, this adapter
36
+ * finalizes the claim automatically after `await next()`: a downstream
37
+ * 2xx **commits** the key (later retries dedup); a 5xx or a thrown
38
+ * handler **releases** it (the sender's retry re-processes instead of
39
+ * being silently dropped). Operators who need explicit control can
40
+ * still call `c.get("idempotency").commit()` / `.release()`.
41
+ *
34
42
  * **Raw body**: Hono exposes `await c.req.text()` natively, which
35
43
  * the middleware reads when `secret` is configured. No extra setup
36
44
  * needed.
@@ -42,11 +50,18 @@ import { type CheckWebhookOptions } from "../check.js";
42
50
  * generic on the returned {@link MiddlewareHandler} threads it
43
51
  * through so route handlers downstream of `app.post(..., webhookMiddleware(...), handler)`
44
52
  * see `c.get("idempotency")` typed without a manual cast.
53
+ *
54
+ * `commit` / `release` finalize the tentative claim — call one after
55
+ * the handler resolves its outcome. This adapter also finalizes
56
+ * automatically based on the response status, so explicit calls are
57
+ * only needed when the auto-detection doesn't fit.
45
58
  */
46
59
  export type WebhookVariables = {
47
60
  idempotency: {
48
61
  key: string;
49
62
  deduped: boolean;
63
+ commit: () => void | Promise<void>;
64
+ release: () => void | Promise<void>;
50
65
  };
51
66
  };
52
67
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/receiver/hono/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,EAAE,KAAK,mBAAmB,EAAgB,MAAM,aAAa,CAAC;AAErE;;;;;GAKG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,OAAO,CAAA;KAAE,CAAC;CAChD,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,mBAAmB,GAC3B,iBAAiB,CAAC;IAAE,SAAS,EAAE,gBAAgB,CAAA;CAAE,CAAC,CAWpD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/receiver/hono/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAC;AAC9C,OAAO,EAAE,KAAK,mBAAmB,EAAgB,MAAM,aAAa,CAAC;AAGrE;;;;;;;;;;GAUG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,WAAW,EAAE;QACX,GAAG,EAAE,MAAM,CAAC;QACZ,OAAO,EAAE,OAAO,CAAC;QACjB,MAAM,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;QACnC,OAAO,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;KACrC,CAAC;CACH,CAAC;AAEF;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,mBAAmB,GAC3B,iBAAiB,CAAC;IAAE,SAAS,EAAE,gBAAgB,CAAA;CAAE,CAAC,CA4BpD"}
@@ -1 +1 @@
1
- {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/receiver/start.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,eAAe,EAEf,eAAe,EAEhB,MAAM,6BAA6B,CAAC;AAIrC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,eAAe,CA2FlE"}
1
+ {"version":3,"file":"start.d.ts","sourceRoot":"","sources":["../../../src/receiver/start.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,eAAe,EAEf,eAAe,EAEhB,MAAM,6BAA6B,CAAC;AAIrC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4CG;AACH,wBAAgB,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,eAAe,CAkGlE"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/receiver/trpc/index.ts"],"names":[],"mappings":"AAyCA,OAAO,EAAE,KAAK,mBAAmB,EAAgB,MAAM,aAAa,CAAC;AAErE;;;;;;;;;;;;GAYG;AAEH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,mBAAmB,GAAG,GAAG,CA2BnE"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/receiver/trpc/index.ts"],"names":[],"mappings":"AAgDA,OAAO,EAAE,KAAK,mBAAmB,EAAgB,MAAM,aAAa,CAAC;AAGrE;;;;;;;;;;;;GAYG;AAEH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,mBAAmB,GAAG,GAAG,CA0DnE"}
@@ -80,7 +80,15 @@ async function withIdempotency(store, key, handler) {
80
80
  if (!fresh) {
81
81
  return { deduped: true };
82
82
  }
83
- return { deduped: false, result: await handler() };
83
+ let result;
84
+ try {
85
+ result = await handler();
86
+ } catch (err) {
87
+ await store.release(key);
88
+ throw err;
89
+ }
90
+ await store.commit(key);
91
+ return { deduped: false, result };
84
92
  }
85
93
 
86
94
  // ../../node_modules/.pnpm/zod@4.4.3/node_modules/zod/v4/classic/external.js
@@ -14601,8 +14609,8 @@ config(en_default());
14601
14609
  var DEFAULT_SSE_MAX_CONNECTIONS = 500;
14602
14610
  var DEFAULT_SSE_HEARTBEAT_MS = 3e4;
14603
14611
  var SseOptionsSchema = external_exports.object({
14604
- maxConnections: external_exports.number().min(1).max(1e4).default(DEFAULT_SSE_MAX_CONNECTIONS),
14605
- heartbeatMs: external_exports.number().min(15e3).max(3e5).default(DEFAULT_SSE_HEARTBEAT_MS)
14612
+ maxConnections: external_exports.number().int().min(1).max(1e4).default(DEFAULT_SSE_MAX_CONNECTIONS),
14613
+ heartbeatMs: external_exports.number().int().min(15e3).max(3e5).default(DEFAULT_SSE_HEARTBEAT_MS)
14606
14614
  });
14607
14615
  function resolveSseConfig(options) {
14608
14616
  const parsed = SseOptionsSchema.parse({