@crowdsource.you/core 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 (339) hide show
  1. package/README.md +571 -0
  2. package/dist/cases.d.ts +66 -0
  3. package/dist/cases.d.ts.map +1 -0
  4. package/dist/cases.js +79 -0
  5. package/dist/cases.js.map +1 -0
  6. package/dist/client.d.ts +90 -0
  7. package/dist/client.d.ts.map +1 -0
  8. package/dist/client.js +125 -0
  9. package/dist/client.js.map +1 -0
  10. package/dist/communityNotes.d.ts +49 -0
  11. package/dist/communityNotes.d.ts.map +1 -0
  12. package/dist/communityNotes.js +104 -0
  13. package/dist/communityNotes.js.map +1 -0
  14. package/dist/credential.d.ts +58 -0
  15. package/dist/credential.d.ts.map +1 -0
  16. package/dist/credential.js +71 -0
  17. package/dist/credential.js.map +1 -0
  18. package/dist/defaults.d.ts +61 -0
  19. package/dist/defaults.d.ts.map +1 -0
  20. package/dist/defaults.js +82 -0
  21. package/dist/defaults.js.map +1 -0
  22. package/dist/digest.d.ts +44 -0
  23. package/dist/digest.d.ts.map +1 -0
  24. package/dist/digest.js +79 -0
  25. package/dist/digest.js.map +1 -0
  26. package/dist/envelope.d.ts +143 -0
  27. package/dist/envelope.d.ts.map +1 -0
  28. package/dist/envelope.js +258 -0
  29. package/dist/envelope.js.map +1 -0
  30. package/dist/errors.d.ts +90 -0
  31. package/dist/errors.d.ts.map +1 -0
  32. package/dist/errors.js +151 -0
  33. package/dist/errors.js.map +1 -0
  34. package/dist/esm/cases.js +74 -0
  35. package/dist/esm/cases.js.map +1 -0
  36. package/dist/esm/client.js +121 -0
  37. package/dist/esm/client.js.map +1 -0
  38. package/dist/esm/communityNotes.js +100 -0
  39. package/dist/esm/communityNotes.js.map +1 -0
  40. package/dist/esm/credential.js +67 -0
  41. package/dist/esm/credential.js.map +1 -0
  42. package/dist/esm/defaults.js +77 -0
  43. package/dist/esm/defaults.js.map +1 -0
  44. package/dist/esm/digest.js +74 -0
  45. package/dist/esm/digest.js.map +1 -0
  46. package/dist/esm/envelope.js +252 -0
  47. package/dist/esm/envelope.js.map +1 -0
  48. package/dist/esm/errors.js +140 -0
  49. package/dist/esm/errors.js.map +1 -0
  50. package/dist/esm/express/index.js +29 -0
  51. package/dist/esm/express/index.js.map +1 -0
  52. package/dist/esm/express/middleware.js +293 -0
  53. package/dist/esm/express/middleware.js.map +1 -0
  54. package/dist/esm/express/store.js +69 -0
  55. package/dist/esm/express/store.js.map +1 -0
  56. package/dist/esm/express/verify.js +133 -0
  57. package/dist/esm/express/verify.js.map +1 -0
  58. package/dist/esm/index.js +57 -0
  59. package/dist/esm/index.js.map +1 -0
  60. package/dist/esm/outbox/client.js +43 -0
  61. package/dist/esm/outbox/client.js.map +1 -0
  62. package/dist/esm/outbox/decision.js +153 -0
  63. package/dist/esm/outbox/decision.js.map +1 -0
  64. package/dist/esm/outbox/delivery.js +129 -0
  65. package/dist/esm/outbox/delivery.js.map +1 -0
  66. package/dist/esm/outbox/enforcement/executor.js +219 -0
  67. package/dist/esm/outbox/enforcement/executor.js.map +1 -0
  68. package/dist/esm/outbox/enforcement/planner.js +326 -0
  69. package/dist/esm/outbox/enforcement/planner.js.map +1 -0
  70. package/dist/esm/outbox/evidence.js +173 -0
  71. package/dist/esm/outbox/evidence.js.map +1 -0
  72. package/dist/esm/outbox/inbound.js +87 -0
  73. package/dist/esm/outbox/inbound.js.map +1 -0
  74. package/dist/esm/outbox/index.js +71 -0
  75. package/dist/esm/outbox/index.js.map +1 -0
  76. package/dist/esm/outbox/intake.js +140 -0
  77. package/dist/esm/outbox/intake.js.map +1 -0
  78. package/dist/esm/outbox/integration.js +116 -0
  79. package/dist/esm/outbox/integration.js.map +1 -0
  80. package/dist/esm/outbox/outbox/dispatcher.js +114 -0
  81. package/dist/esm/outbox/outbox/dispatcher.js.map +1 -0
  82. package/dist/esm/outbox/outbox/service.js +271 -0
  83. package/dist/esm/outbox/outbox/service.js.map +1 -0
  84. package/dist/esm/outbox/postgres/index.js +41 -0
  85. package/dist/esm/outbox/postgres/index.js.map +1 -0
  86. package/dist/esm/outbox/postgres/registries.js +155 -0
  87. package/dist/esm/outbox/postgres/registries.js.map +1 -0
  88. package/dist/esm/outbox/postgres/reportColumns.js +191 -0
  89. package/dist/esm/outbox/postgres/reportColumns.js.map +1 -0
  90. package/dist/esm/outbox/postgres/store/enforcement.js +158 -0
  91. package/dist/esm/outbox/postgres/store/enforcement.js.map +1 -0
  92. package/dist/esm/outbox/postgres/store/events.js +101 -0
  93. package/dist/esm/outbox/postgres/store/events.js.map +1 -0
  94. package/dist/esm/outbox/postgres/store/index.js +59 -0
  95. package/dist/esm/outbox/postgres/store/index.js.map +1 -0
  96. package/dist/esm/outbox/postgres/store/outbox.js +207 -0
  97. package/dist/esm/outbox/postgres/store/outbox.js.map +1 -0
  98. package/dist/esm/outbox/postgres/store/reports.js +231 -0
  99. package/dist/esm/outbox/postgres/store/reports.js.map +1 -0
  100. package/dist/esm/outbox/postgres/store/transaction.js +29 -0
  101. package/dist/esm/outbox/postgres/store/transaction.js.map +1 -0
  102. package/dist/esm/outbox/postgres/tables.js +270 -0
  103. package/dist/esm/outbox/postgres/tables.js.map +1 -0
  104. package/dist/esm/outbox/reconciliation.js +157 -0
  105. package/dist/esm/outbox/reconciliation.js.map +1 -0
  106. package/dist/esm/outbox/reportStatus.js +22 -0
  107. package/dist/esm/outbox/reportStatus.js.map +1 -0
  108. package/dist/esm/outbox/retention.js +33 -0
  109. package/dist/esm/outbox/retention.js.map +1 -0
  110. package/dist/esm/outbox/store/types.js +30 -0
  111. package/dist/esm/outbox/store/types.js.map +1 -0
  112. package/dist/esm/outbox/types.js +23 -0
  113. package/dist/esm/outbox/types.js.map +1 -0
  114. package/dist/esm/outbox/webhook.js +145 -0
  115. package/dist/esm/outbox/webhook.js.map +1 -0
  116. package/dist/esm/package.json +1 -0
  117. package/dist/esm/reports.js +74 -0
  118. package/dist/esm/reports.js.map +1 -0
  119. package/dist/esm/testing/fixtures.js +132 -0
  120. package/dist/esm/testing/fixtures.js.map +1 -0
  121. package/dist/esm/testing/index.js +33 -0
  122. package/dist/esm/testing/index.js.map +1 -0
  123. package/dist/esm/testing/sandbox.js +337 -0
  124. package/dist/esm/testing/sandbox.js.map +1 -0
  125. package/dist/esm/testing/webhook-simulator.js +93 -0
  126. package/dist/esm/testing/webhook-simulator.js.map +1 -0
  127. package/dist/esm/transport.js +177 -0
  128. package/dist/esm/transport.js.map +1 -0
  129. package/dist/esm/webhookEndpoints.js +139 -0
  130. package/dist/esm/webhookEndpoints.js.map +1 -0
  131. package/dist/express/index.d.ts +32 -0
  132. package/dist/express/index.d.ts.map +1 -0
  133. package/dist/express/index.js +40 -0
  134. package/dist/express/index.js.map +1 -0
  135. package/dist/express/middleware.d.ts +97 -0
  136. package/dist/express/middleware.d.ts.map +1 -0
  137. package/dist/express/middleware.js +298 -0
  138. package/dist/express/middleware.js.map +1 -0
  139. package/dist/express/store.d.ts +45 -0
  140. package/dist/express/store.d.ts.map +1 -0
  141. package/dist/express/store.js +72 -0
  142. package/dist/express/store.js.map +1 -0
  143. package/dist/express/verify.d.ts +86 -0
  144. package/dist/express/verify.d.ts.map +1 -0
  145. package/dist/express/verify.js +138 -0
  146. package/dist/express/verify.js.map +1 -0
  147. package/dist/index.d.ts +67 -0
  148. package/dist/index.d.ts.map +1 -0
  149. package/dist/index.js +89 -0
  150. package/dist/index.js.map +1 -0
  151. package/dist/outbox/client.d.ts +35 -0
  152. package/dist/outbox/client.d.ts.map +1 -0
  153. package/dist/outbox/client.js +46 -0
  154. package/dist/outbox/client.js.map +1 -0
  155. package/dist/outbox/decision.d.ts +36 -0
  156. package/dist/outbox/decision.d.ts.map +1 -0
  157. package/dist/outbox/decision.js +159 -0
  158. package/dist/outbox/decision.js.map +1 -0
  159. package/dist/outbox/delivery.d.ts +50 -0
  160. package/dist/outbox/delivery.d.ts.map +1 -0
  161. package/dist/outbox/delivery.js +135 -0
  162. package/dist/outbox/delivery.js.map +1 -0
  163. package/dist/outbox/enforcement/executor.d.ts +26 -0
  164. package/dist/outbox/enforcement/executor.d.ts.map +1 -0
  165. package/dist/outbox/enforcement/executor.js +222 -0
  166. package/dist/outbox/enforcement/executor.js.map +1 -0
  167. package/dist/outbox/enforcement/planner.d.ts +50 -0
  168. package/dist/outbox/enforcement/planner.d.ts.map +1 -0
  169. package/dist/outbox/enforcement/planner.js +333 -0
  170. package/dist/outbox/enforcement/planner.js.map +1 -0
  171. package/dist/outbox/evidence.d.ts +114 -0
  172. package/dist/outbox/evidence.d.ts.map +1 -0
  173. package/dist/outbox/evidence.js +181 -0
  174. package/dist/outbox/evidence.js.map +1 -0
  175. package/dist/outbox/inbound.d.ts +78 -0
  176. package/dist/outbox/inbound.d.ts.map +1 -0
  177. package/dist/outbox/inbound.js +91 -0
  178. package/dist/outbox/inbound.js.map +1 -0
  179. package/dist/outbox/index.d.ts +79 -0
  180. package/dist/outbox/index.d.ts.map +1 -0
  181. package/dist/outbox/index.js +98 -0
  182. package/dist/outbox/index.js.map +1 -0
  183. package/dist/outbox/intake.d.ts +62 -0
  184. package/dist/outbox/intake.d.ts.map +1 -0
  185. package/dist/outbox/intake.js +145 -0
  186. package/dist/outbox/intake.js.map +1 -0
  187. package/dist/outbox/integration.d.ts +62 -0
  188. package/dist/outbox/integration.d.ts.map +1 -0
  189. package/dist/outbox/integration.js +119 -0
  190. package/dist/outbox/integration.js.map +1 -0
  191. package/dist/outbox/outbox/dispatcher.d.ts +26 -0
  192. package/dist/outbox/outbox/dispatcher.d.ts.map +1 -0
  193. package/dist/outbox/outbox/dispatcher.js +119 -0
  194. package/dist/outbox/outbox/dispatcher.js.map +1 -0
  195. package/dist/outbox/outbox/service.d.ts +124 -0
  196. package/dist/outbox/outbox/service.d.ts.map +1 -0
  197. package/dist/outbox/outbox/service.js +279 -0
  198. package/dist/outbox/outbox/service.js.map +1 -0
  199. package/dist/outbox/postgres/index.d.ts +44 -0
  200. package/dist/outbox/postgres/index.d.ts.map +1 -0
  201. package/dist/outbox/postgres/index.js +51 -0
  202. package/dist/outbox/postgres/index.js.map +1 -0
  203. package/dist/outbox/postgres/registries.d.ts +69 -0
  204. package/dist/outbox/postgres/registries.d.ts.map +1 -0
  205. package/dist/outbox/postgres/registries.js +159 -0
  206. package/dist/outbox/postgres/registries.js.map +1 -0
  207. package/dist/outbox/postgres/reportColumns.d.ts +154 -0
  208. package/dist/outbox/postgres/reportColumns.d.ts.map +1 -0
  209. package/dist/outbox/postgres/reportColumns.js +195 -0
  210. package/dist/outbox/postgres/reportColumns.js.map +1 -0
  211. package/dist/outbox/postgres/store/enforcement.d.ts +33 -0
  212. package/dist/outbox/postgres/store/enforcement.d.ts.map +1 -0
  213. package/dist/outbox/postgres/store/enforcement.js +161 -0
  214. package/dist/outbox/postgres/store/enforcement.js.map +1 -0
  215. package/dist/outbox/postgres/store/events.d.ts +46 -0
  216. package/dist/outbox/postgres/store/events.d.ts.map +1 -0
  217. package/dist/outbox/postgres/store/events.js +104 -0
  218. package/dist/outbox/postgres/store/events.js.map +1 -0
  219. package/dist/outbox/postgres/store/index.d.ts +27 -0
  220. package/dist/outbox/postgres/store/index.d.ts.map +1 -0
  221. package/dist/outbox/postgres/store/index.js +62 -0
  222. package/dist/outbox/postgres/store/index.js.map +1 -0
  223. package/dist/outbox/postgres/store/outbox.d.ts +8 -0
  224. package/dist/outbox/postgres/store/outbox.d.ts.map +1 -0
  225. package/dist/outbox/postgres/store/outbox.js +210 -0
  226. package/dist/outbox/postgres/store/outbox.js.map +1 -0
  227. package/dist/outbox/postgres/store/reports.d.ts +69 -0
  228. package/dist/outbox/postgres/store/reports.d.ts.map +1 -0
  229. package/dist/outbox/postgres/store/reports.js +234 -0
  230. package/dist/outbox/postgres/store/reports.js.map +1 -0
  231. package/dist/outbox/postgres/store/transaction.d.ts +49 -0
  232. package/dist/outbox/postgres/store/transaction.d.ts.map +1 -0
  233. package/dist/outbox/postgres/store/transaction.js +32 -0
  234. package/dist/outbox/postgres/store/transaction.js.map +1 -0
  235. package/dist/outbox/postgres/tables.d.ts +737 -0
  236. package/dist/outbox/postgres/tables.d.ts.map +1 -0
  237. package/dist/outbox/postgres/tables.js +273 -0
  238. package/dist/outbox/postgres/tables.js.map +1 -0
  239. package/dist/outbox/reconciliation.d.ts +49 -0
  240. package/dist/outbox/reconciliation.d.ts.map +1 -0
  241. package/dist/outbox/reconciliation.js +162 -0
  242. package/dist/outbox/reconciliation.js.map +1 -0
  243. package/dist/outbox/reportStatus.d.ts +12 -0
  244. package/dist/outbox/reportStatus.d.ts.map +1 -0
  245. package/dist/outbox/reportStatus.js +25 -0
  246. package/dist/outbox/reportStatus.js.map +1 -0
  247. package/dist/outbox/retention.d.ts +33 -0
  248. package/dist/outbox/retention.d.ts.map +1 -0
  249. package/dist/outbox/retention.js +36 -0
  250. package/dist/outbox/retention.js.map +1 -0
  251. package/dist/outbox/store/types.d.ts +466 -0
  252. package/dist/outbox/store/types.d.ts.map +1 -0
  253. package/dist/outbox/store/types.js +31 -0
  254. package/dist/outbox/store/types.js.map +1 -0
  255. package/dist/outbox/types.d.ts +660 -0
  256. package/dist/outbox/types.d.ts.map +1 -0
  257. package/dist/outbox/types.js +24 -0
  258. package/dist/outbox/types.js.map +1 -0
  259. package/dist/outbox/webhook.d.ts +15 -0
  260. package/dist/outbox/webhook.d.ts.map +1 -0
  261. package/dist/outbox/webhook.js +148 -0
  262. package/dist/outbox/webhook.js.map +1 -0
  263. package/dist/reports.d.ts +73 -0
  264. package/dist/reports.d.ts.map +1 -0
  265. package/dist/reports.js +78 -0
  266. package/dist/reports.js.map +1 -0
  267. package/dist/testing/fixtures.d.ts +62 -0
  268. package/dist/testing/fixtures.d.ts.map +1 -0
  269. package/dist/testing/fixtures.js +137 -0
  270. package/dist/testing/fixtures.js.map +1 -0
  271. package/dist/testing/index.d.ts +36 -0
  272. package/dist/testing/index.d.ts.map +1 -0
  273. package/dist/testing/index.js +43 -0
  274. package/dist/testing/index.js.map +1 -0
  275. package/dist/testing/sandbox.d.ts +109 -0
  276. package/dist/testing/sandbox.d.ts.map +1 -0
  277. package/dist/testing/sandbox.js +342 -0
  278. package/dist/testing/sandbox.js.map +1 -0
  279. package/dist/testing/webhook-simulator.d.ts +78 -0
  280. package/dist/testing/webhook-simulator.d.ts.map +1 -0
  281. package/dist/testing/webhook-simulator.js +98 -0
  282. package/dist/testing/webhook-simulator.js.map +1 -0
  283. package/dist/transport.d.ts +59 -0
  284. package/dist/transport.d.ts.map +1 -0
  285. package/dist/transport.js +181 -0
  286. package/dist/transport.js.map +1 -0
  287. package/dist/webhookEndpoints.d.ts +147 -0
  288. package/dist/webhookEndpoints.d.ts.map +1 -0
  289. package/dist/webhookEndpoints.js +143 -0
  290. package/dist/webhookEndpoints.js.map +1 -0
  291. package/package.json +127 -0
  292. package/src/cases.ts +119 -0
  293. package/src/client.ts +202 -0
  294. package/src/communityNotes.ts +194 -0
  295. package/src/credential.ts +100 -0
  296. package/src/defaults.ts +87 -0
  297. package/src/digest.ts +91 -0
  298. package/src/envelope.ts +432 -0
  299. package/src/errors.ts +165 -0
  300. package/src/express/index.ts +43 -0
  301. package/src/express/middleware.ts +387 -0
  302. package/src/express/store.ts +85 -0
  303. package/src/express/verify.ts +166 -0
  304. package/src/index.ts +107 -0
  305. package/src/outbox/client.ts +75 -0
  306. package/src/outbox/decision.ts +209 -0
  307. package/src/outbox/delivery.ts +163 -0
  308. package/src/outbox/enforcement/executor.ts +288 -0
  309. package/src/outbox/enforcement/planner.ts +377 -0
  310. package/src/outbox/evidence.ts +231 -0
  311. package/src/outbox/inbound.ts +140 -0
  312. package/src/outbox/index.ts +160 -0
  313. package/src/outbox/intake.ts +175 -0
  314. package/src/outbox/integration.ts +205 -0
  315. package/src/outbox/outbox/dispatcher.ts +131 -0
  316. package/src/outbox/outbox/service.ts +444 -0
  317. package/src/outbox/postgres/index.ts +59 -0
  318. package/src/outbox/postgres/registries.ts +177 -0
  319. package/src/outbox/postgres/reportColumns.ts +281 -0
  320. package/src/outbox/postgres/store/enforcement.ts +186 -0
  321. package/src/outbox/postgres/store/events.ts +112 -0
  322. package/src/outbox/postgres/store/index.ts +72 -0
  323. package/src/outbox/postgres/store/outbox.ts +273 -0
  324. package/src/outbox/postgres/store/reports.ts +349 -0
  325. package/src/outbox/postgres/store/transaction.ts +64 -0
  326. package/src/outbox/postgres/tables.ts +339 -0
  327. package/src/outbox/reconciliation.ts +199 -0
  328. package/src/outbox/reportStatus.ts +24 -0
  329. package/src/outbox/retention.ts +34 -0
  330. package/src/outbox/store/types.ts +528 -0
  331. package/src/outbox/types.ts +753 -0
  332. package/src/outbox/webhook.ts +165 -0
  333. package/src/reports.ts +138 -0
  334. package/src/testing/fixtures.ts +183 -0
  335. package/src/testing/index.ts +57 -0
  336. package/src/testing/sandbox.ts +469 -0
  337. package/src/testing/webhook-simulator.ts +166 -0
  338. package/src/transport.ts +250 -0
  339. package/src/webhookEndpoints.ts +256 -0
@@ -0,0 +1,258 @@
1
+ "use strict";
2
+ /**
3
+ * Composing a Case Envelope out of what an application already has.
4
+ *
5
+ * §5 is a rich document contract — resources with stable ids, relations between
6
+ * them, pseudonymous principal bindings, digests, a policy reference, privacy
7
+ * terms. Handing that to an integrator and asking them to fill it in is how a
8
+ * moderation integration becomes a two-week project, and it is how the parts
9
+ * that MATTER get filled in wrong: a random resource id or a per-report binding
10
+ * proof inside the hashed projection means two people reporting the same post
11
+ * open two cases, and "one penalty per incident" (Appendix F) fails in
12
+ * production with nothing failing in a test.
13
+ *
14
+ * So the integrator describes the object — its id, its author, its text, its
15
+ * attachments, what is alleged about it — and this module derives the rest:
16
+ *
17
+ * * **Resource ids are positional and stable** (`res_subject`,
18
+ * `res_attachment_1`, `res_context_1`). Two reporters describing the same
19
+ * post through this SDK produce byte-identical resource lists, which is what
20
+ * makes §7.3's dedup key match.
21
+ * * **Principal refs are derived from the identity**, never generated. Same
22
+ * reason: the content snapshot the server hashes includes every principal
23
+ * the material points at, so a random ref would fragment the case.
24
+ * * **Digests are computed** (see `digest.ts`).
25
+ * * **Relations are derived** from the role each resource was given.
26
+ * * **The binding proof is the Oxy `sub`.** §11.14 requires proof that a
27
+ * pseudonymous ref corresponds to a real identity before anything can touch
28
+ * Oxy Trust. Sign in with Oxy already produced exactly that: a subject
29
+ * issued for this `applicationId`. There is no separate binding step to
30
+ * implement, and this module does not invent one.
31
+ * * **`applicationId` comes from the credential** (see `credential.ts`). No
32
+ * input on this page can carry one.
33
+ */
34
+ Object.defineProperty(exports, "__esModule", { value: true });
35
+ exports.CrowdSourceReportInputError = void 0;
36
+ exports.composeCaseEnvelope = composeCaseEnvelope;
37
+ exports.defaultIdempotencyKey = defaultIdempotencyKey;
38
+ const contracts_1 = require("@crowdsource.you/contracts");
39
+ const defaults_js_1 = require("./defaults.js");
40
+ const digest_js_1 = require("./digest.js");
41
+ const errors_js_1 = require("./errors.js");
42
+ /** Raised when an input cannot become a valid envelope. Never retryable. */
43
+ class CrowdSourceReportInputError extends errors_js_1.CrowdSourceError {
44
+ constructor(message) {
45
+ super(message, false);
46
+ }
47
+ }
48
+ exports.CrowdSourceReportInputError = CrowdSourceReportInputError;
49
+ const SUBJECT_RESOURCE_ID = 'res_subject';
50
+ function isoTimestamp(value) {
51
+ return value instanceof Date ? value.toISOString() : value;
52
+ }
53
+ /**
54
+ * A principal ref derived from the identity, so it is the same value for every
55
+ * reporter.
56
+ *
57
+ * Opaque on purpose: §9.1 keeps identities away from the jury, and a ref that
58
+ * embedded a username would put one on the reviewer's screen. Truncated to 128
59
+ * bits, which is far past any collision risk within one envelope's 50-binding
60
+ * ceiling and keeps the ref short enough to read in a case document.
61
+ */
62
+ function principalRef(type, identity) {
63
+ return `p_${(0, digest_js_1.sha256Digest)((0, digest_js_1.canonicalJson)([type, identity])).slice('sha256:'.length, 'sha256:'.length + 32)}`;
64
+ }
65
+ function resolvePrincipal(input, role) {
66
+ const type = input.type ?? (input.oxyUserId === undefined ? 'local_user' : 'oxy_user');
67
+ if (type === 'oxy_user' && input.oxyUserId === undefined) {
68
+ throw new CrowdSourceReportInputError(`The ${role} is declared as an oxy_user but carries no oxyUserId. The Oxy subject IS the binding proof (§11.14); without it there is nothing to bind.`);
69
+ }
70
+ const externalPrincipalId = input.id ?? input.oxyUserId;
71
+ if (externalPrincipalId === undefined) {
72
+ throw new CrowdSourceReportInputError(`The ${role} carries neither an oxyUserId nor an id, so there is no identity to reference.`);
73
+ }
74
+ const ref = principalRef(type, externalPrincipalId);
75
+ return {
76
+ ref,
77
+ binding: {
78
+ principalRef: ref,
79
+ type,
80
+ externalPrincipalId,
81
+ /**
82
+ * The `sub` itself. §11.14 asks for proof that this ref is that identity,
83
+ * and an OAuth subject issued to this application for this user is that
84
+ * proof — it is not a receipt POINTING at one. Deliberately absent for
85
+ * every other principal type: they have no Oxy identity to move, and
86
+ * requiring a proof from them would lock out every tenant whose users are
87
+ * not Oxy users.
88
+ */
89
+ ...(type === 'oxy_user' && input.oxyUserId !== undefined
90
+ ? { bindingProofId: input.oxyUserId }
91
+ : {}),
92
+ },
93
+ };
94
+ }
95
+ /** The object a resource's digest is taken over — see `digest.ts`. */
96
+ function reviewableRepresentation(resource) {
97
+ if (resource.type === 'custom') {
98
+ return { type: resource.type, schemaId: resource.schemaId, data: resource.payload };
99
+ }
100
+ return { type: resource.type, data: 'data' in resource ? resource.data : null };
101
+ }
102
+ /**
103
+ * Turns one described resource into a contract resource.
104
+ *
105
+ * The digest is the only field invented here. An asset-backed resource does not
106
+ * get one: its bytes are outside the envelope and `asset.sha256` already
107
+ * identifies them, which is the split the contract makes.
108
+ *
109
+ * Returns `unknown` rather than `Resource`, deliberately. The value is assembled
110
+ * from caller data and only becomes a `Resource` when `CaseEnvelopeSchema`
111
+ * parses it at the end of `composeCaseEnvelope`. Declaring it a `Resource` here
112
+ * would need a cast, and a cast is a claim the type system cannot check — the
113
+ * parse is what actually establishes it.
114
+ */
115
+ function composeResource(input, id, role, authorPrincipalRef) {
116
+ const { createdAt, ...rest } = input;
117
+ return {
118
+ ...rest,
119
+ id,
120
+ role,
121
+ ...(createdAt === undefined ? {} : { createdAt: isoTimestamp(createdAt) }),
122
+ ...(authorPrincipalRef === undefined ? {} : { authorPrincipalRef }),
123
+ ...('asset' in input ? {} : { sha256: (0, digest_js_1.resourceDigest)(reviewableRepresentation(input)) }),
124
+ };
125
+ }
126
+ const CONTEXT_RELATIONS = Object.freeze({
127
+ parent: 'replies_to',
128
+ quoted: 'quotes',
129
+ context: 'contextualizes',
130
+ evidence: 'refers_to',
131
+ });
132
+ function normalisedAllegations(input) {
133
+ return input.map((entry) => (typeof entry === 'string' ? { code: entry } : entry));
134
+ }
135
+ /**
136
+ * Composes and VALIDATES a Case Envelope.
137
+ *
138
+ * The parse at the end is not belt-and-braces. Everything above assembles a
139
+ * document from caller data — a subject type, a text body, an asset digest —
140
+ * and the contract is where a bad one is caught. Catching it here means the
141
+ * integrator sees the field and the reason at the call site, in their own
142
+ * process, instead of reading a 422 out of a delivery worker's log an hour
143
+ * later.
144
+ */
145
+ function composeCaseEnvelope(input, composition) {
146
+ if (input.submittedAt === undefined && composition.environment === 'sandbox') {
147
+ throw new CrowdSourceReportInputError('A sandbox report must declare submittedAt: the environment travels in `source`, and `source` cannot be composed without a submission time this client would otherwise have to invent — which would make every retry of this report a 409.');
148
+ }
149
+ const allegations = normalisedAllegations(input.allegations);
150
+ const allegationCodes = allegations.map((allegation) => allegation.code);
151
+ const bindings = [];
152
+ const rememberPrincipal = (principal) => {
153
+ if (!bindings.some((binding) => binding.principalRef === principal.ref)) {
154
+ bindings.push(principal.binding);
155
+ }
156
+ return principal.ref;
157
+ };
158
+ const authorRef = input.subject.author === undefined
159
+ ? undefined
160
+ : rememberPrincipal(resolvePrincipal(input.subject.author, 'subject author'));
161
+ const reporterRef = input.reportedBy === undefined
162
+ ? undefined
163
+ : rememberPrincipal(resolvePrincipal(input.reportedBy, 'reporter'));
164
+ const subjectContent = typeof input.content === 'string'
165
+ ? { type: 'text', data: { text: input.content } }
166
+ : input.content;
167
+ const resources = [
168
+ composeResource(subjectContent, SUBJECT_RESOURCE_ID, 'subject', authorRef),
169
+ ];
170
+ const relations = [];
171
+ (input.attachments ?? []).forEach((attachment, index) => {
172
+ const id = `res_attachment_${index + 1}`;
173
+ resources.push(composeResource(attachment, id, 'attachment', authorRef));
174
+ relations.push({ from: SUBJECT_RESOURCE_ID, type: 'has_attachment', to: id });
175
+ });
176
+ (input.context ?? []).forEach((entry, index) => {
177
+ const id = `res_context_${index + 1}`;
178
+ const { role, ...resource } = entry;
179
+ resources.push(composeResource(resource, id, role, undefined));
180
+ relations.push(role === 'context'
181
+ ? { from: id, type: CONTEXT_RELATIONS[role], to: SUBJECT_RESOURCE_ID }
182
+ : { from: SUBJECT_RESOURCE_ID, type: CONTEXT_RELATIONS[role], to: id });
183
+ });
184
+ const privacy = resolvePrivacy(input.privacy, allegationCodes);
185
+ const envelope = {
186
+ schemaVersion: contracts_1.CASE_ENVELOPE_SCHEMA_VERSION,
187
+ applicationId: composition.applicationId,
188
+ externalReportId: input.externalReportId,
189
+ ...(input.submittedAt === undefined
190
+ ? {}
191
+ : {
192
+ source: {
193
+ environment: composition.environment,
194
+ submittedAt: isoTimestamp(input.submittedAt),
195
+ },
196
+ }),
197
+ subject: {
198
+ externalId: input.subject.externalId,
199
+ type: input.subject.type,
200
+ primaryResourceId: SUBJECT_RESOURCE_ID,
201
+ ...(input.subject.permalink === undefined ? {} : { permalink: input.subject.permalink }),
202
+ },
203
+ principalBindings: bindings,
204
+ resources,
205
+ relations,
206
+ allegations: allegations.map((allegation) => ({
207
+ code: allegation.code,
208
+ ...(allegation.details === undefined ? {} : { details: allegation.details }),
209
+ ...(reporterRef === undefined ? {} : { reporterPrincipalRef: reporterRef }),
210
+ })),
211
+ policy: input.policy ?? defaults_js_1.DEFAULT_POLICY,
212
+ privacy,
213
+ ...(input.urgency === undefined ? {} : { urgency: input.urgency }),
214
+ ...(input.metadata === undefined ? {} : { metadata: input.metadata }),
215
+ };
216
+ const parsed = contracts_1.CaseEnvelopeSchema.safeParse(envelope);
217
+ if (!parsed.success) {
218
+ throw new CrowdSourceReportInputError(`This report cannot be composed into a valid Case Envelope — ${parsed.error.issues
219
+ .map((issue) => `${issue.path.join('.') || '(root)'}: ${issue.message}`)
220
+ .join('; ')}`);
221
+ }
222
+ return parsed.data;
223
+ }
224
+ /**
225
+ * Privacy terms, with §7.5's routing rule as a floor the caller cannot lift.
226
+ *
227
+ * An explicit `allowCommunityReview: true` alongside an allegation §7.5 keeps
228
+ * away from a community jury is REFUSED, not corrected. Correcting it would
229
+ * leave the application believing it had asked for something it did not get,
230
+ * and the next thing built on that belief would be wrong too.
231
+ */
232
+ function resolvePrivacy(requested, allegationCodes) {
233
+ const base = (0, defaults_js_1.defaultPrivacy)(allegationCodes);
234
+ if (requested === undefined)
235
+ return base;
236
+ const forbidden = (0, defaults_js_1.allegationsForbiddingCommunityReview)(allegationCodes);
237
+ if (requested.allowCommunityReview === true && forbidden.length > 0) {
238
+ throw new CrowdSourceReportInputError(`A report alleging ${forbidden.join(', ')} cannot set allowCommunityReview: true — §7.5 routes this material to a specialist team, never to a community jury.`);
239
+ }
240
+ return {
241
+ ...base,
242
+ ...(requested.retentionDays === undefined ? {} : { retentionDays: requested.retentionDays }),
243
+ ...(requested.allowCommunityReview === undefined
244
+ ? {}
245
+ : { allowCommunityReview: requested.allowCommunityReview }),
246
+ ...(requested.containsPersonalData === undefined
247
+ ? {}
248
+ : { containsPersonalData: requested.containsPersonalData }),
249
+ ...(requested.sensitivityHint === undefined
250
+ ? {}
251
+ : { sensitivityHint: requested.sensitivityHint }),
252
+ };
253
+ }
254
+ /** Appendix D: the same report re-delivered must return the same `reportId`. */
255
+ function defaultIdempotencyKey(externalReportId) {
256
+ return `report.${externalReportId}`;
257
+ }
258
+ //# sourceMappingURL=envelope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"envelope.js","sourceRoot":"","sources":["../src/envelope.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,90 @@
1
+ /**
2
+ * The failures an integrator can observe, and the one question they all answer.
3
+ *
4
+ * §7.1 puts the durable retry path in the INTEGRATOR's outbox: a 2xx from their
5
+ * own application means the report is stored locally and will be delivered
6
+ * eventually, never that a synchronous call to CrowdSource succeeded. So the
7
+ * only thing an outbox worker needs from a failure is whether re-delivering the
8
+ * same payload can still succeed. That is `retryable`, and every error below
9
+ * answers it — an integrator branching on `instanceof` or on a status code is
10
+ * re-deriving something this class already knows.
11
+ *
12
+ * The distinction that matters most is 409. §10.5 gives it one meaning: the same
13
+ * `externalReportId` arrived with a different body. Retrying that forever never
14
+ * succeeds and the payload is the thing that has to change, so it is the one
15
+ * 4xx an outbox must stop on rather than back off from.
16
+ */
17
+ /**
18
+ * The machine-readable codes §10.5 assigns a meaning to.
19
+ *
20
+ * Declared here rather than imported because `@crowdsource.you/contracts`
21
+ * does not publish the HTTP error vocabulary — it publishes the documents that
22
+ * travel over HTTP. That is a gap worth closing in contracts rather than a
23
+ * decision to state the list twice: the backend has the same union in
24
+ * `http/apiError.ts`, and the two must not drift. Until it moves, this is the
25
+ * copy integrators compile against.
26
+ */
27
+ export declare const CROWDSOURCE_API_ERROR_CODES: readonly ["invalid_request", "unauthorized", "forbidden", "not_found", "conflict", "payload_too_large", "unprocessable_envelope", "rate_limited", "internal_error", "service_unavailable"];
28
+ export type CrowdSourceApiErrorCode = (typeof CROWDSOURCE_API_ERROR_CODES)[number];
29
+ export declare function isCrowdSourceApiErrorCode(value: unknown): value is CrowdSourceApiErrorCode;
30
+ /**
31
+ * The code to report when the response carried no usable one — a proxy, a load
32
+ * balancer or a gateway answering instead of the service.
33
+ */
34
+ export declare function apiErrorCodeForStatus(status: number): CrowdSourceApiErrorCode;
35
+ /** The base of every error this package throws. */
36
+ export declare class CrowdSourceError extends Error {
37
+ /** Whether re-delivering the same payload can still succeed. */
38
+ readonly retryable: boolean;
39
+ constructor(message: string, retryable: boolean, options?: {
40
+ cause?: unknown;
41
+ });
42
+ }
43
+ /**
44
+ * The client is not configured to be able to make the call.
45
+ *
46
+ * Never retryable: a missing service key, a malformed one or a base URL that is
47
+ * not a URL do not become correct by waiting.
48
+ */
49
+ export declare class CrowdSourceConfigurationError extends CrowdSourceError {
50
+ constructor(message: string);
51
+ }
52
+ /**
53
+ * The request never produced an HTTP response — DNS, connection, TLS, timeout,
54
+ * or an abort.
55
+ *
56
+ * Retryable, with one exception: an abort the CALLER asked for. Retrying that
57
+ * would ignore the instruction, so it is surfaced as not retryable and the
58
+ * caller decides what happens next.
59
+ */
60
+ export declare class CrowdSourceTransportError extends CrowdSourceError {
61
+ constructor(message: string, options?: {
62
+ cause?: unknown;
63
+ retryable?: boolean;
64
+ });
65
+ }
66
+ /**
67
+ * CrowdSource answered, and the answer was a refusal (§10.5).
68
+ *
69
+ * `code` is the machine-readable code from the response body when the service
70
+ * sent one. A proxy or load balancer that answers instead of the service does
71
+ * not, so it is derived from the status in that case rather than left undefined
72
+ * — an integrator switching on `code` should not have to handle "the 502 came
73
+ * from the ALB" as a separate shape.
74
+ */
75
+ export declare class CrowdSourceApiError extends CrowdSourceError {
76
+ readonly status: number;
77
+ readonly code: CrowdSourceApiErrorCode;
78
+ readonly details?: Readonly<Record<string, string | number | boolean>>;
79
+ constructor(input: {
80
+ status: number;
81
+ code: CrowdSourceApiErrorCode;
82
+ message: string;
83
+ details?: Readonly<Record<string, string | number | boolean>>;
84
+ });
85
+ /** True when this is §10.5's "external id reused with a different body". */
86
+ get isPayloadConflict(): boolean;
87
+ }
88
+ export declare function isCrowdSourceError(error: unknown): error is CrowdSourceError;
89
+ export declare function isCrowdSourceApiError(error: unknown): error is CrowdSourceApiError;
90
+ //# sourceMappingURL=errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;;;;;;;;;GASG;AACH,eAAO,MAAM,2BAA2B,4LAW9B,CAAC;AAEX,MAAM,MAAM,uBAAuB,GAAG,CAAC,OAAO,2BAA2B,CAAC,CAAC,MAAM,CAAC,CAAC;AAInF,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,uBAAuB,CAE1F;AAED;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,uBAAuB,CAuB7E;AAED,mDAAmD;AACnD,qBAAa,gBAAiB,SAAQ,KAAK;IACzC,gEAAgE;IAChE,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;gBAEhB,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAA;KAAE;CAK/E;AAED;;;;;GAKG;AACH,qBAAa,6BAA8B,SAAQ,gBAAgB;gBACrD,OAAO,EAAE,MAAM;CAG5B;AAED;;;;;;;GAOG;AACH,qBAAa,yBAA0B,SAAQ,gBAAgB;gBACjD,OAAO,EAAE,MAAM,EAAE,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,SAAS,CAAC,EAAE,OAAO,CAAA;KAAO;CAGpF;AAED;;;;;;;;GAQG;AACH,qBAAa,mBAAoB,SAAQ,gBAAgB;IACvD,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,uBAAuB,CAAC;IACvC,QAAQ,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;gBAE3D,KAAK,EAAE;QACjB,MAAM,EAAE,MAAM,CAAC;QACf,IAAI,EAAE,uBAAuB,CAAC;QAC9B,OAAO,EAAE,MAAM,CAAC;QAChB,OAAO,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;KAC/D;IAOD,4EAA4E;IAC5E,IAAI,iBAAiB,IAAI,OAAO,CAE/B;CACF;AAaD,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,gBAAgB,CAE5E;AAED,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,mBAAmB,CAElF"}
package/dist/errors.js ADDED
@@ -0,0 +1,151 @@
1
+ "use strict";
2
+ /**
3
+ * The failures an integrator can observe, and the one question they all answer.
4
+ *
5
+ * §7.1 puts the durable retry path in the INTEGRATOR's outbox: a 2xx from their
6
+ * own application means the report is stored locally and will be delivered
7
+ * eventually, never that a synchronous call to CrowdSource succeeded. So the
8
+ * only thing an outbox worker needs from a failure is whether re-delivering the
9
+ * same payload can still succeed. That is `retryable`, and every error below
10
+ * answers it — an integrator branching on `instanceof` or on a status code is
11
+ * re-deriving something this class already knows.
12
+ *
13
+ * The distinction that matters most is 409. §10.5 gives it one meaning: the same
14
+ * `externalReportId` arrived with a different body. Retrying that forever never
15
+ * succeeds and the payload is the thing that has to change, so it is the one
16
+ * 4xx an outbox must stop on rather than back off from.
17
+ */
18
+ Object.defineProperty(exports, "__esModule", { value: true });
19
+ exports.CrowdSourceApiError = exports.CrowdSourceTransportError = exports.CrowdSourceConfigurationError = exports.CrowdSourceError = exports.CROWDSOURCE_API_ERROR_CODES = void 0;
20
+ exports.isCrowdSourceApiErrorCode = isCrowdSourceApiErrorCode;
21
+ exports.apiErrorCodeForStatus = apiErrorCodeForStatus;
22
+ exports.isCrowdSourceError = isCrowdSourceError;
23
+ exports.isCrowdSourceApiError = isCrowdSourceApiError;
24
+ /**
25
+ * The machine-readable codes §10.5 assigns a meaning to.
26
+ *
27
+ * Declared here rather than imported because `@crowdsource.you/contracts`
28
+ * does not publish the HTTP error vocabulary — it publishes the documents that
29
+ * travel over HTTP. That is a gap worth closing in contracts rather than a
30
+ * decision to state the list twice: the backend has the same union in
31
+ * `http/apiError.ts`, and the two must not drift. Until it moves, this is the
32
+ * copy integrators compile against.
33
+ */
34
+ exports.CROWDSOURCE_API_ERROR_CODES = [
35
+ 'invalid_request',
36
+ 'unauthorized',
37
+ 'forbidden',
38
+ 'not_found',
39
+ 'conflict',
40
+ 'payload_too_large',
41
+ 'unprocessable_envelope',
42
+ 'rate_limited',
43
+ 'internal_error',
44
+ 'service_unavailable',
45
+ ];
46
+ const API_ERROR_CODE_SET = new Set(exports.CROWDSOURCE_API_ERROR_CODES);
47
+ function isCrowdSourceApiErrorCode(value) {
48
+ return typeof value === 'string' && API_ERROR_CODE_SET.has(value);
49
+ }
50
+ /**
51
+ * The code to report when the response carried no usable one — a proxy, a load
52
+ * balancer or a gateway answering instead of the service.
53
+ */
54
+ function apiErrorCodeForStatus(status) {
55
+ switch (status) {
56
+ case 400:
57
+ return 'invalid_request';
58
+ case 401:
59
+ return 'unauthorized';
60
+ case 403:
61
+ return 'forbidden';
62
+ case 404:
63
+ return 'not_found';
64
+ case 409:
65
+ return 'conflict';
66
+ case 413:
67
+ return 'payload_too_large';
68
+ case 422:
69
+ return 'unprocessable_envelope';
70
+ case 429:
71
+ return 'rate_limited';
72
+ case 503:
73
+ return 'service_unavailable';
74
+ default:
75
+ return 'internal_error';
76
+ }
77
+ }
78
+ /** The base of every error this package throws. */
79
+ class CrowdSourceError extends Error {
80
+ constructor(message, retryable, options) {
81
+ super(message, options);
82
+ this.name = new.target.name;
83
+ this.retryable = retryable;
84
+ }
85
+ }
86
+ exports.CrowdSourceError = CrowdSourceError;
87
+ /**
88
+ * The client is not configured to be able to make the call.
89
+ *
90
+ * Never retryable: a missing service key, a malformed one or a base URL that is
91
+ * not a URL do not become correct by waiting.
92
+ */
93
+ class CrowdSourceConfigurationError extends CrowdSourceError {
94
+ constructor(message) {
95
+ super(message, false);
96
+ }
97
+ }
98
+ exports.CrowdSourceConfigurationError = CrowdSourceConfigurationError;
99
+ /**
100
+ * The request never produced an HTTP response — DNS, connection, TLS, timeout,
101
+ * or an abort.
102
+ *
103
+ * Retryable, with one exception: an abort the CALLER asked for. Retrying that
104
+ * would ignore the instruction, so it is surfaced as not retryable and the
105
+ * caller decides what happens next.
106
+ */
107
+ class CrowdSourceTransportError extends CrowdSourceError {
108
+ constructor(message, options = {}) {
109
+ super(message, options.retryable ?? true, { cause: options.cause });
110
+ }
111
+ }
112
+ exports.CrowdSourceTransportError = CrowdSourceTransportError;
113
+ /**
114
+ * CrowdSource answered, and the answer was a refusal (§10.5).
115
+ *
116
+ * `code` is the machine-readable code from the response body when the service
117
+ * sent one. A proxy or load balancer that answers instead of the service does
118
+ * not, so it is derived from the status in that case rather than left undefined
119
+ * — an integrator switching on `code` should not have to handle "the 502 came
120
+ * from the ALB" as a separate shape.
121
+ */
122
+ class CrowdSourceApiError extends CrowdSourceError {
123
+ constructor(input) {
124
+ super(input.message, RETRYABLE_STATUSES.has(input.status));
125
+ this.status = input.status;
126
+ this.code = input.code;
127
+ this.details = input.details;
128
+ }
129
+ /** True when this is §10.5's "external id reused with a different body". */
130
+ get isPayloadConflict() {
131
+ return this.code === 'conflict';
132
+ }
133
+ }
134
+ exports.CrowdSourceApiError = CrowdSourceApiError;
135
+ /**
136
+ * The statuses a retry of the SAME payload can still resolve.
137
+ *
138
+ * 429 and 503 are the two §10.5 names for "come back later". 5xx is included
139
+ * because a defect on the service side is not a defect in the payload, and the
140
+ * idempotency key makes the retry free of duplicates either way. Every 4xx below
141
+ * 429 is excluded deliberately: a rejected envelope, a missing scope, a revoked
142
+ * credential and a payload conflict all stay rejected.
143
+ */
144
+ const RETRYABLE_STATUSES = new Set([408, 425, 429, 500, 502, 503, 504]);
145
+ function isCrowdSourceError(error) {
146
+ return error instanceof CrowdSourceError;
147
+ }
148
+ function isCrowdSourceApiError(error) {
149
+ return error instanceof CrowdSourceApiError;
150
+ }
151
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,74 @@
1
+ /**
2
+ * `GET /v1/cases/{id}` and `GET /v1/decisions/{id}` (§10.2).
3
+ *
4
+ * Both are look-ups by an id CrowdSource gave the application. There is no case
5
+ * search and there will not be one: "nobody chooses the case they review" is an
6
+ * invariant, and a list endpoint on the application API would be the first step
7
+ * towards a queue somebody browses.
8
+ *
9
+ * `decisions.get` is written against the route §10.2 defines. **The backend does
10
+ * not serve it yet** — nothing publishes decisions, because sortition, review
11
+ * and consensus are not built — so it answers 404 today. It is here because a
12
+ * client of a documented endpoint is not a stub, and because the webhook path
13
+ * (`case.decided`) is how an application learns about a decision anyway; this is
14
+ * the read-back for one it already has an id for.
15
+ */
16
+ import { DecisionSchema } from '@crowdsource.you/contracts';
17
+ import { z } from 'zod';
18
+ import { CrowdSourceTransportError } from './errors.js';
19
+ const CaseViewSchema = z.looseObject({
20
+ caseId: z.string(),
21
+ status: z.string(),
22
+ subject: z.looseObject({ externalId: z.string(), type: z.string() }),
23
+ policy: z.looseObject({ policySetId: z.string(), version: z.string() }),
24
+ taxonomyVersion: z.string(),
25
+ allegationCodes: z.array(z.string()),
26
+ reportCount: z.number(),
27
+ sensitivityClass: z.string(),
28
+ currentRevision: z.number(),
29
+ createdAt: z.string(),
30
+ updatedAt: z.string(),
31
+ });
32
+ export class Cases {
33
+ constructor(transport) {
34
+ this.transport = transport;
35
+ }
36
+ async get(caseId, options = {}) {
37
+ const response = await this.transport.request({
38
+ method: 'GET',
39
+ path: `/v1/cases/${encodeURIComponent(caseId)}`,
40
+ signal: options.signal,
41
+ });
42
+ const parsed = CaseViewSchema.safeParse(response);
43
+ if (!parsed.success) {
44
+ throw new CrowdSourceTransportError('CrowdSource answered with a case this client does not recognise.', { retryable: false, cause: parsed.error });
45
+ }
46
+ return parsed.data;
47
+ }
48
+ }
49
+ export class Decisions {
50
+ constructor(transport) {
51
+ this.transport = transport;
52
+ }
53
+ /**
54
+ * Reads one immutable revision of a decision.
55
+ *
56
+ * A published revision is never edited (Appendix F); a later revision
57
+ * supersedes it and carries `supersedesDecisionId`. So a decision read twice
58
+ * is byte-identical, and an application that cached one never needs to
59
+ * invalidate it — it needs to notice a `decision.corrected` webhook.
60
+ */
61
+ async get(decisionId, options = {}) {
62
+ const response = await this.transport.request({
63
+ method: 'GET',
64
+ path: `/v1/decisions/${encodeURIComponent(decisionId)}`,
65
+ signal: options.signal,
66
+ });
67
+ const parsed = DecisionSchema.safeParse(response);
68
+ if (!parsed.success) {
69
+ throw new CrowdSourceTransportError('CrowdSource answered with a decision this client does not recognise.', { retryable: false, cause: parsed.error });
70
+ }
71
+ return parsed.data;
72
+ }
73
+ }
74
+ //# sourceMappingURL=cases.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cases.js","sourceRoot":"","sources":["../../src/cases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,cAAc,EAAoC,MAAM,4BAA4B,CAAC;AAC9F,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAC;AAyBxD,MAAM,cAAc,GAAG,CAAC,CAAC,WAAW,CAAC;IACnC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE;IAClB,OAAO,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;IACpE,MAAM,EAAE,CAAC,CAAC,WAAW,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;IACvE,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE;IAC3B,eAAe,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;IACpC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE;IAC5B,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE;IAC3B,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;CACtB,CAAC,CAAC;AAMH,MAAM,OAAO,KAAK;IAGhB,YAAY,SAAoB;QAC9B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,MAAc,EAAE,UAAuB,EAAE;QACjD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAU;YACrD,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,aAAa,kBAAkB,CAAC,MAAM,CAAC,EAAE;YAC/C,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,yBAAyB,CACjC,kEAAkE,EAClE,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAC1C,CAAC;QACJ,CAAC;QACD,OAAO,MAAM,CAAC,IAAI,CAAC;IACrB,CAAC;CACF;AAED,MAAM,OAAO,SAAS;IAGpB,YAAY,SAAoB;QAC9B,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,GAAG,CAAC,UAAkB,EAAE,UAAuB,EAAE;QACrD,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAU;YACrD,MAAM,EAAE,KAAK;YACb,IAAI,EAAE,iBAAiB,kBAAkB,CAAC,UAAU,CAAC,EAAE;YACvD,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAC;QAEH,MAAM,MAAM,GAAG,cAAc,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAClD,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;YACpB,MAAM,IAAI,yBAAyB,CACjC,sEAAsE,EACtE,EAAE,SAAS,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,EAAE,CAC1C,CAAC;QACJ,CAAC;QACD,OAAO,MAAM,CAAC,IAAI,CAAC;IACrB,CAAC;CACF"}