hooklatch 0.0.0-stage → 1.0.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.
Files changed (301) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +438 -2
  3. package/dist/adapters/cloudflare.d.ts +11 -0
  4. package/dist/adapters/cloudflare.d.ts.map +1 -0
  5. package/dist/adapters/cloudflare.js +27 -0
  6. package/dist/adapters/cloudflare.js.map +1 -0
  7. package/dist/adapters/express.d.ts +9 -0
  8. package/dist/adapters/express.d.ts.map +1 -0
  9. package/dist/adapters/express.js +63 -0
  10. package/dist/adapters/express.js.map +1 -0
  11. package/dist/adapters/hono.d.ts +12 -0
  12. package/dist/adapters/hono.d.ts.map +1 -0
  13. package/dist/adapters/hono.js +28 -0
  14. package/dist/adapters/hono.js.map +1 -0
  15. package/dist/adapters/nextjs.d.ts +6 -0
  16. package/dist/adapters/nextjs.d.ts.map +1 -0
  17. package/dist/adapters/nextjs.js +56 -0
  18. package/dist/adapters/nextjs.js.map +1 -0
  19. package/dist/adapters/shared.d.ts +8 -0
  20. package/dist/adapters/shared.d.ts.map +1 -0
  21. package/dist/adapters/shared.js +53 -0
  22. package/dist/adapters/shared.js.map +1 -0
  23. package/dist/cjs/adapters/cloudflare.cjs +29 -0
  24. package/dist/cjs/adapters/cloudflare.d.cts +10 -0
  25. package/dist/cjs/adapters/express.cjs +65 -0
  26. package/dist/cjs/adapters/express.d.cts +8 -0
  27. package/dist/cjs/adapters/hono.cjs +30 -0
  28. package/dist/cjs/adapters/hono.d.cts +11 -0
  29. package/dist/cjs/adapters/nextjs.cjs +58 -0
  30. package/dist/cjs/adapters/nextjs.d.cts +5 -0
  31. package/dist/cjs/adapters/shared.cjs +58 -0
  32. package/dist/cjs/adapters/shared.d.cts +7 -0
  33. package/dist/cjs/core.cjs +30 -0
  34. package/dist/cjs/core.d.cts +5 -0
  35. package/dist/cjs/diagnostics/catalog.cjs +341 -0
  36. package/dist/cjs/diagnostics/catalog.d.cts +19 -0
  37. package/dist/cjs/diagnostics/index.cjs +90 -0
  38. package/dist/cjs/diagnostics/index.d.cts +5 -0
  39. package/dist/cjs/diagnostics/types.cjs +2 -0
  40. package/dist/cjs/diagnostics/types.d.cts +20 -0
  41. package/dist/cjs/errors.cjs +13 -0
  42. package/dist/cjs/errors.d.cts +6 -0
  43. package/dist/cjs/index.cjs +9 -0
  44. package/dist/cjs/index.d.cts +3 -0
  45. package/dist/cjs/internal/body.cjs +50 -0
  46. package/dist/cjs/internal/body.d.cts +2 -0
  47. package/dist/cjs/internal/bytes.cjs +43 -0
  48. package/dist/cjs/internal/bytes.d.cts +4 -0
  49. package/dist/cjs/internal/crypto.cjs +52 -0
  50. package/dist/cjs/internal/crypto.d.cts +3 -0
  51. package/dist/cjs/internal/headers.cjs +72 -0
  52. package/dist/cjs/internal/headers.d.cts +2 -0
  53. package/dist/cjs/internal/options.cjs +130 -0
  54. package/dist/cjs/internal/options.d.cts +7 -0
  55. package/dist/cjs/internal/prepare.cjs +11 -0
  56. package/dist/cjs/internal/prepare.d.cts +4 -0
  57. package/dist/cjs/internal/provider-options.cjs +72 -0
  58. package/dist/cjs/internal/provider-options.d.cts +6 -0
  59. package/dist/cjs/internal/provider.cjs +2 -0
  60. package/dist/cjs/internal/provider.d.cts +39 -0
  61. package/dist/cjs/internal/verification.cjs +71 -0
  62. package/dist/cjs/internal/verification.d.cts +12 -0
  63. package/dist/cjs/providers/clerk.cjs +15 -0
  64. package/dist/cjs/providers/clerk.d.cts +9 -0
  65. package/dist/cjs/providers/dodo-payments.cjs +26 -0
  66. package/dist/cjs/providers/dodo-payments.d.cts +20 -0
  67. package/dist/cjs/providers/doppler.cjs +71 -0
  68. package/dist/cjs/providers/doppler.d.cts +37 -0
  69. package/dist/cjs/providers/fal.cjs +80 -0
  70. package/dist/cjs/providers/fal.d.cts +13 -0
  71. package/dist/cjs/providers/github.cjs +52 -0
  72. package/dist/cjs/providers/github.d.cts +7 -0
  73. package/dist/cjs/providers/gitlab.cjs +26 -0
  74. package/dist/cjs/providers/gitlab.d.cts +20 -0
  75. package/dist/cjs/providers/grafana.cjs +180 -0
  76. package/dist/cjs/providers/grafana.d.cts +35 -0
  77. package/dist/cjs/providers/index.cjs +110 -0
  78. package/dist/cjs/providers/index.d.cts +26 -0
  79. package/dist/cjs/providers/lemon-squeezy.cjs +36 -0
  80. package/dist/cjs/providers/lemon-squeezy.d.cts +15 -0
  81. package/dist/cjs/providers/linear.cjs +58 -0
  82. package/dist/cjs/providers/linear.d.cts +36 -0
  83. package/dist/cjs/providers/paddle.cjs +105 -0
  84. package/dist/cjs/providers/paddle.d.cts +14 -0
  85. package/dist/cjs/providers/polar.cjs +80 -0
  86. package/dist/cjs/providers/polar.d.cts +25 -0
  87. package/dist/cjs/providers/razorpay.cjs +43 -0
  88. package/dist/cjs/providers/razorpay.d.cts +19 -0
  89. package/dist/cjs/providers/replicate.cjs +25 -0
  90. package/dist/cjs/providers/replicate.d.cts +19 -0
  91. package/dist/cjs/providers/sanity.cjs +161 -0
  92. package/dist/cjs/providers/sanity.d.cts +38 -0
  93. package/dist/cjs/providers/sentry.cjs +47 -0
  94. package/dist/cjs/providers/sentry.d.cts +25 -0
  95. package/dist/cjs/providers/shared.cjs +49 -0
  96. package/dist/cjs/providers/shared.d.cts +14 -0
  97. package/dist/cjs/providers/shopify.cjs +40 -0
  98. package/dist/cjs/providers/shopify.d.cts +8 -0
  99. package/dist/cjs/providers/standard-webhooks-protocol.cjs +97 -0
  100. package/dist/cjs/providers/standard-webhooks-protocol.d.cts +14 -0
  101. package/dist/cjs/providers/standard-webhooks.cjs +15 -0
  102. package/dist/cjs/providers/standard-webhooks.d.cts +9 -0
  103. package/dist/cjs/providers/stripe.cjs +81 -0
  104. package/dist/cjs/providers/stripe.d.cts +7 -0
  105. package/dist/cjs/providers/svix.cjs +63 -0
  106. package/dist/cjs/providers/svix.d.cts +9 -0
  107. package/dist/cjs/providers/vercel.cjs +39 -0
  108. package/dist/cjs/providers/vercel.d.cts +15 -0
  109. package/dist/cjs/providers/workos.cjs +120 -0
  110. package/dist/cjs/providers/workos.d.cts +32 -0
  111. package/dist/cjs/types.cjs +2 -0
  112. package/dist/cjs/types.d.cts +68 -0
  113. package/dist/cli/args.d.ts +86 -0
  114. package/dist/cli/args.d.ts.map +1 -0
  115. package/dist/cli/args.js +358 -0
  116. package/dist/cli/args.js.map +1 -0
  117. package/dist/cli/filesystem.d.ts +15 -0
  118. package/dist/cli/filesystem.d.ts.map +1 -0
  119. package/dist/cli/filesystem.js +170 -0
  120. package/dist/cli/filesystem.js.map +1 -0
  121. package/dist/cli/index.d.ts +3 -0
  122. package/dist/cli/index.d.ts.map +1 -0
  123. package/dist/cli/index.js +64 -0
  124. package/dist/cli/index.js.map +1 -0
  125. package/dist/cli/templates.d.ts +13 -0
  126. package/dist/cli/templates.d.ts.map +1 -0
  127. package/dist/cli/templates.js +297 -0
  128. package/dist/cli/templates.js.map +1 -0
  129. package/dist/core.d.ts +6 -0
  130. package/dist/core.d.ts.map +1 -0
  131. package/dist/core.js +26 -0
  132. package/dist/core.js.map +1 -0
  133. package/dist/diagnostics/catalog.d.ts +20 -0
  134. package/dist/diagnostics/catalog.d.ts.map +1 -0
  135. package/dist/diagnostics/catalog.js +335 -0
  136. package/dist/diagnostics/catalog.js.map +1 -0
  137. package/dist/diagnostics/index.d.ts +6 -0
  138. package/dist/diagnostics/index.d.ts.map +1 -0
  139. package/dist/diagnostics/index.js +88 -0
  140. package/dist/diagnostics/index.js.map +1 -0
  141. package/dist/diagnostics/types.d.ts +21 -0
  142. package/dist/diagnostics/types.d.ts.map +1 -0
  143. package/dist/diagnostics/types.js +2 -0
  144. package/dist/diagnostics/types.js.map +1 -0
  145. package/dist/errors.d.ts +7 -0
  146. package/dist/errors.d.ts.map +1 -0
  147. package/dist/errors.js +10 -0
  148. package/dist/errors.js.map +1 -0
  149. package/dist/index.d.ts +4 -0
  150. package/dist/index.d.ts.map +1 -0
  151. package/dist/index.js +3 -0
  152. package/dist/index.js.map +1 -0
  153. package/dist/internal/body.d.ts +3 -0
  154. package/dist/internal/body.d.ts.map +1 -0
  155. package/dist/internal/body.js +48 -0
  156. package/dist/internal/body.js.map +1 -0
  157. package/dist/internal/bytes.d.ts +5 -0
  158. package/dist/internal/bytes.d.ts.map +1 -0
  159. package/dist/internal/bytes.js +38 -0
  160. package/dist/internal/bytes.js.map +1 -0
  161. package/dist/internal/crypto.d.ts +4 -0
  162. package/dist/internal/crypto.d.ts.map +1 -0
  163. package/dist/internal/crypto.js +49 -0
  164. package/dist/internal/crypto.js.map +1 -0
  165. package/dist/internal/headers.d.ts +3 -0
  166. package/dist/internal/headers.d.ts.map +1 -0
  167. package/dist/internal/headers.js +70 -0
  168. package/dist/internal/headers.js.map +1 -0
  169. package/dist/internal/options.d.ts +8 -0
  170. package/dist/internal/options.d.ts.map +1 -0
  171. package/dist/internal/options.js +128 -0
  172. package/dist/internal/options.js.map +1 -0
  173. package/dist/internal/prepare.d.ts +5 -0
  174. package/dist/internal/prepare.d.ts.map +1 -0
  175. package/dist/internal/prepare.js +9 -0
  176. package/dist/internal/prepare.js.map +1 -0
  177. package/dist/internal/provider-options.d.ts +7 -0
  178. package/dist/internal/provider-options.d.ts.map +1 -0
  179. package/dist/internal/provider-options.js +69 -0
  180. package/dist/internal/provider-options.js.map +1 -0
  181. package/dist/internal/provider.d.ts +40 -0
  182. package/dist/internal/provider.d.ts.map +1 -0
  183. package/dist/internal/provider.js +2 -0
  184. package/dist/internal/provider.js.map +1 -0
  185. package/dist/internal/verification.d.ts +13 -0
  186. package/dist/internal/verification.d.ts.map +1 -0
  187. package/dist/internal/verification.js +66 -0
  188. package/dist/internal/verification.js.map +1 -0
  189. package/dist/node/adapters/cloudflare.d.ts +1 -0
  190. package/dist/node/adapters/cloudflare.js +3 -0
  191. package/dist/node/adapters/express.d.ts +1 -0
  192. package/dist/node/adapters/express.js +3 -0
  193. package/dist/node/adapters/hono.d.ts +1 -0
  194. package/dist/node/adapters/hono.js +3 -0
  195. package/dist/node/adapters/nextjs.d.ts +1 -0
  196. package/dist/node/adapters/nextjs.js +3 -0
  197. package/dist/node/diagnostics/index.d.ts +1 -0
  198. package/dist/node/diagnostics/index.js +3 -0
  199. package/dist/node/index.d.ts +1 -0
  200. package/dist/node/index.js +6 -0
  201. package/dist/providers/clerk.d.ts +10 -0
  202. package/dist/providers/clerk.d.ts.map +1 -0
  203. package/dist/providers/clerk.js +13 -0
  204. package/dist/providers/clerk.js.map +1 -0
  205. package/dist/providers/dodo-payments.d.ts +21 -0
  206. package/dist/providers/dodo-payments.d.ts.map +1 -0
  207. package/dist/providers/dodo-payments.js +24 -0
  208. package/dist/providers/dodo-payments.js.map +1 -0
  209. package/dist/providers/doppler.d.ts +38 -0
  210. package/dist/providers/doppler.d.ts.map +1 -0
  211. package/dist/providers/doppler.js +69 -0
  212. package/dist/providers/doppler.js.map +1 -0
  213. package/dist/providers/fal.d.ts +14 -0
  214. package/dist/providers/fal.d.ts.map +1 -0
  215. package/dist/providers/fal.js +78 -0
  216. package/dist/providers/fal.js.map +1 -0
  217. package/dist/providers/github.d.ts +8 -0
  218. package/dist/providers/github.d.ts.map +1 -0
  219. package/dist/providers/github.js +50 -0
  220. package/dist/providers/github.js.map +1 -0
  221. package/dist/providers/gitlab.d.ts +21 -0
  222. package/dist/providers/gitlab.d.ts.map +1 -0
  223. package/dist/providers/gitlab.js +24 -0
  224. package/dist/providers/gitlab.js.map +1 -0
  225. package/dist/providers/grafana.d.ts +36 -0
  226. package/dist/providers/grafana.d.ts.map +1 -0
  227. package/dist/providers/grafana.js +178 -0
  228. package/dist/providers/grafana.js.map +1 -0
  229. package/dist/providers/index.d.ts +27 -0
  230. package/dist/providers/index.d.ts.map +1 -0
  231. package/dist/providers/index.js +89 -0
  232. package/dist/providers/index.js.map +1 -0
  233. package/dist/providers/lemon-squeezy.d.ts +16 -0
  234. package/dist/providers/lemon-squeezy.d.ts.map +1 -0
  235. package/dist/providers/lemon-squeezy.js +34 -0
  236. package/dist/providers/lemon-squeezy.js.map +1 -0
  237. package/dist/providers/linear.d.ts +37 -0
  238. package/dist/providers/linear.d.ts.map +1 -0
  239. package/dist/providers/linear.js +56 -0
  240. package/dist/providers/linear.js.map +1 -0
  241. package/dist/providers/paddle.d.ts +15 -0
  242. package/dist/providers/paddle.d.ts.map +1 -0
  243. package/dist/providers/paddle.js +103 -0
  244. package/dist/providers/paddle.js.map +1 -0
  245. package/dist/providers/polar.d.ts +26 -0
  246. package/dist/providers/polar.d.ts.map +1 -0
  247. package/dist/providers/polar.js +78 -0
  248. package/dist/providers/polar.js.map +1 -0
  249. package/dist/providers/razorpay.d.ts +20 -0
  250. package/dist/providers/razorpay.d.ts.map +1 -0
  251. package/dist/providers/razorpay.js +41 -0
  252. package/dist/providers/razorpay.js.map +1 -0
  253. package/dist/providers/replicate.d.ts +20 -0
  254. package/dist/providers/replicate.d.ts.map +1 -0
  255. package/dist/providers/replicate.js +23 -0
  256. package/dist/providers/replicate.js.map +1 -0
  257. package/dist/providers/sanity.d.ts +39 -0
  258. package/dist/providers/sanity.d.ts.map +1 -0
  259. package/dist/providers/sanity.js +159 -0
  260. package/dist/providers/sanity.js.map +1 -0
  261. package/dist/providers/sentry.d.ts +26 -0
  262. package/dist/providers/sentry.d.ts.map +1 -0
  263. package/dist/providers/sentry.js +45 -0
  264. package/dist/providers/sentry.js.map +1 -0
  265. package/dist/providers/shared.d.ts +15 -0
  266. package/dist/providers/shared.d.ts.map +1 -0
  267. package/dist/providers/shared.js +40 -0
  268. package/dist/providers/shared.js.map +1 -0
  269. package/dist/providers/shopify.d.ts +9 -0
  270. package/dist/providers/shopify.d.ts.map +1 -0
  271. package/dist/providers/shopify.js +38 -0
  272. package/dist/providers/shopify.js.map +1 -0
  273. package/dist/providers/standard-webhooks-protocol.d.ts +15 -0
  274. package/dist/providers/standard-webhooks-protocol.d.ts.map +1 -0
  275. package/dist/providers/standard-webhooks-protocol.js +95 -0
  276. package/dist/providers/standard-webhooks-protocol.js.map +1 -0
  277. package/dist/providers/standard-webhooks.d.ts +10 -0
  278. package/dist/providers/standard-webhooks.d.ts.map +1 -0
  279. package/dist/providers/standard-webhooks.js +13 -0
  280. package/dist/providers/standard-webhooks.js.map +1 -0
  281. package/dist/providers/stripe.d.ts +8 -0
  282. package/dist/providers/stripe.d.ts.map +1 -0
  283. package/dist/providers/stripe.js +79 -0
  284. package/dist/providers/stripe.js.map +1 -0
  285. package/dist/providers/svix.d.ts +10 -0
  286. package/dist/providers/svix.d.ts.map +1 -0
  287. package/dist/providers/svix.js +61 -0
  288. package/dist/providers/svix.js.map +1 -0
  289. package/dist/providers/vercel.d.ts +16 -0
  290. package/dist/providers/vercel.d.ts.map +1 -0
  291. package/dist/providers/vercel.js +37 -0
  292. package/dist/providers/vercel.js.map +1 -0
  293. package/dist/providers/workos.d.ts +33 -0
  294. package/dist/providers/workos.d.ts.map +1 -0
  295. package/dist/providers/workos.js +118 -0
  296. package/dist/providers/workos.js.map +1 -0
  297. package/dist/types.d.ts +69 -0
  298. package/dist/types.d.ts.map +1 -0
  299. package/dist/types.js +2 -0
  300. package/dist/types.js.map +1 -0
  301. package/package.json +200 -4
@@ -0,0 +1,15 @@
1
+ import type { ProviderDescriptor } from '../internal/provider.js';
2
+ export interface StandardWebhooksHeaderNames {
3
+ readonly id: string;
4
+ readonly timestamp: string;
5
+ readonly signature: string;
6
+ }
7
+ /**
8
+ * Internal Standard Webhooks v1 protocol factory. `headerNames` selects the
9
+ * canonical or branded header family; callers own alias policy and must never
10
+ * mix names from two families in one configuration.
11
+ */
12
+ export declare function createStandardWebhooksProtocol<P extends string>(provider: P, label: string, headerNames: StandardWebhooksHeaderNames): {
13
+ readonly provider: P;
14
+ } & Pick<ProviderDescriptor, 'decodeSecret' | 'parse'>;
15
+ //# sourceMappingURL=standard-webhooks-protocol.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"standard-webhooks-protocol.d.ts","sourceRoot":"","sources":["../../src/providers/standard-webhooks-protocol.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAkC,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAelG,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,wBAAgB,8BAA8B,CAAC,CAAC,SAAS,MAAM,EAC7D,QAAQ,EAAE,CAAC,EACX,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,2BAA2B,GACvC;IAAE,QAAQ,CAAC,QAAQ,EAAE,CAAC,CAAA;CAAE,GAAG,IAAI,CAAC,kBAAkB,EAAE,cAAc,GAAG,OAAO,CAAC,CAuG/E"}
@@ -0,0 +1,95 @@
1
+ import { HooklatchError } from '../errors.js';
2
+ import { concatBytes, decodeBase64, utf8 } from '../internal/bytes.js';
3
+ import { decodeBase64Signature, failure, isCanonicalTimestamp, isNonEmptySecret, isSchemeToken, } from './shared.js';
4
+ const SCHEME = 'v1';
5
+ const SECRET_PREFIX = 'whsec_';
6
+ const MIN_KEY_BYTES = 24;
7
+ const MAX_KEY_BYTES = 64;
8
+ /**
9
+ * Internal Standard Webhooks v1 protocol factory. `headerNames` selects the
10
+ * canonical or branded header family; callers own alias policy and must never
11
+ * mix names from two families in one configuration.
12
+ */
13
+ export function createStandardWebhooksProtocol(provider, label, headerNames) {
14
+ return {
15
+ provider,
16
+ decodeSecret(secret) {
17
+ if (!isNonEmptySecret(secret)) {
18
+ throw new HooklatchError('invalid-secret', `Invalid ${label} signing secret.`);
19
+ }
20
+ const encoded = secret.startsWith(SECRET_PREFIX)
21
+ ? secret.slice(SECRET_PREFIX.length)
22
+ : secret;
23
+ const bytes = decodeBase64(encoded);
24
+ if (bytes === null || bytes.byteLength < MIN_KEY_BYTES || bytes.byteLength > MAX_KEY_BYTES) {
25
+ throw new HooklatchError('invalid-secret', `Invalid ${label} signing secret.`);
26
+ }
27
+ return bytes;
28
+ },
29
+ parse(headers, rawBody) {
30
+ const signatureRaw = headers.get(headerNames.signature);
31
+ if (signatureRaw === undefined || signatureRaw.trim() === '') {
32
+ return failure('missing-signature', `No ${label} signature header was provided.`);
33
+ }
34
+ const signatures = [];
35
+ let unknownSchemes = 0;
36
+ for (const piece of signatureRaw.split(/\s+/)) {
37
+ if (piece === '')
38
+ continue;
39
+ const separator = piece.indexOf(',');
40
+ if (separator <= 0 || separator === piece.length - 1) {
41
+ return failure('malformed-signature', `The ${label} signature header is malformed.`);
42
+ }
43
+ const version = piece.slice(0, separator);
44
+ const value = piece.slice(separator + 1);
45
+ // HTTP comma-combined duplicate header values never form a valid token.
46
+ if (!isSchemeToken(version) || /[,\s]/.test(value)) {
47
+ return failure('malformed-signature', `The ${label} signature header is malformed.`);
48
+ }
49
+ if (version === SCHEME) {
50
+ const decoded = decodeBase64Signature(value);
51
+ // A malformed `v1` fails closed even when another `v1` value is valid.
52
+ if (decoded === null) {
53
+ return failure('malformed-signature', `The ${label} signature header is malformed.`);
54
+ }
55
+ signatures.push(decoded);
56
+ }
57
+ else {
58
+ unknownSchemes += 1;
59
+ }
60
+ }
61
+ if (signatures.length === 0) {
62
+ return unknownSchemes > 0
63
+ ? failure('unsupported-scheme', `No supported ${label} signature scheme was provided.`)
64
+ : failure('missing-signature', `No ${label} signature value was provided.`);
65
+ }
66
+ const id = headers.get(headerNames.id);
67
+ if (id === undefined || id === '') {
68
+ return failure('missing-identity', `No ${label} message id was provided.`);
69
+ }
70
+ if (id.includes('.') || id.includes(',')) {
71
+ return failure('malformed-signature', `The ${label} message id is malformed.`);
72
+ }
73
+ const timestampText = headers.get(headerNames.timestamp);
74
+ if (timestampText === undefined || timestampText === '') {
75
+ return failure('missing-timestamp', `No ${label} timestamp was provided.`);
76
+ }
77
+ if (!isCanonicalTimestamp(timestampText)) {
78
+ return failure('malformed-signature', `The ${label} timestamp is malformed.`);
79
+ }
80
+ const identity = {
81
+ deliveryId: null,
82
+ eventId: id,
83
+ timestamp: Number(timestampText),
84
+ authenticatedFields: ['eventId', 'timestamp'],
85
+ };
86
+ return {
87
+ ok: true,
88
+ signatures,
89
+ signedContent: concatBytes(utf8(`${id}.${timestampText}.`), rawBody),
90
+ identity,
91
+ };
92
+ },
93
+ };
94
+ }
95
+ //# sourceMappingURL=standard-webhooks-protocol.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"standard-webhooks-protocol.js","sourceRoot":"","sources":["../../src/providers/standard-webhooks-protocol.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Standard Webhooks v1: `webhook-id`, `webhook-timestamp`, and a
3
+ * whitespace-separated `webhook-signature` list of `v1,<base64>` tokens.
4
+ * The signature covers `${id}.${timestamp}.<raw body>`. The Ed25519
5
+ * `v1a` scheme is recognized but unsupported in this release.
6
+ */
7
+ export declare const standardWebhooksDescriptor: {
8
+ readonly provider: "standard-webhooks";
9
+ } & Pick<import("../internal/provider.js").ProviderDescriptor, "decodeSecret" | "parse">;
10
+ //# sourceMappingURL=standard-webhooks.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"standard-webhooks.d.ts","sourceRoot":"","sources":["../../src/providers/standard-webhooks.ts"],"names":[],"mappings":"AAEA;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B;;wFAQtC,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { createStandardWebhooksProtocol } from './standard-webhooks-protocol.js';
2
+ /**
3
+ * Standard Webhooks v1: `webhook-id`, `webhook-timestamp`, and a
4
+ * whitespace-separated `webhook-signature` list of `v1,<base64>` tokens.
5
+ * The signature covers `${id}.${timestamp}.<raw body>`. The Ed25519
6
+ * `v1a` scheme is recognized but unsupported in this release.
7
+ */
8
+ export const standardWebhooksDescriptor = createStandardWebhooksProtocol('standard-webhooks', 'Standard Webhooks', {
9
+ id: 'webhook-id',
10
+ timestamp: 'webhook-timestamp',
11
+ signature: 'webhook-signature',
12
+ });
13
+ //# sourceMappingURL=standard-webhooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"standard-webhooks.js","sourceRoot":"","sources":["../../src/providers/standard-webhooks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,8BAA8B,EAAE,MAAM,iCAAiC,CAAC;AAEjF;;;;;GAKG;AACH,MAAM,CAAC,MAAM,0BAA0B,GAAG,8BAA8B,CACtE,mBAAmB,EACnB,mBAAmB,EACnB;IACE,EAAE,EAAE,YAAY;IAChB,SAAS,EAAE,mBAAmB;IAC9B,SAAS,EAAE,mBAAmB;CAC/B,CACF,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { ProviderDescriptor } from '../internal/provider.js';
2
+ /**
3
+ * Stripe `Stripe-Signature` header: `t=<timestamp>,v1=<hex>[,v1=<hex>][,v0=...]`.
4
+ * Whitespace is permitted around comma-separated items. `t` is a singleton and
5
+ * is signed; repeated `t` is rejected. The signature covers `${t}.<raw body>`.
6
+ */
7
+ export declare const stripeDescriptor: ProviderDescriptor;
8
+ //# sourceMappingURL=stripe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stripe.d.ts","sourceRoot":"","sources":["../../src/providers/stripe.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAkC,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AAclG;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,EAAE,kBAgF9B,CAAC"}
@@ -0,0 +1,79 @@
1
+ import { concatBytes, utf8 } from '../internal/bytes.js';
2
+ import { decodeHexSignature, decodeLiteralSecret, failure, isCanonicalTimestamp, isSchemeToken, } from './shared.js';
3
+ const HEADER = 'stripe-signature';
4
+ const SCHEME = 'v1';
5
+ const TIMESTAMP_KEY = 't';
6
+ /**
7
+ * Stripe `Stripe-Signature` header: `t=<timestamp>,v1=<hex>[,v1=<hex>][,v0=...]`.
8
+ * Whitespace is permitted around comma-separated items. `t` is a singleton and
9
+ * is signed; repeated `t` is rejected. The signature covers `${t}.<raw body>`.
10
+ */
11
+ export const stripeDescriptor = {
12
+ provider: 'stripe',
13
+ decodeSecret(secret) {
14
+ // Stripe keys the HMAC with the literal secret string, including `whsec_`.
15
+ return decodeLiteralSecret(secret, 'Stripe');
16
+ },
17
+ parse(headers, rawBody) {
18
+ const raw = headers.get(HEADER);
19
+ if (raw === undefined || raw.trim() === '') {
20
+ return failure('missing-signature', 'No Stripe signature header was provided.');
21
+ }
22
+ const signatures = [];
23
+ let timestampText;
24
+ let unknownSchemes = 0;
25
+ for (const rawItem of raw.split(',')) {
26
+ const item = rawItem.trim();
27
+ const separator = item.indexOf('=');
28
+ if (item === '' || separator <= 0 || separator === item.length - 1) {
29
+ return failure('malformed-signature', 'The Stripe signature header is malformed.');
30
+ }
31
+ const key = item.slice(0, separator);
32
+ const value = item.slice(separator + 1);
33
+ if (key === TIMESTAMP_KEY) {
34
+ if (timestampText !== undefined) {
35
+ return failure('malformed-signature', 'The Stripe signature header is malformed.');
36
+ }
37
+ if (!isCanonicalTimestamp(value)) {
38
+ return failure('malformed-signature', 'The Stripe signature header is malformed.');
39
+ }
40
+ timestampText = value;
41
+ }
42
+ else if (key === SCHEME) {
43
+ const decoded = decodeHexSignature(value);
44
+ // A malformed `v1` fails closed even when another `v1` value is valid.
45
+ if (decoded === null) {
46
+ return failure('malformed-signature', 'The Stripe signature header is malformed.');
47
+ }
48
+ signatures.push(decoded);
49
+ }
50
+ else if (isSchemeToken(key)) {
51
+ unknownSchemes += 1;
52
+ }
53
+ else {
54
+ return failure('malformed-signature', 'The Stripe signature header is malformed.');
55
+ }
56
+ }
57
+ if (timestampText === undefined) {
58
+ return failure('missing-timestamp', 'No Stripe signature timestamp was provided.');
59
+ }
60
+ if (signatures.length === 0) {
61
+ return unknownSchemes > 0
62
+ ? failure('unsupported-scheme', 'No supported Stripe signature scheme was provided.')
63
+ : failure('missing-signature', 'No Stripe signature value was provided.');
64
+ }
65
+ const identity = {
66
+ deliveryId: null,
67
+ eventId: null,
68
+ timestamp: Number(timestampText),
69
+ authenticatedFields: ['timestamp'],
70
+ };
71
+ return {
72
+ ok: true,
73
+ signatures,
74
+ signedContent: concatBytes(utf8(`${timestampText}.`), rawBody),
75
+ identity,
76
+ };
77
+ },
78
+ };
79
+ //# sourceMappingURL=stripe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stripe.js","sourceRoot":"","sources":["../../src/providers/stripe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { ProviderDescriptor } from '../internal/provider.js';
2
+ /**
3
+ * Svix accepts the branded `svix-*` and canonical `webhook-*` Standard
4
+ * Webhooks header families. A single family is parsed with the existing
5
+ * signature -> identity -> timestamp ordering. When both families have any
6
+ * header present, both must be complete and value-identical; otherwise the
7
+ * request is malformed. A failed family is never rescued by the other one.
8
+ */
9
+ export declare const svixDescriptor: ProviderDescriptor;
10
+ //# sourceMappingURL=svix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svix.d.ts","sourceRoot":"","sources":["../../src/providers/svix.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkC,kBAAkB,EAAE,MAAM,yBAAyB,CAAC;AA0ClG;;;;;;GAMG;AACH,eAAO,MAAM,cAAc,EAAE,kBAyB5B,CAAC"}
@@ -0,0 +1,61 @@
1
+ import { failure } from './shared.js';
2
+ import { createStandardWebhooksProtocol } from './standard-webhooks-protocol.js';
3
+ const BRANDED_HEADERS = {
4
+ id: 'svix-id',
5
+ timestamp: 'svix-timestamp',
6
+ signature: 'svix-signature',
7
+ };
8
+ const CANONICAL_HEADERS = {
9
+ id: 'webhook-id',
10
+ timestamp: 'webhook-timestamp',
11
+ signature: 'webhook-signature',
12
+ };
13
+ const brandedDescriptor = createStandardWebhooksProtocol('svix', 'Svix', BRANDED_HEADERS);
14
+ const canonicalDescriptor = createStandardWebhooksProtocol('svix', 'Svix', CANONICAL_HEADERS);
15
+ function familyPresent(headers, names) {
16
+ return headers.has(names.id) || headers.has(names.timestamp) || headers.has(names.signature);
17
+ }
18
+ function familyComplete(headers, names) {
19
+ const id = headers.get(names.id);
20
+ const timestamp = headers.get(names.timestamp);
21
+ const signature = headers.get(names.signature);
22
+ return id !== undefined && id !== ''
23
+ && timestamp !== undefined && timestamp !== ''
24
+ && signature !== undefined && signature !== '';
25
+ }
26
+ function familiesEqual(headers) {
27
+ return familyComplete(headers, BRANDED_HEADERS)
28
+ && familyComplete(headers, CANONICAL_HEADERS)
29
+ && headers.get(BRANDED_HEADERS.id) === headers.get(CANONICAL_HEADERS.id)
30
+ && headers.get(BRANDED_HEADERS.timestamp) === headers.get(CANONICAL_HEADERS.timestamp)
31
+ && headers.get(BRANDED_HEADERS.signature) === headers.get(CANONICAL_HEADERS.signature);
32
+ }
33
+ /**
34
+ * Svix accepts the branded `svix-*` and canonical `webhook-*` Standard
35
+ * Webhooks header families. A single family is parsed with the existing
36
+ * signature -> identity -> timestamp ordering. When both families have any
37
+ * header present, both must be complete and value-identical; otherwise the
38
+ * request is malformed. A failed family is never rescued by the other one.
39
+ */
40
+ export const svixDescriptor = {
41
+ provider: 'svix',
42
+ decodeSecret(secret) {
43
+ return brandedDescriptor.decodeSecret(secret);
44
+ },
45
+ parse(headers, rawBody) {
46
+ const brandedPresent = familyPresent(headers, BRANDED_HEADERS);
47
+ const canonicalPresent = familyPresent(headers, CANONICAL_HEADERS);
48
+ if (brandedPresent && canonicalPresent) {
49
+ if (!familiesEqual(headers)) {
50
+ return failure('malformed-signature', 'The Svix signature headers are malformed.');
51
+ }
52
+ return brandedDescriptor.parse(headers, rawBody);
53
+ }
54
+ if (canonicalPresent)
55
+ return canonicalDescriptor.parse(headers, rawBody);
56
+ if (brandedPresent)
57
+ return brandedDescriptor.parse(headers, rawBody);
58
+ return failure('missing-signature', 'No Svix signature header was provided.');
59
+ },
60
+ };
61
+ //# sourceMappingURL=svix.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"svix.js","sourceRoot":"","sources":["../../src/providers/svix.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { NormalizedHeaders, ParseResult } from '../internal/provider.js';
2
+ /** Scoped x-vercel-signature webhook recipe; exact bytes and literal UTF-8 keys.
3
+ * https://vercel.com/docs/webhooks/webhooks-api
4
+ * Either hex case is accepted as receiver policy. No freshness is inferred.
5
+ */
6
+ export declare const vercelDescriptor: {
7
+ provider: "vercel";
8
+ crypto: {
9
+ kind: "hmac";
10
+ hash: "SHA-1";
11
+ signatureBytes: 20;
12
+ };
13
+ decodeSecret(secret: string): Uint8Array;
14
+ parse(headers: NormalizedHeaders, rawBody: Uint8Array): ParseResult;
15
+ };
16
+ //# sourceMappingURL=vercel.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vercel.d.ts","sourceRoot":"","sources":["../../src/providers/vercel.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAsB,MAAM,yBAAyB,CAAC;AAGlG;;;GAGG;AACH,eAAO,MAAM,gBAAgB;;;;;;;yBAIN,MAAM,GAAG,UAAU;mBAIzB,iBAAiB,WAAW,UAAU,GAAG,WAAW;CAkBvC,CAAC"}
@@ -0,0 +1,37 @@
1
+ import { decodeLiteralSecret, failure } from './shared.js';
2
+ /** Scoped x-vercel-signature webhook recipe; exact bytes and literal UTF-8 keys.
3
+ * https://vercel.com/docs/webhooks/webhooks-api
4
+ * Either hex case is accepted as receiver policy. No freshness is inferred.
5
+ */
6
+ export const vercelDescriptor = {
7
+ provider: 'vercel',
8
+ crypto: { kind: 'hmac', hash: 'SHA-1', signatureBytes: 20 },
9
+ decodeSecret(secret) {
10
+ return decodeLiteralSecret(secret, 'Vercel');
11
+ },
12
+ parse(headers, rawBody) {
13
+ const raw = headers.get('x-vercel-signature');
14
+ if (raw === undefined || raw.trim() === '') {
15
+ return failure('missing-signature', 'No Vercel signature header was provided.');
16
+ }
17
+ const signature = decodeSignature(raw);
18
+ if (signature === null) {
19
+ return failure('malformed-signature', 'The Vercel signature header is malformed.');
20
+ }
21
+ return {
22
+ ok: true, signatures: [signature], signedContent: rawBody,
23
+ identity: { deliveryId: null, eventId: null, timestamp: null, authenticatedFields: [] },
24
+ };
25
+ },
26
+ };
27
+ /** Deliberately private: the existing shared SHA256 decoder stays 32 bytes. */
28
+ function decodeSignature(value) {
29
+ if (!/^[a-fA-F0-9]{40}$/.test(value))
30
+ return null;
31
+ const bytes = new Uint8Array(20);
32
+ for (let index = 0; index < bytes.length; index++) {
33
+ bytes[index] = Number.parseInt(value.slice(index * 2, index * 2 + 2), 16);
34
+ }
35
+ return bytes;
36
+ }
37
+ //# sourceMappingURL=vercel.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vercel.js","sourceRoot":"","sources":["../../src/providers/vercel.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3D;;;GAGG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG;IAC9B,QAAQ,EAAE,QAAQ;IAClB,MAAM,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,cAAc,EAAE,EAAE,EAAE;IAE3D,YAAY,CAAC,MAAc;QACzB,OAAO,mBAAmB,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAC/C,CAAC;IAED,KAAK,CAAC,OAA0B,EAAE,OAAmB;QACnD,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;QAE9C,IAAI,GAAG,KAAK,SAAS,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;YAC3C,OAAO,OAAO,CAAC,mBAAmB,EAAE,0CAA0C,CAAC,CAAC;QAClF,CAAC;QAED,MAAM,SAAS,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;QAEvC,IAAI,SAAS,KAAK,IAAI,EAAE,CAAC;YACvB,OAAO,OAAO,CAAC,qBAAqB,EAAE,2CAA2C,CAAC,CAAC;QACrF,CAAC;QAED,OAAO;YACL,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,CAAC,SAAS,CAAC,EAAE,aAAa,EAAE,OAAO;YACzD,QAAQ,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,mBAAmB,EAAE,EAAE,EAAE;SACxF,CAAC;IACJ,CAAC;CAC2B,CAAC;AAE/B,+EAA+E;AAC/E,SAAS,eAAe,CAAC,KAAa;IACpC,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC;IAClD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,EAAE,CAAC,CAAC;IAEjC,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QAClD,KAAK,CAAC,KAAK,CAAC,GAAG,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC5E,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,33 @@
1
+ import type { NormalizedHeaders, ParseResult } from '../internal/provider.js';
2
+ /**
3
+ * WorkOS: `WorkOS-Signature: t=<unix milliseconds>, v1=<64 hex>`.
4
+ *
5
+ * The comma-separated field list is validated as a whole before required-field
6
+ * checks. Segments are trimmed only at their outer edges, so whitespace around
7
+ * `=` is rejected; field names are case-sensitive. `t` must appear exactly once
8
+ * and be a canonical nonnegative safe decimal integer in milliseconds (zero is
9
+ * allowed, leading zeros are not). Every `v1` must be a 32-byte hex digest in
10
+ * either case; repeated `v1` values form a Hooklatch rotation accept-set, but a
11
+ * malformed `v1` poisons the header. Unknown field names are validated as
12
+ * opaque values and then ignored.
13
+ *
14
+ * The HMAC-SHA256 covers UTF8(original `t` text + ".") concatenated with the
15
+ * exact raw body. The secret is the literal, untrimmed UTF-8 text; it is never
16
+ * Base64-decoded. Invalid-UTF-8 body handling is a Hooklatch byte-preservation
17
+ * policy, not claimed parity with SDKs that decode the body to a string.
18
+ * Identity is `timestamp = Number(t) / 1000`; freshness is enforced by core and
19
+ * is never evaluated here.
20
+ *
21
+ * This strict grammar, repeated-v1 accept-set, and millisecond identity are
22
+ * documented receiver policies, not claims of exact WorkOS SDK parity. No
23
+ * WorkOS-published signature vector is claimed; tests use synthetic anchors.
24
+ * Sources:
25
+ * - https://workos.com/docs/events/data-syncing/webhooks
26
+ * - https://raw.githubusercontent.com/workos/workos-node/ad8bff226e9b37435f0c62390318d4819f76b3d1/src/common/crypto/signature-provider.ts
27
+ */
28
+ export declare const workosDescriptor: {
29
+ provider: "workos";
30
+ decodeSecret(secret: string): Uint8Array;
31
+ parse(headers: NormalizedHeaders, rawBody: Uint8Array): ParseResult;
32
+ };
33
+ //# sourceMappingURL=workos.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workos.d.ts","sourceRoot":"","sources":["../../src/providers/workos.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,WAAW,EAAsB,MAAM,yBAAyB,CAAC;AAqBlG;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,gBAAgB;;yBAGN,MAAM,GAAG,UAAU;mBAIzB,iBAAiB,WAAW,UAAU,GAAG,WAAW;CA+F2B,CAAC"}
@@ -0,0 +1,118 @@
1
+ import { concatBytes, utf8 } from '../internal/bytes.js';
2
+ import { decodeHexSignature, decodeLiteralSecret, failure, isCanonicalTimestamp, isSchemeToken, } from './shared.js';
3
+ const SIGNATURE_HEADER = 'workos-signature';
4
+ const TIMESTAMP_KEY = 't';
5
+ const SIGNATURE_KEY = 'v1';
6
+ /**
7
+ * Opaque nonempty printable ASCII unknown-field value: no whitespace, commas,
8
+ * or additional equals signs. This is a bounded Hooklatch grammar, not a
9
+ * promise to support an unspecified future signature version.
10
+ */
11
+ const OPAQUE_VALUE = /^[\x21-\x2b\x2d-\x3c\x3e-\x7e]+$/;
12
+ /**
13
+ * WorkOS: `WorkOS-Signature: t=<unix milliseconds>, v1=<64 hex>`.
14
+ *
15
+ * The comma-separated field list is validated as a whole before required-field
16
+ * checks. Segments are trimmed only at their outer edges, so whitespace around
17
+ * `=` is rejected; field names are case-sensitive. `t` must appear exactly once
18
+ * and be a canonical nonnegative safe decimal integer in milliseconds (zero is
19
+ * allowed, leading zeros are not). Every `v1` must be a 32-byte hex digest in
20
+ * either case; repeated `v1` values form a Hooklatch rotation accept-set, but a
21
+ * malformed `v1` poisons the header. Unknown field names are validated as
22
+ * opaque values and then ignored.
23
+ *
24
+ * The HMAC-SHA256 covers UTF8(original `t` text + ".") concatenated with the
25
+ * exact raw body. The secret is the literal, untrimmed UTF-8 text; it is never
26
+ * Base64-decoded. Invalid-UTF-8 body handling is a Hooklatch byte-preservation
27
+ * policy, not claimed parity with SDKs that decode the body to a string.
28
+ * Identity is `timestamp = Number(t) / 1000`; freshness is enforced by core and
29
+ * is never evaluated here.
30
+ *
31
+ * This strict grammar, repeated-v1 accept-set, and millisecond identity are
32
+ * documented receiver policies, not claims of exact WorkOS SDK parity. No
33
+ * WorkOS-published signature vector is claimed; tests use synthetic anchors.
34
+ * Sources:
35
+ * - https://workos.com/docs/events/data-syncing/webhooks
36
+ * - https://raw.githubusercontent.com/workos/workos-node/ad8bff226e9b37435f0c62390318d4819f76b3d1/src/common/crypto/signature-provider.ts
37
+ */
38
+ export const workosDescriptor = {
39
+ provider: 'workos',
40
+ decodeSecret(secret) {
41
+ return decodeLiteralSecret(secret, 'WorkOS');
42
+ },
43
+ parse(headers, rawBody) {
44
+ const raw = headers.get(SIGNATURE_HEADER);
45
+ if (raw === undefined || raw.trim() === '') {
46
+ return failure('missing-signature', 'No WorkOS signature header was provided.');
47
+ }
48
+ const signatures = [];
49
+ let timestampText;
50
+ let timestampCount = 0;
51
+ let unknownFields = 0;
52
+ // Validate the complete structure before any required-field decision.
53
+ for (const rawSegment of raw.split(',')) {
54
+ const segment = rawSegment.trim();
55
+ if (segment === '') {
56
+ return failure('malformed-signature', 'The WorkOS signature header is malformed.');
57
+ }
58
+ // Reject missing keys, empty values, and extra equals signs.
59
+ const separator = segment.indexOf('=');
60
+ if (separator <= 0 || separator === segment.length - 1 || segment.indexOf('=', separator + 1) !== -1) {
61
+ return failure('malformed-signature', 'The WorkOS signature header is malformed.');
62
+ }
63
+ const key = segment.slice(0, separator);
64
+ const value = segment.slice(separator + 1);
65
+ if (!isSchemeToken(key)) {
66
+ return failure('malformed-signature', 'The WorkOS signature header is malformed.');
67
+ }
68
+ if (key === TIMESTAMP_KEY) {
69
+ timestampCount += 1;
70
+ // Duplicate timestamps fail even when the values agree.
71
+ if (timestampCount > 1) {
72
+ return failure('malformed-signature', 'The WorkOS signature header is malformed.');
73
+ }
74
+ if (!isCanonicalTimestamp(value)) {
75
+ return failure('malformed-signature', 'The WorkOS signature header is malformed.');
76
+ }
77
+ timestampText = value;
78
+ continue;
79
+ }
80
+ if (key === SIGNATURE_KEY) {
81
+ const decoded = decodeHexSignature(value);
82
+ // One malformed v1 poisons the whole header, even beside a valid v1.
83
+ if (decoded === null) {
84
+ return failure('malformed-signature', 'The WorkOS signature header is malformed.');
85
+ }
86
+ signatures.push(decoded);
87
+ continue;
88
+ }
89
+ // Unknown fields are structurally validated, then ignored.
90
+ if (!OPAQUE_VALUE.test(value)) {
91
+ return failure('malformed-signature', 'The WorkOS signature header is malformed.');
92
+ }
93
+ unknownFields += 1;
94
+ }
95
+ // Required-field checks run only after the whole structure validated.
96
+ if (signatures.length === 0) {
97
+ return unknownFields > 0
98
+ ? failure('unsupported-scheme', 'No supported WorkOS signature scheme was provided.')
99
+ : failure('missing-signature', 'No WorkOS signature value was provided.');
100
+ }
101
+ if (timestampText === undefined) {
102
+ return failure('missing-timestamp', 'No WorkOS timestamp was provided.');
103
+ }
104
+ const identity = {
105
+ deliveryId: null,
106
+ eventId: null,
107
+ timestamp: Number(timestampText) / 1000,
108
+ authenticatedFields: ['timestamp'],
109
+ };
110
+ return {
111
+ ok: true,
112
+ signatures,
113
+ signedContent: concatBytes(utf8(`${timestampText}.`), rawBody),
114
+ identity,
115
+ };
116
+ },
117
+ };
118
+ //# sourceMappingURL=workos.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"workos.js","sourceRoot":"","sources":["../../src/providers/workos.ts"],"names":[],"mappings":"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"}