@bgord/bun 1.9.0 → 1.9.2

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 (546) hide show
  1. package/dist/basic-auth-password.vo.d.ts +1 -1
  2. package/dist/basic-auth-password.vo.d.ts.map +1 -1
  3. package/dist/basic-auth-password.vo.js +1 -1
  4. package/dist/basic-auth-password.vo.js.map +1 -1
  5. package/dist/basic-auth-username.vo.d.ts +1 -1
  6. package/dist/basic-auth-username.vo.d.ts.map +1 -1
  7. package/dist/basic-auth-username.vo.js +1 -1
  8. package/dist/basic-auth-username.vo.js.map +1 -1
  9. package/dist/binary.vo.d.ts +1 -1
  10. package/dist/binary.vo.d.ts.map +1 -1
  11. package/dist/binary.vo.js +1 -1
  12. package/dist/binary.vo.js.map +1 -1
  13. package/dist/cache-subject-segment-env.strategy.d.ts +3 -3
  14. package/dist/client-ip.vo.d.ts +1 -1
  15. package/dist/client-ip.vo.d.ts.map +1 -1
  16. package/dist/client-ip.vo.js +1 -1
  17. package/dist/client-ip.vo.js.map +1 -1
  18. package/dist/client-user-agent.vo.d.ts +1 -1
  19. package/dist/client-user-agent.vo.d.ts.map +1 -1
  20. package/dist/client-user-agent.vo.js +1 -1
  21. package/dist/client-user-agent.vo.js.map +1 -1
  22. package/dist/command.types.d.ts +1 -1
  23. package/dist/command.types.d.ts.map +1 -1
  24. package/dist/commit-sha-value.vo.d.ts +1 -1
  25. package/dist/commit-sha-value.vo.d.ts.map +1 -1
  26. package/dist/commit-sha-value.vo.js +1 -1
  27. package/dist/commit-sha-value.vo.js.map +1 -1
  28. package/dist/correlation-id.vo.d.ts +1 -1
  29. package/dist/correlation-id.vo.d.ts.map +1 -1
  30. package/dist/dispatching-event-store.d.ts +1 -1
  31. package/dist/dispatching-event-store.d.ts.map +1 -1
  32. package/dist/encryption-key-value.vo.d.ts +1 -1
  33. package/dist/encryption-key-value.vo.d.ts.map +1 -1
  34. package/dist/encryption-key-value.vo.js +1 -1
  35. package/dist/encryption-key-value.vo.js.map +1 -1
  36. package/dist/environment-loader-encrypted.adapter.d.ts +4 -4
  37. package/dist/environment-loader-encrypted.adapter.d.ts.map +1 -1
  38. package/dist/environment-loader-noop.adapter.d.ts +3 -3
  39. package/dist/environment-loader-noop.adapter.d.ts.map +1 -1
  40. package/dist/environment-loader-process-safe.adapter.d.ts +4 -4
  41. package/dist/environment-loader-process-safe.adapter.d.ts.map +1 -1
  42. package/dist/environment-loader-process.adapter.d.ts +4 -4
  43. package/dist/environment-loader-process.adapter.d.ts.map +1 -1
  44. package/dist/environment-loader.port.d.ts +3 -3
  45. package/dist/environment-loader.port.d.ts.map +1 -1
  46. package/dist/event-envelope.d.ts +1 -1
  47. package/dist/event-envelope.d.ts.map +1 -1
  48. package/dist/event-envelope.js +1 -1
  49. package/dist/event-envelope.js.map +1 -1
  50. package/dist/event-handler-bare.strategy.d.ts +1 -1
  51. package/dist/event-handler-bare.strategy.d.ts.map +1 -1
  52. package/dist/event-handler-noop.strategy.d.ts +1 -1
  53. package/dist/event-handler-noop.strategy.d.ts.map +1 -1
  54. package/dist/event-handler-with-logger.strategy.d.ts +1 -1
  55. package/dist/event-handler-with-logger.strategy.d.ts.map +1 -1
  56. package/dist/event-handler.strategy.d.ts +1 -1
  57. package/dist/event-handler.strategy.d.ts.map +1 -1
  58. package/dist/event-store.d.ts +1 -1
  59. package/dist/event-store.d.ts.map +1 -1
  60. package/dist/event-stream.vo.d.ts +1 -1
  61. package/dist/event-stream.vo.d.ts.map +1 -1
  62. package/dist/event-stream.vo.js +1 -1
  63. package/dist/event-stream.vo.js.map +1 -1
  64. package/dist/event.types.d.ts +1 -1
  65. package/dist/event.types.d.ts.map +1 -1
  66. package/dist/hash-value.vo.d.ts +1 -1
  67. package/dist/hash-value.vo.d.ts.map +1 -1
  68. package/dist/hash-value.vo.js +1 -1
  69. package/dist/hash-value.vo.js.map +1 -1
  70. package/dist/hcaptcha-secret-key.vo.d.ts +1 -1
  71. package/dist/hcaptcha-secret-key.vo.d.ts.map +1 -1
  72. package/dist/hcaptcha-secret-key.vo.js +1 -1
  73. package/dist/hcaptcha-secret-key.vo.js.map +1 -1
  74. package/dist/hcaptcha-site-key.vo.d.ts +1 -1
  75. package/dist/hcaptcha-site-key.vo.d.ts.map +1 -1
  76. package/dist/hcaptcha-site-key.vo.js +1 -1
  77. package/dist/hcaptcha-site-key.vo.js.map +1 -1
  78. package/dist/healthcheck.service.d.ts +3 -3
  79. package/dist/logger-winston-local.adapter.d.ts.map +1 -1
  80. package/dist/logger-winston-local.adapter.js +2 -1
  81. package/dist/logger-winston-local.adapter.js.map +1 -1
  82. package/dist/logger-winston-production.adapter.d.ts.map +1 -1
  83. package/dist/logger-winston-production.adapter.js +3 -2
  84. package/dist/logger-winston-production.adapter.js.map +1 -1
  85. package/dist/logger-winston.adapter.d.ts +2 -2
  86. package/dist/logger.port.d.ts +3 -3
  87. package/dist/logger.port.d.ts.map +1 -1
  88. package/dist/logger.port.js +1 -1
  89. package/dist/logger.port.js.map +1 -1
  90. package/dist/mailer-content-html.vo.d.ts +1 -1
  91. package/dist/mailer-content-html.vo.d.ts.map +1 -1
  92. package/dist/mailer-content-html.vo.js +1 -1
  93. package/dist/mailer-content-html.vo.js.map +1 -1
  94. package/dist/mailer-subject.vo.d.ts +1 -1
  95. package/dist/mailer-subject.vo.d.ts.map +1 -1
  96. package/dist/mailer-subject.vo.js +1 -1
  97. package/dist/mailer-subject.vo.js.map +1 -1
  98. package/dist/modules/history/events/HISTORY_CLEARED_EVENT.d.ts +1 -1
  99. package/dist/modules/history/events/HISTORY_CLEARED_EVENT.d.ts.map +1 -1
  100. package/dist/modules/history/events/HISTORY_CLEARED_EVENT.js +1 -1
  101. package/dist/modules/history/events/HISTORY_CLEARED_EVENT.js.map +1 -1
  102. package/dist/modules/history/events/HISTORY_POPULATED_EVENT.d.ts +1 -1
  103. package/dist/modules/history/events/HISTORY_POPULATED_EVENT.d.ts.map +1 -1
  104. package/dist/modules/history/events/HISTORY_POPULATED_EVENT.js +1 -1
  105. package/dist/modules/history/events/HISTORY_POPULATED_EVENT.js.map +1 -1
  106. package/dist/modules/history/value-objects/history-created-at.d.ts +1 -1
  107. package/dist/modules/history/value-objects/history-created-at.d.ts.map +1 -1
  108. package/dist/modules/history/value-objects/history-operation.d.ts +1 -1
  109. package/dist/modules/history/value-objects/history-operation.d.ts.map +1 -1
  110. package/dist/modules/history/value-objects/history-operation.js +1 -1
  111. package/dist/modules/history/value-objects/history-operation.js.map +1 -1
  112. package/dist/modules/history/value-objects/history-payload.d.ts +1 -1
  113. package/dist/modules/history/value-objects/history-payload.d.ts.map +1 -1
  114. package/dist/modules/history/value-objects/history-payload.js +1 -1
  115. package/dist/modules/history/value-objects/history-payload.js.map +1 -1
  116. package/dist/modules/history/value-objects/history-subject.d.ts +1 -1
  117. package/dist/modules/history/value-objects/history-subject.d.ts.map +1 -1
  118. package/dist/modules/history/value-objects/history-subject.js +1 -1
  119. package/dist/modules/history/value-objects/history-subject.js.map +1 -1
  120. package/dist/modules/history/value-objects/history.d.ts +1 -1
  121. package/dist/modules/history/value-objects/history.d.ts.map +1 -1
  122. package/dist/modules/history/value-objects/history.js +1 -1
  123. package/dist/modules/history/value-objects/history.js.map +1 -1
  124. package/dist/modules/preferences/commands/SET_USER_LANGUAGE_COMMAND.d.ts +1 -1
  125. package/dist/modules/preferences/commands/SET_USER_LANGUAGE_COMMAND.d.ts.map +1 -1
  126. package/dist/modules/preferences/commands/SET_USER_LANGUAGE_COMMAND.js +1 -1
  127. package/dist/modules/preferences/commands/SET_USER_LANGUAGE_COMMAND.js.map +1 -1
  128. package/dist/modules/preferences/events/USER_LANGUAGE_SET_EVENT.d.ts +1 -1
  129. package/dist/modules/preferences/events/USER_LANGUAGE_SET_EVENT.d.ts.map +1 -1
  130. package/dist/modules/preferences/events/USER_LANGUAGE_SET_EVENT.js +1 -1
  131. package/dist/modules/preferences/events/USER_LANGUAGE_SET_EVENT.js.map +1 -1
  132. package/dist/modules/system/events/HOUR_HAS_PASSED_EVENT.d.ts +1 -1
  133. package/dist/modules/system/events/HOUR_HAS_PASSED_EVENT.d.ts.map +1 -1
  134. package/dist/modules/system/events/HOUR_HAS_PASSED_EVENT.js +1 -1
  135. package/dist/modules/system/events/HOUR_HAS_PASSED_EVENT.js.map +1 -1
  136. package/dist/modules/system/events/MINUTE_HAS_PASSED_EVENT.d.ts +1 -1
  137. package/dist/modules/system/events/MINUTE_HAS_PASSED_EVENT.d.ts.map +1 -1
  138. package/dist/modules/system/events/MINUTE_HAS_PASSED_EVENT.js +1 -1
  139. package/dist/modules/system/events/MINUTE_HAS_PASSED_EVENT.js.map +1 -1
  140. package/dist/modules/system/events/SECURITY_VIOLATION_DETECTED_EVENT.d.ts +1 -1
  141. package/dist/modules/system/events/SECURITY_VIOLATION_DETECTED_EVENT.d.ts.map +1 -1
  142. package/dist/modules/system/events/SECURITY_VIOLATION_DETECTED_EVENT.js +1 -1
  143. package/dist/modules/system/events/SECURITY_VIOLATION_DETECTED_EVENT.js.map +1 -1
  144. package/dist/node-env.vo.d.ts +11 -9
  145. package/dist/node-env.vo.d.ts.map +1 -1
  146. package/dist/node-env.vo.js +10 -3
  147. package/dist/node-env.vo.js.map +1 -1
  148. package/dist/nonce-value.vo.d.ts +1 -1
  149. package/dist/nonce-value.vo.d.ts.map +1 -1
  150. package/dist/nonce-value.vo.js +1 -1
  151. package/dist/nonce-value.vo.js.map +1 -1
  152. package/dist/port.vo.d.ts +1 -1
  153. package/dist/port.vo.d.ts.map +1 -1
  154. package/dist/port.vo.js +1 -1
  155. package/dist/port.vo.js.map +1 -1
  156. package/dist/prerequisite-verifier-timezone-utc.adapter.d.ts +1 -1
  157. package/dist/prerequisite-verifier-timezone-utc.adapter.d.ts.map +1 -1
  158. package/dist/prerequisite-verifier-timezone-utc.adapter.js +1 -1
  159. package/dist/prerequisite-verifier-timezone-utc.adapter.js.map +1 -1
  160. package/dist/recaptcha-secret-key.vo.d.ts +1 -1
  161. package/dist/recaptcha-secret-key.vo.d.ts.map +1 -1
  162. package/dist/recaptcha-secret-key.vo.js +1 -1
  163. package/dist/recaptcha-secret-key.vo.js.map +1 -1
  164. package/dist/recaptcha-site-key.vo.d.ts +1 -1
  165. package/dist/recaptcha-site-key.vo.d.ts.map +1 -1
  166. package/dist/recaptcha-site-key.vo.js +1 -1
  167. package/dist/recaptcha-site-key.vo.js.map +1 -1
  168. package/dist/security-countermeasure-name.vo.d.ts +1 -1
  169. package/dist/security-countermeasure-name.vo.d.ts.map +1 -1
  170. package/dist/security-countermeasure-name.vo.js +1 -1
  171. package/dist/security-countermeasure-name.vo.js.map +1 -1
  172. package/dist/security-rule-name.vo.d.ts +1 -1
  173. package/dist/security-rule-name.vo.d.ts.map +1 -1
  174. package/dist/security-rule-name.vo.js +1 -1
  175. package/dist/security-rule-name.vo.js.map +1 -1
  176. package/dist/smtp-host.vo.d.ts +1 -1
  177. package/dist/smtp-host.vo.d.ts.map +1 -1
  178. package/dist/smtp-host.vo.js +1 -1
  179. package/dist/smtp-host.vo.js.map +1 -1
  180. package/dist/smtp-pass.vo.d.ts +1 -1
  181. package/dist/smtp-pass.vo.d.ts.map +1 -1
  182. package/dist/smtp-pass.vo.js +1 -1
  183. package/dist/smtp-pass.vo.js.map +1 -1
  184. package/dist/smtp-port.vo.d.ts +1 -1
  185. package/dist/smtp-port.vo.d.ts.map +1 -1
  186. package/dist/smtp-user.vo.d.ts +1 -1
  187. package/dist/smtp-user.vo.d.ts.map +1 -1
  188. package/dist/smtp-user.vo.js +1 -1
  189. package/dist/smtp-user.vo.js.map +1 -1
  190. package/dist/tsconfig.tsbuildinfo +1 -1
  191. package/dist/uuid.vo.d.ts +1 -1
  192. package/dist/uuid.vo.d.ts.map +1 -1
  193. package/dist/uuid.vo.js +1 -1
  194. package/dist/uuid.vo.js.map +1 -1
  195. package/package.json +4 -3
  196. package/src/antivirus-clamav.adapter.ts +34 -0
  197. package/src/antivirus-noop.adapter.ts +8 -0
  198. package/src/antivirus.port.ts +9 -0
  199. package/src/api-version.middleware.ts +31 -0
  200. package/src/basic-auth-password.vo.ts +17 -0
  201. package/src/basic-auth-username.vo.ts +17 -0
  202. package/src/basic-auth.service.ts +14 -0
  203. package/src/better-auth-logger.service.ts +45 -0
  204. package/src/binary.vo.ts +22 -0
  205. package/src/bots.vo.ts +132 -0
  206. package/src/build-info-repository-file.strategy.ts +23 -0
  207. package/src/build-info-repository-noop.strategy.ts +16 -0
  208. package/src/build-info-repository-package-json.strategy.ts +25 -0
  209. package/src/build-info-repository.strategy.ts +13 -0
  210. package/src/cache-file.service.ts +37 -0
  211. package/src/cache-repository-lru-cache.adapter.ts +58 -0
  212. package/src/cache-repository-node-cache.adapter.ts +32 -0
  213. package/src/cache-repository-noop.adapter.ts +15 -0
  214. package/src/cache-repository.port.ts +11 -0
  215. package/src/cache-resolver-simple.strategy.ts +33 -0
  216. package/src/cache-resolver.strategy.ts +17 -0
  217. package/src/cache-response.middleware.ts +51 -0
  218. package/src/cache-subject-application-resolver.vo.ts +34 -0
  219. package/src/cache-subject-request-resolver.vo.ts +37 -0
  220. package/src/cache-subject-segment-application.strategy.ts +7 -0
  221. package/src/cache-subject-segment-build.strategy.ts +14 -0
  222. package/src/cache-subject-segment-cookie.strategy.ts +14 -0
  223. package/src/cache-subject-segment-env.strategy.ts +10 -0
  224. package/src/cache-subject-segment-fixed.strategy.ts +12 -0
  225. package/src/cache-subject-segment-header.strategy.ts +13 -0
  226. package/src/cache-subject-segment-ip.strategy.ts +9 -0
  227. package/src/cache-subject-segment-path.strategy.ts +8 -0
  228. package/src/cache-subject-segment-query.strategy.ts +18 -0
  229. package/src/cache-subject-segment-request.strategy.ts +9 -0
  230. package/src/cache-subject-segment-user.strategy.ts +8 -0
  231. package/src/certificate-inspector-noop.adapter.ts +10 -0
  232. package/src/certificate-inspector-tls.adapter.ts +42 -0
  233. package/src/certificate-inspector.port.ts +7 -0
  234. package/src/checksum.service.ts +12 -0
  235. package/src/client-from-hono.adapter.ts +20 -0
  236. package/src/client-ip.vo.ts +17 -0
  237. package/src/client-user-agent.vo.ts +17 -0
  238. package/src/client.vo.ts +52 -0
  239. package/src/clock-fixed.adapter.ts +14 -0
  240. package/src/clock-offset.adapter.ts +15 -0
  241. package/src/clock-system.adapter.ts +8 -0
  242. package/src/clock.port.ts +5 -0
  243. package/src/command-envelope.ts +16 -0
  244. package/src/command-logger.service.ts +23 -0
  245. package/src/command.types.ts +13 -0
  246. package/src/commit-sha-value.vo.ts +18 -0
  247. package/src/commit-sha.vo.ts +29 -0
  248. package/src/context.middleware.ts +24 -0
  249. package/src/correlation-id.vo.ts +6 -0
  250. package/src/correlation-storage.service.ts +31 -0
  251. package/src/crypto-aes-gcm.service.ts +37 -0
  252. package/src/crypto-key-provider-file.adapter.ts +29 -0
  253. package/src/crypto-key-provider-memory.adapter.ts +17 -0
  254. package/src/crypto-key-provider-noop.adapter.ts +9 -0
  255. package/src/crypto-key-provider-with-cache.adapter.ts +28 -0
  256. package/src/crypto-key-provider.port.ts +3 -0
  257. package/src/csv-stringifier.adapter.ts +8 -0
  258. package/src/csv-stringifier.port.ts +8 -0
  259. package/src/disk-space-checker-bun.adapter.ts +18 -0
  260. package/src/disk-space-checker-noop.adapter.ts +10 -0
  261. package/src/disk-space-checker.port.ts +5 -0
  262. package/src/dispatching-event-store.ts +36 -0
  263. package/src/encryption-aes-gcm.adapter.ts +57 -0
  264. package/src/encryption-iv.vo.ts +9 -0
  265. package/src/encryption-key-value.vo.ts +18 -0
  266. package/src/encryption-key.vo.ts +41 -0
  267. package/src/encryption-noop.adapter.ts +18 -0
  268. package/src/encryption.port.ts +12 -0
  269. package/src/environment-file-parser.service.ts +35 -0
  270. package/src/environment-loader-encrypted.adapter.ts +31 -0
  271. package/src/environment-loader-noop.adapter.ts +16 -0
  272. package/src/environment-loader-process-safe.adapter.ts +35 -0
  273. package/src/environment-loader-process.adapter.ts +16 -0
  274. package/src/environment-loader.port.ts +8 -0
  275. package/src/etag-extractor.middleware.ts +18 -0
  276. package/src/event-bus-like.types.ts +10 -0
  277. package/src/event-envelope.ts +27 -0
  278. package/src/event-handler-bare.strategy.ts +9 -0
  279. package/src/event-handler-noop.strategy.ts +9 -0
  280. package/src/event-handler-with-logger.strategy.ts +31 -0
  281. package/src/event-handler.strategy.ts +8 -0
  282. package/src/event-logger.service.ts +23 -0
  283. package/src/event-loop-lag.service.ts +32 -0
  284. package/src/event-loop-utilization.service.ts +21 -0
  285. package/src/event-publisher.types.ts +3 -0
  286. package/src/event-store-like.types.ts +3 -0
  287. package/src/event-store.ts +64 -0
  288. package/src/event-stream.vo.ts +14 -0
  289. package/src/event.types.ts +16 -0
  290. package/src/file-cleaner-bun-forgiving.adapter.ts +10 -0
  291. package/src/file-cleaner-bun.adapter.ts +8 -0
  292. package/src/file-cleaner-noop.adapter.ts +6 -0
  293. package/src/file-cleaner.port.ts +5 -0
  294. package/src/file-draft-zip.service.ts +34 -0
  295. package/src/file-draft.service.ts +33 -0
  296. package/src/file-reader-json-bun-forgiving.adapter.ts +14 -0
  297. package/src/file-reader-json-bun.adapter.ts +10 -0
  298. package/src/file-reader-json-noop.adapter.ts +12 -0
  299. package/src/file-reader-json-with-cache.adapter.ts +34 -0
  300. package/src/file-reader-json.port.ts +7 -0
  301. package/src/file-renamer-fs-forgiving.adapter.ts +17 -0
  302. package/src/file-renamer-fs.adapter.ts +15 -0
  303. package/src/file-renamer-noop.adapter.ts +9 -0
  304. package/src/file-renamer.port.ts +8 -0
  305. package/src/file-uploader.middleware.ts +39 -0
  306. package/src/graceful-shutdown.service.ts +68 -0
  307. package/src/gzip-bun.adapter.ts +12 -0
  308. package/src/gzip-noop.adapter.ts +7 -0
  309. package/src/gzip-stream.adapter.ts +19 -0
  310. package/src/gzip.port.ts +10 -0
  311. package/src/hash-content-noop.strategy.ts +8 -0
  312. package/src/hash-content-sha256-bun.strategy.ts +11 -0
  313. package/src/hash-content.strategy.ts +5 -0
  314. package/src/hash-file-noop.adapter.ts +14 -0
  315. package/src/hash-file-sha256-bun.adapter.ts +23 -0
  316. package/src/hash-file.port.ts +13 -0
  317. package/src/hash-value.vo.ts +15 -0
  318. package/src/hash.vo.ts +29 -0
  319. package/src/hcaptcha-secret-key.vo.ts +15 -0
  320. package/src/hcaptcha-site-key.vo.ts +12 -0
  321. package/src/healthcheck.service.ts +138 -0
  322. package/src/http-logger.middleware.ts +100 -0
  323. package/src/i18n.service.ts +62 -0
  324. package/src/id-provider-crypto.adapter.ts +8 -0
  325. package/src/id-provider-deterministic.adapter.ts +21 -0
  326. package/src/id-provider.port.ts +5 -0
  327. package/src/image-alpha-noop.adapter.ts +7 -0
  328. package/src/image-alpha-sharp.adapter.ts +38 -0
  329. package/src/image-alpha.port.ts +19 -0
  330. package/src/image-blur-noop.adapter.ts +7 -0
  331. package/src/image-blur-sharp.adapter.ts +33 -0
  332. package/src/image-blur.port.ts +18 -0
  333. package/src/image-compressor-noop.adapter.ts +7 -0
  334. package/src/image-compressor-sharp.adapter.ts +36 -0
  335. package/src/image-compressor.port.ts +18 -0
  336. package/src/image-exif-clear-noop.adapter.ts +7 -0
  337. package/src/image-exif-clear-sharp.adapter.ts +30 -0
  338. package/src/image-exif-clear.port.ts +16 -0
  339. package/src/image-formatter-noop.adapter.ts +10 -0
  340. package/src/image-formatter-sharp.adapter.ts +40 -0
  341. package/src/image-formatter.port.ts +17 -0
  342. package/src/image-info-noop.adapter.ts +15 -0
  343. package/src/image-info-sharp.adapter.ts +27 -0
  344. package/src/image-info.port.ts +12 -0
  345. package/src/image-processor-noop.adapter.ts +10 -0
  346. package/src/image-processor-sharp.adapter.ts +60 -0
  347. package/src/image-processor.port.ts +25 -0
  348. package/src/image-resizer-noop.adapter.ts +7 -0
  349. package/src/image-resizer-sharp.adapter.ts +41 -0
  350. package/src/image-resizer.port.ts +18 -0
  351. package/src/in-flight-requests-tracker.service.ts +22 -0
  352. package/src/in-flight-requests.middleware.ts +15 -0
  353. package/src/index.ts +307 -0
  354. package/src/instrumentation.service.ts +39 -0
  355. package/src/invariant-error-handler.service.ts +22 -0
  356. package/src/invariant.service.ts +27 -0
  357. package/src/job-handler-bare.strategy.ts +15 -0
  358. package/src/job-handler-noop.strategy.ts +9 -0
  359. package/src/job-handler-with-logger.strategy.ts +44 -0
  360. package/src/job-handler.strategy.ts +10 -0
  361. package/src/jobs.service.ts +16 -0
  362. package/src/logger-format-error.service.ts +27 -0
  363. package/src/logger-noop.adapter.ts +17 -0
  364. package/src/logger-winston-local.adapter.ts +24 -0
  365. package/src/logger-winston-production.adapter.ts +38 -0
  366. package/src/logger-winston.adapter.ts +63 -0
  367. package/src/logger.port.ts +64 -0
  368. package/src/mailer-content-html.vo.ts +11 -0
  369. package/src/mailer-noop.adapter.ts +21 -0
  370. package/src/mailer-smtp-with-logger.adapter.ts +33 -0
  371. package/src/mailer-smtp.adapter.ts +33 -0
  372. package/src/mailer-subject.vo.ts +10 -0
  373. package/src/mailer.port.ts +6 -0
  374. package/src/maintenance-mode.middleware.ts +15 -0
  375. package/src/memory-consumption.service.ts +23 -0
  376. package/src/modules/history/event-handlers/index.ts +2 -0
  377. package/src/modules/history/event-handlers/onHistoryClearedEvent.ts +6 -0
  378. package/src/modules/history/event-handlers/onHistoryPopulatedEvent.ts +10 -0
  379. package/src/modules/history/events/HISTORY_CLEARED_EVENT.ts +13 -0
  380. package/src/modules/history/events/HISTORY_POPULATED_EVENT.ts +17 -0
  381. package/src/modules/history/events/index.ts +2 -0
  382. package/src/modules/history/index.ts +4 -0
  383. package/src/modules/history/ports/history-projection.ts +7 -0
  384. package/src/modules/history/ports/history-reader.ts +5 -0
  385. package/src/modules/history/ports/history-writer.ts +7 -0
  386. package/src/modules/history/ports/index.ts +3 -0
  387. package/src/modules/history/value-objects/history-created-at.ts +6 -0
  388. package/src/modules/history/value-objects/history-id.ts +3 -0
  389. package/src/modules/history/value-objects/history-operation.ts +12 -0
  390. package/src/modules/history/value-objects/history-payload.ts +15 -0
  391. package/src/modules/history/value-objects/history-subject.ts +14 -0
  392. package/src/modules/history/value-objects/history.ts +26 -0
  393. package/src/modules/history/value-objects/index.ts +6 -0
  394. package/src/modules/preferences/command-handlers/handleSetUserLanguageCommand.ts +36 -0
  395. package/src/modules/preferences/command-handlers/index.ts +1 -0
  396. package/src/modules/preferences/commands/SET_USER_LANGUAGE_COMMAND.ts +14 -0
  397. package/src/modules/preferences/commands/index.ts +1 -0
  398. package/src/modules/preferences/events/USER_LANGUAGE_SET_EVENT.ts +14 -0
  399. package/src/modules/preferences/events/index.ts +1 -0
  400. package/src/modules/preferences/index.ts +7 -0
  401. package/src/modules/preferences/invariants/index.ts +1 -0
  402. package/src/modules/preferences/invariants/user-language-has-changed.ts +26 -0
  403. package/src/modules/preferences/open-host-queries/index.ts +1 -0
  404. package/src/modules/preferences/open-host-queries/user-language.ts +23 -0
  405. package/src/modules/preferences/ports/index.ts +2 -0
  406. package/src/modules/preferences/ports/user-language-query.ts +5 -0
  407. package/src/modules/preferences/ports/user-language-resolver.ts +22 -0
  408. package/src/modules/preferences/value-objects/index.ts +1 -0
  409. package/src/modules/preferences/value-objects/supported-languages-set.ts +17 -0
  410. package/src/modules/system/events/HOUR_HAS_PASSED_EVENT.ts +13 -0
  411. package/src/modules/system/events/MINUTE_HAS_PASSED_EVENT.ts +13 -0
  412. package/src/modules/system/events/SECURITY_VIOLATION_DETECTED_EVENT.ts +23 -0
  413. package/src/modules/system/events/index.ts +3 -0
  414. package/src/modules/system/index.ts +2 -0
  415. package/src/modules/system/services/index.ts +2 -0
  416. package/src/modules/system/services/passage-of-time-hourly.service.ts +35 -0
  417. package/src/modules/system/services/passage-of-time-minute.service.ts +35 -0
  418. package/src/node-env.vo.ts +12 -0
  419. package/src/nonce-provider-crypto.adapter.ts +18 -0
  420. package/src/nonce-provider-deterministic.adapter.ts +21 -0
  421. package/src/nonce-provider-noop.adapter.ts +8 -0
  422. package/src/nonce-provider.port.ts +5 -0
  423. package/src/nonce-value.vo.ts +18 -0
  424. package/src/pdf-generator-noop.adapter.ts +23 -0
  425. package/src/pdf-generator.port.ts +5 -0
  426. package/src/ping.service.ts +7 -0
  427. package/src/port.vo.ts +14 -0
  428. package/src/prerequisite-runner-startup.service.ts +44 -0
  429. package/src/prerequisite-verifier-binary.adapter.ts +21 -0
  430. package/src/prerequisite-verifier-bun.adapter.ts +21 -0
  431. package/src/prerequisite-verifier-clock-drift.adapter.ts +32 -0
  432. package/src/prerequisite-verifier-directory.adapter.ts +48 -0
  433. package/src/prerequisite-verifier-dns.adapter.ts +20 -0
  434. package/src/prerequisite-verifier-external-api.adapter.ts +20 -0
  435. package/src/prerequisite-verifier-file.adapter.ts +49 -0
  436. package/src/prerequisite-verifier-jobs.adapter.ts +15 -0
  437. package/src/prerequisite-verifier-log-file.adapter.ts +29 -0
  438. package/src/prerequisite-verifier-mailer.adapter.ts +22 -0
  439. package/src/prerequisite-verifier-memory.adapter.ts +22 -0
  440. package/src/prerequisite-verifier-node.adapter.ts +21 -0
  441. package/src/prerequisite-verifier-os.adapter.ts +22 -0
  442. package/src/prerequisite-verifier-outside-connectivity.adapter.ts +23 -0
  443. package/src/prerequisite-verifier-port.adapter.ts +23 -0
  444. package/src/prerequisite-verifier-ram.adapter.ts +20 -0
  445. package/src/prerequisite-verifier-running-user.adapter.ts +17 -0
  446. package/src/prerequisite-verifier-self.adapter.ts +11 -0
  447. package/src/prerequisite-verifier-space.adapter.ts +32 -0
  448. package/src/prerequisite-verifier-sqlite.adapter.ts +25 -0
  449. package/src/prerequisite-verifier-ssl-certificate-expiry.adapter.ts +28 -0
  450. package/src/prerequisite-verifier-timezone-utc.adapter.ts +20 -0
  451. package/src/prerequisite-verifier-translations.adapter.ts +65 -0
  452. package/src/prerequisite-verifier-with-cache.adapter.ts +35 -0
  453. package/src/prerequisite-verifier-with-fail-safe.adapter.ts +37 -0
  454. package/src/prerequisite-verifier-with-logger.adapter.ts +51 -0
  455. package/src/prerequisite-verifier-with-retry.adapter.ts +35 -0
  456. package/src/prerequisite-verifier-with-timeout.adapter.ts +31 -0
  457. package/src/prerequisite-verifier.decorator.ts +49 -0
  458. package/src/prerequisite-verifier.port.ts +38 -0
  459. package/src/prerequisite.vo.ts +28 -0
  460. package/src/recaptcha-secret-key.vo.ts +15 -0
  461. package/src/recaptcha-site-key.vo.ts +12 -0
  462. package/src/redactor-compact-array.strategy.ts +10 -0
  463. package/src/redactor-compact-object.strategy.ts +25 -0
  464. package/src/redactor-composite.strategy.ts +9 -0
  465. package/src/redactor-mask.strategy.ts +38 -0
  466. package/src/redactor-noop.strategy.ts +7 -0
  467. package/src/redactor.strategy.ts +3 -0
  468. package/src/remote-file-storage-disk.adapter.ts +72 -0
  469. package/src/remote-file-storage-noop.adapter.ts +70 -0
  470. package/src/remote-file-storage.port.ts +17 -0
  471. package/src/retry-backoff-exponential.strategy.ts +10 -0
  472. package/src/retry-backoff-fibonacci.strategy.ts +16 -0
  473. package/src/retry-backoff-linear.strategy.ts +10 -0
  474. package/src/retry-backoff-noop.strategy.ts +8 -0
  475. package/src/retry-backoff.strategy.ts +5 -0
  476. package/src/retry.service.ts +37 -0
  477. package/src/safe-parse-body.service.ts +12 -0
  478. package/src/sealer-aes-gcm.adapter.ts +38 -0
  479. package/src/sealer-noop.adapter.ts +11 -0
  480. package/src/sealer.port.ts +4 -0
  481. package/src/security-context.vo.ts +13 -0
  482. package/src/security-countermeasure-ban.strategy.ts +63 -0
  483. package/src/security-countermeasure-mirage.strategy.ts +31 -0
  484. package/src/security-countermeasure-name.vo.ts +22 -0
  485. package/src/security-countermeasure-noop.strategy.ts +12 -0
  486. package/src/security-countermeasure-report.strategy.ts +27 -0
  487. package/src/security-countermeasure-tarpit.strategy.ts +31 -0
  488. package/src/security-countermeasure.strategy.ts +16 -0
  489. package/src/security-policy.vo.ts +9 -0
  490. package/src/security-rule-and.strategy.ts +25 -0
  491. package/src/security-rule-bait-routes.strategy.ts +15 -0
  492. package/src/security-rule-fail.strategy.ts +12 -0
  493. package/src/security-rule-honey-pot-field.strategy.ts +20 -0
  494. package/src/security-rule-name.vo.ts +22 -0
  495. package/src/security-rule-or.strategy.ts +25 -0
  496. package/src/security-rule-pass.strategy.ts +12 -0
  497. package/src/security-rule-user-agent.strategy.ts +20 -0
  498. package/src/security-rule-violation-threshold.strategy.ts +50 -0
  499. package/src/security-rule.strategy.ts +8 -0
  500. package/src/setup.service.ts +102 -0
  501. package/src/shield-api-key.strategy.ts +20 -0
  502. package/src/shield-auth.strategy.ts +38 -0
  503. package/src/shield-basic-auth.strategy.ts +17 -0
  504. package/src/shield-csrf.strategy.ts +23 -0
  505. package/src/shield-hcaptcha-local.strategy.ts +22 -0
  506. package/src/shield-hcaptcha.strategy.ts +24 -0
  507. package/src/shield-noop.strategy.ts +6 -0
  508. package/src/shield-rate-limit.strategy.ts +41 -0
  509. package/src/shield-recaptcha.strategy.ts +49 -0
  510. package/src/shield-security.strategy.ts +80 -0
  511. package/src/shield-timeout.strategy.ts +19 -0
  512. package/src/shield.strategy.ts +5 -0
  513. package/src/simulated-error.middleware.ts +8 -0
  514. package/src/sleeper-noop.adapter.ts +5 -0
  515. package/src/sleeper-system.adapter.ts +8 -0
  516. package/src/sleeper.port.ts +5 -0
  517. package/src/slower.middleware.ts +14 -0
  518. package/src/smtp-host.vo.ts +17 -0
  519. package/src/smtp-pass.vo.ts +17 -0
  520. package/src/smtp-port.vo.ts +5 -0
  521. package/src/smtp-user.vo.ts +17 -0
  522. package/src/ssr.ts +57 -0
  523. package/src/static-files.service.ts +85 -0
  524. package/src/stopwatch.service.ts +30 -0
  525. package/src/temporary-file-absolute.adapter.ts +31 -0
  526. package/src/temporary-file-noop.adapter.ts +16 -0
  527. package/src/temporary-file.port.ts +9 -0
  528. package/src/time-zone-offset.middleware.ts +24 -0
  529. package/src/timekeeper-google.adapter.ts +18 -0
  530. package/src/timekeeper-noop.adapter.ts +12 -0
  531. package/src/timekeeper.port.ts +5 -0
  532. package/src/timeout-cancellable-runner-bare.adapter.ts +35 -0
  533. package/src/timeout-cancellable-runner-noop.adapter.ts +9 -0
  534. package/src/timeout-cancellable-runner.port.ts +7 -0
  535. package/src/timeout-runner-bare.adapter.ts +23 -0
  536. package/src/timeout-runner-error.adapter.ts +8 -0
  537. package/src/timeout-runner-monitor.adapter.ts +24 -0
  538. package/src/timeout-runner-noop.adapter.ts +8 -0
  539. package/src/timeout-runner.port.ts +7 -0
  540. package/src/to-event-map.types.ts +3 -0
  541. package/src/translations.service.ts +20 -0
  542. package/src/uptime.service.ts +17 -0
  543. package/src/uuid.vo.ts +7 -0
  544. package/src/visitor-id-client.strategy.ts +20 -0
  545. package/src/visitor-id.strategy.ts +5 -0
  546. package/src/weak-etag-extractor.middleware.ts +17 -0
@@ -0,0 +1,38 @@
1
+ import cloneDeepWith from "lodash/cloneDeepWith";
2
+ import type { RedactorStrategy } from "./redactor.strategy";
3
+
4
+ export class RedactorMaskStrategy implements RedactorStrategy {
5
+ static readonly DEFAULT_KEYS: readonly string[] = [
6
+ "authorization",
7
+ "cookie",
8
+ "set-cookie",
9
+ "x-api-key",
10
+ "apikey",
11
+ "token",
12
+ "accesstoken",
13
+ "refreshtoken",
14
+ "password",
15
+ "currentpassword",
16
+ "newpassword",
17
+ "passwordconfirmation",
18
+ "clientsecret",
19
+ "secret",
20
+ "otp",
21
+ "code",
22
+ ];
23
+
24
+ private readonly keys: Set<string>;
25
+
26
+ constructor(keys?: readonly string[]) {
27
+ this.keys = keys?.length
28
+ ? new Set(keys.map((key) => key.toLowerCase()))
29
+ : new Set(RedactorMaskStrategy.DEFAULT_KEYS);
30
+ }
31
+
32
+ redact<T>(input: T): T {
33
+ return cloneDeepWith(input, (_value, key) => {
34
+ if (typeof key === "string" && this.keys.has(key.toLowerCase())) return "***";
35
+ return undefined;
36
+ });
37
+ }
38
+ }
@@ -0,0 +1,7 @@
1
+ import type { RedactorStrategy } from "./redactor.strategy";
2
+
3
+ export class RedactorNoopStrategy implements RedactorStrategy {
4
+ redact<T>(input: T): T {
5
+ return input;
6
+ }
7
+ }
@@ -0,0 +1,3 @@
1
+ export interface RedactorStrategy {
2
+ redact<T>(value: T): T;
3
+ }
@@ -0,0 +1,72 @@
1
+ import fs from "node:fs/promises";
2
+ import * as tools from "@bgord/tools";
3
+ import type { FileCleanerPort } from "./file-cleaner.port";
4
+ import type { FileRenamerPort } from "./file-renamer.port";
5
+ import type { HashFilePort } from "./hash-file.port";
6
+ import type {
7
+ RemoteFileStoragePort,
8
+ RemoteHeadResult,
9
+ RemotePutFromPathInput,
10
+ RemotePutFromPathResult,
11
+ } from "./remote-file-storage.port";
12
+
13
+ type RemoteFileStorageDiskConfig = { root: tools.DirectoryPathAbsoluteType };
14
+
15
+ type Dependencies = { HashFile: HashFilePort; FileCleaner: FileCleanerPort; FileRenamer: FileRenamerPort };
16
+
17
+ export class RemoteFileStorageDiskAdapter implements RemoteFileStoragePort {
18
+ constructor(
19
+ private readonly config: RemoteFileStorageDiskConfig,
20
+ private readonly deps: Dependencies,
21
+ ) {}
22
+
23
+ private resolveKeyToAbsoluteFilePath(key: tools.ObjectKeyType): tools.FilePathAbsolute {
24
+ const parts = key.split("/");
25
+ const filename = tools.Filename.fromString(parts.pop() as string);
26
+
27
+ const directory = tools.DirectoryPathAbsoluteSchema.parse(`${this.config.root}/${parts.join("/")}`);
28
+
29
+ return tools.FilePathAbsolute.fromPartsSafe(directory, filename);
30
+ }
31
+
32
+ async putFromPath(input: RemotePutFromPathInput): Promise<RemotePutFromPathResult> {
33
+ const final = this.resolveKeyToAbsoluteFilePath(input.key);
34
+ const temporary = final.withFilename(final.getFilename().withSuffix("-part"));
35
+
36
+ await fs.mkdir(final.getDirectory(), { recursive: true });
37
+
38
+ const source = Bun.file(input.path.get());
39
+ await Bun.write(temporary.get(), source);
40
+ await this.deps.FileRenamer.rename(temporary, final);
41
+
42
+ return this.deps.HashFile.hash(final);
43
+ }
44
+
45
+ async head(key: tools.ObjectKeyType): Promise<RemoteHeadResult> {
46
+ const path = this.resolveKeyToAbsoluteFilePath(key);
47
+
48
+ try {
49
+ return { exists: true, ...(await this.deps.HashFile.hash(path)) };
50
+ } catch {
51
+ return { exists: false };
52
+ }
53
+ }
54
+
55
+ async getStream(key: tools.ObjectKeyType): Promise<ReadableStream | null> {
56
+ const path = this.resolveKeyToAbsoluteFilePath(key);
57
+
58
+ try {
59
+ return Bun.file(path.get()).stream();
60
+ } catch {
61
+ return null;
62
+ }
63
+ }
64
+
65
+ async delete(key: tools.ObjectKeyType): Promise<void> {
66
+ await this.deps.FileCleaner.delete(this.resolveKeyToAbsoluteFilePath(key));
67
+ }
68
+
69
+ get root() {
70
+ return this.config.root;
71
+ }
72
+ }
@@ -0,0 +1,70 @@
1
+ import * as tools from "@bgord/tools";
2
+ import type { ClockPort } from "./clock.port";
3
+ import { Hash } from "./hash.vo";
4
+ import type { LoggerPort } from "./logger.port";
5
+ import type {
6
+ RemoteFileStoragePort,
7
+ RemoteHeadResult,
8
+ RemotePutFromPathInput,
9
+ RemotePutFromPathResult,
10
+ } from "./remote-file-storage.port";
11
+
12
+ type Dependencies = { Logger: LoggerPort; Clock: ClockPort };
13
+
14
+ type RemoteFileStorageNoopConfig = { root: tools.DirectoryPathAbsoluteType };
15
+
16
+ export class RemoteFileStorageNoopAdapter implements RemoteFileStoragePort {
17
+ private readonly base = { component: "infra", operation: "RemoteFileStorageNoopAdapter" };
18
+
19
+ constructor(
20
+ private readonly config: RemoteFileStorageNoopConfig,
21
+ private readonly deps: Dependencies,
22
+ ) {}
23
+
24
+ async putFromPath(input: RemotePutFromPathInput): Promise<RemotePutFromPathResult> {
25
+ this.deps.Logger.info({
26
+ message: "[NOOP] RemoteFileStorageNoopAdapter putFromPath",
27
+ metadata: { input },
28
+ ...this.base,
29
+ });
30
+
31
+ return {
32
+ etag: Hash.fromString("0000000000000000000000000000000000000000000000000000000000000000"),
33
+ size: tools.Size.fromBytes(10),
34
+ lastModified: this.deps.Clock.now(),
35
+ mime: tools.MIMES.text,
36
+ };
37
+ }
38
+
39
+ async head(key: tools.ObjectKeyType): Promise<RemoteHeadResult> {
40
+ this.deps.Logger.info({
41
+ message: "[NOOP] RemoteFileStorageNoopAdapter head",
42
+ metadata: { key },
43
+ ...this.base,
44
+ });
45
+
46
+ return { exists: false };
47
+ }
48
+
49
+ async getStream(key: tools.ObjectKeyType): Promise<ReadableStream | null> {
50
+ this.deps.Logger.info({
51
+ message: "[NOOP] RemoteFileStorageNoopAdapter getStream",
52
+ metadata: { key },
53
+ ...this.base,
54
+ });
55
+
56
+ return null;
57
+ }
58
+
59
+ async delete(key: tools.ObjectKeyType): Promise<void> {
60
+ this.deps.Logger.info({
61
+ message: "[NOOP] RemoteFileStorageNoopAdapter delete",
62
+ metadata: { key },
63
+ ...this.base,
64
+ });
65
+ }
66
+
67
+ get root() {
68
+ return this.config.root;
69
+ }
70
+ }
@@ -0,0 +1,17 @@
1
+ import type * as tools from "@bgord/tools";
2
+ import type { HashFileResult } from "./hash-file.port";
3
+
4
+ export type RemotePutFromPathInput = {
5
+ key: tools.ObjectKeyType;
6
+ path: tools.FilePathRelative | tools.FilePathAbsolute;
7
+ };
8
+ export type RemotePutFromPathResult = HashFileResult;
9
+ export type RemoteHeadResult = { exists: false } | ({ exists: true } & HashFileResult);
10
+
11
+ export interface RemoteFileStoragePort {
12
+ putFromPath(input: RemotePutFromPathInput): Promise<RemotePutFromPathResult>;
13
+ head(key: tools.ObjectKeyType): Promise<RemoteHeadResult>;
14
+ getStream(key: tools.ObjectKeyType): Promise<ReadableStream | null>;
15
+ delete(key: tools.ObjectKeyType): Promise<void>;
16
+ get root(): tools.DirectoryPathAbsoluteType;
17
+ }
@@ -0,0 +1,10 @@
1
+ import * as tools from "@bgord/tools";
2
+ import type { RetryBackoffStrategy } from "./retry-backoff.strategy";
3
+
4
+ export class RetryBackoffExponentialStrategy implements RetryBackoffStrategy {
5
+ constructor(private readonly delay: tools.Duration) {}
6
+
7
+ next(attempt: tools.IntegerPositiveType) {
8
+ return this.delay.times(tools.MultiplicationFactor.parse(2 ** (attempt - 1)));
9
+ }
10
+ }
@@ -0,0 +1,16 @@
1
+ import * as tools from "@bgord/tools";
2
+ import type { RetryBackoffStrategy } from "./retry-backoff.strategy";
3
+
4
+ export class RetryBackoffFibonacciStrategy implements RetryBackoffStrategy {
5
+ constructor(private readonly delay: tools.Duration) {}
6
+
7
+ next(attempt: tools.IntegerPositiveType) {
8
+ return this.delay.times(tools.MultiplicationFactor.parse(this.fibonacci(attempt)));
9
+ }
10
+
11
+ private fibonacci(n: number): number {
12
+ if (n === 0) return 0;
13
+ if (n === 1) return 1;
14
+ return this.fibonacci(n - 1) + this.fibonacci(n - 2);
15
+ }
16
+ }
@@ -0,0 +1,10 @@
1
+ import * as tools from "@bgord/tools";
2
+ import type { RetryBackoffStrategy } from "./retry-backoff.strategy";
3
+
4
+ export class RetryBackoffLinearStrategy implements RetryBackoffStrategy {
5
+ constructor(private readonly delay: tools.Duration) {}
6
+
7
+ next(attempt: tools.IntegerPositiveType) {
8
+ return this.delay.times(tools.MultiplicationFactor.parse(attempt));
9
+ }
10
+ }
@@ -0,0 +1,8 @@
1
+ import * as tools from "@bgord/tools";
2
+ import type { RetryBackoffStrategy } from "./retry-backoff.strategy";
3
+
4
+ export class RetryBackoffNoopStrategy implements RetryBackoffStrategy {
5
+ next() {
6
+ return tools.Duration.Ms(0);
7
+ }
8
+ }
@@ -0,0 +1,5 @@
1
+ import type * as tools from "@bgord/tools";
2
+
3
+ export interface RetryBackoffStrategy {
4
+ next(attempt: tools.IntegerPositiveType): tools.Duration;
5
+ }
@@ -0,0 +1,37 @@
1
+ import * as tools from "@bgord/tools";
2
+ import type { RetryBackoffStrategy } from "./retry-backoff.strategy";
3
+ import type { SleeperPort } from "./sleeper.port";
4
+
5
+ type Dependencies = { Sleeper: SleeperPort };
6
+
7
+ export type RetryConfigType = {
8
+ max: tools.IntegerPositiveType;
9
+ backoff: RetryBackoffStrategy;
10
+ when?: (error: unknown) => boolean;
11
+ };
12
+
13
+ export const RetryError = { InvalidMax: "retry.invalid.max" };
14
+
15
+ export class Retry {
16
+ constructor(private readonly deps: Dependencies) {}
17
+
18
+ async run<T>(action: () => Promise<T>, config: RetryConfigType): Promise<T> {
19
+ if (config.max < 1) throw new Error(RetryError.InvalidMax);
20
+
21
+ let lastError: unknown;
22
+
23
+ for (let attempt = 1; attempt <= config.max; attempt++) {
24
+ try {
25
+ return await action();
26
+ } catch (error) {
27
+ lastError = error;
28
+
29
+ if (attempt === config.max || (config.when && !config.when(error))) break;
30
+
31
+ await this.deps.Sleeper.wait(config.backoff.next(tools.IntegerPositive.parse(attempt)));
32
+ }
33
+ }
34
+
35
+ throw lastError;
36
+ }
37
+ }
@@ -0,0 +1,12 @@
1
+ import type hono from "hono";
2
+
3
+ export async function safeParseBody(c: hono.Context): Promise<any> {
4
+ try {
5
+ const rawBody = await c.req.text();
6
+
7
+ if (!rawBody.trim()) return {};
8
+ return JSON.parse(rawBody);
9
+ } catch {
10
+ return {};
11
+ }
12
+ }
@@ -0,0 +1,38 @@
1
+ import { CryptoAesGcm } from "./crypto-aes-gcm.service";
2
+ import type { CryptoKeyProviderPort } from "./crypto-key-provider.port";
3
+ import { EncryptionIV } from "./encryption-iv.vo";
4
+ import type { SealerPort } from "./sealer.port";
5
+
6
+ type Dependencies = { CryptoKeyProvider: CryptoKeyProviderPort };
7
+
8
+ export const SealerAesGcmAdapterError = { InvalidPayload: "sealer.aes.gcm.adapter.invalid.payload" };
9
+
10
+ export class SealerAesGcmAdapter implements SealerPort {
11
+ private static readonly PREFIX = "sealed:gcm:";
12
+
13
+ constructor(private readonly deps: Dependencies) {}
14
+
15
+ async seal(value: unknown): Promise<string> {
16
+ const key = await this.deps.CryptoKeyProvider.get();
17
+
18
+ const iv = EncryptionIV.generate();
19
+ const plaintext = new TextEncoder().encode(JSON.stringify(value));
20
+
21
+ const payload = await CryptoAesGcm.encrypt(key, plaintext.buffer, iv);
22
+
23
+ return SealerAesGcmAdapter.PREFIX + Buffer.from(payload).toString("base64");
24
+ }
25
+
26
+ async unseal(value: string): Promise<unknown> {
27
+ if (!value.startsWith(SealerAesGcmAdapter.PREFIX)) {
28
+ throw new Error(SealerAesGcmAdapterError.InvalidPayload);
29
+ }
30
+
31
+ const key = await this.deps.CryptoKeyProvider.get();
32
+ const bytes = Buffer.from(value.slice(SealerAesGcmAdapter.PREFIX.length), "base64");
33
+
34
+ const decrypted = await CryptoAesGcm.decrypt(key, bytes);
35
+
36
+ return JSON.parse(new TextDecoder().decode(decrypted));
37
+ }
38
+ }
@@ -0,0 +1,11 @@
1
+ import type { SealerPort } from "./sealer.port";
2
+
3
+ export class SealerNoopAdapter implements SealerPort {
4
+ async seal(value: unknown): Promise<string> {
5
+ return `sealed:${JSON.stringify(value)}`;
6
+ }
7
+
8
+ async unseal(value: string): Promise<unknown> {
9
+ return JSON.parse(value.replace("sealed:", ""));
10
+ }
11
+ }
@@ -0,0 +1,4 @@
1
+ export interface SealerPort {
2
+ seal(value: unknown): Promise<string>;
3
+ unseal(value: string): Promise<unknown>;
4
+ }
@@ -0,0 +1,13 @@
1
+ import type { Client } from "./client.vo";
2
+ import type { SecurityCountermeasureNameType } from "./security-countermeasure-name.vo";
3
+ import type { SecurityRuleNameType } from "./security-rule-name.vo";
4
+ import type { UUIDType } from "./uuid.vo";
5
+
6
+ export class SecurityContext {
7
+ constructor(
8
+ readonly rule: SecurityRuleNameType,
9
+ readonly countermeasure: SecurityCountermeasureNameType,
10
+ readonly client: Client,
11
+ readonly userId: UUIDType | undefined,
12
+ ) {}
13
+ }
@@ -0,0 +1,63 @@
1
+ import type { ContentfulStatusCode } from "hono/utils/http-status";
2
+ import type { ClockPort } from "./clock.port";
3
+ import { CorrelationStorage } from "./correlation-storage.service";
4
+ import { createEventEnvelope } from "./event-envelope";
5
+ import type { EventStoreLike } from "./event-store-like.types";
6
+ import type { IdProviderPort } from "./id-provider.port";
7
+ import type { LoggerPort } from "./logger.port";
8
+ import {
9
+ SECURITY_VIOLATION_DETECTED_EVENT,
10
+ SecurityViolationDetectedEvent,
11
+ type SecurityViolationDetectedEventType,
12
+ } from "./modules/system/events/SECURITY_VIOLATION_DETECTED_EVENT";
13
+ import type { SecurityContext } from "./security-context.vo";
14
+ import type { SecurityAction, SecurityCountermeasureStrategy } from "./security-countermeasure.strategy";
15
+ import { SecurityCountermeasureName } from "./security-countermeasure-name.vo";
16
+
17
+ type Dependencies = {
18
+ IdProvider: IdProviderPort;
19
+ Clock: ClockPort;
20
+ Logger: LoggerPort;
21
+ EventStore: EventStoreLike<SecurityViolationDetectedEventType>;
22
+ };
23
+
24
+ export const SecurityCountermeasureBanStrategyError = {
25
+ Executed: "security.countermeasure.ban.strategy.executed",
26
+ };
27
+
28
+ export class SecurityCountermeasureBanStrategy implements SecurityCountermeasureStrategy {
29
+ constructor(
30
+ private readonly deps: Dependencies,
31
+ private readonly config: { response: { status: ContentfulStatusCode } } = { response: { status: 403 } },
32
+ ) {}
33
+
34
+ async execute(context: SecurityContext): Promise<SecurityAction> {
35
+ const action = {
36
+ kind: "deny",
37
+ reason: SecurityCountermeasureBanStrategyError.Executed,
38
+ ...this.config,
39
+ } as const;
40
+
41
+ this.deps.Logger.info({
42
+ message: "Security countermeasure ban",
43
+ component: "security",
44
+ operation: "security_countermeasure_ban",
45
+ correlationId: CorrelationStorage.get(),
46
+ metadata: context,
47
+ });
48
+
49
+ const event = SecurityViolationDetectedEvent.parse({
50
+ ...createEventEnvelope("security", this.deps),
51
+ name: SECURITY_VIOLATION_DETECTED_EVENT,
52
+ payload: { ...context, countermeasure: this.name, action: action.kind },
53
+ } satisfies SecurityViolationDetectedEventType);
54
+
55
+ await this.deps.EventStore.save([event]);
56
+
57
+ return action;
58
+ }
59
+
60
+ get name() {
61
+ return SecurityCountermeasureName.parse("ban");
62
+ }
63
+ }
@@ -0,0 +1,31 @@
1
+ import type { ContentfulStatusCode } from "hono/utils/http-status";
2
+ import { CorrelationStorage } from "./correlation-storage.service";
3
+ import type { LoggerPort } from "./logger.port";
4
+ import type { SecurityContext } from "./security-context.vo";
5
+ import type { SecurityAction, SecurityCountermeasureStrategy } from "./security-countermeasure.strategy";
6
+ import { SecurityCountermeasureName } from "./security-countermeasure-name.vo";
7
+
8
+ type Dependencies = { Logger: LoggerPort };
9
+
10
+ export class SecurityCountermeasureMirageStrategy implements SecurityCountermeasureStrategy {
11
+ constructor(
12
+ private readonly deps: Dependencies,
13
+ private readonly config: { response: { status: ContentfulStatusCode } } = { response: { status: 200 } },
14
+ ) {}
15
+
16
+ async execute(context: SecurityContext): Promise<SecurityAction> {
17
+ this.deps.Logger.info({
18
+ message: "Security countermeasure mirage",
19
+ component: "security",
20
+ operation: "security_countermeasure_mirage",
21
+ correlationId: CorrelationStorage.get(),
22
+ metadata: context,
23
+ });
24
+
25
+ return { kind: "mirage", ...this.config };
26
+ }
27
+
28
+ get name() {
29
+ return SecurityCountermeasureName.parse("mirage");
30
+ }
31
+ }
@@ -0,0 +1,22 @@
1
+ import * as z from "zod/v4";
2
+
3
+ export const SecurityCountermeasureNameError = {
4
+ Type: "security.countermeasure.name.type",
5
+ Empty: "security.countermeasure.name.empty",
6
+ TooLong: "security.countermeasure.name.too.long",
7
+ BadChars: "security.countermeasure.name.bad.chars",
8
+ };
9
+
10
+ // One to sixty four letters, digits, or underscores
11
+ const CHARS_WHITELIST = /^[a-zA-Z0-9_]{1,64}$/;
12
+
13
+ // Stryker disable all
14
+ export const SecurityCountermeasureName = z
15
+ // Stryker restore all
16
+ .string(SecurityCountermeasureNameError.Type)
17
+ .min(1, SecurityCountermeasureNameError.Empty)
18
+ .max(64, SecurityCountermeasureNameError.TooLong)
19
+ .regex(CHARS_WHITELIST, SecurityCountermeasureNameError.BadChars)
20
+ .brand("SecurityCountermeasureName");
21
+
22
+ export type SecurityCountermeasureNameType = z.infer<typeof SecurityCountermeasureName>;
@@ -0,0 +1,12 @@
1
+ import type { SecurityAction, SecurityCountermeasureStrategy } from "./security-countermeasure.strategy";
2
+ import { SecurityCountermeasureName } from "./security-countermeasure-name.vo";
3
+
4
+ export class SecurityCountermeasureNoopStrategy implements SecurityCountermeasureStrategy {
5
+ async execute(): Promise<SecurityAction> {
6
+ return { kind: "allow" };
7
+ }
8
+
9
+ get name() {
10
+ return SecurityCountermeasureName.parse("noop");
11
+ }
12
+ }
@@ -0,0 +1,27 @@
1
+ import { CorrelationStorage } from "./correlation-storage.service";
2
+ import type { LoggerPort } from "./logger.port";
3
+ import type { SecurityContext } from "./security-context.vo";
4
+ import type { SecurityAction, SecurityCountermeasureStrategy } from "./security-countermeasure.strategy";
5
+ import { SecurityCountermeasureName } from "./security-countermeasure-name.vo";
6
+
7
+ type Dependencies = { Logger: LoggerPort };
8
+
9
+ export class SecurityCountermeasureReportStrategy implements SecurityCountermeasureStrategy {
10
+ constructor(private readonly deps: Dependencies) {}
11
+
12
+ async execute(context: SecurityContext): Promise<SecurityAction> {
13
+ this.deps.Logger.info({
14
+ message: "Security countermeasure report",
15
+ component: "security",
16
+ operation: "security_countermeasure_report",
17
+ correlationId: CorrelationStorage.get(),
18
+ metadata: context,
19
+ });
20
+
21
+ return { kind: "allow" };
22
+ }
23
+
24
+ get name() {
25
+ return SecurityCountermeasureName.parse("report");
26
+ }
27
+ }
@@ -0,0 +1,31 @@
1
+ import type * as tools from "@bgord/tools";
2
+ import { CorrelationStorage } from "./correlation-storage.service";
3
+ import type { LoggerPort } from "./logger.port";
4
+ import type { SecurityContext } from "./security-context.vo";
5
+ import type { SecurityAction, SecurityCountermeasureStrategy } from "./security-countermeasure.strategy";
6
+ import { SecurityCountermeasureName } from "./security-countermeasure-name.vo";
7
+
8
+ type Dependencies = { Logger: LoggerPort };
9
+
10
+ export class SecurityCountermeasureTarpitStrategy implements SecurityCountermeasureStrategy {
11
+ constructor(
12
+ private readonly deps: Dependencies,
13
+ private readonly config: { duration: tools.Duration; after: SecurityAction },
14
+ ) {}
15
+
16
+ async execute(context: SecurityContext): Promise<SecurityAction> {
17
+ this.deps.Logger.info({
18
+ message: "Security countermeasure tarpit",
19
+ component: "security",
20
+ operation: "security_countermeasure_tarpit",
21
+ correlationId: CorrelationStorage.get(),
22
+ metadata: context,
23
+ });
24
+
25
+ return { kind: "delay", ...this.config };
26
+ }
27
+
28
+ get name() {
29
+ return SecurityCountermeasureName.parse("tarpit");
30
+ }
31
+ }
@@ -0,0 +1,16 @@
1
+ import type * as tools from "@bgord/tools";
2
+ import type { ContentfulStatusCode } from "hono/utils/http-status";
3
+ import type { SecurityContext } from "./security-context.vo";
4
+ import type { SecurityCountermeasureNameType } from "./security-countermeasure-name.vo";
5
+
6
+ export type SecurityAction =
7
+ | { kind: "allow" }
8
+ | { kind: "deny"; reason: string; response: { status: ContentfulStatusCode } }
9
+ | { kind: "delay"; duration: tools.Duration; after: SecurityAction }
10
+ | { kind: "mirage"; response: { status: ContentfulStatusCode } };
11
+
12
+ export interface SecurityCountermeasureStrategy {
13
+ execute(context: SecurityContext): Promise<SecurityAction>;
14
+
15
+ get name(): SecurityCountermeasureNameType;
16
+ }
@@ -0,0 +1,9 @@
1
+ import type { SecurityCountermeasureStrategy } from "./security-countermeasure.strategy";
2
+ import type { SecurityRuleStrategy } from "./security-rule.strategy";
3
+
4
+ export class SecurityPolicy {
5
+ constructor(
6
+ readonly rule: SecurityRuleStrategy,
7
+ readonly countermeasure: SecurityCountermeasureStrategy,
8
+ ) {}
9
+ }
@@ -0,0 +1,25 @@
1
+ import type { Context } from "hono";
2
+ import type { SecurityRuleStrategy } from "./security-rule.strategy";
3
+ import { SecurityRuleName } from "./security-rule-name.vo";
4
+
5
+ export const SecurityRuleAndStrategyError = {
6
+ MissingRules: "security.rule.and.adapter.error.missing.rules",
7
+ MaxRules: "security.rule.and.adapter.error.max.rules",
8
+ };
9
+
10
+ export class SecurityRuleAndStrategy implements SecurityRuleStrategy {
11
+ constructor(private readonly rules: SecurityRuleStrategy[]) {
12
+ if (rules.length === 0) throw new Error(SecurityRuleAndStrategyError.MissingRules);
13
+ if (rules.length > 5) throw new Error(SecurityRuleAndStrategyError.MaxRules);
14
+ }
15
+
16
+ async isViolated(c: Context) {
17
+ const reports = await Promise.all(this.rules.map((rule) => rule.isViolated(c)));
18
+
19
+ return reports.every(Boolean);
20
+ }
21
+
22
+ get name() {
23
+ return SecurityRuleName.parse(`and_${this.rules.map((rule) => rule.name).join("_")}`);
24
+ }
25
+ }
@@ -0,0 +1,15 @@
1
+ import type { Context } from "hono";
2
+ import type { SecurityRuleStrategy } from "./security-rule.strategy";
3
+ import { SecurityRuleName } from "./security-rule-name.vo";
4
+
5
+ export class SecurityRuleBaitRoutesStrategy implements SecurityRuleStrategy {
6
+ constructor(private readonly routes: string[]) {}
7
+
8
+ async isViolated(c: Context) {
9
+ return this.routes.includes(c.req.path);
10
+ }
11
+
12
+ get name() {
13
+ return SecurityRuleName.parse("bait_routes");
14
+ }
15
+ }