primcli 3.0.0-preview.1 → 3.0.0-preview.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -2
- package/dist/{api-command-ctHBqTL5.js → api-command-DWjtyqH9.js} +52 -11
- package/dist/{json-output-BzSBR-KX.js → json-output-DWrJMakZ.js} +7 -1
- package/dist/{machine-session-Cp_eQ9t_.js → machine-session-BG4getHB.js} +4 -4
- package/dist/{notify-session-BN0JTPZ3.js → notify-session-8Jv4jJzI.js} +2 -2
- package/dist/oclif/auto-signal-worker.js +3 -3
- package/dist/oclif/auto-signals.js +1 -1
- package/dist/oclif/index.js +2960 -465
- package/dist/oclif/proxy-auto-detect.js +1 -1
- package/dist/oclif/receiver-heal.js +2 -2
- package/dist/{repeats-Dj_o6c-X-Bf9G0xds.js → repeats-Dj_o6c-X-BKHiZsYv.js} +80 -24
- package/dist/{scoped-chat-DZ42V3jq.js → scoped-chat-_AEpylPV.js} +1 -1
- package/dist/{signal-command-CRUMUCNa.js → signal-command-CBHAR7zj.js} +4 -4
- package/man/primitive.1 +13 -3
- package/package.json +2 -2
package/dist/oclif/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
import { $ as AutomatedFilterUnsupportedError, A as sleep$3, At as
|
|
3
|
-
import { S as readBundledConnectSkill, _ as NotificationOutcomeUnknownError, a as NotificationRetryError, b as installedConnectSkillFile, c as readConversationStatusContent, d as SESSION_UUID$1, g as NativeSessionNotLoadedError, h as NativeSessionError, i as notificationReceiptPage, l as createListenHandler, m as NativeSessionDisconnectedError, n as notificationSenders, o as isRoutineNotificationContent, p as defaultSessionSocket, r as openSessionNotifications, s as notificationPartReader, t as notificationScope, u as readableDelivery, v as connectSkillTarget, x as installedVersion, y as installConnectSkill } from "../notify-session-
|
|
1
|
+
import { $ as deriveSendIdempotencyKey, A as wakeRelationship, At as ATTACHMENT_WAIT_MAX_MS, B as readEmailInteraction, Bt as CliOrgRefusedError, C as readThreadContext, Ct as currentMailSessionKey, Dt as formatAlreadySentNotice, E as serverRelationship, Et as runtimeSessionVariableList, F as readPendingMail, Ft as createCliApiClient, G as MAX_SEND_WAIT_TIMEOUT_MS, H as replyInteractionWarning, Ht as fetchCliOrgs, I as recordPendingMail, It as refreshStoredCliCredentials, J as assertValidIdempotencyKey, K as SEND_OUTCOME_HELP, L as removePendingMail, Lt as refuseOrgSelectionForProfile, M as clearConsumedPendingMail, Mt as ConnectedAgentKeyRequiredError, N as clearReadPendingMail, O as wakeReadCommand, Ot as withFlagSuggestion, P as pendingMailPath, Pt as createAuthenticatedCliApiClient, Q as classifySendError, R as interactionHumanLine, Rt as resolveCliApiRequestConfig, S as latestOwnOutbound, St as loadSkillLine, T as serverMuted, Tt as detectRuntimeSession, Ut as revokeUserLogin, V as replyExpectation, Vt as credentialsFromUserLogin, W as IDEMPOTENCY_KEY_FLAG_DESCRIPTION, Wt as switchCurrentOrg, X as buildThrownSendFailureEnvelope, Y as buildFollowUpCommand, Z as checkPriorReplies, _ as explainPendingMailNotFound, _t as cliInvocation, a as createOperationCommand, at as formatSendFailureSummary, b as displayAddress, bt as generatedAgentName, c as formatErrorPayload, ct as reportSendCommandResult, d as isGrantRefusal, dt as sendWaitClampNotice, et as excludeSignalReplies, f as parameterFlagName, ft as sentHistoryWindowStart, g as writeErrorWithHints, h as surfaceUnauthorizedHint, ht as thrownErrorExitCode, i as TIME_FLAG_DESCRIPTION, it as formatPriorRepliesWarning, j as claimPendingMail, jt as withAttachmentWait, k as wakeRecipientField, kt as ATTACHMENT_WAIT_FLAG_DESCRIPTION, l as hasControlCharacter$1, lt as sendIdentityFields, m as runWithTiming, mt as successfulSendOutcome, n as API_ERROR_CODES, nt as formatDeletedEarlierSendNotice, o as extractErrorCode, ot as formatSendRecordFailureSummary, p as readTextFileFlag, pt as serializeErrorPayload, q as apiResultHttpStatus, r as OPERATION_PATH_FLAGS, rt as formatPriorRepliesCheckSkipped, s as extractErrorPayload, st as priorRepliesThatWentOut, t as API_BASE_URL_FLAG_DESCRIPTION, tt as followUpCommandPrefix, u as headerFlagName, ut as sendOutcomeExitCode, v as bareAddress, vt as connectNextSteps, w as sentInThread, wt as detectAgentRuntime, x as formatMailWakeLine, xt as identitySuggestions, y as describeWake, z as interactionNextActions, zt as selectedOrgFromEnv } from "../api-command-DWjtyqH9.js";
|
|
2
|
+
import { $ as AutomatedFilterUnsupportedError, $n as updateRoute, $t as listAgentContacts, A as sleep$3, An as resendAgentSignupVerification, At as getAccessMode, B as hasReplyState, Bn as setFunctionSecret, Bt as getFunctionTestRunTrace, C as collectNewAcceptedEmails, Ct as deleteWakeAuthorization, D as filtersFromFlags, Dn as removeDefaultNetworkMember, E as fetchEmailSearchPage, En as redeemCreditCode, Et as downloadEmailAttachmentByFilename, F as assertAwaitingFilterRows, Fn as searchEmails, Ft as getCreditBalance, Gn as startCliLogin, Gt as getOwnGrant, H as queryUsesAwaiting, Hn as simulateRoute, Ht as getKey, I as awaitingRejectedError, In as searchMemories, It as getDefaultNetworkAgent, J as parseWebhookEvent, Jn as unsetFunctionRoute, Jt as getThread, K as isEmailReceivedEvent, Kn as stopRepeatFromEmail, Kt as getRepeatingSend, L as ensureSearchReportsReplyState, Ln as semanticSearch, Lt as getEmail, M as AWAITING_VALUES, Mn as rotateKey, Mt as getAgentContactPolicy, N as REPLY_STATE_UNSUPPORTED_CODE, Nn as runWakeSchedule, O as quoteDslValue, On as reorderRoutes, Ot as downloadSentAttachmentArchiveMember, P as ReplyStateUnsupportedError, Pt as getConversation, Q as AUTOMATED_VALUES, Qn as updateRepeatingSend, R as formatAwaitingCell, Rn as sendEmail, Rt as getFunction, S as transientFailure, Sn as pullWebhookEvent, St as deleteRoute, T as encodeReceivedAtSearchCursor, Tt as downloadEmailAttachmentArchiveMember, Un as startAgentClaim, Ut as getMemory, V as isAwaitingRejectedError, Vn as setMemory, Vt as getInboxStatus, Wn as startAgentSignup, Wt as getOrgRoutingTopology, X as AUTOMATED_FILTER_UNSUPPORTED_CODE, Xn as updateFunction, Y as parseFromHeader, Yn as updateDefaultNetworkMember, Yt as getWakeSchedule, Z as AUTOMATED_FLAG_DESCRIPTION, Zn as updateKey, Zt as leaveOrganization, _ as describeApiFailure, _n as listSentEmails, _t as createWakeAuthorization, a as REPEAT_IDLE_MAX_MINUTES, an as listEmailAttachmentArchiveMembers, at as hasAutomatedVerdict, b as retryTransient, bn as listWakeSchedules, cn as listFunctionLogs, ct as cancelSentEmail, d as parseRepeatTick, dn as listKeys, dt as cliLogout, en as listAgentNetworks, er as updateWakeAuthorization, et as assertAutomatedVerdict, f as preparePresenceAliveEmail, fn as listMailboxAccess, ft as completeWebhookEvent, g as WaitDeadlineReached, gn as listSentAttachmentArchiveMembers, gt as createRoute, hn as listRoutes, ht as createKey, i as REPEAT_EVERY_MAX_MINUTES, in as listDomains, j as AWAITING_FLAG_DESCRIPTION, jn as revokeCredential, jt as getAccount, k as sinceFromFlags, kn as replyToEmail, kt as downloadSentAttachmentByFilename, l as parseInteractionEnvelope, ln as listFunctions, lt as cancelSentEmailByIdempotencyKey, m as repeatStopCommand, mn as listRoles, mt as createFunction, nn as listDefaultNetworkAgents, nr as verifyAgentClaim, o as REPEAT_MAX_SENDS_MAX, on as listEmails, ot as isAutomatedRejectedError, p as prepareSignalEmail, pn as listRepeatingSends, pt as createEndpoint, qn as testFunction, qt as getSentEmail, rn as listDefaultNetworkMembers, rr as verifyAgentSignup, s as buildRepeatStopBody, sn as listEndpoints, st as addDefaultNetworkMember, tr as updateWakeSchedule, tt as automatedRejectedError, u as parsePresenceEnvelope, un as listGroups, ut as checkDefaultNetworkContactAdmission, vn as listWakeAuthorizations, vt as createWakeSchedule, w as cursorFromAcceptedRows, wt as deleteWakeSchedule, x as retryingOperation, xn as pollCliLogin, xt as deleteMemory, y as pauseForTransientFailure, yn as listWakeDispatches, z as formatRepliesCell, zn as setFunctionRoute, zt as getFunctionRouting } from "../repeats-Dj_o6c-X-BKHiZsYv.js";
|
|
3
|
+
import { S as readBundledConnectSkill, _ as NotificationOutcomeUnknownError, a as NotificationRetryError, b as installedConnectSkillFile, c as readConversationStatusContent, d as SESSION_UUID$1, g as NativeSessionNotLoadedError, h as NativeSessionError, i as notificationReceiptPage, l as createListenHandler, m as NativeSessionDisconnectedError, n as notificationSenders, o as isRoutineNotificationContent, p as defaultSessionSocket, r as openSessionNotifications, s as notificationPartReader, t as notificationScope, u as readableDelivery, v as connectSkillTarget, x as installedVersion, y as installConnectSkill } from "../notify-session-8Jv4jJzI.js";
|
|
4
4
|
import { A as AGENT_ADDRESS_ENV, C as saveCliCredentials, D as loadActiveChatState, E as deleteChatState, F as agentProfilesDirectory, H as requireDefaultLoginProfile, M as AgentConnectionSetupError, N as agentProfileDirectory, O as loadChatConversationByLocalId, P as agentProfileName, R as loadConnectedAgentProfile, S as resolveCliAuth, T as chatStatePath, W as PrimitiveApiClient, _ as deleteCliCredentials, a as normalizeCliEnvironmentName, b as loadCliCredentials, c as resolveConfigEnvironment, g as credentialsPath, h as credentialsLockPath, i as loadCliConfig, j as AGENT_PROFILE_ENV, k as saveActiveChatState, l as saveCliConfig, m as cliAccessTokenExpiresAt, n as deleteCliConfig, o as redactCliEnvironment, p as acquireCliCredentialsLock, r as emptyCliConfig, s as removeCliEnvironment, u as upsertCliEnvironment, v as deleteCliCredentialsLock, w as saveSignupCredentials, y as detectPrimitiveKeyEnvMisname } from "../cli-config-Ms_0vNjq.js";
|
|
5
5
|
import { C as resolveListenSubscription, S as normalizeListenOrigin, _ as acquireListenLock, a as mailLockBusy, c as mailTime, d as readMailJson, f as removeMailFile, g as ListenStateError, h as writeMailJson, i as mailId, l as privateMailDirectory, m as withMailLock, o as mailObject, u as privateMailPermissions, y as listenIdentity } from "../shared-mail-files-BAQSGxxz.js";
|
|
6
|
-
import { $ as saveConnectionName, A as ContactPolicyReadRetryError, B as AddressNotesApiError, C as RECEIVER_MODES, Ct as upsertManagedBlock, D as registrationSummary, Dt as refreshOwnerMemberAddressPeriodically, E as failedSessionRegistration, Et as addSessionReceiver, F as canonicalContactSelector, G as contactAgentAddress, H as runAddressNotesRequest, I as AgentDisconnectError, J as agentInvitationHash, K as runContactRequest, L as claimOverRevokedSetup, M as NetworkAdmissionPendingError, N as createNotificationContactPolicy, O as registrationSummaryLine, Ot as withOwnerMemberAddress, P as evaluateContactPolicy, Q as refusalAfterReplacement, R as clearRevokedAddresses, S as runAgentConnect, St as readManagedFile, T as verificationReplySubmitted, Tt as readHookLauncherWarning, U as ContactsApiError, V as addressNoteTarget, W as contactAddress, X as readAgentInvitation, Y as connectAgent, Z as receiverStatusCommand, _ as enrollmentResumes, _t as samePath, a as endSession, at as boundSessionProfiles, b as invitationProfileName, bt as inspectManagedBlock, c as pendingSessionDisconnects, ct as describeSessionHookChange, d as registerSession, dt as ephemeralCliReason, et as savedReceiver, f as retryPendingDisconnects, ft as findOnPath, g as enrollAgent, gt as repairClaudeHooks, h as staleSessionAgents, ht as readClaudeSettings, i as connectedProfilesForSession, it as recordHookMailCheck, j as NETWORK_ADMISSION_PENDING_RETRY_MS, k as waitForRegistrations, l as psProcessInfo, lt as describeSessionHookItem, m as runDetached, mt as inspectClaudeHooks, n as OMP_MAIN, nt as releaseRegistrationsForProfile, o as headlessClaudeRun, ot as claudeConfigDir, p as revokeStaleSessionAgents, pt as hasMachineSessionHooks, q as agentConnectionStatus, r as agentConnectionState, rt as installClaudeWakeHook, st as currentCliLocation, t as HOOK_END_GRACE_MS, tt as MACHINE_RUNTIMES, u as readClaudeHookInput, ut as ensureHookLauncher, v as connectWarnings, vt as writeClaudeSettings, w as externalReceivingState, wt as writeManagedFile, x as pollCheckCommand, xt as jsonIndentation, y as defaultAgentProfileName, yt as MachineFileError, z as disconnectAgent } from "../machine-session-
|
|
7
|
-
import { a as readBeforeDeadline, c as readPresenceProjection, i as readApiBeforeDeadline, n as isPlainChatReply, o as scopedChatSenderTrust, r as isScopedChatReply, s as presenceDisposition, t as isConnectedChatCredential } from "../scoped-chat-
|
|
6
|
+
import { $ as saveConnectionName, A as ContactPolicyReadRetryError, B as AddressNotesApiError, C as RECEIVER_MODES, Ct as upsertManagedBlock, D as registrationSummary, Dt as refreshOwnerMemberAddressPeriodically, E as failedSessionRegistration, Et as addSessionReceiver, F as canonicalContactSelector, G as contactAgentAddress, H as runAddressNotesRequest, I as AgentDisconnectError, J as agentInvitationHash, K as runContactRequest, L as claimOverRevokedSetup, M as NetworkAdmissionPendingError, N as createNotificationContactPolicy, O as registrationSummaryLine, Ot as withOwnerMemberAddress, P as evaluateContactPolicy, Q as refusalAfterReplacement, R as clearRevokedAddresses, S as runAgentConnect, St as readManagedFile, T as verificationReplySubmitted, Tt as readHookLauncherWarning, U as ContactsApiError, V as addressNoteTarget, W as contactAddress, X as readAgentInvitation, Y as connectAgent, Z as receiverStatusCommand, _ as enrollmentResumes, _t as samePath, a as endSession, at as boundSessionProfiles, b as invitationProfileName, bt as inspectManagedBlock, c as pendingSessionDisconnects, ct as describeSessionHookChange, d as registerSession, dt as ephemeralCliReason, et as savedReceiver, f as retryPendingDisconnects, ft as findOnPath, g as enrollAgent, gt as repairClaudeHooks, h as staleSessionAgents, ht as readClaudeSettings, i as connectedProfilesForSession, it as recordHookMailCheck, j as NETWORK_ADMISSION_PENDING_RETRY_MS, k as waitForRegistrations, l as psProcessInfo, lt as describeSessionHookItem, m as runDetached, mt as inspectClaudeHooks, n as OMP_MAIN, nt as releaseRegistrationsForProfile, o as headlessClaudeRun, ot as claudeConfigDir, p as revokeStaleSessionAgents, pt as hasMachineSessionHooks, q as agentConnectionStatus, r as agentConnectionState, rt as installClaudeWakeHook, st as currentCliLocation, t as HOOK_END_GRACE_MS, tt as MACHINE_RUNTIMES, u as readClaudeHookInput, ut as ensureHookLauncher, v as connectWarnings, vt as writeClaudeSettings, w as externalReceivingState, wt as writeManagedFile, x as pollCheckCommand, xt as jsonIndentation, y as defaultAgentProfileName, yt as MachineFileError, z as disconnectAgent } from "../machine-session-BG4getHB.js";
|
|
7
|
+
import { a as readBeforeDeadline, c as readPresenceProjection, i as readApiBeforeDeadline, n as isPlainChatReply, o as scopedChatSenderTrust, r as isScopedChatReply, s as presenceDisposition, t as isConnectedChatCredential } from "../scoped-chat-_AEpylPV.js";
|
|
8
8
|
import { autoSignalEligible, dispatchAutoRead, dispatchAutoWorking, haltAutoWorking, isSentSignal, readWorkingLease, restoreAutoWorking } from "./auto-signals.js";
|
|
9
|
-
import { a as ensureSharedMailSubscription, c as isConnectedAgentKey, d as reserveSharedMailSubscription, f as followEmailConversation, g as EventReceiverError, h as EventConnection, i as sharedMailScope, l as createSharedMailWaiter, m as otherParticipants, n as reconcileChatSend, p as readConversationFollow, r as openSharedMailReceiver, s as AGENT_CONNECTION_REQUIRED_MESSAGE, t as sendSignal, u as openSharedMailStore } from "../signal-command-
|
|
10
|
-
import { n as
|
|
9
|
+
import { a as ensureSharedMailSubscription, c as isConnectedAgentKey, d as reserveSharedMailSubscription, f as followEmailConversation, g as EventReceiverError, h as EventConnection, i as sharedMailScope, l as createSharedMailWaiter, m as otherParticipants, n as reconcileChatSend, p as readConversationFollow, r as openSharedMailReceiver, s as AGENT_CONNECTION_REQUIRED_MESSAGE, t as sendSignal, u as openSharedMailStore } from "../signal-command-CBHAR7zj.js";
|
|
10
|
+
import { i as runStreamingJson, n as guardJsonOutputCommands, r as jsonOutputRequested, t as JSON_OUTPUT_FLAG } from "../json-output-DWrJMakZ.js";
|
|
11
11
|
import { c as startBackgroundListen, i as backgroundListenToken, l as stopBackgroundListen, o as runBackgroundListen, r as backgroundListenStatus, u as verifyBackgroundListenTarget } from "../listen-background-C0F9gNDD.js";
|
|
12
12
|
import { ORG_SELECTION_ENV } from "./global-org-flag.js";
|
|
13
13
|
import { n as createConfig, t as createClient } from "../client.gen-6rZvmHfx.js";
|
|
@@ -172,7 +172,7 @@ const openapiDocument = {
|
|
|
172
172
|
},
|
|
173
173
|
{
|
|
174
174
|
"name": "Mailbox access",
|
|
175
|
-
"description": "Who may read, draft and send for each mailbox, and the groups access can be given to. Readable by people and org-wide API keys; changed by a dashboard session, an org-wide API key, or the person's own Primitive CLI. Other OAuth apps need a session step-up to change it. Answers 404 feature_disabled while
|
|
175
|
+
"description": "Who may read, draft and send for each mailbox, and the groups access can be given to. Readable by people and org-wide API keys; changed by a dashboard session, an org-wide API key, or the person's own Primitive CLI. Other OAuth apps need a session step-up to change it. Answers 404 feature_disabled, with details.feature naming the feature (mailbox_access, or roles for groups), while it is not enabled for the organization; only Primitive turns it on.",
|
|
176
176
|
"x-openapi-spec": "https://api.primitive.dev/v1/openapi/tags/mailbox-access"
|
|
177
177
|
},
|
|
178
178
|
{
|
|
@@ -187,7 +187,7 @@ const openapiDocument = {
|
|
|
187
187
|
},
|
|
188
188
|
{
|
|
189
189
|
"name": "Roles and members",
|
|
190
|
-
"description": "Roles, member roles and removal, the mailbox access mode, break-glass, transfers and suspensions. Reads are open to people; every write is person only: a dashboard session, or the person's own OAuth or CLI token with a session step-up. API keys never reach these. Answers 404 feature_disabled while the feature is not enabled for the organization.",
|
|
190
|
+
"description": "Roles, member roles and removal, the mailbox access mode, break-glass, transfers and suspensions. Reads are open to people; every write is person only: a dashboard session, or the person's own OAuth or CLI token with a session step-up. API keys never reach these. Answers 404 feature_disabled while the feature is not enabled for the organization, with details.feature naming the feature; only Primitive turns it on.",
|
|
191
191
|
"x-openapi-spec": "https://api.primitive.dev/v1/openapi/tags/roles-and-members"
|
|
192
192
|
},
|
|
193
193
|
{
|
|
@@ -20885,7 +20885,7 @@ const openapiDocument = {
|
|
|
20885
20885
|
}
|
|
20886
20886
|
},
|
|
20887
20887
|
"403": {
|
|
20888
|
-
"description": "feature_disabled: interactions (or, for wake.dispatch, Wake dispatch) are not enabled for this organization; grant_forbidden: the credential does not hold the permission",
|
|
20888
|
+
"description": "feature_disabled: interactions (or, for wake.dispatch, Wake dispatch) are not enabled for this organization, and details.feature is interactions or wake_dispatch; only Primitive turns them on. grant_forbidden: the credential does not hold the permission",
|
|
20889
20889
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
20890
20890
|
},
|
|
20891
20891
|
"429": {
|
|
@@ -20972,7 +20972,7 @@ const openapiDocument = {
|
|
|
20972
20972
|
}
|
|
20973
20973
|
},
|
|
20974
20974
|
"403": {
|
|
20975
|
-
"description": "feature_disabled: interactions (or, for wake.dispatch, Wake dispatch) are not enabled for this organization; grant_forbidden: the credential does not hold the permission",
|
|
20975
|
+
"description": "feature_disabled: interactions (or, for wake.dispatch, Wake dispatch) are not enabled for this organization, and details.feature is interactions or wake_dispatch; only Primitive turns them on. grant_forbidden: the credential does not hold the permission",
|
|
20976
20976
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
20977
20977
|
},
|
|
20978
20978
|
"429": {
|
|
@@ -21064,7 +21064,7 @@ const openapiDocument = {
|
|
|
21064
21064
|
}
|
|
21065
21065
|
},
|
|
21066
21066
|
"403": {
|
|
21067
|
-
"description": "feature_disabled: interactions (or, for wake.dispatch, Wake dispatch) are not enabled for this organization; grant_forbidden: the credential does not hold the permission",
|
|
21067
|
+
"description": "feature_disabled: interactions (or, for wake.dispatch, Wake dispatch) are not enabled for this organization, and details.feature is interactions or wake_dispatch; only Primitive turns them on. grant_forbidden: the credential does not hold the permission",
|
|
21068
21068
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
21069
21069
|
},
|
|
21070
21070
|
"404": {
|
|
@@ -21184,7 +21184,7 @@ const openapiDocument = {
|
|
|
21184
21184
|
}
|
|
21185
21185
|
},
|
|
21186
21186
|
"403": {
|
|
21187
|
-
"description": "feature_disabled: interactions (or, for wake.dispatch, Wake dispatch) are not enabled for this organization; grant_forbidden: the credential does not hold the permission",
|
|
21187
|
+
"description": "feature_disabled: interactions (or, for wake.dispatch, Wake dispatch) are not enabled for this organization, and details.feature is interactions or wake_dispatch; only Primitive turns them on. grant_forbidden: the credential does not hold the permission",
|
|
21188
21188
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
21189
21189
|
},
|
|
21190
21190
|
"404": {
|
|
@@ -21648,7 +21648,7 @@ const openapiDocument = {
|
|
|
21648
21648
|
"/email-rules/test": { "post": {
|
|
21649
21649
|
"operationId": "testEmailRule",
|
|
21650
21650
|
"summary": "Test a rule against received mail",
|
|
21651
|
-
"description": "Runs a rule over received mail and reports what it would decide for each email: matched, near_miss, no_match, unclassified or not_found. Test an unsaved tree from a compile response, or a saved rule by rule_id (its current version, run with its author's access). Either way the rule reads only mail its author can read. Without email_ids, the newest emails it can read are tested, at most 200 and none older than 30 days. Emails not classified yet that arrived more than 2 hours ago are classified first and their classification is saved, unless classify_missing is false; newer ones are left to normal classification and reported unclassified with reason pending. The rule itself records nothing and grants nothing. Classification and the rule's own questions stop at about 90 seconds; run the test again to continue where it stopped. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
21651
|
+
"description": "Runs a rule over received mail and reports what it would decide for each email: matched, near_miss, no_match, unclassified or not_found. Test an unsaved tree from a compile response, or a saved rule by rule_id (its current version, run with its author's access). Either way the rule reads only mail its author can read, and only what its scope covers; an unsaved tree covers only your own mail unless evaluation_scope names more. Without email_ids, the newest emails it can read are tested, at most 200 and none older than 30 days. Emails not classified yet that arrived more than 2 hours ago are classified first and their classification is saved, unless classify_missing is false; newer ones are left to normal classification and reported unclassified with reason pending. The rule itself records nothing and grants nothing. Classification and the rule's own questions stop at about 90 seconds; run the test again to continue where it stopped. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
21652
21652
|
"tags": ["Email Rules"],
|
|
21653
21653
|
"security": [{ "BearerAuth": [] }],
|
|
21654
21654
|
"requestBody": {
|
|
@@ -21671,7 +21671,7 @@ const openapiDocument = {
|
|
|
21671
21671
|
}
|
|
21672
21672
|
},
|
|
21673
21673
|
"400": {
|
|
21674
|
-
"description": "validation_error: give exactly one of tree and rule_id, at most 200 email_ids, and a tree that is valid for the column contract. A saved rule whose current version no longer renders answers details.reason version_not_renderable.",
|
|
21674
|
+
"description": "validation_error: give exactly one of tree and rule_id, at most 200 email_ids, and a tree that is valid for the column contract. evaluation_scope, scope_selection and kind go only with tree. A saved rule whose current version no longer renders answers details.reason version_not_renderable.",
|
|
21675
21675
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
21676
21676
|
},
|
|
21677
21677
|
"401": {
|
|
@@ -21694,7 +21694,7 @@ const openapiDocument = {
|
|
|
21694
21694
|
}
|
|
21695
21695
|
},
|
|
21696
21696
|
"403": {
|
|
21697
|
-
"description": "feature_not_enabled: the email rules feature is not enabled for this organization yet. Permission refusals answer forbidden or grant_forbidden instead. grant_forbidden with details.reason mail_depth: your access to mail shows headers only, and a rule decides on what emails say.",
|
|
21697
|
+
"description": "feature_not_enabled: the email rules feature is not enabled for this organization yet. Permission refusals answer forbidden or grant_forbidden instead. grant_forbidden with details.reason mail_depth: your access to mail shows headers only, and a rule decides on what emails say. email_rule_scope_not_readable: scope_selection names something you cannot read.",
|
|
21698
21698
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
21699
21699
|
},
|
|
21700
21700
|
"404": {
|
|
@@ -21702,7 +21702,7 @@ const openapiDocument = {
|
|
|
21702
21702
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
21703
21703
|
},
|
|
21704
21704
|
"409": {
|
|
21705
|
-
"description": "email_rule_author_unresolvable: the rule cannot run as its author (for an unsaved tree, the caller). details.reason is left, revoked, suspended, membership_ended, no_mail_read, no_own_mailbox or
|
|
21705
|
+
"description": "email_rule_author_unresolvable: the rule cannot run as its author (for an unsaved tree, the caller). details.reason is left, revoked, suspended, membership_ended, no_mail_read, no_own_mailbox, no_shareable_mailbox or no_selected_mailbox.",
|
|
21706
21706
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
21707
21707
|
},
|
|
21708
21708
|
"429": {
|
|
@@ -21745,7 +21745,7 @@ const openapiDocument = {
|
|
|
21745
21745
|
"/email-rules/test-sample": { "post": {
|
|
21746
21746
|
"operationId": "testEmailRuleOnSample",
|
|
21747
21747
|
"summary": "Test a rule against a made-up email",
|
|
21748
|
-
"description": "Reports what a rule would decide for an email you describe: its sender, recipients, subject, plain text and attachment types, and optionally whether it is automated or from a mailing list and its spam score. The email is classified the way received mail is, and the rule's conditions and its own questions are decided as they would be for received mail with that content and those signals, received now. Without them it is not automated and not from a mailing list; a rule that reads a spam score you gave none for is decided on no score, and spam_score is listed in unset_columns. Nothing is stored: no email, classification or decision. Test an unsaved tree from a compile response, or a saved rule by rule_id (its current version). The answer includes what the classifier read from the email. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
21748
|
+
"description": "Reports what a rule would decide for an email you describe: its sender, recipients, subject, plain text and attachment types, and optionally whether it is automated or from a mailing list and its spam score. The email is classified the way received mail is, and the rule's conditions and its own questions are decided as they would be for received mail with that content and those signals, received now. Without them it is not automated and not from a mailing list; a rule that reads a spam score you gave none for is decided on no score, and spam_score is listed in unset_columns. Nothing is stored: no email, classification or decision. Test an unsaved tree from a compile response, or a saved rule by rule_id (its current version); an unsaved tree is run as covering only your own mail unless evaluation_scope names more, as on POST /email-rules/test. The answer includes what the classifier read from the email. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
21749
21749
|
"tags": ["Email Rules"],
|
|
21750
21750
|
"security": [{ "BearerAuth": [] }],
|
|
21751
21751
|
"requestBody": {
|
|
@@ -21768,7 +21768,7 @@ const openapiDocument = {
|
|
|
21768
21768
|
}
|
|
21769
21769
|
},
|
|
21770
21770
|
"400": {
|
|
21771
|
-
"description": "validation_error: give exactly one of tree and rule_id, an email with a sender, 1 to 50 To addresses (and up to 50 Cc), and a text body, and a tree that is valid for the column contract and within the size limits for a saved rule. A saved rule whose current version no longer renders answers details.reason version_not_renderable.",
|
|
21771
|
+
"description": "validation_error: give exactly one of tree and rule_id (evaluation_scope, scope_selection and kind only with tree), an email with a sender, 1 to 50 To addresses (and up to 50 Cc), and a text body, and a tree that is valid for the column contract and within the size limits for a saved rule. A saved rule whose current version no longer renders answers details.reason version_not_renderable.",
|
|
21772
21772
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
21773
21773
|
},
|
|
21774
21774
|
"401": {
|
|
@@ -21791,7 +21791,7 @@ const openapiDocument = {
|
|
|
21791
21791
|
}
|
|
21792
21792
|
},
|
|
21793
21793
|
"403": {
|
|
21794
|
-
"description": "feature_not_enabled: the email rules feature is not enabled for this organization yet. Permission refusals answer forbidden or grant_forbidden instead.",
|
|
21794
|
+
"description": "feature_not_enabled: the email rules feature is not enabled for this organization yet. Permission refusals answer forbidden or grant_forbidden instead. email_rule_scope_not_readable: scope_selection names something you cannot read.",
|
|
21795
21795
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
21796
21796
|
},
|
|
21797
21797
|
"404": {
|
|
@@ -21799,7 +21799,7 @@ const openapiDocument = {
|
|
|
21799
21799
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
21800
21800
|
},
|
|
21801
21801
|
"409": {
|
|
21802
|
-
"description": "email_rule_author_unresolvable: the rule cannot run as its author (for an unsaved tree, you), so it would decide nothing for real. details.reason is left, revoked, suspended, membership_ended, no_mail_read, no_own_mailbox or
|
|
21802
|
+
"description": "email_rule_author_unresolvable: the rule cannot run as its author (for an unsaved tree, you), so it would decide nothing for real. details.reason is left, revoked, suspended, membership_ended, no_mail_read, no_own_mailbox, no_shareable_mailbox or no_selected_mailbox.",
|
|
21803
21803
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
21804
21804
|
},
|
|
21805
21805
|
"429": {
|
|
@@ -21843,7 +21843,7 @@ const openapiDocument = {
|
|
|
21843
21843
|
"post": {
|
|
21844
21844
|
"operationId": "createEmailRule",
|
|
21845
21845
|
"summary": "Create a rule",
|
|
21846
|
-
"description": "Saves a rule as version 1, from a compile response or a tree you wrote. The tree is checked against the column contract. New rules start in observe, where what the rule matches is recorded and nothing is granted; draft is not evaluated. The caller is the rule's author, and the rule never reaches mail the author cannot read. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
21846
|
+
"description": "Saves a rule as version 1, from a compile response or a tree you wrote. The tree is checked against the column contract. New rules start in observe, where what the rule matches is recorded and nothing is granted or blocked; draft is not evaluated. The caller is the rule's author, and the rule never reaches mail the author cannot read. evaluation_scope chooses whose mail it runs over: own_mailboxes (only your own mail) when omitted, so any other scope (author for all you can read, or selected) is named; scope_selection may name only what you can read. The answer carries the scope as stored. kind do_not_share makes a rule that blocks sharing: it runs before every other rule, and while it is active no rule shares an email it matches or cannot decide. A key cannot list one (details.reason rule_blocks_sharing on the key). Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
21847
21847
|
"tags": ["Email Rules"],
|
|
21848
21848
|
"security": [{ "BearerAuth": [] }],
|
|
21849
21849
|
"requestBody": {
|
|
@@ -21892,7 +21892,11 @@ const openapiDocument = {
|
|
|
21892
21892
|
}
|
|
21893
21893
|
},
|
|
21894
21894
|
"403": {
|
|
21895
|
-
"description": "feature_not_enabled: the email rules feature is not enabled for this organization yet. Permission refusals answer forbidden or grant_forbidden instead.",
|
|
21895
|
+
"description": "feature_not_enabled: the email rules feature is not enabled for this organization yet. Permission refusals answer forbidden or grant_forbidden instead. email_rule_scope_not_readable: scope_selection names something you cannot read (details.addresses, details.domains).",
|
|
21896
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
21897
|
+
},
|
|
21898
|
+
"409": {
|
|
21899
|
+
"description": "email_rule_author_unresolvable: the rule could not run as you over the chosen scope. details.reason is left, revoked, suspended, membership_ended, no_mail_read, no_own_mailbox or no_shareable_mailbox. With no evaluation_scope it covers only your own mail, so no_own_mailbox or no_shareable_mailbox there means a scope must be named.",
|
|
21896
21900
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
21897
21901
|
},
|
|
21898
21902
|
"429": {
|
|
@@ -21935,7 +21939,7 @@ const openapiDocument = {
|
|
|
21935
21939
|
"get": {
|
|
21936
21940
|
"operationId": "listEmailRules",
|
|
21937
21941
|
"summary": "List rules",
|
|
21938
|
-
"description": "The rules the caller can see, newest first: their own, or every member's rules for a caller who reads the whole organization's mail. With matched_email_id, only the rules that matched that email. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
21942
|
+
"description": "The rules the caller can see, newest first: their own, or every member's rules for a caller who reads the whole organization's mail. Each carries its scope (evaluation_scope, and scope_selection for a selected rule). With matched_email_id, only the rules that matched that email. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
21939
21943
|
"tags": ["Email Rules"],
|
|
21940
21944
|
"security": [{ "BearerAuth": [] }],
|
|
21941
21945
|
"parameters": [
|
|
@@ -22055,7 +22059,7 @@ const openapiDocument = {
|
|
|
22055
22059
|
"get": {
|
|
22056
22060
|
"operationId": "getEmailRule",
|
|
22057
22061
|
"summary": "Read a rule",
|
|
22058
|
-
"description": "A rule and its current version. The SQL the version renders to is included only when include_sql is true. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
22062
|
+
"description": "A rule, its scope (evaluation_scope, and scope_selection for a selected rule) and its current version. What the scope comes to for its author now is GET /email-rules/{id}/scope. The SQL the version renders to is included only when include_sql is true. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
22059
22063
|
"tags": ["Email Rules"],
|
|
22060
22064
|
"security": [{ "BearerAuth": [] }],
|
|
22061
22065
|
"parameters": [{
|
|
@@ -22170,7 +22174,7 @@ const openapiDocument = {
|
|
|
22170
22174
|
"patch": {
|
|
22171
22175
|
"operationId": "updateEmailRule",
|
|
22172
22176
|
"summary": "Change a rule",
|
|
22173
|
-
"description": "Renames the rule, saves a new version (english, tree and explanation together; earlier versions are kept unchanged)
|
|
22177
|
+
"description": "Renames the rule, saves a new version (english, tree and explanation together; earlier versions are kept unchanged), changes its state (draft, disabled; observe; or active) or changes whose mail it runs over (evaluation_scope, with scope_selection when selected). Only the rule's author may rename it, add a version, change its scope or move it to observe or active; anyone else who can see it may only disable it (state draft), and while it is shared with another member only if they manage members from the dashboard. Omit evaluation_scope to keep the current scope. A scope change saves a new version with the same conditions; what was granted stays. A shared rule keeps its scope. A rule's kind never changes. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
22174
22178
|
"tags": ["Email Rules"],
|
|
22175
22179
|
"security": [{ "BearerAuth": [] }],
|
|
22176
22180
|
"parameters": [{
|
|
@@ -22235,7 +22239,7 @@ const openapiDocument = {
|
|
|
22235
22239
|
}
|
|
22236
22240
|
},
|
|
22237
22241
|
"403": {
|
|
22238
|
-
"description": "feature_not_enabled: the email rules feature is not enabled for this organization yet. Permission refusals answer forbidden or grant_forbidden instead. email_rule_author_only: only the rule's author may make this change. forbidden with details.reason rule_shared: the rule is shared with another member, so only its author, or someone who manages members from the dashboard, can turn it off.",
|
|
22242
|
+
"description": "feature_not_enabled: the email rules feature is not enabled for this organization yet. Permission refusals answer forbidden or grant_forbidden instead. email_rule_author_only: only the rule's author may make this change. forbidden with details.reason rule_shared: the rule is shared with another member, so only its author, or someone who manages members from the dashboard, can turn it off. email_rule_scope_not_readable: scope_selection names something you cannot read.",
|
|
22239
22243
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22240
22244
|
},
|
|
22241
22245
|
"404": {
|
|
@@ -22252,7 +22256,7 @@ const openapiDocument = {
|
|
|
22252
22256
|
} }
|
|
22253
22257
|
},
|
|
22254
22258
|
"409": {
|
|
22255
|
-
"description": "email_rule_conflict: the rule changed while saving; read it again and retry.",
|
|
22259
|
+
"description": "email_rule_conflict: the rule changed while saving; read it again and retry. email_rule_scope_locked: the rule is shared. email_rule_author_unresolvable: the rule could not run as you over the chosen scope.",
|
|
22256
22260
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22257
22261
|
},
|
|
22258
22262
|
"429": {
|
|
@@ -22516,252 +22520,17 @@ const openapiDocument = {
|
|
|
22516
22520
|
},
|
|
22517
22521
|
"x-primitive-permission": ["mail:read"]
|
|
22518
22522
|
} },
|
|
22519
|
-
"/
|
|
22520
|
-
"
|
|
22521
|
-
|
|
22522
|
-
|
|
22523
|
-
"description": "Asks another member of the organization for a rule over their own mail, from a compile response or a tree you wrote. Name them by user id, or by their member mailbox address (at most 30 lookups by address an hour). Nothing is evaluated and nothing is shared until they accept, and they may change the rule first; they see the request and can preview what it matches in their own mail. You may have at most 5 pending requests to one member and 50 in all. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
22524
|
-
"tags": ["Email Rules"],
|
|
22525
|
-
"security": [{ "BearerAuth": [] }],
|
|
22526
|
-
"requestBody": {
|
|
22527
|
-
"required": true,
|
|
22528
|
-
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateEmailRuleRequestRequest" } } }
|
|
22529
|
-
},
|
|
22530
|
-
"responses": {
|
|
22531
|
-
"201": {
|
|
22532
|
-
"description": "Ask a member for a rule",
|
|
22533
|
-
"content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
|
|
22534
|
-
"type": "object",
|
|
22535
|
-
"required": ["data"],
|
|
22536
|
-
"properties": { "data": { "$ref": "#/components/schemas/CreateEmailRuleRequestResult" } }
|
|
22537
|
-
}] } } }
|
|
22538
|
-
},
|
|
22539
|
-
"400": {
|
|
22540
|
-
"description": "validation_error: give exactly one of target_user_id and target_email and a tree that is valid for the column contract; details.reason self_request when the member named is you.",
|
|
22541
|
-
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22542
|
-
},
|
|
22543
|
-
"401": {
|
|
22544
|
-
"description": "Invalid or missing API key",
|
|
22545
|
-
"content": { "application/json": {
|
|
22546
|
-
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
22547
|
-
"example": {
|
|
22548
|
-
"success": false,
|
|
22549
|
-
"error": {
|
|
22550
|
-
"code": "unauthorized",
|
|
22551
|
-
"message": "Invalid or missing API key"
|
|
22552
|
-
}
|
|
22553
|
-
}
|
|
22554
|
-
} },
|
|
22555
|
-
"headers": {
|
|
22556
|
-
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-unauthenticated" },
|
|
22557
|
-
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-unauthenticated" },
|
|
22558
|
-
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset-unauthenticated" },
|
|
22559
|
-
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-unauthenticated" }
|
|
22560
|
-
}
|
|
22561
|
-
},
|
|
22562
|
-
"403": {
|
|
22563
|
-
"description": "feature_not_enabled: the email rules feature is not enabled for this organization yet. Permission refusals answer forbidden or grant_forbidden instead.",
|
|
22564
|
-
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22565
|
-
},
|
|
22566
|
-
"404": {
|
|
22567
|
-
"description": "not_found: no current member of this organization matches the member named.",
|
|
22568
|
-
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22569
|
-
},
|
|
22570
|
-
"409": {
|
|
22571
|
-
"description": "email_rule_request_limit: you already have the most pending requests allowed (details.limit, and details.scope target or total).",
|
|
22572
|
-
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22573
|
-
},
|
|
22574
|
-
"429": {
|
|
22575
|
-
"description": "Rate limit exceeded. The `ratelimit-*` headers describe the limiter that rejected this request, with its own limit and window, not the API budget that successful responses report. A limiter that reports only a wait sends `Retry-After` alone.",
|
|
22576
|
-
"headers": {
|
|
22577
|
-
"Retry-After": {
|
|
22578
|
-
"schema": { "type": "integer" },
|
|
22579
|
-
"description": "Seconds to wait before retrying"
|
|
22580
|
-
},
|
|
22581
|
-
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-429" },
|
|
22582
|
-
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-429" },
|
|
22583
|
-
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
22584
|
-
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-429" }
|
|
22585
|
-
},
|
|
22586
|
-
"content": { "application/json": {
|
|
22587
|
-
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
22588
|
-
"example": {
|
|
22589
|
-
"success": false,
|
|
22590
|
-
"error": {
|
|
22591
|
-
"code": "rate_limit_exceeded",
|
|
22592
|
-
"message": "Rate limit exceeded"
|
|
22593
|
-
}
|
|
22594
|
-
}
|
|
22595
|
-
} }
|
|
22596
|
-
},
|
|
22597
|
-
"503": {
|
|
22598
|
-
"description": "service_unavailable: looking members up by address is unavailable right now. Try again in a moment, or name them by user id.",
|
|
22599
|
-
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22600
|
-
}
|
|
22601
|
-
},
|
|
22602
|
-
"x-primitive-permission": ["mail:read"],
|
|
22603
|
-
"parameters": [{
|
|
22604
|
-
"name": "Idempotency-Key",
|
|
22605
|
-
"in": "header",
|
|
22606
|
-
"required": false,
|
|
22607
|
-
"description": "Optional, and not used to deduplicate: this operation stores no result by the key, so a retry with the same key runs the request again. Operations that need a credential refuse a key that is empty, longer than 255 characters or not printable ASCII with 400 `validation_error` and echo a valid one in the Idempotency-Key response header; operations that need none ignore it.",
|
|
22608
|
-
"schema": {
|
|
22609
|
-
"type": "string",
|
|
22610
|
-
"minLength": 1,
|
|
22611
|
-
"maxLength": 255
|
|
22612
|
-
}
|
|
22613
|
-
}]
|
|
22614
|
-
},
|
|
22615
|
-
"get": {
|
|
22616
|
-
"operationId": "listEmailRuleRequests",
|
|
22617
|
-
"summary": "List rule requests",
|
|
22618
|
-
"description": "Rule requests, newest first: those made to you (box incoming, the default), those you made (outgoing), or every one you can see (all). Pending ones by default; status decided lists accepted, declined and withdrawn ones, and any lists both. A request is visible to the member who made it, the member it was made to, and the organization's owners and admins. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
22619
|
-
"tags": ["Email Rules"],
|
|
22620
|
-
"security": [{ "BearerAuth": [] }],
|
|
22621
|
-
"parameters": [
|
|
22622
|
-
{
|
|
22623
|
-
"name": "box",
|
|
22624
|
-
"in": "query",
|
|
22625
|
-
"required": false,
|
|
22626
|
-
"description": "incoming, outgoing or all.",
|
|
22627
|
-
"schema": {
|
|
22628
|
-
"default": "incoming",
|
|
22629
|
-
"description": "incoming: requests made to you; outgoing: requests you made; all: every request you can see (owners and admins see the organization's).",
|
|
22630
|
-
"type": "string",
|
|
22631
|
-
"enum": [
|
|
22632
|
-
"incoming",
|
|
22633
|
-
"outgoing",
|
|
22634
|
-
"all"
|
|
22635
|
-
]
|
|
22636
|
-
}
|
|
22637
|
-
},
|
|
22638
|
-
{
|
|
22639
|
-
"name": "status",
|
|
22640
|
-
"in": "query",
|
|
22641
|
-
"required": false,
|
|
22642
|
-
"description": "pending, decided or any.",
|
|
22643
|
-
"schema": {
|
|
22644
|
-
"default": "pending",
|
|
22645
|
-
"type": "string",
|
|
22646
|
-
"enum": [
|
|
22647
|
-
"pending",
|
|
22648
|
-
"decided",
|
|
22649
|
-
"any"
|
|
22650
|
-
]
|
|
22651
|
-
}
|
|
22652
|
-
},
|
|
22653
|
-
{
|
|
22654
|
-
"name": "limit",
|
|
22655
|
-
"in": "query",
|
|
22656
|
-
"required": false,
|
|
22657
|
-
"description": "Maximum number of items to return.",
|
|
22658
|
-
"schema": {
|
|
22659
|
-
"default": 25,
|
|
22660
|
-
"type": "integer",
|
|
22661
|
-
"minimum": 1,
|
|
22662
|
-
"maximum": 100
|
|
22663
|
-
}
|
|
22664
|
-
},
|
|
22665
|
-
{
|
|
22666
|
-
"name": "cursor",
|
|
22667
|
-
"in": "query",
|
|
22668
|
-
"required": false,
|
|
22669
|
-
"description": "Opaque cursor from the previous page's next_cursor. Omit for the first page.",
|
|
22670
|
-
"schema": {
|
|
22671
|
-
"type": "string",
|
|
22672
|
-
"maxLength": 200
|
|
22673
|
-
}
|
|
22674
|
-
}
|
|
22675
|
-
],
|
|
22676
|
-
"responses": {
|
|
22677
|
-
"200": {
|
|
22678
|
-
"description": "List rule requests",
|
|
22679
|
-
"content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
|
|
22680
|
-
"type": "object",
|
|
22681
|
-
"required": ["data"],
|
|
22682
|
-
"properties": { "data": { "$ref": "#/components/schemas/ListEmailRuleRequestsResult" } }
|
|
22683
|
-
}] } } },
|
|
22684
|
-
"headers": {
|
|
22685
|
-
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit" },
|
|
22686
|
-
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining" },
|
|
22687
|
-
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
22688
|
-
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy" }
|
|
22689
|
-
}
|
|
22690
|
-
},
|
|
22691
|
-
"400": {
|
|
22692
|
-
"description": "Invalid request parameters",
|
|
22693
|
-
"content": { "application/json": {
|
|
22694
|
-
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
22695
|
-
"example": {
|
|
22696
|
-
"success": false,
|
|
22697
|
-
"error": {
|
|
22698
|
-
"code": "validation_error",
|
|
22699
|
-
"message": "Invalid domain format"
|
|
22700
|
-
}
|
|
22701
|
-
}
|
|
22702
|
-
} }
|
|
22703
|
-
},
|
|
22704
|
-
"401": {
|
|
22705
|
-
"description": "Invalid or missing API key",
|
|
22706
|
-
"content": { "application/json": {
|
|
22707
|
-
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
22708
|
-
"example": {
|
|
22709
|
-
"success": false,
|
|
22710
|
-
"error": {
|
|
22711
|
-
"code": "unauthorized",
|
|
22712
|
-
"message": "Invalid or missing API key"
|
|
22713
|
-
}
|
|
22714
|
-
}
|
|
22715
|
-
} },
|
|
22716
|
-
"headers": {
|
|
22717
|
-
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-unauthenticated" },
|
|
22718
|
-
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-unauthenticated" },
|
|
22719
|
-
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset-unauthenticated" },
|
|
22720
|
-
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-unauthenticated" }
|
|
22721
|
-
}
|
|
22722
|
-
},
|
|
22723
|
-
"403": {
|
|
22724
|
-
"description": "feature_not_enabled: the email rules feature is not enabled for this organization yet. Permission refusals answer forbidden or grant_forbidden instead.",
|
|
22725
|
-
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22726
|
-
},
|
|
22727
|
-
"429": {
|
|
22728
|
-
"description": "Rate limit exceeded. The `ratelimit-*` headers describe the limiter that rejected this request, with its own limit and window, not the API budget that successful responses report. A limiter that reports only a wait sends `Retry-After` alone.",
|
|
22729
|
-
"headers": {
|
|
22730
|
-
"Retry-After": {
|
|
22731
|
-
"schema": { "type": "integer" },
|
|
22732
|
-
"description": "Seconds to wait before retrying"
|
|
22733
|
-
},
|
|
22734
|
-
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-429" },
|
|
22735
|
-
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-429" },
|
|
22736
|
-
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
22737
|
-
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-429" }
|
|
22738
|
-
},
|
|
22739
|
-
"content": { "application/json": {
|
|
22740
|
-
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
22741
|
-
"example": {
|
|
22742
|
-
"success": false,
|
|
22743
|
-
"error": {
|
|
22744
|
-
"code": "rate_limit_exceeded",
|
|
22745
|
-
"message": "Rate limit exceeded"
|
|
22746
|
-
}
|
|
22747
|
-
}
|
|
22748
|
-
} }
|
|
22749
|
-
}
|
|
22750
|
-
},
|
|
22751
|
-
"x-primitive-permission": ["mail:read"]
|
|
22752
|
-
}
|
|
22753
|
-
},
|
|
22754
|
-
"/email-rule-requests/{id}": { "get": {
|
|
22755
|
-
"operationId": "getEmailRuleRequest",
|
|
22756
|
-
"summary": "Read a rule request",
|
|
22757
|
-
"description": "A rule request: the rule as proposed, who made it and to whom, and whether each of them is still a member. A request is visible to the member who made it, the member it was made to, and the organization's owners and admins. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
22523
|
+
"/emails/{id}/rule-results": { "get": {
|
|
22524
|
+
"operationId": "listEmailRuleResults",
|
|
22525
|
+
"summary": "List every rule's result on an email",
|
|
22526
|
+
"description": "Every rule the caller can see and what it decided about this email: those that matched, those that did not, and those that have not run on it, with what is known about them. A result names the version of the rule that decided and carries that version's conditions and questions. A matched rule with kind do_not_share keeps rules from sharing the email while it is active; anything shared before then stays shared. Only a caller who can read the email gets an answer, and a rule the caller cannot see is left out. At most 50 rules are listed, those with a result first; hidden counts the rest. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
22758
22527
|
"tags": ["Email Rules"],
|
|
22759
22528
|
"security": [{ "BearerAuth": [] }],
|
|
22760
22529
|
"parameters": [{
|
|
22761
22530
|
"name": "id",
|
|
22762
22531
|
"in": "path",
|
|
22763
22532
|
"required": true,
|
|
22764
|
-
"description": "The
|
|
22533
|
+
"description": "The email id.",
|
|
22765
22534
|
"schema": {
|
|
22766
22535
|
"type": "string",
|
|
22767
22536
|
"format": "uuid"
|
|
@@ -22769,11 +22538,11 @@ const openapiDocument = {
|
|
|
22769
22538
|
}],
|
|
22770
22539
|
"responses": {
|
|
22771
22540
|
"200": {
|
|
22772
|
-
"description": "
|
|
22541
|
+
"description": "List every rule's result on an email",
|
|
22773
22542
|
"content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
|
|
22774
22543
|
"type": "object",
|
|
22775
22544
|
"required": ["data"],
|
|
22776
|
-
"properties": { "data": { "$ref": "#/components/schemas/
|
|
22545
|
+
"properties": { "data": { "$ref": "#/components/schemas/ListEmailRuleResultsResult" } }
|
|
22777
22546
|
}] } } },
|
|
22778
22547
|
"headers": {
|
|
22779
22548
|
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit" },
|
|
@@ -22806,7 +22575,7 @@ const openapiDocument = {
|
|
|
22806
22575
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22807
22576
|
},
|
|
22808
22577
|
"404": {
|
|
22809
|
-
"description": "not_found: no
|
|
22578
|
+
"description": "not_found: no such email, or not one the caller can read.",
|
|
22810
22579
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22811
22580
|
},
|
|
22812
22581
|
"429": {
|
|
@@ -22835,39 +22604,39 @@ const openapiDocument = {
|
|
|
22835
22604
|
},
|
|
22836
22605
|
"x-primitive-permission": ["mail:read"]
|
|
22837
22606
|
} },
|
|
22838
|
-
"/email-
|
|
22839
|
-
"operationId": "
|
|
22840
|
-
"summary": "
|
|
22841
|
-
"description": "
|
|
22607
|
+
"/email-rules/{id}/versions": { "get": {
|
|
22608
|
+
"operationId": "listEmailRuleVersions",
|
|
22609
|
+
"summary": "Read versions of a rule",
|
|
22610
|
+
"description": "The named versions of a rule, as they were written: what each one's conditions and questions were, so a decision can be read against the version that made it. Numbers that are not versions of the rule are left out. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
22842
22611
|
"tags": ["Email Rules"],
|
|
22843
22612
|
"security": [{ "BearerAuth": [] }],
|
|
22844
22613
|
"parameters": [{
|
|
22845
22614
|
"name": "id",
|
|
22846
22615
|
"in": "path",
|
|
22847
22616
|
"required": true,
|
|
22848
|
-
"description": "The
|
|
22617
|
+
"description": "The rule id.",
|
|
22849
22618
|
"schema": {
|
|
22850
22619
|
"type": "string",
|
|
22851
22620
|
"format": "uuid"
|
|
22852
22621
|
}
|
|
22853
22622
|
}, {
|
|
22854
|
-
"name": "
|
|
22855
|
-
"in": "
|
|
22856
|
-
"required":
|
|
22857
|
-
"description": "
|
|
22623
|
+
"name": "versions",
|
|
22624
|
+
"in": "query",
|
|
22625
|
+
"required": true,
|
|
22626
|
+
"description": "The version numbers, comma-separated, at most 100.",
|
|
22858
22627
|
"schema": {
|
|
22859
22628
|
"type": "string",
|
|
22860
|
-
"
|
|
22861
|
-
"
|
|
22629
|
+
"pattern": "^[1-9]\\d{0,8}(,[1-9]\\d{0,8}){0,99}$",
|
|
22630
|
+
"description": "The version numbers to read, comma-separated."
|
|
22862
22631
|
}
|
|
22863
22632
|
}],
|
|
22864
22633
|
"responses": {
|
|
22865
22634
|
"200": {
|
|
22866
|
-
"description": "
|
|
22635
|
+
"description": "Read versions of a rule",
|
|
22867
22636
|
"content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
|
|
22868
22637
|
"type": "object",
|
|
22869
22638
|
"required": ["data"],
|
|
22870
|
-
"properties": { "data": { "$ref": "#/components/schemas/
|
|
22639
|
+
"properties": { "data": { "$ref": "#/components/schemas/ListEmailRuleVersionsResult" } }
|
|
22871
22640
|
}] } } },
|
|
22872
22641
|
"headers": {
|
|
22873
22642
|
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit" },
|
|
@@ -22876,6 +22645,19 @@ const openapiDocument = {
|
|
|
22876
22645
|
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy" }
|
|
22877
22646
|
}
|
|
22878
22647
|
},
|
|
22648
|
+
"400": {
|
|
22649
|
+
"description": "Invalid request parameters",
|
|
22650
|
+
"content": { "application/json": {
|
|
22651
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
22652
|
+
"example": {
|
|
22653
|
+
"success": false,
|
|
22654
|
+
"error": {
|
|
22655
|
+
"code": "validation_error",
|
|
22656
|
+
"message": "Invalid domain format"
|
|
22657
|
+
}
|
|
22658
|
+
}
|
|
22659
|
+
} }
|
|
22660
|
+
},
|
|
22879
22661
|
"401": {
|
|
22880
22662
|
"description": "Invalid or missing API key",
|
|
22881
22663
|
"content": { "application/json": {
|
|
@@ -22896,16 +22678,620 @@ const openapiDocument = {
|
|
|
22896
22678
|
}
|
|
22897
22679
|
},
|
|
22898
22680
|
"403": {
|
|
22899
|
-
"description": "feature_not_enabled: the email rules feature is not enabled for this organization yet. Permission refusals answer forbidden or grant_forbidden instead.
|
|
22681
|
+
"description": "feature_not_enabled: the email rules feature is not enabled for this organization yet. Permission refusals answer forbidden or grant_forbidden instead.",
|
|
22900
22682
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22901
22683
|
},
|
|
22902
22684
|
"404": {
|
|
22903
|
-
"description": "
|
|
22904
|
-
"content": { "application/json": {
|
|
22905
|
-
|
|
22906
|
-
|
|
22907
|
-
|
|
22908
|
-
|
|
22685
|
+
"description": "Resource not found",
|
|
22686
|
+
"content": { "application/json": {
|
|
22687
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
22688
|
+
"example": {
|
|
22689
|
+
"success": false,
|
|
22690
|
+
"error": {
|
|
22691
|
+
"code": "not_found",
|
|
22692
|
+
"message": "Resource not found"
|
|
22693
|
+
}
|
|
22694
|
+
}
|
|
22695
|
+
} }
|
|
22696
|
+
},
|
|
22697
|
+
"429": {
|
|
22698
|
+
"description": "Rate limit exceeded. The `ratelimit-*` headers describe the limiter that rejected this request, with its own limit and window, not the API budget that successful responses report. A limiter that reports only a wait sends `Retry-After` alone.",
|
|
22699
|
+
"headers": {
|
|
22700
|
+
"Retry-After": {
|
|
22701
|
+
"schema": { "type": "integer" },
|
|
22702
|
+
"description": "Seconds to wait before retrying"
|
|
22703
|
+
},
|
|
22704
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-429" },
|
|
22705
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-429" },
|
|
22706
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
22707
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-429" }
|
|
22708
|
+
},
|
|
22709
|
+
"content": { "application/json": {
|
|
22710
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
22711
|
+
"example": {
|
|
22712
|
+
"success": false,
|
|
22713
|
+
"error": {
|
|
22714
|
+
"code": "rate_limit_exceeded",
|
|
22715
|
+
"message": "Rate limit exceeded"
|
|
22716
|
+
}
|
|
22717
|
+
}
|
|
22718
|
+
} }
|
|
22719
|
+
}
|
|
22720
|
+
},
|
|
22721
|
+
"x-primitive-permission": ["mail:read"]
|
|
22722
|
+
} },
|
|
22723
|
+
"/email-rules/{id}/scope": { "get": {
|
|
22724
|
+
"operationId": "getEmailRuleScope",
|
|
22725
|
+
"summary": "Read what a rule covers",
|
|
22726
|
+
"description": "Whose mail the rule runs over, and what that comes to now: a rule never reaches further than what its author can read when it runs, so what a selected rule names and its author can no longer read stops matching. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
22727
|
+
"tags": ["Email Rules"],
|
|
22728
|
+
"security": [{ "BearerAuth": [] }],
|
|
22729
|
+
"parameters": [{
|
|
22730
|
+
"name": "id",
|
|
22731
|
+
"in": "path",
|
|
22732
|
+
"required": true,
|
|
22733
|
+
"description": "The rule id.",
|
|
22734
|
+
"schema": {
|
|
22735
|
+
"type": "string",
|
|
22736
|
+
"format": "uuid"
|
|
22737
|
+
}
|
|
22738
|
+
}],
|
|
22739
|
+
"responses": {
|
|
22740
|
+
"200": {
|
|
22741
|
+
"description": "Read what a rule covers",
|
|
22742
|
+
"content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
|
|
22743
|
+
"type": "object",
|
|
22744
|
+
"required": ["data"],
|
|
22745
|
+
"properties": { "data": { "$ref": "#/components/schemas/GetEmailRuleScopeResult" } }
|
|
22746
|
+
}] } } },
|
|
22747
|
+
"headers": {
|
|
22748
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit" },
|
|
22749
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining" },
|
|
22750
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
22751
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy" }
|
|
22752
|
+
}
|
|
22753
|
+
},
|
|
22754
|
+
"401": {
|
|
22755
|
+
"description": "Invalid or missing API key",
|
|
22756
|
+
"content": { "application/json": {
|
|
22757
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
22758
|
+
"example": {
|
|
22759
|
+
"success": false,
|
|
22760
|
+
"error": {
|
|
22761
|
+
"code": "unauthorized",
|
|
22762
|
+
"message": "Invalid or missing API key"
|
|
22763
|
+
}
|
|
22764
|
+
}
|
|
22765
|
+
} },
|
|
22766
|
+
"headers": {
|
|
22767
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-unauthenticated" },
|
|
22768
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-unauthenticated" },
|
|
22769
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset-unauthenticated" },
|
|
22770
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-unauthenticated" }
|
|
22771
|
+
}
|
|
22772
|
+
},
|
|
22773
|
+
"403": {
|
|
22774
|
+
"description": "feature_not_enabled: the email rules feature is not enabled for this organization yet. Permission refusals answer forbidden or grant_forbidden instead.",
|
|
22775
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22776
|
+
},
|
|
22777
|
+
"404": {
|
|
22778
|
+
"description": "not_found: no such rule, or not one you can see.",
|
|
22779
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22780
|
+
},
|
|
22781
|
+
"429": {
|
|
22782
|
+
"description": "Rate limit exceeded. The `ratelimit-*` headers describe the limiter that rejected this request, with its own limit and window, not the API budget that successful responses report. A limiter that reports only a wait sends `Retry-After` alone.",
|
|
22783
|
+
"headers": {
|
|
22784
|
+
"Retry-After": {
|
|
22785
|
+
"schema": { "type": "integer" },
|
|
22786
|
+
"description": "Seconds to wait before retrying"
|
|
22787
|
+
},
|
|
22788
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-429" },
|
|
22789
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-429" },
|
|
22790
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
22791
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-429" }
|
|
22792
|
+
},
|
|
22793
|
+
"content": { "application/json": {
|
|
22794
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
22795
|
+
"example": {
|
|
22796
|
+
"success": false,
|
|
22797
|
+
"error": {
|
|
22798
|
+
"code": "rate_limit_exceeded",
|
|
22799
|
+
"message": "Rate limit exceeded"
|
|
22800
|
+
}
|
|
22801
|
+
}
|
|
22802
|
+
} }
|
|
22803
|
+
}
|
|
22804
|
+
},
|
|
22805
|
+
"x-primitive-permission": ["mail:read"]
|
|
22806
|
+
} },
|
|
22807
|
+
"/email-rule-scope-options": { "get": {
|
|
22808
|
+
"operationId": "listEmailRuleScopeOptions",
|
|
22809
|
+
"summary": "List what a rule can cover",
|
|
22810
|
+
"description": "How much the caller can read, and the inboxes and domains the caller can read, which is what they may name when a rule runs over selected inboxes and domains. For a caller who reads the whole organization, addresses lists the inboxes known as someone's (member addresses, members' verified work emails at the organization's domains, agents' addresses and inboxes with shared access), not every address that receives mail: may_name_unlisted says when an address that is not listed, such as an inbox nobody has claimed, may be named too. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
22811
|
+
"tags": ["Email Rules"],
|
|
22812
|
+
"security": [{ "BearerAuth": [] }],
|
|
22813
|
+
"parameters": [{
|
|
22814
|
+
"name": "q",
|
|
22815
|
+
"in": "query",
|
|
22816
|
+
"required": false,
|
|
22817
|
+
"description": "Only inboxes and domains containing this text.",
|
|
22818
|
+
"schema": {
|
|
22819
|
+
"description": "Only inboxes and domains containing this text.",
|
|
22820
|
+
"type": "string",
|
|
22821
|
+
"maxLength": 200
|
|
22822
|
+
}
|
|
22823
|
+
}],
|
|
22824
|
+
"responses": {
|
|
22825
|
+
"200": {
|
|
22826
|
+
"description": "List what a rule can cover",
|
|
22827
|
+
"content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
|
|
22828
|
+
"type": "object",
|
|
22829
|
+
"required": ["data"],
|
|
22830
|
+
"properties": { "data": { "$ref": "#/components/schemas/ListEmailRuleScopeOptionsResult" } }
|
|
22831
|
+
}] } } },
|
|
22832
|
+
"headers": {
|
|
22833
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit" },
|
|
22834
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining" },
|
|
22835
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
22836
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy" }
|
|
22837
|
+
}
|
|
22838
|
+
},
|
|
22839
|
+
"400": {
|
|
22840
|
+
"description": "Invalid request parameters",
|
|
22841
|
+
"content": { "application/json": {
|
|
22842
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
22843
|
+
"example": {
|
|
22844
|
+
"success": false,
|
|
22845
|
+
"error": {
|
|
22846
|
+
"code": "validation_error",
|
|
22847
|
+
"message": "Invalid domain format"
|
|
22848
|
+
}
|
|
22849
|
+
}
|
|
22850
|
+
} }
|
|
22851
|
+
},
|
|
22852
|
+
"401": {
|
|
22853
|
+
"description": "Invalid or missing API key",
|
|
22854
|
+
"content": { "application/json": {
|
|
22855
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
22856
|
+
"example": {
|
|
22857
|
+
"success": false,
|
|
22858
|
+
"error": {
|
|
22859
|
+
"code": "unauthorized",
|
|
22860
|
+
"message": "Invalid or missing API key"
|
|
22861
|
+
}
|
|
22862
|
+
}
|
|
22863
|
+
} },
|
|
22864
|
+
"headers": {
|
|
22865
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-unauthenticated" },
|
|
22866
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-unauthenticated" },
|
|
22867
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset-unauthenticated" },
|
|
22868
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-unauthenticated" }
|
|
22869
|
+
}
|
|
22870
|
+
},
|
|
22871
|
+
"403": {
|
|
22872
|
+
"description": "feature_not_enabled: the email rules feature is not enabled for this organization yet. Permission refusals answer forbidden or grant_forbidden instead.",
|
|
22873
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22874
|
+
},
|
|
22875
|
+
"409": {
|
|
22876
|
+
"description": "email_rule_author_unresolvable: rules cannot run as you right now.",
|
|
22877
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22878
|
+
},
|
|
22879
|
+
"429": {
|
|
22880
|
+
"description": "Rate limit exceeded. The `ratelimit-*` headers describe the limiter that rejected this request, with its own limit and window, not the API budget that successful responses report. A limiter that reports only a wait sends `Retry-After` alone.",
|
|
22881
|
+
"headers": {
|
|
22882
|
+
"Retry-After": {
|
|
22883
|
+
"schema": { "type": "integer" },
|
|
22884
|
+
"description": "Seconds to wait before retrying"
|
|
22885
|
+
},
|
|
22886
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-429" },
|
|
22887
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-429" },
|
|
22888
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
22889
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-429" }
|
|
22890
|
+
},
|
|
22891
|
+
"content": { "application/json": {
|
|
22892
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
22893
|
+
"example": {
|
|
22894
|
+
"success": false,
|
|
22895
|
+
"error": {
|
|
22896
|
+
"code": "rate_limit_exceeded",
|
|
22897
|
+
"message": "Rate limit exceeded"
|
|
22898
|
+
}
|
|
22899
|
+
}
|
|
22900
|
+
} }
|
|
22901
|
+
}
|
|
22902
|
+
},
|
|
22903
|
+
"x-primitive-permission": ["mail:read"]
|
|
22904
|
+
} },
|
|
22905
|
+
"/email-rule-requests": {
|
|
22906
|
+
"post": {
|
|
22907
|
+
"operationId": "createEmailRuleRequest",
|
|
22908
|
+
"summary": "Ask a member for a rule",
|
|
22909
|
+
"description": "Asks another member of the organization for a rule over their own mail, from a compile response or a tree you wrote. Name them by user id, or by their member mailbox address (at most 30 lookups by address an hour). Nothing is evaluated and nothing is shared until they accept, and they may change the rule first; they see the request and can preview what it matches in their own mail. You may have at most 5 pending requests to one member and 50 in all. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
22910
|
+
"tags": ["Email Rules"],
|
|
22911
|
+
"security": [{ "BearerAuth": [] }],
|
|
22912
|
+
"requestBody": {
|
|
22913
|
+
"required": true,
|
|
22914
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateEmailRuleRequestRequest" } } }
|
|
22915
|
+
},
|
|
22916
|
+
"responses": {
|
|
22917
|
+
"201": {
|
|
22918
|
+
"description": "Ask a member for a rule",
|
|
22919
|
+
"content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
|
|
22920
|
+
"type": "object",
|
|
22921
|
+
"required": ["data"],
|
|
22922
|
+
"properties": { "data": { "$ref": "#/components/schemas/CreateEmailRuleRequestResult" } }
|
|
22923
|
+
}] } } }
|
|
22924
|
+
},
|
|
22925
|
+
"400": {
|
|
22926
|
+
"description": "validation_error: give exactly one of target_user_id and target_email and a tree that is valid for the column contract; details.reason self_request when the member named is you.",
|
|
22927
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22928
|
+
},
|
|
22929
|
+
"401": {
|
|
22930
|
+
"description": "Invalid or missing API key",
|
|
22931
|
+
"content": { "application/json": {
|
|
22932
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
22933
|
+
"example": {
|
|
22934
|
+
"success": false,
|
|
22935
|
+
"error": {
|
|
22936
|
+
"code": "unauthorized",
|
|
22937
|
+
"message": "Invalid or missing API key"
|
|
22938
|
+
}
|
|
22939
|
+
}
|
|
22940
|
+
} },
|
|
22941
|
+
"headers": {
|
|
22942
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-unauthenticated" },
|
|
22943
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-unauthenticated" },
|
|
22944
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset-unauthenticated" },
|
|
22945
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-unauthenticated" }
|
|
22946
|
+
}
|
|
22947
|
+
},
|
|
22948
|
+
"403": {
|
|
22949
|
+
"description": "feature_not_enabled: the email rules feature is not enabled for this organization yet. Permission refusals answer forbidden or grant_forbidden instead.",
|
|
22950
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22951
|
+
},
|
|
22952
|
+
"404": {
|
|
22953
|
+
"description": "not_found: no current member of this organization matches the member named.",
|
|
22954
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22955
|
+
},
|
|
22956
|
+
"409": {
|
|
22957
|
+
"description": "email_rule_request_limit: you already have the most pending requests allowed (details.limit, and details.scope target or total).",
|
|
22958
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22959
|
+
},
|
|
22960
|
+
"429": {
|
|
22961
|
+
"description": "Rate limit exceeded. The `ratelimit-*` headers describe the limiter that rejected this request, with its own limit and window, not the API budget that successful responses report. A limiter that reports only a wait sends `Retry-After` alone.",
|
|
22962
|
+
"headers": {
|
|
22963
|
+
"Retry-After": {
|
|
22964
|
+
"schema": { "type": "integer" },
|
|
22965
|
+
"description": "Seconds to wait before retrying"
|
|
22966
|
+
},
|
|
22967
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-429" },
|
|
22968
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-429" },
|
|
22969
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
22970
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-429" }
|
|
22971
|
+
},
|
|
22972
|
+
"content": { "application/json": {
|
|
22973
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
22974
|
+
"example": {
|
|
22975
|
+
"success": false,
|
|
22976
|
+
"error": {
|
|
22977
|
+
"code": "rate_limit_exceeded",
|
|
22978
|
+
"message": "Rate limit exceeded"
|
|
22979
|
+
}
|
|
22980
|
+
}
|
|
22981
|
+
} }
|
|
22982
|
+
},
|
|
22983
|
+
"503": {
|
|
22984
|
+
"description": "service_unavailable: looking members up by address is unavailable right now. Try again in a moment, or name them by user id.",
|
|
22985
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22986
|
+
}
|
|
22987
|
+
},
|
|
22988
|
+
"x-primitive-permission": ["mail:read"],
|
|
22989
|
+
"parameters": [{
|
|
22990
|
+
"name": "Idempotency-Key",
|
|
22991
|
+
"in": "header",
|
|
22992
|
+
"required": false,
|
|
22993
|
+
"description": "Optional, and not used to deduplicate: this operation stores no result by the key, so a retry with the same key runs the request again. Operations that need a credential refuse a key that is empty, longer than 255 characters or not printable ASCII with 400 `validation_error` and echo a valid one in the Idempotency-Key response header; operations that need none ignore it.",
|
|
22994
|
+
"schema": {
|
|
22995
|
+
"type": "string",
|
|
22996
|
+
"minLength": 1,
|
|
22997
|
+
"maxLength": 255
|
|
22998
|
+
}
|
|
22999
|
+
}]
|
|
23000
|
+
},
|
|
23001
|
+
"get": {
|
|
23002
|
+
"operationId": "listEmailRuleRequests",
|
|
23003
|
+
"summary": "List rule requests",
|
|
23004
|
+
"description": "Rule requests, newest first: those made to you (box incoming, the default), those you made (outgoing), or every one you can see (all). Pending ones by default; status decided lists accepted, declined and withdrawn ones, and any lists both. A request is visible to the member who made it, the member it was made to, and the organization's owners and admins. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
23005
|
+
"tags": ["Email Rules"],
|
|
23006
|
+
"security": [{ "BearerAuth": [] }],
|
|
23007
|
+
"parameters": [
|
|
23008
|
+
{
|
|
23009
|
+
"name": "box",
|
|
23010
|
+
"in": "query",
|
|
23011
|
+
"required": false,
|
|
23012
|
+
"description": "incoming, outgoing or all.",
|
|
23013
|
+
"schema": {
|
|
23014
|
+
"default": "incoming",
|
|
23015
|
+
"description": "incoming: requests made to you; outgoing: requests you made; all: every request you can see (owners and admins see the organization's).",
|
|
23016
|
+
"type": "string",
|
|
23017
|
+
"enum": [
|
|
23018
|
+
"incoming",
|
|
23019
|
+
"outgoing",
|
|
23020
|
+
"all"
|
|
23021
|
+
]
|
|
23022
|
+
}
|
|
23023
|
+
},
|
|
23024
|
+
{
|
|
23025
|
+
"name": "status",
|
|
23026
|
+
"in": "query",
|
|
23027
|
+
"required": false,
|
|
23028
|
+
"description": "pending, decided or any.",
|
|
23029
|
+
"schema": {
|
|
23030
|
+
"default": "pending",
|
|
23031
|
+
"type": "string",
|
|
23032
|
+
"enum": [
|
|
23033
|
+
"pending",
|
|
23034
|
+
"decided",
|
|
23035
|
+
"any"
|
|
23036
|
+
]
|
|
23037
|
+
}
|
|
23038
|
+
},
|
|
23039
|
+
{
|
|
23040
|
+
"name": "limit",
|
|
23041
|
+
"in": "query",
|
|
23042
|
+
"required": false,
|
|
23043
|
+
"description": "Maximum number of items to return.",
|
|
23044
|
+
"schema": {
|
|
23045
|
+
"default": 25,
|
|
23046
|
+
"type": "integer",
|
|
23047
|
+
"minimum": 1,
|
|
23048
|
+
"maximum": 100
|
|
23049
|
+
}
|
|
23050
|
+
},
|
|
23051
|
+
{
|
|
23052
|
+
"name": "cursor",
|
|
23053
|
+
"in": "query",
|
|
23054
|
+
"required": false,
|
|
23055
|
+
"description": "Opaque cursor from the previous page's next_cursor. Omit for the first page.",
|
|
23056
|
+
"schema": {
|
|
23057
|
+
"type": "string",
|
|
23058
|
+
"maxLength": 200
|
|
23059
|
+
}
|
|
23060
|
+
}
|
|
23061
|
+
],
|
|
23062
|
+
"responses": {
|
|
23063
|
+
"200": {
|
|
23064
|
+
"description": "List rule requests",
|
|
23065
|
+
"content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
|
|
23066
|
+
"type": "object",
|
|
23067
|
+
"required": ["data"],
|
|
23068
|
+
"properties": { "data": { "$ref": "#/components/schemas/ListEmailRuleRequestsResult" } }
|
|
23069
|
+
}] } } },
|
|
23070
|
+
"headers": {
|
|
23071
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit" },
|
|
23072
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining" },
|
|
23073
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
23074
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy" }
|
|
23075
|
+
}
|
|
23076
|
+
},
|
|
23077
|
+
"400": {
|
|
23078
|
+
"description": "Invalid request parameters",
|
|
23079
|
+
"content": { "application/json": {
|
|
23080
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
23081
|
+
"example": {
|
|
23082
|
+
"success": false,
|
|
23083
|
+
"error": {
|
|
23084
|
+
"code": "validation_error",
|
|
23085
|
+
"message": "Invalid domain format"
|
|
23086
|
+
}
|
|
23087
|
+
}
|
|
23088
|
+
} }
|
|
23089
|
+
},
|
|
23090
|
+
"401": {
|
|
23091
|
+
"description": "Invalid or missing API key",
|
|
23092
|
+
"content": { "application/json": {
|
|
23093
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
23094
|
+
"example": {
|
|
23095
|
+
"success": false,
|
|
23096
|
+
"error": {
|
|
23097
|
+
"code": "unauthorized",
|
|
23098
|
+
"message": "Invalid or missing API key"
|
|
23099
|
+
}
|
|
23100
|
+
}
|
|
23101
|
+
} },
|
|
23102
|
+
"headers": {
|
|
23103
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-unauthenticated" },
|
|
23104
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-unauthenticated" },
|
|
23105
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset-unauthenticated" },
|
|
23106
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-unauthenticated" }
|
|
23107
|
+
}
|
|
23108
|
+
},
|
|
23109
|
+
"403": {
|
|
23110
|
+
"description": "feature_not_enabled: the email rules feature is not enabled for this organization yet. Permission refusals answer forbidden or grant_forbidden instead.",
|
|
23111
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
23112
|
+
},
|
|
23113
|
+
"429": {
|
|
23114
|
+
"description": "Rate limit exceeded. The `ratelimit-*` headers describe the limiter that rejected this request, with its own limit and window, not the API budget that successful responses report. A limiter that reports only a wait sends `Retry-After` alone.",
|
|
23115
|
+
"headers": {
|
|
23116
|
+
"Retry-After": {
|
|
23117
|
+
"schema": { "type": "integer" },
|
|
23118
|
+
"description": "Seconds to wait before retrying"
|
|
23119
|
+
},
|
|
23120
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-429" },
|
|
23121
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-429" },
|
|
23122
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
23123
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-429" }
|
|
23124
|
+
},
|
|
23125
|
+
"content": { "application/json": {
|
|
23126
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
23127
|
+
"example": {
|
|
23128
|
+
"success": false,
|
|
23129
|
+
"error": {
|
|
23130
|
+
"code": "rate_limit_exceeded",
|
|
23131
|
+
"message": "Rate limit exceeded"
|
|
23132
|
+
}
|
|
23133
|
+
}
|
|
23134
|
+
} }
|
|
23135
|
+
}
|
|
23136
|
+
},
|
|
23137
|
+
"x-primitive-permission": ["mail:read"]
|
|
23138
|
+
}
|
|
23139
|
+
},
|
|
23140
|
+
"/email-rule-requests/{id}": { "get": {
|
|
23141
|
+
"operationId": "getEmailRuleRequest",
|
|
23142
|
+
"summary": "Read a rule request",
|
|
23143
|
+
"description": "A rule request: the rule as proposed, who made it and to whom, and whether each of them is still a member. A request is visible to the member who made it, the member it was made to, and the organization's owners and admins. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
23144
|
+
"tags": ["Email Rules"],
|
|
23145
|
+
"security": [{ "BearerAuth": [] }],
|
|
23146
|
+
"parameters": [{
|
|
23147
|
+
"name": "id",
|
|
23148
|
+
"in": "path",
|
|
23149
|
+
"required": true,
|
|
23150
|
+
"description": "The request id.",
|
|
23151
|
+
"schema": {
|
|
23152
|
+
"type": "string",
|
|
23153
|
+
"format": "uuid"
|
|
23154
|
+
}
|
|
23155
|
+
}],
|
|
23156
|
+
"responses": {
|
|
23157
|
+
"200": {
|
|
23158
|
+
"description": "Read a rule request",
|
|
23159
|
+
"content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
|
|
23160
|
+
"type": "object",
|
|
23161
|
+
"required": ["data"],
|
|
23162
|
+
"properties": { "data": { "$ref": "#/components/schemas/GetEmailRuleRequestResult" } }
|
|
23163
|
+
}] } } },
|
|
23164
|
+
"headers": {
|
|
23165
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit" },
|
|
23166
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining" },
|
|
23167
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
23168
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy" }
|
|
23169
|
+
}
|
|
23170
|
+
},
|
|
23171
|
+
"401": {
|
|
23172
|
+
"description": "Invalid or missing API key",
|
|
23173
|
+
"content": { "application/json": {
|
|
23174
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
23175
|
+
"example": {
|
|
23176
|
+
"success": false,
|
|
23177
|
+
"error": {
|
|
23178
|
+
"code": "unauthorized",
|
|
23179
|
+
"message": "Invalid or missing API key"
|
|
23180
|
+
}
|
|
23181
|
+
}
|
|
23182
|
+
} },
|
|
23183
|
+
"headers": {
|
|
23184
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-unauthenticated" },
|
|
23185
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-unauthenticated" },
|
|
23186
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset-unauthenticated" },
|
|
23187
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-unauthenticated" }
|
|
23188
|
+
}
|
|
23189
|
+
},
|
|
23190
|
+
"403": {
|
|
23191
|
+
"description": "feature_not_enabled: the email rules feature is not enabled for this organization yet. Permission refusals answer forbidden or grant_forbidden instead.",
|
|
23192
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
23193
|
+
},
|
|
23194
|
+
"404": {
|
|
23195
|
+
"description": "not_found: no request you can see has this id.",
|
|
23196
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
23197
|
+
},
|
|
23198
|
+
"429": {
|
|
23199
|
+
"description": "Rate limit exceeded. The `ratelimit-*` headers describe the limiter that rejected this request, with its own limit and window, not the API budget that successful responses report. A limiter that reports only a wait sends `Retry-After` alone.",
|
|
23200
|
+
"headers": {
|
|
23201
|
+
"Retry-After": {
|
|
23202
|
+
"schema": { "type": "integer" },
|
|
23203
|
+
"description": "Seconds to wait before retrying"
|
|
23204
|
+
},
|
|
23205
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-429" },
|
|
23206
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-429" },
|
|
23207
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
23208
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-429" }
|
|
23209
|
+
},
|
|
23210
|
+
"content": { "application/json": {
|
|
23211
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
23212
|
+
"example": {
|
|
23213
|
+
"success": false,
|
|
23214
|
+
"error": {
|
|
23215
|
+
"code": "rate_limit_exceeded",
|
|
23216
|
+
"message": "Rate limit exceeded"
|
|
23217
|
+
}
|
|
23218
|
+
}
|
|
23219
|
+
} }
|
|
23220
|
+
}
|
|
23221
|
+
},
|
|
23222
|
+
"x-primitive-permission": ["mail:read"]
|
|
23223
|
+
} },
|
|
23224
|
+
"/email-rule-requests/{id}/decline": { "post": {
|
|
23225
|
+
"operationId": "declineEmailRuleRequest",
|
|
23226
|
+
"summary": "Decline a rule request",
|
|
23227
|
+
"description": "Declines a pending request made to you. Nothing is written but the decision. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
23228
|
+
"tags": ["Email Rules"],
|
|
23229
|
+
"security": [{ "BearerAuth": [] }],
|
|
23230
|
+
"parameters": [{
|
|
23231
|
+
"name": "id",
|
|
23232
|
+
"in": "path",
|
|
23233
|
+
"required": true,
|
|
23234
|
+
"description": "The request id.",
|
|
23235
|
+
"schema": {
|
|
23236
|
+
"type": "string",
|
|
23237
|
+
"format": "uuid"
|
|
23238
|
+
}
|
|
23239
|
+
}, {
|
|
23240
|
+
"name": "Idempotency-Key",
|
|
23241
|
+
"in": "header",
|
|
23242
|
+
"required": false,
|
|
23243
|
+
"description": "Optional, and not used to deduplicate: this operation stores no result by the key, so a retry with the same key runs the request again. Operations that need a credential refuse a key that is empty, longer than 255 characters or not printable ASCII with 400 `validation_error` and echo a valid one in the Idempotency-Key response header; operations that need none ignore it.",
|
|
23244
|
+
"schema": {
|
|
23245
|
+
"type": "string",
|
|
23246
|
+
"minLength": 1,
|
|
23247
|
+
"maxLength": 255
|
|
23248
|
+
}
|
|
23249
|
+
}],
|
|
23250
|
+
"responses": {
|
|
23251
|
+
"200": {
|
|
23252
|
+
"description": "Decline a rule request",
|
|
23253
|
+
"content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
|
|
23254
|
+
"type": "object",
|
|
23255
|
+
"required": ["data"],
|
|
23256
|
+
"properties": { "data": { "$ref": "#/components/schemas/DeclineEmailRuleRequestResult" } }
|
|
23257
|
+
}] } } },
|
|
23258
|
+
"headers": {
|
|
23259
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit" },
|
|
23260
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining" },
|
|
23261
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
23262
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy" }
|
|
23263
|
+
}
|
|
23264
|
+
},
|
|
23265
|
+
"401": {
|
|
23266
|
+
"description": "Invalid or missing API key",
|
|
23267
|
+
"content": { "application/json": {
|
|
23268
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
23269
|
+
"example": {
|
|
23270
|
+
"success": false,
|
|
23271
|
+
"error": {
|
|
23272
|
+
"code": "unauthorized",
|
|
23273
|
+
"message": "Invalid or missing API key"
|
|
23274
|
+
}
|
|
23275
|
+
}
|
|
23276
|
+
} },
|
|
23277
|
+
"headers": {
|
|
23278
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-unauthenticated" },
|
|
23279
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-unauthenticated" },
|
|
23280
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset-unauthenticated" },
|
|
23281
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-unauthenticated" }
|
|
23282
|
+
}
|
|
23283
|
+
},
|
|
23284
|
+
"403": {
|
|
23285
|
+
"description": "feature_not_enabled: the email rules feature is not enabled for this organization yet. Permission refusals answer forbidden or grant_forbidden instead. email_rule_request_target_only: only the member the request was made to may decline it.",
|
|
23286
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
23287
|
+
},
|
|
23288
|
+
"404": {
|
|
23289
|
+
"description": "not_found: no request you can see has this id.",
|
|
23290
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
23291
|
+
},
|
|
23292
|
+
"409": {
|
|
23293
|
+
"description": "email_rule_request_not_pending: the request was already accepted, declined or withdrawn (details.status).",
|
|
23294
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22909
23295
|
},
|
|
22910
23296
|
"429": {
|
|
22911
23297
|
"description": "Rate limit exceeded. The `ratelimit-*` headers describe the limiter that rejected this request, with its own limit and window, not the API budget that successful responses report. A limiter that reports only a wait sends `Retry-After` alone.",
|
|
@@ -30954,7 +31340,7 @@ const openapiDocument = {
|
|
|
30954
31340
|
"summary": "List every credential",
|
|
30955
31341
|
"tags": ["Credentials"],
|
|
30956
31342
|
"security": [{ "BearerAuth": [] }],
|
|
30957
|
-
"description": "Every credential that can act in the organization: API keys, Function keys, agent connection keys, connected apps (OAuth), agent delegates and, where enabled, CLI logins. Secrets are never returned. Filter with kind. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled.\n\nPerson only: a dashboard session. The person's role must hold credentials:read. API keys, agent connection keys and agents are refused.",
|
|
31343
|
+
"description": "Every credential that can act in the organization: API keys, Function keys, agent connection keys, connected apps (OAuth), agent delegates and, where enabled, CLI logins. Secrets are never returned. Filter with kind. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session. The person's role must hold credentials:read. API keys, agent connection keys and agents are refused.",
|
|
30958
31344
|
"x-primitive-person-only": { "access": "session" },
|
|
30959
31345
|
"parameters": [{
|
|
30960
31346
|
"name": "kind",
|
|
@@ -31083,7 +31469,7 @@ const openapiDocument = {
|
|
|
31083
31469
|
"summary": "Revoke a credential",
|
|
31084
31470
|
"tags": ["Credentials"],
|
|
31085
31471
|
"security": [{ "BearerAuth": [] }],
|
|
31086
|
-
"description": "Revoke one credential by kind and id. A Function key is rotated, never revoked (409 rotate_instead). An API key is revoked only by a person whose own access covers the key's access (an owner covers every key); otherwise 403 grant_forbidden, details.reason target_not_covered. What the credential set up keeps working and is listed in standing_objects for review. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled.\n\nPerson only: a dashboard session. The person's role must hold keys:manage. API keys, agent connection keys and agents are refused.",
|
|
31472
|
+
"description": "Revoke one credential by kind and id. A Function key is rotated, never revoked (409 rotate_instead). An API key is revoked only by a person whose own access covers the key's access (an owner covers every key); otherwise 403 grant_forbidden, details.reason target_not_covered. What the credential set up keeps working and is listed in standing_objects for review. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session. The person's role must hold keys:manage. API keys, agent connection keys and agents are refused.",
|
|
31087
31473
|
"x-primitive-person-only": { "access": "session" },
|
|
31088
31474
|
"parameters": [{
|
|
31089
31475
|
"name": "Idempotency-Key",
|
|
@@ -31223,7 +31609,7 @@ const openapiDocument = {
|
|
|
31223
31609
|
"summary": "Revoke every credential (emergency)",
|
|
31224
31610
|
"tags": ["Credentials"],
|
|
31225
31611
|
"security": [{ "BearerAuth": [] }],
|
|
31226
|
-
"description": "The emergency response to a leak: revokes every API key, agent connection key and connected app created since a time, rotates the organization Function key and every running Function's own key, and optionally suspends Functions. Owners only, from a dashboard session, and the body must confirm with \"revoke all\". Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled.\n\nPerson only: a dashboard session. The person's role must hold credentials:revoke_all. API keys, agent connection keys and agents are refused.",
|
|
31612
|
+
"description": "The emergency response to a leak: revokes every API key, agent connection key and connected app created since a time, rotates the organization Function key and every running Function's own key, and optionally suspends Functions. Owners only, from a dashboard session, and the body must confirm with \"revoke all\". Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session. The person's role must hold credentials:revoke_all. API keys, agent connection keys and agents are refused.",
|
|
31227
31613
|
"x-primitive-person-only": { "access": "session" },
|
|
31228
31614
|
"parameters": [{
|
|
31229
31615
|
"name": "Idempotency-Key",
|
|
@@ -31350,7 +31736,7 @@ const openapiDocument = {
|
|
|
31350
31736
|
"summary": "Read the credential audit trail",
|
|
31351
31737
|
"tags": ["Credentials"],
|
|
31352
31738
|
"security": [{ "BearerAuth": [] }],
|
|
31353
|
-
"description": "Credential events (created, rotated, edited, revoked, used with a step-up, policy changes), newest first, with a cursor. format=csv returns the same page as CSV. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled.\n\nPerson only: a dashboard session. The person's role must hold credential_events:read. API keys, agent connection keys and agents are refused.",
|
|
31739
|
+
"description": "Credential events (created, rotated, edited, revoked, used with a step-up, policy changes), newest first, with a cursor. format=csv returns the same page as CSV. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session. The person's role must hold credential_events:read. API keys, agent connection keys and agents are refused.",
|
|
31354
31740
|
"x-primitive-person-only": { "access": "session" },
|
|
31355
31741
|
"parameters": [
|
|
31356
31742
|
{
|
|
@@ -31552,7 +31938,7 @@ const openapiDocument = {
|
|
|
31552
31938
|
"summary": "Read the credential policy",
|
|
31553
31939
|
"tags": ["Credentials"],
|
|
31554
31940
|
"security": [{ "BearerAuth": [] }],
|
|
31555
|
-
"description": "The organization credential policy: key lifetime and expiry rules, who may create super admin keys, whether members may create keys and the other rules every new key is held to. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled.\n\nPerson only: a dashboard session. The person's role must hold credentials:read. API keys, agent connection keys and agents are refused.",
|
|
31941
|
+
"description": "The organization credential policy: key lifetime and expiry rules, who may create super admin keys, whether members may create keys and the other rules every new key is held to. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session. The person's role must hold credentials:read. API keys, agent connection keys and agents are refused.",
|
|
31556
31942
|
"x-primitive-person-only": { "access": "session" },
|
|
31557
31943
|
"parameters": [],
|
|
31558
31944
|
"responses": {
|
|
@@ -31665,7 +32051,7 @@ const openapiDocument = {
|
|
|
31665
32051
|
"summary": "Change the credential policy",
|
|
31666
32052
|
"tags": ["Credentials"],
|
|
31667
32053
|
"security": [{ "BearerAuth": [] }],
|
|
31668
|
-
"description": "Change one or more policy rules. Admins may only tighten the policy; loosening any rule needs an owner. Owners and admins are emailed about every change. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled.\n\nPerson only: a dashboard session. The person's role must hold credential_policy:manage. API keys, agent connection keys and agents are refused.",
|
|
32054
|
+
"description": "Change one or more policy rules. Admins may only tighten the policy; loosening any rule needs an owner. Owners and admins are emailed about every change. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session. The person's role must hold credential_policy:manage. API keys, agent connection keys and agents are refused.",
|
|
31669
32055
|
"x-primitive-person-only": { "access": "session" },
|
|
31670
32056
|
"parameters": [],
|
|
31671
32057
|
"responses": {
|
|
@@ -31783,7 +32169,7 @@ const openapiDocument = {
|
|
|
31783
32169
|
"summary": "Read the key builder",
|
|
31784
32170
|
"tags": ["Credentials"],
|
|
31785
32171
|
"security": [{ "BearerAuth": [] }],
|
|
31786
|
-
"description": "The key presets the caller may use (each with whether it is available and why not), the permission matrix for custom keys and the policy in force. An area marked org_wide_only (Members) is listed only to a person who holds its permission, and only a custom key with no addresses or domains may hold it. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled.\n\nPerson only: a dashboard session. The person's role must hold keys:read. API keys, agent connection keys and agents are refused.",
|
|
32172
|
+
"description": "The key presets the caller may use (each with whether it is available and why not), the permission matrix for custom keys and the policy in force. An area marked org_wide_only (Members) is listed only to a person who holds its permission, and only a custom key with no addresses or domains may hold it. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session. The person's role must hold keys:read. API keys, agent connection keys and agents are refused.",
|
|
31787
32173
|
"x-primitive-person-only": { "access": "session" },
|
|
31788
32174
|
"parameters": [],
|
|
31789
32175
|
"responses": {
|
|
@@ -31897,10 +32283,11 @@ const openapiDocument = {
|
|
|
31897
32283
|
"summary": "Create an API key",
|
|
31898
32284
|
"tags": ["Credentials"],
|
|
31899
32285
|
"security": [{ "BearerAuth": [] }],
|
|
31900
|
-
"description": "Create an API key, super admin or narrowed to a preset or a custom permission set, optionally with an expiry and conditions. The secret is returned once. A key never holds more than the person creating it; the credential policy decides who may create which keys. grant is required: a request without it is refused (400 validation_error, details.reason grant_required), never treated as super admin. A custom key must say which mail it reaches: the addresses and domains it lists (grant.addresses, grant.domains), or every mailbox in the organization with grant.mail_scope \"org\", which cannot be combined with them; one that says neither is refused (400 validation_error, details.reason mail_scope_required). Super admin, Send only and Read only reach every mailbox by definition. members:read is only for an org-wide custom key: naming it with grant.addresses or grant.domains is refused (400). Owners and admins are emailed about every super admin key. Send an Idempotency-Key to retry safely: a second create by the same person under the same key makes no second key and is refused (409 idempotency_key_reused) with the first key's id in error.details.key_id, so a caller whose first answer was lost can revoke that key. The onboarding field is for the dashboard only. The
|
|
32286
|
+
"description": "Create an API key, super admin or narrowed to a preset or a custom permission set, optionally with an expiry and conditions. The secret is returned once. A key never holds more than the person creating it; the credential policy decides who may create which keys. grant is required: a request without it is refused (400 validation_error, details.reason grant_required), never treated as super admin. A custom key must say which mail it reaches: the addresses and domains it lists (grant.addresses, grant.domains), or every mailbox in the organization with grant.mail_scope \"org\", which cannot be combined with them; one that says neither is refused (400 validation_error, details.reason mail_scope_required). Super admin, Send only and Read only reach every mailbox by definition. members:read is only for an org-wide custom key: naming it with grant.addresses or grant.domains is refused (400). Owners and admins are emailed about every super admin key. Send an Idempotency-Key to retry safely: a second create by the same person under the same key makes no second key and is refused (409 idempotency_key_reused) with the first key's id in error.details.key_id, so a caller whose first answer was lost can revoke that key. The onboarding field is for the dashboard only. The person's own Primitive CLI login needs no step-up (it acts as the person, held to the same rules); the Primitive app's token is refused, even with one. While the organization's keys API is not enabled, this answers 404 feature_disabled (details.feature keys_api; only Primitive turns it on), except that a dashboard session may still create a super admin key (the dashboard's own create).\n\nPerson only: a dashboard session, the person's own Primitive CLI login with no step-up, or the person's own OAuth token with a step-up token for purpose `keys.create` in the Primitive-Step-Up header. Without one any other OAuth token is answered 403 step_up_required, whose details carry the dashboard URL that issues it (or 403 grant_forbidden when the person's role, or the client, could not do it anyway). The person's role must hold keys:manage. API keys and agent connection keys are refused. An agent acting for the person is refused unless it carries a step-up token the person issued in the dashboard.",
|
|
31901
32287
|
"x-primitive-person-only": {
|
|
31902
32288
|
"access": "step_up",
|
|
31903
|
-
"step_up_purpose": "keys.create"
|
|
32289
|
+
"step_up_purpose": "keys.create",
|
|
32290
|
+
"cli_without_step_up": true
|
|
31904
32291
|
},
|
|
31905
32292
|
"parameters": [
|
|
31906
32293
|
{
|
|
@@ -31927,7 +32314,7 @@ const openapiDocument = {
|
|
|
31927
32314
|
"name": "Primitive-Step-Up",
|
|
31928
32315
|
"in": "header",
|
|
31929
32316
|
"required": false,
|
|
31930
|
-
"description": "A single-use step-up token of purpose `keys.create` (Create, rotate or change an API key), valid 5 minutes. When this operation answers 403 `step_up_required`, the person confirms at the link in `details.step_up_url` and the request is retried with the token that page shows, in this header. Accepted only with the person's own OAuth token of the client it was confirmed for; refused with a token issued for MCP, with any API key or agent connection key, and with a dashboard session. The Primitive
|
|
32317
|
+
"description": "A single-use step-up token of purpose `keys.create` (Create, rotate or change an API key), valid 5 minutes. When this operation answers 403 `step_up_required`, the person confirms at the link in `details.step_up_url` and the request is retried with the token that page shows, in this header. Accepted only with the person's own OAuth token of the client it was confirmed for; refused with a token issued for MCP, with any API key or agent connection key, and with a dashboard session. The Primitive app is refused for this purpose even with a token (403 `grant_forbidden`, `details.reason` `dashboard_only`). The person's own Primitive CLI login needs no token for this purpose while the organization's keys API is on (a token it sends is still checked); while it is off, a token it sends is refused the same way.",
|
|
31931
32318
|
"schema": {
|
|
31932
32319
|
"type": "string",
|
|
31933
32320
|
"pattern": "^pstep_[0-9a-f]{64}$"
|
|
@@ -32055,7 +32442,7 @@ const openapiDocument = {
|
|
|
32055
32442
|
"summary": "List API keys",
|
|
32056
32443
|
"tags": ["Credentials"],
|
|
32057
32444
|
"security": [{ "BearerAuth": [] }],
|
|
32058
|
-
"description": "Key metadata, never a secret: name, prefix, grant, creator, last use, expiry and suspension. The person needs access to the whole organization's mail. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled.\n\nPerson only: a dashboard session or the person's own Primitive CLI token; no other OAuth app. The person's role must hold keys:read. API keys, agent connection keys and agents are refused.",
|
|
32445
|
+
"description": "Key metadata, never a secret: name, prefix, grant, creator, last use, expiry and suspension. The person needs access to the whole organization's mail. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session or the person's own Primitive CLI token; no other OAuth app. The person's role must hold keys:read. API keys, agent connection keys and agents are refused.",
|
|
32059
32446
|
"x-primitive-person-only": { "access": "session_or_cli" },
|
|
32060
32447
|
"parameters": [{
|
|
32061
32448
|
"name": "cursor",
|
|
@@ -32178,10 +32565,11 @@ const openapiDocument = {
|
|
|
32178
32565
|
"summary": "Rotate an API key",
|
|
32179
32566
|
"tags": ["Credentials"],
|
|
32180
32567
|
"security": [{ "BearerAuth": [] }],
|
|
32181
|
-
"description": "Mint a successor with the same grant and return its secret once. The old key keeps working for overlap_seconds, then stops. The person rotating must cover the key's access (403 grant_forbidden, details.reason target_not_covered), and a key an owner created is rotated by an owner only (403 forbidden, details.reason owner_key_rotation), since rotating hands over the new secret. The Primitive CLI's token is refused, even with
|
|
32568
|
+
"description": "Mint a successor with the same grant and return its secret once. The old key keeps working for overlap_seconds, then stops. The person rotating must cover the key's access (403 grant_forbidden, details.reason target_not_covered), and a key an owner created is rotated by an owner only (403 forbidden, details.reason owner_key_rotation), since rotating hands over the new secret. The person's own Primitive CLI login needs no step-up (it acts as the person, held to the same rules); the Primitive app's token is refused, even with one. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session, the person's own Primitive CLI login with no step-up, or the person's own OAuth token with a step-up token for purpose `keys.create` in the Primitive-Step-Up header. Without one any other OAuth token is answered 403 step_up_required, whose details carry the dashboard URL that issues it (or 403 grant_forbidden when the person's role, or the client, could not do it anyway). The person's role must hold keys:manage. API keys and agent connection keys are refused. An agent acting for the person is refused unless it carries a step-up token the person issued in the dashboard.",
|
|
32182
32569
|
"x-primitive-person-only": {
|
|
32183
32570
|
"access": "step_up",
|
|
32184
|
-
"step_up_purpose": "keys.create"
|
|
32571
|
+
"step_up_purpose": "keys.create",
|
|
32572
|
+
"cli_without_step_up": true
|
|
32185
32573
|
},
|
|
32186
32574
|
"parameters": [
|
|
32187
32575
|
{
|
|
@@ -32198,7 +32586,7 @@ const openapiDocument = {
|
|
|
32198
32586
|
"name": "Primitive-Step-Up",
|
|
32199
32587
|
"in": "header",
|
|
32200
32588
|
"required": false,
|
|
32201
|
-
"description": "A single-use step-up token of purpose `keys.create` (Create, rotate or change an API key), valid 5 minutes. When this operation answers 403 `step_up_required`, the person confirms at the link in `details.step_up_url` and the request is retried with the token that page shows, in this header. Accepted only with the person's own OAuth token of the client it was confirmed for; refused with a token issued for MCP, with any API key or agent connection key, and with a dashboard session. The Primitive
|
|
32589
|
+
"description": "A single-use step-up token of purpose `keys.create` (Create, rotate or change an API key), valid 5 minutes. When this operation answers 403 `step_up_required`, the person confirms at the link in `details.step_up_url` and the request is retried with the token that page shows, in this header. Accepted only with the person's own OAuth token of the client it was confirmed for; refused with a token issued for MCP, with any API key or agent connection key, and with a dashboard session. The Primitive app is refused for this purpose even with a token (403 `grant_forbidden`, `details.reason` `dashboard_only`). The person's own Primitive CLI login needs no token for this purpose while the organization's keys API is on (a token it sends is still checked); while it is off, a token it sends is refused the same way.",
|
|
32202
32590
|
"schema": {
|
|
32203
32591
|
"type": "string",
|
|
32204
32592
|
"pattern": "^pstep_[0-9a-f]{64}$"
|
|
@@ -32344,10 +32732,11 @@ const openapiDocument = {
|
|
|
32344
32732
|
"summary": "Change an API key",
|
|
32345
32733
|
"tags": ["Credentials"],
|
|
32346
32734
|
"security": [{ "BearerAuth": [] }],
|
|
32347
|
-
"description": "Rename a key, change its expiry, its grant or its conditions, or suspend it. Any change needs the person's own access to cover the key's access now (an owner covers every key); otherwise 403 grant_forbidden, details.reason target_not_covered. A grant change is a new version of the key and is held to the same rules as creating one (a custom grant that does not say which mail it reaches is refused with details.reason mail_scope_required), so it takes the same step-up. The Primitive CLI's token is refused, even with
|
|
32735
|
+
"description": "Rename a key, change its expiry, its grant or its conditions, or suspend it. Any change needs the person's own access to cover the key's access now (an owner covers every key); otherwise 403 grant_forbidden, details.reason target_not_covered. A grant change is a new version of the key and is held to the same rules as creating one (a custom grant that does not say which mail it reaches is refused with details.reason mail_scope_required), so it takes the same step-up. The person's own Primitive CLI login needs no step-up (it acts as the person, held to the same rules); the Primitive app's token is refused, even with one. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session, the person's own Primitive CLI login with no step-up, or the person's own OAuth token with a step-up token for purpose `keys.create` in the Primitive-Step-Up header. Without one any other OAuth token is answered 403 step_up_required, whose details carry the dashboard URL that issues it (or 403 grant_forbidden when the person's role, or the client, could not do it anyway). The person's role must hold keys:manage. API keys and agent connection keys are refused. An agent acting for the person is refused unless it carries a step-up token the person issued in the dashboard.",
|
|
32348
32736
|
"x-primitive-person-only": {
|
|
32349
32737
|
"access": "step_up",
|
|
32350
|
-
"step_up_purpose": "keys.create"
|
|
32738
|
+
"step_up_purpose": "keys.create",
|
|
32739
|
+
"cli_without_step_up": true
|
|
32351
32740
|
},
|
|
32352
32741
|
"parameters": [{
|
|
32353
32742
|
"name": "id",
|
|
@@ -32362,7 +32751,7 @@ const openapiDocument = {
|
|
|
32362
32751
|
"name": "Primitive-Step-Up",
|
|
32363
32752
|
"in": "header",
|
|
32364
32753
|
"required": false,
|
|
32365
|
-
"description": "A single-use step-up token of purpose `keys.create` (Create, rotate or change an API key), valid 5 minutes. When this operation answers 403 `step_up_required`, the person confirms at the link in `details.step_up_url` and the request is retried with the token that page shows, in this header. Accepted only with the person's own OAuth token of the client it was confirmed for; refused with a token issued for MCP, with any API key or agent connection key, and with a dashboard session. The Primitive
|
|
32754
|
+
"description": "A single-use step-up token of purpose `keys.create` (Create, rotate or change an API key), valid 5 minutes. When this operation answers 403 `step_up_required`, the person confirms at the link in `details.step_up_url` and the request is retried with the token that page shows, in this header. Accepted only with the person's own OAuth token of the client it was confirmed for; refused with a token issued for MCP, with any API key or agent connection key, and with a dashboard session. The Primitive app is refused for this purpose even with a token (403 `grant_forbidden`, `details.reason` `dashboard_only`). The person's own Primitive CLI login needs no token for this purpose while the organization's keys API is on (a token it sends is still checked); while it is off, a token it sends is refused the same way.",
|
|
32366
32755
|
"schema": {
|
|
32367
32756
|
"type": "string",
|
|
32368
32757
|
"pattern": "^pstep_[0-9a-f]{64}$"
|
|
@@ -32495,7 +32884,7 @@ const openapiDocument = {
|
|
|
32495
32884
|
"summary": "Get an API key",
|
|
32496
32885
|
"tags": ["Credentials"],
|
|
32497
32886
|
"security": [{ "BearerAuth": [] }],
|
|
32498
|
-
"description": "One key's metadata, never its secret. The person needs access to the whole organization's mail. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled.\n\nPerson only: a dashboard session or the person's own Primitive CLI token; no other OAuth app. The person's role must hold keys:read. API keys, agent connection keys and agents are refused.",
|
|
32887
|
+
"description": "One key's metadata, never its secret. The person needs access to the whole organization's mail. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session or the person's own Primitive CLI token; no other OAuth app. The person's role must hold keys:read. API keys, agent connection keys and agents are refused.",
|
|
32499
32888
|
"x-primitive-person-only": { "access": "session_or_cli" },
|
|
32500
32889
|
"parameters": [{
|
|
32501
32890
|
"name": "id",
|
|
@@ -32618,7 +33007,7 @@ const openapiDocument = {
|
|
|
32618
33007
|
"summary": "Suggest a least-privilege grant for a key",
|
|
32619
33008
|
"tags": ["Credentials"],
|
|
32620
33009
|
"security": [{ "BearerAuth": [] }],
|
|
32621
|
-
"description": "The permissions a key used over the last 30 days, as a custom grant that would have served every successful call (also as builder areas), the narrowest mail scope its calls support (depth is deprecated: raw when it downloaded raw MIME, otherwise content) (the mailboxes of the messages it named and sent, with notes on what the request log cannot account for), and whether it is unused. Calls to routes only the super admin key can use (groups and mailbox access) derive no permission, since a custom key is refused there; super_admin_only_calls counts them. usage gives the same window anonymized: successful and failed requests per UTC day, the routes called by their declared template (never the called path) with the permission each needed, and how many mailboxes the key read and sent from (counts only, and only for a person with access to the whole organization's mail). Nothing is applied: narrowing is a change to the key (PATCH /v1/keys/:id). Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled.\n\nPerson only: a dashboard session. The person's role must hold credentials:read. API keys, agent connection keys and agents are refused.",
|
|
33010
|
+
"description": "The permissions a key used over the last 30 days, as a custom grant that would have served every successful call (also as builder areas), the narrowest mail scope its calls support (depth is deprecated: raw when it downloaded raw MIME, otherwise content) (the mailboxes of the messages it named and sent, with notes on what the request log cannot account for), and whether it is unused. Calls to routes only the super admin key can use (groups and mailbox access) derive no permission, since a custom key is refused there; super_admin_only_calls counts them. usage gives the same window anonymized: successful and failed requests per UTC day, the routes called by their declared template (never the called path) with the permission each needed, and how many mailboxes the key read and sent from (counts only, and only for a person with access to the whole organization's mail). Nothing is applied: narrowing is a change to the key (PATCH /v1/keys/:id). Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session. The person's role must hold credentials:read. API keys, agent connection keys and agents are refused.",
|
|
32622
33011
|
"x-primitive-person-only": { "access": "session" },
|
|
32623
33012
|
"parameters": [{
|
|
32624
33013
|
"name": "id",
|
|
@@ -36159,7 +36548,7 @@ const openapiDocument = {
|
|
|
36159
36548
|
"/access-suspensions/{id}/decision": { "post": {
|
|
36160
36549
|
"operationId": "decideSuspension",
|
|
36161
36550
|
"summary": "Decide a suspension",
|
|
36162
|
-
"description": "Keep, narrow or revoke one suspended or flagged item. Keeping it, and revoking an API key, needs the decider to cover it (revoking an uncovered key is refused with `grant_forbidden`, `target_not_covered`). Keeping an API key rotated (`rotate: true`, other than the shared Function key) also revokes its older secrets still in a rotation overlap, and needs keys:manage on both the credential and the person: without it, or if the decider lost members:manage meanwhile, it is refused with `grant_forbidden` (`keys_manage_required` or `actor_access_changed`) and nothing is rotated. Person only: a dashboard session, or the person's own OAuth or CLI token with a session step-up of purpose `suspensions.decide` (the person confirms at the step_up_url a 403 step_up_required answer carries, which names this client, then send the token in the Primitive-Step-Up header; the token works only with the client it was confirmed for). Needs members:manage. API keys are refused.",
|
|
36551
|
+
"description": "Keep, narrow or revoke one suspended or flagged item. Keeping it, and revoking an API key, needs the decider to cover it (revoking an uncovered key is refused with `grant_forbidden`, `target_not_covered`). Keeping an API key rotated (`rotate: true`, other than the shared Function key) also revokes its older secrets still in a rotation overlap, and needs keys:manage on both the credential and the person: without it, or if the decider lost members:manage meanwhile, it is refused with `grant_forbidden` (`keys_manage_required` or `actor_access_changed`) and nothing is rotated. A rule share paused by a role change (`email_rule_share`) takes keep, which leaves it paused, or revoke, which ends the share and needs confirm: true (the person it was shared with loses the emails already shared; without it, 409 `confirmation_required`). Neither of the share's two people may keep it (`grant_forbidden`, `share_decision_forbidden`). Access a person gave on their own mailbox (`mailbox_access`) takes keep or revoke, and both need delegations:manage; revoke removes only what that person gave on that mailbox. Nobody the access reaches, nor the person who gave it, may keep it (`grant_forbidden`, `mailbox_access_decision_forbidden`). Person only: a dashboard session, or the person's own OAuth or CLI token with a session step-up of purpose `suspensions.decide` (the person confirms at the step_up_url a 403 step_up_required answer carries, which names this client, then send the token in the Primitive-Step-Up header; the token works only with the client it was confirmed for). Needs members:manage. API keys are refused.",
|
|
36163
36552
|
"tags": ["Roles and members"],
|
|
36164
36553
|
"security": [{ "BearerAuth": [] }],
|
|
36165
36554
|
"parameters": [
|
|
@@ -37851,6 +38240,8 @@ const openapiDocument = {
|
|
|
37851
38240
|
"email_rule_request_party_left",
|
|
37852
38241
|
"email_rule_request_proposer_only",
|
|
37853
38242
|
"email_rule_request_target_only",
|
|
38243
|
+
"email_rule_scope_locked",
|
|
38244
|
+
"email_rule_scope_not_readable",
|
|
37854
38245
|
"email_rule_share_ended",
|
|
37855
38246
|
"email_rule_share_limit",
|
|
37856
38247
|
"embedding_provider_unavailable",
|
|
@@ -38000,6 +38391,7 @@ const openapiDocument = {
|
|
|
38000
38391
|
"signal_not_allowed",
|
|
38001
38392
|
"signal_parent_not_ready",
|
|
38002
38393
|
"signal_sender_unauthenticated",
|
|
38394
|
+
"signing_secret_unavailable",
|
|
38003
38395
|
"signup_failed",
|
|
38004
38396
|
"standing_owner_revoked",
|
|
38005
38397
|
"step_up_invalid",
|
|
@@ -47520,96 +47912,132 @@ const openapiDocument = {
|
|
|
47520
47912
|
"vocabulary",
|
|
47521
47913
|
"when",
|
|
47522
47914
|
"questions"
|
|
47523
|
-
]
|
|
47524
|
-
},
|
|
47525
|
-
"explanation": {
|
|
47526
|
-
"type": "string",
|
|
47527
|
-
"description": "What the rule matches, in plain English."
|
|
47528
|
-
},
|
|
47529
|
-
"assumptions": {
|
|
47530
|
-
"type": "array",
|
|
47531
|
-
"items": { "type": "string" },
|
|
47532
|
-
"description": "Readings the compiler chose where the description was open to more than one."
|
|
47533
|
-
},
|
|
47534
|
-
"warnings": {
|
|
47535
|
-
"type": "array",
|
|
47536
|
-
"items": { "type": "string" },
|
|
47537
|
-
"description": "Parts of the description the column contract cannot express, and how the rule handles them."
|
|
47915
|
+
]
|
|
47916
|
+
},
|
|
47917
|
+
"explanation": {
|
|
47918
|
+
"type": "string",
|
|
47919
|
+
"description": "What the rule matches, in plain English."
|
|
47920
|
+
},
|
|
47921
|
+
"assumptions": {
|
|
47922
|
+
"type": "array",
|
|
47923
|
+
"items": { "type": "string" },
|
|
47924
|
+
"description": "Readings the compiler chose where the description was open to more than one."
|
|
47925
|
+
},
|
|
47926
|
+
"warnings": {
|
|
47927
|
+
"type": "array",
|
|
47928
|
+
"items": { "type": "string" },
|
|
47929
|
+
"description": "Parts of the description the column contract cannot express, and how the rule handles them."
|
|
47930
|
+
},
|
|
47931
|
+
"compiled_by": {
|
|
47932
|
+
"type": "string",
|
|
47933
|
+
"description": "An opaque name for the version of the rule compiler that produced the rule, such as rule-compiler-v1. Send it back as compiled_by when you save the rule."
|
|
47934
|
+
},
|
|
47935
|
+
"sql": {
|
|
47936
|
+
"description": "Present only when include_sql was true.",
|
|
47937
|
+
"type": "object",
|
|
47938
|
+
"properties": {
|
|
47939
|
+
"expression": {
|
|
47940
|
+
"type": "string",
|
|
47941
|
+
"description": "A parameterized boolean expression over one row per email."
|
|
47942
|
+
},
|
|
47943
|
+
"params": {
|
|
47944
|
+
"type": "array",
|
|
47945
|
+
"items": {},
|
|
47946
|
+
"description": "The values bound to $1, $2 and so on."
|
|
47947
|
+
}
|
|
47948
|
+
},
|
|
47949
|
+
"required": ["expression", "params"]
|
|
47950
|
+
}
|
|
47951
|
+
},
|
|
47952
|
+
"required": [
|
|
47953
|
+
"tree",
|
|
47954
|
+
"explanation",
|
|
47955
|
+
"assumptions",
|
|
47956
|
+
"warnings",
|
|
47957
|
+
"compiled_by"
|
|
47958
|
+
]
|
|
47959
|
+
},
|
|
47960
|
+
"TestEmailRuleRequest": {
|
|
47961
|
+
"type": "object",
|
|
47962
|
+
"properties": {
|
|
47963
|
+
"tree": {
|
|
47964
|
+
"description": "An unsaved rule tree, as POST /email-rules/compile returned it. Give tree or rule_id, not both.",
|
|
47965
|
+
"type": "object",
|
|
47966
|
+
"properties": {
|
|
47967
|
+
"version": {
|
|
47968
|
+
"type": "number",
|
|
47969
|
+
"const": 1
|
|
47970
|
+
},
|
|
47971
|
+
"vocabulary": {
|
|
47972
|
+
"type": "string",
|
|
47973
|
+
"description": "The column contract version the rule is written against, for example v1."
|
|
47974
|
+
},
|
|
47975
|
+
"when": {
|
|
47976
|
+
"type": "object",
|
|
47977
|
+
"propertyNames": { "type": "string" },
|
|
47978
|
+
"additionalProperties": {},
|
|
47979
|
+
"description": "The rule's conditions: a condition ({column, op, value?, min_confidence?}) or a group ({all: [...]}, {any: [...]} or {not: ...})."
|
|
47980
|
+
},
|
|
47981
|
+
"questions": {
|
|
47982
|
+
"type": "array",
|
|
47983
|
+
"items": { "type": "string" },
|
|
47984
|
+
"description": "Yes/no questions of the rule's own, asked about an email only after its conditions match. An email matches only if every answer is yes."
|
|
47985
|
+
}
|
|
47986
|
+
},
|
|
47987
|
+
"required": [
|
|
47988
|
+
"version",
|
|
47989
|
+
"vocabulary",
|
|
47990
|
+
"when",
|
|
47991
|
+
"questions"
|
|
47992
|
+
],
|
|
47993
|
+
"additionalProperties": false
|
|
47538
47994
|
},
|
|
47539
|
-
"
|
|
47995
|
+
"evaluation_scope": {
|
|
47540
47996
|
"type": "string",
|
|
47541
|
-
"
|
|
47997
|
+
"enum": [
|
|
47998
|
+
"author",
|
|
47999
|
+
"own_mailboxes",
|
|
48000
|
+
"selected"
|
|
48001
|
+
],
|
|
48002
|
+
"description": "own_mailboxes (the default): mail to your own addresses and agents (for a rule that shares, those you can send from). author: all mail you can read, including inboxes added later. selected: what scope_selection names."
|
|
47542
48003
|
},
|
|
47543
|
-
"
|
|
47544
|
-
"description": "Present only when include_sql was true.",
|
|
48004
|
+
"scope_selection": {
|
|
47545
48005
|
"type": "object",
|
|
47546
48006
|
"properties": {
|
|
47547
|
-
"
|
|
47548
|
-
"
|
|
47549
|
-
"description": "A parameterized boolean expression over one row per email."
|
|
47550
|
-
},
|
|
47551
|
-
"params": {
|
|
48007
|
+
"addresses": {
|
|
48008
|
+
"maxItems": 100,
|
|
47552
48009
|
"type": "array",
|
|
47553
|
-
"items": {
|
|
47554
|
-
|
|
47555
|
-
|
|
47556
|
-
|
|
47557
|
-
|
|
47558
|
-
|
|
47559
|
-
},
|
|
47560
|
-
"required": [
|
|
47561
|
-
"tree",
|
|
47562
|
-
"explanation",
|
|
47563
|
-
"assumptions",
|
|
47564
|
-
"warnings",
|
|
47565
|
-
"compiled_by"
|
|
47566
|
-
]
|
|
47567
|
-
},
|
|
47568
|
-
"TestEmailRuleRequest": {
|
|
47569
|
-
"type": "object",
|
|
47570
|
-
"properties": {
|
|
47571
|
-
"tree": {
|
|
47572
|
-
"description": "An unsaved rule tree, as POST /email-rules/compile returned it. Give tree or rule_id, not both.",
|
|
47573
|
-
"type": "object",
|
|
47574
|
-
"properties": {
|
|
47575
|
-
"version": {
|
|
47576
|
-
"type": "number",
|
|
47577
|
-
"const": 1
|
|
47578
|
-
},
|
|
47579
|
-
"vocabulary": {
|
|
47580
|
-
"type": "string",
|
|
47581
|
-
"description": "The column contract version the rule is written against, for example v1."
|
|
47582
|
-
},
|
|
47583
|
-
"when": {
|
|
47584
|
-
"type": "object",
|
|
47585
|
-
"propertyNames": { "type": "string" },
|
|
47586
|
-
"additionalProperties": {},
|
|
47587
|
-
"description": "The rule's conditions: a condition ({column, op, value?, min_confidence?}) or a group ({all: [...]}, {any: [...]} or {not: ...})."
|
|
48010
|
+
"items": {
|
|
48011
|
+
"type": "string",
|
|
48012
|
+
"minLength": 3,
|
|
48013
|
+
"maxLength": 320,
|
|
48014
|
+
"pattern": "^[^\\s@]+@[^\\s@]+$"
|
|
48015
|
+
}
|
|
47588
48016
|
},
|
|
47589
|
-
"
|
|
48017
|
+
"domains": {
|
|
48018
|
+
"maxItems": 50,
|
|
47590
48019
|
"type": "array",
|
|
47591
|
-
"items": {
|
|
47592
|
-
|
|
48020
|
+
"items": {
|
|
48021
|
+
"type": "string",
|
|
48022
|
+
"minLength": 1,
|
|
48023
|
+
"maxLength": 253,
|
|
48024
|
+
"pattern": "^[^\\s@]+\\.[^\\s@]+$"
|
|
48025
|
+
}
|
|
47593
48026
|
}
|
|
47594
48027
|
},
|
|
47595
|
-
"
|
|
47596
|
-
|
|
47597
|
-
"vocabulary",
|
|
47598
|
-
"when",
|
|
47599
|
-
"questions"
|
|
47600
|
-
],
|
|
47601
|
-
"additionalProperties": false
|
|
47602
|
-
},
|
|
47603
|
-
"evaluation_scope": {
|
|
47604
|
-
"type": "string",
|
|
47605
|
-
"enum": ["author", "own_mailboxes"],
|
|
47606
|
-
"description": "Whose mail an unsaved tree runs over. author, the default: all the mail you can read. own_mailboxes: only mail to your own addresses. Only with tree: a saved rule uses its own."
|
|
48028
|
+
"additionalProperties": false,
|
|
48029
|
+
"description": "Inboxes, and domains (every address at them the author can read), for a selected rule; each one you can read."
|
|
47607
48030
|
},
|
|
47608
48031
|
"rule_id": {
|
|
47609
48032
|
"description": "A saved rule you can see. Its current version is tested, with its author's access.",
|
|
47610
48033
|
"type": "string",
|
|
47611
48034
|
"format": "uuid"
|
|
47612
48035
|
},
|
|
48036
|
+
"kind": {
|
|
48037
|
+
"description": "For an unsaved tree: do_not_share tests it as a rule that blocks sharing, so an email it cannot decide counts as matched. A saved rule uses its own.",
|
|
48038
|
+
"type": "string",
|
|
48039
|
+
"enum": ["grant", "do_not_share"]
|
|
48040
|
+
},
|
|
47613
48041
|
"email_ids": {
|
|
47614
48042
|
"description": "Test exactly these emails. Without it, the newest emails the rule can read are tested, at most 200 and none older than 30 days.",
|
|
47615
48043
|
"minItems": 1,
|
|
@@ -47874,14 +48302,50 @@ const openapiDocument = {
|
|
|
47874
48302
|
},
|
|
47875
48303
|
"evaluation_scope": {
|
|
47876
48304
|
"type": "string",
|
|
47877
|
-
"enum": [
|
|
47878
|
-
|
|
48305
|
+
"enum": [
|
|
48306
|
+
"author",
|
|
48307
|
+
"own_mailboxes",
|
|
48308
|
+
"selected"
|
|
48309
|
+
],
|
|
48310
|
+
"description": "own_mailboxes (the default): mail to your own addresses and agents (for a rule that shares, those you can send from). author: all mail you can read, including inboxes added later. selected: what scope_selection names."
|
|
48311
|
+
},
|
|
48312
|
+
"scope_selection": {
|
|
48313
|
+
"type": "object",
|
|
48314
|
+
"properties": {
|
|
48315
|
+
"addresses": {
|
|
48316
|
+
"maxItems": 100,
|
|
48317
|
+
"type": "array",
|
|
48318
|
+
"items": {
|
|
48319
|
+
"type": "string",
|
|
48320
|
+
"minLength": 3,
|
|
48321
|
+
"maxLength": 320,
|
|
48322
|
+
"pattern": "^[^\\s@]+@[^\\s@]+$"
|
|
48323
|
+
}
|
|
48324
|
+
},
|
|
48325
|
+
"domains": {
|
|
48326
|
+
"maxItems": 50,
|
|
48327
|
+
"type": "array",
|
|
48328
|
+
"items": {
|
|
48329
|
+
"type": "string",
|
|
48330
|
+
"minLength": 1,
|
|
48331
|
+
"maxLength": 253,
|
|
48332
|
+
"pattern": "^[^\\s@]+\\.[^\\s@]+$"
|
|
48333
|
+
}
|
|
48334
|
+
}
|
|
48335
|
+
},
|
|
48336
|
+
"additionalProperties": false,
|
|
48337
|
+
"description": "Inboxes, and domains (every address at them the author can read), for a selected rule; each one you can read."
|
|
47879
48338
|
},
|
|
47880
48339
|
"rule_id": {
|
|
47881
48340
|
"description": "A saved rule you can see. Its current version is tested.",
|
|
47882
48341
|
"type": "string",
|
|
47883
48342
|
"format": "uuid"
|
|
47884
48343
|
},
|
|
48344
|
+
"kind": {
|
|
48345
|
+
"description": "For an unsaved tree: do_not_share tests it as a rule that blocks sharing, so an email it cannot decide counts as matched. A saved rule uses its own.",
|
|
48346
|
+
"type": "string",
|
|
48347
|
+
"enum": ["grant", "do_not_share"]
|
|
48348
|
+
},
|
|
47885
48349
|
"email": {
|
|
47886
48350
|
"type": "object",
|
|
47887
48351
|
"properties": {
|
|
@@ -48105,11 +48569,52 @@ const openapiDocument = {
|
|
|
48105
48569
|
"maxLength": 200,
|
|
48106
48570
|
"description": "A short name for the rule."
|
|
48107
48571
|
},
|
|
48572
|
+
"kind": {
|
|
48573
|
+
"description": "grant (the default): what the rule matches can be shared. do_not_share: the rule runs before every other rule, and while it is active no rule shares an email it matches; an email it cannot decide counts as matched. Set when the rule is created; it never changes.",
|
|
48574
|
+
"type": "string",
|
|
48575
|
+
"enum": ["grant", "do_not_share"]
|
|
48576
|
+
},
|
|
48108
48577
|
"state": {
|
|
48109
|
-
"description": "observe (the default) records what the rule would match and grants nothing; draft is not evaluated.",
|
|
48578
|
+
"description": "observe (the default) records what the rule would match and grants or blocks nothing; draft is not evaluated.",
|
|
48110
48579
|
"type": "string",
|
|
48111
48580
|
"enum": ["draft", "observe"]
|
|
48112
48581
|
},
|
|
48582
|
+
"evaluation_scope": {
|
|
48583
|
+
"type": "string",
|
|
48584
|
+
"enum": [
|
|
48585
|
+
"author",
|
|
48586
|
+
"own_mailboxes",
|
|
48587
|
+
"selected"
|
|
48588
|
+
],
|
|
48589
|
+
"description": "own_mailboxes (the default): mail to your own addresses and agents (for a rule that shares, those you can send from). author: all mail you can read, including inboxes added later. selected: what scope_selection names."
|
|
48590
|
+
},
|
|
48591
|
+
"scope_selection": {
|
|
48592
|
+
"type": "object",
|
|
48593
|
+
"properties": {
|
|
48594
|
+
"addresses": {
|
|
48595
|
+
"maxItems": 100,
|
|
48596
|
+
"type": "array",
|
|
48597
|
+
"items": {
|
|
48598
|
+
"type": "string",
|
|
48599
|
+
"minLength": 3,
|
|
48600
|
+
"maxLength": 320,
|
|
48601
|
+
"pattern": "^[^\\s@]+@[^\\s@]+$"
|
|
48602
|
+
}
|
|
48603
|
+
},
|
|
48604
|
+
"domains": {
|
|
48605
|
+
"maxItems": 50,
|
|
48606
|
+
"type": "array",
|
|
48607
|
+
"items": {
|
|
48608
|
+
"type": "string",
|
|
48609
|
+
"minLength": 1,
|
|
48610
|
+
"maxLength": 253,
|
|
48611
|
+
"pattern": "^[^\\s@]+\\.[^\\s@]+$"
|
|
48612
|
+
}
|
|
48613
|
+
}
|
|
48614
|
+
},
|
|
48615
|
+
"additionalProperties": false,
|
|
48616
|
+
"description": "Inboxes, and domains (every address at them the author can read), for a selected rule; each one you can read."
|
|
48617
|
+
},
|
|
48113
48618
|
"english": {
|
|
48114
48619
|
"type": "string",
|
|
48115
48620
|
"minLength": 1,
|
|
@@ -48205,6 +48710,35 @@ const openapiDocument = {
|
|
|
48205
48710
|
"active"
|
|
48206
48711
|
]
|
|
48207
48712
|
},
|
|
48713
|
+
"kind": {
|
|
48714
|
+
"description": "do_not_share: the rule blocks sharing of what it matches. Absent (or grant) on a rule that shares what it matches.",
|
|
48715
|
+
"type": "string",
|
|
48716
|
+
"enum": ["grant", "do_not_share"]
|
|
48717
|
+
},
|
|
48718
|
+
"evaluation_scope": {
|
|
48719
|
+
"description": "Whose mail the rule runs over, as stored; GET /email-rules/{id}/scope says what that comes to now.",
|
|
48720
|
+
"type": "string",
|
|
48721
|
+
"enum": [
|
|
48722
|
+
"author",
|
|
48723
|
+
"own_mailboxes",
|
|
48724
|
+
"selected"
|
|
48725
|
+
]
|
|
48726
|
+
},
|
|
48727
|
+
"scope_selection": {
|
|
48728
|
+
"type": ["object", "null"],
|
|
48729
|
+
"properties": {
|
|
48730
|
+
"addresses": {
|
|
48731
|
+
"type": "array",
|
|
48732
|
+
"items": { "type": "string" }
|
|
48733
|
+
},
|
|
48734
|
+
"domains": {
|
|
48735
|
+
"type": "array",
|
|
48736
|
+
"items": { "type": "string" }
|
|
48737
|
+
}
|
|
48738
|
+
},
|
|
48739
|
+
"required": ["addresses", "domains"],
|
|
48740
|
+
"description": "What a selected rule names; null for any other scope."
|
|
48741
|
+
},
|
|
48208
48742
|
"current_version": {
|
|
48209
48743
|
"type": ["integer", "null"],
|
|
48210
48744
|
"exclusiveMinimum": 0
|
|
@@ -48341,6 +48875,35 @@ const openapiDocument = {
|
|
|
48341
48875
|
"active"
|
|
48342
48876
|
]
|
|
48343
48877
|
},
|
|
48878
|
+
"kind": {
|
|
48879
|
+
"description": "do_not_share: the rule blocks sharing of what it matches. Absent (or grant) on a rule that shares what it matches.",
|
|
48880
|
+
"type": "string",
|
|
48881
|
+
"enum": ["grant", "do_not_share"]
|
|
48882
|
+
},
|
|
48883
|
+
"evaluation_scope": {
|
|
48884
|
+
"description": "Whose mail the rule runs over, as stored; GET /email-rules/{id}/scope says what that comes to now.",
|
|
48885
|
+
"type": "string",
|
|
48886
|
+
"enum": [
|
|
48887
|
+
"author",
|
|
48888
|
+
"own_mailboxes",
|
|
48889
|
+
"selected"
|
|
48890
|
+
]
|
|
48891
|
+
},
|
|
48892
|
+
"scope_selection": {
|
|
48893
|
+
"type": ["object", "null"],
|
|
48894
|
+
"properties": {
|
|
48895
|
+
"addresses": {
|
|
48896
|
+
"type": "array",
|
|
48897
|
+
"items": { "type": "string" }
|
|
48898
|
+
},
|
|
48899
|
+
"domains": {
|
|
48900
|
+
"type": "array",
|
|
48901
|
+
"items": { "type": "string" }
|
|
48902
|
+
}
|
|
48903
|
+
},
|
|
48904
|
+
"required": ["addresses", "domains"],
|
|
48905
|
+
"description": "What a selected rule names; null for any other scope."
|
|
48906
|
+
},
|
|
48344
48907
|
"current_version": {
|
|
48345
48908
|
"type": ["integer", "null"],
|
|
48346
48909
|
"exclusiveMinimum": 0
|
|
@@ -48390,6 +48953,35 @@ const openapiDocument = {
|
|
|
48390
48953
|
"active"
|
|
48391
48954
|
]
|
|
48392
48955
|
},
|
|
48956
|
+
"kind": {
|
|
48957
|
+
"description": "do_not_share: the rule blocks sharing of what it matches. Absent (or grant) on a rule that shares what it matches.",
|
|
48958
|
+
"type": "string",
|
|
48959
|
+
"enum": ["grant", "do_not_share"]
|
|
48960
|
+
},
|
|
48961
|
+
"evaluation_scope": {
|
|
48962
|
+
"description": "Whose mail the rule runs over, as stored; GET /email-rules/{id}/scope says what that comes to now.",
|
|
48963
|
+
"type": "string",
|
|
48964
|
+
"enum": [
|
|
48965
|
+
"author",
|
|
48966
|
+
"own_mailboxes",
|
|
48967
|
+
"selected"
|
|
48968
|
+
]
|
|
48969
|
+
},
|
|
48970
|
+
"scope_selection": {
|
|
48971
|
+
"type": ["object", "null"],
|
|
48972
|
+
"properties": {
|
|
48973
|
+
"addresses": {
|
|
48974
|
+
"type": "array",
|
|
48975
|
+
"items": { "type": "string" }
|
|
48976
|
+
},
|
|
48977
|
+
"domains": {
|
|
48978
|
+
"type": "array",
|
|
48979
|
+
"items": { "type": "string" }
|
|
48980
|
+
}
|
|
48981
|
+
},
|
|
48982
|
+
"required": ["addresses", "domains"],
|
|
48983
|
+
"description": "What a selected rule names; null for any other scope."
|
|
48984
|
+
},
|
|
48393
48985
|
"current_version": {
|
|
48394
48986
|
"type": ["integer", "null"],
|
|
48395
48987
|
"exclusiveMinimum": 0
|
|
@@ -48518,7 +49110,7 @@ const openapiDocument = {
|
|
|
48518
49110
|
"description": "A short name for the rule."
|
|
48519
49111
|
},
|
|
48520
49112
|
"state": {
|
|
48521
|
-
"description": "draft disables the rule; observe records decisions; active also grants what it matches. Keys read and receive what a rule granted only while it is active: leaving active pauses that, and returning to active restores reads and the delivery of queued mail not yet skipped.",
|
|
49113
|
+
"description": "draft disables the rule; observe records decisions; active also grants what it matches, or for a do_not_share rule keeps it from being shared. Keys read and receive what a rule granted only while it is active: leaving active pauses that, and returning to active restores reads and the delivery of queued mail not yet skipped.",
|
|
48522
49114
|
"type": "string",
|
|
48523
49115
|
"enum": [
|
|
48524
49116
|
"draft",
|
|
@@ -48595,6 +49187,42 @@ const openapiDocument = {
|
|
|
48595
49187
|
"type": "string",
|
|
48596
49188
|
"minLength": 1,
|
|
48597
49189
|
"maxLength": 64
|
|
49190
|
+
},
|
|
49191
|
+
"evaluation_scope": {
|
|
49192
|
+
"type": "string",
|
|
49193
|
+
"enum": [
|
|
49194
|
+
"author",
|
|
49195
|
+
"own_mailboxes",
|
|
49196
|
+
"selected"
|
|
49197
|
+
],
|
|
49198
|
+
"description": "author: all mail its author can read. own_mailboxes: mail to their own addresses. selected: what scope_selection names. Never more than the author can read."
|
|
49199
|
+
},
|
|
49200
|
+
"scope_selection": {
|
|
49201
|
+
"type": "object",
|
|
49202
|
+
"properties": {
|
|
49203
|
+
"addresses": {
|
|
49204
|
+
"maxItems": 100,
|
|
49205
|
+
"type": "array",
|
|
49206
|
+
"items": {
|
|
49207
|
+
"type": "string",
|
|
49208
|
+
"minLength": 3,
|
|
49209
|
+
"maxLength": 320,
|
|
49210
|
+
"pattern": "^[^\\s@]+@[^\\s@]+$"
|
|
49211
|
+
}
|
|
49212
|
+
},
|
|
49213
|
+
"domains": {
|
|
49214
|
+
"maxItems": 50,
|
|
49215
|
+
"type": "array",
|
|
49216
|
+
"items": {
|
|
49217
|
+
"type": "string",
|
|
49218
|
+
"minLength": 1,
|
|
49219
|
+
"maxLength": 253,
|
|
49220
|
+
"pattern": "^[^\\s@]+\\.[^\\s@]+$"
|
|
49221
|
+
}
|
|
49222
|
+
}
|
|
49223
|
+
},
|
|
49224
|
+
"additionalProperties": false,
|
|
49225
|
+
"description": "Inboxes, and domains (every address at them the author can read), for a selected rule; each one you can read."
|
|
48598
49226
|
}
|
|
48599
49227
|
},
|
|
48600
49228
|
"additionalProperties": false
|
|
@@ -48615,6 +49243,35 @@ const openapiDocument = {
|
|
|
48615
49243
|
"active"
|
|
48616
49244
|
]
|
|
48617
49245
|
},
|
|
49246
|
+
"kind": {
|
|
49247
|
+
"description": "do_not_share: the rule blocks sharing of what it matches. Absent (or grant) on a rule that shares what it matches.",
|
|
49248
|
+
"type": "string",
|
|
49249
|
+
"enum": ["grant", "do_not_share"]
|
|
49250
|
+
},
|
|
49251
|
+
"evaluation_scope": {
|
|
49252
|
+
"description": "Whose mail the rule runs over, as stored; GET /email-rules/{id}/scope says what that comes to now.",
|
|
49253
|
+
"type": "string",
|
|
49254
|
+
"enum": [
|
|
49255
|
+
"author",
|
|
49256
|
+
"own_mailboxes",
|
|
49257
|
+
"selected"
|
|
49258
|
+
]
|
|
49259
|
+
},
|
|
49260
|
+
"scope_selection": {
|
|
49261
|
+
"type": ["object", "null"],
|
|
49262
|
+
"properties": {
|
|
49263
|
+
"addresses": {
|
|
49264
|
+
"type": "array",
|
|
49265
|
+
"items": { "type": "string" }
|
|
49266
|
+
},
|
|
49267
|
+
"domains": {
|
|
49268
|
+
"type": "array",
|
|
49269
|
+
"items": { "type": "string" }
|
|
49270
|
+
}
|
|
49271
|
+
},
|
|
49272
|
+
"required": ["addresses", "domains"],
|
|
49273
|
+
"description": "What a selected rule names; null for any other scope."
|
|
49274
|
+
},
|
|
48618
49275
|
"current_version": {
|
|
48619
49276
|
"type": ["integer", "null"],
|
|
48620
49277
|
"exclusiveMinimum": 0
|
|
@@ -48792,6 +49449,370 @@ const openapiDocument = {
|
|
|
48792
49449
|
]
|
|
48793
49450
|
}
|
|
48794
49451
|
},
|
|
49452
|
+
"ListEmailRuleResultsResult": {
|
|
49453
|
+
"type": "object",
|
|
49454
|
+
"properties": {
|
|
49455
|
+
"rules": {
|
|
49456
|
+
"type": "array",
|
|
49457
|
+
"items": {
|
|
49458
|
+
"type": "object",
|
|
49459
|
+
"properties": {
|
|
49460
|
+
"id": {
|
|
49461
|
+
"type": "string",
|
|
49462
|
+
"format": "uuid"
|
|
49463
|
+
},
|
|
49464
|
+
"name": { "type": "string" },
|
|
49465
|
+
"state": {
|
|
49466
|
+
"type": "string",
|
|
49467
|
+
"enum": [
|
|
49468
|
+
"draft",
|
|
49469
|
+
"observe",
|
|
49470
|
+
"active"
|
|
49471
|
+
]
|
|
49472
|
+
},
|
|
49473
|
+
"kind": {
|
|
49474
|
+
"description": "do_not_share: the rule blocks sharing of what it matches. While it is active, no rule shares an email it has matched from then on; anything shared before, including while it was in observe, stays shared. Absent on a rule that shares what it matches.",
|
|
49475
|
+
"type": "string",
|
|
49476
|
+
"enum": ["grant", "do_not_share"]
|
|
49477
|
+
},
|
|
49478
|
+
"decision": {
|
|
49479
|
+
"type": ["object", "null"],
|
|
49480
|
+
"properties": {
|
|
49481
|
+
"rule_version": {
|
|
49482
|
+
"type": "integer",
|
|
49483
|
+
"exclusiveMinimum": 0,
|
|
49484
|
+
"description": "The version of the rule that decided."
|
|
49485
|
+
},
|
|
49486
|
+
"matched": { "type": "boolean" },
|
|
49487
|
+
"parts": {
|
|
49488
|
+
"type": "array",
|
|
49489
|
+
"items": {
|
|
49490
|
+
"type": "object",
|
|
49491
|
+
"properties": {
|
|
49492
|
+
"index": {
|
|
49493
|
+
"type": "integer",
|
|
49494
|
+
"minimum": 0
|
|
49495
|
+
},
|
|
49496
|
+
"matched": { "type": "boolean" },
|
|
49497
|
+
"columns": {
|
|
49498
|
+
"type": "array",
|
|
49499
|
+
"items": { "type": "string" }
|
|
49500
|
+
}
|
|
49501
|
+
},
|
|
49502
|
+
"required": [
|
|
49503
|
+
"index",
|
|
49504
|
+
"matched",
|
|
49505
|
+
"columns"
|
|
49506
|
+
]
|
|
49507
|
+
},
|
|
49508
|
+
"description": "How each top-level part of the rule decided. Empty when a fact the rule reads was missing, so it was not evaluated."
|
|
49509
|
+
},
|
|
49510
|
+
"question_answers": {
|
|
49511
|
+
"type": "array",
|
|
49512
|
+
"items": {
|
|
49513
|
+
"type": "object",
|
|
49514
|
+
"properties": {
|
|
49515
|
+
"question": { "type": "string" },
|
|
49516
|
+
"answer": { "type": ["boolean", "null"] },
|
|
49517
|
+
"probability": { "type": ["number", "null"] },
|
|
49518
|
+
"error_class": { "type": "string" }
|
|
49519
|
+
},
|
|
49520
|
+
"required": [
|
|
49521
|
+
"question",
|
|
49522
|
+
"answer",
|
|
49523
|
+
"probability"
|
|
49524
|
+
]
|
|
49525
|
+
},
|
|
49526
|
+
"description": "The answers to the rule's own questions, asked only when its conditions matched."
|
|
49527
|
+
},
|
|
49528
|
+
"tree": {
|
|
49529
|
+
"type": ["object", "null"],
|
|
49530
|
+
"properties": {
|
|
49531
|
+
"version": {
|
|
49532
|
+
"type": "number",
|
|
49533
|
+
"const": 1
|
|
49534
|
+
},
|
|
49535
|
+
"vocabulary": {
|
|
49536
|
+
"type": "string",
|
|
49537
|
+
"description": "The column contract version the rule is written against, for example v1."
|
|
49538
|
+
},
|
|
49539
|
+
"when": {
|
|
49540
|
+
"type": "object",
|
|
49541
|
+
"propertyNames": { "type": "string" },
|
|
49542
|
+
"additionalProperties": {},
|
|
49543
|
+
"description": "The rule's conditions: a condition ({column, op, value?, min_confidence?}) or a group ({all: [...]}, {any: [...]} or {not: ...})."
|
|
49544
|
+
},
|
|
49545
|
+
"questions": {
|
|
49546
|
+
"type": "array",
|
|
49547
|
+
"items": { "type": "string" },
|
|
49548
|
+
"description": "Yes/no questions of the rule's own, asked about an email only after its conditions match. An email matches only if every answer is yes."
|
|
49549
|
+
}
|
|
49550
|
+
},
|
|
49551
|
+
"required": [
|
|
49552
|
+
"version",
|
|
49553
|
+
"vocabulary",
|
|
49554
|
+
"when",
|
|
49555
|
+
"questions"
|
|
49556
|
+
],
|
|
49557
|
+
"description": "The conditions and questions of the version that decided, so the result reads in that version's words."
|
|
49558
|
+
},
|
|
49559
|
+
"created_at": {
|
|
49560
|
+
"type": "string",
|
|
49561
|
+
"format": "date-time"
|
|
49562
|
+
}
|
|
49563
|
+
},
|
|
49564
|
+
"required": [
|
|
49565
|
+
"rule_version",
|
|
49566
|
+
"matched",
|
|
49567
|
+
"parts",
|
|
49568
|
+
"question_answers",
|
|
49569
|
+
"tree",
|
|
49570
|
+
"created_at"
|
|
49571
|
+
],
|
|
49572
|
+
"description": "What the rule most recently decided about this email; null when it has not run on it."
|
|
49573
|
+
},
|
|
49574
|
+
"not_run_reason": {
|
|
49575
|
+
"type": ["string", "null"],
|
|
49576
|
+
"enum": [
|
|
49577
|
+
"draft",
|
|
49578
|
+
"created_after_email",
|
|
49579
|
+
null
|
|
49580
|
+
],
|
|
49581
|
+
"description": "What is known about a rule with no result on this email. draft: the rule is a draft now. created_after_email: the rule was created after the email arrived. Null when it has a result, or when nothing is known."
|
|
49582
|
+
},
|
|
49583
|
+
"author_left": {
|
|
49584
|
+
"description": "On a do-not-share rule whose author is no longer a member of the organization: it blocks nothing now, whatever it decided. Absent otherwise.",
|
|
49585
|
+
"type": "boolean",
|
|
49586
|
+
"const": true
|
|
49587
|
+
}
|
|
49588
|
+
},
|
|
49589
|
+
"required": [
|
|
49590
|
+
"id",
|
|
49591
|
+
"name",
|
|
49592
|
+
"state",
|
|
49593
|
+
"decision",
|
|
49594
|
+
"not_run_reason"
|
|
49595
|
+
]
|
|
49596
|
+
},
|
|
49597
|
+
"description": "Every rule the caller can see: those that matched this email, then those that did not, then those that have not run on it; newest rule first within each."
|
|
49598
|
+
},
|
|
49599
|
+
"hidden": {
|
|
49600
|
+
"type": "integer",
|
|
49601
|
+
"minimum": 0,
|
|
49602
|
+
"description": "How many more rules the caller can see that are not listed."
|
|
49603
|
+
}
|
|
49604
|
+
},
|
|
49605
|
+
"required": ["rules", "hidden"]
|
|
49606
|
+
},
|
|
49607
|
+
"ListEmailRuleVersionsResult": {
|
|
49608
|
+
"type": "array",
|
|
49609
|
+
"items": {
|
|
49610
|
+
"type": "object",
|
|
49611
|
+
"properties": {
|
|
49612
|
+
"version": {
|
|
49613
|
+
"type": "integer",
|
|
49614
|
+
"exclusiveMinimum": 0
|
|
49615
|
+
},
|
|
49616
|
+
"english": { "type": "string" },
|
|
49617
|
+
"tree": {
|
|
49618
|
+
"type": "object",
|
|
49619
|
+
"properties": {
|
|
49620
|
+
"version": {
|
|
49621
|
+
"type": "number",
|
|
49622
|
+
"const": 1
|
|
49623
|
+
},
|
|
49624
|
+
"vocabulary": {
|
|
49625
|
+
"type": "string",
|
|
49626
|
+
"description": "The column contract version the rule is written against, for example v1."
|
|
49627
|
+
},
|
|
49628
|
+
"when": {
|
|
49629
|
+
"type": "object",
|
|
49630
|
+
"propertyNames": { "type": "string" },
|
|
49631
|
+
"additionalProperties": {},
|
|
49632
|
+
"description": "The rule's conditions: a condition ({column, op, value?, min_confidence?}) or a group ({all: [...]}, {any: [...]} or {not: ...})."
|
|
49633
|
+
},
|
|
49634
|
+
"questions": {
|
|
49635
|
+
"type": "array",
|
|
49636
|
+
"items": { "type": "string" },
|
|
49637
|
+
"description": "Yes/no questions of the rule's own, asked about an email only after its conditions match. An email matches only if every answer is yes."
|
|
49638
|
+
}
|
|
49639
|
+
},
|
|
49640
|
+
"required": [
|
|
49641
|
+
"version",
|
|
49642
|
+
"vocabulary",
|
|
49643
|
+
"when",
|
|
49644
|
+
"questions"
|
|
49645
|
+
]
|
|
49646
|
+
},
|
|
49647
|
+
"explanation": { "type": "string" },
|
|
49648
|
+
"assumptions": {
|
|
49649
|
+
"type": "array",
|
|
49650
|
+
"items": { "type": "string" }
|
|
49651
|
+
},
|
|
49652
|
+
"warnings": {
|
|
49653
|
+
"type": "array",
|
|
49654
|
+
"items": { "type": "string" }
|
|
49655
|
+
},
|
|
49656
|
+
"compiled_by": {
|
|
49657
|
+
"type": "string",
|
|
49658
|
+
"description": "Who produced the tree, as the caller stated it when saving (not verified), for example rule-compiler-v1 or member."
|
|
49659
|
+
},
|
|
49660
|
+
"vocabulary": { "type": "string" },
|
|
49661
|
+
"created_at": {
|
|
49662
|
+
"type": "string",
|
|
49663
|
+
"format": "date-time"
|
|
49664
|
+
},
|
|
49665
|
+
"sql": {
|
|
49666
|
+
"description": "Present only when include_sql was true.",
|
|
49667
|
+
"type": "object",
|
|
49668
|
+
"properties": {
|
|
49669
|
+
"expression": {
|
|
49670
|
+
"type": "string",
|
|
49671
|
+
"description": "A parameterized boolean expression over one row per email."
|
|
49672
|
+
},
|
|
49673
|
+
"params": {
|
|
49674
|
+
"type": "array",
|
|
49675
|
+
"items": {},
|
|
49676
|
+
"description": "The values bound to $1, $2 and so on."
|
|
49677
|
+
}
|
|
49678
|
+
},
|
|
49679
|
+
"required": ["expression", "params"]
|
|
49680
|
+
}
|
|
49681
|
+
},
|
|
49682
|
+
"required": [
|
|
49683
|
+
"version",
|
|
49684
|
+
"english",
|
|
49685
|
+
"tree",
|
|
49686
|
+
"explanation",
|
|
49687
|
+
"assumptions",
|
|
49688
|
+
"warnings",
|
|
49689
|
+
"compiled_by",
|
|
49690
|
+
"vocabulary",
|
|
49691
|
+
"created_at"
|
|
49692
|
+
]
|
|
49693
|
+
}
|
|
49694
|
+
},
|
|
49695
|
+
"GetEmailRuleScopeResult": {
|
|
49696
|
+
"type": "object",
|
|
49697
|
+
"properties": {
|
|
49698
|
+
"evaluation_scope": {
|
|
49699
|
+
"type": "string",
|
|
49700
|
+
"enum": [
|
|
49701
|
+
"author",
|
|
49702
|
+
"own_mailboxes",
|
|
49703
|
+
"selected"
|
|
49704
|
+
],
|
|
49705
|
+
"description": "author: all mail its author can read. own_mailboxes: mail to their own addresses. selected: what scope_selection names. Never more than the author can read."
|
|
49706
|
+
},
|
|
49707
|
+
"scope_selection": {
|
|
49708
|
+
"type": ["object", "null"],
|
|
49709
|
+
"properties": {
|
|
49710
|
+
"addresses": {
|
|
49711
|
+
"type": "array",
|
|
49712
|
+
"items": { "type": "string" }
|
|
49713
|
+
},
|
|
49714
|
+
"domains": {
|
|
49715
|
+
"type": "array",
|
|
49716
|
+
"items": { "type": "string" }
|
|
49717
|
+
}
|
|
49718
|
+
},
|
|
49719
|
+
"required": ["addresses", "domains"]
|
|
49720
|
+
},
|
|
49721
|
+
"locked": {
|
|
49722
|
+
"type": "boolean",
|
|
49723
|
+
"description": "Shared, so its scope cannot change."
|
|
49724
|
+
},
|
|
49725
|
+
"author_reach": {
|
|
49726
|
+
"type": ["string", "null"],
|
|
49727
|
+
"enum": [
|
|
49728
|
+
"organization",
|
|
49729
|
+
"limited",
|
|
49730
|
+
"own",
|
|
49731
|
+
null
|
|
49732
|
+
],
|
|
49733
|
+
"description": "How much its author can read now; null when it cannot run as them."
|
|
49734
|
+
},
|
|
49735
|
+
"no_longer_readable": {
|
|
49736
|
+
"type": "object",
|
|
49737
|
+
"properties": {
|
|
49738
|
+
"addresses": {
|
|
49739
|
+
"type": "array",
|
|
49740
|
+
"items": { "type": "string" }
|
|
49741
|
+
},
|
|
49742
|
+
"domains": {
|
|
49743
|
+
"type": "array",
|
|
49744
|
+
"items": { "type": "string" }
|
|
49745
|
+
}
|
|
49746
|
+
},
|
|
49747
|
+
"required": ["addresses", "domains"],
|
|
49748
|
+
"description": "What scope_selection names that its author no longer reads in full."
|
|
49749
|
+
},
|
|
49750
|
+
"still_read": {
|
|
49751
|
+
"description": "Inboxes its author still reads at the domains in no_longer_readable; the rule still covers them.",
|
|
49752
|
+
"type": "array",
|
|
49753
|
+
"items": { "type": "string" }
|
|
49754
|
+
},
|
|
49755
|
+
"stopped_reason": {
|
|
49756
|
+
"description": "Why it cannot run now (a reason as on POST /email-rules/test), or null.",
|
|
49757
|
+
"type": ["string", "null"]
|
|
49758
|
+
}
|
|
49759
|
+
},
|
|
49760
|
+
"required": [
|
|
49761
|
+
"evaluation_scope",
|
|
49762
|
+
"scope_selection",
|
|
49763
|
+
"locked",
|
|
49764
|
+
"author_reach",
|
|
49765
|
+
"no_longer_readable",
|
|
49766
|
+
"stopped_reason"
|
|
49767
|
+
]
|
|
49768
|
+
},
|
|
49769
|
+
"ListEmailRuleScopeOptionsResult": {
|
|
49770
|
+
"type": "object",
|
|
49771
|
+
"properties": {
|
|
49772
|
+
"reach": {
|
|
49773
|
+
"type": "string",
|
|
49774
|
+
"enum": [
|
|
49775
|
+
"organization",
|
|
49776
|
+
"limited",
|
|
49777
|
+
"own"
|
|
49778
|
+
],
|
|
49779
|
+
"description": "organization: all of the organization's mail. own: only your own. limited: some inboxes or domains."
|
|
49780
|
+
},
|
|
49781
|
+
"own_mail": {
|
|
49782
|
+
"type": "boolean",
|
|
49783
|
+
"description": "Whether a rule over only your own mail would run for you."
|
|
49784
|
+
},
|
|
49785
|
+
"own_mail_to_block": {
|
|
49786
|
+
"description": "Whether a do_not_share rule over only your own mail would run for you: it covers every own mailbox you read, including ones you could not share.",
|
|
49787
|
+
"type": "boolean"
|
|
49788
|
+
},
|
|
49789
|
+
"addresses": {
|
|
49790
|
+
"type": "array",
|
|
49791
|
+
"items": { "type": "string" },
|
|
49792
|
+
"description": "Inboxes you can read, matching q. For someone who reads the whole organization, the inboxes known as someone's: member addresses, members' verified work emails at the organization's domains, agents' addresses and inboxes with shared access. Otherwise the inboxes your access lists (search with q for those past the first page). See may_name_unlisted for what else you may name."
|
|
49793
|
+
},
|
|
49794
|
+
"domains": {
|
|
49795
|
+
"type": "array",
|
|
49796
|
+
"items": { "type": "string" },
|
|
49797
|
+
"description": "Domains you can read, matching q."
|
|
49798
|
+
},
|
|
49799
|
+
"more": {
|
|
49800
|
+
"type": "boolean",
|
|
49801
|
+
"description": "More match than are listed."
|
|
49802
|
+
},
|
|
49803
|
+
"may_name_unlisted": {
|
|
49804
|
+
"description": "Whether you may also name an inbox this list never shows, however it is searched (more only says whether a search would show further ones): true when you read the whole organization (any address, such as an inbox at its domains nobody has claimed yet) or read a domain (any address there your access does not leave out). Name it in scope_selection.addresses as you would a listed one. Absent from a server that predates it.",
|
|
49805
|
+
"type": "boolean"
|
|
49806
|
+
}
|
|
49807
|
+
},
|
|
49808
|
+
"required": [
|
|
49809
|
+
"reach",
|
|
49810
|
+
"own_mail",
|
|
49811
|
+
"addresses",
|
|
49812
|
+
"domains",
|
|
49813
|
+
"more"
|
|
49814
|
+
]
|
|
49815
|
+
},
|
|
48795
49816
|
"CreateEmailRuleRequestRequest": {
|
|
48796
49817
|
"type": "object",
|
|
48797
49818
|
"properties": {
|
|
@@ -49974,6 +50995,35 @@ const openapiDocument = {
|
|
|
49974
50995
|
"active"
|
|
49975
50996
|
]
|
|
49976
50997
|
},
|
|
50998
|
+
"kind": {
|
|
50999
|
+
"description": "do_not_share: the rule blocks sharing of what it matches. Absent (or grant) on a rule that shares what it matches.",
|
|
51000
|
+
"type": "string",
|
|
51001
|
+
"enum": ["grant", "do_not_share"]
|
|
51002
|
+
},
|
|
51003
|
+
"evaluation_scope": {
|
|
51004
|
+
"description": "Whose mail the rule runs over, as stored; GET /email-rules/{id}/scope says what that comes to now.",
|
|
51005
|
+
"type": "string",
|
|
51006
|
+
"enum": [
|
|
51007
|
+
"author",
|
|
51008
|
+
"own_mailboxes",
|
|
51009
|
+
"selected"
|
|
51010
|
+
]
|
|
51011
|
+
},
|
|
51012
|
+
"scope_selection": {
|
|
51013
|
+
"type": ["object", "null"],
|
|
51014
|
+
"properties": {
|
|
51015
|
+
"addresses": {
|
|
51016
|
+
"type": "array",
|
|
51017
|
+
"items": { "type": "string" }
|
|
51018
|
+
},
|
|
51019
|
+
"domains": {
|
|
51020
|
+
"type": "array",
|
|
51021
|
+
"items": { "type": "string" }
|
|
51022
|
+
}
|
|
51023
|
+
},
|
|
51024
|
+
"required": ["addresses", "domains"],
|
|
51025
|
+
"description": "What a selected rule names; null for any other scope."
|
|
51026
|
+
},
|
|
49977
51027
|
"current_version": {
|
|
49978
51028
|
"type": ["integer", "null"],
|
|
49979
51029
|
"exclusiveMinimum": 0
|
|
@@ -67819,7 +68869,7 @@ const operationManifest = [
|
|
|
67819
68869
|
"binaryResponse": false,
|
|
67820
68870
|
"bodyRequired": true,
|
|
67821
68871
|
"command": "create-key",
|
|
67822
|
-
"description": "Create an API key, super admin or narrowed to a preset or a custom permission set, optionally with an expiry and conditions. The secret is returned once. A key never holds more than the person creating it; the credential policy decides who may create which keys. grant is required: a request without it is refused (400 validation_error, details.reason grant_required), never treated as super admin. A custom key must say which mail it reaches: the addresses and domains it lists (grant.addresses, grant.domains), or every mailbox in the organization with grant.mail_scope \"org\", which cannot be combined with them; one that says neither is refused (400 validation_error, details.reason mail_scope_required). Super admin, Send only and Read only reach every mailbox by definition. members:read is only for an org-wide custom key: naming it with grant.addresses or grant.domains is refused (400). Owners and admins are emailed about every super admin key. Send an Idempotency-Key to retry safely: a second create by the same person under the same key makes no second key and is refused (409 idempotency_key_reused) with the first key's id in error.details.key_id, so a caller whose first answer was lost can revoke that key. The onboarding field is for the dashboard only. The
|
|
68872
|
+
"description": "Create an API key, super admin or narrowed to a preset or a custom permission set, optionally with an expiry and conditions. The secret is returned once. A key never holds more than the person creating it; the credential policy decides who may create which keys. grant is required: a request without it is refused (400 validation_error, details.reason grant_required), never treated as super admin. A custom key must say which mail it reaches: the addresses and domains it lists (grant.addresses, grant.domains), or every mailbox in the organization with grant.mail_scope \"org\", which cannot be combined with them; one that says neither is refused (400 validation_error, details.reason mail_scope_required). Super admin, Send only and Read only reach every mailbox by definition. members:read is only for an org-wide custom key: naming it with grant.addresses or grant.domains is refused (400). Owners and admins are emailed about every super admin key. Send an Idempotency-Key to retry safely: a second create by the same person under the same key makes no second key and is refused (409 idempotency_key_reused) with the first key's id in error.details.key_id, so a caller whose first answer was lost can revoke that key. The onboarding field is for the dashboard only. The person's own Primitive CLI login needs no step-up (it acts as the person, held to the same rules); the Primitive app's token is refused, even with one. While the organization's keys API is not enabled, this answers 404 feature_disabled (details.feature keys_api; only Primitive turns it on), except that a dashboard session may still create a super admin key (the dashboard's own create).\n\nPerson only: a dashboard session, the person's own Primitive CLI login with no step-up, or the person's own OAuth token with a step-up token for purpose `keys.create` in the Primitive-Step-Up header. Without one any other OAuth token is answered 403 step_up_required, whose details carry the dashboard URL that issues it (or 403 grant_forbidden when the person's role, or the client, could not do it anyway). The person's role must hold keys:manage. API keys and agent connection keys are refused. An agent acting for the person is refused unless it carries a step-up token the person issued in the dashboard.",
|
|
67823
68873
|
"hasJsonBody": true,
|
|
67824
68874
|
"method": "POST",
|
|
67825
68875
|
"operationId": "createKey",
|
|
@@ -67842,7 +68892,7 @@ const operationManifest = [
|
|
|
67842
68892
|
"type": "string"
|
|
67843
68893
|
},
|
|
67844
68894
|
{
|
|
67845
|
-
"description": "A single-use step-up token of purpose `keys.create` (Create, rotate or change an API key), valid 5 minutes. When this operation answers 403 `step_up_required`, the person confirms at the link in `details.step_up_url` and the request is retried with the token that page shows, in this header. Accepted only with the person's own OAuth token of the client it was confirmed for; refused with a token issued for MCP, with any API key or agent connection key, and with a dashboard session. The Primitive
|
|
68895
|
+
"description": "A single-use step-up token of purpose `keys.create` (Create, rotate or change an API key), valid 5 minutes. When this operation answers 403 `step_up_required`, the person confirms at the link in `details.step_up_url` and the request is retried with the token that page shows, in this header. Accepted only with the person's own OAuth token of the client it was confirmed for; refused with a token issued for MCP, with any API key or agent connection key, and with a dashboard session. The Primitive app is refused for this purpose even with a token (403 `grant_forbidden`, `details.reason` `dashboard_only`). The person's own Primitive CLI login needs no token for this purpose while the organization's keys API is on (a token it sends is still checked); while it is off, a token it sends is refused the same way.",
|
|
67846
68896
|
"enum": null,
|
|
67847
68897
|
"name": "Primitive-Step-Up",
|
|
67848
68898
|
"required": false,
|
|
@@ -68071,7 +69121,7 @@ const operationManifest = [
|
|
|
68071
69121
|
"binaryResponse": false,
|
|
68072
69122
|
"bodyRequired": false,
|
|
68073
69123
|
"command": "get-credential-policy",
|
|
68074
|
-
"description": "The organization credential policy: key lifetime and expiry rules, who may create super admin keys, whether members may create keys and the other rules every new key is held to. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled.\n\nPerson only: a dashboard session. The person's role must hold credentials:read. API keys, agent connection keys and agents are refused.",
|
|
69124
|
+
"description": "The organization credential policy: key lifetime and expiry rules, who may create super admin keys, whether members may create keys and the other rules every new key is held to. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session. The person's role must hold credentials:read. API keys, agent connection keys and agents are refused.",
|
|
68075
69125
|
"hasJsonBody": false,
|
|
68076
69126
|
"method": "GET",
|
|
68077
69127
|
"operationId": "getCredentialPolicy",
|
|
@@ -68130,7 +69180,7 @@ const operationManifest = [
|
|
|
68130
69180
|
"binaryResponse": false,
|
|
68131
69181
|
"bodyRequired": false,
|
|
68132
69182
|
"command": "get-key",
|
|
68133
|
-
"description": "One key's metadata, never its secret. The person needs access to the whole organization's mail. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled.\n\nPerson only: a dashboard session or the person's own Primitive CLI token; no other OAuth app. The person's role must hold keys:read. API keys, agent connection keys and agents are refused.",
|
|
69183
|
+
"description": "One key's metadata, never its secret. The person needs access to the whole organization's mail. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session or the person's own Primitive CLI token; no other OAuth app. The person's role must hold keys:read. API keys, agent connection keys and agents are refused.",
|
|
68134
69184
|
"hasJsonBody": false,
|
|
68135
69185
|
"method": "GET",
|
|
68136
69186
|
"operationId": "getKey",
|
|
@@ -68208,7 +69258,7 @@ const operationManifest = [
|
|
|
68208
69258
|
"binaryResponse": false,
|
|
68209
69259
|
"bodyRequired": false,
|
|
68210
69260
|
"command": "get-key-builder",
|
|
68211
|
-
"description": "The key presets the caller may use (each with whether it is available and why not), the permission matrix for custom keys and the policy in force. An area marked org_wide_only (Members) is listed only to a person who holds its permission, and only a custom key with no addresses or domains may hold it. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled.\n\nPerson only: a dashboard session. The person's role must hold keys:read. API keys, agent connection keys and agents are refused.",
|
|
69261
|
+
"description": "The key presets the caller may use (each with whether it is available and why not), the permission matrix for custom keys and the policy in force. An area marked org_wide_only (Members) is listed only to a person who holds its permission, and only a custom key with no addresses or domains may hold it. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session. The person's role must hold keys:read. API keys, agent connection keys and agents are refused.",
|
|
68212
69262
|
"hasJsonBody": false,
|
|
68213
69263
|
"method": "GET",
|
|
68214
69264
|
"operationId": "getKeyBuilder",
|
|
@@ -68341,7 +69391,7 @@ const operationManifest = [
|
|
|
68341
69391
|
"binaryResponse": false,
|
|
68342
69392
|
"bodyRequired": false,
|
|
68343
69393
|
"command": "get-key-suggestion",
|
|
68344
|
-
"description": "The permissions a key used over the last 30 days, as a custom grant that would have served every successful call (also as builder areas), the narrowest mail scope its calls support (depth is deprecated: raw when it downloaded raw MIME, otherwise content) (the mailboxes of the messages it named and sent, with notes on what the request log cannot account for), and whether it is unused. Calls to routes only the super admin key can use (groups and mailbox access) derive no permission, since a custom key is refused there; super_admin_only_calls counts them. usage gives the same window anonymized: successful and failed requests per UTC day, the routes called by their declared template (never the called path) with the permission each needed, and how many mailboxes the key read and sent from (counts only, and only for a person with access to the whole organization's mail). Nothing is applied: narrowing is a change to the key (PATCH /v1/keys/:id). Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled.\n\nPerson only: a dashboard session. The person's role must hold credentials:read. API keys, agent connection keys and agents are refused.",
|
|
69394
|
+
"description": "The permissions a key used over the last 30 days, as a custom grant that would have served every successful call (also as builder areas), the narrowest mail scope its calls support (depth is deprecated: raw when it downloaded raw MIME, otherwise content) (the mailboxes of the messages it named and sent, with notes on what the request log cannot account for), and whether it is unused. Calls to routes only the super admin key can use (groups and mailbox access) derive no permission, since a custom key is refused there; super_admin_only_calls counts them. usage gives the same window anonymized: successful and failed requests per UTC day, the routes called by their declared template (never the called path) with the permission each needed, and how many mailboxes the key read and sent from (counts only, and only for a person with access to the whole organization's mail). Nothing is applied: narrowing is a change to the key (PATCH /v1/keys/:id). Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session. The person's role must hold credentials:read. API keys, agent connection keys and agents are refused.",
|
|
68345
69395
|
"hasJsonBody": false,
|
|
68346
69396
|
"method": "GET",
|
|
68347
69397
|
"operationId": "getKeySuggestion",
|
|
@@ -68585,7 +69635,7 @@ const operationManifest = [
|
|
|
68585
69635
|
"binaryResponse": false,
|
|
68586
69636
|
"bodyRequired": false,
|
|
68587
69637
|
"command": "list-credential-events",
|
|
68588
|
-
"description": "Credential events (created, rotated, edited, revoked, used with a step-up, policy changes), newest first, with a cursor. format=csv returns the same page as CSV. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled.\n\nPerson only: a dashboard session. The person's role must hold credential_events:read. API keys, agent connection keys and agents are refused.",
|
|
69638
|
+
"description": "Credential events (created, rotated, edited, revoked, used with a step-up, policy changes), newest first, with a cursor. format=csv returns the same page as CSV. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session. The person's role must hold credential_events:read. API keys, agent connection keys and agents are refused.",
|
|
68589
69639
|
"hasJsonBody": false,
|
|
68590
69640
|
"method": "GET",
|
|
68591
69641
|
"operationId": "listCredentialEvents",
|
|
@@ -68714,7 +69764,7 @@ const operationManifest = [
|
|
|
68714
69764
|
"binaryResponse": false,
|
|
68715
69765
|
"bodyRequired": false,
|
|
68716
69766
|
"command": "list-credentials",
|
|
68717
|
-
"description": "Every credential that can act in the organization: API keys, Function keys, agent connection keys, connected apps (OAuth), agent delegates and, where enabled, CLI logins. Secrets are never returned. Filter with kind. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled.\n\nPerson only: a dashboard session. The person's role must hold credentials:read. API keys, agent connection keys and agents are refused.",
|
|
69767
|
+
"description": "Every credential that can act in the organization: API keys, Function keys, agent connection keys, connected apps (OAuth), agent delegates and, where enabled, CLI logins. Secrets are never returned. Filter with kind. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session. The person's role must hold credentials:read. API keys, agent connection keys and agents are refused.",
|
|
68718
69768
|
"hasJsonBody": false,
|
|
68719
69769
|
"method": "GET",
|
|
68720
69770
|
"operationId": "listCredentials",
|
|
@@ -68950,7 +70000,7 @@ const operationManifest = [
|
|
|
68950
70000
|
"binaryResponse": false,
|
|
68951
70001
|
"bodyRequired": false,
|
|
68952
70002
|
"command": "list-keys",
|
|
68953
|
-
"description": "Key metadata, never a secret: name, prefix, grant, creator, last use, expiry and suspension. The person needs access to the whole organization's mail. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled.\n\nPerson only: a dashboard session or the person's own Primitive CLI token; no other OAuth app. The person's role must hold keys:read. API keys, agent connection keys and agents are refused.",
|
|
70003
|
+
"description": "Key metadata, never a secret: name, prefix, grant, creator, last use, expiry and suspension. The person needs access to the whole organization's mail. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session or the person's own Primitive CLI token; no other OAuth app. The person's role must hold keys:read. API keys, agent connection keys and agents are refused.",
|
|
68954
70004
|
"hasJsonBody": false,
|
|
68955
70005
|
"method": "GET",
|
|
68956
70006
|
"operationId": "listKeys",
|
|
@@ -69039,7 +70089,7 @@ const operationManifest = [
|
|
|
69039
70089
|
"binaryResponse": false,
|
|
69040
70090
|
"bodyRequired": true,
|
|
69041
70091
|
"command": "revoke-all-credentials",
|
|
69042
|
-
"description": "The emergency response to a leak: revokes every API key, agent connection key and connected app created since a time, rotates the organization Function key and every running Function's own key, and optionally suspends Functions. Owners only, from a dashboard session, and the body must confirm with \"revoke all\". Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled.\n\nPerson only: a dashboard session. The person's role must hold credentials:revoke_all. API keys, agent connection keys and agents are refused.",
|
|
70092
|
+
"description": "The emergency response to a leak: revokes every API key, agent connection key and connected app created since a time, rotates the organization Function key and every running Function's own key, and optionally suspends Functions. Owners only, from a dashboard session, and the body must confirm with \"revoke all\". Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session. The person's role must hold credentials:revoke_all. API keys, agent connection keys and agents are refused.",
|
|
69043
70093
|
"hasJsonBody": true,
|
|
69044
70094
|
"method": "POST",
|
|
69045
70095
|
"operationId": "revokeAllCredentials",
|
|
@@ -69124,7 +70174,7 @@ const operationManifest = [
|
|
|
69124
70174
|
"binaryResponse": false,
|
|
69125
70175
|
"bodyRequired": true,
|
|
69126
70176
|
"command": "revoke-credential",
|
|
69127
|
-
"description": "Revoke one credential by kind and id. A Function key is rotated, never revoked (409 rotate_instead). An API key is revoked only by a person whose own access covers the key's access (an owner covers every key); otherwise 403 grant_forbidden, details.reason target_not_covered. What the credential set up keeps working and is listed in standing_objects for review. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled.\n\nPerson only: a dashboard session. The person's role must hold keys:manage. API keys, agent connection keys and agents are refused.",
|
|
70177
|
+
"description": "Revoke one credential by kind and id. A Function key is rotated, never revoked (409 rotate_instead). An API key is revoked only by a person whose own access covers the key's access (an owner covers every key); otherwise 403 grant_forbidden, details.reason target_not_covered. What the credential set up keeps working and is listed in standing_objects for review. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session. The person's role must hold keys:manage. API keys, agent connection keys and agents are refused.",
|
|
69128
70178
|
"hasJsonBody": true,
|
|
69129
70179
|
"method": "POST",
|
|
69130
70180
|
"operationId": "revokeCredential",
|
|
@@ -69246,7 +70296,7 @@ const operationManifest = [
|
|
|
69246
70296
|
"binaryResponse": false,
|
|
69247
70297
|
"bodyRequired": true,
|
|
69248
70298
|
"command": "rotate-key",
|
|
69249
|
-
"description": "Mint a successor with the same grant and return its secret once. The old key keeps working for overlap_seconds, then stops. The person rotating must cover the key's access (403 grant_forbidden, details.reason target_not_covered), and a key an owner created is rotated by an owner only (403 forbidden, details.reason owner_key_rotation), since rotating hands over the new secret. The Primitive CLI's token is refused, even with
|
|
70299
|
+
"description": "Mint a successor with the same grant and return its secret once. The old key keeps working for overlap_seconds, then stops. The person rotating must cover the key's access (403 grant_forbidden, details.reason target_not_covered), and a key an owner created is rotated by an owner only (403 forbidden, details.reason owner_key_rotation), since rotating hands over the new secret. The person's own Primitive CLI login needs no step-up (it acts as the person, held to the same rules); the Primitive app's token is refused, even with one. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session, the person's own Primitive CLI login with no step-up, or the person's own OAuth token with a step-up token for purpose `keys.create` in the Primitive-Step-Up header. Without one any other OAuth token is answered 403 step_up_required, whose details carry the dashboard URL that issues it (or 403 grant_forbidden when the person's role, or the client, could not do it anyway). The person's role must hold keys:manage. API keys and agent connection keys are refused. An agent acting for the person is refused unless it carries a step-up token the person issued in the dashboard.",
|
|
69250
70300
|
"hasJsonBody": true,
|
|
69251
70301
|
"method": "POST",
|
|
69252
70302
|
"operationId": "rotateKey",
|
|
@@ -69260,7 +70310,7 @@ const operationManifest = [
|
|
|
69260
70310
|
}],
|
|
69261
70311
|
"queryParams": [],
|
|
69262
70312
|
"headerParams": [{
|
|
69263
|
-
"description": "A single-use step-up token of purpose `keys.create` (Create, rotate or change an API key), valid 5 minutes. When this operation answers 403 `step_up_required`, the person confirms at the link in `details.step_up_url` and the request is retried with the token that page shows, in this header. Accepted only with the person's own OAuth token of the client it was confirmed for; refused with a token issued for MCP, with any API key or agent connection key, and with a dashboard session. The Primitive
|
|
70313
|
+
"description": "A single-use step-up token of purpose `keys.create` (Create, rotate or change an API key), valid 5 minutes. When this operation answers 403 `step_up_required`, the person confirms at the link in `details.step_up_url` and the request is retried with the token that page shows, in this header. Accepted only with the person's own OAuth token of the client it was confirmed for; refused with a token issued for MCP, with any API key or agent connection key, and with a dashboard session. The Primitive app is refused for this purpose even with a token (403 `grant_forbidden`, `details.reason` `dashboard_only`). The person's own Primitive CLI login needs no token for this purpose while the organization's keys API is on (a token it sends is still checked); while it is off, a token it sends is refused the same way.",
|
|
69264
70314
|
"enum": null,
|
|
69265
70315
|
"name": "Primitive-Step-Up",
|
|
69266
70316
|
"required": false,
|
|
@@ -69318,7 +70368,7 @@ const operationManifest = [
|
|
|
69318
70368
|
"binaryResponse": false,
|
|
69319
70369
|
"bodyRequired": true,
|
|
69320
70370
|
"command": "update-credential-policy",
|
|
69321
|
-
"description": "Change one or more policy rules. Admins may only tighten the policy; loosening any rule needs an owner. Owners and admins are emailed about every change. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled.\n\nPerson only: a dashboard session. The person's role must hold credential_policy:manage. API keys, agent connection keys and agents are refused.",
|
|
70371
|
+
"description": "Change one or more policy rules. Admins may only tighten the policy; loosening any rule needs an owner. Owners and admins are emailed about every change. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session. The person's role must hold credential_policy:manage. API keys, agent connection keys and agents are refused.",
|
|
69322
70372
|
"hasJsonBody": true,
|
|
69323
70373
|
"method": "PATCH",
|
|
69324
70374
|
"operationId": "updateCredentialPolicy",
|
|
@@ -69406,7 +70456,7 @@ const operationManifest = [
|
|
|
69406
70456
|
"binaryResponse": false,
|
|
69407
70457
|
"bodyRequired": true,
|
|
69408
70458
|
"command": "update-key",
|
|
69409
|
-
"description": "Rename a key, change its expiry, its grant or its conditions, or suspend it. Any change needs the person's own access to cover the key's access now (an owner covers every key); otherwise 403 grant_forbidden, details.reason target_not_covered. A grant change is a new version of the key and is held to the same rules as creating one (a custom grant that does not say which mail it reaches is refused with details.reason mail_scope_required), so it takes the same step-up. The Primitive CLI's token is refused, even with
|
|
70459
|
+
"description": "Rename a key, change its expiry, its grant or its conditions, or suspend it. Any change needs the person's own access to cover the key's access now (an owner covers every key); otherwise 403 grant_forbidden, details.reason target_not_covered. A grant change is a new version of the key and is held to the same rules as creating one (a custom grant that does not say which mail it reaches is refused with details.reason mail_scope_required), so it takes the same step-up. The person's own Primitive CLI login needs no step-up (it acts as the person, held to the same rules); the Primitive app's token is refused, even with one. Needs the organization's credential features to be enabled; while they are not, this answers 404 feature_disabled, with details.feature naming the feature. Only Primitive turns these on.\n\nPerson only: a dashboard session, the person's own Primitive CLI login with no step-up, or the person's own OAuth token with a step-up token for purpose `keys.create` in the Primitive-Step-Up header. Without one any other OAuth token is answered 403 step_up_required, whose details carry the dashboard URL that issues it (or 403 grant_forbidden when the person's role, or the client, could not do it anyway). The person's role must hold keys:manage. API keys and agent connection keys are refused. An agent acting for the person is refused unless it carries a step-up token the person issued in the dashboard.",
|
|
69410
70460
|
"hasJsonBody": true,
|
|
69411
70461
|
"method": "PATCH",
|
|
69412
70462
|
"operationId": "updateKey",
|
|
@@ -69420,7 +70470,7 @@ const operationManifest = [
|
|
|
69420
70470
|
}],
|
|
69421
70471
|
"queryParams": [],
|
|
69422
70472
|
"headerParams": [{
|
|
69423
|
-
"description": "A single-use step-up token of purpose `keys.create` (Create, rotate or change an API key), valid 5 minutes. When this operation answers 403 `step_up_required`, the person confirms at the link in `details.step_up_url` and the request is retried with the token that page shows, in this header. Accepted only with the person's own OAuth token of the client it was confirmed for; refused with a token issued for MCP, with any API key or agent connection key, and with a dashboard session. The Primitive
|
|
70473
|
+
"description": "A single-use step-up token of purpose `keys.create` (Create, rotate or change an API key), valid 5 minutes. When this operation answers 403 `step_up_required`, the person confirms at the link in `details.step_up_url` and the request is retried with the token that page shows, in this header. Accepted only with the person's own OAuth token of the client it was confirmed for; refused with a token issued for MCP, with any API key or agent connection key, and with a dashboard session. The Primitive app is refused for this purpose even with a token (403 `grant_forbidden`, `details.reason` `dashboard_only`). The person's own Primitive CLI login needs no token for this purpose while the organization's keys API is on (a token it sends is still checked); while it is off, a token it sends is refused the same way.",
|
|
69424
70474
|
"enum": null,
|
|
69425
70475
|
"name": "Primitive-Step-Up",
|
|
69426
70476
|
"required": false,
|
|
@@ -71684,6 +72734,35 @@ const operationManifest = [
|
|
|
71684
72734
|
"active"
|
|
71685
72735
|
]
|
|
71686
72736
|
},
|
|
72737
|
+
"kind": {
|
|
72738
|
+
"description": "do_not_share: the rule blocks sharing of what it matches. Absent (or grant) on a rule that shares what it matches.",
|
|
72739
|
+
"type": "string",
|
|
72740
|
+
"enum": ["grant", "do_not_share"]
|
|
72741
|
+
},
|
|
72742
|
+
"evaluation_scope": {
|
|
72743
|
+
"description": "Whose mail the rule runs over, as stored; GET /email-rules/{id}/scope says what that comes to now.",
|
|
72744
|
+
"type": "string",
|
|
72745
|
+
"enum": [
|
|
72746
|
+
"author",
|
|
72747
|
+
"own_mailboxes",
|
|
72748
|
+
"selected"
|
|
72749
|
+
]
|
|
72750
|
+
},
|
|
72751
|
+
"scope_selection": {
|
|
72752
|
+
"type": ["object", "null"],
|
|
72753
|
+
"properties": {
|
|
72754
|
+
"addresses": {
|
|
72755
|
+
"type": "array",
|
|
72756
|
+
"items": { "type": "string" }
|
|
72757
|
+
},
|
|
72758
|
+
"domains": {
|
|
72759
|
+
"type": "array",
|
|
72760
|
+
"items": { "type": "string" }
|
|
72761
|
+
}
|
|
72762
|
+
},
|
|
72763
|
+
"required": ["addresses", "domains"],
|
|
72764
|
+
"description": "What a selected rule names; null for any other scope."
|
|
72765
|
+
},
|
|
71687
72766
|
"current_version": {
|
|
71688
72767
|
"type": ["integer", "null"],
|
|
71689
72768
|
"exclusiveMinimum": 0
|
|
@@ -72090,7 +73169,7 @@ const operationManifest = [
|
|
|
72090
73169
|
"binaryResponse": false,
|
|
72091
73170
|
"bodyRequired": true,
|
|
72092
73171
|
"command": "create-email-rule",
|
|
72093
|
-
"description": "Saves a rule as version 1, from a compile response or a tree you wrote. The tree is checked against the column contract. New rules start in observe, where what the rule matches is recorded and nothing is granted; draft is not evaluated. The caller is the rule's author, and the rule never reaches mail the author cannot read. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
73172
|
+
"description": "Saves a rule as version 1, from a compile response or a tree you wrote. The tree is checked against the column contract. New rules start in observe, where what the rule matches is recorded and nothing is granted or blocked; draft is not evaluated. The caller is the rule's author, and the rule never reaches mail the author cannot read. evaluation_scope chooses whose mail it runs over: own_mailboxes (only your own mail) when omitted, so any other scope (author for all you can read, or selected) is named; scope_selection may name only what you can read. The answer carries the scope as stored. kind do_not_share makes a rule that blocks sharing: it runs before every other rule, and while it is active no rule shares an email it matches or cannot decide. A key cannot list one (details.reason rule_blocks_sharing on the key). Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
72094
73173
|
"hasJsonBody": true,
|
|
72095
73174
|
"method": "POST",
|
|
72096
73175
|
"operationId": "createEmailRule",
|
|
@@ -72114,11 +73193,52 @@ const operationManifest = [
|
|
|
72114
73193
|
"maxLength": 200,
|
|
72115
73194
|
"description": "A short name for the rule."
|
|
72116
73195
|
},
|
|
73196
|
+
"kind": {
|
|
73197
|
+
"description": "grant (the default): what the rule matches can be shared. do_not_share: the rule runs before every other rule, and while it is active no rule shares an email it matches; an email it cannot decide counts as matched. Set when the rule is created; it never changes.",
|
|
73198
|
+
"type": "string",
|
|
73199
|
+
"enum": ["grant", "do_not_share"]
|
|
73200
|
+
},
|
|
72117
73201
|
"state": {
|
|
72118
|
-
"description": "observe (the default) records what the rule would match and grants nothing; draft is not evaluated.",
|
|
73202
|
+
"description": "observe (the default) records what the rule would match and grants or blocks nothing; draft is not evaluated.",
|
|
72119
73203
|
"type": "string",
|
|
72120
73204
|
"enum": ["draft", "observe"]
|
|
72121
73205
|
},
|
|
73206
|
+
"evaluation_scope": {
|
|
73207
|
+
"type": "string",
|
|
73208
|
+
"enum": [
|
|
73209
|
+
"author",
|
|
73210
|
+
"own_mailboxes",
|
|
73211
|
+
"selected"
|
|
73212
|
+
],
|
|
73213
|
+
"description": "own_mailboxes (the default): mail to your own addresses and agents (for a rule that shares, those you can send from). author: all mail you can read, including inboxes added later. selected: what scope_selection names."
|
|
73214
|
+
},
|
|
73215
|
+
"scope_selection": {
|
|
73216
|
+
"type": "object",
|
|
73217
|
+
"properties": {
|
|
73218
|
+
"addresses": {
|
|
73219
|
+
"maxItems": 100,
|
|
73220
|
+
"type": "array",
|
|
73221
|
+
"items": {
|
|
73222
|
+
"type": "string",
|
|
73223
|
+
"minLength": 3,
|
|
73224
|
+
"maxLength": 320,
|
|
73225
|
+
"pattern": "^[^\\s@]+@[^\\s@]+$"
|
|
73226
|
+
}
|
|
73227
|
+
},
|
|
73228
|
+
"domains": {
|
|
73229
|
+
"maxItems": 50,
|
|
73230
|
+
"type": "array",
|
|
73231
|
+
"items": {
|
|
73232
|
+
"type": "string",
|
|
73233
|
+
"minLength": 1,
|
|
73234
|
+
"maxLength": 253,
|
|
73235
|
+
"pattern": "^[^\\s@]+\\.[^\\s@]+$"
|
|
73236
|
+
}
|
|
73237
|
+
}
|
|
73238
|
+
},
|
|
73239
|
+
"additionalProperties": false,
|
|
73240
|
+
"description": "Inboxes, and domains (every address at them the author can read), for a selected rule; each one you can read."
|
|
73241
|
+
},
|
|
72122
73242
|
"english": {
|
|
72123
73243
|
"type": "string",
|
|
72124
73244
|
"minLength": 1,
|
|
@@ -72214,6 +73334,35 @@ const operationManifest = [
|
|
|
72214
73334
|
"active"
|
|
72215
73335
|
]
|
|
72216
73336
|
},
|
|
73337
|
+
"kind": {
|
|
73338
|
+
"description": "do_not_share: the rule blocks sharing of what it matches. Absent (or grant) on a rule that shares what it matches.",
|
|
73339
|
+
"type": "string",
|
|
73340
|
+
"enum": ["grant", "do_not_share"]
|
|
73341
|
+
},
|
|
73342
|
+
"evaluation_scope": {
|
|
73343
|
+
"description": "Whose mail the rule runs over, as stored; GET /email-rules/{id}/scope says what that comes to now.",
|
|
73344
|
+
"type": "string",
|
|
73345
|
+
"enum": [
|
|
73346
|
+
"author",
|
|
73347
|
+
"own_mailboxes",
|
|
73348
|
+
"selected"
|
|
73349
|
+
]
|
|
73350
|
+
},
|
|
73351
|
+
"scope_selection": {
|
|
73352
|
+
"type": ["object", "null"],
|
|
73353
|
+
"properties": {
|
|
73354
|
+
"addresses": {
|
|
73355
|
+
"type": "array",
|
|
73356
|
+
"items": { "type": "string" }
|
|
73357
|
+
},
|
|
73358
|
+
"domains": {
|
|
73359
|
+
"type": "array",
|
|
73360
|
+
"items": { "type": "string" }
|
|
73361
|
+
}
|
|
73362
|
+
},
|
|
73363
|
+
"required": ["addresses", "domains"],
|
|
73364
|
+
"description": "What a selected rule names; null for any other scope."
|
|
73365
|
+
},
|
|
72217
73366
|
"current_version": {
|
|
72218
73367
|
"type": ["integer", "null"],
|
|
72219
73368
|
"exclusiveMinimum": 0
|
|
@@ -72882,7 +74031,7 @@ const operationManifest = [
|
|
|
72882
74031
|
"binaryResponse": false,
|
|
72883
74032
|
"bodyRequired": false,
|
|
72884
74033
|
"command": "get-email-rule",
|
|
72885
|
-
"description": "A rule and its current version. The SQL the version renders to is included only when include_sql is true. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
74034
|
+
"description": "A rule, its scope (evaluation_scope, and scope_selection for a selected rule) and its current version. What the scope comes to for its author now is GET /email-rules/{id}/scope. The SQL the version renders to is included only when include_sql is true. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
72886
74035
|
"hasJsonBody": false,
|
|
72887
74036
|
"method": "GET",
|
|
72888
74037
|
"operationId": "getEmailRule",
|
|
@@ -72920,6 +74069,35 @@ const operationManifest = [
|
|
|
72920
74069
|
"active"
|
|
72921
74070
|
]
|
|
72922
74071
|
},
|
|
74072
|
+
"kind": {
|
|
74073
|
+
"description": "do_not_share: the rule blocks sharing of what it matches. Absent (or grant) on a rule that shares what it matches.",
|
|
74074
|
+
"type": "string",
|
|
74075
|
+
"enum": ["grant", "do_not_share"]
|
|
74076
|
+
},
|
|
74077
|
+
"evaluation_scope": {
|
|
74078
|
+
"description": "Whose mail the rule runs over, as stored; GET /email-rules/{id}/scope says what that comes to now.",
|
|
74079
|
+
"type": "string",
|
|
74080
|
+
"enum": [
|
|
74081
|
+
"author",
|
|
74082
|
+
"own_mailboxes",
|
|
74083
|
+
"selected"
|
|
74084
|
+
]
|
|
74085
|
+
},
|
|
74086
|
+
"scope_selection": {
|
|
74087
|
+
"type": ["object", "null"],
|
|
74088
|
+
"properties": {
|
|
74089
|
+
"addresses": {
|
|
74090
|
+
"type": "array",
|
|
74091
|
+
"items": { "type": "string" }
|
|
74092
|
+
},
|
|
74093
|
+
"domains": {
|
|
74094
|
+
"type": "array",
|
|
74095
|
+
"items": { "type": "string" }
|
|
74096
|
+
}
|
|
74097
|
+
},
|
|
74098
|
+
"required": ["addresses", "domains"],
|
|
74099
|
+
"description": "What a selected rule names; null for any other scope."
|
|
74100
|
+
},
|
|
72923
74101
|
"current_version": {
|
|
72924
74102
|
"type": ["integer", "null"],
|
|
72925
74103
|
"exclusiveMinimum": 0
|
|
@@ -73231,6 +74409,105 @@ const operationManifest = [
|
|
|
73231
74409
|
"tag": "Email Rules",
|
|
73232
74410
|
"tagCommand": "email-rules"
|
|
73233
74411
|
},
|
|
74412
|
+
{
|
|
74413
|
+
"binaryResponse": false,
|
|
74414
|
+
"bodyRequired": false,
|
|
74415
|
+
"command": "get-email-rule-scope",
|
|
74416
|
+
"description": "Whose mail the rule runs over, and what that comes to now: a rule never reaches further than what its author can read when it runs, so what a selected rule names and its author can no longer read stops matching. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
74417
|
+
"hasJsonBody": false,
|
|
74418
|
+
"method": "GET",
|
|
74419
|
+
"operationId": "getEmailRuleScope",
|
|
74420
|
+
"path": "/email-rules/{id}/scope",
|
|
74421
|
+
"pathParams": [{
|
|
74422
|
+
"description": "The rule id.",
|
|
74423
|
+
"enum": null,
|
|
74424
|
+
"name": "id",
|
|
74425
|
+
"required": true,
|
|
74426
|
+
"type": "string"
|
|
74427
|
+
}],
|
|
74428
|
+
"queryParams": [],
|
|
74429
|
+
"headerParams": [],
|
|
74430
|
+
"permissions": ["mail:read"],
|
|
74431
|
+
"requestSchema": null,
|
|
74432
|
+
"responseSchema": {
|
|
74433
|
+
"type": "object",
|
|
74434
|
+
"properties": {
|
|
74435
|
+
"evaluation_scope": {
|
|
74436
|
+
"type": "string",
|
|
74437
|
+
"enum": [
|
|
74438
|
+
"author",
|
|
74439
|
+
"own_mailboxes",
|
|
74440
|
+
"selected"
|
|
74441
|
+
],
|
|
74442
|
+
"description": "author: all mail its author can read. own_mailboxes: mail to their own addresses. selected: what scope_selection names. Never more than the author can read."
|
|
74443
|
+
},
|
|
74444
|
+
"scope_selection": {
|
|
74445
|
+
"type": ["object", "null"],
|
|
74446
|
+
"properties": {
|
|
74447
|
+
"addresses": {
|
|
74448
|
+
"type": "array",
|
|
74449
|
+
"items": { "type": "string" }
|
|
74450
|
+
},
|
|
74451
|
+
"domains": {
|
|
74452
|
+
"type": "array",
|
|
74453
|
+
"items": { "type": "string" }
|
|
74454
|
+
}
|
|
74455
|
+
},
|
|
74456
|
+
"required": ["addresses", "domains"]
|
|
74457
|
+
},
|
|
74458
|
+
"locked": {
|
|
74459
|
+
"type": "boolean",
|
|
74460
|
+
"description": "Shared, so its scope cannot change."
|
|
74461
|
+
},
|
|
74462
|
+
"author_reach": {
|
|
74463
|
+
"type": ["string", "null"],
|
|
74464
|
+
"enum": [
|
|
74465
|
+
"organization",
|
|
74466
|
+
"limited",
|
|
74467
|
+
"own",
|
|
74468
|
+
null
|
|
74469
|
+
],
|
|
74470
|
+
"description": "How much its author can read now; null when it cannot run as them."
|
|
74471
|
+
},
|
|
74472
|
+
"no_longer_readable": {
|
|
74473
|
+
"type": "object",
|
|
74474
|
+
"properties": {
|
|
74475
|
+
"addresses": {
|
|
74476
|
+
"type": "array",
|
|
74477
|
+
"items": { "type": "string" }
|
|
74478
|
+
},
|
|
74479
|
+
"domains": {
|
|
74480
|
+
"type": "array",
|
|
74481
|
+
"items": { "type": "string" }
|
|
74482
|
+
}
|
|
74483
|
+
},
|
|
74484
|
+
"required": ["addresses", "domains"],
|
|
74485
|
+
"description": "What scope_selection names that its author no longer reads in full."
|
|
74486
|
+
},
|
|
74487
|
+
"still_read": {
|
|
74488
|
+
"description": "Inboxes its author still reads at the domains in no_longer_readable; the rule still covers them.",
|
|
74489
|
+
"type": "array",
|
|
74490
|
+
"items": { "type": "string" }
|
|
74491
|
+
},
|
|
74492
|
+
"stopped_reason": {
|
|
74493
|
+
"description": "Why it cannot run now (a reason as on POST /email-rules/test), or null.",
|
|
74494
|
+
"type": ["string", "null"]
|
|
74495
|
+
}
|
|
74496
|
+
},
|
|
74497
|
+
"required": [
|
|
74498
|
+
"evaluation_scope",
|
|
74499
|
+
"scope_selection",
|
|
74500
|
+
"locked",
|
|
74501
|
+
"author_reach",
|
|
74502
|
+
"no_longer_readable",
|
|
74503
|
+
"stopped_reason"
|
|
74504
|
+
]
|
|
74505
|
+
},
|
|
74506
|
+
"sdkName": "getEmailRuleScope",
|
|
74507
|
+
"summary": "Read what a rule covers",
|
|
74508
|
+
"tag": "Email Rules",
|
|
74509
|
+
"tagCommand": "email-rules"
|
|
74510
|
+
},
|
|
73234
74511
|
{
|
|
73235
74512
|
"binaryResponse": false,
|
|
73236
74513
|
"bodyRequired": false,
|
|
@@ -73742,6 +75019,258 @@ const operationManifest = [
|
|
|
73742
75019
|
"tag": "Email Rules",
|
|
73743
75020
|
"tagCommand": "email-rules"
|
|
73744
75021
|
},
|
|
75022
|
+
{
|
|
75023
|
+
"binaryResponse": false,
|
|
75024
|
+
"bodyRequired": false,
|
|
75025
|
+
"command": "list-email-rule-results",
|
|
75026
|
+
"description": "Every rule the caller can see and what it decided about this email: those that matched, those that did not, and those that have not run on it, with what is known about them. A result names the version of the rule that decided and carries that version's conditions and questions. A matched rule with kind do_not_share keeps rules from sharing the email while it is active; anything shared before then stays shared. Only a caller who can read the email gets an answer, and a rule the caller cannot see is left out. At most 50 rules are listed, those with a result first; hidden counts the rest. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
75027
|
+
"hasJsonBody": false,
|
|
75028
|
+
"method": "GET",
|
|
75029
|
+
"operationId": "listEmailRuleResults",
|
|
75030
|
+
"path": "/emails/{id}/rule-results",
|
|
75031
|
+
"pathParams": [{
|
|
75032
|
+
"description": "The email id.",
|
|
75033
|
+
"enum": null,
|
|
75034
|
+
"name": "id",
|
|
75035
|
+
"required": true,
|
|
75036
|
+
"type": "string"
|
|
75037
|
+
}],
|
|
75038
|
+
"queryParams": [],
|
|
75039
|
+
"headerParams": [],
|
|
75040
|
+
"permissions": ["mail:read"],
|
|
75041
|
+
"requestSchema": null,
|
|
75042
|
+
"responseSchema": {
|
|
75043
|
+
"type": "object",
|
|
75044
|
+
"properties": {
|
|
75045
|
+
"rules": {
|
|
75046
|
+
"type": "array",
|
|
75047
|
+
"items": {
|
|
75048
|
+
"type": "object",
|
|
75049
|
+
"properties": {
|
|
75050
|
+
"id": {
|
|
75051
|
+
"type": "string",
|
|
75052
|
+
"format": "uuid"
|
|
75053
|
+
},
|
|
75054
|
+
"name": { "type": "string" },
|
|
75055
|
+
"state": {
|
|
75056
|
+
"type": "string",
|
|
75057
|
+
"enum": [
|
|
75058
|
+
"draft",
|
|
75059
|
+
"observe",
|
|
75060
|
+
"active"
|
|
75061
|
+
]
|
|
75062
|
+
},
|
|
75063
|
+
"kind": {
|
|
75064
|
+
"description": "do_not_share: the rule blocks sharing of what it matches. While it is active, no rule shares an email it has matched from then on; anything shared before, including while it was in observe, stays shared. Absent on a rule that shares what it matches.",
|
|
75065
|
+
"type": "string",
|
|
75066
|
+
"enum": ["grant", "do_not_share"]
|
|
75067
|
+
},
|
|
75068
|
+
"decision": {
|
|
75069
|
+
"type": ["object", "null"],
|
|
75070
|
+
"properties": {
|
|
75071
|
+
"rule_version": {
|
|
75072
|
+
"type": "integer",
|
|
75073
|
+
"exclusiveMinimum": 0,
|
|
75074
|
+
"description": "The version of the rule that decided."
|
|
75075
|
+
},
|
|
75076
|
+
"matched": { "type": "boolean" },
|
|
75077
|
+
"parts": {
|
|
75078
|
+
"type": "array",
|
|
75079
|
+
"items": {
|
|
75080
|
+
"type": "object",
|
|
75081
|
+
"properties": {
|
|
75082
|
+
"index": {
|
|
75083
|
+
"type": "integer",
|
|
75084
|
+
"minimum": 0
|
|
75085
|
+
},
|
|
75086
|
+
"matched": { "type": "boolean" },
|
|
75087
|
+
"columns": {
|
|
75088
|
+
"type": "array",
|
|
75089
|
+
"items": { "type": "string" }
|
|
75090
|
+
}
|
|
75091
|
+
},
|
|
75092
|
+
"required": [
|
|
75093
|
+
"index",
|
|
75094
|
+
"matched",
|
|
75095
|
+
"columns"
|
|
75096
|
+
]
|
|
75097
|
+
},
|
|
75098
|
+
"description": "How each top-level part of the rule decided. Empty when a fact the rule reads was missing, so it was not evaluated."
|
|
75099
|
+
},
|
|
75100
|
+
"question_answers": {
|
|
75101
|
+
"type": "array",
|
|
75102
|
+
"items": {
|
|
75103
|
+
"type": "object",
|
|
75104
|
+
"properties": {
|
|
75105
|
+
"question": { "type": "string" },
|
|
75106
|
+
"answer": { "type": ["boolean", "null"] },
|
|
75107
|
+
"probability": { "type": ["number", "null"] },
|
|
75108
|
+
"error_class": { "type": "string" }
|
|
75109
|
+
},
|
|
75110
|
+
"required": [
|
|
75111
|
+
"question",
|
|
75112
|
+
"answer",
|
|
75113
|
+
"probability"
|
|
75114
|
+
]
|
|
75115
|
+
},
|
|
75116
|
+
"description": "The answers to the rule's own questions, asked only when its conditions matched."
|
|
75117
|
+
},
|
|
75118
|
+
"tree": {
|
|
75119
|
+
"type": ["object", "null"],
|
|
75120
|
+
"properties": {
|
|
75121
|
+
"version": {
|
|
75122
|
+
"type": "number",
|
|
75123
|
+
"const": 1
|
|
75124
|
+
},
|
|
75125
|
+
"vocabulary": {
|
|
75126
|
+
"type": "string",
|
|
75127
|
+
"description": "The column contract version the rule is written against, for example v1."
|
|
75128
|
+
},
|
|
75129
|
+
"when": {
|
|
75130
|
+
"type": "object",
|
|
75131
|
+
"propertyNames": { "type": "string" },
|
|
75132
|
+
"additionalProperties": {},
|
|
75133
|
+
"description": "The rule's conditions: a condition ({column, op, value?, min_confidence?}) or a group ({all: [...]}, {any: [...]} or {not: ...})."
|
|
75134
|
+
},
|
|
75135
|
+
"questions": {
|
|
75136
|
+
"type": "array",
|
|
75137
|
+
"items": { "type": "string" },
|
|
75138
|
+
"description": "Yes/no questions of the rule's own, asked about an email only after its conditions match. An email matches only if every answer is yes."
|
|
75139
|
+
}
|
|
75140
|
+
},
|
|
75141
|
+
"required": [
|
|
75142
|
+
"version",
|
|
75143
|
+
"vocabulary",
|
|
75144
|
+
"when",
|
|
75145
|
+
"questions"
|
|
75146
|
+
],
|
|
75147
|
+
"description": "The conditions and questions of the version that decided, so the result reads in that version's words."
|
|
75148
|
+
},
|
|
75149
|
+
"created_at": {
|
|
75150
|
+
"type": "string",
|
|
75151
|
+
"format": "date-time"
|
|
75152
|
+
}
|
|
75153
|
+
},
|
|
75154
|
+
"required": [
|
|
75155
|
+
"rule_version",
|
|
75156
|
+
"matched",
|
|
75157
|
+
"parts",
|
|
75158
|
+
"question_answers",
|
|
75159
|
+
"tree",
|
|
75160
|
+
"created_at"
|
|
75161
|
+
],
|
|
75162
|
+
"description": "What the rule most recently decided about this email; null when it has not run on it."
|
|
75163
|
+
},
|
|
75164
|
+
"not_run_reason": {
|
|
75165
|
+
"type": ["string", "null"],
|
|
75166
|
+
"enum": [
|
|
75167
|
+
"draft",
|
|
75168
|
+
"created_after_email",
|
|
75169
|
+
null
|
|
75170
|
+
],
|
|
75171
|
+
"description": "What is known about a rule with no result on this email. draft: the rule is a draft now. created_after_email: the rule was created after the email arrived. Null when it has a result, or when nothing is known."
|
|
75172
|
+
},
|
|
75173
|
+
"author_left": {
|
|
75174
|
+
"description": "On a do-not-share rule whose author is no longer a member of the organization: it blocks nothing now, whatever it decided. Absent otherwise.",
|
|
75175
|
+
"type": "boolean",
|
|
75176
|
+
"const": true
|
|
75177
|
+
}
|
|
75178
|
+
},
|
|
75179
|
+
"required": [
|
|
75180
|
+
"id",
|
|
75181
|
+
"name",
|
|
75182
|
+
"state",
|
|
75183
|
+
"decision",
|
|
75184
|
+
"not_run_reason"
|
|
75185
|
+
]
|
|
75186
|
+
},
|
|
75187
|
+
"description": "Every rule the caller can see: those that matched this email, then those that did not, then those that have not run on it; newest rule first within each."
|
|
75188
|
+
},
|
|
75189
|
+
"hidden": {
|
|
75190
|
+
"type": "integer",
|
|
75191
|
+
"minimum": 0,
|
|
75192
|
+
"description": "How many more rules the caller can see that are not listed."
|
|
75193
|
+
}
|
|
75194
|
+
},
|
|
75195
|
+
"required": ["rules", "hidden"]
|
|
75196
|
+
},
|
|
75197
|
+
"sdkName": "listEmailRuleResults",
|
|
75198
|
+
"summary": "List every rule's result on an email",
|
|
75199
|
+
"tag": "Email Rules",
|
|
75200
|
+
"tagCommand": "email-rules"
|
|
75201
|
+
},
|
|
75202
|
+
{
|
|
75203
|
+
"binaryResponse": false,
|
|
75204
|
+
"bodyRequired": false,
|
|
75205
|
+
"command": "list-email-rule-scope-options",
|
|
75206
|
+
"description": "How much the caller can read, and the inboxes and domains the caller can read, which is what they may name when a rule runs over selected inboxes and domains. For a caller who reads the whole organization, addresses lists the inboxes known as someone's (member addresses, members' verified work emails at the organization's domains, agents' addresses and inboxes with shared access), not every address that receives mail: may_name_unlisted says when an address that is not listed, such as an inbox nobody has claimed, may be named too. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
75207
|
+
"hasJsonBody": false,
|
|
75208
|
+
"method": "GET",
|
|
75209
|
+
"operationId": "listEmailRuleScopeOptions",
|
|
75210
|
+
"path": "/email-rule-scope-options",
|
|
75211
|
+
"pathParams": [],
|
|
75212
|
+
"queryParams": [{
|
|
75213
|
+
"description": "Only inboxes and domains containing this text.",
|
|
75214
|
+
"enum": null,
|
|
75215
|
+
"name": "q",
|
|
75216
|
+
"required": false,
|
|
75217
|
+
"type": "string"
|
|
75218
|
+
}],
|
|
75219
|
+
"headerParams": [],
|
|
75220
|
+
"permissions": ["mail:read"],
|
|
75221
|
+
"requestSchema": null,
|
|
75222
|
+
"responseSchema": {
|
|
75223
|
+
"type": "object",
|
|
75224
|
+
"properties": {
|
|
75225
|
+
"reach": {
|
|
75226
|
+
"type": "string",
|
|
75227
|
+
"enum": [
|
|
75228
|
+
"organization",
|
|
75229
|
+
"limited",
|
|
75230
|
+
"own"
|
|
75231
|
+
],
|
|
75232
|
+
"description": "organization: all of the organization's mail. own: only your own. limited: some inboxes or domains."
|
|
75233
|
+
},
|
|
75234
|
+
"own_mail": {
|
|
75235
|
+
"type": "boolean",
|
|
75236
|
+
"description": "Whether a rule over only your own mail would run for you."
|
|
75237
|
+
},
|
|
75238
|
+
"own_mail_to_block": {
|
|
75239
|
+
"description": "Whether a do_not_share rule over only your own mail would run for you: it covers every own mailbox you read, including ones you could not share.",
|
|
75240
|
+
"type": "boolean"
|
|
75241
|
+
},
|
|
75242
|
+
"addresses": {
|
|
75243
|
+
"type": "array",
|
|
75244
|
+
"items": { "type": "string" },
|
|
75245
|
+
"description": "Inboxes you can read, matching q. For someone who reads the whole organization, the inboxes known as someone's: member addresses, members' verified work emails at the organization's domains, agents' addresses and inboxes with shared access. Otherwise the inboxes your access lists (search with q for those past the first page). See may_name_unlisted for what else you may name."
|
|
75246
|
+
},
|
|
75247
|
+
"domains": {
|
|
75248
|
+
"type": "array",
|
|
75249
|
+
"items": { "type": "string" },
|
|
75250
|
+
"description": "Domains you can read, matching q."
|
|
75251
|
+
},
|
|
75252
|
+
"more": {
|
|
75253
|
+
"type": "boolean",
|
|
75254
|
+
"description": "More match than are listed."
|
|
75255
|
+
},
|
|
75256
|
+
"may_name_unlisted": {
|
|
75257
|
+
"description": "Whether you may also name an inbox this list never shows, however it is searched (more only says whether a search would show further ones): true when you read the whole organization (any address, such as an inbox at its domains nobody has claimed yet) or read a domain (any address there your access does not leave out). Name it in scope_selection.addresses as you would a listed one. Absent from a server that predates it.",
|
|
75258
|
+
"type": "boolean"
|
|
75259
|
+
}
|
|
75260
|
+
},
|
|
75261
|
+
"required": [
|
|
75262
|
+
"reach",
|
|
75263
|
+
"own_mail",
|
|
75264
|
+
"addresses",
|
|
75265
|
+
"domains",
|
|
75266
|
+
"more"
|
|
75267
|
+
]
|
|
75268
|
+
},
|
|
75269
|
+
"sdkName": "listEmailRuleScopeOptions",
|
|
75270
|
+
"summary": "List what a rule can cover",
|
|
75271
|
+
"tag": "Email Rules",
|
|
75272
|
+
"tagCommand": "email-rules"
|
|
75273
|
+
},
|
|
73745
75274
|
{
|
|
73746
75275
|
"binaryResponse": false,
|
|
73747
75276
|
"bodyRequired": false,
|
|
@@ -74266,11 +75795,130 @@ const operationManifest = [
|
|
|
74266
75795
|
"tag": "Email Rules",
|
|
74267
75796
|
"tagCommand": "email-rules"
|
|
74268
75797
|
},
|
|
75798
|
+
{
|
|
75799
|
+
"binaryResponse": false,
|
|
75800
|
+
"bodyRequired": false,
|
|
75801
|
+
"command": "list-email-rule-versions",
|
|
75802
|
+
"description": "The named versions of a rule, as they were written: what each one's conditions and questions were, so a decision can be read against the version that made it. Numbers that are not versions of the rule are left out. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
75803
|
+
"hasJsonBody": false,
|
|
75804
|
+
"method": "GET",
|
|
75805
|
+
"operationId": "listEmailRuleVersions",
|
|
75806
|
+
"path": "/email-rules/{id}/versions",
|
|
75807
|
+
"pathParams": [{
|
|
75808
|
+
"description": "The rule id.",
|
|
75809
|
+
"enum": null,
|
|
75810
|
+
"name": "id",
|
|
75811
|
+
"required": true,
|
|
75812
|
+
"type": "string"
|
|
75813
|
+
}],
|
|
75814
|
+
"queryParams": [{
|
|
75815
|
+
"description": "The version numbers, comma-separated, at most 100.",
|
|
75816
|
+
"enum": null,
|
|
75817
|
+
"name": "versions",
|
|
75818
|
+
"required": true,
|
|
75819
|
+
"type": "string"
|
|
75820
|
+
}],
|
|
75821
|
+
"headerParams": [],
|
|
75822
|
+
"permissions": ["mail:read"],
|
|
75823
|
+
"requestSchema": null,
|
|
75824
|
+
"responseSchema": {
|
|
75825
|
+
"type": "array",
|
|
75826
|
+
"items": {
|
|
75827
|
+
"type": "object",
|
|
75828
|
+
"properties": {
|
|
75829
|
+
"version": {
|
|
75830
|
+
"type": "integer",
|
|
75831
|
+
"exclusiveMinimum": 0
|
|
75832
|
+
},
|
|
75833
|
+
"english": { "type": "string" },
|
|
75834
|
+
"tree": {
|
|
75835
|
+
"type": "object",
|
|
75836
|
+
"properties": {
|
|
75837
|
+
"version": {
|
|
75838
|
+
"type": "number",
|
|
75839
|
+
"const": 1
|
|
75840
|
+
},
|
|
75841
|
+
"vocabulary": {
|
|
75842
|
+
"type": "string",
|
|
75843
|
+
"description": "The column contract version the rule is written against, for example v1."
|
|
75844
|
+
},
|
|
75845
|
+
"when": {
|
|
75846
|
+
"type": "object",
|
|
75847
|
+
"propertyNames": { "type": "string" },
|
|
75848
|
+
"additionalProperties": {},
|
|
75849
|
+
"description": "The rule's conditions: a condition ({column, op, value?, min_confidence?}) or a group ({all: [...]}, {any: [...]} or {not: ...})."
|
|
75850
|
+
},
|
|
75851
|
+
"questions": {
|
|
75852
|
+
"type": "array",
|
|
75853
|
+
"items": { "type": "string" },
|
|
75854
|
+
"description": "Yes/no questions of the rule's own, asked about an email only after its conditions match. An email matches only if every answer is yes."
|
|
75855
|
+
}
|
|
75856
|
+
},
|
|
75857
|
+
"required": [
|
|
75858
|
+
"version",
|
|
75859
|
+
"vocabulary",
|
|
75860
|
+
"when",
|
|
75861
|
+
"questions"
|
|
75862
|
+
]
|
|
75863
|
+
},
|
|
75864
|
+
"explanation": { "type": "string" },
|
|
75865
|
+
"assumptions": {
|
|
75866
|
+
"type": "array",
|
|
75867
|
+
"items": { "type": "string" }
|
|
75868
|
+
},
|
|
75869
|
+
"warnings": {
|
|
75870
|
+
"type": "array",
|
|
75871
|
+
"items": { "type": "string" }
|
|
75872
|
+
},
|
|
75873
|
+
"compiled_by": {
|
|
75874
|
+
"type": "string",
|
|
75875
|
+
"description": "Who produced the tree, as the caller stated it when saving (not verified), for example rule-compiler-v1 or member."
|
|
75876
|
+
},
|
|
75877
|
+
"vocabulary": { "type": "string" },
|
|
75878
|
+
"created_at": {
|
|
75879
|
+
"type": "string",
|
|
75880
|
+
"format": "date-time"
|
|
75881
|
+
},
|
|
75882
|
+
"sql": {
|
|
75883
|
+
"description": "Present only when include_sql was true.",
|
|
75884
|
+
"type": "object",
|
|
75885
|
+
"properties": {
|
|
75886
|
+
"expression": {
|
|
75887
|
+
"type": "string",
|
|
75888
|
+
"description": "A parameterized boolean expression over one row per email."
|
|
75889
|
+
},
|
|
75890
|
+
"params": {
|
|
75891
|
+
"type": "array",
|
|
75892
|
+
"items": {},
|
|
75893
|
+
"description": "The values bound to $1, $2 and so on."
|
|
75894
|
+
}
|
|
75895
|
+
},
|
|
75896
|
+
"required": ["expression", "params"]
|
|
75897
|
+
}
|
|
75898
|
+
},
|
|
75899
|
+
"required": [
|
|
75900
|
+
"version",
|
|
75901
|
+
"english",
|
|
75902
|
+
"tree",
|
|
75903
|
+
"explanation",
|
|
75904
|
+
"assumptions",
|
|
75905
|
+
"warnings",
|
|
75906
|
+
"compiled_by",
|
|
75907
|
+
"vocabulary",
|
|
75908
|
+
"created_at"
|
|
75909
|
+
]
|
|
75910
|
+
}
|
|
75911
|
+
},
|
|
75912
|
+
"sdkName": "listEmailRuleVersions",
|
|
75913
|
+
"summary": "Read versions of a rule",
|
|
75914
|
+
"tag": "Email Rules",
|
|
75915
|
+
"tagCommand": "email-rules"
|
|
75916
|
+
},
|
|
74269
75917
|
{
|
|
74270
75918
|
"binaryResponse": false,
|
|
74271
75919
|
"bodyRequired": false,
|
|
74272
75920
|
"command": "list-email-rules",
|
|
74273
|
-
"description": "The rules the caller can see, newest first: their own, or every member's rules for a caller who reads the whole organization's mail. With matched_email_id, only the rules that matched that email. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
75921
|
+
"description": "The rules the caller can see, newest first: their own, or every member's rules for a caller who reads the whole organization's mail. Each carries its scope (evaluation_scope, and scope_selection for a selected rule). With matched_email_id, only the rules that matched that email. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
74274
75922
|
"hasJsonBody": false,
|
|
74275
75923
|
"method": "GET",
|
|
74276
75924
|
"operationId": "listEmailRules",
|
|
@@ -74323,6 +75971,35 @@ const operationManifest = [
|
|
|
74323
75971
|
"active"
|
|
74324
75972
|
]
|
|
74325
75973
|
},
|
|
75974
|
+
"kind": {
|
|
75975
|
+
"description": "do_not_share: the rule blocks sharing of what it matches. Absent (or grant) on a rule that shares what it matches.",
|
|
75976
|
+
"type": "string",
|
|
75977
|
+
"enum": ["grant", "do_not_share"]
|
|
75978
|
+
},
|
|
75979
|
+
"evaluation_scope": {
|
|
75980
|
+
"description": "Whose mail the rule runs over, as stored; GET /email-rules/{id}/scope says what that comes to now.",
|
|
75981
|
+
"type": "string",
|
|
75982
|
+
"enum": [
|
|
75983
|
+
"author",
|
|
75984
|
+
"own_mailboxes",
|
|
75985
|
+
"selected"
|
|
75986
|
+
]
|
|
75987
|
+
},
|
|
75988
|
+
"scope_selection": {
|
|
75989
|
+
"type": ["object", "null"],
|
|
75990
|
+
"properties": {
|
|
75991
|
+
"addresses": {
|
|
75992
|
+
"type": "array",
|
|
75993
|
+
"items": { "type": "string" }
|
|
75994
|
+
},
|
|
75995
|
+
"domains": {
|
|
75996
|
+
"type": "array",
|
|
75997
|
+
"items": { "type": "string" }
|
|
75998
|
+
}
|
|
75999
|
+
},
|
|
76000
|
+
"required": ["addresses", "domains"],
|
|
76001
|
+
"description": "What a selected rule names; null for any other scope."
|
|
76002
|
+
},
|
|
74326
76003
|
"current_version": {
|
|
74327
76004
|
"type": ["integer", "null"],
|
|
74328
76005
|
"exclusiveMinimum": 0
|
|
@@ -74572,7 +76249,7 @@ const operationManifest = [
|
|
|
74572
76249
|
"binaryResponse": false,
|
|
74573
76250
|
"bodyRequired": true,
|
|
74574
76251
|
"command": "test-email-rule",
|
|
74575
|
-
"description": "Runs a rule over received mail and reports what it would decide for each email: matched, near_miss, no_match, unclassified or not_found. Test an unsaved tree from a compile response, or a saved rule by rule_id (its current version, run with its author's access). Either way the rule reads only mail its author can read. Without email_ids, the newest emails it can read are tested, at most 200 and none older than 30 days. Emails not classified yet that arrived more than 2 hours ago are classified first and their classification is saved, unless classify_missing is false; newer ones are left to normal classification and reported unclassified with reason pending. The rule itself records nothing and grants nothing. Classification and the rule's own questions stop at about 90 seconds; run the test again to continue where it stopped. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
76252
|
+
"description": "Runs a rule over received mail and reports what it would decide for each email: matched, near_miss, no_match, unclassified or not_found. Test an unsaved tree from a compile response, or a saved rule by rule_id (its current version, run with its author's access). Either way the rule reads only mail its author can read, and only what its scope covers; an unsaved tree covers only your own mail unless evaluation_scope names more. Without email_ids, the newest emails it can read are tested, at most 200 and none older than 30 days. Emails not classified yet that arrived more than 2 hours ago are classified first and their classification is saved, unless classify_missing is false; newer ones are left to normal classification and reported unclassified with reason pending. The rule itself records nothing and grants nothing. Classification and the rule's own questions stop at about 90 seconds; run the test again to continue where it stopped. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
74576
76253
|
"hasJsonBody": true,
|
|
74577
76254
|
"method": "POST",
|
|
74578
76255
|
"operationId": "testEmailRule",
|
|
@@ -74624,14 +76301,50 @@ const operationManifest = [
|
|
|
74624
76301
|
},
|
|
74625
76302
|
"evaluation_scope": {
|
|
74626
76303
|
"type": "string",
|
|
74627
|
-
"enum": [
|
|
74628
|
-
|
|
76304
|
+
"enum": [
|
|
76305
|
+
"author",
|
|
76306
|
+
"own_mailboxes",
|
|
76307
|
+
"selected"
|
|
76308
|
+
],
|
|
76309
|
+
"description": "own_mailboxes (the default): mail to your own addresses and agents (for a rule that shares, those you can send from). author: all mail you can read, including inboxes added later. selected: what scope_selection names."
|
|
76310
|
+
},
|
|
76311
|
+
"scope_selection": {
|
|
76312
|
+
"type": "object",
|
|
76313
|
+
"properties": {
|
|
76314
|
+
"addresses": {
|
|
76315
|
+
"maxItems": 100,
|
|
76316
|
+
"type": "array",
|
|
76317
|
+
"items": {
|
|
76318
|
+
"type": "string",
|
|
76319
|
+
"minLength": 3,
|
|
76320
|
+
"maxLength": 320,
|
|
76321
|
+
"pattern": "^[^\\s@]+@[^\\s@]+$"
|
|
76322
|
+
}
|
|
76323
|
+
},
|
|
76324
|
+
"domains": {
|
|
76325
|
+
"maxItems": 50,
|
|
76326
|
+
"type": "array",
|
|
76327
|
+
"items": {
|
|
76328
|
+
"type": "string",
|
|
76329
|
+
"minLength": 1,
|
|
76330
|
+
"maxLength": 253,
|
|
76331
|
+
"pattern": "^[^\\s@]+\\.[^\\s@]+$"
|
|
76332
|
+
}
|
|
76333
|
+
}
|
|
76334
|
+
},
|
|
76335
|
+
"additionalProperties": false,
|
|
76336
|
+
"description": "Inboxes, and domains (every address at them the author can read), for a selected rule; each one you can read."
|
|
74629
76337
|
},
|
|
74630
76338
|
"rule_id": {
|
|
74631
76339
|
"description": "A saved rule you can see. Its current version is tested, with its author's access.",
|
|
74632
76340
|
"type": "string",
|
|
74633
76341
|
"format": "uuid"
|
|
74634
76342
|
},
|
|
76343
|
+
"kind": {
|
|
76344
|
+
"description": "For an unsaved tree: do_not_share tests it as a rule that blocks sharing, so an email it cannot decide counts as matched. A saved rule uses its own.",
|
|
76345
|
+
"type": "string",
|
|
76346
|
+
"enum": ["grant", "do_not_share"]
|
|
76347
|
+
},
|
|
74635
76348
|
"email_ids": {
|
|
74636
76349
|
"description": "Test exactly these emails. Without it, the newest emails the rule can read are tested, at most 200 and none older than 30 days.",
|
|
74637
76350
|
"minItems": 1,
|
|
@@ -74868,7 +76581,7 @@ const operationManifest = [
|
|
|
74868
76581
|
"binaryResponse": false,
|
|
74869
76582
|
"bodyRequired": true,
|
|
74870
76583
|
"command": "test-email-rule-on-sample",
|
|
74871
|
-
"description": "Reports what a rule would decide for an email you describe: its sender, recipients, subject, plain text and attachment types, and optionally whether it is automated or from a mailing list and its spam score. The email is classified the way received mail is, and the rule's conditions and its own questions are decided as they would be for received mail with that content and those signals, received now. Without them it is not automated and not from a mailing list; a rule that reads a spam score you gave none for is decided on no score, and spam_score is listed in unset_columns. Nothing is stored: no email, classification or decision. Test an unsaved tree from a compile response, or a saved rule by rule_id (its current version). The answer includes what the classifier read from the email. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
76584
|
+
"description": "Reports what a rule would decide for an email you describe: its sender, recipients, subject, plain text and attachment types, and optionally whether it is automated or from a mailing list and its spam score. The email is classified the way received mail is, and the rule's conditions and its own questions are decided as they would be for received mail with that content and those signals, received now. Without them it is not automated and not from a mailing list; a rule that reads a spam score you gave none for is decided on no score, and spam_score is listed in unset_columns. Nothing is stored: no email, classification or decision. Test an unsaved tree from a compile response, or a saved rule by rule_id (its current version); an unsaved tree is run as covering only your own mail unless evaluation_scope names more, as on POST /email-rules/test. The answer includes what the classifier read from the email. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
74872
76585
|
"hasJsonBody": true,
|
|
74873
76586
|
"method": "POST",
|
|
74874
76587
|
"operationId": "testEmailRuleOnSample",
|
|
@@ -74920,14 +76633,50 @@ const operationManifest = [
|
|
|
74920
76633
|
},
|
|
74921
76634
|
"evaluation_scope": {
|
|
74922
76635
|
"type": "string",
|
|
74923
|
-
"enum": [
|
|
74924
|
-
|
|
76636
|
+
"enum": [
|
|
76637
|
+
"author",
|
|
76638
|
+
"own_mailboxes",
|
|
76639
|
+
"selected"
|
|
76640
|
+
],
|
|
76641
|
+
"description": "own_mailboxes (the default): mail to your own addresses and agents (for a rule that shares, those you can send from). author: all mail you can read, including inboxes added later. selected: what scope_selection names."
|
|
76642
|
+
},
|
|
76643
|
+
"scope_selection": {
|
|
76644
|
+
"type": "object",
|
|
76645
|
+
"properties": {
|
|
76646
|
+
"addresses": {
|
|
76647
|
+
"maxItems": 100,
|
|
76648
|
+
"type": "array",
|
|
76649
|
+
"items": {
|
|
76650
|
+
"type": "string",
|
|
76651
|
+
"minLength": 3,
|
|
76652
|
+
"maxLength": 320,
|
|
76653
|
+
"pattern": "^[^\\s@]+@[^\\s@]+$"
|
|
76654
|
+
}
|
|
76655
|
+
},
|
|
76656
|
+
"domains": {
|
|
76657
|
+
"maxItems": 50,
|
|
76658
|
+
"type": "array",
|
|
76659
|
+
"items": {
|
|
76660
|
+
"type": "string",
|
|
76661
|
+
"minLength": 1,
|
|
76662
|
+
"maxLength": 253,
|
|
76663
|
+
"pattern": "^[^\\s@]+\\.[^\\s@]+$"
|
|
76664
|
+
}
|
|
76665
|
+
}
|
|
76666
|
+
},
|
|
76667
|
+
"additionalProperties": false,
|
|
76668
|
+
"description": "Inboxes, and domains (every address at them the author can read), for a selected rule; each one you can read."
|
|
74925
76669
|
},
|
|
74926
76670
|
"rule_id": {
|
|
74927
76671
|
"description": "A saved rule you can see. Its current version is tested.",
|
|
74928
76672
|
"type": "string",
|
|
74929
76673
|
"format": "uuid"
|
|
74930
76674
|
},
|
|
76675
|
+
"kind": {
|
|
76676
|
+
"description": "For an unsaved tree: do_not_share tests it as a rule that blocks sharing, so an email it cannot decide counts as matched. A saved rule uses its own.",
|
|
76677
|
+
"type": "string",
|
|
76678
|
+
"enum": ["grant", "do_not_share"]
|
|
76679
|
+
},
|
|
74931
76680
|
"email": {
|
|
74932
76681
|
"type": "object",
|
|
74933
76682
|
"properties": {
|
|
@@ -75151,7 +76900,7 @@ const operationManifest = [
|
|
|
75151
76900
|
"binaryResponse": false,
|
|
75152
76901
|
"bodyRequired": true,
|
|
75153
76902
|
"command": "update-email-rule",
|
|
75154
|
-
"description": "Renames the rule, saves a new version (english, tree and explanation together; earlier versions are kept unchanged)
|
|
76903
|
+
"description": "Renames the rule, saves a new version (english, tree and explanation together; earlier versions are kept unchanged), changes its state (draft, disabled; observe; or active) or changes whose mail it runs over (evaluation_scope, with scope_selection when selected). Only the rule's author may rename it, add a version, change its scope or move it to observe or active; anyone else who can see it may only disable it (state draft), and while it is shared with another member only if they manage members from the dashboard. Omit evaluation_scope to keep the current scope. A scope change saves a new version with the same conditions; what was granted stays. A shared rule keeps its scope. A rule's kind never changes. Needs mail:read, a credential acting as a member with their full access (API keys, agent keys and narrowed tokens are refused), and the email rules feature on the organization.",
|
|
75155
76904
|
"hasJsonBody": true,
|
|
75156
76905
|
"method": "PATCH",
|
|
75157
76906
|
"operationId": "updateEmailRule",
|
|
@@ -75176,7 +76925,7 @@ const operationManifest = [
|
|
|
75176
76925
|
"description": "A short name for the rule."
|
|
75177
76926
|
},
|
|
75178
76927
|
"state": {
|
|
75179
|
-
"description": "draft disables the rule; observe records decisions; active also grants what it matches. Keys read and receive what a rule granted only while it is active: leaving active pauses that, and returning to active restores reads and the delivery of queued mail not yet skipped.",
|
|
76928
|
+
"description": "draft disables the rule; observe records decisions; active also grants what it matches, or for a do_not_share rule keeps it from being shared. Keys read and receive what a rule granted only while it is active: leaving active pauses that, and returning to active restores reads and the delivery of queued mail not yet skipped.",
|
|
75180
76929
|
"type": "string",
|
|
75181
76930
|
"enum": [
|
|
75182
76931
|
"draft",
|
|
@@ -75253,6 +77002,42 @@ const operationManifest = [
|
|
|
75253
77002
|
"type": "string",
|
|
75254
77003
|
"minLength": 1,
|
|
75255
77004
|
"maxLength": 64
|
|
77005
|
+
},
|
|
77006
|
+
"evaluation_scope": {
|
|
77007
|
+
"type": "string",
|
|
77008
|
+
"enum": [
|
|
77009
|
+
"author",
|
|
77010
|
+
"own_mailboxes",
|
|
77011
|
+
"selected"
|
|
77012
|
+
],
|
|
77013
|
+
"description": "author: all mail its author can read. own_mailboxes: mail to their own addresses. selected: what scope_selection names. Never more than the author can read."
|
|
77014
|
+
},
|
|
77015
|
+
"scope_selection": {
|
|
77016
|
+
"type": "object",
|
|
77017
|
+
"properties": {
|
|
77018
|
+
"addresses": {
|
|
77019
|
+
"maxItems": 100,
|
|
77020
|
+
"type": "array",
|
|
77021
|
+
"items": {
|
|
77022
|
+
"type": "string",
|
|
77023
|
+
"minLength": 3,
|
|
77024
|
+
"maxLength": 320,
|
|
77025
|
+
"pattern": "^[^\\s@]+@[^\\s@]+$"
|
|
77026
|
+
}
|
|
77027
|
+
},
|
|
77028
|
+
"domains": {
|
|
77029
|
+
"maxItems": 50,
|
|
77030
|
+
"type": "array",
|
|
77031
|
+
"items": {
|
|
77032
|
+
"type": "string",
|
|
77033
|
+
"minLength": 1,
|
|
77034
|
+
"maxLength": 253,
|
|
77035
|
+
"pattern": "^[^\\s@]+\\.[^\\s@]+$"
|
|
77036
|
+
}
|
|
77037
|
+
}
|
|
77038
|
+
},
|
|
77039
|
+
"additionalProperties": false,
|
|
77040
|
+
"description": "Inboxes, and domains (every address at them the author can read), for a selected rule; each one you can read."
|
|
75256
77041
|
}
|
|
75257
77042
|
},
|
|
75258
77043
|
"additionalProperties": false
|
|
@@ -75273,6 +77058,35 @@ const operationManifest = [
|
|
|
75273
77058
|
"active"
|
|
75274
77059
|
]
|
|
75275
77060
|
},
|
|
77061
|
+
"kind": {
|
|
77062
|
+
"description": "do_not_share: the rule blocks sharing of what it matches. Absent (or grant) on a rule that shares what it matches.",
|
|
77063
|
+
"type": "string",
|
|
77064
|
+
"enum": ["grant", "do_not_share"]
|
|
77065
|
+
},
|
|
77066
|
+
"evaluation_scope": {
|
|
77067
|
+
"description": "Whose mail the rule runs over, as stored; GET /email-rules/{id}/scope says what that comes to now.",
|
|
77068
|
+
"type": "string",
|
|
77069
|
+
"enum": [
|
|
77070
|
+
"author",
|
|
77071
|
+
"own_mailboxes",
|
|
77072
|
+
"selected"
|
|
77073
|
+
]
|
|
77074
|
+
},
|
|
77075
|
+
"scope_selection": {
|
|
77076
|
+
"type": ["object", "null"],
|
|
77077
|
+
"properties": {
|
|
77078
|
+
"addresses": {
|
|
77079
|
+
"type": "array",
|
|
77080
|
+
"items": { "type": "string" }
|
|
77081
|
+
},
|
|
77082
|
+
"domains": {
|
|
77083
|
+
"type": "array",
|
|
77084
|
+
"items": { "type": "string" }
|
|
77085
|
+
}
|
|
77086
|
+
},
|
|
77087
|
+
"required": ["addresses", "domains"],
|
|
77088
|
+
"description": "What a selected rule names; null for any other scope."
|
|
77089
|
+
},
|
|
75276
77090
|
"current_version": {
|
|
75277
77091
|
"type": ["integer", "null"],
|
|
75278
77092
|
"exclusiveMinimum": 0
|
|
@@ -90750,7 +92564,7 @@ const operationManifest = [
|
|
|
90750
92564
|
"binaryResponse": false,
|
|
90751
92565
|
"bodyRequired": true,
|
|
90752
92566
|
"command": "decide-suspension",
|
|
90753
|
-
"description": "Keep, narrow or revoke one suspended or flagged item. Keeping it, and revoking an API key, needs the decider to cover it (revoking an uncovered key is refused with `grant_forbidden`, `target_not_covered`). Keeping an API key rotated (`rotate: true`, other than the shared Function key) also revokes its older secrets still in a rotation overlap, and needs keys:manage on both the credential and the person: without it, or if the decider lost members:manage meanwhile, it is refused with `grant_forbidden` (`keys_manage_required` or `actor_access_changed`) and nothing is rotated. Person only: a dashboard session, or the person's own OAuth or CLI token with a session step-up of purpose `suspensions.decide` (the person confirms at the step_up_url a 403 step_up_required answer carries, which names this client, then send the token in the Primitive-Step-Up header; the token works only with the client it was confirmed for). Needs members:manage. API keys are refused.",
|
|
92567
|
+
"description": "Keep, narrow or revoke one suspended or flagged item. Keeping it, and revoking an API key, needs the decider to cover it (revoking an uncovered key is refused with `grant_forbidden`, `target_not_covered`). Keeping an API key rotated (`rotate: true`, other than the shared Function key) also revokes its older secrets still in a rotation overlap, and needs keys:manage on both the credential and the person: without it, or if the decider lost members:manage meanwhile, it is refused with `grant_forbidden` (`keys_manage_required` or `actor_access_changed`) and nothing is rotated. A rule share paused by a role change (`email_rule_share`) takes keep, which leaves it paused, or revoke, which ends the share and needs confirm: true (the person it was shared with loses the emails already shared; without it, 409 `confirmation_required`). Neither of the share's two people may keep it (`grant_forbidden`, `share_decision_forbidden`). Access a person gave on their own mailbox (`mailbox_access`) takes keep or revoke, and both need delegations:manage; revoke removes only what that person gave on that mailbox. Nobody the access reaches, nor the person who gave it, may keep it (`grant_forbidden`, `mailbox_access_decision_forbidden`). Person only: a dashboard session, or the person's own OAuth or CLI token with a session step-up of purpose `suspensions.decide` (the person confirms at the step_up_url a 403 step_up_required answer carries, which names this client, then send the token in the Primitive-Step-Up header; the token works only with the client it was confirmed for). Needs members:manage. API keys are refused.",
|
|
90754
92568
|
"hasJsonBody": true,
|
|
90755
92569
|
"method": "POST",
|
|
90756
92570
|
"operationId": "decideSuspension",
|
|
@@ -102204,14 +104018,14 @@ function isMemoryJsonValue(value, seen = /* @__PURE__ */ new Set()) {
|
|
|
102204
104018
|
}
|
|
102205
104019
|
}
|
|
102206
104020
|
// src/oclif/cli-operations.ts
|
|
102207
|
-
const
|
|
104021
|
+
const KEY_WRITE_OPERATION_IDS = /* @__PURE__ */ new Set([
|
|
102208
104022
|
"credentials:create-key",
|
|
102209
104023
|
"credentials:rotate-key",
|
|
102210
104024
|
"credentials:update-key",
|
|
102211
104025
|
"credentials:revoke-credential"
|
|
102212
104026
|
]);
|
|
102213
|
-
/** The operations the CLI
|
|
102214
|
-
const cliOperationManifest = operationManifest.filter((operation) => !
|
|
104027
|
+
/** The operations the CLI generates commands for: the manifest without the key writes. */
|
|
104028
|
+
const cliOperationManifest = operationManifest.filter((operation) => !KEY_WRITE_OPERATION_IDS.has(`${operation.tagCommand}:${operation.command}`));
|
|
102215
104029
|
// src/oclif/agent-mail-check.ts
|
|
102216
104030
|
/**
|
|
102217
104031
|
* One check for mail that arrived since this profile's previous check. It is
|
|
@@ -108882,7 +110696,7 @@ async function checkAccount(client) {
|
|
|
108882
110696
|
outcome: {
|
|
108883
110697
|
status: "fail",
|
|
108884
110698
|
message: `API rejected the key (${typeof apiError === "object" && apiError !== null ? JSON.stringify(apiError).slice(0, 300) : String(apiError).slice(0, 300)})`,
|
|
108885
|
-
hint: "Run `primitive whoami` for the full error envelope. If the key was rotated,
|
|
110699
|
+
hint: "Run `primitive whoami` for the full error envelope. If the key was rotated, use its new secret; if it was revoked, create a key with `primitive keys create` or in the dashboard."
|
|
108886
110700
|
},
|
|
108887
110701
|
account: null
|
|
108888
110702
|
};
|
|
@@ -111816,8 +113630,8 @@ const PRIMITIVE_TEAM_AUTHOR = {
|
|
|
111816
113630
|
name: "Primitive Team",
|
|
111817
113631
|
url: "https://primitive.dev"
|
|
111818
113632
|
};
|
|
111819
|
-
const SDK_VERSION_RANGE = "^3.0.0-preview.
|
|
111820
|
-
const CLI_VERSION_RANGE = "^3.0.0-preview.
|
|
113633
|
+
const SDK_VERSION_RANGE = "^3.0.0-preview.3";
|
|
113634
|
+
const CLI_VERSION_RANGE = "^3.0.0-preview.3";
|
|
111821
113635
|
const ESBUILD_VERSION_RANGE = "^0.27.0";
|
|
111822
113636
|
function renderHandler() {
|
|
111823
113637
|
return `// env.PRIMITIVE_API_KEY, env.PRIMITIVE_WEBHOOK_SECRET, and
|
|
@@ -112945,6 +114759,7 @@ var FunctionsRouteGetCommand = class FunctionsRouteGetCommand extends Command {
|
|
|
112945
114759
|
static summary = "Show a function's current route binding";
|
|
112946
114760
|
static examples = ["<%= config.bin %> functions route-get --id <fn-id>"];
|
|
112947
114761
|
static flags = {
|
|
114762
|
+
json: JSON_OUTPUT_FLAG,
|
|
112948
114763
|
"api-key": Flags.string({
|
|
112949
114764
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
112950
114765
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -113007,6 +114822,7 @@ var FunctionsRouteSetCommand = class FunctionsRouteSetCommand extends Command {
|
|
|
113007
114822
|
"<%= config.bin %> functions route-set --id <fn-id> --domain <domain-id> --takeover"
|
|
113008
114823
|
];
|
|
113009
114824
|
static flags = {
|
|
114825
|
+
json: JSON_OUTPUT_FLAG,
|
|
113010
114826
|
"api-key": Flags.string({
|
|
113011
114827
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
113012
114828
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -113079,6 +114895,7 @@ var FunctionsRouteUnsetCommand = class FunctionsRouteUnsetCommand extends Comman
|
|
|
113079
114895
|
static summary = "Unbind any route from a function";
|
|
113080
114896
|
static examples = ["<%= config.bin %> functions route-unset --id <fn-id>"];
|
|
113081
114897
|
static flags = {
|
|
114898
|
+
json: JSON_OUTPUT_FLAG,
|
|
113082
114899
|
"api-key": Flags.string({
|
|
113083
114900
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
113084
114901
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -113129,6 +114946,7 @@ var FunctionsRoutingTopologyCommand = class FunctionsRoutingTopologyCommand exte
|
|
|
113129
114946
|
static summary = "Show the org-wide function routing topology";
|
|
113130
114947
|
static examples = ["<%= config.bin %> functions routing-topology"];
|
|
113131
114948
|
static flags = {
|
|
114949
|
+
json: JSON_OUTPUT_FLAG,
|
|
113132
114950
|
"api-key": Flags.string({
|
|
113133
114951
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
113134
114952
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -113255,6 +115073,7 @@ var FunctionsSetSecretCommand = class FunctionsSetSecretCommand extends Command
|
|
|
113255
115073
|
"printf '%s' \"$MY_API_KEY\" | <%= config.bin %> functions set-secret --id <fn-id> --key MY_API_KEY --stdin --redeploy"
|
|
113256
115074
|
];
|
|
113257
115075
|
static flags = {
|
|
115076
|
+
json: JSON_OUTPUT_FLAG,
|
|
113258
115077
|
"api-key": Flags.string({
|
|
113259
115078
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
113260
115079
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -114577,7 +116396,10 @@ var InboxSetupCommand = class InboxSetupCommand extends Command {
|
|
|
114577
116396
|
}
|
|
114578
116397
|
};
|
|
114579
116398
|
// src/oclif/commands/keys.ts
|
|
114580
|
-
const
|
|
116399
|
+
const STORE_SECRET_NOTICE = "Store this key now. It is shown only once, and the CLI does not save it.";
|
|
116400
|
+
const HELD_REQUEST_NOTICE = "A request already held open with this key, such as a long poll or a wait, ends once because the key's permissions changed. Run it again to use the new permissions.";
|
|
116401
|
+
const STEP_UP_HEADER$1 = "Primitive-Step-Up";
|
|
116402
|
+
const LIST_PAGE_LIMIT = 50;
|
|
114581
116403
|
const API_KEY_FLAG$1 = Flags.string({
|
|
114582
116404
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved login credentials).",
|
|
114583
116405
|
env: "PRIMITIVE_API_KEY",
|
|
@@ -114588,68 +116410,695 @@ const API_BASE_URL_FLAG$2 = Flags.string({
|
|
|
114588
116410
|
env: "PRIMITIVE_API_BASE_URL",
|
|
114589
116411
|
hidden: true
|
|
114590
116412
|
});
|
|
114591
|
-
|
|
114592
|
-
|
|
114593
|
-
|
|
114594
|
-
|
|
114595
|
-
|
|
114596
|
-
|
|
114597
|
-
|
|
116413
|
+
const APPROVAL_FLAGS = {
|
|
116414
|
+
"step-up-token": Flags.string({ description: "One-time token from the approval page, for a request you already approved in the browser. Sent in the Primitive-Step-Up header." }),
|
|
116415
|
+
browser: Flags.boolean({
|
|
116416
|
+
allowNo: true,
|
|
116417
|
+
default: true,
|
|
116418
|
+
description: "Open the approval page in your browser. Use --no-browser to only print its link."
|
|
116419
|
+
})
|
|
116420
|
+
};
|
|
116421
|
+
function unwrap(data) {
|
|
116422
|
+
return data?.data ?? data;
|
|
116423
|
+
}
|
|
116424
|
+
async function call(request) {
|
|
116425
|
+
try {
|
|
116426
|
+
const result = await request;
|
|
116427
|
+
if (result.error !== void 0 || !result.response?.ok) return {
|
|
116428
|
+
ok: false,
|
|
116429
|
+
payload: result.error === void 0 || result.error === null || typeof result.error === "string" ? {
|
|
116430
|
+
code: "http_error",
|
|
116431
|
+
message: typeof result.error === "string" && result.error.trim() || `HTTP ${result.response?.status ?? ""}`.trim()
|
|
116432
|
+
} : extractErrorPayload(result.error)
|
|
116433
|
+
};
|
|
116434
|
+
return {
|
|
116435
|
+
ok: true,
|
|
116436
|
+
data: unwrap(result.data)
|
|
116437
|
+
};
|
|
116438
|
+
} catch (error) {
|
|
116439
|
+
return {
|
|
116440
|
+
ok: false,
|
|
116441
|
+
payload: extractErrorPayload(error)
|
|
116442
|
+
};
|
|
114598
116443
|
}
|
|
114599
|
-
|
|
114600
|
-
|
|
114601
|
-
|
|
116444
|
+
}
|
|
116445
|
+
/** The approval link of a `step_up_required` refusal, if that is what it is. */
|
|
116446
|
+
function stepUpUrlOf$1(payload) {
|
|
116447
|
+
if (extractErrorCode(payload) !== "step_up_required") return void 0;
|
|
116448
|
+
if (!payload || typeof payload !== "object") return void 0;
|
|
116449
|
+
const details = payload.details;
|
|
116450
|
+
if (!details || typeof details !== "object") return void 0;
|
|
116451
|
+
const url = details.step_up_url;
|
|
116452
|
+
return typeof url === "string" && url.length > 0 ? url : void 0;
|
|
116453
|
+
}
|
|
116454
|
+
/**
|
|
116455
|
+
* Send a request, and when the server asks the person to approve it, show
|
|
116456
|
+
* the approval link, open it where possible, wait for the token the page
|
|
116457
|
+
* shows, and send the request once more with it. Without a terminal to wait
|
|
116458
|
+
* in, the refusal is returned with its link, to rerun with --step-up-token.
|
|
116459
|
+
*/
|
|
116460
|
+
async function withApproval(attempt, io) {
|
|
116461
|
+
const first = await attempt(io.stepUpToken);
|
|
116462
|
+
if (first.ok) return first;
|
|
116463
|
+
const stepUpUrl = stepUpUrlOf$1(first.payload);
|
|
116464
|
+
if (!stepUpUrl || io.stepUpToken || !io.interactive) return {
|
|
116465
|
+
...first,
|
|
116466
|
+
...stepUpUrl ? { stepUpUrl } : {}
|
|
116467
|
+
};
|
|
116468
|
+
io.write(`Approve this request in your browser: ${stepUpUrl}\n`);
|
|
116469
|
+
if (io.openBrowser) io.open(stepUpUrl);
|
|
116470
|
+
io.write("After you confirm, the page shows a one-time token. Paste it here to finish.\n");
|
|
116471
|
+
const token = (await io.prompt("Token: ")).trim();
|
|
116472
|
+
if (!token) return {
|
|
116473
|
+
...first,
|
|
116474
|
+
stepUpUrl
|
|
116475
|
+
};
|
|
116476
|
+
return attempt(token);
|
|
116477
|
+
}
|
|
116478
|
+
async function promptLine$2(question) {
|
|
116479
|
+
const rl = createInterface({
|
|
116480
|
+
input: process.stdin,
|
|
116481
|
+
output: process.stderr
|
|
114602
116482
|
});
|
|
114603
|
-
|
|
116483
|
+
try {
|
|
116484
|
+
return await rl.question(question);
|
|
116485
|
+
} finally {
|
|
116486
|
+
rl.close();
|
|
116487
|
+
}
|
|
114604
116488
|
}
|
|
114605
|
-
function
|
|
114606
|
-
return
|
|
116489
|
+
function approvalIo(flags) {
|
|
116490
|
+
return {
|
|
116491
|
+
stepUpToken: flags["step-up-token"],
|
|
116492
|
+
interactive: !flags.json && Boolean(process.stdin.isTTY && process.stderr.isTTY),
|
|
116493
|
+
openBrowser: flags.browser,
|
|
116494
|
+
open: openBrowser,
|
|
116495
|
+
prompt: promptLine$2,
|
|
116496
|
+
write: (text) => process.stderr.write(text)
|
|
116497
|
+
};
|
|
116498
|
+
}
|
|
116499
|
+
/** Comma-separated and repeated values, trimmed, without duplicates. */
|
|
116500
|
+
function listFlag(values) {
|
|
116501
|
+
const out = [];
|
|
116502
|
+
for (const value of values ?? []) for (const part of value.split(",")) {
|
|
116503
|
+
const item = part.trim();
|
|
116504
|
+
if (item && !out.includes(item)) out.push(item);
|
|
116505
|
+
}
|
|
116506
|
+
return out;
|
|
116507
|
+
}
|
|
116508
|
+
function stringList(value) {
|
|
116509
|
+
return Array.isArray(value) && value.every((v) => typeof v === "string") ? [...value] : null;
|
|
116510
|
+
}
|
|
116511
|
+
/** Which mail a key reaches, in words. */
|
|
116512
|
+
function describeMailScope(grant) {
|
|
116513
|
+
if (grant.template === "super_admin") return "every mailbox";
|
|
116514
|
+
if (grant.template === "connected_agent") return "its agent's address";
|
|
116515
|
+
const scope = grant.mail_scope;
|
|
116516
|
+
if (scope === "org") return "every mailbox";
|
|
116517
|
+
if (!scope || typeof scope !== "object" || Array.isArray(scope)) return "unknown";
|
|
116518
|
+
const record = scope;
|
|
116519
|
+
const parts = [];
|
|
116520
|
+
const addresses = stringList(record.addresses) ?? [];
|
|
116521
|
+
const domains = stringList(record.domains) ?? [];
|
|
116522
|
+
const rules = stringList(record.rules) ?? [];
|
|
116523
|
+
if (addresses.length > 0) parts.push(`addresses ${addresses.join(", ")}`);
|
|
116524
|
+
if (domains.length > 0) parts.push(`domains ${domains.join(", ")}`);
|
|
116525
|
+
if (rules.length > 0) parts.push(`rules ${rules.join(", ")}`);
|
|
116526
|
+
return parts.length > 0 ? parts.join("; ") : "no mailbox";
|
|
116527
|
+
}
|
|
116528
|
+
/** What a key may do, in words. */
|
|
116529
|
+
function describePermissions(grant) {
|
|
116530
|
+
if (grant.template === "super_admin") return "super admin (every permission)";
|
|
116531
|
+
if (grant.template) return grant.template;
|
|
116532
|
+
const permissions = grant.permissions ?? [];
|
|
116533
|
+
return permissions.length > 0 ? permissions.join(", ") : "none";
|
|
114607
116534
|
}
|
|
114608
116535
|
function formatKeyRows(rows) {
|
|
114609
116536
|
if (rows.length === 0) return "No API keys.";
|
|
114610
116537
|
return rows.map((row) => {
|
|
114611
|
-
const
|
|
114612
|
-
|
|
114613
|
-
return `${row.id} ${row.prefix ?? ""} ${row.name ?? "(unnamed)"} ${grant} expires ${row.expires_at ?? "never"} last used ${row.last_used_at ?? "never"}${flags}`;
|
|
116538
|
+
const suspended = row.suspended ? " [suspended]" : "";
|
|
116539
|
+
return `${row.id} ${row.key_prefix} ${row.name ?? "(unnamed)"} ${describePermissions(row.grant)} mail: ${describeMailScope(row.grant)} expires ${row.expires_at ?? "never"} last used ${row.last_used_at ?? "never"}${suspended}`;
|
|
114614
116540
|
}).join("\n");
|
|
114615
116541
|
}
|
|
116542
|
+
function formatKeyDetail(key) {
|
|
116543
|
+
const lines = [
|
|
116544
|
+
`Name: ${key.name ?? "(unnamed)"}`,
|
|
116545
|
+
`Id: ${key.id}`,
|
|
116546
|
+
`Prefix: ${key.key_prefix}`,
|
|
116547
|
+
`Kind: ${key.kind}`,
|
|
116548
|
+
`Mail: ${describeMailScope(key.grant)}`,
|
|
116549
|
+
`Created: ${key.created_at ?? "unknown"}`,
|
|
116550
|
+
`Expires: ${key.expires_at ?? "never"}`,
|
|
116551
|
+
`Last used: ${key.last_used_at ?? "never"}`,
|
|
116552
|
+
`Suspended: ${key.suspended ? "yes" : "no"}`
|
|
116553
|
+
];
|
|
116554
|
+
if (key.agent_address) lines.push(`Agent: ${key.agent_address}`);
|
|
116555
|
+
if (key.grant.template) lines.push(`Permissions: ${describePermissions(key.grant)}`);
|
|
116556
|
+
else {
|
|
116557
|
+
lines.push("Permissions:");
|
|
116558
|
+
for (const permission of key.grant.permissions ?? []) lines.push(` ${permission}`);
|
|
116559
|
+
}
|
|
116560
|
+
return lines.join("\n");
|
|
116561
|
+
}
|
|
116562
|
+
const EVERY_MAILBOX_PRESETS = /* @__PURE__ */ new Set([
|
|
116563
|
+
"super_admin",
|
|
116564
|
+
"read_only",
|
|
116565
|
+
"send_only"
|
|
116566
|
+
]);
|
|
116567
|
+
const LISTED_PRESETS = /* @__PURE__ */ new Set(["own_addresses", "own_addresses_read_only"]);
|
|
116568
|
+
const KEY_PRESETS = [...EVERY_MAILBOX_PRESETS, ...LISTED_PRESETS];
|
|
116569
|
+
/**
|
|
116570
|
+
* The grant a new key asks for. There is no default: the caller names a
|
|
116571
|
+
* preset or the permissions, and a key with chosen permissions also says
|
|
116572
|
+
* which mail it reaches (addresses, domains, email rules, or every mailbox).
|
|
116573
|
+
*/
|
|
116574
|
+
function buildCreateGrant(choice) {
|
|
116575
|
+
const listed = choice.addresses.length > 0 || choice.domains.length > 0 || choice.rules.length > 0;
|
|
116576
|
+
const scope = {
|
|
116577
|
+
...choice.addresses.length > 0 ? { addresses: choice.addresses } : {},
|
|
116578
|
+
...choice.domains.length > 0 ? { domains: choice.domains } : {},
|
|
116579
|
+
...choice.rules.length > 0 ? { rules: choice.rules } : {}
|
|
116580
|
+
};
|
|
116581
|
+
if (choice.permissions.length > 0) {
|
|
116582
|
+
if (choice.preset) return {
|
|
116583
|
+
ok: false,
|
|
116584
|
+
message: "Pass either --preset or --permission, not both."
|
|
116585
|
+
};
|
|
116586
|
+
if (listed === choice.allMailboxes) return {
|
|
116587
|
+
ok: false,
|
|
116588
|
+
message: choice.allMailboxes ? "--all-mailboxes reaches every mailbox, so it cannot be combined with --address, --domain or --rule." : "Say which mail the key reaches: --address, --domain or --rule (each repeatable), or --all-mailboxes."
|
|
116589
|
+
};
|
|
116590
|
+
return {
|
|
116591
|
+
ok: true,
|
|
116592
|
+
grant: {
|
|
116593
|
+
preset: "custom",
|
|
116594
|
+
permissions: choice.permissions,
|
|
116595
|
+
...choice.allMailboxes ? { mail_scope: "org" } : scope
|
|
116596
|
+
}
|
|
116597
|
+
};
|
|
116598
|
+
}
|
|
116599
|
+
if (!choice.preset) return {
|
|
116600
|
+
ok: false,
|
|
116601
|
+
message: "Say what the key can do: pass --preset or --permission. There is no default."
|
|
116602
|
+
};
|
|
116603
|
+
if (choice.allMailboxes) return {
|
|
116604
|
+
ok: false,
|
|
116605
|
+
message: "--all-mailboxes is only for a key with --permission."
|
|
116606
|
+
};
|
|
116607
|
+
if (EVERY_MAILBOX_PRESETS.has(choice.preset)) {
|
|
116608
|
+
if (listed) return {
|
|
116609
|
+
ok: false,
|
|
116610
|
+
message: `${choice.preset} reaches every mailbox, so it takes no --address, --domain or --rule.`
|
|
116611
|
+
};
|
|
116612
|
+
return {
|
|
116613
|
+
ok: true,
|
|
116614
|
+
grant: choice.preset
|
|
116615
|
+
};
|
|
116616
|
+
}
|
|
116617
|
+
if (LISTED_PRESETS.has(choice.preset)) {
|
|
116618
|
+
if (!listed) return {
|
|
116619
|
+
ok: false,
|
|
116620
|
+
message: `${choice.preset} needs --address, --domain or --rule.`
|
|
116621
|
+
};
|
|
116622
|
+
return {
|
|
116623
|
+
ok: true,
|
|
116624
|
+
grant: {
|
|
116625
|
+
preset: choice.preset,
|
|
116626
|
+
...scope
|
|
116627
|
+
}
|
|
116628
|
+
};
|
|
116629
|
+
}
|
|
116630
|
+
return {
|
|
116631
|
+
ok: false,
|
|
116632
|
+
message: `--preset must be one of ${KEY_PRESETS.join(", ")}.`
|
|
116633
|
+
};
|
|
116634
|
+
}
|
|
116635
|
+
/** The mail scope fields a change can send back unchanged. */
|
|
116636
|
+
const RESTATABLE_SCOPE_FIELDS = /* @__PURE__ */ new Set([
|
|
116637
|
+
"addresses",
|
|
116638
|
+
"domains",
|
|
116639
|
+
"rules",
|
|
116640
|
+
"depth"
|
|
116641
|
+
]);
|
|
116642
|
+
/**
|
|
116643
|
+
* The grant that restates a key's current grant with permissions added or
|
|
116644
|
+
* removed, or its email rules replaced, and everything else as it is. Only a
|
|
116645
|
+
* key with a permission list and a mail scope the CLI can restate exactly;
|
|
116646
|
+
* anything else is changed in the dashboard.
|
|
116647
|
+
*/
|
|
116648
|
+
function buildUpdatedGrant(current, change) {
|
|
116649
|
+
if (current.template === "super_admin") return {
|
|
116650
|
+
ok: false,
|
|
116651
|
+
message: "This is a super admin key: it holds every permission already. To narrow it, create a key with only what you need, then revoke this one."
|
|
116652
|
+
};
|
|
116653
|
+
if (current.template) return {
|
|
116654
|
+
ok: false,
|
|
116655
|
+
message: `This key's permissions come from its template (${current.template}) and are not changed here.`
|
|
116656
|
+
};
|
|
116657
|
+
const resources = current.resources;
|
|
116658
|
+
if (resources !== void 0 && resources !== null && (typeof resources !== "object" || Object.keys(resources).length > 0)) return {
|
|
116659
|
+
ok: false,
|
|
116660
|
+
message: "This key is limited to selected resources, which the CLI cannot restate. Change it in the dashboard."
|
|
116661
|
+
};
|
|
116662
|
+
const held = stringList(current.permissions);
|
|
116663
|
+
if (!held) return {
|
|
116664
|
+
ok: false,
|
|
116665
|
+
message: "This key's permissions could not be read."
|
|
116666
|
+
};
|
|
116667
|
+
const permissions = [.../* @__PURE__ */ new Set([...held, ...change.add])].filter((p) => !change.remove.includes(p)).sort();
|
|
116668
|
+
if (permissions.length === 0) return {
|
|
116669
|
+
ok: false,
|
|
116670
|
+
message: "A key needs at least one permission. To stop it working, revoke it."
|
|
116671
|
+
};
|
|
116672
|
+
const scope = current.mail_scope;
|
|
116673
|
+
if (scope === "org") {
|
|
116674
|
+
if (change.rules) return {
|
|
116675
|
+
ok: false,
|
|
116676
|
+
message: "This key reaches every mailbox, so email rules cannot be set on it. Create a key limited to the rules instead."
|
|
116677
|
+
};
|
|
116678
|
+
return {
|
|
116679
|
+
ok: true,
|
|
116680
|
+
grant: {
|
|
116681
|
+
preset: "custom",
|
|
116682
|
+
permissions,
|
|
116683
|
+
mail_scope: "org"
|
|
116684
|
+
},
|
|
116685
|
+
permissions
|
|
116686
|
+
};
|
|
116687
|
+
}
|
|
116688
|
+
if (!scope || typeof scope !== "object" || Array.isArray(scope)) return {
|
|
116689
|
+
ok: false,
|
|
116690
|
+
message: "This key's mail scope could not be read. Change it in the dashboard."
|
|
116691
|
+
};
|
|
116692
|
+
const record = scope;
|
|
116693
|
+
const addresses = stringList(record.addresses ?? []);
|
|
116694
|
+
const domains = stringList(record.domains ?? []);
|
|
116695
|
+
const rules = change.rules ?? stringList(record.rules ?? []);
|
|
116696
|
+
if (!addresses || !domains || !rules || Object.keys(record).some((field) => !RESTATABLE_SCOPE_FIELDS.has(field))) return {
|
|
116697
|
+
ok: false,
|
|
116698
|
+
message: "This key's mail scope has settings the CLI cannot restate. Change it in the dashboard."
|
|
116699
|
+
};
|
|
116700
|
+
if (addresses.length === 0 && domains.length === 0 && rules.length === 0) return {
|
|
116701
|
+
ok: false,
|
|
116702
|
+
message: "The key would reach no mail. Keep at least one address, domain or rule."
|
|
116703
|
+
};
|
|
116704
|
+
return {
|
|
116705
|
+
ok: true,
|
|
116706
|
+
grant: {
|
|
116707
|
+
preset: "custom",
|
|
116708
|
+
permissions,
|
|
116709
|
+
...addresses.length > 0 ? { addresses } : {},
|
|
116710
|
+
...domains.length > 0 ? { domains } : {},
|
|
116711
|
+
...rules.length > 0 ? { rules } : {}
|
|
116712
|
+
},
|
|
116713
|
+
permissions
|
|
116714
|
+
};
|
|
116715
|
+
}
|
|
116716
|
+
async function authenticate(command, flags) {
|
|
116717
|
+
return createAuthenticatedCliApiClient({
|
|
116718
|
+
apiKey: flags["api-key"],
|
|
116719
|
+
apiBaseUrl: flags["api-base-url"],
|
|
116720
|
+
configDir: command.config.configDir
|
|
116721
|
+
});
|
|
116722
|
+
}
|
|
116723
|
+
/** Print a refusal and set a failing exit code. */
|
|
116724
|
+
function reportKeysError(command, outcome, auth, json) {
|
|
116725
|
+
if (json) process.stderr.write(`${JSON.stringify(outcome.payload)}\n`);
|
|
116726
|
+
else writeErrorWithHints(outcome.payload);
|
|
116727
|
+
if (outcome.stepUpUrl) process.stderr.write(`Approve this request in your browser: ${outcome.stepUpUrl}\nThen run the same command again with --step-up-token <token from the page>.\n`);
|
|
116728
|
+
surfaceUnauthorizedHint({
|
|
116729
|
+
auth: auth.auth,
|
|
116730
|
+
baseUrlOverridden: auth.baseUrlOverridden,
|
|
116731
|
+
configDir: command.config.configDir,
|
|
116732
|
+
payload: outcome.payload
|
|
116733
|
+
});
|
|
116734
|
+
process.exitCode = 1;
|
|
116735
|
+
}
|
|
116736
|
+
function writeWarnings(warnings) {
|
|
116737
|
+
for (const warning of warnings ?? []) if (typeof warning.description === "string") process.stderr.write(`Note: ${warning.description}\n`);
|
|
116738
|
+
}
|
|
114616
116739
|
var KeysListCommand = class KeysListCommand extends Command {
|
|
114617
|
-
static description = `List the organization's API keys
|
|
116740
|
+
static description = `List the organization's API keys with their permissions, mail scope, expiry and last use. Only metadata is shown, never a secret.
|
|
114618
116741
|
|
|
114619
|
-
|
|
116742
|
+
You see your own keys, and every key if your role may read them all, as in the dashboard.`;
|
|
114620
116743
|
static summary = "List API keys";
|
|
114621
116744
|
static examples = ["<%= config.bin %> keys list", "<%= config.bin %> keys list --json"];
|
|
114622
116745
|
static flags = {
|
|
114623
116746
|
"api-key": API_KEY_FLAG$1,
|
|
114624
116747
|
"api-base-url": API_BASE_URL_FLAG$2,
|
|
114625
|
-
json: Flags.boolean({ description: "Print the
|
|
116748
|
+
json: Flags.boolean({ description: "Print the keys as JSON." })
|
|
114626
116749
|
};
|
|
114627
116750
|
async run() {
|
|
114628
116751
|
const { flags } = await this.parse(KeysListCommand);
|
|
114629
|
-
const
|
|
114630
|
-
|
|
114631
|
-
|
|
114632
|
-
|
|
114633
|
-
|
|
114634
|
-
|
|
114635
|
-
|
|
114636
|
-
|
|
114637
|
-
|
|
116752
|
+
const auth = await authenticate(this, flags);
|
|
116753
|
+
const items = [];
|
|
116754
|
+
let cursor;
|
|
116755
|
+
for (let page = 0; page < LIST_PAGE_LIMIT; page += 1) {
|
|
116756
|
+
const result = await call(listKeys({
|
|
116757
|
+
client: auth.apiClient.client,
|
|
116758
|
+
...cursor ? { query: { cursor } } : {}
|
|
116759
|
+
}));
|
|
116760
|
+
if (!result.ok) {
|
|
116761
|
+
reportKeysError(this, result, auth, Boolean(flags.json));
|
|
116762
|
+
return;
|
|
116763
|
+
}
|
|
116764
|
+
items.push(...result.data.items);
|
|
116765
|
+
cursor = result.data.next_cursor ?? void 0;
|
|
116766
|
+
if (!cursor) break;
|
|
116767
|
+
}
|
|
116768
|
+
if (flags.json) {
|
|
116769
|
+
this.log(JSON.stringify(items, null, 2));
|
|
116770
|
+
return;
|
|
116771
|
+
}
|
|
116772
|
+
this.log(formatKeyRows(items));
|
|
116773
|
+
}
|
|
116774
|
+
};
|
|
116775
|
+
var KeysGetCommand = class KeysGetCommand extends Command {
|
|
116776
|
+
static description = "Show one API key: its permissions, the mail it reaches, expiry and last use. Never a secret.";
|
|
116777
|
+
static summary = "Show an API key";
|
|
116778
|
+
static examples = ["<%= config.bin %> keys get 0f0e0d0c-0b0a-4908-8706-050403020100", "<%= config.bin %> keys get 0f0e0d0c-0b0a-4908-8706-050403020100 --json"];
|
|
116779
|
+
static args = { id: Args.string({
|
|
116780
|
+
description: "The key's id.",
|
|
116781
|
+
required: true
|
|
116782
|
+
}) };
|
|
116783
|
+
static flags = {
|
|
116784
|
+
"api-key": API_KEY_FLAG$1,
|
|
116785
|
+
"api-base-url": API_BASE_URL_FLAG$2,
|
|
116786
|
+
json: Flags.boolean({ description: "Print the key as JSON." })
|
|
116787
|
+
};
|
|
116788
|
+
async run() {
|
|
116789
|
+
const { args, flags } = await this.parse(KeysGetCommand);
|
|
116790
|
+
const auth = await authenticate(this, flags);
|
|
116791
|
+
const result = await call(getKey({
|
|
116792
|
+
client: auth.apiClient.client,
|
|
116793
|
+
path: { id: args.id }
|
|
116794
|
+
}));
|
|
116795
|
+
if (!result.ok) {
|
|
116796
|
+
reportKeysError(this, result, auth, Boolean(flags.json));
|
|
116797
|
+
return;
|
|
116798
|
+
}
|
|
116799
|
+
this.log(flags.json ? JSON.stringify(result.data, null, 2) : formatKeyDetail(result.data));
|
|
116800
|
+
}
|
|
116801
|
+
};
|
|
116802
|
+
/** The new secret on stdout alone, everything else on stderr. */
|
|
116803
|
+
function printSecret(command, json, document, secret, summary) {
|
|
116804
|
+
if (json) {
|
|
116805
|
+
command.log(JSON.stringify({
|
|
116806
|
+
...document,
|
|
116807
|
+
notice: STORE_SECRET_NOTICE
|
|
116808
|
+
}, null, 2));
|
|
116809
|
+
return;
|
|
116810
|
+
}
|
|
116811
|
+
process.stderr.write(`${summary}\n\n`);
|
|
116812
|
+
command.log(secret);
|
|
116813
|
+
process.stderr.write(`\n${STORE_SECRET_NOTICE}\n`);
|
|
116814
|
+
}
|
|
116815
|
+
var KeysCreateCommand = class KeysCreateCommand extends Command {
|
|
116816
|
+
static description = `Create an API key. Say what it can do with --preset or --permission; there is no default.
|
|
116817
|
+
|
|
116818
|
+
The key is created directly. If your organization requires approval, the command prints the approval link, opens it where it can, and waits for the one-time token the page shows. In a script it prints the link and exits: approve, then run it again with --step-up-token. The key never holds more than you do, and your organization's credential policy applies.
|
|
116819
|
+
|
|
116820
|
+
The secret is printed once, on its own line on stdout (in the JSON with --json). Store it right away: it is not shown again and the CLI does not save it.
|
|
116821
|
+
|
|
116822
|
+
A key limited to email rules (--rule, repeatable) reaches only the mail those rules match. Give it mail:read with --permission, or use --preset own_addresses_read_only.`;
|
|
116823
|
+
static summary = "Create an API key";
|
|
116824
|
+
static examples = [
|
|
116825
|
+
"<%= config.bin %> keys create --name reader --preset read_only",
|
|
116826
|
+
"<%= config.bin %> keys create --name orders --permission mail:read --rule 3b0f6a1e-6c7a-4f43-9d8e-2a1b5c4d3e2f",
|
|
116827
|
+
"<%= config.bin %> keys create --name support --permission mail:read,mail:reply --address support@example.com --expires-in-days 90",
|
|
116828
|
+
"<%= config.bin %> keys create --name everything --preset super_admin"
|
|
116829
|
+
];
|
|
116830
|
+
static flags = {
|
|
116831
|
+
"api-key": API_KEY_FLAG$1,
|
|
116832
|
+
"api-base-url": API_BASE_URL_FLAG$2,
|
|
116833
|
+
name: Flags.string({ description: "A name for the key." }),
|
|
116834
|
+
preset: Flags.string({
|
|
116835
|
+
description: "A preset grant.",
|
|
116836
|
+
options: [...KEY_PRESETS]
|
|
116837
|
+
}),
|
|
116838
|
+
permission: Flags.string({
|
|
116839
|
+
description: "A permission the key holds (repeatable, or comma-separated), for a custom key.",
|
|
116840
|
+
multiple: true
|
|
116841
|
+
}),
|
|
116842
|
+
address: Flags.string({
|
|
116843
|
+
description: "An address the key reaches (repeatable).",
|
|
116844
|
+
multiple: true
|
|
116845
|
+
}),
|
|
116846
|
+
domain: Flags.string({
|
|
116847
|
+
description: "A domain the key reaches (repeatable).",
|
|
116848
|
+
multiple: true
|
|
116849
|
+
}),
|
|
116850
|
+
rule: Flags.string({
|
|
116851
|
+
description: "An email rule id whose matching mail the key reaches (repeatable).",
|
|
116852
|
+
multiple: true
|
|
116853
|
+
}),
|
|
116854
|
+
"all-mailboxes": Flags.boolean({ description: "A key with --permission that reaches every mailbox." }),
|
|
116855
|
+
"expires-in-days": Flags.integer({
|
|
116856
|
+
description: "Expire the key after this many days.",
|
|
116857
|
+
min: 1
|
|
116858
|
+
}),
|
|
116859
|
+
"expires-at": Flags.string({
|
|
116860
|
+
description: "Expire the key at this ISO 8601 time.",
|
|
116861
|
+
exclusive: ["expires-in-days"]
|
|
116862
|
+
}),
|
|
116863
|
+
...APPROVAL_FLAGS,
|
|
116864
|
+
json: Flags.boolean({ description: "Print the new key, its secret included, as JSON." })
|
|
116865
|
+
};
|
|
116866
|
+
async run() {
|
|
116867
|
+
const { flags } = await this.parse(KeysCreateCommand);
|
|
116868
|
+
const grant = buildCreateGrant({
|
|
116869
|
+
preset: flags.preset,
|
|
116870
|
+
permissions: listFlag(flags.permission),
|
|
116871
|
+
addresses: listFlag(flags.address),
|
|
116872
|
+
domains: listFlag(flags.domain),
|
|
116873
|
+
rules: listFlag(flags.rule),
|
|
116874
|
+
allMailboxes: flags["all-mailboxes"]
|
|
114638
116875
|
});
|
|
114639
|
-
if (
|
|
114640
|
-
|
|
114641
|
-
|
|
114642
|
-
|
|
114643
|
-
|
|
114644
|
-
},
|
|
116876
|
+
if (!grant.ok) this.error(grant.message, { exit: 2 });
|
|
116877
|
+
const auth = await authenticate(this, flags);
|
|
116878
|
+
const body = {
|
|
116879
|
+
grant: grant.grant,
|
|
116880
|
+
...flags.name ? { name: flags.name } : {},
|
|
116881
|
+
...flags["expires-in-days"] ? { expires_in_days: flags["expires-in-days"] } : {},
|
|
116882
|
+
...flags["expires-at"] ? { expires_at: flags["expires-at"] } : {}
|
|
116883
|
+
};
|
|
116884
|
+
const idempotencyKey = `cli-${randomUUID()}`;
|
|
116885
|
+
const result = await withApproval((token) => call(createKey({
|
|
116886
|
+
client: auth.apiClient.client,
|
|
116887
|
+
body,
|
|
116888
|
+
headers: {
|
|
116889
|
+
"Idempotency-Key": idempotencyKey,
|
|
116890
|
+
...token ? { [STEP_UP_HEADER$1]: token } : {}
|
|
116891
|
+
}
|
|
116892
|
+
})), approvalIo(flags));
|
|
116893
|
+
if (!result.ok) {
|
|
116894
|
+
reportKeysError(this, result, auth, Boolean(flags.json));
|
|
116895
|
+
return;
|
|
116896
|
+
}
|
|
116897
|
+
const key = result.data;
|
|
116898
|
+
if (!flags.json) writeWarnings(key.warnings);
|
|
116899
|
+
printSecret(this, Boolean(flags.json), key, key.key, [
|
|
116900
|
+
`Created API key ${key.name ?? "(unnamed)"} (${key.id}), prefix ${key.key_prefix}.`,
|
|
116901
|
+
`Permissions: ${describePermissions({
|
|
116902
|
+
template: key.grant.template,
|
|
116903
|
+
permissions: key.grant.permissions,
|
|
116904
|
+
mail_scope: key.grant.mail_scope
|
|
116905
|
+
})}`,
|
|
116906
|
+
`Mail: ${describeMailScope({
|
|
116907
|
+
template: key.grant.template,
|
|
116908
|
+
permissions: key.grant.permissions,
|
|
116909
|
+
mail_scope: key.grant.mail_scope
|
|
116910
|
+
})}`,
|
|
116911
|
+
`Expires: ${key.expires_at ?? "never"}`
|
|
116912
|
+
].join("\n"));
|
|
116913
|
+
}
|
|
116914
|
+
};
|
|
116915
|
+
var KeysRotateCommand = class KeysRotateCommand extends Command {
|
|
116916
|
+
static description = `Rotate an API key: make a successor with the same permissions and print its secret once. The old key keeps working for the overlap, then stops.
|
|
116917
|
+
|
|
116918
|
+
The rotation runs directly; if your organization requires approval, the command prints the approval link and takes --step-up-token, as for a new key. Store the new secret right away: it is not shown again and the CLI does not save it.`;
|
|
116919
|
+
static summary = "Rotate an API key";
|
|
116920
|
+
static examples = ["<%= config.bin %> keys rotate 0f0e0d0c-0b0a-4908-8706-050403020100", "<%= config.bin %> keys rotate 0f0e0d0c-0b0a-4908-8706-050403020100 --overlap-seconds 0"];
|
|
116921
|
+
static args = { id: Args.string({
|
|
116922
|
+
description: "The key's id.",
|
|
116923
|
+
required: true
|
|
116924
|
+
}) };
|
|
116925
|
+
static flags = {
|
|
116926
|
+
"api-key": API_KEY_FLAG$1,
|
|
116927
|
+
"api-base-url": API_BASE_URL_FLAG$2,
|
|
116928
|
+
"overlap-seconds": Flags.integer({
|
|
116929
|
+
description: "How long the old key keeps working, in seconds. 0 stops it now.",
|
|
116930
|
+
min: 0
|
|
116931
|
+
}),
|
|
116932
|
+
...APPROVAL_FLAGS,
|
|
116933
|
+
json: Flags.boolean({ description: "Print the new key, its secret included, as JSON." })
|
|
116934
|
+
};
|
|
116935
|
+
async run() {
|
|
116936
|
+
const { args, flags } = await this.parse(KeysRotateCommand);
|
|
116937
|
+
const auth = await authenticate(this, flags);
|
|
116938
|
+
const body = flags["overlap-seconds"] === void 0 ? {} : { overlap_seconds: flags["overlap-seconds"] };
|
|
116939
|
+
const result = await withApproval((token) => call(rotateKey({
|
|
116940
|
+
client: auth.apiClient.client,
|
|
116941
|
+
path: { id: args.id },
|
|
116942
|
+
body,
|
|
116943
|
+
...token ? { headers: { [STEP_UP_HEADER$1]: token } } : {}
|
|
116944
|
+
})), approvalIo(flags));
|
|
116945
|
+
if (!result.ok) {
|
|
116946
|
+
reportKeysError(this, result, auth, Boolean(flags.json));
|
|
116947
|
+
return;
|
|
116948
|
+
}
|
|
116949
|
+
const rotated = result.data;
|
|
116950
|
+
printSecret(this, Boolean(flags.json), rotated, rotated.key, `Rotated key ${rotated.previous_key_id}. The new key is ${rotated.id}, prefix ${rotated.key_prefix}. The old key works until ${rotated.previous_key_expires_at}.`);
|
|
116951
|
+
}
|
|
116952
|
+
};
|
|
116953
|
+
var KeysUpdateCommand = class KeysUpdateCommand extends Command {
|
|
116954
|
+
static description = `Change an API key's permissions, email rules or name. It keeps its id and secret.
|
|
116955
|
+
|
|
116956
|
+
--add and --remove take permissions (repeatable, or comma-separated). --rule sets the email rules the key reaches, replacing the ones it has. Everything else about the key stays as it is.
|
|
116957
|
+
|
|
116958
|
+
The change runs directly; if your organization requires approval, the command prints the approval link and takes --step-up-token, as for a new key. A key never holds more than you do.`;
|
|
116959
|
+
static summary = "Change an API key";
|
|
116960
|
+
static examples = [
|
|
116961
|
+
"<%= config.bin %> keys update 0f0e0d0c-0b0a-4908-8706-050403020100 --add mail:send,mail:reply",
|
|
116962
|
+
"<%= config.bin %> keys update 0f0e0d0c-0b0a-4908-8706-050403020100 --remove mail:send",
|
|
116963
|
+
"<%= config.bin %> keys update 0f0e0d0c-0b0a-4908-8706-050403020100 --rule 3b0f6a1e-6c7a-4f43-9d8e-2a1b5c4d3e2f"
|
|
116964
|
+
];
|
|
116965
|
+
static args = { id: Args.string({
|
|
116966
|
+
description: "The key's id.",
|
|
116967
|
+
required: true
|
|
116968
|
+
}) };
|
|
116969
|
+
static flags = {
|
|
116970
|
+
"api-key": API_KEY_FLAG$1,
|
|
116971
|
+
"api-base-url": API_BASE_URL_FLAG$2,
|
|
116972
|
+
add: Flags.string({
|
|
116973
|
+
description: "Permissions to add (repeatable, or comma-separated).",
|
|
116974
|
+
multiple: true
|
|
116975
|
+
}),
|
|
116976
|
+
remove: Flags.string({
|
|
116977
|
+
description: "Permissions to remove (repeatable, or comma-separated).",
|
|
116978
|
+
multiple: true
|
|
116979
|
+
}),
|
|
116980
|
+
rule: Flags.string({
|
|
116981
|
+
description: "An email rule id the key reaches (repeatable). Replaces the key's rules.",
|
|
116982
|
+
multiple: true
|
|
116983
|
+
}),
|
|
116984
|
+
name: Flags.string({ description: "A new name for the key." }),
|
|
116985
|
+
...APPROVAL_FLAGS,
|
|
116986
|
+
json: Flags.boolean({ description: "Print the result as JSON." })
|
|
116987
|
+
};
|
|
116988
|
+
async run() {
|
|
116989
|
+
const { args, flags } = await this.parse(KeysUpdateCommand);
|
|
116990
|
+
const add = listFlag(flags.add);
|
|
116991
|
+
const remove = listFlag(flags.remove);
|
|
116992
|
+
const rules = flags.rule ? listFlag(flags.rule) : void 0;
|
|
116993
|
+
const both = add.filter((p) => remove.includes(p));
|
|
116994
|
+
if (both.length > 0) this.error(`Both added and removed: ${both.join(", ")}.`, { exit: 2 });
|
|
116995
|
+
const changesGrant = add.length > 0 || remove.length > 0 || !!rules;
|
|
116996
|
+
if (!changesGrant && flags.name === void 0) this.error("Nothing to change: pass --add, --remove, --rule or --name.", { exit: 2 });
|
|
116997
|
+
const auth = await authenticate(this, flags);
|
|
116998
|
+
const body = { ...flags.name !== void 0 ? { name: flags.name } : {} };
|
|
116999
|
+
if (changesGrant) {
|
|
117000
|
+
const current = await call(getKey({
|
|
117001
|
+
client: auth.apiClient.client,
|
|
117002
|
+
path: { id: args.id }
|
|
117003
|
+
}));
|
|
117004
|
+
if (!current.ok) {
|
|
117005
|
+
reportKeysError(this, current, auth, Boolean(flags.json));
|
|
117006
|
+
return;
|
|
117007
|
+
}
|
|
117008
|
+
const next = buildUpdatedGrant(current.data.grant, {
|
|
117009
|
+
add,
|
|
117010
|
+
remove,
|
|
117011
|
+
...rules ? { rules } : {}
|
|
117012
|
+
});
|
|
117013
|
+
if (!next.ok) this.error(next.message, { exit: 2 });
|
|
117014
|
+
body.grant = next.grant;
|
|
117015
|
+
const ref = current.data.grant.ref;
|
|
117016
|
+
if (typeof ref === "string") body.expected_grant_ref = ref;
|
|
117017
|
+
}
|
|
117018
|
+
const result = await withApproval((token) => call(updateKey({
|
|
117019
|
+
client: auth.apiClient.client,
|
|
117020
|
+
path: { id: args.id },
|
|
117021
|
+
body,
|
|
117022
|
+
...token ? { headers: { [STEP_UP_HEADER$1]: token } } : {}
|
|
117023
|
+
})), approvalIo(flags));
|
|
117024
|
+
if (!result.ok) {
|
|
117025
|
+
reportKeysError(this, result, auth, Boolean(flags.json));
|
|
114645
117026
|
return;
|
|
114646
117027
|
}
|
|
114647
|
-
const
|
|
117028
|
+
const grantChanged = result.data.changed.includes("grant");
|
|
117029
|
+
const after = grantChanged ? await call(getKey({
|
|
117030
|
+
client: auth.apiClient.client,
|
|
117031
|
+
path: { id: args.id }
|
|
117032
|
+
})) : null;
|
|
114648
117033
|
if (flags.json) {
|
|
114649
|
-
this.log(JSON.stringify(
|
|
117034
|
+
this.log(JSON.stringify({
|
|
117035
|
+
...result.data,
|
|
117036
|
+
...after?.ok ? { key: after.data } : {},
|
|
117037
|
+
...grantChanged ? { notice: HELD_REQUEST_NOTICE } : {}
|
|
117038
|
+
}, null, 2));
|
|
114650
117039
|
return;
|
|
114651
117040
|
}
|
|
114652
|
-
|
|
117041
|
+
writeWarnings(result.data.warnings);
|
|
117042
|
+
const changed = result.data.changed;
|
|
117043
|
+
this.log(changed.length > 0 ? `Updated key ${args.id}: ${changed.join(", ")}.` : `Key ${args.id} already matched; nothing changed.`);
|
|
117044
|
+
if (after?.ok) {
|
|
117045
|
+
this.log(`Permissions: ${describePermissions(after.data.grant)}`);
|
|
117046
|
+
this.log(`Mail: ${describeMailScope(after.data.grant)}`);
|
|
117047
|
+
}
|
|
117048
|
+
if (grantChanged) process.stderr.write(`${HELD_REQUEST_NOTICE}\n`);
|
|
117049
|
+
}
|
|
117050
|
+
};
|
|
117051
|
+
var KeysRevokeCommand = class KeysRevokeCommand extends Command {
|
|
117052
|
+
static description = `Revoke an API key. It stops working at once; what it set up keeps working and is listed for review.
|
|
117053
|
+
|
|
117054
|
+
Asks for confirmation first; pass --yes to skip the prompt in scripts.`;
|
|
117055
|
+
static summary = "Revoke an API key";
|
|
117056
|
+
static examples = ["<%= config.bin %> keys revoke 0f0e0d0c-0b0a-4908-8706-050403020100", "<%= config.bin %> keys revoke 0f0e0d0c-0b0a-4908-8706-050403020100 --yes"];
|
|
117057
|
+
static args = { id: Args.string({
|
|
117058
|
+
description: "The key's id.",
|
|
117059
|
+
required: true
|
|
117060
|
+
}) };
|
|
117061
|
+
static flags = {
|
|
117062
|
+
"api-key": API_KEY_FLAG$1,
|
|
117063
|
+
"api-base-url": API_BASE_URL_FLAG$2,
|
|
117064
|
+
yes: Flags.boolean({
|
|
117065
|
+
char: "y",
|
|
117066
|
+
description: "Revoke without asking for confirmation."
|
|
117067
|
+
}),
|
|
117068
|
+
reason: Flags.string({ description: "Why, recorded with the revocation." }),
|
|
117069
|
+
json: Flags.boolean({ description: "Print the result as JSON." })
|
|
117070
|
+
};
|
|
117071
|
+
async run() {
|
|
117072
|
+
const { args, flags } = await this.parse(KeysRevokeCommand);
|
|
117073
|
+
if (!flags.yes) {
|
|
117074
|
+
if (flags.json || !(process.stdin.isTTY && process.stderr.isTTY)) this.error("Not revoking: no terminal to confirm in. Pass --yes to revoke without a prompt.", { exit: 2 });
|
|
117075
|
+
const answer = await promptLine$2(`Revoke key ${args.id}? It stops working at once. [y/N] `);
|
|
117076
|
+
if (!/^y(es)?$/i.test(answer.trim())) {
|
|
117077
|
+
process.stderr.write("Cancelled. The key still works.\n");
|
|
117078
|
+
process.exitCode = 1;
|
|
117079
|
+
return;
|
|
117080
|
+
}
|
|
117081
|
+
}
|
|
117082
|
+
const auth = await authenticate(this, flags);
|
|
117083
|
+
const result = await call(revokeCredential({
|
|
117084
|
+
client: auth.apiClient.client,
|
|
117085
|
+
body: {
|
|
117086
|
+
kind: "org_key",
|
|
117087
|
+
id: args.id,
|
|
117088
|
+
...flags.reason ? { reason: flags.reason } : {}
|
|
117089
|
+
}
|
|
117090
|
+
}));
|
|
117091
|
+
if (!result.ok) {
|
|
117092
|
+
reportKeysError(this, result, auth, Boolean(flags.json));
|
|
117093
|
+
return;
|
|
117094
|
+
}
|
|
117095
|
+
if (flags.json) {
|
|
117096
|
+
this.log(JSON.stringify(result.data, null, 2));
|
|
117097
|
+
return;
|
|
117098
|
+
}
|
|
117099
|
+
this.log(`Revoked key ${args.id}.`);
|
|
117100
|
+
const standing = result.data.standing_objects;
|
|
117101
|
+
if (Array.isArray(standing) && standing.length > 0) this.log(`It set up ${standing.length} item(s) that keep working. Review them with --json.`);
|
|
114653
117102
|
}
|
|
114654
117103
|
};
|
|
114655
117104
|
const hash = (value) => createHash("sha256").update(value).digest("hex");
|
|
@@ -119864,6 +122313,16 @@ function printData(command, responseData) {
|
|
|
119864
122313
|
const data = responseData?.data ?? null;
|
|
119865
122314
|
command.log(JSON.stringify(data, null, 2));
|
|
119866
122315
|
}
|
|
122316
|
+
const CONTROL_CHARACTERS = new RegExp(`[${String.fromCharCode(0)}-${String.fromCharCode(31)}]`);
|
|
122317
|
+
/**
|
|
122318
|
+
* The stderr line naming the next page's cursor. A memory key can hold a line
|
|
122319
|
+
* break or another control character, which would split or garble the line,
|
|
122320
|
+
* so such a cursor is printed JSON-encoded, with a note on how to pass it.
|
|
122321
|
+
*/
|
|
122322
|
+
function nextCursorLine(cursor) {
|
|
122323
|
+
if (!CONTROL_CHARACTERS.test(cursor)) return `next cursor: ${cursor}\n`;
|
|
122324
|
+
return `next cursor (JSON-encoded, it holds control characters; decode it before passing it to --cursor, or read meta.cursor with --json --envelope): ${JSON.stringify(cursor)}\n`;
|
|
122325
|
+
}
|
|
119867
122326
|
function handleMemoryInputError(error) {
|
|
119868
122327
|
if (!(error instanceof MemoryCliInputError)) return false;
|
|
119869
122328
|
process.stderr.write(`${error.message}\n`);
|
|
@@ -120003,6 +122462,7 @@ var MemoriesSetCommand = class MemoriesSetCommand extends Command {
|
|
|
120003
122462
|
value: Args.string({ description: "JSON value. Strings must be quoted as JSON strings." })
|
|
120004
122463
|
};
|
|
120005
122464
|
static flags = {
|
|
122465
|
+
json: JSON_OUTPUT_FLAG,
|
|
120006
122466
|
"api-key": API_KEY_FLAG,
|
|
120007
122467
|
"api-base-url": API_BASE_URL_FLAG$1,
|
|
120008
122468
|
...SCOPE_FLAGS,
|
|
@@ -120094,6 +122554,7 @@ var MemoriesGetCommand = class MemoriesGetCommand extends Command {
|
|
|
120094
122554
|
required: true
|
|
120095
122555
|
}) };
|
|
120096
122556
|
static flags = {
|
|
122557
|
+
json: JSON_OUTPUT_FLAG,
|
|
120097
122558
|
"api-key": API_KEY_FLAG,
|
|
120098
122559
|
"api-base-url": API_BASE_URL_FLAG$1,
|
|
120099
122560
|
...SCOPE_FLAGS,
|
|
@@ -120147,6 +122608,7 @@ var MemoriesDeleteCommand = class MemoriesDeleteCommand extends Command {
|
|
|
120147
122608
|
required: true
|
|
120148
122609
|
}) };
|
|
120149
122610
|
static flags = {
|
|
122611
|
+
json: JSON_OUTPUT_FLAG,
|
|
120150
122612
|
"api-key": API_KEY_FLAG,
|
|
120151
122613
|
"api-base-url": API_BASE_URL_FLAG$1,
|
|
120152
122614
|
...SCOPE_FLAGS,
|
|
@@ -120201,6 +122663,7 @@ var MemoriesSearchCommand = class MemoriesSearchCommand extends Command {
|
|
|
120201
122663
|
];
|
|
120202
122664
|
static args = { prefix: Args.string({ description: "Key prefix. Omit to list all active memories in scope." }) };
|
|
120203
122665
|
static flags = {
|
|
122666
|
+
json: JSON_OUTPUT_FLAG,
|
|
120204
122667
|
"api-key": API_KEY_FLAG,
|
|
120205
122668
|
"api-base-url": API_BASE_URL_FLAG$1,
|
|
120206
122669
|
...SCOPE_FLAGS,
|
|
@@ -120210,7 +122673,8 @@ var MemoriesSearchCommand = class MemoriesSearchCommand extends Command {
|
|
|
120210
122673
|
min: 1,
|
|
120211
122674
|
max: 100
|
|
120212
122675
|
}),
|
|
120213
|
-
cursor: Flags.string({ description: "Key cursor from
|
|
122676
|
+
cursor: Flags.string({ description: "Key cursor from the previous page. The next page's cursor is meta.cursor, null on the last page: without --json it is printed on stderr as `next cursor: <value>` (JSON-encoded, with a note, when it holds control characters); with --json, add --envelope to get it, the reliable way for a script to page." }),
|
|
122677
|
+
envelope: Flags.boolean({ description: "Print the full response envelope, including meta.cursor for the next page. Defaults to printing only the data payload." }),
|
|
120214
122678
|
"metadata-only": Flags.boolean({ description: "Omit memory values and return metadata only." }),
|
|
120215
122679
|
"updated-after": Flags.string({ description: "Only include memories updated at or after this ISO timestamp." }),
|
|
120216
122680
|
"updated-before": Flags.string({ description: "Only include memories updated at or before this ISO timestamp." }),
|
|
@@ -120247,7 +122711,11 @@ var MemoriesSearchCommand = class MemoriesSearchCommand extends Command {
|
|
|
120247
122711
|
});
|
|
120248
122712
|
return;
|
|
120249
122713
|
}
|
|
120250
|
-
|
|
122714
|
+
const envelope = result.data;
|
|
122715
|
+
const cursor = envelope?.meta?.cursor;
|
|
122716
|
+
if (cursor && !flags.json) process.stderr.write(nextCursorLine(cursor));
|
|
122717
|
+
if (flags.envelope) this.log(JSON.stringify(envelope ?? null, null, 2));
|
|
122718
|
+
else printData(this, result.data);
|
|
120251
122719
|
});
|
|
120252
122720
|
}
|
|
120253
122721
|
};
|
|
@@ -120767,6 +123235,7 @@ var OrgSecretsListCommand = class OrgSecretsListCommand extends Command {
|
|
|
120767
123235
|
static summary = "List global secrets (keys only; values never returned)";
|
|
120768
123236
|
static examples = ["<%= config.bin %> org secrets list"];
|
|
120769
123237
|
static flags = {
|
|
123238
|
+
json: JSON_OUTPUT_FLAG,
|
|
120770
123239
|
"api-key": Flags.string({
|
|
120771
123240
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
120772
123241
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -120812,6 +123281,7 @@ var OrgSecretsRemoveCommand = class OrgSecretsRemoveCommand extends Command {
|
|
|
120812
123281
|
static aliases = ["org:secrets:delete"];
|
|
120813
123282
|
static examples = ["<%= config.bin %> org secrets remove --key MY_API_KEY"];
|
|
120814
123283
|
static flags = {
|
|
123284
|
+
json: JSON_OUTPUT_FLAG,
|
|
120815
123285
|
"api-key": Flags.string({
|
|
120816
123286
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
120817
123287
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -120872,6 +123342,7 @@ var OrgSecretsSetCommand = class OrgSecretsSetCommand extends Command {
|
|
|
120872
123342
|
"printf '%s' \"$MY_API_KEY\" | <%= config.bin %> org secrets set --key MY_API_KEY --stdin"
|
|
120873
123343
|
];
|
|
120874
123344
|
static flags = {
|
|
123345
|
+
json: JSON_OUTPUT_FLAG,
|
|
120875
123346
|
"api-key": Flags.string({
|
|
120876
123347
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
120877
123348
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -122224,6 +124695,7 @@ var RoutesAddCommand = class RoutesAddCommand extends Command {
|
|
|
122224
124695
|
required: true
|
|
122225
124696
|
}) };
|
|
122226
124697
|
static flags = {
|
|
124698
|
+
json: JSON_OUTPUT_FLAG,
|
|
122227
124699
|
"api-key": Flags.string({
|
|
122228
124700
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
122229
124701
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -122303,6 +124775,7 @@ var RoutesListCommand = class RoutesListCommand extends Command {
|
|
|
122303
124775
|
static summary = "List recipient routes";
|
|
122304
124776
|
static examples = ["<%= config.bin %> routes list"];
|
|
122305
124777
|
static flags = {
|
|
124778
|
+
json: JSON_OUTPUT_FLAG,
|
|
122306
124779
|
"api-key": Flags.string({
|
|
122307
124780
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
122308
124781
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -122352,6 +124825,7 @@ var RoutesRemoveCommand = class RoutesRemoveCommand extends Command {
|
|
|
122352
124825
|
required: true
|
|
122353
124826
|
}) };
|
|
122354
124827
|
static flags = {
|
|
124828
|
+
json: JSON_OUTPUT_FLAG,
|
|
122355
124829
|
"api-key": Flags.string({
|
|
122356
124830
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
122357
124831
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -122418,6 +124892,7 @@ var RoutesReorderCommand = class RoutesReorderCommand extends Command {
|
|
|
122418
124892
|
static summary = "Reorder recipient routes";
|
|
122419
124893
|
static examples = ["<%= config.bin %> routes reorder --set <route-id>=10", "<%= config.bin %> routes reorder --set <id-a>=10 --set <id-b>=20"];
|
|
122420
124894
|
static flags = {
|
|
124895
|
+
json: JSON_OUTPUT_FLAG,
|
|
122421
124896
|
"api-key": Flags.string({
|
|
122422
124897
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
122423
124898
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -122483,6 +124958,7 @@ var RoutesTestCommand = class RoutesTestCommand extends Command {
|
|
|
122483
124958
|
required: true
|
|
122484
124959
|
}) };
|
|
122485
124960
|
static flags = {
|
|
124961
|
+
json: JSON_OUTPUT_FLAG,
|
|
122486
124962
|
"api-key": Flags.string({
|
|
122487
124963
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
122488
124964
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -122555,6 +125031,7 @@ var RoutesUpdateCommand = class RoutesUpdateCommand extends Command {
|
|
|
122555
125031
|
required: true
|
|
122556
125032
|
}) };
|
|
122557
125033
|
static flags = {
|
|
125034
|
+
json: JSON_OUTPUT_FLAG,
|
|
122558
125035
|
"api-key": Flags.string({
|
|
122559
125036
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
122560
125037
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -124800,6 +127277,7 @@ var WakeAuthorizationsCreateCommand = class WakeAuthorizationsCreateCommand exte
|
|
|
124800
127277
|
static summary = "Create a wake authorization";
|
|
124801
127278
|
static examples = ["<%= config.bin %> wake authorizations create --endpoint <endpoint-id> --domain agents.acme.dev --command process_inbox"];
|
|
124802
127279
|
static flags = {
|
|
127280
|
+
json: JSON_OUTPUT_FLAG,
|
|
124803
127281
|
"api-key": Flags.string({
|
|
124804
127282
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
124805
127283
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -124870,6 +127348,7 @@ var WakeAuthorizationsDeleteCommand = class WakeAuthorizationsDeleteCommand exte
|
|
|
124870
127348
|
required: true
|
|
124871
127349
|
}) };
|
|
124872
127350
|
static flags = {
|
|
127351
|
+
json: JSON_OUTPUT_FLAG,
|
|
124873
127352
|
"api-key": Flags.string({
|
|
124874
127353
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
124875
127354
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -124916,6 +127395,7 @@ var WakeAuthorizationsListCommand = class WakeAuthorizationsListCommand extends
|
|
|
124916
127395
|
static summary = "List wake authorizations";
|
|
124917
127396
|
static examples = ["<%= config.bin %> wake authorizations list", "<%= config.bin %> wake authorizations list --endpoint <endpoint-id>"];
|
|
124918
127397
|
static flags = {
|
|
127398
|
+
json: JSON_OUTPUT_FLAG,
|
|
124919
127399
|
"api-key": Flags.string({
|
|
124920
127400
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
124921
127401
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -124967,6 +127447,7 @@ var WakeAuthorizationsUpdateCommand = class WakeAuthorizationsUpdateCommand exte
|
|
|
124967
127447
|
required: true
|
|
124968
127448
|
}) };
|
|
124969
127449
|
static flags = {
|
|
127450
|
+
json: JSON_OUTPUT_FLAG,
|
|
124970
127451
|
"api-key": Flags.string({
|
|
124971
127452
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
124972
127453
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -125019,6 +127500,7 @@ var WakeDispatchesListCommand = class WakeDispatchesListCommand extends Command
|
|
|
125019
127500
|
static summary = "List recent wake dispatches";
|
|
125020
127501
|
static examples = ["<%= config.bin %> wake dispatches list", "<%= config.bin %> wake dispatches list --limit 20"];
|
|
125021
127502
|
static flags = {
|
|
127503
|
+
json: JSON_OUTPUT_FLAG,
|
|
125022
127504
|
"api-key": Flags.string({
|
|
125023
127505
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
125024
127506
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -125066,6 +127548,7 @@ var WakeSchedulesCreateCommand = class WakeSchedulesCreateCommand extends Comman
|
|
|
125066
127548
|
static summary = "Create a wake schedule";
|
|
125067
127549
|
static examples = ["<%= config.bin %> wake schedules create --from scheduler@acme.dev --to alice@acme.dev --command process_inbox --cron \"0 9 * * *\" --timezone America/New_York"];
|
|
125068
127550
|
static flags = {
|
|
127551
|
+
json: JSON_OUTPUT_FLAG,
|
|
125069
127552
|
"api-key": Flags.string({
|
|
125070
127553
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
125071
127554
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -125151,6 +127634,7 @@ var WakeSchedulesDeleteCommand = class WakeSchedulesDeleteCommand extends Comman
|
|
|
125151
127634
|
required: true
|
|
125152
127635
|
}) };
|
|
125153
127636
|
static flags = {
|
|
127637
|
+
json: JSON_OUTPUT_FLAG,
|
|
125154
127638
|
"api-key": Flags.string({
|
|
125155
127639
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
125156
127640
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -125201,6 +127685,7 @@ var WakeSchedulesGetCommand = class WakeSchedulesGetCommand extends Command {
|
|
|
125201
127685
|
required: true
|
|
125202
127686
|
}) };
|
|
125203
127687
|
static flags = {
|
|
127688
|
+
json: JSON_OUTPUT_FLAG,
|
|
125204
127689
|
"api-key": Flags.string({
|
|
125205
127690
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
125206
127691
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -125247,6 +127732,7 @@ var WakeSchedulesListCommand = class WakeSchedulesListCommand extends Command {
|
|
|
125247
127732
|
static summary = "List wake schedules";
|
|
125248
127733
|
static examples = ["<%= config.bin %> wake schedules list"];
|
|
125249
127734
|
static flags = {
|
|
127735
|
+
json: JSON_OUTPUT_FLAG,
|
|
125250
127736
|
"api-key": Flags.string({
|
|
125251
127737
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
125252
127738
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -125296,6 +127782,7 @@ var WakeSchedulesRunCommand = class WakeSchedulesRunCommand extends Command {
|
|
|
125296
127782
|
required: true
|
|
125297
127783
|
}) };
|
|
125298
127784
|
static flags = {
|
|
127785
|
+
json: JSON_OUTPUT_FLAG,
|
|
125299
127786
|
"api-key": Flags.string({
|
|
125300
127787
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
125301
127788
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -125346,6 +127833,7 @@ var WakeSchedulesUpdateCommand = class WakeSchedulesUpdateCommand extends Comman
|
|
|
125346
127833
|
required: true
|
|
125347
127834
|
}) };
|
|
125348
127835
|
static flags = {
|
|
127836
|
+
json: JSON_OUTPUT_FLAG,
|
|
125349
127837
|
"api-key": Flags.string({
|
|
125350
127838
|
description: "Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)",
|
|
125351
127839
|
env: "PRIMITIVE_API_KEY"
|
|
@@ -125708,7 +128196,7 @@ function renderFishCompletion(binName) {
|
|
|
125708
128196
|
const topicOperations = cliOperationManifest.filter((operation) => operation.tagCommand === topic);
|
|
125709
128197
|
for (const operation of topicOperations) {
|
|
125710
128198
|
lines.push(`complete -c ${binName} -f -n '__fish_${binName}_topic_needs_subcommand ${fishEscape(topic)}' -a '${fishEscape(operation.command)}' -d '${fishEscape(operation.summary ?? `${operation.method} ${operation.path}`)}'`);
|
|
125711
|
-
for (const parameter of [...operation.pathParams, ...operation.queryParams]) lines.push(`complete -c ${binName} -n '${operationCondition(operation).replace(BIN_PLACEHOLDER, binName)}' -l '${fishEscape(parameter.name
|
|
128199
|
+
for (const parameter of [...operation.pathParams, ...operation.queryParams]) lines.push(`complete -c ${binName} -n '${operationCondition(operation).replace(BIN_PLACEHOLDER, binName)}' -l '${fishEscape(parameterFlagName(operation.sdkName, parameter.name))}' -r -d '${fishEscape(OPERATION_PATH_FLAGS[operation.sdkName]?.[parameter.name]?.description ?? parameter.description ?? parameter.name)}'`);
|
|
125712
128200
|
for (const parameter of operation.headerParams) lines.push(`complete -c ${binName} -n '${operationCondition(operation).replace(BIN_PLACEHOLDER, binName)}' -l '${fishEscape(headerFlagName(parameter.name))}' -r -d '${fishEscape(parameter.description ?? parameter.name)}'`);
|
|
125713
128201
|
lines.push(`complete -c ${binName} -n '${operationCondition(operation).replace(BIN_PLACEHOLDER, binName)}' -l 'api-key' -r -d 'Primitive API key override (defaults to PRIMITIVE_API_KEY or saved OAuth login credentials)'`);
|
|
125714
128202
|
if (!operation.binaryResponse) lines.push(`complete -c ${binName} -n '${operationCondition(operation).replace(BIN_PLACEHOLDER, binName)}' -l 'envelope' -d 'Print the full response envelope, including pagination metadata'`);
|
|
@@ -125759,6 +128247,7 @@ function readCompletionFunction(cacheDir, bin, shell) {
|
|
|
125759
128247
|
var ListOperationsCommand = class extends Command {
|
|
125760
128248
|
static description = "List all generated API operations as JSON. Useful for piping to `jq` to discover available commands, their request/response schemas, and per-field descriptions. For inspecting a single operation in detail, prefer `primitive describe <command-or-operation-name>`.";
|
|
125761
128249
|
static summary = "List all generated API operations (JSON)";
|
|
128250
|
+
static flags = { json: JSON_OUTPUT_FLAG };
|
|
125762
128251
|
async run() {
|
|
125763
128252
|
this.log(JSON.stringify(cliOperationManifest, null, 2));
|
|
125764
128253
|
}
|
|
@@ -125854,6 +128343,7 @@ var DescribeCommand = class DescribeCommand extends Command {
|
|
|
125854
128343
|
"<%= config.bin %> describe emails:get",
|
|
125855
128344
|
"<%= config.bin %> describe sent:get"
|
|
125856
128345
|
];
|
|
128346
|
+
static flags = { json: JSON_OUTPUT_FLAG };
|
|
125857
128347
|
async run() {
|
|
125858
128348
|
const { args } = await this.parse(DescribeCommand);
|
|
125859
128349
|
const { match, candidates } = lookupOperation(args.command);
|
|
@@ -126092,6 +128582,11 @@ const COMMANDS = {
|
|
|
126092
128582
|
"org:use": OrgUseCommand,
|
|
126093
128583
|
"cli:list-cli-orgs": OrgsCommand,
|
|
126094
128584
|
"keys:list": KeysListCommand,
|
|
128585
|
+
"keys:get": KeysGetCommand,
|
|
128586
|
+
"keys:create": KeysCreateCommand,
|
|
128587
|
+
"keys:rotate": KeysRotateCommand,
|
|
128588
|
+
"keys:update": KeysUpdateCommand,
|
|
128589
|
+
"keys:revoke": KeysRevokeCommand,
|
|
126095
128590
|
"roles:list": RolesListCommand,
|
|
126096
128591
|
"roles:groups": RolesGroupsCommand,
|
|
126097
128592
|
"roles:mailbox-access": RolesMailboxAccessCommand,
|