@voyantjs/hono 0.80.2 → 0.80.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { MiddlewareHandler } from "hono";
|
|
2
|
-
import { type DbFactory, type VoyantBindings, type VoyantVariables } from "../types.js";
|
|
2
|
+
import { type DbFactory, type VoyantBindings, type VoyantDb, type VoyantVariables } from "../types.js";
|
|
3
3
|
/**
|
|
4
4
|
* Twenty-four hours, in milliseconds. Default TTL for stored idempotency
|
|
5
5
|
* keys. Tunable per middleware instance.
|
|
@@ -22,6 +22,13 @@ export interface IdempotencyKeyOptions {
|
|
|
22
22
|
* working through a deprecation window.
|
|
23
23
|
*/
|
|
24
24
|
required?: boolean;
|
|
25
|
+
/**
|
|
26
|
+
* Query parameters that affect the response contract and should be included
|
|
27
|
+
* in the idempotency fingerprint alongside the request body. Reusing the
|
|
28
|
+
* same key with different fingerprinted query values returns 409 instead of
|
|
29
|
+
* replaying a response captured under different request semantics.
|
|
30
|
+
*/
|
|
31
|
+
fingerprintSearchParams?: readonly string[];
|
|
25
32
|
/**
|
|
26
33
|
* Optional callback that, given the response body that's about to be
|
|
27
34
|
* stored, returns a `referenceId` (typically the booking id). Used for
|
|
@@ -57,9 +64,11 @@ declare module "hono" {
|
|
|
57
64
|
* the `db` middleware that ships with `createApp`) — caller is responsible
|
|
58
65
|
* for ordering this middleware after `db`.
|
|
59
66
|
*/
|
|
60
|
-
export declare function idempotencyKey<TBindings extends
|
|
67
|
+
export declare function idempotencyKey<TBindings extends object = VoyantBindings, TVariables extends {
|
|
68
|
+
db: VoyantDb;
|
|
69
|
+
} = VoyantVariables>(options?: IdempotencyKeyOptions): MiddlewareHandler<{
|
|
61
70
|
Bindings: TBindings;
|
|
62
|
-
Variables:
|
|
71
|
+
Variables: TVariables;
|
|
63
72
|
}>;
|
|
64
73
|
/**
|
|
65
74
|
* Sweep expired idempotency rows. Call from a daily cron.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"idempotency-key.d.ts","sourceRoot":"","sources":["../../src/middleware/idempotency-key.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAE7C,OAAO,EACL,KAAK,SAAS,EAEd,KAAK,cAAc,
|
|
1
|
+
{"version":3,"file":"idempotency-key.d.ts","sourceRoot":"","sources":["../../src/middleware/idempotency-key.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAE7C,OAAO,EACL,KAAK,SAAS,EAEd,KAAK,cAAc,EACnB,KAAK,QAAQ,EACb,KAAK,eAAe,EACrB,MAAM,aAAa,CAAA;AAEpB;;;GAGG;AACH,eAAO,MAAM,0BAA0B,QAAsB,CAAA;AAmB7D,MAAM,WAAW,qBAAqB;IACpC;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,KAAK,CAAC,EAAE,MAAM,CAAA;IACd;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAClB;;;;;OAKG;IACH,uBAAuB,CAAC,EAAE,SAAS,MAAM,EAAE,CAAA;IAC3C;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,CAAA;CAClE;AAED,UAAU,sBAAsB;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,mBAAmB,CAAC,EAAE,OAAO,CAAA;CAC9B;AAED,OAAO,QAAQ,MAAM,CAAC;IACpB,UAAU,kBAAmB,SAAQ,sBAAsB;KAAG;CAC/D;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,cAAc,CAC5B,SAAS,SAAS,MAAM,GAAG,cAAc,EACzC,UAAU,SAAS;IAAE,EAAE,EAAE,QAAQ,CAAA;CAAE,GAAG,eAAe,EAErD,OAAO,GAAE,qBAA0B,GAClC,iBAAiB,CAAC;IACnB,QAAQ,EAAE,SAAS,CAAA;IACnB,SAAS,EAAE,UAAU,CAAA;CACtB,CAAC,CAuID;AAgCD;;;;;;GAMG;AACH,wBAAsB,2BAA2B,CAAC,SAAS,SAAS,cAAc,EAChF,SAAS,EAAE,SAAS,CAAC,SAAS,CAAC,EAC/B,GAAG,EAAE,SAAS,GACb,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,CAAC,CAW9B"}
|
|
@@ -56,9 +56,10 @@ export function idempotencyKey(options = {}) {
|
|
|
56
56
|
if (headerKey.length > 255) {
|
|
57
57
|
return c.json({ error: `${HEADER_NAME} must be 255 characters or fewer` }, 400);
|
|
58
58
|
}
|
|
59
|
-
const
|
|
59
|
+
const requestUrl = new URL(c.req.url);
|
|
60
|
+
const scope = options.scope ?? `${c.req.method} ${requestUrl.pathname}`;
|
|
60
61
|
const rawBody = await c.req.text();
|
|
61
|
-
const bodyHash = await sha256Hex(rawBody);
|
|
62
|
+
const bodyHash = await sha256Hex(buildFingerprintInput(rawBody, requestUrl, options.fingerprintSearchParams));
|
|
62
63
|
// The `db` middleware always unwraps a `DisposableDb` to a plain
|
|
63
64
|
// `VoyantDb` before storing on context, so this cast is safe.
|
|
64
65
|
const db = c.get("db");
|
|
@@ -152,6 +153,15 @@ export function idempotencyKey(options = {}) {
|
|
|
152
153
|
}
|
|
153
154
|
};
|
|
154
155
|
}
|
|
156
|
+
function buildFingerprintInput(rawBody, url, searchParamKeys) {
|
|
157
|
+
if (!searchParamKeys?.length)
|
|
158
|
+
return rawBody;
|
|
159
|
+
const queryFingerprint = searchParamKeys.map((key) => [key, url.searchParams.getAll(key).sort()]);
|
|
160
|
+
return JSON.stringify({
|
|
161
|
+
body: rawBody,
|
|
162
|
+
query: queryFingerprint,
|
|
163
|
+
});
|
|
164
|
+
}
|
|
155
165
|
function pickStringField(body, keys) {
|
|
156
166
|
if (!body || typeof body !== "object")
|
|
157
167
|
return null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@voyantjs/hono",
|
|
3
|
-
"version": "0.80.
|
|
3
|
+
"version": "0.80.3",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -99,18 +99,18 @@
|
|
|
99
99
|
"drizzle-orm": "^0.45.2",
|
|
100
100
|
"hono": "^4.12.10",
|
|
101
101
|
"zod": "^4.3.6",
|
|
102
|
-
"@voyantjs/core": "0.80.
|
|
103
|
-
"@voyantjs/db": "0.80.
|
|
104
|
-
"@voyantjs/types": "0.80.
|
|
105
|
-
"@voyantjs/utils": "0.80.
|
|
106
|
-
"@voyantjs/workflows": "0.80.
|
|
102
|
+
"@voyantjs/core": "0.80.3",
|
|
103
|
+
"@voyantjs/db": "0.80.3",
|
|
104
|
+
"@voyantjs/types": "0.80.3",
|
|
105
|
+
"@voyantjs/utils": "0.80.3",
|
|
106
|
+
"@voyantjs/workflows": "0.80.3"
|
|
107
107
|
},
|
|
108
108
|
"devDependencies": {
|
|
109
109
|
"@cloudflare/workers-types": "^4.20260426.1",
|
|
110
110
|
"typescript": "^6.0.2",
|
|
111
111
|
"vitest": "^4.1.2",
|
|
112
112
|
"@voyantjs/voyant-typescript-config": "0.1.0",
|
|
113
|
-
"@voyantjs/workflows-orchestrator": "0.80.
|
|
113
|
+
"@voyantjs/workflows-orchestrator": "0.80.3"
|
|
114
114
|
},
|
|
115
115
|
"files": [
|
|
116
116
|
"dist"
|