@oxyhq/crowdsource-contracts 0.3.0 → 0.4.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 (81) hide show
  1. package/dist/appeals.d.ts +323 -0
  2. package/dist/appeals.d.ts.map +1 -0
  3. package/dist/appeals.js +203 -0
  4. package/dist/appeals.js.map +1 -0
  5. package/dist/case-envelope.d.ts +3 -3
  6. package/dist/case-envelope.d.ts.map +1 -1
  7. package/dist/case-envelope.js +32 -32
  8. package/dist/case-envelope.js.map +1 -1
  9. package/dist/decisions.d.ts +1 -1
  10. package/dist/decisions.d.ts.map +1 -1
  11. package/dist/decisions.js +28 -28
  12. package/dist/decisions.js.map +1 -1
  13. package/dist/esm/appeals.js +200 -0
  14. package/dist/esm/appeals.js.map +1 -0
  15. package/dist/esm/case-envelope.js +380 -0
  16. package/dist/esm/case-envelope.js.map +1 -0
  17. package/dist/esm/closed.js +32 -0
  18. package/dist/esm/closed.js.map +1 -0
  19. package/dist/esm/decisions.js +195 -0
  20. package/dist/esm/decisions.js.map +1 -0
  21. package/dist/esm/index.js +48 -0
  22. package/dist/esm/index.js.map +1 -0
  23. package/dist/esm/json-schema.js +84 -0
  24. package/dist/esm/json-schema.js.map +1 -0
  25. package/dist/esm/package.json +1 -0
  26. package/dist/esm/policies.js +175 -0
  27. package/dist/esm/policies.js.map +1 -0
  28. package/dist/esm/primitives.js +249 -0
  29. package/dist/esm/primitives.js.map +1 -0
  30. package/dist/esm/reputation-events.js +125 -0
  31. package/dist/esm/reputation-events.js.map +1 -0
  32. package/dist/esm/resources.js +455 -0
  33. package/dist/esm/resources.js.map +1 -0
  34. package/dist/esm/reviewer-surface.js +612 -0
  35. package/dist/esm/reviewer-surface.js.map +1 -0
  36. package/dist/esm/reviews.js +141 -0
  37. package/dist/esm/reviews.js.map +1 -0
  38. package/dist/esm/taxonomy.js +278 -0
  39. package/dist/esm/taxonomy.js.map +1 -0
  40. package/dist/esm/webhooks.js +188 -0
  41. package/dist/esm/webhooks.js.map +1 -0
  42. package/dist/index.d.ts +13 -11
  43. package/dist/index.d.ts.map +1 -1
  44. package/dist/index.js +13 -11
  45. package/dist/index.js.map +1 -1
  46. package/dist/json-schema.d.ts +1 -1
  47. package/dist/json-schema.d.ts.map +1 -1
  48. package/dist/json-schema.js +25 -20
  49. package/dist/json-schema.js.map +1 -1
  50. package/dist/policies.d.ts +1 -1
  51. package/dist/policies.d.ts.map +1 -1
  52. package/dist/policies.js +14 -14
  53. package/dist/policies.js.map +1 -1
  54. package/dist/reputation-events.js +19 -19
  55. package/dist/reputation-events.js.map +1 -1
  56. package/dist/resources.d.ts +60 -2
  57. package/dist/resources.d.ts.map +1 -1
  58. package/dist/resources.js +116 -103
  59. package/dist/resources.js.map +1 -1
  60. package/dist/reviewer-surface.d.ts +1956 -0
  61. package/dist/reviewer-surface.d.ts.map +1 -0
  62. package/dist/reviewer-surface.js +615 -0
  63. package/dist/reviewer-surface.js.map +1 -0
  64. package/dist/reviews.js +15 -15
  65. package/dist/reviews.js.map +1 -1
  66. package/dist/webhooks.d.ts +1 -1
  67. package/dist/webhooks.d.ts.map +1 -1
  68. package/dist/webhooks.js +18 -18
  69. package/dist/webhooks.js.map +1 -1
  70. package/package.json +4 -4
  71. package/src/appeals.ts +229 -0
  72. package/src/case-envelope.ts +5 -5
  73. package/src/decisions.ts +6 -6
  74. package/src/index.ts +13 -11
  75. package/src/json-schema.ts +12 -7
  76. package/src/policies.ts +3 -3
  77. package/src/reputation-events.ts +4 -4
  78. package/src/resources.ts +99 -73
  79. package/src/reviewer-surface.ts +715 -0
  80. package/src/reviews.ts +4 -4
  81. package/src/webhooks.ts +4 -4
@@ -0,0 +1,141 @@
1
+ /**
2
+ * What one reviewer submits (§9.2, §9.3) and how they step away (§4.1).
3
+ *
4
+ * §9.2 splits the form in two — describe the material, then evaluate it against
5
+ * a rule — to reduce anchoring on the reporter's category and to let the same
6
+ * description be reused under different policies. §9.3 then gives one flat
7
+ * result object. Both are true at once: a `ReviewFinding` carries the step-one
8
+ * fields (`code`, `resourceIds`, `severity`, `confidence`) and the step-two
9
+ * fields (`policyRuleIds`), and the enclosing submission carries the step-two
10
+ * verdict (`outcome`, `recommendedActions`). The split is a property of the
11
+ * interface, not of the payload, so it is documented here rather than nested.
12
+ *
13
+ * The submission is `.strict()`, and that is a safety decision, not tidiness.
14
+ * A review belongs to an assignment the server issued; the assignment id comes
15
+ * from the route, the case and the reviewer come from the assignment. If this
16
+ * object tolerated a `caseId`, an `assignmentId` or a `reviewerId`, the day
17
+ * somebody read one of them would be the day a reviewer could vote on a case
18
+ * they were never drawn for — against "nobody chooses the case they review".
19
+ * Strict makes that field impossible rather than merely unused.
20
+ */
21
+ import { z } from 'zod';
22
+ import { CONTRACT_LIMITS, UnitIntervalSchema } from './primitives.js';
23
+ import { PolicyRuleIdSchema } from './policies.js';
24
+ import { ResourceIdSchema } from './resources.js';
25
+ import { FindingContextSchema, RecommendedActionSchema, SeveritySchema, TaxonomyCodeSchema, } from './taxonomy.js';
26
+ /**
27
+ * What a single reviewer can conclude.
28
+ *
29
+ * Narrower than §9.6's decision outcomes on purpose. `inconclusive` is what the
30
+ * consensus engine reports when a panel does not agree — a single reviewer
31
+ * cannot fail to agree with themselves, and "the absence of consensus is
32
+ * neither guilt nor innocence" only holds if `inconclusive` is produced by the
33
+ * engine and never voted for. `duplicate`, `escalated` and `superseded` are
34
+ * likewise case-level states, not opinions about material. The plan never
35
+ * enumerates review outcomes; this is that gap resolved toward the invariant.
36
+ */
37
+ export const REVIEW_OUTCOMES = [
38
+ 'violation',
39
+ 'no_violation',
40
+ 'insufficient_context',
41
+ 'content_unavailable',
42
+ ];
43
+ export const ReviewOutcomeSchema = z.enum(REVIEW_OUTCOMES);
44
+ /** §9.5 feeds this into `contextFactor`: 1.0 if sufficient, 0.5 otherwise. */
45
+ export const CONTEXT_SUFFICIENCIES = ['sufficient', 'insufficient'];
46
+ export const ContextSufficiencySchema = z.enum(CONTEXT_SUFFICIENCIES);
47
+ /**
48
+ * One structured finding from one reviewer (§9.3).
49
+ *
50
+ * `resourceIds` is required and non-empty: §9.4 makes the affected resource one
51
+ * of the dimensions consensus is measured on, so a finding that does not say
52
+ * what it is about cannot be agreed with or disagreed with.
53
+ *
54
+ * `policyRuleIds` is optional: step one of the form can complete without step
55
+ * two — a reviewer may classify material accurately and find no rule that
56
+ * covers it, which is exactly the `no_violation`-with-findings case §6.2
57
+ * describes.
58
+ *
59
+ * `context` is §9.2's and §9.4's "excepción", written as §6.2 writes it: beside
60
+ * the code and the severity, because "artistic nudity" is a different
61
+ * description of the material from "nudity" rather than a different verdict
62
+ * about it. Optional, and absence means no exception applies.
63
+ *
64
+ * `confidence` communicates quality and triggers escalation (§9.5). It never
65
+ * weights the vote.
66
+ */
67
+ export const ReviewFindingSchema = z.strictObject({
68
+ code: TaxonomyCodeSchema,
69
+ resourceIds: z.array(ResourceIdSchema).min(1).max(CONTRACT_LIMITS.RESOURCE_REFS_PER_FINDING_MAX),
70
+ severity: SeveritySchema,
71
+ context: FindingContextSchema.optional(),
72
+ confidence: UnitIntervalSchema,
73
+ policyRuleIds: z.array(PolicyRuleIdSchema).max(CONTRACT_LIMITS.POLICY_RULE_IDS_MAX).optional(),
74
+ });
75
+ /**
76
+ * The body of `POST /v1/reviewer/assignments/{id}/reviews` — §9.3's "result of
77
+ * a review".
78
+ *
79
+ * `recommendedActions` is a list of action tokens here, where a decision's
80
+ * `recommendedActions` are objects that name their target resources. That
81
+ * difference is in the plan (§9.3 versus Appendix B) and is kept: a reviewer
82
+ * recommends a course of action, and the consensus process is what binds an
83
+ * agreed recommendation to the specific resources it applies to.
84
+ */
85
+ export const ReviewSubmissionSchema = z
86
+ .strictObject({
87
+ outcome: ReviewOutcomeSchema,
88
+ contextSufficiency: ContextSufficiencySchema,
89
+ findings: z.array(ReviewFindingSchema).max(CONTRACT_LIMITS.FINDINGS_MAX),
90
+ recommendedActions: z
91
+ .array(RecommendedActionSchema)
92
+ .max(CONTRACT_LIMITS.RECOMMENDED_ACTIONS_MAX),
93
+ /**
94
+ * §13.5 and the "sensitive content never reaches logs" invariant apply to
95
+ * this field as much as to the evidence: a note is free text a human wrote
96
+ * while looking at the material, so it is bounded here and must be treated
97
+ * as case content everywhere downstream — never logged, never attested.
98
+ */
99
+ notes: z.string().max(CONTRACT_LIMITS.LONG_TEXT_MAX_LENGTH).optional(),
100
+ })
101
+ .superRefine((review, ctx) => {
102
+ if (review.outcome === 'insufficient_context' && review.contextSufficiency !== 'insufficient') {
103
+ ctx.addIssue({
104
+ code: 'custom',
105
+ path: ['contextSufficiency'],
106
+ message: 'an outcome of insufficient_context requires contextSufficiency "insufficient"',
107
+ });
108
+ }
109
+ if (review.outcome === 'violation' && review.findings.length === 0) {
110
+ ctx.addIssue({
111
+ code: 'custom',
112
+ path: ['findings'],
113
+ message: 'a violation outcome requires at least one finding',
114
+ });
115
+ }
116
+ });
117
+ /**
118
+ * §4.1: a reviewer may declare a conflict, a language they do not have,
119
+ * material too sensitive for them, or context they cannot obtain — "without
120
+ * penalty". These four are the plan's own list, made structured as §10.3 asks.
121
+ */
122
+ export const RECUSAL_REASONS = [
123
+ 'conflict_of_interest',
124
+ 'language',
125
+ 'too_sensitive',
126
+ 'insufficient_context',
127
+ ];
128
+ export const RecusalReasonSchema = z.enum(RECUSAL_REASONS);
129
+ /**
130
+ * The body of `POST /v1/reviewer/assignments/{id}/recuse`.
131
+ *
132
+ * Strict for the same reason as the submission, and with no free-text field
133
+ * beyond a short optional note: a recusal is routing information, and the more
134
+ * it can say about the case, the more it becomes a channel for case content to
135
+ * leak into operational data.
136
+ */
137
+ export const RecusalSubmissionSchema = z.strictObject({
138
+ reason: RecusalReasonSchema,
139
+ note: z.string().max(CONTRACT_LIMITS.SHORT_TEXT_MAX_LENGTH).optional(),
140
+ });
141
+ //# sourceMappingURL=reviews.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"reviews.js","sourceRoot":"","sources":["../../src/reviews.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,278 @@
1
+ /**
2
+ * The universal classification layer (§6.1, §6.3).
3
+ *
4
+ * §6.1 separates three layers and warns that mixing them makes the service
5
+ * unusable across applications with different rules. This module is the FIRST
6
+ * layer only — "what does the material contain or represent?" — and it belongs
7
+ * to CrowdSource. Whether that content violates anything is the second layer
8
+ * (`policies.ts`, per tenant) and whether it should move global trust is the
9
+ * third (`reputation-events.ts`). Nothing here may encode a single tenant's
10
+ * vocabulary.
11
+ *
12
+ * The code list is CLOSED. `other.policy_specific` and `other.unclassifiable`
13
+ * are the escape hatches the plan provides for material that does not fit; an
14
+ * open string would let a tenant mint private codes, which is precisely the
15
+ * cross-application comparability §6.1 exists to protect. Adding a code is an
16
+ * additive change that bumps `UNIVERSAL_TAXONOMY_VERSION`, and §6.4 requires
17
+ * every decision to record the version it was classified under, so historical
18
+ * decisions keep meaning what they meant.
19
+ */
20
+ import { z } from 'zod';
21
+ /** §6.3 families. */
22
+ export const TAXONOMY_FAMILIES = [
23
+ 'integrity',
24
+ 'harassment',
25
+ 'hate',
26
+ 'violence',
27
+ 'sexual_content',
28
+ 'child_safety',
29
+ 'self_harm',
30
+ 'privacy',
31
+ 'commerce',
32
+ 'platform_abuse',
33
+ 'other',
34
+ ];
35
+ export const TaxonomyFamilySchema = z.enum(TAXONOMY_FAMILIES);
36
+ const INTEGRITY_CODES = [
37
+ 'integrity.spam',
38
+ 'integrity.scam',
39
+ 'integrity.fraud',
40
+ 'integrity.impersonation',
41
+ 'integrity.coordinated_manipulation',
42
+ ];
43
+ const HARASSMENT_CODES = [
44
+ 'harassment.insult',
45
+ 'harassment.targeted_abuse',
46
+ 'harassment.sexual_harassment',
47
+ 'harassment.doxxing',
48
+ 'harassment.credible_threat',
49
+ ];
50
+ const HATE_CODES = [
51
+ 'hate.dehumanization',
52
+ 'hate.slur',
53
+ 'hate.incitement',
54
+ 'hate.protected_targeting',
55
+ ];
56
+ const VIOLENCE_CODES = [
57
+ 'violence.graphic',
58
+ 'violence.threat',
59
+ 'violence.instruction',
60
+ 'violence.celebration',
61
+ ];
62
+ const SEXUAL_CONTENT_CODES = [
63
+ 'sexual_content.nudity',
64
+ 'sexual_content.explicit_activity',
65
+ 'sexual_content.non_consensual',
66
+ 'sexual_content.exploitation',
67
+ ];
68
+ const CHILD_SAFETY_CODES = [
69
+ 'child_safety.sexualization',
70
+ 'child_safety.grooming',
71
+ 'child_safety.exploitation',
72
+ ];
73
+ const SELF_HARM_CODES = [
74
+ 'self_harm.promotion',
75
+ 'self_harm.instruction',
76
+ 'self_harm.imminent_risk',
77
+ ];
78
+ const PRIVACY_CODES = [
79
+ 'privacy.personal_information',
80
+ 'privacy.intimate_media',
81
+ 'privacy.location_exposure',
82
+ ];
83
+ const COMMERCE_CODES = [
84
+ 'commerce.prohibited_item',
85
+ 'commerce.counterfeit',
86
+ 'commerce.misleading_listing',
87
+ 'commerce.unsafe_product',
88
+ ];
89
+ const PLATFORM_ABUSE_CODES = [
90
+ 'platform_abuse.ban_evasion',
91
+ 'platform_abuse.report_abuse',
92
+ 'platform_abuse.automation_abuse',
93
+ ];
94
+ const OTHER_CODES = ['other.policy_specific', 'other.unclassifiable'];
95
+ /**
96
+ * §6.3, grouped.
97
+ *
98
+ * §9.4 requires consensus on the "main taxonomic family", not only on the exact
99
+ * code, so the grouping is part of the contract rather than something the
100
+ * consensus engine re-derives from string prefixes.
101
+ */
102
+ export const TAXONOMY_CODES_BY_FAMILY = Object.freeze({
103
+ integrity: INTEGRITY_CODES,
104
+ harassment: HARASSMENT_CODES,
105
+ hate: HATE_CODES,
106
+ violence: VIOLENCE_CODES,
107
+ sexual_content: SEXUAL_CONTENT_CODES,
108
+ child_safety: CHILD_SAFETY_CODES,
109
+ self_harm: SELF_HARM_CODES,
110
+ privacy: PRIVACY_CODES,
111
+ commerce: COMMERCE_CODES,
112
+ platform_abuse: PLATFORM_ABUSE_CODES,
113
+ other: OTHER_CODES,
114
+ });
115
+ export const UNIVERSAL_TAXONOMY_CODES = [
116
+ ...INTEGRITY_CODES,
117
+ ...HARASSMENT_CODES,
118
+ ...HATE_CODES,
119
+ ...VIOLENCE_CODES,
120
+ ...SEXUAL_CONTENT_CODES,
121
+ ...CHILD_SAFETY_CODES,
122
+ ...SELF_HARM_CODES,
123
+ ...PRIVACY_CODES,
124
+ ...COMMERCE_CODES,
125
+ ...PLATFORM_ABUSE_CODES,
126
+ ...OTHER_CODES,
127
+ ];
128
+ export const TaxonomyCodeSchema = z.enum(UNIVERSAL_TAXONOMY_CODES);
129
+ /**
130
+ * The version of the code list above.
131
+ *
132
+ * §6.4: every decision records the taxonomy version it was decided under, and a
133
+ * policy update never silently rewrites history. Keeping the constant in the
134
+ * same module as the codes is what makes that possible — the two cannot drift.
135
+ * The value is the one the plan uses in Appendix B and §11.6.
136
+ */
137
+ export const UNIVERSAL_TAXONOMY_VERSION = '2026.1';
138
+ /** The family a code belongs to. */
139
+ export function taxonomyFamilyOf(code) {
140
+ const [family] = code.split('.');
141
+ return TaxonomyFamilySchema.parse(family);
142
+ }
143
+ /** §9.4 / §11.8 severity scale. */
144
+ export const SEVERITIES = ['low', 'medium', 'high', 'critical'];
145
+ export const SeveritySchema = z.enum(SEVERITIES);
146
+ /**
147
+ * How far a finding reaches.
148
+ *
149
+ * §11.6 and Appendix B use `oxy_network`; §11.7.5 additionally names
150
+ * `identity_integrity` as a scope that may produce an Oxy Trust effect. The
151
+ * plan never names the third value — the one that means "this matters to the
152
+ * application and stops there" — even though §6.5's entire argument is that
153
+ * most local restrictions must NOT become global sanctions. `application_local`
154
+ * is the contract's name for it and is the ONE token in this package invented
155
+ * rather than quoted. Modelling it as an absent field instead would make
156
+ * §11.7.5 a presence check, which fails open.
157
+ */
158
+ export const FINDING_SCOPES = ['application_local', 'oxy_network', 'identity_integrity'];
159
+ export const FindingScopeSchema = z.enum(FINDING_SCOPES);
160
+ /**
161
+ * Scopes that §11.7.5 allows to reach Oxy Trust.
162
+ *
163
+ * Exported as its own schema so `reputation-events.ts` states the rule in the
164
+ * type rather than re-checking it at runtime.
165
+ */
166
+ export const REPUTATION_ELIGIBLE_FINDING_SCOPES = ['oxy_network', 'identity_integrity'];
167
+ export const ReputationEligibleFindingScopeSchema = z.enum(REPUTATION_ELIGIBLE_FINDING_SCOPES);
168
+ /**
169
+ * Who a finding attributes conduct to.
170
+ *
171
+ * Appendix B and §11.6 use `author`. §11.11 and §11.12 describe confirmed
172
+ * report abuse and confirmed review abuse producing conduct effects of their
173
+ * own, which is where the other two values come from. There is deliberately no
174
+ * `unknown`: attribution exists to name a principal, and §11.7.4 will not let
175
+ * an effect land without a binding proof for that principal anyway.
176
+ */
177
+ export const FINDING_ATTRIBUTIONS = ['author', 'reporter', 'reviewer'];
178
+ export const FindingAttributionSchema = z.enum(FINDING_ATTRIBUTIONS);
179
+ /**
180
+ * What CrowdSource may recommend an application do.
181
+ *
182
+ * The plan writes action tokens in two places. §6.2, §9.3, §10.7 and Appendix B
183
+ * recommend `remove_or_restrict` and `allow_with_label`; §7.6 tabulates, per
184
+ * decision outcome, the actions an application may take in response. They are
185
+ * the same vocabulary seen from the two ends of one exchange, so the contract
186
+ * carries the union as one closed list — otherwise a recommendation and the
187
+ * enforcement that answers it would not be comparable, and §7.6's requirement
188
+ * that an application "record what it did and why" would compare apples to
189
+ * pears.
190
+ *
191
+ * §7.6's outcome→action table is NOT reproduced as a constraint. It bounds what
192
+ * an application may do in response to an outcome, not what a jury may
193
+ * recommend — Appendix B recommends `remove_or_restrict`, which does not appear
194
+ * in §7.6's `violation` row at all. Binding the two would reject the plan's own
195
+ * reference decision.
196
+ */
197
+ export const RECOMMENDED_ACTIONS = [
198
+ 'remove_or_restrict',
199
+ 'allow_with_label',
200
+ 'remove',
201
+ 'hide',
202
+ 'label',
203
+ 'age_gate',
204
+ 'reduce_distribution',
205
+ 'freeze_transaction',
206
+ 'suspend_user',
207
+ 'request_changes',
208
+ 'allow',
209
+ 'restore',
210
+ 'no_action',
211
+ 'request_more_context',
212
+ 'hold',
213
+ 'local_manual_review',
214
+ 'keep_restricted_temporarily',
215
+ 'escalate',
216
+ 'no_global_effect',
217
+ 'specialist_queue',
218
+ 'legal_queue',
219
+ 'safety_queue',
220
+ ];
221
+ export const RecommendedActionSchema = z.enum(RECOMMENDED_ACTIONS);
222
+ /**
223
+ * The context that makes a classification not mean what it usually means —
224
+ * §9.2's and §9.4's "excepción", §6.2's `context`.
225
+ *
226
+ * §6.2's worked example is where this field comes from and what fixes its
227
+ * shape: the jury's finding is `sexual_content.nudity, severity = medium,
228
+ * context = artistic`, and it is that qualifier — not the code and not the
229
+ * severity — that turns the same classification into a violation under one
230
+ * application's policy and not under another's. It therefore belongs to layer
231
+ * one, beside the code: a reviewer describes what the material IS, and
232
+ * "artistic nudity" is a different description from "nudity".
233
+ *
234
+ * §9.4 makes it one of the six dimensions consensus is measured on, which is
235
+ * the reason it must be a CLOSED list. Two reviewers who both answer
236
+ * `no_violation` but for incompatible reasons — one because the material is
237
+ * documentary, one because they think the rule does not cover it at all — have
238
+ * not agreed about the material, and a free-text field could not tell the two
239
+ * apart. An open token would also be a channel for case content to reach a
240
+ * decision record, which §13.5 forbids.
241
+ *
242
+ * Only `artistic` is the plan's own word. The rest are the exception vocabulary
243
+ * every published moderation policy shares, and they are named here rather than
244
+ * left to a tenant because layer one is CrowdSource's (§6.1) — a tenant that
245
+ * could mint its own exception tokens would make findings incomparable across
246
+ * applications, which is exactly what §6.1 exists to prevent. Absence means no
247
+ * exception applies, which is the safe direction: a finding with no exception
248
+ * stands as classified.
249
+ */
250
+ export const FINDING_CONTEXTS = [
251
+ 'artistic',
252
+ 'educational',
253
+ 'documentary',
254
+ 'newsworthy',
255
+ 'satire',
256
+ 'counter_speech',
257
+ 'medical',
258
+ 'consensual',
259
+ 'fictional',
260
+ ];
261
+ export const FindingContextSchema = z.enum(FINDING_CONTEXTS);
262
+ /**
263
+ * A tenant's advance classification of how exposing the material is.
264
+ *
265
+ * The plan names exactly one value — `standard`, in Appendix A — and §7.5
266
+ * clearly implies at least one more (categories that never reach a community
267
+ * jury). Rather than invent the rest, this stays an open lowercase token: it is
268
+ * a HINT (§5.2: "never shown as a verdict"), the authoritative
269
+ * `sensitivity_class` is computed by triage server-side (§12.8), and access to
270
+ * sensitive material is gated on that computed class, never on what the tenant
271
+ * asserted. Closing this list is a product decision that has not been made.
272
+ */
273
+ export const SensitivityHintSchema = z
274
+ .string()
275
+ .min(1)
276
+ .max(40)
277
+ .regex(/^[a-z][a-z0-9_]*$/, 'must be a lowercase token');
278
+ //# sourceMappingURL=taxonomy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"taxonomy.js","sourceRoot":"","sources":["../../src/taxonomy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,188 @@
1
+ /**
2
+ * Outbound webhooks (§10.6–§10.9) and the signature contract (§10.8).
3
+ *
4
+ * §10.11 asks for two behaviours that pull in opposite directions: unknown
5
+ * EVENTS must be ignored safely, and unknown FIELDS must not break clients.
6
+ * This module gives each its own schema rather than compromising on one.
7
+ *
8
+ * * `WebhookEventEnvelopeSchema` validates only what every event has —
9
+ * identity, type, timing, tenant — and leaves `data` opaque. A receiver
10
+ * verifies the signature, records the event id for idempotency, and ignores
11
+ * what it does not recognise, without a schema update ever being the reason
12
+ * a delivery fails.
13
+ * * `KnownWebhookEventSchema` is the discriminated union of the eight events
14
+ * §10.6 defines, for the branch that actually handles one.
15
+ *
16
+ * Everything here is `.loose()`. These payloads travel from CrowdSource to a
17
+ * tenant, so an unknown field is a newer server, not an attack; stripping it
18
+ * would silently discard data from a receiver that persists `event.data` for
19
+ * later processing — which is precisely what §10.8's "respond 2xx quickly and
20
+ * queue the processing" tells receivers to do.
21
+ */
22
+ import { z } from 'zod';
23
+ import { CreateReportResponseSchema } from './case-envelope.js';
24
+ import { DecisionSchema } from './decisions.js';
25
+ import { IdentifierSchema, TimestampSchema } from './primitives.js';
26
+ /** §10.6. */
27
+ export const WEBHOOK_EVENT_TYPES = [
28
+ 'report.received',
29
+ 'case.created',
30
+ 'case.escalated',
31
+ 'case.decided',
32
+ 'decision.corrected',
33
+ 'appeal.created',
34
+ 'appeal.decided',
35
+ 'case.closed',
36
+ ];
37
+ export const WebhookEventTypeSchema = z.enum(WEBHOOK_EVENT_TYPES);
38
+ /**
39
+ * Any event type, including ones this version of the contract does not know.
40
+ *
41
+ * Shape-checked but not enumerated, so that "unknown events must be ignored
42
+ * safely" is something a receiver can DO rather than something it is told about
43
+ * after its parse has already thrown.
44
+ */
45
+ export const AnyWebhookEventTypeSchema = z
46
+ .string()
47
+ .min(3)
48
+ .max(64)
49
+ .regex(/^[a-z][a-z0-9_]*(\.[a-z0-9_]+)+$/, 'must be a dotted lowercase event type');
50
+ const webhookEnvelopeShape = {
51
+ id: IdentifierSchema,
52
+ createdAt: TimestampSchema,
53
+ organizationId: IdentifierSchema,
54
+ applicationId: IdentifierSchema,
55
+ };
56
+ /**
57
+ * The envelope every delivery shares (§10.7), with `data` left opaque.
58
+ *
59
+ * Parse with this first. `id` is the idempotency key §10.8 requires receivers
60
+ * to store; `type` decides whether there is anything to do.
61
+ */
62
+ export const WebhookEventEnvelopeSchema = z.looseObject({
63
+ ...webhookEnvelopeShape,
64
+ type: AnyWebhookEventTypeSchema,
65
+ data: z.record(z.string(), z.unknown()),
66
+ });
67
+ const ReportReceivedEventSchema = z.looseObject({
68
+ ...webhookEnvelopeShape,
69
+ type: z.literal('report.received'),
70
+ /** §10.6: "optional confirmation of receipt and merge" — §10.4's response. */
71
+ data: CreateReportResponseSchema,
72
+ });
73
+ const CaseCreatedEventSchema = z.looseObject({
74
+ ...webhookEnvelopeShape,
75
+ type: z.literal('case.created'),
76
+ data: z.looseObject({ caseId: IdentifierSchema }),
77
+ });
78
+ const CaseEscalatedEventSchema = z.looseObject({
79
+ ...webhookEnvelopeShape,
80
+ type: z.literal('case.escalated'),
81
+ data: z.looseObject({ caseId: IdentifierSchema }),
82
+ });
83
+ const CaseDecidedEventSchema = z.looseObject({
84
+ ...webhookEnvelopeShape,
85
+ type: z.literal('case.decided'),
86
+ data: z.looseObject({ caseId: IdentifierSchema, decision: DecisionSchema }),
87
+ });
88
+ /**
89
+ * §10.6: "a later revision replaces the previous decision".
90
+ *
91
+ * The carried decision must therefore name what it superseded. `DecisionSchema`
92
+ * already requires that of any revision past the first; requiring it again here
93
+ * is what stops a correction from carrying revision 1.
94
+ */
95
+ const DecisionCorrectedEventSchema = z.looseObject({
96
+ ...webhookEnvelopeShape,
97
+ type: z.literal('decision.corrected'),
98
+ data: z.looseObject({
99
+ caseId: IdentifierSchema,
100
+ decision: DecisionSchema.refine((decision) => decision.supersedesDecisionId !== undefined, { message: 'a corrected decision must supersede the decision it replaces' }),
101
+ }),
102
+ });
103
+ const AppealCreatedEventSchema = z.looseObject({
104
+ ...webhookEnvelopeShape,
105
+ type: z.literal('appeal.created'),
106
+ data: z.looseObject({ caseId: IdentifierSchema, appealId: IdentifierSchema }),
107
+ });
108
+ const AppealDecidedEventSchema = z.looseObject({
109
+ ...webhookEnvelopeShape,
110
+ type: z.literal('appeal.decided'),
111
+ data: z.looseObject({
112
+ caseId: IdentifierSchema,
113
+ appealId: IdentifierSchema,
114
+ decision: DecisionSchema,
115
+ }),
116
+ });
117
+ const CaseClosedEventSchema = z.looseObject({
118
+ ...webhookEnvelopeShape,
119
+ type: z.literal('case.closed'),
120
+ data: z.looseObject({ caseId: IdentifierSchema }),
121
+ });
122
+ /**
123
+ * The eight events of §10.6, discriminated on `type`.
124
+ *
125
+ * Only `case.decided` has its payload specified in the plan (§10.7). The other
126
+ * seven carry the case they are about and whatever identifies the object that
127
+ * moved; they are loose, so filling them in later is additive and needs no
128
+ * version bump (§10.11).
129
+ */
130
+ export const KnownWebhookEventSchema = z.discriminatedUnion('type', [
131
+ ReportReceivedEventSchema,
132
+ CaseCreatedEventSchema,
133
+ CaseEscalatedEventSchema,
134
+ CaseDecidedEventSchema,
135
+ DecisionCorrectedEventSchema,
136
+ AppealCreatedEventSchema,
137
+ AppealDecidedEventSchema,
138
+ CaseClosedEventSchema,
139
+ ]);
140
+ /** §10.8 headers, in their canonical casing. HTTP header names are case-insensitive; look them up accordingly. */
141
+ export const WEBHOOK_EVENT_ID_HEADER = 'X-CrowdSource-Event-Id';
142
+ export const WEBHOOK_TIMESTAMP_HEADER = 'X-CrowdSource-Timestamp';
143
+ export const WEBHOOK_SIGNATURE_HEADER = 'X-CrowdSource-Signature';
144
+ /** The signature scheme prefix, as in `v1=<hex>`. */
145
+ export const WEBHOOK_SIGNATURE_VERSION = 'v1';
146
+ /** §10.8: reject timestamps more than five minutes away from now. */
147
+ export const WEBHOOK_TIMESTAMP_TOLERANCE_SECONDS = 300;
148
+ /** Unix seconds, as the header carries them. */
149
+ export const WebhookTimestampHeaderSchema = z
150
+ .string()
151
+ .regex(/^[0-9]{1,15}$/, 'must be unix seconds');
152
+ /** `v1=<64 lowercase hex>` — HMAC-SHA256 of the signed payload. */
153
+ export const WebhookSignatureHeaderSchema = z
154
+ .string()
155
+ .regex(/^v1=[0-9a-f]{64}$/, 'must be "v1=" followed by 64 lowercase hex characters');
156
+ /**
157
+ * The exact bytes both sides sign: `timestamp + "." + rawBody` (§10.8).
158
+ *
159
+ * This lives in the contract, not in the signer or the verifier, because a
160
+ * disagreement between those two about what gets signed is invisible until
161
+ * every delivery starts failing — or, far worse, until a signature validates
162
+ * over bytes that are not the ones the receiver goes on to parse. There is no
163
+ * cryptography here and no transport; the HMAC belongs to the backend's signer
164
+ * and the SDK's middleware.
165
+ *
166
+ * `timestamp` is the header value VERBATIM. Re-deriving it from a parsed number
167
+ * is the mistake this signature exists to catch, and the receiver must verify
168
+ * over exactly what arrived.
169
+ */
170
+ export function buildWebhookSignedPayload(timestamp, rawBody) {
171
+ return `${timestamp}.${rawBody}`;
172
+ }
173
+ /**
174
+ * §10.9's backoff, in seconds after the initial attempt.
175
+ *
176
+ * Published behaviour a tenant plans around, so it belongs to the contract
177
+ * rather than to the delivery worker. After the last one the delivery is
178
+ * `dead_letter`, the tenant is alerted, and replay is manual.
179
+ */
180
+ export const WEBHOOK_RETRY_SCHEDULE_SECONDS = Object.freeze([
181
+ 30,
182
+ 120,
183
+ 900,
184
+ 3600,
185
+ 21600,
186
+ 86400,
187
+ ]);
188
+ //# sourceMappingURL=webhooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"webhooks.js","sourceRoot":"","sources":["../../src/webhooks.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -32,15 +32,17 @@
32
32
  * depth-bounded, scalar-typed, key-restricted and free of prototype-bearing
33
33
  * names.
34
34
  */
35
- export * from './closed';
36
- export * from './primitives';
37
- export * from './taxonomy';
38
- export * from './policies';
39
- export * from './resources';
40
- export * from './case-envelope';
41
- export * from './reviews';
42
- export * from './decisions';
43
- export * from './webhooks';
44
- export * from './reputation-events';
45
- export * from './json-schema';
35
+ export * from './closed.js';
36
+ export * from './primitives.js';
37
+ export * from './taxonomy.js';
38
+ export * from './policies.js';
39
+ export * from './resources.js';
40
+ export * from './case-envelope.js';
41
+ export * from './reviews.js';
42
+ export * from './reviewer-surface.js';
43
+ export * from './decisions.js';
44
+ export * from './appeals.js';
45
+ export * from './webhooks.js';
46
+ export * from './reputation-events.js';
47
+ export * from './json-schema.js';
46
48
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,cAAc,UAAU,CAAC;AACzB,cAAc,cAAc,CAAC;AAC7B,cAAc,YAAY,CAAC;AAC3B,cAAc,YAAY,CAAC;AAC3B,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,qBAAqB,CAAC;AACpC,cAAc,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,cAAc,aAAa,CAAC;AAC5B,cAAc,iBAAiB,CAAC;AAChC,cAAc,eAAe,CAAC;AAC9B,cAAc,eAAe,CAAC;AAC9B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,oBAAoB,CAAC;AACnC,cAAc,cAAc,CAAC;AAC7B,cAAc,uBAAuB,CAAC;AACtC,cAAc,gBAAgB,CAAC;AAC/B,cAAc,cAAc,CAAC;AAC7B,cAAc,eAAe,CAAC;AAC9B,cAAc,wBAAwB,CAAC;AACvC,cAAc,kBAAkB,CAAC"}