calmlens 0.1.1 → 0.17.1

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
@@ -20,53 +20,73 @@ module CalmLens
20
20
  ?idempotency_key: String,
21
21
  ?timeout: number,
22
22
  ?open_timeout: number,
23
- ?max_retries: Integer
23
+ ?upload_timeout: number,
24
+ ?max_retries: Integer,
25
+ ?max_response_bytes: Integer
24
26
  }
25
27
 
26
28
  # ---- Assets (Asset.ts) ----------------------------------------------------------------------
27
29
 
28
30
  # Where the asset is in the pipeline.
29
- type asset_processing_status = "uploading" | "processing" | "done" | "failed"
30
- # The moderation decision in force: a reviewer's when there is one, else the automated one.
31
- type asset_moderation_status = "pending" | "approved" | "rejected"
32
- # What the policy did with flagged content (never `ignore`, unlike `flagged_content_action`).
33
- type asset_moderation_action = "alert" | "hide" | "purge"
34
- type asset_reviewer_action = "approved" | "rejected"
31
+ type asset_classification_status = "pending" | "processing" | "completed" | "failed"
32
+ # A moderation decision, which also decides delivery: served to anyone with access (`allowed`),
33
+ # served like `allowed` but marked so your app reduces its reach (`limited`), only through signed
34
+ # URLs or API keys (`age-restricted`), not served (`blocked`), or not served with the stored
35
+ # content deleted (`purged`).
36
+ type asset_moderation_decision = "allowed" | "limited" | "age-restricted" | "blocked" | "purged"
37
+ # The decision in force: `pending` until classification decides, then a reviewer's decision when
38
+ # there is one, else the policy's.
39
+ type asset_moderation_status = "pending" | asset_moderation_decision
35
40
  # Whether CalmLens holds the content: only until processing finishes, retained, or deleted.
36
41
  type asset_content_status = "temporary" | "stored" | "removed"
37
42
  type asset_content_removal_reason = "policy" | "retention" | "requested" | "parent-removed" | "disposed"
43
+ # 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"
38
45
  type asset_type = "image" | "video" | "audio" | "plaintext-document" | "multimedia-document" | "website" | "file"
39
46
  type asset_visibility = "public" | "private"
40
- # FLAGGED_CONTENT_ACTION_SCHEMA in Project.ts.
41
- type flagged_content_action = "ignore" | "alert" | "hide" | "purge"
47
+ # FLAGGED_CONTENT_ACTION_SCHEMA in PolicyRule.ts.
48
+ type flagged_content_action = "allow" | "limit" | "age-restrict" | "block" | "purge"
42
49
 
43
50
  # A custom metadata item. `value` is any JSON value you chose.
44
51
  type metadata_item = { "id" => String, "value" => json_value }
45
52
  # A metadata item to send. Keys inside `metadata` are sent unchanged, so use `id:` and `value:`.
46
53
  type metadata_item_input = { id: String, value: json_input }
54
+ # An earlier post in the conversation, as the API returns it.
55
+ type moderation_context_item = { "text" => String, ?"authorId" => String }
56
+ # Earlier posts in the conversation, oldest first.
57
+ type moderation_context = { "items" => Array[moderation_context_item] }
58
+ # An earlier post to send. `author_id` is your identifier for who wrote it.
59
+ type moderation_context_item_input = { text: String, ?author_id: String }
60
+ # Earlier posts to send, oldest first; only the posts CalmLens uses are sent.
61
+ type moderation_context_input = { items: Array[moderation_context_item_input] }
47
62
 
48
63
  # ProcessingFeatures.ts: optional analyses to run, keyed by feature. Every feature is off unless
49
64
  # `enabled` is true.
50
65
  type processing_features_input = {
51
66
  ?ocr: { enabled: bool }?,
52
67
  ?person_detection: { enabled: bool }?,
53
- ?face_detection: { enabled: bool, ?age_estimation: bool }?
68
+ ?face_detection: { enabled: bool, ?age_estimation: bool }?,
69
+ ?link_detection: { enabled: bool }?
54
70
  }
55
71
  type processing_options_input = {
56
72
  ?keep_content_after_processing: bool?,
57
- ?flagged_content_policy: { action: flagged_content_action }?,
73
+ # Overrides the project's `storeSensitiveMetadata` setting: false removes embedded EXIF, XMP and
74
+ # IPTC metadata before the image is stored; true stores it as uploaded.
75
+ ?store_sensitive_metadata: bool?,
58
76
  ?features: processing_features_input?
59
77
  }
60
78
 
61
79
  type processing_features = {
62
80
  ?"ocr" => { "enabled" => bool }?,
63
81
  ?"personDetection" => { "enabled" => bool }?,
64
- ?"faceDetection" => { "enabled" => bool, ?"ageEstimation" => bool }?
82
+ ?"faceDetection" => { "enabled" => bool, ?"ageEstimation" => bool }?,
83
+ ?"linkDetection" => { "enabled" => bool }?,
84
+ ?"aiGeneratedDetection" => { "enabled" => bool }?
65
85
  }
66
86
  # The processing options an asset was uploaded with.
67
87
  type processing_options = {
68
88
  ?"keepContentAfterProcessing" => bool?,
69
- ?"flaggedContentPolicy" => { "action" => flagged_content_action }?,
89
+ ?"storeSensitiveMetadata" => bool?,
70
90
  ?"features" => processing_features?
71
91
  }
72
92
 
@@ -77,37 +97,75 @@ module CalmLens
77
97
  ?"sha384" => String?,
78
98
  ?"sha512" => String?
79
99
  }
80
- type image_data = { ?"perceptualHash" => String?, ?"width" => Integer?, ?"height" => Integer? }
81
- type preview_image = {
82
- "fileFormat" => String?,
100
+ # The picture served at the rendered resource; it remains after the content is removed.
101
+ type asset_image = {
102
+ "width" => Integer?,
103
+ "height" => Integer?,
83
104
  "thumbhash" => String?,
84
105
  "averageColor" => String?,
85
- "width" => Integer?,
86
- "height" => Integer?
106
+ "perceptualHash" => String?,
107
+ # How much detail `perceptualHash` captured, from 0 to 100; hashes below 50 match unrelated pictures.
108
+ "perceptualHashQuality" => Integer?
87
109
  }
88
110
  type safety_hold = { "placedAt" => Integer, "reason" => "suspected-illegal-content", ?"disposedAt" => Integer? }
89
111
  # `type: "string"` carries the text in `content`; `type: "document"` stores it under `id`.
90
112
  type extracted_text = { "type" => "string" | "document", ?"content" => String, ?"id" => String }
91
-
92
- # ASSET_PROCESSING_SCHEMA. Epoch times are milliseconds.
93
- type asset_processing = {
94
- "status" => asset_processing_status,
113
+ # Descriptive metadata embedded in an uploaded image. `capturedAt` is ISO 8601, with a UTC offset
114
+ # only when the file records one. `digitalSourceType` is the IPTC code the file declares, such as
115
+ # `digitalCapture`. `containsLocation` says whether the uploaded file embedded GPS coordinates;
116
+ # `creator` and `location` are sensitive and recorded only when `storeSensitiveMetadata` is on.
117
+ type file_metadata_location = { "latitude" => number, "longitude" => number }
118
+ type file_metadata = {
119
+ "capturedAt" => String?,
120
+ "cameraMake" => String?,
121
+ "cameraModel" => String?,
122
+ "lensModel" => String?,
123
+ "software" => String?,
124
+ "creator" => String?,
125
+ "copyright" => String?,
126
+ "digitalSourceType" => String?,
127
+ "containsLocation" => bool,
128
+ "location" => file_metadata_location?
129
+ }
130
+
131
+ type asset_upload = { "status" => "uploading" | "completed", "updatedAt" => Integer?, "partsReceived" => Integer? }
132
+ type asset_classification = {
133
+ "status" => asset_classification_status,
134
+ # `null` unless `status` is `failed`.
135
+ "failureReason" => asset_classification_failure_reason?,
95
136
  "updatedAt" => Integer?,
96
- # Parts of a multipart upload received so far; null otherwise.
97
- "uploadPartsReceived" => Integer?
137
+ "completedAt" => Integer?,
138
+ "moderation" => asset_moderation,
139
+ ?"personDetection" => person_detection_result,
140
+ ?"faceDetection" => face_detection_result,
141
+ ?"linkDetection" => link_detection_result,
142
+ ?"aiGeneratedDetection" => ai_generated_detection_result,
143
+ # Where OCR found text, and personal information within it; redaction transforms blur these regions.
144
+ ?"textRegions" => Array[text_region],
145
+ ?"labels" => Array[classification_label]?
146
+ }
147
+ type asset_review = {
148
+ "id" => String,
149
+ "decision" => asset_moderation_decision,
150
+ "note" => String?,
151
+ ?"reviewerName" => String?,
152
+ ?"reviewerEmail" => String?,
153
+ "reviewedAt" => Integer,
154
+ "appliedToAsset" => bool
98
155
  }
99
- # ASSET_MODERATION_SCHEMA. `action` is kept after a reviewer decides.
156
+ type regional_decision = { "region" => String, "action" => String, "rule" => String, ?"category" => String }
157
+ type test_regional_action = { "region" => String, "action" => String }
100
158
  type asset_moderation = {
159
+ ?"testCategoryActions" => Hash[String, String],
160
+ ?"testRegionalActions" => Array[test_regional_action],
161
+ "manualReviews" => Array[asset_review],
101
162
  "status" => asset_moderation_status,
102
- "action" => asset_moderation_action?,
103
- # Why automated moderation rejected the asset.
104
- "note" => String?,
105
- "reviewerAction" => asset_reviewer_action?,
106
- "reviewerNote" => String?,
107
- "reviewerUserId" => String?,
108
- "reviewedAt" => Integer?,
109
- "decidedAt" => Integer?,
110
- "report" => classification_report?
163
+ ?"automatedAction" => flagged_content_action,
164
+ ?"source" => String, ?"rule" => String,
165
+ "flaggedCategories" => Array[String], "regions" => Array[regional_decision],
166
+ ?"explanationComplete" => bool,
167
+ ?"categories" => Hash[String, category_policy_score],
168
+ ?"raw" => moderation_raw
111
169
  }
112
170
  # ASSET_CONTENT_SCHEMA. `format` is the MIME type.
113
171
  type asset_content = {
@@ -119,15 +177,16 @@ module CalmLens
119
177
  "extension" => String?,
120
178
  "sizeInBytes" => Integer?,
121
179
  "checksums" => checksums?,
122
- "image" => image_data?,
123
- "previewImage" => preview_image?,
124
- "extractedText" => extracted_text?
180
+ "image" => asset_image?,
181
+ "extractedText" => extracted_text?,
182
+ # Metadata embedded in an uploaded image; `null` when it declares none, for other asset types,
183
+ # once the content is removed and while the asset is held.
184
+ "fileMetadata" => file_metadata?
125
185
  }
126
186
 
127
187
  type asset = {
128
188
  "id" => String,
129
189
  "projectId" => String,
130
- ?"userId" => String?,
131
190
  ?"parentId" => String?,
132
191
  ?"folderId" => String?,
133
192
  ?"uploadPresetId" => String?,
@@ -139,11 +198,14 @@ module CalmLens
139
198
  ?"externalUrl" => String?,
140
199
  "type" => asset_type,
141
200
  ?"metadata" => Array[metadata_item]?,
201
+ ?"authorId" => String?,
202
+ # The earlier posts CalmLens used; null once the content is removed.
203
+ ?"context" => moderation_context?,
142
204
  ?"tags" => Array[String]?,
143
205
  ?"processingOptions" => processing_options?,
144
206
  ?"visibility" => asset_visibility?,
145
- "processing" => asset_processing,
146
- "moderation" => asset_moderation,
207
+ "upload" => asset_upload,
208
+ "classification" => asset_classification,
147
209
  "content" => asset_content
148
210
  }
149
211
 
@@ -163,69 +225,18 @@ module CalmLens
163
225
  ?"likelihood" => likelihood,
164
226
  ?"reason" => not_evaluated_reason
165
227
  }
166
- # MODERATION_QUALIFIERS in ModerationPolicyDimensions.ts.
167
- type qualifier_results = {
168
- ?"sexual-nudity" => qualifier_result,
169
- ?"sexual-activity" => qualifier_result,
170
- ?"sexual-explicit-language" => qualifier_result,
171
- ?"sexual-solicitation" => qualifier_result,
172
- ?"sexual-historical" => qualifier_result,
173
- ?"sexual-documentary" => qualifier_result,
174
- ?"sexual-educational" => qualifier_result,
175
- ?"sexual-fictional" => qualifier_result,
176
- ?"sexual-support-prevention" => qualifier_result,
177
- ?"violence-attack" => qualifier_result,
178
- ?"violence-threat" => qualifier_result,
179
- ?"violence-preparation" => qualifier_result,
180
- ?"violence-encouragement" => qualifier_result,
181
- ?"violence-injury" => qualifier_result,
182
- ?"violence-violent-death" => qualifier_result,
183
- ?"violence-natural-death" => qualifier_result,
184
- ?"violence-graphic" => qualifier_result,
185
- ?"violence-historical" => qualifier_result,
186
- ?"violence-documentary" => qualifier_result,
187
- ?"violence-educational" => qualifier_result,
188
- ?"violence-fictional" => qualifier_result,
189
- ?"violence-support-prevention" => qualifier_result,
190
- ?"self-harm-thoughts" => qualifier_result,
191
- ?"self-harm-preparation" => qualifier_result,
192
- ?"self-harm-act" => qualifier_result,
193
- ?"self-harm-methods" => qualifier_result,
194
- ?"self-harm-encouragement" => qualifier_result,
195
- ?"self-harm-documentary" => qualifier_result,
196
- ?"self-harm-educational" => qualifier_result,
197
- ?"self-harm-fictional" => qualifier_result,
198
- ?"self-harm-support-prevention" => qualifier_result,
199
- ?"harassment-abuse" => qualifier_result,
200
- ?"harassment-intimidation" => qualifier_result,
201
- ?"harassment-threat" => qualifier_result,
202
- ?"harassment-sexual" => qualifier_result,
203
- ?"harassment-encouragement" => qualifier_result,
204
- ?"harassment-fictional" => qualifier_result,
205
- ?"hate-abuse" => qualifier_result,
206
- ?"hate-dehumanization" => qualifier_result,
207
- ?"hate-inferiority" => qualifier_result,
208
- ?"hate-exclusion" => qualifier_result,
209
- ?"hate-threat" => qualifier_result,
210
- ?"hate-historical" => qualifier_result,
211
- ?"hate-fictional" => qualifier_result,
212
- ?"criminal-activity-demonstration" => qualifier_result,
213
- ?"criminal-activity-preparation" => qualifier_result,
214
- ?"criminal-activity-request" => qualifier_result,
215
- ?"criminal-activity-instructions" => qualifier_result,
216
- ?"criminal-activity-promotion" => qualifier_result,
217
- ?"criminal-activity-substances" => qualifier_result,
218
- ?"criminal-activity-fraud" => qualifier_result,
219
- ?"criminal-activity-fictional" => qualifier_result
220
- }
228
+ # qualifier_results is generated in qualifiers.rbs.
229
+
221
230
  # `status: "evaluated"` or `"partial"` carries `likelihood` and `score`; `"not-evaluated"`
222
231
  # carries `reason`.
232
+ type policy_condition_result = { "status" => "evaluated" | "not-evaluated", ?"score" => number, ?"reason" => not_evaluated_reason }
223
233
  type category_report = {
224
234
  "status" => "evaluated" | "partial" | "not-evaluated",
225
235
  ?"likelihood" => likelihood,
226
236
  ?"score" => number,
227
237
  ?"reason" => not_evaluated_reason,
228
- ?"qualifiers" => qualifier_results
238
+ ?"qualifiers" => qualifier_results,
239
+ ?"policyConditions" => Hash[String, policy_condition_result]
229
240
  }
230
241
  type classification_categories = {
231
242
  "sexual" => category_report,
@@ -233,7 +244,9 @@ module CalmLens
233
244
  "self-harm" => category_report,
234
245
  "harassment" => category_report,
235
246
  "hate" => category_report,
236
- "criminal-activity" => category_report
247
+ "criminal-activity" => category_report,
248
+ "personal-information" => category_report,
249
+ "profanity" => category_report
237
250
  }
238
251
  type classification_label = {
239
252
  "description" => String,
@@ -276,33 +289,60 @@ module CalmLens
276
289
  ?"faces" => Array[detected_face],
277
290
  ?"reason" => not_evaluated_reason
278
291
  }
292
+ type detected_qr_code = { "value" => String, "box" => bounding_box }
293
+ # A web link found in a QR code or in the text OCR extracted.
294
+ type detected_link = { "url" => String, "source" => "qr-code" | "text" }
295
+ # `status: "evaluated"` carries `qrCodes` and `links`; `"not-evaluated"` carries `reason`.
296
+ type link_detection_result = {
297
+ "status" => "evaluated" | "not-evaluated",
298
+ "stage" => processing_feature_stage,
299
+ ?"qrCodes" => Array[detected_qr_code],
300
+ ?"links" => Array[detected_link],
301
+ ?"reason" => not_evaluated_reason
302
+ }
303
+ type provenance_signal = { "kind" => "c2pa" | "iptc-digital-source-type" | "generator-metadata", "value" => String }
304
+ # `status: "evaluated"` carries `provenance` and `signals`; `"not-evaluated"` carries `reason`.
305
+ type ai_generated_detection_result = {
306
+ "status" => "evaluated" | "not-evaluated",
307
+ "stage" => processing_feature_stage,
308
+ ?"provenance" => "ai-generated" | "ai-edited" | "unknown",
309
+ ?"signals" => Array[provenance_signal],
310
+ ?"reason" => not_evaluated_reason
311
+ }
312
+ # Where OCR found text in an image, and whether it is personal information.
313
+ type text_region = { "box" => bounding_box, "personalInformation" => bool }
279
314
  # Results of the features requested in `processingOptions.features`. OCR stores extracted text on the image
280
315
  # asset instead of a result here.
281
316
  type processing_feature_results = {
282
317
  ?"personDetection" => person_detection_result,
283
- ?"faceDetection" => face_detection_result
318
+ ?"faceDetection" => face_detection_result,
319
+ ?"linkDetection" => link_detection_result,
320
+ ?"aiGeneratedDetection" => ai_generated_detection_result
284
321
  }
285
322
 
286
323
  # How strongly each assessed category meets the policy and what the policy does with it.
287
- type report_policy = {
288
- "score" => number,
289
- "categories" => Hash[String, { "score" => number, "action" => String }]
324
+ type policy_rule_snapshot = {
325
+ "when" => Array[String], "action" => flagged_content_action,
326
+ ?"name" => String, ?"match" => "all", ?"unless" => Array[String]
290
327
  }
291
-
292
- type classification_report = {
293
- "processedAt" => Integer,
328
+ type category_policy_source = { "kind" => String, ?"index" => Integer, ?"indexes" => Array[Integer] }
329
+ type category_policy_settings_snapshot = {
330
+ "categoryAction" => flagged_content_action,
331
+ "allowances" => Array[policy_rule_snapshot], "restrictions" => Array[policy_rule_snapshot]
332
+ }
333
+ type category_policy_score = {
334
+ "score" => number, "action" => flagged_content_action,
335
+ ?"source" => category_policy_source, ?"settings" => category_policy_settings_snapshot
336
+ }
337
+ type moderation_raw = {
294
338
  "categories" => classification_categories,
295
- "score" => number,
296
- ?"notes" => String?,
297
- ?"media" => media_report,
298
- ?"labels" => Array[classification_label]?,
299
- ?"features" => processing_feature_results,
300
- ?"policy" => report_policy
339
+ ?"timeline" => media_report,
340
+ ?"hashMatches" => Array[hash_match]
301
341
  }
302
342
 
303
343
  # ---- Pages and search (Page.ts, AssetSearch.ts) --------------------------------------------
304
344
 
305
- type order_direction = "ASC" | "DESC"
345
+ type order_direction = "asc" | "desc"
306
346
  type order_input = { field: String, direction: order_direction }
307
347
  type order = { "field" => String, "direction" => order_direction }
308
348
 
@@ -316,7 +356,7 @@ module CalmLens
316
356
 
317
357
  type asset_search_mode = "keyword" | "semantic" | "hybrid"
318
358
  type asset_search_match_field = "name" | "id" | "externalId" | "description" | "tags" | "type" | "content.format" |
319
- "content.extension" | "moderation.status" | "visual" | "transcript"
359
+ "content.extension" | "classification.moderation.status" | "visual" | "transcript"
320
360
  type asset_search_result = { "asset" => asset, "score" => number, "matchedFields" => Array[asset_search_match_field] }
321
361
  type asset_search_response = {
322
362
  "query" => String,
@@ -324,30 +364,51 @@ module CalmLens
324
364
  "semanticStatus" => "disabled" | "ready" | "indexing" | "unavailable"
325
365
  }
326
366
 
367
+ type asset_batch_operation = "delete" | "remove-content"
368
+ type batch_assets_response = { "queued" => bool }
327
369
  type signed_url = { "url" => String, "expiresAt" => Integer }
328
370
 
329
371
  # ---- Transforms and lenses (AssetTransform.ts, Lens.ts) -------------------------------------
330
372
 
373
+ # <generated: image-transform-options>
374
+ # Generated by packages/sdk-contract/generate.ts from IMAGE_TRANSFORM_OPTIONS_SCHEMA; do not edit.
331
375
  type image_format = "jpg" | "png" | "webp" | "avif" | "gif"
376
+ type image_quality_level = "low" | "medium" | "high"
332
377
  type image_fit = "scale-down" | "contain" | "pad" | "squeeze" | "cover" | "crop"
378
+ type image_flip = "h" | "v" | "hv"
379
+ type image_segment = "foreground"
333
380
  type image_gravity_side = "face" | "left" | "right" | "top" | "bottom" | "center" | "auto" | "entropy"
381
+ type image_gravity_mode = "remainder" | "box-center"
334
382
 
335
383
  # IMAGE_TRANSFORM_OPTIONS_SCHEMA, as options to send.
336
384
  type image_transform_options_input = {
337
385
  ?format: image_format,
338
386
  ?width: Integer,
339
387
  ?height: Integer,
388
+ ?dpr: number,
389
+ ?anim: bool,
340
390
  ?background: String,
341
391
  ?blur: number,
342
- ?border: { ?color: String, ?width: number },
392
+ ?redact: {
393
+ ?text: bool,
394
+ ?personalInformation: bool
395
+ },
396
+ ?border: {
397
+ ?color: String,
398
+ ?width: number
399
+ },
343
400
  ?brightness: number,
344
401
  ?contrast: number,
345
- ?quality: Integer,
402
+ ?quality: Integer | image_quality_level,
346
403
  ?fit: image_fit,
347
- ?flip: "h" | "v" | "hv",
404
+ ?flip: image_flip,
348
405
  ?gamma: number,
349
- ?segment: "foreground",
350
- ?gravity: image_gravity_side | { mode: "remainder" | "box-center", ?x: number, ?y: number },
406
+ ?segment: image_segment,
407
+ ?gravity: image_gravity_side | {
408
+ mode: image_gravity_mode,
409
+ ?x: number,
410
+ ?y: number
411
+ },
351
412
  ?rotate: 0 | 90 | 180 | 270,
352
413
  ?saturation: number,
353
414
  ?sharpen: number,
@@ -358,7 +419,11 @@ module CalmLens
358
419
  ?right: number,
359
420
  ?width: number,
360
421
  ?height: number,
361
- ?border: bool | { ?color: String, ?tolerance: number, ?keep: number }
422
+ ?border: bool | {
423
+ ?color: String,
424
+ ?tolerance: number,
425
+ ?keep: number
426
+ }
362
427
  }
363
428
  }
364
429
  # IMAGE_TRANSFORM_OPTIONS_SCHEMA, as the API returns it in a lens.
@@ -366,17 +431,30 @@ module CalmLens
366
431
  ?"format" => image_format,
367
432
  ?"width" => Integer,
368
433
  ?"height" => Integer,
434
+ ?"dpr" => number,
435
+ ?"anim" => bool,
369
436
  ?"background" => String,
370
437
  ?"blur" => number,
371
- ?"border" => { ?"color" => String, ?"width" => number },
438
+ ?"redact" => {
439
+ ?"text" => bool,
440
+ ?"personalInformation" => bool
441
+ },
442
+ ?"border" => {
443
+ ?"color" => String,
444
+ ?"width" => number
445
+ },
372
446
  ?"brightness" => number,
373
447
  ?"contrast" => number,
374
- ?"quality" => Integer,
448
+ ?"quality" => Integer | image_quality_level,
375
449
  ?"fit" => image_fit,
376
- ?"flip" => "h" | "v" | "hv",
450
+ ?"flip" => image_flip,
377
451
  ?"gamma" => number,
378
- ?"segment" => "foreground",
379
- ?"gravity" => image_gravity_side | { "mode" => "remainder" | "box-center", ?"x" => number, ?"y" => number },
452
+ ?"segment" => image_segment,
453
+ ?"gravity" => image_gravity_side | {
454
+ "mode" => image_gravity_mode,
455
+ ?"x" => number,
456
+ ?"y" => number
457
+ },
380
458
  ?"rotate" => 0 | 90 | 180 | 270,
381
459
  ?"saturation" => number,
382
460
  ?"sharpen" => number,
@@ -387,15 +465,20 @@ module CalmLens
387
465
  ?"right" => number,
388
466
  ?"width" => number,
389
467
  ?"height" => number,
390
- ?"border" => bool | { ?"color" => String, ?"tolerance" => number, ?"keep" => number }
468
+ ?"border" => bool | {
469
+ ?"color" => String,
470
+ ?"tolerance" => number,
471
+ ?"keep" => number
472
+ }
391
473
  }
392
474
  }
475
+ # </generated: image-transform-options>
393
476
 
394
477
  # One structured transform step. `imageTransform` is the only transform type.
395
478
  type transform_step_input = { type: "imageTransform", ?options: image_transform_options_input }
396
479
  type transform_step = { "type" => "imageTransform", ?"options" => image_transform_options }
397
- # A selector String such as `imageTransform[format=png,width=1024]`, or structured steps, which
398
- # the SDK serializes into a selector.
480
+ # A selector String with one step per path segment, such as `fit=cover,width=1024/blur=12`, or
481
+ # structured steps, which the SDK serializes into a selector.
399
482
  type transform_input = String | transform_step_input | Array[transform_step_input]
400
483
 
401
484
  type lens_type = "image" | "video" | "audio" | "document" | "website"
@@ -412,7 +495,6 @@ module CalmLens
412
495
  type lens = {
413
496
  "id" => String,
414
497
  ?"projectId" => String?,
415
- ?"userId" => String?,
416
498
  "version" => Integer,
417
499
  "identifier" => String,
418
500
  "name" => String,
@@ -435,13 +517,56 @@ module CalmLens
435
517
  ?"updatedAt" => Integer
436
518
  }
437
519
 
520
+ # ---- Hash lists (HashList.ts) ----------------------------------------------------------------
521
+
522
+ type hash_list_action = "flag" | "block"
523
+
524
+ type hash_list = {
525
+ "id" => String,
526
+ "projectId" => String,
527
+ "name" => String,
528
+ ?"description" => String?,
529
+ "action" => hash_list_action,
530
+ "createdAt" => Integer,
531
+ ?"updatedAt" => Integer
532
+ }
533
+
534
+ # A hash list entry an image matched. `distance` is the number of differing bits (0 is the same
535
+ # picture); `action` is `block` when the match was close enough for a block list to block.
536
+ type hash_match = {
537
+ "source" => "hash-list",
538
+ "listId" => String,
539
+ "entryId" => String,
540
+ "distance" => Integer,
541
+ "action" => hash_list_action
542
+ }
543
+
544
+ type hash_list_entry = {
545
+ "id" => String,
546
+ "projectId" => String,
547
+ "hashListId" => String,
548
+ "hash" => String,
549
+ "quality" => number?,
550
+ ?"label" => String?,
551
+ ?"sourceAssetId" => String?,
552
+ "createdAt" => Integer
553
+ }
554
+
555
+ type hash_list_entry_page = {
556
+ "items" => Array[hash_list_entry],
557
+ "hasMore" => bool,
558
+ "nextCursor" => String?,
559
+ "pageSize" => Integer,
560
+ "ordering" => Array[order]
561
+ }
562
+
438
563
  # ---- Events and webhooks (Event.ts, EventCatalog.ts, WebhookPayload.ts) ----------------------
439
564
 
440
565
  # EVENT_TYPES in EventCatalog.ts. Ignore types your code does not handle. Webhook, Slack and email
441
566
  # deliveries and the public events feed leave out facts that hold personal or account data.
442
- type event_type = "asset.uploaded" | "asset.flagged" | "asset.approved" | "asset.rejected" |
443
- "asset.failed" | "asset.deleted" | "asset.content-removed" | "asset.retried" |
444
- "asset.review-requested" | "usage.limit-reached" | "usage.spend-limit-reached" |
567
+ type event_type = "asset.uploaded" | "asset.classified" | "asset.allowed" | "asset.limited" |
568
+ "asset.age-restricted" | "asset.blocked" | "asset.purged" | "asset.failed" | "asset.deleted" | "asset.content-removed" | "asset.retried" |
569
+ "asset.review-requested" | "asset.hash-matched" | "usage.limit-reached" | "usage.spend-limit-reached" |
445
570
  "upload-preset.daily-limit-reached" | "project.member-joined" | "project.member-removed" |
446
571
  "project.member-role-changed" | "project.invitation-sent" | "api-key.created" |
447
572
  "api-key.revoked" | "connector.failing" | "appeal.submitted" | "appeal.resolved"
@@ -457,41 +582,31 @@ module CalmLens
457
582
  # Snapshot of the asset's processing, moderation and content status when the event was created.
458
583
  type event_asset = {
459
584
  "id" => String,
585
+ ?"uploadPresetId" => String?,
460
586
  ?"externalId" => String?,
461
- "processing" => { "status" => asset_processing_status },
462
- "moderation" => { "status" => asset_moderation_status, "action" => asset_moderation_action? },
587
+ "upload" => { "status" => "uploading" | "completed" },
588
+ "classification" => { "status" => asset_classification_status, "moderation" => { "status" => asset_moderation_status } },
463
589
  "content" => { "status" => asset_content_status }
464
590
  }
591
+ # An `events.list` item, and the body of its webhook delivery.
465
592
  type event = {
466
593
  "id" => String,
467
594
  "projectId" => String,
468
- ?"userId" => String?,
469
595
  "type" => event_type,
470
596
  "severity" => event_severity,
471
597
  "title" => String,
472
- ?"description" => String?,
473
- ?"assetId" => String?,
474
- ?"asset" => event_asset?,
598
+ "description" => String?,
599
+ "assetId" => String?,
600
+ "asset" => event_asset?,
475
601
  "facts" => Array[event_fact],
476
- ?"notify" => bool?,
477
- "createdAt" => Integer,
478
- ?"updatedAt" => Integer,
479
- ?"readAt" => Integer?
480
- }
481
- type events_page = { "events" => Array[event], "cursor" => String, "hasMore" => bool }
482
-
483
- # WEBHOOK_EVENT_DATA_SCHEMA: the event fields a webhook delivery carries under `data`.
484
- type webhook_event_data = {
485
- "severity" => event_severity,
486
- "title" => String,
487
- ?"description" => String?,
488
- ?"assetId" => String?,
489
- ?"asset" => event_asset?,
490
- "facts" => Array[event_fact]
602
+ "createdAt" => Integer
491
603
  }
604
+ # Unlike other lists, `nextCursor` is never nil: keep it to receive later events.
605
+ type events_page = { "items" => Array[event], "nextCursor" => String, "hasMore" => bool }
492
606
 
493
607
  # ---- Method options -------------------------------------------------------------------------
494
608
 
609
+ type viewer_claims = { ?region: String, ?age_confirmed: bool }
495
610
  type asset_id_options = { asset_id: String, ?request_options: request_options }
496
611
  # `timeout` is the whole wait in seconds (default 60).
497
612
  type wait_for_decision_options = { asset_id: String, ?timeout: number, ?request_options: request_options }
@@ -506,7 +621,7 @@ module CalmLens
506
621
  ?cursor: String,
507
622
  ?page_size: Integer,
508
623
  ?ordering: Array[order_input],
509
- # An RSQL filter such as `moderation.status==approved`.
624
+ # An RSQL filter such as `classification.moderation.status==allowed`.
510
625
  ?filter: String?,
511
626
  ?folder_id: String?,
512
627
  ?request_options: request_options
@@ -529,10 +644,22 @@ module CalmLens
529
644
  ?visibility: asset_visibility?,
530
645
  ?request_options: request_options
531
646
  }
647
+ type batch_assets_options = { asset_ids: Array[String], operation: asset_batch_operation, ?request_options: request_options }
532
648
  type move_asset_options = { asset_id: String, folder_id: String?, ?request_options: request_options }
649
+ type explain_asset_options = { asset_id: String, ?rerun: bool, ?request_options: request_options }
650
+ # A reviewer's decision. `note` is 1 to 1499 characters; purging also needs `confirm_purge: true`.
651
+ type decide_asset_options = {
652
+ asset_id: String,
653
+ decision: "allowed" | "limited" | "age-restricted" | "blocked" | "purged",
654
+ note: String,
655
+ ?confirm_purge: bool,
656
+ ?request_options: request_options
657
+ }
533
658
  type create_signed_url_options = {
659
+ ?viewer_claims: viewer_claims,
534
660
  asset_id: String,
535
- ?resource: "content" | "preview",
661
+ # Defaults to `rendered` on the server; `original` takes no lens or transform.
662
+ ?resource: "original" | "rendered",
536
663
  ?expires_in_seconds: Integer,
537
664
  # A lens runs before any additional transforms.
538
665
  ?lens: String,
@@ -554,7 +681,7 @@ module CalmLens
554
681
  | { part_number: Integer, base64: String, ?is_final: bool, ?size_in_bytes: Integer }
555
682
  | { part_number: Integer, data: String | Transport::_Reader, ?is_final: bool, ?size_in_bytes: Integer }
556
683
 
557
- # Options of {Assets#create} and {Assets#moderate}: the shared asset fields with exactly one of
684
+ # Options of {Assets#create} and {Assets#classify}: the shared asset fields with exactly one of
558
685
  # `content:` (a whole file), `part:` (the first part of a multipart upload) or `url:` (a page or
559
686
  # file CalmLens fetches).
560
687
  type upload_options = {
@@ -563,6 +690,8 @@ module CalmLens
563
690
  ?description: String?,
564
691
  ?visibility: asset_visibility?,
565
692
  ?metadata: Array[metadata_item_input]?,
693
+ ?author_id: String,
694
+ ?context: moderation_context_input,
566
695
  ?external_id: String?,
567
696
  ?external_url: String?,
568
697
  ?folder_id: String?,
@@ -577,6 +706,8 @@ module CalmLens
577
706
  ?description: String?,
578
707
  ?visibility: asset_visibility?,
579
708
  ?metadata: Array[metadata_item_input]?,
709
+ ?author_id: String,
710
+ ?context: moderation_context_input,
580
711
  ?external_id: String?,
581
712
  ?external_url: String?,
582
713
  ?folder_id: String?,
@@ -590,6 +721,8 @@ module CalmLens
590
721
  ?description: String?,
591
722
  ?visibility: asset_visibility?,
592
723
  ?metadata: Array[metadata_item_input]?,
724
+ ?author_id: String,
725
+ ?context: moderation_context_input,
593
726
  ?external_id: String?,
594
727
  ?external_url: String?,
595
728
  ?folder_id: String?,
@@ -599,13 +732,15 @@ module CalmLens
599
732
  }
600
733
  type upload_part_options = { asset_id: String, part: upload_part, ?queue: bool, ?request_options: request_options }
601
734
 
602
- # Options of {Text#moderate}: the text, with the shared asset fields. `name` defaults to `text`.
735
+ # Options of {Text#classify}: the text, with the shared asset fields. `name` defaults to `text`.
603
736
  type moderate_text_options = {
604
737
  text: String,
605
738
  ?name: String,
606
739
  ?description: String?,
607
740
  ?visibility: asset_visibility?,
608
741
  ?metadata: Array[metadata_item_input]?,
742
+ ?author_id: String,
743
+ ?context: moderation_context_input,
609
744
  ?external_id: String?,
610
745
  ?external_url: String?,
611
746
  ?folder_id: String?,
@@ -623,13 +758,50 @@ module CalmLens
623
758
  }
624
759
  type signed_upload_token = { "token" => String, "expiresAt" => Integer }
625
760
 
626
- type list_folders_options = { ?request_options: request_options }
761
+ type folder_order_input = { field: "name" | "createdAt", direction: order_direction }
762
+ type list_folders_options = {
763
+ ?parent_id: String,
764
+ ?cursor: String,
765
+ # 1 to 100, default 50.
766
+ ?page_size: Integer,
767
+ # At most one entry; the default is `name` ascending.
768
+ ?ordering: Array[folder_order_input],
769
+ ?search: String,
770
+ ?request_options: request_options
771
+ }
772
+ type folder_page = {
773
+ "items" => Array[folder],
774
+ "ancestors" => Array[folder],
775
+ "hasMore" => bool,
776
+ "nextCursor" => String?,
777
+ "pageSize" => Integer,
778
+ "ordering" => Array[order]
779
+ }
627
780
  type folder_id_options = { folder_id: String, ?request_options: request_options }
628
781
  type create_folder_options = { name: String, ?parent_id: String?, ?request_options: request_options }
629
782
  type update_folder_options = { folder_id: String, ?name: String, ?request_options: request_options }
630
783
  type move_folder_options = { folder_id: String, parent_id: String?, ?request_options: request_options }
784
+ # 1 to 100 lists per page, default 50.
785
+ type list_hash_lists_options = { ?cursor: String, ?page_size: Integer, ?request_options: request_options }
786
+ type hash_list_page = {
787
+ "items" => Array[hash_list],
788
+ "hasMore" => bool,
789
+ "nextCursor" => String?,
790
+ "pageSize" => Integer,
791
+ "ordering" => Array[order]
792
+ }
793
+ type hash_list_id_options = { hash_list_id: String, ?request_options: request_options }
794
+ type create_hash_list_options = { name: String, action: hash_list_action, ?description: String?, ?request_options: request_options }
795
+ type update_hash_list_options = { hash_list_id: String, ?name: String, ?description: String?, ?action: hash_list_action,
796
+ ?request_options: request_options }
797
+ type list_hash_list_entries_options = { hash_list_id: String, ?cursor: String, ?page_size: Integer,
798
+ ?request_options: request_options }
799
+ type add_hash_list_entry_options = { hash_list_id: String, ?hash: String, ?quality: number, ?asset_id: String, ?label: String,
800
+ ?request_options: request_options }
801
+ type hash_list_entry_id_options = { entry_id: String, ?request_options: request_options }
631
802
 
632
- type list_events_options = { ?after: String, ?limit: Integer, ?request_options: request_options }
803
+ # `page_size` is 1 to 100, default 50.
804
+ type list_events_options = { ?cursor: String, ?page_size: Integer, ?request_options: request_options }
633
805
 
634
806
  type ensure_lenses_options = { lenses: Array[lens_definition], ?request_options: request_options }
635
807
  type ensure_lens_options = {
@@ -644,16 +816,22 @@ module CalmLens
644
816
  }
645
817
 
646
818
  type asset_url_options = {
819
+ ?viewer_claims: viewer_claims,
647
820
  # The asset ID or external ID.
648
821
  asset_identifier: String,
649
- ?resource: "content" | "preview",
822
+ # `rendered` is the default. `original` takes no lens or transform; `placeholder` is a small blurred PNG
823
+ # and takes no lens, transform or age_confirmed.
824
+ ?resource: "original" | "rendered" | "placeholder",
650
825
  # A lens runs before any additional transforms.
651
826
  ?lens: String,
652
- ?transform: transform_input
827
+ ?transform: transform_input,
828
+ # Appends `?ageConfirmed=true`, so a public `age-restricted` asset is served from this URL. Set it
829
+ # only where your app has already decided the viewer may see age-restricted content.
653
830
  }
654
831
  type serve_options = {
832
+ ?viewer_claims: viewer_claims,
655
833
  asset_identifier: String,
656
- ?resource: "content" | "preview",
834
+ ?resource: "original" | "rendered" | "placeholder",
657
835
  ?lens: String,
658
836
  ?transform: transform_input,
659
837
  ?init: { ?method: "GET" | "HEAD", ?headers: Hash[String, String] },
@@ -672,8 +850,8 @@ module CalmLens
672
850
  ?asset: {
673
851
  id: String,
674
852
  ?external_id: String?,
675
- processing: { status: asset_processing_status },
676
- moderation: { status: asset_moderation_status, action: asset_moderation_action? },
853
+ upload: { status: "uploading" | "completed" },
854
+ classification: { status: asset_classification_status, moderation: { status: asset_moderation_status } },
677
855
  content: { status: asset_content_status }
678
856
  }?,
679
857
  ?facts: Array[event_fact_input],