@portaidentity/server 1.7.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 (742) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/LICENSE +21 -0
  3. package/README.md +33 -0
  4. package/dist/applications/cache.d.ts +64 -0
  5. package/dist/applications/cache.d.ts.map +1 -0
  6. package/dist/applications/cache.js +161 -0
  7. package/dist/applications/cache.js.map +1 -0
  8. package/dist/applications/errors.d.ts +25 -0
  9. package/dist/applications/errors.d.ts.map +1 -0
  10. package/dist/applications/errors.js +31 -0
  11. package/dist/applications/errors.js.map +1 -0
  12. package/dist/applications/index.d.ts +17 -0
  13. package/dist/applications/index.d.ts.map +1 -0
  14. package/dist/applications/index.js +19 -0
  15. package/dist/applications/index.js.map +1 -0
  16. package/dist/applications/repository.d.ts +184 -0
  17. package/dist/applications/repository.d.ts.map +1 -0
  18. package/dist/applications/repository.js +367 -0
  19. package/dist/applications/repository.js.map +1 -0
  20. package/dist/applications/service.d.ts +160 -0
  21. package/dist/applications/service.d.ts.map +1 -0
  22. package/dist/applications/service.js +388 -0
  23. package/dist/applications/service.js.map +1 -0
  24. package/dist/applications/slugs.d.ts +61 -0
  25. package/dist/applications/slugs.d.ts.map +1 -0
  26. package/dist/applications/slugs.js +115 -0
  27. package/dist/applications/slugs.js.map +1 -0
  28. package/dist/applications/types.d.ts +129 -0
  29. package/dist/applications/types.d.ts.map +1 -0
  30. package/dist/applications/types.js +62 -0
  31. package/dist/applications/types.js.map +1 -0
  32. package/dist/auth/csrf.d.ts +71 -0
  33. package/dist/auth/csrf.d.ts.map +1 -0
  34. package/dist/auth/csrf.js +112 -0
  35. package/dist/auth/csrf.js.map +1 -0
  36. package/dist/auth/email-renderer.d.ts +37 -0
  37. package/dist/auth/email-renderer.d.ts.map +1 -0
  38. package/dist/auth/email-renderer.js +116 -0
  39. package/dist/auth/email-renderer.js.map +1 -0
  40. package/dist/auth/email-service.d.ts +154 -0
  41. package/dist/auth/email-service.d.ts.map +1 -0
  42. package/dist/auth/email-service.js +415 -0
  43. package/dist/auth/email-service.js.map +1 -0
  44. package/dist/auth/email-transport.d.ts +65 -0
  45. package/dist/auth/email-transport.d.ts.map +1 -0
  46. package/dist/auth/email-transport.js +82 -0
  47. package/dist/auth/email-transport.js.map +1 -0
  48. package/dist/auth/i18n.d.ts +81 -0
  49. package/dist/auth/i18n.d.ts.map +1 -0
  50. package/dist/auth/i18n.js +395 -0
  51. package/dist/auth/i18n.js.map +1 -0
  52. package/dist/auth/index.d.ts +28 -0
  53. package/dist/auth/index.d.ts.map +1 -0
  54. package/dist/auth/index.js +31 -0
  55. package/dist/auth/index.js.map +1 -0
  56. package/dist/auth/interaction-authority.d.ts +39 -0
  57. package/dist/auth/interaction-authority.d.ts.map +1 -0
  58. package/dist/auth/interaction-authority.js +30 -0
  59. package/dist/auth/interaction-authority.js.map +1 -0
  60. package/dist/auth/magic-link-session.d.ts +81 -0
  61. package/dist/auth/magic-link-session.d.ts.map +1 -0
  62. package/dist/auth/magic-link-session.js +183 -0
  63. package/dist/auth/magic-link-session.js.map +1 -0
  64. package/dist/auth/rate-limiter.d.ts +143 -0
  65. package/dist/auth/rate-limiter.d.ts.map +1 -0
  66. package/dist/auth/rate-limiter.js +220 -0
  67. package/dist/auth/rate-limiter.js.map +1 -0
  68. package/dist/auth/recovery-crypto.d.ts +34 -0
  69. package/dist/auth/recovery-crypto.d.ts.map +1 -0
  70. package/dist/auth/recovery-crypto.js +103 -0
  71. package/dist/auth/recovery-crypto.js.map +1 -0
  72. package/dist/auth/recovery-job-processor.d.ts +24 -0
  73. package/dist/auth/recovery-job-processor.d.ts.map +1 -0
  74. package/dist/auth/recovery-job-processor.js +123 -0
  75. package/dist/auth/recovery-job-processor.js.map +1 -0
  76. package/dist/auth/recovery-job-repository.d.ts +219 -0
  77. package/dist/auth/recovery-job-repository.d.ts.map +1 -0
  78. package/dist/auth/recovery-job-repository.js +340 -0
  79. package/dist/auth/recovery-job-repository.js.map +1 -0
  80. package/dist/auth/recovery-service.d.ts +27 -0
  81. package/dist/auth/recovery-service.d.ts.map +1 -0
  82. package/dist/auth/recovery-service.js +53 -0
  83. package/dist/auth/recovery-service.js.map +1 -0
  84. package/dist/auth/recovery-worker.d.ts +158 -0
  85. package/dist/auth/recovery-worker.d.ts.map +1 -0
  86. package/dist/auth/recovery-worker.js +306 -0
  87. package/dist/auth/recovery-worker.js.map +1 -0
  88. package/dist/auth/template-engine.d.ts +134 -0
  89. package/dist/auth/template-engine.d.ts.map +1 -0
  90. package/dist/auth/template-engine.js +225 -0
  91. package/dist/auth/template-engine.js.map +1 -0
  92. package/dist/auth/token-repository.d.ts +238 -0
  93. package/dist/auth/token-repository.d.ts.map +1 -0
  94. package/dist/auth/token-repository.js +475 -0
  95. package/dist/auth/token-repository.js.map +1 -0
  96. package/dist/auth/tokens.d.ts +45 -0
  97. package/dist/auth/tokens.d.ts.map +1 -0
  98. package/dist/auth/tokens.js +51 -0
  99. package/dist/auth/tokens.js.map +1 -0
  100. package/dist/cli/bootstrap.d.ts +55 -0
  101. package/dist/cli/bootstrap.d.ts.map +1 -0
  102. package/dist/cli/bootstrap.js +90 -0
  103. package/dist/cli/bootstrap.js.map +1 -0
  104. package/dist/cli/commands/health.d.ts +20 -0
  105. package/dist/cli/commands/health.d.ts.map +1 -0
  106. package/dist/cli/commands/health.js +80 -0
  107. package/dist/cli/commands/health.js.map +1 -0
  108. package/dist/cli/commands/init.d.ts +48 -0
  109. package/dist/cli/commands/init.d.ts.map +1 -0
  110. package/dist/cli/commands/init.js +349 -0
  111. package/dist/cli/commands/init.js.map +1 -0
  112. package/dist/cli/commands/migrate.d.ts +19 -0
  113. package/dist/cli/commands/migrate.d.ts.map +1 -0
  114. package/dist/cli/commands/migrate.js +88 -0
  115. package/dist/cli/commands/migrate.js.map +1 -0
  116. package/dist/cli/commands/seed.d.ts +19 -0
  117. package/dist/cli/commands/seed.d.ts.map +1 -0
  118. package/dist/cli/commands/seed.js +71 -0
  119. package/dist/cli/commands/seed.js.map +1 -0
  120. package/dist/cli/commands/user-2fa.d.ts +29 -0
  121. package/dist/cli/commands/user-2fa.d.ts.map +1 -0
  122. package/dist/cli/commands/user-2fa.js +113 -0
  123. package/dist/cli/commands/user-2fa.js.map +1 -0
  124. package/dist/cli/error-handler.d.ts +31 -0
  125. package/dist/cli/error-handler.d.ts.map +1 -0
  126. package/dist/cli/error-handler.js +65 -0
  127. package/dist/cli/error-handler.js.map +1 -0
  128. package/dist/cli/index.d.ts +48 -0
  129. package/dist/cli/index.d.ts.map +1 -0
  130. package/dist/cli/index.js +99 -0
  131. package/dist/cli/index.js.map +1 -0
  132. package/dist/cli/output.d.ts +94 -0
  133. package/dist/cli/output.d.ts.map +1 -0
  134. package/dist/cli/output.js +124 -0
  135. package/dist/cli/output.js.map +1 -0
  136. package/dist/cli/prompt.d.ts +48 -0
  137. package/dist/cli/prompt.d.ts.map +1 -0
  138. package/dist/cli/prompt.js +96 -0
  139. package/dist/cli/prompt.js.map +1 -0
  140. package/dist/clients/cache.d.ts +63 -0
  141. package/dist/clients/cache.d.ts.map +1 -0
  142. package/dist/clients/cache.js +160 -0
  143. package/dist/clients/cache.js.map +1 -0
  144. package/dist/clients/crypto.d.ts +69 -0
  145. package/dist/clients/crypto.d.ts.map +1 -0
  146. package/dist/clients/crypto.js +83 -0
  147. package/dist/clients/crypto.js.map +1 -0
  148. package/dist/clients/errors.d.ts +27 -0
  149. package/dist/clients/errors.d.ts.map +1 -0
  150. package/dist/clients/errors.js +33 -0
  151. package/dist/clients/errors.js.map +1 -0
  152. package/dist/clients/index.d.ts +19 -0
  153. package/dist/clients/index.d.ts.map +1 -0
  154. package/dist/clients/index.js +23 -0
  155. package/dist/clients/index.js.map +1 -0
  156. package/dist/clients/repository.d.ts +161 -0
  157. package/dist/clients/repository.d.ts.map +1 -0
  158. package/dist/clients/repository.js +318 -0
  159. package/dist/clients/repository.js.map +1 -0
  160. package/dist/clients/resolve-login-methods.d.ts +74 -0
  161. package/dist/clients/resolve-login-methods.d.ts.map +1 -0
  162. package/dist/clients/resolve-login-methods.js +68 -0
  163. package/dist/clients/resolve-login-methods.js.map +1 -0
  164. package/dist/clients/secret-repository.d.ts +109 -0
  165. package/dist/clients/secret-repository.d.ts.map +1 -0
  166. package/dist/clients/secret-repository.js +166 -0
  167. package/dist/clients/secret-repository.js.map +1 -0
  168. package/dist/clients/secret-service.d.ts +87 -0
  169. package/dist/clients/secret-service.d.ts.map +1 -0
  170. package/dist/clients/secret-service.js +204 -0
  171. package/dist/clients/secret-service.js.map +1 -0
  172. package/dist/clients/service.d.ts +158 -0
  173. package/dist/clients/service.d.ts.map +1 -0
  174. package/dist/clients/service.js +523 -0
  175. package/dist/clients/service.js.map +1 -0
  176. package/dist/clients/types.d.ts +214 -0
  177. package/dist/clients/types.d.ts.map +1 -0
  178. package/dist/clients/types.js +77 -0
  179. package/dist/clients/types.js.map +1 -0
  180. package/dist/clients/validators.d.ts +87 -0
  181. package/dist/clients/validators.d.ts.map +1 -0
  182. package/dist/clients/validators.js +164 -0
  183. package/dist/clients/validators.js.map +1 -0
  184. package/dist/config/index.d.ts +23 -0
  185. package/dist/config/index.d.ts.map +1 -0
  186. package/dist/config/index.js +52 -0
  187. package/dist/config/index.js.map +1 -0
  188. package/dist/config/schema.d.ts +35 -0
  189. package/dist/config/schema.d.ts.map +1 -0
  190. package/dist/config/schema.js +167 -0
  191. package/dist/config/schema.js.map +1 -0
  192. package/dist/custom-claims/cache.d.ts +48 -0
  193. package/dist/custom-claims/cache.d.ts.map +1 -0
  194. package/dist/custom-claims/cache.js +122 -0
  195. package/dist/custom-claims/cache.js.map +1 -0
  196. package/dist/custom-claims/errors.d.ts +25 -0
  197. package/dist/custom-claims/errors.d.ts.map +1 -0
  198. package/dist/custom-claims/errors.js +31 -0
  199. package/dist/custom-claims/errors.js.map +1 -0
  200. package/dist/custom-claims/index.d.ts +14 -0
  201. package/dist/custom-claims/index.d.ts.map +1 -0
  202. package/dist/custom-claims/index.js +17 -0
  203. package/dist/custom-claims/index.js.map +1 -0
  204. package/dist/custom-claims/repository.d.ts +147 -0
  205. package/dist/custom-claims/repository.d.ts.map +1 -0
  206. package/dist/custom-claims/repository.js +338 -0
  207. package/dist/custom-claims/repository.js.map +1 -0
  208. package/dist/custom-claims/service.d.ts +129 -0
  209. package/dist/custom-claims/service.d.ts.map +1 -0
  210. package/dist/custom-claims/service.js +296 -0
  211. package/dist/custom-claims/service.js.map +1 -0
  212. package/dist/custom-claims/types.d.ts +132 -0
  213. package/dist/custom-claims/types.d.ts.map +1 -0
  214. package/dist/custom-claims/types.js +61 -0
  215. package/dist/custom-claims/types.js.map +1 -0
  216. package/dist/custom-claims/validators.d.ts +61 -0
  217. package/dist/custom-claims/validators.d.ts.map +1 -0
  218. package/dist/custom-claims/validators.js +136 -0
  219. package/dist/custom-claims/validators.js.map +1 -0
  220. package/dist/index.d.ts +14 -0
  221. package/dist/index.d.ts.map +1 -0
  222. package/dist/index.js +91 -0
  223. package/dist/index.js.map +1 -0
  224. package/dist/lib/admin-permissions.d.ts +147 -0
  225. package/dist/lib/admin-permissions.d.ts.map +1 -0
  226. package/dist/lib/admin-permissions.js +261 -0
  227. package/dist/lib/admin-permissions.js.map +1 -0
  228. package/dist/lib/audit-log.d.ts +45 -0
  229. package/dist/lib/audit-log.d.ts.map +1 -0
  230. package/dist/lib/audit-log.js +79 -0
  231. package/dist/lib/audit-log.js.map +1 -0
  232. package/dist/lib/branding-assets.d.ts +47 -0
  233. package/dist/lib/branding-assets.d.ts.map +1 -0
  234. package/dist/lib/branding-assets.js +93 -0
  235. package/dist/lib/branding-assets.js.map +1 -0
  236. package/dist/lib/bulk-operations.d.ts +54 -0
  237. package/dist/lib/bulk-operations.d.ts.map +1 -0
  238. package/dist/lib/bulk-operations.js +201 -0
  239. package/dist/lib/bulk-operations.js.map +1 -0
  240. package/dist/lib/cursor.d.ts +110 -0
  241. package/dist/lib/cursor.d.ts.map +1 -0
  242. package/dist/lib/cursor.js +115 -0
  243. package/dist/lib/cursor.js.map +1 -0
  244. package/dist/lib/data-export.d.ts +67 -0
  245. package/dist/lib/data-export.d.ts.map +1 -0
  246. package/dist/lib/data-export.js +272 -0
  247. package/dist/lib/data-export.js.map +1 -0
  248. package/dist/lib/data-import-plan.d.ts +50 -0
  249. package/dist/lib/data-import-plan.d.ts.map +1 -0
  250. package/dist/lib/data-import-plan.js +235 -0
  251. package/dist/lib/data-import-plan.js.map +1 -0
  252. package/dist/lib/data-import.d.ts +276 -0
  253. package/dist/lib/data-import.d.ts.map +1 -0
  254. package/dist/lib/data-import.js +1694 -0
  255. package/dist/lib/data-import.js.map +1 -0
  256. package/dist/lib/database.d.ts +22 -0
  257. package/dist/lib/database.d.ts.map +1 -0
  258. package/dist/lib/database.js +103 -0
  259. package/dist/lib/database.js.map +1 -0
  260. package/dist/lib/entity-history.d.ts +52 -0
  261. package/dist/lib/entity-history.d.ts.map +1 -0
  262. package/dist/lib/entity-history.js +121 -0
  263. package/dist/lib/entity-history.js.map +1 -0
  264. package/dist/lib/etag.d.ts +92 -0
  265. package/dist/lib/etag.d.ts.map +1 -0
  266. package/dist/lib/etag.js +155 -0
  267. package/dist/lib/etag.js.map +1 -0
  268. package/dist/lib/image-validator.d.ts +44 -0
  269. package/dist/lib/image-validator.d.ts.map +1 -0
  270. package/dist/lib/image-validator.js +204 -0
  271. package/dist/lib/image-validator.js.map +1 -0
  272. package/dist/lib/logger.d.ts +15 -0
  273. package/dist/lib/logger.d.ts.map +1 -0
  274. package/dist/lib/logger.js +84 -0
  275. package/dist/lib/logger.js.map +1 -0
  276. package/dist/lib/migrator.d.ts +14 -0
  277. package/dist/lib/migrator.d.ts.map +1 -0
  278. package/dist/lib/migrator.js +34 -0
  279. package/dist/lib/migrator.js.map +1 -0
  280. package/dist/lib/redis.d.ts +5 -0
  281. package/dist/lib/redis.d.ts.map +1 -0
  282. package/dist/lib/redis.js +29 -0
  283. package/dist/lib/redis.js.map +1 -0
  284. package/dist/lib/runtime-paths.d.ts +38 -0
  285. package/dist/lib/runtime-paths.d.ts.map +1 -0
  286. package/dist/lib/runtime-paths.js +50 -0
  287. package/dist/lib/runtime-paths.js.map +1 -0
  288. package/dist/lib/session-tracking.d.ts +81 -0
  289. package/dist/lib/session-tracking.d.ts.map +1 -0
  290. package/dist/lib/session-tracking.js +145 -0
  291. package/dist/lib/session-tracking.js.map +1 -0
  292. package/dist/lib/signing-key-crypto.d.ts +53 -0
  293. package/dist/lib/signing-key-crypto.d.ts.map +1 -0
  294. package/dist/lib/signing-key-crypto.js +108 -0
  295. package/dist/lib/signing-key-crypto.js.map +1 -0
  296. package/dist/lib/signing-keys.d.ts +141 -0
  297. package/dist/lib/signing-keys.d.ts.map +1 -0
  298. package/dist/lib/signing-keys.js +206 -0
  299. package/dist/lib/signing-keys.js.map +1 -0
  300. package/dist/lib/stats.d.ts +83 -0
  301. package/dist/lib/stats.d.ts.map +1 -0
  302. package/dist/lib/stats.js +187 -0
  303. package/dist/lib/stats.js.map +1 -0
  304. package/dist/lib/super-admin-protection.d.ts +69 -0
  305. package/dist/lib/super-admin-protection.d.ts.map +1 -0
  306. package/dist/lib/super-admin-protection.js +102 -0
  307. package/dist/lib/super-admin-protection.js.map +1 -0
  308. package/dist/lib/system-config.d.ts +79 -0
  309. package/dist/lib/system-config.d.ts.map +1 -0
  310. package/dist/lib/system-config.js +159 -0
  311. package/dist/lib/system-config.js.map +1 -0
  312. package/dist/middleware/admin-auth.d.ts +100 -0
  313. package/dist/middleware/admin-auth.d.ts.map +1 -0
  314. package/dist/middleware/admin-auth.js +241 -0
  315. package/dist/middleware/admin-auth.js.map +1 -0
  316. package/dist/middleware/admin-cors.d.ts +41 -0
  317. package/dist/middleware/admin-cors.d.ts.map +1 -0
  318. package/dist/middleware/admin-cors.js +83 -0
  319. package/dist/middleware/admin-cors.js.map +1 -0
  320. package/dist/middleware/admin-mutation-audit.d.ts +9 -0
  321. package/dist/middleware/admin-mutation-audit.d.ts.map +1 -0
  322. package/dist/middleware/admin-mutation-audit.js +76 -0
  323. package/dist/middleware/admin-mutation-audit.js.map +1 -0
  324. package/dist/middleware/admin-rate-limiter.d.ts +56 -0
  325. package/dist/middleware/admin-rate-limiter.d.ts.map +1 -0
  326. package/dist/middleware/admin-rate-limiter.js +97 -0
  327. package/dist/middleware/admin-rate-limiter.js.map +1 -0
  328. package/dist/middleware/client-secret-hash.d.ts +34 -0
  329. package/dist/middleware/client-secret-hash.d.ts.map +1 -0
  330. package/dist/middleware/client-secret-hash.js +74 -0
  331. package/dist/middleware/client-secret-hash.js.map +1 -0
  332. package/dist/middleware/error-handler.d.ts +3 -0
  333. package/dist/middleware/error-handler.d.ts.map +1 -0
  334. package/dist/middleware/error-handler.js +93 -0
  335. package/dist/middleware/error-handler.js.map +1 -0
  336. package/dist/middleware/health.d.ts +3 -0
  337. package/dist/middleware/health.d.ts.map +1 -0
  338. package/dist/middleware/health.js +35 -0
  339. package/dist/middleware/health.js.map +1 -0
  340. package/dist/middleware/metrics.d.ts +40 -0
  341. package/dist/middleware/metrics.d.ts.map +1 -0
  342. package/dist/middleware/metrics.js +75 -0
  343. package/dist/middleware/metrics.js.map +1 -0
  344. package/dist/middleware/oidc-client-tenant.d.ts +37 -0
  345. package/dist/middleware/oidc-client-tenant.d.ts.map +1 -0
  346. package/dist/middleware/oidc-client-tenant.js +156 -0
  347. package/dist/middleware/oidc-client-tenant.js.map +1 -0
  348. package/dist/middleware/oidc-cors.d.ts +33 -0
  349. package/dist/middleware/oidc-cors.d.ts.map +1 -0
  350. package/dist/middleware/oidc-cors.js +68 -0
  351. package/dist/middleware/oidc-cors.js.map +1 -0
  352. package/dist/middleware/oidc-preflight-cors.d.ts +54 -0
  353. package/dist/middleware/oidc-preflight-cors.d.ts.map +1 -0
  354. package/dist/middleware/oidc-preflight-cors.js +267 -0
  355. package/dist/middleware/oidc-preflight-cors.js.map +1 -0
  356. package/dist/middleware/prompt-login-reset.d.ts +103 -0
  357. package/dist/middleware/prompt-login-reset.d.ts.map +1 -0
  358. package/dist/middleware/prompt-login-reset.js +204 -0
  359. package/dist/middleware/prompt-login-reset.js.map +1 -0
  360. package/dist/middleware/ready.d.ts +23 -0
  361. package/dist/middleware/ready.d.ts.map +1 -0
  362. package/dist/middleware/ready.js +60 -0
  363. package/dist/middleware/ready.js.map +1 -0
  364. package/dist/middleware/request-logger.d.ts +27 -0
  365. package/dist/middleware/request-logger.d.ts.map +1 -0
  366. package/dist/middleware/request-logger.js +46 -0
  367. package/dist/middleware/request-logger.js.map +1 -0
  368. package/dist/middleware/require-permission.d.ts +28 -0
  369. package/dist/middleware/require-permission.d.ts.map +1 -0
  370. package/dist/middleware/require-permission.js +63 -0
  371. package/dist/middleware/require-permission.js.map +1 -0
  372. package/dist/middleware/require-user-organization.d.ts +18 -0
  373. package/dist/middleware/require-user-organization.d.ts.map +1 -0
  374. package/dist/middleware/require-user-organization.js +53 -0
  375. package/dist/middleware/require-user-organization.js.map +1 -0
  376. package/dist/middleware/root-page.d.ts +62 -0
  377. package/dist/middleware/root-page.d.ts.map +1 -0
  378. package/dist/middleware/root-page.js +134 -0
  379. package/dist/middleware/root-page.js.map +1 -0
  380. package/dist/middleware/security-headers.d.ts +98 -0
  381. package/dist/middleware/security-headers.d.ts.map +1 -0
  382. package/dist/middleware/security-headers.js +159 -0
  383. package/dist/middleware/security-headers.js.map +1 -0
  384. package/dist/middleware/tenant-resolver.d.ts +37 -0
  385. package/dist/middleware/tenant-resolver.d.ts.map +1 -0
  386. package/dist/middleware/tenant-resolver.js +71 -0
  387. package/dist/middleware/tenant-resolver.js.map +1 -0
  388. package/dist/middleware/token-rate-limiter.d.ts +89 -0
  389. package/dist/middleware/token-rate-limiter.d.ts.map +1 -0
  390. package/dist/middleware/token-rate-limiter.js +189 -0
  391. package/dist/middleware/token-rate-limiter.js.map +1 -0
  392. package/dist/oidc/account-finder.d.ts +52 -0
  393. package/dist/oidc/account-finder.d.ts.map +1 -0
  394. package/dist/oidc/account-finder.js +134 -0
  395. package/dist/oidc/account-finder.js.map +1 -0
  396. package/dist/oidc/adapter-factory.d.ts +90 -0
  397. package/dist/oidc/adapter-factory.d.ts.map +1 -0
  398. package/dist/oidc/adapter-factory.js +165 -0
  399. package/dist/oidc/adapter-factory.js.map +1 -0
  400. package/dist/oidc/configuration.d.ts +155 -0
  401. package/dist/oidc/configuration.d.ts.map +1 -0
  402. package/dist/oidc/configuration.js +531 -0
  403. package/dist/oidc/configuration.js.map +1 -0
  404. package/dist/oidc/postgres-adapter.d.ts +159 -0
  405. package/dist/oidc/postgres-adapter.d.ts.map +1 -0
  406. package/dist/oidc/postgres-adapter.js +222 -0
  407. package/dist/oidc/postgres-adapter.js.map +1 -0
  408. package/dist/oidc/protocol-security-observer.d.ts +38 -0
  409. package/dist/oidc/protocol-security-observer.d.ts.map +1 -0
  410. package/dist/oidc/protocol-security-observer.js +93 -0
  411. package/dist/oidc/protocol-security-observer.js.map +1 -0
  412. package/dist/oidc/provider.d.ts +37 -0
  413. package/dist/oidc/provider.d.ts.map +1 -0
  414. package/dist/oidc/provider.js +71 -0
  415. package/dist/oidc/provider.js.map +1 -0
  416. package/dist/oidc/redis-adapter.d.ts +140 -0
  417. package/dist/oidc/redis-adapter.d.ts.map +1 -0
  418. package/dist/oidc/redis-adapter.js +344 -0
  419. package/dist/oidc/redis-adapter.js.map +1 -0
  420. package/dist/organizations/cache.d.ts +60 -0
  421. package/dist/organizations/cache.d.ts.map +1 -0
  422. package/dist/organizations/cache.js +157 -0
  423. package/dist/organizations/cache.js.map +1 -0
  424. package/dist/organizations/errors.d.ts +25 -0
  425. package/dist/organizations/errors.d.ts.map +1 -0
  426. package/dist/organizations/errors.js +31 -0
  427. package/dist/organizations/errors.js.map +1 -0
  428. package/dist/organizations/index.d.ts +15 -0
  429. package/dist/organizations/index.d.ts.map +1 -0
  430. package/dist/organizations/index.js +15 -0
  431. package/dist/organizations/index.js.map +1 -0
  432. package/dist/organizations/repository.d.ts +183 -0
  433. package/dist/organizations/repository.d.ts.map +1 -0
  434. package/dist/organizations/repository.js +354 -0
  435. package/dist/organizations/repository.js.map +1 -0
  436. package/dist/organizations/service.d.ts +168 -0
  437. package/dist/organizations/service.d.ts.map +1 -0
  438. package/dist/organizations/service.js +511 -0
  439. package/dist/organizations/service.js.map +1 -0
  440. package/dist/organizations/slugs.d.ts +57 -0
  441. package/dist/organizations/slugs.d.ts.map +1 -0
  442. package/dist/organizations/slugs.js +130 -0
  443. package/dist/organizations/slugs.js.map +1 -0
  444. package/dist/organizations/types.d.ts +146 -0
  445. package/dist/organizations/types.d.ts.map +1 -0
  446. package/dist/organizations/types.js +49 -0
  447. package/dist/organizations/types.js.map +1 -0
  448. package/dist/rbac/cache.d.ts +110 -0
  449. package/dist/rbac/cache.d.ts.map +1 -0
  450. package/dist/rbac/cache.js +271 -0
  451. package/dist/rbac/cache.js.map +1 -0
  452. package/dist/rbac/errors.d.ts +34 -0
  453. package/dist/rbac/errors.d.ts.map +1 -0
  454. package/dist/rbac/errors.js +43 -0
  455. package/dist/rbac/errors.js.map +1 -0
  456. package/dist/rbac/index.d.ts +17 -0
  457. package/dist/rbac/index.d.ts.map +1 -0
  458. package/dist/rbac/index.js +21 -0
  459. package/dist/rbac/index.js.map +1 -0
  460. package/dist/rbac/mapping-repository.d.ts +121 -0
  461. package/dist/rbac/mapping-repository.d.ts.map +1 -0
  462. package/dist/rbac/mapping-repository.js +224 -0
  463. package/dist/rbac/mapping-repository.js.map +1 -0
  464. package/dist/rbac/permission-repository.d.ts +100 -0
  465. package/dist/rbac/permission-repository.d.ts.map +1 -0
  466. package/dist/rbac/permission-repository.js +190 -0
  467. package/dist/rbac/permission-repository.js.map +1 -0
  468. package/dist/rbac/permission-service.d.ts +85 -0
  469. package/dist/rbac/permission-service.d.ts.map +1 -0
  470. package/dist/rbac/permission-service.js +179 -0
  471. package/dist/rbac/permission-service.js.map +1 -0
  472. package/dist/rbac/role-repository.d.ts +104 -0
  473. package/dist/rbac/role-repository.d.ts.map +1 -0
  474. package/dist/rbac/role-repository.js +202 -0
  475. package/dist/rbac/role-repository.js.map +1 -0
  476. package/dist/rbac/role-service.d.ts +111 -0
  477. package/dist/rbac/role-service.d.ts.map +1 -0
  478. package/dist/rbac/role-service.js +256 -0
  479. package/dist/rbac/role-service.js.map +1 -0
  480. package/dist/rbac/slugs.d.ts +116 -0
  481. package/dist/rbac/slugs.d.ts.map +1 -0
  482. package/dist/rbac/slugs.js +178 -0
  483. package/dist/rbac/slugs.js.map +1 -0
  484. package/dist/rbac/types.d.ts +187 -0
  485. package/dist/rbac/types.d.ts.map +1 -0
  486. package/dist/rbac/types.js +75 -0
  487. package/dist/rbac/types.js.map +1 -0
  488. package/dist/rbac/user-role-service.d.ts +101 -0
  489. package/dist/rbac/user-role-service.d.ts.map +1 -0
  490. package/dist/rbac/user-role-service.js +166 -0
  491. package/dist/rbac/user-role-service.js.map +1 -0
  492. package/dist/routes/applications.d.ts +40 -0
  493. package/dist/routes/applications.d.ts.map +1 -0
  494. package/dist/routes/applications.js +284 -0
  495. package/dist/routes/applications.js.map +1 -0
  496. package/dist/routes/audit.d.ts +31 -0
  497. package/dist/routes/audit.d.ts.map +1 -0
  498. package/dist/routes/audit.js +140 -0
  499. package/dist/routes/audit.js.map +1 -0
  500. package/dist/routes/branding.d.ts +17 -0
  501. package/dist/routes/branding.d.ts.map +1 -0
  502. package/dist/routes/branding.js +104 -0
  503. package/dist/routes/branding.js.map +1 -0
  504. package/dist/routes/bulk.d.ts +37 -0
  505. package/dist/routes/bulk.d.ts.map +1 -0
  506. package/dist/routes/bulk.js +94 -0
  507. package/dist/routes/bulk.js.map +1 -0
  508. package/dist/routes/clients.d.ts +44 -0
  509. package/dist/routes/clients.d.ts.map +1 -0
  510. package/dist/routes/clients.js +353 -0
  511. package/dist/routes/clients.js.map +1 -0
  512. package/dist/routes/config.d.ts +35 -0
  513. package/dist/routes/config.d.ts.map +1 -0
  514. package/dist/routes/config.js +115 -0
  515. package/dist/routes/config.js.map +1 -0
  516. package/dist/routes/custom-claims.d.ts +38 -0
  517. package/dist/routes/custom-claims.d.ts.map +1 -0
  518. package/dist/routes/custom-claims.js +208 -0
  519. package/dist/routes/custom-claims.js.map +1 -0
  520. package/dist/routes/exports.d.ts +21 -0
  521. package/dist/routes/exports.d.ts.map +1 -0
  522. package/dist/routes/exports.js +98 -0
  523. package/dist/routes/exports.js.map +1 -0
  524. package/dist/routes/imports.d.ts +18 -0
  525. package/dist/routes/imports.d.ts.map +1 -0
  526. package/dist/routes/imports.js +72 -0
  527. package/dist/routes/imports.js.map +1 -0
  528. package/dist/routes/interactions.d.ts +111 -0
  529. package/dist/routes/interactions.d.ts.map +1 -0
  530. package/dist/routes/interactions.js +1074 -0
  531. package/dist/routes/interactions.js.map +1 -0
  532. package/dist/routes/invitation.d.ts +31 -0
  533. package/dist/routes/invitation.d.ts.map +1 -0
  534. package/dist/routes/invitation.js +342 -0
  535. package/dist/routes/invitation.js.map +1 -0
  536. package/dist/routes/keys.d.ts +28 -0
  537. package/dist/routes/keys.d.ts.map +1 -0
  538. package/dist/routes/keys.js +91 -0
  539. package/dist/routes/keys.js.map +1 -0
  540. package/dist/routes/magic-link.d.ts +43 -0
  541. package/dist/routes/magic-link.d.ts.map +1 -0
  542. package/dist/routes/magic-link.js +264 -0
  543. package/dist/routes/magic-link.js.map +1 -0
  544. package/dist/routes/organizations.d.ts +38 -0
  545. package/dist/routes/organizations.d.ts.map +1 -0
  546. package/dist/routes/organizations.js +347 -0
  547. package/dist/routes/organizations.js.map +1 -0
  548. package/dist/routes/password-reset.d.ts +65 -0
  549. package/dist/routes/password-reset.d.ts.map +1 -0
  550. package/dist/routes/password-reset.js +493 -0
  551. package/dist/routes/password-reset.js.map +1 -0
  552. package/dist/routes/permissions.d.ts +33 -0
  553. package/dist/routes/permissions.d.ts.map +1 -0
  554. package/dist/routes/permissions.js +166 -0
  555. package/dist/routes/permissions.js.map +1 -0
  556. package/dist/routes/roles.d.ts +37 -0
  557. package/dist/routes/roles.d.ts.map +1 -0
  558. package/dist/routes/roles.js +222 -0
  559. package/dist/routes/roles.js.map +1 -0
  560. package/dist/routes/sessions.d.ts +37 -0
  561. package/dist/routes/sessions.d.ts.map +1 -0
  562. package/dist/routes/sessions.js +121 -0
  563. package/dist/routes/sessions.js.map +1 -0
  564. package/dist/routes/stats.d.ts +28 -0
  565. package/dist/routes/stats.d.ts.map +1 -0
  566. package/dist/routes/stats.js +65 -0
  567. package/dist/routes/stats.js.map +1 -0
  568. package/dist/routes/two-factor-admin.d.ts +54 -0
  569. package/dist/routes/two-factor-admin.d.ts.map +1 -0
  570. package/dist/routes/two-factor-admin.js +344 -0
  571. package/dist/routes/two-factor-admin.js.map +1 -0
  572. package/dist/routes/two-factor.d.ts +31 -0
  573. package/dist/routes/two-factor.d.ts.map +1 -0
  574. package/dist/routes/two-factor.js +595 -0
  575. package/dist/routes/two-factor.js.map +1 -0
  576. package/dist/routes/user-roles.d.ts +33 -0
  577. package/dist/routes/user-roles.d.ts.map +1 -0
  578. package/dist/routes/user-roles.js +129 -0
  579. package/dist/routes/user-roles.js.map +1 -0
  580. package/dist/routes/users.d.ts +61 -0
  581. package/dist/routes/users.d.ts.map +1 -0
  582. package/dist/routes/users.js +868 -0
  583. package/dist/routes/users.js.map +1 -0
  584. package/dist/security/decision-context.d.ts +52 -0
  585. package/dist/security/decision-context.d.ts.map +1 -0
  586. package/dist/security/decision-context.js +150 -0
  587. package/dist/security/decision-context.js.map +1 -0
  588. package/dist/security/decision-event.d.ts +128 -0
  589. package/dist/security/decision-event.d.ts.map +1 -0
  590. package/dist/security/decision-event.js +225 -0
  591. package/dist/security/decision-event.js.map +1 -0
  592. package/dist/security/transport-decision.d.ts +6 -0
  593. package/dist/security/transport-decision.d.ts.map +1 -0
  594. package/dist/security/transport-decision.js +37 -0
  595. package/dist/security/transport-decision.js.map +1 -0
  596. package/dist/server.d.ts +50 -0
  597. package/dist/server.d.ts.map +1 -0
  598. package/dist/server.js +491 -0
  599. package/dist/server.js.map +1 -0
  600. package/dist/two-factor/cache.d.ts +47 -0
  601. package/dist/two-factor/cache.d.ts.map +1 -0
  602. package/dist/two-factor/cache.js +122 -0
  603. package/dist/two-factor/cache.js.map +1 -0
  604. package/dist/two-factor/crypto.d.ts +41 -0
  605. package/dist/two-factor/crypto.d.ts.map +1 -0
  606. package/dist/two-factor/crypto.js +94 -0
  607. package/dist/two-factor/crypto.js.map +1 -0
  608. package/dist/two-factor/errors.d.ts +82 -0
  609. package/dist/two-factor/errors.d.ts.map +1 -0
  610. package/dist/two-factor/errors.js +112 -0
  611. package/dist/two-factor/errors.js.map +1 -0
  612. package/dist/two-factor/index.d.ts +18 -0
  613. package/dist/two-factor/index.d.ts.map +1 -0
  614. package/dist/two-factor/index.js +25 -0
  615. package/dist/two-factor/index.js.map +1 -0
  616. package/dist/two-factor/otp.d.ts +43 -0
  617. package/dist/two-factor/otp.d.ts.map +1 -0
  618. package/dist/two-factor/otp.js +57 -0
  619. package/dist/two-factor/otp.js.map +1 -0
  620. package/dist/two-factor/recovery.d.ts +45 -0
  621. package/dist/two-factor/recovery.d.ts.map +1 -0
  622. package/dist/two-factor/recovery.js +104 -0
  623. package/dist/two-factor/recovery.js.map +1 -0
  624. package/dist/two-factor/repository.d.ts +156 -0
  625. package/dist/two-factor/repository.d.ts.map +1 -0
  626. package/dist/two-factor/repository.js +251 -0
  627. package/dist/two-factor/repository.js.map +1 -0
  628. package/dist/two-factor/service.d.ts +232 -0
  629. package/dist/two-factor/service.d.ts.map +1 -0
  630. package/dist/two-factor/service.js +599 -0
  631. package/dist/two-factor/service.js.map +1 -0
  632. package/dist/two-factor/totp.d.ts +57 -0
  633. package/dist/two-factor/totp.d.ts.map +1 -0
  634. package/dist/two-factor/totp.js +96 -0
  635. package/dist/two-factor/totp.js.map +1 -0
  636. package/dist/two-factor/types.d.ts +152 -0
  637. package/dist/two-factor/types.d.ts.map +1 -0
  638. package/dist/two-factor/types.js +64 -0
  639. package/dist/two-factor/types.js.map +1 -0
  640. package/dist/users/cache.d.ts +49 -0
  641. package/dist/users/cache.d.ts.map +1 -0
  642. package/dist/users/cache.js +140 -0
  643. package/dist/users/cache.js.map +1 -0
  644. package/dist/users/claims.d.ts +67 -0
  645. package/dist/users/claims.d.ts.map +1 -0
  646. package/dist/users/claims.js +104 -0
  647. package/dist/users/claims.js.map +1 -0
  648. package/dist/users/errors.d.ts +25 -0
  649. package/dist/users/errors.d.ts.map +1 -0
  650. package/dist/users/errors.js +31 -0
  651. package/dist/users/errors.js.map +1 -0
  652. package/dist/users/gdpr.d.ts +110 -0
  653. package/dist/users/gdpr.d.ts.map +1 -0
  654. package/dist/users/gdpr.js +211 -0
  655. package/dist/users/gdpr.js.map +1 -0
  656. package/dist/users/index.d.ts +20 -0
  657. package/dist/users/index.d.ts.map +1 -0
  658. package/dist/users/index.js +19 -0
  659. package/dist/users/index.js.map +1 -0
  660. package/dist/users/password.d.ts +85 -0
  661. package/dist/users/password.d.ts.map +1 -0
  662. package/dist/users/password.js +138 -0
  663. package/dist/users/password.js.map +1 -0
  664. package/dist/users/repository.d.ts +263 -0
  665. package/dist/users/repository.d.ts.map +1 -0
  666. package/dist/users/repository.js +499 -0
  667. package/dist/users/repository.js.map +1 -0
  668. package/dist/users/service.d.ts +299 -0
  669. package/dist/users/service.d.ts.map +1 -0
  670. package/dist/users/service.js +698 -0
  671. package/dist/users/service.js.map +1 -0
  672. package/dist/users/types.d.ts +220 -0
  673. package/dist/users/types.d.ts.map +1 -0
  674. package/dist/users/types.js +77 -0
  675. package/dist/users/types.js.map +1 -0
  676. package/locales/default/en/common.json +10 -0
  677. package/locales/default/en/consent.json +13 -0
  678. package/locales/default/en/emails.json +17 -0
  679. package/locales/default/en/errors.json +21 -0
  680. package/locales/default/en/forgot-password.json +11 -0
  681. package/locales/default/en/invitation.json +18 -0
  682. package/locales/default/en/login.json +17 -0
  683. package/locales/default/en/logout.json +9 -0
  684. package/locales/default/en/magic-link.json +12 -0
  685. package/locales/default/en/reset-password.json +16 -0
  686. package/locales/default/en/two-factor.json +29 -0
  687. package/migrations/.gitkeep +0 -0
  688. package/migrations/001_extensions.sql +22 -0
  689. package/migrations/002_organizations.sql +43 -0
  690. package/migrations/003_applications.sql +50 -0
  691. package/migrations/004_clients.sql +74 -0
  692. package/migrations/005_users.sql +119 -0
  693. package/migrations/006_roles_permissions.sql +80 -0
  694. package/migrations/007_custom_claims.sql +55 -0
  695. package/migrations/008_config.sql +51 -0
  696. package/migrations/009_audit_log.sql +31 -0
  697. package/migrations/010_oidc_adapter.sql +34 -0
  698. package/migrations/011_seed.sql +53 -0
  699. package/migrations/012_two_factor.sql +88 -0
  700. package/migrations/013_client_secret_sha256.sql +22 -0
  701. package/migrations/014_login_methods.sql +34 -0
  702. package/migrations/015_signing_key_encryption.sql +20 -0
  703. package/migrations/016_failed_login_count.sql +27 -0
  704. package/migrations/017_audit_retention.sql +11 -0
  705. package/migrations/018_admin_api_enhancements.sql +78 -0
  706. package/migrations/019_invitation_details.sql +27 -0
  707. package/migrations/020_two_factor_admin_permission.sql +108 -0
  708. package/migrations/021_auth_recovery_jobs.sql +74 -0
  709. package/migrations/022_recovery_artifact_ownership.sql +25 -0
  710. package/migrations/023_magic_link_authority.sql +39 -0
  711. package/package.json +106 -0
  712. package/templates/default/emails/invitation.hbs +39 -0
  713. package/templates/default/emails/invitation.txt.hbs +18 -0
  714. package/templates/default/emails/magic-link.hbs +30 -0
  715. package/templates/default/emails/magic-link.txt.hbs +11 -0
  716. package/templates/default/emails/otp-code.hbs +31 -0
  717. package/templates/default/emails/otp-code.txt.hbs +15 -0
  718. package/templates/default/emails/password-changed.hbs +24 -0
  719. package/templates/default/emails/password-changed.txt.hbs +7 -0
  720. package/templates/default/emails/password-reset.hbs +30 -0
  721. package/templates/default/emails/password-reset.txt.hbs +11 -0
  722. package/templates/default/emails/welcome.hbs +25 -0
  723. package/templates/default/emails/welcome.txt.hbs +9 -0
  724. package/templates/default/layouts/main.hbs +49 -0
  725. package/templates/default/pages/accept-invite.hbs +25 -0
  726. package/templates/default/pages/consent.hbs +27 -0
  727. package/templates/default/pages/error.hbs +15 -0
  728. package/templates/default/pages/forgot-password.hbs +21 -0
  729. package/templates/default/pages/invite-expired.hbs +6 -0
  730. package/templates/default/pages/invite-success.hbs +9 -0
  731. package/templates/default/pages/login.hbs +108 -0
  732. package/templates/default/pages/logout-success.hbs +5 -0
  733. package/templates/default/pages/logout.hbs +24 -0
  734. package/templates/default/pages/magic-link-sent.hbs +10 -0
  735. package/templates/default/pages/magic-link-success.hbs +17 -0
  736. package/templates/default/pages/reset-password.hbs +20 -0
  737. package/templates/default/pages/reset-success.hbs +9 -0
  738. package/templates/default/pages/two-factor-setup.hbs +65 -0
  739. package/templates/default/pages/two-factor-verify.hbs +77 -0
  740. package/templates/default/partials/flash-messages.hbs +10 -0
  741. package/templates/default/partials/footer.hbs +4 -0
  742. package/templates/default/partials/header.hbs +8 -0
@@ -0,0 +1,155 @@
1
+ /**
2
+ * ETag generation and optimistic concurrency control utility.
3
+ *
4
+ * Provides ETag generation from entity metadata and If-Match header
5
+ * validation for optimistic concurrency on PUT/PATCH endpoints.
6
+ *
7
+ * ETags use MD5 hashing of entity type + ID + updatedAt timestamp.
8
+ * MD5 is used for speed, not security — ETags are not secrets, they
9
+ * are cache/concurrency markers. Weak ETags (W/"...") are used since
10
+ * the comparison is semantic equivalence, not byte-identical content.
11
+ *
12
+ * Integration pattern:
13
+ * GET /:id → setETagHeader(ctx, 'entity', id, updatedAt)
14
+ * PUT /:id → checkIfMatch(ctx, 'entity', id, current.updatedAt, current)
15
+ *
16
+ * @module lib/etag
17
+ */
18
+ import { createHash } from 'node:crypto';
19
+ // ============================================================================
20
+ // ETag Generation
21
+ // ============================================================================
22
+ /**
23
+ * Generate a weak ETag from entity type, ID, and updatedAt timestamp.
24
+ *
25
+ * The ETag is a deterministic MD5 hash of the concatenation:
26
+ * `${entityType}:${id}:${updatedAt.toISOString()}`
27
+ *
28
+ * Format: `W/"<first 16 hex chars of MD5>"` (weak ETag, 64-bit precision)
29
+ *
30
+ * @param entityType - Entity type string (e.g., 'organization', 'user')
31
+ * @param id - Entity UUID
32
+ * @param updatedAt - Entity's last modification timestamp
33
+ * @returns Weak ETag string (e.g., `W/"a1b2c3d4e5f67890"`)
34
+ */
35
+ export function generateETag(entityType, id, updatedAt) {
36
+ const input = `${entityType}:${id}:${updatedAt.toISOString()}`;
37
+ const hash = createHash('md5').update(input).digest('hex').substring(0, 16);
38
+ return `W/"${hash}"`;
39
+ }
40
+ // ============================================================================
41
+ // ETag Comparison
42
+ // ============================================================================
43
+ /**
44
+ * Compare an If-Match header value against the current ETag.
45
+ *
46
+ * Returns true if the ETags match (safe to proceed with the update).
47
+ * Handles:
48
+ * - Quoted strings: `"abc"` matches `W/"abc"` and vice versa
49
+ * - Weak prefix: `W/"abc"` is treated equivalently to `"abc"` for weak comparison
50
+ * - Wildcard: `*` always matches
51
+ * - Multiple ETags: `"abc", "def"` matches if any one matches
52
+ *
53
+ * @param ifMatchHeader - The value of the If-Match HTTP header
54
+ * @param currentETag - The current entity's ETag
55
+ * @returns true if they match
56
+ */
57
+ export function matchesETag(ifMatchHeader, currentETag) {
58
+ const trimmed = ifMatchHeader.trim();
59
+ // Wildcard matches everything
60
+ if (trimmed === '*') {
61
+ return true;
62
+ }
63
+ // Extract the hash portion from the current ETag for comparison
64
+ const currentHash = extractHash(currentETag);
65
+ if (!currentHash) {
66
+ return false;
67
+ }
68
+ // Split on comma for multiple ETags: If-Match: "a", "b", "c"
69
+ const candidates = trimmed.split(',').map((s) => s.trim());
70
+ return candidates.some((candidate) => {
71
+ const candidateHash = extractHash(candidate);
72
+ return candidateHash !== null && candidateHash === currentHash;
73
+ });
74
+ }
75
+ /**
76
+ * Extract the raw hash string from an ETag value.
77
+ *
78
+ * Strips the W/ prefix and surrounding quotes:
79
+ * `W/"abc123"` → `abc123`
80
+ * `"abc123"` → `abc123`
81
+ * `abc123` → `abc123`
82
+ *
83
+ * @param etag - ETag value (possibly with W/ prefix and quotes)
84
+ * @returns The raw hash string, or null if empty/invalid
85
+ */
86
+ function extractHash(etag) {
87
+ let value = etag.trim();
88
+ // Remove weak prefix
89
+ if (value.startsWith('W/')) {
90
+ value = value.substring(2);
91
+ }
92
+ // Remove surrounding quotes
93
+ if (value.startsWith('"') && value.endsWith('"')) {
94
+ value = value.substring(1, value.length - 1);
95
+ }
96
+ return value.length > 0 ? value : null;
97
+ }
98
+ /**
99
+ * Set the ETag header on a GET response.
100
+ *
101
+ * Call this in GET-single-entity handlers after retrieving the entity:
102
+ * ```typescript
103
+ * const org = await getOrganization(id);
104
+ * setETagHeader(ctx, 'organization', id, org.updatedAt);
105
+ * ctx.body = { data: org };
106
+ * ```
107
+ *
108
+ * @param ctx - Koa context (or compatible object with set/get methods)
109
+ * @param entityType - Entity type string (e.g., 'organization')
110
+ * @param id - Entity UUID
111
+ * @param updatedAt - Entity's last modification timestamp
112
+ */
113
+ export function setETagHeader(ctx, entityType, id, updatedAt) {
114
+ const etag = generateETag(entityType, id, updatedAt);
115
+ ctx.set('ETag', etag);
116
+ }
117
+ /**
118
+ * Check the If-Match header on a PUT/PATCH request.
119
+ *
120
+ * If the If-Match header is present and does NOT match the current entity's
121
+ * ETag, sets a 409 Conflict response with the current entity state and
122
+ * returns false (caller should `return` without proceeding).
123
+ *
124
+ * If the header is absent or matches, returns true (safe to proceed).
125
+ * This makes If-Match opt-in — backward compatible with clients that
126
+ * don't send it.
127
+ *
128
+ * @param ctx - Koa context
129
+ * @param entityType - Entity type string
130
+ * @param id - Entity UUID
131
+ * @param updatedAt - Entity's current updatedAt timestamp
132
+ * @param currentEntity - The current entity (included in 409 response body)
133
+ * @returns true if the update may proceed, false if 409 was sent
134
+ */
135
+ export function checkIfMatch(ctx, entityType, id, updatedAt, currentEntity) {
136
+ const ifMatchHeader = ctx.get('If-Match');
137
+ if (!ifMatchHeader) {
138
+ // No If-Match header — backward compatible, proceed without check
139
+ return true;
140
+ }
141
+ const currentETag = generateETag(entityType, id, updatedAt);
142
+ if (matchesETag(ifMatchHeader, currentETag)) {
143
+ return true;
144
+ }
145
+ // Conflict — entity was modified since the client's last read
146
+ ctx.status = 409;
147
+ ctx.body = {
148
+ error: 'Conflict',
149
+ message: 'Entity has been modified since your last read. Please refresh and try again.',
150
+ currentEntity,
151
+ currentETag,
152
+ };
153
+ return false;
154
+ }
155
+ //# sourceMappingURL=etag.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"etag.js","sourceRoot":"","sources":["../../src/lib/etag.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,44 @@
1
+ /**
2
+ * Image validation for branding asset uploads.
3
+ *
4
+ * Validates uploaded images using magic byte signature detection, size limits,
5
+ * and SVG sanitization. This prevents:
6
+ * - Disguised file uploads (wrong content-type vs actual content)
7
+ * - Oversized files
8
+ * - SVG-based XSS via embedded scripts or event handlers
9
+ *
10
+ * @module image-validator
11
+ * @see 06-bulk-operations-branding.md
12
+ */
13
+ export type AssetType = 'logo' | 'favicon';
14
+ /** Result of image validation — either valid or contains an error message */
15
+ export interface ImageValidationResult {
16
+ valid: boolean;
17
+ error?: string;
18
+ /** The detected content type from magic bytes (may differ from declared) */
19
+ detectedType?: string;
20
+ /** True if SVG was sanitized (scripts removed) */
21
+ sanitized?: boolean;
22
+ /** Sanitized buffer (only for SVG; otherwise same as input) */
23
+ data?: Buffer;
24
+ }
25
+ /**
26
+ * Validate an uploaded image buffer against content type, size, and content rules.
27
+ *
28
+ * For binary formats (PNG, JPEG, WebP, ICO), validates magic byte signatures.
29
+ * For SVG, validates XML structure and sanitizes dangerous content (scripts,
30
+ * event handlers, javascript: URIs).
31
+ *
32
+ * @param buffer - Raw file data
33
+ * @param contentType - Declared content type from the upload
34
+ * @param assetType - Whether this is a logo or favicon (determines size limit)
35
+ * @returns Validation result with optional sanitized data for SVGs
36
+ */
37
+ export declare function validateImage(buffer: Buffer, contentType: string, assetType: AssetType): ImageValidationResult;
38
+ /**
39
+ * Get the size limit for an asset type.
40
+ * @param assetType - The asset type
41
+ * @returns Size limit in bytes
42
+ */
43
+ export declare function getSizeLimit(assetType: AssetType): number;
44
+ //# sourceMappingURL=image-validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-validator.d.ts","sourceRoot":"","sources":["../../src/lib/image-validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAMH,MAAM,MAAM,SAAS,GAAG,MAAM,GAAG,SAAS,CAAC;AAE3C,6EAA6E;AAC7E,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,4EAA4E;IAC5E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kDAAkD;IAClD,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAgDD;;;;;;;;;;;GAWG;AACH,wBAAgB,aAAa,CAC3B,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,SAAS,GACnB,qBAAqB,CA8BvB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,SAAS,GAAG,MAAM,CAEzD"}
@@ -0,0 +1,204 @@
1
+ /**
2
+ * Image validation for branding asset uploads.
3
+ *
4
+ * Validates uploaded images using magic byte signature detection, size limits,
5
+ * and SVG sanitization. This prevents:
6
+ * - Disguised file uploads (wrong content-type vs actual content)
7
+ * - Oversized files
8
+ * - SVG-based XSS via embedded scripts or event handlers
9
+ *
10
+ * @module image-validator
11
+ * @see 06-bulk-operations-branding.md
12
+ */
13
+ // ============================================================================
14
+ // Constants
15
+ // ============================================================================
16
+ /** Size limits per asset type (in bytes) */
17
+ const SIZE_LIMITS = {
18
+ logo: 2 * 1024 * 1024, // 2 MB — logos can be larger for hi-DPI
19
+ favicon: 512 * 1024, // 512 KB — favicons should be small
20
+ };
21
+ /**
22
+ * Magic byte signatures for supported image formats.
23
+ * Each entry maps a content type to its expected leading bytes.
24
+ * SVG is XML-based and has no magic bytes — validated separately.
25
+ */
26
+ const MAGIC_SIGNATURES = [
27
+ { type: 'image/png', bytes: [0x89, 0x50, 0x4E, 0x47] },
28
+ { type: 'image/jpeg', bytes: [0xFF, 0xD8, 0xFF] },
29
+ { type: 'image/webp', bytes: [0x52, 0x49, 0x46, 0x46] },
30
+ { type: 'image/x-icon', bytes: [0x00, 0x00, 0x01, 0x00] },
31
+ { type: 'image/vnd.microsoft.icon', bytes: [0x00, 0x00, 0x01, 0x00] },
32
+ ];
33
+ /** Content types that are allowed for upload */
34
+ const ALLOWED_TYPES = new Set([
35
+ 'image/png',
36
+ 'image/jpeg',
37
+ 'image/svg+xml',
38
+ 'image/webp',
39
+ 'image/x-icon',
40
+ 'image/vnd.microsoft.icon',
41
+ ]);
42
+ /**
43
+ * Dangerous SVG elements and attributes that could enable XSS.
44
+ * These are stripped during sanitization to prevent stored XSS attacks.
45
+ */
46
+ const SVG_DANGEROUS_ELEMENTS = /(<script[\s>][\s\S]*?<\/script>|<script[\s>][\s\S]*?\/>)/gi;
47
+ const SVG_EVENT_HANDLERS = /\s+on\w+\s*=\s*(?:"[^"]*"|'[^']*'|[^\s>]*)/gi;
48
+ const SVG_JAVASCRIPT_HREFS = /\s+(href|xlink:href)\s*=\s*["']javascript:[^"']*["']/gi;
49
+ const SVG_DATA_URIS_SCRIPT = /\s+(href|xlink:href)\s*=\s*["']data:text\/html[^"']*["']/gi;
50
+ // ============================================================================
51
+ // Public API
52
+ // ============================================================================
53
+ /**
54
+ * Validate an uploaded image buffer against content type, size, and content rules.
55
+ *
56
+ * For binary formats (PNG, JPEG, WebP, ICO), validates magic byte signatures.
57
+ * For SVG, validates XML structure and sanitizes dangerous content (scripts,
58
+ * event handlers, javascript: URIs).
59
+ *
60
+ * @param buffer - Raw file data
61
+ * @param contentType - Declared content type from the upload
62
+ * @param assetType - Whether this is a logo or favicon (determines size limit)
63
+ * @returns Validation result with optional sanitized data for SVGs
64
+ */
65
+ export function validateImage(buffer, contentType, assetType) {
66
+ // Check content type is allowed
67
+ if (!ALLOWED_TYPES.has(contentType)) {
68
+ return {
69
+ valid: false,
70
+ error: `Unsupported content type: ${contentType}. Allowed: ${[...ALLOWED_TYPES].join(', ')}`,
71
+ };
72
+ }
73
+ // Check buffer is not empty
74
+ if (!buffer || buffer.length === 0) {
75
+ return { valid: false, error: 'Image data cannot be empty' };
76
+ }
77
+ // Check size limit for the asset type
78
+ const sizeLimit = SIZE_LIMITS[assetType];
79
+ if (buffer.length > sizeLimit) {
80
+ return {
81
+ valid: false,
82
+ error: `File too large: ${buffer.length} bytes. Maximum for ${assetType}: ${sizeLimit} bytes (${formatBytes(sizeLimit)})`,
83
+ };
84
+ }
85
+ // SVG validation is content-based (no magic bytes)
86
+ if (contentType === 'image/svg+xml') {
87
+ return validateAndSanitizeSvg(buffer);
88
+ }
89
+ // Binary image format — validate magic bytes
90
+ return validateMagicBytes(buffer, contentType);
91
+ }
92
+ /**
93
+ * Get the size limit for an asset type.
94
+ * @param assetType - The asset type
95
+ * @returns Size limit in bytes
96
+ */
97
+ export function getSizeLimit(assetType) {
98
+ return SIZE_LIMITS[assetType];
99
+ }
100
+ // ============================================================================
101
+ // Internal helpers
102
+ // ============================================================================
103
+ /**
104
+ * Validate a binary image by checking its magic byte signature matches
105
+ * the declared content type. Prevents uploading a PNG disguised as a JPEG, etc.
106
+ */
107
+ function validateMagicBytes(buffer, contentType) {
108
+ const signature = MAGIC_SIGNATURES.find((sig) => sig.type === contentType);
109
+ if (!signature) {
110
+ // No signature defined for this type — allow it (shouldn't happen due to ALLOWED_TYPES check)
111
+ return { valid: true, detectedType: contentType, data: buffer };
112
+ }
113
+ // Check that buffer is at least long enough for the signature
114
+ if (buffer.length < signature.bytes.length) {
115
+ return {
116
+ valid: false,
117
+ error: `File too small to be a valid ${contentType} image`,
118
+ };
119
+ }
120
+ // Compare magic bytes
121
+ const matches = signature.bytes.every((byte, i) => buffer[i] === byte);
122
+ if (!matches) {
123
+ // Try to detect what the file actually is
124
+ const detected = detectContentType(buffer);
125
+ return {
126
+ valid: false,
127
+ error: `File content does not match declared type ${contentType}${detected ? `. Detected: ${detected}` : ''}`,
128
+ detectedType: detected ?? undefined,
129
+ };
130
+ }
131
+ return { valid: true, detectedType: contentType, data: buffer };
132
+ }
133
+ /**
134
+ * Validate SVG content and sanitize dangerous elements.
135
+ * SVGs are XML-based, so we check for script tags, event handlers,
136
+ * and javascript: URIs that could enable stored XSS.
137
+ */
138
+ function validateAndSanitizeSvg(buffer) {
139
+ let content;
140
+ try {
141
+ content = buffer.toString('utf-8');
142
+ }
143
+ catch {
144
+ return { valid: false, error: 'SVG file contains invalid UTF-8 encoding' };
145
+ }
146
+ // Basic SVG structure check — must contain an <svg element
147
+ if (!/<svg[\s>]/i.test(content)) {
148
+ return { valid: false, error: 'File does not appear to be a valid SVG (no <svg> element found)' };
149
+ }
150
+ // Sanitize: strip dangerous elements and attributes
151
+ let sanitized = content;
152
+ let wasSanitized = false;
153
+ // Remove <script> tags and their content
154
+ if (SVG_DANGEROUS_ELEMENTS.test(sanitized)) {
155
+ sanitized = sanitized.replace(SVG_DANGEROUS_ELEMENTS, '');
156
+ wasSanitized = true;
157
+ }
158
+ // Remove on* event handler attributes (onclick, onload, onerror, etc.)
159
+ if (SVG_EVENT_HANDLERS.test(sanitized)) {
160
+ sanitized = sanitized.replace(SVG_EVENT_HANDLERS, '');
161
+ wasSanitized = true;
162
+ }
163
+ // Remove javascript: URIs in href/xlink:href attributes
164
+ if (SVG_JAVASCRIPT_HREFS.test(sanitized)) {
165
+ sanitized = sanitized.replace(SVG_JAVASCRIPT_HREFS, '');
166
+ wasSanitized = true;
167
+ }
168
+ // Remove data:text/html URIs (can embed scripts)
169
+ if (SVG_DATA_URIS_SCRIPT.test(sanitized)) {
170
+ sanitized = sanitized.replace(SVG_DATA_URIS_SCRIPT, '');
171
+ wasSanitized = true;
172
+ }
173
+ return {
174
+ valid: true,
175
+ detectedType: 'image/svg+xml',
176
+ sanitized: wasSanitized,
177
+ data: Buffer.from(sanitized, 'utf-8'),
178
+ };
179
+ }
180
+ /**
181
+ * Attempt to detect the actual content type of a buffer by its magic bytes.
182
+ * Returns null if no known format is detected.
183
+ */
184
+ function detectContentType(buffer) {
185
+ for (const sig of MAGIC_SIGNATURES) {
186
+ if (buffer.length >= sig.bytes.length) {
187
+ const matches = sig.bytes.every((byte, i) => buffer[i] === byte);
188
+ if (matches)
189
+ return sig.type;
190
+ }
191
+ }
192
+ return null;
193
+ }
194
+ /**
195
+ * Format bytes into a human-readable string (e.g., "512 KB", "2 MB").
196
+ */
197
+ function formatBytes(bytes) {
198
+ if (bytes >= 1024 * 1024)
199
+ return `${(bytes / (1024 * 1024)).toFixed(0)} MB`;
200
+ if (bytes >= 1024)
201
+ return `${(bytes / 1024).toFixed(0)} KB`;
202
+ return `${bytes} bytes`;
203
+ }
204
+ //# sourceMappingURL=image-validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"image-validator.js","sourceRoot":"","sources":["../../src/lib/image-validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ /** Observer for ephemeral, in-process validation of actual structured logger calls. */
2
+ export type OperationalLogObserver = (serializedArguments: string) => void;
3
+ /**
4
+ * Observe arguments delivered to the production logger boundary.
5
+ *
6
+ * This is intended for owner-controlled diagnostics and executable privacy validation. Observers
7
+ * are process-local, receive no replay buffer, and must detach immediately after their bounded
8
+ * operation. They cannot alter, suppress, or replace the actual log write.
9
+ *
10
+ * @param observer - Callback receiving one JSON representation per logger call.
11
+ * @returns A function which removes exactly this observer.
12
+ */
13
+ export declare function observeOperationalLogOutput(observer: OperationalLogObserver): () => void;
14
+ export declare const logger: import("pino").Logger<never, boolean>;
15
+ //# sourceMappingURL=logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"AAEA,uFAAuF;AACvF,MAAM,MAAM,sBAAsB,GAAG,CAAC,mBAAmB,EAAE,MAAM,KAAK,IAAI,CAAC;AAI3E;;;;;;;;;GASG;AACH,wBAAgB,2BAA2B,CAAC,QAAQ,EAAE,sBAAsB,GAAG,MAAM,IAAI,CAGxF;AAKD,eAAO,MAAM,MAAM,uCAiDjB,CAAC"}
@@ -0,0 +1,84 @@
1
+ import { pino, stdSerializers } from 'pino';
2
+ const operationalLogObservers = new Set();
3
+ /**
4
+ * Observe arguments delivered to the production logger boundary.
5
+ *
6
+ * This is intended for owner-controlled diagnostics and executable privacy validation. Observers
7
+ * are process-local, receive no replay buffer, and must detach immediately after their bounded
8
+ * operation. They cannot alter, suppress, or replace the actual log write.
9
+ *
10
+ * @param observer - Callback receiving one JSON representation per logger call.
11
+ * @returns A function which removes exactly this observer.
12
+ */
13
+ export function observeOperationalLogOutput(observer) {
14
+ operationalLogObservers.add(observer);
15
+ return () => operationalLogObservers.delete(observer);
16
+ }
17
+ const isProduction = process.env.NODE_ENV === 'production';
18
+ const isTest = process.env.NODE_ENV === 'test';
19
+ export const logger = pino({
20
+ level: process.env.LOG_LEVEL || (isTest ? 'silent' : 'info'),
21
+ transport: !isProduction ? { target: 'pino-pretty', options: { colorize: true } } : undefined,
22
+ serializers: {
23
+ err: stdSerializers.err,
24
+ req: stdSerializers.req,
25
+ res: stdSerializers.res,
26
+ },
27
+ hooks: {
28
+ logMethod(arguments_, method) {
29
+ if (operationalLogObservers.size > 0) {
30
+ const serialized = serializeOperationalLogArguments(arguments_);
31
+ for (const observer of operationalLogObservers)
32
+ observer(serialized);
33
+ }
34
+ return method.apply(this, arguments_);
35
+ },
36
+ },
37
+ // Redact PII and sensitive fields from log output to prevent accidental
38
+ // exposure of credentials, tokens, and personal data. Pino replaces the
39
+ // value at each path with "[Redacted]" before the log line is serialized.
40
+ // Paths use dot-notation with wildcards so nested objects are also covered.
41
+ redact: {
42
+ paths: [
43
+ 'password',
44
+ 'token',
45
+ 'authorization',
46
+ 'cookie',
47
+ 'refresh_token',
48
+ 'client_secret',
49
+ 'req.headers.authorization',
50
+ 'req.headers.cookie',
51
+ '*.password',
52
+ '*.token',
53
+ '*.refresh_token',
54
+ '*.client_secret',
55
+ '*.authorization',
56
+ 'email',
57
+ 'userId',
58
+ 'organizationId',
59
+ 'uid',
60
+ 'interactionUid',
61
+ '*.email',
62
+ '*.userId',
63
+ '*.organizationId',
64
+ '*.uid',
65
+ '*.interactionUid',
66
+ ],
67
+ censor: '[Redacted]',
68
+ },
69
+ });
70
+ /** Serialize one bounded logger invocation without letting observation break the owning request. */
71
+ function serializeOperationalLogArguments(arguments_) {
72
+ try {
73
+ return JSON.stringify(arguments_, (_key, value) => {
74
+ if (value instanceof Error) {
75
+ return { name: value.name, message: value.message, stack: value.stack };
76
+ }
77
+ return value;
78
+ });
79
+ }
80
+ catch {
81
+ return '[unserializable-operational-log]';
82
+ }
83
+ }
84
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/lib/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,cAAc,EAAE,MAAM,MAAM,CAAC;AAK5C,MAAM,uBAAuB,GAAG,IAAI,GAAG,EAA0B,CAAC;AAElE;;;;;;;;;GASG;AACH,MAAM,UAAU,2BAA2B,CAAC,QAAgC;IAC1E,uBAAuB,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACtC,OAAO,GAAG,EAAE,CAAC,uBAAuB,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;AACxD,CAAC;AAED,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,YAAY,CAAC;AAC3D,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,MAAM,CAAC;AAE/C,MAAM,CAAC,MAAM,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,EAAE,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC;IAC5D,SAAS,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,aAAa,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC,CAAC,SAAS;IAC7F,WAAW,EAAE;QACX,GAAG,EAAE,cAAc,CAAC,GAAG;QACvB,GAAG,EAAE,cAAc,CAAC,GAAG;QACvB,GAAG,EAAE,cAAc,CAAC,GAAG;KACxB;IACD,KAAK,EAAE;QACL,SAAS,CAAC,UAAU,EAAE,MAAM;YAC1B,IAAI,uBAAuB,CAAC,IAAI,GAAG,CAAC,EAAE,CAAC;gBACrC,MAAM,UAAU,GAAG,gCAAgC,CAAC,UAAU,CAAC,CAAC;gBAChE,KAAK,MAAM,QAAQ,IAAI,uBAAuB;oBAAE,QAAQ,CAAC,UAAU,CAAC,CAAC;YACvE,CAAC;YACD,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;QACxC,CAAC;KACF;IACD,wEAAwE;IACxE,wEAAwE;IACxE,0EAA0E;IAC1E,4EAA4E;IAC5E,MAAM,EAAE;QACN,KAAK,EAAE;YACL,UAAU;YACV,OAAO;YACP,eAAe;YACf,QAAQ;YACR,eAAe;YACf,eAAe;YACf,2BAA2B;YAC3B,oBAAoB;YACpB,YAAY;YACZ,SAAS;YACT,iBAAiB;YACjB,iBAAiB;YACjB,iBAAiB;YACjB,OAAO;YACP,QAAQ;YACR,gBAAgB;YAChB,KAAK;YACL,gBAAgB;YAChB,SAAS;YACT,UAAU;YACV,kBAAkB;YAClB,OAAO;YACP,kBAAkB;SACnB;QACD,MAAM,EAAE,YAAY;KACrB;CACF,CAAC,CAAC;AAEH,oGAAoG;AACpG,SAAS,gCAAgC,CAAC,UAAqB;IAC7D,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,CAAC,IAAI,EAAE,KAAc,EAAE,EAAE;YACzD,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;gBAC3B,OAAO,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE,KAAK,EAAE,KAAK,CAAC,KAAK,EAAE,CAAC;YAC1E,CAAC;YACD,OAAO,KAAK,CAAC;QACf,CAAC,CAAC,CAAC;IACL,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,kCAAkC,CAAC;IAC5C,CAAC;AACH,CAAC"}
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Run database migrations using node-pg-migrate's programmatic API.
3
+ *
4
+ * Executes SQL migrations from the `migrations/` directory against the
5
+ * database specified by `DATABASE_URL`. This is useful for:
6
+ * - Integration test setup (run migrations before tests)
7
+ * - Application startup (auto-migrate in development)
8
+ * - Programmatic rollback in tests
9
+ *
10
+ * @param direction - 'up' to apply pending migrations, 'down' to rollback
11
+ * @param count - Number of migrations to run (undefined = all pending for 'up', 1 for 'down')
12
+ */
13
+ export declare function runMigrations(direction?: 'up' | 'down', count?: number): Promise<void>;
14
+ //# sourceMappingURL=migrator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrator.d.ts","sourceRoot":"","sources":["../../src/lib/migrator.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;GAWG;AACH,wBAAsB,aAAa,CACjC,SAAS,GAAE,IAAI,GAAG,MAAa,EAC/B,KAAK,CAAC,EAAE,MAAM,GACb,OAAO,CAAC,IAAI,CAAC,CAkBf"}
@@ -0,0 +1,34 @@
1
+ import { runner } from 'node-pg-migrate';
2
+ import { config } from '../config/index.js';
3
+ import { logger } from './logger.js';
4
+ import { getMigrationsDirectory } from './runtime-paths.js';
5
+ /**
6
+ * Run database migrations using node-pg-migrate's programmatic API.
7
+ *
8
+ * Executes SQL migrations from the `migrations/` directory against the
9
+ * database specified by `DATABASE_URL`. This is useful for:
10
+ * - Integration test setup (run migrations before tests)
11
+ * - Application startup (auto-migrate in development)
12
+ * - Programmatic rollback in tests
13
+ *
14
+ * @param direction - 'up' to apply pending migrations, 'down' to rollback
15
+ * @param count - Number of migrations to run (undefined = all pending for 'up', 1 for 'down')
16
+ */
17
+ export async function runMigrations(direction = 'up', count) {
18
+ const migrationsDir = getMigrationsDirectory();
19
+ const options = {
20
+ databaseUrl: config.databaseUrl,
21
+ migrationsTable: 'pgmigrations',
22
+ dir: migrationsDir,
23
+ direction,
24
+ // For 'up', run all pending migrations; for 'down', default to rolling back 1
25
+ count: count ?? (direction === 'up' ? Infinity : 1),
26
+ // Redirect migration log output to pino logger
27
+ log: (msg) => logger.debug({ migration: true }, msg),
28
+ // Don't decamelize SQL file names — we use snake_case already
29
+ decamelize: false,
30
+ };
31
+ await runner(options);
32
+ logger.info({ direction, count }, 'Migrations complete');
33
+ }
34
+ //# sourceMappingURL=migrator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"migrator.js","sourceRoot":"","sources":["../../src/lib/migrator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,iBAAiB,CAAC;AAEzC,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AACrC,OAAO,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAE5D;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,SAAS,GAAkB,IAAI,EAC/B,KAAc;IAEd,MAAM,aAAa,GAAG,sBAAsB,EAAE,CAAC;IAE/C,MAAM,OAAO,GAAiB;QAC5B,WAAW,EAAE,MAAM,CAAC,WAAW;QAC/B,eAAe,EAAE,cAAc;QAC/B,GAAG,EAAE,aAAa;QAClB,SAAS;QACT,8EAA8E;QAC9E,KAAK,EAAE,KAAK,IAAI,CAAC,SAAS,KAAK,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;QACnD,+CAA+C;QAC/C,GAAG,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,GAAG,CAAC;QAC5D,8DAA8D;QAC9D,UAAU,EAAE,KAAK;KAClB,CAAC;IAEF,MAAM,MAAM,CAAC,OAAO,CAAC,CAAC;IACtB,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,qBAAqB,CAAC,CAAC;AAC3D,CAAC"}
@@ -0,0 +1,5 @@
1
+ import { Redis } from 'ioredis';
2
+ export declare function connectRedis(): Promise<Redis>;
3
+ export declare function getRedis(): Redis;
4
+ export declare function disconnectRedis(): Promise<void>;
5
+ //# sourceMappingURL=redis.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis.d.ts","sourceRoot":"","sources":["../../src/lib/redis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAMhC,wBAAsB,YAAY,IAAI,OAAO,CAAC,KAAK,CAAC,CAcnD;AAED,wBAAgB,QAAQ,IAAI,KAAK,CAGhC;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAMrD"}
@@ -0,0 +1,29 @@
1
+ import { Redis } from 'ioredis';
2
+ import { config } from '../config/index.js';
3
+ import { logger } from './logger.js';
4
+ let redis = null;
5
+ export async function connectRedis() {
6
+ redis = new Redis(config.redisUrl, {
7
+ maxRetriesPerRequest: 3,
8
+ lazyConnect: true,
9
+ });
10
+ await redis.connect();
11
+ logger.info('Redis connected');
12
+ redis.on('error', (err) => {
13
+ logger.error({ err }, 'Redis error');
14
+ });
15
+ return redis;
16
+ }
17
+ export function getRedis() {
18
+ if (!redis)
19
+ throw new Error('Redis not connected. Call connectRedis() first.');
20
+ return redis;
21
+ }
22
+ export async function disconnectRedis() {
23
+ if (redis) {
24
+ await redis.quit();
25
+ redis = null;
26
+ logger.info('Redis disconnected');
27
+ }
28
+ }
29
+ //# sourceMappingURL=redis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redis.js","sourceRoot":"","sources":["../../src/lib/redis.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,SAAS,CAAC;AAChC,OAAO,EAAE,MAAM,EAAE,MAAM,oBAAoB,CAAC;AAC5C,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAErC,IAAI,KAAK,GAAiB,IAAI,CAAC;AAE/B,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,KAAK,GAAG,IAAI,KAAK,CAAC,MAAM,CAAC,QAAQ,EAAE;QACjC,oBAAoB,EAAE,CAAC;QACvB,WAAW,EAAE,IAAI;KAClB,CAAC,CAAC;IAEH,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC;IACtB,MAAM,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC;IAE/B,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAU,EAAE,EAAE;QAC/B,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,EAAE,EAAE,aAAa,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,UAAU,QAAQ;IACtB,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,iDAAiD,CAAC,CAAC;IAC/E,OAAO,KAAK,CAAC;AACf,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,KAAK,CAAC,IAAI,EAAE,CAAC;QACnB,KAAK,GAAG,IAAI,CAAC;QACb,MAAM,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;IACpC,CAAC;AACH,CAAC"}