calmlens 0.19.0 → 0.21.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.
data/sig/types.rbs CHANGED
@@ -27,8 +27,10 @@ module CalmLens
27
27
 
28
28
  # ---- Assets (Asset.ts) ----------------------------------------------------------------------
29
29
 
30
- # Where the asset is in the pipeline.
31
- type asset_classification_status = "pending" | "processing" | "completed" | "failed"
30
+ # Where the asset is in the pipeline: `queued` while it waits for its content (a multipart upload
31
+ # still receiving parts) or its turn, `processing`, then `completed` or `failed`. The asset is
32
+ # settled once it is `completed` or `failed`.
33
+ type asset_classification_status = "queued" | "processing" | "completed" | "failed"
32
34
  # A moderation decision, which also decides delivery: served to anyone with access (`allowed`),
33
35
  # served like `allowed` but marked so your app reduces its reach (`limited`), only through signed
34
36
  # URLs or API keys (`age-restricted`), not served (`blocked`), or not served with the stored
@@ -41,7 +43,7 @@ module CalmLens
41
43
  type asset_content_status = "temporary" | "stored" | "removed"
42
44
  type asset_content_removal_reason = "policy" | "retention" | "requested" | "parent-removed" | "disposed"
43
45
  # Why processing failed, while the classification status is `failed`.
44
- type asset_classification_failure_reason = "file-too-large" | "duration-limit" | "resolution-limit" | "unsupported-format" | "undecodable-content" | "multiple-tracks" | "type-mismatch" | "free-upload-limit" | "child-failed" | "processing-error"
46
+ type asset_classification_failure_reason = "file-too-large" | "duration-limit" | "resolution-limit" | "unsupported-format" | "undecodable-content" | "multiple-tracks" | "type-mismatch" | "free-uploads-exhausted" | "media-limit" | "uploads-paused" | "too-many-items" | "processing-error"
45
47
  type asset_type = "image" | "video" | "audio" | "plaintext-document" | "multimedia-document" | "website" | "file"
46
48
  type asset_visibility = "public" | "private"
47
49
  # FLAGGED_CONTENT_ACTION_SCHEMA in PolicyRule.ts.
@@ -66,7 +68,11 @@ module CalmLens
66
68
  ?ocr: { enabled: bool }?,
67
69
  ?person_detection: { enabled: bool }?,
68
70
  ?face_detection: { enabled: bool, ?age_estimation: bool }?,
69
- ?link_detection: { enabled: bool }?
71
+ ?link_detection: { enabled: bool }?,
72
+ # Preview. Prepares an adaptive stream (HLS) of audio or video, served at the `hls` resource and
73
+ # played by the `embed` resource; needs `keep_content_after_processing`. Left out, the project's
74
+ # streaming setting decides.
75
+ ?streaming: { enabled: bool }?
70
76
  }
71
77
  type processing_options_input = {
72
78
  ?keep_content_after_processing: bool?,
@@ -76,20 +82,6 @@ module CalmLens
76
82
  ?features: processing_features_input?
77
83
  }
78
84
 
79
- type processing_features = {
80
- ?"ocr" => { "enabled" => bool }?,
81
- ?"personDetection" => { "enabled" => bool }?,
82
- ?"faceDetection" => { "enabled" => bool, ?"ageEstimation" => bool }?,
83
- ?"linkDetection" => { "enabled" => bool }?,
84
- ?"aiGeneratedDetection" => { "enabled" => bool }?
85
- }
86
- # The processing options an asset was uploaded with.
87
- type processing_options = {
88
- ?"keepContentAfterProcessing" => bool?,
89
- ?"storeSensitiveMetadata" => bool?,
90
- ?"features" => processing_features?
91
- }
92
-
93
85
  type checksums = {
94
86
  ?"md5" => String?,
95
87
  ?"sha1" => String?,
@@ -97,20 +89,42 @@ module CalmLens
97
89
  ?"sha384" => String?,
98
90
  ?"sha512" => String?
99
91
  }
100
- # The picture served at the rendered resource; it remains after the content is removed.
101
- type asset_image = {
92
+ # One rendition of an adaptive stream: `video` for a picture size (video renditions carry no sound;
93
+ # they play with the `audio` rendition), or `audio`. `bandwidth` is the peak bit rate in bits per
94
+ # second, counting the audio a video rendition plays with; `codecs` are RFC 6381 names.
95
+ type asset_hls_rendition = {
96
+ "kind" => "video" | "audio",
97
+ "width" => Integer?,
98
+ "height" => Integer?,
99
+ "bandwidth" => Integer,
100
+ "codecs" => String
101
+ }
102
+ # Preview. The adaptive stream of audio or video: HLS with fragmented MP4 (CMAF) segments, served
103
+ # at the CDN's `hls` resource (`hls/index.m3u8`) and played by its `embed` resource. Renditions list
104
+ # video from the largest down, then audio.
105
+ type asset_hls = { "renditions" => Array[asset_hls_rendition] }
106
+ type asset_rendered_kind = "image" | "pdf" | "video" | "audio"
107
+ # The asset's one displayable file, as the CDN's `rendered` resource serves it: an image, a PDF, or
108
+ # browser-safe video or audio. `peaks` is an audio waveform's normalised peaks.
109
+ type asset_rendered = {
110
+ "kind" => asset_rendered_kind,
111
+ "format" => String,
112
+ "width" => Integer?,
113
+ "height" => Integer?,
114
+ ?"peaks" => Array[Float]
115
+ }
116
+ # The still image that stands for the asset, as the CDN's `preview` resource serves it; the
117
+ # `placeholder` resource is its ThumbHash as a small blurred PNG.
118
+ type asset_preview = {
102
119
  "width" => Integer?,
103
120
  "height" => Integer?,
104
121
  "thumbhash" => String?,
105
- "averageColor" => String?,
106
- "perceptualHash" => String?,
107
- # How much detail `perceptualHash` captured, from 0 to 100; hashes below 50 match unrelated pictures.
108
- "perceptualHashQuality" => Integer?
122
+ "averageColor" => String?
109
123
  }
110
124
  type safety_hold = { "placedAt" => Integer, "reason" => "suspected-illegal-content", ?"disposedAt" => Integer? }
111
125
  # `type: "string"` carries the text in `content`; `type: "document"` stores it under `id`.
112
126
  type extracted_text = { "type" => "string" | "document", ?"content" => String, ?"id" => String }
113
- # Descriptive metadata embedded in an uploaded image. `capturedAt` is ISO 8601, with a UTC offset
127
+ # Descriptive metadata embedded in an uploaded file. `capturedAt` is ISO 8601, with a UTC offset
114
128
  # only when the file records one. `digitalSourceType` is the IPTC code the file declares, such as
115
129
  # `digitalCapture`. `containsLocation` says whether the uploaded file embedded GPS coordinates;
116
130
  # `creator` and `location` are sensitive and recorded only when `storeSensitiveMetadata` is on.
@@ -129,48 +143,76 @@ module CalmLens
129
143
  }
130
144
 
131
145
  type asset_upload = { "status" => "uploading" | "completed", "updatedAt" => Integer?, "partsReceived" => Integer? }
146
+ # How many sections of long audio or video are analysed so far.
147
+ type classification_progress = { "completedSections" => Integer, "totalSections" => Integer }
132
148
  type asset_classification = {
133
149
  "status" => asset_classification_status,
134
150
  # `null` unless `status` is `failed`.
135
151
  "failureReason" => asset_classification_failure_reason?,
136
152
  "updatedAt" => Integer?,
137
153
  "completedAt" => Integer?,
154
+ # While long audio or video is analysed in sections and `status` is `processing`: how many of its
155
+ # sections are done. `nil` otherwise.
156
+ "progress" => classification_progress?,
157
+ # Whether the results came from one of the project's test inputs rather than analysing the
158
+ # content. Never use test results, such as age ranges, for real decisions.
159
+ "testInput" => bool,
138
160
  "moderation" => asset_moderation,
139
- ?"personDetection" => person_detection_result,
140
- ?"faceDetection" => face_detection_result,
141
- ?"linkDetection" => link_detection_result,
142
- # Preview. Where the asset's links lead; present when the project's policy acts on links.
143
- ?"linkSafety" => link_safety_result,
144
- ?"aiGeneratedDetection" => ai_generated_detection_result,
145
- # Where OCR found text, and personal information within it; redaction transforms blur these regions.
146
- ?"textRegions" => Array[text_region],
147
- ?"labels" => Array[classification_label]?
148
- }
161
+ # OCR's result for an image processed with OCR turned on; `nil` when OCR didn't run.
162
+ "ocr" => ocr_result?,
163
+ # Link detection's result for an image; `nil` when it didn't run.
164
+ "linkDetection" => link_detection_result?,
165
+ # Preview. Person and face detection's results; `nil` when they didn't run.
166
+ ?"personDetection" => person_detection_result?,
167
+ ?"faceDetection" => face_detection_result?,
168
+ # Preview. Where the asset's links lead when the project's policy acts on links; otherwise `nil`.
169
+ ?"linkSafety" => link_safety_result?,
170
+ ?"aiGeneratedDetection" => ai_generated_detection_result?
171
+ }
172
+ # Who made a review: a person (`user`, also when an assistant's key acts for one) or an API key
173
+ # (`api-key`), with the user's or API key's ID, `nil` only when it was not recorded.
174
+ type review_actor = { "type" => "user" | "api-key", "id" => String? }
149
175
  type asset_review = {
150
176
  "id" => String,
151
177
  "decision" => asset_moderation_decision,
152
178
  "note" => String?,
153
- ?"reviewerName" => String?,
154
- ?"reviewerEmail" => String?,
179
+ "decidedBy" => review_actor,
155
180
  "reviewedAt" => Integer,
156
- "appliedToAsset" => bool
157
- }
158
- type regional_decision = { "region" => String, "action" => String, "rule" => String, ?"category" => String }
159
- type test_regional_action = { "region" => String, "action" => String }
181
+ # Whether the decision was applied to the asset; `false` for a review queue decision recorded
182
+ # without changing the asset's status.
183
+ "applied" => bool
184
+ }
185
+ # A stricter delivery decision in one region the project serves: the status in force there, the
186
+ # mandatory rule that sets it and the category whose findings it acted on, when it acts on one.
187
+ type regional_decision = {
188
+ "region" => String,
189
+ "status" => "limited" | "age-restricted" | "blocked" | "purged",
190
+ "rule" => String,
191
+ ?"category" => String
192
+ }
193
+ # What decided the automated status: the `policy`'s categories, the asset's `children`, a
194
+ # `hash-list` match, a `mandatory-rule` or `link-safety`.
195
+ type moderation_source = "policy" | "children" | "hash-list" | "mandatory-rule" | "link-safety"
196
+ # Every field but `status`, `manualReviews`, `flaggedCategories`, `regions` and `timeline` is `nil`
197
+ # until moderation decides.
160
198
  type asset_moderation = {
161
- ?"testCategoryActions" => Hash[String, String],
162
- ?"testRegionalActions" => Array[test_regional_action],
163
199
  "manualReviews" => Array[asset_review],
164
200
  "status" => asset_moderation_status,
165
- ?"automatedAction" => flagged_content_action,
166
- ?"source" => String, ?"rule" => String,
201
+ # The policy's original decision; a reviewer's decision can change `status` without changing it.
202
+ "automatedStatus" => asset_moderation_decision?,
203
+ "source" => moderation_source?,
204
+ # The mandatory rule that decided, when `source` is `mandatory-rule`; otherwise `nil`.
205
+ "rule" => String?,
167
206
  "flaggedCategories" => Array[String], "regions" => Array[regional_decision],
168
- ?"explanationComplete" => bool,
169
- ?"categories" => Hash[String, category_policy_score],
170
- # Preview. What the policy's link-safety section made of the asset's links; absent when the
207
+ "explanationComplete" => bool?,
208
+ "categories" => Hash[String, category_policy_score]?,
209
+ # Preview. What the policy's link-safety section made of the asset's links; `nil` when the
171
210
  # policy doesn't act on links.
172
- ?"linkSafety" => link_safety_decision,
173
- ?"raw" => moderation_raw
211
+ ?"linkSafety" => link_safety_decision?,
212
+ # An audio or video asset's findings timeline: how many segments `assets.list_timeline` lists.
213
+ # `null` for other assets and media without findings.
214
+ "timeline" => moderation_timeline?,
215
+ "raw" => moderation_raw?
174
216
  }
175
217
  # ASSET_CONTENT_SCHEMA. `format` is the MIME type.
176
218
  type asset_content = {
@@ -182,11 +224,25 @@ module CalmLens
182
224
  "extension" => String?,
183
225
  "sizeInBytes" => Integer?,
184
226
  "checksums" => checksums?,
185
- "image" => asset_image?,
227
+ # The file's own size, length and page count, where they apply; `null` when unknown.
228
+ "width" => Integer?,
229
+ "height" => Integer?,
230
+ "durationSeconds" => Float?,
231
+ "pageCount" => Integer?,
232
+ "perceptualHash" => String?,
233
+ # How much detail `perceptualHash` captured, from 0 to 100; hashes below 50 match unrelated pictures.
234
+ "perceptualHashQuality" => Integer?,
235
+ # Metadata embedded in the uploaded file; `null` when it declares none, once the content is
236
+ # removed and while the asset is held.
237
+ "metadata" => file_metadata?,
186
238
  "extractedText" => extracted_text?,
187
- # Metadata embedded in an uploaded image; `null` when it declares none, for other asset types,
188
- # once the content is removed and while the asset is held.
189
- "fileMetadata" => file_metadata?
239
+ # `null` until processing makes it, for text, spreadsheets and other files, once the content is
240
+ # removed and while the asset is held.
241
+ "rendered" => asset_rendered?,
242
+ # Preview. The adaptive stream once streaming has prepared one for audio or video; `nil` for
243
+ # other assets, until then, once the content is removed and while the asset is held.
244
+ "hls" => asset_hls?,
245
+ "preview" => asset_preview?
190
246
  }
191
247
 
192
248
  type asset = {
@@ -202,13 +258,14 @@ module CalmLens
202
258
  ?"externalId" => String?,
203
259
  ?"externalUrl" => String?,
204
260
  "type" => asset_type,
205
- ?"metadata" => Array[metadata_item]?,
261
+ # Empty when the asset has none.
262
+ "metadata" => Array[metadata_item],
206
263
  ?"authorId" => String?,
207
264
  # The earlier posts CalmLens used; null once the content is removed.
208
265
  ?"context" => moderation_context?,
209
- ?"tags" => Array[String]?,
210
- ?"processingOptions" => processing_options?,
211
- ?"visibility" => asset_visibility?,
266
+ # Empty when the asset has none.
267
+ "tags" => Array[String],
268
+ "visibility" => asset_visibility,
212
269
  "upload" => asset_upload,
213
270
  "classification" => asset_classification,
214
271
  "content" => asset_content
@@ -234,14 +291,12 @@ module CalmLens
234
291
 
235
292
  # `status: "evaluated"` or `"partial"` carries `likelihood` and `score`; `"not-evaluated"`
236
293
  # carries `reason`.
237
- type policy_condition_result = { "status" => "evaluated" | "not-evaluated", ?"score" => number, ?"reason" => not_evaluated_reason }
238
294
  type category_report = {
239
295
  "status" => "evaluated" | "partial" | "not-evaluated",
240
296
  ?"likelihood" => likelihood,
241
297
  ?"score" => number,
242
298
  ?"reason" => not_evaluated_reason,
243
- ?"qualifiers" => qualifier_results,
244
- ?"policyConditions" => Hash[String, policy_condition_result]
299
+ ?"qualifiers" => qualifier_results
245
300
  }
246
301
  type classification_categories = {
247
302
  "sexual" => category_report,
@@ -253,44 +308,27 @@ module CalmLens
253
308
  "personal-information" => category_report,
254
309
  "profanity" => category_report
255
310
  }
256
- type classification_label = {
257
- "description" => String,
258
- "score" => number,
259
- ?"topicalityScore" => number?,
260
- "likelihood" => likelihood,
261
- ?"knowledgeBaseId" => String?
262
- }
263
311
  type media_segment = {
264
312
  "source" => "frame" | "speech" | "frame-text" | "clip",
265
313
  "startSeconds" => number,
266
314
  "endSeconds" => number,
267
315
  "categories" => classification_categories
268
316
  }
269
- type media_report = {
270
- "durationSeconds" => number,
271
- ?"frameIntervalSeconds" => number,
272
- "sampledFrames" => Integer,
273
- "audioTranscribed" => bool,
274
- "segments" => Array[media_segment]
275
- }
276
317
 
277
318
  # Position and size as fractions of the image width and height, from 0 to 1.
278
319
  type bounding_box = { "left" => number, "top" => number, "width" => number, "height" => number }
279
320
  type age_range = { "low" => Integer, "high" => Integer }
280
321
  type detected_person = { "box" => bounding_box, "confidence" => number }
281
322
  type detected_face = { "box" => bounding_box, "confidence" => number, ?"ageRange" => age_range }
282
- type processing_feature_stage = "beta" | "ga"
283
323
  # `status: "evaluated"` carries `people`; `"not-evaluated"` carries `reason`.
284
324
  type person_detection_result = {
285
325
  "status" => "evaluated" | "not-evaluated",
286
- "stage" => processing_feature_stage,
287
326
  ?"people" => Array[detected_person],
288
327
  ?"reason" => not_evaluated_reason
289
328
  }
290
329
  # `status: "evaluated"` carries `faces`; `"not-evaluated"` carries `reason`.
291
330
  type face_detection_result = {
292
331
  "status" => "evaluated" | "not-evaluated",
293
- "stage" => processing_feature_stage,
294
332
  ?"faces" => Array[detected_face],
295
333
  ?"reason" => not_evaluated_reason
296
334
  }
@@ -300,7 +338,6 @@ module CalmLens
300
338
  # `status: "evaluated"` carries `qrCodes` and `links`; `"not-evaluated"` carries `reason`.
301
339
  type link_detection_result = {
302
340
  "status" => "evaluated" | "not-evaluated",
303
- "stage" => processing_feature_stage,
304
341
  ?"qrCodes" => Array[detected_qr_code],
305
342
  ?"links" => Array[detected_link],
306
343
  ?"reason" => not_evaluated_reason
@@ -338,7 +375,6 @@ module CalmLens
338
375
  # Preview. `status: "evaluated"` carries `links`; `"not-evaluated"` carries `reason`.
339
376
  type link_safety_result = {
340
377
  "status" => "evaluated" | "not-evaluated",
341
- "stage" => processing_feature_stage,
342
378
  ?"links" => Array[checked_link],
343
379
  ?"reason" => not_evaluated_reason
344
380
  }
@@ -355,66 +391,71 @@ module CalmLens
355
391
  },
356
392
  ?"offPlatformLinks" => { "action" => "limit" | "age-restrict" | "block", "allowedDomains" => Array[String] }
357
393
  }
358
- # Preview. The strongest action the asset's links take, the indexes into
359
- # `classification.linkSafety.links` of the links that take it, and the settings in force.
394
+ # Preview. The strongest action the asset's links take, the checked links that take it, and the
395
+ # settings in force.
360
396
  type link_safety_decision = {
361
397
  "action" => link_safety_action,
362
- "links" => Array[Integer],
398
+ "links" => Array[checked_link],
363
399
  "settings" => link_safety_settings
364
400
  }
365
401
  type provenance_signal = { "kind" => "c2pa" | "iptc-digital-source-type" | "generator-metadata", "value" => String }
366
402
  # `status: "evaluated"` carries `provenance` and `signals`; `"not-evaluated"` carries `reason`.
367
403
  type ai_generated_detection_result = {
368
404
  "status" => "evaluated" | "not-evaluated",
369
- "stage" => processing_feature_stage,
370
405
  ?"provenance" => "ai-generated" | "ai-edited" | "unknown",
371
406
  ?"signals" => Array[provenance_signal],
372
407
  ?"reason" => not_evaluated_reason
373
408
  }
374
409
  # Where OCR found text in an image, and whether it is personal information.
375
410
  type text_region = { "box" => bounding_box, "personalInformation" => bool }
376
- # Results of the features requested in `processingOptions.features`. OCR stores extracted text on the image
377
- # asset instead of a result here.
378
- type processing_feature_results = {
379
- ?"personDetection" => person_detection_result,
380
- ?"faceDetection" => face_detection_result,
381
- ?"linkDetection" => link_detection_result,
382
- ?"linkSafety" => link_safety_result,
383
- ?"aiGeneratedDetection" => ai_generated_detection_result
411
+ # `status: "evaluated"` carries `textRegions`, where OCR found text (redaction transforms blur
412
+ # these regions); `"not-evaluated"` carries `reason`. The text itself is `content.extractedText`.
413
+ type ocr_result = {
414
+ "status" => "evaluated" | "not-evaluated",
415
+ ?"textRegions" => Array[text_region],
416
+ ?"reason" => not_evaluated_reason
384
417
  }
385
418
 
386
419
  # How strongly each assessed category meets the policy and what the policy does with it.
387
420
  type policy_rule_snapshot = {
388
421
  "when" => Array[String], "action" => flagged_content_action,
389
- ?"name" => String, ?"match" => "all", ?"unless" => Array[String]
422
+ ?"name" => String, ?"unless" => Array[String]
390
423
  }
391
- type category_policy_source = { "kind" => String, ?"index" => Integer, ?"indexes" => Array[Integer] }
424
+ # What decided a category's action: its `default` action, a policy score `below-threshold`, or the
425
+ # `allowance` or `restriction` rules listed by `indexes` (at least one, the decisive rule first).
426
+ type category_policy_source = { "kind" => "default" | "below-threshold" } |
427
+ { "kind" => "allowance" | "restriction", "indexes" => Array[Integer] }
392
428
  type category_policy_settings_snapshot = {
393
- "categoryAction" => flagged_content_action,
429
+ "action" => flagged_content_action,
394
430
  "allowances" => Array[policy_rule_snapshot], "restrictions" => Array[policy_rule_snapshot]
395
431
  }
396
432
  type category_policy_score = {
397
433
  "score" => number, "action" => flagged_content_action,
398
434
  ?"source" => category_policy_source, ?"settings" => category_policy_settings_snapshot
399
435
  }
436
+ type moderation_timeline = { "segmentCount" => Integer }
400
437
  type moderation_raw = {
401
438
  "categories" => classification_categories,
402
- ?"timeline" => media_report,
403
- ?"hashMatches" => Array[hash_match]
439
+ # Empty when the image matched no hash list entry.
440
+ "hashMatches" => Array[hash_match]
404
441
  }
405
442
 
406
443
  # ---- Pages and search (Page.ts, AssetSearch.ts) --------------------------------------------
407
444
 
408
- type order_direction = "asc" | "desc"
409
- type order_input = { field: String, direction: order_direction }
410
- type order = { "field" => String, "direction" => order_direction }
445
+ # A list's sort: comma-separated fields, each ascending unless prefixed with `-`, such as
446
+ # `-createdAt,id`.
447
+ type sort = String
411
448
 
412
449
  type asset_page = {
413
450
  "items" => Array[asset],
414
451
  "hasMore" => bool,
415
- "nextCursor" => String?,
416
- "pageSize" => Integer,
417
- "ordering" => Array[order]
452
+ "nextCursor" => String?
453
+ }
454
+ # One page of an audio or video asset's findings timeline, in time order.
455
+ type asset_timeline_page = {
456
+ "items" => Array[media_segment],
457
+ "hasMore" => bool,
458
+ "nextCursor" => String?
418
459
  }
419
460
 
420
461
  type asset_search_mode = "keyword" | "semantic" | "hybrid"
@@ -428,8 +469,32 @@ module CalmLens
428
469
  }
429
470
 
430
471
  type asset_batch_operation = "delete" | "remove-content"
431
- type batch_assets_response = { "queued" => bool }
432
- type signed_url = { "url" => String, "expiresAt" => Integer }
472
+ # `batchId` is named by the `batch-id` fact of the events the batch causes.
473
+ type batch_assets_response = { "batchId" => String, "status" => "queued", "assetCount" => Integer }
474
+ # A signed asset URL, with any resource, selector and viewer claims appended, and when it expires
475
+ # (milliseconds since the Unix epoch).
476
+ type signed_asset_url = { "url" => String, "expiresAt" => Integer }
477
+ # Whether the viewer an asset URL's claims describe can see the content now.
478
+ type asset_availability = "available" | "age-restricted" | "unavailable"
479
+ # ASSET_INFO_SCHEMA: what the CDN's `info` resource returns, an allowlist of the asset's public
480
+ # fields plus the viewer's `availability`.
481
+ type asset_info = {
482
+ "id" => String,
483
+ "projectId" => String,
484
+ "type" => asset_type,
485
+ "externalUrl" => String?,
486
+ "content" => {
487
+ "format" => String?,
488
+ "width" => Integer?,
489
+ "height" => Integer?,
490
+ "durationSeconds" => Float?,
491
+ "pageCount" => Integer?,
492
+ "rendered" => asset_rendered?,
493
+ "preview" => asset_preview?,
494
+ "hls" => asset_hls?
495
+ },
496
+ "availability" => asset_availability
497
+ }
433
498
 
434
499
  # ---- Transforms and lenses (AssetTransform.ts, Lens.ts) -------------------------------------
435
500
 
@@ -544,20 +609,18 @@ module CalmLens
544
609
  type transform_input = String | image_transform_options_input
545
610
 
546
611
  type lens_type = "image" | "video" | "audio" | "document" | "website"
547
- # ENSURE_LENS_BODY_SCHEMA. Changing a saved lens needs a greater `version` (default 1).
612
+ # ENSURE_LENS_BODY_SCHEMA: a lens definition, which the CDN serves once it is saved.
548
613
  type lens_definition = {
549
614
  identifier: String,
550
615
  name: String,
551
616
  type: lens_type,
552
617
  active: bool,
553
618
  ?description: String?,
554
- ?version: Integer,
555
619
  ?transform: image_transform_options_input?
556
620
  }
557
621
  type lens = {
558
622
  "id" => String,
559
623
  ?"projectId" => String?,
560
- "version" => Integer,
561
624
  "identifier" => String,
562
625
  "name" => String,
563
626
  ?"description" => String?,
@@ -567,6 +630,11 @@ module CalmLens
567
630
  "createdAt" => Integer,
568
631
  ?"updatedAt" => Integer
569
632
  }
633
+ type lens_page = {
634
+ "items" => Array[lens],
635
+ "hasMore" => bool,
636
+ "nextCursor" => String?
637
+ }
570
638
 
571
639
  # ---- Folders (Folder.ts) --------------------------------------------------------------------
572
640
 
@@ -597,8 +665,8 @@ module CalmLens
597
665
  # picture); `action` is `block` when the match was close enough for a block list to block.
598
666
  type hash_match = {
599
667
  "source" => "hash-list",
600
- "listId" => String,
601
- "entryId" => String,
668
+ "hashListId" => String,
669
+ "hashListEntryId" => String,
602
670
  "distance" => Integer,
603
671
  "action" => hash_list_action
604
672
  }
@@ -610,71 +678,85 @@ module CalmLens
610
678
  "hash" => String,
611
679
  "quality" => number?,
612
680
  ?"label" => String?,
613
- ?"sourceAssetId" => String?,
681
+ # The asset the hash was taken from, when the entry was added from an asset.
682
+ ?"assetId" => String?,
614
683
  "createdAt" => Integer
615
684
  }
616
685
 
617
686
  type hash_list_entry_page = {
618
687
  "items" => Array[hash_list_entry],
619
688
  "hasMore" => bool,
620
- "nextCursor" => String?,
621
- "pageSize" => Integer,
622
- "ordering" => Array[order]
689
+ "nextCursor" => String?
623
690
  }
624
691
 
625
692
  # ---- Policies (Policy.ts) ---------------------------------------------------------------------
626
693
 
627
694
  type policy_preset_id = "general-community" | "children-platform" | "education-support" | "wholesome-community"
628
- # What a policy does with one category: `action` when its policy score reaches 0.5 (default
629
- # `block`), allowances that let covered content through or act on it more softly, and
630
- # restrictions, which outweigh allowances.
695
+ # What a policy does with one category: `action` when its policy score reaches 0.5, allowances
696
+ # that let covered content through or act on it more softly, and restrictions, which outweigh
697
+ # allowances.
631
698
  type category_policy_settings = {
632
- ?"action" => flagged_content_action,
633
- ?"allowances" => Array[policy_rule_snapshot],
634
- ?"restrictions" => Array[policy_rule_snapshot]
699
+ "action" => flagged_content_action,
700
+ "allowances" => Array[policy_rule_snapshot],
701
+ "restrictions" => Array[policy_rule_snapshot]
635
702
  }
636
- # Settings by category (`sexual`, `violence`, ...), and optionally link safety.
703
+ # Settings for every category, and optionally link safety.
637
704
  type policy_settings = {
638
- "categorySettings" => Hash[String, category_policy_settings],
705
+ "categorySettings" => {
706
+ "sexual" => category_policy_settings,
707
+ "violence" => category_policy_settings,
708
+ "self-harm" => category_policy_settings,
709
+ "harassment" => category_policy_settings,
710
+ "hate" => category_policy_settings,
711
+ "criminal-activity" => category_policy_settings,
712
+ "personal-information" => category_policy_settings,
713
+ "profanity" => category_policy_settings
714
+ },
639
715
  ?"linkSafety" => link_safety_settings
640
716
  }
717
+ # How a policy relates to its preset: `live` follows the latest release (the organisation's own
718
+ # preset policy with automatic updates on), `pinned` is the organisation's own preset policy held
719
+ # at one release, and `copy` is a policy made from a preset.
720
+ type policy_preset_mode = "live" | "pinned" | "copy"
641
721
  # Where a policy started from a built-in preset. `version` is the release it is pinned to,
642
- # `latestVersion` the newest; `projectId` is the project whose preset policy it is, or nil for a copy.
722
+ # `latestVersion` the newest.
643
723
  type policy_preset_origin = {
644
724
  "id" => policy_preset_id,
645
725
  "version" => Integer,
646
726
  "latestVersion" => Integer,
647
- "projectId" => String?
727
+ "mode" => policy_preset_mode
648
728
  }
649
- # A moderation policy. Policies belong to the project's organisation and its projects share them.
650
- # Send `revision` with each change; a policy changed since is refused with `policy/revision-conflict`.
729
+ # A moderation policy. Policies belong to the organisation and its projects share them. Send
730
+ # `revision` with each change; a policy changed since is refused with `policy/revision-conflict`.
651
731
  type policy = {
652
732
  "id" => String,
653
733
  "name" => String,
654
734
  "description" => String,
655
735
  "settings" => policy_settings,
656
736
  "revision" => Integer,
657
- "automaticUpdates" => bool,
658
737
  "preset" => policy_preset_origin?,
659
738
  "projectIds" => Array[String],
660
739
  "createdAt" => Integer,
661
740
  "updatedAt" => Integer
662
741
  }
663
- # Every policy of the project's organisation, oldest first, and the one the project moderates with.
664
- type policy_list = { "policies" => Array[policy], "projectPolicyId" => String }
742
+ # A page of the organisation's policies, oldest first unless `sort` says otherwise.
743
+ type policy_page = { "items" => Array[policy], "hasMore" => bool, "nextCursor" => String? }
665
744
 
666
745
  # ---- Events and webhooks (Event.ts, EventCatalog.ts, WebhookPayload.ts) ----------------------
667
746
 
668
747
  # EVENT_TYPES in EventCatalog.ts. Ignore types your code does not handle. Webhook, Slack and email
669
748
  # deliveries and the public events feed leave out facts that hold personal or account data.
670
- type event_type = "asset.uploaded" | "asset.classified" | "asset.allowed" | "asset.limited" |
671
- "asset.age-restricted" | "asset.blocked" | "asset.purged" | "asset.failed" | "asset.deleted" | "asset.content-removed" | "asset.retried" |
672
- "asset.review-requested" | "asset.hash-matched" | "usage.limit-reached" | "usage.spend-limit-reached" |
749
+ type event_type = "asset.uploaded" | "asset.classified" | "asset.region-restricted" | "asset.allowed" | "asset.limited" |
750
+ "asset.age-restricted" | "asset.blocked" | "asset.purged" | "asset.failed" | "asset.progress-updated" |
751
+ "asset.deleted" | "asset.content-removed" | "asset.retried" | "asset.rerun-requested" | "asset.review-requested" |
752
+ "asset.hash-matched" | "asset.link-flagged" | "usage.free-uploads-exhausted" | "usage.uploads-paused" |
673
753
  "upload-preset.daily-limit-reached" | "project.member-joined" | "project.member-removed" |
674
- "project.member-role-changed" | "project.invitation-sent" | "api-key.created" |
675
- "api-key.revoked" | "connector.failing" | "appeal.submitted" | "appeal.resolved"
754
+ "project.member-left" | "project.member-role-changed" | "project.invitation-sent" |
755
+ "project.transferred" | "api-key.created" | "api-key.revoked" | "api-key.deleted" |
756
+ "connector.disabled" | "appeal.submitted" | "appeal.resolved"
676
757
  type event_severity = "low" | "high"
677
- # A registered fact's value: text, an enum value, a count, a list of enum values, or null.
758
+ # A registered fact's value: text, an enum value, a count or a time in milliseconds (such as
759
+ # `resumes-at`), a list of enum values (such as `flagged-categories`), or null.
678
760
  # Test sends carry `{ "key" => "test", "value" => true }`.
679
761
  type event_fact_value = String | Integer | bool | Array[String] | nil
680
762
  # A registered fact. `key` is a kebab-case key registered for the event's type, such as
@@ -688,18 +770,31 @@ module CalmLens
688
770
  ?"uploadPresetId" => String?,
689
771
  ?"externalId" => String?,
690
772
  "upload" => { "status" => "uploading" | "completed" },
691
- "classification" => { "status" => asset_classification_status, "moderation" => { "status" => asset_moderation_status } },
773
+ # `testInput`: whether the results came from one of the project's test inputs rather than
774
+ # analysing the content. Never use test results, such as age ranges, for real decisions.
775
+ "classification" => { "status" => asset_classification_status, "testInput" => bool,
776
+ "moderation" => { "status" => asset_moderation_status } },
692
777
  "content" => { "status" => asset_content_status }
693
778
  }
779
+ # Who caused an event: a `user` (a person in the portal, or an assistant acting for one), an
780
+ # `api-key`, `automated` moderation or CalmLens itself (`system`). `id` is the user's or API key's
781
+ # ID, nil for `automated` and `system` and when it was not recorded.
782
+ type actor_type = "user" | "api-key" | "automated" | "system"
783
+ type actor = { "type" => actor_type, "id" => String? }
784
+ type actor_input = { type: actor_type, id: String? }
785
+
694
786
  # An `events.list` item, and the body of its webhook delivery.
695
787
  type event = {
696
788
  "id" => String,
697
789
  "projectId" => String,
790
+ "actor" => actor,
698
791
  "type" => event_type,
699
792
  "severity" => event_severity,
700
793
  "title" => String,
701
794
  "description" => String?,
702
795
  "assetId" => String?,
796
+ # Increases with each event about the same asset; nil for events not about an asset.
797
+ "assetSequence" => Integer?,
703
798
  "asset" => event_asset?,
704
799
  "facts" => Array[event_fact],
705
800
  "createdAt" => Integer
@@ -724,23 +819,31 @@ module CalmLens
724
819
  type asset_search_options = {
725
820
  query: String,
726
821
  ?mode: asset_search_mode,
727
- ?limit: Integer,
822
+ # How many results, 1 to 20 (default 10).
823
+ ?page_size: Integer,
728
824
  ?request_options: request_options
729
825
  }
730
826
  type list_assets_options = {
731
827
  ?cursor: String,
732
828
  ?page_size: Integer,
733
- ?ordering: Array[order_input],
734
- # An RSQL filter such as `classification.moderation.status==allowed`.
829
+ # `createdAt` and `id`; `-createdAt` by default.
830
+ ?sort: sort,
831
+ # An RSQL filter such as `classification.moderation.status==allowed`; `folderId==fldr_…` lists
832
+ # one folder's assets.
735
833
  ?filter: String?,
736
- ?folder_id: String?,
737
834
  ?request_options: request_options
738
835
  }
739
836
  type list_asset_children_options = {
740
837
  asset_id: String,
741
838
  ?cursor: String,
742
839
  ?page_size: Integer,
743
- ?ordering: Array[order_input],
840
+ ?sort: sort,
841
+ ?request_options: request_options
842
+ }
843
+ type list_asset_timeline_options = {
844
+ asset_id: String,
845
+ ?cursor: String,
846
+ ?page_size: Integer,
744
847
  ?request_options: request_options
745
848
  }
746
849
  type update_asset_options = {
@@ -765,15 +868,21 @@ module CalmLens
765
868
  ?confirm_purge: bool,
766
869
  ?request_options: request_options
767
870
  }
768
- type create_signed_url_options = {
769
- ?viewer_claims: viewer_claims,
770
- asset_id: String,
771
- # Defaults to `rendered` on the server; `original` takes no lens or transform.
772
- ?resource: "original" | "rendered",
773
- ?expires_in_seconds: Integer,
774
- # Transform options replace the lens's options of the same name.
871
+ # The resources beneath an asset URL ({CalmLens::CDN::RESOURCES}).
872
+ type cdn_resource = "original" | "rendered" | "preview" | "hls" | "embed" | "placeholder" | "info"
873
+ type sign_asset_url_options = {
874
+ # Exactly one of `asset_id` and `external_id`.
875
+ ?asset_id: String,
876
+ ?external_id: String,
877
+ ?project_id: String,
878
+ # Whole seconds from 1 to 86400; 900 by default.
879
+ ?expires_in: Integer,
880
+ # Whether the URL also serves `original`; false by default.
881
+ ?original: bool,
882
+ ?resource: cdn_resource,
775
883
  ?lens: String,
776
884
  ?transform: transform_input,
885
+ ?viewer_claims: viewer_claims,
777
886
  ?request_options: request_options
778
887
  }
779
888
 
@@ -800,6 +909,8 @@ module CalmLens
800
909
  ?description: String?,
801
910
  ?visibility: asset_visibility?,
802
911
  ?metadata: Array[metadata_item_input]?,
912
+ # Tags for the asset, such as `['catalogue', 'backpacks']`.
913
+ ?tags: Array[String]?,
803
914
  ?author_id: String,
804
915
  ?context: moderation_context_input,
805
916
  ?external_id: String?,
@@ -816,6 +927,8 @@ module CalmLens
816
927
  ?description: String?,
817
928
  ?visibility: asset_visibility?,
818
929
  ?metadata: Array[metadata_item_input]?,
930
+ # Tags for the asset, such as `['catalogue', 'backpacks']`.
931
+ ?tags: Array[String]?,
819
932
  ?author_id: String,
820
933
  ?context: moderation_context_input,
821
934
  ?external_id: String?,
@@ -831,6 +944,8 @@ module CalmLens
831
944
  ?description: String?,
832
945
  ?visibility: asset_visibility?,
833
946
  ?metadata: Array[metadata_item_input]?,
947
+ # Tags for the asset, such as `['catalogue', 'backpacks']`.
948
+ ?tags: Array[String]?,
834
949
  ?author_id: String,
835
950
  ?context: moderation_context_input,
836
951
  ?external_id: String?,
@@ -840,7 +955,8 @@ module CalmLens
840
955
  ?processing_options: processing_options_input?,
841
956
  ?request_options: request_options
842
957
  }
843
- type upload_part_options = { asset_id: String, part: upload_part, ?queue: bool, ?request_options: request_options }
958
+ # `wait` overrides whether the final part waits for the decision, chosen when the upload started.
959
+ type upload_part_options = { asset_id: String, part: upload_part, ?wait: bool, ?request_options: request_options }
844
960
 
845
961
  # Options of {Text#classify}: the text, with the shared asset fields. `name` defaults to `text`.
846
962
  type moderate_text_options = {
@@ -849,6 +965,7 @@ module CalmLens
849
965
  ?description: String?,
850
966
  ?visibility: asset_visibility?,
851
967
  ?metadata: Array[metadata_item_input]?,
968
+ ?tags: Array[String]?,
852
969
  ?author_id: String,
853
970
  ?context: moderation_context_input,
854
971
  ?external_id: String?,
@@ -863,19 +980,19 @@ module CalmLens
863
980
  type sign_upload_token_options = {
864
981
  upload_preset_id: String,
865
982
  ?external_id: String,
866
- ?expires_in_seconds: Integer,
983
+ # Seconds the token can start an upload, 1 to 3600; 600 by default.
984
+ ?expires_in: Integer,
867
985
  ?request_options: request_options
868
986
  }
869
987
  type signed_upload_token = { "token" => String, "expiresAt" => Integer }
870
988
 
871
- type folder_order_input = { field: "name" | "createdAt", direction: order_direction }
872
989
  type list_folders_options = {
873
990
  ?parent_id: String,
874
991
  ?cursor: String,
875
992
  # 1 to 100, default 50.
876
993
  ?page_size: Integer,
877
- # At most one entry; the default is `name` ascending.
878
- ?ordering: Array[folder_order_input],
994
+ # `name` (the default) or `createdAt`, descending when prefixed with `-`.
995
+ ?sort: sort,
879
996
  ?search: String,
880
997
  ?request_options: request_options
881
998
  }
@@ -883,39 +1000,36 @@ module CalmLens
883
1000
  "items" => Array[folder],
884
1001
  "ancestors" => Array[folder],
885
1002
  "hasMore" => bool,
886
- "nextCursor" => String?,
887
- "pageSize" => Integer,
888
- "ordering" => Array[order]
1003
+ "nextCursor" => String?
889
1004
  }
890
1005
  type folder_id_options = { folder_id: String, ?request_options: request_options }
891
1006
  type create_folder_options = { name: String, ?parent_id: String?, ?request_options: request_options }
892
1007
  type update_folder_options = { folder_id: String, ?name: String, ?request_options: request_options }
893
1008
  type move_folder_options = { folder_id: String, parent_id: String?, ?request_options: request_options }
894
- # 1 to 100 lists per page, default 50.
895
- type list_hash_lists_options = { ?cursor: String, ?page_size: Integer, ?request_options: request_options }
1009
+ # 1 to 100 lists per page, default 50; `sort` is `createdAt` and `id`, `-createdAt` by default.
1010
+ type list_hash_lists_options = { ?cursor: String, ?page_size: Integer, ?sort: sort, ?request_options: request_options }
896
1011
  type hash_list_page = {
897
1012
  "items" => Array[hash_list],
898
1013
  "hasMore" => bool,
899
- "nextCursor" => String?,
900
- "pageSize" => Integer,
901
- "ordering" => Array[order]
1014
+ "nextCursor" => String?
902
1015
  }
903
1016
  type hash_list_id_options = { hash_list_id: String, ?request_options: request_options }
904
1017
  type create_hash_list_options = { name: String, action: hash_list_action, ?description: String?, ?request_options: request_options }
905
1018
  type update_hash_list_options = { hash_list_id: String, ?name: String, ?description: String?, ?action: hash_list_action,
906
1019
  ?request_options: request_options }
907
- type list_hash_list_entries_options = { hash_list_id: String, ?cursor: String, ?page_size: Integer,
1020
+ type list_hash_list_entries_options = { hash_list_id: String, ?cursor: String, ?page_size: Integer, ?sort: sort,
908
1021
  ?request_options: request_options }
909
1022
  type add_hash_list_entry_options = { hash_list_id: String, ?hash: String, ?quality: number, ?asset_id: String, ?label: String,
910
1023
  ?request_options: request_options }
911
1024
  type hash_list_entry_id_options = { entry_id: String, ?request_options: request_options }
912
1025
 
913
1026
  # Policy settings as options: snake_case Symbol keys, or a policy's `settings` as the API returned it.
914
- type policy_rule_input = { when: Array[String], action: flagged_content_action, ?name: String, ?match: "all", ?unless: Array[String] }
1027
+ type policy_rule_input = { when: Array[String], action: flagged_content_action, ?name: String, ?unless: Array[String] }
1028
+ # Every category needs its `action`, `allowances` and `restrictions`.
915
1029
  type category_policy_settings_input = {
916
- ?action: flagged_content_action,
917
- ?allowances: Array[policy_rule_input],
918
- ?restrictions: Array[policy_rule_input]
1030
+ action: flagged_content_action,
1031
+ allowances: Array[policy_rule_input],
1032
+ restrictions: Array[policy_rule_input]
919
1033
  }
920
1034
  type link_safety_settings_input = {
921
1035
  verdict_actions: Hash[String | Symbol, link_safety_action],
@@ -925,7 +1039,9 @@ module CalmLens
925
1039
  category_settings: Hash[String | Symbol, category_policy_settings_input],
926
1040
  ?link_safety: link_safety_settings_input
927
1041
  }
928
- type list_policies_options = { ?request_options: request_options }
1042
+ # `sort` is `createdAt` and `id`, `createdAt` (oldest first) by default.
1043
+ type list_policies_options = { ?cursor: String, ?page_size: Integer, ?sort: sort, ?request_options: request_options }
1044
+ type request_only_options = { ?request_options: request_options }
929
1045
  type policy_id_options = { policy_id: String, ?request_options: request_options }
930
1046
  # Send `settings` (defining every category) with a `name`, or `preset_id` to copy the latest
931
1047
  # release of a built-in preset, named after it unless you give a `name`.
@@ -933,16 +1049,18 @@ module CalmLens
933
1049
  ?preset_id: policy_preset_id, ?request_options: request_options }
934
1050
  type update_policy_options = { policy_id: String, revision: Integer, ?name: String, ?description: String,
935
1051
  ?settings: policy_settings_input, ?request_options: request_options }
936
- # `reset` restores the pinned preset version (send `preset.version`); `update` moves an unchanged
937
- # copy to the latest release (send `preset.latestVersion`).
938
- type apply_policy_preset_options = { policy_id: String, operation: "reset" | "update", revision: Integer,
939
- preset_version: Integer, ?request_options: request_options }
1052
+ # `reset` restores the pinned release (send `preset.version`); `upgrade` moves an unchanged
1053
+ # `pinned` or `copy` policy to the latest release (send `preset.latestVersion`).
1054
+ type restore_policy_options = { policy_id: String, revision: Integer, preset_version: Integer,
1055
+ ?request_options: request_options }
940
1056
  type set_policy_automatic_updates_options = { policy_id: String, enabled: bool, revision: Integer,
941
1057
  preset_version: Integer, ?request_options: request_options }
942
1058
  type assign_policy_options = { policy_id: String, ?request_options: request_options }
943
1059
 
944
- # `page_size` is 1 to 100, default 50.
945
- type list_events_options = { ?cursor: String, ?page_size: Integer, ?request_options: request_options }
1060
+ # `page_size` is 1 to 100, default 50. `types` and `asset_id` narrow the feed; a cursor belongs to
1061
+ # the filters it was issued with.
1062
+ type list_events_options = { ?cursor: String, ?page_size: Integer, ?types: Array[event_type], ?asset_id: String,
1063
+ ?request_options: request_options }
946
1064
 
947
1065
  type ensure_lenses_options = { lenses: Array[lens_definition], ?request_options: request_options }
948
1066
  type ensure_lens_options = {
@@ -951,28 +1069,49 @@ module CalmLens
951
1069
  type: lens_type,
952
1070
  active: bool,
953
1071
  ?description: String?,
954
- ?version: Integer,
1072
+ ?transform: image_transform_options_input?,
1073
+ ?request_options: request_options
1074
+ }
1075
+ # `sort` is `createdAt` and `id`, `-createdAt` (newest first) by default.
1076
+ type list_lenses_options = { ?cursor: String, ?page_size: Integer, ?sort: sort, ?request_options: request_options }
1077
+ type lens_id_options = { lens_id: String, ?request_options: request_options }
1078
+ # The identifier must be new to the project.
1079
+ type create_lens_options = ensure_lens_options
1080
+ type update_lens_options = {
1081
+ lens_id: String,
1082
+ ?name: String,
1083
+ ?description: String?,
1084
+ ?type: lens_type,
1085
+ ?active: bool,
955
1086
  ?transform: image_transform_options_input?,
956
1087
  ?request_options: request_options
957
1088
  }
958
1089
 
959
1090
  type asset_url_options = {
960
- ?viewer_claims: viewer_claims,
961
- # The asset ID or external ID.
962
- asset_identifier: String,
963
- # `rendered` is the default. `original` takes no lens or transform; `placeholder` is a small blurred PNG
964
- # that takes no lens or transform.
965
- ?resource: "original" | "rendered" | "placeholder",
966
- # Transform options replace the lens's options of the same name.
1091
+ # Exactly one of `asset_id` and `external_id`.
1092
+ ?asset_id: String,
1093
+ ?external_id: String,
1094
+ # The client's project by default.
1095
+ ?project_id: String,
1096
+ # Without one, the URL is the asset URL itself. `original`, `hls` (the HLS master playlist),
1097
+ # `embed` (the page that shows the asset), `placeholder` (a small blurred PNG) and `info` take no
1098
+ # lens or transform; `preview` takes them, and `rendered` does when it is an image.
1099
+ ?resource: cdn_resource,
1100
+ # Transform options replace the lens's options of the same name; both need a resource.
967
1101
  ?lens: String,
968
1102
  ?transform: transform_input,
969
- # Appends `?ageConfirmed=true`, so a public `age-restricted` asset is served from this URL. Set it
970
- # only where your app has already decided the viewer may see age-restricted content.
1103
+ # Unsigned viewer assertions, sent as the `viewerClaims` query without the defaults. Set
1104
+ # `age_confirmed` only where your app has already decided the viewer may see age-restricted content.
1105
+ ?viewer_claims: viewer_claims,
1106
+ ?request_options: request_options
971
1107
  }
972
1108
  type serve_options = {
1109
+ ?asset_id: String,
1110
+ ?external_id: String,
1111
+ ?project_id: String,
973
1112
  ?viewer_claims: viewer_claims,
974
- asset_identifier: String,
975
- ?resource: "original" | "rendered" | "placeholder",
1113
+ # `rendered` by default.
1114
+ ?resource: cdn_resource,
976
1115
  ?lens: String,
977
1116
  ?transform: transform_input,
978
1117
  ?init: { ?method: "GET" | "HEAD", ?headers: Hash[String, String] },
@@ -984,6 +1123,8 @@ module CalmLens
984
1123
  type: event_type,
985
1124
  ?id: String,
986
1125
  ?project_id: String,
1126
+ # The mock API key (`{ 'type' => 'api-key', 'id' => nil }`) when omitted.
1127
+ ?actor: actor_input,
987
1128
  ?severity: event_severity,
988
1129
  ?title: String,
989
1130
  ?description: String?,