primcli 3.0.0-preview.13 → 3.0.0-preview.15
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/dist/{api-command-D5Tj9C-K.js → api-command-D5Nbd6Pq.js} +1339 -85
- package/dist/{machine-session-BMr-zPLx.js → machine-session-DyGP7wDs.js} +4 -4
- package/dist/{notify-session-cIUz_kxR.js → notify-session-B64Lgv6Z.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 +1604 -154
- package/dist/oclif/receiver-heal.js +2 -2
- package/dist/{repeats-Dj_o6c-X-ykfsraq6.js → repeats-Dj_o6c-X-C1y88ZwJ.js} +84 -12
- package/dist/{scoped-chat-DVSsLSRw.js → scoped-chat-CocomDwR.js} +1 -1
- package/dist/{signal-command-gpH2AhIi.js → signal-command-lJM0763f.js} +4 -4
- package/package.json +1 -1
package/dist/oclif/index.js
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { $ as
|
|
2
|
-
import { $
|
|
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 interactionNextActions, $t as ConnectedAgentKeyRequiredError, A as openBrowser, B as serverRelationship, Bt as runtimeSessionVariableList, C as approveThenRerunHint, Ct as sendIdentityFields, D as canOfferCopyHotkey, Dt as serializeErrorPayload, E as withApproval, Et as sentHistoryWindowStart, F as formatMailWakeLine, Ft as identitySuggestions, G as claimPendingMail, Gt as readCallerMailFor, H as wakeReadCommand, Ht as withFlagSuggestion, I as latestOwnOutbound, It as loadSkillLine, J as pendingMailPath, Jt as isEmailId, K as clearConsumedPendingMail, Kt as classificationFactLines, L as readThreadContext, Lt as currentMailSessionKey, M as bareAddress, Mt as connectNextSteps, N as describeWake, O as formatBrowserLoginInstructions, Ot as successfulSendOutcome, P as displayAddress, Pt as generatedAgentName, Q as interactionHumanLine, Qt as withAttachmentWait, R as sentInThread, Rt as detectAgentRuntime, S as STEP_UP_TOKEN_FLAG_DESCRIPTION, St as reportSendCommandResult, T as terminalApprovalIo, Tt as sendWaitClampNotice, U as wakeRecipientField, Ut as emptyEmailListHint, Vt as formatAlreadySentNotice, W as wakeRelationship, Wt as mailReach, X as recordPendingMail, Xt as ATTACHMENT_WAIT_FLAG_DESCRIPTION, Y as readPendingMail, Yt as noFactsMessage, Z as removePendingMail, Zt as ATTACHMENT_WAIT_MAX_MS, _ as surfaceUnauthorizedHint, _n as sanitizeForTerminal, _t as formatPriorRepliesCheckSkipped, a as createOperationCommand, an as resolveCliApiRequestConfig, at as MAX_SEND_WAIT_TIMEOUT_MS, b as BROWSER_FLAG_DESCRIPTION, bt as formatSendRecordFailureSummary, c as formatErrorPayload, cn as RESTRICTED_ROLE_NOTE, ct as assertValidIdempotencyKey, d as isGrantRefusal, dn as isBuiltInRoleKey, dt as checkPriorReplies, et as readEmailInteraction, f as networkErrorHint, fn as revokeUserLogin, ft as classifySendError, g as runWithTiming, gn as routeWarningLines, gt as formatDeletedEarlierSendNotice, h as refusalDetails, hn as switchCurrentOrg, ht as followUpCommandPrefix, i as TIME_FLAG_DESCRIPTION, in as refuseOrgSelectionForProfile, it as IDEMPOTENCY_KEY_FLAG_DESCRIPTION, j as explainPendingMailNotFound, jt as cliInvocation, k as listenForCopyHotkey, kt as thrownErrorExitCode, l as hasControlCharacter$1, ln as credentialsFromUserLogin, lt as buildFollowUpCommand, m as readTextFileFlag, mn as roleKeyText, mt as excludeSignalReplies, n as API_ERROR_CODES, nn as createCliApiClient, nt as replyInteractionWarning, o as extractErrorCode, on as selectedOrgFromEnv, ot as SEND_OUTCOME_HELP, p as parameterFlagName, pn as roleKeyLabel, pt as deriveSendIdempotencyKey, q as clearReadPendingMail, qt as classificationOf, r as OPERATION_PATH_FLAGS, rn as refreshStoredCliCredentials, s as extractErrorPayload, sn as CliOrgRefusedError, st as apiResultHttpStatus, t as API_BASE_URL_FLAG_DESCRIPTION, tn as createAuthenticatedCliApiClient, tt as replyExpectation, u as headerFlagName, un as fetchCliOrgs, ut as buildThrownSendFailureEnvelope, v as takesStepUp, vn as setKnownCommands, vt as formatPriorRepliesWarning, w as promptLine$2, wt as sendOutcomeExitCode, x as STEP_UP_HEADER$1, xt as priorRepliesThatWentOut, y as writeErrorWithHints, yn as operationManifest, yt as formatSendFailureSummary, z as serverMuted, zt as detectRuntimeSession } from "../api-command-D5Nbd6Pq.js";
|
|
2
|
+
import { $n as setMemory, $t as getOwnGrant, A as filtersFromFlags, An as listWakeAuthorizations, At as deleteWakeAuthorization, B as awaitingRejectedError, Bn as reorderRoutes, C as transientFailure, Cn as listMailboxAccess, Ct as createRoute, D as cursorFromAcceptedRows, Dn as listRoutes, E as collectNewAcceptedEmails, En as listRoles, F as AWAITING_FLAG_DESCRIPTION, Ft as downloadSentAttachmentArchiveMember, G as isAwaitingRejectedError, Gn as runWakeSchedule, Gt as getFunction, H as formatAwaitingCell, Hn as resendAgentSignupVerification, Ht as getCreditBalance, I as AWAITING_VALUES, It as downloadSentAttachmentByFilename, Jn as searchMemories, Jt as getInboxStatus, K as queryUsesAwaiting, Kt as getFunctionRouting, L as REPLY_STATE_UNSUPPORTED_CODE, Lt as getAccessMode, M as quoteDslValue, Mn as listWakeSchedules, Mt as downloadEmailAttachmentArchiveMember, N as sinceFromFlags, Nn as pollCliLogin, Nt as downloadEmailAttachmentByFilename, O as encodeReceivedAtSearchCursor, On as listSentAttachmentArchiveMembers, Ot as deleteMemory, P as sleep$3, Pn as pullWebhookEvent, Q as isEmailReceivedEvent, Qn as setFunctionSecret, Qt as getOutboundStatus, R as ReplyStateUnsupportedError, Rn as redeemCreditCode, Rt as getAccount, S as retryingOperation, Sn as listKeys, St as createKey, T as SINCE_VALUE_HELP, Tn as listRepeatingSends, Tt as createWakeSchedule, U as formatRepliesCell, Un as revokeCredential, Ut as getDefaultNetworkAgent, V as ensureSearchReportsReplyState, Vn as replyToEmail, Vt as getConversation, W as hasReplyState, Wn as rotateKey, Wt as getEmail, Xn as sendEmail, Xt as getMemory, Yn as semanticSearch, Yt as getKey, Zn as setFunctionRoute, Zt as getOrgRoutingTopology, _ as backoffDelay, _n as listEmails, _t as checkSendability, a as REPEAT_IDLE_MAX_MINUTES, ar as testFunction, at as AutomatedFilterUnsupportedError, b as pauseForTransientFailure, bn as listFunctions, bt as createEndpoint, cr as updateFunction, d as parseRepeatTick, dr as updateRoute, dt as hasAutomatedVerdict, en as getRepeatingSend, er as simulateRoute, et as parseWebhookEvent, f as preparePresenceAliveEmail, fn as listDefaultNetworkAgents, fr as updateWakeAuthorization, ft as isAutomatedRejectedError, g as WaitDeadlineReached, gn as listEmailRuleResults, gr as whoami, gt as checkDefaultNetworkContactAdmission, hn as listEmailAttachmentArchiveMembers, hr as verifyAgentSignup, ht as cancelSentEmailByIdempotencyKey, i as REPEAT_EVERY_MAX_MINUTES, in as getWakeSchedule, ir as stopRepeatFromEmail, it as AUTOMATED_VALUES, j as lateMailReread, jn as listWakeDispatches, jt as deleteWakeSchedule, k as fetchEmailSearchPage, kn as listSentEmails, kt as deleteRoute, l as parseInteractionEnvelope, ln as listAgentContacts, lr as updateKey, m as repeatStopCommand, mn as listDomains, mr as verifyAgentClaim, mt as cancelSentEmail, nn as getSentEmail, nr as startAgentSignup, nt as AUTOMATED_FILTER_UNSUPPORTED_CODE, o as REPEAT_MAX_SENDS_MAX, on as leaveOrganization, or as unsetFunctionRoute, ot as assertAutomatedVerdict, p as prepareSignalEmail, pn as listDefaultNetworkMembers, pr as updateWakeSchedule, pt as addDefaultNetworkMember, qn as searchEmails, qt as getFunctionTestRunTrace, rn as getThread, rr as startCliLogin, rt as AUTOMATED_FLAG_DESCRIPTION, s as buildRepeatStopBody, sn as listActivityObjects, sr as updateDefaultNetworkMember, st as automatedRejectedError, tn as getSendFrom, tr as startAgentClaim, tt as parseFromHeader, u as parsePresenceEnvelope, un as listAgentNetworks, ur as updateRepeatingSend, v as describeApiFailure, vn as listEndpoints, vt as cliLogout, w as waitOutRetryAfter, wn as listOrganizationPeople, wt as createWakeAuthorization, x as retryTransient, xn as listGroups, xt as createFunction, yn as listFunctionLogs, yt as completeWebhookEvent, z as assertAwaitingFilterRows, zn as removeDefaultNetworkMember, zt as getAgentContactPolicy } from "../repeats-Dj_o6c-X-C1y88ZwJ.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-B64Lgv6Z.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-DyGP7wDs.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-CocomDwR.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-
|
|
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-lJM0763f.js";
|
|
10
10
|
import { a as thrownErrorBody, i as runStreamingJson, n as guardJsonOutputCommands, r as jsonOutputRequested, t as JSON_OUTPUT_FLAG } from "../json-output-ch756TXV.js";
|
|
11
11
|
import { a as backgroundListenStatus, c as runBackgroundListen, d as stopBackgroundListen, f as verifyBackgroundListenTarget, o as backgroundListenToken, r as backgroundListenConfiguration, u as startBackgroundListen } from "../listen-background-DyBYca28.js";
|
|
12
12
|
import { ORG_SELECTION_ENV } from "./global-org-flag.js";
|
|
@@ -184,6 +184,11 @@ const openapiDocument = {
|
|
|
184
184
|
"description": "Organization administration for people: your own connected apps and CLI logins, the organization's connected apps, its name and logo, and semantic search consent. API keys, agent connection keys and agents are refused. Billing and deleting the organization are done in the dashboard only.",
|
|
185
185
|
"x-openapi-spec": "https://api.primitive.dev/v1/openapi/tags/organization-settings"
|
|
186
186
|
},
|
|
187
|
+
{
|
|
188
|
+
"name": "Email notifications",
|
|
189
|
+
"description": "The notification emails Primitive sends an organization's members: the organization chooses, per kind, whether it is off, left to each member or required, and each member chooses where it is left to them. Some kinds are always sent. API keys, agent connection keys and agents are refused.",
|
|
190
|
+
"x-openapi-spec": "https://api.primitive.dev/v1/openapi/tags/email-notifications"
|
|
191
|
+
},
|
|
187
192
|
{
|
|
188
193
|
"name": "Roles and members",
|
|
189
194
|
"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; contact Primitive to turn it on.",
|
|
@@ -221,7 +226,7 @@ const openapiDocument = {
|
|
|
221
226
|
},
|
|
222
227
|
{
|
|
223
228
|
"name": "Email Rule Oversight",
|
|
224
|
-
"description": "The email rules that reach your own mailboxes, whoever wrote them, read-only, and your objections to them: asking a rule's author to turn it off. The organization needs the email rules feature, and the caller must be a member with mail:read on their own dashboard session or the Primitive CLI, not narrowed.",
|
|
229
|
+
"description": "The email rules that reach your own mailboxes, whoever wrote them, read-only, and your objections to them: asking a rule's author to turn it off, narrow it or explain it. The organization needs the email rules feature, and the caller must be a member with mail:read on their own dashboard session or the Primitive CLI, not narrowed.",
|
|
225
230
|
"x-openapi-spec": "https://api.primitive.dev/v1/openapi/tags/email-rule-oversight"
|
|
226
231
|
},
|
|
227
232
|
{
|
|
@@ -21774,7 +21779,7 @@ const openapiDocument = {
|
|
|
21774
21779
|
"/activity/objects": { "get": {
|
|
21775
21780
|
"operationId": "listActivityObjects",
|
|
21776
21781
|
"summary": "List what you created, or what you were asked",
|
|
21777
|
-
"description": "The objects the caller created, newest first, each with where it stands now, including ones since disabled, deleted or revoked where the object keeps a row: Functions, endpoints, Function triggers, pull subscriptions, recipient routes, filters, wake schedules, repeating sends and scheduled sends. An API key, an app or an agent sees what it created itself; a webhook given to an API key lists under that key. A person (a dashboard session, or their own Primitive CLI or app login) sees what they created through any credential of theirs, each item naming it, and also their API keys, personal agents, email rules, rule requests and objections to rules over their mail (objections only on the dashboard or the Primitive CLI). Each kind is listed only if the caller could list it through that kind's own route; a kind it could not is named in withheld, with no count. Ids, names and states only: never a webhook URL or mail content. Needs activity:read_self. With relation=asked it lists instead what other members asked of the person, open or answered: the rule requests made to them, and the objections to rules they wrote, under their current membership, each naming the member who asked or objected in created_through. A key, an app or an agent has none, and gets both kinds in withheld. With relation=concerning it lists instead what other members did that concerns the person's own mail: each time a rule started covering one of their mailboxes
|
|
21782
|
+
"description": "The objects the caller created, newest first, each with where it stands now, including ones since disabled, deleted or revoked where the object keeps a row: Functions, endpoints, Function triggers, pull subscriptions, recipient routes, filters, wake schedules, repeating sends and scheduled sends. An API key, an app or an agent sees what it created itself; a webhook given to an API key lists under that key. A person (a dashboard session, or their own Primitive CLI or app login) sees what they created through any credential of theirs, each item naming it, and also their API keys, personal agents, email rules, rule requests and objections to rules over their mail (objections only on the dashboard or the Primitive CLI). Each kind is listed only if the caller could list it through that kind's own route; a kind it could not is named in withheld, with no count. Ids, names and states only: never a webhook URL or mail content. Needs activity:read_self. With relation=asked it lists instead what other members asked of the person, open or answered: the rule requests made to them, and the objections to rules they wrote, under their current membership, each naming the member who asked or objected in created_through. A key, an app or an agent has none, and gets both kinds in withheld. With relation=concerning it lists instead what other members did that concerns the person's own mail: each time a rule started covering one of their mailboxes, saved a new version, or changed who receives its matches while covering it, named as the rule was then, naming its author in created_through, under their current membership; only on the dashboard or the Primitive CLI. A key, an app or an agent has none, and gets email_rule_coverage in withheld. A notice never reads as ended. Notices are written by a periodic job and can lag: until the notices record a rule starting to cover you, the first page lists that rule as pending (pending_complete says whether that check finished), and as_of says about when the notices last looked. For what covers you now, read GET /email-rules/covering-me.",
|
|
21778
21783
|
"tags": ["Activity"],
|
|
21779
21784
|
"security": [{ "BearerAuth": [] }],
|
|
21780
21785
|
"parameters": [
|
|
@@ -21785,7 +21790,7 @@ const openapiDocument = {
|
|
|
21785
21790
|
"description": "created (the default), asked or concerning.",
|
|
21786
21791
|
"schema": {
|
|
21787
21792
|
"default": "created",
|
|
21788
|
-
"description": "created (the default): what you created. asked: what other members asked of you, open or answered: rule requests made to you, and objections to rules you wrote; kind may then name only email_rule_request and email_rule_objection. concerning: what other members did that concerns your own mail: an active rule that started covering one of your mailboxes,
|
|
21793
|
+
"description": "created (the default): what you created. asked: what other members asked of you, open or answered: rule requests made to you, and objections to rules you wrote; kind may then name only email_rule_request and email_rule_objection. concerning: what other members did that concerns your own mail: an active rule that started covering one of your mailboxes, saved a new version, or changed who receives its matches while covering it (email_rule_coverage, the only kind it takes). A rule in draft or observe is not told of; GET /v1/email-rules/covering-me lists it. asked and concerning are for a person's own view only.",
|
|
21789
21794
|
"type": "string",
|
|
21790
21795
|
"enum": [
|
|
21791
21796
|
"created",
|
|
@@ -22112,7 +22117,7 @@ const openapiDocument = {
|
|
|
22112
22117
|
"/email-rules/test": { "post": {
|
|
22113
22118
|
"operationId": "testEmailRule",
|
|
22114
22119
|
"summary": "Test a rule against received mail",
|
|
22115
|
-
"description": "Runs a rule over received mail and reports what it would decide for each email (matched, near_miss, no_match, unclassified, skipped or not_found), with a summary of how each top-level condition and question decided. Test an unsaved tree,
|
|
22120
|
+
"description": "Runs a rule over received mail and reports what it would decide for each email (matched, near_miss, no_match, unclassified, skipped or not_found), with a summary of how each top-level condition and question decided. Test an unsaved tree, a saved rule by rule_id (its current version, as its author), or a pending rule request by request_id (its rule as asked, as you, over your own mailboxes). It reads only mail its author can read and its scope covers. A rule you see only because it covers your own mailboxes runs as you, over only those, from the dashboard or the Primitive CLI. Without email_ids it tests the newest emails, at most 200 and none older than 30 days, plus any expected ones. Unclassified emails over 2 hours old are classified first unless classify_missing is false. It records no decision and grants nothing, and stops at about 90 seconds. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token).",
|
|
22116
22121
|
"tags": ["Email Rules"],
|
|
22117
22122
|
"security": [{ "BearerAuth": [] }],
|
|
22118
22123
|
"requestBody": {
|
|
@@ -22135,7 +22140,7 @@ const openapiDocument = {
|
|
|
22135
22140
|
}
|
|
22136
22141
|
},
|
|
22137
22142
|
"400": {
|
|
22138
|
-
"description": "validation_error: give exactly one of tree and
|
|
22143
|
+
"description": "validation_error: give exactly one of tree, rule_id and request_id, at most 200 email_ids (with the expected emails), 1 to 100 expected emails none in both lists (or only expect.samples, up to 20), and a tree that is valid for the column contract. evaluation_scope, scope_selection and kind go only with tree. A saved rule's current version or a request's rule that no longer renders answers details.reason version_not_renderable; email_ids that with its saved expectations name over 200 emails, too_many_emails.",
|
|
22139
22144
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22140
22145
|
},
|
|
22141
22146
|
"401": {
|
|
@@ -22162,11 +22167,11 @@ const openapiDocument = {
|
|
|
22162
22167
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22163
22168
|
},
|
|
22164
22169
|
"404": {
|
|
22165
|
-
"description": "not_found: rule_id names no rule you can see or that covers your mailboxes (details.reason rule_not_found).",
|
|
22170
|
+
"description": "not_found: rule_id names no rule you can see or that covers your mailboxes (details.reason rule_not_found), or request_id no rule request you can see (request_not_found).",
|
|
22166
22171
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22167
22172
|
},
|
|
22168
22173
|
"409": {
|
|
22169
|
-
"description": "email_rule_author_unresolvable: the rule cannot run as its author (for an unsaved tree or a rule covering you, the caller). details.reason is left, revoked, suspended, membership_ended, no_mail_read, no_own_mailbox, no_shareable_mailbox or no_selected_mailbox.",
|
|
22174
|
+
"description": "email_rule_author_unresolvable: the rule cannot run as its author (for an unsaved tree, a request or a rule covering you, the caller). details.reason is left, revoked, suspended, membership_ended, no_mail_read, no_own_mailbox, no_shareable_mailbox or no_selected_mailbox. email_rule_request_not_pending: request_id names a request already decided.",
|
|
22170
22175
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22171
22176
|
},
|
|
22172
22177
|
"429": {
|
|
@@ -22314,7 +22319,7 @@ const openapiDocument = {
|
|
|
22314
22319
|
"/email-rules/test-sample": { "post": {
|
|
22315
22320
|
"operationId": "testEmailRuleOnSample",
|
|
22316
22321
|
"summary": "Test a rule against a made-up email",
|
|
22317
|
-
"description": "Reports what a rule would decide for an email you describe (sender, recipients, subject, plain text, attachment types and file names; optionally automated, from a mailing list, and a spam score), classified and decided as received mail would be. A rule reading a spam score you gave none for decides on none (unset_columns). Nothing is stored. Test an unsaved tree or a
|
|
22322
|
+
"description": "Reports what a rule would decide for an email you describe (sender, recipients, subject, plain text, attachment types and file names; optionally automated, from a mailing list, and a spam score), classified and decided as received mail would be. A rule reading a spam score you gave none for decides on none (unset_columns). Nothing is stored. Test an unsaved tree, a saved rule by rule_id, or a pending rule request by request_id (its rule as asked, as you). The answer includes what the classifier read. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token).",
|
|
22318
22323
|
"tags": ["Email Rules"],
|
|
22319
22324
|
"security": [{ "BearerAuth": [] }],
|
|
22320
22325
|
"requestBody": {
|
|
@@ -22337,7 +22342,7 @@ const openapiDocument = {
|
|
|
22337
22342
|
}
|
|
22338
22343
|
},
|
|
22339
22344
|
"400": {
|
|
22340
|
-
"description": "validation_error: give exactly one of tree and
|
|
22345
|
+
"description": "validation_error: give exactly one of tree, rule_id and request_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's current version or a request's rule that no longer renders answers details.reason version_not_renderable. With with_protection: not_a_grant_rule, or protection_mailbox_outside_rule when the rule does not run over the first recipient.",
|
|
22341
22346
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22342
22347
|
},
|
|
22343
22348
|
"401": {
|
|
@@ -22360,15 +22365,15 @@ const openapiDocument = {
|
|
|
22360
22365
|
}
|
|
22361
22366
|
},
|
|
22362
22367
|
"403": {
|
|
22363
|
-
"description": "feature_not_enabled: this organization lacks the email rules feature; permission refusals answer forbidden or grant_forbidden. email_rule_scope_not_readable: scope_selection names something you cannot read. forbidden with details.reason covering_view_only: you read this rule only in the covering view, since it decided on your mail before and covers none of your mailboxes now (details.covering_view).",
|
|
22368
|
+
"description": "feature_not_enabled: this organization lacks the email rules feature; permission refusals answer forbidden or grant_forbidden. email_rule_scope_not_readable: scope_selection names something you cannot read. forbidden with details.reason covering_view_only: you read this rule only in the covering view, since it decided on your mail before and covers none of your mailboxes now (details.covering_view). grant_forbidden protection_mailbox_not_read: with_protection at a mailbox you do not read in full.",
|
|
22364
22369
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22365
22370
|
},
|
|
22366
22371
|
"404": {
|
|
22367
|
-
"description": "not_found: rule_id names no rule you can see or that covers your mailboxes (details.reason rule_not_found).",
|
|
22372
|
+
"description": "not_found: rule_id names no rule you can see or that covers your mailboxes (details.reason rule_not_found), or request_id no rule request you can see (request_not_found).",
|
|
22368
22373
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22369
22374
|
},
|
|
22370
22375
|
"409": {
|
|
22371
|
-
"description": "email_rule_author_unresolvable: the rule cannot run as its author (for an unsaved tree or a rule covering you, 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.",
|
|
22376
|
+
"description": "email_rule_author_unresolvable: the rule cannot run as its author (for an unsaved tree, a request or a rule covering you, 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. email_rule_request_not_pending: request_id names a request already decided.",
|
|
22372
22377
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22373
22378
|
},
|
|
22374
22379
|
"429": {
|
|
@@ -22393,6 +22398,10 @@ const openapiDocument = {
|
|
|
22393
22398
|
}
|
|
22394
22399
|
}
|
|
22395
22400
|
} }
|
|
22401
|
+
},
|
|
22402
|
+
"503": {
|
|
22403
|
+
"description": "service_unavailable: with_protection could not read the do-not-share rules in time (protection_unavailable), or its limit could not be checked (protection_limit_unavailable).",
|
|
22404
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
22396
22405
|
}
|
|
22397
22406
|
},
|
|
22398
22407
|
"x-primitive-permission": ["mail:read"],
|
|
@@ -23497,7 +23506,7 @@ const openapiDocument = {
|
|
|
23497
23506
|
"post": {
|
|
23498
23507
|
"operationId": "createEmailRuleRequest",
|
|
23499
23508
|
"summary": "Ask a member for a rule",
|
|
23500
|
-
"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, or by their verified work email if you can list members (at most 30 lookups by address an hour). Nothing is evaluated or shared until they accept, and they may change the rule first. A message (up to 500 characters, fixed once sent) tells them why you ask. At most 5 pending requests to one member and 50 in all. With members:read the answer says whether they can accept it under their role (target_can_accept, target_warning); POST /v1/email-rule-requests/target-check checks first. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token).",
|
|
23509
|
+
"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, or by their verified work email if you can list members (at most 30 lookups by address an hour). Nothing is evaluated or shared until they accept, and they may change the rule first. A message (up to 500 characters, fixed once sent) tells them why you ask. With an Idempotency-Key, asking again for exactly what a pending request of yours to the same member asks (name, english, tree, explanation and message, naming them the same way) returns that request with existing: true (200), so a retry never asks them twice. At most 5 pending requests to one member and 50 in all. With members:read the answer says whether they can accept it under their role (target_can_accept, target_warning); POST /v1/email-rule-requests/target-check checks first. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token).",
|
|
23501
23510
|
"tags": ["Email Rules"],
|
|
23502
23511
|
"security": [{ "BearerAuth": [] }],
|
|
23503
23512
|
"requestBody": {
|
|
@@ -23505,6 +23514,20 @@ const openapiDocument = {
|
|
|
23505
23514
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateEmailRuleRequestRequest" } } }
|
|
23506
23515
|
},
|
|
23507
23516
|
"responses": {
|
|
23517
|
+
"200": {
|
|
23518
|
+
"description": "The pending request this create matched (existing: true): no second one was made.",
|
|
23519
|
+
"content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
|
|
23520
|
+
"type": "object",
|
|
23521
|
+
"required": ["data"],
|
|
23522
|
+
"properties": { "data": { "$ref": "#/components/schemas/CreateEmailRuleRequestResult" } }
|
|
23523
|
+
}] } } },
|
|
23524
|
+
"headers": {
|
|
23525
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit" },
|
|
23526
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining" },
|
|
23527
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
23528
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy" }
|
|
23529
|
+
}
|
|
23530
|
+
},
|
|
23508
23531
|
"201": {
|
|
23509
23532
|
"description": "Ask a member for a rule",
|
|
23510
23533
|
"content": { "application/json": { "schema": { "allOf": [{ "$ref": "#/components/schemas/SuccessEnvelope" }, {
|
|
@@ -23576,18 +23599,18 @@ const openapiDocument = {
|
|
|
23576
23599
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
23577
23600
|
}
|
|
23578
23601
|
},
|
|
23579
|
-
"x-primitive-permission": ["mail:read"],
|
|
23580
23602
|
"parameters": [{
|
|
23581
23603
|
"name": "Idempotency-Key",
|
|
23582
23604
|
"in": "header",
|
|
23583
23605
|
"required": false,
|
|
23584
|
-
"description": "Optional,
|
|
23606
|
+
"description": "Optional. With a key, a create identical to a pending request of yours to the same member (name, english, tree, explanation and message, naming the member the same way) returns that request with existing: true (200) instead of making a second one. The key itself is not stored, so any key does this, and a create without one is never matched to an existing request. A key that is empty, longer than 255 characters or not printable ASCII is refused with 400 `validation_error`; a valid one is echoed in the Idempotency-Key response header.",
|
|
23585
23607
|
"schema": {
|
|
23586
23608
|
"type": "string",
|
|
23587
23609
|
"minLength": 1,
|
|
23588
23610
|
"maxLength": 255
|
|
23589
23611
|
}
|
|
23590
|
-
}]
|
|
23612
|
+
}],
|
|
23613
|
+
"x-primitive-permission": ["mail:read"]
|
|
23591
23614
|
},
|
|
23592
23615
|
"get": {
|
|
23593
23616
|
"operationId": "listEmailRuleRequests",
|
|
@@ -24858,7 +24881,7 @@ const openapiDocument = {
|
|
|
24858
24881
|
"/email-rules/covering-me": { "get": {
|
|
24859
24882
|
"operationId": "listEmailRulesCoveringMe",
|
|
24860
24883
|
"summary": "List the rules over your mail",
|
|
24861
|
-
"description": "Every email rule that covers one of your own mailboxes now, yours included, newest first, in any state. A rule covers you when the scope it runs with now reaches one of your own mailboxes (your member mailbox, or a personal agent's address): one whose author reads all your mail (author scope, for an author who reads the organization's mail or holds an access entry for your mailbox), or one that names your mailbox or its domain (selected). Another member's own_mailboxes rule never covers you. You see its name, wording, current tree, state, kind and author, and which of your own mailboxes it reaches. Its wording and tree are shown as written, so they can name other addresses (a condition on who an email is from or to). While it covers you, you also see who receives what it matches (receivers): how many API keys, webhooks and shares, the member each belongs to (or the organization), and the sites the webhooks deliver to. You do not see which keys, webhooks or shares they are (no ids, names, prefixes, or URLs beyond the site), the other inboxes and domains its scope names, or its saved expectations. A page can hold fewer rules than limit, or none, and still carry a cursor (one request reads a bounded number of rules): keep reading until meta.cursor is null. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token). Only on your own dashboard session or the Primitive CLI.",
|
|
24884
|
+
"description": "Every email rule that covers one of your own mailboxes now, yours included, newest first, in any state. A rule covers you when the scope it runs with now reaches one of your own mailboxes (your member mailbox, or a personal agent's address): one whose author reads all your mail (author scope, for an author who reads the organization's mail or holds an access entry for your mailbox), or one that names your mailbox or its domain (selected). Another member's own_mailboxes rule never covers you. You see its name, wording, current tree, state, kind and author, and which of your own mailboxes it reaches. Its wording and tree are shown as written, so they can name other addresses (a condition on who an email is from or to). While it covers you, you also see who receives what it matches (receivers): how many API keys, webhooks and shares, the member each belongs to (or the organization), and the sites the webhooks deliver to. You do not see which keys, webhooks or shares they are (no ids, names, prefixes, or URLs beyond the site), the other inboxes and domains its scope names, or its saved expectations. A page can hold fewer rules than limit, or none, and still carry a cursor (one request reads a bounded number of rules): keep reading until meta.cursor is null. For what happened to one email of yours, every rule's decision on it and, for another member's rule covering you, who receives what it shares: GET /v1/emails/{id}/rule-results (primitive email-rules list-email-rule-results --email-id <email-id>). Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token). Only on your own dashboard session or the Primitive CLI.",
|
|
24862
24885
|
"tags": ["Email Rule Oversight"],
|
|
24863
24886
|
"security": [{ "BearerAuth": [] }],
|
|
24864
24887
|
"parameters": [{
|
|
@@ -24956,7 +24979,7 @@ const openapiDocument = {
|
|
|
24956
24979
|
"/email-rules/covering-me/{id}": { "get": {
|
|
24957
24980
|
"operationId": "getEmailRuleCoveringMe",
|
|
24958
24981
|
"summary": "Get a rule over your mail",
|
|
24959
|
-
"description": "One rule that covers one of your own mailboxes, read-only, with its current version; or one that no longer does but decided on mail at your own mailbox (covers_now false), shown as the version that last decided on your mail, without its current name. You see its name, wording, current tree, state, kind and author, and which of your own mailboxes it reaches. Its wording and tree are shown as written, so they can name other addresses (a condition on who an email is from or to). While it covers you, you also see who receives what it matches (receivers): how many API keys, webhooks and shares, the member each belongs to (or the organization), and the sites the webhooks deliver to. You do not see which keys, webhooks or shares they are (no ids, names, prefixes, or URLs beyond the site), the other inboxes and domains its scope names, or its saved expectations. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token). Only on your own dashboard session or the Primitive CLI.",
|
|
24982
|
+
"description": "One rule that covers one of your own mailboxes, read-only, with its current version; or one that no longer does but decided on mail at your own mailbox (covers_now false), shown as the version that last decided on your mail, without its current name. You see its name, wording, current tree, state, kind and author, and which of your own mailboxes it reaches. Its wording and tree are shown as written, so they can name other addresses (a condition on who an email is from or to). While it covers you, you also see who receives what it matches (receivers): how many API keys, webhooks and shares, the member each belongs to (or the organization), and the sites the webhooks deliver to. You do not see which keys, webhooks or shares they are (no ids, names, prefixes, or URLs beyond the site), the other inboxes and domains its scope names, or its saved expectations. For what happened to one email of yours, every rule's decision on it and, for another member's rule covering you, who receives what it shares: GET /v1/emails/{id}/rule-results (primitive email-rules list-email-rule-results --email-id <email-id>). Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token). Only on your own dashboard session or the Primitive CLI.",
|
|
24960
24983
|
"tags": ["Email Rule Oversight"],
|
|
24961
24984
|
"security": [{ "BearerAuth": [] }],
|
|
24962
24985
|
"parameters": [{
|
|
@@ -25008,7 +25031,7 @@ const openapiDocument = {
|
|
|
25008
25031
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
25009
25032
|
},
|
|
25010
25033
|
"404": {
|
|
25011
|
-
"description": "not_found: no rule with this id covers your mailboxes or decided on your mail.",
|
|
25034
|
+
"description": "not_found: no rule with this id covers your mailboxes or decided on your mail; details.reason rule_deleted (with details.rule_name) for one deleted after you were told it covered you.",
|
|
25012
25035
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
25013
25036
|
},
|
|
25014
25037
|
"429": {
|
|
@@ -25134,7 +25157,7 @@ const openapiDocument = {
|
|
|
25134
25157
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
25135
25158
|
},
|
|
25136
25159
|
"404": {
|
|
25137
|
-
"description": "not_found: no rule with this id covers your mailboxes or decided on your mail.",
|
|
25160
|
+
"description": "not_found: no rule with this id covers your mailboxes or decided on your mail; details.reason rule_deleted (with details.rule_name) for one deleted after you were told it covered you.",
|
|
25138
25161
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
25139
25162
|
},
|
|
25140
25163
|
"429": {
|
|
@@ -25262,7 +25285,7 @@ const openapiDocument = {
|
|
|
25262
25285
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
25263
25286
|
},
|
|
25264
25287
|
"404": {
|
|
25265
|
-
"description": "not_found: no rule with this id covers your mailboxes or decided on your mail.",
|
|
25288
|
+
"description": "not_found: no rule with this id covers your mailboxes or decided on your mail; details.reason rule_deleted (with details.rule_name) for one deleted after you were told it covered you.",
|
|
25266
25289
|
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
25267
25290
|
},
|
|
25268
25291
|
"429": {
|
|
@@ -25295,7 +25318,7 @@ const openapiDocument = {
|
|
|
25295
25318
|
"post": {
|
|
25296
25319
|
"operationId": "createEmailRuleObjection",
|
|
25297
25320
|
"summary": "Object to a rule over your mail",
|
|
25298
|
-
"description": "
|
|
25321
|
+
"description": "Objects to a rule that covers one of your own mailboxes now: say in the message what you ask its author, to turn it off, narrow it, or explain who receives what it matches. The author answers by accepting, which turns it off, or by declining, optionally with a reason you see; the rule keeps running unless they accept. Only a rule that covers you now: one you see only because it once decided on your mail cannot be objected to. An objection is seen by the member who made it, the rule's author and the organization's owners and admins. It stays pending until the rule's author accepts it, turning the rule off, or declines it (optionally with a reason the objector sees), or the member who made it withdraws it, which clears its message. It never changes after that. You may have one pending objection per rule and 50 in all, and object to the same rule again only 10 minutes after you last did, whatever became of it. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token). Only on your own dashboard session or the Primitive CLI.",
|
|
25299
25322
|
"tags": ["Email Rule Oversight"],
|
|
25300
25323
|
"security": [{ "BearerAuth": [] }],
|
|
25301
25324
|
"requestBody": {
|
|
@@ -25396,7 +25419,7 @@ const openapiDocument = {
|
|
|
25396
25419
|
"get": {
|
|
25397
25420
|
"operationId": "listEmailRuleObjections",
|
|
25398
25421
|
"summary": "List objections",
|
|
25399
|
-
"description": "Objections you made and objections to rules you wrote (by default), only one of the two, or every objection you can see, newest first. An objection is seen by the member who made it, the rule's author and the organization's owners and admins. It stays pending until the rule's author accepts it, turning the rule off, or declines it, or the member who made it withdraws it, which clears its message. It never changes after that. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token). Only on your own dashboard session or the Primitive CLI.",
|
|
25422
|
+
"description": "Objections you made and objections to rules you wrote (by default), only one of the two, or every objection you can see, newest first. An objection is seen by the member who made it, the rule's author and the organization's owners and admins. It stays pending until the rule's author accepts it, turning the rule off, or declines it (optionally with a reason the objector sees), or the member who made it withdraws it, which clears its message. It never changes after that. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token). Only on your own dashboard session or the Primitive CLI.",
|
|
25400
25423
|
"tags": ["Email Rule Oversight"],
|
|
25401
25424
|
"security": [{ "BearerAuth": [] }],
|
|
25402
25425
|
"parameters": [
|
|
@@ -25530,7 +25553,7 @@ const openapiDocument = {
|
|
|
25530
25553
|
"/email-rule-objections/{id}": { "get": {
|
|
25531
25554
|
"operationId": "getEmailRuleObjection",
|
|
25532
25555
|
"summary": "Get an objection",
|
|
25533
|
-
"description": "One objection you can see. An objection is seen by the member who made it, the rule's author and the organization's owners and admins. It stays pending until the rule's author accepts it, turning the rule off, or declines it, or the member who made it withdraws it, which clears its message. It never changes after that. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token). Only on your own dashboard session or the Primitive CLI.",
|
|
25556
|
+
"description": "One objection you can see. An objection is seen by the member who made it, the rule's author and the organization's owners and admins. It stays pending until the rule's author accepts it, turning the rule off, or declines it (optionally with a reason the objector sees), or the member who made it withdraws it, which clears its message. It never changes after that. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token). Only on your own dashboard session or the Primitive CLI.",
|
|
25534
25557
|
"tags": ["Email Rule Oversight"],
|
|
25535
25558
|
"security": [{ "BearerAuth": [] }],
|
|
25536
25559
|
"parameters": [{
|
|
@@ -25712,7 +25735,7 @@ const openapiDocument = {
|
|
|
25712
25735
|
"/email-rule-objections/{id}/decline": { "post": {
|
|
25713
25736
|
"operationId": "declineEmailRuleObjection",
|
|
25714
25737
|
"summary": "Decline an objection to your rule",
|
|
25715
|
-
"description": "Declines a pending objection to a rule you wrote, optionally saying why; the rule stays as it is. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token). Only on your own dashboard session or the Primitive CLI.",
|
|
25738
|
+
"description": "Declines a pending objection to a rule you wrote, optionally saying why (reason), which the member who objected sees; the rule stays as it is. When its message asks you to narrow the rule or explain who receives it, the reason is your answer; narrow it with a new version as well if you agree. Needs mail:read, the email rules feature, and a member's own full-access credential (no API key, agent key or narrowed token). Only on your own dashboard session or the Primitive CLI.",
|
|
25716
25739
|
"tags": ["Email Rule Oversight"],
|
|
25717
25740
|
"security": [{ "BearerAuth": [] }],
|
|
25718
25741
|
"parameters": [{
|
|
@@ -34798,7 +34821,7 @@ const openapiDocument = {
|
|
|
34798
34821
|
"summary": "Rotate an API key",
|
|
34799
34822
|
"tags": ["Credentials"],
|
|
34800
34823
|
"security": [{ "BearerAuth": [] }],
|
|
34801
|
-
"description": "Mint a successor with a new id and the same name, grant, expiry and conditions, and return its secret once. The old key keeps working for overlap_seconds, then stops: 24 hours when overlap_seconds is omitted, at most 7 days, never past its own expires_at, and at once with 0 (which is how to rotate a key whose secret leaked). previous_key_expires_at says when the old key stops. Revoking the successor during the overlap also revokes the old key when you may revoke that one too; the revoke's predecessors_left counts any left working. Rotating does not extend a key: the successor keeps the old expiry unless expires_at gives it a new one. That needs keys:manage (403 forbidden otherwise), is held to the credential policy (400 when past its maximum lifetime, with the latest expiry it allows now in the message), and someone limited to their own keys can only keep or bring it forward (403 grant_forbidden, details.reason own_key_tighten_only); the old key then never outlives the new one. The person rotating must cover the key's access (403 grant_forbidden, details.reason target_not_covered), and a key an owner holds 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) unless the organization's credential policy sets cli_writes_require_approval; 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. Contact Primitive to turn them on.\n\nPerson only: a dashboard session, the person's own Primitive CLI login with no step-up (unless the organization's credential policy sets cli_writes_require_approval), 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.",
|
|
34824
|
+
"description": "Mint a successor with a new id and the same name, grant, expiry and conditions, and return its secret once, with its name and grant so you can see they carried over. The old key keeps working for overlap_seconds, then stops: 24 hours when overlap_seconds is omitted, at most 7 days, never past its own expires_at, and at once with 0 (which is how to rotate a key whose secret leaked). previous_key_expires_at says when the old key stops. Revoking the successor during the overlap also revokes the old key when you may revoke that one too; the revoke's predecessors_left counts any left working. Rotating does not extend a key: the successor keeps the old expiry unless expires_at gives it a new one. That needs keys:manage (403 forbidden otherwise), is held to the credential policy (400 when past its maximum lifetime, with the latest expiry it allows now in the message), and someone limited to their own keys can only keep or bring it forward (403 grant_forbidden, details.reason own_key_tighten_only); the old key then never outlives the new one. The person rotating must cover the key's access (403 grant_forbidden, details.reason target_not_covered), and a key an owner holds 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) unless the organization's credential policy sets cli_writes_require_approval; 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. Contact Primitive to turn them on.\n\nPerson only: a dashboard session, the person's own Primitive CLI login with no step-up (unless the organization's credential policy sets cli_writes_require_approval), 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.",
|
|
34802
34825
|
"x-primitive-person-only": {
|
|
34803
34826
|
"access": "step_up",
|
|
34804
34827
|
"step_up_purpose": "keys.create",
|
|
@@ -36033,7 +36056,7 @@ const openapiDocument = {
|
|
|
36033
36056
|
"name": "Primitive-Step-Up",
|
|
36034
36057
|
"in": "header",
|
|
36035
36058
|
"required": false,
|
|
36036
|
-
"description": "A single-use step-up token of purpose `org_settings.write` (Change the organization name, logo
|
|
36059
|
+
"description": "A single-use step-up token of purpose `org_settings.write` (Change the organization name, logo, semantic search setting or email notification settings), 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.",
|
|
36037
36060
|
"schema": {
|
|
36038
36061
|
"type": "string",
|
|
36039
36062
|
"pattern": "^pstep_[0-9a-f]{64}$"
|
|
@@ -36184,7 +36207,7 @@ const openapiDocument = {
|
|
|
36184
36207
|
"name": "Primitive-Step-Up",
|
|
36185
36208
|
"in": "header",
|
|
36186
36209
|
"required": false,
|
|
36187
|
-
"description": "A single-use step-up token of purpose `org_settings.write` (Change the organization name, logo
|
|
36210
|
+
"description": "A single-use step-up token of purpose `org_settings.write` (Change the organization name, logo, semantic search setting or email notification settings), 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.",
|
|
36188
36211
|
"schema": {
|
|
36189
36212
|
"type": "string",
|
|
36190
36213
|
"pattern": "^pstep_[0-9a-f]{64}$"
|
|
@@ -36333,7 +36356,7 @@ const openapiDocument = {
|
|
|
36333
36356
|
"name": "Primitive-Step-Up",
|
|
36334
36357
|
"in": "header",
|
|
36335
36358
|
"required": false,
|
|
36336
|
-
"description": "A single-use step-up token of purpose `org_settings.write` (Change the organization name, logo
|
|
36359
|
+
"description": "A single-use step-up token of purpose `org_settings.write` (Change the organization name, logo, semantic search setting or email notification settings), 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.",
|
|
36337
36360
|
"schema": {
|
|
36338
36361
|
"type": "string",
|
|
36339
36362
|
"pattern": "^pstep_[0-9a-f]{64}$"
|
|
@@ -36444,34 +36467,548 @@ const openapiDocument = {
|
|
|
36444
36467
|
}
|
|
36445
36468
|
}
|
|
36446
36469
|
} }
|
|
36447
|
-
},
|
|
36448
|
-
"502": {
|
|
36449
|
-
"description": "upstream_unavailable: the organization profile could not be reached, or (after a write) the change was saved but could not be read back. Retryable for a read; read the profile again before repeating a write.",
|
|
36450
|
-
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
36451
|
-
},
|
|
36452
|
-
"503": {
|
|
36453
|
-
"description": "upstream_unavailable: the organization profile is temporarily unavailable. Retry-After says when to retry.",
|
|
36454
|
-
"headers": { "Retry-After": {
|
|
36455
|
-
"description": "Seconds to wait before retrying.",
|
|
36456
|
-
"schema": {
|
|
36457
|
-
"type": "integer",
|
|
36458
|
-
"minimum": 1
|
|
36459
|
-
}
|
|
36460
|
-
} },
|
|
36461
|
-
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
36470
|
+
},
|
|
36471
|
+
"502": {
|
|
36472
|
+
"description": "upstream_unavailable: the organization profile could not be reached, or (after a write) the change was saved but could not be read back. Retryable for a read; read the profile again before repeating a write.",
|
|
36473
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
36474
|
+
},
|
|
36475
|
+
"503": {
|
|
36476
|
+
"description": "upstream_unavailable: the organization profile is temporarily unavailable. Retry-After says when to retry.",
|
|
36477
|
+
"headers": { "Retry-After": {
|
|
36478
|
+
"description": "Seconds to wait before retrying.",
|
|
36479
|
+
"schema": {
|
|
36480
|
+
"type": "integer",
|
|
36481
|
+
"minimum": 1
|
|
36482
|
+
}
|
|
36483
|
+
} },
|
|
36484
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/ErrorResponse" } } }
|
|
36485
|
+
}
|
|
36486
|
+
},
|
|
36487
|
+
"x-primitive-permission": ["org:manage"],
|
|
36488
|
+
"x-primitive-permission-alternatives": [["members:manage"]]
|
|
36489
|
+
}
|
|
36490
|
+
},
|
|
36491
|
+
"/search-settings": {
|
|
36492
|
+
"get": {
|
|
36493
|
+
"operationId": "getSearchSettings",
|
|
36494
|
+
"summary": "Get the semantic search setting",
|
|
36495
|
+
"tags": ["Organization settings"],
|
|
36496
|
+
"security": [{ "BearerAuth": [] }],
|
|
36497
|
+
"description": "Whether the organization consents to semantic search, and whether it is active: it also needs a paid plan, the feature to be available to the organization, and HIPAA mode off.\n\nPerson only: a dashboard session or the person's own OAuth token (the CLI or an app they connected). API keys, agent connection keys and agents are refused.",
|
|
36498
|
+
"x-primitive-person-only": { "access": "person" },
|
|
36499
|
+
"parameters": [],
|
|
36500
|
+
"responses": {
|
|
36501
|
+
"200": {
|
|
36502
|
+
"description": "Success",
|
|
36503
|
+
"content": { "application/json": { "schema": {
|
|
36504
|
+
"type": "object",
|
|
36505
|
+
"required": ["success", "data"],
|
|
36506
|
+
"properties": {
|
|
36507
|
+
"success": {
|
|
36508
|
+
"type": "boolean",
|
|
36509
|
+
"const": true
|
|
36510
|
+
},
|
|
36511
|
+
"data": { "$ref": "#/components/schemas/OrgSettings_getSearchSettings_Result" }
|
|
36512
|
+
}
|
|
36513
|
+
} } },
|
|
36514
|
+
"headers": {
|
|
36515
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit" },
|
|
36516
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining" },
|
|
36517
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
36518
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy" }
|
|
36519
|
+
}
|
|
36520
|
+
},
|
|
36521
|
+
"400": {
|
|
36522
|
+
"description": "Invalid request parameters",
|
|
36523
|
+
"content": { "application/json": {
|
|
36524
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36525
|
+
"example": {
|
|
36526
|
+
"success": false,
|
|
36527
|
+
"error": {
|
|
36528
|
+
"code": "validation_error",
|
|
36529
|
+
"message": "Invalid domain format"
|
|
36530
|
+
}
|
|
36531
|
+
}
|
|
36532
|
+
} }
|
|
36533
|
+
},
|
|
36534
|
+
"401": {
|
|
36535
|
+
"description": "Invalid or missing API key",
|
|
36536
|
+
"content": { "application/json": {
|
|
36537
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36538
|
+
"example": {
|
|
36539
|
+
"success": false,
|
|
36540
|
+
"error": {
|
|
36541
|
+
"code": "unauthorized",
|
|
36542
|
+
"message": "Invalid or missing API key"
|
|
36543
|
+
}
|
|
36544
|
+
}
|
|
36545
|
+
} },
|
|
36546
|
+
"headers": {
|
|
36547
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-unauthenticated" },
|
|
36548
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-unauthenticated" },
|
|
36549
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset-unauthenticated" },
|
|
36550
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-unauthenticated" }
|
|
36551
|
+
}
|
|
36552
|
+
},
|
|
36553
|
+
"403": {
|
|
36554
|
+
"description": "Authenticated caller lacks permission for the operation",
|
|
36555
|
+
"content": { "application/json": {
|
|
36556
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36557
|
+
"example": {
|
|
36558
|
+
"success": false,
|
|
36559
|
+
"error": {
|
|
36560
|
+
"code": "forbidden",
|
|
36561
|
+
"message": "Insufficient permissions"
|
|
36562
|
+
}
|
|
36563
|
+
}
|
|
36564
|
+
} }
|
|
36565
|
+
},
|
|
36566
|
+
"404": {
|
|
36567
|
+
"description": "Resource not found",
|
|
36568
|
+
"content": { "application/json": {
|
|
36569
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36570
|
+
"example": {
|
|
36571
|
+
"success": false,
|
|
36572
|
+
"error": {
|
|
36573
|
+
"code": "not_found",
|
|
36574
|
+
"message": "Resource not found"
|
|
36575
|
+
}
|
|
36576
|
+
}
|
|
36577
|
+
} }
|
|
36578
|
+
},
|
|
36579
|
+
"429": {
|
|
36580
|
+
"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.",
|
|
36581
|
+
"headers": {
|
|
36582
|
+
"Retry-After": {
|
|
36583
|
+
"schema": { "type": "integer" },
|
|
36584
|
+
"description": "Seconds to wait before retrying"
|
|
36585
|
+
},
|
|
36586
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-429" },
|
|
36587
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-429" },
|
|
36588
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
36589
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-429" }
|
|
36590
|
+
},
|
|
36591
|
+
"content": { "application/json": {
|
|
36592
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36593
|
+
"example": {
|
|
36594
|
+
"success": false,
|
|
36595
|
+
"error": {
|
|
36596
|
+
"code": "rate_limit_exceeded",
|
|
36597
|
+
"message": "Rate limit exceeded"
|
|
36598
|
+
}
|
|
36599
|
+
}
|
|
36600
|
+
} }
|
|
36601
|
+
}
|
|
36602
|
+
},
|
|
36603
|
+
"x-primitive-permission": ["org:read"]
|
|
36604
|
+
},
|
|
36605
|
+
"put": {
|
|
36606
|
+
"operationId": "updateSearchSettings",
|
|
36607
|
+
"summary": "Change the semantic search setting",
|
|
36608
|
+
"tags": ["Organization settings"],
|
|
36609
|
+
"security": [{ "BearerAuth": [] }],
|
|
36610
|
+
"description": "Consent to, or withdraw consent from, semantic search. Consenting sends the organization's mail content to an embedding provider, so it is a person's decision. Turning it on is refused with 409 under HIPAA mode (hipaa_mode), without a paid plan (plan_required) or while it is not available to the organization (not_available). Turning it off is always allowed.\n\nPerson only: a dashboard session, or the person's own OAuth token with a step-up token for purpose `org_settings.write` in the Primitive-Step-Up header. Without one an 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 could not do it anyway). The person's role must hold search_settings: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.",
|
|
36611
|
+
"x-primitive-person-only": {
|
|
36612
|
+
"access": "step_up",
|
|
36613
|
+
"step_up_purpose": "org_settings.write"
|
|
36614
|
+
},
|
|
36615
|
+
"parameters": [{
|
|
36616
|
+
"name": "Primitive-Step-Up",
|
|
36617
|
+
"in": "header",
|
|
36618
|
+
"required": false,
|
|
36619
|
+
"description": "A single-use step-up token of purpose `org_settings.write` (Change the organization name, logo, semantic search setting or email notification settings), 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.",
|
|
36620
|
+
"schema": {
|
|
36621
|
+
"type": "string",
|
|
36622
|
+
"pattern": "^pstep_[0-9a-f]{64}$"
|
|
36623
|
+
}
|
|
36624
|
+
}],
|
|
36625
|
+
"responses": {
|
|
36626
|
+
"200": {
|
|
36627
|
+
"description": "Success",
|
|
36628
|
+
"content": { "application/json": { "schema": {
|
|
36629
|
+
"type": "object",
|
|
36630
|
+
"required": ["success", "data"],
|
|
36631
|
+
"properties": {
|
|
36632
|
+
"success": {
|
|
36633
|
+
"type": "boolean",
|
|
36634
|
+
"const": true
|
|
36635
|
+
},
|
|
36636
|
+
"data": { "$ref": "#/components/schemas/OrgSettings_updateSearchSettings_Result" }
|
|
36637
|
+
}
|
|
36638
|
+
} } },
|
|
36639
|
+
"headers": {
|
|
36640
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit" },
|
|
36641
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining" },
|
|
36642
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
36643
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy" }
|
|
36644
|
+
}
|
|
36645
|
+
},
|
|
36646
|
+
"400": {
|
|
36647
|
+
"description": "Invalid request parameters",
|
|
36648
|
+
"content": { "application/json": {
|
|
36649
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36650
|
+
"example": {
|
|
36651
|
+
"success": false,
|
|
36652
|
+
"error": {
|
|
36653
|
+
"code": "validation_error",
|
|
36654
|
+
"message": "Invalid domain format"
|
|
36655
|
+
}
|
|
36656
|
+
}
|
|
36657
|
+
} }
|
|
36658
|
+
},
|
|
36659
|
+
"401": {
|
|
36660
|
+
"description": "Invalid or missing API key",
|
|
36661
|
+
"content": { "application/json": {
|
|
36662
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36663
|
+
"example": {
|
|
36664
|
+
"success": false,
|
|
36665
|
+
"error": {
|
|
36666
|
+
"code": "unauthorized",
|
|
36667
|
+
"message": "Invalid or missing API key"
|
|
36668
|
+
}
|
|
36669
|
+
}
|
|
36670
|
+
} },
|
|
36671
|
+
"headers": {
|
|
36672
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-unauthenticated" },
|
|
36673
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-unauthenticated" },
|
|
36674
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset-unauthenticated" },
|
|
36675
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-unauthenticated" }
|
|
36676
|
+
}
|
|
36677
|
+
},
|
|
36678
|
+
"403": {
|
|
36679
|
+
"description": "Authenticated caller lacks permission for the operation",
|
|
36680
|
+
"content": { "application/json": {
|
|
36681
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36682
|
+
"example": {
|
|
36683
|
+
"success": false,
|
|
36684
|
+
"error": {
|
|
36685
|
+
"code": "forbidden",
|
|
36686
|
+
"message": "Insufficient permissions"
|
|
36687
|
+
}
|
|
36688
|
+
}
|
|
36689
|
+
} }
|
|
36690
|
+
},
|
|
36691
|
+
"404": {
|
|
36692
|
+
"description": "Resource not found",
|
|
36693
|
+
"content": { "application/json": {
|
|
36694
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36695
|
+
"example": {
|
|
36696
|
+
"success": false,
|
|
36697
|
+
"error": {
|
|
36698
|
+
"code": "not_found",
|
|
36699
|
+
"message": "Resource not found"
|
|
36700
|
+
}
|
|
36701
|
+
}
|
|
36702
|
+
} }
|
|
36703
|
+
},
|
|
36704
|
+
"409": {
|
|
36705
|
+
"description": "The request conflicts with the current state of the resource",
|
|
36706
|
+
"content": { "application/json": {
|
|
36707
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36708
|
+
"example": {
|
|
36709
|
+
"success": false,
|
|
36710
|
+
"error": {
|
|
36711
|
+
"code": "conflict",
|
|
36712
|
+
"message": "The request conflicts with the current state of the resource"
|
|
36713
|
+
}
|
|
36714
|
+
}
|
|
36715
|
+
} }
|
|
36716
|
+
},
|
|
36717
|
+
"429": {
|
|
36718
|
+
"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.",
|
|
36719
|
+
"headers": {
|
|
36720
|
+
"Retry-After": {
|
|
36721
|
+
"schema": { "type": "integer" },
|
|
36722
|
+
"description": "Seconds to wait before retrying"
|
|
36723
|
+
},
|
|
36724
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-429" },
|
|
36725
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-429" },
|
|
36726
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
36727
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-429" }
|
|
36728
|
+
},
|
|
36729
|
+
"content": { "application/json": {
|
|
36730
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36731
|
+
"example": {
|
|
36732
|
+
"success": false,
|
|
36733
|
+
"error": {
|
|
36734
|
+
"code": "rate_limit_exceeded",
|
|
36735
|
+
"message": "Rate limit exceeded"
|
|
36736
|
+
}
|
|
36737
|
+
}
|
|
36738
|
+
} }
|
|
36739
|
+
}
|
|
36740
|
+
},
|
|
36741
|
+
"requestBody": {
|
|
36742
|
+
"required": true,
|
|
36743
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/OrgSettings_updateSearchSettings_Input" } } }
|
|
36744
|
+
},
|
|
36745
|
+
"x-primitive-permission": ["search_settings:manage"]
|
|
36746
|
+
}
|
|
36747
|
+
},
|
|
36748
|
+
"/email-notification-settings": {
|
|
36749
|
+
"get": {
|
|
36750
|
+
"operationId": "getEmailNotificationSettings",
|
|
36751
|
+
"summary": "Get the organization's email notification settings",
|
|
36752
|
+
"tags": ["Email notifications"],
|
|
36753
|
+
"security": [{ "BearerAuth": [] }],
|
|
36754
|
+
"description": "Every kind of notification email Primitive sends the organization's members, and who may turn it off. Each kind lists its label and description, its class, whether it needs an entitlement and whether the organization has it, the organization's mode (null for platform_required) and the modes it may choose, and whether the calling member gets it and may change that.\n\nPerson only: a dashboard session or the person's own OAuth token (the CLI or an app they connected). API keys, agent connection keys and agents are refused.",
|
|
36755
|
+
"x-primitive-person-only": { "access": "person" },
|
|
36756
|
+
"parameters": [],
|
|
36757
|
+
"responses": {
|
|
36758
|
+
"200": {
|
|
36759
|
+
"description": "Success",
|
|
36760
|
+
"content": { "application/json": { "schema": {
|
|
36761
|
+
"type": "object",
|
|
36762
|
+
"required": ["success", "data"],
|
|
36763
|
+
"properties": {
|
|
36764
|
+
"success": {
|
|
36765
|
+
"type": "boolean",
|
|
36766
|
+
"const": true
|
|
36767
|
+
},
|
|
36768
|
+
"data": { "$ref": "#/components/schemas/EmailNotifications_getEmailNotificationSettings_Result" }
|
|
36769
|
+
}
|
|
36770
|
+
} } },
|
|
36771
|
+
"headers": {
|
|
36772
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit" },
|
|
36773
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining" },
|
|
36774
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
36775
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy" }
|
|
36776
|
+
}
|
|
36777
|
+
},
|
|
36778
|
+
"400": {
|
|
36779
|
+
"description": "Invalid request parameters",
|
|
36780
|
+
"content": { "application/json": {
|
|
36781
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36782
|
+
"example": {
|
|
36783
|
+
"success": false,
|
|
36784
|
+
"error": {
|
|
36785
|
+
"code": "validation_error",
|
|
36786
|
+
"message": "Invalid domain format"
|
|
36787
|
+
}
|
|
36788
|
+
}
|
|
36789
|
+
} }
|
|
36790
|
+
},
|
|
36791
|
+
"401": {
|
|
36792
|
+
"description": "Invalid or missing API key",
|
|
36793
|
+
"content": { "application/json": {
|
|
36794
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36795
|
+
"example": {
|
|
36796
|
+
"success": false,
|
|
36797
|
+
"error": {
|
|
36798
|
+
"code": "unauthorized",
|
|
36799
|
+
"message": "Invalid or missing API key"
|
|
36800
|
+
}
|
|
36801
|
+
}
|
|
36802
|
+
} },
|
|
36803
|
+
"headers": {
|
|
36804
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-unauthenticated" },
|
|
36805
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-unauthenticated" },
|
|
36806
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset-unauthenticated" },
|
|
36807
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-unauthenticated" }
|
|
36808
|
+
}
|
|
36809
|
+
},
|
|
36810
|
+
"403": {
|
|
36811
|
+
"description": "Authenticated caller lacks permission for the operation",
|
|
36812
|
+
"content": { "application/json": {
|
|
36813
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36814
|
+
"example": {
|
|
36815
|
+
"success": false,
|
|
36816
|
+
"error": {
|
|
36817
|
+
"code": "forbidden",
|
|
36818
|
+
"message": "Insufficient permissions"
|
|
36819
|
+
}
|
|
36820
|
+
}
|
|
36821
|
+
} }
|
|
36822
|
+
},
|
|
36823
|
+
"404": {
|
|
36824
|
+
"description": "Resource not found",
|
|
36825
|
+
"content": { "application/json": {
|
|
36826
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36827
|
+
"example": {
|
|
36828
|
+
"success": false,
|
|
36829
|
+
"error": {
|
|
36830
|
+
"code": "not_found",
|
|
36831
|
+
"message": "Resource not found"
|
|
36832
|
+
}
|
|
36833
|
+
}
|
|
36834
|
+
} }
|
|
36835
|
+
},
|
|
36836
|
+
"429": {
|
|
36837
|
+
"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.",
|
|
36838
|
+
"headers": {
|
|
36839
|
+
"Retry-After": {
|
|
36840
|
+
"schema": { "type": "integer" },
|
|
36841
|
+
"description": "Seconds to wait before retrying"
|
|
36842
|
+
},
|
|
36843
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-429" },
|
|
36844
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-429" },
|
|
36845
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
36846
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-429" }
|
|
36847
|
+
},
|
|
36848
|
+
"content": { "application/json": {
|
|
36849
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36850
|
+
"example": {
|
|
36851
|
+
"success": false,
|
|
36852
|
+
"error": {
|
|
36853
|
+
"code": "rate_limit_exceeded",
|
|
36854
|
+
"message": "Rate limit exceeded"
|
|
36855
|
+
}
|
|
36856
|
+
}
|
|
36857
|
+
} }
|
|
36858
|
+
}
|
|
36859
|
+
},
|
|
36860
|
+
"x-primitive-permission": ["org:read"]
|
|
36861
|
+
},
|
|
36862
|
+
"put": {
|
|
36863
|
+
"operationId": "updateEmailNotificationSettings",
|
|
36864
|
+
"summary": "Change the organization's email notification settings",
|
|
36865
|
+
"tags": ["Email notifications"],
|
|
36866
|
+
"security": [{ "BearerAuth": [] }],
|
|
36867
|
+
"description": "Set the organization's mode for one or more kinds: off (nobody gets it), optional_on (each member gets it unless they turn it off), optional_off (only members who turn it on get it) or required (every member gets it). Kinds left out keep their mode. An unknown kind is refused with 400 (validation_error, details.reason unknown_kind). A platform_required kind is refused with 409 (conflict, details.reason platform_required), and required for an optional kind with 409 (conflict, details.reason mode_not_allowed); nothing is changed. Answers the settings as they now stand. Each kind lists its label and description, its class, whether it needs an entitlement and whether the organization has it, the organization's mode (null for platform_required) and the modes it may choose, and whether the calling member gets it and may change that.\n\nPerson only: a dashboard session, or the person's own OAuth token with a step-up token for purpose `org_settings.write` in the Primitive-Step-Up header. Without one an 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 could not do it anyway). The person's role must hold notification_policy: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.",
|
|
36868
|
+
"x-primitive-person-only": {
|
|
36869
|
+
"access": "step_up",
|
|
36870
|
+
"step_up_purpose": "org_settings.write"
|
|
36871
|
+
},
|
|
36872
|
+
"parameters": [{
|
|
36873
|
+
"name": "Primitive-Step-Up",
|
|
36874
|
+
"in": "header",
|
|
36875
|
+
"required": false,
|
|
36876
|
+
"description": "A single-use step-up token of purpose `org_settings.write` (Change the organization name, logo, semantic search setting or email notification settings), 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.",
|
|
36877
|
+
"schema": {
|
|
36878
|
+
"type": "string",
|
|
36879
|
+
"pattern": "^pstep_[0-9a-f]{64}$"
|
|
36880
|
+
}
|
|
36881
|
+
}],
|
|
36882
|
+
"responses": {
|
|
36883
|
+
"200": {
|
|
36884
|
+
"description": "Success",
|
|
36885
|
+
"content": { "application/json": { "schema": {
|
|
36886
|
+
"type": "object",
|
|
36887
|
+
"required": ["success", "data"],
|
|
36888
|
+
"properties": {
|
|
36889
|
+
"success": {
|
|
36890
|
+
"type": "boolean",
|
|
36891
|
+
"const": true
|
|
36892
|
+
},
|
|
36893
|
+
"data": { "$ref": "#/components/schemas/EmailNotifications_updateEmailNotificationSettings_Result" }
|
|
36894
|
+
}
|
|
36895
|
+
} } },
|
|
36896
|
+
"headers": {
|
|
36897
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit" },
|
|
36898
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining" },
|
|
36899
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
36900
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy" }
|
|
36901
|
+
}
|
|
36902
|
+
},
|
|
36903
|
+
"400": {
|
|
36904
|
+
"description": "Invalid request parameters",
|
|
36905
|
+
"content": { "application/json": {
|
|
36906
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36907
|
+
"example": {
|
|
36908
|
+
"success": false,
|
|
36909
|
+
"error": {
|
|
36910
|
+
"code": "validation_error",
|
|
36911
|
+
"message": "Invalid domain format"
|
|
36912
|
+
}
|
|
36913
|
+
}
|
|
36914
|
+
} }
|
|
36915
|
+
},
|
|
36916
|
+
"401": {
|
|
36917
|
+
"description": "Invalid or missing API key",
|
|
36918
|
+
"content": { "application/json": {
|
|
36919
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36920
|
+
"example": {
|
|
36921
|
+
"success": false,
|
|
36922
|
+
"error": {
|
|
36923
|
+
"code": "unauthorized",
|
|
36924
|
+
"message": "Invalid or missing API key"
|
|
36925
|
+
}
|
|
36926
|
+
}
|
|
36927
|
+
} },
|
|
36928
|
+
"headers": {
|
|
36929
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-unauthenticated" },
|
|
36930
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-unauthenticated" },
|
|
36931
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset-unauthenticated" },
|
|
36932
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-unauthenticated" }
|
|
36933
|
+
}
|
|
36934
|
+
},
|
|
36935
|
+
"403": {
|
|
36936
|
+
"description": "Authenticated caller lacks permission for the operation",
|
|
36937
|
+
"content": { "application/json": {
|
|
36938
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36939
|
+
"example": {
|
|
36940
|
+
"success": false,
|
|
36941
|
+
"error": {
|
|
36942
|
+
"code": "forbidden",
|
|
36943
|
+
"message": "Insufficient permissions"
|
|
36944
|
+
}
|
|
36945
|
+
}
|
|
36946
|
+
} }
|
|
36947
|
+
},
|
|
36948
|
+
"404": {
|
|
36949
|
+
"description": "Resource not found",
|
|
36950
|
+
"content": { "application/json": {
|
|
36951
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36952
|
+
"example": {
|
|
36953
|
+
"success": false,
|
|
36954
|
+
"error": {
|
|
36955
|
+
"code": "not_found",
|
|
36956
|
+
"message": "Resource not found"
|
|
36957
|
+
}
|
|
36958
|
+
}
|
|
36959
|
+
} }
|
|
36960
|
+
},
|
|
36961
|
+
"409": {
|
|
36962
|
+
"description": "The request conflicts with the current state of the resource",
|
|
36963
|
+
"content": { "application/json": {
|
|
36964
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36965
|
+
"example": {
|
|
36966
|
+
"success": false,
|
|
36967
|
+
"error": {
|
|
36968
|
+
"code": "conflict",
|
|
36969
|
+
"message": "The request conflicts with the current state of the resource"
|
|
36970
|
+
}
|
|
36971
|
+
}
|
|
36972
|
+
} }
|
|
36973
|
+
},
|
|
36974
|
+
"429": {
|
|
36975
|
+
"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.",
|
|
36976
|
+
"headers": {
|
|
36977
|
+
"Retry-After": {
|
|
36978
|
+
"schema": { "type": "integer" },
|
|
36979
|
+
"description": "Seconds to wait before retrying"
|
|
36980
|
+
},
|
|
36981
|
+
"ratelimit-limit": { "$ref": "#/components/headers/ratelimit-limit-429" },
|
|
36982
|
+
"ratelimit-remaining": { "$ref": "#/components/headers/ratelimit-remaining-429" },
|
|
36983
|
+
"ratelimit-reset": { "$ref": "#/components/headers/ratelimit-reset" },
|
|
36984
|
+
"ratelimit-policy": { "$ref": "#/components/headers/ratelimit-policy-429" }
|
|
36985
|
+
},
|
|
36986
|
+
"content": { "application/json": {
|
|
36987
|
+
"schema": { "$ref": "#/components/schemas/ErrorResponse" },
|
|
36988
|
+
"example": {
|
|
36989
|
+
"success": false,
|
|
36990
|
+
"error": {
|
|
36991
|
+
"code": "rate_limit_exceeded",
|
|
36992
|
+
"message": "Rate limit exceeded"
|
|
36993
|
+
}
|
|
36994
|
+
}
|
|
36995
|
+
} }
|
|
36462
36996
|
}
|
|
36463
36997
|
},
|
|
36464
|
-
"
|
|
36465
|
-
|
|
36998
|
+
"requestBody": {
|
|
36999
|
+
"required": true,
|
|
37000
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/EmailNotifications_updateEmailNotificationSettings_Input" } } }
|
|
37001
|
+
},
|
|
37002
|
+
"x-primitive-permission": ["notification_policy:manage"]
|
|
36466
37003
|
}
|
|
36467
37004
|
},
|
|
36468
|
-
"/
|
|
37005
|
+
"/email-notification-preferences": {
|
|
36469
37006
|
"get": {
|
|
36470
|
-
"operationId": "
|
|
36471
|
-
"summary": "Get
|
|
36472
|
-
"tags": ["
|
|
37007
|
+
"operationId": "getEmailNotificationPreferences",
|
|
37008
|
+
"summary": "Get my email notification preferences",
|
|
37009
|
+
"tags": ["Email notifications"],
|
|
36473
37010
|
"security": [{ "BearerAuth": [] }],
|
|
36474
|
-
"description": "
|
|
37011
|
+
"description": "The notification emails the calling member gets, and which of them they may turn on or off. Each kind lists its label and description, its class, whether it needs an entitlement and whether the organization has it, the organization's mode (null for platform_required) and the modes it may choose, and whether the calling member gets it and may change that.\n\nPerson only: a dashboard session or the person's own OAuth token (the CLI or an app they connected). The person's role must hold notifications:manage. API keys, agent connection keys and agents are refused.",
|
|
36475
37012
|
"x-primitive-person-only": { "access": "person" },
|
|
36476
37013
|
"parameters": [],
|
|
36477
37014
|
"responses": {
|
|
@@ -36485,7 +37022,7 @@ const openapiDocument = {
|
|
|
36485
37022
|
"type": "boolean",
|
|
36486
37023
|
"const": true
|
|
36487
37024
|
},
|
|
36488
|
-
"data": { "$ref": "#/components/schemas/
|
|
37025
|
+
"data": { "$ref": "#/components/schemas/EmailNotifications_getEmailNotificationPreferences_Result" }
|
|
36489
37026
|
}
|
|
36490
37027
|
} } },
|
|
36491
37028
|
"headers": {
|
|
@@ -36577,28 +37114,16 @@ const openapiDocument = {
|
|
|
36577
37114
|
} }
|
|
36578
37115
|
}
|
|
36579
37116
|
},
|
|
36580
|
-
"x-primitive-permission": ["
|
|
37117
|
+
"x-primitive-permission": ["notifications:manage"]
|
|
36581
37118
|
},
|
|
36582
37119
|
"put": {
|
|
36583
|
-
"operationId": "
|
|
36584
|
-
"summary": "Change
|
|
36585
|
-
"tags": ["
|
|
37120
|
+
"operationId": "updateEmailNotificationPreferences",
|
|
37121
|
+
"summary": "Change my email notification preferences",
|
|
37122
|
+
"tags": ["Email notifications"],
|
|
36586
37123
|
"security": [{ "BearerAuth": [] }],
|
|
36587
|
-
"description": "
|
|
36588
|
-
"x-primitive-person-only": {
|
|
36589
|
-
|
|
36590
|
-
"step_up_purpose": "org_settings.write"
|
|
36591
|
-
},
|
|
36592
|
-
"parameters": [{
|
|
36593
|
-
"name": "Primitive-Step-Up",
|
|
36594
|
-
"in": "header",
|
|
36595
|
-
"required": false,
|
|
36596
|
-
"description": "A single-use step-up token of purpose `org_settings.write` (Change the organization name, logo or semantic search setting), 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.",
|
|
36597
|
-
"schema": {
|
|
36598
|
-
"type": "string",
|
|
36599
|
-
"pattern": "^pstep_[0-9a-f]{64}$"
|
|
36600
|
-
}
|
|
36601
|
-
}],
|
|
37124
|
+
"description": "Turn one or more kinds on or off for the calling member. Only a kind whose organization mode is optional_on or optional_off can be changed: a platform_required kind, one the organization requires, and one it turned off are refused with 409 (conflict, details.reason not_member_choice, details.org_mode saying which), and nothing is changed. An unknown kind is refused with 400. Answers the preferences as they now stand. Each kind lists its label and description, its class, whether it needs an entitlement and whether the organization has it, the organization's mode (null for platform_required) and the modes it may choose, and whether the calling member gets it and may change that.\n\nPerson only: a dashboard session or the person's own OAuth token (the CLI or an app they connected). The person's role must hold notifications:manage. API keys, agent connection keys and agents are refused.",
|
|
37125
|
+
"x-primitive-person-only": { "access": "person" },
|
|
37126
|
+
"parameters": [],
|
|
36602
37127
|
"responses": {
|
|
36603
37128
|
"200": {
|
|
36604
37129
|
"description": "Success",
|
|
@@ -36610,7 +37135,7 @@ const openapiDocument = {
|
|
|
36610
37135
|
"type": "boolean",
|
|
36611
37136
|
"const": true
|
|
36612
37137
|
},
|
|
36613
|
-
"data": { "$ref": "#/components/schemas/
|
|
37138
|
+
"data": { "$ref": "#/components/schemas/EmailNotifications_updateEmailNotificationPreferences_Result" }
|
|
36614
37139
|
}
|
|
36615
37140
|
} } },
|
|
36616
37141
|
"headers": {
|
|
@@ -36717,9 +37242,9 @@ const openapiDocument = {
|
|
|
36717
37242
|
},
|
|
36718
37243
|
"requestBody": {
|
|
36719
37244
|
"required": true,
|
|
36720
|
-
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/
|
|
37245
|
+
"content": { "application/json": { "schema": { "$ref": "#/components/schemas/EmailNotifications_updateEmailNotificationPreferences_Input" } } }
|
|
36721
37246
|
},
|
|
36722
|
-
"x-primitive-permission": ["
|
|
37247
|
+
"x-primitive-permission": ["notifications:manage"]
|
|
36723
37248
|
}
|
|
36724
37249
|
},
|
|
36725
37250
|
"/roles": {
|
|
@@ -40654,6 +41179,7 @@ const openapiDocument = {
|
|
|
40654
41179
|
"agent_work_version_conflict",
|
|
40655
41180
|
"already_claimed",
|
|
40656
41181
|
"already_member",
|
|
41182
|
+
"always_sent",
|
|
40657
41183
|
"archive_busy",
|
|
40658
41184
|
"archive_invalid",
|
|
40659
41185
|
"archive_limit_exceeded",
|
|
@@ -40846,6 +41372,7 @@ const openapiDocument = {
|
|
|
40846
41372
|
"removal_failed",
|
|
40847
41373
|
"removal_timeout",
|
|
40848
41374
|
"request_expired",
|
|
41375
|
+
"required_by_organization",
|
|
40849
41376
|
"resend_limit_exceeded",
|
|
40850
41377
|
"resend_too_soon",
|
|
40851
41378
|
"role_assigned",
|
|
@@ -42728,8 +43255,14 @@ const openapiDocument = {
|
|
|
42728
43255
|
"format": "date-time"
|
|
42729
43256
|
},
|
|
42730
43257
|
"raw_size_bytes": { "type": ["integer", "null"] },
|
|
42731
|
-
"webhook_status": {
|
|
42732
|
-
|
|
43258
|
+
"webhook_status": {
|
|
43259
|
+
"$ref": "#/components/schemas/EmailWebhookStatus",
|
|
43260
|
+
"description": "The email's own routed delivery only (where routing sent it); a rule's deliveries never change this, and are in `rule_deliveries` on GET /emails/{id} for the mailbox's owner. Its delivery state. `pending` with 0 attempts can also mean no route webhook took it."
|
|
43261
|
+
},
|
|
43262
|
+
"webhook_attempt_count": {
|
|
43263
|
+
"type": "integer",
|
|
43264
|
+
"description": "The email's own routed delivery only (where routing sent it); a rule's deliveries never change this, and are in `rule_deliveries` on GET /emails/{id} for the mailbox's owner. Its attempts."
|
|
43265
|
+
},
|
|
42733
43266
|
"thread_id": {
|
|
42734
43267
|
"type": ["string", "null"],
|
|
42735
43268
|
"format": "uuid",
|
|
@@ -43227,17 +43760,31 @@ const openapiDocument = {
|
|
|
43227
43760
|
"format": "date-time"
|
|
43228
43761
|
},
|
|
43229
43762
|
"rejection_reason": { "type": ["string", "null"] },
|
|
43230
|
-
"webhook_status": {
|
|
43231
|
-
|
|
43763
|
+
"webhook_status": {
|
|
43764
|
+
"$ref": "#/components/schemas/EmailWebhookStatus",
|
|
43765
|
+
"description": "The email's own routed delivery only (where routing sent it); a rule's deliveries never change this, and are in `rule_deliveries` on GET /emails/{id} for the mailbox's owner. Its delivery state. `pending` with 0 attempts can also mean no route webhook took it."
|
|
43766
|
+
},
|
|
43767
|
+
"webhook_attempt_count": {
|
|
43768
|
+
"type": "integer",
|
|
43769
|
+
"description": "The email's own routed delivery only (where routing sent it); a rule's deliveries never change this, and are in `rule_deliveries` on GET /emails/{id} for the mailbox's owner. Its attempts."
|
|
43770
|
+
},
|
|
43232
43771
|
"webhook_last_attempt_at": {
|
|
43233
43772
|
"type": ["string", "null"],
|
|
43234
|
-
"format": "date-time"
|
|
43773
|
+
"format": "date-time",
|
|
43774
|
+
"description": "The email's own routed delivery only (where routing sent it); a rule's deliveries never change this, and are in `rule_deliveries` on GET /emails/{id} for the mailbox's owner. Its last attempt."
|
|
43775
|
+
},
|
|
43776
|
+
"webhook_last_status_code": {
|
|
43777
|
+
"type": ["integer", "null"],
|
|
43778
|
+
"description": "The email's own routed delivery only (where routing sent it); a rule's deliveries never change this, and are in `rule_deliveries` on GET /emails/{id} for the mailbox's owner. What it last answered."
|
|
43779
|
+
},
|
|
43780
|
+
"webhook_last_error": {
|
|
43781
|
+
"type": ["string", "null"],
|
|
43782
|
+
"description": "The email's own routed delivery only (where routing sent it); a rule's deliveries never change this, and are in `rule_deliveries` on GET /emails/{id} for the mailbox's owner. Its last error."
|
|
43235
43783
|
},
|
|
43236
|
-
"webhook_last_status_code": { "type": ["integer", "null"] },
|
|
43237
|
-
"webhook_last_error": { "type": ["string", "null"] },
|
|
43238
43784
|
"webhook_fired_at": {
|
|
43239
43785
|
"type": ["string", "null"],
|
|
43240
|
-
"format": "date-time"
|
|
43786
|
+
"format": "date-time",
|
|
43787
|
+
"description": "The email's own routed delivery only (where routing sent it); a rule's deliveries never change this, and are in `rule_deliveries` on GET /emails/{id} for the mailbox's owner. When it was delivered."
|
|
43241
43788
|
},
|
|
43242
43789
|
"smtp_helo": { "type": ["string", "null"] },
|
|
43243
43790
|
"smtp_mail_from": {
|
|
@@ -43531,6 +44078,81 @@ const openapiDocument = {
|
|
|
43531
44078
|
}
|
|
43532
44079
|
}
|
|
43533
44080
|
},
|
|
44081
|
+
"rule_deliveries": {
|
|
44082
|
+
"type": ["object", "null"],
|
|
44083
|
+
"description": "Where Email Rules delivered this email by webhook, for the owner of the mailbox it is at, on their own dashboard session or the Primitive CLI. Null for everyone else, and when it could not be read in time. A key reading it through a rule is not a delivery.",
|
|
44084
|
+
"required": [
|
|
44085
|
+
"rules",
|
|
44086
|
+
"hidden",
|
|
44087
|
+
"complete"
|
|
44088
|
+
],
|
|
44089
|
+
"properties": {
|
|
44090
|
+
"rules": {
|
|
44091
|
+
"type": "array",
|
|
44092
|
+
"description": "Each rule over your mail that queued a webhook delivery of this email, newest rule first.",
|
|
44093
|
+
"items": {
|
|
44094
|
+
"type": "object",
|
|
44095
|
+
"required": [
|
|
44096
|
+
"rule_id",
|
|
44097
|
+
"name",
|
|
44098
|
+
"delivered",
|
|
44099
|
+
"pending",
|
|
44100
|
+
"failed",
|
|
44101
|
+
"not_sent",
|
|
44102
|
+
"hosts",
|
|
44103
|
+
"hosts_not_listed"
|
|
44104
|
+
],
|
|
44105
|
+
"properties": {
|
|
44106
|
+
"rule_id": {
|
|
44107
|
+
"type": "string",
|
|
44108
|
+
"format": "uuid",
|
|
44109
|
+
"description": "The rule. A webhook sent it through several rules counts under one."
|
|
44110
|
+
},
|
|
44111
|
+
"name": { "type": "string" },
|
|
44112
|
+
"delivered": {
|
|
44113
|
+
"type": "integer",
|
|
44114
|
+
"minimum": 0,
|
|
44115
|
+
"description": "Webhooks it was delivered to."
|
|
44116
|
+
},
|
|
44117
|
+
"pending": {
|
|
44118
|
+
"type": "integer",
|
|
44119
|
+
"minimum": 0,
|
|
44120
|
+
"description": "Webhooks still owed it."
|
|
44121
|
+
},
|
|
44122
|
+
"failed": {
|
|
44123
|
+
"type": "integer",
|
|
44124
|
+
"minimum": 0,
|
|
44125
|
+
"description": "Webhooks whose attempts gave up."
|
|
44126
|
+
},
|
|
44127
|
+
"not_sent": {
|
|
44128
|
+
"type": "integer",
|
|
44129
|
+
"minimum": 0,
|
|
44130
|
+
"description": "Webhooks it was not sent to after all."
|
|
44131
|
+
},
|
|
44132
|
+
"hosts": {
|
|
44133
|
+
"type": "array",
|
|
44134
|
+
"items": { "type": "string" },
|
|
44135
|
+
"description": "The sites it was delivered to at the time, named as the covering view names sites; they may differ from the rule's current receivers there."
|
|
44136
|
+
},
|
|
44137
|
+
"hosts_not_listed": {
|
|
44138
|
+
"type": "integer",
|
|
44139
|
+
"minimum": 0,
|
|
44140
|
+
"description": "Sites past the listed ones."
|
|
44141
|
+
}
|
|
44142
|
+
}
|
|
44143
|
+
}
|
|
44144
|
+
},
|
|
44145
|
+
"hidden": {
|
|
44146
|
+
"type": "integer",
|
|
44147
|
+
"minimum": 0,
|
|
44148
|
+
"description": "Rules that queued a delivery of it that are not listed: they do not cover your mailboxes now, or are past the 50 one answer judges."
|
|
44149
|
+
},
|
|
44150
|
+
"complete": {
|
|
44151
|
+
"type": "boolean",
|
|
44152
|
+
"description": "False when a delivery may be missing: the email is older than 14 days, or it has more deliveries or rules than one answer reads."
|
|
44153
|
+
}
|
|
44154
|
+
}
|
|
44155
|
+
},
|
|
43534
44156
|
"from_name": {
|
|
43535
44157
|
"type": ["string", "null"],
|
|
43536
44158
|
"description": "Display name from the `From:` header, decoded for display: RFC 2047 encoded words are decoded in their declared charset and folded lines are joined (e.g. `Dana Rúiz` for `=?UTF-8?Q?Dana_R=C3=BAiz?= <dana@example.com>`). Null when the header carries no display name. For display only: identify the sender by `from_email`, never by this name, which the sender chooses freely."
|
|
@@ -44543,7 +45165,7 @@ const openapiDocument = {
|
|
|
44543
45165
|
"type": "object",
|
|
44544
45166
|
"additionalProperties": false,
|
|
44545
45167
|
"required": ["url"],
|
|
44546
|
-
"description": "One-click unsubscribe for the message. Primitive writes a `List-Unsubscribe` header naming `url` (and `mailto` when given) and, unless `one_click` is false, `List-Unsubscribe-Post: List-Unsubscribe=One-Click` (RFC 8058), and DKIM-signs both. A receiver that offers one-click unsubscribe sends an HTTPS POST to `url` with the form body `List-Unsubscribe=One-Click`; your endpoint records the unsubscribe. Every recipient of
|
|
45168
|
+
"description": "One-click unsubscribe for the message. Primitive writes a `List-Unsubscribe` header naming `url` (and `mailto` when given) and, unless `one_click` is false, `List-Unsubscribe-Post: List-Unsubscribe=One-Click` (RFC 8058), and DKIM-signs both. A receiver that offers one-click unsubscribe sends an HTTPS POST to `url` with the form body `List-Unsubscribe=One-Click`; your endpoint records the unsubscribe. Every recipient of a message would get the same `url`, so another recipient could unsubscribe whoever it identifies: a send with `unsubscribe` must have exactly one recipient, one entry across `to`, `cc` and `bcc` (an address given twice counts twice), and a send to more is refused with a `validation_error`. Send one message per recipient, for example with `POST /v1/send-mail/batch`. The `headers` map refuses both header names, so this field is the only way to set them, and the headers it adds count toward the 25 entries `headers` may hold. A field whose rendered `List-Unsubscribe` would pass 980 characters is refused. Not accepted on a repeating send.",
|
|
44547
45169
|
"properties": {
|
|
44548
45170
|
"url": {
|
|
44549
45171
|
"type": "string",
|
|
@@ -45615,7 +46237,7 @@ const openapiDocument = {
|
|
|
45615
46237
|
"type": "object",
|
|
45616
46238
|
"additionalProperties": false,
|
|
45617
46239
|
"required": ["url"],
|
|
45618
|
-
"description": "One-click unsubscribe for the message. Primitive writes a `List-Unsubscribe` header naming `url` (and `mailto` when given) and, unless `one_click` is false, `List-Unsubscribe-Post: List-Unsubscribe=One-Click` (RFC 8058), and DKIM-signs both. A receiver that offers one-click unsubscribe sends an HTTPS POST to `url` with the form body `List-Unsubscribe=One-Click`; your endpoint records the unsubscribe. Every recipient of
|
|
46240
|
+
"description": "One-click unsubscribe for the message. Primitive writes a `List-Unsubscribe` header naming `url` (and `mailto` when given) and, unless `one_click` is false, `List-Unsubscribe-Post: List-Unsubscribe=One-Click` (RFC 8058), and DKIM-signs both. A receiver that offers one-click unsubscribe sends an HTTPS POST to `url` with the form body `List-Unsubscribe=One-Click`; your endpoint records the unsubscribe. Every recipient of a message would get the same `url`, so another recipient could unsubscribe whoever it identifies: a reply with `unsubscribe` must go to the one address it answers, and one with `reply_all` that adds a cc is refused with a `validation_error`. The `headers` map refuses both header names, so this field is the only way to set them, and the headers it adds count toward the 25 entries `headers` may hold. A field whose rendered `List-Unsubscribe` would pass 980 characters is refused. Not accepted on a repeating send.",
|
|
45619
46241
|
"properties": {
|
|
45620
46242
|
"url": {
|
|
45621
46243
|
"type": "string",
|
|
@@ -50757,7 +51379,7 @@ const openapiDocument = {
|
|
|
50757
51379
|
},
|
|
50758
51380
|
"state": {
|
|
50759
51381
|
"type": "string",
|
|
50760
|
-
"description": "Where it stands now: enabled, disabled, deleted or replaced (endpoints and routes), enabled or disabled (filters, wake schedules), live, suspended or deleted (Functions), active, paused or ended (repeating sends), scheduled (scheduled sends), active, suspended, expired or revoked (API keys), pending, claimed, connected or revoked (agents), draft, observe or active (email rules), pending, accepted, declined or withdrawn (rule requests and objections), and for a coverage notice what it told: started (a rule was made or turned active over your mailboxes, or an active rule came to reach you; once per rule, not per mailbox), new_version, or baseline (it already covered you when notices began). pending: a rule started covering your mailbox and the notices have not recorded that start yet (a restart within an hour of the last start notice is recorded without a new one); its id is then the rule's, and created_at when the rule last changed."
|
|
51382
|
+
"description": "Where it stands now: enabled, disabled, deleted or replaced (endpoints and routes), enabled or disabled (filters, wake schedules), live, suspended or deleted (Functions), active, paused or ended (repeating sends), scheduled (scheduled sends), active, suspended, expired or revoked (API keys), pending, claimed, connected or revoked (agents), draft, observe or active (email rules), pending, accepted, declined or withdrawn (rule requests and objections), and for a coverage notice what it told: started (a rule was made or turned active over your mailboxes, or an active rule came to reach you; once per rule, not per mailbox), new_version, receivers_changed (who receives an active rule's matches changed: its keys, webhooks or share), or baseline (it already covered you when notices began). pending: a rule started covering your mailbox and the notices have not recorded that start yet (a restart within an hour of the last start notice is recorded without a new one); its id is then the rule's, and created_at when the rule last changed."
|
|
50761
51383
|
},
|
|
50762
51384
|
"created_at": {
|
|
50763
51385
|
"type": "string",
|
|
@@ -50766,7 +51388,7 @@ const openapiDocument = {
|
|
|
50766
51388
|
"ended_at": {
|
|
50767
51389
|
"type": ["string", "null"],
|
|
50768
51390
|
"format": "date-time",
|
|
50769
|
-
"description": "When it was deleted, replaced or revoked, when an API key expired, when a repeating send stopped, or when a rule request or objection was decided (accepted, declined or withdrawn); null otherwise, as on every coverage notice."
|
|
51391
|
+
"description": "When it was deleted, replaced or revoked, when an API key expired, when a repeating send stopped, or when a rule request or objection was decided (accepted, declined or withdrawn); null otherwise, as on every coverage notice (rule_now marks one whose rule was deleted)."
|
|
50770
51392
|
},
|
|
50771
51393
|
"owned_now": {
|
|
50772
51394
|
"type": "string",
|
|
@@ -50796,9 +51418,77 @@ const openapiDocument = {
|
|
|
50796
51418
|
]
|
|
50797
51419
|
},
|
|
50798
51420
|
"rule_id": {
|
|
50799
|
-
"description": "For email_rule_coverage, always: the rule it is about, since names need not be unique (for pending, the same as id). GET /v1/email-rules/covering-me/{rule_id} shows the rule while it covers you, or as it last decided on your mail; otherwise it answers not_found.",
|
|
51421
|
+
"description": "For email_rule_coverage, always: the rule it is about, since names need not be unique (for pending, the same as id). GET /v1/email-rules/covering-me/{rule_id} shows the rule while it covers you, or as it last decided on your mail; otherwise it answers not_found, with details.reason rule_deleted once a rule you were told of is deleted.",
|
|
50800
51422
|
"type": "string",
|
|
50801
51423
|
"format": "uuid"
|
|
51424
|
+
},
|
|
51425
|
+
"rule_now": {
|
|
51426
|
+
"description": "For email_rule_coverage: deleted once the rule it is about has been deleted. Left out while it exists, or when that could not be checked.",
|
|
51427
|
+
"type": "string",
|
|
51428
|
+
"enum": ["deleted"]
|
|
51429
|
+
},
|
|
51430
|
+
"receivers_change": {
|
|
51431
|
+
"description": "For a receivers_changed notice: who received the rule's matches before and after, in totals. They can be equal when only an owner or a webhook site changed; covering-me shows them by owner. A rotated key counts once here while the old one still works; covering-me counts both.",
|
|
51432
|
+
"type": "object",
|
|
51433
|
+
"properties": {
|
|
51434
|
+
"before": {
|
|
51435
|
+
"type": "object",
|
|
51436
|
+
"properties": {
|
|
51437
|
+
"keys": {
|
|
51438
|
+
"type": "integer",
|
|
51439
|
+
"minimum": 0
|
|
51440
|
+
},
|
|
51441
|
+
"reads_in_full": {
|
|
51442
|
+
"type": "integer",
|
|
51443
|
+
"minimum": 0,
|
|
51444
|
+
"description": "Of the keys, how many also read your own mail beyond the rule."
|
|
51445
|
+
},
|
|
51446
|
+
"webhooks": {
|
|
51447
|
+
"type": "integer",
|
|
51448
|
+
"minimum": 0
|
|
51449
|
+
},
|
|
51450
|
+
"shares": {
|
|
51451
|
+
"type": "integer",
|
|
51452
|
+
"minimum": 0
|
|
51453
|
+
}
|
|
51454
|
+
},
|
|
51455
|
+
"required": [
|
|
51456
|
+
"keys",
|
|
51457
|
+
"reads_in_full",
|
|
51458
|
+
"webhooks",
|
|
51459
|
+
"shares"
|
|
51460
|
+
]
|
|
51461
|
+
},
|
|
51462
|
+
"after": {
|
|
51463
|
+
"type": "object",
|
|
51464
|
+
"properties": {
|
|
51465
|
+
"keys": {
|
|
51466
|
+
"type": "integer",
|
|
51467
|
+
"minimum": 0
|
|
51468
|
+
},
|
|
51469
|
+
"reads_in_full": {
|
|
51470
|
+
"type": "integer",
|
|
51471
|
+
"minimum": 0,
|
|
51472
|
+
"description": "Of the keys, how many also read your own mail beyond the rule."
|
|
51473
|
+
},
|
|
51474
|
+
"webhooks": {
|
|
51475
|
+
"type": "integer",
|
|
51476
|
+
"minimum": 0
|
|
51477
|
+
},
|
|
51478
|
+
"shares": {
|
|
51479
|
+
"type": "integer",
|
|
51480
|
+
"minimum": 0
|
|
51481
|
+
}
|
|
51482
|
+
},
|
|
51483
|
+
"required": [
|
|
51484
|
+
"keys",
|
|
51485
|
+
"reads_in_full",
|
|
51486
|
+
"webhooks",
|
|
51487
|
+
"shares"
|
|
51488
|
+
]
|
|
51489
|
+
}
|
|
51490
|
+
},
|
|
51491
|
+
"required": ["before", "after"]
|
|
50802
51492
|
}
|
|
50803
51493
|
},
|
|
50804
51494
|
"required": [
|
|
@@ -50845,7 +51535,7 @@ const openapiDocument = {
|
|
|
50845
51535
|
"as_of": {
|
|
50846
51536
|
"type": ["string", "null"],
|
|
50847
51537
|
"format": "date-time",
|
|
50848
|
-
"description": "With relation=concerning only: about when the notices last looked at your organization; null if never or unread. Coverage since may have no notice yet."
|
|
51538
|
+
"description": "With relation=concerning only: about when the notices last looked at your organization; null if never or unread. Coverage since may have no notice yet. They look only while one of its rules could cover someone, so this stops moving while none could."
|
|
50849
51539
|
},
|
|
50850
51540
|
"pending_complete": {
|
|
50851
51541
|
"description": "With relation=concerning, on the first page only: whether the check for rules that started covering you without their start notice (state pending, listed ahead of the notices and beyond limit) was finished. false: some may be missing. Absent where there is nothing to check.",
|
|
@@ -51059,6 +51749,44 @@ const openapiDocument = {
|
|
|
51059
51749
|
},
|
|
51060
51750
|
"required": ["checked", "matched"]
|
|
51061
51751
|
},
|
|
51752
|
+
"EmailRuleScopeUsed": {
|
|
51753
|
+
"type": "object",
|
|
51754
|
+
"properties": {
|
|
51755
|
+
"evaluation_scope": {
|
|
51756
|
+
"type": "string",
|
|
51757
|
+
"enum": [
|
|
51758
|
+
"author",
|
|
51759
|
+
"own_mailboxes",
|
|
51760
|
+
"selected"
|
|
51761
|
+
],
|
|
51762
|
+
"description": "author, own_mailboxes or selected, as a rule's evaluation_scope."
|
|
51763
|
+
},
|
|
51764
|
+
"scope_selection": {
|
|
51765
|
+
"type": ["object", "null"],
|
|
51766
|
+
"properties": {
|
|
51767
|
+
"addresses": {
|
|
51768
|
+
"maxItems": 100,
|
|
51769
|
+
"type": "array",
|
|
51770
|
+
"items": {
|
|
51771
|
+
"type": "string",
|
|
51772
|
+
"maxLength": 320
|
|
51773
|
+
}
|
|
51774
|
+
},
|
|
51775
|
+
"domains": {
|
|
51776
|
+
"maxItems": 50,
|
|
51777
|
+
"type": "array",
|
|
51778
|
+
"items": {
|
|
51779
|
+
"type": "string",
|
|
51780
|
+
"maxLength": 253
|
|
51781
|
+
}
|
|
51782
|
+
}
|
|
51783
|
+
},
|
|
51784
|
+
"required": ["addresses", "domains"],
|
|
51785
|
+
"description": "What a selected scope names; null for any other."
|
|
51786
|
+
}
|
|
51787
|
+
},
|
|
51788
|
+
"required": ["evaluation_scope", "scope_selection"]
|
|
51789
|
+
},
|
|
51062
51790
|
"EmailRuleScopeSelection": {
|
|
51063
51791
|
"type": "object",
|
|
51064
51792
|
"properties": {
|
|
@@ -51153,6 +51881,10 @@ const openapiDocument = {
|
|
|
51153
51881
|
"description": "For a grant rule with questions, breadth counted on its conditions alone: the emails its questions are asked about. Null for any other rule, or when not counted in full (as breadth).",
|
|
51154
51882
|
"anyOf": [{ "$ref": "#/components/schemas/EmailRuleBreadth" }, { "type": "null" }]
|
|
51155
51883
|
},
|
|
51884
|
+
"breadth_scope": {
|
|
51885
|
+
"description": "The scope breadth and conditions_breadth are counted over: evaluation_scope as sent, by default own_mailboxes. Not the saved rule's scope, which a write sets with evaluation_scope; writes ignore this, as they ignore breadth.",
|
|
51886
|
+
"$ref": "#/components/schemas/EmailRuleScopeUsed"
|
|
51887
|
+
},
|
|
51156
51888
|
"sql": {
|
|
51157
51889
|
"description": "Present only when include_sql was true.",
|
|
51158
51890
|
"type": "object",
|
|
@@ -51438,7 +52170,7 @@ const openapiDocument = {
|
|
|
51438
52170
|
"type": "object",
|
|
51439
52171
|
"properties": {
|
|
51440
52172
|
"tree": {
|
|
51441
|
-
"description": "An unsaved rule tree, as POST /email-rules/compile returned it or written by hand. Give
|
|
52173
|
+
"description": "An unsaved rule tree, as POST /email-rules/compile returned it or written by hand. Give one of tree, rule_id and request_id.",
|
|
51442
52174
|
"$ref": "#/components/schemas/EmailRuleTreeInput"
|
|
51443
52175
|
},
|
|
51444
52176
|
"evaluation_scope": {
|
|
@@ -51456,8 +52188,13 @@ const openapiDocument = {
|
|
|
51456
52188
|
"type": "string",
|
|
51457
52189
|
"format": "uuid"
|
|
51458
52190
|
},
|
|
52191
|
+
"request_id": {
|
|
52192
|
+
"description": "A pending rule request you can see: its rule as asked, tested as you over your own mailboxes (what accepting would share, for the member asked). Give one of tree, rule_id and request_id.",
|
|
52193
|
+
"type": "string",
|
|
52194
|
+
"format": "uuid"
|
|
52195
|
+
},
|
|
51459
52196
|
"kind": {
|
|
51460
|
-
"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.",
|
|
52197
|
+
"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 or a request uses its own.",
|
|
51461
52198
|
"type": "string",
|
|
51462
52199
|
"enum": ["grant", "do_not_share"]
|
|
51463
52200
|
},
|
|
@@ -51526,6 +52263,20 @@ const openapiDocument = {
|
|
|
51526
52263
|
"type": "integer",
|
|
51527
52264
|
"minimum": 0,
|
|
51528
52265
|
"description": "The most emails the recent window holds: 200, less one place per expected email."
|
|
52266
|
+
},
|
|
52267
|
+
"scope": {
|
|
52268
|
+
"description": "The scope the test ran with: a saved rule's as stored, over its author's mail (GET /email-rules/{id}/scope: what it reaches now), or a tree's as sent, over yours (by default own_mailboxes). A rule covering you, tested as you: own_mailboxes, your mailboxes it covers.",
|
|
52269
|
+
"$ref": "#/components/schemas/EmailRuleScopeUsed"
|
|
52270
|
+
},
|
|
52271
|
+
"oldest_at": {
|
|
52272
|
+
"type": ["string", "null"],
|
|
52273
|
+
"format": "date-time",
|
|
52274
|
+
"description": "When the oldest email tested arrived, expected ones included; null when none was. The window is the newest 200 the scope reaches, so a narrower scope reaches further back: compare counts only over the same scope and span."
|
|
52275
|
+
},
|
|
52276
|
+
"newest_at": {
|
|
52277
|
+
"type": ["string", "null"],
|
|
52278
|
+
"format": "date-time",
|
|
52279
|
+
"description": "When the newest email tested arrived; null when none was."
|
|
51529
52280
|
}
|
|
51530
52281
|
},
|
|
51531
52282
|
"required": [
|
|
@@ -52055,7 +52806,7 @@ const openapiDocument = {
|
|
|
52055
52806
|
"type": "object",
|
|
52056
52807
|
"properties": {
|
|
52057
52808
|
"tree": {
|
|
52058
|
-
"description": "An unsaved rule tree, as POST /email-rules/compile returned it or written by hand. Give
|
|
52809
|
+
"description": "An unsaved rule tree, as POST /email-rules/compile returned it or written by hand. Give one of tree, rule_id and request_id.",
|
|
52059
52810
|
"$ref": "#/components/schemas/EmailRuleTreeInput"
|
|
52060
52811
|
},
|
|
52061
52812
|
"english": {
|
|
@@ -52085,7 +52836,7 @@ const openapiDocument = {
|
|
|
52085
52836
|
"format": "uuid"
|
|
52086
52837
|
},
|
|
52087
52838
|
"kind": {
|
|
52088
|
-
"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.",
|
|
52839
|
+
"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 or a request uses its own.",
|
|
52089
52840
|
"type": "string",
|
|
52090
52841
|
"enum": ["grant", "do_not_share"]
|
|
52091
52842
|
},
|
|
@@ -52173,7 +52924,7 @@ const openapiDocument = {
|
|
|
52173
52924
|
"type": "object",
|
|
52174
52925
|
"properties": {
|
|
52175
52926
|
"tree": {
|
|
52176
|
-
"description": "An unsaved rule tree, as POST /email-rules/compile returned it or written by hand. Give
|
|
52927
|
+
"description": "An unsaved rule tree, as POST /email-rules/compile returned it or written by hand. Give one of tree, rule_id and request_id.",
|
|
52177
52928
|
"$ref": "#/components/schemas/EmailRuleTreeInput"
|
|
52178
52929
|
},
|
|
52179
52930
|
"evaluation_scope": {
|
|
@@ -52191,8 +52942,13 @@ const openapiDocument = {
|
|
|
52191
52942
|
"type": "string",
|
|
52192
52943
|
"format": "uuid"
|
|
52193
52944
|
},
|
|
52945
|
+
"request_id": {
|
|
52946
|
+
"description": "A pending rule request you can see: its rule as asked, tested as you over your own mailboxes (what accepting would share, for the member asked). Give one of tree, rule_id and request_id.",
|
|
52947
|
+
"type": "string",
|
|
52948
|
+
"format": "uuid"
|
|
52949
|
+
},
|
|
52194
52950
|
"kind": {
|
|
52195
|
-
"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.",
|
|
52951
|
+
"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 or a request uses its own.",
|
|
52196
52952
|
"type": "string",
|
|
52197
52953
|
"enum": ["grant", "do_not_share"]
|
|
52198
52954
|
},
|
|
@@ -52291,6 +53047,10 @@ const openapiDocument = {
|
|
|
52291
53047
|
],
|
|
52292
53048
|
"additionalProperties": false,
|
|
52293
53049
|
"description": "A made-up received email. Nothing about it is stored."
|
|
53050
|
+
},
|
|
53051
|
+
"with_protection": {
|
|
53052
|
+
"description": "With true, a grant rule that matches is also judged against the active do-not-share rules over the first recipient's mailbox, which you must read in full and the rule must run over; see protection. Limited to 20 an hour per member.",
|
|
53053
|
+
"type": "boolean"
|
|
52294
53054
|
}
|
|
52295
53055
|
},
|
|
52296
53056
|
"required": ["email"],
|
|
@@ -52420,6 +53180,59 @@ const openapiDocument = {
|
|
|
52420
53180
|
"required": ["value", "confidence"]
|
|
52421
53181
|
},
|
|
52422
53182
|
"description": "What the classifier read from the email, by fact: its value and confidence."
|
|
53183
|
+
},
|
|
53184
|
+
"protection": {
|
|
53185
|
+
"description": "With with_protection: whether a match would be shared. Nothing is stored.",
|
|
53186
|
+
"type": "object",
|
|
53187
|
+
"properties": {
|
|
53188
|
+
"mailbox": {
|
|
53189
|
+
"type": "string",
|
|
53190
|
+
"description": "The mailbox judged: the first recipient."
|
|
53191
|
+
},
|
|
53192
|
+
"outcome": {
|
|
53193
|
+
"type": "string",
|
|
53194
|
+
"enum": [
|
|
53195
|
+
"shared",
|
|
53196
|
+
"withheld",
|
|
53197
|
+
"not_matched"
|
|
53198
|
+
],
|
|
53199
|
+
"description": "not_matched: the rule did not match, so nothing would be shared and no do-not-share rule was judged."
|
|
53200
|
+
},
|
|
53201
|
+
"withheld_by": {
|
|
53202
|
+
"type": "array",
|
|
53203
|
+
"items": {
|
|
53204
|
+
"type": "object",
|
|
53205
|
+
"properties": {
|
|
53206
|
+
"id": {
|
|
53207
|
+
"type": "string",
|
|
53208
|
+
"format": "uuid"
|
|
53209
|
+
},
|
|
53210
|
+
"name": { "type": "string" },
|
|
53211
|
+
"reason": {
|
|
53212
|
+
"type": "string",
|
|
53213
|
+
"enum": ["matched", "undecided"]
|
|
53214
|
+
}
|
|
53215
|
+
},
|
|
53216
|
+
"required": [
|
|
53217
|
+
"id",
|
|
53218
|
+
"name",
|
|
53219
|
+
"reason"
|
|
53220
|
+
]
|
|
53221
|
+
},
|
|
53222
|
+
"description": "Do-not-share rules you can see that would keep it from being shared. undecided: left undecided as real mail would leave it, or not reached by this test (past 50 rules, 10 rules' questions, or the time limit); it is held back either way."
|
|
53223
|
+
},
|
|
53224
|
+
"withheld_by_hidden": {
|
|
53225
|
+
"type": "integer",
|
|
53226
|
+
"minimum": 0,
|
|
53227
|
+
"description": "Rules you cannot see that would."
|
|
53228
|
+
}
|
|
53229
|
+
},
|
|
53230
|
+
"required": [
|
|
53231
|
+
"mailbox",
|
|
53232
|
+
"outcome",
|
|
53233
|
+
"withheld_by",
|
|
53234
|
+
"withheld_by_hidden"
|
|
53235
|
+
]
|
|
52423
53236
|
}
|
|
52424
53237
|
},
|
|
52425
53238
|
"required": [
|
|
@@ -52497,7 +53310,7 @@ const openapiDocument = {
|
|
|
52497
53310
|
"minimum": 0
|
|
52498
53311
|
},
|
|
52499
53312
|
"objection_notice": {
|
|
52500
|
-
"description": "With pending_objections above 0: that members
|
|
53313
|
+
"description": "With pending_objections above 0: that members objected (each message says what they ask: to turn it off, narrow it or explain it), and how to answer.",
|
|
52501
53314
|
"type": "string"
|
|
52502
53315
|
},
|
|
52503
53316
|
"created_at": {
|
|
@@ -52517,6 +53330,10 @@ const openapiDocument = {
|
|
|
52517
53330
|
"type": "array",
|
|
52518
53331
|
"items": { "$ref": "#/components/schemas/EmailRuleScopeWarning" }
|
|
52519
53332
|
},
|
|
53333
|
+
"do_not_share_note": {
|
|
53334
|
+
"description": "On a grant rule's create answer: that active do-not-share rules reaching an email run first: one that matches it keeps it from being shared through this rule, and one that cannot decide it holds it back while it is decided again for up to a day; it is shared through this rule only if none of them then matches it.",
|
|
53335
|
+
"type": "string"
|
|
53336
|
+
},
|
|
52520
53337
|
"expectations": {
|
|
52521
53338
|
"description": "Its saved expectations, each list by email id, as stored: on every create, and on an update that set or removed them.",
|
|
52522
53339
|
"type": "object",
|
|
@@ -52887,6 +53704,10 @@ const openapiDocument = {
|
|
|
52887
53704
|
"conditions_breadth": {
|
|
52888
53705
|
"description": "Ignored.",
|
|
52889
53706
|
"anyOf": [{ "$ref": "#/components/schemas/EmailRuleBreadth" }, { "type": "null" }]
|
|
53707
|
+
},
|
|
53708
|
+
"breadth_scope": {
|
|
53709
|
+
"description": "Ignored (the compile answer's breadth_scope): set a rule's scope with evaluation_scope.",
|
|
53710
|
+
"$ref": "#/components/schemas/EmailRuleScopeUsed"
|
|
52890
53711
|
}
|
|
52891
53712
|
},
|
|
52892
53713
|
"required": [
|
|
@@ -52962,7 +53783,7 @@ const openapiDocument = {
|
|
|
52962
53783
|
"minimum": 0
|
|
52963
53784
|
},
|
|
52964
53785
|
"objection_notice": {
|
|
52965
|
-
"description": "With pending_objections above 0: that members
|
|
53786
|
+
"description": "With pending_objections above 0: that members objected (each message says what they ask: to turn it off, narrow it or explain it), and how to answer.",
|
|
52966
53787
|
"type": "string"
|
|
52967
53788
|
},
|
|
52968
53789
|
"created_at": {
|
|
@@ -53069,7 +53890,7 @@ const openapiDocument = {
|
|
|
53069
53890
|
"minimum": 0
|
|
53070
53891
|
},
|
|
53071
53892
|
"objection_notice": {
|
|
53072
|
-
"description": "With pending_objections above 0: that members
|
|
53893
|
+
"description": "With pending_objections above 0: that members objected (each message says what they ask: to turn it off, narrow it or explain it), and how to answer.",
|
|
53073
53894
|
"type": "string"
|
|
53074
53895
|
},
|
|
53075
53896
|
"created_at": {
|
|
@@ -53192,6 +54013,10 @@ const openapiDocument = {
|
|
|
53192
54013
|
"description": "Ignored.",
|
|
53193
54014
|
"anyOf": [{ "$ref": "#/components/schemas/EmailRuleBreadth" }, { "type": "null" }]
|
|
53194
54015
|
},
|
|
54016
|
+
"breadth_scope": {
|
|
54017
|
+
"description": "Ignored (the compile answer's breadth_scope): set a rule's scope with evaluation_scope.",
|
|
54018
|
+
"$ref": "#/components/schemas/EmailRuleScopeUsed"
|
|
54019
|
+
},
|
|
53195
54020
|
"kind": {
|
|
53196
54021
|
"description": "Must be the rule's own (400 kind_mismatch).",
|
|
53197
54022
|
"type": "string",
|
|
@@ -53486,6 +54311,11 @@ const openapiDocument = {
|
|
|
53486
54311
|
"description": "On a rule over your mail: how many of these keys also list one of your own mailboxes, or its domain, so they read your mail there beyond what this rule matches.",
|
|
53487
54312
|
"type": "integer",
|
|
53488
54313
|
"minimum": 0
|
|
54314
|
+
},
|
|
54315
|
+
"newest_at": {
|
|
54316
|
+
"description": "When the newest of these was made, to the minute: a key, a webhook or the share, or the rule (the share, for what reaches it only through the share) if that was later. Not when a key was given access to this rule, or anything turned back on; a rotated key shows as newly made, and one key on two rules can show the same minute under both.",
|
|
54317
|
+
"type": "string",
|
|
54318
|
+
"format": "date-time"
|
|
53489
54319
|
}
|
|
53490
54320
|
},
|
|
53491
54321
|
"required": ["owner", "count"]
|
|
@@ -53541,6 +54371,11 @@ const openapiDocument = {
|
|
|
53541
54371
|
"description": "Hosts past those listed.",
|
|
53542
54372
|
"type": "integer",
|
|
53543
54373
|
"minimum": 0
|
|
54374
|
+
},
|
|
54375
|
+
"newest_at": {
|
|
54376
|
+
"description": "When the newest of these was made, to the minute: a key, a webhook or the share, or the rule (the share, for what reaches it only through the share) if that was later. Not when a key was given access to this rule, or anything turned back on; a rotated key shows as newly made, and one key on two rules can show the same minute under both.",
|
|
54377
|
+
"type": "string",
|
|
54378
|
+
"format": "date-time"
|
|
53544
54379
|
}
|
|
53545
54380
|
},
|
|
53546
54381
|
"required": ["owner", "count"]
|
|
@@ -53578,6 +54413,11 @@ const openapiDocument = {
|
|
|
53578
54413
|
"count": {
|
|
53579
54414
|
"type": "integer",
|
|
53580
54415
|
"exclusiveMinimum": 0
|
|
54416
|
+
},
|
|
54417
|
+
"newest_at": {
|
|
54418
|
+
"description": "When the newest of these was made, to the minute: a key, a webhook or the share, or the rule (the share, for what reaches it only through the share) if that was later. Not when a key was given access to this rule, or anything turned back on; a rotated key shows as newly made, and one key on two rules can show the same minute under both.",
|
|
54419
|
+
"type": "string",
|
|
54420
|
+
"format": "date-time"
|
|
53581
54421
|
}
|
|
53582
54422
|
},
|
|
53583
54423
|
"required": ["beneficiary", "count"]
|
|
@@ -53741,9 +54581,10 @@ const openapiDocument = {
|
|
|
53741
54581
|
"enum": [
|
|
53742
54582
|
"draft",
|
|
53743
54583
|
"created_after_email",
|
|
54584
|
+
"outside_scope",
|
|
53744
54585
|
null
|
|
53745
54586
|
],
|
|
53746
|
-
"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."
|
|
54587
|
+
"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. outside_scope: the mailbox this email is in is outside what its scope names (its author's own mailboxes, its selection, or all its author reads now), so it does not decide on it. Null when it has a result, or when nothing is known (it may not have decided yet)."
|
|
53747
54588
|
},
|
|
53748
54589
|
"author_left": {
|
|
53749
54590
|
"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.",
|
|
@@ -54075,6 +54916,10 @@ const openapiDocument = {
|
|
|
54075
54916
|
"description": "Ignored.",
|
|
54076
54917
|
"anyOf": [{ "$ref": "#/components/schemas/EmailRuleBreadth" }, { "type": "null" }]
|
|
54077
54918
|
},
|
|
54919
|
+
"breadth_scope": {
|
|
54920
|
+
"description": "Ignored (the compile answer's breadth_scope): set a rule's scope with evaluation_scope.",
|
|
54921
|
+
"$ref": "#/components/schemas/EmailRuleScopeUsed"
|
|
54922
|
+
},
|
|
54078
54923
|
"kind": {
|
|
54079
54924
|
"description": "Only grant.",
|
|
54080
54925
|
"type": "string",
|
|
@@ -54171,7 +55016,7 @@ const openapiDocument = {
|
|
|
54171
55016
|
"type": ["boolean", "null"]
|
|
54172
55017
|
},
|
|
54173
55018
|
"notice": {
|
|
54174
|
-
"description": "For the member asked, while pending: what the rule actually does (server_explanation), Primitive's warnings,
|
|
55019
|
+
"description": "For the member asked, while pending: what the rule actually does (server_explanation), Primitive's warnings, what accepting would share, then where to see what becomes of one email (rule-results). For the member who asked, once accepted with changes: that the request is not what is shared. Else null.",
|
|
54175
55020
|
"type": ["string", "null"]
|
|
54176
55021
|
},
|
|
54177
55022
|
"target_can_accept": {
|
|
@@ -54181,6 +55026,11 @@ const openapiDocument = {
|
|
|
54181
55026
|
"target_warning": {
|
|
54182
55027
|
"description": "Why the member asked cannot accept it yet, naming the permission their role lacks. The request is still sent. Null when they can, or when target_can_accept is null.",
|
|
54183
55028
|
"type": ["string", "null"]
|
|
55029
|
+
},
|
|
55030
|
+
"existing": {
|
|
55031
|
+
"description": "Present, as true, when the create carried an Idempotency-Key and you already had a pending request to this member asking exactly this (name, english, tree, explanation and message, naming the member the same way): that request is returned (200), and no second one is made or sent.",
|
|
55032
|
+
"type": "boolean",
|
|
55033
|
+
"const": true
|
|
54184
55034
|
}
|
|
54185
55035
|
},
|
|
54186
55036
|
"required": [
|
|
@@ -54346,7 +55196,7 @@ const openapiDocument = {
|
|
|
54346
55196
|
"type": ["boolean", "null"]
|
|
54347
55197
|
},
|
|
54348
55198
|
"notice": {
|
|
54349
|
-
"description": "For the member asked, while pending: what the rule actually does (server_explanation), Primitive's warnings,
|
|
55199
|
+
"description": "For the member asked, while pending: what the rule actually does (server_explanation), Primitive's warnings, what accepting would share, then where to see what becomes of one email (rule-results). For the member who asked, once accepted with changes: that the request is not what is shared. Else null.",
|
|
54350
55200
|
"type": ["string", "null"]
|
|
54351
55201
|
}
|
|
54352
55202
|
},
|
|
@@ -54460,7 +55310,7 @@ const openapiDocument = {
|
|
|
54460
55310
|
"minimum": 0
|
|
54461
55311
|
},
|
|
54462
55312
|
"objection_notice": {
|
|
54463
|
-
"description": "With pending_objections above 0: that members
|
|
55313
|
+
"description": "With pending_objections above 0: that members objected (each message says what they ask: to turn it off, narrow it or explain it), and how to answer.",
|
|
54464
55314
|
"type": "string"
|
|
54465
55315
|
},
|
|
54466
55316
|
"created_at": {
|
|
@@ -54706,6 +55556,10 @@ const openapiDocument = {
|
|
|
54706
55556
|
"description": "Ignored.",
|
|
54707
55557
|
"anyOf": [{ "$ref": "#/components/schemas/EmailRuleBreadth" }, { "type": "null" }]
|
|
54708
55558
|
},
|
|
55559
|
+
"breadth_scope": {
|
|
55560
|
+
"description": "Ignored (the compile answer's breadth_scope): set a rule's scope with evaluation_scope.",
|
|
55561
|
+
"$ref": "#/components/schemas/EmailRuleScopeUsed"
|
|
55562
|
+
},
|
|
54709
55563
|
"kind": {
|
|
54710
55564
|
"description": "Only grant.",
|
|
54711
55565
|
"type": "string",
|
|
@@ -54728,7 +55582,7 @@ const openapiDocument = {
|
|
|
54728
55582
|
"rule": { "$ref": "#/components/schemas/EmailRuleWithVersion" },
|
|
54729
55583
|
"share": { "$ref": "#/components/schemas/EmailRuleShare" },
|
|
54730
55584
|
"notice": {
|
|
54731
|
-
"description": "What is now shared, in words. When you changed the rule and it can now match mail the request left out by who it was sent to (such as mail where an address is only copied), that comes first.",
|
|
55585
|
+
"description": "What is now shared, in words. When you changed the rule and it can now match mail the request left out by who it was sent to (such as mail where an address is only copied), that comes first; when you changed its english, tree or explanation (edited_on_accept; a new name alone is no change), that rule.current is what you agreed to and request what was asked.",
|
|
54732
55586
|
"type": "string"
|
|
54733
55587
|
}
|
|
54734
55588
|
},
|
|
@@ -55079,6 +55933,10 @@ const openapiDocument = {
|
|
|
55079
55933
|
"enum": ["grant", "do_not_share"],
|
|
55080
55934
|
"description": "grant: what it matches can be shared. do_not_share: it blocks sharing what it matches."
|
|
55081
55935
|
},
|
|
55936
|
+
"do_not_share_note": {
|
|
55937
|
+
"description": "On a grant rule: that the active do-not-share rules over an email run first, keeping from it what they match and holding back what they cannot decide, which is decided again for up to a day and shared only if none of them then matches it.",
|
|
55938
|
+
"type": "string"
|
|
55939
|
+
},
|
|
55082
55940
|
"author": {
|
|
55083
55941
|
"description": "Who wrote it.",
|
|
55084
55942
|
"$ref": "#/components/schemas/EmailRuleCoveringAuthor"
|
|
@@ -55168,6 +56026,10 @@ const openapiDocument = {
|
|
|
55168
56026
|
"enum": ["grant", "do_not_share"],
|
|
55169
56027
|
"description": "grant: what it matches can be shared. do_not_share: it blocks sharing what it matches."
|
|
55170
56028
|
},
|
|
56029
|
+
"do_not_share_note": {
|
|
56030
|
+
"description": "On a grant rule: that the active do-not-share rules over an email run first, keeping from it what they match and holding back what they cannot decide, which is decided again for up to a day and shared only if none of them then matches it.",
|
|
56031
|
+
"type": "string"
|
|
56032
|
+
},
|
|
55171
56033
|
"author": {
|
|
55172
56034
|
"description": "Who wrote it.",
|
|
55173
56035
|
"$ref": "#/components/schemas/EmailRuleCoveringAuthor"
|
|
@@ -55391,10 +56253,13 @@ const openapiDocument = {
|
|
|
55391
56253
|
"description": "Whether it is to a rule you wrote, in your current membership."
|
|
55392
56254
|
},
|
|
55393
56255
|
"message": {
|
|
55394
|
-
"description": "Why the
|
|
56256
|
+
"description": "Why they object and what they ask (to turn the rule off, narrow it, or explain who receives it); null when none was given, or once withdrawn.",
|
|
56257
|
+
"type": ["string", "null"]
|
|
56258
|
+
},
|
|
56259
|
+
"decline_reason": {
|
|
56260
|
+
"description": "The author's answer when declining, which the objector sees; null when none was given.",
|
|
55395
56261
|
"type": ["string", "null"]
|
|
55396
56262
|
},
|
|
55397
|
-
"decline_reason": { "type": ["string", "null"] },
|
|
55398
56263
|
"created_at": {
|
|
55399
56264
|
"type": "string",
|
|
55400
56265
|
"format": "date-time"
|
|
@@ -55454,7 +56319,7 @@ const openapiDocument = {
|
|
|
55454
56319
|
"type": ["string", "null"],
|
|
55455
56320
|
"minLength": 1,
|
|
55456
56321
|
"maxLength": 500,
|
|
55457
|
-
"description": "Why you object, up to 500 characters
|
|
56322
|
+
"description": "Why you object and what you ask, up to 500 characters: to turn the rule off, to narrow it, or to explain who receives what it matches. Null or absent for none. The rule's author and the organization's owners and admins see it while it stands; withdrawing clears it."
|
|
55458
56323
|
}
|
|
55459
56324
|
},
|
|
55460
56325
|
"required": ["rule_id"],
|
|
@@ -55473,7 +56338,7 @@ const openapiDocument = {
|
|
|
55473
56338
|
"type": ["string", "null"],
|
|
55474
56339
|
"minLength": 1,
|
|
55475
56340
|
"maxLength": 500,
|
|
55476
|
-
"description": "Why you are declining, up to 500 characters; null or absent for none. The member who objected sees it."
|
|
56341
|
+
"description": "Why you are declining, up to 500 characters; null or absent for none. The member who objected sees it: it is how to answer one that asks you to narrow the rule or explain who receives it."
|
|
55477
56342
|
} },
|
|
55478
56343
|
"additionalProperties": false
|
|
55479
56344
|
},
|
|
@@ -59904,6 +60769,14 @@ const openapiDocument = {
|
|
|
59904
60769
|
"additionalProperties": {}
|
|
59905
60770
|
}
|
|
59906
60771
|
},
|
|
60772
|
+
"mail_limits_available": {
|
|
60773
|
+
"description": "Whether a key limited to some mail (addresses, domains or email rules) would be created now. While false, creating one is refused, so a client offers neither the listed-address presets nor a listed mail reach for a custom key.",
|
|
60774
|
+
"type": "boolean"
|
|
60775
|
+
},
|
|
60776
|
+
"org_reach_available": {
|
|
60777
|
+
"description": "Whether the credential policy lets a new key reach every mailbox. While false, creating one is refused, so a client offers no preset that reaches every mailbox, and a custom key lists its addresses or domains. With mail_limits_available false as well, no key can be created and every preset is unavailable.",
|
|
60778
|
+
"type": "boolean"
|
|
60779
|
+
},
|
|
59907
60780
|
"matrix": {
|
|
59908
60781
|
"type": "array",
|
|
59909
60782
|
"items": {
|
|
@@ -60208,6 +61081,36 @@ const openapiDocument = {
|
|
|
60208
61081
|
"pattern": "^(?:(?:\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-(?:(?:0[13578]|1[02])-(?:0[1-9]|[12]\\d|3[01])|(?:0[469]|11)-(?:0[1-9]|[12]\\d|30)|(?:02)-(?:0[1-9]|1\\d|2[0-8])))T(?:(?:[01]\\d|2[0-3]):[0-5]\\d(?::[0-5]\\d(?:\\.\\d+)?)?(?:Z|([+-](?:[01]\\d|2[0-3]):[0-5]\\d)))$"
|
|
60209
61082
|
},
|
|
60210
61083
|
"previous_key_id": { "type": "string" },
|
|
61084
|
+
"name": {
|
|
61085
|
+
"description": "The successor's name: the rotated key's, which it keeps.",
|
|
61086
|
+
"type": ["string", "null"]
|
|
61087
|
+
},
|
|
61088
|
+
"grant": {
|
|
61089
|
+
"description": "The grant the successor holds, as a create answers it: the rotated key's own, carried over unchanged (rules, addresses and domains included).",
|
|
61090
|
+
"type": "object",
|
|
61091
|
+
"properties": {
|
|
61092
|
+
"template": { "type": ["string", "null"] },
|
|
61093
|
+
"credential_grant_id": { "type": ["string", "null"] },
|
|
61094
|
+
"permissions": {
|
|
61095
|
+
"type": ["array", "null"],
|
|
61096
|
+
"items": { "type": "string" }
|
|
61097
|
+
},
|
|
61098
|
+
"mail_scope": {},
|
|
61099
|
+
"resources": {}
|
|
61100
|
+
},
|
|
61101
|
+
"required": [
|
|
61102
|
+
"template",
|
|
61103
|
+
"credential_grant_id",
|
|
61104
|
+
"permissions",
|
|
61105
|
+
"mail_scope",
|
|
61106
|
+
"resources"
|
|
61107
|
+
],
|
|
61108
|
+
"additionalProperties": {}
|
|
61109
|
+
},
|
|
61110
|
+
"rotated_from": {
|
|
61111
|
+
"description": "The rotated key: previous_key_id, under the name GET /v1/keys/{id} gives it.",
|
|
61112
|
+
"type": "string"
|
|
61113
|
+
},
|
|
60211
61114
|
"previous_key_expires_at": {
|
|
60212
61115
|
"type": "string",
|
|
60213
61116
|
"format": "date-time",
|
|
@@ -61178,6 +62081,304 @@ const openapiDocument = {
|
|
|
61178
62081
|
"required": ["semantic_search_opt_in"],
|
|
61179
62082
|
"additionalProperties": false
|
|
61180
62083
|
},
|
|
62084
|
+
"EmailNotifications_getEmailNotificationSettings_Result": {
|
|
62085
|
+
"type": "object",
|
|
62086
|
+
"properties": {
|
|
62087
|
+
"entitled": { "type": "boolean" },
|
|
62088
|
+
"kinds": {
|
|
62089
|
+
"type": "array",
|
|
62090
|
+
"items": {
|
|
62091
|
+
"type": "object",
|
|
62092
|
+
"properties": {
|
|
62093
|
+
"kind": { "type": "string" },
|
|
62094
|
+
"label": { "type": "string" },
|
|
62095
|
+
"description": { "type": "string" },
|
|
62096
|
+
"class": {
|
|
62097
|
+
"type": "string",
|
|
62098
|
+
"enum": [
|
|
62099
|
+
"platform_required",
|
|
62100
|
+
"org_requirable",
|
|
62101
|
+
"optional"
|
|
62102
|
+
]
|
|
62103
|
+
},
|
|
62104
|
+
"entitlement_required": { "type": "boolean" },
|
|
62105
|
+
"entitled": { "type": "boolean" },
|
|
62106
|
+
"org_mode": {
|
|
62107
|
+
"type": ["string", "null"],
|
|
62108
|
+
"enum": [
|
|
62109
|
+
"off",
|
|
62110
|
+
"optional_on",
|
|
62111
|
+
"optional_off",
|
|
62112
|
+
"required",
|
|
62113
|
+
null
|
|
62114
|
+
]
|
|
62115
|
+
},
|
|
62116
|
+
"org_mode_is_default": { "type": "boolean" },
|
|
62117
|
+
"org_modes": {
|
|
62118
|
+
"type": "array",
|
|
62119
|
+
"items": {
|
|
62120
|
+
"type": "string",
|
|
62121
|
+
"enum": [
|
|
62122
|
+
"off",
|
|
62123
|
+
"optional_on",
|
|
62124
|
+
"optional_off",
|
|
62125
|
+
"required"
|
|
62126
|
+
]
|
|
62127
|
+
}
|
|
62128
|
+
},
|
|
62129
|
+
"member_enabled": { "type": "boolean" },
|
|
62130
|
+
"member_can_change": { "type": "boolean" }
|
|
62131
|
+
},
|
|
62132
|
+
"required": [
|
|
62133
|
+
"kind",
|
|
62134
|
+
"label",
|
|
62135
|
+
"description",
|
|
62136
|
+
"class",
|
|
62137
|
+
"entitlement_required",
|
|
62138
|
+
"entitled",
|
|
62139
|
+
"org_mode",
|
|
62140
|
+
"org_mode_is_default",
|
|
62141
|
+
"org_modes",
|
|
62142
|
+
"member_enabled",
|
|
62143
|
+
"member_can_change"
|
|
62144
|
+
]
|
|
62145
|
+
}
|
|
62146
|
+
}
|
|
62147
|
+
},
|
|
62148
|
+
"required": ["entitled", "kinds"]
|
|
62149
|
+
},
|
|
62150
|
+
"EmailNotifications_updateEmailNotificationSettings_Result": {
|
|
62151
|
+
"type": "object",
|
|
62152
|
+
"properties": {
|
|
62153
|
+
"entitled": { "type": "boolean" },
|
|
62154
|
+
"kinds": {
|
|
62155
|
+
"type": "array",
|
|
62156
|
+
"items": {
|
|
62157
|
+
"type": "object",
|
|
62158
|
+
"properties": {
|
|
62159
|
+
"kind": { "type": "string" },
|
|
62160
|
+
"label": { "type": "string" },
|
|
62161
|
+
"description": { "type": "string" },
|
|
62162
|
+
"class": {
|
|
62163
|
+
"type": "string",
|
|
62164
|
+
"enum": [
|
|
62165
|
+
"platform_required",
|
|
62166
|
+
"org_requirable",
|
|
62167
|
+
"optional"
|
|
62168
|
+
]
|
|
62169
|
+
},
|
|
62170
|
+
"entitlement_required": { "type": "boolean" },
|
|
62171
|
+
"entitled": { "type": "boolean" },
|
|
62172
|
+
"org_mode": {
|
|
62173
|
+
"type": ["string", "null"],
|
|
62174
|
+
"enum": [
|
|
62175
|
+
"off",
|
|
62176
|
+
"optional_on",
|
|
62177
|
+
"optional_off",
|
|
62178
|
+
"required",
|
|
62179
|
+
null
|
|
62180
|
+
]
|
|
62181
|
+
},
|
|
62182
|
+
"org_mode_is_default": { "type": "boolean" },
|
|
62183
|
+
"org_modes": {
|
|
62184
|
+
"type": "array",
|
|
62185
|
+
"items": {
|
|
62186
|
+
"type": "string",
|
|
62187
|
+
"enum": [
|
|
62188
|
+
"off",
|
|
62189
|
+
"optional_on",
|
|
62190
|
+
"optional_off",
|
|
62191
|
+
"required"
|
|
62192
|
+
]
|
|
62193
|
+
}
|
|
62194
|
+
},
|
|
62195
|
+
"member_enabled": { "type": "boolean" },
|
|
62196
|
+
"member_can_change": { "type": "boolean" }
|
|
62197
|
+
},
|
|
62198
|
+
"required": [
|
|
62199
|
+
"kind",
|
|
62200
|
+
"label",
|
|
62201
|
+
"description",
|
|
62202
|
+
"class",
|
|
62203
|
+
"entitlement_required",
|
|
62204
|
+
"entitled",
|
|
62205
|
+
"org_mode",
|
|
62206
|
+
"org_mode_is_default",
|
|
62207
|
+
"org_modes",
|
|
62208
|
+
"member_enabled",
|
|
62209
|
+
"member_can_change"
|
|
62210
|
+
]
|
|
62211
|
+
}
|
|
62212
|
+
}
|
|
62213
|
+
},
|
|
62214
|
+
"required": ["entitled", "kinds"]
|
|
62215
|
+
},
|
|
62216
|
+
"EmailNotifications_updateEmailNotificationSettings_Input": {
|
|
62217
|
+
"type": "object",
|
|
62218
|
+
"properties": { "modes": {
|
|
62219
|
+
"type": "object",
|
|
62220
|
+
"propertyNames": {
|
|
62221
|
+
"type": "string",
|
|
62222
|
+
"pattern": "^[a-z][a-z0-9_]{0,63}$"
|
|
62223
|
+
},
|
|
62224
|
+
"additionalProperties": {
|
|
62225
|
+
"type": "string",
|
|
62226
|
+
"enum": [
|
|
62227
|
+
"off",
|
|
62228
|
+
"optional_on",
|
|
62229
|
+
"optional_off",
|
|
62230
|
+
"required"
|
|
62231
|
+
]
|
|
62232
|
+
}
|
|
62233
|
+
} },
|
|
62234
|
+
"required": ["modes"],
|
|
62235
|
+
"additionalProperties": false
|
|
62236
|
+
},
|
|
62237
|
+
"EmailNotifications_getEmailNotificationPreferences_Result": {
|
|
62238
|
+
"type": "object",
|
|
62239
|
+
"properties": {
|
|
62240
|
+
"entitled": { "type": "boolean" },
|
|
62241
|
+
"kinds": {
|
|
62242
|
+
"type": "array",
|
|
62243
|
+
"items": {
|
|
62244
|
+
"type": "object",
|
|
62245
|
+
"properties": {
|
|
62246
|
+
"kind": { "type": "string" },
|
|
62247
|
+
"label": { "type": "string" },
|
|
62248
|
+
"description": { "type": "string" },
|
|
62249
|
+
"class": {
|
|
62250
|
+
"type": "string",
|
|
62251
|
+
"enum": [
|
|
62252
|
+
"platform_required",
|
|
62253
|
+
"org_requirable",
|
|
62254
|
+
"optional"
|
|
62255
|
+
]
|
|
62256
|
+
},
|
|
62257
|
+
"entitlement_required": { "type": "boolean" },
|
|
62258
|
+
"entitled": { "type": "boolean" },
|
|
62259
|
+
"org_mode": {
|
|
62260
|
+
"type": ["string", "null"],
|
|
62261
|
+
"enum": [
|
|
62262
|
+
"off",
|
|
62263
|
+
"optional_on",
|
|
62264
|
+
"optional_off",
|
|
62265
|
+
"required",
|
|
62266
|
+
null
|
|
62267
|
+
]
|
|
62268
|
+
},
|
|
62269
|
+
"org_mode_is_default": { "type": "boolean" },
|
|
62270
|
+
"org_modes": {
|
|
62271
|
+
"type": "array",
|
|
62272
|
+
"items": {
|
|
62273
|
+
"type": "string",
|
|
62274
|
+
"enum": [
|
|
62275
|
+
"off",
|
|
62276
|
+
"optional_on",
|
|
62277
|
+
"optional_off",
|
|
62278
|
+
"required"
|
|
62279
|
+
]
|
|
62280
|
+
}
|
|
62281
|
+
},
|
|
62282
|
+
"member_enabled": { "type": "boolean" },
|
|
62283
|
+
"member_can_change": { "type": "boolean" }
|
|
62284
|
+
},
|
|
62285
|
+
"required": [
|
|
62286
|
+
"kind",
|
|
62287
|
+
"label",
|
|
62288
|
+
"description",
|
|
62289
|
+
"class",
|
|
62290
|
+
"entitlement_required",
|
|
62291
|
+
"entitled",
|
|
62292
|
+
"org_mode",
|
|
62293
|
+
"org_mode_is_default",
|
|
62294
|
+
"org_modes",
|
|
62295
|
+
"member_enabled",
|
|
62296
|
+
"member_can_change"
|
|
62297
|
+
]
|
|
62298
|
+
}
|
|
62299
|
+
}
|
|
62300
|
+
},
|
|
62301
|
+
"required": ["entitled", "kinds"]
|
|
62302
|
+
},
|
|
62303
|
+
"EmailNotifications_updateEmailNotificationPreferences_Result": {
|
|
62304
|
+
"type": "object",
|
|
62305
|
+
"properties": {
|
|
62306
|
+
"entitled": { "type": "boolean" },
|
|
62307
|
+
"kinds": {
|
|
62308
|
+
"type": "array",
|
|
62309
|
+
"items": {
|
|
62310
|
+
"type": "object",
|
|
62311
|
+
"properties": {
|
|
62312
|
+
"kind": { "type": "string" },
|
|
62313
|
+
"label": { "type": "string" },
|
|
62314
|
+
"description": { "type": "string" },
|
|
62315
|
+
"class": {
|
|
62316
|
+
"type": "string",
|
|
62317
|
+
"enum": [
|
|
62318
|
+
"platform_required",
|
|
62319
|
+
"org_requirable",
|
|
62320
|
+
"optional"
|
|
62321
|
+
]
|
|
62322
|
+
},
|
|
62323
|
+
"entitlement_required": { "type": "boolean" },
|
|
62324
|
+
"entitled": { "type": "boolean" },
|
|
62325
|
+
"org_mode": {
|
|
62326
|
+
"type": ["string", "null"],
|
|
62327
|
+
"enum": [
|
|
62328
|
+
"off",
|
|
62329
|
+
"optional_on",
|
|
62330
|
+
"optional_off",
|
|
62331
|
+
"required",
|
|
62332
|
+
null
|
|
62333
|
+
]
|
|
62334
|
+
},
|
|
62335
|
+
"org_mode_is_default": { "type": "boolean" },
|
|
62336
|
+
"org_modes": {
|
|
62337
|
+
"type": "array",
|
|
62338
|
+
"items": {
|
|
62339
|
+
"type": "string",
|
|
62340
|
+
"enum": [
|
|
62341
|
+
"off",
|
|
62342
|
+
"optional_on",
|
|
62343
|
+
"optional_off",
|
|
62344
|
+
"required"
|
|
62345
|
+
]
|
|
62346
|
+
}
|
|
62347
|
+
},
|
|
62348
|
+
"member_enabled": { "type": "boolean" },
|
|
62349
|
+
"member_can_change": { "type": "boolean" }
|
|
62350
|
+
},
|
|
62351
|
+
"required": [
|
|
62352
|
+
"kind",
|
|
62353
|
+
"label",
|
|
62354
|
+
"description",
|
|
62355
|
+
"class",
|
|
62356
|
+
"entitlement_required",
|
|
62357
|
+
"entitled",
|
|
62358
|
+
"org_mode",
|
|
62359
|
+
"org_mode_is_default",
|
|
62360
|
+
"org_modes",
|
|
62361
|
+
"member_enabled",
|
|
62362
|
+
"member_can_change"
|
|
62363
|
+
]
|
|
62364
|
+
}
|
|
62365
|
+
}
|
|
62366
|
+
},
|
|
62367
|
+
"required": ["entitled", "kinds"]
|
|
62368
|
+
},
|
|
62369
|
+
"EmailNotifications_updateEmailNotificationPreferences_Input": {
|
|
62370
|
+
"type": "object",
|
|
62371
|
+
"properties": { "preferences": {
|
|
62372
|
+
"type": "object",
|
|
62373
|
+
"propertyNames": {
|
|
62374
|
+
"type": "string",
|
|
62375
|
+
"pattern": "^[a-z][a-z0-9_]{0,63}$"
|
|
62376
|
+
},
|
|
62377
|
+
"additionalProperties": { "type": "boolean" }
|
|
62378
|
+
} },
|
|
62379
|
+
"required": ["preferences"],
|
|
62380
|
+
"additionalProperties": false
|
|
62381
|
+
},
|
|
61181
62382
|
"ListRolesResult": {
|
|
61182
62383
|
"type": "object",
|
|
61183
62384
|
"properties": {
|
|
@@ -64076,8 +65277,18 @@ const KEY_WRITE_OPERATION_IDS = /* @__PURE__ */ new Set([
|
|
|
64076
65277
|
"credentials:revoke-credential"
|
|
64077
65278
|
]);
|
|
64078
65279
|
const CREDENTIAL_HEADER_OPERATION_IDS = /* @__PURE__ */ new Set(["emails:import-google-mail-message"]);
|
|
65280
|
+
const NOT_YET_OFFERED_OPERATION_IDS = /* @__PURE__ */ new Set([
|
|
65281
|
+
"email-notifications:get-email-notification-preferences",
|
|
65282
|
+
"email-notifications:update-email-notification-preferences",
|
|
65283
|
+
"email-notifications:get-email-notification-settings",
|
|
65284
|
+
"email-notifications:update-email-notification-settings"
|
|
65285
|
+
]);
|
|
64079
65286
|
/** Every operation id the CLI generates no command for. */
|
|
64080
|
-
const CLI_OMITTED_OPERATION_IDS = /* @__PURE__ */ new Set([
|
|
65287
|
+
const CLI_OMITTED_OPERATION_IDS = /* @__PURE__ */ new Set([
|
|
65288
|
+
...KEY_WRITE_OPERATION_IDS,
|
|
65289
|
+
...CREDENTIAL_HEADER_OPERATION_IDS,
|
|
65290
|
+
...NOT_YET_OFFERED_OPERATION_IDS
|
|
65291
|
+
]);
|
|
64081
65292
|
/** The operations the CLI generates commands for: the manifest without CLI_OMITTED_OPERATION_IDS. */
|
|
64082
65293
|
const cliOperationManifest = operationManifest.filter((operation) => !CLI_OMITTED_OPERATION_IDS.has(`${operation.tagCommand}:${operation.command}`));
|
|
64083
65294
|
// src/oclif/commands/activity.ts
|
|
@@ -64091,16 +65302,79 @@ const API_BASE_URL_FLAG$4 = Flags.string({
|
|
|
64091
65302
|
hidden: true
|
|
64092
65303
|
});
|
|
64093
65304
|
const DEFAULT_LIMIT$3 = 50;
|
|
64094
|
-
|
|
65305
|
+
/** How long a read of the feed keeps retrying a transient failure. */
|
|
65306
|
+
const ACTIVITY_RETRY_MS = 15e3;
|
|
65307
|
+
/** The message printed when Primitive could not be reached at all. */
|
|
65308
|
+
const NETWORK_ERROR_MESSAGE = "Could not reach Primitive (network error). Try again in a moment.";
|
|
65309
|
+
/**
|
|
65310
|
+
* The error for a read that got no answer at all: always a plain object, so
|
|
65311
|
+
* it prints the same with and without --json. The transport's own code (a
|
|
65312
|
+
* host that does not resolve, say) is kept as `cause`, as a word, with no
|
|
65313
|
+
* local detail.
|
|
65314
|
+
*/
|
|
65315
|
+
function networkErrorPayload(error) {
|
|
65316
|
+
const cause = error instanceof Error ? error.cause : void 0;
|
|
65317
|
+
const code = cause && typeof cause === "object" ? cause.code : void 0;
|
|
65318
|
+
return {
|
|
65319
|
+
code: "network_error",
|
|
65320
|
+
message: NETWORK_ERROR_MESSAGE,
|
|
65321
|
+
...typeof code === "string" && /^[A-Z0-9_]+$/.test(code) ? { cause: code } : {}
|
|
65322
|
+
};
|
|
65323
|
+
}
|
|
65324
|
+
/**
|
|
65325
|
+
* One page read, retried as the CLI's waits retry a read: a rate limit, a
|
|
65326
|
+
* 502, 503 or 504, or a network error is tried again with backoff, up to
|
|
65327
|
+
* ACTIVITY_ATTEMPTS times within ACTIVITY_RETRY_MS. A read that throws is
|
|
65328
|
+
* taken as the network error it is. A wait (a Retry-After, or the backoff)
|
|
65329
|
+
* longer than the time left is not slept on: the failure is returned at once.
|
|
65330
|
+
*/
|
|
65331
|
+
async function readWithRetry(read) {
|
|
65332
|
+
const deadline = Date.now() + ACTIVITY_RETRY_MS;
|
|
65333
|
+
for (let attempt = 0;; attempt += 1) {
|
|
65334
|
+
let result;
|
|
65335
|
+
try {
|
|
65336
|
+
result = await read();
|
|
65337
|
+
} catch (error) {
|
|
65338
|
+
result = { error };
|
|
65339
|
+
}
|
|
65340
|
+
const failure = transientFailure(result);
|
|
65341
|
+
if (!failure || attempt + 1 >= 4) return result;
|
|
65342
|
+
const wait = failure.retryAfterMs ?? backoffDelay(attempt);
|
|
65343
|
+
if (wait > deadline - Date.now()) return result;
|
|
65344
|
+
if (!await pauseForTransientFailure({
|
|
65345
|
+
...failure,
|
|
65346
|
+
retryAfterMs: wait
|
|
65347
|
+
}, attempt, { deadline })) return result;
|
|
65348
|
+
}
|
|
65349
|
+
}
|
|
65350
|
+
async function call$1(read) {
|
|
64095
65351
|
try {
|
|
64096
|
-
const result = await
|
|
64097
|
-
if (result
|
|
65352
|
+
const result = await readWithRetry(read);
|
|
65353
|
+
if (transientFailure(result)?.reason === "network") return {
|
|
64098
65354
|
ok: false,
|
|
64099
|
-
payload: result.error
|
|
64100
|
-
code: "http_error",
|
|
64101
|
-
message: typeof result.error === "string" && result.error.trim() || `HTTP ${result.response?.status ?? ""}`.trim()
|
|
64102
|
-
} : extractErrorPayload(result.error)
|
|
65355
|
+
payload: networkErrorPayload(result.error)
|
|
64103
65356
|
};
|
|
65357
|
+
if (result.error !== void 0 || !result.response?.ok) {
|
|
65358
|
+
const status = result.response?.status;
|
|
65359
|
+
if (result.error instanceof Error) return {
|
|
65360
|
+
ok: false,
|
|
65361
|
+
response: result.response,
|
|
65362
|
+
payload: {
|
|
65363
|
+
code: "response_error",
|
|
65364
|
+
message: `The answer could not be read${status ? ` (HTTP ${status})` : ""}. Try again in a moment.`
|
|
65365
|
+
}
|
|
65366
|
+
};
|
|
65367
|
+
const extracted = result.error === void 0 || result.error === null || typeof result.error === "string" ? void 0 : extractErrorPayload(result.error);
|
|
65368
|
+
const coded = extracted !== null && typeof extracted === "object" && typeof extracted.code === "string";
|
|
65369
|
+
return {
|
|
65370
|
+
ok: false,
|
|
65371
|
+
response: result.response,
|
|
65372
|
+
payload: coded ? extracted : {
|
|
65373
|
+
code: "http_error",
|
|
65374
|
+
message: typeof result.error === "string" && result.error.trim() || `HTTP ${status ?? ""}`.trim()
|
|
65375
|
+
}
|
|
65376
|
+
};
|
|
65377
|
+
}
|
|
64104
65378
|
const data = result.data;
|
|
64105
65379
|
return {
|
|
64106
65380
|
ok: true,
|
|
@@ -64109,7 +65383,7 @@ async function call$1(request) {
|
|
|
64109
65383
|
} catch (error) {
|
|
64110
65384
|
return {
|
|
64111
65385
|
ok: false,
|
|
64112
|
-
payload:
|
|
65386
|
+
payload: networkErrorPayload(error)
|
|
64113
65387
|
};
|
|
64114
65388
|
}
|
|
64115
65389
|
}
|
|
@@ -64175,15 +65449,56 @@ function formatAskedRows(items, complete = false) {
|
|
|
64175
65449
|
const line = (cells) => cells.map((cell, i) => i === cells.length - 1 ? cell : cell.padEnd(widths[i] ?? 0)).join(" ");
|
|
64176
65450
|
return [line(header), ...rows.map(line)].join("\n");
|
|
64177
65451
|
}
|
|
65452
|
+
const TOTAL_KEYS = [
|
|
65453
|
+
"keys",
|
|
65454
|
+
"reads_in_full",
|
|
65455
|
+
"webhooks",
|
|
65456
|
+
"shares"
|
|
65457
|
+
];
|
|
65458
|
+
/** `value` as receiver totals: an object whose four counts are all non-negative integers. */
|
|
65459
|
+
function receiverTotals(value) {
|
|
65460
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return null;
|
|
65461
|
+
const totals = value;
|
|
65462
|
+
return TOTAL_KEYS.every((key) => {
|
|
65463
|
+
const count = totals[key];
|
|
65464
|
+
return typeof count === "number" && Number.isInteger(count) && count >= 0;
|
|
65465
|
+
}) ? totals : null;
|
|
65466
|
+
}
|
|
65467
|
+
/**
|
|
65468
|
+
* What a receivers_changed notice says changed, from its totals before and
|
|
65469
|
+
* after: "keys 3 to 2 (1 to 0 also reading your mail beyond the rule),
|
|
65470
|
+
* webhooks 2 to 1",
|
|
65471
|
+
* or, when the totals are equal (an owner or a webhook site changed), that
|
|
65472
|
+
* they are. Null for any other notice, and for one whose totals are missing
|
|
65473
|
+
* or not counts (an older server).
|
|
65474
|
+
*/
|
|
65475
|
+
function receiversChangeText(item) {
|
|
65476
|
+
if (item.state !== "receivers_changed") return null;
|
|
65477
|
+
const change = item.receivers_change;
|
|
65478
|
+
const before = receiverTotals(change?.before);
|
|
65479
|
+
const after = receiverTotals(change?.after);
|
|
65480
|
+
if (!before || !after) return null;
|
|
65481
|
+
const moved = (key) => before[key] !== after[key];
|
|
65482
|
+
const span = (key) => `${before[key]} to ${after[key]}`;
|
|
65483
|
+
const full = moved("reads_in_full") ? ` (${span("reads_in_full")} also reading your mail beyond the rule)` : "";
|
|
65484
|
+
const changed = [
|
|
65485
|
+
...moved("keys") ? [`keys ${span("keys")}${full}`] : full ? [`keys ${after.keys}${full}`] : [],
|
|
65486
|
+
...moved("webhooks") ? [`webhooks ${span("webhooks")}`] : [],
|
|
65487
|
+
...moved("shares") ? [`shares ${span("shares")}`] : []
|
|
65488
|
+
];
|
|
65489
|
+
return changed.length > 0 ? changed.join(", ") : "same totals, an owner or webhook site changed";
|
|
65490
|
+
}
|
|
64178
65491
|
/** Where to see what covers you now, whatever the notices have caught up with. */
|
|
64179
65492
|
const COVERING_NOW = `\`primitive email-rule-oversight list-email-rules-covering-me\` shows what covers you now.`;
|
|
64180
65493
|
/**
|
|
64181
|
-
* One line per coverage notice: what it told (started, new_version,
|
|
64182
|
-
* baseline for a rule that already covered you when
|
|
64183
|
-
* rule's name then, and its author; and, first,
|
|
64184
|
-
* whose notice is not written yet (pending,
|
|
64185
|
-
* changed), then the rule's id (rule_id; a pending
|
|
64186
|
-
* rule's), never the notice's own id, which no command
|
|
65494
|
+
* One line per coverage notice: what it told (started, new_version,
|
|
65495
|
+
* receivers_changed, or baseline for a rule that already covered you when
|
|
65496
|
+
* notices began), when, the rule's name then, and its author; and, first,
|
|
65497
|
+
* each rule that covers you now whose notice is not written yet (pending,
|
|
65498
|
+
* dated when the rule last changed), then the rule's id (rule_id; a pending
|
|
65499
|
+
* row's own id is the rule's), never the notice's own id, which no command
|
|
65500
|
+
* takes; and, when any row is a receivers_changed notice with its totals,
|
|
65501
|
+
* what changed in them (CHANGE).
|
|
64187
65502
|
* `complete` says the listing is the whole of it (from the first page to the
|
|
64188
65503
|
* last, nothing withheld). Even then an empty one is no promise that nothing
|
|
64189
65504
|
* covers you: notices can lag, so it
|
|
@@ -64195,24 +65510,30 @@ function formatConcerningRows(items, complete = false, asOf, pendingComplete) {
|
|
|
64195
65510
|
const rows = items.map((item) => [
|
|
64196
65511
|
item.state,
|
|
64197
65512
|
minute(item.created_at),
|
|
64198
|
-
item.name ?? "(unnamed)"
|
|
65513
|
+
`${item.name ?? "(unnamed)"}${item.rule_now === "deleted" ? " (deleted)" : ""}`,
|
|
64199
65514
|
item.created_through.name ?? item.created_through.id ?? "",
|
|
64200
65515
|
item.rule_id ?? (item.state === "pending" ? item.id : "")
|
|
64201
65516
|
]);
|
|
65517
|
+
const changes = items.map((item) => receiversChangeText(item));
|
|
65518
|
+
const withChange = changes.some((change) => change !== null);
|
|
65519
|
+
if (withChange) for (const [i, row] of rows.entries()) row.push(changes[i] ?? "");
|
|
64202
65520
|
const header = [
|
|
64203
65521
|
"NOTICE",
|
|
64204
65522
|
"WHEN (UTC)",
|
|
64205
65523
|
"RULE",
|
|
64206
65524
|
"AUTHOR",
|
|
64207
|
-
"RULE ID"
|
|
65525
|
+
"RULE ID",
|
|
65526
|
+
...withChange ? ["CHANGE"] : []
|
|
64208
65527
|
];
|
|
64209
65528
|
const widths = header.map((h, i) => Math.max(h.length, ...rows.map((row) => (row[i] ?? "").length)));
|
|
64210
65529
|
const line = (cells) => cells.map((cell, i) => i === cells.length - 1 ? cell : cell.padEnd(widths[i] ?? 0)).join(" ").trimEnd();
|
|
64211
65530
|
const pending = items.some((item) => item.state === "pending") ? ["", `pending: the rule covers you now and its notice is not written yet. ${COVERING_NOW}`] : [];
|
|
65531
|
+
const receivers = items.some((item) => item.state === "receivers_changed") ? ["", "receivers_changed: who receives the rule's matches changed, with the totals before and after where the server sends them. `primitive email-rule-oversight get-email-rule-covering-me <rule-id>` shows who receives them now, by owner, while the rule covers you."] : [];
|
|
64212
65532
|
return [
|
|
64213
65533
|
line(header),
|
|
64214
65534
|
...rows.map(line),
|
|
64215
65535
|
...pending,
|
|
65536
|
+
...receivers,
|
|
64216
65537
|
...unfinished ? ["", pending.length > 0 ? unfinished : `${unfinished} ${COVERING_NOW}`] : []
|
|
64217
65538
|
].join("\n");
|
|
64218
65539
|
}
|
|
@@ -64250,7 +65571,7 @@ async function runActivityList(command, flags, relation) {
|
|
|
64250
65571
|
let pendingComplete;
|
|
64251
65572
|
let cursor = flags.cursor;
|
|
64252
65573
|
for (let page = 0; page < (flags.all ? 50 : 1); page += 1) {
|
|
64253
|
-
const result = await call$1(listActivityObjects({
|
|
65574
|
+
const result = await call$1(() => listActivityObjects({
|
|
64254
65575
|
client: auth.apiClient.client,
|
|
64255
65576
|
query: {
|
|
64256
65577
|
...relation !== "created" ? { relation } : {},
|
|
@@ -64262,7 +65583,12 @@ async function runActivityList(command, flags, relation) {
|
|
|
64262
65583
|
}));
|
|
64263
65584
|
if (!result.ok) {
|
|
64264
65585
|
if (flags.json) process.stderr.write(`${JSON.stringify(result.payload)}\n`);
|
|
64265
|
-
else
|
|
65586
|
+
else {
|
|
65587
|
+
writeErrorWithHints(result.payload, result.response);
|
|
65588
|
+
const cause = result.payload?.cause;
|
|
65589
|
+
const hint = typeof cause === "string" ? networkErrorHint(cause) : void 0;
|
|
65590
|
+
if (hint) process.stderr.write(`${hint}\n`);
|
|
65591
|
+
}
|
|
64266
65592
|
surfaceUnauthorizedHint({
|
|
64267
65593
|
auth: auth.auth,
|
|
64268
65594
|
baseUrlOverridden: auth.baseUrlOverridden,
|
|
@@ -64378,7 +65704,7 @@ var ActivityAskedCommand = class ActivityAskedCommand extends Command {
|
|
|
64378
65704
|
}
|
|
64379
65705
|
};
|
|
64380
65706
|
var ActivityConcerningCommand = class ActivityConcerningCommand extends Command {
|
|
64381
|
-
static description = `List what other members did that concerns your own mail, newest first: each time another member's rule started covering your mailboxes, that is, it was made or turned active over them or an active rule came to reach you, once per rule, not per mailbox (started),
|
|
65707
|
+
static description = `List what other members did that concerns your own mail, newest first: each time another member's rule started covering your mailboxes, that is, it was made or turned active over them or an active rule came to reach you, once per rule, not per mailbox (started), saved a new version while covering it (new_version), or changed who receives its matches: its keys, webhooks or share (receivers_changed, with the totals before and after in the table, and under receivers_change with --json, at most once every 15 minutes for a rule), named as the rule was then, with its author. A rule that already covered you when these notices began is listed once as baseline. A rule in draft or observe grants and blocks nothing and gets no notice while it stays there, though \`primitive email-rule-oversight list-email-rules-covering-me\` lists it; turning it active is what is listed, and a rule that covers you again within an hour of its last started or baseline notice gets no new one, though a version it saved meanwhile is listed as new_version, and a change in who receives its matches as receivers_changed. A rule that stops covering you and a rename are not listed.
|
|
64382
65708
|
|
|
64383
65709
|
Notices can lag. Until a start is written, a rule that now covers you is listed first as pending, dated when the rule last changed, and with --json its id is the rule's. When the check for such rules did not finish, the listing says so and --json carries pending_complete: false; run it again in a moment.
|
|
64384
65710
|
|
|
@@ -71553,7 +72879,7 @@ async function checkAskedOfYou(client, now = Date.now()) {
|
|
|
71553
72879
|
const waiting = asked.more ? [`at least ${requests + objections} rule requests and objections`] : [...requests > 0 ? [plural$1(requests, "rule request")] : [], ...objections > 0 ? [plural$1(objections, "objection")] : []];
|
|
71554
72880
|
const items = concerning?.items ?? [];
|
|
71555
72881
|
const pending = items.filter((item) => item.state === "pending").length;
|
|
71556
|
-
const notices = items.filter((item) => (item.state === "started" || item.state === "new_version") && Date.parse(item.created_at) >= since).length;
|
|
72882
|
+
const notices = items.filter((item) => (item.state === "started" || item.state === "new_version" || item.state === "receivers_changed") && Date.parse(item.created_at) >= since).length;
|
|
71557
72883
|
const parts = [
|
|
71558
72884
|
...waiting.length > 0 ? [`${waiting.join(" and ")} waiting for you`] : [],
|
|
71559
72885
|
...ASKED_KINDS.filter((kind) => hidden.has(kind)).map((kind) => `${kind === "email_rule_request" ? "rule requests" : "objections"} not shown to this credential`),
|
|
@@ -71603,7 +72929,7 @@ function checkReceiverStart(configDir, profileName) {
|
|
|
71603
72929
|
}
|
|
71604
72930
|
}
|
|
71605
72931
|
var DoctorCommand = class DoctorCommand extends Command {
|
|
71606
|
-
static description = `Run a one-shot environment health check: Node version, proxy env, CLI auth resolution, /account reachability, verified-domain status, and, signed in as yourself, the rule requests and objections waiting for you and the rules that recently started covering
|
|
72932
|
+
static description = `Run a one-shot environment health check: Node version, proxy env, CLI auth resolution, /account reachability, verified-domain status, and, signed in as yourself, the rule requests and objections waiting for you and the rules over your mail that recently started covering it or changed. With PRIMITIVE_AGENT_PROFILE selected, reports saved identity offline and points to whoami and exact listener status instead of account-only checks. Prints actionable hints for each warning or failure.`;
|
|
71607
72933
|
static summary = "Check the local environment and live API for common problems";
|
|
71608
72934
|
static examples = ["<%= config.bin %> doctor", "<%= config.bin %> doctor --api-key prim_..."];
|
|
71609
72935
|
static flags = {
|
|
@@ -74703,8 +76029,8 @@ const PRIMITIVE_TEAM_AUTHOR = {
|
|
|
74703
76029
|
name: "Primitive Team",
|
|
74704
76030
|
url: "https://primitive.dev"
|
|
74705
76031
|
};
|
|
74706
|
-
const SDK_VERSION_RANGE = "^3.0.0-preview.
|
|
74707
|
-
const CLI_VERSION_RANGE = "^3.0.0-preview.
|
|
76032
|
+
const SDK_VERSION_RANGE = "^3.0.0-preview.15";
|
|
76033
|
+
const CLI_VERSION_RANGE = "^3.0.0-preview.15";
|
|
74708
76034
|
const ESBUILD_VERSION_RANGE = "^0.27.0";
|
|
74709
76035
|
function renderHandler() {
|
|
74710
76036
|
return `// env.PRIMITIVE_API_KEY, env.PRIMITIVE_WEBHOOK_SECRET, and
|
|
@@ -78092,6 +79418,39 @@ function keyNotes(key) {
|
|
|
78092
79418
|
return typeof description === "string" ? [description] : [];
|
|
78093
79419
|
});
|
|
78094
79420
|
}
|
|
79421
|
+
/** Whether a note says the key reads a whole mailbox beside its email rules. */
|
|
79422
|
+
function isWholeMailboxNote(note) {
|
|
79423
|
+
return note !== null && typeof note === "object" && note.reason === "whole_mailbox";
|
|
79424
|
+
}
|
|
79425
|
+
/**
|
|
79426
|
+
* The addresses and domains a key reads in full beside its email rules: the
|
|
79427
|
+
* whole_mailbox notes of its address_warnings, read loosely.
|
|
79428
|
+
*/
|
|
79429
|
+
function wholeMailboxAddresses(notes) {
|
|
79430
|
+
if (!Array.isArray(notes)) return [];
|
|
79431
|
+
return notes.flatMap((note) => {
|
|
79432
|
+
if (!isWholeMailboxNote(note)) return [];
|
|
79433
|
+
const address = note.address;
|
|
79434
|
+
return typeof address === "string" && address ? [address] : [];
|
|
79435
|
+
});
|
|
79436
|
+
}
|
|
79437
|
+
/**
|
|
79438
|
+
* What a key create or update says when the key reads whole mailboxes beside
|
|
79439
|
+
* its email rules: on stderr as a Warning line, or under --json in the
|
|
79440
|
+
* document's whole_mailbox_warning (the JSON guard keeps stderr empty, and the
|
|
79441
|
+
* answer's warnings are the server's objects). Null when it does not. The
|
|
79442
|
+
* exit code is not changed: the key is made or changed as asked.
|
|
79443
|
+
*/
|
|
79444
|
+
function wholeMailboxWarning(keyId, notes) {
|
|
79445
|
+
if (!Array.isArray(notes) || !notes.some(isWholeMailboxNote)) return null;
|
|
79446
|
+
const addresses = wholeMailboxAddresses(notes);
|
|
79447
|
+
return `This key reads ${addresses.length > 0 ? `every email at ${addresses.join(", ")}` : "every email at an address or domain it lists"}, not only the emails its rules grant. An address or domain listed beside a rule is read in full. To limit a key to the rules' emails, create one with the same permissions and only --rule for its mail (no --address or --domain), then revoke this one with \`primitive keys revoke ${keyId}\`.`;
|
|
79448
|
+
}
|
|
79449
|
+
/** The notes other than whole_mailbox, which wholeMailboxWarning says instead. */
|
|
79450
|
+
function otherNotes(notes) {
|
|
79451
|
+
if (!Array.isArray(notes)) return [];
|
|
79452
|
+
return notes.filter((note) => note !== null && typeof note === "object" && !isWholeMailboxNote(note));
|
|
79453
|
+
}
|
|
78095
79454
|
function formatKeyRows(rows, options = {}) {
|
|
78096
79455
|
if (rows.length === 0) return options.includeRevoked ? "No API keys, revoked or not." : "No API keys. Revoked keys are left out; pass --include-revoked to list them too.";
|
|
78097
79456
|
return rows.map((row) => {
|
|
@@ -78099,9 +79458,16 @@ function formatKeyRows(rows, options = {}) {
|
|
|
78099
79458
|
const revoked = row.status === "revoked" ? ` [revoked${row.revoked_at ? ` ${row.revoked_at}` : ""}]` : "";
|
|
78100
79459
|
const count = keyNotes(row).length;
|
|
78101
79460
|
const notes = count > 0 ? ` [${count} ${count === 1 ? "note" : "notes"}: primitive keys get ${row.id}]` : "";
|
|
78102
|
-
|
|
79461
|
+
const inFull = wholeMailboxAddresses(row.address_warnings);
|
|
79462
|
+
const whole = inFull.length > 0 ? ` [reads all mail at ${inFull.join(", ")}, not only its rules' emails]` : "";
|
|
79463
|
+
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}${revoked}${whole}${notes}`;
|
|
78103
79464
|
}).join("\n");
|
|
78104
79465
|
}
|
|
79466
|
+
/** The detail line for the mailboxes a key reads in full beside its rules. */
|
|
79467
|
+
function wholeMailboxLines(key) {
|
|
79468
|
+
const inFull = wholeMailboxAddresses(key.address_warnings);
|
|
79469
|
+
return inFull.length > 0 ? [`In full: ${inFull.join(", ")} (listed beside its rules, so every email there is read, not only what the rules grant)`] : [];
|
|
79470
|
+
}
|
|
78105
79471
|
function formatKeyDetail(key) {
|
|
78106
79472
|
const lines = [
|
|
78107
79473
|
`Name: ${key.name ?? "(unnamed)"}`,
|
|
@@ -78109,6 +79475,7 @@ function formatKeyDetail(key) {
|
|
|
78109
79475
|
`Prefix: ${key.key_prefix}`,
|
|
78110
79476
|
`Kind: ${key.kind}`,
|
|
78111
79477
|
`Mail: ${describeMailScope(key.grant)}`,
|
|
79478
|
+
...wholeMailboxLines(key),
|
|
78112
79479
|
`Created: ${key.created_at ?? "unknown"}`,
|
|
78113
79480
|
`Expires: ${key.expires_at ?? "never"}`,
|
|
78114
79481
|
`Last used: ${key.last_used_at ?? "never"}`,
|
|
@@ -78208,13 +79575,16 @@ function buildCreateGrant(choice) {
|
|
|
78208
79575
|
* The mail scope fields a change can restate. `ended_rules` (rules the key
|
|
78209
79576
|
* lists that read nothing any more: a deleted rule, or a share that ended) is
|
|
78210
79577
|
* read only: a change never sends it back, so the key is saved without them.
|
|
79578
|
+
* `rule_versions` (each listed rule's current version, its state and when
|
|
79579
|
+
* that version was saved) is read only too, and is never sent back.
|
|
78211
79580
|
*/
|
|
78212
79581
|
const RESTATABLE_SCOPE_FIELDS = /* @__PURE__ */ new Set([
|
|
78213
79582
|
"addresses",
|
|
78214
79583
|
"domains",
|
|
78215
79584
|
"rules",
|
|
78216
79585
|
"depth",
|
|
78217
|
-
"ended_rules"
|
|
79586
|
+
"ended_rules",
|
|
79587
|
+
"rule_versions"
|
|
78218
79588
|
]);
|
|
78219
79589
|
/** Whether a change touches the key's email rules at all. */
|
|
78220
79590
|
function changesRules(change) {
|
|
@@ -78311,7 +79681,7 @@ function buildUpdatedGrant(current, change) {
|
|
|
78311
79681
|
}
|
|
78312
79682
|
if (!scope || typeof scope !== "object" || Array.isArray(scope)) return {
|
|
78313
79683
|
ok: false,
|
|
78314
|
-
message: "This key's mail scope could not be read. Change
|
|
79684
|
+
message: "This key's mail scope could not be read. Change the key in the dashboard, or create a key with what you need and revoke this one."
|
|
78315
79685
|
};
|
|
78316
79686
|
const record = scope;
|
|
78317
79687
|
const addresses = stringList(record.addresses ?? []);
|
|
@@ -78324,9 +79694,21 @@ function buildUpdatedGrant(current, change) {
|
|
|
78324
79694
|
message: `${readdedEnded.id} reads nothing any more (${readdedEnded.reason}), so it cannot be added back to the key.`
|
|
78325
79695
|
};
|
|
78326
79696
|
const rules = heldRules ? nextRules(heldRules, change) : null;
|
|
78327
|
-
|
|
79697
|
+
const unknownFields = Object.keys(record).filter((field) => !RESTATABLE_SCOPE_FIELDS.has(field));
|
|
79698
|
+
if (unknownFields.length > 0) {
|
|
79699
|
+
const one = unknownFields.length === 1;
|
|
79700
|
+
return {
|
|
79701
|
+
ok: false,
|
|
79702
|
+
message: `This key's mail scope has ${one ? "a setting" : "settings"} the CLI cannot restate (${unknownFields.join(", ")}), and a change here could drop ${one ? "it" : "them"}. Change the key in the dashboard, or create a key with what you need and revoke this one.`
|
|
79703
|
+
};
|
|
79704
|
+
}
|
|
79705
|
+
if (!addresses || !domains || !rules) return {
|
|
78328
79706
|
ok: false,
|
|
78329
|
-
message:
|
|
79707
|
+
message: `This key's mail scope has ${[
|
|
79708
|
+
...addresses ? [] : ["addresses"],
|
|
79709
|
+
...domains ? [] : ["domains"],
|
|
79710
|
+
...rules ? [] : ["rules"]
|
|
79711
|
+
].join(" and ")} the CLI could not read. Change the key in the dashboard, or create a key with what you need and revoke this one.`
|
|
78330
79712
|
};
|
|
78331
79713
|
if (addresses.length === 0 && domains.length === 0 && rules.length === 0) {
|
|
78332
79714
|
if ((heldRules?.length ?? 0) === 0 && ended.length > 0) return {
|
|
@@ -78469,7 +79851,7 @@ var KeysCreateCommand = class KeysCreateCommand extends Command {
|
|
|
78469
79851
|
|
|
78470
79852
|
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.
|
|
78471
79853
|
|
|
78472
|
-
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.
|
|
79854
|
+
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. An --address or --domain given beside --rule is read in full, every email there and not only what the rules match: the key is still made, and the command warns on stderr, or in whole_mailbox_warning with --json.
|
|
78473
79855
|
|
|
78474
79856
|
${keyPermissionsHelp()}`;
|
|
78475
79857
|
static summary = "Create an API key";
|
|
@@ -78549,9 +79931,13 @@ var KeysCreateCommand = class KeysCreateCommand extends Command {
|
|
|
78549
79931
|
const key = result.data;
|
|
78550
79932
|
if (!flags.json) {
|
|
78551
79933
|
writeWarnings(key.warnings);
|
|
78552
|
-
writeWarnings(key.address_warnings);
|
|
79934
|
+
writeWarnings(otherNotes(key.address_warnings));
|
|
78553
79935
|
}
|
|
78554
|
-
|
|
79936
|
+
const whole = wholeMailboxWarning(key.id, key.address_warnings);
|
|
79937
|
+
printSecret(this, Boolean(flags.json), whole ? {
|
|
79938
|
+
...key,
|
|
79939
|
+
whole_mailbox_warning: whole
|
|
79940
|
+
} : key, key.key, [
|
|
78555
79941
|
`Created API key ${key.name ?? "(unnamed)"} (${key.id}), prefix ${key.key_prefix}.`,
|
|
78556
79942
|
`Permissions: ${describePermissions({
|
|
78557
79943
|
template: key.grant.template,
|
|
@@ -78565,6 +79951,7 @@ var KeysCreateCommand = class KeysCreateCommand extends Command {
|
|
|
78565
79951
|
})}`,
|
|
78566
79952
|
`Expires: ${key.expires_at ?? "never"}`
|
|
78567
79953
|
].join("\n"));
|
|
79954
|
+
if (whole && !flags.json) process.stderr.write(`Warning: ${whole}\n`);
|
|
78568
79955
|
}
|
|
78569
79956
|
};
|
|
78570
79957
|
var KeysRotateCommand = class KeysRotateCommand extends Command {
|
|
@@ -78627,11 +80014,11 @@ var KeysRotateCommand = class KeysRotateCommand extends Command {
|
|
|
78627
80014
|
var KeysUpdateCommand = class KeysUpdateCommand extends Command {
|
|
78628
80015
|
static description = `Change an API key's permissions, email rules, name or expiry. It keeps its id and secret.
|
|
78629
80016
|
|
|
78630
|
-
--add and --remove take permissions (repeatable, or comma-separated); \`primitive keys create --help-full\` lists the permissions a key can hold. --add-rule and --remove-rule add email rules to the key or take them off, and keep its other rules. --rule replaces every rule the key has with the ones given, so pass all the rules it should keep; it cannot be combined with --add-rule or --remove-rule. --expires-at gives it a new expiry: a later one extends it, within your organization's credential policy, and is how to keep a key working past its expiry (rotating keeps the expiry). --no-expiry removes it where the policy allows. An expired key cannot be extended. Everything else about the key stays as it is, and the output lists any rules a change took off.
|
|
80017
|
+
--add and --remove take permissions (repeatable, or comma-separated); \`primitive keys create --help-full\` lists the permissions a key can hold. --add-rule and --remove-rule add email rules to the key or take them off, and keep its other rules. --rule replaces every rule the key has with the ones given, so pass all the rules it should keep; it cannot be combined with --add-rule or --remove-rule. --expires-at gives it a new expiry: a later one extends it, within your organization's credential policy, and is how to keep a key working past its expiry (rotating keeps the expiry). --no-expiry removes it where the policy allows. An expired key cannot be extended. Everything else about the key stays as it is, and the output lists any rules a change took off. When the key's grant is written and it lists an address or domain beside its rules, which it reads in full, the command warns on stderr, or in whole_mailbox_warning with --json.
|
|
78631
80018
|
|
|
78632
80019
|
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.
|
|
78633
80020
|
|
|
78634
|
-
With --json it prints the key as it is now, in the shape keys get prints, with changed, warnings and address_warnings alongside, notice when its permissions or mail changed, rules_added when a change put rules on it (each with granted_emails, how many emails the rule has already shared), rules_removed when a change took rules off,
|
|
80021
|
+
With --json it prints the key as it is now, in the shape keys get prints, with changed, warnings and address_warnings alongside, notice when its permissions or mail changed, rules_added when a change put rules on it (each with granted_emails, how many emails the rule has already shared), rules_removed when a change took rules off, rules_not_on_key for rules asked to be taken off that it did not have, and whole_mailbox_warning when the grant written reads a whole mailbox beside its rules. A permission or rule change that leaves the grant as it is, with no --name, --expires-at or --no-expiry, sends nothing and prints the key with changed: []. If the key cannot be read back after the change, key_error says why and only the change's fields are printed.`;
|
|
78635
80022
|
static summary = "Change an API key";
|
|
78636
80023
|
static examples = [
|
|
78637
80024
|
"<%= config.bin %> keys update 0f0e0d0c-0b0a-4908-8706-050403020100 --add mail:send,mail:reply",
|
|
@@ -78765,6 +80152,7 @@ var KeysUpdateCommand = class KeysUpdateCommand extends Command {
|
|
|
78765
80152
|
path: { id: args.id }
|
|
78766
80153
|
})) : null;
|
|
78767
80154
|
const standingNotes = after?.ok ? after.data.address_warnings : void 0;
|
|
80155
|
+
const whole = grantChanged ? wholeMailboxWarning(args.id, result.data.address_warnings) : null;
|
|
78768
80156
|
if (flags.json) {
|
|
78769
80157
|
this.log(JSON.stringify({
|
|
78770
80158
|
...after?.ok ? after.data : {},
|
|
@@ -78773,12 +80161,13 @@ var KeysUpdateCommand = class KeysUpdateCommand extends Command {
|
|
|
78773
80161
|
...grantChanged ? { notice: HELD_REQUEST_NOTICE } : {},
|
|
78774
80162
|
...grantChanged && rulesRemoved.length > 0 ? { rules_removed: rulesRemoved } : {},
|
|
78775
80163
|
...rulesNotOnKey.length > 0 ? { rules_not_on_key: rulesNotOnKey } : {},
|
|
78776
|
-
...after && !after.ok ? { key_error: after.payload } : {}
|
|
80164
|
+
...after && !after.ok ? { key_error: after.payload } : {},
|
|
80165
|
+
...whole ? { whole_mailbox_warning: whole } : {}
|
|
78777
80166
|
}, null, 2));
|
|
78778
80167
|
return;
|
|
78779
80168
|
}
|
|
78780
80169
|
writeWarnings(result.data.warnings);
|
|
78781
|
-
writeWarnings(result.data.address_warnings);
|
|
80170
|
+
writeWarnings(whole ? otherNotes(result.data.address_warnings) : result.data.address_warnings);
|
|
78782
80171
|
const changed = result.data.changed;
|
|
78783
80172
|
this.log(changed.length > 0 ? `Updated key ${args.id}: ${changed.join(", ")}.` : `Key ${args.id} already matched; nothing changed.`);
|
|
78784
80173
|
if (after?.ok) {
|
|
@@ -78788,6 +80177,7 @@ var KeysUpdateCommand = class KeysUpdateCommand extends Command {
|
|
|
78788
80177
|
if (grantChanged && rulesRemoved.length > 0) this.log(`Rules taken off: ${rulesRemoved.join(", ")}`);
|
|
78789
80178
|
if (changed.includes("expires_at")) this.log(`Expires: ${expiry.expiresAt ?? "never"}`);
|
|
78790
80179
|
if (grantChanged) process.stderr.write(`${HELD_REQUEST_NOTICE}\n`);
|
|
80180
|
+
if (whole) process.stderr.write(`Warning: ${whole}\n`);
|
|
78791
80181
|
}
|
|
78792
80182
|
};
|
|
78793
80183
|
/**
|
|
@@ -83241,9 +84631,51 @@ function compareVersions(a, b) {
|
|
|
83241
84631
|
}
|
|
83242
84632
|
return 0;
|
|
83243
84633
|
}
|
|
83244
|
-
|
|
84634
|
+
function parseVersion(value) {
|
|
84635
|
+
const match = /^v?(\d+)\.(\d+)\.(\d+)(?:-([0-9A-Za-z.-]+))?(?:\+[0-9A-Za-z.-]+)?$/.exec(value.trim());
|
|
84636
|
+
if (!match) return null;
|
|
84637
|
+
return {
|
|
84638
|
+
core: match.slice(1, 4).map(Number),
|
|
84639
|
+
prerelease: match[4] ? match[4].split(".") : []
|
|
84640
|
+
};
|
|
84641
|
+
}
|
|
84642
|
+
/** Whether a version is a prerelease, such as 3.0.0-preview.12. */
|
|
84643
|
+
function isPrerelease(version) {
|
|
84644
|
+
return (parseVersion(version)?.prerelease.length ?? 0) > 0;
|
|
84645
|
+
}
|
|
84646
|
+
/**
|
|
84647
|
+
* Compare two versions in semver order, prereleases included: 3.0.0-preview.9
|
|
84648
|
+
* is older than 3.0.0-preview.12, which is older than 3.0.0. Null when either
|
|
84649
|
+
* is not a version.
|
|
84650
|
+
*/
|
|
84651
|
+
function compareReleaseVersions(a, b) {
|
|
84652
|
+
const left = parseVersion(a);
|
|
84653
|
+
const right = parseVersion(b);
|
|
84654
|
+
if (!left || !right) return null;
|
|
84655
|
+
for (let index = 0; index < 3; index++) {
|
|
84656
|
+
const difference = (left.core[index] ?? 0) - (right.core[index] ?? 0);
|
|
84657
|
+
if (difference) return Math.sign(difference);
|
|
84658
|
+
}
|
|
84659
|
+
if (left.prerelease.length === 0 || right.prerelease.length === 0) return Math.sign(right.prerelease.length - left.prerelease.length);
|
|
84660
|
+
const length = Math.max(left.prerelease.length, right.prerelease.length);
|
|
84661
|
+
for (let index = 0; index < length; index++) {
|
|
84662
|
+
const l = left.prerelease[index];
|
|
84663
|
+
const r = right.prerelease[index];
|
|
84664
|
+
if (l === void 0) return -1;
|
|
84665
|
+
if (r === void 0) return 1;
|
|
84666
|
+
const ln = /^\d+$/.test(l) ? Number(l) : null;
|
|
84667
|
+
const rn = /^\d+$/.test(r) ? Number(r) : null;
|
|
84668
|
+
if (ln !== null && rn !== null) {
|
|
84669
|
+
if (ln !== rn) return Math.sign(ln - rn);
|
|
84670
|
+
} else if (ln !== null) return -1;
|
|
84671
|
+
else if (rn !== null) return 1;
|
|
84672
|
+
else if (l !== r) return l < r ? -1 : 1;
|
|
84673
|
+
}
|
|
84674
|
+
return 0;
|
|
84675
|
+
}
|
|
84676
|
+
async function npmLatestVersion(fetchImpl, tag = "latest") {
|
|
83245
84677
|
try {
|
|
83246
|
-
const response = await fetchImpl(
|
|
84678
|
+
const response = await fetchImpl(`https://registry.npmjs.org/primitive/${tag}`, {
|
|
83247
84679
|
headers: { accept: "application/json" },
|
|
83248
84680
|
redirect: "follow",
|
|
83249
84681
|
signal: AbortSignal.timeout(3e3)
|
|
@@ -83920,11 +85352,23 @@ async function runMachineDoctor(options) {
|
|
|
83920
85352
|
"cli.version": { inspect: async () => {
|
|
83921
85353
|
const version = options.cliVersion;
|
|
83922
85354
|
if (options.minCliVersion) {
|
|
83923
|
-
const compared = compareVersions(version, options.minCliVersion);
|
|
85355
|
+
const compared = isPrerelease(version) ? compareReleaseVersions(version, options.minCliVersion) : compareVersions(version, options.minCliVersion);
|
|
83924
85356
|
if (compared === null) return check("cli.version", "warn", `Cannot compare ${version} with the required ${options.minCliVersion}.`);
|
|
83925
85357
|
if (compared < 0) return check("cli.version", "fail", `${version} is older than the required ${options.minCliVersion}.`, { action: "update_cli" });
|
|
83926
85358
|
}
|
|
83927
|
-
const
|
|
85359
|
+
const readLatest = options.latestVersion ?? (() => npmLatestVersion(fetchImpl));
|
|
85360
|
+
if (isPrerelease(version)) {
|
|
85361
|
+
const [latest, preview] = await Promise.all([readLatest(), (options.previewVersion ?? (() => npmLatestVersion(fetchImpl, "preview")))()]);
|
|
85362
|
+
const released = latest ? compareReleaseVersions(version, latest) : null;
|
|
85363
|
+
if (released !== null && released < 0) return check("cli.version", "warn", `${version} is a preview older than the latest release ${latest}. Install it with \`npm install -g primitive@latest\`.`, { action: "update_cli" });
|
|
85364
|
+
const previewBehind = preview ? compareReleaseVersions(version, preview) : null;
|
|
85365
|
+
if (previewBehind !== null && previewBehind < 0) return check("cli.version", "warn", `${version} is older than the newest preview ${preview}. Install it with \`npm install -g primitive@preview\`.`, { action: "update_cli" });
|
|
85366
|
+
if (previewBehind === 0) return check("cli.version", "ok", `${version} is the newest preview.`);
|
|
85367
|
+
if (previewBehind !== null) return check("cli.version", "ok", `${version} is not older than the newest preview ${preview}.`);
|
|
85368
|
+
const met = options.minCliVersion ? ` meets the required ${options.minCliVersion};` : ";";
|
|
85369
|
+
return check("cli.version", released !== null || options.minCliVersion ? "ok" : "skip", preview ? `${version}; the newest preview could not be compared with it (the tag is not a version).` : released !== null ? `${version} is not older than the latest release ${latest}; the newest preview could not be checked.` : `${version}${met} neither the latest release nor the newest preview could be checked.`);
|
|
85370
|
+
}
|
|
85371
|
+
const latest = await readLatest();
|
|
83928
85372
|
if (!latest) return options.minCliVersion ? check("cli.version", "ok", `${version} meets the required ${options.minCliVersion}; the latest release could not be checked.`) : check("cli.version", "skip", `${version}; the latest release could not be checked.`);
|
|
83929
85373
|
const behind = compareVersions(version, latest);
|
|
83930
85374
|
if (behind !== null && behind < 0) return check("cli.version", "warn", `${version} is older than the latest release ${latest}.`, { action: "update_cli" });
|
|
@@ -86208,7 +87652,10 @@ var ReplyCommand = class ReplyCommand extends Command {
|
|
|
86208
87652
|
description: "Reply to everyone on the email: the sender (or Reply-To) as To, every other To and Cc address as Cc, minus your own address. Bcc is never included.",
|
|
86209
87653
|
exclusive: ["fyi"]
|
|
86210
87654
|
}),
|
|
86211
|
-
body: Flags.string({
|
|
87655
|
+
body: Flags.string({
|
|
87656
|
+
aliases: ["text"],
|
|
87657
|
+
description: "Plain-text reply body (--text is the same flag). Either --body or --html (or both) is required, except with --fyi."
|
|
87658
|
+
}),
|
|
86212
87659
|
"body-file": Flags.string({ description: "Read the plain-text reply body from a UTF-8 file; this does not attach the file. Use --attachment for attachments. Mutually exclusive with --body and --body-stdin." }),
|
|
86213
87660
|
"body-stdin": Flags.boolean({ description: "Read the plain-text reply body from stdin. Mutually exclusive with --body and --body-file. Stdin can only be consumed once." }),
|
|
86214
87661
|
html: Flags.string({ description: "HTML reply body. Either --body or --html (or both) is required." }),
|
|
@@ -87545,7 +88992,10 @@ var SendCommand = class SendCommand extends Command {
|
|
|
87545
88992
|
}),
|
|
87546
88993
|
from: Flags.string({ description: "Sender address. Without it: a connected agent's own address, your member address on your own login, or a key's one granted address; otherwise the command asks for --from, except that a credential without mail:send is refused by that permission." }),
|
|
87547
88994
|
subject: Flags.string({ description: "Subject line. Defaults to the first line of --body / --html when omitted." }),
|
|
87548
|
-
body: Flags.string({
|
|
88995
|
+
body: Flags.string({
|
|
88996
|
+
aliases: ["text"],
|
|
88997
|
+
description: "Plain-text message body (--text is the same flag). Either --body or --html (or both) is required."
|
|
88998
|
+
}),
|
|
87549
88999
|
"body-file": Flags.string({ description: "Read the plain-text message body from a UTF-8 file. This does not attach the file; use --attachment for file attachments. Mutually exclusive with --body and --body-stdin." }),
|
|
87550
89000
|
"body-stdin": Flags.boolean({ description: "Read the plain-text message body from stdin. Mutually exclusive with --body and --body-file. Stdin can only be consumed once." }),
|
|
87551
89001
|
html: Flags.string({ description: "HTML message body. Either --body or --html (or both) is required." }),
|