@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
package/README.md ADDED
@@ -0,0 +1,571 @@
1
+ # @crowdsource.you/core
2
+
3
+ The CrowdSource integration, in one package. The TypeScript client for the
4
+ moderation API is the root import; the Express webhook receiver, the
5
+ transactional outbox and the test sandbox are entry points of the same package.
6
+
7
+ ## The entry points
8
+
9
+ | Import | What it is | What it needs installed |
10
+ | --- | --- | --- |
11
+ | `@crowdsource.you/core` | The API client: compose a Case Envelope, file a report, read a case or a decision, register a webhook endpoint. | nothing beyond `@crowdsource.you/contracts` |
12
+ | `@crowdsource.you/core/express` | The webhook receiver: raw-body capture, HMAC verification, replay protection, typed events. | `express` |
13
+ | `@crowdsource.you/core/outbox` | The application half: a transactional outbox, delivery with retries, decision application and idempotent enforcement. | `express`, `@oxy.so/db`, `drizzle-orm`, `postgres` |
14
+ | `@crowdsource.you/core/outbox/postgres` | The PostgreSQL store behind `/outbox`: table definitions and the store itself. | as above |
15
+ | `@crowdsource.you/core/testing` | Fixtures, a webhook simulator and an in-process sandbox. | nothing beyond contracts |
16
+
17
+ **Importing the root pulls in none of `express`, `drizzle-orm`, `postgres` or
18
+ `@oxy.so/db`.** They are OPTIONAL peer dependencies, reached only through
19
+ `/express` and `/outbox`, so an application that files reports and nothing else
20
+ installs a client and a contracts package and stops there. That is the whole
21
+ reason the receiver and the outbox are subpaths rather than a second package:
22
+ there is no version of this package that can disagree with itself.
23
+
24
+ `@crowdsource.you/contracts` stays a package of its own, and is a **peer
25
+ dependency** here, so you declare it and own its version. That is deliberate:
26
+ every type these entry points return is defined there, and if two copies existed
27
+ in one tree the compiler would report nothing at all while every delivery failed
28
+ at runtime. One copy, chosen by you. It is also the half a React Native UI can
29
+ import without a server-only client landing in the phone bundle.
30
+
31
+ ## What used to be called what
32
+
33
+ Five packages under `@oxy.so` became two under `@crowdsource.you`. The code did
34
+ not change and no export was renamed; the same version number carries the same
35
+ code under the new name.
36
+
37
+ | Before | Now |
38
+ | --- | --- |
39
+ | `@oxy.so/crowdsource-contracts` | `@crowdsource.you/contracts` |
40
+ | `@oxy.so/crowdsource` | `@crowdsource.you/core` |
41
+ | `@oxy.so/crowdsource-express` | `@crowdsource.you/core/express` |
42
+ | `@oxy.so/crowdsource-app` | `@crowdsource.you/core/outbox` |
43
+ | `@oxy.so/crowdsource-app/postgres` | `@crowdsource.you/core/outbox/postgres` |
44
+ | `@oxy.so/crowdsource-testing` | `@crowdsource.you/core/testing` |
45
+
46
+ The old names are not published as shims and never will be: six abandoned
47
+ packages on the registry cost every future reader more than six migration pull
48
+ requests cost us once.
49
+
50
+ ## Installing
51
+
52
+ ```bash
53
+ bun add @crowdsource.you/core @crowdsource.you/contracts
54
+ ```
55
+
56
+ Add `express` if you receive webhooks, and `@oxy.so/db drizzle-orm postgres` if
57
+ you use the outbox.
58
+
59
+ ## The client
60
+
61
+ ## The whole integration
62
+
63
+ ```bash
64
+ CROWDSOURCE_SERVICE_KEY=app_…:csk_…:…
65
+ ```
66
+
67
+ ```ts
68
+ import { CrowdSource } from '@crowdsource.you/core';
69
+
70
+ const crowdsource = new CrowdSource();
71
+
72
+ await crowdsource.reports.create({
73
+ externalReportId: report.id,
74
+ reportedBy: { oxyUserId: session.sub },
75
+ subject: {
76
+ externalId: post.id,
77
+ type: 'social.post',
78
+ author: { oxyUserId: post.authorId },
79
+ },
80
+ content: post.text,
81
+ allegations: ['harassment.targeted_abuse'],
82
+ });
83
+ ```
84
+
85
+ One environment variable and the object being reported. That is the whole
86
+ surface for the common case.
87
+
88
+ ## What the client fills in, so you do not have to
89
+
90
+ | Composed for you | From |
91
+ | --- | --- |
92
+ | `applicationId` | the service key — there is no option to pass one |
93
+ | the Case Envelope, its resource ids and its relations | the subject, content, attachments and context you described |
94
+ | `sha256` on every inline resource | the content itself |
95
+ | principal bindings and their pseudonymous refs | the identities you named, hashed |
96
+ | the identity binding proof (§11.14) | the Oxy `sub` — Sign in with Oxy already produced it |
97
+ | `policy` | `DEFAULT_POLICY`, a pinned immutable version |
98
+ | `privacy` | 30 days (§13.6), and §7.5's community-review restrictions |
99
+ | `Idempotency-Key` | `report.<externalReportId>` (Appendix D) |
100
+ | base URL, timeouts, bounded retries | defaults |
101
+
102
+ Anything in that table can be overridden per report. Nothing in it has to be.
103
+
104
+ ## Environment
105
+
106
+ | Variable | |
107
+ | --- | --- |
108
+ | `CROWDSOURCE_SERVICE_KEY` | Required for a third party. The one value an integration configures. An Oxy service sets `oxyToken` instead and configures nothing — see "Oxy's own services" below. |
109
+ | `CROWDSOURCE_BASE_URL` | Optional. Overrides the service host — set it only to point at a local backend. `http://` is accepted for `localhost` and refused for anything else, because a service credential sent in clear is a credential you have to rotate. |
110
+
111
+ There is **no** `CROWDSOURCE_APP_ID` and there never will be. The application a
112
+ report belongs to is read off the credential; see "The service key" below.
113
+
114
+ ## Rules
115
+
116
+ - **A report is delivered from your own outbox, never from a request handler.**
117
+ §7.1: a 2xx from your application means the report is stored locally with a
118
+ durable retry path — not that a call to CrowdSource succeeded. Every error this
119
+ client throws carries `retryable`, which is the only thing an outbox worker
120
+ needs from it.
121
+ - **`applicationId` comes from the credential.** It is not an option on the
122
+ client, not a field on a report, and not something an envelope input can
123
+ carry.
124
+ - **Re-delivering the same report is safe.** The same `externalReportId` with a
125
+ *different* body is a 409, is not retryable, and means the payload has to
126
+ change.
127
+ - **Evidence never gets a durable URL from CrowdSource.** An asset carries a bare
128
+ Oxy `fileId`; no method here returns a link to bytes (§12.10). `asset.url` is
129
+ provenance only and is never fetched.
130
+ - **Server-side only.** A service credential is your whole moderation stream;
131
+ this package depends on `node:crypto` and must never reach a browser or a
132
+ mobile bundle.
133
+
134
+ ## Oxy's own services
135
+
136
+ Mention, Alia, Homiio and the rest hold no service key. They present the Oxy
137
+ service token their own infrastructure already issues, and CrowdSource resolves
138
+ the tenant from the Oxy application it names:
139
+
140
+ ```ts
141
+ const crowdsource = new CrowdSource({
142
+ oxyToken: () => oxyServices.getServiceToken(),
143
+ });
144
+ ```
145
+
146
+ `oxyToken` is asked once per request attempt, so a cached token refreshed on
147
+ expiry is the expected shape — which is what `getServiceToken()` returns. With it
148
+ set, `CROWDSOURCE_SERVICE_KEY` is neither needed nor read, and there is nothing
149
+ to rotate, store or leak.
150
+
151
+ The token names an *Oxy* application, so there is no `applicationId` to read off
152
+ it. The client asks `GET /v1/applications/me` once on first use and remembers the
153
+ answer, which is why `applicationId` is a promise on this path and a string on
154
+ the other.
155
+
156
+ This is not a way around registration: the Oxy application must be bound to a
157
+ CrowdSource one first, and an unbound token authenticates nothing. Third parties
158
+ keep the service key — they run where Oxy cannot vouch for them.
159
+
160
+ ## The service key
161
+
162
+ CrowdSource issues three values together — the application, the credential id
163
+ and the secret. The client takes them as one opaque string,
164
+ `applicationId:credentialId:secret`, so an integration configures one variable
165
+ and the client reads the application off the credential rather than being told
166
+ it. `formatServiceKey()` builds that string from what
167
+ `issueApplicationCredential` returns.
168
+
169
+ ## Attaching an image, a video or a document
170
+
171
+ Upload the bytes through the **Oxy media chokepoint** with your application's own
172
+ Oxy credentials, then pass the bare file id:
173
+
174
+ ```ts
175
+ await crowdsource.reports.create({
176
+ externalReportId: report.id,
177
+ subject: { externalId: post.id, type: 'social.post' },
178
+ content: post.text,
179
+ attachments: [
180
+ {
181
+ type: 'image',
182
+ asset: {
183
+ fileId: post.imageFileId, // bare Oxy file id — never a URL
184
+ mimeType: 'image/jpeg',
185
+ sha256: `sha256:${digestOf(bytes)}`,
186
+ url: post.remoteImageUrl, // optional provenance. Never fetched.
187
+ },
188
+ },
189
+ ],
190
+ allegations: ['harassment.targeted_abuse'],
191
+ });
192
+ ```
193
+
194
+ **CrowdSource has no upload route of its own, and that is deliberate.** Evidence
195
+ lives behind the one Oxy media chokepoint the whole ecosystem uses, so there is no
196
+ second place for bytes to be, no presigned URL to leak and no bucket to configure.
197
+ Earlier releases shipped an `uploads` client for a presigned flow that was
198
+ superseded before it was ever built; it is gone.
199
+
200
+ `asset.url` is a **provenance record and never a fetch target**. A federated
201
+ post's image genuinely lives elsewhere, so recording where it was found is useful
202
+ — but nothing resolves it. Fetching it would tell that host exactly when its
203
+ content is under review, and would deliver live bytes instead of the version §5.6
204
+ requires the case to pin.
205
+
206
+ Note `asset.sha256` is required, so an application always already holds the bytes
207
+ it is reporting. Putting them through the chokepoint asks for nothing new.
208
+
209
+ `reports.create`, `reports.get`, `cases.get`, `decisions.get`,
210
+ `webhookEndpoints.register` and `webhookEndpoints.rotateSecret` are all served.
211
+
212
+ ## Registering the webhook your decisions arrive on
213
+
214
+ A decision reaches an application over a webhook, not by polling — see
215
+ `@crowdsource.you/core/express`. Tell CrowdSource where to deliver, and store the
216
+ secret it mints:
217
+
218
+ ```ts
219
+ const endpoint = await crowdsource.webhookEndpoints.register({
220
+ url: 'https://example.com/webhooks/crowdsource',
221
+ eventTypes: ['case.decided'],
222
+ });
223
+
224
+ if (endpoint.secret) {
225
+ // The ONLY time this value exists outside CrowdSource. Persist it now, as
226
+ // CROWDSOURCE_WEBHOOK_SECRET, before doing anything else.
227
+ await secrets.put('CROWDSOURCE_WEBHOOK_SECRET', endpoint.secret.value);
228
+ }
229
+ ```
230
+
231
+ `secret` is present only when this call minted one. Re-registering an existing
232
+ URL returns the endpoint with **no** secret, which is what makes this safe to run
233
+ on every boot — it will never invalidate the secret your running process is
234
+ verifying with. The corollary is that re-registering cannot *recover* a secret
235
+ you failed to store:
236
+
237
+ ```ts
238
+ const rotated = await crowdsource.webhookEndpoints.rotateSecret(endpoint.webhookEndpointId, {
239
+ overlapSeconds: 28_800, // 0 for an immediate cutover, which is what a leak needs
240
+ });
241
+ // Serve both until rotated.previousSecret.expiresAt and no delivery is dropped.
242
+ ```
243
+
244
+ The credential needs the `crowdsource:webhooks:manage` scope. There is no list,
245
+ read-back or delete route — the API serves exactly these two — so an integration
246
+ cannot currently enumerate what it has registered.
247
+
248
+ ---
249
+
250
+ # `@crowdsource.you/core/express`
251
+
252
+ Receiving CrowdSource webhooks, safely, in Express.
253
+
254
+ ## The whole integration
255
+
256
+ ```bash
257
+ CROWDSOURCE_WEBHOOK_SECRET=…
258
+ ```
259
+
260
+ ```ts
261
+ import { crowdsourceWebhooks } from '@crowdsource.you/core/express';
262
+
263
+ app.post('/webhooks/crowdsource', crowdsourceWebhooks({
264
+ on: {
265
+ 'case.decided': async (event) => {
266
+ await moderationQueue.add(event.id, event.data);
267
+ },
268
+ },
269
+ }));
270
+ ```
271
+
272
+ No `express.raw`, no body-parser ordering, no secret plumbing, no signature code.
273
+ `event` is narrowed to `case.decided` and its `data.decision` is a typed
274
+ `Decision`.
275
+
276
+ `express` is an optional peer (`>=4.18.0 <6`) — optional because a consumer that
277
+ only files reports imports the root and never reaches this entry point, and
278
+ installing a web framework to do that would be absurd. Reaching `/express`
279
+ without `express` installed fails at import with a module-not-found, which is the
280
+ loud version of that trade.
281
+
282
+ ## Where the secret comes from
283
+
284
+ `CROWDSOURCE_WEBHOOK_SECRET` is minted **once**, by the response to
285
+ `crowdsource.webhookEndpoints.register(...)` — the call that tells CrowdSource
286
+ where to deliver:
287
+
288
+ ```ts
289
+ const endpoint = await crowdsource.webhookEndpoints.register({
290
+ url: 'https://example.com/webhooks/crowdsource',
291
+ eventTypes: ['case.decided'],
292
+ });
293
+ endpoint.secret?.value; // store it now; nothing returns it again
294
+ ```
295
+
296
+ Re-registering the same URL mints nothing, so it cannot recover a secret you
297
+ dropped — `crowdsource.webhookEndpoints.rotateSecret()` is what does.
298
+
299
+ ## Environment
300
+
301
+ | Variable | |
302
+ | --- | --- |
303
+ | `CROWDSOURCE_WEBHOOK_SECRET` | The active signing secret. Also settable as the `secret` option. |
304
+ | `CROWDSOURCE_WEBHOOK_SECRET_PREVIOUS` | The secret being retired. Set it during a rotation overlap — both are accepted while it is present, which is what makes a rotation drop nothing. Clear it after `previousSecret.expiresAt`. Also settable as the `previousSecret` option. |
305
+
306
+ ## Why there is no raw-body step for you to get wrong
307
+
308
+ The likeliest way to ship a broken webhook receiver is to verify a signature over
309
+ `JSON.stringify(req.body)`. It passes every payload a developer writes by hand
310
+ and fails on the first real delivery whose formatting differs — or, worse,
311
+ accepts a forged body that happens to re-serialise identically.
312
+
313
+ So this middleware reads the request stream itself, and when something upstream
314
+ already consumed it — `express.json()` mounted globally, which is the normal
315
+ shape of an Express app — it **refuses** through your error handler instead of
316
+ reconstructing the bytes. `express.raw()` ahead of it and the
317
+ `express.json({ verify })` idiom are both recognised and supported.
318
+
319
+ ## What it guarantees
320
+
321
+ | | |
322
+ | --- | --- |
323
+ | Signature | HMAC-SHA256 over `timestamp + "." + rawBody`, compared with `timingSafeEqual` (§10.8) |
324
+ | Freshness | ±5 minutes, in **both** directions |
325
+ | Replay | one claim per event id; a handler that throws releases it so §10.9's retry still works |
326
+ | Rotation | `previousSecret` is accepted alongside the active one, so a rotation drops nothing |
327
+ | Forward compatibility | an event type this integration does not handle is acknowledged and ignored (§10.11) |
328
+ | Privacy | `onRejected` gets the reason and nothing else — never a body, header or signature |
329
+
330
+ A refused delivery answers 401 and never 2xx, so it stays on the sender's retry
331
+ schedule rather than being retired as processed.
332
+
333
+ ## Deduplication across instances
334
+
335
+ The default store is in-process. Two instances behind a load balancer each keep
336
+ their own, so a redelivery landing on the other instance is not deduplicated.
337
+ That is usually fine — §7.6 makes the application responsible for recording what
338
+ it did about a decision, so enforcement should be idempotent anyway. If yours is
339
+ not, pass a shared `store` (Redis, your own database) implementing
340
+ `claim`/`release`.
341
+
342
+ ## Testing it
343
+
344
+ `@crowdsource.you/core/testing`'s simulator delivers genuinely signed events, and
345
+ can deliver stale, forged and tampered ones on purpose. Asserting that your
346
+ receiver **refuses** those is the half of a webhook test that proves something.
347
+
348
+ ---
349
+
350
+ # `@crowdsource.you/core/outbox`
351
+
352
+ The application-side CrowdSource integration for PostgreSQL applications. It
353
+ stores a report and its outbox event atomically, delivers reports with retries,
354
+ verifies signed webhook bodies, applies revisions in order and records reversible
355
+ enforcement exactly once.
356
+
357
+ This entry point is PostgreSQL-only. The former `/mongoose` entry point was
358
+ removed before the scope rename; the package does not install, import or publish
359
+ a MongoDB driver.
360
+
361
+ ## Install
362
+
363
+ ```sh
364
+ bun add @crowdsource.you/core @crowdsource.you/contracts \
365
+ @oxy.so/db drizzle-orm postgres express
366
+ ```
367
+
368
+ The four runtime peers are optional on the package, so this is the line that
369
+ makes them real. A consumer that never imports `/outbox` installs none of them.
370
+
371
+ ## Schema and store
372
+
373
+ The adopting application owns its report table. Spread the supplied moderation
374
+ columns into that table and use the three package-owned tables for the outbox,
375
+ webhook event ledger and enforcement ledger.
376
+
377
+ ```ts
378
+ import postgres from 'postgres';
379
+ import { drizzle } from 'drizzle-orm/postgres-js';
380
+ import { pgTable, text } from 'drizzle-orm/pg-core';
381
+ import { DATABASE_CASING } from '@oxy.so/db';
382
+ import {
383
+ moderationReportColumns,
384
+ moderationReportTableExtras,
385
+ moderationTables,
386
+ postgresModerationStore,
387
+ } from '@crowdsource.you/core/outbox/postgres';
388
+
389
+ const REPORT_MODERATION = {
390
+ reportedTypes: ['listing', 'review'],
391
+ categories: ['spam', 'harassment'],
392
+ } as const;
393
+
394
+ const reports = pgTable(
395
+ 'reports',
396
+ {
397
+ ...moderationReportColumns(REPORT_MODERATION),
398
+ legacyStatus: text('legacy_status'),
399
+ },
400
+ moderationReportTableExtras(REPORT_MODERATION),
401
+ );
402
+
403
+ const moderation = moderationTables({
404
+ enforcementActions: ['restrict', 'restore', 'review', 'none'] as const,
405
+ });
406
+
407
+ const client = postgres(process.env.DATABASE_URL ?? '', { max: 10 });
408
+ const db = drizzle(client, {
409
+ casing: DATABASE_CASING,
410
+ schema: { reports, ...moderation },
411
+ });
412
+
413
+ const store = postgresModerationStore({
414
+ db,
415
+ reportTable: reports,
416
+ tables: moderation,
417
+ });
418
+ ```
419
+
420
+ Generate and apply DDL from the adopter's complete Drizzle schema before the
421
+ first write. `store.ensureSchema()` validates the required indexes and checks; it
422
+ does not replace migrations.
423
+
424
+ ## Integration
425
+
426
+ ```ts
427
+ import express from 'express';
428
+ import { createModerationIntegration } from '@crowdsource.you/core/outbox';
429
+
430
+ const integration = createModerationIntegration({
431
+ store,
432
+ crowdSource: {
433
+ enabled: true,
434
+ serviceKey: process.env.CROWDSOURCE_SERVICE_KEY,
435
+ webhookSecret: process.env.CROWDSOURCE_WEBHOOK_SECRET,
436
+ enforcementMode: 'observe',
437
+ },
438
+ subjects: [listingSubjectProvider(), reviewSubjectProvider()],
439
+ taxonomy: { version: '2026.07', allegationsFor },
440
+ enforcement: commerceEnforcement,
441
+ logger,
442
+ });
443
+
444
+ await store.ensureSchema();
445
+
446
+ const app = express();
447
+ app.use('/webhooks', integration.webhookRouter());
448
+ app.use(express.json());
449
+ integration.dispatcher.start();
450
+ ```
451
+
452
+ Mount the webhook router before `express.json()`: CrowdSource verifies the exact
453
+ bytes received. The router refuses a request whose body was already parsed.
454
+
455
+ ## Required guarantees
456
+
457
+ - Every application-domain mutation and its outbox row use the same Drizzle
458
+ transaction. A pool handle is rejected by the outbox store.
459
+ - Delivery and webhook event IDs are idempotency keys. Retrying does not create a
460
+ second row or a second enforcement effect.
461
+ - Claims use `FOR UPDATE SKIP LOCKED` and bounded leases, so concurrent workers do
462
+ not process one row twice or wait behind a locked row.
463
+ - PostgreSQL does not provide TTL indexes. Schedule sweeps for
464
+ `moderationExpirySweepTargets()` and retain the supplied expiry indexes.
465
+ - Never log report content, webhook secrets or provider credentials.
466
+
467
+ ## Migrating an adopter's data
468
+
469
+ Do not upgrade first. The repository runbook
470
+ [`../../docs/runbooks/crowdsource-app-postgres-cutover.md`](../../docs/runbooks/crowdsource-app-postgres-cutover.md)
471
+ defines the fail-closed sequence and evidence manifest. The important boundary
472
+ is simple: export with the old application release, import into a separately
473
+ named empty PostgreSQL database, reconcile counts and canonical SHA-256 digests,
474
+ then deploy the PostgreSQL application release. This package cannot infer an
475
+ adopter's custom report collection, primary key or extra columns, so it does not
476
+ ship a data copier that guesses them.
477
+
478
+ ---
479
+
480
+ # `@crowdsource.you/core/testing`
481
+
482
+ Fixtures, a webhook simulator and an in-process sandbox, so an application can
483
+ integrate against CrowdSource before a jury has ever sat.
484
+
485
+ ## The full path, without real juries or real effects
486
+
487
+ ```ts
488
+ import { CrowdSource } from '@crowdsource.you/core';
489
+ import { createCrowdSourceSandbox } from '@crowdsource.you/core/testing';
490
+
491
+ const sandbox = createCrowdSourceSandbox();
492
+ const crowdsource = new CrowdSource({
493
+ serviceKey: sandbox.serviceKey,
494
+ baseUrl: sandbox.baseUrl,
495
+ fetch: sandbox.fetch,
496
+ });
497
+
498
+ // The sandbox signs with its OWN secret. Point the receiver at it, or every
499
+ // delivery below is refused with `signature_mismatch` and the test looks broken.
500
+ process.env.CROWDSOURCE_WEBHOOK_SECRET = sandbox.webhookSecret;
501
+
502
+ const { caseId } = await crowdsource.reports.create({ /* … */ });
503
+
504
+ const decision = sandbox.decide(caseId, { outcome: 'violation' });
505
+ const event = sandbox.eventFor(decision);
506
+ await sandbox.deliver('http://localhost:3000/webhooks/crowdsource', event);
507
+ ```
508
+
509
+ `eventFor` mints a fresh event id on every call, so hold the event if you mean to
510
+ test a REDELIVERY — calling it twice is two different events, and a receiver is
511
+ right to handle both.
512
+
513
+ The report goes through the **real** client — real envelope composition, real
514
+ idempotency key, real error mapping — and the webhook that comes back is
515
+ **genuinely signed**, so the receiver under test is the receiver that will run in
516
+ production. Only the jury is stood in for.
517
+
518
+ ## Asserting your receiver says no
519
+
520
+ ```ts
521
+ import { WebhookSimulator, caseDecidedEventFixture } from '@crowdsource.you/core/testing';
522
+
523
+ const simulator = new WebhookSimulator({ secret, url });
524
+
525
+ await simulator.deliver(caseDecidedEventFixture()); // 200
526
+ await simulator.deliver(caseDecidedEventFixture(), { expired: true }); // must be refused
527
+ await simulator.deliver(caseDecidedEventFixture(), { wrongSecret: 'x' }); // must be refused
528
+ await simulator.deliver(caseDecidedEventFixture(), { tamperedBody: '…' });// must be refused
529
+ ```
530
+
531
+ A suite that only ever sends valid deliveries proves the receiver can say yes.
532
+
533
+ ## What the sandbox actually enforces
534
+
535
+ The rules an integration's code depends on, faithfully: `applicationId` from the
536
+ credential, an idempotency key that returns the same `reportId`, a 409 for a
537
+ reused `externalReportId` with a changed body, §7.3's "two reports about the same
538
+ version of the same content are one case", and a decision that supersedes rather
539
+ than edits.
540
+
541
+ It is **not** the service. It holds nothing between processes, it answers 404 for
542
+ routes the deployed backend does not serve either, and where it and the backend
543
+ disagree the backend is right.
544
+
545
+ ## Rules
546
+
547
+ - Fixtures are synthetic. Real reported material, real evidence and real reviewer
548
+ identities never ship in a test package.
549
+ - Every fixture is validated against the published contracts as it is built. One
550
+ that no longer validates is a failure, not something to loosen: it is how an
551
+ integrator learns a contract moved.
552
+
553
+ ---
554
+
555
+ ## Verification
556
+
557
+ ```sh
558
+ bun run --cwd packages/core lint
559
+ bun run --cwd packages/core build
560
+ CROWDSOURCE_APP_TEST_POSTGRES_URL=postgres://... \
561
+ bun run --cwd packages/core test
562
+ bun run check:outbox-postgres-only
563
+ ```
564
+
565
+ `CROWDSOURCE_APP_TEST_POSTGRES_URL` keeps the name it had when the outbox was its
566
+ own package: only the `/outbox` suite reads it, it is the same server the compose
567
+ file starts, and a rename would silently strand an exported value in somebody's
568
+ shell. The storage behaviour suite runs against PostgreSQL 17, including
569
+ transaction rollback, concurrent claims, idempotent enqueue, revision order and
570
+ enforcement reversal. The invariant mutation runner removes each load-bearing
571
+ guard and requires the named test to fail.
@@ -0,0 +1,66 @@
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 { type Decision, type TaxonomyCode } from '@crowdsource.you/contracts';
17
+ import type { Transport } from './transport.js';
18
+ /**
19
+ * The projection §10.2 returns for a case.
20
+ *
21
+ * Deliberately not the case document. Priority score, review pool and reporter
22
+ * fingerprints never leave the service — an application that could read its own
23
+ * cases' priority could learn which signals move it.
24
+ */
25
+ export interface CaseView {
26
+ readonly caseId: string;
27
+ readonly status: string;
28
+ readonly subject: {
29
+ readonly externalId: string;
30
+ readonly type: string;
31
+ };
32
+ readonly policy: {
33
+ readonly policySetId: string;
34
+ readonly version: string;
35
+ };
36
+ readonly taxonomyVersion: string;
37
+ readonly allegationCodes: readonly (TaxonomyCode | (string & {}))[];
38
+ /** How many reports merged into this case. §7.3: many reports, one case. */
39
+ readonly reportCount: number;
40
+ readonly sensitivityClass: string;
41
+ readonly currentRevision: number;
42
+ readonly createdAt: string;
43
+ readonly updatedAt: string;
44
+ }
45
+ export interface ReadOptions {
46
+ readonly signal?: AbortSignal;
47
+ }
48
+ export declare class Cases {
49
+ private readonly transport;
50
+ constructor(transport: Transport);
51
+ get(caseId: string, options?: ReadOptions): Promise<CaseView>;
52
+ }
53
+ export declare class Decisions {
54
+ private readonly transport;
55
+ constructor(transport: Transport);
56
+ /**
57
+ * Reads one immutable revision of a decision.
58
+ *
59
+ * A published revision is never edited (Appendix F); a later revision
60
+ * supersedes it and carries `supersedesDecisionId`. So a decision read twice
61
+ * is byte-identical, and an application that cached one never needs to
62
+ * invalidate it — it needs to notice a `decision.corrected` webhook.
63
+ */
64
+ get(decisionId: string, options?: ReadOptions): Promise<Decision>;
65
+ }
66
+ //# sourceMappingURL=cases.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cases.d.ts","sourceRoot":"","sources":["../src/cases.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAkB,KAAK,QAAQ,EAAE,KAAK,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAI9F,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAEhD;;;;;;GAMG;AACH,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,OAAO,EAAE;QAAE,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;KAAE,CAAC;IACzE,QAAQ,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAC5E,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,eAAe,EAAE,SAAS,CAAC,YAAY,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;IACpE,4EAA4E;IAC5E,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAgBD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED,qBAAa,KAAK;IAChB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;gBAE1B,SAAS,EAAE,SAAS;IAI1B,GAAG,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC;CAgBxE;AAED,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;gBAE1B,SAAS,EAAE,SAAS;IAIhC;;;;;;;OAOG;IACG,GAAG,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,QAAQ,CAAC;CAgB5E"}