@techelusive/nest-auth 0.0.0-stage → 0.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (340) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/LICENSE +21 -0
  3. package/README.md +204 -2
  4. package/api/openapi.json +4399 -0
  5. package/api/techelusive-authentication.postman_collection.json +3178 -0
  6. package/dist/auth-options.d.ts +156 -0
  7. package/dist/auth-options.js +3 -0
  8. package/dist/auth-options.js.map +1 -0
  9. package/dist/auth-options.validation.d.ts +9 -0
  10. package/dist/auth-options.validation.js +74 -0
  11. package/dist/auth-options.validation.js.map +1 -0
  12. package/dist/auth.module.d.ts +38 -0
  13. package/dist/auth.module.js +173 -0
  14. package/dist/auth.module.js.map +1 -0
  15. package/dist/common/auth-error.d.ts +16 -0
  16. package/dist/common/auth-error.js +23 -0
  17. package/dist/common/auth-error.js.map +1 -0
  18. package/dist/common/auth-exception.filter.d.ts +24 -0
  19. package/dist/common/auth-exception.filter.js +66 -0
  20. package/dist/common/auth-exception.filter.js.map +1 -0
  21. package/dist/common/crypto/jwt.d.ts +89 -0
  22. package/dist/common/crypto/jwt.js +144 -0
  23. package/dist/common/crypto/jwt.js.map +1 -0
  24. package/dist/common/crypto/random-secrets.d.ts +78 -0
  25. package/dist/common/crypto/random-secrets.js +113 -0
  26. package/dist/common/crypto/random-secrets.js.map +1 -0
  27. package/dist/common/crypto/remote-public-keys.d.ts +49 -0
  28. package/dist/common/crypto/remote-public-keys.js +105 -0
  29. package/dist/common/crypto/remote-public-keys.js.map +1 -0
  30. package/dist/common/crypto/totp.d.ts +68 -0
  31. package/dist/common/crypto/totp.js +148 -0
  32. package/dist/common/crypto/totp.js.map +1 -0
  33. package/dist/common/encryption.service.d.ts +36 -0
  34. package/dist/common/encryption.service.js +111 -0
  35. package/dist/common/encryption.service.js.map +1 -0
  36. package/dist/common/identifiers.d.ts +48 -0
  37. package/dist/common/identifiers.js +89 -0
  38. package/dist/common/identifiers.js.map +1 -0
  39. package/dist/common/network-safety.d.ts +19 -0
  40. package/dist/common/network-safety.js +72 -0
  41. package/dist/common/network-safety.js.map +1 -0
  42. package/dist/common/rate-limiter.service.d.ts +63 -0
  43. package/dist/common/rate-limiter.service.js +158 -0
  44. package/dist/common/rate-limiter.service.js.map +1 -0
  45. package/dist/common/refresh-token-cookie.d.ts +78 -0
  46. package/dist/common/refresh-token-cookie.js +185 -0
  47. package/dist/common/refresh-token-cookie.js.map +1 -0
  48. package/dist/common/request-context.d.ts +14 -0
  49. package/dist/common/request-context.js +22 -0
  50. package/dist/common/request-context.js.map +1 -0
  51. package/dist/common/strict-validation.pipe.d.ts +8 -0
  52. package/dist/common/strict-validation.pipe.js +16 -0
  53. package/dist/common/strict-validation.pipe.js.map +1 -0
  54. package/dist/common/time.d.ts +15 -0
  55. package/dist/common/time.js +34 -0
  56. package/dist/common/time.js.map +1 -0
  57. package/dist/constants.d.ts +1326 -0
  58. package/dist/constants.js +1142 -0
  59. package/dist/constants.js.map +1 -0
  60. package/dist/database/create-auth-tables.migration.d.ts +26 -0
  61. package/dist/database/create-auth-tables.migration.js +291 -0
  62. package/dist/database/create-auth-tables.migration.js.map +1 -0
  63. package/dist/database/email-change-and-retention.migration.d.ts +25 -0
  64. package/dist/database/email-change-and-retention.migration.js +54 -0
  65. package/dist/database/email-change-and-retention.migration.js.map +1 -0
  66. package/dist/database/entities/api-key.entity.d.ts +17 -0
  67. package/dist/database/entities/api-key.entity.js +80 -0
  68. package/dist/database/entities/api-key.entity.js.map +1 -0
  69. package/dist/database/entities/audit-log.entity.d.ts +13 -0
  70. package/dist/database/entities/audit-log.entity.js +64 -0
  71. package/dist/database/entities/audit-log.entity.js.map +1 -0
  72. package/dist/database/entities/backup-code.entity.d.ts +9 -0
  73. package/dist/database/entities/backup-code.entity.js +52 -0
  74. package/dist/database/entities/backup-code.entity.js.map +1 -0
  75. package/dist/database/entities/index.d.ts +43 -0
  76. package/dist/database/entities/index.js +82 -0
  77. package/dist/database/entities/index.js.map +1 -0
  78. package/dist/database/entities/json-object.d.ts +12 -0
  79. package/dist/database/entities/json-object.js +3 -0
  80. package/dist/database/entities/json-object.js.map +1 -0
  81. package/dist/database/entities/link-token.entity.d.ts +15 -0
  82. package/dist/database/entities/link-token.entity.js +64 -0
  83. package/dist/database/entities/link-token.entity.js.map +1 -0
  84. package/dist/database/entities/one-time-code.entity.d.ts +16 -0
  85. package/dist/database/entities/one-time-code.entity.js +69 -0
  86. package/dist/database/entities/one-time-code.entity.js.map +1 -0
  87. package/dist/database/entities/organization-invitation.entity.d.ts +14 -0
  88. package/dist/database/entities/organization-invitation.entity.js +73 -0
  89. package/dist/database/entities/organization-invitation.entity.js.map +1 -0
  90. package/dist/database/entities/organization-member.entity.d.ts +9 -0
  91. package/dist/database/entities/organization-member.entity.js +48 -0
  92. package/dist/database/entities/organization-member.entity.js.map +1 -0
  93. package/dist/database/entities/organization.entity.d.ts +12 -0
  94. package/dist/database/entities/organization.entity.js +58 -0
  95. package/dist/database/entities/organization.entity.js.map +1 -0
  96. package/dist/database/entities/passkey.entity.d.ts +19 -0
  97. package/dist/database/entities/passkey.entity.js +78 -0
  98. package/dist/database/entities/passkey.entity.js.map +1 -0
  99. package/dist/database/entities/password.entity.d.ts +6 -0
  100. package/dist/database/entities/password.entity.js +36 -0
  101. package/dist/database/entities/password.entity.js.map +1 -0
  102. package/dist/database/entities/refresh-token.entity.d.ts +9 -0
  103. package/dist/database/entities/refresh-token.entity.js +53 -0
  104. package/dist/database/entities/refresh-token.entity.js.map +1 -0
  105. package/dist/database/entities/session.entity.d.ts +20 -0
  106. package/dist/database/entities/session.entity.js +87 -0
  107. package/dist/database/entities/session.entity.js.map +1 -0
  108. package/dist/database/entities/settings.entity.d.ts +7 -0
  109. package/dist/database/entities/settings.entity.js +41 -0
  110. package/dist/database/entities/settings.entity.js.map +1 -0
  111. package/dist/database/entities/sign-in-challenge.entity.d.ts +23 -0
  112. package/dist/database/entities/sign-in-challenge.entity.js +80 -0
  113. package/dist/database/entities/sign-in-challenge.entity.js.map +1 -0
  114. package/dist/database/entities/signing-key.entity.d.ts +11 -0
  115. package/dist/database/entities/signing-key.entity.js +54 -0
  116. package/dist/database/entities/signing-key.entity.js.map +1 -0
  117. package/dist/database/entities/social-account.entity.d.ts +13 -0
  118. package/dist/database/entities/social-account.entity.js +54 -0
  119. package/dist/database/entities/social-account.entity.js.map +1 -0
  120. package/dist/database/entities/two-factor-secret.entity.d.ts +10 -0
  121. package/dist/database/entities/two-factor-secret.entity.js +48 -0
  122. package/dist/database/entities/two-factor-secret.entity.js.map +1 -0
  123. package/dist/database/entities/user.entity.d.ts +34 -0
  124. package/dist/database/entities/user.entity.js +129 -0
  125. package/dist/database/entities/user.entity.js.map +1 -0
  126. package/dist/database/entities/webhook-delivery.entity.d.ts +17 -0
  127. package/dist/database/entities/webhook-delivery.entity.js +79 -0
  128. package/dist/database/entities/webhook-delivery.entity.js.map +1 -0
  129. package/dist/database/entities/webhook.entity.d.ts +12 -0
  130. package/dist/database/entities/webhook.entity.js +58 -0
  131. package/dist/database/entities/webhook.entity.js.map +1 -0
  132. package/dist/database/typeorm-row.d.ts +21 -0
  133. package/dist/database/typeorm-row.js +29 -0
  134. package/dist/database/typeorm-row.js.map +1 -0
  135. package/dist/features/account/account.controller.d.ts +259 -0
  136. package/dist/features/account/account.controller.js +372 -0
  137. package/dist/features/account/account.controller.js.map +1 -0
  138. package/dist/features/account/account.dto.d.ts +16 -0
  139. package/dist/features/account/account.dto.js +61 -0
  140. package/dist/features/account/account.dto.js.map +1 -0
  141. package/dist/features/account/data-export.service.d.ts +85 -0
  142. package/dist/features/account/data-export.service.js +125 -0
  143. package/dist/features/account/data-export.service.js.map +1 -0
  144. package/dist/features/account/health.service.d.ts +30 -0
  145. package/dist/features/account/health.service.js +59 -0
  146. package/dist/features/account/health.service.js.map +1 -0
  147. package/dist/features/admin/admin.controller.d.ts +382 -0
  148. package/dist/features/admin/admin.controller.js +623 -0
  149. package/dist/features/admin/admin.controller.js.map +1 -0
  150. package/dist/features/admin/admin.dto.d.ts +61 -0
  151. package/dist/features/admin/admin.dto.js +253 -0
  152. package/dist/features/admin/admin.dto.js.map +1 -0
  153. package/dist/features/admin/admin.service.d.ts +142 -0
  154. package/dist/features/admin/admin.service.js +227 -0
  155. package/dist/features/admin/admin.service.js.map +1 -0
  156. package/dist/features/api-keys/api-keys.service.d.ts +67 -0
  157. package/dist/features/api-keys/api-keys.service.js +144 -0
  158. package/dist/features/api-keys/api-keys.service.js.map +1 -0
  159. package/dist/features/email-change/email-change.controller.d.ts +38 -0
  160. package/dist/features/email-change/email-change.controller.js +85 -0
  161. package/dist/features/email-change/email-change.controller.js.map +1 -0
  162. package/dist/features/email-change/email-change.dto.d.ts +10 -0
  163. package/dist/features/email-change/email-change.dto.js +43 -0
  164. package/dist/features/email-change/email-change.dto.js.map +1 -0
  165. package/dist/features/email-change/email-change.service.d.ts +74 -0
  166. package/dist/features/email-change/email-change.service.js +179 -0
  167. package/dist/features/email-change/email-change.service.js.map +1 -0
  168. package/dist/features/email-links/email-verification.service.d.ts +46 -0
  169. package/dist/features/email-links/email-verification.service.js +94 -0
  170. package/dist/features/email-links/email-verification.service.js.map +1 -0
  171. package/dist/features/email-links/link-tokens.service.d.ts +44 -0
  172. package/dist/features/email-links/link-tokens.service.js +122 -0
  173. package/dist/features/email-links/link-tokens.service.js.map +1 -0
  174. package/dist/features/events/auth-events.service.d.ts +52 -0
  175. package/dist/features/events/auth-events.service.js +117 -0
  176. package/dist/features/events/auth-events.service.js.map +1 -0
  177. package/dist/features/maintenance/data-retention.service.d.ts +60 -0
  178. package/dist/features/maintenance/data-retention.service.js +182 -0
  179. package/dist/features/maintenance/data-retention.service.js.map +1 -0
  180. package/dist/features/notifications/notifications.service.d.ts +40 -0
  181. package/dist/features/notifications/notifications.service.js +94 -0
  182. package/dist/features/notifications/notifications.service.js.map +1 -0
  183. package/dist/features/one-time-codes/one-time-codes.service.d.ts +40 -0
  184. package/dist/features/one-time-codes/one-time-codes.service.js +102 -0
  185. package/dist/features/one-time-codes/one-time-codes.service.js.map +1 -0
  186. package/dist/features/organizations/organizations.controller.d.ts +220 -0
  187. package/dist/features/organizations/organizations.controller.js +337 -0
  188. package/dist/features/organizations/organizations.controller.js.map +1 -0
  189. package/dist/features/organizations/organizations.dto.d.ts +31 -0
  190. package/dist/features/organizations/organizations.dto.js +100 -0
  191. package/dist/features/organizations/organizations.dto.js.map +1 -0
  192. package/dist/features/organizations/organizations.service.d.ts +274 -0
  193. package/dist/features/organizations/organizations.service.js +481 -0
  194. package/dist/features/organizations/organizations.service.js.map +1 -0
  195. package/dist/features/passkeys/passkeys.controller.d.ts +92 -0
  196. package/dist/features/passkeys/passkeys.controller.js +183 -0
  197. package/dist/features/passkeys/passkeys.controller.js.map +1 -0
  198. package/dist/features/passkeys/passkeys.dto.d.ts +13 -0
  199. package/dist/features/passkeys/passkeys.dto.js +50 -0
  200. package/dist/features/passkeys/passkeys.dto.js.map +1 -0
  201. package/dist/features/passkeys/passkeys.service.d.ts +159 -0
  202. package/dist/features/passkeys/passkeys.service.js +350 -0
  203. package/dist/features/passkeys/passkeys.service.js.map +1 -0
  204. package/dist/features/passwordless/passwordless-auth.service.d.ts +152 -0
  205. package/dist/features/passwordless/passwordless-auth.service.js +304 -0
  206. package/dist/features/passwordless/passwordless-auth.service.js.map +1 -0
  207. package/dist/features/passwordless/passwordless.controller.d.ts +75 -0
  208. package/dist/features/passwordless/passwordless.controller.js +163 -0
  209. package/dist/features/passwordless/passwordless.controller.js.map +1 -0
  210. package/dist/features/passwordless/passwordless.dto.d.ts +29 -0
  211. package/dist/features/passwordless/passwordless.dto.js +101 -0
  212. package/dist/features/passwordless/passwordless.dto.js.map +1 -0
  213. package/dist/features/passwords/password-auth.service.d.ts +154 -0
  214. package/dist/features/passwords/password-auth.service.js +317 -0
  215. package/dist/features/passwords/password-auth.service.js.map +1 -0
  216. package/dist/features/passwords/password-policy.service.d.ts +63 -0
  217. package/dist/features/passwords/password-policy.service.js +175 -0
  218. package/dist/features/passwords/password-policy.service.js.map +1 -0
  219. package/dist/features/passwords/password.controller.d.ts +95 -0
  220. package/dist/features/passwords/password.controller.js +193 -0
  221. package/dist/features/passwords/password.controller.js.map +1 -0
  222. package/dist/features/passwords/password.dto.d.ts +36 -0
  223. package/dist/features/passwords/password.dto.js +140 -0
  224. package/dist/features/passwords/password.dto.js.map +1 -0
  225. package/dist/features/sessions/session.service.d.ts +132 -0
  226. package/dist/features/sessions/session.service.js +308 -0
  227. package/dist/features/sessions/session.service.js.map +1 -0
  228. package/dist/features/sessions/session.types.d.ts +34 -0
  229. package/dist/features/sessions/session.types.js +3 -0
  230. package/dist/features/sessions/session.types.js.map +1 -0
  231. package/dist/features/settings/settings.defaults.d.ts +2 -0
  232. package/dist/features/settings/settings.defaults.js +7 -0
  233. package/dist/features/settings/settings.defaults.js.map +1 -0
  234. package/dist/features/settings/settings.service.d.ts +44 -0
  235. package/dist/features/settings/settings.service.js +112 -0
  236. package/dist/features/settings/settings.service.js.map +1 -0
  237. package/dist/features/settings/settings.types.d.ts +133 -0
  238. package/dist/features/settings/settings.types.js +3 -0
  239. package/dist/features/settings/settings.types.js.map +1 -0
  240. package/dist/features/settings/settings.validation.d.ts +33 -0
  241. package/dist/features/settings/settings.validation.js +614 -0
  242. package/dist/features/settings/settings.validation.js.map +1 -0
  243. package/dist/features/sign-in/sign-in-challenges.service.d.ts +54 -0
  244. package/dist/features/sign-in/sign-in-challenges.service.js +104 -0
  245. package/dist/features/sign-in/sign-in-challenges.service.js.map +1 -0
  246. package/dist/features/sign-in/sign-in.service.d.ts +127 -0
  247. package/dist/features/sign-in/sign-in.service.js +248 -0
  248. package/dist/features/sign-in/sign-in.service.js.map +1 -0
  249. package/dist/features/sign-in/sign-in.types.d.ts +22 -0
  250. package/dist/features/sign-in/sign-in.types.js +3 -0
  251. package/dist/features/sign-in/sign-in.types.js.map +1 -0
  252. package/dist/features/signing-keys/jwks.controller.d.ts +17 -0
  253. package/dist/features/signing-keys/jwks.controller.js +51 -0
  254. package/dist/features/signing-keys/jwks.controller.js.map +1 -0
  255. package/dist/features/signing-keys/signing-keys.service.d.ts +67 -0
  256. package/dist/features/signing-keys/signing-keys.service.js +142 -0
  257. package/dist/features/signing-keys/signing-keys.service.js.map +1 -0
  258. package/dist/features/social/social-auth.service.d.ts +100 -0
  259. package/dist/features/social/social-auth.service.js +232 -0
  260. package/dist/features/social/social-auth.service.js.map +1 -0
  261. package/dist/features/social/social-providers.service.d.ts +97 -0
  262. package/dist/features/social/social-providers.service.js +214 -0
  263. package/dist/features/social/social-providers.service.js.map +1 -0
  264. package/dist/features/social/social.controller.d.ts +54 -0
  265. package/dist/features/social/social.controller.js +124 -0
  266. package/dist/features/social/social.controller.js.map +1 -0
  267. package/dist/features/social/social.dto.d.ts +11 -0
  268. package/dist/features/social/social.dto.js +38 -0
  269. package/dist/features/social/social.dto.js.map +1 -0
  270. package/dist/features/two-factor/two-factor.controller.d.ts +84 -0
  271. package/dist/features/two-factor/two-factor.controller.js +174 -0
  272. package/dist/features/two-factor/two-factor.controller.js.map +1 -0
  273. package/dist/features/two-factor/two-factor.dto.d.ts +10 -0
  274. package/dist/features/two-factor/two-factor.dto.js +37 -0
  275. package/dist/features/two-factor/two-factor.dto.js.map +1 -0
  276. package/dist/features/two-factor/two-factor.service.d.ts +171 -0
  277. package/dist/features/two-factor/two-factor.service.js +348 -0
  278. package/dist/features/two-factor/two-factor.service.js.map +1 -0
  279. package/dist/features/users/sign-in-methods.service.d.ts +40 -0
  280. package/dist/features/users/sign-in-methods.service.js +81 -0
  281. package/dist/features/users/sign-in-methods.service.js.map +1 -0
  282. package/dist/features/users/sign-up-rules.d.ts +12 -0
  283. package/dist/features/users/sign-up-rules.js +29 -0
  284. package/dist/features/users/sign-up-rules.js.map +1 -0
  285. package/dist/features/users/users.service.d.ts +246 -0
  286. package/dist/features/users/users.service.js +509 -0
  287. package/dist/features/users/users.service.js.map +1 -0
  288. package/dist/features/users/users.types.d.ts +24 -0
  289. package/dist/features/users/users.types.js +3 -0
  290. package/dist/features/users/users.types.js.map +1 -0
  291. package/dist/features/webhooks/webhook-delivery.worker.d.ts +55 -0
  292. package/dist/features/webhooks/webhook-delivery.worker.js +175 -0
  293. package/dist/features/webhooks/webhook-delivery.worker.js.map +1 -0
  294. package/dist/features/webhooks/webhook-signature.d.ts +28 -0
  295. package/dist/features/webhooks/webhook-signature.js +85 -0
  296. package/dist/features/webhooks/webhook-signature.js.map +1 -0
  297. package/dist/features/webhooks/webhooks.service.d.ts +144 -0
  298. package/dist/features/webhooks/webhooks.service.js +238 -0
  299. package/dist/features/webhooks/webhooks.service.js.map +1 -0
  300. package/dist/guards/auth.decorators.d.ts +65 -0
  301. package/dist/guards/auth.decorators.js +68 -0
  302. package/dist/guards/auth.decorators.js.map +1 -0
  303. package/dist/guards/auth.guard.d.ts +47 -0
  304. package/dist/guards/auth.guard.js +132 -0
  305. package/dist/guards/auth.guard.js.map +1 -0
  306. package/dist/index.d.ts +38 -0
  307. package/dist/index.js +95 -0
  308. package/dist/index.js.map +1 -0
  309. package/dist/integrations/console-email-sender.d.ts +15 -0
  310. package/dist/integrations/console-email-sender.js +26 -0
  311. package/dist/integrations/console-email-sender.js.map +1 -0
  312. package/dist/integrations/msg91-sms-sender.d.ts +28 -0
  313. package/dist/integrations/msg91-sms-sender.js +46 -0
  314. package/dist/integrations/msg91-sms-sender.js.map +1 -0
  315. package/docs/README.md +39 -0
  316. package/docs/admin-api-keys-webhooks.md +147 -0
  317. package/docs/api-reference.md +175 -0
  318. package/docs/architecture.md +119 -0
  319. package/docs/client-integration.md +192 -0
  320. package/docs/code-walkthrough.md +273 -0
  321. package/docs/configuration.md +229 -0
  322. package/docs/endpoints/README.md +151 -0
  323. package/docs/endpoints/account.md +363 -0
  324. package/docs/endpoints/admin.md +422 -0
  325. package/docs/endpoints/email-password.md +261 -0
  326. package/docs/endpoints/organizations.md +192 -0
  327. package/docs/endpoints/passkeys.md +195 -0
  328. package/docs/endpoints/passwordless.md +214 -0
  329. package/docs/endpoints/social.md +116 -0
  330. package/docs/endpoints/two-factor.md +146 -0
  331. package/docs/error-codes.md +100 -0
  332. package/docs/events.md +83 -0
  333. package/docs/getting-started.md +139 -0
  334. package/docs/manual-testing.md +215 -0
  335. package/docs/organizations.md +86 -0
  336. package/docs/production-checklist.md +60 -0
  337. package/docs/protecting-routes.md +147 -0
  338. package/docs/security.md +61 -0
  339. package/docs/sign-in-flows.md +294 -0
  340. package/package.json +92 -4
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
3
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
4
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
5
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
6
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
7
+ };
8
+ var __metadata = (this && this.__metadata) || function (k, v) {
9
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
10
+ };
11
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
+ return function (target, key) { decorator(target, key, paramIndex); }
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.WebhookDeliveryWorker = void 0;
16
+ const common_1 = require("@nestjs/common");
17
+ const network_safety_1 = require("../../common/network-safety.js");
18
+ const constants_1 = require("../../constants.js");
19
+ const entities_1 = require("../../database/entities/index.js");
20
+ const webhook_signature_1 = require("./webhook-signature");
21
+ const webhooks_service_1 = require("./webhooks.service");
22
+ /**
23
+ * Sends queued webhook deliveries in the background.
24
+ *
25
+ * - Runs every few seconds on every server. Each server claims different rows
26
+ * (FOR UPDATE SKIP LOCKED), so nothing is sent twice.
27
+ * - A 2xx response = delivered. Anything else is retried with growing delays
28
+ * (1 min, 5 min, 30 min, 2 h, 6 h, 12 h, 24 h), then marked failed.
29
+ * - Redirects are not followed, and the URL is re-checked before every send, so a receiver
30
+ * can't later point us at a private address.
31
+ */
32
+ let WebhookDeliveryWorker = class WebhookDeliveryWorker {
33
+ webhooks;
34
+ logger = new common_1.Logger(constants_1.LOG_CONTEXT.webhookDelivery);
35
+ database;
36
+ timer;
37
+ isRunning = false;
38
+ constructor(options, webhooks) {
39
+ this.webhooks = webhooks;
40
+ this.database = options.dataSource;
41
+ }
42
+ /**
43
+ * Starts the timer that sends due deliveries every few seconds.
44
+ */
45
+ onApplicationBootstrap() {
46
+ this.timer = setInterval(() => void this.sendDueDeliveries(), constants_1.WEBHOOK_WORKER_INTERVAL_MS);
47
+ this.timer.unref(); // Never keeps the process alive on shutdown.
48
+ }
49
+ /**
50
+ * Stops the timer when the app shuts down.
51
+ */
52
+ onModuleDestroy() {
53
+ if (this.timer)
54
+ clearInterval(this.timer);
55
+ }
56
+ /**
57
+ * One round: claim due deliveries and send them. Public so tests and scripts can call it.
58
+ * A round is skipped if the previous one is still running. Errors are logged, never thrown.
59
+ */
60
+ async sendDueDeliveries() {
61
+ if (this.isRunning)
62
+ return;
63
+ this.isRunning = true;
64
+ try {
65
+ const claimedDeliveries = await this.claimDueDeliveries();
66
+ await Promise.all(claimedDeliveries.map((delivery) => this.sendOne(delivery)));
67
+ }
68
+ catch (error) {
69
+ this.logger.error(`Webhook round failed: ${error.message}`);
70
+ }
71
+ finally {
72
+ this.isRunning = false;
73
+ }
74
+ }
75
+ /**
76
+ * Takes due rows and pushes their next attempt a little into the future, in one statement.
77
+ * If this server crashes mid-send, another server picks them up after the claim times out.
78
+ *
79
+ * @returns The deliveries this server should send now.
80
+ */
81
+ async claimDueDeliveries() {
82
+ // For UPDATE ... RETURNING, TypeORM's postgres driver returns [rows, affectedRowCount].
83
+ const [rows] = await this.database.query(`UPDATE auth_webhook_deliveries
84
+ SET next_attempt_at = now() + make_interval(secs => $1)
85
+ WHERE id IN (
86
+ SELECT id FROM auth_webhook_deliveries
87
+ WHERE status = $3 AND next_attempt_at <= now()
88
+ ORDER BY next_attempt_at
89
+ LIMIT $2
90
+ FOR UPDATE SKIP LOCKED)
91
+ RETURNING id, webhook_id, event_name, payload, attempt_count`, [constants_1.WEBHOOK_CLAIM_TIMEOUT_SECONDS, constants_1.WEBHOOK_WORKER_BATCH_SIZE, constants_1.WEBHOOK_DELIVERY_STATUS.pending]);
92
+ return rows.map((row) => Object.assign(new entities_1.WebhookDeliveryEntity(), {
93
+ id: row.id,
94
+ webhookId: row.webhook_id,
95
+ eventName: row.event_name,
96
+ payload: row.payload,
97
+ attemptCount: row.attempt_count,
98
+ }));
99
+ }
100
+ /**
101
+ * Sends one delivery and records what happened. The webhook's URL is checked again first.
102
+ *
103
+ * @param delivery - A claimed delivery.
104
+ */
105
+ async sendOne(delivery) {
106
+ const webhook = await this.database.getRepository(entities_1.WebhookEntity).findOne({ where: { id: delivery.webhookId } });
107
+ if (!webhook || !webhook.isEnabled) {
108
+ await this.recordOutcome(delivery, { isDelivered: false, isFinal: true, error: constants_1.WEBHOOK_DELIVERY_ERROR.webhookUnavailable });
109
+ return;
110
+ }
111
+ const urlProblem = await (0, network_safety_1.findUrlSafetyProblem)(webhook.url);
112
+ if (urlProblem) {
113
+ await this.recordOutcome(delivery, { isDelivered: false, isFinal: false, error: constants_1.WEBHOOK_DELIVERY_ERROR.unsafeUrl(urlProblem) });
114
+ return;
115
+ }
116
+ const body = JSON.stringify({ id: delivery.id, ...delivery.payload });
117
+ const signingSecret = await this.webhooks.decryptSigningSecret(webhook);
118
+ try {
119
+ const response = await fetch(webhook.url, {
120
+ method: constants_1.HTTP_METHOD.post,
121
+ redirect: constants_1.FETCH_REDIRECT_MODE_MANUAL,
122
+ signal: AbortSignal.timeout(constants_1.WEBHOOK_REQUEST_TIMEOUT_MS),
123
+ headers: {
124
+ [constants_1.HTTP_HEADER.contentType]: constants_1.JSON_CONTENT_TYPE,
125
+ [constants_1.HTTP_HEADER.outgoingUserAgent]: constants_1.WEBHOOK_USER_AGENT,
126
+ [constants_1.WEBHOOK_SIGNATURE_HEADER]: (0, webhook_signature_1.createWebhookSignature)(signingSecret, body),
127
+ [constants_1.WEBHOOK_EVENT_HEADER]: delivery.eventName,
128
+ [constants_1.WEBHOOK_DELIVERY_ID_HEADER]: delivery.id,
129
+ },
130
+ body,
131
+ });
132
+ const isDelivered = response.status >= constants_1.SUCCESS_STATUS_RANGE.from && response.status < constants_1.SUCCESS_STATUS_RANGE.toExclusive;
133
+ await this.recordOutcome(delivery, {
134
+ isDelivered,
135
+ isFinal: isDelivered,
136
+ responseStatus: response.status,
137
+ error: isDelivered ? null : constants_1.WEBHOOK_DELIVERY_ERROR.httpStatus(response.status),
138
+ });
139
+ }
140
+ catch (error) {
141
+ await this.recordOutcome(delivery, { isDelivered: false, isFinal: false, error: error.message });
142
+ }
143
+ }
144
+ /**
145
+ * Saves the result of an attempt and schedules the next retry, or marks the delivery
146
+ * delivered or failed.
147
+ *
148
+ * @param delivery - The delivery that was attempted.
149
+ * @param outcome - Whether it was delivered, whether to stop retrying, the HTTP status and the error.
150
+ */
151
+ async recordOutcome(delivery, outcome) {
152
+ const attemptCount = delivery.attemptCount + 1;
153
+ const retryDelaySeconds = constants_1.WEBHOOK_RETRY_DELAYS_SECONDS[attemptCount - 1];
154
+ const hasRetriesLeft = !outcome.isFinal && retryDelaySeconds !== undefined;
155
+ await this.database.getRepository(entities_1.WebhookDeliveryEntity).update({ id: delivery.id }, {
156
+ attemptCount,
157
+ status: outcome.isDelivered
158
+ ? constants_1.WEBHOOK_DELIVERY_STATUS.delivered
159
+ : hasRetriesLeft
160
+ ? constants_1.WEBHOOK_DELIVERY_STATUS.pending
161
+ : constants_1.WEBHOOK_DELIVERY_STATUS.failed,
162
+ deliveredAt: outcome.isDelivered ? new Date() : null,
163
+ lastResponseStatus: outcome.responseStatus ?? null,
164
+ lastError: outcome.error?.slice(0, constants_1.WEBHOOK_ERROR_MAX_LENGTH) ?? null,
165
+ nextAttemptAt: hasRetriesLeft ? new Date(Date.now() + retryDelaySeconds * constants_1.SECOND_IN_MILLISECONDS) : new Date(),
166
+ });
167
+ }
168
+ };
169
+ exports.WebhookDeliveryWorker = WebhookDeliveryWorker;
170
+ exports.WebhookDeliveryWorker = WebhookDeliveryWorker = __decorate([
171
+ (0, common_1.Injectable)(),
172
+ __param(0, (0, common_1.Inject)(constants_1.AUTH_OPTIONS_TOKEN)),
173
+ __metadata("design:paramtypes", [Object, webhooks_service_1.WebhooksService])
174
+ ], WebhookDeliveryWorker);
175
+ //# sourceMappingURL=webhook-delivery.worker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-delivery.worker.js","sourceRoot":"","sources":["../../../src/features/webhooks/webhook-delivery.worker.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Webhook signatures, in the same style as Stripe:
3
+ *
4
+ * X-Techelusive-Signature: t=1792600000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
5
+ *
6
+ * v1 = HMAC-SHA256(signingSecret, `${t}.${rawRequestBody}`) in hex.
7
+ * Including the time stops an attacker from replaying an old delivery later.
8
+ *
9
+ * @param signingSecret - The webhook's signing secret.
10
+ * @param rawBody - The exact JSON body being sent.
11
+ * @param unixTimeSeconds - The signing time; only passed in tests.
12
+ * @returns The value for the signature header.
13
+ */
14
+ export declare function createWebhookSignature(signingSecret: string, rawBody: string, unixTimeSeconds?: number): string;
15
+ /**
16
+ * For the RECEIVING app: checks a delivery is genuine and recent. Exported from the library so
17
+ * your other services can verify webhooks with one call.
18
+ *
19
+ * @param signingSecret - The secret shown when the webhook was created.
20
+ * @param rawBody - The request body exactly as received (not re-serialized JSON).
21
+ * @param signatureHeader - The X-Techelusive-Signature header.
22
+ * @param unixTimeSeconds - The current time; only passed in tests.
23
+ * @returns True when the signature is valid and the delivery is not too old.
24
+ * @example
25
+ * const isGenuine = verifyWebhookSignature(secret, req.rawBody, req.headers['x-techelusive-signature']);
26
+ * if (!isGenuine) return res.status(400).end();
27
+ */
28
+ export declare function verifyWebhookSignature(signingSecret: string, rawBody: string, signatureHeader: string | undefined, unixTimeSeconds?: number): boolean;
@@ -0,0 +1,85 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createWebhookSignature = createWebhookSignature;
4
+ exports.verifyWebhookSignature = verifyWebhookSignature;
5
+ const node_crypto_1 = require("node:crypto");
6
+ const random_secrets_1 = require("../../common/crypto/random-secrets.js");
7
+ const constants_1 = require("../../constants.js");
8
+ const time_1 = require("../../common/time.js");
9
+ /**
10
+ * Webhook signatures, in the same style as Stripe:
11
+ *
12
+ * X-Techelusive-Signature: t=1792600000,v1=5257a869e7ecebeda32affa62cdca3fa51cad7e77a0e56ff536d0ce8e108d8bd
13
+ *
14
+ * v1 = HMAC-SHA256(signingSecret, `${t}.${rawRequestBody}`) in hex.
15
+ * Including the time stops an attacker from replaying an old delivery later.
16
+ *
17
+ * @param signingSecret - The webhook's signing secret.
18
+ * @param rawBody - The exact JSON body being sent.
19
+ * @param unixTimeSeconds - The signing time; only passed in tests.
20
+ * @returns The value for the signature header.
21
+ */
22
+ function createWebhookSignature(signingSecret, rawBody, unixTimeSeconds = (0, time_1.currentUnixTimeSeconds)()) {
23
+ return formatSignatureHeader(unixTimeSeconds, computeSignature(signingSecret, rawBody, unixTimeSeconds));
24
+ }
25
+ /**
26
+ * For the RECEIVING app: checks a delivery is genuine and recent. Exported from the library so
27
+ * your other services can verify webhooks with one call.
28
+ *
29
+ * @param signingSecret - The secret shown when the webhook was created.
30
+ * @param rawBody - The request body exactly as received (not re-serialized JSON).
31
+ * @param signatureHeader - The X-Techelusive-Signature header.
32
+ * @param unixTimeSeconds - The current time; only passed in tests.
33
+ * @returns True when the signature is valid and the delivery is not too old.
34
+ * @example
35
+ * const isGenuine = verifyWebhookSignature(secret, req.rawBody, req.headers['x-techelusive-signature']);
36
+ * if (!isGenuine) return res.status(400).end();
37
+ */
38
+ function verifyWebhookSignature(signingSecret, rawBody, signatureHeader, unixTimeSeconds = (0, time_1.currentUnixTimeSeconds)()) {
39
+ if (!signatureHeader)
40
+ return false;
41
+ const parts = parseSignatureHeader(signatureHeader);
42
+ const signedAt = Number(parts[constants_1.WEBHOOK_SIGNATURE_FORMAT.timestampKey]);
43
+ const presentedSignature = parts[constants_1.WEBHOOK_SIGNATURE_FORMAT.signatureKey];
44
+ if (!Number.isInteger(signedAt) || typeof presentedSignature !== 'string')
45
+ return false;
46
+ if (Math.abs(unixTimeSeconds - signedAt) > constants_1.WEBHOOK_SIGNATURE_TOLERANCE_SECONDS)
47
+ return false;
48
+ return (0, random_secrets_1.constantTimeEquals)(computeSignature(signingSecret, rawBody, signedAt), presentedSignature);
49
+ }
50
+ /**
51
+ * HMAC-SHA256 of "<unix time>.<raw body>", in hex.
52
+ *
53
+ * @param signingSecret - The webhook's signing secret.
54
+ * @param rawBody - The exact JSON body.
55
+ * @param unixTimeSeconds - The signing time.
56
+ * @returns The signature in hex.
57
+ */
58
+ function computeSignature(signingSecret, rawBody, unixTimeSeconds) {
59
+ const signedContent = [String(unixTimeSeconds), rawBody].join(constants_1.WEBHOOK_SIGNATURE_FORMAT.signedContentSeparator);
60
+ return (0, node_crypto_1.createHmac)(constants_1.HASH_ALGORITHM.sha256, signingSecret).update(signedContent).digest(constants_1.TEXT_ENCODING.hex);
61
+ }
62
+ /**
63
+ * Builds the header value: "t=1792600000,v1=abc..."
64
+ *
65
+ * @param unixTimeSeconds - The signing time.
66
+ * @param signature - The hex signature.
67
+ * @returns The header value.
68
+ */
69
+ function formatSignatureHeader(unixTimeSeconds, signature) {
70
+ const { timestampKey, signatureKey, keyValueSeparator, partSeparator } = constants_1.WEBHOOK_SIGNATURE_FORMAT;
71
+ return [timestampKey + keyValueSeparator + unixTimeSeconds, signatureKey + keyValueSeparator + signature].join(partSeparator);
72
+ }
73
+ /**
74
+ * Splits the header into its parts: "t=1,v1=abc" -> { t: "1", v1: "abc" }
75
+ *
76
+ * @param signatureHeader - The header value.
77
+ * @returns The parts by key.
78
+ */
79
+ function parseSignatureHeader(signatureHeader) {
80
+ return Object.fromEntries(signatureHeader.split(constants_1.WEBHOOK_SIGNATURE_FORMAT.partSeparator).map((part) => {
81
+ const separatorIndex = part.indexOf(constants_1.WEBHOOK_SIGNATURE_FORMAT.keyValueSeparator);
82
+ return [part.slice(0, separatorIndex).trim(), part.slice(separatorIndex + 1).trim()];
83
+ }));
84
+ }
85
+ //# sourceMappingURL=webhook-signature.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhook-signature.js","sourceRoot":"","sources":["../../../src/features/webhooks/webhook-signature.ts"],"names":[],"mappings":";;AAuBA,wDAEC;AAeD,wDAcC;AAtDD,6CAAyC;AACzC,mEAAoE;AACpE,2CAKqB;AACrB,wCAAuD;AAEvD;;;;;;;;;;;;GAYG;AACH,SAAgB,sBAAsB,CAAC,aAAqB,EAAE,OAAe,EAAE,eAAe,GAAG,IAAA,6BAAsB,GAAE;IACvH,OAAO,qBAAqB,CAAC,eAAe,EAAE,gBAAgB,CAAC,aAAa,EAAE,OAAO,EAAE,eAAe,CAAC,CAAC,CAAC;AAC3G,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,SAAgB,sBAAsB,CACpC,aAAqB,EACrB,OAAe,EACf,eAAmC,EACnC,eAAe,GAAG,IAAA,6BAAsB,GAAE;IAE1C,IAAI,CAAC,eAAe;QAAE,OAAO,KAAK,CAAC;IACnC,MAAM,KAAK,GAAG,oBAAoB,CAAC,eAAe,CAAC,CAAC;IACpD,MAAM,QAAQ,GAAG,MAAM,CAAC,KAAK,CAAC,oCAAwB,CAAC,YAAY,CAAC,CAAC,CAAC;IACtE,MAAM,kBAAkB,GAAG,KAAK,CAAC,oCAAwB,CAAC,YAAY,CAAC,CAAC;IACxE,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,QAAQ,CAAC,IAAI,OAAO,kBAAkB,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IACxF,IAAI,IAAI,CAAC,GAAG,CAAC,eAAe,GAAG,QAAQ,CAAC,GAAG,+CAAmC;QAAE,OAAO,KAAK,CAAC;IAE7F,OAAO,IAAA,mCAAkB,EAAC,gBAAgB,CAAC,aAAa,EAAE,OAAO,EAAE,QAAQ,CAAC,EAAE,kBAAkB,CAAC,CAAC;AACpG,CAAC;AAED;;;;;;;GAOG;AACH,SAAS,gBAAgB,CAAC,aAAqB,EAAE,OAAe,EAAE,eAAuB;IACvF,MAAM,aAAa,GAAG,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,oCAAwB,CAAC,sBAAsB,CAAC,CAAC;IAC/G,OAAO,IAAA,wBAAU,EAAC,0BAAc,CAAC,MAAM,EAAE,aAAa,CAAC,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,MAAM,CAAC,yBAAa,CAAC,GAAG,CAAC,CAAC;AAC1G,CAAC;AAED;;;;;;GAMG;AACH,SAAS,qBAAqB,CAAC,eAAuB,EAAE,SAAiB;IACvE,MAAM,EAAE,YAAY,EAAE,YAAY,EAAE,iBAAiB,EAAE,aAAa,EAAE,GAAG,oCAAwB,CAAC;IAClG,OAAO,CAAC,YAAY,GAAG,iBAAiB,GAAG,eAAe,EAAE,YAAY,GAAG,iBAAiB,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;AAChI,CAAC;AAED;;;;;GAKG;AACH,SAAS,oBAAoB,CAAC,eAAuB;IACnD,OAAO,MAAM,CAAC,WAAW,CACvB,eAAe,CAAC,KAAK,CAAC,oCAAwB,CAAC,aAAa,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACzE,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,oCAAwB,CAAC,iBAAiB,CAAC,CAAC;QAChF,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,cAAc,CAAC,CAAC,IAAI,EAAE,EAAE,IAAI,CAAC,KAAK,CAAC,cAAc,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;IACvF,CAAC,CAAC,CACH,CAAC;AACJ,CAAC"}
@@ -0,0 +1,144 @@
1
+ import { AuthOptions } from '../../auth-options.js';
2
+ import { EncryptionService } from '../../common/encryption.service.js';
3
+ import { WebhookDeliveryEntity, WebhookEntity } from '../../database/entities/index.js';
4
+ export interface WebhookInput {
5
+ url: string;
6
+ /** Event names to receive, e.g. ["user.created"]. Empty = every event. */
7
+ eventNames?: string[];
8
+ description?: string | null;
9
+ isEnabled?: boolean;
10
+ }
11
+ /** A webhook as shown to admins. The signing secret is only shown when created or rotated. */
12
+ export type WebhookSummary = Omit<WebhookEntity, 'encryptedSigningSecret'>;
13
+ /**
14
+ * Admin management of webhooks: URLs that receive auth events as signed HTTP POSTs.
15
+ * Deliveries themselves are sent by WebhookDeliveryWorker.
16
+ */
17
+ export declare class WebhooksService {
18
+ private readonly encryption;
19
+ private readonly database;
20
+ constructor(options: AuthOptions, encryption: EncryptionService);
21
+ /**
22
+ * Creates a webhook. Returns the signing secret ONCE: the receiver needs it to verify deliveries.
23
+ *
24
+ * @param input - URL, event names (empty = every event), description and on/off state.
25
+ * @returns The webhook and its plain signing secret.
26
+ * @throws AuthError UNSAFE_WEBHOOK_URL when the URL is not https or points at a private address.
27
+ * @throws AuthError VALIDATION_ERROR for unknown event names or too many webhooks.
28
+ */
29
+ createWebhook(input: WebhookInput): Promise<{
30
+ success: true;
31
+ webhook: WebhookSummary;
32
+ signingSecret: string;
33
+ }>;
34
+ /**
35
+ * Lists every webhook, oldest first.
36
+ *
37
+ * @returns The webhooks, without their secrets.
38
+ */
39
+ listWebhooks(): Promise<WebhookSummary[]>;
40
+ /**
41
+ * Changes a webhook. Fields left undefined are not touched.
42
+ *
43
+ * @param webhookId - The webhook.
44
+ * @param changes - The fields to change.
45
+ * @returns The updated webhook.
46
+ * @throws AuthError NOT_FOUND when there is no such webhook.
47
+ * @throws AuthError UNSAFE_WEBHOOK_URL or VALIDATION_ERROR for a bad URL or event name.
48
+ */
49
+ updateWebhook(webhookId: string, changes: Partial<WebhookInput>): Promise<{
50
+ success: true;
51
+ webhook: WebhookSummary;
52
+ }>;
53
+ /**
54
+ * Deletes a webhook (its deliveries are deleted with it).
55
+ *
56
+ * @param webhookId - The webhook.
57
+ * @returns `{ success: true }`.
58
+ * @throws AuthError NOT_FOUND when there is no such webhook.
59
+ */
60
+ deleteWebhook(webhookId: string): Promise<{
61
+ success: true;
62
+ }>;
63
+ /**
64
+ * Replaces the signing secret (e.g. it leaked). The old one stops working at once.
65
+ *
66
+ * @param webhookId - The webhook.
67
+ * @returns The new plain signing secret, shown only this once.
68
+ * @throws AuthError NOT_FOUND when there is no such webhook.
69
+ */
70
+ rotateSigningSecret(webhookId: string): Promise<{
71
+ success: true;
72
+ signingSecret: string;
73
+ }>;
74
+ /**
75
+ * Recent deliveries of one webhook, newest first, for debugging a receiver.
76
+ *
77
+ * @param webhookId - The webhook.
78
+ * @param page - 1-based page number.
79
+ * @param pageSize - Rows per page (capped at MAXIMUM_PAGE_SIZE).
80
+ * @returns One page of deliveries, plus the total.
81
+ */
82
+ listDeliveries(webhookId: string, page?: number, pageSize?: number): Promise<{
83
+ success: true;
84
+ deliveries: WebhookDeliveryEntity[];
85
+ total: number;
86
+ page: number;
87
+ pageSize: number;
88
+ }>;
89
+ /**
90
+ * Sends a failed (or any) delivery again, right away, with a fresh set of retries.
91
+ *
92
+ * @param webhookId - The webhook the delivery belongs to.
93
+ * @param deliveryId - The delivery.
94
+ * @returns `{ success: true }`.
95
+ * @throws AuthError NOT_FOUND when the delivery doesn't exist for this webhook.
96
+ */
97
+ retryDelivery(webhookId: string, deliveryId: string): Promise<{
98
+ success: true;
99
+ }>;
100
+ /**
101
+ * Queues a "webhook.test" delivery so the receiver can be checked end to end.
102
+ *
103
+ * @param webhookId - The webhook.
104
+ * @returns `{ success: true }`.
105
+ * @throws AuthError NOT_FOUND when there is no such webhook.
106
+ */
107
+ sendTestDelivery(webhookId: string): Promise<{
108
+ success: true;
109
+ }>;
110
+ /**
111
+ * Reads a webhook's signing secret. Used by the delivery worker.
112
+ *
113
+ * @param webhook - The webhook row.
114
+ * @returns The plain signing secret.
115
+ */
116
+ decryptSigningSecret(webhook: WebhookEntity): Promise<string>;
117
+ /**
118
+ * @param url - The webhook URL.
119
+ * @throws AuthError UNSAFE_WEBHOOK_URL (with `problem`) when the server must not call it.
120
+ */
121
+ private assertUrlIsSafe;
122
+ /**
123
+ * @param eventNames - The event names the admin chose.
124
+ * @returns The names without duplicates.
125
+ * @throws AuthError VALIDATION_ERROR listing any names that are not real events.
126
+ */
127
+ private validateEventNames;
128
+ /**
129
+ * @returns A new random signing secret like "whsec_...".
130
+ */
131
+ private createSigningSecret;
132
+ /**
133
+ * Binds the encrypted secret to its webhook, so a secret copied to another row won't decrypt.
134
+ *
135
+ * @param webhookId - The webhook.
136
+ * @returns The context for `EncryptionService`.
137
+ */
138
+ private encryptionContext;
139
+ /**
140
+ * @param webhook - The webhook row.
141
+ * @returns The webhook without its encrypted secret, safe to show to admins.
142
+ */
143
+ private toSummary;
144
+ }