mollie-api-typescript 1.4.0 → 1.5.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 (227) hide show
  1. package/README.md +57 -0
  2. package/dist/commonjs/funcs/mandatesList.js +1 -0
  3. package/dist/commonjs/funcs/mandatesList.js.map +1 -1
  4. package/dist/commonjs/index.d.ts +1 -0
  5. package/dist/commonjs/index.d.ts.map +1 -1
  6. package/dist/commonjs/index.js +1 -0
  7. package/dist/commonjs/index.js.map +1 -1
  8. package/dist/commonjs/lib/config.d.ts +2 -2
  9. package/dist/commonjs/lib/config.js +2 -2
  10. package/dist/commonjs/models/billingaddress.d.ts +2 -0
  11. package/dist/commonjs/models/billingaddress.d.ts.map +1 -1
  12. package/dist/commonjs/models/billingaddress.js.map +1 -1
  13. package/dist/commonjs/models/clientlinkrequest.d.ts +4 -0
  14. package/dist/commonjs/models/clientlinkrequest.d.ts.map +1 -1
  15. package/dist/commonjs/models/clientlinkrequest.js.map +1 -1
  16. package/dist/commonjs/models/customerresponse.d.ts +4 -0
  17. package/dist/commonjs/models/customerresponse.d.ts.map +1 -1
  18. package/dist/commonjs/models/customerresponse.js.map +1 -1
  19. package/dist/commonjs/models/entitycustomer.d.ts +4 -0
  20. package/dist/commonjs/models/entitycustomer.d.ts.map +1 -1
  21. package/dist/commonjs/models/entitycustomer.js.map +1 -1
  22. package/dist/commonjs/models/entityorganization.d.ts +4 -0
  23. package/dist/commonjs/models/entityorganization.d.ts.map +1 -1
  24. package/dist/commonjs/models/entityorganization.js.map +1 -1
  25. package/dist/commonjs/models/index.d.ts +1 -0
  26. package/dist/commonjs/models/index.d.ts.map +1 -1
  27. package/dist/commonjs/models/index.js +1 -0
  28. package/dist/commonjs/models/index.js.map +1 -1
  29. package/dist/commonjs/models/listcustomerresponse.d.ts +4 -0
  30. package/dist/commonjs/models/listcustomerresponse.d.ts.map +1 -1
  31. package/dist/commonjs/models/listcustomerresponse.js.map +1 -1
  32. package/dist/commonjs/models/listmandateresponse.d.ts +26 -0
  33. package/dist/commonjs/models/listmandateresponse.d.ts.map +1 -1
  34. package/dist/commonjs/models/listmandateresponse.js +15 -1
  35. package/dist/commonjs/models/listmandateresponse.js.map +1 -1
  36. package/dist/commonjs/models/listpaymentresponse.d.ts +5 -3
  37. package/dist/commonjs/models/listpaymentresponse.d.ts.map +1 -1
  38. package/dist/commonjs/models/listpaymentresponse.js.map +1 -1
  39. package/dist/commonjs/models/listprofileresponse.d.ts +4 -0
  40. package/dist/commonjs/models/listprofileresponse.d.ts.map +1 -1
  41. package/dist/commonjs/models/listprofileresponse.js.map +1 -1
  42. package/dist/commonjs/models/listsettlementpaymentresponse.d.ts +5 -3
  43. package/dist/commonjs/models/listsettlementpaymentresponse.d.ts.map +1 -1
  44. package/dist/commonjs/models/listsettlementpaymentresponse.js.map +1 -1
  45. package/dist/commonjs/models/mandateresponse.d.ts +26 -0
  46. package/dist/commonjs/models/mandateresponse.d.ts.map +1 -1
  47. package/dist/commonjs/models/mandateresponse.js +14 -1
  48. package/dist/commonjs/models/mandateresponse.js.map +1 -1
  49. package/dist/commonjs/models/mandatescopes.d.ts +22 -0
  50. package/dist/commonjs/models/mandatescopes.d.ts.map +1 -0
  51. package/dist/commonjs/models/mandatescopes.js +54 -0
  52. package/dist/commonjs/models/mandatescopes.js.map +1 -0
  53. package/dist/commonjs/models/operations/getcustomer.d.ts +4 -0
  54. package/dist/commonjs/models/operations/getcustomer.d.ts.map +1 -1
  55. package/dist/commonjs/models/operations/getcustomer.js.map +1 -1
  56. package/dist/commonjs/models/operations/listmandates.d.ts +5 -0
  57. package/dist/commonjs/models/operations/listmandates.d.ts.map +1 -1
  58. package/dist/commonjs/models/operations/listmandates.js +1 -0
  59. package/dist/commonjs/models/operations/listmandates.js.map +1 -1
  60. package/dist/commonjs/models/operations/submitonboardingdata.d.ts +4 -0
  61. package/dist/commonjs/models/operations/submitonboardingdata.d.ts.map +1 -1
  62. package/dist/commonjs/models/operations/submitonboardingdata.js.map +1 -1
  63. package/dist/commonjs/models/operations/updatecustomer.d.ts +4 -0
  64. package/dist/commonjs/models/operations/updatecustomer.d.ts.map +1 -1
  65. package/dist/commonjs/models/operations/updatecustomer.js.map +1 -1
  66. package/dist/commonjs/models/operations/updateprofile.d.ts +4 -0
  67. package/dist/commonjs/models/operations/updateprofile.d.ts.map +1 -1
  68. package/dist/commonjs/models/operations/updateprofile.js.map +1 -1
  69. package/dist/commonjs/models/paymentaddress.d.ts +2 -0
  70. package/dist/commonjs/models/paymentaddress.d.ts.map +1 -1
  71. package/dist/commonjs/models/paymentaddress.js.map +1 -1
  72. package/dist/commonjs/models/paymentrequest.d.ts +13 -3
  73. package/dist/commonjs/models/paymentrequest.d.ts.map +1 -1
  74. package/dist/commonjs/models/paymentrequest.js +1 -0
  75. package/dist/commonjs/models/paymentrequest.js.map +1 -1
  76. package/dist/commonjs/models/paymentresponse.d.ts +5 -3
  77. package/dist/commonjs/models/paymentresponse.d.ts.map +1 -1
  78. package/dist/commonjs/models/paymentresponse.js.map +1 -1
  79. package/dist/commonjs/models/profilerequest.d.ts +4 -0
  80. package/dist/commonjs/models/profilerequest.d.ts.map +1 -1
  81. package/dist/commonjs/models/profilerequest.js.map +1 -1
  82. package/dist/commonjs/models/profileresponse.d.ts +4 -0
  83. package/dist/commonjs/models/profileresponse.d.ts.map +1 -1
  84. package/dist/commonjs/models/profileresponse.js.map +1 -1
  85. package/dist/commonjs/models/salesinvoicerecipient.d.ts +4 -0
  86. package/dist/commonjs/models/salesinvoicerecipient.d.ts.map +1 -1
  87. package/dist/commonjs/models/salesinvoicerecipient.js.map +1 -1
  88. package/dist/commonjs/models/salesinvoicerecipientresponse.d.ts +4 -0
  89. package/dist/commonjs/models/salesinvoicerecipientresponse.d.ts.map +1 -1
  90. package/dist/commonjs/models/salesinvoicerecipientresponse.js.map +1 -1
  91. package/dist/commonjs/utils/webhooks/index.d.ts +2 -0
  92. package/dist/commonjs/utils/webhooks/index.d.ts.map +1 -0
  93. package/dist/commonjs/utils/webhooks/index.js +7 -0
  94. package/dist/commonjs/utils/webhooks/index.js.map +1 -0
  95. package/dist/commonjs/utils/webhooks/signature_validator.d.ts +17 -0
  96. package/dist/commonjs/utils/webhooks/signature_validator.d.ts.map +1 -0
  97. package/dist/commonjs/utils/webhooks/signature_validator.js +88 -0
  98. package/dist/commonjs/utils/webhooks/signature_validator.js.map +1 -0
  99. package/dist/esm/funcs/mandatesList.js +1 -0
  100. package/dist/esm/funcs/mandatesList.js.map +1 -1
  101. package/dist/esm/index.d.ts +1 -0
  102. package/dist/esm/index.d.ts.map +1 -1
  103. package/dist/esm/index.js +1 -0
  104. package/dist/esm/index.js.map +1 -1
  105. package/dist/esm/lib/config.d.ts +2 -2
  106. package/dist/esm/lib/config.js +2 -2
  107. package/dist/esm/models/billingaddress.d.ts +2 -0
  108. package/dist/esm/models/billingaddress.d.ts.map +1 -1
  109. package/dist/esm/models/billingaddress.js.map +1 -1
  110. package/dist/esm/models/clientlinkrequest.d.ts +4 -0
  111. package/dist/esm/models/clientlinkrequest.d.ts.map +1 -1
  112. package/dist/esm/models/clientlinkrequest.js.map +1 -1
  113. package/dist/esm/models/customerresponse.d.ts +4 -0
  114. package/dist/esm/models/customerresponse.d.ts.map +1 -1
  115. package/dist/esm/models/customerresponse.js.map +1 -1
  116. package/dist/esm/models/entitycustomer.d.ts +4 -0
  117. package/dist/esm/models/entitycustomer.d.ts.map +1 -1
  118. package/dist/esm/models/entitycustomer.js.map +1 -1
  119. package/dist/esm/models/entityorganization.d.ts +4 -0
  120. package/dist/esm/models/entityorganization.d.ts.map +1 -1
  121. package/dist/esm/models/entityorganization.js.map +1 -1
  122. package/dist/esm/models/index.d.ts +1 -0
  123. package/dist/esm/models/index.d.ts.map +1 -1
  124. package/dist/esm/models/index.js +1 -0
  125. package/dist/esm/models/index.js.map +1 -1
  126. package/dist/esm/models/listcustomerresponse.d.ts +4 -0
  127. package/dist/esm/models/listcustomerresponse.d.ts.map +1 -1
  128. package/dist/esm/models/listcustomerresponse.js.map +1 -1
  129. package/dist/esm/models/listmandateresponse.d.ts +26 -0
  130. package/dist/esm/models/listmandateresponse.d.ts.map +1 -1
  131. package/dist/esm/models/listmandateresponse.js +14 -0
  132. package/dist/esm/models/listmandateresponse.js.map +1 -1
  133. package/dist/esm/models/listpaymentresponse.d.ts +5 -3
  134. package/dist/esm/models/listpaymentresponse.d.ts.map +1 -1
  135. package/dist/esm/models/listpaymentresponse.js.map +1 -1
  136. package/dist/esm/models/listprofileresponse.d.ts +4 -0
  137. package/dist/esm/models/listprofileresponse.d.ts.map +1 -1
  138. package/dist/esm/models/listprofileresponse.js.map +1 -1
  139. package/dist/esm/models/listsettlementpaymentresponse.d.ts +5 -3
  140. package/dist/esm/models/listsettlementpaymentresponse.d.ts.map +1 -1
  141. package/dist/esm/models/listsettlementpaymentresponse.js.map +1 -1
  142. package/dist/esm/models/mandateresponse.d.ts +26 -0
  143. package/dist/esm/models/mandateresponse.d.ts.map +1 -1
  144. package/dist/esm/models/mandateresponse.js +13 -0
  145. package/dist/esm/models/mandateresponse.js.map +1 -1
  146. package/dist/esm/models/mandatescopes.d.ts +22 -0
  147. package/dist/esm/models/mandatescopes.d.ts.map +1 -0
  148. package/dist/esm/models/mandatescopes.js +18 -0
  149. package/dist/esm/models/mandatescopes.js.map +1 -0
  150. package/dist/esm/models/operations/getcustomer.d.ts +4 -0
  151. package/dist/esm/models/operations/getcustomer.d.ts.map +1 -1
  152. package/dist/esm/models/operations/getcustomer.js.map +1 -1
  153. package/dist/esm/models/operations/listmandates.d.ts +5 -0
  154. package/dist/esm/models/operations/listmandates.d.ts.map +1 -1
  155. package/dist/esm/models/operations/listmandates.js +1 -0
  156. package/dist/esm/models/operations/listmandates.js.map +1 -1
  157. package/dist/esm/models/operations/submitonboardingdata.d.ts +4 -0
  158. package/dist/esm/models/operations/submitonboardingdata.d.ts.map +1 -1
  159. package/dist/esm/models/operations/submitonboardingdata.js.map +1 -1
  160. package/dist/esm/models/operations/updatecustomer.d.ts +4 -0
  161. package/dist/esm/models/operations/updatecustomer.d.ts.map +1 -1
  162. package/dist/esm/models/operations/updatecustomer.js.map +1 -1
  163. package/dist/esm/models/operations/updateprofile.d.ts +4 -0
  164. package/dist/esm/models/operations/updateprofile.d.ts.map +1 -1
  165. package/dist/esm/models/operations/updateprofile.js.map +1 -1
  166. package/dist/esm/models/paymentaddress.d.ts +2 -0
  167. package/dist/esm/models/paymentaddress.d.ts.map +1 -1
  168. package/dist/esm/models/paymentaddress.js.map +1 -1
  169. package/dist/esm/models/paymentrequest.d.ts +13 -3
  170. package/dist/esm/models/paymentrequest.d.ts.map +1 -1
  171. package/dist/esm/models/paymentrequest.js +1 -0
  172. package/dist/esm/models/paymentrequest.js.map +1 -1
  173. package/dist/esm/models/paymentresponse.d.ts +5 -3
  174. package/dist/esm/models/paymentresponse.d.ts.map +1 -1
  175. package/dist/esm/models/paymentresponse.js.map +1 -1
  176. package/dist/esm/models/profilerequest.d.ts +4 -0
  177. package/dist/esm/models/profilerequest.d.ts.map +1 -1
  178. package/dist/esm/models/profilerequest.js.map +1 -1
  179. package/dist/esm/models/profileresponse.d.ts +4 -0
  180. package/dist/esm/models/profileresponse.d.ts.map +1 -1
  181. package/dist/esm/models/profileresponse.js.map +1 -1
  182. package/dist/esm/models/salesinvoicerecipient.d.ts +4 -0
  183. package/dist/esm/models/salesinvoicerecipient.d.ts.map +1 -1
  184. package/dist/esm/models/salesinvoicerecipient.js.map +1 -1
  185. package/dist/esm/models/salesinvoicerecipientresponse.d.ts +4 -0
  186. package/dist/esm/models/salesinvoicerecipientresponse.d.ts.map +1 -1
  187. package/dist/esm/models/salesinvoicerecipientresponse.js.map +1 -1
  188. package/dist/esm/utils/webhooks/index.d.ts +2 -0
  189. package/dist/esm/utils/webhooks/index.d.ts.map +1 -0
  190. package/dist/esm/utils/webhooks/index.js +2 -0
  191. package/dist/esm/utils/webhooks/index.js.map +1 -0
  192. package/dist/esm/utils/webhooks/signature_validator.d.ts +17 -0
  193. package/dist/esm/utils/webhooks/signature_validator.d.ts.map +1 -0
  194. package/dist/esm/utils/webhooks/signature_validator.js +83 -0
  195. package/dist/esm/utils/webhooks/signature_validator.js.map +1 -0
  196. package/jsr.json +1 -1
  197. package/package.json +1 -1
  198. package/src/funcs/mandatesList.ts +1 -0
  199. package/src/index.ts +1 -0
  200. package/src/lib/config.ts +2 -2
  201. package/src/models/billingaddress.ts +2 -0
  202. package/src/models/clientlinkrequest.ts +4 -0
  203. package/src/models/customerresponse.ts +4 -0
  204. package/src/models/entitycustomer.ts +4 -0
  205. package/src/models/entityorganization.ts +4 -0
  206. package/src/models/index.ts +1 -0
  207. package/src/models/listcustomerresponse.ts +4 -0
  208. package/src/models/listmandateresponse.ts +36 -0
  209. package/src/models/listpaymentresponse.ts +5 -3
  210. package/src/models/listprofileresponse.ts +4 -0
  211. package/src/models/listsettlementpaymentresponse.ts +5 -3
  212. package/src/models/mandateresponse.ts +33 -0
  213. package/src/models/mandatescopes.ts +30 -0
  214. package/src/models/operations/getcustomer.ts +4 -0
  215. package/src/models/operations/listmandates.ts +6 -0
  216. package/src/models/operations/submitonboardingdata.ts +4 -0
  217. package/src/models/operations/updatecustomer.ts +4 -0
  218. package/src/models/operations/updateprofile.ts +4 -0
  219. package/src/models/paymentaddress.ts +2 -0
  220. package/src/models/paymentrequest.ts +14 -3
  221. package/src/models/paymentresponse.ts +5 -3
  222. package/src/models/profilerequest.ts +4 -0
  223. package/src/models/profileresponse.ts +4 -0
  224. package/src/models/salesinvoicerecipient.ts +4 -0
  225. package/src/models/salesinvoicerecipientresponse.ts +4 -0
  226. package/src/utils/webhooks/index.ts +4 -0
  227. package/src/utils/webhooks/signature_validator.ts +136 -0
@@ -23,6 +23,10 @@ export type UpdateProfileRequestBody = {
23
23
  website?: string | null | undefined;
24
24
  /**
25
25
  * The email address associated with the profile's trade name or brand.
26
+ *
27
+ * @remarks
28
+ *
29
+ * If the domain contains non-ASCII characters, encode it as Punycode per [RFC 3492](https://www.rfc-editor.org/rfc/rfc3492).
26
30
  */
27
31
  email?: string | null | undefined;
28
32
  /**
@@ -64,6 +64,8 @@ export type PaymentAddress = {
64
64
  * email upon payment creation. The language of the email will follow the locale parameter of the payment.
65
65
  *
66
66
  * Required for payment methods `billie`, `in3`, `klarna` and `riverty`.
67
+ *
68
+ * If the domain contains non-ASCII characters, encode it as Punycode per [RFC 3492](https://www.rfc-editor.org/rfc/rfc3492).
67
69
  */
68
70
  email?: string | undefined;
69
71
  /**
@@ -176,6 +176,8 @@ export type PaymentRequestBillingAddress = {
176
176
  * email upon payment creation. The language of the email will follow the locale parameter of the payment.
177
177
  *
178
178
  * Required for payment methods `billie`, `in3`, `klarna` and `riverty`.
179
+ *
180
+ * If the domain contains non-ASCII characters, encode it as Punycode per [RFC 3492](https://www.rfc-editor.org/rfc/rfc3492).
179
181
  */
180
182
  email?: string | undefined;
181
183
  /**
@@ -443,12 +445,12 @@ export type PaymentRequest = {
443
445
  routing?: Array<EntityPaymentRoute> | null | undefined;
444
446
  sequenceType?: SequenceType | undefined;
445
447
  /**
446
- * **Only relevant for recurring payments.**
448
+ * **Only relevant for recurring payments and stored cards.**
447
449
  *
448
450
  * @remarks
449
451
  *
450
- * When creating recurring payments, the ID of a specific [mandate](get-mandate) can be supplied to indicate which of
451
- * the customer's accounts should be credited.
452
+ * When creating recurring or stored cards payments, the ID of a specific [mandate](get-mandate) can be supplied to indicate which of
453
+ * the customer's accounts should be debited.
452
454
  */
453
455
  mandateId?: string | null | undefined;
454
456
  customerId?: string | undefined;
@@ -466,6 +468,13 @@ export type PaymentRequest = {
466
468
  * The date by which the payment should be completed in `YYYY-MM-DD` format
467
469
  */
468
470
  dueDate?: string | undefined;
471
+ /**
472
+ * Whether the card details should be stored for the customer after a successful payment. This will create a mandate for the customer,
473
+ *
474
+ * @remarks
475
+ * allowing for future customer present saved-card CIT payments. Requires customerId, cardToken, and the creditcard method to be specified.
476
+ */
477
+ storeCredentials?: boolean | undefined;
469
478
  /**
470
479
  * Whether to create the entity in test mode or live mode.
471
480
  *
@@ -738,6 +747,7 @@ export type PaymentRequest$Outbound = {
738
747
  customerId?: string | undefined;
739
748
  profileId?: string | undefined;
740
749
  dueDate?: string | undefined;
750
+ storeCredentials?: boolean | undefined;
741
751
  testmode?: boolean | null | undefined;
742
752
  applePayPaymentToken?: string | undefined;
743
753
  company?: Company$Outbound | undefined;
@@ -789,6 +799,7 @@ export const PaymentRequest$outboundSchema: z.ZodType<
789
799
  customerId: z.string().optional(),
790
800
  profileId: z.string().optional(),
791
801
  dueDate: z.string().optional(),
802
+ storeCredentials: z.boolean().optional(),
792
803
  testmode: z.nullable(z.boolean()).optional(),
793
804
  applePayPaymentToken: z.string().optional(),
794
805
  company: z.lazy(() => Company$outboundSchema).optional(),
@@ -321,6 +321,8 @@ export type PaymentResponseBillingAddress = {
321
321
  * email upon payment creation. The language of the email will follow the locale parameter of the payment.
322
322
  *
323
323
  * Required for payment methods `billie`, `in3`, `klarna` and `riverty`.
324
+ *
325
+ * If the domain contains non-ASCII characters, encode it as Punycode per [RFC 3492](https://www.rfc-editor.org/rfc/rfc3492).
324
326
  */
325
327
  email?: string | undefined;
326
328
  /**
@@ -1042,12 +1044,12 @@ export type PaymentResponse = {
1042
1044
  */
1043
1045
  subscriptionId?: string | null | undefined;
1044
1046
  /**
1045
- * **Only relevant for recurring payments.**
1047
+ * **Only relevant for recurring payments and stored cards.**
1046
1048
  *
1047
1049
  * @remarks
1048
1050
  *
1049
- * When creating recurring payments, the ID of a specific [mandate](get-mandate) can be supplied to indicate which of
1050
- * the customer's accounts should be credited.
1051
+ * When creating recurring or stored cards payments, the ID of a specific [mandate](get-mandate) can be supplied to indicate which of
1052
+ * the customer's accounts should be debited.
1051
1053
  */
1052
1054
  mandateId?: string | null | undefined;
1053
1055
  customerId?: string | undefined;
@@ -22,6 +22,10 @@ export type ProfileRequest = {
22
22
  website: string;
23
23
  /**
24
24
  * The email address associated with the profile's trade name or brand.
25
+ *
26
+ * @remarks
27
+ *
28
+ * If the domain contains non-ASCII characters, encode it as Punycode per [RFC 3492](https://www.rfc-editor.org/rfc/rfc3492).
25
29
  */
26
30
  email: string;
27
31
  /**
@@ -123,6 +123,10 @@ export type ProfileResponse = {
123
123
  website: string;
124
124
  /**
125
125
  * The email address associated with the profile's trade name or brand.
126
+ *
127
+ * @remarks
128
+ *
129
+ * If the domain contains non-ASCII characters, encode it as Punycode per [RFC 3492](https://www.rfc-editor.org/rfc/rfc3492).
126
130
  */
127
131
  email: string;
128
132
  /**
@@ -59,6 +59,10 @@ export type SalesInvoiceRecipient = {
59
59
  vatNumber?: string | null | undefined;
60
60
  /**
61
61
  * The email address of the recipient.
62
+ *
63
+ * @remarks
64
+ *
65
+ * If the domain contains non-ASCII characters, encode it as Punycode per [RFC 3492](https://www.rfc-editor.org/rfc/rfc3492).
62
66
  */
63
67
  email: string;
64
68
  /**
@@ -62,6 +62,10 @@ export type SalesInvoiceRecipientResponse = {
62
62
  vatNumber?: string | null | undefined;
63
63
  /**
64
64
  * The email address of the recipient.
65
+ *
66
+ * @remarks
67
+ *
68
+ * If the domain contains non-ASCII characters, encode it as Punycode per [RFC 3492](https://www.rfc-editor.org/rfc/rfc3492).
65
69
  */
66
70
  email: string;
67
71
  /**
@@ -0,0 +1,4 @@
1
+ export {
2
+ InvalidSignatureException,
3
+ SignatureValidator,
4
+ } from "./signature_validator.js";
@@ -0,0 +1,136 @@
1
+ export class InvalidSignatureException extends Error {
2
+ constructor(message: string) {
3
+ super(message);
4
+ this.name = "InvalidSignatureException";
5
+
6
+ Object.setPrototypeOf(this, InvalidSignatureException.prototype);
7
+ }
8
+ }
9
+
10
+ export class SignatureValidator {
11
+ static readonly SIGNATURE_HEADER = "X-Mollie-Signature";
12
+ private static readonly SIGNATURE_PREFIX = "sha256=";
13
+
14
+ private readonly signingSecrets: string[];
15
+
16
+ constructor(signingSecrets: string | string[]) {
17
+ this.signingSecrets = Array.isArray(signingSecrets)
18
+ ? [...signingSecrets]
19
+ : [signingSecrets];
20
+ }
21
+
22
+ static async validate(
23
+ payload: string,
24
+ signingSecrets: string | string[],
25
+ signatures?: string | string[] | null,
26
+ ): Promise<boolean> {
27
+ return new SignatureValidator(signingSecrets).validatePayload(
28
+ payload,
29
+ signatures,
30
+ );
31
+ }
32
+
33
+ async validatePayload(
34
+ payload: string,
35
+ signatures?: string | string[] | null,
36
+ ): Promise<boolean> {
37
+ const signatureList = this.normalizeSignatures(signatures);
38
+
39
+ if (signatureList.length === 0) {
40
+ return false;
41
+ }
42
+
43
+ return this.validateSignatures(payload, signatureList);
44
+ }
45
+
46
+ private normalizeSignatures(
47
+ signatures?: string | string[] | null,
48
+ ): string[] {
49
+ if (typeof signatures === "string") {
50
+ return signatures ? [signatures] : [];
51
+ }
52
+
53
+ if (!signatures) {
54
+ return [];
55
+ }
56
+
57
+ return signatures.filter((signature): signature is string => !!signature);
58
+ }
59
+
60
+ private async validateSignatures(
61
+ payload: string,
62
+ signatures: string[],
63
+ ): Promise<boolean> {
64
+ for (const signature of signatures) {
65
+ const extractedSignature = this.extractSignature(signature);
66
+
67
+ if (await this.isValidSignature(extractedSignature, payload)) {
68
+ return true;
69
+ }
70
+ }
71
+
72
+ throw new InvalidSignatureException("Invalid webhook signature");
73
+ }
74
+
75
+ private extractSignature(signatureHeader: string): string {
76
+ if (signatureHeader.startsWith(SignatureValidator.SIGNATURE_PREFIX)) {
77
+ return signatureHeader.slice(SignatureValidator.SIGNATURE_PREFIX.length);
78
+ }
79
+
80
+ return signatureHeader;
81
+ }
82
+
83
+ private async isValidSignature(
84
+ providedSignature: string,
85
+ payload: string,
86
+ ): Promise<boolean> {
87
+ for (const secret of this.signingSecrets) {
88
+ const expectedSignature = await SignatureValidator.createSignature(
89
+ payload,
90
+ secret,
91
+ );
92
+
93
+ if (constantTimeEquals(expectedSignature, providedSignature)) {
94
+ return true;
95
+ }
96
+ }
97
+
98
+ return false;
99
+ }
100
+
101
+ static async createSignature(payload: string, secret: string): Promise<string> {
102
+ const subtle = globalThis.crypto?.subtle;
103
+ if (!subtle) {
104
+ throw new Error("Web Crypto API is not available in this runtime");
105
+ }
106
+
107
+ const encoder = new TextEncoder();
108
+ const key = await subtle.importKey(
109
+ "raw",
110
+ encoder.encode(secret),
111
+ { name: "HMAC", hash: "SHA-256" },
112
+ false,
113
+ ["sign"],
114
+ );
115
+ const signature = await subtle.sign("HMAC", key, encoder.encode(payload));
116
+
117
+ return toHex(signature);
118
+ }
119
+ }
120
+
121
+ function constantTimeEquals(left: string, right: string): boolean {
122
+ const maxLength = Math.max(left.length, right.length);
123
+ let mismatch = left.length ^ right.length;
124
+
125
+ for (let index = 0; index < maxLength; index++) {
126
+ mismatch |= (left.charCodeAt(index) || 0) ^ (right.charCodeAt(index) || 0);
127
+ }
128
+
129
+ return mismatch === 0;
130
+ }
131
+
132
+ function toHex(buffer: ArrayBuffer): string {
133
+ return Array.from(new Uint8Array(buffer))
134
+ .map((value) => value.toString(16).padStart(2, "0"))
135
+ .join("");
136
+ }