@heavybit/shared-lib 0.0.0-stage → 1.1.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 (298) hide show
  1. package/dist/cjs/access/index.js +118 -0
  2. package/dist/cjs/access/index.js.map +1 -0
  3. package/dist/cjs/alerting/index.js +56 -0
  4. package/dist/cjs/alerting/index.js.map +1 -0
  5. package/dist/cjs/cache/index.js +167 -0
  6. package/dist/cjs/cache/index.js.map +1 -0
  7. package/dist/cjs/common/async.js +40 -0
  8. package/dist/cjs/common/async.js.map +1 -0
  9. package/dist/cjs/common/audit.js +21 -0
  10. package/dist/cjs/common/audit.js.map +1 -0
  11. package/dist/cjs/common/crypto.js +75 -0
  12. package/dist/cjs/common/crypto.js.map +1 -0
  13. package/dist/cjs/common/errors.js +90 -0
  14. package/dist/cjs/common/errors.js.map +1 -0
  15. package/dist/cjs/common/id.js +40 -0
  16. package/dist/cjs/common/id.js.map +1 -0
  17. package/dist/cjs/common/index.js +28 -0
  18. package/dist/cjs/common/index.js.map +1 -0
  19. package/dist/cjs/common/jwt.js +59 -0
  20. package/dist/cjs/common/jwt.js.map +1 -0
  21. package/dist/cjs/common/password.js +38 -0
  22. package/dist/cjs/common/password.js.map +1 -0
  23. package/dist/cjs/common/phone.js +42 -0
  24. package/dist/cjs/common/phone.js.map +1 -0
  25. package/dist/cjs/common/response.js +32 -0
  26. package/dist/cjs/common/response.js.map +1 -0
  27. package/dist/cjs/common/text.js +46 -0
  28. package/dist/cjs/common/text.js.map +1 -0
  29. package/dist/cjs/common/time.js +109 -0
  30. package/dist/cjs/common/time.js.map +1 -0
  31. package/dist/cjs/config/index.js +96 -0
  32. package/dist/cjs/config/index.js.map +1 -0
  33. package/dist/cjs/contracts/editorial-draft.js +111 -0
  34. package/dist/cjs/contracts/editorial-draft.js.map +1 -0
  35. package/dist/cjs/contracts/index.js +20 -0
  36. package/dist/cjs/contracts/index.js.map +1 -0
  37. package/dist/cjs/contracts/notification-dispatch.js +92 -0
  38. package/dist/cjs/contracts/notification-dispatch.js.map +1 -0
  39. package/dist/cjs/contracts/upload-import.js +54 -0
  40. package/dist/cjs/contracts/upload-import.js.map +1 -0
  41. package/dist/cjs/database/index.js +57 -0
  42. package/dist/cjs/database/index.js.map +1 -0
  43. package/dist/cjs/express/auth.js +72 -0
  44. package/dist/cjs/express/auth.js.map +1 -0
  45. package/dist/cjs/express/health.js +31 -0
  46. package/dist/cjs/express/health.js.map +1 -0
  47. package/dist/cjs/express/index.js +20 -0
  48. package/dist/cjs/express/index.js.map +1 -0
  49. package/dist/cjs/express/middleware.js +95 -0
  50. package/dist/cjs/express/middleware.js.map +1 -0
  51. package/dist/cjs/http/index.js +90 -0
  52. package/dist/cjs/http/index.js.map +1 -0
  53. package/dist/cjs/http/safe-fetch.js +199 -0
  54. package/dist/cjs/http/safe-fetch.js.map +1 -0
  55. package/dist/cjs/identity/index.js +117 -0
  56. package/dist/cjs/identity/index.js.map +1 -0
  57. package/dist/cjs/index.js +29 -0
  58. package/dist/cjs/index.js.map +1 -0
  59. package/dist/cjs/knex/index.js +76 -0
  60. package/dist/cjs/knex/index.js.map +1 -0
  61. package/dist/cjs/logging/index.js +75 -0
  62. package/dist/cjs/logging/index.js.map +1 -0
  63. package/dist/cjs/messaging/connection.js +115 -0
  64. package/dist/cjs/messaging/connection.js.map +1 -0
  65. package/dist/cjs/messaging/consumer.js +134 -0
  66. package/dist/cjs/messaging/consumer.js.map +1 -0
  67. package/dist/cjs/messaging/envelope.js +23 -0
  68. package/dist/cjs/messaging/envelope.js.map +1 -0
  69. package/dist/cjs/messaging/idempotency.js +57 -0
  70. package/dist/cjs/messaging/idempotency.js.map +1 -0
  71. package/dist/cjs/messaging/index.js +62 -0
  72. package/dist/cjs/messaging/index.js.map +1 -0
  73. package/dist/cjs/messaging/monitor.js +48 -0
  74. package/dist/cjs/messaging/monitor.js.map +1 -0
  75. package/dist/cjs/messaging/outbox.js +135 -0
  76. package/dist/cjs/messaging/outbox.js.map +1 -0
  77. package/dist/cjs/messaging/publisher.js +149 -0
  78. package/dist/cjs/messaging/publisher.js.map +1 -0
  79. package/dist/cjs/messaging/rpc.js +125 -0
  80. package/dist/cjs/messaging/rpc.js.map +1 -0
  81. package/dist/cjs/messaging/staff-notifier.js +78 -0
  82. package/dist/cjs/messaging/staff-notifier.js.map +1 -0
  83. package/dist/cjs/messaging/topology.js +22 -0
  84. package/dist/cjs/messaging/topology.js.map +1 -0
  85. package/dist/cjs/package.json +1 -0
  86. package/dist/cjs/rate-limit/index.js +61 -0
  87. package/dist/cjs/rate-limit/index.js.map +1 -0
  88. package/dist/cjs/scheduling/index.js +88 -0
  89. package/dist/cjs/scheduling/index.js.map +1 -0
  90. package/dist/cjs/security/index.js +39 -0
  91. package/dist/cjs/security/index.js.map +1 -0
  92. package/dist/cjs/socket/index.js +53 -0
  93. package/dist/cjs/socket/index.js.map +1 -0
  94. package/dist/cjs/testing/index.js +73 -0
  95. package/dist/cjs/testing/index.js.map +1 -0
  96. package/dist/cjs/types/index.js +3 -0
  97. package/dist/cjs/types/index.js.map +1 -0
  98. package/dist/cjs/validation/index.js +41 -0
  99. package/dist/cjs/validation/index.js.map +1 -0
  100. package/dist/esm/access/index.js +104 -0
  101. package/dist/esm/access/index.js.map +1 -0
  102. package/dist/esm/alerting/index.js +52 -0
  103. package/dist/esm/alerting/index.js.map +1 -0
  104. package/dist/esm/cache/index.js +163 -0
  105. package/dist/esm/cache/index.js.map +1 -0
  106. package/dist/esm/common/async.js +33 -0
  107. package/dist/esm/common/async.js.map +1 -0
  108. package/dist/esm/common/audit.js +18 -0
  109. package/dist/esm/common/audit.js.map +1 -0
  110. package/dist/esm/common/crypto.js +64 -0
  111. package/dist/esm/common/crypto.js.map +1 -0
  112. package/dist/esm/common/errors.js +75 -0
  113. package/dist/esm/common/errors.js.map +1 -0
  114. package/dist/esm/common/id.js +33 -0
  115. package/dist/esm/common/id.js.map +1 -0
  116. package/dist/esm/common/index.js +12 -0
  117. package/dist/esm/common/index.js.map +1 -0
  118. package/dist/esm/common/jwt.js +49 -0
  119. package/dist/esm/common/jwt.js.map +1 -0
  120. package/dist/esm/common/password.js +30 -0
  121. package/dist/esm/common/password.js.map +1 -0
  122. package/dist/esm/common/phone.js +33 -0
  123. package/dist/esm/common/phone.js.map +1 -0
  124. package/dist/esm/common/response.js +24 -0
  125. package/dist/esm/common/response.js.map +1 -0
  126. package/dist/esm/common/text.js +39 -0
  127. package/dist/esm/common/text.js.map +1 -0
  128. package/dist/esm/common/time.js +96 -0
  129. package/dist/esm/common/time.js.map +1 -0
  130. package/dist/esm/config/index.js +88 -0
  131. package/dist/esm/config/index.js.map +1 -0
  132. package/dist/esm/contracts/editorial-draft.js +108 -0
  133. package/dist/esm/contracts/editorial-draft.js.map +1 -0
  134. package/dist/esm/contracts/index.js +4 -0
  135. package/dist/esm/contracts/index.js.map +1 -0
  136. package/dist/esm/contracts/notification-dispatch.js +89 -0
  137. package/dist/esm/contracts/notification-dispatch.js.map +1 -0
  138. package/dist/esm/contracts/upload-import.js +51 -0
  139. package/dist/esm/contracts/upload-import.js.map +1 -0
  140. package/dist/esm/database/index.js +48 -0
  141. package/dist/esm/database/index.js.map +1 -0
  142. package/dist/esm/express/auth.js +63 -0
  143. package/dist/esm/express/auth.js.map +1 -0
  144. package/dist/esm/express/health.js +27 -0
  145. package/dist/esm/express/health.js.map +1 -0
  146. package/dist/esm/express/index.js +4 -0
  147. package/dist/esm/express/index.js.map +1 -0
  148. package/dist/esm/express/middleware.js +84 -0
  149. package/dist/esm/express/middleware.js.map +1 -0
  150. package/dist/esm/http/index.js +73 -0
  151. package/dist/esm/http/index.js.map +1 -0
  152. package/dist/esm/http/safe-fetch.js +193 -0
  153. package/dist/esm/http/safe-fetch.js.map +1 -0
  154. package/dist/esm/identity/index.js +111 -0
  155. package/dist/esm/identity/index.js.map +1 -0
  156. package/dist/esm/index.js +13 -0
  157. package/dist/esm/index.js.map +1 -0
  158. package/dist/esm/knex/index.js +66 -0
  159. package/dist/esm/knex/index.js.map +1 -0
  160. package/dist/esm/logging/index.js +67 -0
  161. package/dist/esm/logging/index.js.map +1 -0
  162. package/dist/esm/messaging/connection.js +108 -0
  163. package/dist/esm/messaging/connection.js.map +1 -0
  164. package/dist/esm/messaging/consumer.js +130 -0
  165. package/dist/esm/messaging/consumer.js.map +1 -0
  166. package/dist/esm/messaging/envelope.js +19 -0
  167. package/dist/esm/messaging/envelope.js.map +1 -0
  168. package/dist/esm/messaging/idempotency.js +52 -0
  169. package/dist/esm/messaging/idempotency.js.map +1 -0
  170. package/dist/esm/messaging/index.js +45 -0
  171. package/dist/esm/messaging/index.js.map +1 -0
  172. package/dist/esm/messaging/monitor.js +44 -0
  173. package/dist/esm/messaging/monitor.js.map +1 -0
  174. package/dist/esm/messaging/outbox.js +129 -0
  175. package/dist/esm/messaging/outbox.js.map +1 -0
  176. package/dist/esm/messaging/publisher.js +142 -0
  177. package/dist/esm/messaging/publisher.js.map +1 -0
  178. package/dist/esm/messaging/rpc.js +120 -0
  179. package/dist/esm/messaging/rpc.js.map +1 -0
  180. package/dist/esm/messaging/staff-notifier.js +73 -0
  181. package/dist/esm/messaging/staff-notifier.js.map +1 -0
  182. package/dist/esm/messaging/topology.js +16 -0
  183. package/dist/esm/messaging/topology.js.map +1 -0
  184. package/dist/esm/package.json +1 -0
  185. package/dist/esm/rate-limit/index.js +56 -0
  186. package/dist/esm/rate-limit/index.js.map +1 -0
  187. package/dist/esm/scheduling/index.js +83 -0
  188. package/dist/esm/scheduling/index.js.map +1 -0
  189. package/dist/esm/security/index.js +36 -0
  190. package/dist/esm/security/index.js.map +1 -0
  191. package/dist/esm/socket/index.js +47 -0
  192. package/dist/esm/socket/index.js.map +1 -0
  193. package/dist/esm/testing/index.js +66 -0
  194. package/dist/esm/testing/index.js.map +1 -0
  195. package/dist/esm/types/index.js +2 -0
  196. package/dist/esm/types/index.js.map +1 -0
  197. package/dist/esm/validation/index.js +36 -0
  198. package/dist/esm/validation/index.js.map +1 -0
  199. package/dist/types/access/index.d.ts +50 -0
  200. package/dist/types/access/index.d.ts.map +1 -0
  201. package/dist/types/alerting/index.d.ts +43 -0
  202. package/dist/types/alerting/index.d.ts.map +1 -0
  203. package/dist/types/cache/index.d.ts +45 -0
  204. package/dist/types/cache/index.d.ts.map +1 -0
  205. package/dist/types/common/async.d.ts +14 -0
  206. package/dist/types/common/async.d.ts.map +1 -0
  207. package/dist/types/common/audit.d.ts +17 -0
  208. package/dist/types/common/audit.d.ts.map +1 -0
  209. package/dist/types/common/crypto.d.ts +18 -0
  210. package/dist/types/common/crypto.d.ts.map +1 -0
  211. package/dist/types/common/errors.d.ts +71 -0
  212. package/dist/types/common/errors.d.ts.map +1 -0
  213. package/dist/types/common/id.d.ts +14 -0
  214. package/dist/types/common/id.d.ts.map +1 -0
  215. package/dist/types/common/index.d.ts +12 -0
  216. package/dist/types/common/index.d.ts.map +1 -0
  217. package/dist/types/common/jwt.d.ts +28 -0
  218. package/dist/types/common/jwt.d.ts.map +1 -0
  219. package/dist/types/common/password.d.ts +4 -0
  220. package/dist/types/common/password.d.ts.map +1 -0
  221. package/dist/types/common/phone.d.ts +10 -0
  222. package/dist/types/common/phone.d.ts.map +1 -0
  223. package/dist/types/common/response.d.ts +12 -0
  224. package/dist/types/common/response.d.ts.map +1 -0
  225. package/dist/types/common/text.d.ts +10 -0
  226. package/dist/types/common/text.d.ts.map +1 -0
  227. package/dist/types/common/time.d.ts +40 -0
  228. package/dist/types/common/time.d.ts.map +1 -0
  229. package/dist/types/config/index.d.ts +115 -0
  230. package/dist/types/config/index.d.ts.map +1 -0
  231. package/dist/types/contracts/editorial-draft.d.ts +577 -0
  232. package/dist/types/contracts/editorial-draft.d.ts.map +1 -0
  233. package/dist/types/contracts/index.d.ts +4 -0
  234. package/dist/types/contracts/index.d.ts.map +1 -0
  235. package/dist/types/contracts/notification-dispatch.d.ts +175 -0
  236. package/dist/types/contracts/notification-dispatch.d.ts.map +1 -0
  237. package/dist/types/contracts/upload-import.d.ts +96 -0
  238. package/dist/types/contracts/upload-import.d.ts.map +1 -0
  239. package/dist/types/database/index.d.ts +25 -0
  240. package/dist/types/database/index.d.ts.map +1 -0
  241. package/dist/types/express/auth.d.ts +27 -0
  242. package/dist/types/express/auth.d.ts.map +1 -0
  243. package/dist/types/express/health.d.ts +14 -0
  244. package/dist/types/express/health.d.ts.map +1 -0
  245. package/dist/types/express/index.d.ts +4 -0
  246. package/dist/types/express/index.d.ts.map +1 -0
  247. package/dist/types/express/middleware.d.ts +20 -0
  248. package/dist/types/express/middleware.d.ts.map +1 -0
  249. package/dist/types/http/index.d.ts +34 -0
  250. package/dist/types/http/index.d.ts.map +1 -0
  251. package/dist/types/http/safe-fetch.d.ts +58 -0
  252. package/dist/types/http/safe-fetch.d.ts.map +1 -0
  253. package/dist/types/identity/index.d.ts +51 -0
  254. package/dist/types/identity/index.d.ts.map +1 -0
  255. package/dist/types/index.d.ts +10 -0
  256. package/dist/types/index.d.ts.map +1 -0
  257. package/dist/types/knex/index.d.ts +25 -0
  258. package/dist/types/knex/index.d.ts.map +1 -0
  259. package/dist/types/logging/index.d.ts +22 -0
  260. package/dist/types/logging/index.d.ts.map +1 -0
  261. package/dist/types/messaging/connection.d.ts +48 -0
  262. package/dist/types/messaging/connection.d.ts.map +1 -0
  263. package/dist/types/messaging/consumer.d.ts +56 -0
  264. package/dist/types/messaging/consumer.d.ts.map +1 -0
  265. package/dist/types/messaging/envelope.d.ts +16 -0
  266. package/dist/types/messaging/envelope.d.ts.map +1 -0
  267. package/dist/types/messaging/idempotency.d.ts +29 -0
  268. package/dist/types/messaging/idempotency.d.ts.map +1 -0
  269. package/dist/types/messaging/index.d.ts +39 -0
  270. package/dist/types/messaging/index.d.ts.map +1 -0
  271. package/dist/types/messaging/monitor.d.ts +23 -0
  272. package/dist/types/messaging/monitor.d.ts.map +1 -0
  273. package/dist/types/messaging/outbox.d.ts +51 -0
  274. package/dist/types/messaging/outbox.d.ts.map +1 -0
  275. package/dist/types/messaging/publisher.d.ts +84 -0
  276. package/dist/types/messaging/publisher.d.ts.map +1 -0
  277. package/dist/types/messaging/rpc.d.ts +46 -0
  278. package/dist/types/messaging/rpc.d.ts.map +1 -0
  279. package/dist/types/messaging/staff-notifier.d.ts +56 -0
  280. package/dist/types/messaging/staff-notifier.d.ts.map +1 -0
  281. package/dist/types/messaging/topology.d.ts +23 -0
  282. package/dist/types/messaging/topology.d.ts.map +1 -0
  283. package/dist/types/rate-limit/index.d.ts +28 -0
  284. package/dist/types/rate-limit/index.d.ts.map +1 -0
  285. package/dist/types/scheduling/index.d.ts +33 -0
  286. package/dist/types/scheduling/index.d.ts.map +1 -0
  287. package/dist/types/security/index.d.ts +20 -0
  288. package/dist/types/security/index.d.ts.map +1 -0
  289. package/dist/types/socket/index.d.ts +30 -0
  290. package/dist/types/socket/index.d.ts.map +1 -0
  291. package/dist/types/testing/index.d.ts +41 -0
  292. package/dist/types/testing/index.d.ts.map +1 -0
  293. package/dist/types/types/index.d.ts +65 -0
  294. package/dist/types/types/index.d.ts.map +1 -0
  295. package/dist/types/validation/index.d.ts +34 -0
  296. package/dist/types/validation/index.d.ts.map +1 -0
  297. package/package.json +189 -4
  298. package/README.md +0 -3
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ID_PATTERN = exports.ID_LENGTH = void 0;
4
+ exports.newId = newId;
5
+ exports.isId = isId;
6
+ exports.idTimestamp = idTimestamp;
7
+ exports.fixtureId = fixtureId;
8
+ const ulid_1 = require("ulid");
9
+ /**
10
+ * Primary keys are ULIDs: 26-char Crockford base32, lexicographically sortable by creation
11
+ * time, so B-tree inserts stay append-only (unlike random UUIDv4) and IDs double as a coarse
12
+ * creation timestamp. Store them in `CHAR(26)` columns.
13
+ */
14
+ const nextUlid = (0, ulid_1.monotonicFactory)();
15
+ exports.ID_LENGTH = 26;
16
+ exports.ID_PATTERN = /^[0-9A-HJKMNP-TV-Z]{26}$/;
17
+ /** A new time-ordered, monotonic ULID. */
18
+ function newId() {
19
+ return nextUlid();
20
+ }
21
+ function isId(value) {
22
+ return typeof value === 'string' && exports.ID_PATTERN.test(value);
23
+ }
24
+ /** Creation time encoded in a ULID. */
25
+ function idTimestamp(id) {
26
+ return new Date((0, ulid_1.decodeTime)(id));
27
+ }
28
+ const FIXTURE_PREFIX = '01K6SEED';
29
+ /**
30
+ * A stable, valid ID for seed/fixture rows: the same `(namespace, n)` always yields the same ID, so
31
+ * seeds in different services can reference each other's rows without sharing a database.
32
+ * `namespace` is two Crockford characters (e.g. `PR` for profiles).
33
+ */
34
+ function fixtureId(namespace, n) {
35
+ const id = `${FIXTURE_PREFIX}${namespace.toUpperCase()}${String(n).padStart(exports.ID_LENGTH - FIXTURE_PREFIX.length - namespace.length, '0')}`;
36
+ if (!exports.ID_PATTERN.test(id))
37
+ throw new Error(`Invalid fixture id namespace/sequence: ${namespace}/${n}`);
38
+ return id;
39
+ }
40
+ //# sourceMappingURL=id.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"id.js","sourceRoot":"","sources":["../../../src/common/id.ts"],"names":[],"mappings":";;;AAaA,sBAEC;AAED,oBAEC;AAGD,kCAEC;AASD,8BAIC;AArCD,+BAAoD;AAEpD;;;;GAIG;AACH,MAAM,QAAQ,GAAG,IAAA,uBAAgB,GAAE,CAAC;AAEvB,QAAA,SAAS,GAAG,EAAE,CAAC;AACf,QAAA,UAAU,GAAG,0BAA0B,CAAC;AAErD,0CAA0C;AAC1C,SAAgB,KAAK;IACnB,OAAO,QAAQ,EAAE,CAAC;AACpB,CAAC;AAED,SAAgB,IAAI,CAAC,KAAc;IACjC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,kBAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AAC7D,CAAC;AAED,uCAAuC;AACvC,SAAgB,WAAW,CAAC,EAAU;IACpC,OAAO,IAAI,IAAI,CAAC,IAAA,iBAAU,EAAC,EAAE,CAAC,CAAC,CAAC;AAClC,CAAC;AAED,MAAM,cAAc,GAAG,UAAU,CAAC;AAElC;;;;GAIG;AACH,SAAgB,SAAS,CAAC,SAAiB,EAAE,CAAS;IACpD,MAAM,EAAE,GAAG,GAAG,cAAc,GAAG,SAAS,CAAC,WAAW,EAAE,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,iBAAS,GAAG,cAAc,CAAC,MAAM,GAAG,SAAS,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,CAAC;IACzI,IAAI,CAAC,kBAAU,CAAC,IAAI,CAAC,EAAE,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,0CAA0C,SAAS,IAAI,CAAC,EAAE,CAAC,CAAC;IACtG,OAAO,EAAE,CAAC;AACZ,CAAC"}
@@ -0,0 +1,28 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ __exportStar(require("./id.js"), exports);
18
+ __exportStar(require("./errors.js"), exports);
19
+ __exportStar(require("./response.js"), exports);
20
+ __exportStar(require("./crypto.js"), exports);
21
+ __exportStar(require("./password.js"), exports);
22
+ __exportStar(require("./jwt.js"), exports);
23
+ __exportStar(require("./text.js"), exports);
24
+ __exportStar(require("./async.js"), exports);
25
+ __exportStar(require("./phone.js"), exports);
26
+ __exportStar(require("./time.js"), exports);
27
+ __exportStar(require("./audit.js"), exports);
28
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/common/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,0CAAwB;AACxB,8CAA4B;AAC5B,gDAA8B;AAC9B,8CAA4B;AAC5B,gDAA8B;AAC9B,2CAAyB;AACzB,4CAA0B;AAC1B,6CAA2B;AAC3B,6CAA2B;AAC3B,4CAA0B;AAC1B,6CAA2B"}
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.signJwt = signJwt;
7
+ exports.verifyJwt = verifyJwt;
8
+ exports.decodeJwt = decodeJwt;
9
+ exports.extractBearerToken = extractBearerToken;
10
+ exports.durationToSeconds = durationToSeconds;
11
+ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
12
+ function signJwt(payload, secret, options) {
13
+ return jsonwebtoken_1.default.sign(payload, secret, {
14
+ algorithm: 'HS256',
15
+ expiresIn: options.expiresIn,
16
+ ...(options.issuer ? { issuer: options.issuer } : {}),
17
+ ...(options.audience ? { audience: options.audience } : {}),
18
+ ...(options.jwtId ? { jwtid: options.jwtId } : {}),
19
+ });
20
+ }
21
+ /** Verifies signature, expiry and (when given) issuer/audience. Throws on any failure. */
22
+ function verifyJwt(token, secret, options = {}) {
23
+ const decoded = jsonwebtoken_1.default.verify(token, secret, {
24
+ algorithms: ['HS256'],
25
+ ...(options.issuer ? { issuer: options.issuer } : {}),
26
+ ...(options.audience ? { audience: options.audience } : {}),
27
+ });
28
+ if (typeof decoded === 'string' || !decoded.sub)
29
+ throw new Error('Invalid token payload');
30
+ return decoded;
31
+ }
32
+ function decodeJwt(token) {
33
+ const decoded = jsonwebtoken_1.default.decode(token);
34
+ return decoded && typeof decoded !== 'string' ? decoded : null;
35
+ }
36
+ function extractBearerToken(header) {
37
+ if (!header)
38
+ return null;
39
+ const [scheme, token] = header.split(' ');
40
+ return scheme?.toLowerCase() === 'bearer' && token ? token.trim() : null;
41
+ }
42
+ /** Converts `'15m'`, `'30d'`, `3600` into seconds. */
43
+ function durationToSeconds(value) {
44
+ if (typeof value === 'number')
45
+ return value;
46
+ const match = /^(\d+)\s*(ms|s|m|h|d|w)?$/.exec(value.trim());
47
+ if (!match)
48
+ throw new Error(`Invalid duration: ${value}`);
49
+ const amount = Number(match[1]);
50
+ switch (match[2]) {
51
+ case 'ms': return Math.ceil(amount / 1000);
52
+ case 'm': return amount * 60;
53
+ case 'h': return amount * 3600;
54
+ case 'd': return amount * 86_400;
55
+ case 'w': return amount * 604_800;
56
+ default: return amount;
57
+ }
58
+ }
59
+ //# sourceMappingURL=jwt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"jwt.js","sourceRoot":"","sources":["../../../src/common/jwt.ts"],"names":[],"mappings":";;;;;AAyBA,0BAQC;AAGD,8BAQC;AAED,8BAGC;AAED,gDAIC;AAGD,8CAaC;AAvED,gEAA+B;AAyB/B,SAAgB,OAAO,CAAC,OAAgC,EAAE,MAAc,EAAE,OAAuB;IAC/F,OAAO,sBAAG,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,EAAE;QAC/B,SAAS,EAAE,OAAO;QAClB,SAAS,EAAE,OAAO,CAAC,SAAyC;QAC5D,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,GAAG,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACnD,CAAC,CAAC;AACL,CAAC;AAED,0FAA0F;AAC1F,SAAgB,SAAS,CAAkC,KAAa,EAAE,MAAc,EAAE,UAA4B,EAAE;IACtH,MAAM,OAAO,GAAG,sBAAG,CAAC,MAAM,CAAC,KAAK,EAAE,MAAM,EAAE;QACxC,UAAU,EAAE,CAAC,OAAO,CAAC;QACrB,GAAG,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACrD,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC5D,CAAC,CAAC;IACH,IAAI,OAAO,OAAO,KAAK,QAAQ,IAAI,CAAC,OAAO,CAAC,GAAG;QAAE,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC1F,OAAO,OAAuB,CAAC;AACjC,CAAC;AAED,SAAgB,SAAS,CAAkC,KAAa;IACtE,MAAM,OAAO,GAAG,sBAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAClC,OAAO,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,CAAC,CAAC,CAAE,OAAwB,CAAC,CAAC,CAAC,IAAI,CAAC;AACnF,CAAC;AAED,SAAgB,kBAAkB,CAAC,MAAsB;IACvD,IAAI,CAAC,MAAM;QAAE,OAAO,IAAI,CAAC;IACzB,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC1C,OAAO,MAAM,EAAE,WAAW,EAAE,KAAK,QAAQ,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC;AAC3E,CAAC;AAED,sDAAsD;AACtD,SAAgB,iBAAiB,CAAC,KAAsB;IACtD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,KAAK,CAAC;IAC5C,MAAM,KAAK,GAAG,2BAA2B,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IAC7D,IAAI,CAAC,KAAK;QAAE,MAAM,IAAI,KAAK,CAAC,qBAAqB,KAAK,EAAE,CAAC,CAAC;IAC1D,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAChC,QAAQ,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QACjB,KAAK,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,IAAI,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;QAC3C,KAAK,GAAG,CAAC,CAAC,OAAO,MAAM,GAAG,EAAE,CAAC;QAC7B,KAAK,GAAG,CAAC,CAAC,OAAO,MAAM,GAAG,IAAI,CAAC;QAC/B,KAAK,GAAG,CAAC,CAAC,OAAO,MAAM,GAAG,MAAM,CAAC;QACjC,KAAK,GAAG,CAAC,CAAC,OAAO,MAAM,GAAG,OAAO,CAAC;QAClC,OAAO,CAAC,CAAC,OAAO,MAAM,CAAC;IACzB,CAAC;AACH,CAAC"}
@@ -0,0 +1,38 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.hashPassword = hashPassword;
7
+ exports.verifyPassword = verifyPassword;
8
+ exports.needsRehash = needsRehash;
9
+ const argon2_1 = __importDefault(require("argon2"));
10
+ const bcryptjs_1 = __importDefault(require("bcryptjs"));
11
+ /**
12
+ * Passwords are hashed with argon2id. Legacy bcrypt hashes (`$2a$`, `$2b$`, `$2y$`) still
13
+ * verify so migrated accounts can sign in; callers should re-hash on success when
14
+ * `needsRehash()` is true.
15
+ */
16
+ const ARGON2_OPTIONS = { type: argon2_1.default.argon2id, memoryCost: 19_456, timeCost: 2, parallelism: 1 };
17
+ const BCRYPT_PREFIX = /^\$2[aby]\$/;
18
+ async function hashPassword(password) {
19
+ return argon2_1.default.hash(password, ARGON2_OPTIONS);
20
+ }
21
+ async function verifyPassword(password, hash) {
22
+ if (!hash)
23
+ return false;
24
+ try {
25
+ if (BCRYPT_PREFIX.test(hash))
26
+ return await bcryptjs_1.default.compare(password, hash);
27
+ return await argon2_1.default.verify(hash, password);
28
+ }
29
+ catch {
30
+ return false;
31
+ }
32
+ }
33
+ function needsRehash(hash) {
34
+ if (BCRYPT_PREFIX.test(hash))
35
+ return true;
36
+ return argon2_1.default.needsRehash(hash, ARGON2_OPTIONS);
37
+ }
38
+ //# sourceMappingURL=password.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"password.js","sourceRoot":"","sources":["../../../src/common/password.ts"],"names":[],"mappings":";;;;;AAYA,oCAEC;AAED,wCAQC;AAED,kCAGC;AA7BD,oDAA4B;AAC5B,wDAA8B;AAE9B;;;;GAIG;AACH,MAAM,cAAc,GAAG,EAAE,IAAI,EAAE,gBAAM,CAAC,QAAQ,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,WAAW,EAAE,CAAC,EAAW,CAAC;AAE3G,MAAM,aAAa,GAAG,aAAa,CAAC;AAE7B,KAAK,UAAU,YAAY,CAAC,QAAgB;IACjD,OAAO,gBAAM,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC;AAC/C,CAAC;AAEM,KAAK,UAAU,cAAc,CAAC,QAAgB,EAAE,IAA+B;IACpF,IAAI,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC;IACxB,IAAI,CAAC;QACH,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;YAAE,OAAO,MAAM,kBAAM,CAAC,OAAO,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;QAC1E,OAAO,MAAM,gBAAM,CAAC,MAAM,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED,SAAgB,WAAW,CAAC,IAAY;IACtC,IAAI,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC;QAAE,OAAO,IAAI,CAAC;IAC1C,OAAO,gBAAM,CAAC,WAAW,CAAC,IAAI,EAAE,cAAc,CAAC,CAAC;AAClD,CAAC"}
@@ -0,0 +1,42 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.toE164 = toE164;
7
+ exports.toMsisdn = toMsisdn;
8
+ exports.phoneRegion = phoneRegion;
9
+ exports.maskPhone = maskPhone;
10
+ const google_libphonenumber_1 = __importDefault(require("google-libphonenumber"));
11
+ const util = google_libphonenumber_1.default.PhoneNumberUtil.getInstance();
12
+ const { PhoneNumberFormat } = google_libphonenumber_1.default;
13
+ /**
14
+ * Normalises a phone number to E.164 (`+254712345678`). Returns null for anything that is not a
15
+ * valid number for the given default region.
16
+ */
17
+ function toE164(phone, defaultRegion = 'KE') {
18
+ try {
19
+ const parsed = util.parseAndKeepRawInput(phone.trim(), defaultRegion);
20
+ return util.isValidNumber(parsed) ? util.format(parsed, PhoneNumberFormat.E164) : null;
21
+ }
22
+ catch {
23
+ return null;
24
+ }
25
+ }
26
+ /** E.164 without the plus sign, as most SMS gateways expect (`254712345678`). */
27
+ function toMsisdn(phone, defaultRegion = 'KE') {
28
+ const e164 = toE164(phone, defaultRegion);
29
+ return e164 ? e164.slice(1) : null;
30
+ }
31
+ function phoneRegion(phone, defaultRegion = 'KE') {
32
+ try {
33
+ return util.getRegionCodeForNumber(util.parse(phone, defaultRegion)) ?? null;
34
+ }
35
+ catch {
36
+ return null;
37
+ }
38
+ }
39
+ function maskPhone(phone) {
40
+ return phone.length <= 4 ? '****' : `${phone.slice(0, 4)}****${phone.slice(-2)}`;
41
+ }
42
+ //# sourceMappingURL=phone.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"phone.js","sourceRoot":"","sources":["../../../src/common/phone.ts"],"names":[],"mappings":";;;;;AASA,wBAOC;AAGD,4BAGC;AAED,kCAMC;AAED,8BAEC;AAlCD,kFAAmD;AAEnD,MAAM,IAAI,GAAG,+BAAc,CAAC,eAAe,CAAC,WAAW,EAAE,CAAC;AAC1D,MAAM,EAAE,iBAAiB,EAAE,GAAG,+BAAc,CAAC;AAE7C;;;GAGG;AACH,SAAgB,MAAM,CAAC,KAAa,EAAE,aAAa,GAAG,IAAI;IACxD,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,IAAI,CAAC,oBAAoB,CAAC,KAAK,CAAC,IAAI,EAAE,EAAE,aAAa,CAAC,CAAC;QACtE,OAAO,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACzF,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,iFAAiF;AACjF,SAAgB,QAAQ,CAAC,KAAa,EAAE,aAAa,GAAG,IAAI;IAC1D,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC;IAC1C,OAAO,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AACrC,CAAC;AAED,SAAgB,WAAW,CAAC,KAAa,EAAE,aAAa,GAAG,IAAI;IAC7D,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,sBAAsB,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,aAAa,CAAC,CAAC,IAAI,IAAI,CAAC;IAC/E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAgB,SAAS,CAAC,KAAa;IACrC,OAAO,KAAK,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;AACnF,CAAC"}
@@ -0,0 +1,32 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.successResponse = successResponse;
4
+ exports.errorResponse = errorResponse;
5
+ exports.buildPaginationMeta = buildPaginationMeta;
6
+ exports.paginatedResponse = paginatedResponse;
7
+ exports.buildPaginatedResult = buildPaginatedResult;
8
+ exports.pageOffset = pageOffset;
9
+ /** Standard success envelope: `{ success, message, data }`. */
10
+ function successResponse(data, message = 'Success') {
11
+ return { success: true, message, data };
12
+ }
13
+ /** Standard error envelope: `{ success: false, message, code?, errors? }`. */
14
+ function errorResponse(message, errors, code) {
15
+ return { success: false, message, ...(code ? { code } : {}), ...(errors ? { errors } : {}) };
16
+ }
17
+ function buildPaginationMeta(total, page, limit) {
18
+ const totalPages = limit > 0 ? Math.max(1, Math.ceil(total / limit)) : 1;
19
+ return { page, limit, total, totalPages, hasNext: page < totalPages, hasPrev: page > 1 };
20
+ }
21
+ /** Paginated envelope: `{ success, message, data: T[], meta }`. */
22
+ function paginatedResponse(data, total, page, limit, message = 'Success') {
23
+ return { success: true, message, data, meta: buildPaginationMeta(total, page, limit) };
24
+ }
25
+ function buildPaginatedResult(data, total, page, limit) {
26
+ return { data, meta: buildPaginationMeta(total, page, limit) };
27
+ }
28
+ /** SQL offset for 1-based pages. */
29
+ function pageOffset(page, limit) {
30
+ return Math.max(0, (Math.max(1, page) - 1) * limit);
31
+ }
32
+ //# sourceMappingURL=response.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"response.js","sourceRoot":"","sources":["../../../src/common/response.ts"],"names":[],"mappings":";;AAGA,0CAEC;AAGD,sCAEC;AAED,kDAGC;AAGD,8CAEC;AAED,oDAEC;AAGD,gCAEC;AA3BD,+DAA+D;AAC/D,SAAgB,eAAe,CAAI,IAAO,EAAE,OAAO,GAAG,SAAS;IAC7D,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC1C,CAAC;AAED,8EAA8E;AAC9E,SAAgB,aAAa,CAAC,OAAe,EAAE,MAAiC,EAAE,IAAa;IAC7F,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC;AAC/F,CAAC;AAED,SAAgB,mBAAmB,CAAC,KAAa,EAAE,IAAY,EAAE,KAAa;IAC5E,MAAM,UAAU,GAAG,KAAK,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACzE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,GAAG,UAAU,EAAE,OAAO,EAAE,IAAI,GAAG,CAAC,EAAE,CAAC;AAC3F,CAAC;AAED,mEAAmE;AACnE,SAAgB,iBAAiB,CAAI,IAAS,EAAE,KAAa,EAAE,IAAY,EAAE,KAAa,EAAE,OAAO,GAAG,SAAS;IAC7G,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,mBAAmB,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;AACzF,CAAC;AAED,SAAgB,oBAAoB,CAAI,IAAS,EAAE,KAAa,EAAE,IAAY,EAAE,KAAa;IAC3F,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,mBAAmB,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC;AACjE,CAAC;AAED,oCAAoC;AACpC,SAAgB,UAAU,CAAC,IAAY,EAAE,KAAa;IACpD,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,KAAK,CAAC,CAAC;AACtD,CAAC"}
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.slugify = slugify;
4
+ exports.interpolate = interpolate;
5
+ exports.templateVariables = templateVariables;
6
+ exports.escapeHtml = escapeHtml;
7
+ exports.maskEmail = maskEmail;
8
+ /** URL slug: lowercase ASCII, dash-separated, accents folded. */
9
+ function slugify(value, maxLength = 80) {
10
+ return value
11
+ .normalize('NFKD')
12
+ .replace(/[̀-ͯ]/g, '')
13
+ .toLowerCase()
14
+ .replace(/&/g, ' and ')
15
+ .replace(/[^a-z0-9]+/g, '-')
16
+ .replace(/^-+|-+$/g, '')
17
+ .slice(0, maxLength)
18
+ .replace(/-+$/g, '');
19
+ }
20
+ /** Replaces `{{ name }}` placeholders; unknown names become empty strings. */
21
+ function interpolate(template, variables, escape) {
22
+ return template.replace(/\{\{\s*([\w.]+)\s*\}\}/g, (_, path) => {
23
+ const value = path.split('.').reduce((acc, key) => (acc && typeof acc === 'object' ? acc[key] : undefined), variables);
24
+ const text = value === undefined || value === null ? '' : String(value);
25
+ return escape ? escape(text) : text;
26
+ });
27
+ }
28
+ /** Placeholder names used by a template, e.g. `['user.name', 'code']`. */
29
+ function templateVariables(template) {
30
+ const names = new Set();
31
+ for (const match of template.matchAll(/\{\{\s*([\w.]+)\s*\}\}/g))
32
+ names.add(match[1]);
33
+ return [...names];
34
+ }
35
+ const HTML_ESCAPES = { '&': '&amp;', '<': '&lt;', '>': '&gt;', '"': '&quot;', "'": '&#39;' };
36
+ function escapeHtml(value) {
37
+ return value.replace(/[&<>"']/g, (ch) => HTML_ESCAPES[ch]);
38
+ }
39
+ /** `jane.doe@example.com` → `ja***@example.com` for logs and audit trails. */
40
+ function maskEmail(email) {
41
+ const [local, domain] = email.split('@');
42
+ if (!local || !domain)
43
+ return '***';
44
+ return `${local.slice(0, 2)}***@${domain}`;
45
+ }
46
+ //# sourceMappingURL=text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"text.js","sourceRoot":"","sources":["../../../src/common/text.ts"],"names":[],"mappings":";;AACA,0BAUC;AAGD,kCAMC;AAGD,8CAIC;AAID,gCAEC;AAGD,8BAIC;AAxCD,iEAAiE;AACjE,SAAgB,OAAO,CAAC,KAAa,EAAE,SAAS,GAAG,EAAE;IACnD,OAAO,KAAK;SACT,SAAS,CAAC,MAAM,CAAC;SACjB,OAAO,CAAC,QAAQ,EAAE,EAAE,CAAC;SACrB,WAAW,EAAE;SACb,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC;SACtB,OAAO,CAAC,aAAa,EAAE,GAAG,CAAC;SAC3B,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;SACvB,KAAK,CAAC,CAAC,EAAE,SAAS,CAAC;SACnB,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;AACzB,CAAC;AAED,8EAA8E;AAC9E,SAAgB,WAAW,CAAC,QAAgB,EAAE,SAAkC,EAAE,MAAkC;IAClH,OAAO,QAAQ,CAAC,OAAO,CAAC,yBAAyB,EAAE,CAAC,CAAC,EAAE,IAAY,EAAE,EAAE;QACrE,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,MAAM,CAAU,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,CAAC,CAAC,CAAE,GAA+B,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,EAAE,SAAS,CAAC,CAAC;QAC7J,MAAM,IAAI,GAAG,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QACxE,OAAO,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACtC,CAAC,CAAC,CAAC;AACL,CAAC;AAED,0EAA0E;AAC1E,SAAgB,iBAAiB,CAAC,QAAgB;IAChD,MAAM,KAAK,GAAG,IAAI,GAAG,EAAU,CAAC;IAChC,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,QAAQ,CAAC,yBAAyB,CAAC;QAAE,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAE,CAAC,CAAC;IACvF,OAAO,CAAC,GAAG,KAAK,CAAC,CAAC;AACpB,CAAC;AAED,MAAM,YAAY,GAA2B,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC;AAErH,SAAgB,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,UAAU,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,YAAY,CAAC,EAAE,CAAE,CAAC,CAAC;AAC9D,CAAC;AAED,8EAA8E;AAC9E,SAAgB,SAAS,CAAC,KAAa;IACrC,MAAM,CAAC,KAAK,EAAE,MAAM,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACzC,IAAI,CAAC,KAAK,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IACpC,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,OAAO,MAAM,EAAE,CAAC;AAC7C,CAAC"}
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addMinutes = exports.addSeconds = void 0;
4
+ exports.isValidTimeZone = isValidTimeZone;
5
+ exports.formatInTimeZone = formatInTimeZone;
6
+ exports.formatInstantInZone = formatInstantInZone;
7
+ exports.timeZoneOffsetMinutes = timeZoneOffsetMinutes;
8
+ exports.parseClockTime = parseClockTime;
9
+ exports.zonedWallTimeToInstant = zonedWallTimeToInstant;
10
+ exports.zonedDayBounds = zonedDayBounds;
11
+ exports.quietWindowEndAt = quietWindowEndAt;
12
+ /** True for IANA zones the runtime knows (`Africa/Nairobi`), false for garbage. */
13
+ function isValidTimeZone(zone) {
14
+ try {
15
+ new Intl.DateTimeFormat('en-US', { timeZone: zone });
16
+ return true;
17
+ }
18
+ catch {
19
+ return false;
20
+ }
21
+ }
22
+ /** Formats an instant in a zone, e.g. `30 Sep 2026, 14:05 EAT`. Falls back to UTC for invalid zones. */
23
+ function formatInTimeZone(date, zone, locale = 'en-GB') {
24
+ const timeZone = isValidTimeZone(zone) ? zone : 'UTC';
25
+ return new Intl.DateTimeFormat(locale, {
26
+ timeZone,
27
+ day: '2-digit',
28
+ month: 'short',
29
+ year: 'numeric',
30
+ hour: '2-digit',
31
+ minute: '2-digit',
32
+ timeZoneName: 'short',
33
+ }).format(new Date(date));
34
+ }
35
+ /**
36
+ * Formats an instant for a person in their zone, falling back to `fallbackZone` (itself falling back to
37
+ * UTC) when theirs is missing or unknown. Never throws, and says when it fell back so callers can log it.
38
+ */
39
+ function formatInstantInZone(instant, zone, fallbackZone = 'UTC', locale = 'en-GB') {
40
+ const usedFallback = !(typeof zone === 'string' && zone && isValidTimeZone(zone));
41
+ const timezone = usedFallback ? (isValidTimeZone(fallbackZone) ? fallbackZone : 'UTC') : zone;
42
+ const date = new Date(instant);
43
+ return { text: Number.isNaN(date.getTime()) ? '' : formatInTimeZone(date, timezone, locale), timezone, usedFallback };
44
+ }
45
+ /** Offset of `zone` from UTC in minutes at `at` (positive east of Greenwich). */
46
+ function timeZoneOffsetMinutes(zone, at = new Date()) {
47
+ const parts = new Intl.DateTimeFormat('en-US', {
48
+ timeZone: zone, hourCycle: 'h23', year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', second: '2-digit',
49
+ }).formatToParts(at);
50
+ const get = (type) => Number(parts.find((p) => p.type === type)?.value);
51
+ const asUtc = Date.UTC(get('year'), get('month') - 1, get('day'), get('hour'), get('minute'), get('second'));
52
+ return Math.round((asUtc - Math.floor(at.getTime() / 1000) * 1000) / 60_000);
53
+ }
54
+ const addSeconds = (date, seconds) => new Date(date.getTime() + seconds * 1000);
55
+ exports.addSeconds = addSeconds;
56
+ const addMinutes = (date, minutes) => (0, exports.addSeconds)(date, minutes * 60);
57
+ exports.addMinutes = addMinutes;
58
+ const MS_PER_MINUTE = 60_000;
59
+ const MS_PER_DAY = 86_400_000;
60
+ const CLOCK_TIME = /^([01]\d|2[0-3]):([0-5]\d)$/;
61
+ /** Minutes since midnight of a 24-hour `HH:MM` clock time. Throws on anything else (never guesses). */
62
+ function parseClockTime(value) {
63
+ const match = CLOCK_TIME.exec(String(value ?? '').trim());
64
+ if (!match)
65
+ throw new RangeError(`Not a 24-hour HH:MM clock time: "${value}"`);
66
+ return Number(match[1]) * 60 + Number(match[2]);
67
+ }
68
+ /** The local calendar date of `at` in `zone`, and how far into that local day it is. */
69
+ function localDate(at, zone) {
70
+ const local = new Date(at.getTime() + timeZoneOffsetMinutes(zone, at) * MS_PER_MINUTE);
71
+ const msOfDay = ((local.getTime() % MS_PER_DAY) + MS_PER_DAY) % MS_PER_DAY;
72
+ return { year: local.getUTCFullYear(), month: local.getUTCMonth(), day: local.getUTCDate(), msOfDay };
73
+ }
74
+ /**
75
+ * The instant a wall-clock time occurs in `zone` (month is 0-based; an overflowing day rolls over).
76
+ * The offset is read again at the first estimate, so the result is right across a DST change; a wall
77
+ * time skipped by a spring-forward resolves to the nearest valid instant.
78
+ */
79
+ function zonedWallTimeToInstant(year, month, day, minutesOfDay, zone) {
80
+ const wall = Date.UTC(year, month, day) + minutesOfDay * MS_PER_MINUTE;
81
+ const estimate = wall - timeZoneOffsetMinutes(zone, new Date(wall)) * MS_PER_MINUTE;
82
+ return new Date(wall - timeZoneOffsetMinutes(zone, new Date(estimate)) * MS_PER_MINUTE);
83
+ }
84
+ /** The local calendar day containing `at` in `zone`, as a half-open `[start, end)` UTC range (23–25 h on DST days). */
85
+ function zonedDayBounds(at, zone) {
86
+ const { year, month, day } = localDate(at, zone);
87
+ return { start: zonedWallTimeToInstant(year, month, day, 0, zone), end: zonedWallTimeToInstant(year, month, day + 1, 0, zone) };
88
+ }
89
+ /**
90
+ * When `at` falls inside the daily window `[start, end)` (local `HH:MM` times in `zone`; the window may
91
+ * cross midnight), the instant that window ends; otherwise null. `start === end` means no window.
92
+ */
93
+ function quietWindowEndAt(at, zone, start, end) {
94
+ const startMin = parseClockTime(start);
95
+ const endMin = parseClockTime(end);
96
+ if (startMin === endMin)
97
+ return null;
98
+ const { year, month, day, msOfDay } = localDate(at, zone);
99
+ const startMs = startMin * MS_PER_MINUTE;
100
+ const endMs = endMin * MS_PER_MINUTE;
101
+ const crossesMidnight = startMin > endMin;
102
+ const inside = crossesMidnight ? msOfDay >= startMs || msOfDay < endMs : msOfDay >= startMs && msOfDay < endMs;
103
+ if (!inside)
104
+ return null;
105
+ // A midnight-crossing window entered before midnight ends tomorrow; otherwise it ends today.
106
+ const endsTomorrow = crossesMidnight && msOfDay >= startMs;
107
+ return zonedWallTimeToInstant(year, month, day + (endsTomorrow ? 1 : 0), endMin, zone);
108
+ }
109
+ //# sourceMappingURL=time.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"time.js","sourceRoot":"","sources":["../../../src/common/time.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.listFromEnv = exports.ConfigError = exports.redisEnv = exports.messagingEnv = exports.databaseEnv = exports.serviceEnv = void 0;
4
+ exports.amqpUrlFromEnv = amqpUrlFromEnv;
5
+ exports.loadDotEnv = loadDotEnv;
6
+ exports.loadEnv = loadEnv;
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = require("node:path");
9
+ const zod_1 = require("zod");
10
+ /**
11
+ * Environment building blocks. Services compose the pieces they need:
12
+ *
13
+ * const env = loadEnv(serviceEnv.merge(databaseEnv).merge(messagingEnv).extend({ MY_VAR: z.string() }));
14
+ */
15
+ exports.serviceEnv = zod_1.z.object({
16
+ NODE_ENV: zod_1.z.enum(['development', 'test', 'staging', 'production']).default('development'),
17
+ PORT: zod_1.z.coerce.number().int().positive(),
18
+ SERVICE_NAME: zod_1.z.string().min(1),
19
+ /** Short app identifier used in exchange names and key prefixes (e.g. `showbiz`). */
20
+ APP_NAME: zod_1.z.string().min(1).default('app'),
21
+ LOG_LEVEL: zod_1.z.enum(['error', 'warn', 'info', 'http', 'debug']).optional(),
22
+ CORS_ORIGINS: zod_1.z.string().default(''),
23
+ /** Verifies gateway-signed identity headers. */
24
+ GATEWAY_SHARED_SECRET: zod_1.z.string().min(16),
25
+ /** Authenticates service-to-service `/internal/*` calls. */
26
+ INTERNAL_SERVICE_SECRET: zod_1.z.string().min(16),
27
+ });
28
+ exports.databaseEnv = zod_1.z.object({
29
+ DB_HOST: zod_1.z.string().default('127.0.0.1'),
30
+ DB_PORT: zod_1.z.coerce.number().int().positive().default(3306),
31
+ DB_USER: zod_1.z.string().default('root'),
32
+ DB_PASSWORD: zod_1.z.string().default(''),
33
+ DB_NAME: zod_1.z.string().min(1),
34
+ DB_POOL_MAX: zod_1.z.coerce.number().int().positive().default(10),
35
+ });
36
+ exports.messagingEnv = zod_1.z.object({
37
+ RABBITMQ_URL: zod_1.z.string().optional(),
38
+ RABBITMQ_HOST: zod_1.z.string().default('127.0.0.1'),
39
+ RABBITMQ_PORT: zod_1.z.coerce.number().int().positive().default(5672),
40
+ RABBITMQ_USERNAME: zod_1.z.string().default('guest'),
41
+ RABBITMQ_PASSWORD: zod_1.z.string().default('guest'),
42
+ RABBITMQ_VHOST: zod_1.z.string().default('/'),
43
+ /** Environment prefix for queue and exchange names (`dev`, `staging`, `prod`). */
44
+ QUEUE_PREFIX: zod_1.z.string().default('dev'),
45
+ RABBITMQ_ENABLED: zod_1.z.enum(['true', 'false']).default('true').transform((v) => v === 'true'),
46
+ });
47
+ exports.redisEnv = zod_1.z.object({
48
+ REDIS_URL: zod_1.z.string().optional(),
49
+ REDIS_DB: zod_1.z.coerce.number().int().min(0).default(0),
50
+ /** Key prefix, e.g. `app:dev:` — never share one between apps or environments. */
51
+ REDIS_PREFIX: zod_1.z.string().default(''),
52
+ });
53
+ /** Builds an AMQP URL from discrete env vars (or returns RABBITMQ_URL when set). */
54
+ function amqpUrlFromEnv(env) {
55
+ if (env.RABBITMQ_URL)
56
+ return env.RABBITMQ_URL;
57
+ const vhost = env.RABBITMQ_VHOST === '/' ? '%2F' : encodeURIComponent(env.RABBITMQ_VHOST.replace(/^\//, ''));
58
+ return `amqp://${encodeURIComponent(env.RABBITMQ_USERNAME)}:${encodeURIComponent(env.RABBITMQ_PASSWORD)}@${env.RABBITMQ_HOST}:${env.RABBITMQ_PORT}/${vhost}`;
59
+ }
60
+ /** Reads `KEY=value` lines from a dotenv file into process.env without overriding set values. */
61
+ function loadDotEnv(path = (0, node_path_1.resolve)(process.cwd(), '.env')) {
62
+ if (!(0, node_fs_1.existsSync)(path))
63
+ return;
64
+ for (const line of (0, node_fs_1.readFileSync)(path, 'utf8').split(/\r?\n/)) {
65
+ const trimmed = line.trim();
66
+ if (!trimmed || trimmed.startsWith('#'))
67
+ continue;
68
+ const eq = trimmed.indexOf('=');
69
+ if (eq === -1)
70
+ continue;
71
+ const key = trimmed.slice(0, eq).trim();
72
+ let value = trimmed.slice(eq + 1).trim();
73
+ if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'")))
74
+ value = value.slice(1, -1);
75
+ if (process.env[key] === undefined)
76
+ process.env[key] = value;
77
+ }
78
+ }
79
+ class ConfigError extends Error {
80
+ }
81
+ exports.ConfigError = ConfigError;
82
+ /** Loads `.env` (if present) and validates process.env. Throws ConfigError listing every problem. */
83
+ function loadEnv(schema, source = process.env, options = {}) {
84
+ if (options.dotenv !== false && source === process.env)
85
+ loadDotEnv();
86
+ const result = schema.safeParse(source);
87
+ if (!result.success) {
88
+ const lines = result.error.issues.map((i) => ` ${i.path.join('.')}: ${i.message}`).join('\n');
89
+ throw new ConfigError(`Invalid environment configuration:\n${lines}`);
90
+ }
91
+ return result.data;
92
+ }
93
+ /** Comma-separated env value → trimmed, non-empty list. */
94
+ const listFromEnv = (value) => (value ?? '').split(',').map((s) => s.trim()).filter(Boolean);
95
+ exports.listFromEnv = listFromEnv;
96
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/config/index.ts"],"names":[],"mappings":"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"}