@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,45 @@
1
+ /**
2
+ * Idempotency by event id (§10.8: "store the processed event id").
3
+ *
4
+ * A delivery is retried on the schedule in §10.9 — six times over 24 hours —
5
+ * and a retry can also happen because the receiver's 2xx was lost rather than
6
+ * because it failed. So the same event WILL arrive twice at a healthy receiver,
7
+ * and "did I already do this?" is the only thing standing between that and a
8
+ * piece of content being removed twice or a user being suspended twice.
9
+ *
10
+ * The interface is claim/release rather than a "seen?" check, because the
11
+ * obvious design is wrong in a way that is hard to see. Recording the id BEFORE
12
+ * the handler runs makes a handler failure permanent: every retry is deduped
13
+ * away and the work is lost silently, which is the worst possible outcome for a
14
+ * moderation decision. Recording it AFTER lets two concurrent deliveries of the
15
+ * same event both run. Claiming before and releasing on failure gets both: one
16
+ * in flight, and a failure still retryable.
17
+ */
18
+ export interface ProcessedEventStore {
19
+ /** True when this call took the claim; false when the event is already held. */
20
+ claim(eventId: string): boolean | Promise<boolean>;
21
+ /** Gives the claim back so a redelivery can be processed. */
22
+ release(eventId: string): void | Promise<void>;
23
+ }
24
+ export interface MemoryProcessedEventStoreOptions {
25
+ readonly ttlMs?: number;
26
+ readonly maxEntries?: number;
27
+ }
28
+ /**
29
+ * The default store: an in-process map with a TTL.
30
+ *
31
+ * **Per process.** Two instances behind a load balancer each keep their own,
32
+ * so a redelivery that lands on the other instance is NOT deduped. That is
33
+ * usually fine — the handlers a receiver should be writing are idempotent
34
+ * anyway, because §7.6 makes the application responsible for recording what it
35
+ * did about a decision — but an application whose enforcement is not idempotent
36
+ * must pass a shared store (Redis, its own database) instead. Saying so here is
37
+ * the point: a dedupe that silently only works on one instance is exactly the
38
+ * kind of thing that looks correct in staging.
39
+ *
40
+ * There is no timer. Expiry is evaluated on read and the map is pruned on
41
+ * insert, so nothing here keeps a Node event loop alive — a module-level
42
+ * `setInterval` in a library is how a consumer's test run stops exiting.
43
+ */
44
+ export declare function memoryProcessedEventStore(options?: MemoryProcessedEventStoreOptions): ProcessedEventStore;
45
+ //# sourceMappingURL=store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/express/store.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAOH,MAAM,WAAW,mBAAmB;IAClC,gFAAgF;IAChF,KAAK,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACnD,6DAA6D;IAC7D,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,yBAAyB,CACvC,OAAO,GAAE,gCAAqC,GAC7C,mBAAmB,CA+BrB"}
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ /**
3
+ * Idempotency by event id (§10.8: "store the processed event id").
4
+ *
5
+ * A delivery is retried on the schedule in §10.9 — six times over 24 hours —
6
+ * and a retry can also happen because the receiver's 2xx was lost rather than
7
+ * because it failed. So the same event WILL arrive twice at a healthy receiver,
8
+ * and "did I already do this?" is the only thing standing between that and a
9
+ * piece of content being removed twice or a user being suspended twice.
10
+ *
11
+ * The interface is claim/release rather than a "seen?" check, because the
12
+ * obvious design is wrong in a way that is hard to see. Recording the id BEFORE
13
+ * the handler runs makes a handler failure permanent: every retry is deduped
14
+ * away and the work is lost silently, which is the worst possible outcome for a
15
+ * moderation decision. Recording it AFTER lets two concurrent deliveries of the
16
+ * same event both run. Claiming before and releasing on failure gets both: one
17
+ * in flight, and a failure still retryable.
18
+ */
19
+ Object.defineProperty(exports, "__esModule", { value: true });
20
+ exports.memoryProcessedEventStore = memoryProcessedEventStore;
21
+ /** The retry schedule of §10.9 ends at 24 hours; a claim outlives it. */
22
+ const DEFAULT_TTL_MS = 25 * 60 * 60 * 1000;
23
+ const DEFAULT_MAX_ENTRIES = 10000;
24
+ /**
25
+ * The default store: an in-process map with a TTL.
26
+ *
27
+ * **Per process.** Two instances behind a load balancer each keep their own,
28
+ * so a redelivery that lands on the other instance is NOT deduped. That is
29
+ * usually fine — the handlers a receiver should be writing are idempotent
30
+ * anyway, because §7.6 makes the application responsible for recording what it
31
+ * did about a decision — but an application whose enforcement is not idempotent
32
+ * must pass a shared store (Redis, its own database) instead. Saying so here is
33
+ * the point: a dedupe that silently only works on one instance is exactly the
34
+ * kind of thing that looks correct in staging.
35
+ *
36
+ * There is no timer. Expiry is evaluated on read and the map is pruned on
37
+ * insert, so nothing here keeps a Node event loop alive — a module-level
38
+ * `setInterval` in a library is how a consumer's test run stops exiting.
39
+ */
40
+ function memoryProcessedEventStore(options = {}) {
41
+ const ttlMs = options.ttlMs ?? DEFAULT_TTL_MS;
42
+ const maxEntries = options.maxEntries ?? DEFAULT_MAX_ENTRIES;
43
+ const claims = new Map();
44
+ const prune = (now) => {
45
+ for (const [eventId, expiresAt] of claims) {
46
+ if (expiresAt <= now)
47
+ claims.delete(eventId);
48
+ }
49
+ // Insertion-ordered, so the oldest claims go first once the cap is hit.
50
+ while (claims.size >= maxEntries) {
51
+ const oldest = claims.keys().next();
52
+ if (oldest.done === true)
53
+ break;
54
+ claims.delete(oldest.value);
55
+ }
56
+ };
57
+ return {
58
+ claim(eventId) {
59
+ const now = Date.now();
60
+ const held = claims.get(eventId);
61
+ if (held !== undefined && held > now)
62
+ return false;
63
+ prune(now);
64
+ claims.set(eventId, now + ttlMs);
65
+ return true;
66
+ },
67
+ release(eventId) {
68
+ claims.delete(eventId);
69
+ },
70
+ };
71
+ }
72
+ //# sourceMappingURL=store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"store.js","sourceRoot":"","sources":["../../src/express/store.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;GAgBG;;AAmCH,8DAiCC;AAlED,yEAAyE;AACzE,MAAM,cAAc,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,IAAK,CAAC;AAE5C,MAAM,mBAAmB,GAAG,KAAM,CAAC;AAcnC;;;;;;;;;;;;;;;GAeG;AACH,SAAgB,yBAAyB,CACvC,UAA4C,EAAE;IAE9C,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,cAAc,CAAC;IAC9C,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,IAAI,mBAAmB,CAAC;IAC7D,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAC;IAEzC,MAAM,KAAK,GAAG,CAAC,GAAW,EAAQ,EAAE;QAClC,KAAK,MAAM,CAAC,OAAO,EAAE,SAAS,CAAC,IAAI,MAAM,EAAE,CAAC;YAC1C,IAAI,SAAS,IAAI,GAAG;gBAAE,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAC/C,CAAC;QACD,wEAAwE;QACxE,OAAO,MAAM,CAAC,IAAI,IAAI,UAAU,EAAE,CAAC;YACjC,MAAM,MAAM,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;YACpC,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI;gBAAE,MAAM;YAChC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAC9B,CAAC;IACH,CAAC,CAAC;IAEF,OAAO;QACL,KAAK,CAAC,OAAe;YACnB,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;YACvB,MAAM,IAAI,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACjC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,GAAG,GAAG;gBAAE,OAAO,KAAK,CAAC;YAEnD,KAAK,CAAC,GAAG,CAAC,CAAC;YACX,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,GAAG,KAAK,CAAC,CAAC;YACjC,OAAO,IAAI,CAAC;QACd,CAAC;QACD,OAAO,CAAC,OAAe;YACrB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACzB,CAAC;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Webhook signature verification (§10.8), as a pure function.
3
+ *
4
+ * Kept free of Express, of I/O and of the clock so that the security-critical
5
+ * decision — do these bytes carry a valid, fresh signature from a secret we
6
+ * hold? — can be attacked directly by a test rather than through a request. A
7
+ * signature check that cannot be made to fail is worse than no check at all, so
8
+ * the corpus in `__tests__/verify.test.ts` is mutation-tested: each deliberately
9
+ * weakened verifier must be CAUGHT by at least one case, and a case that no
10
+ * mutant fails is a case that proves nothing.
11
+ *
12
+ * §10.8 in full, and where each line lands:
13
+ *
14
+ * * `signedPayload = timestamp + "." + rawBody` — `buildWebhookSignedPayload`
15
+ * in the contracts package, so the signer and the verifier cannot disagree
16
+ * about what gets signed. This module works on the BYTES of that value (see
17
+ * `signedPayloadBytes`).
18
+ * * "reject timestamps more than five minutes away" — `TOLERANCE`, applied in
19
+ * BOTH directions. A future timestamp is as much a replay signal as an old
20
+ * one, and only checking the past accepts a signature minted for a clock
21
+ * nobody controls.
22
+ * * "compare signatures in constant time" — `timingSafeEqual` over the decoded
23
+ * digests. Never `===`: it returns on the first differing byte, which is a
24
+ * forgery oracle with enough attempts.
25
+ * * "store the processed event id" — `store.ts`, not here. Freshness and
26
+ * authenticity are decidable from the request; whether it was already
27
+ * handled is not.
28
+ * * "allow two secrets during rotation" — `secrets` is a list, every entry is
29
+ * tried, and the result names WHICH one matched so an operator can see the
30
+ * old secret going quiet before they retire it.
31
+ */
32
+ /**
33
+ * Why a delivery was refused. Terse on purpose: it goes back on the wire, into
34
+ * the sender's delivery log, and into `onRejected`.
35
+ *
36
+ * The first eight are what verification itself decides; the last three are the
37
+ * middleware's. They share one vocabulary so the reason a receiver reports and
38
+ * the reason it answers with are always the same string — two lists would drift
39
+ * the first time one of them grew.
40
+ */
41
+ export declare const WEBHOOK_REJECTIONS: readonly ["missing_event_id", "missing_timestamp", "missing_signature", "malformed_timestamp", "malformed_signature", "timestamp_out_of_window", "signature_mismatch", "no_secret_configured", "malformed_event", "event_id_mismatch", "payload_too_large"];
42
+ export type WebhookRejection = (typeof WEBHOOK_REJECTIONS)[number];
43
+ export interface WebhookVerificationInput {
44
+ readonly eventIdHeader: string | undefined;
45
+ readonly timestampHeader: string | undefined;
46
+ readonly signatureHeader: string | undefined;
47
+ /** The bytes as they arrived. Never a re-serialisation of a parsed body. */
48
+ readonly rawBody: Buffer;
49
+ /** Active secret first; the previous one during rotation (§10.8). */
50
+ readonly secrets: readonly string[];
51
+ readonly nowMs: number;
52
+ readonly toleranceSeconds?: number;
53
+ }
54
+ export type WebhookVerification = {
55
+ readonly ok: true;
56
+ readonly eventId: string;
57
+ /** Which configured secret matched. `0` is the active one. */
58
+ readonly secretIndex: number;
59
+ } | {
60
+ readonly ok: false;
61
+ readonly rejection: WebhookRejection;
62
+ };
63
+ /**
64
+ * The exact bytes signed, without a UTF-8 round trip.
65
+ *
66
+ * §10.8 defines the signed payload as a STRING, and
67
+ * `buildWebhookSignedPayload` is that definition. Decoding the body to a string
68
+ * to rebuild it would map any invalid UTF-8 byte to U+FFFD — which is lossy, so
69
+ * two different bodies could produce the same signed payload. Concatenating the
70
+ * prefix bytes with the body bytes is the same value for every well-formed
71
+ * (UTF-8) JSON body and is not lossy for anything else. `verify.test.ts` asserts
72
+ * the two agree.
73
+ */
74
+ export declare function signedPayloadBytes(timestamp: string, rawBody: Buffer): Buffer;
75
+ /**
76
+ * Verifies one delivery.
77
+ *
78
+ * Order matters: everything cheap and decidable from the headers is checked
79
+ * BEFORE any HMAC is computed, so a flood of malformed deliveries cannot be
80
+ * turned into a CPU cost. The one thing that must not be reordered is the
81
+ * timestamp window, which §10.8 puts before the comparison — a signature that
82
+ * was valid last week is still cryptographically valid, and freshness is the
83
+ * only thing that makes it a replay.
84
+ */
85
+ export declare function verifyWebhookDelivery(input: WebhookVerificationInput): WebhookVerification;
86
+ //# sourceMappingURL=verify.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.d.ts","sourceRoot":"","sources":["../../src/express/verify.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AAYH;;;;;;;;GAQG;AACH,eAAO,MAAM,kBAAkB,6PAYrB,CAAC;AAEX,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,kBAAkB,CAAC,CAAC,MAAM,CAAC,CAAC;AAEnE,MAAM,WAAW,wBAAwB;IACvC,QAAQ,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3C,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,eAAe,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7C,4EAA4E;IAC5E,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,qEAAqE;IACrE,QAAQ,CAAC,OAAO,EAAE,SAAS,MAAM,EAAE,CAAC;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;CACpC;AAED,MAAM,MAAM,mBAAmB,GAC3B;IACE,QAAQ,CAAC,EAAE,EAAE,IAAI,CAAC;IAClB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,8DAA8D;IAC9D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;CAC9B,GACD;IAAE,QAAQ,CAAC,EAAE,EAAE,KAAK,CAAC;IAAC,QAAQ,CAAC,SAAS,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAEjE;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAM7E;AAYD;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,wBAAwB,GAAG,mBAAmB,CAsC1F"}
@@ -0,0 +1,138 @@
1
+ "use strict";
2
+ /**
3
+ * Webhook signature verification (§10.8), as a pure function.
4
+ *
5
+ * Kept free of Express, of I/O and of the clock so that the security-critical
6
+ * decision — do these bytes carry a valid, fresh signature from a secret we
7
+ * hold? — can be attacked directly by a test rather than through a request. A
8
+ * signature check that cannot be made to fail is worse than no check at all, so
9
+ * the corpus in `__tests__/verify.test.ts` is mutation-tested: each deliberately
10
+ * weakened verifier must be CAUGHT by at least one case, and a case that no
11
+ * mutant fails is a case that proves nothing.
12
+ *
13
+ * §10.8 in full, and where each line lands:
14
+ *
15
+ * * `signedPayload = timestamp + "." + rawBody` — `buildWebhookSignedPayload`
16
+ * in the contracts package, so the signer and the verifier cannot disagree
17
+ * about what gets signed. This module works on the BYTES of that value (see
18
+ * `signedPayloadBytes`).
19
+ * * "reject timestamps more than five minutes away" — `TOLERANCE`, applied in
20
+ * BOTH directions. A future timestamp is as much a replay signal as an old
21
+ * one, and only checking the past accepts a signature minted for a clock
22
+ * nobody controls.
23
+ * * "compare signatures in constant time" — `timingSafeEqual` over the decoded
24
+ * digests. Never `===`: it returns on the first differing byte, which is a
25
+ * forgery oracle with enough attempts.
26
+ * * "store the processed event id" — `store.ts`, not here. Freshness and
27
+ * authenticity are decidable from the request; whether it was already
28
+ * handled is not.
29
+ * * "allow two secrets during rotation" — `secrets` is a list, every entry is
30
+ * tried, and the result names WHICH one matched so an operator can see the
31
+ * old secret going quiet before they retire it.
32
+ */
33
+ Object.defineProperty(exports, "__esModule", { value: true });
34
+ exports.WEBHOOK_REJECTIONS = void 0;
35
+ exports.signedPayloadBytes = signedPayloadBytes;
36
+ exports.verifyWebhookDelivery = verifyWebhookDelivery;
37
+ const node_crypto_1 = require("node:crypto");
38
+ const contracts_1 = require("@crowdsource.you/contracts");
39
+ /**
40
+ * Why a delivery was refused. Terse on purpose: it goes back on the wire, into
41
+ * the sender's delivery log, and into `onRejected`.
42
+ *
43
+ * The first eight are what verification itself decides; the last three are the
44
+ * middleware's. They share one vocabulary so the reason a receiver reports and
45
+ * the reason it answers with are always the same string — two lists would drift
46
+ * the first time one of them grew.
47
+ */
48
+ exports.WEBHOOK_REJECTIONS = [
49
+ 'missing_event_id',
50
+ 'missing_timestamp',
51
+ 'missing_signature',
52
+ 'malformed_timestamp',
53
+ 'malformed_signature',
54
+ 'timestamp_out_of_window',
55
+ 'signature_mismatch',
56
+ 'no_secret_configured',
57
+ 'malformed_event',
58
+ 'event_id_mismatch',
59
+ 'payload_too_large',
60
+ ];
61
+ /**
62
+ * The exact bytes signed, without a UTF-8 round trip.
63
+ *
64
+ * §10.8 defines the signed payload as a STRING, and
65
+ * `buildWebhookSignedPayload` is that definition. Decoding the body to a string
66
+ * to rebuild it would map any invalid UTF-8 byte to U+FFFD — which is lossy, so
67
+ * two different bodies could produce the same signed payload. Concatenating the
68
+ * prefix bytes with the body bytes is the same value for every well-formed
69
+ * (UTF-8) JSON body and is not lossy for anything else. `verify.test.ts` asserts
70
+ * the two agree.
71
+ */
72
+ function signedPayloadBytes(timestamp, rawBody) {
73
+ // The prefix is taken FROM the contract's own function rather than restated
74
+ // as `${timestamp}.`, so a change to the separator follows automatically
75
+ // instead of leaving two definitions to drift.
76
+ const prefix = (0, contracts_1.buildWebhookSignedPayload)(timestamp, '');
77
+ return Buffer.concat([Buffer.from(prefix, 'utf8'), rawBody]);
78
+ }
79
+ function digestsMatch(expectedHex, presentedHex) {
80
+ const expected = Buffer.from(expectedHex, 'hex');
81
+ const presented = Buffer.from(presentedHex, 'hex');
82
+ // The header schema fixes the length at 64 hex characters, so this is never
83
+ // the branch that rejects a real delivery — it is what stops `timingSafeEqual`
84
+ // from throwing if that ever stops being true.
85
+ if (expected.length !== presented.length)
86
+ return false;
87
+ return (0, node_crypto_1.timingSafeEqual)(expected, presented);
88
+ }
89
+ /**
90
+ * Verifies one delivery.
91
+ *
92
+ * Order matters: everything cheap and decidable from the headers is checked
93
+ * BEFORE any HMAC is computed, so a flood of malformed deliveries cannot be
94
+ * turned into a CPU cost. The one thing that must not be reordered is the
95
+ * timestamp window, which §10.8 puts before the comparison — a signature that
96
+ * was valid last week is still cryptographically valid, and freshness is the
97
+ * only thing that makes it a replay.
98
+ */
99
+ function verifyWebhookDelivery(input) {
100
+ if (input.secrets.length === 0)
101
+ return { ok: false, rejection: 'no_secret_configured' };
102
+ const eventId = input.eventIdHeader?.trim();
103
+ if (!eventId)
104
+ return { ok: false, rejection: 'missing_event_id' };
105
+ if (input.timestampHeader === undefined)
106
+ return { ok: false, rejection: 'missing_timestamp' };
107
+ if (input.signatureHeader === undefined)
108
+ return { ok: false, rejection: 'missing_signature' };
109
+ if (!contracts_1.WebhookTimestampHeaderSchema.safeParse(input.timestampHeader).success) {
110
+ return { ok: false, rejection: 'malformed_timestamp' };
111
+ }
112
+ if (!contracts_1.WebhookSignatureHeaderSchema.safeParse(input.signatureHeader).success) {
113
+ return { ok: false, rejection: 'malformed_signature' };
114
+ }
115
+ const tolerance = input.toleranceSeconds ?? contracts_1.WEBHOOK_TIMESTAMP_TOLERANCE_SECONDS;
116
+ const skewSeconds = Math.abs(input.nowMs / 1000 - Number(input.timestampHeader));
117
+ if (skewSeconds > tolerance)
118
+ return { ok: false, rejection: 'timestamp_out_of_window' };
119
+ const presentedHex = input.signatureHeader.slice(`${contracts_1.WEBHOOK_SIGNATURE_VERSION}=`.length);
120
+ const payload = signedPayloadBytes(input.timestampHeader, input.rawBody);
121
+ /**
122
+ * Every secret is tried and the loop does not break early. Breaking would make
123
+ * "the active secret matched" measurably faster than "the previous one did",
124
+ * which tells a caller how far through a rotation the receiver is — small, but
125
+ * free to avoid.
126
+ */
127
+ let matchedIndex = -1;
128
+ input.secrets.forEach((secret, index) => {
129
+ const expected = (0, node_crypto_1.createHmac)('sha256', secret).update(payload).digest('hex');
130
+ if (digestsMatch(expected, presentedHex) && matchedIndex === -1) {
131
+ matchedIndex = index;
132
+ }
133
+ });
134
+ if (matchedIndex === -1)
135
+ return { ok: false, rejection: 'signature_mismatch' };
136
+ return { ok: true, eventId, secretIndex: matchedIndex };
137
+ }
138
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../../src/express/verify.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,67 @@
1
+ /**
2
+ * `@crowdsource.you/core` — the TypeScript client for the CrowdSource moderation
3
+ * API.
4
+ *
5
+ * The smallest integration this package supports, in full:
6
+ *
7
+ * ```ts
8
+ * import { CrowdSource } from '@crowdsource.you/core';
9
+ *
10
+ * const crowdsource = new CrowdSource();
11
+ *
12
+ * await crowdsource.reports.create({
13
+ * externalReportId: report.id,
14
+ * reportedBy: { oxyUserId: session.sub },
15
+ * subject: {
16
+ * externalId: post.id,
17
+ * type: 'social.post',
18
+ * author: { oxyUserId: post.authorId },
19
+ * },
20
+ * content: post.text,
21
+ * allegations: ['harassment.targeted_abuse'],
22
+ * });
23
+ * ```
24
+ *
25
+ * One environment variable (`CROWDSOURCE_SERVICE_KEY`) and the object being
26
+ * reported. The Case Envelope, its resource ids, its digests, its relations, its
27
+ * principal bindings, the identity binding proof, the policy version, the
28
+ * retention terms and the idempotency key are all composed from that — see
29
+ * `envelope.ts` for what each one is derived from and why it cannot be left to
30
+ * the caller.
31
+ *
32
+ * Types come from `@crowdsource.you/contracts`. This package re-exports none
33
+ * of them: an integrator imports the contract from the contract package, so a
34
+ * `Decision` or a `TaxonomyCode` has exactly one definition.
35
+ */
36
+ export { CrowdSource, SERVICE_KEY_ENV_VAR, BASE_URL_ENV_VAR } from './client.js';
37
+ export type { CrowdSourceOptions } from './client.js';
38
+ export { formatServiceKey, parseServiceKey } from './credential.js';
39
+ export type { ServiceCredential } from './credential.js';
40
+ export { COMMUNITY_REVIEW_FORBIDDEN_ALLEGATIONS, DEFAULT_BASE_URL, DEFAULT_POLICY, DEFAULT_RETENTION_DAYS, } from './defaults.js';
41
+ export { canonicalJson, resourceDigest, sha256Digest } from './digest.js';
42
+ export type { CanonicalValue } from './digest.js';
43
+ /**
44
+ * `composeCaseEnvelope` is deliberately NOT exported.
45
+ *
46
+ * It is the one function in this package that takes an `applicationId`, and it
47
+ * takes it from `Reports`, which got it from the credential. Exporting it would
48
+ * put an `applicationId` parameter on the public surface — which is the thing
49
+ * Appendix F says must not exist, however carefully the doc comment above it
50
+ * were worded. The envelope a report produces is reachable by reading what
51
+ * `reports.create` sends, not by building one yourself.
52
+ */
53
+ export { CrowdSourceReportInputError, defaultIdempotencyKey } from './envelope.js';
54
+ export type { AllegationInput, ContextInput, ContextRole, PrincipalInput, ReportInput, ReportSubjectInput, ResourceInput, } from './envelope.js';
55
+ export { CROWDSOURCE_API_ERROR_CODES, CrowdSourceApiError, CrowdSourceConfigurationError, CrowdSourceError, CrowdSourceTransportError, isCrowdSourceApiError, isCrowdSourceApiErrorCode, isCrowdSourceError, } from './errors.js';
56
+ export type { CrowdSourceApiErrorCode } from './errors.js';
57
+ export { Reports } from './reports.js';
58
+ export type { ReportReceipt, ReportRequestOptions } from './reports.js';
59
+ export { Cases, Decisions } from './cases.js';
60
+ export type { CaseView, ReadOptions } from './cases.js';
61
+ export { CommunityNotes } from './communityNotes.js';
62
+ export type { CommunityNoteReadOptions, CommunityNoteRequestOptions } from './communityNotes.js';
63
+ export { WebhookEndpoints } from './webhookEndpoints.js';
64
+ export type { RegisterWebhookEndpointInput, RotateSecretOptions, RotatedWebhookSecret, WebhookEndpoint, WebhookEndpointRequestOptions, WebhookSecret, } from './webhookEndpoints.js';
65
+ export { DEFAULT_MAX_ATTEMPTS, DEFAULT_TIMEOUT_MS } from './transport.js';
66
+ export type { FetchLike } from './transport.js';
67
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAEH,OAAO,EAAE,WAAW,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AACjF,YAAY,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAEtD,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AACpE,YAAY,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAEzD,OAAO,EACL,sCAAsC,EACtC,gBAAgB,EAChB,cAAc,EACd,sBAAsB,GACvB,MAAM,eAAe,CAAC;AAEvB,OAAO,EAAE,aAAa,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC1E,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAElD;;;;;;;;;GASG;AACH,OAAO,EAAE,2BAA2B,EAAE,qBAAqB,EAAE,MAAM,eAAe,CAAC;AACnF,YAAY,EACV,eAAe,EACf,YAAY,EACZ,WAAW,EACX,cAAc,EACd,WAAW,EACX,kBAAkB,EAClB,aAAa,GACd,MAAM,eAAe,CAAC;AAEvB,OAAO,EACL,2BAA2B,EAC3B,mBAAmB,EACnB,6BAA6B,EAC7B,gBAAgB,EAChB,yBAAyB,EACzB,qBAAqB,EACrB,yBAAyB,EACzB,kBAAkB,GACnB,MAAM,aAAa,CAAC;AACrB,YAAY,EAAE,uBAAuB,EAAE,MAAM,aAAa,CAAC;AAE3D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,YAAY,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAC;AAExE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAC9C,YAAY,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAGxD,OAAO,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AACrD,YAAY,EAAE,wBAAwB,EAAE,2BAA2B,EAAE,MAAM,qBAAqB,CAAC;AAEjG,OAAO,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AACzD,YAAY,EACV,4BAA4B,EAC5B,mBAAmB,EACnB,oBAAoB,EACpB,eAAe,EACf,6BAA6B,EAC7B,aAAa,GACd,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAAE,oBAAoB,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AAC1E,YAAY,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,89 @@
1
+ "use strict";
2
+ /**
3
+ * `@crowdsource.you/core` — the TypeScript client for the CrowdSource moderation
4
+ * API.
5
+ *
6
+ * The smallest integration this package supports, in full:
7
+ *
8
+ * ```ts
9
+ * import { CrowdSource } from '@crowdsource.you/core';
10
+ *
11
+ * const crowdsource = new CrowdSource();
12
+ *
13
+ * await crowdsource.reports.create({
14
+ * externalReportId: report.id,
15
+ * reportedBy: { oxyUserId: session.sub },
16
+ * subject: {
17
+ * externalId: post.id,
18
+ * type: 'social.post',
19
+ * author: { oxyUserId: post.authorId },
20
+ * },
21
+ * content: post.text,
22
+ * allegations: ['harassment.targeted_abuse'],
23
+ * });
24
+ * ```
25
+ *
26
+ * One environment variable (`CROWDSOURCE_SERVICE_KEY`) and the object being
27
+ * reported. The Case Envelope, its resource ids, its digests, its relations, its
28
+ * principal bindings, the identity binding proof, the policy version, the
29
+ * retention terms and the idempotency key are all composed from that — see
30
+ * `envelope.ts` for what each one is derived from and why it cannot be left to
31
+ * the caller.
32
+ *
33
+ * Types come from `@crowdsource.you/contracts`. This package re-exports none
34
+ * of them: an integrator imports the contract from the contract package, so a
35
+ * `Decision` or a `TaxonomyCode` has exactly one definition.
36
+ */
37
+ Object.defineProperty(exports, "__esModule", { value: true });
38
+ exports.DEFAULT_TIMEOUT_MS = exports.DEFAULT_MAX_ATTEMPTS = exports.WebhookEndpoints = exports.CommunityNotes = exports.Decisions = exports.Cases = exports.Reports = exports.isCrowdSourceError = exports.isCrowdSourceApiErrorCode = exports.isCrowdSourceApiError = exports.CrowdSourceTransportError = exports.CrowdSourceError = exports.CrowdSourceConfigurationError = exports.CrowdSourceApiError = exports.CROWDSOURCE_API_ERROR_CODES = exports.defaultIdempotencyKey = exports.CrowdSourceReportInputError = exports.sha256Digest = exports.resourceDigest = exports.canonicalJson = exports.DEFAULT_RETENTION_DAYS = exports.DEFAULT_POLICY = exports.DEFAULT_BASE_URL = exports.COMMUNITY_REVIEW_FORBIDDEN_ALLEGATIONS = exports.parseServiceKey = exports.formatServiceKey = exports.BASE_URL_ENV_VAR = exports.SERVICE_KEY_ENV_VAR = exports.CrowdSource = void 0;
39
+ var client_js_1 = require("./client.js");
40
+ Object.defineProperty(exports, "CrowdSource", { enumerable: true, get: function () { return client_js_1.CrowdSource; } });
41
+ Object.defineProperty(exports, "SERVICE_KEY_ENV_VAR", { enumerable: true, get: function () { return client_js_1.SERVICE_KEY_ENV_VAR; } });
42
+ Object.defineProperty(exports, "BASE_URL_ENV_VAR", { enumerable: true, get: function () { return client_js_1.BASE_URL_ENV_VAR; } });
43
+ var credential_js_1 = require("./credential.js");
44
+ Object.defineProperty(exports, "formatServiceKey", { enumerable: true, get: function () { return credential_js_1.formatServiceKey; } });
45
+ Object.defineProperty(exports, "parseServiceKey", { enumerable: true, get: function () { return credential_js_1.parseServiceKey; } });
46
+ var defaults_js_1 = require("./defaults.js");
47
+ Object.defineProperty(exports, "COMMUNITY_REVIEW_FORBIDDEN_ALLEGATIONS", { enumerable: true, get: function () { return defaults_js_1.COMMUNITY_REVIEW_FORBIDDEN_ALLEGATIONS; } });
48
+ Object.defineProperty(exports, "DEFAULT_BASE_URL", { enumerable: true, get: function () { return defaults_js_1.DEFAULT_BASE_URL; } });
49
+ Object.defineProperty(exports, "DEFAULT_POLICY", { enumerable: true, get: function () { return defaults_js_1.DEFAULT_POLICY; } });
50
+ Object.defineProperty(exports, "DEFAULT_RETENTION_DAYS", { enumerable: true, get: function () { return defaults_js_1.DEFAULT_RETENTION_DAYS; } });
51
+ var digest_js_1 = require("./digest.js");
52
+ Object.defineProperty(exports, "canonicalJson", { enumerable: true, get: function () { return digest_js_1.canonicalJson; } });
53
+ Object.defineProperty(exports, "resourceDigest", { enumerable: true, get: function () { return digest_js_1.resourceDigest; } });
54
+ Object.defineProperty(exports, "sha256Digest", { enumerable: true, get: function () { return digest_js_1.sha256Digest; } });
55
+ /**
56
+ * `composeCaseEnvelope` is deliberately NOT exported.
57
+ *
58
+ * It is the one function in this package that takes an `applicationId`, and it
59
+ * takes it from `Reports`, which got it from the credential. Exporting it would
60
+ * put an `applicationId` parameter on the public surface — which is the thing
61
+ * Appendix F says must not exist, however carefully the doc comment above it
62
+ * were worded. The envelope a report produces is reachable by reading what
63
+ * `reports.create` sends, not by building one yourself.
64
+ */
65
+ var envelope_js_1 = require("./envelope.js");
66
+ Object.defineProperty(exports, "CrowdSourceReportInputError", { enumerable: true, get: function () { return envelope_js_1.CrowdSourceReportInputError; } });
67
+ Object.defineProperty(exports, "defaultIdempotencyKey", { enumerable: true, get: function () { return envelope_js_1.defaultIdempotencyKey; } });
68
+ var errors_js_1 = require("./errors.js");
69
+ Object.defineProperty(exports, "CROWDSOURCE_API_ERROR_CODES", { enumerable: true, get: function () { return errors_js_1.CROWDSOURCE_API_ERROR_CODES; } });
70
+ Object.defineProperty(exports, "CrowdSourceApiError", { enumerable: true, get: function () { return errors_js_1.CrowdSourceApiError; } });
71
+ Object.defineProperty(exports, "CrowdSourceConfigurationError", { enumerable: true, get: function () { return errors_js_1.CrowdSourceConfigurationError; } });
72
+ Object.defineProperty(exports, "CrowdSourceError", { enumerable: true, get: function () { return errors_js_1.CrowdSourceError; } });
73
+ Object.defineProperty(exports, "CrowdSourceTransportError", { enumerable: true, get: function () { return errors_js_1.CrowdSourceTransportError; } });
74
+ Object.defineProperty(exports, "isCrowdSourceApiError", { enumerable: true, get: function () { return errors_js_1.isCrowdSourceApiError; } });
75
+ Object.defineProperty(exports, "isCrowdSourceApiErrorCode", { enumerable: true, get: function () { return errors_js_1.isCrowdSourceApiErrorCode; } });
76
+ Object.defineProperty(exports, "isCrowdSourceError", { enumerable: true, get: function () { return errors_js_1.isCrowdSourceError; } });
77
+ var reports_js_1 = require("./reports.js");
78
+ Object.defineProperty(exports, "Reports", { enumerable: true, get: function () { return reports_js_1.Reports; } });
79
+ var cases_js_1 = require("./cases.js");
80
+ Object.defineProperty(exports, "Cases", { enumerable: true, get: function () { return cases_js_1.Cases; } });
81
+ Object.defineProperty(exports, "Decisions", { enumerable: true, get: function () { return cases_js_1.Decisions; } });
82
+ var communityNotes_js_1 = require("./communityNotes.js");
83
+ Object.defineProperty(exports, "CommunityNotes", { enumerable: true, get: function () { return communityNotes_js_1.CommunityNotes; } });
84
+ var webhookEndpoints_js_1 = require("./webhookEndpoints.js");
85
+ Object.defineProperty(exports, "WebhookEndpoints", { enumerable: true, get: function () { return webhookEndpoints_js_1.WebhookEndpoints; } });
86
+ var transport_js_1 = require("./transport.js");
87
+ Object.defineProperty(exports, "DEFAULT_MAX_ATTEMPTS", { enumerable: true, get: function () { return transport_js_1.DEFAULT_MAX_ATTEMPTS; } });
88
+ Object.defineProperty(exports, "DEFAULT_TIMEOUT_MS", { enumerable: true, get: function () { return transport_js_1.DEFAULT_TIMEOUT_MS; } });
89
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;;;AAEH,yCAAiF;AAAxE,wGAAA,WAAW,OAAA;AAAE,gHAAA,mBAAmB,OAAA;AAAE,6GAAA,gBAAgB,OAAA;AAG3D,iDAAoE;AAA3D,iHAAA,gBAAgB,OAAA;AAAE,gHAAA,eAAe,OAAA;AAG1C,6CAKuB;AAJrB,qIAAA,sCAAsC,OAAA;AACtC,+GAAA,gBAAgB,OAAA;AAChB,6GAAA,cAAc,OAAA;AACd,qHAAA,sBAAsB,OAAA;AAGxB,yCAA0E;AAAjE,0GAAA,aAAa,OAAA;AAAE,2GAAA,cAAc,OAAA;AAAE,yGAAA,YAAY,OAAA;AAGpD;;;;;;;;;GASG;AACH,6CAAmF;AAA1E,0HAAA,2BAA2B,OAAA;AAAE,oHAAA,qBAAqB,OAAA;AAW3D,yCASqB;AARnB,wHAAA,2BAA2B,OAAA;AAC3B,gHAAA,mBAAmB,OAAA;AACnB,0HAAA,6BAA6B,OAAA;AAC7B,6GAAA,gBAAgB,OAAA;AAChB,sHAAA,yBAAyB,OAAA;AACzB,kHAAA,qBAAqB,OAAA;AACrB,sHAAA,yBAAyB,OAAA;AACzB,+GAAA,kBAAkB,OAAA;AAIpB,2CAAuC;AAA9B,qGAAA,OAAO,OAAA;AAGhB,uCAA8C;AAArC,iGAAA,KAAK,OAAA;AAAE,qGAAA,SAAS,OAAA;AAIzB,yDAAqD;AAA5C,mHAAA,cAAc,OAAA;AAGvB,6DAAyD;AAAhD,uHAAA,gBAAgB,OAAA;AAUzB,+CAA0E;AAAjE,oHAAA,oBAAoB,OAAA;AAAE,kHAAA,kBAAkB,OAAA"}
@@ -0,0 +1,35 @@
1
+ import { CrowdSource } from '../index.js';
2
+ import type { CrowdSourceConnectionConfig, ModerationLogger } from './types.js';
3
+ /**
4
+ * The CrowdSource client, built once and only when configured.
5
+ *
6
+ * There is deliberately almost nothing here. The SDK already owns the base URL,
7
+ * the timeouts, the bounded per-attempt retries, the idempotency key and the
8
+ * error classification, and a wrapper that re-implemented any of them would be a
9
+ * second answer to a question that has one. What this adds is exactly two
10
+ * things: the client is absent until the integration is switched on, and it is
11
+ * built once rather than per delivery.
12
+ *
13
+ * `applicationId` appears nowhere — the client reads it off the service key, and
14
+ * there is no option, field or parameter through which one could be passed.
15
+ */
16
+ export interface CrowdSourceClientProvider {
17
+ /**
18
+ * The client, or `undefined` when the integration is not configured.
19
+ *
20
+ * `undefined` rather than a throw: a disabled integration is the normal state
21
+ * of a local checkout and of every deployment before rollout, and a report
22
+ * filed there must still be stored. The delivery worker is what notices there
23
+ * is nowhere to send it.
24
+ *
25
+ * A MISCONFIGURED client — a malformed service key — is a different thing and
26
+ * is logged once at error level. Once, because the alternative is one line per
27
+ * delivery attempt per report, which buries the cause it is meant to reveal.
28
+ */
29
+ get(): CrowdSource | undefined;
30
+ }
31
+ export declare function createClientProvider(input: {
32
+ config: CrowdSourceConnectionConfig;
33
+ logger: ModerationLogger;
34
+ }): CrowdSourceClientProvider;
35
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/outbox/client.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,KAAK,EAAE,2BAA2B,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEhF;;;;;;;;;;;;GAYG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;;;;;;;;;OAWG;IACH,GAAG,IAAI,WAAW,GAAG,SAAS,CAAC;CAChC;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE;IAC1C,MAAM,EAAE,2BAA2B,CAAC;IACpC,MAAM,EAAE,gBAAgB,CAAC;CAC1B,GAAG,yBAAyB,CAuC5B"}
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createClientProvider = createClientProvider;
4
+ const index_js_1 = require("../index.js");
5
+ function createClientProvider(input) {
6
+ let client = null;
7
+ let configurationError = null;
8
+ return {
9
+ get() {
10
+ if (!input.config.enabled)
11
+ return undefined;
12
+ if (client)
13
+ return client;
14
+ if (configurationError !== null)
15
+ return undefined;
16
+ const serviceKey = input.config.serviceKey;
17
+ if (!serviceKey) {
18
+ configurationError = 'no CrowdSource service key is configured';
19
+ input.logger.error('[CrowdSource] enabled but not configured', {
20
+ reason: configurationError,
21
+ });
22
+ return undefined;
23
+ }
24
+ try {
25
+ client = new index_js_1.CrowdSource({
26
+ serviceKey,
27
+ ...(input.config.baseUrl === undefined ? {} : { baseUrl: input.config.baseUrl }),
28
+ });
29
+ input.logger.info('[CrowdSource] client ready', {
30
+ applicationId: client.applicationId,
31
+ });
32
+ return client;
33
+ }
34
+ catch (error) {
35
+ // The SDK's configuration errors name which part of the key is wrong and
36
+ // never echo the secret, so the message is safe to log.
37
+ configurationError = error instanceof Error ? error.message : String(error);
38
+ input.logger.error('[CrowdSource] service key rejected', {
39
+ reason: configurationError,
40
+ });
41
+ return undefined;
42
+ }
43
+ },
44
+ };
45
+ }
46
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/outbox/client.ts"],"names":[],"mappings":";;AAgCA,oDA0CC;AA1ED,0CAA0C;AAgC1C,SAAgB,oBAAoB,CAAC,KAGpC;IACC,IAAI,MAAM,GAAuB,IAAI,CAAC;IACtC,IAAI,kBAAkB,GAAkB,IAAI,CAAC;IAE7C,OAAO;QACL,GAAG;YACD,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO;gBAAE,OAAO,SAAS,CAAC;YAC5C,IAAI,MAAM;gBAAE,OAAO,MAAM,CAAC;YAC1B,IAAI,kBAAkB,KAAK,IAAI;gBAAE,OAAO,SAAS,CAAC;YAElD,MAAM,UAAU,GAAG,KAAK,CAAC,MAAM,CAAC,UAAU,CAAC;YAC3C,IAAI,CAAC,UAAU,EAAE,CAAC;gBAChB,kBAAkB,GAAG,0CAA0C,CAAC;gBAChE,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,0CAA0C,EAAE;oBAC7D,MAAM,EAAE,kBAAkB;iBAC3B,CAAC,CAAC;gBACH,OAAO,SAAS,CAAC;YACnB,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,GAAG,IAAI,sBAAW,CAAC;oBACvB,UAAU;oBACV,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,OAAO,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;iBACjF,CAAC,CAAC;gBACH,KAAK,CAAC,MAAM,CAAC,IAAI,CAAC,4BAA4B,EAAE;oBAC9C,aAAa,EAAE,MAAM,CAAC,aAAa;iBACpC,CAAC,CAAC;gBACH,OAAO,MAAM,CAAC;YAChB,CAAC;YAAC,OAAO,KAAc,EAAE,CAAC;gBACxB,yEAAyE;gBACzE,wDAAwD;gBACxD,kBAAkB,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;gBAC5E,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,oCAAoC,EAAE;oBACvD,MAAM,EAAE,kBAAkB;iBAC3B,CAAC,CAAC;gBACH,OAAO,SAAS,CAAC;YACnB,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}