@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
package/src/resources.ts CHANGED
@@ -41,9 +41,9 @@ import {
41
41
  OxyFileIdSchema,
42
42
  Sha256DigestSchema,
43
43
  TimestampSchema,
44
- } from './primitives';
45
- import { PolicyVersionSchema } from './policies';
46
- import { SensitivityHintSchema } from './taxonomy';
44
+ } from './primitives.js';
45
+ import { PolicyVersionSchema } from './policies.js';
46
+ import { SensitivityHintSchema } from './taxonomy.js';
47
47
 
48
48
  /** A resource id, unique within one envelope (§5.2 `id`). */
49
49
  export const ResourceIdSchema = IdentifierSchema;
@@ -176,13 +176,46 @@ const resourceBaseShape = {
176
176
  const inlineResourceShape = { ...resourceBaseShape, sha256: Sha256DigestSchema };
177
177
  const assetResourceShape = { ...resourceBaseShape, sha256: Sha256DigestSchema.optional() };
178
178
 
179
+ /**
180
+ * The `data` of each resource type, named.
181
+ *
182
+ * Extracted so the reviewer surface (`reviewer-surface.ts`) can build its own
183
+ * resource union — same content, no `sha256`, a media handle instead of an asset
184
+ * locator — out of THESE schemas rather than restating twelve content shapes.
185
+ * A second copy would drift, and the direction it would drift in is a jury shown
186
+ * less than the application sent.
187
+ */
188
+ export const TextResourceDataSchema = z.strictObject({
189
+ text: z.string().min(1).max(CONTRACT_LIMITS.TEXT_RESOURCE_MAX_LENGTH),
190
+ formatting: TextFormattingSchema.optional(),
191
+ });
192
+
179
193
  const TextResourceSchema = z.strictObject({
180
194
  ...inlineResourceShape,
181
195
  type: z.literal('text'),
182
- data: z.strictObject({
183
- text: z.string().min(1).max(CONTRACT_LIMITS.TEXT_RESOURCE_MAX_LENGTH),
184
- formatting: TextFormattingSchema.optional(),
185
- }),
196
+ data: TextResourceDataSchema,
197
+ });
198
+
199
+ export const VideoResourceDataSchema = z.strictObject({
200
+ timeRange: z
201
+ .strictObject({
202
+ startSeconds: z.number().nonnegative(),
203
+ endSeconds: z.number().positive(),
204
+ })
205
+ .refine((range) => range.endSeconds > range.startSeconds, {
206
+ message: 'endSeconds must be greater than startSeconds',
207
+ path: ['endSeconds'],
208
+ })
209
+ .optional(),
210
+ });
211
+
212
+ export const AudioResourceDataSchema = z.strictObject({
213
+ transcript: z.string().max(CONTRACT_LIMITS.EXTRACTED_TEXT_MAX_LENGTH).optional(),
214
+ });
215
+
216
+ export const DocumentResourceDataSchema = z.strictObject({
217
+ title: z.string().min(1).max(CONTRACT_LIMITS.SHORT_TEXT_MAX_LENGTH),
218
+ extractedText: z.string().max(CONTRACT_LIMITS.EXTRACTED_TEXT_MAX_LENGTH).optional(),
186
219
  });
187
220
 
188
221
  const ImageResourceSchema = z
@@ -198,20 +231,7 @@ const VideoResourceSchema = z
198
231
  ...assetResourceShape,
199
232
  type: z.literal('video'),
200
233
  asset: AssetRefSchema,
201
- data: z
202
- .strictObject({
203
- timeRange: z
204
- .strictObject({
205
- startSeconds: z.number().nonnegative(),
206
- endSeconds: z.number().positive(),
207
- })
208
- .refine((range) => range.endSeconds > range.startSeconds, {
209
- message: 'endSeconds must be greater than startSeconds',
210
- path: ['endSeconds'],
211
- })
212
- .optional(),
213
- })
214
- .optional(),
234
+ data: VideoResourceDataSchema.optional(),
215
235
  })
216
236
  .superRefine((resource, ctx) => {
217
237
  mediaTypeMismatch(ctx, resource.asset.mimeType, ['video/']);
@@ -229,11 +249,7 @@ const AudioResourceSchema = z
229
249
  ...assetResourceShape,
230
250
  type: z.literal('audio'),
231
251
  asset: AssetRefSchema,
232
- data: z
233
- .strictObject({
234
- transcript: z.string().max(CONTRACT_LIMITS.EXTRACTED_TEXT_MAX_LENGTH).optional(),
235
- })
236
- .optional(),
252
+ data: AudioResourceDataSchema.optional(),
237
253
  })
238
254
  .superRefine((resource, ctx) => {
239
255
  mediaTypeMismatch(ctx, resource.asset.mimeType, ['audio/']);
@@ -251,34 +267,30 @@ const DocumentResourceSchema = z
251
267
  ...assetResourceShape,
252
268
  type: z.literal('document'),
253
269
  asset: AssetRefSchema,
254
- data: z.strictObject({
255
- title: z.string().min(1).max(CONTRACT_LIMITS.SHORT_TEXT_MAX_LENGTH),
256
- extractedText: z.string().max(CONTRACT_LIMITS.EXTRACTED_TEXT_MAX_LENGTH).optional(),
257
- }),
270
+ data: DocumentResourceDataSchema,
258
271
  })
259
272
  .superRefine((resource, ctx) =>
260
273
  mediaTypeMismatch(ctx, resource.asset.mimeType, ['application/', 'text/']),
261
274
  );
262
275
 
276
+ export const LinkResourceDataSchema = z.strictObject({
277
+ url: HttpUrlSchema,
278
+ title: z.string().max(CONTRACT_LIMITS.SHORT_TEXT_MAX_LENGTH).optional(),
279
+ resolvedHost: z
280
+ .string()
281
+ .max(253)
282
+ .regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/, 'must be a hostname')
283
+ .optional(),
284
+ snapshot: z.string().max(CONTRACT_LIMITS.EXTRACTED_TEXT_MAX_LENGTH).optional(),
285
+ });
286
+
263
287
  const LinkResourceSchema = z.strictObject({
264
288
  ...inlineResourceShape,
265
289
  type: z.literal('link'),
266
- data: z.strictObject({
267
- url: HttpUrlSchema,
268
- title: z.string().max(CONTRACT_LIMITS.SHORT_TEXT_MAX_LENGTH).optional(),
269
- resolvedHost: z
270
- .string()
271
- .max(253)
272
- .regex(/^[a-z0-9]([a-z0-9-]*[a-z0-9])?(\.[a-z0-9]([a-z0-9-]*[a-z0-9])?)*$/, 'must be a hostname')
273
- .optional(),
274
- snapshot: z.string().max(CONTRACT_LIMITS.EXTRACTED_TEXT_MAX_LENGTH).optional(),
275
- }),
290
+ data: LinkResourceDataSchema,
276
291
  });
277
292
 
278
- const ProfileResourceSchema = z.strictObject({
279
- ...inlineResourceShape,
280
- type: z.literal('profile'),
281
- data: z.strictObject({
293
+ export const ProfileResourceDataSchema = z.strictObject({
282
294
  /**
283
295
  * Every field is optional on purpose. A federated or unresolved actor
284
296
  * routinely has no display name, and requiring one would push applications
@@ -289,41 +301,50 @@ const ProfileResourceSchema = z.strictObject({
289
301
  bio: z.string().max(CONTRACT_LIMITS.LONG_TEXT_MAX_LENGTH).optional(),
290
302
  /** An `image` resource in the same envelope. */
291
303
  avatarRef: ResourceIdSchema.optional(),
292
- claims: MetadataBagSchema.optional(),
293
- }),
304
+ claims: MetadataBagSchema.optional(),
294
305
  });
295
306
 
296
- const ConversationResourceSchema = z.strictObject({
307
+ const ProfileResourceSchema = z.strictObject({
297
308
  ...inlineResourceShape,
298
- type: z.literal('conversation'),
299
- data: z.strictObject({
309
+ type: z.literal('profile'),
310
+ data: ProfileResourceDataSchema,
311
+ });
312
+
313
+ export const ConversationResourceDataSchema = z.strictObject({
300
314
  /**
301
315
  * Ordered (§5.3). §13.5 asks for five messages around the incident rather
302
316
  * than the whole thread, which is why this is a bounded list of ids the
303
317
  * application chose, not a pointer to a conversation.
304
318
  */
305
- messageResourceIds: z
306
- .array(ResourceIdSchema)
307
- .min(1)
308
- .max(CONTRACT_LIMITS.CONVERSATION_MESSAGES_MAX),
309
- }),
319
+ messageResourceIds: z
320
+ .array(ResourceIdSchema)
321
+ .min(1)
322
+ .max(CONTRACT_LIMITS.CONVERSATION_MESSAGES_MAX),
323
+ });
324
+
325
+ const ConversationResourceSchema = z.strictObject({
326
+ ...inlineResourceShape,
327
+ type: z.literal('conversation'),
328
+ data: ConversationResourceDataSchema,
329
+ });
330
+
331
+ export const ListingResourceDataSchema = z.strictObject({
332
+ title: z.string().min(1).max(CONTRACT_LIMITS.SHORT_TEXT_MAX_LENGTH),
333
+ description: z.string().max(CONTRACT_LIMITS.LONG_TEXT_MAX_LENGTH).optional(),
334
+ price: z.number().finite().nonnegative().optional(),
335
+ currency: z
336
+ .string()
337
+ .regex(/^[A-Z]{3}$/, 'must be an ISO 4217 alphabetic code')
338
+ .optional(),
339
+ sellerRef: PrincipalRefSchema.optional(),
340
+ mediaRefs: z.array(ResourceIdSchema).max(CONTRACT_LIMITS.LISTING_MEDIA_REFS_MAX).optional(),
310
341
  });
311
342
 
312
343
  const ListingResourceSchema = z
313
344
  .strictObject({
314
345
  ...inlineResourceShape,
315
346
  type: z.literal('listing'),
316
- data: z.strictObject({
317
- title: z.string().min(1).max(CONTRACT_LIMITS.SHORT_TEXT_MAX_LENGTH),
318
- description: z.string().max(CONTRACT_LIMITS.LONG_TEXT_MAX_LENGTH).optional(),
319
- price: z.number().finite().nonnegative().optional(),
320
- currency: z
321
- .string()
322
- .regex(/^[A-Z]{3}$/, 'must be an ISO 4217 alphabetic code')
323
- .optional(),
324
- sellerRef: PrincipalRefSchema.optional(),
325
- mediaRefs: z.array(ResourceIdSchema).max(CONTRACT_LIMITS.LISTING_MEDIA_REFS_MAX).optional(),
326
- }),
347
+ data: ListingResourceDataSchema,
327
348
  })
328
349
  .superRefine((resource, ctx) => {
329
350
  const hasPrice = resource.data.price !== undefined;
@@ -343,15 +364,17 @@ const COARSE_COORDINATE_DECIMALS = 2;
343
364
  const isCoarse = (value: number): boolean =>
344
365
  Number.isInteger(value * 10 ** COARSE_COORDINATE_DECIMALS);
345
366
 
367
+ export const LocationResourceDataSchema = z.strictObject({
368
+ label: z.string().max(CONTRACT_LIMITS.SHORT_TEXT_MAX_LENGTH).optional(),
369
+ latitude: z.number().min(-90).max(90).optional(),
370
+ longitude: z.number().min(-180).max(180).optional(),
371
+ });
372
+
346
373
  const LocationResourceSchema = z
347
374
  .strictObject({
348
375
  ...inlineResourceShape,
349
376
  type: z.literal('location'),
350
- data: z.strictObject({
351
- label: z.string().max(CONTRACT_LIMITS.SHORT_TEXT_MAX_LENGTH).optional(),
352
- latitude: z.number().min(-90).max(90).optional(),
353
- longitude: z.number().min(-180).max(180).optional(),
354
- }),
377
+ data: LocationResourceDataSchema,
355
378
  })
356
379
  .superRefine((resource, ctx) => {
357
380
  const { label, latitude, longitude } = resource.data;
@@ -391,12 +414,15 @@ const LocationResourceSchema = z
391
414
  }
392
415
  });
393
416
 
417
+ export const MetadataResourceDataSchema = MetadataBagSchema.refine(
418
+ (bag) => Object.keys(bag).length >= 1,
419
+ { message: 'a metadata resource must carry at least one field' },
420
+ );
421
+
394
422
  const MetadataResourceSchema = z.strictObject({
395
423
  ...inlineResourceShape,
396
424
  type: z.literal('metadata'),
397
- data: MetadataBagSchema.refine((bag) => Object.keys(bag).length >= 1, {
398
- message: 'a metadata resource must carry at least one field',
399
- }),
425
+ data: MetadataResourceDataSchema,
400
426
  });
401
427
 
402
428
  const CustomResourceSchema = z.strictObject({