calmlens 0.21.0 → 0.23.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
@@ -102,7 +102,11 @@ module CalmLens
102
102
  # Preview. The adaptive stream of audio or video: HLS with fragmented MP4 (CMAF) segments, served
103
103
  # at the CDN's `hls` resource (`hls/index.m3u8`) and played by its `embed` resource. Renditions list
104
104
  # video from the largest down, then audio.
105
- type asset_hls = { "renditions" => Array[asset_hls_rendition] }
105
+ type asset_hls = {
106
+ "status" => String,
107
+ "reason" => String?,
108
+ "renditions" => Array[asset_hls_rendition]
109
+ }
106
110
  type asset_rendered_kind = "image" | "pdf" | "video" | "audio"
107
111
  # The asset's one displayable file, as the CDN's `rendered` resource serves it: an image, a PDF, or
108
112
  # browser-safe video or audio. `peaks` is an audio waveform's normalised peaks.
@@ -193,13 +197,32 @@ module CalmLens
193
197
  # What decided the automated status: the `policy`'s categories, the asset's `children`, a
194
198
  # `hash-list` match, a `mandatory-rule` or `link-safety`.
195
199
  type moderation_source = "policy" | "children" | "hash-list" | "mandatory-rule" | "link-safety"
200
+ # The policy that made a decision: its ID, its revision then and, for a policy from a preset, the
201
+ # preset release it used.
202
+ type decision_policy = {
203
+ "id" => String,
204
+ "revision" => Integer,
205
+ "preset" => { "id" => String, "version" => Integer }?
206
+ }
207
+ # A review the human review queue is waiting for: when the asset joined it (Unix milliseconds),
208
+ # why, and the categories that made the decision uncertain.
209
+ type asset_pending_review = {
210
+ "requestedAt" => Integer,
211
+ "reason" => "sampled" | "uncertain",
212
+ "uncertainCategories" => Array[String]
213
+ }
196
214
  # Every field but `status`, `manualReviews`, `flaggedCategories`, `regions` and `timeline` is `nil`
197
- # until moderation decides.
215
+ # until moderation decides; `pendingReview` is `nil` when no review is waiting.
198
216
  type asset_moderation = {
199
217
  "manualReviews" => Array[asset_review],
200
218
  "status" => asset_moderation_status,
201
219
  # The policy's original decision; a reviewer's decision can change `status` without changing it.
202
220
  "automatedStatus" => asset_moderation_decision?,
221
+ # The policy that made the automated decision, as it was then.
222
+ "policy" => decision_policy?,
223
+ # The review the human review queue is waiting for, set with the automated decision that
224
+ # joined the queue; `nil` when no review is waiting.
225
+ "pendingReview" => asset_pending_review?,
203
226
  "source" => moderation_source?,
204
227
  # The mandatory rule that decided, when `source` is `mandatory-rule`; otherwise `nil`.
205
228
  "rule" => String?,
@@ -249,6 +272,8 @@ module CalmLens
249
272
  "id" => String,
250
273
  "projectId" => String,
251
274
  ?"parentId" => String?,
275
+ # The pages of the parent document a child shows, from 1; empty when unknown or not a child.
276
+ ?"parentPages" => Array[Integer],
252
277
  ?"folderId" => String?,
253
278
  ?"uploadPresetId" => String?,
254
279
  "createdAt" => Integer,
@@ -276,6 +301,9 @@ module CalmLens
276
301
  type likelihood = "very-unlikely" | "unlikely" | "possible" | "likely" | "very-likely"
277
302
  # not-supported: this processing path cannot assess the signal; unavailable: assessment failed.
278
303
  type not_evaluated_reason = "not-supported" | "unavailable"
304
+ # A processing feature's reason, which adds in-children: a document's or website's images are each
305
+ # a child asset with its own result (`assets.list_children`).
306
+ type feature_not_evaluated_reason = not_evaluated_reason | "in-children"
279
307
  type classification_category = "sexual" | "violence" | "self-harm" | "harassment" | "hate" | "criminal-activity"
280
308
 
281
309
  # `status: "evaluated"` carries `someScore`, `likelihood` and optionally `allScore`;
@@ -324,13 +352,13 @@ module CalmLens
324
352
  type person_detection_result = {
325
353
  "status" => "evaluated" | "not-evaluated",
326
354
  ?"people" => Array[detected_person],
327
- ?"reason" => not_evaluated_reason
355
+ ?"reason" => feature_not_evaluated_reason
328
356
  }
329
357
  # `status: "evaluated"` carries `faces`; `"not-evaluated"` carries `reason`.
330
358
  type face_detection_result = {
331
359
  "status" => "evaluated" | "not-evaluated",
332
360
  ?"faces" => Array[detected_face],
333
- ?"reason" => not_evaluated_reason
361
+ ?"reason" => feature_not_evaluated_reason
334
362
  }
335
363
  type detected_qr_code = { "value" => String, "box" => bounding_box }
336
364
  # A web link found in a QR code or in the text OCR extracted.
@@ -340,7 +368,7 @@ module CalmLens
340
368
  "status" => "evaluated" | "not-evaluated",
341
369
  ?"qrCodes" => Array[detected_qr_code],
342
370
  ?"links" => Array[detected_link],
343
- ?"reason" => not_evaluated_reason
371
+ ?"reason" => feature_not_evaluated_reason
344
372
  }
345
373
  # Link safety (preview, LinkSafety.ts).
346
374
  # What a link's destination is: `safe` when every reputation check passed, `adult` or `gambling`
@@ -404,16 +432,15 @@ module CalmLens
404
432
  "status" => "evaluated" | "not-evaluated",
405
433
  ?"provenance" => "ai-generated" | "ai-edited" | "unknown",
406
434
  ?"signals" => Array[provenance_signal],
407
- ?"reason" => not_evaluated_reason
435
+ ?"reason" => feature_not_evaluated_reason
408
436
  }
409
437
  # Where OCR found text in an image, and whether it is personal information.
410
438
  type text_region = { "box" => bounding_box, "personalInformation" => bool }
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`.
439
+ # `status: "evaluated"` carries `textRegions`, where OCR found text; `"not-evaluated"` carries `reason`. The text itself is `content.extractedText`.
413
440
  type ocr_result = {
414
441
  "status" => "evaluated" | "not-evaluated",
415
442
  ?"textRegions" => Array[text_region],
416
- ?"reason" => not_evaluated_reason
443
+ ?"reason" => feature_not_evaluated_reason
417
444
  }
418
445
 
419
446
  # How strongly each assessed category meets the policy and what the policy does with it.
@@ -424,7 +451,7 @@ module CalmLens
424
451
  # What decided a category's action: its `default` action, a policy score `below-threshold`, or the
425
452
  # `allowance` or `restriction` rules listed by `indexes` (at least one, the decisive rule first).
426
453
  type category_policy_source = { "kind" => "default" | "below-threshold" } |
427
- { "kind" => "allowance" | "restriction", "indexes" => Array[Integer] }
454
+ { "kind" => "allowance" | "restriction", "indexes" => Array[Integer], "conditionScore" => Float }
428
455
  type category_policy_settings_snapshot = {
429
456
  "action" => flagged_content_action,
430
457
  "allowances" => Array[policy_rule_snapshot], "restrictions" => Array[policy_rule_snapshot]
@@ -517,11 +544,6 @@ module CalmLens
517
544
  ?anim: bool,
518
545
  ?background: String,
519
546
  ?blur: number,
520
- ?redact: {
521
- ?text: bool,
522
- ?personalInformation: bool,
523
- ?faces: bool
524
- },
525
547
  ?border: {
526
548
  ?color: String,
527
549
  ?width: number
@@ -564,11 +586,6 @@ module CalmLens
564
586
  ?"anim" => bool,
565
587
  ?"background" => String,
566
588
  ?"blur" => number,
567
- ?"redact" => {
568
- ?"text" => bool,
569
- ?"personalInformation" => bool,
570
- ?"faces" => bool
571
- },
572
589
  ?"border" => {
573
590
  ?"color" => String,
574
591
  ?"width" => number
@@ -609,12 +626,12 @@ module CalmLens
609
626
  type transform_input = String | image_transform_options_input
610
627
 
611
628
  type lens_type = "image" | "video" | "audio" | "document" | "website"
612
- # ENSURE_LENS_BODY_SCHEMA: a lens definition, which the CDN serves once it is saved.
629
+ # ENSURE_LENS_BODY_SCHEMA: a lens definition, which the CDN serves once it is saved unless `active` is false.
613
630
  type lens_definition = {
614
631
  identifier: String,
615
632
  name: String,
616
633
  type: lens_type,
617
- active: bool,
634
+ ?active: bool,
618
635
  ?description: String?,
619
636
  ?transform: image_transform_options_input?
620
637
  }
@@ -636,6 +653,81 @@ module CalmLens
636
653
  "nextCursor" => String?
637
654
  }
638
655
 
656
+ # ---- Configuration as data (UploadPreset.ts, ProjectConfiguration.ts) --------------------------
657
+
658
+ type upload_preset_access = "token" | "anyone"
659
+ # An upload preset's processing options, as the API returns them.
660
+ type upload_preset_processing_options = {
661
+ ?"keepContentAfterProcessing" => bool?,
662
+ ?"storeSensitiveMetadata" => bool?,
663
+ ?"features" => {
664
+ ?"ocr" => { "enabled" => bool }?,
665
+ ?"personDetection" => { "enabled" => bool }?,
666
+ ?"faceDetection" => { "enabled" => bool, ?"ageEstimation" => bool? }?,
667
+ ?"linkDetection" => { "enabled" => bool }?,
668
+ ?"streaming" => { "enabled" => bool }?
669
+ }?
670
+ }
671
+ # The rules for uploads made from browsers and apps. `key` is unique in its project; `revision`
672
+ # counts changes, starting at 1. Send it back with a change.
673
+ type upload_preset = {
674
+ "id" => String,
675
+ "projectId" => String,
676
+ ?"createdByUserId" => String?,
677
+ "key" => String,
678
+ "revision" => Integer,
679
+ "name" => String,
680
+ "access" => upload_preset_access,
681
+ "enabled" => bool,
682
+ ?"allowedContentTypes" => Array[String]?,
683
+ ?"maxSizeInBytes" => Integer?,
684
+ ?"folderId" => String?,
685
+ ?"policyId" => String?,
686
+ "visibility" => asset_visibility,
687
+ ?"processingOptions" => upload_preset_processing_options?,
688
+ "revealDecision" => bool,
689
+ ?"dailyUploadLimit" => Integer?,
690
+ ?"allowedOrigins" => Array[String]?,
691
+ "createdAt" => Integer,
692
+ "updatedAt" => Integer
693
+ }
694
+ type upload_preset_page = { "items" => Array[upload_preset], "hasMore" => bool, "nextCursor" => String? }
695
+ type ensure_upload_presets_response = { "uploadPresets" => Array[upload_preset] }
696
+
697
+ type remote_url_rule = { "mode" => "allow" | "deny", "domains" => Array[String] }
698
+ type human_review_settings = {
699
+ "allowedSamplePercent" => number,
700
+ "restrictedSamplePercent" => number,
701
+ "uncertaintyMarginPercent" => number,
702
+ "reviewMissingEvidence" => bool
703
+ }
704
+ type public_project_settings = {
705
+ "optOutJurisdictions" => Array[String],
706
+ "blockUnmoderatedAssets" => bool,
707
+ "storeSensitiveMetadata" => bool,
708
+ "streamingEnabled" => bool,
709
+ "aiMediaSearchEnabled" => bool,
710
+ "remoteUrlRule" => remote_url_rule?,
711
+ "websiteSubmissionsPerMinute" => Integer?,
712
+ "humanReview" => human_review_settings
713
+ }
714
+ # The project's settings, with defaults filled in. `revision` counts changes to the settings and
715
+ # metadata fields, starting at 1. Send it back with a change.
716
+ type project_settings_resource = { "projectId" => String, "revision" => Integer, "settings" => public_project_settings }
717
+
718
+ type metadata_field_type = "string" | "number" | "boolean" | "date" | "url"
719
+ type metadata_field_icon = "tag" | "hash" | "user" | "folder" | "layers" | "photo" | "link"
720
+ # A metadata field the portal shows and filters by. `color` is `#rrggbb`.
721
+ type metadata_field = {
722
+ "id" => String,
723
+ "title" => String,
724
+ ?"description" => String,
725
+ "type" => metadata_field_type,
726
+ "icon" => metadata_field_icon,
727
+ "color" => String
728
+ }
729
+ type metadata_fields_resource = { "projectId" => String, "revision" => Integer, "fields" => Array[metadata_field] }
730
+
639
731
  # ---- Folders (Folder.ts) --------------------------------------------------------------------
640
732
 
641
733
  type folder = {
@@ -1067,7 +1159,7 @@ module CalmLens
1067
1159
  identifier: String,
1068
1160
  name: String,
1069
1161
  type: lens_type,
1070
- active: bool,
1162
+ ?active: bool,
1071
1163
  ?description: String?,
1072
1164
  ?transform: image_transform_options_input?,
1073
1165
  ?request_options: request_options
@@ -1087,6 +1179,64 @@ module CalmLens
1087
1179
  ?request_options: request_options
1088
1180
  }
1089
1181
 
1182
+ # `sort` is `createdAt` and `id`, `createdAt` (oldest first) by default.
1183
+ type list_upload_presets_options = { ?cursor: String, ?page_size: Integer, ?sort: sort, ?request_options: request_options }
1184
+ # One preset's whole definition, by `key`; fields left out take their defaults. Send the `revision`
1185
+ # you read (0 for a preset that must not exist yet) to refuse a change made since.
1186
+ type upload_preset_definition = {
1187
+ key: String,
1188
+ name: String,
1189
+ ?revision: Integer,
1190
+ ?access: upload_preset_access,
1191
+ ?enabled: bool,
1192
+ ?allowed_content_types: Array[String]?,
1193
+ ?max_size_in_bytes: Integer?,
1194
+ ?folder_id: String?,
1195
+ ?policy_id: String?,
1196
+ ?visibility: asset_visibility,
1197
+ ?processing_options: processing_options_input?,
1198
+ ?reveal_decision: bool,
1199
+ ?daily_upload_limit: Integer?,
1200
+ ?allowed_origins: Array[String]?
1201
+ }
1202
+ type ensure_upload_presets_options = { upload_presets: Array[upload_preset_definition], ?request_options: request_options }
1203
+ type upload_preset_id_options = { upload_preset_id: String, ?request_options: request_options }
1204
+ # The complete settings: those left out return to their defaults.
1205
+ type project_settings_input = {
1206
+ ?opt_out_jurisdictions: Array[String],
1207
+ ?block_unmoderated_assets: bool,
1208
+ ?store_sensitive_metadata: bool,
1209
+ ?streaming_enabled: bool,
1210
+ ?ai_media_search_enabled: bool,
1211
+ ?remote_url_rule: { mode: "allow" | "deny", domains: Array[String] }?,
1212
+ ?website_submissions_per_minute: Integer?,
1213
+ ?human_review: {
1214
+ ?allowed_sample_percent: number,
1215
+ ?restricted_sample_percent: number,
1216
+ ?uncertainty_margin_percent: number,
1217
+ ?review_missing_evidence: bool
1218
+ }
1219
+ }
1220
+ # Send the `revision` you read to refuse settings changed since. `search_indexing_budget_units` is
1221
+ # needed when turning on `ai_media_search_enabled`.
1222
+ type update_project_settings_options = {
1223
+ ?revision: Integer,
1224
+ settings: project_settings_input,
1225
+ ?search_indexing_budget_units: number,
1226
+ ?request_options: request_options
1227
+ }
1228
+ type metadata_field_input = {
1229
+ id: String,
1230
+ title: String,
1231
+ ?description: String,
1232
+ type: metadata_field_type,
1233
+ icon: metadata_field_icon,
1234
+ color: String
1235
+ }
1236
+ # Fields to create or replace by ID; other fields are kept.
1237
+ type ensure_metadata_fields_options = { ?revision: Integer, fields: Array[metadata_field_input], ?request_options: request_options }
1238
+ type delete_metadata_field_options = { field_id: String, ?revision: Integer, ?request_options: request_options }
1239
+
1090
1240
  type asset_url_options = {
1091
1241
  # Exactly one of `asset_id` and `external_id`.
1092
1242
  ?asset_id: String,
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: calmlens
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.21.0
4
+ version: 0.23.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - CalmLens
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-11-08 00:00:00.000000000 Z
11
+ date: 2026-11-09 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: 'Server-side client for the CalmLens API: moderation, uploads, events,
14
14
  webhooks and CDN delivery.'
@@ -32,6 +32,7 @@ files:
32
32
  - lib/calmlens/moderation_context.rb
33
33
  - lib/calmlens/option_keys.rb
34
34
  - lib/calmlens/policies.rb
35
+ - lib/calmlens/project_configuration.rb
35
36
  - lib/calmlens/resource.rb
36
37
  - lib/calmlens/response.rb
37
38
  - lib/calmlens/server_client.rb