@heavybit/shared-lib 0.0.0-stage → 1.2.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 (310) 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 +21 -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/express/security.js +18 -0
  52. package/dist/cjs/express/security.js.map +1 -0
  53. package/dist/cjs/http/index.js +90 -0
  54. package/dist/cjs/http/index.js.map +1 -0
  55. package/dist/cjs/http/safe-fetch.js +199 -0
  56. package/dist/cjs/http/safe-fetch.js.map +1 -0
  57. package/dist/cjs/identity/index.js +117 -0
  58. package/dist/cjs/identity/index.js.map +1 -0
  59. package/dist/cjs/index.js +29 -0
  60. package/dist/cjs/index.js.map +1 -0
  61. package/dist/cjs/knex/index.js +76 -0
  62. package/dist/cjs/knex/index.js.map +1 -0
  63. package/dist/cjs/logging/index.js +75 -0
  64. package/dist/cjs/logging/index.js.map +1 -0
  65. package/dist/cjs/messaging/connection.js +115 -0
  66. package/dist/cjs/messaging/connection.js.map +1 -0
  67. package/dist/cjs/messaging/consumer.js +134 -0
  68. package/dist/cjs/messaging/consumer.js.map +1 -0
  69. package/dist/cjs/messaging/envelope.js +23 -0
  70. package/dist/cjs/messaging/envelope.js.map +1 -0
  71. package/dist/cjs/messaging/idempotency.js +57 -0
  72. package/dist/cjs/messaging/idempotency.js.map +1 -0
  73. package/dist/cjs/messaging/index.js +62 -0
  74. package/dist/cjs/messaging/index.js.map +1 -0
  75. package/dist/cjs/messaging/monitor.js +48 -0
  76. package/dist/cjs/messaging/monitor.js.map +1 -0
  77. package/dist/cjs/messaging/outbox.js +135 -0
  78. package/dist/cjs/messaging/outbox.js.map +1 -0
  79. package/dist/cjs/messaging/publisher.js +149 -0
  80. package/dist/cjs/messaging/publisher.js.map +1 -0
  81. package/dist/cjs/messaging/rpc.js +125 -0
  82. package/dist/cjs/messaging/rpc.js.map +1 -0
  83. package/dist/cjs/messaging/staff-notifier.js +78 -0
  84. package/dist/cjs/messaging/staff-notifier.js.map +1 -0
  85. package/dist/cjs/messaging/topology.js +22 -0
  86. package/dist/cjs/messaging/topology.js.map +1 -0
  87. package/dist/cjs/metrics/index.js +15 -0
  88. package/dist/cjs/metrics/index.js.map +1 -0
  89. package/dist/cjs/package.json +1 -0
  90. package/dist/cjs/rate-limit/index.js +61 -0
  91. package/dist/cjs/rate-limit/index.js.map +1 -0
  92. package/dist/cjs/scheduling/index.js +88 -0
  93. package/dist/cjs/scheduling/index.js.map +1 -0
  94. package/dist/cjs/security/index.js +39 -0
  95. package/dist/cjs/security/index.js.map +1 -0
  96. package/dist/cjs/socket/index.js +53 -0
  97. package/dist/cjs/socket/index.js.map +1 -0
  98. package/dist/cjs/testing/index.js +73 -0
  99. package/dist/cjs/testing/index.js.map +1 -0
  100. package/dist/cjs/types/index.js +3 -0
  101. package/dist/cjs/types/index.js.map +1 -0
  102. package/dist/cjs/validation/index.js +41 -0
  103. package/dist/cjs/validation/index.js.map +1 -0
  104. package/dist/esm/access/index.js +104 -0
  105. package/dist/esm/access/index.js.map +1 -0
  106. package/dist/esm/alerting/index.js +52 -0
  107. package/dist/esm/alerting/index.js.map +1 -0
  108. package/dist/esm/cache/index.js +163 -0
  109. package/dist/esm/cache/index.js.map +1 -0
  110. package/dist/esm/common/async.js +33 -0
  111. package/dist/esm/common/async.js.map +1 -0
  112. package/dist/esm/common/audit.js +18 -0
  113. package/dist/esm/common/audit.js.map +1 -0
  114. package/dist/esm/common/crypto.js +64 -0
  115. package/dist/esm/common/crypto.js.map +1 -0
  116. package/dist/esm/common/errors.js +75 -0
  117. package/dist/esm/common/errors.js.map +1 -0
  118. package/dist/esm/common/id.js +33 -0
  119. package/dist/esm/common/id.js.map +1 -0
  120. package/dist/esm/common/index.js +12 -0
  121. package/dist/esm/common/index.js.map +1 -0
  122. package/dist/esm/common/jwt.js +49 -0
  123. package/dist/esm/common/jwt.js.map +1 -0
  124. package/dist/esm/common/password.js +30 -0
  125. package/dist/esm/common/password.js.map +1 -0
  126. package/dist/esm/common/phone.js +33 -0
  127. package/dist/esm/common/phone.js.map +1 -0
  128. package/dist/esm/common/response.js +24 -0
  129. package/dist/esm/common/response.js.map +1 -0
  130. package/dist/esm/common/text.js +39 -0
  131. package/dist/esm/common/text.js.map +1 -0
  132. package/dist/esm/common/time.js +96 -0
  133. package/dist/esm/common/time.js.map +1 -0
  134. package/dist/esm/config/index.js +88 -0
  135. package/dist/esm/config/index.js.map +1 -0
  136. package/dist/esm/contracts/editorial-draft.js +108 -0
  137. package/dist/esm/contracts/editorial-draft.js.map +1 -0
  138. package/dist/esm/contracts/index.js +4 -0
  139. package/dist/esm/contracts/index.js.map +1 -0
  140. package/dist/esm/contracts/notification-dispatch.js +89 -0
  141. package/dist/esm/contracts/notification-dispatch.js.map +1 -0
  142. package/dist/esm/contracts/upload-import.js +51 -0
  143. package/dist/esm/contracts/upload-import.js.map +1 -0
  144. package/dist/esm/database/index.js +48 -0
  145. package/dist/esm/database/index.js.map +1 -0
  146. package/dist/esm/express/auth.js +63 -0
  147. package/dist/esm/express/auth.js.map +1 -0
  148. package/dist/esm/express/health.js +27 -0
  149. package/dist/esm/express/health.js.map +1 -0
  150. package/dist/esm/express/index.js +5 -0
  151. package/dist/esm/express/index.js.map +1 -0
  152. package/dist/esm/express/middleware.js +84 -0
  153. package/dist/esm/express/middleware.js.map +1 -0
  154. package/dist/esm/express/security.js +11 -0
  155. package/dist/esm/express/security.js.map +1 -0
  156. package/dist/esm/http/index.js +73 -0
  157. package/dist/esm/http/index.js.map +1 -0
  158. package/dist/esm/http/safe-fetch.js +193 -0
  159. package/dist/esm/http/safe-fetch.js.map +1 -0
  160. package/dist/esm/identity/index.js +111 -0
  161. package/dist/esm/identity/index.js.map +1 -0
  162. package/dist/esm/index.js +13 -0
  163. package/dist/esm/index.js.map +1 -0
  164. package/dist/esm/knex/index.js +66 -0
  165. package/dist/esm/knex/index.js.map +1 -0
  166. package/dist/esm/logging/index.js +67 -0
  167. package/dist/esm/logging/index.js.map +1 -0
  168. package/dist/esm/messaging/connection.js +108 -0
  169. package/dist/esm/messaging/connection.js.map +1 -0
  170. package/dist/esm/messaging/consumer.js +130 -0
  171. package/dist/esm/messaging/consumer.js.map +1 -0
  172. package/dist/esm/messaging/envelope.js +19 -0
  173. package/dist/esm/messaging/envelope.js.map +1 -0
  174. package/dist/esm/messaging/idempotency.js +52 -0
  175. package/dist/esm/messaging/idempotency.js.map +1 -0
  176. package/dist/esm/messaging/index.js +45 -0
  177. package/dist/esm/messaging/index.js.map +1 -0
  178. package/dist/esm/messaging/monitor.js +44 -0
  179. package/dist/esm/messaging/monitor.js.map +1 -0
  180. package/dist/esm/messaging/outbox.js +129 -0
  181. package/dist/esm/messaging/outbox.js.map +1 -0
  182. package/dist/esm/messaging/publisher.js +142 -0
  183. package/dist/esm/messaging/publisher.js.map +1 -0
  184. package/dist/esm/messaging/rpc.js +120 -0
  185. package/dist/esm/messaging/rpc.js.map +1 -0
  186. package/dist/esm/messaging/staff-notifier.js +73 -0
  187. package/dist/esm/messaging/staff-notifier.js.map +1 -0
  188. package/dist/esm/messaging/topology.js +16 -0
  189. package/dist/esm/messaging/topology.js.map +1 -0
  190. package/dist/esm/metrics/index.js +6 -0
  191. package/dist/esm/metrics/index.js.map +1 -0
  192. package/dist/esm/package.json +1 -0
  193. package/dist/esm/rate-limit/index.js +56 -0
  194. package/dist/esm/rate-limit/index.js.map +1 -0
  195. package/dist/esm/scheduling/index.js +83 -0
  196. package/dist/esm/scheduling/index.js.map +1 -0
  197. package/dist/esm/security/index.js +36 -0
  198. package/dist/esm/security/index.js.map +1 -0
  199. package/dist/esm/socket/index.js +47 -0
  200. package/dist/esm/socket/index.js.map +1 -0
  201. package/dist/esm/testing/index.js +66 -0
  202. package/dist/esm/testing/index.js.map +1 -0
  203. package/dist/esm/types/index.js +2 -0
  204. package/dist/esm/types/index.js.map +1 -0
  205. package/dist/esm/validation/index.js +36 -0
  206. package/dist/esm/validation/index.js.map +1 -0
  207. package/dist/types/access/index.d.ts +50 -0
  208. package/dist/types/access/index.d.ts.map +1 -0
  209. package/dist/types/alerting/index.d.ts +43 -0
  210. package/dist/types/alerting/index.d.ts.map +1 -0
  211. package/dist/types/cache/index.d.ts +45 -0
  212. package/dist/types/cache/index.d.ts.map +1 -0
  213. package/dist/types/common/async.d.ts +14 -0
  214. package/dist/types/common/async.d.ts.map +1 -0
  215. package/dist/types/common/audit.d.ts +17 -0
  216. package/dist/types/common/audit.d.ts.map +1 -0
  217. package/dist/types/common/crypto.d.ts +18 -0
  218. package/dist/types/common/crypto.d.ts.map +1 -0
  219. package/dist/types/common/errors.d.ts +71 -0
  220. package/dist/types/common/errors.d.ts.map +1 -0
  221. package/dist/types/common/id.d.ts +14 -0
  222. package/dist/types/common/id.d.ts.map +1 -0
  223. package/dist/types/common/index.d.ts +12 -0
  224. package/dist/types/common/index.d.ts.map +1 -0
  225. package/dist/types/common/jwt.d.ts +28 -0
  226. package/dist/types/common/jwt.d.ts.map +1 -0
  227. package/dist/types/common/password.d.ts +4 -0
  228. package/dist/types/common/password.d.ts.map +1 -0
  229. package/dist/types/common/phone.d.ts +10 -0
  230. package/dist/types/common/phone.d.ts.map +1 -0
  231. package/dist/types/common/response.d.ts +12 -0
  232. package/dist/types/common/response.d.ts.map +1 -0
  233. package/dist/types/common/text.d.ts +10 -0
  234. package/dist/types/common/text.d.ts.map +1 -0
  235. package/dist/types/common/time.d.ts +40 -0
  236. package/dist/types/common/time.d.ts.map +1 -0
  237. package/dist/types/config/index.d.ts +115 -0
  238. package/dist/types/config/index.d.ts.map +1 -0
  239. package/dist/types/contracts/editorial-draft.d.ts +577 -0
  240. package/dist/types/contracts/editorial-draft.d.ts.map +1 -0
  241. package/dist/types/contracts/index.d.ts +4 -0
  242. package/dist/types/contracts/index.d.ts.map +1 -0
  243. package/dist/types/contracts/notification-dispatch.d.ts +175 -0
  244. package/dist/types/contracts/notification-dispatch.d.ts.map +1 -0
  245. package/dist/types/contracts/upload-import.d.ts +96 -0
  246. package/dist/types/contracts/upload-import.d.ts.map +1 -0
  247. package/dist/types/database/index.d.ts +25 -0
  248. package/dist/types/database/index.d.ts.map +1 -0
  249. package/dist/types/express/auth.d.ts +27 -0
  250. package/dist/types/express/auth.d.ts.map +1 -0
  251. package/dist/types/express/health.d.ts +14 -0
  252. package/dist/types/express/health.d.ts.map +1 -0
  253. package/dist/types/express/index.d.ts +5 -0
  254. package/dist/types/express/index.d.ts.map +1 -0
  255. package/dist/types/express/middleware.d.ts +20 -0
  256. package/dist/types/express/middleware.d.ts.map +1 -0
  257. package/dist/types/express/security.d.ts +9 -0
  258. package/dist/types/express/security.d.ts.map +1 -0
  259. package/dist/types/http/index.d.ts +34 -0
  260. package/dist/types/http/index.d.ts.map +1 -0
  261. package/dist/types/http/safe-fetch.d.ts +58 -0
  262. package/dist/types/http/safe-fetch.d.ts.map +1 -0
  263. package/dist/types/identity/index.d.ts +51 -0
  264. package/dist/types/identity/index.d.ts.map +1 -0
  265. package/dist/types/index.d.ts +10 -0
  266. package/dist/types/index.d.ts.map +1 -0
  267. package/dist/types/knex/index.d.ts +25 -0
  268. package/dist/types/knex/index.d.ts.map +1 -0
  269. package/dist/types/logging/index.d.ts +22 -0
  270. package/dist/types/logging/index.d.ts.map +1 -0
  271. package/dist/types/messaging/connection.d.ts +48 -0
  272. package/dist/types/messaging/connection.d.ts.map +1 -0
  273. package/dist/types/messaging/consumer.d.ts +56 -0
  274. package/dist/types/messaging/consumer.d.ts.map +1 -0
  275. package/dist/types/messaging/envelope.d.ts +16 -0
  276. package/dist/types/messaging/envelope.d.ts.map +1 -0
  277. package/dist/types/messaging/idempotency.d.ts +29 -0
  278. package/dist/types/messaging/idempotency.d.ts.map +1 -0
  279. package/dist/types/messaging/index.d.ts +39 -0
  280. package/dist/types/messaging/index.d.ts.map +1 -0
  281. package/dist/types/messaging/monitor.d.ts +23 -0
  282. package/dist/types/messaging/monitor.d.ts.map +1 -0
  283. package/dist/types/messaging/outbox.d.ts +51 -0
  284. package/dist/types/messaging/outbox.d.ts.map +1 -0
  285. package/dist/types/messaging/publisher.d.ts +84 -0
  286. package/dist/types/messaging/publisher.d.ts.map +1 -0
  287. package/dist/types/messaging/rpc.d.ts +46 -0
  288. package/dist/types/messaging/rpc.d.ts.map +1 -0
  289. package/dist/types/messaging/staff-notifier.d.ts +56 -0
  290. package/dist/types/messaging/staff-notifier.d.ts.map +1 -0
  291. package/dist/types/messaging/topology.d.ts +23 -0
  292. package/dist/types/messaging/topology.d.ts.map +1 -0
  293. package/dist/types/metrics/index.d.ts +7 -0
  294. package/dist/types/metrics/index.d.ts.map +1 -0
  295. package/dist/types/rate-limit/index.d.ts +28 -0
  296. package/dist/types/rate-limit/index.d.ts.map +1 -0
  297. package/dist/types/scheduling/index.d.ts +33 -0
  298. package/dist/types/scheduling/index.d.ts.map +1 -0
  299. package/dist/types/security/index.d.ts +20 -0
  300. package/dist/types/security/index.d.ts.map +1 -0
  301. package/dist/types/socket/index.d.ts +30 -0
  302. package/dist/types/socket/index.d.ts.map +1 -0
  303. package/dist/types/testing/index.d.ts +41 -0
  304. package/dist/types/testing/index.d.ts.map +1 -0
  305. package/dist/types/types/index.d.ts +65 -0
  306. package/dist/types/types/index.d.ts.map +1 -0
  307. package/dist/types/validation/index.d.ts +34 -0
  308. package/dist/types/validation/index.d.ts.map +1 -0
  309. package/package.json +181 -4
  310. package/README.md +0 -3
@@ -0,0 +1,118 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.WILDCARD_PERMISSION = void 0;
4
+ exports.hasPermission = hasPermission;
5
+ exports.hasAllPermissions = hasAllPermissions;
6
+ exports.hasRole = hasRole;
7
+ exports.requireUser = requireUser;
8
+ exports.assertPermission = assertPermission;
9
+ exports.scopeIds = scopeIds;
10
+ exports.assertSelfOrPermission = assertSelfOrPermission;
11
+ exports.assertInScope = assertInScope;
12
+ exports.resolveActiveScopeId = resolveActiveScopeId;
13
+ exports.resolvePrimaryScopeId = resolvePrimaryScopeId;
14
+ exports.ownerFilter = ownerFilter;
15
+ const errors_js_1 = require("../common/errors.js");
16
+ /**
17
+ * Permission and ownership checks. Keep every authorization decision in these helpers (not
18
+ * inline in controllers) so the rules are identical across endpoints and services.
19
+ *
20
+ * Permission strings are dotted (`users.manage`, `media.manage.any`). Grants may use
21
+ * wildcards: `*` grants everything; `media.*` grants any permission starting with `media.`.
22
+ */
23
+ exports.WILDCARD_PERMISSION = '*';
24
+ function grants(granted, required) {
25
+ if (granted === exports.WILDCARD_PERMISSION || granted === required)
26
+ return true;
27
+ return granted.endsWith('.*') && required.startsWith(granted.slice(0, -1));
28
+ }
29
+ /** True when the user holds at least one of `required`. */
30
+ function hasPermission(user, ...required) {
31
+ if (!user)
32
+ return false;
33
+ return required.some((perm) => user.permissions.some((g) => grants(g, perm)));
34
+ }
35
+ function hasAllPermissions(user, ...required) {
36
+ if (!user)
37
+ return false;
38
+ return required.every((perm) => user.permissions.some((g) => grants(g, perm)));
39
+ }
40
+ function hasRole(user, ...roles) {
41
+ return !!user && roles.some((role) => user.roles.includes(role));
42
+ }
43
+ function requireUser(user) {
44
+ if (!user)
45
+ throw new errors_js_1.UnauthorizedError();
46
+ return user;
47
+ }
48
+ function assertPermission(user, ...required) {
49
+ const u = requireUser(user);
50
+ if (!hasPermission(u, ...required))
51
+ throw new errors_js_1.ForbiddenError();
52
+ return u;
53
+ }
54
+ /** IDs the user may act on within a scope (e.g. profiles they are a member of). */
55
+ function scopeIds(user, scope) {
56
+ return user?.scopes?.[scope] ?? [];
57
+ }
58
+ /**
59
+ * Self-owned data: allow when the caller *is* `ownerUserId`, or holds `bypassPermission`.
60
+ * Throws ForbiddenError otherwise.
61
+ */
62
+ function assertSelfOrPermission(user, ownerUserId, bypassPermission) {
63
+ const u = requireUser(user);
64
+ if (u.id === ownerUserId)
65
+ return u;
66
+ if (bypassPermission && hasPermission(u, bypassPermission))
67
+ return u;
68
+ throw new errors_js_1.ForbiddenError();
69
+ }
70
+ /**
71
+ * Scoped data: allow when `resourceScopeId` is one of the caller's scope IDs, or the caller holds
72
+ * `bypassPermission`.
73
+ */
74
+ function assertInScope(user, scope, resourceScopeId, bypassPermission) {
75
+ const u = requireUser(user);
76
+ if (scopeIds(u, scope).includes(resourceScopeId))
77
+ return u;
78
+ if (bypassPermission && hasPermission(u, bypassPermission))
79
+ return u;
80
+ throw new errors_js_1.ForbiddenError();
81
+ }
82
+ /**
83
+ * Resolves the single scope ID a request acts on. With one membership it is implicit; with
84
+ * several the client names one (e.g. `x-active-profile-id`), which must be a member ID.
85
+ * IDs from request bodies are never trusted — only the gateway-signed scopes.
86
+ */
87
+ function resolveActiveScopeId(user, scope, requested) {
88
+ const ids = scopeIds(requireUser(user), scope);
89
+ if (requested) {
90
+ if (!ids.includes(requested))
91
+ throw new errors_js_1.ForbiddenError(`Not a member of this ${scope}`);
92
+ return requested;
93
+ }
94
+ if (ids.length === 1)
95
+ return ids[0];
96
+ if (ids.length === 0)
97
+ throw new errors_js_1.ForbiddenError(`No ${scope} is linked to this account`);
98
+ throw new errors_js_1.ForbiddenError(`Select a ${scope} to act on`, { code: 'SCOPE_SELECTION_REQUIRED' });
99
+ }
100
+ /**
101
+ * Like `resolveActiveScopeId`, for screens that work without a selector: with several memberships
102
+ * and none named, the first (primary) one is used. A named ID must still be a member ID.
103
+ */
104
+ function resolvePrimaryScopeId(user, scope, requested) {
105
+ const ids = scopeIds(requireUser(user), scope);
106
+ return resolveActiveScopeId(user, scope, requested || ids[0]);
107
+ }
108
+ /**
109
+ * Repository filter for list queries: `{ all: true }` for callers holding `bypassPermission`,
110
+ * otherwise the caller's own scope IDs (possibly empty → return nothing).
111
+ */
112
+ function ownerFilter(user, scope, bypassPermission) {
113
+ const u = requireUser(user);
114
+ if (bypassPermission && hasPermission(u, bypassPermission))
115
+ return { all: true };
116
+ return { all: false, ids: scopeIds(u, scope) };
117
+ }
118
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/access/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SlackAlerter = void 0;
4
+ const index_js_1 = require("../logging/index.js");
5
+ /**
6
+ * Posts alerts to a Slack notification webhook as `{ messages, alert_type, app_name, environment, consolidate }`.
7
+ * An unset URL is a valid "alerts off" configuration: the first skipped alert is warned about once, then silently.
8
+ */
9
+ class SlackAlerter {
10
+ options;
11
+ warnedUnconfigured = false;
12
+ logger;
13
+ constructor(options) {
14
+ this.options = options;
15
+ this.logger = options.logger ?? index_js_1.silentLogger;
16
+ }
17
+ get configured() {
18
+ return Boolean(this.options.url);
19
+ }
20
+ async send(messages, options = {}) {
21
+ if (!this.options.url) {
22
+ if (!this.warnedUnconfigured)
23
+ this.logger.warn('Slack alert URL is not configured; alerts are logged only');
24
+ this.warnedUnconfigured = true;
25
+ return false;
26
+ }
27
+ const payload = {
28
+ messages,
29
+ alert_type: options.alertType ?? 'app-alert',
30
+ app_name: this.options.app,
31
+ environment: this.options.environment,
32
+ consolidate: true,
33
+ };
34
+ const post = this.options.fetch ?? fetch;
35
+ try {
36
+ const res = await post(this.options.url, {
37
+ method: 'POST',
38
+ headers: { 'Content-Type': 'application/json' },
39
+ body: JSON.stringify(payload),
40
+ signal: AbortSignal.timeout(this.options.timeoutMs ?? 10_000),
41
+ });
42
+ if (!res.ok) {
43
+ const body = await res.text().catch(() => '');
44
+ this.logger.error('Slack alert rejected', { status: res.status, body: body.slice(0, 200) });
45
+ return false;
46
+ }
47
+ return true;
48
+ }
49
+ catch (error) {
50
+ this.logger.error('Slack alert failed', { error: error.message });
51
+ return false;
52
+ }
53
+ }
54
+ }
55
+ exports.SlackAlerter = SlackAlerter;
56
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/alerting/index.ts"],"names":[],"mappings":";;;AAAA,kDAAmD;AA+BnD;;;GAGG;AACH,MAAa,YAAY;IAIM;IAHrB,kBAAkB,GAAG,KAAK,CAAC;IAClB,MAAM,CAAS;IAEhC,YAA6B,OAA4B;QAA5B,YAAO,GAAP,OAAO,CAAqB;QACvD,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,IAAI,uBAAY,CAAC;IAC/C,CAAC;IAED,IAAI,UAAU;QACZ,OAAO,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC;IACnC,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,QAAkB,EAAE,UAAkC,EAAE;QACjE,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC;YACtB,IAAI,CAAC,IAAI,CAAC,kBAAkB;gBAAE,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,2DAA2D,CAAC,CAAC;YAC5G,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC;YAC/B,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,OAAO,GAAsB;YACjC,QAAQ;YACR,UAAU,EAAE,OAAO,CAAC,SAAS,IAAI,WAAW;YAC5C,QAAQ,EAAE,IAAI,CAAC,OAAO,CAAC,GAAG;YAC1B,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW;YACrC,WAAW,EAAE,IAAI;SAClB,CAAC;QACF,MAAM,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,KAAK,CAAC;QACzC,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE;gBACvC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC;gBAC7B,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,IAAI,MAAM,CAAC;aAC9D,CAAC,CAAC;YACH,IAAI,CAAC,GAAG,CAAC,EAAE,EAAE,CAAC;gBACZ,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,EAAE,CAAC,CAAC;gBAC9C,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,EAAE,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;gBAC5F,OAAO,KAAK,CAAC;YACf,CAAC;YACD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,oBAAoB,EAAE,EAAE,KAAK,EAAG,KAAe,CAAC,OAAO,EAAE,CAAC,CAAC;YAC7E,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;CACF;AA5CD,oCA4CC"}
@@ -0,0 +1,167 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createCache = createCache;
4
+ exports.createRedisClient = createRedisClient;
5
+ const ioredis_1 = require("ioredis");
6
+ const index_js_1 = require("../logging/index.js");
7
+ const NULL_SENTINEL = '__null__';
8
+ class MemoryStore {
9
+ max;
10
+ map = new Map();
11
+ constructor(max) {
12
+ this.max = max;
13
+ }
14
+ get(key) {
15
+ const entry = this.map.get(key);
16
+ if (!entry)
17
+ return undefined;
18
+ if (entry.expiresAt < Date.now()) {
19
+ this.map.delete(key);
20
+ return undefined;
21
+ }
22
+ // Refresh recency for LRU eviction.
23
+ this.map.delete(key);
24
+ this.map.set(key, entry);
25
+ return entry.value;
26
+ }
27
+ set(key, value, ttlSec) {
28
+ if (this.map.size >= this.max)
29
+ this.map.delete(this.map.keys().next().value);
30
+ this.map.set(key, { value, expiresAt: Date.now() + ttlSec * 1000 });
31
+ }
32
+ del(key) {
33
+ this.map.delete(key);
34
+ }
35
+ }
36
+ /**
37
+ * Redis-backed cache with tag invalidation. If Redis errors, reads fall through to the loader
38
+ * and writes go to a bounded in-memory store, so a cache outage degrades latency rather than
39
+ * availability.
40
+ */
41
+ function createCache(options) {
42
+ const logger = options.logger ?? index_js_1.silentLogger;
43
+ const defaultTtl = options.defaultTtlSec ?? 60;
44
+ const memory = new MemoryStore(options.memoryMaxEntries ?? 5000);
45
+ const inflight = new Map();
46
+ const k = (key) => `${options.namespace}:${key}`;
47
+ const tagKey = (tag) => `${options.namespace}:tag:${tag}`;
48
+ let warned = false;
49
+ const redisFailed = (error) => {
50
+ if (!warned)
51
+ logger.warn('Cache backend unavailable; using in-memory fallback', { error: error.message });
52
+ warned = true;
53
+ };
54
+ const readRaw = async (key) => {
55
+ if (options.redis) {
56
+ try {
57
+ const value = await options.redis.get(k(key));
58
+ warned = false;
59
+ return value ?? undefined;
60
+ }
61
+ catch (error) {
62
+ redisFailed(error);
63
+ }
64
+ }
65
+ return memory.get(k(key));
66
+ };
67
+ const writeRaw = async (key, raw, opts = {}) => {
68
+ const ttl = opts.ttlSec ?? defaultTtl;
69
+ if (options.redis) {
70
+ try {
71
+ const pipeline = options.redis.multi().set(k(key), raw, 'EX', ttl);
72
+ for (const tag of opts.tags ?? [])
73
+ pipeline.sadd(tagKey(tag), k(key)).expire(tagKey(tag), Math.max(ttl, 86_400));
74
+ await pipeline.exec();
75
+ return;
76
+ }
77
+ catch (error) {
78
+ redisFailed(error);
79
+ }
80
+ }
81
+ memory.set(k(key), raw, ttl);
82
+ };
83
+ const cache = {
84
+ async get(key) {
85
+ const raw = await readRaw(key);
86
+ if (raw === undefined || raw === NULL_SENTINEL)
87
+ return undefined;
88
+ return JSON.parse(raw);
89
+ },
90
+ async set(key, value, opts) {
91
+ await writeRaw(key, value === null ? NULL_SENTINEL : JSON.stringify(value), opts);
92
+ },
93
+ async del(...keys) {
94
+ for (const key of keys)
95
+ memory.del(k(key));
96
+ if (options.redis && keys.length)
97
+ await options.redis.del(...keys.map(k)).catch(redisFailed);
98
+ },
99
+ async wrap(key, loader, opts = {}) {
100
+ const raw = await readRaw(key);
101
+ if (raw !== undefined) {
102
+ if (raw === NULL_SENTINEL)
103
+ return null;
104
+ return JSON.parse(raw);
105
+ }
106
+ const existing = inflight.get(key);
107
+ if (existing)
108
+ return existing;
109
+ const load = (async () => {
110
+ try {
111
+ const value = await loader();
112
+ if (value !== null && value !== undefined)
113
+ await writeRaw(key, JSON.stringify(value), opts);
114
+ else if (opts.cacheNull)
115
+ await writeRaw(key, NULL_SENTINEL, { ...opts, ttlSec: Math.min(opts.ttlSec ?? defaultTtl, 30) });
116
+ return value;
117
+ }
118
+ finally {
119
+ inflight.delete(key);
120
+ }
121
+ })();
122
+ inflight.set(key, load);
123
+ return load;
124
+ },
125
+ async invalidateTags(...tags) {
126
+ if (!options.redis)
127
+ return;
128
+ try {
129
+ for (const tag of tags) {
130
+ const members = await options.redis.smembers(tagKey(tag));
131
+ for (const member of members)
132
+ memory.del(member);
133
+ if (members.length)
134
+ await options.redis.del(...members);
135
+ await options.redis.del(tagKey(tag));
136
+ }
137
+ }
138
+ catch (error) {
139
+ redisFailed(error);
140
+ }
141
+ },
142
+ };
143
+ return cache;
144
+ }
145
+ /** ioredis client that never crashes the process on connection errors and retries forever. */
146
+ function createRedisClient(opts) {
147
+ const logger = opts.logger ?? index_js_1.silentLogger;
148
+ const base = {
149
+ db: opts.db ?? 0,
150
+ keyPrefix: opts.keyPrefix || undefined,
151
+ lazyConnect: false,
152
+ enableOfflineQueue: false,
153
+ maxRetriesPerRequest: 1,
154
+ retryStrategy: (times) => Math.min(times * 500, 10_000),
155
+ ...opts.options,
156
+ };
157
+ const client = opts.url ? new ioredis_1.Redis(opts.url, base) : new ioredis_1.Redis(base);
158
+ let lastError = '';
159
+ client.on('error', (error) => {
160
+ if (error.message !== lastError)
161
+ logger.warn('Redis error', { error: error.message });
162
+ lastError = error.message;
163
+ });
164
+ client.on('ready', () => { lastError = ''; logger.info('Redis connected', { db: base.db }); });
165
+ return client;
166
+ }
167
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/cache/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sleep = void 0;
4
+ exports.retry = retry;
5
+ exports.withTimeout = withTimeout;
6
+ exports.chunk = chunk;
7
+ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
8
+ exports.sleep = sleep;
9
+ /** Runs `fn`, retrying failures with exponential back-off. */
10
+ async function retry(fn, options) {
11
+ const delay = options.delayMs ?? ((n) => Math.min(5000, 200 * 2 ** (n - 1)));
12
+ let attempt = 0;
13
+ for (;;) {
14
+ try {
15
+ return await fn(attempt);
16
+ }
17
+ catch (error) {
18
+ attempt += 1;
19
+ if (attempt > options.retries || (options.shouldRetry && !options.shouldRetry(error)))
20
+ throw error;
21
+ await (0, exports.sleep)(delay(attempt));
22
+ }
23
+ }
24
+ }
25
+ /** Rejects with `onTimeout()` if `promise` does not settle within `ms`. */
26
+ function withTimeout(promise, ms, onTimeout) {
27
+ let timer;
28
+ return Promise.race([
29
+ promise.finally(() => clearTimeout(timer)),
30
+ new Promise((_, reject) => { timer = setTimeout(() => reject(onTimeout()), ms); }),
31
+ ]);
32
+ }
33
+ /** Splits `items` into arrays of at most `size`. */
34
+ function chunk(items, size) {
35
+ const out = [];
36
+ for (let i = 0; i < items.length; i += size)
37
+ out.push(items.slice(i, i + size));
38
+ return out;
39
+ }
40
+ //# sourceMappingURL=async.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"async.js","sourceRoot":"","sources":["../../../src/common/async.ts"],"names":[],"mappings":";;;AAUA,sBAYC;AAGD,kCAMC;AAGD,sBAIC;AAtCM,MAAM,KAAK,GAAG,CAAC,EAAU,EAAiB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;AAAzF,QAAA,KAAK,SAAoF;AAStG,8DAA8D;AACvD,KAAK,UAAU,KAAK,CAAI,EAAmC,EAAE,OAAqB;IACvF,MAAM,KAAK,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC,CAAC,CAAS,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,GAAG,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACrF,IAAI,OAAO,GAAG,CAAC,CAAC;IAChB,SAAS,CAAC;QACR,IAAI,CAAC;YACH,OAAO,MAAM,EAAE,CAAC,OAAO,CAAC,CAAC;QAC3B,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO,IAAI,CAAC,CAAC;YACb,IAAI,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,CAAC,OAAO,CAAC,WAAW,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;gBAAE,MAAM,KAAK,CAAC;YACnG,MAAM,IAAA,aAAK,EAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC;AACH,CAAC;AAED,2EAA2E;AAC3E,SAAgB,WAAW,CAAI,OAAmB,EAAE,EAAU,EAAE,SAAsB;IACpF,IAAI,KAAoC,CAAC;IACzC,OAAO,OAAO,CAAC,IAAI,CAAC;QAClB,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;QAC1C,IAAI,OAAO,CAAQ,CAAC,CAAC,EAAE,MAAM,EAAE,EAAE,GAAG,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;KAC1F,CAAC,CAAC;AACL,CAAC;AAED,oDAAoD;AACpD,SAAgB,KAAK,CAAI,KAAmB,EAAE,IAAY;IACxD,MAAM,GAAG,GAAU,EAAE,CAAC;IACtB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,IAAI,IAAI;QAAE,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,CAAC;IAChF,OAAO,GAAG,CAAC;AACb,CAAC"}
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.buildAuditRow = buildAuditRow;
4
+ const id_js_1 = require("./id.js");
5
+ /**
6
+ * Builds the row for a `*_audits` sibling table: a copy of the parent row plus `action`,
7
+ * `parentId`, and a fresh `id`. The parent's timestamps are dropped so the audit row records
8
+ * when the change happened. The actor lands in `createdBy`/`updatedBy` exactly as on the parent
9
+ * (null for system operations). Strip secrets (e.g. password hashes) before calling.
10
+ */
11
+ function buildAuditRow(row, action, actorId = null) {
12
+ const { id: parentId, createdAt: _createdAt, updatedAt: _updatedAt, ...rest } = row;
13
+ return {
14
+ ...rest,
15
+ id: (0, id_js_1.newId)(),
16
+ parentId,
17
+ action,
18
+ ...(action === 'create' ? { createdBy: actorId, updatedBy: actorId } : { updatedBy: actorId }),
19
+ };
20
+ }
21
+ //# sourceMappingURL=audit.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audit.js","sourceRoot":"","sources":["../../../src/common/audit.ts"],"names":[],"mappings":";;AAYA,sCASC;AArBD,mCAAgC;AAMhC;;;;;GAKG;AACH,SAAgB,aAAa,CAA2B,GAAM,EAAE,MAAmB,EAAE,UAAyB,IAAI;IAChH,MAAM,EAAE,EAAE,EAAE,QAAQ,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,GAAG,IAAI,EAAE,GAAG,GAAuD,CAAC;IACxI,OAAO;QACL,GAAI,IAAkD;QACtD,EAAE,EAAE,IAAA,aAAK,GAAE;QACX,QAAQ;QACR,MAAM;QACN,GAAG,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,CAAC;KAC/F,CAAC;AACJ,CAAC"}
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.sha256 = sha256;
4
+ exports.hmacSha256 = hmacSha256;
5
+ exports.safeEqual = safeEqual;
6
+ exports.randomToken = randomToken;
7
+ exports.randomNumericCode = randomNumericCode;
8
+ exports.hashToken = hashToken;
9
+ exports.encryptSecret = encryptSecret;
10
+ exports.decryptSecret = decryptSecret;
11
+ exports.isEncryptedSecret = isEncryptedSecret;
12
+ const node_crypto_1 = require("node:crypto");
13
+ function sha256(value) {
14
+ return (0, node_crypto_1.createHash)('sha256').update(value).digest('hex');
15
+ }
16
+ function hmacSha256(secret, value) {
17
+ return (0, node_crypto_1.createHmac)('sha256', secret).update(value).digest('hex');
18
+ }
19
+ /** Constant-time string comparison (false when lengths differ). */
20
+ function safeEqual(a, b) {
21
+ const left = Buffer.from(a);
22
+ const right = Buffer.from(b);
23
+ return left.length === right.length && (0, node_crypto_1.timingSafeEqual)(left, right);
24
+ }
25
+ /** URL-safe random token (default 32 bytes of entropy). */
26
+ function randomToken(bytes = 32) {
27
+ return (0, node_crypto_1.randomBytes)(bytes).toString('base64url');
28
+ }
29
+ /** Numeric one-time code, e.g. `'042917'`. Uses a CSPRNG. */
30
+ function randomNumericCode(length = 6) {
31
+ let code = '';
32
+ for (let i = 0; i < length; i += 1)
33
+ code += String((0, node_crypto_1.randomInt)(0, 10));
34
+ return code;
35
+ }
36
+ /**
37
+ * Hash a value that must be looked up later (refresh tokens, reset tokens, OTPs) with a
38
+ * server-side pepper so a database leak alone cannot be replayed.
39
+ */
40
+ function hashToken(token, pepper) {
41
+ return hmacSha256(pepper, token);
42
+ }
43
+ const CIPHER = 'aes-256-gcm';
44
+ const IV_BYTES = 12;
45
+ const FORMAT_VERSION = 'v1';
46
+ /** Accepts a 32-byte key as hex/base64, or any passphrase (derived with SHA-256). */
47
+ function resolveKey(key) {
48
+ if (/^[0-9a-f]{64}$/i.test(key))
49
+ return Buffer.from(key, 'hex');
50
+ const b64 = Buffer.from(key, 'base64');
51
+ if (b64.length === 32 && /^[A-Za-z0-9+/=_-]+$/.test(key))
52
+ return b64;
53
+ return (0, node_crypto_1.createHash)('sha256').update(key).digest();
54
+ }
55
+ /** AES-256-GCM encrypt. Output: `v1:<iv>:<tag>:<ciphertext>` (base64url parts). */
56
+ function encryptSecret(plaintext, key) {
57
+ const iv = (0, node_crypto_1.randomBytes)(IV_BYTES);
58
+ const cipher = (0, node_crypto_1.createCipheriv)(CIPHER, resolveKey(key), iv);
59
+ const encrypted = Buffer.concat([cipher.update(plaintext, 'utf8'), cipher.final()]);
60
+ const tag = cipher.getAuthTag();
61
+ return [FORMAT_VERSION, iv.toString('base64url'), tag.toString('base64url'), encrypted.toString('base64url')].join(':');
62
+ }
63
+ function decryptSecret(payload, key) {
64
+ const [version, iv, tag, data] = payload.split(':');
65
+ if (version !== FORMAT_VERSION || !iv || !tag || data === undefined) {
66
+ throw new Error('Unsupported encrypted payload format');
67
+ }
68
+ const decipher = (0, node_crypto_1.createDecipheriv)(CIPHER, resolveKey(key), Buffer.from(iv, 'base64url'));
69
+ decipher.setAuthTag(Buffer.from(tag, 'base64url'));
70
+ return Buffer.concat([decipher.update(Buffer.from(data, 'base64url')), decipher.final()]).toString('utf8');
71
+ }
72
+ function isEncryptedSecret(value) {
73
+ return typeof value === 'string' && value.startsWith(`${FORMAT_VERSION}:`) && value.split(':').length === 4;
74
+ }
75
+ //# sourceMappingURL=crypto.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"crypto.js","sourceRoot":"","sources":["../../../src/common/crypto.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NonRetryableError = exports.ServiceUnavailableError = exports.TooManyRequestsError = exports.ValidationError = exports.ConflictError = exports.NotFoundError = exports.ForbiddenError = exports.UnauthorizedError = exports.BadRequestError = exports.AppError = void 0;
4
+ exports.isAppError = isAppError;
5
+ exports.publicMessage = publicMessage;
6
+ /**
7
+ * Base class for errors that map to an HTTP status. Throw these from services; the shared
8
+ * error middleware turns them into the standard envelope. Anything that is not an AppError is
9
+ * reported as a 500 with a generic message so internals never leak.
10
+ */
11
+ class AppError extends Error {
12
+ statusCode;
13
+ code;
14
+ errors;
15
+ /** Consumers dead-letter immediately instead of retrying when this is false. */
16
+ retryable;
17
+ constructor(statusCode, message, options = {}) {
18
+ super(message, options.cause ? { cause: options.cause } : undefined);
19
+ this.name = new.target.name;
20
+ this.statusCode = statusCode;
21
+ this.code = options.code ?? defaultCode(statusCode);
22
+ this.errors = options.errors;
23
+ this.retryable = options.retryable ?? statusCode >= 500;
24
+ }
25
+ }
26
+ exports.AppError = AppError;
27
+ function defaultCode(status) {
28
+ switch (status) {
29
+ case 400: return 'BAD_REQUEST';
30
+ case 401: return 'UNAUTHENTICATED';
31
+ case 403: return 'FORBIDDEN';
32
+ case 404: return 'NOT_FOUND';
33
+ case 409: return 'CONFLICT';
34
+ case 422: return 'VALIDATION_FAILED';
35
+ case 429: return 'RATE_LIMITED';
36
+ case 503: return 'SERVICE_UNAVAILABLE';
37
+ default: return status >= 500 ? 'INTERNAL_ERROR' : 'ERROR';
38
+ }
39
+ }
40
+ class BadRequestError extends AppError {
41
+ constructor(message = 'Bad request', options = {}) { super(400, message, options); }
42
+ }
43
+ exports.BadRequestError = BadRequestError;
44
+ class UnauthorizedError extends AppError {
45
+ constructor(message = 'Authentication required', options = {}) { super(401, message, options); }
46
+ }
47
+ exports.UnauthorizedError = UnauthorizedError;
48
+ class ForbiddenError extends AppError {
49
+ constructor(message = 'You do not have permission to perform this action', options = {}) { super(403, message, options); }
50
+ }
51
+ exports.ForbiddenError = ForbiddenError;
52
+ class NotFoundError extends AppError {
53
+ constructor(message = 'Resource not found', options = {}) { super(404, message, options); }
54
+ }
55
+ exports.NotFoundError = NotFoundError;
56
+ class ConflictError extends AppError {
57
+ constructor(message = 'Resource already exists', options = {}) { super(409, message, options); }
58
+ }
59
+ exports.ConflictError = ConflictError;
60
+ class ValidationError extends AppError {
61
+ constructor(errors, message = 'Validation failed') { super(422, message, { errors }); }
62
+ }
63
+ exports.ValidationError = ValidationError;
64
+ class TooManyRequestsError extends AppError {
65
+ constructor(message = 'Too many requests. Please try again later.', options = {}) { super(429, message, options); }
66
+ }
67
+ exports.TooManyRequestsError = TooManyRequestsError;
68
+ class ServiceUnavailableError extends AppError {
69
+ constructor(message = 'Service temporarily unavailable', options = {}) { super(503, message, options); }
70
+ }
71
+ exports.ServiceUnavailableError = ServiceUnavailableError;
72
+ /** A failure that will never succeed on retry (bad payload, unknown template, …). */
73
+ class NonRetryableError extends AppError {
74
+ constructor(message, options = {}) {
75
+ super(422, message, { ...options, retryable: false });
76
+ }
77
+ }
78
+ exports.NonRetryableError = NonRetryableError;
79
+ function isAppError(error) {
80
+ return error instanceof AppError;
81
+ }
82
+ /** Message safe to show a caller; hides internals for unexpected errors. */
83
+ function publicMessage(error) {
84
+ if (isAppError(error) && error.statusCode < 500)
85
+ return error.message;
86
+ if (isAppError(error) && error.statusCode === 503)
87
+ return error.message;
88
+ return 'Internal server error';
89
+ }
90
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../../src/common/errors.ts"],"names":[],"mappings":"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"}