@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,111 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.editorialDraftSubmitSchema = exports.FACT_KINDS = exports.QUALITY_GATE_NAMES = exports.GATE_VERDICTS = exports.DRAFT_RISKS = exports.DRAFT_SOURCE_ROLES = exports.EDITORIAL_DRAFT_LIMITS = exports.EDITORIAL_DRAFT_SUBMIT = void 0;
4
+ const zod_1 = require("zod");
5
+ const index_js_1 = require("../validation/index.js");
6
+ /**
7
+ * The newswire → editorial draft hand-off (design Appendix A.4 plus `paragraphFactIds` and
8
+ * `image.uploadId`, decision R14). newswire-service stages it through its outbox; editorial-service
9
+ * validates it with the same schema before creating the story. One contract for both sides.
10
+ */
11
+ exports.EDITORIAL_DRAFT_SUBMIT = 'editorial:draft.submit';
12
+ /** Field limits of the contract (editorial's story columns). */
13
+ exports.EDITORIAL_DRAFT_LIMITS = {
14
+ headline: 200,
15
+ excerpt: 400,
16
+ tags: 6,
17
+ seoTitle: 70,
18
+ seoDescription: 170,
19
+ };
20
+ exports.DRAFT_SOURCE_ROLES = ['primary', 'corroborating'];
21
+ exports.DRAFT_RISKS = ['low', 'medium', 'high'];
22
+ exports.GATE_VERDICTS = ['pass', 'review', 'block'];
23
+ /**
24
+ * Every quality gate newswire runs on a draft, in design order. A submitted draft carries one result per
25
+ * gate; editorial treats a missing one as not passed (auto-publish never runs on an unchecked draft).
26
+ */
27
+ exports.QUALITY_GATE_NAMES = [
28
+ 'originality', 'grounding', 'quote_limits', 'corroboration', 'conflicts',
29
+ 'sensitivity', 'category', 'freshness', 'duplicate_of_published', 'length_format',
30
+ ];
31
+ exports.FACT_KINDS = ['event', 'person', 'date', 'place', 'number', 'quote', 'context'];
32
+ const text = zod_1.z.string().trim().min(1);
33
+ const httpsUrl = zod_1.z
34
+ .string()
35
+ .url()
36
+ .refine((u) => u.startsWith('https://'), 'Source URL must use https');
37
+ const draftSourceSchema = zod_1.z.object({
38
+ name: text.max(160),
39
+ url: httpsUrl,
40
+ publishedAt: zod_1.z.string().datetime({ offset: true }).optional(),
41
+ role: zod_1.z.enum(exports.DRAFT_SOURCE_ROLES),
42
+ });
43
+ const gateResultSchema = zod_1.z.object({
44
+ gate: text,
45
+ verdict: zod_1.z.enum(exports.GATE_VERDICTS),
46
+ reasons: zod_1.z.array(zod_1.z.string()),
47
+ metrics: zod_1.z.record(zod_1.z.string(), zod_1.z.number()).optional(),
48
+ });
49
+ const factSupportSchema = zod_1.z.object({ itemId: index_js_1.idSchema, paragraph: zod_1.z.number().int().min(1) });
50
+ const factSchema = zod_1.z.object({
51
+ id: text,
52
+ statement: text,
53
+ kind: zod_1.z.enum(exports.FACT_KINDS),
54
+ entities: zod_1.z.array(zod_1.z.string()),
55
+ supportedBy: zod_1.z.array(factSupportSchema).min(1),
56
+ conflictsWith: zod_1.z.array(zod_1.z.string()),
57
+ independentSources: zod_1.z.number().int().min(0),
58
+ });
59
+ const quoteSchema = factSupportSchema.extend({ text, speaker: text });
60
+ const conflictSchema = zod_1.z.object({ description: text, factIds: zod_1.z.array(zod_1.z.string()) });
61
+ exports.editorialDraftSubmitSchema = zod_1.z
62
+ .object({
63
+ draftId: index_js_1.idSchema,
64
+ clusterId: index_js_1.idSchema,
65
+ headline: text.max(exports.EDITORIAL_DRAFT_LIMITS.headline),
66
+ excerpt: text.max(exports.EDITORIAL_DRAFT_LIMITS.excerpt),
67
+ paragraphs: zod_1.z.array(text).min(1),
68
+ /** The fact-sheet fact ids each paragraph asserts (same length as `paragraphs`). */
69
+ paragraphFactIds: zod_1.z.array(zod_1.z.array(zod_1.z.string())),
70
+ category: text.max(60),
71
+ tags: zod_1.z.array(text.max(40)).max(exports.EDITORIAL_DRAFT_LIMITS.tags),
72
+ seo: zod_1.z.object({
73
+ title: text.max(exports.EDITORIAL_DRAFT_LIMITS.seoTitle),
74
+ description: text.max(exports.EDITORIAL_DRAFT_LIMITS.seoDescription),
75
+ }),
76
+ social: zod_1.z.object({ facebook: text, x: text, whatsapp: text, instagram: text }),
77
+ sources: zod_1.z.array(draftSourceSchema).min(1),
78
+ /** An imported or profile cover (upload-service id), or null when the draft has none. */
79
+ image: zod_1.z.object({ uploadId: index_js_1.idSchema, credit: text.max(160), alt: text.max(255) }).nullable(),
80
+ relatedProfileIds: zod_1.z.array(index_js_1.idSchema),
81
+ suggestedProfileIds: zod_1.z.array(index_js_1.idSchema),
82
+ review: zod_1.z.object({
83
+ confidence: zod_1.z.number().min(0).max(1),
84
+ risk: zod_1.z.enum(exports.DRAFT_RISKS),
85
+ riskReasons: zod_1.z.array(zod_1.z.string()),
86
+ gates: zod_1.z.array(gateResultSchema),
87
+ factSheet: zod_1.z.object({
88
+ facts: zod_1.z.array(factSchema),
89
+ quotes: zod_1.z.array(quoteSchema),
90
+ conflicts: zod_1.z.array(conflictSchema),
91
+ }),
92
+ /** Prompt slug → version used to produce the draft. */
93
+ promptVersions: zod_1.z.record(zod_1.z.string(), zod_1.z.number().int().positive()),
94
+ }),
95
+ })
96
+ .superRefine((draft, ctx) => {
97
+ if (draft.paragraphFactIds.length !== draft.paragraphs.length) {
98
+ ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['paragraphFactIds'], message: 'Must have one entry per paragraph' });
99
+ }
100
+ const factIds = new Set(draft.review.factSheet.facts.map((f) => f.id));
101
+ draft.paragraphFactIds.forEach((ids, i) => {
102
+ for (const id of ids) {
103
+ if (!factIds.has(id))
104
+ ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['paragraphFactIds', i], message: `Unknown fact id ${id}` });
105
+ }
106
+ });
107
+ if (draft.sources.filter((s) => s.role === 'primary').length !== 1) {
108
+ ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['sources'], message: 'Exactly one source must be primary' });
109
+ }
110
+ });
111
+ //# sourceMappingURL=editorial-draft.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editorial-draft.js","sourceRoot":"","sources":["../../../src/contracts/editorial-draft.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AACxB,qDAAkD;AAElD;;;;GAIG;AACU,QAAA,sBAAsB,GAAG,wBAAwB,CAAC;AAE/D,gEAAgE;AACnD,QAAA,sBAAsB,GAAG;IACpC,QAAQ,EAAE,GAAG;IACb,OAAO,EAAE,GAAG;IACZ,IAAI,EAAE,CAAC;IACP,QAAQ,EAAE,EAAE;IACZ,cAAc,EAAE,GAAG;CACX,CAAC;AAEE,QAAA,kBAAkB,GAAG,CAAC,SAAS,EAAE,eAAe,CAAU,CAAC;AAC3D,QAAA,WAAW,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAU,CAAC;AACjD,QAAA,aAAa,GAAG,CAAC,MAAM,EAAE,QAAQ,EAAE,OAAO,CAAU,CAAC;AAClE;;;GAGG;AACU,QAAA,kBAAkB,GAAG;IAChC,aAAa,EAAE,WAAW,EAAE,cAAc,EAAE,eAAe,EAAE,WAAW;IACxE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,wBAAwB,EAAE,eAAe;CACzE,CAAC;AAEE,QAAA,UAAU,GAAG,CAAC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,SAAS,CAAU,CAAC;AAEtG,MAAM,IAAI,GAAG,OAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;AAEtC,MAAM,QAAQ,GAAG,OAAC;KACf,MAAM,EAAE;KACR,GAAG,EAAE;KACL,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,2BAA2B,CAAC,CAAC;AAExE,MAAM,iBAAiB,GAAG,OAAC,CAAC,MAAM,CAAC;IACjC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC;IACnB,GAAG,EAAE,QAAQ;IACb,WAAW,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC7D,IAAI,EAAE,OAAC,CAAC,IAAI,CAAC,0BAAkB,CAAC;CACjC,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,OAAC,CAAC,MAAM,CAAC;IAChC,IAAI,EAAE,IAAI;IACV,OAAO,EAAE,OAAC,CAAC,IAAI,CAAC,qBAAa,CAAC;IAC9B,OAAO,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;IAC5B,OAAO,EAAE,OAAC,CAAC,MAAM,CAAC,OAAC,CAAC,MAAM,EAAE,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,CAAC,QAAQ,EAAE;CACrD,CAAC,CAAC;AAEH,MAAM,iBAAiB,GAAG,OAAC,CAAC,MAAM,CAAC,EAAE,MAAM,EAAE,mBAAQ,EAAE,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;AAE7F,MAAM,UAAU,GAAG,OAAC,CAAC,MAAM,CAAC;IAC1B,EAAE,EAAE,IAAI;IACR,SAAS,EAAE,IAAI;IACf,IAAI,EAAE,OAAC,CAAC,IAAI,CAAC,kBAAU,CAAC;IACxB,QAAQ,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;IAC7B,WAAW,EAAE,OAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9C,aAAa,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;IAClC,kBAAkB,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;CAC5C,CAAC,CAAC;AAEH,MAAM,WAAW,GAAG,iBAAiB,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;AAEtE,MAAM,cAAc,GAAG,OAAC,CAAC,MAAM,CAAC,EAAE,WAAW,EAAE,IAAI,EAAE,OAAO,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC;AAExE,QAAA,0BAA0B,GAAG,OAAC;KACxC,MAAM,CAAC;IACN,OAAO,EAAE,mBAAQ;IACjB,SAAS,EAAE,mBAAQ;IACnB,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,8BAAsB,CAAC,QAAQ,CAAC;IACnD,OAAO,EAAE,IAAI,CAAC,GAAG,CAAC,8BAAsB,CAAC,OAAO,CAAC;IACjD,UAAU,EAAE,OAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAChC,oFAAoF;IACpF,gBAAgB,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC,CAAC;IAC9C,QAAQ,EAAE,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;IACtB,IAAI,EAAE,OAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,8BAAsB,CAAC,IAAI,CAAC;IAC5D,GAAG,EAAE,OAAC,CAAC,MAAM,CAAC;QACZ,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,8BAAsB,CAAC,QAAQ,CAAC;QAChD,WAAW,EAAE,IAAI,CAAC,GAAG,CAAC,8BAAsB,CAAC,cAAc,CAAC;KAC7D,CAAC;IACF,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;IAC9E,OAAO,EAAE,OAAC,CAAC,KAAK,CAAC,iBAAiB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC1C,yFAAyF;IACzF,KAAK,EAAE,OAAC,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,mBAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE;IAC7F,iBAAiB,EAAE,OAAC,CAAC,KAAK,CAAC,mBAAQ,CAAC;IACpC,mBAAmB,EAAE,OAAC,CAAC,KAAK,CAAC,mBAAQ,CAAC;IACtC,MAAM,EAAE,OAAC,CAAC,MAAM,CAAC;QACf,UAAU,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACpC,IAAI,EAAE,OAAC,CAAC,IAAI,CAAC,mBAAW,CAAC;QACzB,WAAW,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC;QAChC,KAAK,EAAE,OAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC;QAChC,SAAS,EAAE,OAAC,CAAC,MAAM,CAAC;YAClB,KAAK,EAAE,OAAC,CAAC,KAAK,CAAC,UAAU,CAAC;YAC1B,MAAM,EAAE,OAAC,CAAC,KAAK,CAAC,WAAW,CAAC;YAC5B,SAAS,EAAE,OAAC,CAAC,KAAK,CAAC,cAAc,CAAC;SACnC,CAAC;QACF,uDAAuD;QACvD,cAAc,EAAE,OAAC,CAAC,MAAM,CAAC,OAAC,CAAC,MAAM,EAAE,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,EAAE,CAAC;KAClE,CAAC;CACH,CAAC;KACD,WAAW,CAAC,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;IAC1B,IAAI,KAAK,CAAC,gBAAgB,CAAC,MAAM,KAAK,KAAK,CAAC,UAAU,CAAC,MAAM,EAAE,CAAC;QAC9D,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAC,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,kBAAkB,CAAC,EAAE,OAAO,EAAE,mCAAmC,EAAE,CAAC,CAAC;IAC1H,CAAC;IACD,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACvE,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE;QACxC,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;YACrB,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC;gBAAE,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAC,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,kBAAkB,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,mBAAmB,EAAE,EAAE,EAAE,CAAC,CAAC;QACvI,CAAC;IACH,CAAC,CAAC,CAAC;IACH,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACnE,GAAG,CAAC,QAAQ,CAAC,EAAE,IAAI,EAAE,OAAC,CAAC,YAAY,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,oCAAoC,EAAE,CAAC,CAAC;IAClH,CAAC;AACH,CAAC,CAAC,CAAC"}
@@ -0,0 +1,20 @@
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("./editorial-draft.js"), exports);
18
+ __exportStar(require("./notification-dispatch.js"), exports);
19
+ __exportStar(require("./upload-import.js"), exports);
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/contracts/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,uDAAqC;AACrC,6DAA2C;AAC3C,qDAAmC"}
@@ -0,0 +1,92 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DISPATCH_TEMPLATE_VARIABLES = exports.notificationDispatchSchema = exports.dispatchRecipientSchema = exports.dispatchValueSchema = exports.DISPATCH_LIMITS = exports.NOTIFICATION_CATEGORIES = exports.DISPATCH_CHANNELS = exports.NOTIFICATION_DISPATCH = void 0;
4
+ const zod_1 = require("zod");
5
+ /**
6
+ * `notification:dispatch` — the one command every Showbiz service stages (through its outbox) to have
7
+ * notification-service render a seeded template and deliver it by email and/or the in-app feed. No
8
+ * other service sends email itself. One contract for both sides: producers type their payload with it
9
+ * and notification-service validates against it, so the two cannot drift.
10
+ */
11
+ exports.NOTIFICATION_DISPATCH = 'notification:dispatch';
12
+ /** Channels a dispatch may ask for. `in_app` needs a recipient `userId` (the bell feed is per user). */
13
+ exports.DISPATCH_CHANNELS = ['email', 'in_app'];
14
+ /**
15
+ * What a dispatch is about. Account mail (`security`, `account`, `team`, `marketing`) goes to a user;
16
+ * `staff` is an operational alert to a configured staff address.
17
+ */
18
+ exports.NOTIFICATION_CATEGORIES = ['security', 'account', 'team', 'marketing', 'staff'];
19
+ exports.DISPATCH_LIMITS = {
20
+ template: 100,
21
+ email: 254,
22
+ name: 200,
23
+ dataKeys: 40,
24
+ dataKey: 64,
25
+ dataValue: 2000,
26
+ secretKeys: 10,
27
+ permission: 100,
28
+ };
29
+ /** Template variables are flat scalars: they are printed into the copy, never serialised objects. */
30
+ exports.dispatchValueSchema = zod_1.z.union([zod_1.z.string().max(exports.DISPATCH_LIMITS.dataValue), zod_1.z.number().finite(), zod_1.z.boolean(), zod_1.z.null()]);
31
+ exports.dispatchRecipientSchema = zod_1.z.object({
32
+ email: zod_1.z.string().trim().email().max(exports.DISPATCH_LIMITS.email),
33
+ name: zod_1.z.string().trim().max(exports.DISPATCH_LIMITS.name).optional(),
34
+ userId: zod_1.z.string().max(36).nullish(),
35
+ locale: zod_1.z.string().max(20).nullish(),
36
+ /** IANA zone; time variables are rendered in it. */
37
+ timezone: zod_1.z.string().max(64).nullish(),
38
+ });
39
+ const dataKey = zod_1.z.string().regex(/^[A-Za-z][A-Za-z0-9_]*$/, 'Use a template variable name').max(exports.DISPATCH_LIMITS.dataKey);
40
+ exports.notificationDispatchSchema = zod_1.z
41
+ .object({
42
+ /** Seeded `notification_templates.slug`. */
43
+ template: zod_1.z.string().trim().min(1).max(exports.DISPATCH_LIMITS.template),
44
+ category: zod_1.z.enum(exports.NOTIFICATION_CATEGORIES),
45
+ recipient: exports.dispatchRecipientSchema,
46
+ channels: zod_1.z.array(zod_1.z.enum(exports.DISPATCH_CHANNELS)).min(1).max(exports.DISPATCH_CHANNELS.length),
47
+ data: zod_1.z
48
+ .record(dataKey, exports.dispatchValueSchema)
49
+ .default({})
50
+ .refine((data) => Object.keys(data).length <= exports.DISPATCH_LIMITS.dataKeys, `At most ${exports.DISPATCH_LIMITS.dataKeys} variables`),
51
+ /**
52
+ * Keys of `data` holding a one-time secret (a sign-in code, a reset or confirm link). They are used to
53
+ * render the email and nothing else: notification-service never stores them and never puts them in the
54
+ * in-app feed, and email-service masks them in what it keeps.
55
+ */
56
+ secretKeys: zod_1.z.array(dataKey).max(exports.DISPATCH_LIMITS.secretKeys).default([]),
57
+ /** Security and staff alerts are always delivered, whatever the recipient's preferences. */
58
+ bypassPreferences: zod_1.z.boolean().optional(),
59
+ /** The permission staff recipients hold; informational until recipients are resolved by permission. */
60
+ targetPermission: zod_1.z.string().max(exports.DISPATCH_LIMITS.permission).optional(),
61
+ })
62
+ .superRefine((dispatch, ctx) => {
63
+ for (const key of dispatch.secretKeys) {
64
+ if (!(key in dispatch.data)) {
65
+ ctx.addIssue({ code: zod_1.z.ZodIssueCode.custom, path: ['secretKeys'], message: `Secret key "${key}" is not in data` });
66
+ }
67
+ }
68
+ });
69
+ /**
70
+ * The seeded templates Showbiz services dispatch, with the variables (`data` keys) each dispatch carries.
71
+ * Producers send exactly these keys; a seeded template may use any subset (notification-service dead-letters
72
+ * a dispatch missing a variable its template uses). Both sides test against this table.
73
+ */
74
+ exports.DISPATCH_TEMPLATE_VARIABLES = {
75
+ // auth-admin-service: account and security mail
76
+ 'account-activation': ['name', 'code', 'expiresInHours'],
77
+ 'login-otp': ['name', 'code', 'expiresInMinutes', 'device'],
78
+ 'password-reset': ['name', 'resetUrl', 'expiresInMinutes'],
79
+ 'staff-invitation': ['name', 'resetUrl', 'expiresInMinutes'],
80
+ 'password-changed': ['name', 'changedAt'],
81
+ 'new-device-login': ['name', 'device', 'ip', 'country', 'occurredAt', 'confirmUrl', 'disputeUrl'],
82
+ 'team-member-added': ['name', 'profileName', 'role', 'invitedBy'],
83
+ 'account-suspended': ['name', 'reason'],
84
+ 'welcome-listener': ['name'],
85
+ 'welcome-creator': ['name'],
86
+ // ai / newswire / editorial: staff alerts
87
+ 'ai_budget_threshold': ['requester', 'period', 'threshold_pct', 'spent_usd', 'limit_usd'],
88
+ 'newswire_source_unhealthy': ['source_name', 'source_slug', 'consecutive_failures', 'last_error', 'last_success_at'],
89
+ 'newswire_block_rate_high': ['blocked', 'total', 'block_rate_pct', 'window_hours'],
90
+ 'autopublish_audit_alert': ['problem_rate_pct', 'problem_count', 'sample_count', 'window_days', 'action_taken'],
91
+ };
92
+ //# sourceMappingURL=notification-dispatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notification-dispatch.js","sourceRoot":"","sources":["../../../src/contracts/notification-dispatch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.uploadImportFailedSchema = exports.uploadImportCompletedSchema = exports.uploadImportCommandSchema = exports.UPLOAD_IMPORT_LIMITS = exports.UPLOAD_IMPORT_POLICIES = exports.UPLOAD_IMPORT_EVENTS = exports.UPLOAD_IMPORT = void 0;
4
+ const zod_1 = require("zod");
5
+ const index_js_1 = require("../validation/index.js");
6
+ /**
7
+ * Licensed image import by URL (Newswire R5, decision R39). newswire-service (and later
8
+ * editorial-service) sends `upload:import`; upload-service fetches the file and answers with an
9
+ * `upload.import.completed` or `upload.import.failed` event. One contract for both sides.
10
+ */
11
+ exports.UPLOAD_IMPORT = 'upload:import';
12
+ exports.UPLOAD_IMPORT_EVENTS = {
13
+ COMPLETED: 'upload.import.completed',
14
+ FAILED: 'upload.import.failed',
15
+ };
16
+ /** Upload policies an import may use. */
17
+ exports.UPLOAD_IMPORT_POLICIES = ['news_image'];
18
+ /** Field limits of the contract (upload-service's `uploads` columns). */
19
+ exports.UPLOAD_IMPORT_LIMITS = {
20
+ url: 2048,
21
+ ownerType: 50,
22
+ licenceHolder: 160,
23
+ licenceBasis: 255,
24
+ reason: 255,
25
+ };
26
+ /**
27
+ * `upload:import` data. The URL is only length-checked here: upload-service rejects a non-https or
28
+ * unsafe URL itself, so the sender hears about it through a `failed` event instead of a dead letter.
29
+ */
30
+ exports.uploadImportCommandSchema = zod_1.z.object({
31
+ /** ULID the outcome event echoes back; upload-service is idempotent on it. */
32
+ importId: index_js_1.idSchema,
33
+ url: zod_1.z.string().min(1).max(exports.UPLOAD_IMPORT_LIMITS.url),
34
+ policy: zod_1.z.enum(exports.UPLOAD_IMPORT_POLICIES),
35
+ /** Echoed in the outcome only; the imported upload is a system row with no owner. */
36
+ ownerType: zod_1.z.string().min(1).max(exports.UPLOAD_IMPORT_LIMITS.ownerType),
37
+ ownerId: index_js_1.idSchema,
38
+ licence: zod_1.z.object({
39
+ holder: zod_1.z.string().trim().min(1).max(exports.UPLOAD_IMPORT_LIMITS.licenceHolder),
40
+ basis: zod_1.z.string().trim().min(1).max(exports.UPLOAD_IMPORT_LIMITS.licenceBasis),
41
+ }),
42
+ });
43
+ exports.uploadImportCompletedSchema = zod_1.z.object({
44
+ importId: index_js_1.idSchema,
45
+ uploadId: index_js_1.idSchema,
46
+ ownerType: zod_1.z.string().min(1).max(exports.UPLOAD_IMPORT_LIMITS.ownerType),
47
+ ownerId: index_js_1.idSchema,
48
+ });
49
+ /** `reason` is a machine code (`too_large`, `http_404`, …; see upload-service `ImportFailureReason`). */
50
+ exports.uploadImportFailedSchema = zod_1.z.object({
51
+ importId: index_js_1.idSchema,
52
+ reason: zod_1.z.string().min(1).max(exports.UPLOAD_IMPORT_LIMITS.reason),
53
+ });
54
+ //# sourceMappingURL=upload-import.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"upload-import.js","sourceRoot":"","sources":["../../../src/contracts/upload-import.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AACxB,qDAAkD;AAElD;;;;GAIG;AACU,QAAA,aAAa,GAAG,eAAe,CAAC;AAEhC,QAAA,oBAAoB,GAAG;IAClC,SAAS,EAAE,yBAAyB;IACpC,MAAM,EAAE,sBAAsB;CACtB,CAAC;AAEX,yCAAyC;AAC5B,QAAA,sBAAsB,GAAG,CAAC,YAAY,CAAU,CAAC;AAG9D,yEAAyE;AAC5D,QAAA,oBAAoB,GAAG;IAClC,GAAG,EAAE,IAAI;IACT,SAAS,EAAE,EAAE;IACb,aAAa,EAAE,GAAG;IAClB,YAAY,EAAE,GAAG;IACjB,MAAM,EAAE,GAAG;CACH,CAAC;AAEX;;;GAGG;AACU,QAAA,yBAAyB,GAAG,OAAC,CAAC,MAAM,CAAC;IAChD,8EAA8E;IAC9E,QAAQ,EAAE,mBAAQ;IAClB,GAAG,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,4BAAoB,CAAC,GAAG,CAAC;IACpD,MAAM,EAAE,OAAC,CAAC,IAAI,CAAC,8BAAsB,CAAC;IACtC,qFAAqF;IACrF,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,4BAAoB,CAAC,SAAS,CAAC;IAChE,OAAO,EAAE,mBAAQ;IACjB,OAAO,EAAE,OAAC,CAAC,MAAM,CAAC;QAChB,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,4BAAoB,CAAC,aAAa,CAAC;QACxE,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,4BAAoB,CAAC,YAAY,CAAC;KACvE,CAAC;CACH,CAAC,CAAC;AAEU,QAAA,2BAA2B,GAAG,OAAC,CAAC,MAAM,CAAC;IAClD,QAAQ,EAAE,mBAAQ;IAClB,QAAQ,EAAE,mBAAQ;IAClB,SAAS,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,4BAAoB,CAAC,SAAS,CAAC;IAChE,OAAO,EAAE,mBAAQ;CAClB,CAAC,CAAC;AAEH,yGAAyG;AAC5F,QAAA,wBAAwB,GAAG,OAAC,CAAC,MAAM,CAAC;IAC/C,QAAQ,EAAE,mBAAQ;IAClB,MAAM,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,4BAAoB,CAAC,MAAM,CAAC;CAC3D,CAAC,CAAC"}
@@ -0,0 +1,57 @@
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.createMysqlPool = createMysqlPool;
7
+ exports.createKnexConfig = createKnexConfig;
8
+ exports.pingMysql = pingMysql;
9
+ exports.escapeLike = escapeLike;
10
+ const promise_1 = __importDefault(require("mysql2/promise"));
11
+ /**
12
+ * mysql2 pool for Drizzle. Sessions run in UTC and utf8mb4 so timestamps and emoji round-trip
13
+ * unchanged regardless of server defaults.
14
+ */
15
+ function createMysqlPool(options) {
16
+ return promise_1.default.createPool({
17
+ host: options.host,
18
+ port: options.port,
19
+ user: options.user,
20
+ password: options.password,
21
+ database: options.database,
22
+ connectionLimit: options.poolMax ?? 10,
23
+ waitForConnections: true,
24
+ enableKeepAlive: true,
25
+ timezone: 'Z',
26
+ charset: 'utf8mb4_unicode_ci',
27
+ dateStrings: false,
28
+ supportBigNumbers: true,
29
+ });
30
+ }
31
+ /** Knex config for migrations/seeds and query-builder use (same session settings as the pool). */
32
+ function createKnexConfig(options) {
33
+ return {
34
+ client: 'mysql2',
35
+ connection: {
36
+ host: options.host,
37
+ port: options.port,
38
+ user: options.user,
39
+ password: options.password,
40
+ database: options.database,
41
+ timezone: 'Z',
42
+ charset: 'utf8mb4',
43
+ },
44
+ pool: { min: 0, max: options.poolMax ?? 10 },
45
+ migrations: { directory: options.migrationsDir ?? './migrations', tableName: 'knex_migrations', loadExtensions: ['.cjs', '.js'] },
46
+ seeds: { directory: options.seedsDir ?? './seeds', loadExtensions: ['.cjs', '.js'] },
47
+ };
48
+ }
49
+ /** Readiness probe helper. */
50
+ async function pingMysql(pool) {
51
+ await pool.query('SELECT 1');
52
+ }
53
+ /** Escapes `%`, `_` and `\` for use inside a LIKE pattern. */
54
+ function escapeLike(value) {
55
+ return value.replace(/[\\%_]/g, (ch) => `\\${ch}`);
56
+ }
57
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/database/index.ts"],"names":[],"mappings":";;;;;AAgBA,0CAeC;AAGD,4CAgBC;AAGD,8BAEC;AAGD,gCAEC;AA3DD,6DAAmC;AAWnC;;;GAGG;AACH,SAAgB,eAAe,CAAC,OAA+B;IAC7D,OAAO,iBAAK,CAAC,UAAU,CAAC;QACtB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,IAAI,EAAE,OAAO,CAAC,IAAI;QAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,QAAQ,EAAE,OAAO,CAAC,QAAQ;QAC1B,eAAe,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE;QACtC,kBAAkB,EAAE,IAAI;QACxB,eAAe,EAAE,IAAI;QACrB,QAAQ,EAAE,GAAG;QACb,OAAO,EAAE,oBAAoB;QAC7B,WAAW,EAAE,KAAK;QAClB,iBAAiB,EAAE,IAAI;KACxB,CAAC,CAAC;AACL,CAAC;AAED,kGAAkG;AAClG,SAAgB,gBAAgB,CAAC,OAA+E;IAC9G,OAAO;QACL,MAAM,EAAE,QAAQ;QAChB,UAAU,EAAE;YACV,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,QAAQ,EAAE,GAAG;YACb,OAAO,EAAE,SAAS;SACnB;QACD,IAAI,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,OAAO,IAAI,EAAE,EAAE;QAC5C,UAAU,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,aAAa,IAAI,cAAc,EAAE,SAAS,EAAE,iBAAiB,EAAE,cAAc,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE;QACjI,KAAK,EAAE,EAAE,SAAS,EAAE,OAAO,CAAC,QAAQ,IAAI,SAAS,EAAE,cAAc,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE;KACrF,CAAC;AACJ,CAAC;AAED,8BAA8B;AACvB,KAAK,UAAU,SAAS,CAAC,IAAgB;IAC9C,MAAM,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC;AAC/B,CAAC;AAED,8DAA8D;AAC9D,SAAgB,UAAU,CAAC,KAAa;IACtC,OAAO,KAAK,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;AACrD,CAAC"}
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.requireRole = exports.requireAllPermissions = exports.requirePermission = void 0;
4
+ exports.authenticateFromGateway = authenticateFromGateway;
5
+ exports.optionalAuthFromGateway = optionalAuthFromGateway;
6
+ exports.requireInternalServiceSecret = requireInternalServiceSecret;
7
+ const index_js_1 = require("../access/index.js");
8
+ const crypto_js_1 = require("../common/crypto.js");
9
+ const response_js_1 = require("../common/response.js");
10
+ const index_js_2 = require("../identity/index.js");
11
+ function resolveIdentity(req, options) {
12
+ const result = (0, index_js_2.verifyIdentityHeaders)(req.headers, options.secret, { maxSkewMs: options.maxSkewMs });
13
+ if (result.status === 'authenticated') {
14
+ req.user = result.user;
15
+ return 'ok';
16
+ }
17
+ if (result.status === 'invalid') {
18
+ options.logger?.warn('Rejected forged or stale gateway identity', { reason: result.reason, path: req.path });
19
+ return 'invalid';
20
+ }
21
+ return 'anonymous';
22
+ }
23
+ /** Requires a valid gateway-signed identity; 401 otherwise. */
24
+ function authenticateFromGateway(options) {
25
+ return (req, res, next) => {
26
+ if (resolveIdentity(req, options) === 'ok')
27
+ return next();
28
+ res.status(401).json((0, response_js_1.errorResponse)('Authentication required', undefined, 'UNAUTHENTICATED'));
29
+ };
30
+ }
31
+ /** Attaches `req.user` when a valid identity is present; continues anonymously otherwise. */
32
+ function optionalAuthFromGateway(options) {
33
+ return (req, res, next) => {
34
+ if (resolveIdentity(req, options) === 'invalid') {
35
+ res.status(401).json((0, response_js_1.errorResponse)('Invalid identity', undefined, 'UNAUTHENTICATED'));
36
+ return;
37
+ }
38
+ next();
39
+ };
40
+ }
41
+ function guard(check, message = 'You do not have permission to perform this action') {
42
+ return (req, res, next) => {
43
+ if (!req.user) {
44
+ res.status(401).json((0, response_js_1.errorResponse)('Authentication required', undefined, 'UNAUTHENTICATED'));
45
+ return;
46
+ }
47
+ if (!check(req.user)) {
48
+ res.status(403).json((0, response_js_1.errorResponse)(message, undefined, 'FORBIDDEN'));
49
+ return;
50
+ }
51
+ next();
52
+ };
53
+ }
54
+ /** Allows callers holding any of `permissions`. */
55
+ const requirePermission = (...permissions) => guard((u) => (0, index_js_1.hasPermission)(u, ...permissions));
56
+ exports.requirePermission = requirePermission;
57
+ /** Allows callers holding every one of `permissions`. */
58
+ const requireAllPermissions = (...permissions) => guard((u) => (0, index_js_1.hasAllPermissions)(u, ...permissions));
59
+ exports.requireAllPermissions = requireAllPermissions;
60
+ /** Allows callers with any of `roles`. Prefer permissions; roles are for coarse gates only. */
61
+ const requireRole = (...roles) => guard((u) => (0, index_js_1.hasRole)(u, ...roles), 'Insufficient role');
62
+ exports.requireRole = requireRole;
63
+ /** Guards `/internal/*` routes: requires the shared service secret header. */
64
+ function requireInternalServiceSecret(secret) {
65
+ return (req, res, next) => {
66
+ const provided = req.headers[index_js_2.CONTEXT_HEADERS.INTERNAL_SECRET];
67
+ if (typeof provided === 'string' && secret && (0, crypto_js_1.safeEqual)(provided, secret))
68
+ return next();
69
+ res.status(401).json((0, response_js_1.errorResponse)('Invalid internal service credentials', undefined, 'UNAUTHENTICATED'));
70
+ };
71
+ }
72
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../../src/express/auth.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,31 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.livenessHandler = livenessHandler;
4
+ exports.readinessHandler = readinessHandler;
5
+ const async_js_1 = require("../common/async.js");
6
+ /** `GET /health` — liveness: the process is up. Never touches dependencies. */
7
+ function livenessHandler(options) {
8
+ const startedAt = Date.now();
9
+ return (_req, res) => {
10
+ res.json({ status: 'ok', service: options.service, version: options.version, uptimeSec: Math.round((Date.now() - startedAt) / 1000) });
11
+ };
12
+ }
13
+ /** `GET /health/ready` — readiness: every dependency responds. 503 when any fails. */
14
+ function readinessHandler(options) {
15
+ return async (_req, res) => {
16
+ const entries = Object.entries(options.checks ?? {});
17
+ const results = await Promise.all(entries.map(async ([name, check]) => {
18
+ const started = Date.now();
19
+ try {
20
+ const detail = await (0, async_js_1.withTimeout)(Promise.resolve(check()), options.timeoutMs ?? 3000, () => new Error('timeout'));
21
+ return [name, { status: 'up', latencyMs: Date.now() - started, ...(detail && typeof detail === 'object' ? { detail } : {}) }];
22
+ }
23
+ catch (error) {
24
+ return [name, { status: 'down', latencyMs: Date.now() - started, error: error.message }];
25
+ }
26
+ }));
27
+ const healthy = results.every(([, r]) => r.status === 'up');
28
+ res.status(healthy ? 200 : 503).json({ status: healthy ? 'ok' : 'degraded', service: options.service, checks: Object.fromEntries(results) });
29
+ };
30
+ }
31
+ //# sourceMappingURL=health.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"health.js","sourceRoot":"","sources":["../../../src/express/health.ts"],"names":[],"mappings":";;AAcA,0CAKC;AAGD,4CAeC;AApCD,iDAAiD;AAYjD,+EAA+E;AAC/E,SAAgB,eAAe,CAAC,OAAsB;IACpD,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IAC7B,OAAO,CAAC,IAAa,EAAE,GAAa,EAAE,EAAE;QACtC,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC,GAAG,IAAI,CAAC,EAAE,CAAC,CAAC;IACzI,CAAC,CAAC;AACJ,CAAC;AAED,sFAAsF;AACtF,SAAgB,gBAAgB,CAAC,OAAsB;IACrD,OAAO,KAAK,EAAE,IAAa,EAAE,GAAa,EAAE,EAAE;QAC5C,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;QACrD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE;YACpE,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YAC3B,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,IAAA,sBAAW,EAAC,OAAO,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,EAAE,OAAO,CAAC,SAAS,IAAI,IAAI,EAAE,GAAG,EAAE,CAAC,IAAI,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC;gBAClH,OAAO,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,EAAE,GAAG,CAAC,MAAM,IAAI,OAAO,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAU,CAAC;YACzI,CAAC;YAAC,OAAO,KAAK,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO,EAAE,KAAK,EAAG,KAAe,CAAC,OAAO,EAAE,CAAU,CAAC;YAC/G,CAAC;QACH,CAAC,CAAC,CAAC,CAAC;QACJ,MAAM,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,IAAI,CAAC,CAAC;QAC5D,GAAG,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,UAAU,EAAE,OAAO,EAAE,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,WAAW,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;IAC/I,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,20 @@
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("./auth.js"), exports);
18
+ __exportStar(require("./middleware.js"), exports);
19
+ __exportStar(require("./health.js"), exports);
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/express/index.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;AAAA,4CAA0B;AAC1B,kDAAgC;AAChC,8CAA4B"}
@@ -0,0 +1,95 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.correlationMiddleware = correlationMiddleware;
4
+ exports.correlationId = correlationId;
5
+ exports.clientIp = clientIp;
6
+ exports.clientTimezone = clientTimezone;
7
+ exports.anonId = anonId;
8
+ exports.validate = validate;
9
+ exports.asyncHandler = asyncHandler;
10
+ exports.errorHandler = errorHandler;
11
+ exports.notFoundHandler = notFoundHandler;
12
+ const errors_js_1 = require("../common/errors.js");
13
+ const id_js_1 = require("../common/id.js");
14
+ const response_js_1 = require("../common/response.js");
15
+ const index_js_1 = require("../identity/index.js");
16
+ const index_js_2 = require("../validation/index.js");
17
+ /** Ensures every request carries `x-correlation-id` (reused from the gateway when present). */
18
+ function correlationMiddleware() {
19
+ return (req, res, next) => {
20
+ const incoming = req.headers[index_js_1.CONTEXT_HEADERS.CORRELATION_ID];
21
+ const id = typeof incoming === 'string' && incoming.length <= 128 ? incoming : (0, id_js_1.newId)();
22
+ req.headers[index_js_1.CONTEXT_HEADERS.CORRELATION_ID] = id;
23
+ res.setHeader(index_js_1.CONTEXT_HEADERS.CORRELATION_ID, id);
24
+ next();
25
+ };
26
+ }
27
+ function correlationId(req) {
28
+ const value = req.headers[index_js_1.CONTEXT_HEADERS.CORRELATION_ID];
29
+ return typeof value === 'string' ? value : undefined;
30
+ }
31
+ /** Real client IP: gateway-forwarded header first, then Express's `req.ip`. */
32
+ function clientIp(req) {
33
+ const forwarded = req.headers[index_js_1.CONTEXT_HEADERS.CLIENT_IP];
34
+ if (typeof forwarded === 'string' && forwarded)
35
+ return forwarded;
36
+ return req.ip ?? null;
37
+ }
38
+ function clientTimezone(req) {
39
+ const tz = req.headers[index_js_1.CONTEXT_HEADERS.TIMEZONE];
40
+ return typeof tz === 'string' && tz ? tz : null;
41
+ }
42
+ function anonId(req) {
43
+ const id = req.headers[index_js_1.CONTEXT_HEADERS.ANON_ID];
44
+ return typeof id === 'string' && id ? id : null;
45
+ }
46
+ /** Validates and replaces `req[part]` with the parsed value; 422 with field errors on failure. */
47
+ function validate(schema, part = 'body') {
48
+ return (req, res, next) => {
49
+ const result = schema.safeParse(req[part]);
50
+ if (!result.success) {
51
+ res.status(422).json((0, response_js_1.errorResponse)('Validation failed', (0, index_js_2.zodIssuesToErrors)(result.error), 'VALIDATION_FAILED'));
52
+ return;
53
+ }
54
+ // Express 5 exposes req.query as a getter; redefine to store the parsed value.
55
+ Object.defineProperty(req, part, { value: result.data, writable: true, configurable: true, enumerable: true });
56
+ next();
57
+ };
58
+ }
59
+ /** Wraps an async handler so rejections reach the error middleware (needed on Express 4). */
60
+ function asyncHandler(fn) {
61
+ return (req, res, next) => {
62
+ fn(req, res, next).catch(next);
63
+ };
64
+ }
65
+ /** Maps AppErrors to their status; everything else becomes a logged 500 with a generic message. */
66
+ function errorHandler(logger) {
67
+ return (err, req, res, _next) => {
68
+ if (res.headersSent)
69
+ return;
70
+ const bodyError = err;
71
+ if (bodyError?.type === 'entity.parse.failed') {
72
+ res.status(400).json((0, response_js_1.errorResponse)('Malformed JSON body', undefined, 'BAD_REQUEST'));
73
+ return;
74
+ }
75
+ if (bodyError?.type === 'entity.too.large') {
76
+ res.status(413).json((0, response_js_1.errorResponse)('Request body too large', undefined, 'PAYLOAD_TOO_LARGE'));
77
+ return;
78
+ }
79
+ if ((0, errors_js_1.isAppError)(err)) {
80
+ if (err.statusCode >= 500)
81
+ logger?.error(err.message, { path: req.path, code: err.code, correlationId: correlationId(req) });
82
+ res.status(err.statusCode).json((0, response_js_1.errorResponse)((0, errors_js_1.publicMessage)(err), err.errors, err.code));
83
+ return;
84
+ }
85
+ const error = err instanceof Error ? err : new Error(String(err));
86
+ logger?.error('Unhandled error', { error: error.message, stack: error.stack, path: req.path, correlationId: correlationId(req) });
87
+ res.status(500).json((0, response_js_1.errorResponse)('Internal server error', undefined, 'INTERNAL_ERROR'));
88
+ };
89
+ }
90
+ function notFoundHandler() {
91
+ return (_req, res) => {
92
+ res.status(404).json((0, response_js_1.errorResponse)('Resource not found', undefined, 'NOT_FOUND'));
93
+ };
94
+ }
95
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../../src/express/middleware.ts"],"names":[],"mappings":"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"}