From eda45e043733e2a3e0fe65c46e94569dd8ff4fec Mon Sep 17 00:00:00 2001 From: chrisdengso <8185683+chrisdengso@users.noreply.github.com> Date: Mon, 9 Nov 2026 12:11:51 +0000 Subject: [PATCH] fix: v0.6.1 --- .speakeasy/gen.lock | 72 ++-- .speakeasy/gen.yaml | 2 +- .speakeasy/openapi.json | 323 +++++++++++++----- CHANGELOG.md | 10 + README.md | 1 + internal/cli/actions/create.go | 2 +- internal/cli/actions/execute.go | 2 +- internal/cli/actions/list.go | 2 +- internal/cli/actions/retrieve.go | 2 +- internal/cli/actions/update.go | 2 +- internal/cli/content/submit.go | 2 +- internal/cli/queue/items/list.go | 2 +- internal/cli/queue/items/resolve.go | 4 +- internal/cli/queue/items/resolvemany.go | 4 +- internal/cli/queue/items/unresolve.go | 4 +- internal/cli/version.go | 2 +- internal/cli/wordlist/delete.go | 94 +++++ internal/cli/wordlist/root.go | 4 + internal/sdk/actions.go | 10 +- internal/sdk/content.go | 1 + internal/sdk/items.go | 8 +- internal/sdk/models/components/queueitem.go | 4 +- .../sdk/models/operations/deletewordlist.go | 91 +++++ .../sdk/models/operations/resolvequeueitem.go | 2 +- .../models/operations/resolvequeueitems.go | 4 +- .../sdk/models/operations/submitcontent.go | 2 +- .../models/operations/unresolvequeueitem.go | 2 +- internal/sdk/moderationapi.go | 6 +- internal/sdk/wordlist.go | 232 +++++++++++++ internal/usage/bodyschemas.go | 4 +- internal/usage/schema.go | 11 +- 31 files changed, 767 insertions(+), 144 deletions(-) create mode 100644 internal/cli/wordlist/delete.go create mode 100644 internal/sdk/models/operations/deletewordlist.go diff --git a/.speakeasy/gen.lock b/.speakeasy/gen.lock index 2e3a3f2..3e7473d 100644 --- a/.speakeasy/gen.lock +++ b/.speakeasy/gen.lock @@ -1,12 +1,12 @@ lockVersion: 2.0.0 id: f6fec850-ef66-45dd-9a18-cec7cc0801ce management: - docChecksum: d6bce8a263f0ec11d54bdf026957ba2f + docChecksum: ee682d1963be184ab35560fa9a9c50c9 docVersion: 1.1.0 speakeasyVersion: internal generationVersion: internal - releaseVersion: 0.6.0 - configChecksum: 4cc78732410808a71d9e1e939e1e4dc3 + releaseVersion: 0.6.1 + configChecksum: 927969eff5ab77ad68a24fac0cb3f9cc repoURL: https://github.com/moderation-api/cli installationURL: https://github.com/moderation-api/cli published: true @@ -47,19 +47,19 @@ trackedFiles: internal/cli/account/root.go: last_write_checksum: sha1:aa12668d14acb9eabe91fd5232123b0a364ef721 internal/cli/actions/create.go: - last_write_checksum: sha1:846b618c38a651abceec5bc49e1a57b090113fba + last_write_checksum: sha1:f2bcdb236ccb20d4ef4bbbdb727ed040b4510939 internal/cli/actions/delete.go: last_write_checksum: sha1:c71d0687c59b64159890fec7b396414008aa123b internal/cli/actions/execute.go: - last_write_checksum: sha1:4e3e4e3af01895f2f7afe1d7823f245139399f80 + last_write_checksum: sha1:ca40ac513a4f834cd6b4a417f308c378781944ee internal/cli/actions/list.go: - last_write_checksum: sha1:cb002d17fddd5b5eabee0c3ff054a53bc74633be + last_write_checksum: sha1:9b7b6bfcf56db5644c9e3ccbf4253155a2e3924e internal/cli/actions/retrieve.go: - last_write_checksum: sha1:e35e8ec7923a423a7e66f5d51dc8c951e815d11a + last_write_checksum: sha1:3758a7b5891470cd059ebfaebd62639e08ff6699 internal/cli/actions/root.go: last_write_checksum: sha1:bfc573f85ebfb3ddd27c0168b84918d3bed46899 internal/cli/actions/update.go: - last_write_checksum: sha1:0636aeef587e5fa1bdf536a7a7cac8077b2e3f4d + last_write_checksum: sha1:a82181ece85987d142355a469276426199318c5c internal/cli/analytics/authors.go: last_write_checksum: sha1:dd0a5a802a85800cf68c373b7c2c7f4b1df005d6 internal/cli/analytics/automation.go: @@ -117,7 +117,7 @@ trackedFiles: internal/cli/content/root.go: last_write_checksum: sha1:785c6f2a7a640f7d8c59f657a2648e31f78661c9 internal/cli/content/submit.go: - last_write_checksum: sha1:5db89edd5a5f6b7867090c973744f629e4498422 + last_write_checksum: sha1:4a2093666ff8d1ee43a4fefb35142c1b9ea1a5bb internal/cli/feedback/create.go: last_write_checksum: sha1:1e22b74d4129da1cc98e9500a4e279f825d49567 internal/cli/feedback/root.go: @@ -145,15 +145,15 @@ trackedFiles: internal/cli/queue/getstats.go: last_write_checksum: sha1:dccfb6a53167375a75d7a41b243f93e3938fb475 internal/cli/queue/items/list.go: - last_write_checksum: sha1:9472e50b9528c24b556b64d4acd269dfcbffbde0 + last_write_checksum: sha1:09acae5af2de89fe61b89ef8658a5cd2685f1fa7 internal/cli/queue/items/resolve.go: - last_write_checksum: sha1:82554a72880ca640f629bd4e37593bd9e638b595 + last_write_checksum: sha1:a5ac2373401a91ce4acc8e12d6655a87525e68c7 internal/cli/queue/items/resolvemany.go: - last_write_checksum: sha1:6bafd91917a5fa29a12dfa448d2d8d7b72e66517 + last_write_checksum: sha1:952ff62c546fc4635719a61936c526fa8a96b94a internal/cli/queue/items/root.go: last_write_checksum: sha1:b90044575e57963575795c052a3e3b20b5bccf1f internal/cli/queue/items/unresolve.go: - last_write_checksum: sha1:2ca0793ed1596af844d545e617ae27f902f19186 + last_write_checksum: sha1:6b6f849526d53d2b59446f09126a5fe35a5f28aa internal/cli/queue/list.go: last_write_checksum: sha1:6c90a4b14db41fdc45b41c4b8a05adb9159e109a internal/cli/queue/retrieve.go: @@ -163,7 +163,7 @@ trackedFiles: internal/cli/root.go: last_write_checksum: sha1:e5d1b2211d9b4aaa93e95f248ce7db2af0a1844c internal/cli/version.go: - last_write_checksum: sha1:8ec1fd280177b7de452c747511fd0ad1c8619898 + last_write_checksum: sha1:c6616d9a645013aaa7d66cb0cfde4722849eca51 internal/cli/webhooks/create.go: last_write_checksum: sha1:98c73266c8954efcf0da2493ae41909df45a38f0 internal/cli/webhooks/delete.go: @@ -184,6 +184,8 @@ trackedFiles: last_write_checksum: sha1:1cf0058687544cf792329d1944330e3a86b2bb7d internal/cli/wordlist/create.go: last_write_checksum: sha1:40c5b64716f2bcadf2d668ac1e0d63137780b288 + internal/cli/wordlist/delete.go: + last_write_checksum: sha1:102c9488b7a13d0159ea312fa47ab08e4e572931 internal/cli/wordlist/getembeddingstatus.go: last_write_checksum: sha1:127a47ac52060279377b439b9d53722ff2ce3836 internal/cli/wordlist/list.go: @@ -191,7 +193,7 @@ trackedFiles: internal/cli/wordlist/retrieve.go: last_write_checksum: sha1:12b90a87f77658b316d8f66a8f31159da76e909c internal/cli/wordlist/root.go: - last_write_checksum: sha1:ad86a0ad77b173379c1d373cf95d33996e2fe88c + last_write_checksum: sha1:b98758cc7f7ece90d255cff18f44c61f9c327650 internal/cli/wordlist/update.go: last_write_checksum: sha1:f59d133aa483d707135b86e4239a9d0d962e0170 internal/cli/wordlist/words/add.go: @@ -261,7 +263,7 @@ trackedFiles: internal/sdk/account.go: last_write_checksum: sha1:c73d83f641b59a97479506597334a95539d34e16 internal/sdk/actions.go: - last_write_checksum: sha1:d6f0d54d24673ae13bd908680018b71e7d520820 + last_write_checksum: sha1:94f854ce11d440307de136d18bd2a229b84968cf internal/sdk/analytics.go: last_write_checksum: sha1:b33d5be04b4ba31ea97e2b4a23af2ba00869da59 internal/sdk/apikeys.go: @@ -271,11 +273,11 @@ trackedFiles: internal/sdk/channels.go: last_write_checksum: sha1:9725f5e3d5a0f5de727883345c47910195549294 internal/sdk/content.go: - last_write_checksum: sha1:cccfa1b907ecf93c3f82bb8c15e599ada01e50fd + last_write_checksum: sha1:42b3c6379e70b300b68f6dbf18c086fb2991e27f internal/sdk/feedback.go: last_write_checksum: sha1:e851165bd315e8c590b4df1a5b6d40d4e2fa4a92 internal/sdk/items.go: - last_write_checksum: sha1:6da4b4e01374a5310ddd040e15cef9ec9c02d58f + last_write_checksum: sha1:30cd6aad0ca8f601038acf5c99cf03acc1570534 internal/sdk/models/components/authenticationerror.go: last_write_checksum: sha1:a3e65f0561efe3e332c01c0966f9b34f017e92eb internal/sdk/models/components/badrequesterror.go: @@ -307,7 +309,7 @@ trackedFiles: internal/sdk/models/components/queue.go: last_write_checksum: sha1:7fbe5aa0d9bf34eacb6eeb3dd1c3621d6c44b1d0 internal/sdk/models/components/queueitem.go: - last_write_checksum: sha1:2cd9946435953cc326610016dee84c1ac5e9ed66 + last_write_checksum: sha1:bbbbd2a941908c3dcaabde2c3a024d686aac2763 internal/sdk/models/components/queuewithcounts.go: last_write_checksum: sha1:7955e2097d8a045e8c91fc7e95a03ebfe32d6286 internal/sdk/models/components/ratelimiterror.go: @@ -346,6 +348,8 @@ trackedFiles: last_write_checksum: sha1:f0c5345c149027a90591b4dedf592d321bb00162 internal/sdk/models/operations/deletewebhook.go: last_write_checksum: sha1:ec51074ff96306e513685d48124863e5fe0d7f4d + internal/sdk/models/operations/deletewordlist.go: + last_write_checksum: sha1:2437abfd126b0f79971794cbd633ab75a460c473 internal/sdk/models/operations/duplicatechannel.go: last_write_checksum: sha1:80fb60a28f7301aae451e519ccdcafb734a92ade internal/sdk/models/operations/duplicateproject.go: @@ -409,17 +413,17 @@ trackedFiles: internal/sdk/models/operations/removewordlistwords.go: last_write_checksum: sha1:3f05a9e7df2be903164ba8bc07835473087b7f64 internal/sdk/models/operations/resolvequeueitem.go: - last_write_checksum: sha1:eb416c24aa5b611629925fd8caa77f4ce33bd475 + last_write_checksum: sha1:df2b43fe7abfc79d057a0b15481d6093311b83d7 internal/sdk/models/operations/resolvequeueitems.go: - last_write_checksum: sha1:f43daa692b1e8203ce8ebf2adf80b79e9f04b8ae + last_write_checksum: sha1:67cb09a546f1c617a9e239a64776d5d69244bfdd internal/sdk/models/operations/submitcontent.go: - last_write_checksum: sha1:cb670d0bf2fdcd9c7ac68031c7512e2c7d0604bf + last_write_checksum: sha1:9cce6e5ba0a74616d1be4427478571e979ff7a16 internal/sdk/models/operations/suspendauthor.go: last_write_checksum: sha1:af885ce2174abc6695e4dbaddd7b468d50d47bdd internal/sdk/models/operations/unblockauthor.go: last_write_checksum: sha1:b3ad277887e69ba140a561cde376dc0d17716ed5 internal/sdk/models/operations/unresolvequeueitem.go: - last_write_checksum: sha1:093fc225a3915f232e5fc18512eb0df40cfc956d + last_write_checksum: sha1:da5eb701b541f7ef8005acf308623b4ff4e840a2 internal/sdk/models/operations/updateaction.go: last_write_checksum: sha1:bdd668d1dd1d7d164eac482e10050cd4b8a80bf9 internal/sdk/models/operations/updateauthor.go: @@ -451,7 +455,7 @@ trackedFiles: internal/sdk/models/sdkerrors/sdkdefaulterror.go: last_write_checksum: sha1:437b3a3eacb54d8648a68f80b3cd38fa5019f006 internal/sdk/moderationapi.go: - last_write_checksum: sha1:23253dcf72960a999e32bf25f7b5bb41c216d3e4 + last_write_checksum: sha1:cfa2d1043d9446d0aadd3c8def4a69e416d6c97f internal/sdk/optionalnullable/optionalnullable.go: last_write_checksum: sha1:b828c94c45116e632925027e4e2c211e971e04e2 internal/sdk/optionalnullable/optionalnullable_test.go: @@ -505,15 +509,15 @@ trackedFiles: internal/sdk/webhooksecret.go: last_write_checksum: sha1:dba657bf0d16c657a8dbca1ae9f620394a15b83c internal/sdk/wordlist.go: - last_write_checksum: sha1:3e9a9d7460d5fa4594d078c798d713e1fad2c9dc + last_write_checksum: sha1:8ece3f9b112924179c5a80cc5daed35b438e4631 internal/sdk/words.go: last_write_checksum: sha1:444eb505ec11550665c14531b19b6ef451b2f4cf internal/testclient/testclient.go: last_write_checksum: sha1:7107e59d336235c44af152c5a61ee3896a7841fa internal/usage/bodyschemas.go: - last_write_checksum: sha1:27959b7df8d97c2b4639655c81c330a43114d7d6 + last_write_checksum: sha1:b7a71350264254881d21f50b539474c00d1e50f2 internal/usage/schema.go: - last_write_checksum: sha1:3ca5ea9c7c1891b13d1e360a33e7075bd5db1f0b + last_write_checksum: sha1:487d38bfa637fae39dc22d56968f9eee30483ce2 scripts/install.ps1: last_write_checksum: sha1:bd3a52c28f647ed881c6e8d72abf2d84216976c9 scripts/install.sh: @@ -1567,4 +1571,18 @@ examples: application/json: {"type": "not_found_error", "code": "resource_not_found", "message": "Not found", "request_id": "h8fkz6kkzoa446ffve37atys", "doc_url": "https://confused-bell.org"} "429": application/json: {"type": "rate_limit_error", "code": "rate_limit_exceeded", "message": "Rate limit exceeded", "request_id": "h8fkz6kkzoa446ffve37atys", "doc_url": "https://nervous-partridge.org/"} + deleteWordlist: + speakeasy-default-delete-wordlist: + parameters: + path: + id: "" + responses: + "200": + application/json: {"id": "", "deleted": true, "detachedChannelIds": ["", "", ""]} + "401": + application/json: {"type": "authentication_error", "code": "unauthorized", "message": "Authorization not provided", "request_id": "h8fkz6kkzoa446ffve37atys", "doc_url": "https://rotating-exterior.biz/"} + "404": + application/json: {"type": "not_found_error", "code": "resource_not_found", "message": "Not found", "request_id": "h8fkz6kkzoa446ffve37atys", "doc_url": "https://flickering-airmail.org/"} + "429": + application/json: {"type": "rate_limit_error", "code": "rate_limit_exceeded", "message": "Rate limit exceeded", "request_id": "h8fkz6kkzoa446ffve37atys", "doc_url": "https://decent-millet.biz"} examplesVersion: 1.0.2 diff --git a/.speakeasy/gen.yaml b/.speakeasy/gen.yaml index 14a289f..c20258e 100644 --- a/.speakeasy/gen.yaml +++ b/.speakeasy/gen.yaml @@ -32,7 +32,7 @@ generation: generateNewTests: true skipResponseBodyAssertions: false cli: - version: 0.6.0 + version: 0.6.1 additionalDependencies: {} agentEnvironmentDetection: true arrayFlagFormat: repeatable diff --git a/.speakeasy/openapi.json b/.speakeasy/openapi.json index 9a2cf7e..ce4de79 100644 --- a/.speakeasy/openapi.json +++ b/.speakeasy/openapi.json @@ -394,7 +394,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } } }, @@ -591,7 +592,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } } }, @@ -790,7 +792,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } } }, @@ -972,7 +975,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } } }, @@ -1179,7 +1183,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } } }, @@ -1433,7 +1438,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } } }, @@ -1624,7 +1630,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false }, "x-speakeasy-pagination": { "type": "offsetLimit", @@ -1874,7 +1881,8 @@ "write" ], "readOnlyHint": false, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } } }, @@ -1993,7 +2001,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } }, "put": { @@ -2234,7 +2243,8 @@ "destructive" ], "readOnlyHint": false, - "destructiveHint": true + "destructiveHint": true, + "openWorldHint": false } }, "delete": { @@ -2360,7 +2370,8 @@ "destructive" ], "readOnlyHint": false, - "destructiveHint": true + "destructiveHint": true, + "openWorldHint": false } } }, @@ -2510,7 +2521,8 @@ "write" ], "readOnlyHint": false, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } } }, @@ -2658,7 +2670,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false }, "x-speakeasy-pagination": { "type": "offsetLimit", @@ -2805,7 +2818,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } } }, @@ -3025,7 +3039,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } } }, @@ -3033,7 +3048,7 @@ "get": { "operationId": "listQueueItems", "summary": "List queue items", - "description": "List the items of a review queue, with the filters and the date window of the queue applied. By default only pending items. The list is paginated. Use the item `id` to resolve or unresolve an item.", + "description": "List the items of a review queue, with the filters and the date window of the queue applied. By default only pending items. The list is paginated. Use the item `id` or `contentId` to resolve or unresolve an item.", "tags": [ "Review queues" ], @@ -3254,7 +3269,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false }, "x-speakeasy-pagination": { "type": "offsetLimit", @@ -3281,7 +3297,7 @@ "post": { "operationId": "resolveQueueItem", "summary": "Resolve a queue item", - "description": "Mark an item of a queue as resolved. It is the same as a check-off in the dashboard: the item leaves the pending list and a QUEUE_ITEM_COMPLETED webhook is sent. To also take a moderation action, use `POST /actions/execute`.", + "description": "Mark an item of a queue as resolved. It is the same as a check-off in the dashboard: the item leaves the pending list and a QUEUE_ITEM_COMPLETED webhook is sent. `itemId` is the item `id` or your `contentId`. To also take a moderation action, use `POST /actions/execute`.", "tags": [ "Review queues" ], @@ -3306,10 +3322,10 @@ "name": "itemId", "schema": { "type": "string", - "description": "The item ID to resolve." + "description": "The item to resolve: the item `id` from `GET /queue/{id}/items`, or the `contentId` you sent to `POST /moderate` (webhooks send it as `item.id`). For a content ID, the newest submission with that content ID is used, as the queue shows it." }, "required": true, - "description": "The item ID to resolve." + "description": "The item to resolve: the item `id` from `GET /queue/{id}/items`, or the `contentId` you sent to `POST /moderate` (webhooks send it as `item.id`). For a content ID, the newest submission with that content ID is used, as the queue shows it." }, { "in": "header", @@ -3406,7 +3422,8 @@ "write" ], "readOnlyHint": false, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": true } } }, @@ -3414,7 +3431,7 @@ "post": { "operationId": "resolveQueueItems", "summary": "Resolve queue items", - "description": "Mark up to 100 items of a queue as resolved in one request. Each item is resolved the same as with `POST /queue/{id}/items/{itemId}/resolve`. IDs that do not exist in the project are skipped and returned in `notFoundIds`.", + "description": "Mark up to 100 items of a queue as resolved in one request. Each item is resolved the same as with `POST /queue/{id}/items/{itemId}/resolve`, and each ID is an item `id` or your `contentId`. IDs that match no item in the project are skipped and returned in `notFoundIds`.", "tags": [ "Review queues" ], @@ -3459,7 +3476,7 @@ "items": { "type": "string" }, - "description": "The item IDs to resolve. Up to 100." + "description": "The items to resolve, up to 100. Each is the item `id` from `GET /queue/{id}/items`, or the `contentId` you sent to `POST /moderate` (webhooks send it as `item.id`). For a content ID, the newest submission with that content ID is used, as the queue shows it." } }, "required": [ @@ -3492,7 +3509,7 @@ "items": { "type": "string" }, - "description": "Item IDs that do not exist in the project." + "description": "IDs from `itemIds` that match no item or content ID in the project." } }, "required": [ @@ -3563,7 +3580,8 @@ "write" ], "readOnlyHint": false, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": true } } }, @@ -3571,7 +3589,7 @@ "post": { "operationId": "unresolveQueueItem", "summary": "Unresolve a queue item", - "description": "Mark a resolved item of a queue as pending again. It is the same as removing a check-off in the dashboard: the item comes back in the pending list.", + "description": "Mark a resolved item of a queue as pending again. It is the same as removing a check-off in the dashboard: the item comes back in the pending list. `itemId` is the item `id` or your `contentId`.", "tags": [ "Review queues" ], @@ -3596,10 +3614,10 @@ "name": "itemId", "schema": { "type": "string", - "description": "The item ID to unresolve." + "description": "The item to unresolve: the item `id` from `GET /queue/{id}/items`, or the `contentId` you sent to `POST /moderate` (webhooks send it as `item.id`). For a content ID, the newest submission with that content ID is used, as the queue shows it." }, "required": true, - "description": "The item ID to unresolve." + "description": "The item to unresolve: the item `id` from `GET /queue/{id}/items`, or the `contentId` you sent to `POST /moderate` (webhooks send it as `item.id`). For a content ID, the newest submission with that content ID is used, as the queue shows it." }, { "in": "header", @@ -3705,7 +3723,8 @@ "write" ], "readOnlyHint": false, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } } }, @@ -3713,7 +3732,7 @@ "get": { "operationId": "listActions", "summary": "List moderation actions", - "description": "List the moderation actions of the project. The list is paginated.", + "description": "List the moderation actions of the project, with their webhooks. An action is a decision that a reviewer or a rule can take on content or an author. Built-in actions (for example reject an item or block an author) change the item or author in Moderation API. Custom actions record the decision and send it to the webhooks of the action, where the customer platform acts on it. The list is paginated.", "tags": [ "Actions" ], @@ -3988,7 +4007,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false }, "x-speakeasy-pagination": { "type": "offsetLimit", @@ -4013,7 +4033,7 @@ "post": { "operationId": "createAction", "summary": "Create an action", - "description": "Create an action.", + "description": "Create an action that reviewers and rules can take. `type` sets what it does: a built-in type changes the item or author in Moderation API, and a custom type (`ITEM_CUSTOM`, `AUTHOR_CUSTOM`) only records the decision for the webhooks to deliver. Creating an action does not execute it.", "tags": [ "Actions" ], @@ -4347,7 +4367,8 @@ "write" ], "readOnlyHint": false, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } } }, @@ -4355,7 +4376,7 @@ "get": { "operationId": "getAction", "summary": "Get an action", - "description": "Get an action by ID.", + "description": "Get an action by ID: its type, where it shows in the review queues, the values it takes and its webhooks.", "tags": [ "Actions" ], @@ -4574,13 +4595,14 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } }, "put": { "operationId": "updateAction", "summary": "Update an action", - "description": "Update an action.", + "description": "Update the settings of an action: its name, type, queues and values. The new settings apply the next time the action is executed. Updating an action does not execute it.", "tags": [ "Actions" ], @@ -4925,7 +4947,8 @@ "destructive" ], "readOnlyHint": false, - "destructiveHint": true + "destructiveHint": true, + "openWorldHint": false } }, "delete": { @@ -5037,7 +5060,8 @@ "destructive" ], "readOnlyHint": false, - "destructiveHint": true + "destructiveHint": true, + "openWorldHint": false } } }, @@ -5045,7 +5069,7 @@ "post": { "operationId": "executeAction", "summary": "Execute moderation action", - "description": "Execute a moderation action on one or more content items.", + "description": "Execute one action of the project, by ID or key, on content items or authors. A built-in action changes them in Moderation API (for example rejects the items or blocks the authors). Every executed action is recorded, and the project sends it to the webhooks of the action and to its other webhook endpoints, where the customer platform can act on it. List the actions first to see what each one does.", "tags": [ "Actions" ], @@ -5198,7 +5222,8 @@ "destructive" ], "readOnlyHint": false, - "destructiveHint": true + "destructiveHint": true, + "openWorldHint": true } } }, @@ -5206,7 +5231,7 @@ "post": { "operationId": "executeActionById", "summary": "Execute an action", - "description": "Execute an action on a set of content items in a queue.", + "description": "Execute an action on a set of content items in a queue. The project sends the result to the webhooks of the action. Use `POST /actions/execute` instead.", "tags": [ "Actions" ], @@ -5487,7 +5512,8 @@ "destructive" ], "readOnlyHint": false, - "destructiveHint": true + "destructiveHint": true, + "openWorldHint": true } } }, @@ -5625,7 +5651,8 @@ "write" ], "readOnlyHint": false, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": true } } }, @@ -5751,7 +5778,8 @@ "destructive" ], "readOnlyHint": false, - "destructiveHint": true + "destructiveHint": true, + "openWorldHint": true } } }, @@ -5886,7 +5914,8 @@ "destructive" ], "readOnlyHint": false, - "destructiveHint": true + "destructiveHint": true, + "openWorldHint": true } } }, @@ -6012,7 +6041,8 @@ "write" ], "readOnlyHint": false, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": true } } }, @@ -6183,7 +6213,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false }, "x-speakeasy-pagination": { "type": "offsetLimit", @@ -6405,7 +6436,8 @@ "write" ], "readOnlyHint": false, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": true } } }, @@ -6557,7 +6589,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } }, "put": { @@ -6767,7 +6800,8 @@ "destructive" ], "readOnlyHint": false, - "destructiveHint": true + "destructiveHint": true, + "openWorldHint": true } }, "delete": { @@ -6869,7 +6903,8 @@ "destructive" ], "readOnlyHint": false, - "destructiveHint": true + "destructiveHint": true, + "openWorldHint": false } } }, @@ -7664,7 +7699,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } } }, @@ -8066,7 +8102,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false }, "x-speakeasy-pagination": { "type": "offsetLimit", @@ -8255,7 +8292,8 @@ "write" ], "readOnlyHint": false, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } } }, @@ -8431,7 +8469,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } }, "put": { @@ -8620,7 +8659,119 @@ "destructive" ], "readOnlyHint": false, - "destructiveHint": true + "destructiveHint": true, + "openWorldHint": false + } + }, + "delete": { + "operationId": "deleteWordlist", + "summary": "Delete wordlist", + "description": "Delete a wordlist and its words. Channels that use the wordlist do not block the delete: the wordlist is removed from their policies. `detachedChannelIds` lists those channels. This cannot be undone.", + "tags": [ + "Wordlists" + ], + "security": [ + { + "Authorization": [] + } + ], + "parameters": [ + { + "in": "path", + "name": "id", + "schema": { + "type": "string", + "description": "ID of the wordlist to delete" + }, + "required": true, + "description": "ID of the wordlist to delete" + }, + { + "in": "header", + "name": "Project-Id", + "required": false, + "schema": { + "type": "string" + }, + "description": "The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error.", + "x-speakeasy-name-override": "projectId" + } + ], + "responses": { + "200": { + "description": "Wordlist deleted successfully", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "ID of the deleted wordlist" + }, + "deleted": { + "type": "boolean", + "description": "Whether the wordlist was deleted" + }, + "detachedChannelIds": { + "type": "array", + "items": { + "type": "string" + }, + "description": "IDs of the channels that used the wordlist. It was removed from them." + } + }, + "required": [ + "id", + "deleted", + "detachedChannelIds" + ], + "additionalProperties": false + } + } + } + }, + "401": { + "description": "Authorization not provided", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/AuthenticationError" + } + } + } + }, + "404": { + "description": "Not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NotFoundError" + } + } + } + }, + "429": { + "description": "Too many requests. Retry after the number of seconds in the `Retry-After` header.", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RateLimitError" + } + } + } + } + }, + "x-speakeasy-group": "wordlist", + "x-speakeasy-name-override": "delete", + "x-speakeasy-mcp": { + "title": "Delete wordlist", + "scopes": [ + "destructive" + ], + "readOnlyHint": false, + "destructiveHint": true, + "openWorldHint": false } } }, @@ -8760,7 +8911,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } } }, @@ -8910,7 +9062,8 @@ "write" ], "readOnlyHint": false, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } }, "delete": { @@ -9043,7 +9196,8 @@ "destructive" ], "readOnlyHint": false, - "destructiveHint": true + "destructiveHint": true, + "openWorldHint": false } } }, @@ -9051,6 +9205,7 @@ "post": { "operationId": "submitContent", "summary": "Submit content", + "description": "Moderate one piece of content: text, an image, a video, audio or an object with several fields. The project checks it against the policies of its channel and returns the result. Act on `recommendation.action` (allow, review or reject). The content is stored in the project unless `doNotStore` is set, and items to review go to the review queue. The project can send the result to its webhook endpoints.", "tags": [ "Content" ], @@ -10174,13 +10329,15 @@ "const": "unicode_spoofing" }, "signals": { - "description": "Per-signal flag toggles. Omitted spoofing signals are enabled; encoding_damage defaults to off because decode damage (U+FFFD) marks a broken pipeline, not an attack. A disabled signal is still detected and reported as a label, but does not by itself flag the policy.", + "description": "Per-signal flag toggles. Omitted spoofing signals are enabled; encoding_damage defaults to off because decode damage (U+FFFD) marks a broken pipeline, not an attack, and hidden_lookalike and leetspeak default to off because they are opt-in. A disabled signal is still detected and reported as a label, but does not by itself flag the policy. Lookalike words are only spelled out in the cleaned text when their signal is enabled.", "type": "object", "propertyNames": { "type": "string", "enum": [ "mixed_script", "confusable_word", + "hidden_lookalike", + "leetspeak", "invisible", "zalgo", "illegal", @@ -11440,7 +11597,8 @@ "write" ], "readOnlyHint": false, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": true } } }, @@ -11548,7 +11706,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false }, "x-speakeasy-pagination": { "type": "offsetLimit", @@ -11684,7 +11843,8 @@ "write" ], "readOnlyHint": false, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } } }, @@ -11773,7 +11933,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } }, "put": { @@ -11940,7 +12101,8 @@ "destructive" ], "readOnlyHint": false, - "destructiveHint": true + "destructiveHint": true, + "openWorldHint": false } }, "delete": { @@ -12042,7 +12204,8 @@ "destructive" ], "readOnlyHint": false, - "destructiveHint": true + "destructiveHint": true, + "openWorldHint": false } } }, @@ -12159,7 +12322,8 @@ "write" ], "readOnlyHint": false, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } } }, @@ -12277,7 +12441,8 @@ "write" ], "readOnlyHint": false, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } } }, @@ -12405,7 +12570,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false }, "x-speakeasy-pagination": { "type": "offsetLimit", @@ -12569,7 +12735,8 @@ "write" ], "readOnlyHint": false, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } } }, @@ -12658,7 +12825,8 @@ "read" ], "readOnlyHint": true, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } }, "put": { @@ -12868,7 +13036,8 @@ "destructive" ], "readOnlyHint": false, - "destructiveHint": true + "destructiveHint": true, + "openWorldHint": false } }, "delete": { @@ -12980,7 +13149,8 @@ "destructive" ], "readOnlyHint": false, - "destructiveHint": true + "destructiveHint": true, + "openWorldHint": false } } }, @@ -13104,7 +13274,8 @@ "write" ], "readOnlyHint": false, - "destructiveHint": false + "destructiveHint": false, + "openWorldHint": false } } }, @@ -13528,11 +13699,11 @@ "properties": { "id": { "type": "string", - "description": "The item ID. Use it to resolve or unresolve the item in this queue." + "description": "The item ID: the ID of this submission. Use it, or `contentId`, to resolve or unresolve the item in this queue." }, "contentId": { "type": "string", - "description": "Your content ID, as you sent it to `POST /moderate`." + "description": "Your content ID, as you sent it to `POST /moderate`. Webhooks send it as `item.id`. The resolve endpoints accept it in place of `id`." }, "content": { "anyOf": [ diff --git a/CHANGELOG.md b/CHANGELOG.md index 5632536..bea0764 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Changelog +## 0.6.1 (2026-11-09) + +Full Changelog: [v0.6.0...v0.6.1](https://github.com/moderation-api/cli/compare/v0.6.0...v0.6.1) + +### API changes + +- `POST /moderate`: added the new `hidden_lookalike` enum value to the request property `policies/items/oneOf[subschema #36: Unicode Spoofing]/signals/propertyNames/` +- `POST /moderate`: added the new `leetspeak` enum value to the request property `policies/items/oneOf[subschema #36: Unicode Spoofing]/signals/propertyNames/` +- `DELETE /wordlist/{id}`: endpoint added + ## 0.6.0 (2026-10-28) Full Changelog: [v0.5.0...v0.6.0](https://github.com/moderation-api/cli/compare/v0.5.0...v0.6.0) diff --git a/README.md b/README.md index 81a7f11..b5d7dbf 100644 --- a/README.md +++ b/README.md @@ -417,6 +417,7 @@ modapi projects list --secret-key "$MODAPI_ORGANIZATION_KEY" * [`create`](docs/modapi_wordlist_create.md) - Create wordlist * [`retrieve`](docs/modapi_wordlist_retrieve.md) - Get wordlist * [`update`](docs/modapi_wordlist_update.md) - Update wordlist + * [`delete`](docs/modapi_wordlist_delete.md) - Delete wordlist * [`get-embedding-status`](docs/modapi_wordlist_get-embedding-status.md) - Get embedding status * [`words`](docs/modapi_wordlist_words.md) - Operations for words * [`add`](docs/modapi_wordlist_words_add.md) - Add words to wordlist diff --git a/internal/cli/actions/create.go b/internal/cli/actions/create.go index 29b22aa..7976465 100644 --- a/internal/cli/actions/create.go +++ b/internal/cli/actions/create.go @@ -33,7 +33,7 @@ func initCreateCmd(parent *cobra.Command) error { var cmd = &cobra.Command{ Use: "create", Short: "Create an action", - Long: "Create an action.", + Long: "Create an action that reviewers and rules can take. `type` sets what it does: a built-in type changes the item or author in Moderation API, and a custom type (`ITEM_CUSTOM`, `AUTHOR_CUSTOM`) only records the decision for the webhooks to deliver. Creating an action does not execute it.", Example: " modapi actions create --name 'Suspend for 24 hours'", Args: cobra.NoArgs, RunE: runCreateCmd, diff --git a/internal/cli/actions/execute.go b/internal/cli/actions/execute.go index 9183aec..7a47047 100644 --- a/internal/cli/actions/execute.go +++ b/internal/cli/actions/execute.go @@ -30,7 +30,7 @@ func initExecuteCmd(parent *cobra.Command) error { var cmd = &cobra.Command{ Use: "execute", Short: "Execute moderation action", - Long: "Execute a moderation action on one or more content items.", + Long: "Execute one action of the project, by ID or key, on content items or authors. A built-in action changes them in Moderation API (for example rejects the items or blocks the authors). Every executed action is recorded, and the project sends it to the webhooks of the action and to its other webhook endpoints, where the customer platform can act on it. List the actions first to see what each one does.", Example: " modapi actions execute --action-key suspend-24h", Args: cobra.NoArgs, RunE: runExecuteCmd, diff --git a/internal/cli/actions/list.go b/internal/cli/actions/list.go index d8cfd13..929cdac 100644 --- a/internal/cli/actions/list.go +++ b/internal/cli/actions/list.go @@ -25,7 +25,7 @@ func initListCmd(parent *cobra.Command) error { var cmd = &cobra.Command{ Use: "list", Short: "List moderation actions", - Long: "List the moderation actions of the project. The list is paginated.", + Long: "List the moderation actions of the project, with their webhooks. An action is a decision that a reviewer or a rule can take on content or an author. Built-in actions (for example reject an item or block an author) change the item or author in Moderation API. Custom actions record the decision and send it to the webhooks of the action, where the customer platform acts on it. The list is paginated.", Example: " modapi actions list", Args: cobra.NoArgs, RunE: runListCmd, diff --git a/internal/cli/actions/retrieve.go b/internal/cli/actions/retrieve.go index e889399..56039f2 100644 --- a/internal/cli/actions/retrieve.go +++ b/internal/cli/actions/retrieve.go @@ -24,7 +24,7 @@ func initRetrieveCmd(parent *cobra.Command) error { var cmd = &cobra.Command{ Use: "retrieve [id]", Short: "Get an action", - Long: "Get an action by ID.", + Long: "Get an action by ID: its type, where it shows in the review queues, the values it takes and its webhooks.", Example: " modapi actions retrieve --id ", Args: flagutil.PositionalFlagArgs, RunE: runRetrieveCmd, diff --git a/internal/cli/actions/update.go b/internal/cli/actions/update.go index 58ed83f..00ece00 100644 --- a/internal/cli/actions/update.go +++ b/internal/cli/actions/update.go @@ -35,7 +35,7 @@ func initUpdateCmd(parent *cobra.Command) error { var cmd = &cobra.Command{ Use: "update [id]", Short: "Update an action", - Long: "Update an action.", + Long: "Update the settings of an action: its name, type, queues and values. The new settings apply the next time the action is executed. Updating an action does not execute it.", Example: " modapi actions update --id ", Args: flagutil.PositionalFlagArgs, RunE: runUpdateCmd, diff --git a/internal/cli/content/submit.go b/internal/cli/content/submit.go index 22e265d..74472f6 100644 --- a/internal/cli/content/submit.go +++ b/internal/cli/content/submit.go @@ -48,7 +48,7 @@ func initSubmitCmd(parent *cobra.Command) error { var cmd = &cobra.Command{ Use: "submit", Short: "Submit content", - Long: "Submit content", + Long: "Moderate one piece of content: text, an image, a video, audio or an object with several fields. The project checks it against the policies of its channel and returns the result. Act on `recommendation.action` (allow, review or reject). The content is stored in the project unless `doNotStore` is set, and items to review go to the review queue. The project can send the result to its webhook endpoints.", Example: " modapi content submit --content '{\"type\":\"text\",\"text\":\"Hey, check out my profile for a deal!\"}'", Args: cobra.NoArgs, RunE: runSubmitCmd, diff --git a/internal/cli/queue/items/list.go b/internal/cli/queue/items/list.go index 5890aec..7a2e85b 100644 --- a/internal/cli/queue/items/list.go +++ b/internal/cli/queue/items/list.go @@ -34,7 +34,7 @@ func initListCmd(parent *cobra.Command) error { var cmd = &cobra.Command{ Use: "list [id]", Short: "List queue items", - Long: "List the items of a review queue, with the filters and the date window of the queue applied. By default only pending items. The list is paginated. Use the item `id` to resolve or unresolve an item.", + Long: "List the items of a review queue, with the filters and the date window of the queue applied. By default only pending items. The list is paginated. Use the item `id` or `contentId` to resolve or unresolve an item.", Example: " modapi queue items list --id ", Args: flagutil.PositionalFlagArgs, RunE: runListCmd, diff --git a/internal/cli/queue/items/resolve.go b/internal/cli/queue/items/resolve.go index 32ada46..c204e5b 100644 --- a/internal/cli/queue/items/resolve.go +++ b/internal/cli/queue/items/resolve.go @@ -15,7 +15,7 @@ import ( var resolveCmdMeta = []flagutil.FlagMeta{ {FlagName: "id", FieldPath: "ID", Kind: flagutil.FlagKindString, Required: true, Description: "The queue ID. [required]"}, - {FlagName: "item-id", FieldPath: "ItemID", Kind: flagutil.FlagKindString, Required: true, Description: "The item ID to resolve. [required]"}, + {FlagName: "item-id", FieldPath: "ItemID", Kind: flagutil.FlagKindString, Required: true, Description: "The item to resolve: the item 'id' from 'GET /queue/{id}/items', or the 'contentId' you sent to 'POST /moderate' (webhooks send it as 'item.id'). For a content ID, the newest submission with that content ID is used, as the queue shows it. [required]"}, {FlagName: "project-id", Shorthand: "p", FieldPath: "ProjectID", Kind: flagutil.FlagKindString, Optional: true, Description: "The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error."}, } @@ -24,7 +24,7 @@ func initResolveCmd(parent *cobra.Command) error { var cmd = &cobra.Command{ Use: "resolve", Short: "Resolve a queue item", - Long: "Mark an item of a queue as resolved. It is the same as a check-off in the dashboard: the item leaves the pending list and a QUEUE_ITEM_COMPLETED webhook is sent. To also take a moderation action, use `POST /actions/execute`.", + Long: "Mark an item of a queue as resolved. It is the same as a check-off in the dashboard: the item leaves the pending list and a QUEUE_ITEM_COMPLETED webhook is sent. `itemId` is the item `id` or your `contentId`. To also take a moderation action, use `POST /actions/execute`.", Example: " modapi queue items resolve --id --item-id ", Args: cobra.NoArgs, RunE: runResolveCmd, diff --git a/internal/cli/queue/items/resolvemany.go b/internal/cli/queue/items/resolvemany.go index ec1a83b..443e91e 100644 --- a/internal/cli/queue/items/resolvemany.go +++ b/internal/cli/queue/items/resolvemany.go @@ -17,7 +17,7 @@ import ( var resolveManyCmdMeta = []flagutil.FlagMeta{ {FlagName: "id", Shorthand: "i", FieldPath: "ID", Kind: flagutil.FlagKindString, Required: true, Description: "The queue ID. [required]"}, {FlagName: "project-id", Shorthand: "p", FieldPath: "ProjectID", Kind: flagutil.FlagKindString, Optional: true, Description: "The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error."}, - {FlagName: "item-ids", FieldPath: "Body.ItemIds", Kind: flagutil.FlagKindStringArray, Required: true, Description: "The item IDs to resolve. Up to 100. [required]"}, + {FlagName: "item-ids", FieldPath: "Body.ItemIds", Kind: flagutil.FlagKindStringArray, Required: true, Description: "The items to resolve, up to 100. Each is the item 'id' from 'GET /queue/{id}/items', or the 'contentId' you sent to 'POST /moderate' (webhooks send it as 'item.id'). For a content ID, the newest submission with that content ID is used, as the queue shows it. [required]"}, } // initResolveManyCmd initializes the resolve-many command. @@ -25,7 +25,7 @@ func initResolveManyCmd(parent *cobra.Command) error { var cmd = &cobra.Command{ Use: "resolve-many [id]", Short: "Resolve queue items", - Long: "Mark up to 100 items of a queue as resolved in one request. Each item is resolved the same as with `POST /queue/{id}/items/{itemId}/resolve`. IDs that do not exist in the project are skipped and returned in `notFoundIds`.", + Long: "Mark up to 100 items of a queue as resolved in one request. Each item is resolved the same as with `POST /queue/{id}/items/{itemId}/resolve`, and each ID is an item `id` or your `contentId`. IDs that match no item in the project are skipped and returned in `notFoundIds`.", Example: " modapi queue items resolve-many --id --item-ids clx8k2v0e000108l4a9bz3f7q --item-ids clx8k2v0e000208l4h2mc6d1r", Args: flagutil.PositionalFlagArgs, RunE: runResolveManyCmd, diff --git a/internal/cli/queue/items/unresolve.go b/internal/cli/queue/items/unresolve.go index 77f64f6..f459117 100644 --- a/internal/cli/queue/items/unresolve.go +++ b/internal/cli/queue/items/unresolve.go @@ -15,7 +15,7 @@ import ( var unresolveCmdMeta = []flagutil.FlagMeta{ {FlagName: "id", FieldPath: "ID", Kind: flagutil.FlagKindString, Required: true, Description: "The queue ID. [required]"}, - {FlagName: "item-id", FieldPath: "ItemID", Kind: flagutil.FlagKindString, Required: true, Description: "The item ID to unresolve. [required]"}, + {FlagName: "item-id", FieldPath: "ItemID", Kind: flagutil.FlagKindString, Required: true, Description: "The item to unresolve: the item 'id' from 'GET /queue/{id}/items', or the 'contentId' you sent to 'POST /moderate' (webhooks send it as 'item.id'). For a content ID, the newest submission with that content ID is used, as the queue shows it. [required]"}, {FlagName: "project-id", Shorthand: "p", FieldPath: "ProjectID", Kind: flagutil.FlagKindString, Optional: true, Description: "The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error."}, } @@ -24,7 +24,7 @@ func initUnresolveCmd(parent *cobra.Command) error { var cmd = &cobra.Command{ Use: "unresolve", Short: "Unresolve a queue item", - Long: "Mark a resolved item of a queue as pending again. It is the same as removing a check-off in the dashboard: the item comes back in the pending list.", + Long: "Mark a resolved item of a queue as pending again. It is the same as removing a check-off in the dashboard: the item comes back in the pending list. `itemId` is the item `id` or your `contentId`.", Example: " modapi queue items unresolve --id --item-id ", Args: cobra.NoArgs, RunE: runUnresolveCmd, diff --git a/internal/cli/version.go b/internal/cli/version.go index c1573ad..f8522b5 100644 --- a/internal/cli/version.go +++ b/internal/cli/version.go @@ -14,7 +14,7 @@ import ( // which propagates the value here (see cmd/modapi/main.go): // // go build -ldflags "-X main.version=x.y.z" ./cmd/modapi -var Version = "0.6.0" +var Version = "0.6.1" // BuildTime is optionally set at build time via ldflags targeting the main package. var BuildTime string diff --git a/internal/cli/wordlist/delete.go b/internal/cli/wordlist/delete.go new file mode 100644 index 0000000..f4a6907 --- /dev/null +++ b/internal/cli/wordlist/delete.go @@ -0,0 +1,94 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package wordlist + +import ( + "fmt" + "github.com/moderation-api/cli/internal/client" + "github.com/moderation-api/cli/internal/flagutil" + "github.com/moderation-api/cli/internal/interactive" + "github.com/moderation-api/cli/internal/output" + "github.com/moderation-api/cli/internal/sdk" + "github.com/moderation-api/cli/internal/sdk/models/operations" + "github.com/moderation-api/cli/internal/usage" + "github.com/spf13/cobra" +) + +var deleteCmdMeta = []flagutil.FlagMeta{ + {FlagName: "id", Shorthand: "i", FieldPath: "ID", Kind: flagutil.FlagKindString, Required: true, Description: "ID of the wordlist to delete [required]"}, + {FlagName: "project-id", Shorthand: "p", FieldPath: "ProjectID", Kind: flagutil.FlagKindString, Optional: true, Description: "The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error."}, +} + +// initDeleteCmd initializes the delete command. +func initDeleteCmd(parent *cobra.Command) error { + var cmd = &cobra.Command{ + Use: "delete [id]", + Short: "Delete wordlist", + Long: "Delete a wordlist and its words. Channels that use the wordlist do not block the delete: the wordlist is removed from their policies. `detachedChannelIds` lists those channels. This cannot be undone.", + Example: " modapi wordlist delete --id ", + Args: flagutil.PositionalFlagArgs, + RunE: runDeleteCmd, + Annotations: map[string]string{ + "speakeasy_operation": "deleteWordlist", + }, + } + flagutil.RegisterFlags(cmd, deleteCmdMeta) + if err := flagutil.ValidateMeta[operations.DeleteWordlistRequest](deleteCmdMeta); err != nil { + return fmt.Errorf("invalid metadata for delete: %w", err) + } + if err := flagutil.DeclarePositionalFlag(cmd, "id", "ID of the wordlist to delete (or pass it as the [id] argument)", true); err != nil { + return err + } + if err := interactive.Declare(cmd, interactive.CommandSpec{Args: []interactive.ArgSpec{ + {Name: "id", Summary: "ID of the wordlist to delete", Required: true, SatisfiedBy: []string{"id"}}, + }}); err != nil { + return fmt.Errorf("declare interactive arguments for delete: %w", err) + } + parent.AddCommand(cmd) + return nil +} + +// runDeleteCmd executes the delete command. +func runDeleteCmd(cmd *cobra.Command, args []string) error { + if usage.UsageRequested(cmd) { + return usage.EmitSchema(cmd, cmd.OutOrStdout()) + } + if err := flagutil.ResolvePositionalFlag(cmd, args); err != nil { + return err + } + req, err := flagutil.BuildRequest[operations.DeleteWordlistRequest](cmd, deleteCmdMeta, "", "") + if err != nil { + return flagutil.WithCLIValidation(err) + } + s, err := client.NewClient(cmd) + if err != nil { + return err + } + sdkOpts, err := output.PrepareCallOpts(cmd) + if err != nil { + return err + } + // Dry-run: force skip deserialization so the synthetic empty response + // does not cause parse failures in typed response handling. + if client.IsDryRun(cmd) { + sdkOpts = append(sdkOpts, operations.WithSkipDeserialization()) + } + if err := output.ValidateGlobalServerIndex(cmd, len(sdk.ServerList)); err != nil { + return err + } + if output.WantsRawJSON(cmd) { + sdkOpts = append(sdkOpts, operations.WithSkipDeserialization()) + } + stopProgress := output.StartRequestProgress(cmd) + defer stopProgress() + res, err := s.Wordlist.Delete(cmd.Context(), *req, sdkOpts...) + stopProgress() + if err != nil { + return output.Error(cmd, err) + } + + if err := output.Result(cmd, res); err != nil { + return err + } + return nil +} diff --git a/internal/cli/wordlist/root.go b/internal/cli/wordlist/root.go index 61a0cc3..0a569ba 100644 --- a/internal/cli/wordlist/root.go +++ b/internal/cli/wordlist/root.go @@ -43,6 +43,10 @@ func InitWordlistRoot(parent *cobra.Command) error { return err } + if err := initDeleteCmd(WordlistCmd); err != nil { + return err + } + if err := initGetEmbeddingStatusCmd(WordlistCmd); err != nil { return err } diff --git a/internal/sdk/actions.go b/internal/sdk/actions.go index 8d3a7f4..d8a4636 100644 --- a/internal/sdk/actions.go +++ b/internal/sdk/actions.go @@ -32,7 +32,7 @@ func newActions(rootSDK *ModerationAPI, sdkConfig config.SDKConfiguration, hooks } // List moderation actions -// List the moderation actions of the project. The list is paginated. +// List the moderation actions of the project, with their webhooks. An action is a decision that a reviewer or a rule can take on content or an author. Built-in actions (for example reject an item or block an author) change the item or author in Moderation API. Custom actions record the decision and send it to the webhooks of the action, where the customer platform acts on it. The list is paginated. func (s *Actions) List(ctx context.Context, request *operations.ListActionsRequest, opts ...operations.Option) (*operations.ListActionsResponse, error) { o := operations.Options{} supportedOptions := []string{ @@ -408,7 +408,7 @@ func (s *Actions) List(ctx context.Context, request *operations.ListActionsReque } // Create an action -// Create an action. +// Create an action that reviewers and rules can take. `type` sets what it does: a built-in type changes the item or author in Moderation API, and a custom type (`ITEM_CUSTOM`, `AUTHOR_CUSTOM`) only records the decision for the webhooks to deliver. Creating an action does not execute it. func (s *Actions) Create(ctx context.Context, request operations.CreateActionRequest, opts ...operations.Option) (*operations.CreateActionResponse, error) { o := operations.Options{} supportedOptions := []string{ @@ -672,7 +672,7 @@ func (s *Actions) Create(ctx context.Context, request operations.CreateActionReq } // Retrieve - Get an action -// Get an action by ID. +// Get an action by ID: its type, where it shows in the review queues, the values it takes and its webhooks. func (s *Actions) Retrieve(ctx context.Context, request operations.GetActionRequest, opts ...operations.Option) (*operations.GetActionResponse, error) { o := operations.Options{} supportedOptions := []string{ @@ -929,7 +929,7 @@ func (s *Actions) Retrieve(ctx context.Context, request operations.GetActionRequ } // Update an action -// Update an action. +// Update the settings of an action: its name, type, queues and values. The new settings apply the next time the action is executed. Updating an action does not execute it. func (s *Actions) Update(ctx context.Context, request operations.UpdateActionRequest, opts ...operations.Option) (*operations.UpdateActionResponse, error) { o := operations.Options{} supportedOptions := []string{ @@ -1475,7 +1475,7 @@ func (s *Actions) Delete(ctx context.Context, request operations.DeleteActionReq } // Execute moderation action -// Execute a moderation action on one or more content items. +// Execute one action of the project, by ID or key, on content items or authors. A built-in action changes them in Moderation API (for example rejects the items or blocks the authors). Every executed action is recorded, and the project sends it to the webhooks of the action and to its other webhook endpoints, where the customer platform can act on it. List the actions first to see what each one does. func (s *Actions) Execute(ctx context.Context, request operations.ExecuteActionRequest, opts ...operations.Option) (*operations.ExecuteActionResponse, error) { o := operations.Options{} supportedOptions := []string{ diff --git a/internal/sdk/content.go b/internal/sdk/content.go index cc77d44..b0ba25b 100644 --- a/internal/sdk/content.go +++ b/internal/sdk/content.go @@ -559,6 +559,7 @@ func (s *Content) Allow(ctx context.Context, request operations.AllowContentRequ } // Submit content +// Moderate one piece of content: text, an image, a video, audio or an object with several fields. The project checks it against the policies of its channel and returns the result. Act on `recommendation.action` (allow, review or reject). The content is stored in the project unless `doNotStore` is set, and items to review go to the review queue. The project can send the result to its webhook endpoints. func (s *Content) Submit(ctx context.Context, request operations.SubmitContentRequest, opts ...operations.Option) (*operations.SubmitContentResponse, error) { o := operations.Options{} supportedOptions := []string{ diff --git a/internal/sdk/items.go b/internal/sdk/items.go index 2f3d207..a8b5cf5 100644 --- a/internal/sdk/items.go +++ b/internal/sdk/items.go @@ -31,7 +31,7 @@ func newItems(rootSDK *ModerationAPI, sdkConfig config.SDKConfiguration, hooks * } // List queue items -// List the items of a review queue, with the filters and the date window of the queue applied. By default only pending items. The list is paginated. Use the item `id` to resolve or unresolve an item. +// List the items of a review queue, with the filters and the date window of the queue applied. By default only pending items. The list is paginated. Use the item `id` or `contentId` to resolve or unresolve an item. func (s *Items) List(ctx context.Context, request operations.ListQueueItemsRequest, opts ...operations.Option) (*operations.ListQueueItemsResponse, error) { o := operations.Options{} supportedOptions := []string{ @@ -404,7 +404,7 @@ func (s *Items) List(ctx context.Context, request operations.ListQueueItemsReque } // Resolve a queue item -// Mark an item of a queue as resolved. It is the same as a check-off in the dashboard: the item leaves the pending list and a QUEUE_ITEM_COMPLETED webhook is sent. To also take a moderation action, use `POST /actions/execute`. +// Mark an item of a queue as resolved. It is the same as a check-off in the dashboard: the item leaves the pending list and a QUEUE_ITEM_COMPLETED webhook is sent. `itemId` is the item `id` or your `contentId`. To also take a moderation action, use `POST /actions/execute`. func (s *Items) Resolve(ctx context.Context, request operations.ResolveQueueItemRequest, opts ...operations.Option) (*operations.ResolveQueueItemResponse, error) { o := operations.Options{} supportedOptions := []string{ @@ -686,7 +686,7 @@ func (s *Items) Resolve(ctx context.Context, request operations.ResolveQueueItem } // ResolveMany - Resolve queue items -// Mark up to 100 items of a queue as resolved in one request. Each item is resolved the same as with `POST /queue/{id}/items/{itemId}/resolve`. IDs that do not exist in the project are skipped and returned in `notFoundIds`. +// Mark up to 100 items of a queue as resolved in one request. Each item is resolved the same as with `POST /queue/{id}/items/{itemId}/resolve`, and each ID is an item `id` or your `contentId`. IDs that match no item in the project are skipped and returned in `notFoundIds`. func (s *Items) ResolveMany(ctx context.Context, request operations.ResolveQueueItemsRequest, opts ...operations.Option) (*operations.ResolveQueueItemsResponse, error) { o := operations.Options{} supportedOptions := []string{ @@ -975,7 +975,7 @@ func (s *Items) ResolveMany(ctx context.Context, request operations.ResolveQueue } // Unresolve a queue item -// Mark a resolved item of a queue as pending again. It is the same as removing a check-off in the dashboard: the item comes back in the pending list. +// Mark a resolved item of a queue as pending again. It is the same as removing a check-off in the dashboard: the item comes back in the pending list. `itemId` is the item `id` or your `contentId`. func (s *Items) Unresolve(ctx context.Context, request operations.UnresolveQueueItemRequest, opts ...operations.Option) (*operations.UnresolveQueueItemResponse, error) { o := operations.Options{} supportedOptions := []string{ diff --git a/internal/sdk/models/components/queueitem.go b/internal/sdk/models/components/queueitem.go index 0b5f5c3..b7ad61a 100644 --- a/internal/sdk/models/components/queueitem.go +++ b/internal/sdk/models/components/queueitem.go @@ -932,9 +932,9 @@ func (e *QueueItemStatus) IsExact() bool { } type QueueItem struct { - // The item ID. Use it to resolve or unresolve the item in this queue. + // The item ID: the ID of this submission. Use it, or `contentId`, to resolve or unresolve the item in this queue. ID string `json:"id"` - // Your content ID, as you sent it to `POST /moderate`. + // Your content ID, as you sent it to `POST /moderate`. Webhooks send it as `item.id`. The resolve endpoints accept it in place of `id`. ContentID string `json:"contentId"` // The submitted content. Content *QueueItemContent `json:"content"` diff --git a/internal/sdk/models/operations/deletewordlist.go b/internal/sdk/models/operations/deletewordlist.go new file mode 100644 index 0000000..e0e8ecb --- /dev/null +++ b/internal/sdk/models/operations/deletewordlist.go @@ -0,0 +1,91 @@ +// Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT. + +package operations + +import ( + "github.com/moderation-api/cli/internal/sdk/models/components" + "github.com/moderation-api/cli/internal/sdk/sdkinternal/utils" +) + +type DeleteWordlistRequest struct { + // ID of the wordlist to delete + ID string `pathParam:"style=simple,explode=false,name=id"` + // The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error. + ProjectID *string `header:"style=simple,explode=false,name=Project-Id"` +} + +func (d *DeleteWordlistRequest) GetID() string { + if d == nil { + return "" + } + return d.ID +} + +func (d *DeleteWordlistRequest) GetProjectID() *string { + if d == nil { + return nil + } + return d.ProjectID +} + +// DeleteWordlistResponseBody - Wordlist deleted successfully +type DeleteWordlistResponseBody struct { + // ID of the deleted wordlist + ID string `json:"id"` + // Whether the wordlist was deleted + Deleted bool `json:"deleted"` + // IDs of the channels that used the wordlist. It was removed from them. + DetachedChannelIds []string `json:"detachedChannelIds"` +} + +func (d *DeleteWordlistResponseBody) GetID() string { + if d == nil { + return "" + } + return d.ID +} + +func (d *DeleteWordlistResponseBody) GetDeleted() bool { + if d == nil { + return false + } + return d.Deleted +} + +func (d *DeleteWordlistResponseBody) GetDetachedChannelIds() []string { + if d == nil { + return []string{} + } + return d.DetachedChannelIds +} + +type DeleteWordlistResponse struct { + HTTPMeta components.HTTPMetadata `json:"-"` + // Wordlist deleted successfully + Object *DeleteWordlistResponseBody +} + +func (d DeleteWordlistResponse) MarshalJSON() ([]byte, error) { + return utils.MarshalJSON(d, "", false) +} + +func (d *DeleteWordlistResponse) UnmarshalJSON(data []byte) error { + if err := utils.UnmarshalJSON(data, &d, "", false, nil); err != nil { + return err + } + return nil +} + +func (d *DeleteWordlistResponse) GetHTTPMeta() components.HTTPMetadata { + if d == nil { + return components.HTTPMetadata{} + } + return d.HTTPMeta +} + +func (d *DeleteWordlistResponse) GetObject() *DeleteWordlistResponseBody { + if d == nil { + return nil + } + return d.Object +} diff --git a/internal/sdk/models/operations/resolvequeueitem.go b/internal/sdk/models/operations/resolvequeueitem.go index a04ece6..5c91ca7 100644 --- a/internal/sdk/models/operations/resolvequeueitem.go +++ b/internal/sdk/models/operations/resolvequeueitem.go @@ -10,7 +10,7 @@ import ( type ResolveQueueItemRequest struct { // The queue ID. ID string `pathParam:"style=simple,explode=false,name=id"` - // The item ID to resolve. + // The item to resolve: the item `id` from `GET /queue/{id}/items`, or the `contentId` you sent to `POST /moderate` (webhooks send it as `item.id`). For a content ID, the newest submission with that content ID is used, as the queue shows it. ItemID string `pathParam:"style=simple,explode=false,name=itemId"` // The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error. ProjectID *string `header:"style=simple,explode=false,name=Project-Id"` diff --git a/internal/sdk/models/operations/resolvequeueitems.go b/internal/sdk/models/operations/resolvequeueitems.go index c785a9e..2770a47 100644 --- a/internal/sdk/models/operations/resolvequeueitems.go +++ b/internal/sdk/models/operations/resolvequeueitems.go @@ -8,7 +8,7 @@ import ( ) type ResolveQueueItemsRequestBody struct { - // The item IDs to resolve. Up to 100. + // The items to resolve, up to 100. Each is the item `id` from `GET /queue/{id}/items`, or the `contentId` you sent to `POST /moderate` (webhooks send it as `item.id`). For a content ID, the newest submission with that content ID is used, as the queue shows it. ItemIds []string `json:"itemIds"` } @@ -52,7 +52,7 @@ func (r *ResolveQueueItemsRequest) GetBody() ResolveQueueItemsRequestBody { type ResolveQueueItemsResponseBody struct { // Number of items resolved. Resolved int64 `json:"resolved"` - // Item IDs that do not exist in the project. + // IDs from `itemIds` that match no item or content ID in the project. NotFoundIds []string `json:"notFoundIds"` } diff --git a/internal/sdk/models/operations/submitcontent.go b/internal/sdk/models/operations/submitcontent.go index 7c5f540..de23620 100644 --- a/internal/sdk/models/operations/submitcontent.go +++ b/internal/sdk/models/operations/submitcontent.go @@ -1049,7 +1049,7 @@ type UnicodeSpoofing struct { Threshold *float64 `json:"threshold,omitzero"` //lint:ignore U1000 accessed via reflection for JSON marshaling id string `const:"unicode_spoofing" json:"id"` - // Per-signal flag toggles. Omitted spoofing signals are enabled; encoding_damage defaults to off because decode damage (U+FFFD) marks a broken pipeline, not an attack. A disabled signal is still detected and reported as a label, but does not by itself flag the policy. + // Per-signal flag toggles. Omitted spoofing signals are enabled; encoding_damage defaults to off because decode damage (U+FFFD) marks a broken pipeline, not an attack, and hidden_lookalike and leetspeak default to off because they are opt-in. A disabled signal is still detected and reported as a label, but does not by itself flag the policy. Lookalike words are only spelled out in the cleaned text when their signal is enabled. Signals map[string]SignalsRequest `json:"signals,omitzero"` } diff --git a/internal/sdk/models/operations/unresolvequeueitem.go b/internal/sdk/models/operations/unresolvequeueitem.go index 8d74756..94c666b 100644 --- a/internal/sdk/models/operations/unresolvequeueitem.go +++ b/internal/sdk/models/operations/unresolvequeueitem.go @@ -10,7 +10,7 @@ import ( type UnresolveQueueItemRequest struct { // The queue ID. ID string `pathParam:"style=simple,explode=false,name=id"` - // The item ID to unresolve. + // The item to unresolve: the item `id` from `GET /queue/{id}/items`, or the `contentId` you sent to `POST /moderate` (webhooks send it as `item.id`). For a content ID, the newest submission with that content ID is used, as the queue shows it. ItemID string `pathParam:"style=simple,explode=false,name=itemId"` // The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error. ProjectID *string `header:"style=simple,explode=false,name=Project-Id"` diff --git a/internal/sdk/moderationapi.go b/internal/sdk/moderationapi.go index 8afdde1..d24bfb6 100644 --- a/internal/sdk/moderationapi.go +++ b/internal/sdk/moderationapi.go @@ -139,10 +139,10 @@ func WithTimeout(timeout time.Duration) SDKOption { // New creates a new instance of the SDK with the provided options func New(opts ...SDKOption) *ModerationAPI { sdk := &ModerationAPI{ - SDKVersion: "0.6.0", + SDKVersion: "0.6.1", sdkConfiguration: config.SDKConfiguration{ - UserAgent: "speakeasy-sdk/go 0.6.0 internal 1.1.0 github.com/moderation-api/cli/internal/sdk", - SDKVersion: "0.6.0", + UserAgent: "speakeasy-sdk/go 0.6.1 internal 1.1.0 github.com/moderation-api/cli/internal/sdk", + SDKVersion: "0.6.1", GenVersion: "internal", OpenAPIDocVersion: "1.1.0", ServerList: ServerList, diff --git a/internal/sdk/wordlist.go b/internal/sdk/wordlist.go index 79e264e..7473a82 100644 --- a/internal/sdk/wordlist.go +++ b/internal/sdk/wordlist.go @@ -1220,6 +1220,238 @@ func (s *Wordlist) Update(ctx context.Context, request operations.UpdateWordlist } +// Delete wordlist +// Delete a wordlist and its words. Channels that use the wordlist do not block the delete: the wordlist is removed from their policies. `detachedChannelIds` lists those channels. This cannot be undone. +func (s *Wordlist) Delete(ctx context.Context, request operations.DeleteWordlistRequest, opts ...operations.Option) (*operations.DeleteWordlistResponse, error) { + o := operations.Options{} + supportedOptions := []string{ + operations.SupportedOptionTimeout, + operations.SupportedOptionSkipDeserialization, + } + + for _, opt := range opts { + if err := opt(&o, supportedOptions...); err != nil { + return nil, fmt.Errorf("error applying option: %w", err) + } + } + + var baseURL string + if o.ServerURL == nil { + baseURL = utils.ReplaceParameters(s.sdkConfiguration.GetServerDetails()) + } else { + baseURL = *o.ServerURL + } + opURL, err := utils.GenerateURL(ctx, baseURL, "/wordlist/{id}", request, nil) + if err != nil { + return nil, fmt.Errorf("error generating URL: %w", err) + } + + hookCtx := hooks.HookContext{ + SDK: s.rootSDK, + SDKConfiguration: s.sdkConfiguration, + BaseURL: baseURL, + Context: ctx, + OperationID: "deleteWordlist", + SecuritySource: s.sdkConfiguration.Security, + } + + timeout := o.Timeout + if timeout == nil { + timeout = s.sdkConfiguration.Timeout + } + + var streamCancel context.CancelFunc + + if timeout != nil { + var cancel context.CancelFunc + ctx, cancel = context.WithTimeout(ctx, *timeout) + streamCancel = cancel + defer func() { + if streamCancel != nil { + streamCancel() + } + }() + } + + req, err := http.NewRequestWithContext(ctx, "DELETE", opURL, nil) + if err != nil { + return nil, fmt.Errorf("error creating request: %w", err) + } + req.Header.Set("Accept", "application/json") + req.Header.Set("User-Agent", s.sdkConfiguration.UserAgent) + + utils.PopulateHeaders(ctx, req, request, nil) + + if err := utils.PopulateSecurity(ctx, req, s.sdkConfiguration.Security); err != nil { + return nil, err + } + + for k, v := range o.SetHeaders { + req.Header.Set(k, v) + } + + req, err = s.hooks.BeforeRequest(hooks.BeforeRequestContext{HookContext: hookCtx}, req) + if err != nil { + return nil, err + } + + httpRes, err := s.sdkConfiguration.Client.Do(req) + if err != nil || httpRes == nil { + if err != nil { + err = fmt.Errorf("error sending request: %w", err) + } else { + err = fmt.Errorf("error sending request: no response") + } + + _, err = s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, nil, err) + return nil, err + } else if utils.MatchStatusCodes([]string{"4XX", "5XX"}, httpRes.StatusCode) { + _httpRes, err := s.hooks.AfterError(hooks.AfterErrorContext{HookContext: hookCtx}, httpRes, nil) + if err != nil { + return nil, err + } else if _httpRes != nil { + httpRes = _httpRes + } + } else { + httpRes, err = s.hooks.AfterSuccess(hooks.AfterSuccessContext{HookContext: hookCtx}, httpRes) + if err != nil { + return nil, err + } + } + + res := &operations.DeleteWordlistResponse{ + HTTPMeta: components.HTTPMetadata{ + Request: req, + Response: httpRes, + }, + } + + switch { + case httpRes.StatusCode == 200: + switch { + case utils.MatchContentType(httpRes.Header.Get("Content-Type"), `application/json`): + if o.SkipDeserialization != nil && *o.SkipDeserialization { + httpRes.Body = utils.BodyWithCancel(httpRes.Body, streamCancel) + streamCancel = nil + } else { + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + + var out operations.DeleteWordlistResponseBody + if err := utils.UnmarshalJsonFromResponseBody(bytes.NewBuffer(rawBody), &out, ""); err != nil { + return nil, err + } + + res.Object = &out + } + default: + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + return nil, sdkerrors.NewSDKDefaultError(fmt.Sprintf("unknown content-type received: %s", httpRes.Header.Get("Content-Type")), httpRes.StatusCode, string(rawBody), httpRes) + } + case httpRes.StatusCode == 401: + switch { + case utils.MatchContentType(httpRes.Header.Get("Content-Type"), `application/json`): + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + + var out sdkerrors.AuthenticationError + if err := utils.UnmarshalJsonFromResponseBody(bytes.NewBuffer(rawBody), &out, ""); err != nil { + return nil, sdkerrors.NewResponseValidationError("response did not match the declared error schema", httpRes.StatusCode, string(rawBody), httpRes, err) + } + + out.HTTPMeta = components.HTTPMetadata{ + Request: req, + Response: httpRes, + } + return nil, &out + default: + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + return nil, sdkerrors.NewSDKDefaultError(fmt.Sprintf("unknown content-type received: %s", httpRes.Header.Get("Content-Type")), httpRes.StatusCode, string(rawBody), httpRes) + } + case httpRes.StatusCode == 404: + switch { + case utils.MatchContentType(httpRes.Header.Get("Content-Type"), `application/json`): + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + + var out sdkerrors.NotFoundError + if err := utils.UnmarshalJsonFromResponseBody(bytes.NewBuffer(rawBody), &out, ""); err != nil { + return nil, sdkerrors.NewResponseValidationError("response did not match the declared error schema", httpRes.StatusCode, string(rawBody), httpRes, err) + } + + out.HTTPMeta = components.HTTPMetadata{ + Request: req, + Response: httpRes, + } + return nil, &out + default: + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + return nil, sdkerrors.NewSDKDefaultError(fmt.Sprintf("unknown content-type received: %s", httpRes.Header.Get("Content-Type")), httpRes.StatusCode, string(rawBody), httpRes) + } + case httpRes.StatusCode == 429: + switch { + case utils.MatchContentType(httpRes.Header.Get("Content-Type"), `application/json`): + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + + var out sdkerrors.RateLimitError + if err := utils.UnmarshalJsonFromResponseBody(bytes.NewBuffer(rawBody), &out, ""); err != nil { + return nil, sdkerrors.NewResponseValidationError("response did not match the declared error schema", httpRes.StatusCode, string(rawBody), httpRes, err) + } + + out.HTTPMeta = components.HTTPMetadata{ + Request: req, + Response: httpRes, + } + return nil, &out + default: + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + return nil, sdkerrors.NewSDKDefaultError(fmt.Sprintf("unknown content-type received: %s", httpRes.Header.Get("Content-Type")), httpRes.StatusCode, string(rawBody), httpRes) + } + case httpRes.StatusCode >= 400 && httpRes.StatusCode < 500: + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + return nil, sdkerrors.NewSDKDefaultError("API error occurred", httpRes.StatusCode, string(rawBody), httpRes) + case httpRes.StatusCode >= 500 && httpRes.StatusCode < 600: + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + return nil, sdkerrors.NewSDKDefaultError("API error occurred", httpRes.StatusCode, string(rawBody), httpRes) + default: + rawBody, err := utils.ConsumeRawBody(httpRes) + if err != nil { + return nil, err + } + return nil, sdkerrors.NewSDKDefaultError("unknown status code returned", httpRes.StatusCode, string(rawBody), httpRes) + } + + return res, nil + +} + // GetEmbeddingStatus - Get embedding status // Get the current embedding progress status for a wordlist func (s *Wordlist) GetEmbeddingStatus(ctx context.Context, request operations.GetWordlistEmbeddingStatusRequest, opts ...operations.Option) (*operations.GetWordlistEmbeddingStatusResponse, error) { diff --git a/internal/usage/bodyschemas.go b/internal/usage/bodyschemas.go index 34c7e07..f23de81 100644 --- a/internal/usage/bodyschemas.go +++ b/internal/usage/bodyschemas.go @@ -23,8 +23,8 @@ var bodySchemas = map[string]string{ "duplicateProject": "{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"properties\":{\"name\":{\"description\":\"Name of the copy. Defaults to the original name with \\\"(copy)\\\".\",\"maxLength\":75,\"minLength\":1,\"type\":\"string\"\x7d\x7d,\"type\":\"object\"}", "executeAction": "{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"description\":\"Input parameters\",\"properties\":{\"actionKey\":{\"description\":\"ID or key of the action to execute\",\"type\":\"string\"},\"authorIds\":{\"description\":\"IDs of the authors to apply the action to. Provide this or contentIds.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"contentIds\":{\"description\":\"IDs of the content items to apply the action to. Provide this or authorIds.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"createCasebookCase\":{\"description\":\"Record an allow or reject decision as a casebook case. Defaults to true when `moderator` is set, else false. Without `moderator`, the case is recorded as System.\",\"type\":\"boolean\"},\"duration\":{\"description\":\"Optional duration in milliseconds for actions with timeouts\",\"minimum\":0,\"type\":\"number\"},\"moderator\":{\"description\":\"The user ID or email of the organization member who made the decision. The action is recorded as theirs.\",\"type\":\"string\"},\"queueId\":{\"description\":\"Optional queue ID if the action is queue-specific\",\"type\":\"string\"},\"value\":{\"description\":\"Optional value to provide with the action\",\"type\":\"string\"\x7d\x7d,\"required\":[\"actionKey\"],\"type\":\"object\"}", "rejectContent": "{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"properties\":{\"createCasebookCase\":{\"description\":\"Record an allow or reject decision as a casebook case. Defaults to true when `moderator` is set, else false. Without `moderator`, the case is recorded as System.\",\"type\":\"boolean\"},\"moderator\":{\"description\":\"The user ID or email of the organization member who made the decision. The action is recorded as theirs.\",\"type\":\"string\"},\"queueId\":{\"description\":\"The queue the content is reviewed in. Defaults to the project's default queue.\",\"type\":\"string\"},\"reason\":{\"description\":\"Why the action was taken. Saved with the action and sent in the webhook event.\",\"type\":\"string\"\x7d\x7d,\"type\":\"object\"}", - "resolveQueueItems": "{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"properties\":{\"itemIds\":{\"description\":\"The item IDs to resolve. Up to 100.\",\"items\":{\"type\":\"string\"},\"maxItems\":100,\"minItems\":1,\"type\":\"array\"\x7d\x7d,\"required\":[\"itemIds\"],\"type\":\"object\"}", - "submitContent": "{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"properties\":{\"authorId\":{\"description\":\"The author of the content.\",\"type\":\"string\"},\"channel\":{\"description\":\"Provide a channel ID or key. Will use the project's default channel if not provided.\",\"type\":\"string\"},\"clientAction\":{\"description\":\"A recommendation from your own client-side flagging (e.g. a banned-IP list or a third-party tool). Feeds the rules engine and can escalate or override the recommended action. Does not change whether our analysis flagged the content.\",\"properties\":{\"action\":{\"description\":\"Your recommendation for the content: allow, review, or reject.\",\"enum\":[\"review\",\"allow\",\"reject\"],\"type\":\"string\"},\"behavior\":{\"description\":\"How your recommendation combines with ours. Defaults to 'escalate', which only applies it when stricter than ours; 'override' replaces ours outright.\",\"enum\":[\"override\",\"escalate\"],\"type\":\"string\"},\"reason\":{\"description\":\"A human-readable explanation for your recommendation.\",\"maxLength\":500,\"type\":\"string\"},\"source\":{\"description\":\"Where your recommendation came from, e.g. \\\"banned-ip\\\".\",\"maxLength\":100,\"type\":\"string\"\x7d\x7d,\"required\":[\"action\"],\"type\":\"object\"},\"content\":{\"description\":\"The content sent for moderation\",\"oneOf\":[{\"description\":\"Text\",\"properties\":{\"text\":{\"description\":\"The content text\",\"maxLength\":100000,\"type\":\"string\"},\"type\":{\"const\":\"text\",\"type\":\"string\"\x7d\x7d,\"required\":[\"type\",\"text\"],\"title\":\"Text\",\"type\":\"object\"},{\"description\":\"Image\",\"properties\":{\"data\":{\"description\":\"Base64-encoded image data. Either url or data must be provided. Note: base64 images are not stored and will not appear in the review queue.\",\"maxLength\":5500000,\"type\":\"string\"},\"type\":{\"const\":\"image\",\"type\":\"string\"},\"url\":{\"description\":\"A public URL of the image content. Either url or data must be provided.\",\"format\":\"uri\",\"type\":\"string\"\x7d\x7d,\"required\":[\"type\"],\"title\":\"Image\",\"type\":\"object\"},{\"description\":\"Video\",\"properties\":{\"type\":{\"const\":\"video\",\"type\":\"string\"},\"url\":{\"description\":\"A public URL of the video content\",\"format\":\"uri\",\"type\":\"string\"\x7d\x7d,\"required\":[\"type\",\"url\"],\"title\":\"Video\",\"type\":\"object\"},{\"description\":\"Audio\",\"properties\":{\"type\":{\"const\":\"audio\",\"type\":\"string\"},\"url\":{\"description\":\"The URL of the audio content\",\"format\":\"uri\",\"type\":\"string\"\x7d\x7d,\"required\":[\"type\",\"url\"],\"title\":\"Audio\",\"type\":\"object\"},{\"description\":\"Object\",\"properties\":{\"data\":{\"additionalProperties\":{\"oneOf\":[{\"description\":\"Text\",\"properties\":{\"text\":{\"description\":\"The content text\",\"maxLength\":100000,\"type\":\"string\"},\"type\":{\"const\":\"text\",\"type\":\"string\"\x7d\x7d,\"required\":[\"type\",\"text\"],\"title\":\"Text\",\"type\":\"object\"},{\"description\":\"Image\",\"properties\":{\"data\":{\"description\":\"Base64-encoded image data. Either url or data must be provided. Note: base64 images are not stored and will not appear in the review queue.\",\"maxLength\":5500000,\"type\":\"string\"},\"type\":{\"const\":\"image\",\"type\":\"string\"},\"url\":{\"description\":\"A public URL of the image content. Either url or data must be provided.\",\"format\":\"uri\",\"type\":\"string\"\x7d\x7d,\"required\":[\"type\"],\"title\":\"Image\",\"type\":\"object\"},{\"description\":\"Video\",\"properties\":{\"type\":{\"const\":\"video\",\"type\":\"string\"},\"url\":{\"description\":\"A public URL of the video content\",\"format\":\"uri\",\"type\":\"string\"\x7d\x7d,\"required\":[\"type\",\"url\"],\"title\":\"Video\",\"type\":\"object\"},{\"description\":\"Audio\",\"properties\":{\"type\":{\"const\":\"audio\",\"type\":\"string\"},\"url\":{\"description\":\"The URL of the audio content\",\"format\":\"uri\",\"type\":\"string\"\x7d\x7d,\"required\":[\"type\",\"url\"],\"title\":\"Audio\",\"type\":\"object\"}],\"title\":\"Content leaf\",\"type\":\"object\"},\"description\":\"Values in the object. Can be mixed content types.\",\"propertyNames\":{\"description\":\"The key of the content node\",\"type\":\"string\"},\"type\":\"object\"},\"type\":{\"const\":\"object\",\"type\":\"string\"\x7d\x7d,\"required\":[\"type\",\"data\"],\"title\":\"Object\",\"type\":\"object\"}],\"type\":\"object\"},\"contentId\":{\"description\":\"The unique ID of the content in your database.\",\"maxLength\":100,\"type\":\"string\"},\"conversationId\":{\"description\":\"For example the ID of a chat room or a post\",\"type\":\"string\"},\"doNotStore\":{\"description\":\"Process the content without saving it on our servers. The item is still created and appears in the review queue, analytics and author history with its moderation results, but its content is empty, so reviewers cannot see what was submitted.\",\"type\":\"boolean\"},\"metaType\":{\"description\":\"The meta type of content being moderated\",\"enum\":[\"profile\",\"message\",\"post\",\"comment\",\"event\",\"product\",\"review\",\"voice\",\"other\"],\"type\":\"string\"},\"metadata\":{\"additionalProperties\":{},\"description\":\"Any metadata you want to store with the content\",\"propertyNames\":{\"type\":\"string\"},\"type\":\"object\"},\"policies\":{\"description\":\"(Enterprise) override the channel policies for this moderation request only.\",\"items\":{\"oneOf\":[{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"toxicity\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Toxicity\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"personal_information\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Personal Information\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"hate\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Hate\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"illicit\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Illicit\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"illicit_drugs\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Illicit Drugs\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"illicit_alcohol\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Illicit Alcohol\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"illicit_firearms\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Illicit Firearms\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"illicit_tobacco\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Illicit Tobacco\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"illicit_gambling\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Illicit Gambling\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"cannabis\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Cannabis\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"adult\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Adult\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"crypto\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Crypto\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"sexual\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Sexual\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"sexual_minors\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Sexual Minors\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"profanity\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Profanity\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"violence\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Violence\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"self_harm\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Self Harm\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"spam\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Spam\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"low_quality\",\"type\":\"string\"},\"minWords\":{\"description\":\"Flag content with fewer than this many words as low-effort. Defaults to 3. Set to disable by omitting.\",\"minimum\":1,\"type\":\"integer\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Low-quality content\",\"type\":\"object\"},{\"properties\":{\"comparator\":{\"description\":\"Flag images that contain \\\"at least\\\" or \\\"fewer than\\\" the configured number of faces. Defaults to at_least.\",\"enum\":[\"at_least\",\"fewer_than\"],\"type\":\"string\"},\"count\":{\"description\":\"Number of faces the comparator applies to. Defaults to 1, so the default rule flags any image containing a face.\",\"minimum\":0,\"type\":\"integer\"},\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"face_detection\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Face detection\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"self_promotion\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Self Promotion\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"political\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Political\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"religion\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Religion\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"threat\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Threat\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"sexual_solicitation\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Sexual Solicitation\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"channel_circumvent\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Channel Circumvention\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"illegal_trade\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Illegal Trade\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"alcohol\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Alcohol\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"drugs\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Drugs\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"gambling\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Gambling\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"tobacco\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Tobacco\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"weapons\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Weapons\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"promotion\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Promotion\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"extremism\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Extremism\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"code_abuse\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Code Abuse\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"unicode_spoofing\",\"type\":\"string\"},\"signals\":{\"additionalProperties\":{\"properties\":{\"flag\":{\"type\":\"boolean\"\x7d\x7d,\"type\":\"object\"},\"description\":\"Per-signal flag toggles. Omitted spoofing signals are enabled; encoding_damage defaults to off because decode damage (U+FFFD) marks a broken pipeline, not an attack. A disabled signal is still detected and reported as a label, but does not by itself flag the policy.\",\"propertyNames\":{\"enum\":[\"mixed_script\",\"confusable_word\",\"invisible\",\"zalgo\",\"illegal\",\"encoding_damage\"],\"type\":\"string\"},\"type\":\"object\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Unicode Spoofing\",\"type\":\"object\"},{\"properties\":{\"entities\":{\"additionalProperties\":{\"additionalProperties\":{},\"properties\":{\"enable\":{\"type\":\"boolean\"},\"flag\":{\"type\":\"boolean\"},\"mask\":{\"type\":\"string\"},\"shouldMask\":{\"type\":\"boolean\"\x7d\x7d,\"type\":\"object\"},\"propertyNames\":{\"enum\":[\"email\",\"phone\",\"url\",\"address\",\"name\",\"username\",\"ip_address\",\"credit_card\",\"sensitive_other\"],\"type\":\"string\"},\"type\":\"object\"},\"id\":{\"const\":\"pii\",\"type\":\"string\"\x7d\x7d,\"required\":[\"id\",\"entities\"],\"title\":\"PII Masking\",\"type\":\"object\"},{\"properties\":{\"entities\":{\"additionalProperties\":{\"additionalProperties\":{},\"properties\":{\"enable\":{\"type\":\"boolean\"},\"flag\":{\"type\":\"boolean\"},\"mask\":{\"type\":\"string\"},\"shouldMask\":{\"type\":\"boolean\"\x7d\x7d,\"type\":\"object\"},\"propertyNames\":{\"enum\":[\"email\",\"phone\",\"url\",\"address\",\"name\",\"username\",\"ip_address\",\"credit_card\",\"sensitive_other\"],\"type\":\"string\"},\"type\":\"object\"},\"id\":{\"const\":\"url\",\"type\":\"string\"\x7d\x7d,\"required\":[\"id\",\"entities\"],\"title\":\"URL Masking\",\"type\":\"object\"},{\"properties\":{\"allowlistWordlistIds\":{\"description\":\"IDs of wordlists whose entries are treated as allowed URL domains. Matches short-circuit the risk model and are never flagged.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"blocklistWordlistIds\":{\"description\":\"IDs of wordlists whose entries are treated as blocked URL domains. Matches short-circuit the risk model and are always flagged. Blocklists take precedence over allowlists.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"flag\":{\"type\":\"boolean\"},\"flagLinkShorteners\":{\"description\":\"When true, any URL detected as a free link shortener (bit.ly, t.co, tinyurl, etc.) is always flagged regardless of risk score. Allowlist matches still win.\",\"type\":\"boolean\"},\"id\":{\"const\":\"url_risk\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"URL Risk\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"guidelineKey\":{\"type\":\"string\"},\"id\":{\"const\":\"guideline\",\"type\":\"string\"},\"instructions\":{\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\",\"instructions\",\"guidelineKey\"],\"title\":\"Guideline\",\"type\":\"object\"}],\"type\":\"object\"},\"type\":\"array\"},\"timestamp\":{\"description\":\"Unix timestamp (in milliseconds) of when the content was created. Use if content is not submitted in real-time.\",\"type\":\"number\"\x7d\x7d,\"required\":[\"content\"],\"type\":\"object\"}", + "resolveQueueItems": "{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"properties\":{\"itemIds\":{\"description\":\"The items to resolve, up to 100. Each is the item `id` from `GET /queue/{id}/items`, or the `contentId` you sent to `POST /moderate` (webhooks send it as `item.id`). For a content ID, the newest submission with that content ID is used, as the queue shows it.\",\"items\":{\"type\":\"string\"},\"maxItems\":100,\"minItems\":1,\"type\":\"array\"\x7d\x7d,\"required\":[\"itemIds\"],\"type\":\"object\"}", + "submitContent": "{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"properties\":{\"authorId\":{\"description\":\"The author of the content.\",\"type\":\"string\"},\"channel\":{\"description\":\"Provide a channel ID or key. Will use the project's default channel if not provided.\",\"type\":\"string\"},\"clientAction\":{\"description\":\"A recommendation from your own client-side flagging (e.g. a banned-IP list or a third-party tool). Feeds the rules engine and can escalate or override the recommended action. Does not change whether our analysis flagged the content.\",\"properties\":{\"action\":{\"description\":\"Your recommendation for the content: allow, review, or reject.\",\"enum\":[\"review\",\"allow\",\"reject\"],\"type\":\"string\"},\"behavior\":{\"description\":\"How your recommendation combines with ours. Defaults to 'escalate', which only applies it when stricter than ours; 'override' replaces ours outright.\",\"enum\":[\"override\",\"escalate\"],\"type\":\"string\"},\"reason\":{\"description\":\"A human-readable explanation for your recommendation.\",\"maxLength\":500,\"type\":\"string\"},\"source\":{\"description\":\"Where your recommendation came from, e.g. \\\"banned-ip\\\".\",\"maxLength\":100,\"type\":\"string\"\x7d\x7d,\"required\":[\"action\"],\"type\":\"object\"},\"content\":{\"description\":\"The content sent for moderation\",\"oneOf\":[{\"description\":\"Text\",\"properties\":{\"text\":{\"description\":\"The content text\",\"maxLength\":100000,\"type\":\"string\"},\"type\":{\"const\":\"text\",\"type\":\"string\"\x7d\x7d,\"required\":[\"type\",\"text\"],\"title\":\"Text\",\"type\":\"object\"},{\"description\":\"Image\",\"properties\":{\"data\":{\"description\":\"Base64-encoded image data. Either url or data must be provided. Note: base64 images are not stored and will not appear in the review queue.\",\"maxLength\":5500000,\"type\":\"string\"},\"type\":{\"const\":\"image\",\"type\":\"string\"},\"url\":{\"description\":\"A public URL of the image content. Either url or data must be provided.\",\"format\":\"uri\",\"type\":\"string\"\x7d\x7d,\"required\":[\"type\"],\"title\":\"Image\",\"type\":\"object\"},{\"description\":\"Video\",\"properties\":{\"type\":{\"const\":\"video\",\"type\":\"string\"},\"url\":{\"description\":\"A public URL of the video content\",\"format\":\"uri\",\"type\":\"string\"\x7d\x7d,\"required\":[\"type\",\"url\"],\"title\":\"Video\",\"type\":\"object\"},{\"description\":\"Audio\",\"properties\":{\"type\":{\"const\":\"audio\",\"type\":\"string\"},\"url\":{\"description\":\"The URL of the audio content\",\"format\":\"uri\",\"type\":\"string\"\x7d\x7d,\"required\":[\"type\",\"url\"],\"title\":\"Audio\",\"type\":\"object\"},{\"description\":\"Object\",\"properties\":{\"data\":{\"additionalProperties\":{\"oneOf\":[{\"description\":\"Text\",\"properties\":{\"text\":{\"description\":\"The content text\",\"maxLength\":100000,\"type\":\"string\"},\"type\":{\"const\":\"text\",\"type\":\"string\"\x7d\x7d,\"required\":[\"type\",\"text\"],\"title\":\"Text\",\"type\":\"object\"},{\"description\":\"Image\",\"properties\":{\"data\":{\"description\":\"Base64-encoded image data. Either url or data must be provided. Note: base64 images are not stored and will not appear in the review queue.\",\"maxLength\":5500000,\"type\":\"string\"},\"type\":{\"const\":\"image\",\"type\":\"string\"},\"url\":{\"description\":\"A public URL of the image content. Either url or data must be provided.\",\"format\":\"uri\",\"type\":\"string\"\x7d\x7d,\"required\":[\"type\"],\"title\":\"Image\",\"type\":\"object\"},{\"description\":\"Video\",\"properties\":{\"type\":{\"const\":\"video\",\"type\":\"string\"},\"url\":{\"description\":\"A public URL of the video content\",\"format\":\"uri\",\"type\":\"string\"\x7d\x7d,\"required\":[\"type\",\"url\"],\"title\":\"Video\",\"type\":\"object\"},{\"description\":\"Audio\",\"properties\":{\"type\":{\"const\":\"audio\",\"type\":\"string\"},\"url\":{\"description\":\"The URL of the audio content\",\"format\":\"uri\",\"type\":\"string\"\x7d\x7d,\"required\":[\"type\",\"url\"],\"title\":\"Audio\",\"type\":\"object\"}],\"title\":\"Content leaf\",\"type\":\"object\"},\"description\":\"Values in the object. Can be mixed content types.\",\"propertyNames\":{\"description\":\"The key of the content node\",\"type\":\"string\"},\"type\":\"object\"},\"type\":{\"const\":\"object\",\"type\":\"string\"\x7d\x7d,\"required\":[\"type\",\"data\"],\"title\":\"Object\",\"type\":\"object\"}],\"type\":\"object\"},\"contentId\":{\"description\":\"The unique ID of the content in your database.\",\"maxLength\":100,\"type\":\"string\"},\"conversationId\":{\"description\":\"For example the ID of a chat room or a post\",\"type\":\"string\"},\"doNotStore\":{\"description\":\"Process the content without saving it on our servers. The item is still created and appears in the review queue, analytics and author history with its moderation results, but its content is empty, so reviewers cannot see what was submitted.\",\"type\":\"boolean\"},\"metaType\":{\"description\":\"The meta type of content being moderated\",\"enum\":[\"profile\",\"message\",\"post\",\"comment\",\"event\",\"product\",\"review\",\"voice\",\"other\"],\"type\":\"string\"},\"metadata\":{\"additionalProperties\":{},\"description\":\"Any metadata you want to store with the content\",\"propertyNames\":{\"type\":\"string\"},\"type\":\"object\"},\"policies\":{\"description\":\"(Enterprise) override the channel policies for this moderation request only.\",\"items\":{\"oneOf\":[{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"toxicity\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Toxicity\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"personal_information\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Personal Information\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"hate\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Hate\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"illicit\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Illicit\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"illicit_drugs\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Illicit Drugs\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"illicit_alcohol\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Illicit Alcohol\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"illicit_firearms\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Illicit Firearms\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"illicit_tobacco\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Illicit Tobacco\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"illicit_gambling\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Illicit Gambling\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"cannabis\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Cannabis\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"adult\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Adult\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"crypto\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Crypto\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"sexual\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Sexual\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"sexual_minors\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Sexual Minors\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"profanity\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Profanity\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"violence\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Violence\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"self_harm\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Self Harm\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"spam\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Spam\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"low_quality\",\"type\":\"string\"},\"minWords\":{\"description\":\"Flag content with fewer than this many words as low-effort. Defaults to 3. Set to disable by omitting.\",\"minimum\":1,\"type\":\"integer\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Low-quality content\",\"type\":\"object\"},{\"properties\":{\"comparator\":{\"description\":\"Flag images that contain \\\"at least\\\" or \\\"fewer than\\\" the configured number of faces. Defaults to at_least.\",\"enum\":[\"at_least\",\"fewer_than\"],\"type\":\"string\"},\"count\":{\"description\":\"Number of faces the comparator applies to. Defaults to 1, so the default rule flags any image containing a face.\",\"minimum\":0,\"type\":\"integer\"},\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"face_detection\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Face detection\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"self_promotion\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Self Promotion\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"political\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Political\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"religion\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Religion\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"threat\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Threat\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"sexual_solicitation\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Sexual Solicitation\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"channel_circumvent\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Channel Circumvention\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"illegal_trade\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Illegal Trade\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"alcohol\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Alcohol\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"drugs\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Drugs\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"gambling\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Gambling\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"tobacco\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Tobacco\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"weapons\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Weapons\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"promotion\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Promotion\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"extremism\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Extremism\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"code_abuse\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Code Abuse\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"id\":{\"const\":\"unicode_spoofing\",\"type\":\"string\"},\"signals\":{\"additionalProperties\":{\"properties\":{\"flag\":{\"type\":\"boolean\"\x7d\x7d,\"type\":\"object\"},\"description\":\"Per-signal flag toggles. Omitted spoofing signals are enabled; encoding_damage defaults to off because decode damage (U+FFFD) marks a broken pipeline, not an attack, and hidden_lookalike and leetspeak default to off because they are opt-in. A disabled signal is still detected and reported as a label, but does not by itself flag the policy. Lookalike words are only spelled out in the cleaned text when their signal is enabled.\",\"propertyNames\":{\"enum\":[\"mixed_script\",\"confusable_word\",\"hidden_lookalike\",\"leetspeak\",\"invisible\",\"zalgo\",\"illegal\",\"encoding_damage\"],\"type\":\"string\"},\"type\":\"object\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"Unicode Spoofing\",\"type\":\"object\"},{\"properties\":{\"entities\":{\"additionalProperties\":{\"additionalProperties\":{},\"properties\":{\"enable\":{\"type\":\"boolean\"},\"flag\":{\"type\":\"boolean\"},\"mask\":{\"type\":\"string\"},\"shouldMask\":{\"type\":\"boolean\"\x7d\x7d,\"type\":\"object\"},\"propertyNames\":{\"enum\":[\"email\",\"phone\",\"url\",\"address\",\"name\",\"username\",\"ip_address\",\"credit_card\",\"sensitive_other\"],\"type\":\"string\"},\"type\":\"object\"},\"id\":{\"const\":\"pii\",\"type\":\"string\"\x7d\x7d,\"required\":[\"id\",\"entities\"],\"title\":\"PII Masking\",\"type\":\"object\"},{\"properties\":{\"entities\":{\"additionalProperties\":{\"additionalProperties\":{},\"properties\":{\"enable\":{\"type\":\"boolean\"},\"flag\":{\"type\":\"boolean\"},\"mask\":{\"type\":\"string\"},\"shouldMask\":{\"type\":\"boolean\"\x7d\x7d,\"type\":\"object\"},\"propertyNames\":{\"enum\":[\"email\",\"phone\",\"url\",\"address\",\"name\",\"username\",\"ip_address\",\"credit_card\",\"sensitive_other\"],\"type\":\"string\"},\"type\":\"object\"},\"id\":{\"const\":\"url\",\"type\":\"string\"\x7d\x7d,\"required\":[\"id\",\"entities\"],\"title\":\"URL Masking\",\"type\":\"object\"},{\"properties\":{\"allowlistWordlistIds\":{\"description\":\"IDs of wordlists whose entries are treated as allowed URL domains. Matches short-circuit the risk model and are never flagged.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"blocklistWordlistIds\":{\"description\":\"IDs of wordlists whose entries are treated as blocked URL domains. Matches short-circuit the risk model and are always flagged. Blocklists take precedence over allowlists.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"flag\":{\"type\":\"boolean\"},\"flagLinkShorteners\":{\"description\":\"When true, any URL detected as a free link shortener (bit.ly, t.co, tinyurl, etc.) is always flagged regardless of risk score. Allowlist matches still win.\",\"type\":\"boolean\"},\"id\":{\"const\":\"url_risk\",\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\"],\"title\":\"URL Risk\",\"type\":\"object\"},{\"properties\":{\"flag\":{\"type\":\"boolean\"},\"guidelineKey\":{\"type\":\"string\"},\"id\":{\"const\":\"guideline\",\"type\":\"string\"},\"instructions\":{\"type\":\"string\"},\"threshold\":{\"maximum\":1,\"minimum\":0,\"type\":\"number\"\x7d\x7d,\"required\":[\"flag\",\"id\",\"instructions\",\"guidelineKey\"],\"title\":\"Guideline\",\"type\":\"object\"}],\"type\":\"object\"},\"type\":\"array\"},\"timestamp\":{\"description\":\"Unix timestamp (in milliseconds) of when the content was created. Use if content is not submitted in real-time.\",\"type\":\"number\"\x7d\x7d,\"required\":[\"content\"],\"type\":\"object\"}", "suspendAuthor": "{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"properties\":{\"duration\":{\"description\":\"How long the suspension lasts, in milliseconds. Defaults to 24 hours.\",\"minimum\":0,\"type\":\"number\"},\"reason\":{\"description\":\"Why the action was taken. Saved with the action and sent in the webhook event.\",\"type\":\"string\"\x7d\x7d,\"type\":\"object\"}", "unblockAuthor": "{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"properties\":{\"reason\":{\"description\":\"Why the action was taken. Saved with the action and sent in the webhook event.\",\"type\":\"string\"\x7d\x7d,\"type\":\"object\"}", "updateAction": "{\"$schema\":\"https://json-schema.org/draft/2020-12/schema\",\"properties\":{\"builtIn\":{\"default\":false,\"description\":\"Whether the action is a built-in action or a custom one.\",\"type\":[\"boolean\",\"null\"]},\"description\":{\"description\":\"The description of the action.\",\"type\":[\"string\",\"null\"]},\"filterInQueueIds\":{\"default\":[],\"description\":\"The IDs of the queues the action is available in.\",\"items\":{\"type\":\"string\"},\"type\":\"array\"},\"freeText\":{\"default\":false,\"description\":\"Whether the action allows any text to be entered as a value or if it must be one of the possible values.\",\"type\":\"boolean\"},\"key\":{\"description\":\"User defined key of the action.\",\"type\":[\"string\",\"null\"]},\"name\":{\"description\":\"The name of the action.\",\"type\":\"string\"},\"position\":{\"default\":\"ALL_QUEUES\",\"description\":\"Show the action in all queues, selected queues or no queues (to use via API only).\",\"enum\":[\"ALL_QUEUES\",\"SOME_QUEUES\",\"HIDDEN\"],\"type\":\"string\"},\"possibleValues\":{\"default\":[],\"description\":\"The possible values of the action. The user will be prompted to select one of these values when executing the action.\",\"items\":{\"properties\":{\"value\":{\"description\":\"The value of the action.\",\"type\":\"string\"\x7d\x7d,\"required\":[\"value\"],\"type\":\"object\"},\"type\":\"array\"},\"queueBehaviour\":{\"default\":\"NO_CHANGE\",\"description\":\"Whether the action resolves and removes the item, unresolves and re-add it to the queue, or does not change the resolve status.\",\"enum\":[\"REMOVE\",\"ADD\",\"NO_CHANGE\"],\"type\":\"string\"},\"type\":{\"anyOf\":[{\"enum\":[\"AUTHOR_BLOCK\",\"AUTHOR_BLOCK_TEMP\",\"AUTHOR_UNBLOCK\",\"AUTHOR_DELETE\",\"AUTHOR_REPORT\",\"AUTHOR_WARN\",\"AUTHOR_CUSTOM\",\"ITEM_REJECT\",\"ITEM_ALLOW\",\"ITEM_CUSTOM\"],\"type\":\"string\"},{\"type\":\"null\"}],\"description\":\"The type of the action.\"},\"valueRequired\":{\"default\":false,\"description\":\"Whether the action requires a value to be executed.\",\"type\":\"boolean\"\x7d\x7d,\"type\":\"object\"}", diff --git a/internal/usage/schema.go b/internal/usage/schema.go index f804666..ad115d3 100644 --- a/internal/usage/schema.go +++ b/internal/usage/schema.go @@ -28,7 +28,7 @@ type usageNode struct { } var usageNodes = map[string]usageNode{ - "": {head: "name \"modapi\"\nbin \"modapi\"\nabout \"Moderation API: Moderate text, images, video and audio in real time, manage authors, review queues and actions, and receive webhooks.\"\nversion \"0.6.0\"\nconfig {\n file \"~/.config/modapi/config.yaml\"\n}", flags: []usageItem{{key: "usage", text: "flag \"--usage\" help=\"Print the CLI Usage schema in KDL format\" global=#true"}, {key: "version", text: "flag \"-v --version\" help=\"Print the CLI version\""}, {key: "output-format", text: "flag \"-o --output-format \" help=\"Specify the output format. Options: pretty, json, yaml, table, toon.\" global=#true config=\"output_format\" default=\"pretty\""}, {key: "color", text: "flag \"--color \" help=\"Control colored output: auto (color when output is a TTY), always, or never. Respects NO_COLOR and FORCE_COLOR env vars.\" global=#true default=\"auto\""}, {key: "jq", text: "flag \"-q --jq \" help=\"Filter and transform output using a jq expression (e.g., '.name', '.items[] | .id')\" global=#true"}, {key: "raw-output", text: "flag \"--raw-output\" help=\"Write --jq string results as raw text instead of JSON strings (like jq -r); non-string results stay JSON\" global=#true default=#false"}, {key: "server-url", text: "flag \"--server-url \" help=\"Override the default server URL\" global=#true"}, {key: "server", text: "flag \"--server \" help=\"Select a server by index (for indexed servers) or name (for named servers)\" global=#true"}, {key: "header", text: "flag \"-H --header \" help=\"Set a custom HTTP request header (format: \\\"Key: Value\\\"). Can be specified multiple times.\" global=#true var=#true"}, {key: "include-headers", text: "flag \"--include-headers\" help=\"Include HTTP response headers in the output\" global=#true default=#false"}, {key: "timeout", text: "flag \"--timeout \" help=\"HTTP request timeout (e.g., 30s, 5m, 100ms)\" global=#true config=\"timeout\""}, {key: "interactive", text: "flag \"--interactive\" help=\"Prompt for missing inputs and open guided configure/auth forms (forms fall back to line prompts on stdin off-TTY)\" global=#true default=#true"}, {key: "no-interactive", text: "flag \"--no-interactive\" help=\"Disable all interactive features (auto-prompting, explorer auto-launch, TUI forms)\" global=#true default=#false"}, {key: "dry-run", text: "flag \"--dry-run\" help=\"Preview API requests without sending them (no network, no OS keychain). Human preview on stderr; with -o json or --jq, one JSON object per request on stdout. Local mutation commands (auth login, auth logout and configure) make no request: they skip prompts and writes and report a no-op (stderr, or one JSON object on stdout in the machine form)\" global=#true default=#false"}, {key: "debug", text: "flag \"-d --debug\" help=\"Log request and response diagnostics to stderr\" global=#true default=#false"}, {key: "agent-mode", text: "flag \"--agent-mode\" help=\"Enable structured errors and default TOON output for AI coding agents. Automatically enabled when a known agent environment is detected (CLAUDECODE, CURSOR_AGENT, etc.). Use --agent-mode=false to disable.\" global=#true default=#false"}, {key: "secret-key", text: "flag \"--secret-key \" help=\"HTTP Bearer\" global=#true env=\"MODAPI_SECRET_KEY\" config=\"security.secret_key\""}, {key: "no-keyring", text: "flag \"--no-keyring\" help=\"Never read or write the OS keychain; store secrets in the config file instead\" global=#true env=\"MODAPI_NO_KEYRING\" config=\"no_keyring\" default=#false"}}, children: []string{"account", "actions", "analytics", "auth", "authors", "channels", "completion", "configure", "content", "explore", "feedback", "help", "projects", "queue", "version", "webhook-secret", "webhooks", "whoami", "wordlist"}}, + "": {head: "name \"modapi\"\nbin \"modapi\"\nabout \"Moderation API: Moderate text, images, video and audio in real time, manage authors, review queues and actions, and receive webhooks.\"\nversion \"0.6.1\"\nconfig {\n file \"~/.config/modapi/config.yaml\"\n}", flags: []usageItem{{key: "usage", text: "flag \"--usage\" help=\"Print the CLI Usage schema in KDL format\" global=#true"}, {key: "version", text: "flag \"-v --version\" help=\"Print the CLI version\""}, {key: "output-format", text: "flag \"-o --output-format \" help=\"Specify the output format. Options: pretty, json, yaml, table, toon.\" global=#true config=\"output_format\" default=\"pretty\""}, {key: "color", text: "flag \"--color \" help=\"Control colored output: auto (color when output is a TTY), always, or never. Respects NO_COLOR and FORCE_COLOR env vars.\" global=#true default=\"auto\""}, {key: "jq", text: "flag \"-q --jq \" help=\"Filter and transform output using a jq expression (e.g., '.name', '.items[] | .id')\" global=#true"}, {key: "raw-output", text: "flag \"--raw-output\" help=\"Write --jq string results as raw text instead of JSON strings (like jq -r); non-string results stay JSON\" global=#true default=#false"}, {key: "server-url", text: "flag \"--server-url \" help=\"Override the default server URL\" global=#true"}, {key: "server", text: "flag \"--server \" help=\"Select a server by index (for indexed servers) or name (for named servers)\" global=#true"}, {key: "header", text: "flag \"-H --header \" help=\"Set a custom HTTP request header (format: \\\"Key: Value\\\"). Can be specified multiple times.\" global=#true var=#true"}, {key: "include-headers", text: "flag \"--include-headers\" help=\"Include HTTP response headers in the output\" global=#true default=#false"}, {key: "timeout", text: "flag \"--timeout \" help=\"HTTP request timeout (e.g., 30s, 5m, 100ms)\" global=#true config=\"timeout\""}, {key: "interactive", text: "flag \"--interactive\" help=\"Prompt for missing inputs and open guided configure/auth forms (forms fall back to line prompts on stdin off-TTY)\" global=#true default=#true"}, {key: "no-interactive", text: "flag \"--no-interactive\" help=\"Disable all interactive features (auto-prompting, explorer auto-launch, TUI forms)\" global=#true default=#false"}, {key: "dry-run", text: "flag \"--dry-run\" help=\"Preview API requests without sending them (no network, no OS keychain). Human preview on stderr; with -o json or --jq, one JSON object per request on stdout. Local mutation commands (auth login, auth logout and configure) make no request: they skip prompts and writes and report a no-op (stderr, or one JSON object on stdout in the machine form)\" global=#true default=#false"}, {key: "debug", text: "flag \"-d --debug\" help=\"Log request and response diagnostics to stderr\" global=#true default=#false"}, {key: "agent-mode", text: "flag \"--agent-mode\" help=\"Enable structured errors and default TOON output for AI coding agents. Automatically enabled when a known agent environment is detected (CLAUDECODE, CURSOR_AGENT, etc.). Use --agent-mode=false to disable.\" global=#true default=#false"}, {key: "secret-key", text: "flag \"--secret-key \" help=\"HTTP Bearer\" global=#true env=\"MODAPI_SECRET_KEY\" config=\"security.secret_key\""}, {key: "no-keyring", text: "flag \"--no-keyring\" help=\"Never read or write the OS keychain; store secrets in the config file instead\" global=#true env=\"MODAPI_NO_KEYRING\" config=\"no_keyring\" default=#false"}}, children: []string{"account", "actions", "analytics", "auth", "authors", "channels", "completion", "configure", "content", "explore", "feedback", "help", "projects", "queue", "version", "webhook-secret", "webhooks", "whoami", "wordlist"}}, "account": {head: "cmd \"account\" help=\"Operations for account\"", children: []string{"retrieve"}}, "account retrieve": {head: "cmd \"retrieve\" help=\"Get account details\"", flags: []usageItem{{key: "project-id", text: " flag \"-p --project-id \" help=\"The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error.\""}}}, "actions": {head: "cmd \"actions\" help=\"Operations for actions\"", children: []string{"create", "delete", "execute", "list", "retrieve", "update"}}, @@ -92,9 +92,9 @@ var usageNodes = map[string]usageNode{ "queue get-stats": {head: "cmd \"get-stats\" help=\"Get queue statistics\"", aliases: []usageItem{{key: "gs", text: " alias \"gs\""}}, args: []usageItem{{key: "id", text: " arg \"id\" help=\"The queue ID. (or use --id)\""}}, flags: []usageItem{{key: "id", text: " flag \"-i --id \" help=\"The queue ID. (or pass it as the [id] argument)\""}, {key: "within-days", text: " flag \"-w --within-days \" help=\"integer value\" default=30"}, {key: "project-id", text: " flag \"-p --project-id \" help=\"The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error.\""}}}, "queue items": {head: "cmd \"items\" help=\"Operations for items\"", children: []string{"list", "resolve", "resolve-many", "unresolve"}}, "queue items list": {head: "cmd \"list\" help=\"List queue items\"", args: []usageItem{{key: "id", text: " arg \"id\" help=\"The queue ID. (or use --id)\""}}, flags: []usageItem{{key: "id", text: " flag \"-i --id \" help=\"The queue ID. (or pass it as the [id] argument)\""}, {key: "page", text: " flag \"--page \" help=\"integer value\" default=1"}, {key: "page-size", text: " flag \"--page-size \" help=\"integer value\" default=20"}, {key: "sort", text: " flag \"-s --sort \" help=\"options: FIFO, LIFO, RANDOM, SEVERITY_DESC\""}, {key: "include-resolved", text: " flag \"--include-resolved\" help=\"boolean flag\""}, {key: "conversation-ids", text: " flag \"-c --conversation-ids \" help=\"list of values\" var=#true"}, {key: "labels", text: " flag \"-l --labels \" help=\"list of values\" var=#true"}, {key: "author-id", text: " flag \"--author-id \" help=\"string value\""}, {key: "filtered-action-ids", text: " flag \"-f --filtered-action-ids \" help=\"list of values\" var=#true"}, {key: "after-date", text: " flag \"--after-date \" help=\"string value\""}, {key: "before-date", text: " flag \"-b --before-date \" help=\"string value\""}, {key: "project-id", text: " flag \"--project-id \" help=\"The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error.\""}, {key: "all", text: " flag \"-a --all\" help=\"Automatically paginate and fetch all results (streams NDJSON for JSON output)\""}, {key: "max-pages", text: " flag \"--max-pages \" help=\"Maximum number of pages to fetch when using --all (0 = no limit)\" default=0"}}}, - "queue items resolve": {head: "cmd \"resolve\" help=\"Resolve a queue item\"", flags: []usageItem{{key: "id", text: " flag \"--id \" help=\"The queue ID. [required]\""}, {key: "item-id", text: " flag \"--item-id \" help=\"The item ID to resolve. [required]\""}, {key: "project-id", text: " flag \"-p --project-id \" help=\"The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error.\""}}}, - "queue items resolve-many": {head: "cmd \"resolve-many\" help=\"Resolve queue items\"", aliases: []usageItem{{key: "rm", text: " alias \"rm\""}}, args: []usageItem{{key: "id", text: " arg \"id\" help=\"The queue ID. (or use --id)\""}}, flags: []usageItem{{key: "id", text: " flag \"-i --id \" help=\"The queue ID. (or pass it as the [id] argument)\""}, {key: "project-id", text: " flag \"-p --project-id \" help=\"The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error.\""}, {key: "item-ids", text: " flag \"--item-ids \" help=\"The item IDs to resolve. Up to 100. [required]\" var=#true"}, {key: "body", text: " flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\""}, {key: "schema", text: " flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\""}}}, - "queue items unresolve": {head: "cmd \"unresolve\" help=\"Unresolve a queue item\"", flags: []usageItem{{key: "id", text: " flag \"--id \" help=\"The queue ID. [required]\""}, {key: "item-id", text: " flag \"--item-id \" help=\"The item ID to unresolve. [required]\""}, {key: "project-id", text: " flag \"-p --project-id \" help=\"The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error.\""}}}, + "queue items resolve": {head: "cmd \"resolve\" help=\"Resolve a queue item\"", flags: []usageItem{{key: "id", text: " flag \"--id \" help=\"The queue ID. [required]\""}, {key: "item-id", text: " flag \"--item-id \" help=\"The item to resolve: the item 'id' from 'GET /queue/{id}/items', or the 'contentId' you sent to 'POST /moderate' (webhooks send it as 'item.id'). For a content ID, the newest submission with that content ID is used, as the queue shows it. [required]\""}, {key: "project-id", text: " flag \"-p --project-id \" help=\"The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error.\""}}}, + "queue items resolve-many": {head: "cmd \"resolve-many\" help=\"Resolve queue items\"", aliases: []usageItem{{key: "rm", text: " alias \"rm\""}}, args: []usageItem{{key: "id", text: " arg \"id\" help=\"The queue ID. (or use --id)\""}}, flags: []usageItem{{key: "id", text: " flag \"-i --id \" help=\"The queue ID. (or pass it as the [id] argument)\""}, {key: "project-id", text: " flag \"-p --project-id \" help=\"The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error.\""}, {key: "item-ids", text: " flag \"--item-ids \" help=\"The items to resolve, up to 100. Each is the item 'id' from 'GET /queue/{id}/items', or the 'contentId' you sent to 'POST /moderate' (webhooks send it as 'item.id'). For a content ID, the newest submission with that content ID is used, as the queue shows it. [required]\" var=#true"}, {key: "body", text: " flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\""}, {key: "schema", text: " flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\""}}}, + "queue items unresolve": {head: "cmd \"unresolve\" help=\"Unresolve a queue item\"", flags: []usageItem{{key: "id", text: " flag \"--id \" help=\"The queue ID. [required]\""}, {key: "item-id", text: " flag \"--item-id \" help=\"The item to unresolve: the item 'id' from 'GET /queue/{id}/items', or the 'contentId' you sent to 'POST /moderate' (webhooks send it as 'item.id'). For a content ID, the newest submission with that content ID is used, as the queue shows it. [required]\""}, {key: "project-id", text: " flag \"-p --project-id \" help=\"The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error.\""}}}, "queue list": {head: "cmd \"list\" help=\"List queues\"", flags: []usageItem{{key: "page", text: " flag \"--page \" help=\"integer value\" default=1"}, {key: "page-size", text: " flag \"--page-size \" help=\"integer value\" default=20"}, {key: "project-id", text: " flag \"--project-id \" help=\"The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error.\""}, {key: "all", text: " flag \"-a --all\" help=\"Automatically paginate and fetch all results (streams NDJSON for JSON output)\""}, {key: "max-pages", text: " flag \"--max-pages \" help=\"Maximum number of pages to fetch when using --all (0 = no limit)\" default=0"}}}, "queue retrieve": {head: "cmd \"retrieve\" help=\"Get a queue\"", args: []usageItem{{key: "id", text: " arg \"id\" help=\"The queue ID. (or use --id)\""}}, flags: []usageItem{{key: "id", text: " flag \"-i --id \" help=\"The queue ID. (or pass it as the [id] argument)\""}, {key: "project-id", text: " flag \"-p --project-id \" help=\"The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error.\""}}}, "version": {head: "cmd \"version\" help=\"Print the CLI version\""}, @@ -107,8 +107,9 @@ var usageNodes = map[string]usageNode{ "webhooks retrieve": {head: "cmd \"retrieve\" help=\"Get a webhook\"", args: []usageItem{{key: "id", text: " arg \"id\" help=\"The ID of the webhook to get. (or use --id)\""}}, flags: []usageItem{{key: "id", text: " flag \"-i --id \" help=\"The ID of the webhook to get. (or pass it as the [id] argument)\""}, {key: "project-id", text: " flag \"-p --project-id \" help=\"The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error.\""}}}, "webhooks update": {head: "cmd \"update\" help=\"Update a webhook\"", args: []usageItem{{key: "id", text: " arg \"id\" help=\"The ID of the webhook to update. (or use --id)\""}}, flags: []usageItem{{key: "id", text: " flag \"-i --id \" help=\"The ID of the webhook to update. (or pass it as the [id] argument)\""}, {key: "project-id", text: " flag \"-p --project-id \" help=\"The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error.\""}, {key: "name", text: " flag \"-n --name \" help=\"The webhook's name, used to identify it in the dashboard\""}, {key: "description", text: " flag \"--description \" help=\"The webhook's description\""}, {key: "url", text: " flag \"-u --url \" help=\"The webhook's URL. We'll call this URL when an event occurs.\""}, {key: "event-types", text: " flag \"-e --event-types \" help=\"Event types this webhook subscribes to. One webhook URL receives all events you list here. (options: QUEUE_ITEM_NEW, QUEUE_ITEM_COMPLETED, QUEUE_ITEM_ACTION, QUEUE_ITEM_REJECTED, QUEUE_ITEM_ALLOWED, AUTHOR_BLOCKED, AUTHOR_UNBLOCKED, AUTHOR_SUSPENDED, AUTHOR_UPDATED, AUTHOR_TRUST_LEVEL_CHANGED, AUTHOR_ACTION)\" var=#true"}, {key: "body", text: " flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\""}, {key: "schema", text: " flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\""}}}, "whoami": {head: "cmd \"whoami\" help=\"Display current authentication configuration\""}, - "wordlist": {head: "cmd \"wordlist\" help=\"Operations for wordlist\"", children: []string{"create", "get-embedding-status", "list", "retrieve", "update", "words"}}, + "wordlist": {head: "cmd \"wordlist\" help=\"Operations for wordlist\"", children: []string{"create", "delete", "get-embedding-status", "list", "retrieve", "update", "words"}}, "wordlist create": {head: "cmd \"create\" help=\"Create wordlist\"", flags: []usageItem{{key: "project-id", text: " flag \"-p --project-id \" help=\"The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error.\""}, {key: "name", text: " flag \"-n --name \" help=\"Name of the wordlist [required]\""}, {key: "key", text: " flag \"-k --key \" help=\"Key of the wordlist. Default: made from the name. If the key is already in use, a suffix is added.\""}, {key: "description", text: " flag \"--description \" help=\"Description of the wordlist\""}, {key: "words", text: " flag \"-w --words \" help=\"Words to add to the wordlist. Words are converted to lowercase. Duplicate and empty words are ignored. Maximum 5000 words.\" var=#true"}, {key: "body", text: " flag \"--body \" help=\"Request body as JSON (alternative to individual flags). Can also be provided via stdin; @path reads a file, @- reads stdin to EOF. Use --schema to print the exact JSON Schema.\""}, {key: "schema", text: " flag \"--schema\" help=\"Print the exact JSON Schema of the request body and exit\""}}}, + "wordlist delete": {head: "cmd \"delete\" help=\"Delete wordlist\"", args: []usageItem{{key: "id", text: " arg \"id\" help=\"ID of the wordlist to delete (or use --id)\""}}, flags: []usageItem{{key: "id", text: " flag \"-i --id \" help=\"ID of the wordlist to delete (or pass it as the [id] argument)\""}, {key: "project-id", text: " flag \"-p --project-id \" help=\"The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error.\""}}}, "wordlist get-embedding-status": {head: "cmd \"get-embedding-status\" help=\"Get embedding status\"", aliases: []usageItem{{key: "ges", text: " alias \"ges\""}}, args: []usageItem{{key: "id", text: " arg \"id\" help=\"ID of the wordlist to check embedding status for (or use --id)\""}}, flags: []usageItem{{key: "id", text: " flag \"-i --id \" help=\"ID of the wordlist to check embedding status for (or pass it as the [id] argument)\""}, {key: "project-id", text: " flag \"-p --project-id \" help=\"The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error.\""}}}, "wordlist list": {head: "cmd \"list\" help=\"List wordlists\"", flags: []usageItem{{key: "page", text: " flag \"--page \" help=\"integer value\" default=1"}, {key: "page-size", text: " flag \"--page-size \" help=\"integer value\" default=20"}, {key: "project-id", text: " flag \"--project-id \" help=\"The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error.\""}, {key: "all", text: " flag \"-a --all\" help=\"Automatically paginate and fetch all results (streams NDJSON for JSON output)\""}, {key: "max-pages", text: " flag \"--max-pages \" help=\"Maximum number of pages to fetch when using --all (0 = no limit)\" default=0"}}}, "wordlist retrieve": {head: "cmd \"retrieve\" help=\"Get wordlist\"", args: []usageItem{{key: "id", text: " arg \"id\" help=\"ID of the wordlist to get (or use --id)\""}}, flags: []usageItem{{key: "id", text: " flag \"-i --id \" help=\"ID of the wordlist to get (or pass it as the [id] argument)\""}, {key: "project-id", text: " flag \"-p --project-id \" help=\"The project to act on, by ID or name. Required with an organization key unless the key reaches only one project; list projects with GET /projects. A project key acts on its own project and needs no value: naming another one is an error.\""}}},