+ {LOGO_ART}
+
+ );
+};
+
+const monoFallback = 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, monospace';
diff --git a/demo/src/components/OutputLine.tsx b/demo/src/components/OutputLine.tsx
new file mode 100644
index 00000000..4a023ea5
--- /dev/null
+++ b/demo/src/components/OutputLine.tsx
@@ -0,0 +1,31 @@
+import { interpolate, useCurrentFrame } from "remotion";
+import { f, monoFamily, toneColor } from "../theme";
+import type { OutLineV } from "../timeline";
+
+// Renders one pre-authored output line, fading/sliding in at its start frame.
+export const OutputLine: React.FC<{ line: OutLineV; fontSize: number }> = ({ line, fontSize }) => {
+ const frame = useCurrentFrame();
+ const elapsed = frame - line.start;
+ const opacity = interpolate(elapsed, [0, f(8)], [0, 1], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
+ const dy = interpolate(elapsed, [0, f(8)], [6, 0], { extrapolateLeft: "clamp", extrapolateRight: "clamp" });
+ const indent = " ".repeat(line.line.indent ?? 0);
+
+ return (
+ ` to finish.", tone: "dim" },
+ ],
+ hold: 18,
+ },
+ { kind: "blank" },
+ { kind: "command", text: "primitive signup confirm you@acme.dev 418207", cps: 26, hold: 10 },
+ {
+ kind: "output",
+ perLine: 8,
+ lines: [
+ { text: "Logged in to org 6b21f4e0-9c3a-4d77-b1e2-3f8a0c5d1e94 (Acme).", tone: "success" },
+ { text: "Saved credentials to ~/.config/primitive/credentials.json.", tone: "dim" },
+ ],
+ hold: 26,
+ },
+ ],
+ },
+ {
+ id: "inbox",
+ label: "3 · Inbox",
+ explainer: {
+ heading: "Your inbox is ready",
+ body: "Every new account comes with a real email address your AI agents can receive mail at — already set up and ready to go.",
+ },
+ entries: [
+ { kind: "blank" },
+ { kind: "command", text: "primitive inbox setup", cps: 26, hold: 10 },
+ {
+ kind: "output",
+ perLine: 4,
+ lines: [
+ { text: "Inbound setup", tone: "accent" },
+ { text: "" },
+ { text: "Inbound mail is ready and at least one processing route is enabled." },
+ { text: "" },
+ { text: "Readiness: ready", tone: "success" },
+ { text: "Receiving: yes", tone: "success" },
+ { text: "Processing: yes", tone: "success" },
+ { text: "Mode: actively processed", tone: "dim" },
+ { text: "" },
+ { text: "Receive address: inbox@swift-fox.primitive.email", tone: "accent" },
+ { text: "Receive domain: swift-fox.primitive.email (Primitive-managed)", tone: "dim" },
+ { text: "" },
+ { text: "Domains" },
+ { text: "- acme.dev: ready, receive yes, process yes, routes 1", tone: "dim" },
+ { text: "- swift-fox.primitive.email: ready, receive yes, process yes, routes 1", tone: "dim" },
+ { text: "" },
+ { text: "Processing routes: 3 enabled endpoint(s), 7 deployed Function(s)" },
+ ],
+ hold: 28,
+ },
+ ],
+ },
+ {
+ id: "send",
+ label: "4 · Send",
+ explainer: {
+ heading: "Send an email",
+ body: "One command sends a real email through Primitive — and it waits for the receiving mail server to confirm delivery with a “250 OK”.",
+ },
+ entries: [
+ { kind: "blank" },
+ { kind: "command", text: "primitive send --to inbox@swift-fox.primitive.email \\", cps: 26 },
+ { kind: "command", prefix: " ", prefixTone: "dim", text: '--subject "Hello from the CLI" \\', cps: 30 },
+ {
+ kind: "command",
+ prefix: " ",
+ prefixTone: "dim",
+ text: '--body "Sent straight from my terminal." --wait',
+ cps: 34,
+ hold: 14,
+ },
+ {
+ // Real /send-mail envelope captured from a genuine authenticated send
+ // (wait:true). queue_id is null, client_idempotency_key is a 64-hex
+ // digest, and the smtp_* / delivery_status fields are the real wait
+ // outcome. Only the from/to addresses are mapped to the demo persona.
+ kind: "output",
+ perLine: 4,
+ lines: [
+ { text: "{" },
+ { text: '"id": "238772f2-81fe-4f98-9829-93c6a546b79d",', tone: "string", indent: 2 },
+ { text: '"status": "delivered",', tone: "accent", indent: 2 },
+ { text: '"from": "agent@acme.dev",', tone: "string", indent: 2 },
+ { text: '"queue_id": null,', tone: "dim", indent: 2 },
+ { text: '"accepted": [', tone: "string", indent: 2 },
+ { text: '"inbox@swift-fox.primitive.email"', tone: "string", indent: 4 },
+ { text: "],", indent: 2 },
+ { text: '"rejected": [],', tone: "string", indent: 2 },
+ { text: '"client_idempotency_key": "24f940d0db002e08bcda7d7d9b610511752dd8e6fa29be51a825ff47a8ff83a4",', tone: "string", indent: 2 },
+ { text: '"request_id": "a694fd98-f3f2-4365-88ab-0f82447c8b28",', tone: "string", indent: 2 },
+ { text: '"content_hash": "d5456fb6ad9a7c4d796f5f6f08f79b7f5a560a5b13cbfb7b823c69f75630cd90",', tone: "string", indent: 2 },
+ { text: '"idempotent_replay": false,', tone: "dim", indent: 2 },
+ { text: '"delivery_status": "delivered",', tone: "success", indent: 2 },
+ { text: '"smtp_response_code": 250,', tone: "success", indent: 2 },
+ { text: '"smtp_response_text": "250 2.0.0 Ok: message accepted",', tone: "string", indent: 2 },
+ { text: '"smtp_enhanced_status_code": "2.0.0"', tone: "dim", indent: 2 },
+ { text: "}" },
+ ],
+ hold: 50,
+ },
+ ],
+ },
+];
diff --git a/demo/src/scriptAgent.ts b/demo/src/scriptAgent.ts
new file mode 100644
index 00000000..69afe769
--- /dev/null
+++ b/demo/src/scriptAgent.ts
@@ -0,0 +1,182 @@
+// Storyline 2: "Give your agent email." Same brand + terminal machinery as the
+// SDK demo, different transcript. Every line is grounded in real product
+// behavior:
+// - beat 1: the agent gets an email via the CLI — real `primitive signup`
+// (terms + 6-digit code, captured from a real staging run) and `primitive
+// whoami` (formatWhoamiSummary), whose "Managed inbox: any-local-part@..."
+// line is the agent's assigned *.primitive.email address.
+// - beat 2: real `primitive functions init` scaffold output (email-reply
+// template) + trimmed real lines from the mono-repo dev-help-agent handler
+// (apps/dev-help-agent-fn/handler.ts).
+// - beat 3: real `primitive functions deploy` output — CreateFunctionResult
+// {id,name,deploy_status} JSON + the route-bound stderr hint.
+// - beat 4: real `primitive chat` transcript shape (cli-node .../chat.ts
+// formatChatResponse); the reply body is an accurate answer about the real
+// /v1/send-mail API. Identity is the demo persona (agent@acme.dev).
+
+import type { Section } from "./script";
+
+export const agentIntroTitle = "primitive";
+export const agentIntroTagline = "give your agent email";
+
+export const agentSections: Section[] = [
+ {
+ id: "email",
+ label: "1 · Give your agent email",
+ entries: [
+ { kind: "command", text: "primitive signup agent@acme.dev", cps: 26, hold: 8 },
+ {
+ kind: "output",
+ perLine: 6,
+ lines: [
+ { text: "By continuing, you agree to Primitive's Terms of Service and Privacy Policy:" },
+ { text: " https://primitive.dev/terms", tone: "url" },
+ { text: " https://primitive.dev/privacy", tone: "url" },
+ ],
+ hold: 4,
+ },
+ { kind: "command", prefix: "Type 'yes' to continue: ", prefixTone: "default", text: "yes", cps: 9, hold: 10 },
+ {
+ kind: "output",
+ perLine: 7,
+ lines: [
+ { text: "Sent a 6-digit verification code to agent@acme.dev." },
+ { text: "Run `primitive signup confirm agent@acme.dev ` to finish.", tone: "dim" },
+ ],
+ hold: 14,
+ },
+ { kind: "blank" },
+ { kind: "command", text: "primitive signup confirm agent@acme.dev 418207", cps: 26, hold: 10 },
+ {
+ kind: "output",
+ perLine: 8,
+ lines: [{ text: "Logged in to org 6b21f4e0-9c3a-4d77-b1e2-3f8a0c5d1e94 (Acme).", tone: "success" }],
+ hold: 12,
+ },
+ { kind: "blank" },
+ { kind: "command", text: "primitive whoami", cps: 24, hold: 10 },
+ {
+ kind: "output",
+ perLine: 6,
+ lines: [
+ { text: "Authenticated as agent@acme.dev" },
+ { text: "Account id: 9b3c1a7e-2f44-4d18-bc60-1e5a7d2c9f01", tone: "dim" },
+ { text: "Plan: free", tone: "dim" },
+ { text: "Managed inbox: any-local-part@swift-fox.primitive.email", tone: "accent" },
+ ],
+ hold: 28,
+ },
+ ],
+ },
+ {
+ id: "build",
+ label: "2 · Build the agent",
+ entries: [
+ { kind: "blank" },
+ { kind: "command", text: "primitive functions init dev-help-agent", cps: 26, hold: 10 },
+ {
+ kind: "output",
+ perLine: 5,
+ lines: [
+ { text: "Scaffolded ~/dev-help-agent from email-reply template." },
+ { text: "Next:", tone: "dim" },
+ { text: " cd ~/dev-help-agent", tone: "dim" },
+ { text: " npm install", tone: "dim" },
+ { text: " npm run deploy", tone: "dim" },
+ ],
+ hold: 16,
+ },
+ { kind: "blank" },
+ { kind: "command", text: "cat handler.ts", cps: 22, hold: 10 },
+ {
+ kind: "output",
+ perLine: 6,
+ lines: [
+ { text: "import { createPrimitiveClient, normalizeReceivedEmail }", tone: "dim" },
+ { text: " from '@primitivedotdev/sdk/api'", tone: "dim" },
+ { text: "" },
+ { text: "const ALLOWED_RECIPIENT = 'dev_help@agent.primitive.dev'" },
+ { text: "" },
+ { text: "// receive the email, ask the model, reply with the answer", tone: "dim" },
+ { text: "const email = normalizeReceivedEmail(event)" },
+ { text: "const question = buildQuestion(email.subject, email.text)" },
+ { text: "const answer = await askAgent(env, question)" },
+ { text: "" },
+ { text: "const client = createPrimitiveClient({ apiKey: env.PRIMITIVE_API_KEY })" },
+ { text: "await client.reply(email, { text: answer })", tone: "accent" },
+ ],
+ hold: 30,
+ },
+ ],
+ },
+ {
+ id: "deploy",
+ label: "3 · Deploy it",
+ entries: [
+ { kind: "blank" },
+ { kind: "command", text: "primitive functions deploy --name dev-help-agent --file ./dist/handler.js", cps: 34, hold: 14 },
+ {
+ kind: "output",
+ perLine: 5,
+ lines: [
+ { text: "{" },
+ { text: '"id": "a3f2c1d4-7b8e-4a90-bc11-2e6f5a0d9c34",', tone: "string", indent: 2 },
+ { text: '"name": "dev-help-agent",', tone: "string", indent: 2 },
+ { text: '"deploy_status": "deployed"', tone: "accent", indent: 2 },
+ { text: "}" },
+ { text: "" },
+ { text: "Route bound. Function will receive inbound mail.", tone: "success" },
+ ],
+ hold: 30,
+ },
+ ],
+ },
+ {
+ id: "chat",
+ label: "4 · Chat with it",
+ entries: [
+ { kind: "blank" },
+ { kind: "command", text: 'primitive chat dev_help@agent.primitive.dev "How do I send an email with the API?"', cps: 36, hold: 10 },
+ {
+ kind: "output",
+ perLine: 6,
+ lines: [{ text: "Message sent; waiting for reply from dev_help@agent.primitive.dev", tone: "amber" }],
+ hold: 26,
+ },
+ {
+ kind: "output",
+ perLine: 5,
+ lines: [
+ { text: "Reply received", tone: "success" },
+ { text: "" },
+ { text: "Sent", tone: "accent" },
+ { text: " To: dev_help@agent.primitive.dev", tone: "dim" },
+ { text: " From: agent@acme.dev", tone: "dim" },
+ { text: " Subject: How do I send an email with the API?", tone: "dim" },
+ { text: " Delivery status: delivered", tone: "success" },
+ { text: "" },
+ { text: "Reply", tone: "accent" },
+ { text: " From: dev_help@agent.primitive.dev", tone: "dim" },
+ { text: " Subject: Re: How do I send an email with the API?", tone: "dim" },
+ { text: " Received: 2026-06-15T17:42:08Z", tone: "dim" },
+ { text: " Match: fallback, matched by sender/time window", tone: "dim" },
+ ],
+ hold: 10,
+ },
+ {
+ kind: "output",
+ perLine: 6,
+ lines: [
+ { text: "Response body (text; use --json for parsing)", tone: "accent" },
+ { text: "----- BEGIN RESPONSE -----", tone: "dim" },
+ { text: "Send a POST to https://api.primitive.dev/v1/send-mail with" },
+ { text: "Authorization: Bearer prim_ and a JSON body:" },
+ { text: '{ "from", "to", "subject", "body_text" }.', tone: "string" },
+ { text: "Add an Idempotency-Key header so retries are safe." },
+ { text: "----- END RESPONSE -----", tone: "dim" },
+ ],
+ hold: 55,
+ },
+ ],
+ },
+];
diff --git a/demo/src/scriptAgentSignup.ts b/demo/src/scriptAgentSignup.ts
new file mode 100644
index 00000000..cb50e825
--- /dev/null
+++ b/demo/src/scriptAgentSignup.ts
@@ -0,0 +1,94 @@
+// Storyline: "the agent self-signup flow" — the REAL emailless, zero-touch path
+// a headless agent uses to give ITSELF an identity, driven through the Primitive
+// CLI. One command creates the account with no email and no human; the returned
+// `prim_` API key + provisioned `*.primitive.email` inbox work immediately, on
+// the reply-only `agent` plan.
+//
+// Source of truth (primitive-mono-repo + sdks):
+// - CLI command: `primitive agent create-agent-account` (alias `primitive
+// agent create`) — the generated `createAgentAccount` operation
+// (sdks/cli-node/src/oclif/index.ts COMMAND_ALIASES; sdks/openapi
+// /agent/accounts → operationId createAgentAccount). Generated operation
+// commands print the bare `data` object (api-command.ts
+// operationOutputPayload), so the `{ success, data }` envelope is unwrapped.
+// - Request: CreateAgentAccountInput { terms_accepted: true, device_name? }.
+// - Response: AgentAccountResult { api_key, org_id, address, plan, limits,
+// upgrade } (sdks/openapi/primitive-api.yaml). Endpoint + handler:
+// packages/api/src/routes/v1/agent.ts → createEmaillessAgentAccount.
+// - Payoff: `primitive account show` (alias for getAccount) → GET /v1/account
+// returns { …customer, plan, entitlements, managed_inbox_address, limits }
+// (packages/api/src/routes/v1/account.ts). An emailless account's `email`
+// is null — the literal "emailless" proof — and the `agent` plan grants
+// `send_mail` + `send_to_known_addresses` (reply-only).
+//
+// Everything shown is REAL. `address` / `managed_inbox_address` use the
+// documented example `brave-crow.primitive.email` (auth.md / generateName). The
+// `api_key` is a SECRET shown exactly once, so its value is elided to `prim_…`
+// rather than invented; the org UUID is truncated; nested `limits` / `upgrade`
+// objects are abbreviated with the `"...": "..."` convention auth.md itself
+// uses. No command, flag, field name, or shape is faked.
+
+import type { Section } from "./script";
+
+export const agentSignupIntroTitle = "primitive";
+export const agentSignupCaption = "agent signup";
+// Outro reference: the actual one-command self-signup.
+export const agentSignupOutroInstall = "primitive agent create-agent-account";
+export const agentSignupOutroRepo = "primitive.dev/auth.md";
+
+export const agentSignupSections: Section[] = [
+ {
+ id: "register",
+ label: "1 · Self-register",
+ explainer: {
+ heading: "The agent signs itself up",
+ body: "One command — no email, no human, no browser. Primitive returns a prim_ API key and a managed *.primitive.email inbox on the spot. This is the zero-touch path for headless agents.",
+ },
+ entries: [
+ // hold ~52 (30fps-baseline) → with holdScale 1.3 + f() ≈ 2.3s pause after
+ // the command runs, before the response prints.
+ { kind: "command", text: "primitive agent create-agent-account --terms-accepted", cps: 60, hold: 52 },
+ {
+ kind: "output",
+ perLine: 3,
+ lines: [
+ { text: "{" },
+ { text: '"api_key": "prim_…",', indent: 2 },
+ { text: '"org_id": "6b21f4e0-9c3a-4d77-…",', indent: 2 },
+ { text: '"address": "brave-crow.primitive.email",', indent: 2 },
+ { text: '"plan": "agent",', indent: 2 },
+ { text: '"limits": { "send_per_hour": 10, "send_per_day": 50 },', indent: 2 },
+ { text: '"upgrade": { "plan": "developer", "...": "..." }', indent: 2 },
+ { text: "}" },
+ ],
+ hold: 12,
+ },
+ ],
+ },
+ {
+ id: "use",
+ label: "2 · It's live",
+ explainer: {
+ heading: "The key works immediately",
+ body: "Bearer the new key on any call. The account is emailless (email: null) on the reply-only agent plan, with its own inbox — ready to receive mail and reply. Upgrade later by confirming an email.",
+ },
+ entries: [
+ { kind: "blank" },
+ // hold ~52 → ~2.3s pause after the command runs, before the response.
+ { kind: "command", text: "primitive account show --api-key prim_…", cps: 48, hold: 52 },
+ {
+ kind: "output",
+ perLine: 3,
+ lines: [
+ { text: "{" },
+ { text: '"email": null,', indent: 2 },
+ { text: '"plan": "agent",', indent: 2 },
+ { text: '"managed_inbox_address": "brave-crow.primitive.email",', indent: 2 },
+ { text: '"entitlements": ["send_mail", "send_to_known_addresses"]', indent: 2 },
+ { text: "}" },
+ ],
+ hold: 16,
+ },
+ ],
+ },
+];
diff --git a/demo/src/scriptChatGPT.ts b/demo/src/scriptChatGPT.ts
new file mode 100644
index 00000000..4f9f0160
--- /dev/null
+++ b/demo/src/scriptChatGPT.ts
@@ -0,0 +1,174 @@
+// Storyline: "Primitive, inside ChatGPT" — a live agent↔agent email round-trip.
+// The user asks ChatGPT to email another company's scheduling agent and WAIT;
+// ChatGPT sends real mail via the Primitive connector, watches the thread, a
+// real reply lands, and ChatGPT confirms back — all in one flow. This is the
+// thing only a real two-way inbox makes possible.
+//
+// Faithfulness: the inline cards are the genuine Primitive email-console widget
+// (resources/read ui://widget/primitive-email-v1.html), tool names + titles
+// match the connector's toolTitles map (sendEmail→"Email sent",
+// getEmail→"Email details", replyToEmail→"Reply sent"), and every payload uses
+// the widget's structuredContent shape { tool, status, data } (object → Summary
+// key/values). Identity is the Acme demo persona on its managed inbox.
+
+import { f } from "./theme";
+
+export const chatGptIntroTitle = "primitive";
+export const chatGptIntroTagline = "email, inside ChatGPT";
+export const chatGptOutroPrimary = "now live in the ChatGPT app directory";
+export const chatGptOutroUrl = "primitive.dev/chatgpt";
+
+export interface WidgetEmail {
+ subject: string;
+ from_email?: string;
+ to_email?: string;
+ status?: string;
+}
+
+export interface WidgetPayload {
+ tool: string;
+ status: number;
+ // array → Messages list; object → Summary key/values.
+ data: WidgetEmail[] | Record;
+}
+
+// A conversation is an ordered list of steps. Each step renders in the
+// scrollback in order; the timeline below assigns absolute frames.
+export type Step =
+ | { kind: "user"; text: string }
+ | { kind: "tool"; tool: string; working: string; payload: WidgetPayload }
+ | { kind: "wait"; label: string }
+ | { kind: "say"; text: string };
+
+export const chatSteps: Step[] = [
+ {
+ kind: "user",
+ text: "Email the scheduling agent at scheduling@amber-finch.primitive.email — ask for their earliest demo slot next week, then wait for the reply.",
+ },
+ {
+ kind: "tool",
+ tool: "sendEmail",
+ working: "Sending your email",
+ payload: {
+ tool: "sendEmail",
+ status: 200,
+ data: {
+ id: "em_7c41a9d2",
+ to_email: "scheduling@amber-finch.primitive.email",
+ subject: "Demo availability next week",
+ status: "delivered",
+ },
+ },
+ },
+ { kind: "say", text: "Sent to the scheduling agent. Watching the thread for their reply…" },
+ { kind: "wait", label: "Waiting for reply from scheduling@amber-finch.primitive.email" },
+ {
+ kind: "tool",
+ tool: "getEmail",
+ working: "Reading their reply",
+ payload: {
+ tool: "getEmail",
+ status: 200,
+ data: {
+ from_email: "scheduling@amber-finch.primitive.email",
+ subject: "Re: Demo availability next week",
+ message: "Thursday 10:00 AM PT works for us — I'll hold the slot.",
+ received: "42s ago",
+ status: "received",
+ },
+ },
+ },
+ { kind: "say", text: "The scheduling agent replied — earliest slot is Thursday, 10:00 AM PT. Want me to confirm it?" },
+ { kind: "user", text: "Yes, confirm Thursday 10 AM." },
+ {
+ kind: "tool",
+ tool: "replyToEmail",
+ working: "Confirming the slot",
+ payload: {
+ tool: "replyToEmail",
+ status: 200,
+ data: {
+ id: "em_7c41b0f5",
+ to_email: "scheduling@amber-finch.primitive.email",
+ subject: "Re: Demo availability next week",
+ status: "delivered",
+ },
+ },
+ },
+ { kind: "say", text: "Done ✓ Confirmed Thursday, 10:00 AM PT — the whole thread is in your Primitive inbox." },
+];
+
+// ---- Timeline (baseline 30fps frames; f() scales to render fps) ----
+
+const TYPE_CPS = 32; // composer typing speed
+const ASSISTANT_CPS = 52; // reply streaming speed
+const FPS_BASE = 30;
+
+const USER_PRE = 6; // idle before the user starts typing
+const USER_SEND_PAUSE = 10; // pause after typing, before send
+const USER_SEND_HOLD = 12; // dwell after the bubble lands
+const TOOL_WORKING = 28; // "Working" shown before the chip resolves
+const TOOL_TO_WIDGET = 12; // chip resolve → card reveal
+const WIDGET_DWELL = 92; // hold the card on screen to read it
+const SAY_HOLD = 30; // dwell after a streamed reply
+const WAIT_DUR = 112; // live "waiting for reply" beat
+
+const typeFrames = (text: string, cps: number) => Math.max(8, Math.round((text.length / cps) * FPS_BASE));
+
+export interface TimedStep {
+ step: Step;
+ start: number;
+ end: number;
+ // user
+ typeStart?: number;
+ typeDur?: number;
+ sendAt?: number;
+ // tool
+ workingAt?: number;
+ resolveAt?: number;
+ widgetAt?: number;
+ // say
+ textDur?: number;
+}
+
+export interface ChatTimeline {
+ steps: TimedStep[];
+ total: number; // baseline frames
+}
+
+export function buildChatTimeline(steps: Step[] = chatSteps): ChatTimeline {
+ const timed: TimedStep[] = [];
+ let cursor = 0;
+
+ for (const step of steps) {
+ const start = cursor;
+ if (step.kind === "user") {
+ const typeStart = start + USER_PRE;
+ const typeDur = typeFrames(step.text, TYPE_CPS);
+ const sendAt = typeStart + typeDur + USER_SEND_PAUSE;
+ const end = sendAt + USER_SEND_HOLD;
+ timed.push({ step, start, end, typeStart, typeDur, sendAt });
+ cursor = end;
+ } else if (step.kind === "tool") {
+ const workingAt = start;
+ const resolveAt = start + TOOL_WORKING;
+ const widgetAt = resolveAt + TOOL_TO_WIDGET;
+ const end = widgetAt + WIDGET_DWELL;
+ timed.push({ step, start, end, workingAt, resolveAt, widgetAt });
+ cursor = end;
+ } else if (step.kind === "wait") {
+ const end = start + WAIT_DUR;
+ timed.push({ step, start, end });
+ cursor = end;
+ } else {
+ const textDur = typeFrames(step.text, ASSISTANT_CPS);
+ const end = start + textDur + SAY_HOLD;
+ timed.push({ step, start, end, textDur });
+ cursor = end;
+ }
+ }
+
+ return { steps: timed, total: cursor };
+}
+
+export const chatBodyFrames = (): number => f(buildChatTimeline().total);
diff --git a/demo/src/scriptCombined.ts b/demo/src/scriptCombined.ts
new file mode 100644
index 00000000..48d78ab4
--- /dev/null
+++ b/demo/src/scriptCombined.ts
@@ -0,0 +1,107 @@
+// Combined demo: sign up → deploy a Function → add the skill → chat with it.
+// Explained side-panel cut, ~60s, screen clears between phases, benchmarks slide
+// at the end. Headings / side content are lowercase; terminal lines keep CLI
+// casing. ids/codes/domains are clean mocks (OK per direction); the deployed
+// agent (dev_help) is what we chat at dev_help@agent.acme.com.
+
+import type { Section } from "./script";
+
+export const combinedIntroTitle = "primitive";
+export const combinedIntroTagline = "email infrastructure built for agents";
+
+const FN_ID = "f7c0e9a2";
+
+export const combinedSections: Section[] = [
+ {
+ id: "signup",
+ label: "1 · sign up",
+ explainer: {
+ heading: "get on the network",
+ body: "this is all it takes to put an agent on the network: one signup, one code. it now has its own email address.",
+ },
+ entries: [
+ { kind: "command", text: "primitive signup you@acme.dev --accept-terms", cps: 30, hold: 8 },
+ {
+ kind: "output",
+ perLine: 6,
+ lines: [
+ { text: "Sent a 6-digit verification code to you@acme.dev." },
+ { text: "Run `primitive signup confirm you@acme.dev ` to finish.", tone: "dim" },
+ ],
+ hold: 8,
+ },
+ { kind: "command", text: "primitive signup confirm you@acme.dev 481920", cps: 30, hold: 8 },
+ { kind: "output", perLine: 6, lines: [{ text: "Logged in to org acme (Acme).", tone: "success" }], hold: 6 },
+ { kind: "command", text: "primitive whoami", cps: 26, hold: 8 },
+ {
+ kind: "output",
+ perLine: 6,
+ lines: [
+ { text: "Authenticated as you@acme.dev" },
+ { text: "Managed inbox: any@agent.acme.com", tone: "accent" },
+ ],
+ hold: 18,
+ },
+ ],
+ },
+ {
+ id: "deploy",
+ label: "2 · deploy an agent",
+ explainer: {
+ heading: "deploy an agent",
+ body: "ship a function that runs on every email your agent receives — live at your address in one command.",
+ },
+ entries: [
+ { kind: "command", text: "primitive functions init dev_help --template support", cps: 30, hold: 6 },
+ { kind: "output", perLine: 6, lines: [{ text: "Scaffolded ~/dev_help from support template.", tone: "dim" }], hold: 8 },
+ { kind: "command", text: "primitive functions deploy --name dev_help --source . --wait", cps: 34, hold: 8 },
+ {
+ kind: "output",
+ perLine: 5,
+ lines: [
+ { text: "{" },
+ { text: `"id": "${FN_ID}",`, tone: "string", indent: 2 },
+ { text: '"name": "dev_help",', tone: "string", indent: 2 },
+ { text: '"deploy_status": "deployed"', tone: "accent", indent: 2 },
+ { text: "}" },
+ { text: "" },
+ { text: "any agent can now send to dev_help@agent.acme.com", tone: "success" },
+ ],
+ hold: 18,
+ },
+ ],
+ },
+ {
+ id: "chat",
+ label: "3 · use the cli & chat",
+ explainer: {
+ heading: "use the cli and chat",
+ body: "any agent can leverage the primitive cli to communicate with you and handle your requests.",
+ },
+ entries: [
+ { kind: "command", text: 'primitive chat dev_help@agent.acme.com "how to add a secret?"', cps: 36, hold: 8 },
+ {
+ kind: "output",
+ perLine: 6,
+ lines: [{ text: "Message sent; waiting for reply from dev_help@agent.acme.com", tone: "amber" }],
+ hold: 14,
+ },
+ {
+ kind: "output",
+ perLine: 5,
+ lines: [
+ { text: "Reply received", tone: "success" },
+ { text: "" },
+ { text: "Response body (text)", tone: "accent" },
+ { text: "----- BEGIN RESPONSE -----", tone: "dim" },
+ { text: "Store it as a Function secret, then read it from env:" },
+ { text: " primitive functions set-secret --key OPENAI_KEY \\" },
+ { text: " --value-from-env OPENAI_KEY --redeploy" },
+ { text: "It's injected as env.OPENAI_KEY at runtime." },
+ { text: "----- END RESPONSE -----", tone: "dim" },
+ ],
+ hold: 40,
+ },
+ ],
+ },
+];
diff --git a/demo/src/scriptNetwork.ts b/demo/src/scriptNetwork.ts
new file mode 100644
index 00000000..7566359a
--- /dev/null
+++ b/demo/src/scriptNetwork.ts
@@ -0,0 +1,106 @@
+// YC cut: "get any agent on the network." Minimal + explanatory, ~60s. The story
+// is the SKILL: add it, then watch an agent leverage email on its own. All real.
+//
+// beat 1 (add the skill): real `npx skills add primitivedotdev/skills` output
+// (skills.sh CLI — Clack ◇/● milestones; spinner frames + risk-assessment box
+// omitted for legibility, nothing altered). Installs primitive-chat +
+// primitive-inbox to every detected coding agent (Claude Code, Codex, Zed…).
+// beat 2 (agent leverages email): the agent now has the `primitive chat` verb
+// and uses it to email another agent (dev_help@agent.primitive.dev) and get
+// the answer back. Real `primitive chat` transcript shape (chat.ts
+// formatChatResponse); the reply is an accurate answer about a real CLI flow
+// (`functions set-secret --value-from-env … --redeploy`, the scaffold's own
+// documented pattern). from = agent@ (chat's default sender).
+//
+// Skill source: ~/repos/skills (github.com/primitivedotdev/skills). Identity is
+// the demo persona; commands/flags/output match the real CLIs.
+
+import type { Section } from "./script";
+
+export const networkIntroTitle = "primitive";
+export const networkIntroTagline = "get your agent on the network";
+export const networkOutroInstall = "npx skills add primitivedotdev/skills";
+export const networkOutroRepo = "skills.sh/primitivedotdev/skills";
+
+export const networkSections: Section[] = [
+ {
+ id: "skill",
+ label: "add the skill",
+ explainer: {
+ heading: "Add the skill",
+ body: "One command teaches your coding agent — Claude Code, Codex, and 50+ others — to send email and get the reply. That's the whole on-ramp. Any product can do this.",
+ },
+ entries: [
+ { kind: "command", text: "npx skills add primitivedotdev/skills", cps: 28, hold: 12 },
+ {
+ kind: "output",
+ perLine: 6,
+ lines: [
+ { text: "◇ Source: https://github.com/primitivedotdev/skills.git", tone: "dim" },
+ { text: "◇ Repository cloned", tone: "dim" },
+ { text: "◇ Found 2 skills" },
+ { text: "● Installing to: Claude Code, Codex, Zed", tone: "accent" },
+ { text: "◇ Installation Summary" },
+ { text: " ./.agents/skills/primitive-chat", tone: "dim" },
+ { text: " ./.agents/skills/primitive-inbox", tone: "dim" },
+ { text: "◇ Installation complete", tone: "success" },
+ ],
+ hold: 26,
+ },
+ ],
+ },
+ {
+ id: "chat",
+ label: "now it just emails",
+ explainer: {
+ heading: "Now it just emails",
+ body: "Stuck on a tool, your agent emails the vendor's own agent and gets the answer back — one command, no SMTP, no API keys, no human in the loop.",
+ },
+ entries: [
+ { kind: "blank" },
+ {
+ kind: "command",
+ text: 'primitive chat dev_help@agent.primitive.dev "How do I store a secret for my Function?"',
+ cps: 38,
+ hold: 10,
+ },
+ {
+ kind: "output",
+ perLine: 6,
+ lines: [{ text: "Message sent; waiting for reply from dev_help@agent.primitive.dev", tone: "amber" }],
+ hold: 24,
+ },
+ {
+ kind: "output",
+ perLine: 5,
+ lines: [
+ { text: "Reply received", tone: "success" },
+ { text: "" },
+ { text: "Sent", tone: "accent" },
+ { text: " To: dev_help@agent.primitive.dev", tone: "dim" },
+ { text: " From: agent@swift-fox.primitive.email", tone: "dim" },
+ { text: " Delivery status: delivered", tone: "success" },
+ { text: "" },
+ { text: "Reply", tone: "accent" },
+ { text: " From: dev_help@agent.primitive.dev", tone: "dim" },
+ { text: " Match: fallback, matched by sender/time window", tone: "dim" },
+ ],
+ hold: 8,
+ },
+ {
+ kind: "output",
+ perLine: 6,
+ lines: [
+ { text: "Response body (text; use --json for parsing)", tone: "accent" },
+ { text: "----- BEGIN RESPONSE -----", tone: "dim" },
+ { text: "Set it as a Function secret, then read it from env in your handler:" },
+ { text: " primitive functions set-secret --id --key OPENAI_KEY \\" },
+ { text: " --value-from-env OPENAI_KEY --redeploy" },
+ { text: "It's injected as env.OPENAI_KEY at runtime; redeploy picks it up.", tone: "dim" },
+ { text: "----- END RESPONSE -----", tone: "dim" },
+ ],
+ hold: 50,
+ },
+ ],
+ },
+];
diff --git a/demo/src/scriptX402.ts b/demo/src/scriptX402.ts
new file mode 100644
index 00000000..77200db5
--- /dev/null
+++ b/demo/src/scriptX402.ts
@@ -0,0 +1,107 @@
+// Storyline: "x402 agent-to-agent payments" — the launch-week-02 companion to
+// the agent-signup clip. We watch ONE agent's run transcript: mid-task it needs
+// a GPU compute job it can't run locally, reaches a compute-provider agent over
+// email, clears the payment ITSELF, and gets the result back in the thread.
+//
+// TRUTHFULNESS (this feature is SDK-driven, not auto-wired to email — verified
+// in primitive-mono-repo):
+// - x402 today is explicit SDK calls: the payee calls `x402.charge()` to quote
+// a price; the payer calls `x402.pay(challenge, { signer })` to sign locally
+// and settle. There is NO platform mechanism that auto-injects a 402 onto an
+// email reply (x402.ts mints a SYNTHETIC interaction_id `${uuid}@x402
+// .primitive`; x402_challenges has no FK to any email/thread; engine.test.ts
+// notes interaction-wiring is future work: "approval/x402 WILL"). So this
+// transcript shows the AGENT doing the work: the provider quoted with one
+// charge() call and emailed the challenge back; our agent reads it and pays.
+// Email is the (real) channel; the payment is an explicit (real) SDK action.
+// - Every transcript line maps to a real op: sending/receiving email is core
+// Primitive; `x402.pay()` → POST /v1/x402/challenges/:id/pay; the spend
+// policy (kill-switch / per-payment / daily / allowlist) is enforced
+// server-side on pay; `settle_tx` is the real on-chain hash from the x402
+// facilitator. `buyer-agent.ts` is illustrative glue around those calls.
+// - base-sepolia is the demoable network (settles for free via the public
+// facilitator; mainnet `base` is real USDC). Amounts are testnet USDC base
+// units (6 decimals): "2000000" = 2 USDC, "5000000"/"50000000" = 5/50 USDC.
+// - Persona address (gpu-farm.primitive.email) is a demo identity, per the
+// other clips; the SECRET/unknowable values are truncated for display, never
+// invented: the resolved `pay_to` (0x…), the on-chain `settle_tx` (0x…).
+//
+// Source of truth: sdks/sdk-node/src/x402/client.ts (charge/pay/setSpendPolicy),
+// README "x402 agent-to-agent payments"; packages/api/src/routes/v1/x402.ts.
+
+import type { Section } from "./script";
+
+export const x402IntroTitle = "primitive";
+export const x402Caption = "agent payments";
+// Outro reference: install the SDK that ships the x402 client.
+export const x402OutroInstall = "npm i @primitivedotdev/sdk";
+export const x402OutroRepo = "primitive.dev/blog/launch-week-02";
+
+export const x402Sections: Section[] = [
+ {
+ id: "job",
+ label: "1 · The job",
+ explainer: {
+ heading: "Your agent needs compute",
+ body: "Mid-task it needs a GPU job it can't run locally. It reaches a compute-provider agent over email and gets back a price — not a signup wall. The provider quoted it with one x402 call; our agent just reads the reply.",
+ },
+ entries: [
+ { kind: "command", text: "npx tsx buyer-agent.ts", cps: 60, hold: 44 },
+ {
+ kind: "output",
+ perLine: 4,
+ lines: [
+ { text: "job: embed 2M documents — no local GPU", tone: "accent" },
+ { text: "→ emailing jobs@gpu-farm.primitive.email …", tone: "dim" },
+ { text: "← reply: queued · 2 USDC to start the run", tone: "amber" },
+ ],
+ hold: 16,
+ },
+ ],
+ },
+ {
+ id: "pay",
+ label: "2 · Clear it",
+ explainer: {
+ heading: "It pays — within your limits",
+ body: "The agent signs an EIP-3009 authorization with its own key (the key never leaves it) and Primitive settles on Base. Non-custodial. It stays inside the spend policy you set — over the cap, the payment is declined and logged.",
+ },
+ entries: [
+ { kind: "blank" },
+ {
+ kind: "output",
+ perLine: 4,
+ lines: [
+ { text: "→ challenge: 2 USDC · base-sepolia", tone: "default" },
+ { text: " pay_to 0x8f3c…b21c", tone: "dim" },
+ { text: "→ spend policy: ≤5 USDC · ≤50/day ✓ ok", tone: "default" },
+ { text: "→ signing transferWithAuthorization …", tone: "dim" },
+ { text: "→ x402.pay() → settled ✓", tone: "success" },
+ { text: " tx 0x… ↗ basescan", tone: "url" },
+ ],
+ hold: 18,
+ },
+ ],
+ },
+ {
+ id: "settled",
+ label: "3 · Settled",
+ explainer: {
+ heading: "Work comes back, with a receipt",
+ body: "The provider runs the job and returns the result in the same thread. One email exchange, one on-chain payment — no invoice, no Stripe account, no human in the loop — and a receipt you can audit.",
+ },
+ entries: [
+ { kind: "blank" },
+ {
+ kind: "output",
+ perLine: 4,
+ lines: [
+ { text: "← job complete · 2M embeddings ready", tone: "accent" },
+ { text: "→ replying to the thread with the output", tone: "dim" },
+ { text: "✓ done · paid 2 USDC · 0 humans · 1 thread", tone: "success" },
+ ],
+ hold: 14,
+ },
+ ],
+ },
+];
diff --git a/demo/src/theme.ts b/demo/src/theme.ts
new file mode 100644
index 00000000..81b75d3b
--- /dev/null
+++ b/demo/src/theme.ts
@@ -0,0 +1,125 @@
+import { loadFont as loadMono } from "@remotion/google-fonts/JetBrainsMono";
+import { loadFont as loadInter } from "@remotion/google-fonts/Inter";
+import { continueRender, delayRender, staticFile } from "remotion";
+
+// Brand system mirrored from primitive-mono-repo/web (app/globals.css):
+// brutalist / retro-computing — JetBrains Mono everywhere, sharp corners,
+// thick borders, hard offset shadows, green primary, base #1d1d1d / #f4f4f4.
+const mono = loadMono("normal", {
+ weights: ["400", "700", "800"],
+ subsets: ["latin"],
+ ignoreTooManyRequestsWarning: true,
+});
+
+export const monoFamily = mono.fontFamily;
+// The wordmark/titles use mono too (the site sets `body { font-mono }`).
+export const sansFamily = mono.fontFamily;
+
+// Inter — used ONLY for the mocked ChatGPT host chrome (sidebar, message
+// bubbles, composer) so it reads as the real app. The Primitive email widget
+// embedded inside it stays JetBrains Mono, on-brand, exactly like production.
+const inter = loadInter("normal", {
+ weights: ["400", "500", "600", "700"],
+ subsets: ["latin"],
+ ignoreTooManyRequestsWarning: true,
+});
+export const uiSansFamily = inter.fontFamily;
+
+// The custom logo face used to render the braille-art mark (PrimitiveLogoMono).
+export const LOGO_FONT = "PrimitiveLogoMono";
+if (typeof document !== "undefined") {
+ const handle = delayRender("load-logo-font");
+ const face = new FontFace(LOGO_FONT, `url(${staticFile("PrimitiveLogoMono.woff2")})`);
+ face
+ .load()
+ .then((loaded) => {
+ document.fonts.add(loaded);
+ continueRender(handle);
+ })
+ .catch(() => continueRender(handle));
+}
+
+export type Format = "landscape" | "square" | "vertical";
+
+export const BASE_FPS = 30;
+export const FPS = 60;
+export const f = (baselineFrames: number): number => Math.round((baselineFrames * FPS) / BASE_FPS);
+
+// Dark-mode brand tokens from globals.css :root / .dark.
+export const theme = {
+ // base
+ baseDark: "#1d1d1d",
+ baseDarkSecondary: "#181818",
+ baseLight: "#f4f4f4",
+ muted: "#9a9a9a", // base-muted-dark
+
+ // app surface (flat — brutalist, no gradient glow)
+ pageBg: "#1d1d1d",
+
+ // terminal window: dark surface, thick light foreground border, hard shadow
+ windowBg: "#181818",
+ windowBorder: "#f4f4f4",
+ titlebarBg: "#1d1d1d",
+ titlebarText: "#9a9a9a",
+ // brutalist hard offset shadow color (foreground)
+ hardShadow: "#f4f4f4",
+ dotRed: "#dc2626",
+ dotYellow: "#fbbf24",
+ dotGreen: "#15803d",
+
+ // text
+ text: "#f4f4f4",
+ dim: "#9a9a9a",
+ prompt: "#4ade80", // bright green $
+ command: "#f4f4f4",
+ accent: "#22c55e", // brand green (bright on dark)
+ accentDeep: "#15803d", // primary green
+ amber: "#fbbf24",
+ url: "#57c7ff", // dark-mode logo-scanline blue
+ jsonKey: "#57c7ff",
+ jsonString: "#f4f4f4",
+ success: "#4ade80",
+ cursor: "#4ade80",
+
+ // animated braille glyph (dark-mode --logo-idle-* + reveal/glitch)
+ logoIdle1: "hsl(150, 90%, 65%)",
+ logoIdle2: "hsl(175, 80%, 55%)",
+ logoIdle3: "hsl(200, 80%, 60%)",
+ logoGlitch: "#ff6ac1",
+
+ cardText: "#f4f4f4",
+ cardDim: "#9a9a9a",
+} as const;
+
+export type Tone = "default" | "dim" | "success" | "url" | "accent" | "key" | "string" | "amber";
+
+export function toneColor(tone: Tone | undefined): string {
+ switch (tone) {
+ case "dim":
+ return theme.dim;
+ case "success":
+ return theme.success;
+ case "url":
+ return theme.url;
+ case "accent":
+ return theme.accent;
+ case "amber":
+ return theme.amber;
+ case "key":
+ return theme.jsonKey;
+ case "string":
+ return theme.jsonString;
+ default:
+ return theme.text;
+ }
+}
+
+// Per-format layout tuning.
+export const layout: Record<
+ Format,
+ { width: number; height: number; fontSize: number; maxLines: number; padding: number }
+> = {
+ landscape: { width: 1920, height: 1080, fontSize: 30, maxLines: 22, padding: 120 },
+ square: { width: 1080, height: 1080, fontSize: 26, maxLines: 20, padding: 60 },
+ vertical: { width: 1080, height: 1920, fontSize: 30, maxLines: 24, padding: 60 },
+};
diff --git a/demo/src/timeline.ts b/demo/src/timeline.ts
new file mode 100644
index 00000000..fcb1a71e
--- /dev/null
+++ b/demo/src/timeline.ts
@@ -0,0 +1,125 @@
+import { FPS, f } from "./theme";
+import { type Entry, type OutLine, type Section, type Tone, sections } from "./script";
+
+// Baseline (30fps) frame counts; converted to the render rate via f() at use.
+const DEFAULT_CPS = 26;
+const DEFAULT_HOLD = 10;
+const DEFAULT_PERLINE = 6;
+const BLANK_FRAMES = 7;
+
+export interface CmdLine {
+ kind: "cmd";
+ start: number;
+ typeDuration: number;
+ endHold: number;
+ prefix: string;
+ prefixTone: Tone;
+ text: string;
+ sectionId: string;
+}
+
+export interface OutLineV {
+ kind: "out";
+ start: number;
+ line: OutLine;
+ sectionId: string;
+}
+
+export interface BlankLine {
+ kind: "blank";
+ start: number;
+ sectionId: string;
+}
+
+export type VLine = CmdLine | OutLineV | BlankLine;
+
+export interface SectionRange {
+ id: string;
+ label: string;
+ start: number;
+ end: number;
+}
+
+export interface Timeline {
+ lines: VLine[];
+ ranges: SectionRange[];
+ total: number;
+}
+
+function typeFrames(text: string, cps: number): number {
+ // cps is chars/second, so this is already real-time-correct at any FPS.
+ return Math.max(f(6), Math.ceil((text.length / cps) * FPS));
+}
+
+export interface TimelineOptions {
+ // Multiplier applied to every hold/pause (1 = authored pacing, >1 = slower).
+ holdScale?: number;
+ // Idle pause (30fps-baseline frames) inserted at the start of each section,
+ // before its first entry — gives the viewer time to read the explainer.
+ leadInFrames?: number;
+ // Extra dwell (30fps-baseline frames) held at the END of each section, with
+ // the finished output still on screen, before the next section begins.
+ sectionEndHoldFrames?: number;
+ // Pad each section to this many FINAL frames so every step takes equal
+ // wall-time (even distribution). The slack is held at the end (content on
+ // screen). Sections naturally longer than this are left as-is.
+ equalizeSectionFinalFrames?: number;
+}
+
+export function buildTimeline(secs: Section[] = sections, opts: TimelineOptions = {}): Timeline {
+ const holdScale = opts.holdScale ?? 1;
+ const leadIn = f(opts.leadInFrames ?? 0);
+ const sectionEndHold = f(opts.sectionEndHoldFrames ?? 0);
+ const scaleHold = (baseline: number) => f(Math.round(baseline * holdScale));
+
+ const lines: VLine[] = [];
+ const ranges: SectionRange[] = [];
+ let cursor = 0;
+
+ for (const section of secs) {
+ const sectionStart = cursor;
+ // Lead-in pause: terminal sits idle while the explainer panel is read.
+ cursor += leadIn;
+ for (const entry of section.entries as Entry[]) {
+ if (entry.kind === "blank") {
+ lines.push({ kind: "blank", start: cursor, sectionId: section.id });
+ cursor += f(BLANK_FRAMES);
+ continue;
+ }
+ if (entry.kind === "command") {
+ const cps = entry.cps ?? DEFAULT_CPS;
+ const dur = typeFrames(entry.text, cps);
+ const endHold = scaleHold(entry.hold ?? DEFAULT_HOLD);
+ lines.push({
+ kind: "cmd",
+ start: cursor,
+ typeDuration: dur,
+ endHold,
+ prefix: entry.prefix ?? "$ ",
+ prefixTone: entry.prefixTone ?? "accent",
+ text: entry.text,
+ sectionId: section.id,
+ });
+ cursor += dur + endHold;
+ continue;
+ }
+ // output
+ const perLine = f(entry.perLine ?? DEFAULT_PERLINE);
+ entry.lines.forEach((line, i) => {
+ lines.push({ kind: "out", start: cursor + i * perLine, line, sectionId: section.id });
+ });
+ cursor += entry.lines.length * perLine + scaleHold(entry.hold ?? DEFAULT_HOLD);
+ }
+ // Hold the finished step on screen before clearing to the next.
+ cursor += sectionEndHold;
+ // Equalize step wall-time: pad to the target so every step is the same
+ // length (slack held at the end, content on screen).
+ const equalizeTo = opts.equalizeSectionFinalFrames;
+ if (equalizeTo && cursor - sectionStart < equalizeTo) {
+ cursor = sectionStart + equalizeTo;
+ }
+ ranges.push({ id: section.id, label: section.label, start: sectionStart, end: cursor });
+ }
+
+ return { lines, ranges, total: cursor };
+}
diff --git a/demo/tsconfig.json b/demo/tsconfig.json
new file mode 100644
index 00000000..aa2d7080
--- /dev/null
+++ b/demo/tsconfig.json
@@ -0,0 +1,17 @@
+{
+ "compilerOptions": {
+ "target": "ESNext",
+ "module": "ESNext",
+ "moduleResolution": "Bundler",
+ "jsx": "react-jsx",
+ "lib": ["DOM", "DOM.Iterable", "ESNext"],
+ "strict": true,
+ "noUnusedLocals": true,
+ "noUnusedParameters": true,
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "noEmit": true
+ },
+ "include": ["src", "remotion.config.ts"]
+}
diff --git a/openapi/primitive-api.codegen.json b/openapi/primitive-api.codegen.json
index fe39aed9..fcfdafc1 100644
--- a/openapi/primitive-api.codegen.json
+++ b/openapi/primitive-api.codegen.json
@@ -4114,6 +4114,72 @@
}
}
},
+ "/sent-emails/{id}/reply": {
+ "get": {
+ "operationId": "awaitReply",
+ "summary": "Get (or wait for) the reply to a sent email",
+ "description": "Returns the first threaded inbound reply to a send, keyed by\nthe inbound email's `reply_to_sent_email_id`. This is the\ncanonical \"did a reply arrive for this send?\" call: after\n/send-mail, poll (or long-poll) here instead of hand-rolling\nan /emails/search loop.\n\nBy default the call returns immediately with `reply: null`\nwhen nothing has arrived yet. Set `wait=true` to long-poll:\nthe server holds the request up to `wait_timeout_ms`\n(default 10000, max 30000), returning as soon as the first\nreply lands. On a wait that elapses with no reply, the\nresponse has `reply: null` and `timed_out: true`.\n\nThe reply object is compact (headers plus bodies); fetch\n`/emails/{id}` with `reply.id` for the fully parsed record,\nor `/threads/{thread_id}` for the whole back-and-forth.\n",
+ "tags": [
+ "Sending"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/ResourceId"
+ },
+ {
+ "name": "wait",
+ "in": "query",
+ "schema": {
+ "type": "boolean"
+ },
+ "description": "When true, long-poll up to `wait_timeout_ms` for the\nfirst reply to arrive instead of returning immediately.\nMirrors send-mail's server-side `wait` semantics. The\nserver accepts only the literal strings `true` / `false`\n(standard boolean query serialization); omitted means\nno wait.\n"
+ },
+ {
+ "name": "wait_timeout_ms",
+ "in": "query",
+ "schema": {
+ "type": "integer",
+ "minimum": 1000,
+ "maximum": 30000
+ },
+ "description": "Maximum time to hold the request when `wait=true`.\nServer default is 10000. NOT given an OpenAPI `default`\non purpose, matching the `/emails` `wait` parameter: a\ndefault makes some generators send the value on every\ncall.\n"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Reply status for the send (reply may be null)",
+ "content": {
+ "application/json": {
+ "schema": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/SuccessEnvelope"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/AwaitReplyResult"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ },
+ "400": {
+ "$ref": "#/components/responses/ValidationError"
+ },
+ "401": {
+ "$ref": "#/components/responses/Unauthorized"
+ },
+ "404": {
+ "$ref": "#/components/responses/NotFound"
+ }
+ }
+ }
+ },
"/threads/{id}": {
"parameters": [
{
@@ -11908,6 +11974,106 @@
}
]
},
+ "ReplyEmail": {
+ "type": "object",
+ "description": "A threaded inbound reply to one of the org's sends, keyed by\nthe inbound email's `reply_to_sent_email_id`. Compact on\npurpose: enough to read the reply and decide what to do\nnext, with `/emails/{id}` available for the fully parsed\ndetail.\n",
+ "properties": {
+ "id": {
+ "type": "string",
+ "format": "uuid",
+ "description": "Inbound email row id; usable with `/emails/{id}`."
+ },
+ "thread_id": {
+ "type": "string",
+ "format": "uuid",
+ "description": "Conversation thread id; usable with `/threads/{id}`.",
+ "nullable": true
+ },
+ "reply_to_sent_email_id": {
+ "type": "string",
+ "format": "uuid",
+ "description": "The sent-email id this inbound message replied to.",
+ "nullable": true
+ },
+ "from_email": {
+ "type": "string",
+ "description": "Sender of the reply (From header when present, else envelope sender)."
+ },
+ "to_email": {
+ "type": "string",
+ "description": "Recipient address the reply arrived at."
+ },
+ "subject": {
+ "type": "string",
+ "nullable": true
+ },
+ "body_text": {
+ "type": "string",
+ "description": "Plain-text body of the reply, when present.",
+ "nullable": true
+ },
+ "body_html": {
+ "type": "string",
+ "description": "HTML body of the reply, when present.",
+ "nullable": true
+ },
+ "received_at": {
+ "type": "string",
+ "format": "date-time",
+ "nullable": true
+ },
+ "status": {
+ "type": "string",
+ "description": "Inbound processing status of the reply row. Typically an\n`EmailStatus` value, but left as an open string here to\nmatch the server contract, which does not narrow it.\n"
+ }
+ },
+ "required": [
+ "id",
+ "thread_id",
+ "reply_to_sent_email_id",
+ "from_email",
+ "to_email",
+ "subject",
+ "body_text",
+ "body_html",
+ "received_at",
+ "status"
+ ]
+ },
+ "AwaitReplyResult": {
+ "type": "object",
+ "description": "Result of `/sent-emails/{id}/reply`. `reply` is null when no\nreply has arrived yet (no-wait call, or the wait timed out).\n",
+ "properties": {
+ "sent_email_id": {
+ "type": "string",
+ "format": "uuid",
+ "description": "The send this lookup was keyed on (echoes the path id)."
+ },
+ "reply": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/ReplyEmail"
+ }
+ ],
+ "nullable": true
+ },
+ "waited": {
+ "type": "boolean",
+ "description": "Whether the call ran in long-poll mode (`wait=true`)."
+ },
+ "timed_out": {
+ "type": "boolean",
+ "description": "True only when a `wait=true` call elapsed its timeout with no reply."
+ }
+ },
+ "required": [
+ "sent_email_id",
+ "reply",
+ "waited",
+ "timed_out"
+ ],
+ "additionalProperties": false
+ },
"ReplyInput": {
"type": "object",
"additionalProperties": false,
diff --git a/openapi/primitive-api.yaml b/openapi/primitive-api.yaml
index b724cc8c..70431df4 100644
--- a/openapi/primitive-api.yaml
+++ b/openapi/primitive-api.yaml
@@ -3053,6 +3053,72 @@ paths:
'404':
$ref: '#/components/responses/NotFound'
+ /sent-emails/{id}/reply:
+ get:
+ operationId: awaitReply
+ summary: Get (or wait for) the reply to a sent email
+ description: |
+ Returns the first threaded inbound reply to a send, keyed by
+ the inbound email's `reply_to_sent_email_id`. This is the
+ canonical "did a reply arrive for this send?" call: after
+ /send-mail, poll (or long-poll) here instead of hand-rolling
+ an /emails/search loop.
+
+ By default the call returns immediately with `reply: null`
+ when nothing has arrived yet. Set `wait=true` to long-poll:
+ the server holds the request up to `wait_timeout_ms`
+ (default 10000, max 30000), returning as soon as the first
+ reply lands. On a wait that elapses with no reply, the
+ response has `reply: null` and `timed_out: true`.
+
+ The reply object is compact (headers plus bodies); fetch
+ `/emails/{id}` with `reply.id` for the fully parsed record,
+ or `/threads/{thread_id}` for the whole back-and-forth.
+ tags: [Sending]
+ parameters:
+ - $ref: '#/components/parameters/ResourceId'
+ - name: wait
+ in: query
+ schema:
+ type: boolean
+ description: |
+ When true, long-poll up to `wait_timeout_ms` for the
+ first reply to arrive instead of returning immediately.
+ Mirrors send-mail's server-side `wait` semantics. The
+ server accepts only the literal strings `true` / `false`
+ (standard boolean query serialization); omitted means
+ no wait.
+ - name: wait_timeout_ms
+ in: query
+ schema:
+ type: integer
+ minimum: 1000
+ maximum: 30000
+ description: |
+ Maximum time to hold the request when `wait=true`.
+ Server default is 10000. NOT given an OpenAPI `default`
+ on purpose, matching the `/emails` `wait` parameter: a
+ default makes some generators send the value on every
+ call.
+ responses:
+ '200':
+ description: Reply status for the send (reply may be null)
+ content:
+ application/json:
+ schema:
+ allOf:
+ - $ref: '#/components/schemas/SuccessEnvelope'
+ - type: object
+ properties:
+ data:
+ $ref: '#/components/schemas/AwaitReplyResult'
+ '400':
+ $ref: '#/components/responses/ValidationError'
+ '401':
+ $ref: '#/components/responses/Unauthorized'
+ '404':
+ $ref: '#/components/responses/NotFound'
+
# ---------------------------------------------------------------------------
# Threads
# ---------------------------------------------------------------------------
@@ -8536,6 +8602,75 @@ components:
carried only a plain-text body, or when bodies
have been discarded post-send.
+ ReplyEmail:
+ type: object
+ description: |
+ A threaded inbound reply to one of the org's sends, keyed by
+ the inbound email's `reply_to_sent_email_id`. Compact on
+ purpose: enough to read the reply and decide what to do
+ next, with `/emails/{id}` available for the fully parsed
+ detail.
+ properties:
+ id:
+ type: string
+ format: uuid
+ description: Inbound email row id; usable with `/emails/{id}`.
+ thread_id:
+ type: [string, 'null']
+ format: uuid
+ description: Conversation thread id; usable with `/threads/{id}`.
+ reply_to_sent_email_id:
+ type: [string, 'null']
+ format: uuid
+ description: The sent-email id this inbound message replied to.
+ from_email:
+ type: string
+ description: Sender of the reply (From header when present, else envelope sender).
+ to_email:
+ type: string
+ description: Recipient address the reply arrived at.
+ subject:
+ type: [string, 'null']
+ body_text:
+ type: [string, 'null']
+ description: Plain-text body of the reply, when present.
+ body_html:
+ type: [string, 'null']
+ description: HTML body of the reply, when present.
+ received_at:
+ type: [string, 'null']
+ format: date-time
+ status:
+ type: string
+ description: |
+ Inbound processing status of the reply row. Typically an
+ `EmailStatus` value, but left as an open string here to
+ match the server contract, which does not narrow it.
+ required: [id, thread_id, reply_to_sent_email_id, from_email, to_email, subject, body_text, body_html, received_at, status]
+
+ AwaitReplyResult:
+ type: object
+ description: |
+ Result of `/sent-emails/{id}/reply`. `reply` is null when no
+ reply has arrived yet (no-wait call, or the wait timed out).
+ properties:
+ sent_email_id:
+ type: string
+ format: uuid
+ description: The send this lookup was keyed on (echoes the path id).
+ reply:
+ allOf:
+ - $ref: '#/components/schemas/ReplyEmail'
+ nullable: true
+ waited:
+ type: boolean
+ description: Whether the call ran in long-poll mode (`wait=true`).
+ timed_out:
+ type: boolean
+ description: True only when a `wait=true` call elapsed its timeout with no reply.
+ required: [sent_email_id, reply, waited, timed_out]
+ additionalProperties: false
+
ReplyInput:
type: object
additionalProperties: false
diff --git a/packages/api-core/src/api/index.ts b/packages/api-core/src/api/index.ts
index e04782cd..fe619edc 100644
--- a/packages/api-core/src/api/index.ts
+++ b/packages/api-core/src/api/index.ts
@@ -1,4 +1,4 @@
// This file is auto-generated by @hey-api/openapi-ts
-export { addDomain, cliLogout, createAgentAccount, createAgentClaimLink, createChallenge, createEmailChallenge, createEndpoint, createFilter, createFunction, createFunctionSecret, createOrgSecret, createRegistry, createRoute, createWakeAuthorization, createWakeSchedule, decideRegistryRequest, defineAgent, deleteDomain, deleteEmail, deleteEndpoint, deleteFilter, deleteFunction, deleteFunctionSecret, deleteMemory, deleteOrgSecret, deleteRegistry, deleteRoute, deleteWakeAuthorization, deleteWakeSchedule, discardEmailContent, downloadAttachments, downloadDomainZoneFile, downloadRawEmail, getAccount, getAgent, getChallenge, getConversation, getEmail, getFunction, getFunctionRouting, getFunctionTestRunTrace, getInboxStatus, getMemory, getOrgRoutingTopology, getRegistry, getSendPermissions, getSentEmail, getSpendPolicy, getStorageStats, getTemplate, getTemplateInstall, getThread, getWakeSchedule, getWebhookSecret, installTemplate, listDeclinedPayments, listDeliveries, listDomains, listEmails, listEndpoints, listFilters, listFunctionLogs, listFunctions, listFunctionSecrets, listOrgSecrets, listPayoutAddresses, listRegistries, listRegistryAgents, listRegistryRequests, listRoutes, listSentEmails, listTemplates, listWakeAuthorizations, listWakeDispatches, listWakeSchedules, type Options, payChallenge, pollCliLogin, publishAgent, registerPayoutAddress, reorderRoutes, replayDelivery, replayEmailWebhooks, replyToEmail, resendAgentSignupVerification, resendCliSignupVerification, resolveRegistryHandle, rotateWebhookSecret, runWakeSchedule, searchEmails, searchMemories, semanticSearch, sendEmail, setFunctionRoute, setFunctionSecret, setMemory, setOrgSecret, simulateRoute, startAgentClaim, startAgentSignup, startCliLogin, startCliSignup, testEndpoint, testFunction, unpublishAgent, unsetFunctionRoute, updateAccount, updateDomain, updateEndpoint, updateFilter, updateFunction, updateRegistry, updateRoute, updateSpendPolicy, updateWakeAuthorization, updateWakeSchedule, verifyAgentClaim, verifyAgentSignup, verifyCliSignup, verifyDomain } from './sdk.gen.js';
-export type { Account, AccountUpdated, AddDomainData, AddDomainError, AddDomainErrors, AddDomainInput, AddDomainResponse, AddDomainResponses, AgentAccountResult, AgentAccountUpgradeHint, AgentClaimLinkResult, AgentClaimResult, AgentClaimStartResult, AgentOrgRef, AgentSignupResendResult, AgentSignupStartResult, AgentSignupVerifyResult, ClientOptions, CliLoginPollResult, CliLoginStartResult, CliLogoutData, CliLogoutError, CliLogoutErrors, CliLogoutInput, CliLogoutResponse, CliLogoutResponses, CliLogoutResult, CliSignupResendResult, CliSignupStartResult, CliSignupVerifyResult, Conversation, ConversationMessage, CreateAgentAccountData, CreateAgentAccountError, CreateAgentAccountErrors, CreateAgentAccountInput, CreateAgentAccountResponse, CreateAgentAccountResponses, CreateAgentClaimLinkData, CreateAgentClaimLinkError, CreateAgentClaimLinkErrors, CreateAgentClaimLinkInput, CreateAgentClaimLinkResponse, CreateAgentClaimLinkResponses, CreateChallengeData, CreateChallengeError, CreateChallengeErrors, CreateChallengeInput, CreateChallengeResponse, CreateChallengeResponses, CreateEmailChallengeData, CreateEmailChallengeError, CreateEmailChallengeErrors, CreateEmailChallengeInput, CreateEmailChallengeResponse, CreateEmailChallengeResponses, CreateEndpointData, CreateEndpointError, CreateEndpointErrors, CreateEndpointInput, CreateEndpointResponse, CreateEndpointResponses, CreateFilterData, CreateFilterError, CreateFilterErrors, CreateFilterInput, CreateFilterResponse, CreateFilterResponses, CreateFunctionData, CreateFunctionError, CreateFunctionErrors, CreateFunctionInput, CreateFunctionResponse, CreateFunctionResponses, CreateFunctionResult, CreateFunctionSecretData, CreateFunctionSecretError, CreateFunctionSecretErrors, CreateFunctionSecretInput, CreateFunctionSecretResponse, CreateFunctionSecretResponses, CreateOrgSecretData, CreateOrgSecretError, CreateOrgSecretErrors, CreateOrgSecretInput, CreateOrgSecretResponse, CreateOrgSecretResponses, CreateRegistryData, CreateRegistryError, CreateRegistryErrors, CreateRegistryInput, CreateRegistryResponse, CreateRegistryResponses, CreateRouteData, CreateRouteError, CreateRouteErrors, CreateRouteInput, CreateRouteResponse, CreateRouteResponses, CreateWakeAuthorizationData, CreateWakeAuthorizationError, CreateWakeAuthorizationErrors, CreateWakeAuthorizationInput, CreateWakeAuthorizationResponse, CreateWakeAuthorizationResponses, CreateWakeScheduleData, CreateWakeScheduleError, CreateWakeScheduleErrors, CreateWakeScheduleInput, CreateWakeScheduleResponse, CreateWakeScheduleResponses, Cursor, DecideRegistryRequestData, DecideRegistryRequestError, DecideRegistryRequestErrors, DecideRegistryRequestInput, DecideRegistryRequestResponse, DecideRegistryRequestResponses, DefineAgentData, DefineAgentError, DefineAgentErrors, DefineAgentInput, DefineAgentResponse, DefineAgentResponses, DeleteDomainData, DeleteDomainError, DeleteDomainErrors, DeleteDomainResponse, DeleteDomainResponses, DeleteEmailData, DeleteEmailError, DeleteEmailErrors, DeleteEmailResponse, DeleteEmailResponses, DeleteEndpointData, DeleteEndpointError, DeleteEndpointErrors, DeleteEndpointResponse, DeleteEndpointResponses, DeleteFilterData, DeleteFilterError, DeleteFilterErrors, DeleteFilterResponse, DeleteFilterResponses, DeleteFunctionData, DeleteFunctionError, DeleteFunctionErrors, DeleteFunctionResponse, DeleteFunctionResponses, DeleteFunctionSecretData, DeleteFunctionSecretError, DeleteFunctionSecretErrors, DeleteFunctionSecretResponse, DeleteFunctionSecretResponses, DeleteMemoryData, DeleteMemoryError, DeleteMemoryErrors, DeleteMemoryResponse, DeleteMemoryResponses, DeleteMemoryResult, DeleteOrgSecretData, DeleteOrgSecretError, DeleteOrgSecretErrors, DeleteOrgSecretResponse, DeleteOrgSecretResponses, DeleteRegistryData, DeleteRegistryError, DeleteRegistryErrors, DeleteRegistryResponse, DeleteRegistryResponses, DeleteRouteData, DeleteRouteError, DeleteRouteErrors, DeleteRouteResponse, DeleteRouteResponses, DeleteWakeAuthorizationData, DeleteWakeAuthorizationError, DeleteWakeAuthorizationErrors, DeleteWakeAuthorizationResponse, DeleteWakeAuthorizationResponses, DeleteWakeScheduleData, DeleteWakeScheduleError, DeleteWakeScheduleErrors, DeleteWakeScheduleResponse, DeleteWakeScheduleResponses, DeliveryStatus, DeliverySummary, DiscardContentResult, DiscardEmailContentData, DiscardEmailContentError, DiscardEmailContentErrors, DiscardEmailContentResponse, DiscardEmailContentResponses, DkimSignature, Domain, DomainDnsRecord, DomainVerifyResult, DownloadAttachmentsData, DownloadAttachmentsError, DownloadAttachmentsErrors, DownloadAttachmentsResponse, DownloadAttachmentsResponses, DownloadDomainZoneFileData, DownloadDomainZoneFileError, DownloadDomainZoneFileErrors, DownloadDomainZoneFileResponse, DownloadDomainZoneFileResponses, DownloadRawEmailData, DownloadRawEmailError, DownloadRawEmailErrors, DownloadRawEmailResponse, DownloadRawEmailResponses, EmailAddress, EmailAttachment, EmailAuth, EmailDetail, EmailDetailReply, EmailSearchFacetBucket, EmailSearchFacets, EmailSearchHighlights, EmailSearchMeta, EmailSearchResult, EmailStatus, EmailSummary, EmailWebhookStatus, Endpoint, ErrorResponse, Filter, FunctionDeployStatus, FunctionDetail, FunctionListItem, FunctionLogRow, FunctionRouteBody, FunctionRouteResult, FunctionRouting, FunctionSecretListItem, FunctionSecretWriteResult, FunctionTestRun, FunctionTestRunDelivery, FunctionTestRunDeliveryEndpoint, FunctionTestRunInboundEmail, FunctionTestRunOutboundRequest, FunctionTestRunReply, FunctionTestRunSend, FunctionTestRunState, FunctionTestRunTrace, GateDenial, GateFix, GetAccountData, GetAccountError, GetAccountErrors, GetAccountResponse, GetAccountResponses, GetAgentData, GetAgentError, GetAgentErrors, GetAgentResponse, GetAgentResponses, GetChallengeData, GetChallengeError, GetChallengeErrors, GetChallengeResponse, GetChallengeResponses, GetConversationData, GetConversationError, GetConversationErrors, GetConversationResponse, GetConversationResponses, GetEmailData, GetEmailError, GetEmailErrors, GetEmailResponse, GetEmailResponses, GetFunctionData, GetFunctionError, GetFunctionErrors, GetFunctionResponse, GetFunctionResponses, GetFunctionRoutingData, GetFunctionRoutingError, GetFunctionRoutingErrors, GetFunctionRoutingResponse, GetFunctionRoutingResponses, GetFunctionTestRunTraceData, GetFunctionTestRunTraceError, GetFunctionTestRunTraceErrors, GetFunctionTestRunTraceResponse, GetFunctionTestRunTraceResponses, GetInboxStatusData, GetInboxStatusError, GetInboxStatusErrors, GetInboxStatusResponse, GetInboxStatusResponses, GetMemoryData, GetMemoryError, GetMemoryErrors, GetMemoryResponse, GetMemoryResponses, GetOrgRoutingTopologyData, GetOrgRoutingTopologyError, GetOrgRoutingTopologyErrors, GetOrgRoutingTopologyResponse, GetOrgRoutingTopologyResponses, GetRegistryData, GetRegistryError, GetRegistryErrors, GetRegistryResponse, GetRegistryResponses, GetSendPermissionsData, GetSendPermissionsError, GetSendPermissionsErrors, GetSendPermissionsResponse, GetSendPermissionsResponses, GetSentEmailData, GetSentEmailError, GetSentEmailErrors, GetSentEmailResponse, GetSentEmailResponses, GetSpendPolicyData, GetSpendPolicyError, GetSpendPolicyErrors, GetSpendPolicyResponse, GetSpendPolicyResponses, GetStorageStatsData, GetStorageStatsError, GetStorageStatsErrors, GetStorageStatsResponse, GetStorageStatsResponses, GetTemplateData, GetTemplateError, GetTemplateErrors, GetTemplateInstallData, GetTemplateInstallError, GetTemplateInstallErrors, GetTemplateInstallResponse, GetTemplateInstallResponses, GetTemplateResponse, GetTemplateResponses, GetThreadData, GetThreadError, GetThreadErrors, GetThreadResponse, GetThreadResponses, GetWakeScheduleData, GetWakeScheduleError, GetWakeScheduleErrors, GetWakeScheduleResponse, GetWakeScheduleResponses, GetWebhookSecretData, GetWebhookSecretError, GetWebhookSecretErrors, GetWebhookSecretResponse, GetWebhookSecretResponses, IdempotencyKey, InboxStatus, InboxStatusDomain, InboxStatusEndpointSummary, InboxStatusFunctionSummary, InboxStatusNextAction, InboxStatusRecentEmailSummary, InstallTemplateBody, InstallTemplateData, InstallTemplateError, InstallTemplateErrors, InstallTemplateResponse, InstallTemplateResponses, Limit, ListDeclinedPaymentsData, ListDeclinedPaymentsError, ListDeclinedPaymentsErrors, ListDeclinedPaymentsResponse, ListDeclinedPaymentsResponses, ListDeliveriesData, ListDeliveriesError, ListDeliveriesErrors, ListDeliveriesResponse, ListDeliveriesResponses, ListDomainsData, ListDomainsError, ListDomainsErrors, ListDomainsResponse, ListDomainsResponses, ListEmailsData, ListEmailsError, ListEmailsErrors, ListEmailsResponse, ListEmailsResponses, ListEndpointsData, ListEndpointsError, ListEndpointsErrors, ListEndpointsResponse, ListEndpointsResponses, ListEnvelope, ListFiltersData, ListFiltersError, ListFiltersErrors, ListFiltersResponse, ListFiltersResponses, ListFunctionLogsData, ListFunctionLogsError, ListFunctionLogsErrors, ListFunctionLogsResponse, ListFunctionLogsResponses, ListFunctionsData, ListFunctionSecretsData, ListFunctionSecretsError, ListFunctionSecretsErrors, ListFunctionSecretsResponse, ListFunctionSecretsResponses, ListFunctionsError, ListFunctionsErrors, ListFunctionsResponse, ListFunctionsResponses, ListOrgSecretsData, ListOrgSecretsError, ListOrgSecretsErrors, ListOrgSecretsResponse, ListOrgSecretsResponses, ListPayoutAddressesData, ListPayoutAddressesError, ListPayoutAddressesErrors, ListPayoutAddressesResponse, ListPayoutAddressesResponses, ListRegistriesData, ListRegistriesError, ListRegistriesErrors, ListRegistriesResponse, ListRegistriesResponses, ListRegistryAgentsData, ListRegistryAgentsResponse, ListRegistryAgentsResponses, ListRegistryRequestsData, ListRegistryRequestsError, ListRegistryRequestsErrors, ListRegistryRequestsResponse, ListRegistryRequestsResponses, ListRoutesData, ListRoutesError, ListRoutesErrors, ListRoutesResponse, ListRoutesResponses, ListSentEmailsData, ListSentEmailsError, ListSentEmailsErrors, ListSentEmailsResponse, ListSentEmailsResponses, ListTemplatesData, ListTemplatesError, ListTemplatesErrors, ListTemplatesResponse, ListTemplatesResponses, ListWakeAuthorizationsData, ListWakeAuthorizationsError, ListWakeAuthorizationsErrors, ListWakeAuthorizationsResponse, ListWakeAuthorizationsResponses, ListWakeDispatchesData, ListWakeDispatchesError, ListWakeDispatchesErrors, ListWakeDispatchesResponse, ListWakeDispatchesResponses, ListWakeSchedulesData, ListWakeSchedulesError, ListWakeSchedulesErrors, ListWakeSchedulesResponse, ListWakeSchedulesResponses, MemoryJsonValue, MemoryKeyQuery, MemoryRecord, MemoryRecordWithValue, MemoryResolvedScope, MemoryScope, MemoryScopeId, MemoryScopeQueryType, NumericString, OrgSecretListItem, OrgSecretWriteResult, PaginationMeta, ParsedEmailData, PayChallengeData, PayChallengeError, PayChallengeErrors, PayChallengeInput, PayChallengeResponse, PayChallengeResponses, PlanLimits, PollCliLoginData, PollCliLoginError, PollCliLoginErrors, PollCliLoginInput, PollCliLoginResponse, PollCliLoginResponses, PublishAgentData, PublishAgentError, PublishAgentErrors, PublishAgentInput, PublishAgentResponse, PublishAgentResponses, PublishAgentResult, PublishPolicy, RecipientRoute, RegisterPayoutAddressData, RegisterPayoutAddressError, RegisterPayoutAddressErrors, RegisterPayoutAddressInput, RegisterPayoutAddressResponse, RegisterPayoutAddressResponses, Registry, RegistryAgent, RegistryRequest, ReorderRoutesData, ReorderRoutesError, ReorderRoutesErrors, ReorderRoutesInput, ReorderRoutesResponse, ReorderRoutesResponses, ReplayDeliveryData, ReplayDeliveryError, ReplayDeliveryErrors, ReplayDeliveryResponse, ReplayDeliveryResponses, ReplayEmailWebhooksData, ReplayEmailWebhooksError, ReplayEmailWebhooksErrors, ReplayEmailWebhooksResponse, ReplayEmailWebhooksResponses, ReplayResult, ReplyInput, ReplyToEmailData, ReplyToEmailError, ReplyToEmailErrors, ReplyToEmailResponse, ReplyToEmailResponses, ResendAgentSignupVerificationData, ResendAgentSignupVerificationError, ResendAgentSignupVerificationErrors, ResendAgentSignupVerificationInput, ResendAgentSignupVerificationResponse, ResendAgentSignupVerificationResponses, ResendCliSignupVerificationData, ResendCliSignupVerificationError, ResendCliSignupVerificationErrors, ResendCliSignupVerificationInput, ResendCliSignupVerificationResponse, ResendCliSignupVerificationResponses, ResolveRegistryHandleData, ResolveRegistryHandleError, ResolveRegistryHandleErrors, ResolveRegistryHandleResponse, ResolveRegistryHandleResponses, ResourceId, RotateWebhookSecretData, RotateWebhookSecretError, RotateWebhookSecretErrors, RotateWebhookSecretResponse, RotateWebhookSecretResponses, RouteEvaluatedEntry, RoutingTopology, RunWakeScheduleData, RunWakeScheduleError, RunWakeScheduleErrors, RunWakeScheduleResponse, RunWakeScheduleResponses, SearchEmailsData, SearchEmailsError, SearchEmailsErrors, SearchEmailsResponse, SearchEmailsResponses, SearchMemoriesData, SearchMemoriesError, SearchMemoriesErrors, SearchMemoriesResponse, SearchMemoriesResponses, SemanticSearchCoverage, SemanticSearchData, SemanticSearchError, SemanticSearchErrors, SemanticSearchField, SemanticSearchInput, SemanticSearchMeta, SemanticSearchResponse, SemanticSearchResponses, SemanticSearchResult, SemanticSearchScoreBreakdown, SemanticSearchSnippet, SendEmailData, SendEmailError, SendEmailErrors, SendEmailResponse, SendEmailResponses, SendMailAttachment, SendMailInput, SendMailPayloadRef, SendMailResult, SendPermissionAddress, SendPermissionAnyRecipient, SendPermissionManagedZone, SendPermissionRule, SendPermissionsMeta, SendPermissionYourDomain, SentEmailDetail, SentEmailStatus, SentEmailSummary, SetFunctionRouteData, SetFunctionRouteError, SetFunctionRouteErrors, SetFunctionRouteResponse, SetFunctionRouteResponses, SetFunctionSecretData, SetFunctionSecretError, SetFunctionSecretErrors, SetFunctionSecretInput, SetFunctionSecretResponse, SetFunctionSecretResponses, SetMemoryData, SetMemoryError, SetMemoryErrors, SetMemoryInput, SetMemoryResponse, SetMemoryResponses, SetOrgSecretData, SetOrgSecretError, SetOrgSecretErrors, SetOrgSecretInput, SetOrgSecretResponse, SetOrgSecretResponses, SimulateRouteData, SimulateRouteError, SimulateRouteErrors, SimulateRouteInput, SimulateRouteResponse, SimulateRouteResponses, SimulateRouteResult, StartAgentClaimData, StartAgentClaimError, StartAgentClaimErrors, StartAgentClaimInput, StartAgentClaimResponse, StartAgentClaimResponses, StartAgentSignupData, StartAgentSignupError, StartAgentSignupErrors, StartAgentSignupInput, StartAgentSignupResponse, StartAgentSignupResponses, StartCliLoginData, StartCliLoginError, StartCliLoginErrors, StartCliLoginInput, StartCliLoginResponse, StartCliLoginResponses, StartCliSignupData, StartCliSignupError, StartCliSignupErrors, StartCliSignupInput, StartCliSignupResponse, StartCliSignupResponses, StorageStats, SuccessEnvelope, TemplateAuthor, TemplateInstall, TemplateInstallState, TemplateInstallStatus, TemplateManifest, TemplateRegistryDetail, TemplateRegistryPage, TemplateRegistryStatus, TemplateRegistrySummary, TemplateSecret, TemplateSecretGroup, TemplateSetup, TemplateSource, TemplateVariable, TemplateVariableValidation, TestEndpointData, TestEndpointError, TestEndpointErrors, TestEndpointResponse, TestEndpointResponses, TestFunctionData, TestFunctionError, TestFunctionErrors, TestFunctionResponse, TestFunctionResponses, TestInvocationResult, TestResult, Thread, ThreadMessage, UnpublishAgentData, UnpublishAgentError, UnpublishAgentErrors, UnpublishAgentResponse, UnpublishAgentResponses, UnsetFunctionRouteData, UnsetFunctionRouteError, UnsetFunctionRouteErrors, UnsetFunctionRouteResponse, UnsetFunctionRouteResponses, UnverifiedDomain, UpdateAccountData, UpdateAccountError, UpdateAccountErrors, UpdateAccountInput, UpdateAccountResponse, UpdateAccountResponses, UpdateDomainData, UpdateDomainError, UpdateDomainErrors, UpdateDomainInput, UpdateDomainResponse, UpdateDomainResponses, UpdateEndpointData, UpdateEndpointError, UpdateEndpointErrors, UpdateEndpointInput, UpdateEndpointResponse, UpdateEndpointResponses, UpdateFilterData, UpdateFilterError, UpdateFilterErrors, UpdateFilterInput, UpdateFilterResponse, UpdateFilterResponses, UpdateFunctionData, UpdateFunctionError, UpdateFunctionErrors, UpdateFunctionInput, UpdateFunctionResponse, UpdateFunctionResponses, UpdateRegistryData, UpdateRegistryError, UpdateRegistryErrors, UpdateRegistryInput, UpdateRegistryResponse, UpdateRegistryResponses, UpdateRouteData, UpdateRouteError, UpdateRouteErrors, UpdateRouteInput, UpdateRouteResponse, UpdateRouteResponses, UpdateSpendPolicyData, UpdateSpendPolicyError, UpdateSpendPolicyErrors, UpdateSpendPolicyInput, UpdateSpendPolicyResponse, UpdateSpendPolicyResponses, UpdateWakeAuthorizationData, UpdateWakeAuthorizationError, UpdateWakeAuthorizationErrors, UpdateWakeAuthorizationInput, UpdateWakeAuthorizationResponse, UpdateWakeAuthorizationResponses, UpdateWakeScheduleData, UpdateWakeScheduleError, UpdateWakeScheduleErrors, UpdateWakeScheduleInput, UpdateWakeScheduleResponse, UpdateWakeScheduleResponses, VerifiedDomain, VerifyAgentClaimData, VerifyAgentClaimError, VerifyAgentClaimErrors, VerifyAgentClaimInput, VerifyAgentClaimResponse, VerifyAgentClaimResponses, VerifyAgentSignupData, VerifyAgentSignupError, VerifyAgentSignupErrors, VerifyAgentSignupInput, VerifyAgentSignupResponse, VerifyAgentSignupResponses, VerifyCliSignupData, VerifyCliSignupError, VerifyCliSignupErrors, VerifyCliSignupInput, VerifyCliSignupResponse, VerifyCliSignupResponses, VerifyDomainData, VerifyDomainError, VerifyDomainErrors, VerifyDomainResponse, VerifyDomainResponses, WakeAuthorization, WakeDispatch, WakeSchedule, WebhookSecret, X402Challenge, X402DeclinedPayment, X402EmailChallenge, X402EmailChallengeDetails, X402NonceBinding, X402PaymentPayload, X402PaymentRequirements, X402PayoutAddress, X402Receipt, X402SpendPolicy } from './types.gen.js';
+export { addDomain, awaitReply, cliLogout, createAgentAccount, createAgentClaimLink, createChallenge, createEmailChallenge, createEndpoint, createFilter, createFunction, createFunctionSecret, createOrgSecret, createRegistry, createRoute, createWakeAuthorization, createWakeSchedule, decideRegistryRequest, defineAgent, deleteDomain, deleteEmail, deleteEndpoint, deleteFilter, deleteFunction, deleteFunctionSecret, deleteMemory, deleteOrgSecret, deleteRegistry, deleteRoute, deleteWakeAuthorization, deleteWakeSchedule, discardEmailContent, downloadAttachments, downloadDomainZoneFile, downloadRawEmail, getAccount, getAgent, getChallenge, getConversation, getEmail, getFunction, getFunctionRouting, getFunctionTestRunTrace, getInboxStatus, getMemory, getOrgRoutingTopology, getRegistry, getSendPermissions, getSentEmail, getSpendPolicy, getStorageStats, getTemplate, getTemplateInstall, getThread, getWakeSchedule, getWebhookSecret, installTemplate, listDeclinedPayments, listDeliveries, listDomains, listEmails, listEndpoints, listFilters, listFunctionLogs, listFunctions, listFunctionSecrets, listOrgSecrets, listPayoutAddresses, listRegistries, listRegistryAgents, listRegistryRequests, listRoutes, listSentEmails, listTemplates, listWakeAuthorizations, listWakeDispatches, listWakeSchedules, type Options, payChallenge, pollCliLogin, publishAgent, registerPayoutAddress, reorderRoutes, replayDelivery, replayEmailWebhooks, replyToEmail, resendAgentSignupVerification, resendCliSignupVerification, resolveRegistryHandle, rotateWebhookSecret, runWakeSchedule, searchEmails, searchMemories, semanticSearch, sendEmail, setFunctionRoute, setFunctionSecret, setMemory, setOrgSecret, simulateRoute, startAgentClaim, startAgentSignup, startCliLogin, startCliSignup, testEndpoint, testFunction, unpublishAgent, unsetFunctionRoute, updateAccount, updateDomain, updateEndpoint, updateFilter, updateFunction, updateRegistry, updateRoute, updateSpendPolicy, updateWakeAuthorization, updateWakeSchedule, verifyAgentClaim, verifyAgentSignup, verifyCliSignup, verifyDomain } from './sdk.gen.js';
+export type { Account, AccountUpdated, AddDomainData, AddDomainError, AddDomainErrors, AddDomainInput, AddDomainResponse, AddDomainResponses, AgentAccountResult, AgentAccountUpgradeHint, AgentClaimLinkResult, AgentClaimResult, AgentClaimStartResult, AgentOrgRef, AgentSignupResendResult, AgentSignupStartResult, AgentSignupVerifyResult, AwaitReplyData, AwaitReplyError, AwaitReplyErrors, AwaitReplyResponse, AwaitReplyResponses, AwaitReplyResult, ClientOptions, CliLoginPollResult, CliLoginStartResult, CliLogoutData, CliLogoutError, CliLogoutErrors, CliLogoutInput, CliLogoutResponse, CliLogoutResponses, CliLogoutResult, CliSignupResendResult, CliSignupStartResult, CliSignupVerifyResult, Conversation, ConversationMessage, CreateAgentAccountData, CreateAgentAccountError, CreateAgentAccountErrors, CreateAgentAccountInput, CreateAgentAccountResponse, CreateAgentAccountResponses, CreateAgentClaimLinkData, CreateAgentClaimLinkError, CreateAgentClaimLinkErrors, CreateAgentClaimLinkInput, CreateAgentClaimLinkResponse, CreateAgentClaimLinkResponses, CreateChallengeData, CreateChallengeError, CreateChallengeErrors, CreateChallengeInput, CreateChallengeResponse, CreateChallengeResponses, CreateEmailChallengeData, CreateEmailChallengeError, CreateEmailChallengeErrors, CreateEmailChallengeInput, CreateEmailChallengeResponse, CreateEmailChallengeResponses, CreateEndpointData, CreateEndpointError, CreateEndpointErrors, CreateEndpointInput, CreateEndpointResponse, CreateEndpointResponses, CreateFilterData, CreateFilterError, CreateFilterErrors, CreateFilterInput, CreateFilterResponse, CreateFilterResponses, CreateFunctionData, CreateFunctionError, CreateFunctionErrors, CreateFunctionInput, CreateFunctionResponse, CreateFunctionResponses, CreateFunctionResult, CreateFunctionSecretData, CreateFunctionSecretError, CreateFunctionSecretErrors, CreateFunctionSecretInput, CreateFunctionSecretResponse, CreateFunctionSecretResponses, CreateOrgSecretData, CreateOrgSecretError, CreateOrgSecretErrors, CreateOrgSecretInput, CreateOrgSecretResponse, CreateOrgSecretResponses, CreateRegistryData, CreateRegistryError, CreateRegistryErrors, CreateRegistryInput, CreateRegistryResponse, CreateRegistryResponses, CreateRouteData, CreateRouteError, CreateRouteErrors, CreateRouteInput, CreateRouteResponse, CreateRouteResponses, CreateWakeAuthorizationData, CreateWakeAuthorizationError, CreateWakeAuthorizationErrors, CreateWakeAuthorizationInput, CreateWakeAuthorizationResponse, CreateWakeAuthorizationResponses, CreateWakeScheduleData, CreateWakeScheduleError, CreateWakeScheduleErrors, CreateWakeScheduleInput, CreateWakeScheduleResponse, CreateWakeScheduleResponses, Cursor, DecideRegistryRequestData, DecideRegistryRequestError, DecideRegistryRequestErrors, DecideRegistryRequestInput, DecideRegistryRequestResponse, DecideRegistryRequestResponses, DefineAgentData, DefineAgentError, DefineAgentErrors, DefineAgentInput, DefineAgentResponse, DefineAgentResponses, DeleteDomainData, DeleteDomainError, DeleteDomainErrors, DeleteDomainResponse, DeleteDomainResponses, DeleteEmailData, DeleteEmailError, DeleteEmailErrors, DeleteEmailResponse, DeleteEmailResponses, DeleteEndpointData, DeleteEndpointError, DeleteEndpointErrors, DeleteEndpointResponse, DeleteEndpointResponses, DeleteFilterData, DeleteFilterError, DeleteFilterErrors, DeleteFilterResponse, DeleteFilterResponses, DeleteFunctionData, DeleteFunctionError, DeleteFunctionErrors, DeleteFunctionResponse, DeleteFunctionResponses, DeleteFunctionSecretData, DeleteFunctionSecretError, DeleteFunctionSecretErrors, DeleteFunctionSecretResponse, DeleteFunctionSecretResponses, DeleteMemoryData, DeleteMemoryError, DeleteMemoryErrors, DeleteMemoryResponse, DeleteMemoryResponses, DeleteMemoryResult, DeleteOrgSecretData, DeleteOrgSecretError, DeleteOrgSecretErrors, DeleteOrgSecretResponse, DeleteOrgSecretResponses, DeleteRegistryData, DeleteRegistryError, DeleteRegistryErrors, DeleteRegistryResponse, DeleteRegistryResponses, DeleteRouteData, DeleteRouteError, DeleteRouteErrors, DeleteRouteResponse, DeleteRouteResponses, DeleteWakeAuthorizationData, DeleteWakeAuthorizationError, DeleteWakeAuthorizationErrors, DeleteWakeAuthorizationResponse, DeleteWakeAuthorizationResponses, DeleteWakeScheduleData, DeleteWakeScheduleError, DeleteWakeScheduleErrors, DeleteWakeScheduleResponse, DeleteWakeScheduleResponses, DeliveryStatus, DeliverySummary, DiscardContentResult, DiscardEmailContentData, DiscardEmailContentError, DiscardEmailContentErrors, DiscardEmailContentResponse, DiscardEmailContentResponses, DkimSignature, Domain, DomainDnsRecord, DomainVerifyResult, DownloadAttachmentsData, DownloadAttachmentsError, DownloadAttachmentsErrors, DownloadAttachmentsResponse, DownloadAttachmentsResponses, DownloadDomainZoneFileData, DownloadDomainZoneFileError, DownloadDomainZoneFileErrors, DownloadDomainZoneFileResponse, DownloadDomainZoneFileResponses, DownloadRawEmailData, DownloadRawEmailError, DownloadRawEmailErrors, DownloadRawEmailResponse, DownloadRawEmailResponses, EmailAddress, EmailAttachment, EmailAuth, EmailDetail, EmailDetailReply, EmailSearchFacetBucket, EmailSearchFacets, EmailSearchHighlights, EmailSearchMeta, EmailSearchResult, EmailStatus, EmailSummary, EmailWebhookStatus, Endpoint, ErrorResponse, Filter, FunctionDeployStatus, FunctionDetail, FunctionListItem, FunctionLogRow, FunctionRouteBody, FunctionRouteResult, FunctionRouting, FunctionSecretListItem, FunctionSecretWriteResult, FunctionTestRun, FunctionTestRunDelivery, FunctionTestRunDeliveryEndpoint, FunctionTestRunInboundEmail, FunctionTestRunOutboundRequest, FunctionTestRunReply, FunctionTestRunSend, FunctionTestRunState, FunctionTestRunTrace, GateDenial, GateFix, GetAccountData, GetAccountError, GetAccountErrors, GetAccountResponse, GetAccountResponses, GetAgentData, GetAgentError, GetAgentErrors, GetAgentResponse, GetAgentResponses, GetChallengeData, GetChallengeError, GetChallengeErrors, GetChallengeResponse, GetChallengeResponses, GetConversationData, GetConversationError, GetConversationErrors, GetConversationResponse, GetConversationResponses, GetEmailData, GetEmailError, GetEmailErrors, GetEmailResponse, GetEmailResponses, GetFunctionData, GetFunctionError, GetFunctionErrors, GetFunctionResponse, GetFunctionResponses, GetFunctionRoutingData, GetFunctionRoutingError, GetFunctionRoutingErrors, GetFunctionRoutingResponse, GetFunctionRoutingResponses, GetFunctionTestRunTraceData, GetFunctionTestRunTraceError, GetFunctionTestRunTraceErrors, GetFunctionTestRunTraceResponse, GetFunctionTestRunTraceResponses, GetInboxStatusData, GetInboxStatusError, GetInboxStatusErrors, GetInboxStatusResponse, GetInboxStatusResponses, GetMemoryData, GetMemoryError, GetMemoryErrors, GetMemoryResponse, GetMemoryResponses, GetOrgRoutingTopologyData, GetOrgRoutingTopologyError, GetOrgRoutingTopologyErrors, GetOrgRoutingTopologyResponse, GetOrgRoutingTopologyResponses, GetRegistryData, GetRegistryError, GetRegistryErrors, GetRegistryResponse, GetRegistryResponses, GetSendPermissionsData, GetSendPermissionsError, GetSendPermissionsErrors, GetSendPermissionsResponse, GetSendPermissionsResponses, GetSentEmailData, GetSentEmailError, GetSentEmailErrors, GetSentEmailResponse, GetSentEmailResponses, GetSpendPolicyData, GetSpendPolicyError, GetSpendPolicyErrors, GetSpendPolicyResponse, GetSpendPolicyResponses, GetStorageStatsData, GetStorageStatsError, GetStorageStatsErrors, GetStorageStatsResponse, GetStorageStatsResponses, GetTemplateData, GetTemplateError, GetTemplateErrors, GetTemplateInstallData, GetTemplateInstallError, GetTemplateInstallErrors, GetTemplateInstallResponse, GetTemplateInstallResponses, GetTemplateResponse, GetTemplateResponses, GetThreadData, GetThreadError, GetThreadErrors, GetThreadResponse, GetThreadResponses, GetWakeScheduleData, GetWakeScheduleError, GetWakeScheduleErrors, GetWakeScheduleResponse, GetWakeScheduleResponses, GetWebhookSecretData, GetWebhookSecretError, GetWebhookSecretErrors, GetWebhookSecretResponse, GetWebhookSecretResponses, IdempotencyKey, InboxStatus, InboxStatusDomain, InboxStatusEndpointSummary, InboxStatusFunctionSummary, InboxStatusNextAction, InboxStatusRecentEmailSummary, InstallTemplateBody, InstallTemplateData, InstallTemplateError, InstallTemplateErrors, InstallTemplateResponse, InstallTemplateResponses, Limit, ListDeclinedPaymentsData, ListDeclinedPaymentsError, ListDeclinedPaymentsErrors, ListDeclinedPaymentsResponse, ListDeclinedPaymentsResponses, ListDeliveriesData, ListDeliveriesError, ListDeliveriesErrors, ListDeliveriesResponse, ListDeliveriesResponses, ListDomainsData, ListDomainsError, ListDomainsErrors, ListDomainsResponse, ListDomainsResponses, ListEmailsData, ListEmailsError, ListEmailsErrors, ListEmailsResponse, ListEmailsResponses, ListEndpointsData, ListEndpointsError, ListEndpointsErrors, ListEndpointsResponse, ListEndpointsResponses, ListEnvelope, ListFiltersData, ListFiltersError, ListFiltersErrors, ListFiltersResponse, ListFiltersResponses, ListFunctionLogsData, ListFunctionLogsError, ListFunctionLogsErrors, ListFunctionLogsResponse, ListFunctionLogsResponses, ListFunctionsData, ListFunctionSecretsData, ListFunctionSecretsError, ListFunctionSecretsErrors, ListFunctionSecretsResponse, ListFunctionSecretsResponses, ListFunctionsError, ListFunctionsErrors, ListFunctionsResponse, ListFunctionsResponses, ListOrgSecretsData, ListOrgSecretsError, ListOrgSecretsErrors, ListOrgSecretsResponse, ListOrgSecretsResponses, ListPayoutAddressesData, ListPayoutAddressesError, ListPayoutAddressesErrors, ListPayoutAddressesResponse, ListPayoutAddressesResponses, ListRegistriesData, ListRegistriesError, ListRegistriesErrors, ListRegistriesResponse, ListRegistriesResponses, ListRegistryAgentsData, ListRegistryAgentsResponse, ListRegistryAgentsResponses, ListRegistryRequestsData, ListRegistryRequestsError, ListRegistryRequestsErrors, ListRegistryRequestsResponse, ListRegistryRequestsResponses, ListRoutesData, ListRoutesError, ListRoutesErrors, ListRoutesResponse, ListRoutesResponses, ListSentEmailsData, ListSentEmailsError, ListSentEmailsErrors, ListSentEmailsResponse, ListSentEmailsResponses, ListTemplatesData, ListTemplatesError, ListTemplatesErrors, ListTemplatesResponse, ListTemplatesResponses, ListWakeAuthorizationsData, ListWakeAuthorizationsError, ListWakeAuthorizationsErrors, ListWakeAuthorizationsResponse, ListWakeAuthorizationsResponses, ListWakeDispatchesData, ListWakeDispatchesError, ListWakeDispatchesErrors, ListWakeDispatchesResponse, ListWakeDispatchesResponses, ListWakeSchedulesData, ListWakeSchedulesError, ListWakeSchedulesErrors, ListWakeSchedulesResponse, ListWakeSchedulesResponses, MemoryJsonValue, MemoryKeyQuery, MemoryRecord, MemoryRecordWithValue, MemoryResolvedScope, MemoryScope, MemoryScopeId, MemoryScopeQueryType, NumericString, OrgSecretListItem, OrgSecretWriteResult, PaginationMeta, ParsedEmailData, PayChallengeData, PayChallengeError, PayChallengeErrors, PayChallengeInput, PayChallengeResponse, PayChallengeResponses, PlanLimits, PollCliLoginData, PollCliLoginError, PollCliLoginErrors, PollCliLoginInput, PollCliLoginResponse, PollCliLoginResponses, PublishAgentData, PublishAgentError, PublishAgentErrors, PublishAgentInput, PublishAgentResponse, PublishAgentResponses, PublishAgentResult, PublishPolicy, RecipientRoute, RegisterPayoutAddressData, RegisterPayoutAddressError, RegisterPayoutAddressErrors, RegisterPayoutAddressInput, RegisterPayoutAddressResponse, RegisterPayoutAddressResponses, Registry, RegistryAgent, RegistryRequest, ReorderRoutesData, ReorderRoutesError, ReorderRoutesErrors, ReorderRoutesInput, ReorderRoutesResponse, ReorderRoutesResponses, ReplayDeliveryData, ReplayDeliveryError, ReplayDeliveryErrors, ReplayDeliveryResponse, ReplayDeliveryResponses, ReplayEmailWebhooksData, ReplayEmailWebhooksError, ReplayEmailWebhooksErrors, ReplayEmailWebhooksResponse, ReplayEmailWebhooksResponses, ReplayResult, ReplyEmail, ReplyInput, ReplyToEmailData, ReplyToEmailError, ReplyToEmailErrors, ReplyToEmailResponse, ReplyToEmailResponses, ResendAgentSignupVerificationData, ResendAgentSignupVerificationError, ResendAgentSignupVerificationErrors, ResendAgentSignupVerificationInput, ResendAgentSignupVerificationResponse, ResendAgentSignupVerificationResponses, ResendCliSignupVerificationData, ResendCliSignupVerificationError, ResendCliSignupVerificationErrors, ResendCliSignupVerificationInput, ResendCliSignupVerificationResponse, ResendCliSignupVerificationResponses, ResolveRegistryHandleData, ResolveRegistryHandleError, ResolveRegistryHandleErrors, ResolveRegistryHandleResponse, ResolveRegistryHandleResponses, ResourceId, RotateWebhookSecretData, RotateWebhookSecretError, RotateWebhookSecretErrors, RotateWebhookSecretResponse, RotateWebhookSecretResponses, RouteEvaluatedEntry, RoutingTopology, RunWakeScheduleData, RunWakeScheduleError, RunWakeScheduleErrors, RunWakeScheduleResponse, RunWakeScheduleResponses, SearchEmailsData, SearchEmailsError, SearchEmailsErrors, SearchEmailsResponse, SearchEmailsResponses, SearchMemoriesData, SearchMemoriesError, SearchMemoriesErrors, SearchMemoriesResponse, SearchMemoriesResponses, SemanticSearchCoverage, SemanticSearchData, SemanticSearchError, SemanticSearchErrors, SemanticSearchField, SemanticSearchInput, SemanticSearchMeta, SemanticSearchResponse, SemanticSearchResponses, SemanticSearchResult, SemanticSearchScoreBreakdown, SemanticSearchSnippet, SendEmailData, SendEmailError, SendEmailErrors, SendEmailResponse, SendEmailResponses, SendMailAttachment, SendMailInput, SendMailPayloadRef, SendMailResult, SendPermissionAddress, SendPermissionAnyRecipient, SendPermissionManagedZone, SendPermissionRule, SendPermissionsMeta, SendPermissionYourDomain, SentEmailDetail, SentEmailStatus, SentEmailSummary, SetFunctionRouteData, SetFunctionRouteError, SetFunctionRouteErrors, SetFunctionRouteResponse, SetFunctionRouteResponses, SetFunctionSecretData, SetFunctionSecretError, SetFunctionSecretErrors, SetFunctionSecretInput, SetFunctionSecretResponse, SetFunctionSecretResponses, SetMemoryData, SetMemoryError, SetMemoryErrors, SetMemoryInput, SetMemoryResponse, SetMemoryResponses, SetOrgSecretData, SetOrgSecretError, SetOrgSecretErrors, SetOrgSecretInput, SetOrgSecretResponse, SetOrgSecretResponses, SimulateRouteData, SimulateRouteError, SimulateRouteErrors, SimulateRouteInput, SimulateRouteResponse, SimulateRouteResponses, SimulateRouteResult, StartAgentClaimData, StartAgentClaimError, StartAgentClaimErrors, StartAgentClaimInput, StartAgentClaimResponse, StartAgentClaimResponses, StartAgentSignupData, StartAgentSignupError, StartAgentSignupErrors, StartAgentSignupInput, StartAgentSignupResponse, StartAgentSignupResponses, StartCliLoginData, StartCliLoginError, StartCliLoginErrors, StartCliLoginInput, StartCliLoginResponse, StartCliLoginResponses, StartCliSignupData, StartCliSignupError, StartCliSignupErrors, StartCliSignupInput, StartCliSignupResponse, StartCliSignupResponses, StorageStats, SuccessEnvelope, TemplateAuthor, TemplateInstall, TemplateInstallState, TemplateInstallStatus, TemplateManifest, TemplateRegistryDetail, TemplateRegistryPage, TemplateRegistryStatus, TemplateRegistrySummary, TemplateSecret, TemplateSecretGroup, TemplateSetup, TemplateSource, TemplateVariable, TemplateVariableValidation, TestEndpointData, TestEndpointError, TestEndpointErrors, TestEndpointResponse, TestEndpointResponses, TestFunctionData, TestFunctionError, TestFunctionErrors, TestFunctionResponse, TestFunctionResponses, TestInvocationResult, TestResult, Thread, ThreadMessage, UnpublishAgentData, UnpublishAgentError, UnpublishAgentErrors, UnpublishAgentResponse, UnpublishAgentResponses, UnsetFunctionRouteData, UnsetFunctionRouteError, UnsetFunctionRouteErrors, UnsetFunctionRouteResponse, UnsetFunctionRouteResponses, UnverifiedDomain, UpdateAccountData, UpdateAccountError, UpdateAccountErrors, UpdateAccountInput, UpdateAccountResponse, UpdateAccountResponses, UpdateDomainData, UpdateDomainError, UpdateDomainErrors, UpdateDomainInput, UpdateDomainResponse, UpdateDomainResponses, UpdateEndpointData, UpdateEndpointError, UpdateEndpointErrors, UpdateEndpointInput, UpdateEndpointResponse, UpdateEndpointResponses, UpdateFilterData, UpdateFilterError, UpdateFilterErrors, UpdateFilterInput, UpdateFilterResponse, UpdateFilterResponses, UpdateFunctionData, UpdateFunctionError, UpdateFunctionErrors, UpdateFunctionInput, UpdateFunctionResponse, UpdateFunctionResponses, UpdateRegistryData, UpdateRegistryError, UpdateRegistryErrors, UpdateRegistryInput, UpdateRegistryResponse, UpdateRegistryResponses, UpdateRouteData, UpdateRouteError, UpdateRouteErrors, UpdateRouteInput, UpdateRouteResponse, UpdateRouteResponses, UpdateSpendPolicyData, UpdateSpendPolicyError, UpdateSpendPolicyErrors, UpdateSpendPolicyInput, UpdateSpendPolicyResponse, UpdateSpendPolicyResponses, UpdateWakeAuthorizationData, UpdateWakeAuthorizationError, UpdateWakeAuthorizationErrors, UpdateWakeAuthorizationInput, UpdateWakeAuthorizationResponse, UpdateWakeAuthorizationResponses, UpdateWakeScheduleData, UpdateWakeScheduleError, UpdateWakeScheduleErrors, UpdateWakeScheduleInput, UpdateWakeScheduleResponse, UpdateWakeScheduleResponses, VerifiedDomain, VerifyAgentClaimData, VerifyAgentClaimError, VerifyAgentClaimErrors, VerifyAgentClaimInput, VerifyAgentClaimResponse, VerifyAgentClaimResponses, VerifyAgentSignupData, VerifyAgentSignupError, VerifyAgentSignupErrors, VerifyAgentSignupInput, VerifyAgentSignupResponse, VerifyAgentSignupResponses, VerifyCliSignupData, VerifyCliSignupError, VerifyCliSignupErrors, VerifyCliSignupInput, VerifyCliSignupResponse, VerifyCliSignupResponses, VerifyDomainData, VerifyDomainError, VerifyDomainErrors, VerifyDomainResponse, VerifyDomainResponses, WakeAuthorization, WakeDispatch, WakeSchedule, WebhookSecret, X402Challenge, X402DeclinedPayment, X402EmailChallenge, X402EmailChallengeDetails, X402NonceBinding, X402PaymentPayload, X402PaymentRequirements, X402PayoutAddress, X402Receipt, X402SpendPolicy } from './types.gen.js';
diff --git a/packages/api-core/src/api/sdk.gen.ts b/packages/api-core/src/api/sdk.gen.ts
index af7bd108..cbd6dae2 100644
--- a/packages/api-core/src/api/sdk.gen.ts
+++ b/packages/api-core/src/api/sdk.gen.ts
@@ -2,7 +2,7 @@
import type { Client, Options as Options2, TDataShape } from './client/index.js';
import { client } from './client.gen.js';
-import type { AddDomainData, AddDomainErrors, AddDomainResponses, CliLogoutData, CliLogoutErrors, CliLogoutResponses, CreateAgentAccountData, CreateAgentAccountErrors, CreateAgentAccountResponses, CreateAgentClaimLinkData, CreateAgentClaimLinkErrors, CreateAgentClaimLinkResponses, CreateChallengeData, CreateChallengeErrors, CreateChallengeResponses, CreateEmailChallengeData, CreateEmailChallengeErrors, CreateEmailChallengeResponses, CreateEndpointData, CreateEndpointErrors, CreateEndpointResponses, CreateFilterData, CreateFilterErrors, CreateFilterResponses, CreateFunctionData, CreateFunctionErrors, CreateFunctionResponses, CreateFunctionSecretData, CreateFunctionSecretErrors, CreateFunctionSecretResponses, CreateOrgSecretData, CreateOrgSecretErrors, CreateOrgSecretResponses, CreateRegistryData, CreateRegistryErrors, CreateRegistryResponses, CreateRouteData, CreateRouteErrors, CreateRouteResponses, CreateWakeAuthorizationData, CreateWakeAuthorizationErrors, CreateWakeAuthorizationResponses, CreateWakeScheduleData, CreateWakeScheduleErrors, CreateWakeScheduleResponses, DecideRegistryRequestData, DecideRegistryRequestErrors, DecideRegistryRequestResponses, DefineAgentData, DefineAgentErrors, DefineAgentResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponses, DeleteEmailData, DeleteEmailErrors, DeleteEmailResponses, DeleteEndpointData, DeleteEndpointErrors, DeleteEndpointResponses, DeleteFilterData, DeleteFilterErrors, DeleteFilterResponses, DeleteFunctionData, DeleteFunctionErrors, DeleteFunctionResponses, DeleteFunctionSecretData, DeleteFunctionSecretErrors, DeleteFunctionSecretResponses, DeleteMemoryData, DeleteMemoryErrors, DeleteMemoryResponses, DeleteOrgSecretData, DeleteOrgSecretErrors, DeleteOrgSecretResponses, DeleteRegistryData, DeleteRegistryErrors, DeleteRegistryResponses, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponses, DeleteWakeAuthorizationData, DeleteWakeAuthorizationErrors, DeleteWakeAuthorizationResponses, DeleteWakeScheduleData, DeleteWakeScheduleErrors, DeleteWakeScheduleResponses, DiscardEmailContentData, DiscardEmailContentErrors, DiscardEmailContentResponses, DownloadAttachmentsData, DownloadAttachmentsErrors, DownloadAttachmentsResponses, DownloadDomainZoneFileData, DownloadDomainZoneFileErrors, DownloadDomainZoneFileResponses, DownloadRawEmailData, DownloadRawEmailErrors, DownloadRawEmailResponses, GetAccountData, GetAccountErrors, GetAccountResponses, GetAgentData, GetAgentErrors, GetAgentResponses, GetChallengeData, GetChallengeErrors, GetChallengeResponses, GetConversationData, GetConversationErrors, GetConversationResponses, GetEmailData, GetEmailErrors, GetEmailResponses, GetFunctionData, GetFunctionErrors, GetFunctionResponses, GetFunctionRoutingData, GetFunctionRoutingErrors, GetFunctionRoutingResponses, GetFunctionTestRunTraceData, GetFunctionTestRunTraceErrors, GetFunctionTestRunTraceResponses, GetInboxStatusData, GetInboxStatusErrors, GetInboxStatusResponses, GetMemoryData, GetMemoryErrors, GetMemoryResponses, GetOrgRoutingTopologyData, GetOrgRoutingTopologyErrors, GetOrgRoutingTopologyResponses, GetRegistryData, GetRegistryErrors, GetRegistryResponses, GetSendPermissionsData, GetSendPermissionsErrors, GetSendPermissionsResponses, GetSentEmailData, GetSentEmailErrors, GetSentEmailResponses, GetSpendPolicyData, GetSpendPolicyErrors, GetSpendPolicyResponses, GetStorageStatsData, GetStorageStatsErrors, GetStorageStatsResponses, GetTemplateData, GetTemplateErrors, GetTemplateInstallData, GetTemplateInstallErrors, GetTemplateInstallResponses, GetTemplateResponses, GetThreadData, GetThreadErrors, GetThreadResponses, GetWakeScheduleData, GetWakeScheduleErrors, GetWakeScheduleResponses, GetWebhookSecretData, GetWebhookSecretErrors, GetWebhookSecretResponses, InstallTemplateData, InstallTemplateErrors, InstallTemplateResponses, ListDeclinedPaymentsData, ListDeclinedPaymentsErrors, ListDeclinedPaymentsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponses, ListEndpointsData, ListEndpointsErrors, ListEndpointsResponses, ListFiltersData, ListFiltersErrors, ListFiltersResponses, ListFunctionLogsData, ListFunctionLogsErrors, ListFunctionLogsResponses, ListFunctionsData, ListFunctionSecretsData, ListFunctionSecretsErrors, ListFunctionSecretsResponses, ListFunctionsErrors, ListFunctionsResponses, ListOrgSecretsData, ListOrgSecretsErrors, ListOrgSecretsResponses, ListPayoutAddressesData, ListPayoutAddressesErrors, ListPayoutAddressesResponses, ListRegistriesData, ListRegistriesErrors, ListRegistriesResponses, ListRegistryAgentsData, ListRegistryAgentsResponses, ListRegistryRequestsData, ListRegistryRequestsErrors, ListRegistryRequestsResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponses, ListSentEmailsData, ListSentEmailsErrors, ListSentEmailsResponses, ListTemplatesData, ListTemplatesErrors, ListTemplatesResponses, ListWakeAuthorizationsData, ListWakeAuthorizationsErrors, ListWakeAuthorizationsResponses, ListWakeDispatchesData, ListWakeDispatchesErrors, ListWakeDispatchesResponses, ListWakeSchedulesData, ListWakeSchedulesErrors, ListWakeSchedulesResponses, PayChallengeData, PayChallengeErrors, PayChallengeResponses, PollCliLoginData, PollCliLoginErrors, PollCliLoginResponses, PublishAgentData, PublishAgentErrors, PublishAgentResponses, RegisterPayoutAddressData, RegisterPayoutAddressErrors, RegisterPayoutAddressResponses, ReorderRoutesData, ReorderRoutesErrors, ReorderRoutesResponses, ReplayDeliveryData, ReplayDeliveryErrors, ReplayDeliveryResponses, ReplayEmailWebhooksData, ReplayEmailWebhooksErrors, ReplayEmailWebhooksResponses, ReplyToEmailData, ReplyToEmailErrors, ReplyToEmailResponses, ResendAgentSignupVerificationData, ResendAgentSignupVerificationErrors, ResendAgentSignupVerificationResponses, ResendCliSignupVerificationData, ResendCliSignupVerificationErrors, ResendCliSignupVerificationResponses, ResolveRegistryHandleData, ResolveRegistryHandleErrors, ResolveRegistryHandleResponses, RotateWebhookSecretData, RotateWebhookSecretErrors, RotateWebhookSecretResponses, RunWakeScheduleData, RunWakeScheduleErrors, RunWakeScheduleResponses, SearchEmailsData, SearchEmailsErrors, SearchEmailsResponses, SearchMemoriesData, SearchMemoriesErrors, SearchMemoriesResponses, SemanticSearchData, SemanticSearchErrors, SemanticSearchResponses, SendEmailData, SendEmailErrors, SendEmailResponses, SetFunctionRouteData, SetFunctionRouteErrors, SetFunctionRouteResponses, SetFunctionSecretData, SetFunctionSecretErrors, SetFunctionSecretResponses, SetMemoryData, SetMemoryErrors, SetMemoryResponses, SetOrgSecretData, SetOrgSecretErrors, SetOrgSecretResponses, SimulateRouteData, SimulateRouteErrors, SimulateRouteResponses, StartAgentClaimData, StartAgentClaimErrors, StartAgentClaimResponses, StartAgentSignupData, StartAgentSignupErrors, StartAgentSignupResponses, StartCliLoginData, StartCliLoginErrors, StartCliLoginResponses, StartCliSignupData, StartCliSignupErrors, StartCliSignupResponses, TestEndpointData, TestEndpointErrors, TestEndpointResponses, TestFunctionData, TestFunctionErrors, TestFunctionResponses, UnpublishAgentData, UnpublishAgentErrors, UnpublishAgentResponses, UnsetFunctionRouteData, UnsetFunctionRouteErrors, UnsetFunctionRouteResponses, UpdateAccountData, UpdateAccountErrors, UpdateAccountResponses, UpdateDomainData, UpdateDomainErrors, UpdateDomainResponses, UpdateEndpointData, UpdateEndpointErrors, UpdateEndpointResponses, UpdateFilterData, UpdateFilterErrors, UpdateFilterResponses, UpdateFunctionData, UpdateFunctionErrors, UpdateFunctionResponses, UpdateRegistryData, UpdateRegistryErrors, UpdateRegistryResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteResponses, UpdateSpendPolicyData, UpdateSpendPolicyErrors, UpdateSpendPolicyResponses, UpdateWakeAuthorizationData, UpdateWakeAuthorizationErrors, UpdateWakeAuthorizationResponses, UpdateWakeScheduleData, UpdateWakeScheduleErrors, UpdateWakeScheduleResponses, VerifyAgentClaimData, VerifyAgentClaimErrors, VerifyAgentClaimResponses, VerifyAgentSignupData, VerifyAgentSignupErrors, VerifyAgentSignupResponses, VerifyCliSignupData, VerifyCliSignupErrors, VerifyCliSignupResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponses } from './types.gen.js';
+import type { AddDomainData, AddDomainErrors, AddDomainResponses, AwaitReplyData, AwaitReplyErrors, AwaitReplyResponses, CliLogoutData, CliLogoutErrors, CliLogoutResponses, CreateAgentAccountData, CreateAgentAccountErrors, CreateAgentAccountResponses, CreateAgentClaimLinkData, CreateAgentClaimLinkErrors, CreateAgentClaimLinkResponses, CreateChallengeData, CreateChallengeErrors, CreateChallengeResponses, CreateEmailChallengeData, CreateEmailChallengeErrors, CreateEmailChallengeResponses, CreateEndpointData, CreateEndpointErrors, CreateEndpointResponses, CreateFilterData, CreateFilterErrors, CreateFilterResponses, CreateFunctionData, CreateFunctionErrors, CreateFunctionResponses, CreateFunctionSecretData, CreateFunctionSecretErrors, CreateFunctionSecretResponses, CreateOrgSecretData, CreateOrgSecretErrors, CreateOrgSecretResponses, CreateRegistryData, CreateRegistryErrors, CreateRegistryResponses, CreateRouteData, CreateRouteErrors, CreateRouteResponses, CreateWakeAuthorizationData, CreateWakeAuthorizationErrors, CreateWakeAuthorizationResponses, CreateWakeScheduleData, CreateWakeScheduleErrors, CreateWakeScheduleResponses, DecideRegistryRequestData, DecideRegistryRequestErrors, DecideRegistryRequestResponses, DefineAgentData, DefineAgentErrors, DefineAgentResponses, DeleteDomainData, DeleteDomainErrors, DeleteDomainResponses, DeleteEmailData, DeleteEmailErrors, DeleteEmailResponses, DeleteEndpointData, DeleteEndpointErrors, DeleteEndpointResponses, DeleteFilterData, DeleteFilterErrors, DeleteFilterResponses, DeleteFunctionData, DeleteFunctionErrors, DeleteFunctionResponses, DeleteFunctionSecretData, DeleteFunctionSecretErrors, DeleteFunctionSecretResponses, DeleteMemoryData, DeleteMemoryErrors, DeleteMemoryResponses, DeleteOrgSecretData, DeleteOrgSecretErrors, DeleteOrgSecretResponses, DeleteRegistryData, DeleteRegistryErrors, DeleteRegistryResponses, DeleteRouteData, DeleteRouteErrors, DeleteRouteResponses, DeleteWakeAuthorizationData, DeleteWakeAuthorizationErrors, DeleteWakeAuthorizationResponses, DeleteWakeScheduleData, DeleteWakeScheduleErrors, DeleteWakeScheduleResponses, DiscardEmailContentData, DiscardEmailContentErrors, DiscardEmailContentResponses, DownloadAttachmentsData, DownloadAttachmentsErrors, DownloadAttachmentsResponses, DownloadDomainZoneFileData, DownloadDomainZoneFileErrors, DownloadDomainZoneFileResponses, DownloadRawEmailData, DownloadRawEmailErrors, DownloadRawEmailResponses, GetAccountData, GetAccountErrors, GetAccountResponses, GetAgentData, GetAgentErrors, GetAgentResponses, GetChallengeData, GetChallengeErrors, GetChallengeResponses, GetConversationData, GetConversationErrors, GetConversationResponses, GetEmailData, GetEmailErrors, GetEmailResponses, GetFunctionData, GetFunctionErrors, GetFunctionResponses, GetFunctionRoutingData, GetFunctionRoutingErrors, GetFunctionRoutingResponses, GetFunctionTestRunTraceData, GetFunctionTestRunTraceErrors, GetFunctionTestRunTraceResponses, GetInboxStatusData, GetInboxStatusErrors, GetInboxStatusResponses, GetMemoryData, GetMemoryErrors, GetMemoryResponses, GetOrgRoutingTopologyData, GetOrgRoutingTopologyErrors, GetOrgRoutingTopologyResponses, GetRegistryData, GetRegistryErrors, GetRegistryResponses, GetSendPermissionsData, GetSendPermissionsErrors, GetSendPermissionsResponses, GetSentEmailData, GetSentEmailErrors, GetSentEmailResponses, GetSpendPolicyData, GetSpendPolicyErrors, GetSpendPolicyResponses, GetStorageStatsData, GetStorageStatsErrors, GetStorageStatsResponses, GetTemplateData, GetTemplateErrors, GetTemplateInstallData, GetTemplateInstallErrors, GetTemplateInstallResponses, GetTemplateResponses, GetThreadData, GetThreadErrors, GetThreadResponses, GetWakeScheduleData, GetWakeScheduleErrors, GetWakeScheduleResponses, GetWebhookSecretData, GetWebhookSecretErrors, GetWebhookSecretResponses, InstallTemplateData, InstallTemplateErrors, InstallTemplateResponses, ListDeclinedPaymentsData, ListDeclinedPaymentsErrors, ListDeclinedPaymentsResponses, ListDeliveriesData, ListDeliveriesErrors, ListDeliveriesResponses, ListDomainsData, ListDomainsErrors, ListDomainsResponses, ListEmailsData, ListEmailsErrors, ListEmailsResponses, ListEndpointsData, ListEndpointsErrors, ListEndpointsResponses, ListFiltersData, ListFiltersErrors, ListFiltersResponses, ListFunctionLogsData, ListFunctionLogsErrors, ListFunctionLogsResponses, ListFunctionsData, ListFunctionSecretsData, ListFunctionSecretsErrors, ListFunctionSecretsResponses, ListFunctionsErrors, ListFunctionsResponses, ListOrgSecretsData, ListOrgSecretsErrors, ListOrgSecretsResponses, ListPayoutAddressesData, ListPayoutAddressesErrors, ListPayoutAddressesResponses, ListRegistriesData, ListRegistriesErrors, ListRegistriesResponses, ListRegistryAgentsData, ListRegistryAgentsResponses, ListRegistryRequestsData, ListRegistryRequestsErrors, ListRegistryRequestsResponses, ListRoutesData, ListRoutesErrors, ListRoutesResponses, ListSentEmailsData, ListSentEmailsErrors, ListSentEmailsResponses, ListTemplatesData, ListTemplatesErrors, ListTemplatesResponses, ListWakeAuthorizationsData, ListWakeAuthorizationsErrors, ListWakeAuthorizationsResponses, ListWakeDispatchesData, ListWakeDispatchesErrors, ListWakeDispatchesResponses, ListWakeSchedulesData, ListWakeSchedulesErrors, ListWakeSchedulesResponses, PayChallengeData, PayChallengeErrors, PayChallengeResponses, PollCliLoginData, PollCliLoginErrors, PollCliLoginResponses, PublishAgentData, PublishAgentErrors, PublishAgentResponses, RegisterPayoutAddressData, RegisterPayoutAddressErrors, RegisterPayoutAddressResponses, ReorderRoutesData, ReorderRoutesErrors, ReorderRoutesResponses, ReplayDeliveryData, ReplayDeliveryErrors, ReplayDeliveryResponses, ReplayEmailWebhooksData, ReplayEmailWebhooksErrors, ReplayEmailWebhooksResponses, ReplyToEmailData, ReplyToEmailErrors, ReplyToEmailResponses, ResendAgentSignupVerificationData, ResendAgentSignupVerificationErrors, ResendAgentSignupVerificationResponses, ResendCliSignupVerificationData, ResendCliSignupVerificationErrors, ResendCliSignupVerificationResponses, ResolveRegistryHandleData, ResolveRegistryHandleErrors, ResolveRegistryHandleResponses, RotateWebhookSecretData, RotateWebhookSecretErrors, RotateWebhookSecretResponses, RunWakeScheduleData, RunWakeScheduleErrors, RunWakeScheduleResponses, SearchEmailsData, SearchEmailsErrors, SearchEmailsResponses, SearchMemoriesData, SearchMemoriesErrors, SearchMemoriesResponses, SemanticSearchData, SemanticSearchErrors, SemanticSearchResponses, SendEmailData, SendEmailErrors, SendEmailResponses, SetFunctionRouteData, SetFunctionRouteErrors, SetFunctionRouteResponses, SetFunctionSecretData, SetFunctionSecretErrors, SetFunctionSecretResponses, SetMemoryData, SetMemoryErrors, SetMemoryResponses, SetOrgSecretData, SetOrgSecretErrors, SetOrgSecretResponses, SimulateRouteData, SimulateRouteErrors, SimulateRouteResponses, StartAgentClaimData, StartAgentClaimErrors, StartAgentClaimResponses, StartAgentSignupData, StartAgentSignupErrors, StartAgentSignupResponses, StartCliLoginData, StartCliLoginErrors, StartCliLoginResponses, StartCliSignupData, StartCliSignupErrors, StartCliSignupResponses, TestEndpointData, TestEndpointErrors, TestEndpointResponses, TestFunctionData, TestFunctionErrors, TestFunctionResponses, UnpublishAgentData, UnpublishAgentErrors, UnpublishAgentResponses, UnsetFunctionRouteData, UnsetFunctionRouteErrors, UnsetFunctionRouteResponses, UpdateAccountData, UpdateAccountErrors, UpdateAccountResponses, UpdateDomainData, UpdateDomainErrors, UpdateDomainResponses, UpdateEndpointData, UpdateEndpointErrors, UpdateEndpointResponses, UpdateFilterData, UpdateFilterErrors, UpdateFilterResponses, UpdateFunctionData, UpdateFunctionErrors, UpdateFunctionResponses, UpdateRegistryData, UpdateRegistryErrors, UpdateRegistryResponses, UpdateRouteData, UpdateRouteErrors, UpdateRouteResponses, UpdateSpendPolicyData, UpdateSpendPolicyErrors, UpdateSpendPolicyResponses, UpdateWakeAuthorizationData, UpdateWakeAuthorizationErrors, UpdateWakeAuthorizationResponses, UpdateWakeScheduleData, UpdateWakeScheduleErrors, UpdateWakeScheduleResponses, VerifyAgentClaimData, VerifyAgentClaimErrors, VerifyAgentClaimResponses, VerifyAgentSignupData, VerifyAgentSignupErrors, VerifyAgentSignupResponses, VerifyCliSignupData, VerifyCliSignupErrors, VerifyCliSignupResponses, VerifyDomainData, VerifyDomainErrors, VerifyDomainResponses } from './types.gen.js';
export type Options = Options2 & {
/**
@@ -1224,6 +1224,33 @@ export const getSentEmail = (options: Opti
...options
});
+/**
+ * Get (or wait for) the reply to a sent email
+ *
+ * Returns the first threaded inbound reply to a send, keyed by
+ * the inbound email's `reply_to_sent_email_id`. This is the
+ * canonical "did a reply arrive for this send?" call: after
+ * /send-mail, poll (or long-poll) here instead of hand-rolling
+ * an /emails/search loop.
+ *
+ * By default the call returns immediately with `reply: null`
+ * when nothing has arrived yet. Set `wait=true` to long-poll:
+ * the server holds the request up to `wait_timeout_ms`
+ * (default 10000, max 30000), returning as soon as the first
+ * reply lands. On a wait that elapses with no reply, the
+ * response has `reply: null` and `timed_out: true`.
+ *
+ * The reply object is compact (headers plus bodies); fetch
+ * `/emails/{id}` with `reply.id` for the fully parsed record,
+ * or `/threads/{thread_id}` for the whole back-and-forth.
+ *
+ */
+export const awaitReply = (options: Options) => (options.client ?? client).get({
+ security: [{ scheme: 'bearer', type: 'http' }],
+ url: '/sent-emails/{id}/reply',
+ ...options
+});
+
/**
* Get a conversation thread by id
*
diff --git a/packages/api-core/src/api/types.gen.ts b/packages/api-core/src/api/types.gen.ts
index 7cd16ddc..0b1cc3ed 100644
--- a/packages/api-core/src/api/types.gen.ts
+++ b/packages/api-core/src/api/types.gen.ts
@@ -2405,6 +2405,75 @@ export type SentEmailDetail = SentEmailSummary & {
body_html?: string | null;
};
+/**
+ * A threaded inbound reply to one of the org's sends, keyed by
+ * the inbound email's `reply_to_sent_email_id`. Compact on
+ * purpose: enough to read the reply and decide what to do
+ * next, with `/emails/{id}` available for the fully parsed
+ * detail.
+ *
+ */
+export type ReplyEmail = {
+ /**
+ * Inbound email row id; usable with `/emails/{id}`.
+ */
+ id: string;
+ /**
+ * Conversation thread id; usable with `/threads/{id}`.
+ */
+ thread_id: string | null;
+ /**
+ * The sent-email id this inbound message replied to.
+ */
+ reply_to_sent_email_id: string | null;
+ /**
+ * Sender of the reply (From header when present, else envelope sender).
+ */
+ from_email: string;
+ /**
+ * Recipient address the reply arrived at.
+ */
+ to_email: string;
+ subject: string | null;
+ /**
+ * Plain-text body of the reply, when present.
+ */
+ body_text: string | null;
+ /**
+ * HTML body of the reply, when present.
+ */
+ body_html: string | null;
+ received_at: string | null;
+ /**
+ * Inbound processing status of the reply row. Typically an
+ * `EmailStatus` value, but left as an open string here to
+ * match the server contract, which does not narrow it.
+ *
+ */
+ status: string;
+};
+
+/**
+ * Result of `/sent-emails/{id}/reply`. `reply` is null when no
+ * reply has arrived yet (no-wait call, or the wait timed out).
+ *
+ */
+export type AwaitReplyResult = {
+ /**
+ * The send this lookup was keyed on (echoes the path id).
+ */
+ sent_email_id: string;
+ reply: ReplyEmail | null;
+ /**
+ * Whether the call ran in long-poll mode (`wait=true`).
+ */
+ waited: boolean;
+ /**
+ * True only when a `wait=true` call elapsed its timeout with no reply.
+ */
+ timed_out: boolean;
+};
+
/**
* Body shape for `/emails/{id}/reply`. Intentionally narrow:
* recipients (`to`), subject, and threading headers
@@ -6780,6 +6849,66 @@ export type GetSentEmailResponses = {
export type GetSentEmailResponse = GetSentEmailResponses[keyof GetSentEmailResponses];
+export type AwaitReplyData = {
+ body?: never;
+ path: {
+ /**
+ * Resource UUID
+ */
+ id: string;
+ };
+ query?: {
+ /**
+ * When true, long-poll up to `wait_timeout_ms` for the
+ * first reply to arrive instead of returning immediately.
+ * Mirrors send-mail's server-side `wait` semantics. The
+ * server accepts only the literal strings `true` / `false`
+ * (standard boolean query serialization); omitted means
+ * no wait.
+ *
+ */
+ wait?: boolean;
+ /**
+ * Maximum time to hold the request when `wait=true`.
+ * Server default is 10000. NOT given an OpenAPI `default`
+ * on purpose, matching the `/emails` `wait` parameter: a
+ * default makes some generators send the value on every
+ * call.
+ *
+ */
+ wait_timeout_ms?: number;
+ };
+ url: '/sent-emails/{id}/reply';
+};
+
+export type AwaitReplyErrors = {
+ /**
+ * Invalid request parameters
+ */
+ 400: ErrorResponse;
+ /**
+ * Invalid or missing API key
+ */
+ 401: ErrorResponse;
+ /**
+ * Resource not found
+ */
+ 404: ErrorResponse;
+};
+
+export type AwaitReplyError = AwaitReplyErrors[keyof AwaitReplyErrors];
+
+export type AwaitReplyResponses = {
+ /**
+ * Reply status for the send (reply may be null)
+ */
+ 200: SuccessEnvelope & {
+ data?: AwaitReplyResult;
+ };
+};
+
+export type AwaitReplyResponse = AwaitReplyResponses[keyof AwaitReplyResponses];
+
export type GetThreadData = {
body?: never;
path: {
diff --git a/packages/api-core/src/openapi/openapi.generated.ts b/packages/api-core/src/openapi/openapi.generated.ts
index bcd99ff4..ed88e805 100644
--- a/packages/api-core/src/openapi/openapi.generated.ts
+++ b/packages/api-core/src/openapi/openapi.generated.ts
@@ -4121,6 +4121,72 @@ export const openapiDocument: Record = {
}
}
},
+ "/sent-emails/{id}/reply": {
+ "get": {
+ "operationId": "awaitReply",
+ "summary": "Get (or wait for) the reply to a sent email",
+ "description": "Returns the first threaded inbound reply to a send, keyed by\nthe inbound email's `reply_to_sent_email_id`. This is the\ncanonical \"did a reply arrive for this send?\" call: after\n/send-mail, poll (or long-poll) here instead of hand-rolling\nan /emails/search loop.\n\nBy default the call returns immediately with `reply: null`\nwhen nothing has arrived yet. Set `wait=true` to long-poll:\nthe server holds the request up to `wait_timeout_ms`\n(default 10000, max 30000), returning as soon as the first\nreply lands. On a wait that elapses with no reply, the\nresponse has `reply: null` and `timed_out: true`.\n\nThe reply object is compact (headers plus bodies); fetch\n`/emails/{id}` with `reply.id` for the fully parsed record,\nor `/threads/{thread_id}` for the whole back-and-forth.\n",
+ "tags": [
+ "Sending"
+ ],
+ "parameters": [
+ {
+ "$ref": "#/components/parameters/ResourceId"
+ },
+ {
+ "name": "wait",
+ "in": "query",
+ "schema": {
+ "type": "boolean"
+ },
+ "description": "When true, long-poll up to `wait_timeout_ms` for the\nfirst reply to arrive instead of returning immediately.\nMirrors send-mail's server-side `wait` semantics. The\nserver accepts only the literal strings `true` / `false`\n(standard boolean query serialization); omitted means\nno wait.\n"
+ },
+ {
+ "name": "wait_timeout_ms",
+ "in": "query",
+ "schema": {
+ "type": "integer",
+ "minimum": 1000,
+ "maximum": 30000
+ },
+ "description": "Maximum time to hold the request when `wait=true`.\nServer default is 10000. NOT given an OpenAPI `default`\non purpose, matching the `/emails` `wait` parameter: a\ndefault makes some generators send the value on every\ncall.\n"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "Reply status for the send (reply may be null)",
+ "content": {
+ "application/json": {
+ "schema": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/SuccessEnvelope"
+ },
+ {
+ "type": "object",
+ "properties": {
+ "data": {
+ "$ref": "#/components/schemas/AwaitReplyResult"
+ }
+ }
+ }
+ ]
+ }
+ }
+ }
+ },
+ "400": {
+ "$ref": "#/components/responses/ValidationError"
+ },
+ "401": {
+ "$ref": "#/components/responses/Unauthorized"
+ },
+ "404": {
+ "$ref": "#/components/responses/NotFound"
+ }
+ }
+ }
+ },
"/threads/{id}": {
"parameters": [
{
@@ -12213,6 +12279,118 @@ export const openapiDocument: Record = {
}
]
},
+ "ReplyEmail": {
+ "type": "object",
+ "description": "A threaded inbound reply to one of the org's sends, keyed by\nthe inbound email's `reply_to_sent_email_id`. Compact on\npurpose: enough to read the reply and decide what to do\nnext, with `/emails/{id}` available for the fully parsed\ndetail.\n",
+ "properties": {
+ "id": {
+ "type": "string",
+ "format": "uuid",
+ "description": "Inbound email row id; usable with `/emails/{id}`."
+ },
+ "thread_id": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "uuid",
+ "description": "Conversation thread id; usable with `/threads/{id}`."
+ },
+ "reply_to_sent_email_id": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "uuid",
+ "description": "The sent-email id this inbound message replied to."
+ },
+ "from_email": {
+ "type": "string",
+ "description": "Sender of the reply (From header when present, else envelope sender)."
+ },
+ "to_email": {
+ "type": "string",
+ "description": "Recipient address the reply arrived at."
+ },
+ "subject": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "body_text": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Plain-text body of the reply, when present."
+ },
+ "body_html": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "HTML body of the reply, when present."
+ },
+ "received_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "status": {
+ "type": "string",
+ "description": "Inbound processing status of the reply row. Typically an\n`EmailStatus` value, but left as an open string here to\nmatch the server contract, which does not narrow it.\n"
+ }
+ },
+ "required": [
+ "id",
+ "thread_id",
+ "reply_to_sent_email_id",
+ "from_email",
+ "to_email",
+ "subject",
+ "body_text",
+ "body_html",
+ "received_at",
+ "status"
+ ]
+ },
+ "AwaitReplyResult": {
+ "type": "object",
+ "description": "Result of `/sent-emails/{id}/reply`. `reply` is null when no\nreply has arrived yet (no-wait call, or the wait timed out).\n",
+ "properties": {
+ "sent_email_id": {
+ "type": "string",
+ "format": "uuid",
+ "description": "The send this lookup was keyed on (echoes the path id)."
+ },
+ "reply": {
+ "allOf": [
+ {
+ "$ref": "#/components/schemas/ReplyEmail"
+ }
+ ],
+ "nullable": true
+ },
+ "waited": {
+ "type": "boolean",
+ "description": "Whether the call ran in long-poll mode (`wait=true`)."
+ },
+ "timed_out": {
+ "type": "boolean",
+ "description": "True only when a `wait=true` call elapsed its timeout with no reply."
+ }
+ },
+ "required": [
+ "sent_email_id",
+ "reply",
+ "waited",
+ "timed_out"
+ ],
+ "additionalProperties": false
+ },
"ReplyInput": {
"type": "object",
"additionalProperties": false,
diff --git a/packages/api-core/src/openapi/operations.generated.ts b/packages/api-core/src/openapi/operations.generated.ts
index 40b0e979..c32b944b 100644
--- a/packages/api-core/src/openapi/operations.generated.ts
+++ b/packages/api-core/src/openapi/operations.generated.ts
@@ -10538,6 +10538,157 @@ export const operationManifest: PrimitiveOperationManifest[] = [
"tag": "Search",
"tagCommand": "search"
},
+ {
+ "binaryResponse": false,
+ "bodyRequired": false,
+ "command": "await-reply",
+ "description": "Returns the first threaded inbound reply to a send, keyed by\nthe inbound email's `reply_to_sent_email_id`. This is the\ncanonical \"did a reply arrive for this send?\" call: after\n/send-mail, poll (or long-poll) here instead of hand-rolling\nan /emails/search loop.\n\nBy default the call returns immediately with `reply: null`\nwhen nothing has arrived yet. Set `wait=true` to long-poll:\nthe server holds the request up to `wait_timeout_ms`\n(default 10000, max 30000), returning as soon as the first\nreply lands. On a wait that elapses with no reply, the\nresponse has `reply: null` and `timed_out: true`.\n\nThe reply object is compact (headers plus bodies); fetch\n`/emails/{id}` with `reply.id` for the fully parsed record,\nor `/threads/{thread_id}` for the whole back-and-forth.\n",
+ "hasJsonBody": false,
+ "method": "GET",
+ "operationId": "awaitReply",
+ "path": "/sent-emails/{id}/reply",
+ "pathParams": [
+ {
+ "description": "Resource UUID",
+ "enum": null,
+ "name": "id",
+ "required": true,
+ "type": "string"
+ }
+ ],
+ "queryParams": [
+ {
+ "description": "When true, long-poll up to `wait_timeout_ms` for the\nfirst reply to arrive instead of returning immediately.\nMirrors send-mail's server-side `wait` semantics. The\nserver accepts only the literal strings `true` / `false`\n(standard boolean query serialization); omitted means\nno wait.\n",
+ "enum": null,
+ "name": "wait",
+ "required": false,
+ "type": "boolean"
+ },
+ {
+ "description": "Maximum time to hold the request when `wait=true`.\nServer default is 10000. NOT given an OpenAPI `default`\non purpose, matching the `/emails` `wait` parameter: a\ndefault makes some generators send the value on every\ncall.\n",
+ "enum": null,
+ "maximum": 30000,
+ "minimum": 1000,
+ "name": "wait_timeout_ms",
+ "required": false,
+ "type": "integer"
+ }
+ ],
+ "requestSchema": null,
+ "responseSchema": {
+ "type": "object",
+ "description": "Result of `/sent-emails/{id}/reply`. `reply` is null when no\nreply has arrived yet (no-wait call, or the wait timed out).\n",
+ "properties": {
+ "sent_email_id": {
+ "type": "string",
+ "format": "uuid",
+ "description": "The send this lookup was keyed on (echoes the path id)."
+ },
+ "reply": {
+ "allOf": [
+ {
+ "type": "object",
+ "description": "A threaded inbound reply to one of the org's sends, keyed by\nthe inbound email's `reply_to_sent_email_id`. Compact on\npurpose: enough to read the reply and decide what to do\nnext, with `/emails/{id}` available for the fully parsed\ndetail.\n",
+ "properties": {
+ "id": {
+ "type": "string",
+ "format": "uuid",
+ "description": "Inbound email row id; usable with `/emails/{id}`."
+ },
+ "thread_id": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "uuid",
+ "description": "Conversation thread id; usable with `/threads/{id}`."
+ },
+ "reply_to_sent_email_id": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "uuid",
+ "description": "The sent-email id this inbound message replied to."
+ },
+ "from_email": {
+ "type": "string",
+ "description": "Sender of the reply (From header when present, else envelope sender)."
+ },
+ "to_email": {
+ "type": "string",
+ "description": "Recipient address the reply arrived at."
+ },
+ "subject": {
+ "type": [
+ "string",
+ "null"
+ ]
+ },
+ "body_text": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "Plain-text body of the reply, when present."
+ },
+ "body_html": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "description": "HTML body of the reply, when present."
+ },
+ "received_at": {
+ "type": [
+ "string",
+ "null"
+ ],
+ "format": "date-time"
+ },
+ "status": {
+ "type": "string",
+ "description": "Inbound processing status of the reply row. Typically an\n`EmailStatus` value, but left as an open string here to\nmatch the server contract, which does not narrow it.\n"
+ }
+ },
+ "required": [
+ "id",
+ "thread_id",
+ "reply_to_sent_email_id",
+ "from_email",
+ "to_email",
+ "subject",
+ "body_text",
+ "body_html",
+ "received_at",
+ "status"
+ ]
+ }
+ ],
+ "nullable": true
+ },
+ "waited": {
+ "type": "boolean",
+ "description": "Whether the call ran in long-poll mode (`wait=true`)."
+ },
+ "timed_out": {
+ "type": "boolean",
+ "description": "True only when a `wait=true` call elapsed its timeout with no reply."
+ }
+ },
+ "required": [
+ "sent_email_id",
+ "reply",
+ "waited",
+ "timed_out"
+ ],
+ "additionalProperties": false
+ },
+ "sdkName": "awaitReply",
+ "summary": "Get (or wait for) the reply to a sent email",
+ "tag": "Sending",
+ "tagCommand": "sending"
+ },
{
"binaryResponse": false,
"bodyRequired": false,
diff --git a/sdk-go/api/oas_client_gen.go b/sdk-go/api/oas_client_gen.go
index 1510ab71..0dec6f4b 100644
--- a/sdk-go/api/oas_client_gen.go
+++ b/sdk-go/api/oas_client_gen.go
@@ -38,6 +38,25 @@ type Invoker interface {
//
// POST /domains
AddDomain(ctx context.Context, request *AddDomainInput) (AddDomainRes, error)
+ // AwaitReply invokes awaitReply operation.
+ //
+ // Returns the first threaded inbound reply to a send, keyed by
+ // the inbound email's `reply_to_sent_email_id`. This is the
+ // canonical "did a reply arrive for this send?" call: after
+ // /send-mail, poll (or long-poll) here instead of hand-rolling
+ // an /emails/search loop.
+ // By default the call returns immediately with `reply: null`
+ // when nothing has arrived yet. Set `wait=true` to long-poll:
+ // the server holds the request up to `wait_timeout_ms`
+ // (default 10000, max 30000), returning as soon as the first
+ // reply lands. On a wait that elapses with no reply, the
+ // response has `reply: null` and `timed_out: true`.
+ // The reply object is compact (headers plus bodies); fetch
+ // `/emails/{id}` with `reply.id` for the fully parsed record,
+ // or `/threads/{thread_id}` for the whole back-and-forth.
+ //
+ // GET /sent-emails/{id}/reply
+ AwaitReply(ctx context.Context, params AwaitReplyParams) (AwaitReplyRes, error)
// CliLogout invokes cliLogout operation.
//
// Revokes the OAuth grant used to authenticate the request. API-key
@@ -1390,6 +1409,183 @@ func (c *Client) sendAddDomain(ctx context.Context, request *AddDomainInput) (re
return result, nil
}
+// AwaitReply invokes awaitReply operation.
+//
+// Returns the first threaded inbound reply to a send, keyed by
+// the inbound email's `reply_to_sent_email_id`. This is the
+// canonical "did a reply arrive for this send?" call: after
+// /send-mail, poll (or long-poll) here instead of hand-rolling
+// an /emails/search loop.
+// By default the call returns immediately with `reply: null`
+// when nothing has arrived yet. Set `wait=true` to long-poll:
+// the server holds the request up to `wait_timeout_ms`
+// (default 10000, max 30000), returning as soon as the first
+// reply lands. On a wait that elapses with no reply, the
+// response has `reply: null` and `timed_out: true`.
+// The reply object is compact (headers plus bodies); fetch
+// `/emails/{id}` with `reply.id` for the fully parsed record,
+// or `/threads/{thread_id}` for the whole back-and-forth.
+//
+// GET /sent-emails/{id}/reply
+func (c *Client) AwaitReply(ctx context.Context, params AwaitReplyParams) (AwaitReplyRes, error) {
+ res, err := c.sendAwaitReply(ctx, params)
+ return res, err
+}
+
+func (c *Client) sendAwaitReply(ctx context.Context, params AwaitReplyParams) (res AwaitReplyRes, err error) {
+ otelAttrs := []attribute.KeyValue{
+ otelogen.OperationID("awaitReply"),
+ semconv.HTTPRequestMethodKey.String("GET"),
+ semconv.URLTemplateKey.String("/sent-emails/{id}/reply"),
+ }
+ otelAttrs = append(otelAttrs, c.cfg.Attributes...)
+
+ // Run stopwatch.
+ startTime := time.Now()
+ defer func() {
+ // Use floating point division here for higher precision (instead of Millisecond method).
+ elapsedDuration := time.Since(startTime)
+ c.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), metric.WithAttributes(otelAttrs...))
+ }()
+
+ // Increment request counter.
+ c.requests.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+
+ // Start a span for this request.
+ ctx, span := c.cfg.Tracer.Start(ctx, AwaitReplyOperation,
+ trace.WithAttributes(otelAttrs...),
+ clientSpanKind,
+ )
+ // Track stage for error reporting.
+ var stage string
+ defer func() {
+ if err != nil {
+ span.RecordError(err)
+ span.SetStatus(codes.Error, stage)
+ c.errors.Add(ctx, 1, metric.WithAttributes(otelAttrs...))
+ }
+ span.End()
+ }()
+
+ stage = "BuildURL"
+ u := uri.Clone(c.requestURL(ctx))
+ var pathParts [3]string
+ pathParts[0] = "/sent-emails/"
+ {
+ // Encode "id" parameter.
+ e := uri.NewPathEncoder(uri.PathEncoderConfig{
+ Param: "id",
+ Style: uri.PathStyleSimple,
+ Explode: false,
+ })
+ if err := func() error {
+ return e.EncodeValue(conv.UUIDToString(params.ID))
+ }(); err != nil {
+ return res, errors.Wrap(err, "encode path")
+ }
+ encoded, err := e.Result()
+ if err != nil {
+ return res, errors.Wrap(err, "encode path")
+ }
+ pathParts[1] = encoded
+ }
+ pathParts[2] = "/reply"
+ uri.AddPathParts(u, pathParts[:]...)
+
+ stage = "EncodeQueryParams"
+ q := uri.NewQueryEncoder()
+ {
+ // Encode "wait" parameter.
+ cfg := uri.QueryParameterEncodingConfig{
+ Name: "wait",
+ Style: uri.QueryStyleForm,
+ Explode: true,
+ }
+
+ if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
+ if val, ok := params.Wait.Get(); ok {
+ return e.EncodeValue(conv.BoolToString(val))
+ }
+ return nil
+ }); err != nil {
+ return res, errors.Wrap(err, "encode query")
+ }
+ }
+ {
+ // Encode "wait_timeout_ms" parameter.
+ cfg := uri.QueryParameterEncodingConfig{
+ Name: "wait_timeout_ms",
+ Style: uri.QueryStyleForm,
+ Explode: true,
+ }
+
+ if err := q.EncodeParam(cfg, func(e uri.Encoder) error {
+ if val, ok := params.WaitTimeoutMs.Get(); ok {
+ return e.EncodeValue(conv.IntToString(val))
+ }
+ return nil
+ }); err != nil {
+ return res, errors.Wrap(err, "encode query")
+ }
+ }
+ u.RawQuery = q.Values().Encode()
+
+ stage = "EncodeRequest"
+ r, err := ht.NewRequest(ctx, "GET", u)
+ if err != nil {
+ return res, errors.Wrap(err, "create request")
+ }
+
+ {
+ type bitset = [1]uint8
+ var satisfied bitset
+ {
+ stage = "Security:BearerAuth"
+ switch err := c.securityBearerAuth(ctx, AwaitReplyOperation, r); {
+ case err == nil: // if NO error
+ satisfied[0] |= 1 << 0
+ case errors.Is(err, ogenerrors.ErrSkipClientSecurity):
+ // Skip this security.
+ default:
+ return res, errors.Wrap(err, "security \"BearerAuth\"")
+ }
+ }
+
+ if ok := func() bool {
+ nextRequirement:
+ for _, requirement := range []bitset{
+ {0b00000001},
+ } {
+ for i, mask := range requirement {
+ if satisfied[i]&mask != mask {
+ continue nextRequirement
+ }
+ }
+ return true
+ }
+ return false
+ }(); !ok {
+ return res, ogenerrors.ErrSecurityRequirementIsNotSatisfied
+ }
+ }
+
+ stage = "SendRequest"
+ resp, err := c.cfg.Client.Do(r)
+ if err != nil {
+ return res, errors.Wrap(err, "do request")
+ }
+ body := resp.Body
+ defer body.Close()
+
+ stage = "DecodeResponse"
+ result, err := decodeAwaitReplyResponse(resp)
+ if err != nil {
+ return res, errors.Wrap(err, "decode response")
+ }
+
+ return result, nil
+}
+
// CliLogout invokes cliLogout operation.
//
// Revokes the OAuth grant used to authenticate the request. API-key
diff --git a/sdk-go/api/oas_handlers_gen.go b/sdk-go/api/oas_handlers_gen.go
index 7559ba1a..2776749a 100644
--- a/sdk-go/api/oas_handlers_gen.go
+++ b/sdk-go/api/oas_handlers_gen.go
@@ -224,6 +224,214 @@ func (s *Server) handleAddDomainRequest(args [0]string, argsEscaped bool, w http
}
}
+// handleAwaitReplyRequest handles awaitReply operation.
+//
+// Returns the first threaded inbound reply to a send, keyed by
+// the inbound email's `reply_to_sent_email_id`. This is the
+// canonical "did a reply arrive for this send?" call: after
+// /send-mail, poll (or long-poll) here instead of hand-rolling
+// an /emails/search loop.
+// By default the call returns immediately with `reply: null`
+// when nothing has arrived yet. Set `wait=true` to long-poll:
+// the server holds the request up to `wait_timeout_ms`
+// (default 10000, max 30000), returning as soon as the first
+// reply lands. On a wait that elapses with no reply, the
+// response has `reply: null` and `timed_out: true`.
+// The reply object is compact (headers plus bodies); fetch
+// `/emails/{id}` with `reply.id` for the fully parsed record,
+// or `/threads/{thread_id}` for the whole back-and-forth.
+//
+// GET /sent-emails/{id}/reply
+func (s *Server) handleAwaitReplyRequest(args [1]string, argsEscaped bool, w http.ResponseWriter, r *http.Request) {
+ statusWriter := &codeRecorder{ResponseWriter: w}
+ w = statusWriter
+ otelAttrs := []attribute.KeyValue{
+ otelogen.OperationID("awaitReply"),
+ semconv.HTTPRequestMethodKey.String("GET"),
+ semconv.HTTPRouteKey.String("/sent-emails/{id}/reply"),
+ }
+ // Add attributes from config.
+ otelAttrs = append(otelAttrs, s.cfg.Attributes...)
+
+ // Start a span for this request.
+ ctx, span := s.cfg.Tracer.Start(r.Context(), AwaitReplyOperation,
+ trace.WithAttributes(otelAttrs...),
+ serverSpanKind,
+ )
+ defer span.End()
+
+ // Add Labeler to context.
+ labeler := &Labeler{attrs: otelAttrs}
+ ctx = contextWithLabeler(ctx, labeler)
+
+ // Run stopwatch.
+ startTime := time.Now()
+ defer func() {
+ elapsedDuration := time.Since(startTime)
+
+ attrSet := labeler.AttributeSet()
+ attrs := attrSet.ToSlice()
+ code := statusWriter.status
+ if code != 0 {
+ codeAttr := semconv.HTTPResponseStatusCode(code)
+ attrs = append(attrs, codeAttr)
+ span.SetAttributes(codeAttr)
+ }
+ attrOpt := metric.WithAttributes(attrs...)
+
+ // Increment request counter.
+ s.requests.Add(ctx, 1, attrOpt)
+
+ // Use floating point division here for higher precision (instead of Millisecond method).
+ s.duration.Record(ctx, float64(elapsedDuration)/float64(time.Millisecond), attrOpt)
+ }()
+
+ var (
+ recordError = func(stage string, err error) {
+ span.RecordError(err)
+
+ // https://opentelemetry.io/docs/specs/semconv/http/http-spans/#status
+ // Span Status MUST be left unset if HTTP status code was in the 1xx, 2xx or 3xx ranges,
+ // unless there was another error (e.g., network error receiving the response body; or 3xx codes with
+ // max redirects exceeded), in which case status MUST be set to Error.
+ code := statusWriter.status
+ if code < 100 || code >= 500 {
+ span.SetStatus(codes.Error, stage)
+ }
+
+ attrSet := labeler.AttributeSet()
+ attrs := attrSet.ToSlice()
+ if code != 0 {
+ attrs = append(attrs, semconv.HTTPResponseStatusCode(code))
+ }
+
+ s.errors.Add(ctx, 1, metric.WithAttributes(attrs...))
+ }
+ err error
+ opErrContext = ogenerrors.OperationContext{
+ Name: AwaitReplyOperation,
+ ID: "awaitReply",
+ }
+ )
+ {
+ type bitset = [1]uint8
+ var satisfied bitset
+ {
+ sctx, ok, err := s.securityBearerAuth(ctx, AwaitReplyOperation, r)
+ if err != nil {
+ err = &ogenerrors.SecurityError{
+ OperationContext: opErrContext,
+ Security: "BearerAuth",
+ Err: err,
+ }
+ defer recordError("Security:BearerAuth", err)
+ s.cfg.ErrorHandler(ctx, w, r, err)
+ return
+ }
+ if ok {
+ satisfied[0] |= 1 << 0
+ ctx = sctx
+ }
+ }
+
+ if ok := func() bool {
+ nextRequirement:
+ for _, requirement := range []bitset{
+ {0b00000001},
+ } {
+ for i, mask := range requirement {
+ if satisfied[i]&mask != mask {
+ continue nextRequirement
+ }
+ }
+ return true
+ }
+ return false
+ }(); !ok {
+ err = &ogenerrors.SecurityError{
+ OperationContext: opErrContext,
+ Err: ogenerrors.ErrSecurityRequirementIsNotSatisfied,
+ }
+ defer recordError("Security", err)
+ s.cfg.ErrorHandler(ctx, w, r, err)
+ return
+ }
+ }
+ params, err := decodeAwaitReplyParams(args, argsEscaped, r)
+ if err != nil {
+ err = &ogenerrors.DecodeParamsError{
+ OperationContext: opErrContext,
+ Err: err,
+ }
+ defer recordError("DecodeParams", err)
+ s.cfg.ErrorHandler(ctx, w, r, err)
+ return
+ }
+
+ var rawBody []byte
+
+ var response AwaitReplyRes
+ if m := s.cfg.Middleware; m != nil {
+ mreq := middleware.Request{
+ Context: ctx,
+ OperationName: AwaitReplyOperation,
+ OperationSummary: "Get (or wait for) the reply to a sent email",
+ OperationID: "awaitReply",
+ Body: nil,
+ RawBody: rawBody,
+ Params: middleware.Parameters{
+ {
+ Name: "id",
+ In: "path",
+ }: params.ID,
+ {
+ Name: "wait",
+ In: "query",
+ }: params.Wait,
+ {
+ Name: "wait_timeout_ms",
+ In: "query",
+ }: params.WaitTimeoutMs,
+ },
+ Raw: r,
+ }
+
+ type (
+ Request = struct{}
+ Params = AwaitReplyParams
+ Response = AwaitReplyRes
+ )
+ response, err = middleware.HookMiddleware[
+ Request,
+ Params,
+ Response,
+ ](
+ m,
+ mreq,
+ unpackAwaitReplyParams,
+ func(ctx context.Context, request Request, params Params) (response Response, err error) {
+ response, err = s.h.AwaitReply(ctx, params)
+ return response, err
+ },
+ )
+ } else {
+ response, err = s.h.AwaitReply(ctx, params)
+ }
+ if err != nil {
+ defer recordError("Internal", err)
+ s.cfg.ErrorHandler(ctx, w, r, err)
+ return
+ }
+
+ if err := encodeAwaitReplyResponse(response, w, span); err != nil {
+ defer recordError("EncodeResponse", err)
+ if !errors.Is(err, ht.ErrInternalServerErrorResponse) {
+ s.cfg.ErrorHandler(ctx, w, r, err)
+ }
+ return
+ }
+}
+
// handleCliLogoutRequest handles cliLogout operation.
//
// Revokes the OAuth grant used to authenticate the request. API-key
diff --git a/sdk-go/api/oas_interfaces_gen.go b/sdk-go/api/oas_interfaces_gen.go
index bcc7e7ef..b628293d 100644
--- a/sdk-go/api/oas_interfaces_gen.go
+++ b/sdk-go/api/oas_interfaces_gen.go
@@ -5,6 +5,10 @@ type AddDomainRes interface {
addDomainRes()
}
+type AwaitReplyRes interface {
+ awaitReplyRes()
+}
+
type CliLogoutRes interface {
cliLogoutRes()
}
diff --git a/sdk-go/api/oas_json_gen.go b/sdk-go/api/oas_json_gen.go
index bc458595..b1963ae1 100644
--- a/sdk-go/api/oas_json_gen.go
+++ b/sdk-go/api/oas_json_gen.go
@@ -2495,6 +2495,376 @@ func (s *AgentSignupVerifyResultTokenType) UnmarshalJSON(data []byte) error {
return s.Decode(d)
}
+// Encode encodes AwaitReplyBadRequest as json.
+func (s *AwaitReplyBadRequest) Encode(e *jx.Encoder) {
+ unwrapped := (*ErrorResponse)(s)
+
+ unwrapped.Encode(e)
+}
+
+// Decode decodes AwaitReplyBadRequest from json.
+func (s *AwaitReplyBadRequest) Decode(d *jx.Decoder) error {
+ if s == nil {
+ return errors.New("invalid: unable to decode AwaitReplyBadRequest to nil")
+ }
+ var unwrapped ErrorResponse
+ if err := func() error {
+ if err := unwrapped.Decode(d); err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return errors.Wrap(err, "alias")
+ }
+ *s = AwaitReplyBadRequest(unwrapped)
+ return nil
+}
+
+// MarshalJSON implements stdjson.Marshaler.
+func (s *AwaitReplyBadRequest) MarshalJSON() ([]byte, error) {
+ e := jx.Encoder{}
+ s.Encode(&e)
+ return e.Bytes(), nil
+}
+
+// UnmarshalJSON implements stdjson.Unmarshaler.
+func (s *AwaitReplyBadRequest) UnmarshalJSON(data []byte) error {
+ d := jx.DecodeBytes(data)
+ return s.Decode(d)
+}
+
+// Encode encodes AwaitReplyNotFound as json.
+func (s *AwaitReplyNotFound) Encode(e *jx.Encoder) {
+ unwrapped := (*ErrorResponse)(s)
+
+ unwrapped.Encode(e)
+}
+
+// Decode decodes AwaitReplyNotFound from json.
+func (s *AwaitReplyNotFound) Decode(d *jx.Decoder) error {
+ if s == nil {
+ return errors.New("invalid: unable to decode AwaitReplyNotFound to nil")
+ }
+ var unwrapped ErrorResponse
+ if err := func() error {
+ if err := unwrapped.Decode(d); err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return errors.Wrap(err, "alias")
+ }
+ *s = AwaitReplyNotFound(unwrapped)
+ return nil
+}
+
+// MarshalJSON implements stdjson.Marshaler.
+func (s *AwaitReplyNotFound) MarshalJSON() ([]byte, error) {
+ e := jx.Encoder{}
+ s.Encode(&e)
+ return e.Bytes(), nil
+}
+
+// UnmarshalJSON implements stdjson.Unmarshaler.
+func (s *AwaitReplyNotFound) UnmarshalJSON(data []byte) error {
+ d := jx.DecodeBytes(data)
+ return s.Decode(d)
+}
+
+// Encode implements json.Marshaler.
+func (s *AwaitReplyOK) Encode(e *jx.Encoder) {
+ e.ObjStart()
+ s.encodeFields(e)
+ e.ObjEnd()
+}
+
+// encodeFields encodes fields.
+func (s *AwaitReplyOK) encodeFields(e *jx.Encoder) {
+ {
+ e.FieldStart("success")
+ e.Bool(true)
+ }
+ {
+ e.FieldStart("data")
+ s.Data.Encode(e)
+ }
+}
+
+var jsonFieldsNameOfAwaitReplyOK = [2]string{
+ 0: "success",
+ 1: "data",
+}
+
+// Decode decodes AwaitReplyOK from json.
+func (s *AwaitReplyOK) Decode(d *jx.Decoder) error {
+ if s == nil {
+ return errors.New("invalid: unable to decode AwaitReplyOK to nil")
+ }
+ var requiredBitSet [1]uint8
+
+ if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
+ switch string(k) {
+ case "success":
+ requiredBitSet[0] |= 1 << 0
+ if err := func() error {
+ v, err := d.Bool()
+ s.Success = bool(v)
+ if err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return errors.Wrap(err, "decode field \"success\"")
+ }
+ case "data":
+ requiredBitSet[0] |= 1 << 1
+ if err := func() error {
+ if err := s.Data.Decode(d); err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return errors.Wrap(err, "decode field \"data\"")
+ }
+ default:
+ return d.Skip()
+ }
+ return nil
+ }); err != nil {
+ return errors.Wrap(err, "decode AwaitReplyOK")
+ }
+ // Validate required fields.
+ var failures []validate.FieldError
+ for i, mask := range [1]uint8{
+ 0b00000011,
+ } {
+ if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
+ // Mask only required fields and check equality to mask using XOR.
+ //
+ // If XOR result is not zero, result is not equal to expected, so some fields are missed.
+ // Bits of fields which would be set are actually bits of missed fields.
+ missed := bits.OnesCount8(result)
+ for bitN := 0; bitN < missed; bitN++ {
+ bitIdx := bits.TrailingZeros8(result)
+ fieldIdx := i*8 + bitIdx
+ var name string
+ if fieldIdx < len(jsonFieldsNameOfAwaitReplyOK) {
+ name = jsonFieldsNameOfAwaitReplyOK[fieldIdx]
+ } else {
+ name = strconv.Itoa(fieldIdx)
+ }
+ failures = append(failures, validate.FieldError{
+ Name: name,
+ Error: validate.ErrFieldRequired,
+ })
+ // Reset bit.
+ result &^= 1 << bitIdx
+ }
+ }
+ }
+ if len(failures) > 0 {
+ return &validate.Error{Fields: failures}
+ }
+
+ return nil
+}
+
+// MarshalJSON implements stdjson.Marshaler.
+func (s *AwaitReplyOK) MarshalJSON() ([]byte, error) {
+ e := jx.Encoder{}
+ s.Encode(&e)
+ return e.Bytes(), nil
+}
+
+// UnmarshalJSON implements stdjson.Unmarshaler.
+func (s *AwaitReplyOK) UnmarshalJSON(data []byte) error {
+ d := jx.DecodeBytes(data)
+ return s.Decode(d)
+}
+
+// Encode implements json.Marshaler.
+func (s *AwaitReplyResult) Encode(e *jx.Encoder) {
+ e.ObjStart()
+ s.encodeFields(e)
+ e.ObjEnd()
+}
+
+// encodeFields encodes fields.
+func (s *AwaitReplyResult) encodeFields(e *jx.Encoder) {
+ {
+ e.FieldStart("sent_email_id")
+ json.EncodeUUID(e, s.SentEmailID)
+ }
+ {
+ e.FieldStart("reply")
+ s.Reply.Encode(e)
+ }
+ {
+ e.FieldStart("waited")
+ e.Bool(s.Waited)
+ }
+ {
+ e.FieldStart("timed_out")
+ e.Bool(s.TimedOut)
+ }
+}
+
+var jsonFieldsNameOfAwaitReplyResult = [4]string{
+ 0: "sent_email_id",
+ 1: "reply",
+ 2: "waited",
+ 3: "timed_out",
+}
+
+// Decode decodes AwaitReplyResult from json.
+func (s *AwaitReplyResult) Decode(d *jx.Decoder) error {
+ if s == nil {
+ return errors.New("invalid: unable to decode AwaitReplyResult to nil")
+ }
+ var requiredBitSet [1]uint8
+
+ if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
+ switch string(k) {
+ case "sent_email_id":
+ requiredBitSet[0] |= 1 << 0
+ if err := func() error {
+ v, err := json.DecodeUUID(d)
+ s.SentEmailID = v
+ if err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return errors.Wrap(err, "decode field \"sent_email_id\"")
+ }
+ case "reply":
+ requiredBitSet[0] |= 1 << 1
+ if err := func() error {
+ if err := s.Reply.Decode(d); err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return errors.Wrap(err, "decode field \"reply\"")
+ }
+ case "waited":
+ requiredBitSet[0] |= 1 << 2
+ if err := func() error {
+ v, err := d.Bool()
+ s.Waited = bool(v)
+ if err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return errors.Wrap(err, "decode field \"waited\"")
+ }
+ case "timed_out":
+ requiredBitSet[0] |= 1 << 3
+ if err := func() error {
+ v, err := d.Bool()
+ s.TimedOut = bool(v)
+ if err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return errors.Wrap(err, "decode field \"timed_out\"")
+ }
+ default:
+ return errors.Errorf("unexpected field %q", k)
+ }
+ return nil
+ }); err != nil {
+ return errors.Wrap(err, "decode AwaitReplyResult")
+ }
+ // Validate required fields.
+ var failures []validate.FieldError
+ for i, mask := range [1]uint8{
+ 0b00001111,
+ } {
+ if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
+ // Mask only required fields and check equality to mask using XOR.
+ //
+ // If XOR result is not zero, result is not equal to expected, so some fields are missed.
+ // Bits of fields which would be set are actually bits of missed fields.
+ missed := bits.OnesCount8(result)
+ for bitN := 0; bitN < missed; bitN++ {
+ bitIdx := bits.TrailingZeros8(result)
+ fieldIdx := i*8 + bitIdx
+ var name string
+ if fieldIdx < len(jsonFieldsNameOfAwaitReplyResult) {
+ name = jsonFieldsNameOfAwaitReplyResult[fieldIdx]
+ } else {
+ name = strconv.Itoa(fieldIdx)
+ }
+ failures = append(failures, validate.FieldError{
+ Name: name,
+ Error: validate.ErrFieldRequired,
+ })
+ // Reset bit.
+ result &^= 1 << bitIdx
+ }
+ }
+ }
+ if len(failures) > 0 {
+ return &validate.Error{Fields: failures}
+ }
+
+ return nil
+}
+
+// MarshalJSON implements stdjson.Marshaler.
+func (s *AwaitReplyResult) MarshalJSON() ([]byte, error) {
+ e := jx.Encoder{}
+ s.Encode(&e)
+ return e.Bytes(), nil
+}
+
+// UnmarshalJSON implements stdjson.Unmarshaler.
+func (s *AwaitReplyResult) UnmarshalJSON(data []byte) error {
+ d := jx.DecodeBytes(data)
+ return s.Decode(d)
+}
+
+// Encode encodes AwaitReplyUnauthorized as json.
+func (s *AwaitReplyUnauthorized) Encode(e *jx.Encoder) {
+ unwrapped := (*ErrorResponse)(s)
+
+ unwrapped.Encode(e)
+}
+
+// Decode decodes AwaitReplyUnauthorized from json.
+func (s *AwaitReplyUnauthorized) Decode(d *jx.Decoder) error {
+ if s == nil {
+ return errors.New("invalid: unable to decode AwaitReplyUnauthorized to nil")
+ }
+ var unwrapped ErrorResponse
+ if err := func() error {
+ if err := unwrapped.Decode(d); err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return errors.Wrap(err, "alias")
+ }
+ *s = AwaitReplyUnauthorized(unwrapped)
+ return nil
+}
+
+// MarshalJSON implements stdjson.Marshaler.
+func (s *AwaitReplyUnauthorized) MarshalJSON() ([]byte, error) {
+ e := jx.Encoder{}
+ s.Encode(&e)
+ return e.Bytes(), nil
+}
+
+// UnmarshalJSON implements stdjson.Unmarshaler.
+func (s *AwaitReplyUnauthorized) UnmarshalJSON(data []byte) error {
+ d := jx.DecodeBytes(data)
+ return s.Decode(d)
+}
+
// Encode implements json.Marshaler.
func (s *CliLoginPollResult) Encode(e *jx.Encoder) {
e.ObjStart()
@@ -36041,6 +36411,50 @@ func (s *NilInt) UnmarshalJSON(data []byte) error {
return s.Decode(d)
}
+// Encode encodes ReplyEmail as json.
+func (o NilReplyEmail) Encode(e *jx.Encoder) {
+ if o.Null {
+ e.Null()
+ return
+ }
+ o.Value.Encode(e)
+}
+
+// Decode decodes ReplyEmail from json.
+func (o *NilReplyEmail) Decode(d *jx.Decoder) error {
+ if o == nil {
+ return errors.New("invalid: unable to decode NilReplyEmail to nil")
+ }
+ if d.Next() == jx.Null {
+ if err := d.Null(); err != nil {
+ return err
+ }
+
+ var v ReplyEmail
+ o.Value = v
+ o.Null = true
+ return nil
+ }
+ o.Null = false
+ if err := o.Value.Decode(d); err != nil {
+ return err
+ }
+ return nil
+}
+
+// MarshalJSON implements stdjson.Marshaler.
+func (s NilReplyEmail) MarshalJSON() ([]byte, error) {
+ e := jx.Encoder{}
+ s.Encode(&e)
+ return e.Bytes(), nil
+}
+
+// UnmarshalJSON implements stdjson.Unmarshaler.
+func (s *NilReplyEmail) UnmarshalJSON(data []byte) error {
+ d := jx.DecodeBytes(data)
+ return s.Decode(d)
+}
+
// Encode encodes RoutingTopologyDomainsItemRoutedFunction as json.
func (o NilRoutingTopologyDomainsItemRoutedFunction) Encode(e *jx.Encoder) {
if o.Null {
@@ -43524,6 +43938,244 @@ func (s *ReplayResult) UnmarshalJSON(data []byte) error {
return s.Decode(d)
}
+// Encode implements json.Marshaler.
+func (s *ReplyEmail) Encode(e *jx.Encoder) {
+ e.ObjStart()
+ s.encodeFields(e)
+ e.ObjEnd()
+}
+
+// encodeFields encodes fields.
+func (s *ReplyEmail) encodeFields(e *jx.Encoder) {
+ {
+ e.FieldStart("id")
+ json.EncodeUUID(e, s.ID)
+ }
+ {
+ e.FieldStart("thread_id")
+ s.ThreadID.Encode(e)
+ }
+ {
+ e.FieldStart("reply_to_sent_email_id")
+ s.ReplyToSentEmailID.Encode(e)
+ }
+ {
+ e.FieldStart("from_email")
+ e.Str(s.FromEmail)
+ }
+ {
+ e.FieldStart("to_email")
+ e.Str(s.ToEmail)
+ }
+ {
+ e.FieldStart("subject")
+ s.Subject.Encode(e)
+ }
+ {
+ e.FieldStart("body_text")
+ s.BodyText.Encode(e)
+ }
+ {
+ e.FieldStart("body_html")
+ s.BodyHTML.Encode(e)
+ }
+ {
+ e.FieldStart("received_at")
+ s.ReceivedAt.Encode(e, json.EncodeDateTime)
+ }
+ {
+ e.FieldStart("status")
+ e.Str(s.Status)
+ }
+}
+
+var jsonFieldsNameOfReplyEmail = [10]string{
+ 0: "id",
+ 1: "thread_id",
+ 2: "reply_to_sent_email_id",
+ 3: "from_email",
+ 4: "to_email",
+ 5: "subject",
+ 6: "body_text",
+ 7: "body_html",
+ 8: "received_at",
+ 9: "status",
+}
+
+// Decode decodes ReplyEmail from json.
+func (s *ReplyEmail) Decode(d *jx.Decoder) error {
+ if s == nil {
+ return errors.New("invalid: unable to decode ReplyEmail to nil")
+ }
+ var requiredBitSet [2]uint8
+
+ if err := d.ObjBytes(func(d *jx.Decoder, k []byte) error {
+ switch string(k) {
+ case "id":
+ requiredBitSet[0] |= 1 << 0
+ if err := func() error {
+ v, err := json.DecodeUUID(d)
+ s.ID = v
+ if err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return errors.Wrap(err, "decode field \"id\"")
+ }
+ case "thread_id":
+ requiredBitSet[0] |= 1 << 1
+ if err := func() error {
+ if err := s.ThreadID.Decode(d); err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return errors.Wrap(err, "decode field \"thread_id\"")
+ }
+ case "reply_to_sent_email_id":
+ requiredBitSet[0] |= 1 << 2
+ if err := func() error {
+ if err := s.ReplyToSentEmailID.Decode(d); err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return errors.Wrap(err, "decode field \"reply_to_sent_email_id\"")
+ }
+ case "from_email":
+ requiredBitSet[0] |= 1 << 3
+ if err := func() error {
+ v, err := d.Str()
+ s.FromEmail = string(v)
+ if err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return errors.Wrap(err, "decode field \"from_email\"")
+ }
+ case "to_email":
+ requiredBitSet[0] |= 1 << 4
+ if err := func() error {
+ v, err := d.Str()
+ s.ToEmail = string(v)
+ if err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return errors.Wrap(err, "decode field \"to_email\"")
+ }
+ case "subject":
+ requiredBitSet[0] |= 1 << 5
+ if err := func() error {
+ if err := s.Subject.Decode(d); err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return errors.Wrap(err, "decode field \"subject\"")
+ }
+ case "body_text":
+ requiredBitSet[0] |= 1 << 6
+ if err := func() error {
+ if err := s.BodyText.Decode(d); err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return errors.Wrap(err, "decode field \"body_text\"")
+ }
+ case "body_html":
+ requiredBitSet[0] |= 1 << 7
+ if err := func() error {
+ if err := s.BodyHTML.Decode(d); err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return errors.Wrap(err, "decode field \"body_html\"")
+ }
+ case "received_at":
+ requiredBitSet[1] |= 1 << 0
+ if err := func() error {
+ if err := s.ReceivedAt.Decode(d, json.DecodeDateTime); err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return errors.Wrap(err, "decode field \"received_at\"")
+ }
+ case "status":
+ requiredBitSet[1] |= 1 << 1
+ if err := func() error {
+ v, err := d.Str()
+ s.Status = string(v)
+ if err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return errors.Wrap(err, "decode field \"status\"")
+ }
+ default:
+ return d.Skip()
+ }
+ return nil
+ }); err != nil {
+ return errors.Wrap(err, "decode ReplyEmail")
+ }
+ // Validate required fields.
+ var failures []validate.FieldError
+ for i, mask := range [2]uint8{
+ 0b11111111,
+ 0b00000011,
+ } {
+ if result := (requiredBitSet[i] & mask) ^ mask; result != 0 {
+ // Mask only required fields and check equality to mask using XOR.
+ //
+ // If XOR result is not zero, result is not equal to expected, so some fields are missed.
+ // Bits of fields which would be set are actually bits of missed fields.
+ missed := bits.OnesCount8(result)
+ for bitN := 0; bitN < missed; bitN++ {
+ bitIdx := bits.TrailingZeros8(result)
+ fieldIdx := i*8 + bitIdx
+ var name string
+ if fieldIdx < len(jsonFieldsNameOfReplyEmail) {
+ name = jsonFieldsNameOfReplyEmail[fieldIdx]
+ } else {
+ name = strconv.Itoa(fieldIdx)
+ }
+ failures = append(failures, validate.FieldError{
+ Name: name,
+ Error: validate.ErrFieldRequired,
+ })
+ // Reset bit.
+ result &^= 1 << bitIdx
+ }
+ }
+ }
+ if len(failures) > 0 {
+ return &validate.Error{Fields: failures}
+ }
+
+ return nil
+}
+
+// MarshalJSON implements stdjson.Marshaler.
+func (s *ReplyEmail) MarshalJSON() ([]byte, error) {
+ e := jx.Encoder{}
+ s.Encode(&e)
+ return e.Bytes(), nil
+}
+
+// UnmarshalJSON implements stdjson.Unmarshaler.
+func (s *ReplyEmail) UnmarshalJSON(data []byte) error {
+ d := jx.DecodeBytes(data)
+ return s.Decode(d)
+}
+
// Encode implements json.Marshaler.
func (s *ReplyInput) Encode(e *jx.Encoder) {
e.ObjStart()
diff --git a/sdk-go/api/oas_operations_gen.go b/sdk-go/api/oas_operations_gen.go
index 46e5cd54..96e806bc 100644
--- a/sdk-go/api/oas_operations_gen.go
+++ b/sdk-go/api/oas_operations_gen.go
@@ -7,6 +7,7 @@ type OperationName = string
const (
AddDomainOperation OperationName = "AddDomain"
+ AwaitReplyOperation OperationName = "AwaitReply"
CliLogoutOperation OperationName = "CliLogout"
CreateAgentAccountOperation OperationName = "CreateAgentAccount"
CreateAgentClaimLinkOperation OperationName = "CreateAgentClaimLink"
diff --git a/sdk-go/api/oas_parameters_gen.go b/sdk-go/api/oas_parameters_gen.go
index 526c3a1b..5b9d11b6 100644
--- a/sdk-go/api/oas_parameters_gen.go
+++ b/sdk-go/api/oas_parameters_gen.go
@@ -16,6 +16,211 @@ import (
"github.com/ogen-go/ogen/validate"
)
+// AwaitReplyParams is parameters of awaitReply operation.
+type AwaitReplyParams struct {
+ // Resource UUID.
+ ID uuid.UUID
+ // When true, long-poll up to `wait_timeout_ms` for the
+ // first reply to arrive instead of returning immediately.
+ // Mirrors send-mail's server-side `wait` semantics. The
+ // server accepts only the literal strings `true` / `false`
+ // (standard boolean query serialization); omitted means
+ // no wait.
+ Wait OptBool `json:",omitempty,omitzero"`
+ // Maximum time to hold the request when `wait=true`.
+ // Server default is 10000. NOT given an OpenAPI `default`
+ // on purpose, matching the `/emails` `wait` parameter: a
+ // default makes some generators send the value on every
+ // call.
+ WaitTimeoutMs OptInt `json:",omitempty,omitzero"`
+}
+
+func unpackAwaitReplyParams(packed middleware.Parameters) (params AwaitReplyParams) {
+ {
+ key := middleware.ParameterKey{
+ Name: "id",
+ In: "path",
+ }
+ params.ID = packed[key].(uuid.UUID)
+ }
+ {
+ key := middleware.ParameterKey{
+ Name: "wait",
+ In: "query",
+ }
+ if v, ok := packed[key]; ok {
+ params.Wait = v.(OptBool)
+ }
+ }
+ {
+ key := middleware.ParameterKey{
+ Name: "wait_timeout_ms",
+ In: "query",
+ }
+ if v, ok := packed[key]; ok {
+ params.WaitTimeoutMs = v.(OptInt)
+ }
+ }
+ return params
+}
+
+func decodeAwaitReplyParams(args [1]string, argsEscaped bool, r *http.Request) (params AwaitReplyParams, _ error) {
+ q := uri.NewQueryDecoder(r.URL.Query())
+ // Decode path: id.
+ if err := func() error {
+ param := args[0]
+ if argsEscaped {
+ unescaped, err := url.PathUnescape(args[0])
+ if err != nil {
+ return errors.Wrap(err, "unescape path")
+ }
+ param = unescaped
+ }
+ if len(param) > 0 {
+ d := uri.NewPathDecoder(uri.PathDecoderConfig{
+ Param: "id",
+ Value: param,
+ Style: uri.PathStyleSimple,
+ Explode: false,
+ })
+
+ if err := func() error {
+ val, err := d.DecodeValue()
+ if err != nil {
+ return err
+ }
+
+ c, err := conv.ToUUID(val)
+ if err != nil {
+ return err
+ }
+
+ params.ID = c
+ return nil
+ }(); err != nil {
+ return err
+ }
+ } else {
+ return validate.ErrFieldRequired
+ }
+ return nil
+ }(); err != nil {
+ return params, &ogenerrors.DecodeParamError{
+ Name: "id",
+ In: "path",
+ Err: err,
+ }
+ }
+ // Decode query: wait.
+ if err := func() error {
+ cfg := uri.QueryParameterDecodingConfig{
+ Name: "wait",
+ Style: uri.QueryStyleForm,
+ Explode: true,
+ }
+
+ if err := q.HasParam(cfg); err == nil {
+ if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
+ var paramsDotWaitVal bool
+ if err := func() error {
+ val, err := d.DecodeValue()
+ if err != nil {
+ return err
+ }
+
+ c, err := conv.ToBool(val)
+ if err != nil {
+ return err
+ }
+
+ paramsDotWaitVal = c
+ return nil
+ }(); err != nil {
+ return err
+ }
+ params.Wait.SetTo(paramsDotWaitVal)
+ return nil
+ }); err != nil {
+ return err
+ }
+ }
+ return nil
+ }(); err != nil {
+ return params, &ogenerrors.DecodeParamError{
+ Name: "wait",
+ In: "query",
+ Err: err,
+ }
+ }
+ // Decode query: wait_timeout_ms.
+ if err := func() error {
+ cfg := uri.QueryParameterDecodingConfig{
+ Name: "wait_timeout_ms",
+ Style: uri.QueryStyleForm,
+ Explode: true,
+ }
+
+ if err := q.HasParam(cfg); err == nil {
+ if err := q.DecodeParam(cfg, func(d uri.Decoder) error {
+ var paramsDotWaitTimeoutMsVal int
+ if err := func() error {
+ val, err := d.DecodeValue()
+ if err != nil {
+ return err
+ }
+
+ c, err := conv.ToInt(val)
+ if err != nil {
+ return err
+ }
+
+ paramsDotWaitTimeoutMsVal = c
+ return nil
+ }(); err != nil {
+ return err
+ }
+ params.WaitTimeoutMs.SetTo(paramsDotWaitTimeoutMsVal)
+ return nil
+ }); err != nil {
+ return err
+ }
+ if err := func() error {
+ if value, ok := params.WaitTimeoutMs.Get(); ok {
+ if err := func() error {
+ if err := (validate.Int{
+ MinSet: true,
+ Min: 1000,
+ MaxSet: true,
+ Max: 30000,
+ MinExclusive: false,
+ MaxExclusive: false,
+ MultipleOfSet: false,
+ MultipleOf: 0,
+ Pattern: nil,
+ }).Validate(int64(value)); err != nil {
+ return errors.Wrap(err, "int")
+ }
+ return nil
+ }(); err != nil {
+ return err
+ }
+ }
+ return nil
+ }(); err != nil {
+ return err
+ }
+ }
+ return nil
+ }(); err != nil {
+ return params, &ogenerrors.DecodeParamError{
+ Name: "wait_timeout_ms",
+ In: "query",
+ Err: err,
+ }
+ }
+ return params, nil
+}
+
// CreateEmailChallengeParams is parameters of createEmailChallenge operation.
type CreateEmailChallengeParams struct {
// Optional idempotency key. Retrying a request with the same key returns
diff --git a/sdk-go/api/oas_response_decoders_gen.go b/sdk-go/api/oas_response_decoders_gen.go
index 6596dbd4..a1a32416 100644
--- a/sdk-go/api/oas_response_decoders_gen.go
+++ b/sdk-go/api/oas_response_decoders_gen.go
@@ -198,6 +198,179 @@ func decodeAddDomainResponse(resp *http.Response) (res AddDomainRes, _ error) {
return res, validate.UnexpectedStatusCodeWithResponse(resp)
}
+func decodeAwaitReplyResponse(resp *http.Response) (res AwaitReplyRes, _ error) {
+ switch resp.StatusCode {
+ case 200:
+ // Code 200.
+ ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+ if err != nil {
+ return res, errors.Wrap(err, "parse media type")
+ }
+ switch {
+ case ct == "application/json":
+ buf, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return res, err
+ }
+ d := jx.DecodeBytes(buf)
+
+ var response AwaitReplyOK
+ if err := func() error {
+ if err := response.Decode(d); err != nil {
+ return err
+ }
+ if err := d.Skip(); err != io.EOF {
+ return errors.New("unexpected trailing data")
+ }
+ return nil
+ }(); err != nil {
+ err = &ogenerrors.DecodeBodyError{
+ ContentType: ct,
+ Body: buf,
+ Err: err,
+ }
+ return res, err
+ }
+ return &response, nil
+ default:
+ return res, validate.InvalidContentType(ct)
+ }
+ case 400:
+ // Code 400.
+ ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+ if err != nil {
+ return res, errors.Wrap(err, "parse media type")
+ }
+ switch {
+ case ct == "application/json":
+ buf, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return res, err
+ }
+ d := jx.DecodeBytes(buf)
+
+ var response AwaitReplyBadRequest
+ if err := func() error {
+ if err := response.Decode(d); err != nil {
+ return err
+ }
+ if err := d.Skip(); err != io.EOF {
+ return errors.New("unexpected trailing data")
+ }
+ return nil
+ }(); err != nil {
+ err = &ogenerrors.DecodeBodyError{
+ ContentType: ct,
+ Body: buf,
+ Err: err,
+ }
+ return res, err
+ }
+ // Validate response.
+ if err := func() error {
+ if err := response.Validate(); err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return res, errors.Wrap(err, "validate")
+ }
+ return &response, nil
+ default:
+ return res, validate.InvalidContentType(ct)
+ }
+ case 401:
+ // Code 401.
+ ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+ if err != nil {
+ return res, errors.Wrap(err, "parse media type")
+ }
+ switch {
+ case ct == "application/json":
+ buf, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return res, err
+ }
+ d := jx.DecodeBytes(buf)
+
+ var response AwaitReplyUnauthorized
+ if err := func() error {
+ if err := response.Decode(d); err != nil {
+ return err
+ }
+ if err := d.Skip(); err != io.EOF {
+ return errors.New("unexpected trailing data")
+ }
+ return nil
+ }(); err != nil {
+ err = &ogenerrors.DecodeBodyError{
+ ContentType: ct,
+ Body: buf,
+ Err: err,
+ }
+ return res, err
+ }
+ // Validate response.
+ if err := func() error {
+ if err := response.Validate(); err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return res, errors.Wrap(err, "validate")
+ }
+ return &response, nil
+ default:
+ return res, validate.InvalidContentType(ct)
+ }
+ case 404:
+ // Code 404.
+ ct, _, err := mime.ParseMediaType(resp.Header.Get("Content-Type"))
+ if err != nil {
+ return res, errors.Wrap(err, "parse media type")
+ }
+ switch {
+ case ct == "application/json":
+ buf, err := io.ReadAll(resp.Body)
+ if err != nil {
+ return res, err
+ }
+ d := jx.DecodeBytes(buf)
+
+ var response AwaitReplyNotFound
+ if err := func() error {
+ if err := response.Decode(d); err != nil {
+ return err
+ }
+ if err := d.Skip(); err != io.EOF {
+ return errors.New("unexpected trailing data")
+ }
+ return nil
+ }(); err != nil {
+ err = &ogenerrors.DecodeBodyError{
+ ContentType: ct,
+ Body: buf,
+ Err: err,
+ }
+ return res, err
+ }
+ // Validate response.
+ if err := func() error {
+ if err := response.Validate(); err != nil {
+ return err
+ }
+ return nil
+ }(); err != nil {
+ return res, errors.Wrap(err, "validate")
+ }
+ return &response, nil
+ default:
+ return res, validate.InvalidContentType(ct)
+ }
+ }
+ return res, validate.UnexpectedStatusCodeWithResponse(resp)
+}
+
func decodeCliLogoutResponse(resp *http.Response) (res CliLogoutRes, _ error) {
switch resp.StatusCode {
case 200:
diff --git a/sdk-go/api/oas_response_encoders_gen.go b/sdk-go/api/oas_response_encoders_gen.go
index 25bd6017..bff85042 100644
--- a/sdk-go/api/oas_response_encoders_gen.go
+++ b/sdk-go/api/oas_response_encoders_gen.go
@@ -73,6 +73,65 @@ func encodeAddDomainResponse(response AddDomainRes, w http.ResponseWriter, span
}
}
+func encodeAwaitReplyResponse(response AwaitReplyRes, w http.ResponseWriter, span trace.Span) error {
+ switch response := response.(type) {
+ case *AwaitReplyOK:
+ w.Header().Set("Content-Type", "application/json; charset=utf-8")
+ w.WriteHeader(200)
+ span.SetStatus(codes.Ok, http.StatusText(200))
+
+ e := new(jx.Encoder)
+ response.Encode(e)
+ if _, err := e.WriteTo(w); err != nil {
+ return errors.Wrap(err, "write")
+ }
+
+ return nil
+
+ case *AwaitReplyBadRequest:
+ w.Header().Set("Content-Type", "application/json; charset=utf-8")
+ w.WriteHeader(400)
+ span.SetStatus(codes.Error, http.StatusText(400))
+
+ e := new(jx.Encoder)
+ response.Encode(e)
+ if _, err := e.WriteTo(w); err != nil {
+ return errors.Wrap(err, "write")
+ }
+
+ return nil
+
+ case *AwaitReplyUnauthorized:
+ w.Header().Set("Content-Type", "application/json; charset=utf-8")
+ w.WriteHeader(401)
+ span.SetStatus(codes.Error, http.StatusText(401))
+
+ e := new(jx.Encoder)
+ response.Encode(e)
+ if _, err := e.WriteTo(w); err != nil {
+ return errors.Wrap(err, "write")
+ }
+
+ return nil
+
+ case *AwaitReplyNotFound:
+ w.Header().Set("Content-Type", "application/json; charset=utf-8")
+ w.WriteHeader(404)
+ span.SetStatus(codes.Error, http.StatusText(404))
+
+ e := new(jx.Encoder)
+ response.Encode(e)
+ if _, err := e.WriteTo(w); err != nil {
+ return errors.Wrap(err, "write")
+ }
+
+ return nil
+
+ default:
+ return errors.Errorf("unexpected response type: %T", response)
+ }
+}
+
func encodeCliLogoutResponse(response CliLogoutRes, w http.ResponseWriter, span trace.Span) error {
switch response := response.(type) {
case *CliLogoutOK:
diff --git a/sdk-go/api/oas_router_gen.go b/sdk-go/api/oas_router_gen.go
index ca055a74..9a75a84a 100644
--- a/sdk-go/api/oas_router_gen.go
+++ b/sdk-go/api/oas_router_gen.go
@@ -11,284 +11,287 @@ import (
)
var (
- rn56AllowedHeaders = map[string]string{
+ rn59AllowedHeaders = map[string]string{
"GET": "Authorization",
"PATCH": "Authorization,Content-Type",
}
- rn74AllowedHeaders = map[string]string{
+ rn75AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn83AllowedHeaders = map[string]string{
+ rn84AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn113AllowedHeaders = map[string]string{
+ rn114AllowedHeaders = map[string]string{
"POST": "Authorization",
}
- rn4AllowedHeaders = map[string]string{
+ rn7AllowedHeaders = map[string]string{
"POST": "Content-Type",
}
- rn6AllowedHeaders = map[string]string{
+ rn9AllowedHeaders = map[string]string{
"POST": "Authorization,Content-Type",
}
- rn125AllowedHeaders = map[string]string{
+ rn126AllowedHeaders = map[string]string{
"POST": "Authorization,Content-Type",
}
- rn134AllowedHeaders = map[string]string{
+ rn135AllowedHeaders = map[string]string{
"POST": "Authorization,Content-Type",
}
- rn108AllowedHeaders = map[string]string{
+ rn109AllowedHeaders = map[string]string{
"POST": "Content-Type",
}
- rn127AllowedHeaders = map[string]string{
+ rn128AllowedHeaders = map[string]string{
"POST": "Content-Type",
}
- rn135AllowedHeaders = map[string]string{
+ rn136AllowedHeaders = map[string]string{
"POST": "Content-Type",
}
- rn29AllowedHeaders = map[string]string{
+ rn32AllowedHeaders = map[string]string{
"POST": "Authorization,Content-Type",
}
- rn99AllowedHeaders = map[string]string{
+ rn100AllowedHeaders = map[string]string{
"POST": "Content-Type",
}
- rn129AllowedHeaders = map[string]string{
+ rn130AllowedHeaders = map[string]string{
"POST": "Content-Type",
}
- rn3AllowedHeaders = map[string]string{
+ rn6AllowedHeaders = map[string]string{
"POST": "Authorization,Content-Type",
}
- rn110AllowedHeaders = map[string]string{
+ rn111AllowedHeaders = map[string]string{
"POST": "Content-Type",
}
- rn131AllowedHeaders = map[string]string{
+ rn132AllowedHeaders = map[string]string{
"POST": "Content-Type",
}
- rn136AllowedHeaders = map[string]string{
+ rn137AllowedHeaders = map[string]string{
"POST": "Content-Type",
}
rn1AllowedHeaders = map[string]string{
"GET": "Authorization",
"POST": "Authorization,Content-Type",
}
- rn31AllowedHeaders = map[string]string{
+ rn34AllowedHeaders = map[string]string{
"DELETE": "Authorization",
"PATCH": "Authorization,Content-Type",
}
- rn138AllowedHeaders = map[string]string{
+ rn139AllowedHeaders = map[string]string{
"POST": "Authorization",
}
- rn53AllowedHeaders = map[string]string{
+ rn56AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn88AllowedHeaders = map[string]string{
+ rn89AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn115AllowedHeaders = map[string]string{
+ rn116AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn34AllowedHeaders = map[string]string{
+ rn37AllowedHeaders = map[string]string{
"DELETE": "Authorization",
"GET": "Authorization",
}
- rn52AllowedHeaders = map[string]string{
+ rn55AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn61AllowedHeaders = map[string]string{
+ rn64AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn50AllowedHeaders = map[string]string{
+ rn53AllowedHeaders = map[string]string{
"POST": "Authorization",
}
- rn54AllowedHeaders = map[string]string{
+ rn57AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn105AllowedHeaders = map[string]string{
+ rn106AllowedHeaders = map[string]string{
"POST": "Authorization",
}
- rn107AllowedHeaders = map[string]string{
+ rn108AllowedHeaders = map[string]string{
"POST": "Authorization,Content-Type",
}
- rn10AllowedHeaders = map[string]string{
+ rn13AllowedHeaders = map[string]string{
"GET": "Authorization",
"POST": "Authorization,Content-Type",
}
- rn36AllowedHeaders = map[string]string{
+ rn39AllowedHeaders = map[string]string{
"DELETE": "Authorization",
"PATCH": "Authorization,Content-Type",
}
- rn132AllowedHeaders = map[string]string{
+ rn133AllowedHeaders = map[string]string{
"POST": "Authorization",
}
- rn11AllowedHeaders = map[string]string{
+ rn14AllowedHeaders = map[string]string{
"GET": "Authorization",
"POST": "Authorization,Content-Type",
}
- rn38AllowedHeaders = map[string]string{
+ rn41AllowedHeaders = map[string]string{
"DELETE": "Authorization",
"PATCH": "Authorization,Content-Type",
}
- rn13AllowedHeaders = map[string]string{
+ rn16AllowedHeaders = map[string]string{
"GET": "Authorization",
"POST": "Authorization,Content-Type",
}
- rn68AllowedHeaders = map[string]string{
+ rn71AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn15AllowedHeaders = map[string]string{
+ rn18AllowedHeaders = map[string]string{
"DELETE": "Authorization",
"GET": "Authorization",
"PUT": "Authorization,Content-Type",
}
- rn89AllowedHeaders = map[string]string{
+ rn90AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn122AllowedHeaders = map[string]string{
+ rn123AllowedHeaders = map[string]string{
"DELETE": "Authorization",
"PUT": "Authorization,Content-Type",
}
- rn63AllowedHeaders = map[string]string{
+ rn66AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn16AllowedHeaders = map[string]string{
+ rn19AllowedHeaders = map[string]string{
"GET": "Authorization",
"POST": "Authorization,Content-Type",
}
- rn40AllowedHeaders = map[string]string{
+ rn43AllowedHeaders = map[string]string{
"DELETE": "Authorization",
"PUT": "Authorization,Content-Type",
}
- rn133AllowedHeaders = map[string]string{
+ rn134AllowedHeaders = map[string]string{
"POST": "Authorization,Content-Type",
}
- rn66AllowedHeaders = map[string]string{
+ rn69AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn67AllowedHeaders = map[string]string{
+ rn70AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn41AllowedHeaders = map[string]string{
+ rn44AllowedHeaders = map[string]string{
"DELETE": "Authorization,X-Primitive-Function-Id",
"GET": "Authorization,X-Primitive-Function-Id",
"PUT": "Authorization,Content-Type,X-Primitive-Function-Id",
}
- rn116AllowedHeaders = map[string]string{
+ rn117AllowedHeaders = map[string]string{
"GET": "Authorization,X-Primitive-Function-Id",
}
- rn17AllowedHeaders = map[string]string{
+ rn20AllowedHeaders = map[string]string{
"GET": "Authorization",
"POST": "Authorization,Content-Type",
}
- rn43AllowedHeaders = map[string]string{
+ rn46AllowedHeaders = map[string]string{
"DELETE": "Authorization",
"PUT": "Authorization,Content-Type",
}
- rn18AllowedHeaders = map[string]string{
+ rn21AllowedHeaders = map[string]string{
"GET": "Authorization",
"POST": "Authorization,Content-Type",
}
- rn25AllowedHeaders = map[string]string{
+ rn28AllowedHeaders = map[string]string{
"DELETE": "Authorization",
"PATCH": "Authorization,Content-Type",
}
- rn92AllowedHeaders = map[string]string{
+ rn93AllowedHeaders = map[string]string{
"POST": "Authorization,Content-Type",
}
- rn112AllowedHeaders = map[string]string{
+ rn113AllowedHeaders = map[string]string{
"DELETE": "Authorization",
}
- rn93AllowedHeaders = map[string]string{
+ rn94AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn27AllowedHeaders = map[string]string{
+ rn30AllowedHeaders = map[string]string{
"POST": "Authorization,Content-Type",
}
- rn20AllowedHeaders = map[string]string{
+ rn23AllowedHeaders = map[string]string{
"GET": "Authorization",
"POST": "Authorization,Content-Type",
}
- rn100AllowedHeaders = map[string]string{
+ rn101AllowedHeaders = map[string]string{
"POST": "Authorization,Content-Type",
}
- rn123AllowedHeaders = map[string]string{
+ rn124AllowedHeaders = map[string]string{
"POST": "Authorization,Content-Type",
}
- rn45AllowedHeaders = map[string]string{
+ rn48AllowedHeaders = map[string]string{
"DELETE": "Authorization",
"PATCH": "Authorization,Content-Type",
}
- rn118AllowedHeaders = map[string]string{
+ rn119AllowedHeaders = map[string]string{
"POST": "Authorization,Content-Type",
}
- rn120AllowedHeaders = map[string]string{
+ rn121AllowedHeaders = map[string]string{
"POST": "Authorization,Content-Type,Idempotency-Key",
}
- rn69AllowedHeaders = map[string]string{
+ rn73AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn94AllowedHeaders = map[string]string{
+ rn95AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn72AllowedHeaders = map[string]string{
+ rn4AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn78AllowedHeaders = map[string]string{
+ rn5AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn84AllowedHeaders = map[string]string{
+ rn79AllowedHeaders = map[string]string{
+ "GET": "Authorization",
+ }
+ rn85AllowedHeaders = map[string]string{
"POST": "Authorization,Content-Type",
}
- rn81AllowedHeaders = map[string]string{
+ rn82AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn21AllowedHeaders = map[string]string{
+ rn24AllowedHeaders = map[string]string{
"GET": "Authorization",
"POST": "Authorization,Content-Type",
}
- rn47AllowedHeaders = map[string]string{
+ rn50AllowedHeaders = map[string]string{
"DELETE": "Authorization",
"PATCH": "Authorization,Content-Type",
}
- rn96AllowedHeaders = map[string]string{
+ rn97AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn23AllowedHeaders = map[string]string{
+ rn26AllowedHeaders = map[string]string{
"GET": "Authorization",
"POST": "Authorization,Content-Type",
}
- rn49AllowedHeaders = map[string]string{
+ rn52AllowedHeaders = map[string]string{
"DELETE": "Authorization",
"GET": "Authorization",
"PATCH": "Authorization,Content-Type",
}
- rn114AllowedHeaders = map[string]string{
+ rn115AllowedHeaders = map[string]string{
"POST": "Authorization",
}
- rn87AllowedHeaders = map[string]string{
+ rn88AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn103AllowedHeaders = map[string]string{
+ rn104AllowedHeaders = map[string]string{
"POST": "Authorization",
}
- rn7AllowedHeaders = map[string]string{
+ rn10AllowedHeaders = map[string]string{
"POST": "Authorization,Content-Type",
}
- rn60AllowedHeaders = map[string]string{
+ rn63AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn97AllowedHeaders = map[string]string{
+ rn98AllowedHeaders = map[string]string{
"POST": "Authorization,Content-Type",
}
- rn85AllowedHeaders = map[string]string{
+ rn86AllowedHeaders = map[string]string{
"GET": "Authorization",
}
- rn9AllowedHeaders = map[string]string{
+ rn12AllowedHeaders = map[string]string{
"POST": "Authorization,Content-Type,Idempotency-Key",
}
- rn90AllowedHeaders = map[string]string{
+ rn91AllowedHeaders = map[string]string{
"GET": "Authorization",
"POST": "Authorization,Content-Type",
}
- rn73AllowedHeaders = map[string]string{
+ rn74AllowedHeaders = map[string]string{
"GET": "Authorization",
"PUT": "Authorization,Content-Type",
}
@@ -374,7 +377,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET,PATCH",
- allowedHeaders: rn56AllowedHeaders,
+ allowedHeaders: rn59AllowedHeaders,
acceptPost: "",
acceptPatch: "application/json",
})
@@ -411,7 +414,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn74AllowedHeaders,
+ allowedHeaders: rn75AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -435,7 +438,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn83AllowedHeaders,
+ allowedHeaders: rn84AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -460,7 +463,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn113AllowedHeaders,
+ allowedHeaders: rn114AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -515,7 +518,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn4AllowedHeaders,
+ allowedHeaders: rn7AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -552,7 +555,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn6AllowedHeaders,
+ allowedHeaders: rn9AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -577,7 +580,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn125AllowedHeaders,
+ allowedHeaders: rn126AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -602,7 +605,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn134AllowedHeaders,
+ allowedHeaders: rn135AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -641,7 +644,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn108AllowedHeaders,
+ allowedHeaders: rn109AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -666,7 +669,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn127AllowedHeaders,
+ allowedHeaders: rn128AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -691,7 +694,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn135AllowedHeaders,
+ allowedHeaders: rn136AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -719,7 +722,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn29AllowedHeaders,
+ allowedHeaders: rn32AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -822,7 +825,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn99AllowedHeaders,
+ allowedHeaders: rn100AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -847,7 +850,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn129AllowedHeaders,
+ allowedHeaders: rn130AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -874,7 +877,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn3AllowedHeaders,
+ allowedHeaders: rn6AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -913,7 +916,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn110AllowedHeaders,
+ allowedHeaders: rn111AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -938,7 +941,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn131AllowedHeaders,
+ allowedHeaders: rn132AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -963,7 +966,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn136AllowedHeaders,
+ allowedHeaders: rn137AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -1032,7 +1035,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "DELETE,PATCH",
- allowedHeaders: rn31AllowedHeaders,
+ allowedHeaders: rn34AllowedHeaders,
acceptPost: "",
acceptPatch: "application/json",
})
@@ -1071,7 +1074,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn138AllowedHeaders,
+ allowedHeaders: rn139AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -1098,7 +1101,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn53AllowedHeaders,
+ allowedHeaders: rn56AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -1140,7 +1143,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn88AllowedHeaders,
+ allowedHeaders: rn89AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -1177,7 +1180,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn115AllowedHeaders,
+ allowedHeaders: rn116AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -1210,7 +1213,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "DELETE,GET",
- allowedHeaders: rn34AllowedHeaders,
+ allowedHeaders: rn37AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -1249,7 +1252,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn52AllowedHeaders,
+ allowedHeaders: rn55AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -1276,7 +1279,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn61AllowedHeaders,
+ allowedHeaders: rn64AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -1303,7 +1306,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn50AllowedHeaders,
+ allowedHeaders: rn53AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -1342,7 +1345,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn54AllowedHeaders,
+ allowedHeaders: rn57AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -1381,7 +1384,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn105AllowedHeaders,
+ allowedHeaders: rn106AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -1408,7 +1411,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn107AllowedHeaders,
+ allowedHeaders: rn108AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -1444,7 +1447,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET,POST",
- allowedHeaders: rn10AllowedHeaders,
+ allowedHeaders: rn13AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -1483,7 +1486,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "DELETE,PATCH",
- allowedHeaders: rn36AllowedHeaders,
+ allowedHeaders: rn39AllowedHeaders,
acceptPost: "",
acceptPatch: "application/json",
})
@@ -1510,7 +1513,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn132AllowedHeaders,
+ allowedHeaders: rn133AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -1554,7 +1557,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET,POST",
- allowedHeaders: rn11AllowedHeaders,
+ allowedHeaders: rn14AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -1594,7 +1597,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "DELETE,PATCH",
- allowedHeaders: rn38AllowedHeaders,
+ allowedHeaders: rn41AllowedHeaders,
acceptPost: "",
acceptPatch: "application/json",
})
@@ -1622,7 +1625,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET,POST",
- allowedHeaders: rn13AllowedHeaders,
+ allowedHeaders: rn16AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -1659,7 +1662,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn68AllowedHeaders,
+ allowedHeaders: rn71AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -1696,7 +1699,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "DELETE,GET,PUT",
- allowedHeaders: rn15AllowedHeaders,
+ allowedHeaders: rn18AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -1735,7 +1738,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn89AllowedHeaders,
+ allowedHeaders: rn90AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -1778,7 +1781,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "DELETE,PUT",
- allowedHeaders: rn122AllowedHeaders,
+ allowedHeaders: rn123AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -1805,7 +1808,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn63AllowedHeaders,
+ allowedHeaders: rn66AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -1837,7 +1840,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET,POST",
- allowedHeaders: rn16AllowedHeaders,
+ allowedHeaders: rn19AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -1879,7 +1882,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "DELETE,PUT",
- allowedHeaders: rn40AllowedHeaders,
+ allowedHeaders: rn43AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -1907,7 +1910,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn133AllowedHeaders,
+ allowedHeaders: rn134AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -1956,7 +1959,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn66AllowedHeaders,
+ allowedHeaders: rn69AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -1993,7 +1996,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn67AllowedHeaders,
+ allowedHeaders: rn70AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -2021,7 +2024,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "DELETE,GET,PUT",
- allowedHeaders: rn41AllowedHeaders,
+ allowedHeaders: rn44AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -2046,7 +2049,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn116AllowedHeaders,
+ allowedHeaders: rn117AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -2074,7 +2077,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET,POST",
- allowedHeaders: rn17AllowedHeaders,
+ allowedHeaders: rn20AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -2114,7 +2117,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "DELETE,PUT",
- allowedHeaders: rn43AllowedHeaders,
+ allowedHeaders: rn46AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -2154,7 +2157,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET,POST",
- allowedHeaders: rn18AllowedHeaders,
+ allowedHeaders: rn21AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -2197,7 +2200,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "DELETE,GET,PATCH",
- allowedHeaders: rn25AllowedHeaders,
+ allowedHeaders: rn28AllowedHeaders,
acceptPost: "",
acceptPatch: "application/json",
})
@@ -2239,7 +2242,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET,POST",
- allowedHeaders: rn92AllowedHeaders,
+ allowedHeaders: rn93AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -2281,7 +2284,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "DELETE,GET",
- allowedHeaders: rn112AllowedHeaders,
+ allowedHeaders: rn113AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -2309,7 +2312,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn93AllowedHeaders,
+ allowedHeaders: rn94AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -2346,7 +2349,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn27AllowedHeaders,
+ allowedHeaders: rn30AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -2380,7 +2383,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET,POST",
- allowedHeaders: rn20AllowedHeaders,
+ allowedHeaders: rn23AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -2417,7 +2420,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn100AllowedHeaders,
+ allowedHeaders: rn101AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -2443,7 +2446,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn123AllowedHeaders,
+ allowedHeaders: rn124AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -2477,7 +2480,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "DELETE,PATCH",
- allowedHeaders: rn45AllowedHeaders,
+ allowedHeaders: rn48AllowedHeaders,
acceptPost: "",
acceptPatch: "application/json",
})
@@ -2518,7 +2521,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn118AllowedHeaders,
+ allowedHeaders: rn119AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -2567,7 +2570,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn120AllowedHeaders,
+ allowedHeaders: rn121AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -2592,7 +2595,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn69AllowedHeaders,
+ allowedHeaders: rn73AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -2618,7 +2621,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn94AllowedHeaders,
+ allowedHeaders: rn95AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -2636,16 +2639,15 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
// Param: "id"
- // Leaf parameter, slashes are prohibited
+ // Match until "/"
idx := strings.IndexByte(elem, '/')
- if idx >= 0 {
- break
+ if idx < 0 {
+ idx = len(elem)
}
- args[0] = elem
- elem = ""
+ args[0] = elem[:idx]
+ elem = elem[idx:]
if len(elem) == 0 {
- // Leaf node.
switch r.Method {
case "GET":
s.handleGetSentEmailRequest([1]string{
@@ -2654,7 +2656,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn72AllowedHeaders,
+ allowedHeaders: rn4AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -2662,6 +2664,35 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return
}
+ switch elem[0] {
+ case '/': // Prefix: "/reply"
+
+ if l := len("/reply"); len(elem) >= l && elem[0:l] == "/reply" {
+ elem = elem[l:]
+ } else {
+ break
+ }
+
+ if len(elem) == 0 {
+ // Leaf node.
+ switch r.Method {
+ case "GET":
+ s.handleAwaitReplyRequest([1]string{
+ args[0],
+ }, elemIsEscaped, w, r)
+ default:
+ s.notAllowed(w, r, notAllowedParams{
+ allowedMethods: "GET",
+ allowedHeaders: rn5AllowedHeaders,
+ acceptPost: "",
+ acceptPatch: "",
+ })
+ }
+
+ return
+ }
+
+ }
}
@@ -2744,7 +2775,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn78AllowedHeaders,
+ allowedHeaders: rn79AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -2800,7 +2831,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn84AllowedHeaders,
+ allowedHeaders: rn85AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -2840,7 +2871,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn81AllowedHeaders,
+ allowedHeaders: rn82AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -2892,7 +2923,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET,POST",
- allowedHeaders: rn21AllowedHeaders,
+ allowedHeaders: rn24AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -2932,7 +2963,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "DELETE,PATCH",
- allowedHeaders: rn47AllowedHeaders,
+ allowedHeaders: rn50AllowedHeaders,
acceptPost: "",
acceptPatch: "application/json",
})
@@ -2959,7 +2990,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn96AllowedHeaders,
+ allowedHeaders: rn97AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -2985,7 +3016,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET,POST",
- allowedHeaders: rn23AllowedHeaders,
+ allowedHeaders: rn26AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -3028,7 +3059,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "DELETE,GET,PATCH",
- allowedHeaders: rn49AllowedHeaders,
+ allowedHeaders: rn52AllowedHeaders,
acceptPost: "",
acceptPatch: "application/json",
})
@@ -3055,7 +3086,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn114AllowedHeaders,
+ allowedHeaders: rn115AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -3085,7 +3116,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn87AllowedHeaders,
+ allowedHeaders: rn88AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -3133,7 +3164,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn103AllowedHeaders,
+ allowedHeaders: rn104AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -3175,7 +3206,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn7AllowedHeaders,
+ allowedHeaders: rn10AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -3210,7 +3241,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn60AllowedHeaders,
+ allowedHeaders: rn63AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -3237,7 +3268,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn97AllowedHeaders,
+ allowedHeaders: rn98AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -3266,7 +3297,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET",
- allowedHeaders: rn85AllowedHeaders,
+ allowedHeaders: rn86AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -3291,7 +3322,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "POST",
- allowedHeaders: rn9AllowedHeaders,
+ allowedHeaders: rn12AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -3318,7 +3349,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET,POST",
- allowedHeaders: rn90AllowedHeaders,
+ allowedHeaders: rn91AllowedHeaders,
acceptPost: "application/json",
acceptPatch: "",
})
@@ -3345,7 +3376,7 @@ func (s *Server) ServeHTTP(w http.ResponseWriter, r *http.Request) {
default:
s.notAllowed(w, r, notAllowedParams{
allowedMethods: "GET,PUT",
- allowedHeaders: rn73AllowedHeaders,
+ allowedHeaders: rn74AllowedHeaders,
acceptPost: "",
acceptPatch: "",
})
@@ -5828,16 +5859,15 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
}
// Param: "id"
- // Leaf parameter, slashes are prohibited
+ // Match until "/"
idx := strings.IndexByte(elem, '/')
- if idx >= 0 {
- break
+ if idx < 0 {
+ idx = len(elem)
}
- args[0] = elem
- elem = ""
+ args[0] = elem[:idx]
+ elem = elem[idx:]
if len(elem) == 0 {
- // Leaf node.
switch method {
case "GET":
r.name = GetSentEmailOperation
@@ -5852,6 +5882,33 @@ func (s *Server) FindPath(method string, u *url.URL) (r Route, _ bool) {
return
}
}
+ switch elem[0] {
+ case '/': // Prefix: "/reply"
+
+ if l := len("/reply"); len(elem) >= l && elem[0:l] == "/reply" {
+ elem = elem[l:]
+ } else {
+ break
+ }
+
+ if len(elem) == 0 {
+ // Leaf node.
+ switch method {
+ case "GET":
+ r.name = AwaitReplyOperation
+ r.summary = "Get (or wait for) the reply to a sent email"
+ r.operationID = "awaitReply"
+ r.operationGroup = ""
+ r.pathPattern = "/sent-emails/{id}/reply"
+ r.args = args
+ r.count = 1
+ return r, true
+ default:
+ return
+ }
+ }
+
+ }
}
diff --git a/sdk-go/api/oas_schemas_gen.go b/sdk-go/api/oas_schemas_gen.go
index ae10f4fb..91bedab0 100644
--- a/sdk-go/api/oas_schemas_gen.go
+++ b/sdk-go/api/oas_schemas_gen.go
@@ -1023,6 +1023,99 @@ func (s *AgentSignupVerifyResultTokenType) UnmarshalText(data []byte) error {
}
}
+type AwaitReplyBadRequest ErrorResponse
+
+func (*AwaitReplyBadRequest) awaitReplyRes() {}
+
+type AwaitReplyNotFound ErrorResponse
+
+func (*AwaitReplyNotFound) awaitReplyRes() {}
+
+// Merged schema.
+type AwaitReplyOK struct {
+ Success bool `json:"success"`
+ Data AwaitReplyResult `json:"data"`
+}
+
+// GetSuccess returns the value of Success.
+func (s *AwaitReplyOK) GetSuccess() bool {
+ return s.Success
+}
+
+// GetData returns the value of Data.
+func (s *AwaitReplyOK) GetData() AwaitReplyResult {
+ return s.Data
+}
+
+// SetSuccess sets the value of Success.
+func (s *AwaitReplyOK) SetSuccess(val bool) {
+ s.Success = val
+}
+
+// SetData sets the value of Data.
+func (s *AwaitReplyOK) SetData(val AwaitReplyResult) {
+ s.Data = val
+}
+
+func (*AwaitReplyOK) awaitReplyRes() {}
+
+// Result of `/sent-emails/{id}/reply`. `reply` is null when no
+// reply has arrived yet (no-wait call, or the wait timed out).
+// Ref: #/components/schemas/AwaitReplyResult
+type AwaitReplyResult struct {
+ // The send this lookup was keyed on (echoes the path id).
+ SentEmailID uuid.UUID `json:"sent_email_id"`
+ Reply NilReplyEmail `json:"reply"`
+ // Whether the call ran in long-poll mode (`wait=true`).
+ Waited bool `json:"waited"`
+ // True only when a `wait=true` call elapsed its timeout with no reply.
+ TimedOut bool `json:"timed_out"`
+}
+
+// GetSentEmailID returns the value of SentEmailID.
+func (s *AwaitReplyResult) GetSentEmailID() uuid.UUID {
+ return s.SentEmailID
+}
+
+// GetReply returns the value of Reply.
+func (s *AwaitReplyResult) GetReply() NilReplyEmail {
+ return s.Reply
+}
+
+// GetWaited returns the value of Waited.
+func (s *AwaitReplyResult) GetWaited() bool {
+ return s.Waited
+}
+
+// GetTimedOut returns the value of TimedOut.
+func (s *AwaitReplyResult) GetTimedOut() bool {
+ return s.TimedOut
+}
+
+// SetSentEmailID sets the value of SentEmailID.
+func (s *AwaitReplyResult) SetSentEmailID(val uuid.UUID) {
+ s.SentEmailID = val
+}
+
+// SetReply sets the value of Reply.
+func (s *AwaitReplyResult) SetReply(val NilReplyEmail) {
+ s.Reply = val
+}
+
+// SetWaited sets the value of Waited.
+func (s *AwaitReplyResult) SetWaited(val bool) {
+ s.Waited = val
+}
+
+// SetTimedOut sets the value of TimedOut.
+func (s *AwaitReplyResult) SetTimedOut(val bool) {
+ s.TimedOut = val
+}
+
+type AwaitReplyUnauthorized ErrorResponse
+
+func (*AwaitReplyUnauthorized) awaitReplyRes() {}
+
type BearerAuth struct {
Token string
Roles []string
@@ -13912,6 +14005,51 @@ func (o NilInt) Or(d int) int {
return d
}
+// NewNilReplyEmail returns new NilReplyEmail with value set to v.
+func NewNilReplyEmail(v ReplyEmail) NilReplyEmail {
+ return NilReplyEmail{
+ Value: v,
+ }
+}
+
+// NilReplyEmail is nullable ReplyEmail.
+type NilReplyEmail struct {
+ Value ReplyEmail
+ Null bool
+}
+
+// SetTo sets value to v.
+func (o *NilReplyEmail) SetTo(v ReplyEmail) {
+ o.Null = false
+ o.Value = v
+}
+
+// IsNull returns true if value is Null.
+func (o NilReplyEmail) IsNull() bool { return o.Null }
+
+// SetToNull sets value to null.
+func (o *NilReplyEmail) SetToNull() {
+ o.Null = true
+ var v ReplyEmail
+ o.Value = v
+}
+
+// Get returns value and boolean that denotes whether value was set.
+func (o NilReplyEmail) Get() (v ReplyEmail, ok bool) {
+ if o.Null {
+ return v, false
+ }
+ return o.Value, true
+}
+
+// Or returns value if set, or given parameter if does not.
+func (o NilReplyEmail) Or(d ReplyEmail) ReplyEmail {
+ if v, ok := o.Get(); ok {
+ return v
+ }
+ return d
+}
+
// NewNilRoutingTopologyDomainsItemRoutedFunction returns new NilRoutingTopologyDomainsItemRoutedFunction with value set to v.
func NewNilRoutingTopologyDomainsItemRoutedFunction(v RoutingTopologyDomainsItemRoutedFunction) NilRoutingTopologyDomainsItemRoutedFunction {
return NilRoutingTopologyDomainsItemRoutedFunction{
@@ -19162,6 +19300,135 @@ func (s *ReplayResult) SetFailed(val int) {
s.Failed = val
}
+// A threaded inbound reply to one of the org's sends, keyed by
+// the inbound email's `reply_to_sent_email_id`. Compact on
+// purpose: enough to read the reply and decide what to do
+// next, with `/emails/{id}` available for the fully parsed
+// detail.
+// Ref: #/components/schemas/ReplyEmail
+type ReplyEmail struct {
+ // Inbound email row id; usable with `/emails/{id}`.
+ ID uuid.UUID `json:"id"`
+ // Conversation thread id; usable with `/threads/{id}`.
+ ThreadID NilUUID `json:"thread_id"`
+ // The sent-email id this inbound message replied to.
+ ReplyToSentEmailID NilUUID `json:"reply_to_sent_email_id"`
+ // Sender of the reply (From header when present, else envelope sender).
+ FromEmail string `json:"from_email"`
+ // Recipient address the reply arrived at.
+ ToEmail string `json:"to_email"`
+ Subject NilString `json:"subject"`
+ // Plain-text body of the reply, when present.
+ BodyText NilString `json:"body_text"`
+ // HTML body of the reply, when present.
+ BodyHTML NilString `json:"body_html"`
+ ReceivedAt NilDateTime `json:"received_at"`
+ // Inbound processing status of the reply row. Typically an
+ // `EmailStatus` value, but left as an open string here to
+ // match the server contract, which does not narrow it.
+ Status string `json:"status"`
+}
+
+// GetID returns the value of ID.
+func (s *ReplyEmail) GetID() uuid.UUID {
+ return s.ID
+}
+
+// GetThreadID returns the value of ThreadID.
+func (s *ReplyEmail) GetThreadID() NilUUID {
+ return s.ThreadID
+}
+
+// GetReplyToSentEmailID returns the value of ReplyToSentEmailID.
+func (s *ReplyEmail) GetReplyToSentEmailID() NilUUID {
+ return s.ReplyToSentEmailID
+}
+
+// GetFromEmail returns the value of FromEmail.
+func (s *ReplyEmail) GetFromEmail() string {
+ return s.FromEmail
+}
+
+// GetToEmail returns the value of ToEmail.
+func (s *ReplyEmail) GetToEmail() string {
+ return s.ToEmail
+}
+
+// GetSubject returns the value of Subject.
+func (s *ReplyEmail) GetSubject() NilString {
+ return s.Subject
+}
+
+// GetBodyText returns the value of BodyText.
+func (s *ReplyEmail) GetBodyText() NilString {
+ return s.BodyText
+}
+
+// GetBodyHTML returns the value of BodyHTML.
+func (s *ReplyEmail) GetBodyHTML() NilString {
+ return s.BodyHTML
+}
+
+// GetReceivedAt returns the value of ReceivedAt.
+func (s *ReplyEmail) GetReceivedAt() NilDateTime {
+ return s.ReceivedAt
+}
+
+// GetStatus returns the value of Status.
+func (s *ReplyEmail) GetStatus() string {
+ return s.Status
+}
+
+// SetID sets the value of ID.
+func (s *ReplyEmail) SetID(val uuid.UUID) {
+ s.ID = val
+}
+
+// SetThreadID sets the value of ThreadID.
+func (s *ReplyEmail) SetThreadID(val NilUUID) {
+ s.ThreadID = val
+}
+
+// SetReplyToSentEmailID sets the value of ReplyToSentEmailID.
+func (s *ReplyEmail) SetReplyToSentEmailID(val NilUUID) {
+ s.ReplyToSentEmailID = val
+}
+
+// SetFromEmail sets the value of FromEmail.
+func (s *ReplyEmail) SetFromEmail(val string) {
+ s.FromEmail = val
+}
+
+// SetToEmail sets the value of ToEmail.
+func (s *ReplyEmail) SetToEmail(val string) {
+ s.ToEmail = val
+}
+
+// SetSubject sets the value of Subject.
+func (s *ReplyEmail) SetSubject(val NilString) {
+ s.Subject = val
+}
+
+// SetBodyText sets the value of BodyText.
+func (s *ReplyEmail) SetBodyText(val NilString) {
+ s.BodyText = val
+}
+
+// SetBodyHTML sets the value of BodyHTML.
+func (s *ReplyEmail) SetBodyHTML(val NilString) {
+ s.BodyHTML = val
+}
+
+// SetReceivedAt sets the value of ReceivedAt.
+func (s *ReplyEmail) SetReceivedAt(val NilDateTime) {
+ s.ReceivedAt = val
+}
+
+// SetStatus sets the value of Status.
+func (s *ReplyEmail) SetStatus(val string) {
+ s.Status = val
+}
+
// Body shape for `/emails/{id}/reply`. Intentionally narrow:
// recipients (`to`), subject, and threading headers
// (`in_reply_to`, `references`) are derived server-side from
diff --git a/sdk-go/api/oas_security_gen.go b/sdk-go/api/oas_security_gen.go
index 5538dc9e..abe8f09d 100644
--- a/sdk-go/api/oas_security_gen.go
+++ b/sdk-go/api/oas_security_gen.go
@@ -39,6 +39,7 @@ func findAuthorization(h http.Header, prefix string) (string, bool) {
// operationRolesBearerAuth is a private map storing roles per operation.
var operationRolesBearerAuth = map[string][]string{
AddDomainOperation: []string{},
+ AwaitReplyOperation: []string{},
CliLogoutOperation: []string{},
CreateAgentClaimLinkOperation: []string{},
CreateChallengeOperation: []string{},
diff --git a/sdk-go/api/oas_server_gen.go b/sdk-go/api/oas_server_gen.go
index 1ccf384b..341d5644 100644
--- a/sdk-go/api/oas_server_gen.go
+++ b/sdk-go/api/oas_server_gen.go
@@ -18,6 +18,25 @@ type Handler interface {
//
// POST /domains
AddDomain(ctx context.Context, req *AddDomainInput) (AddDomainRes, error)
+ // AwaitReply implements awaitReply operation.
+ //
+ // Returns the first threaded inbound reply to a send, keyed by
+ // the inbound email's `reply_to_sent_email_id`. This is the
+ // canonical "did a reply arrive for this send?" call: after
+ // /send-mail, poll (or long-poll) here instead of hand-rolling
+ // an /emails/search loop.
+ // By default the call returns immediately with `reply: null`
+ // when nothing has arrived yet. Set `wait=true` to long-poll:
+ // the server holds the request up to `wait_timeout_ms`
+ // (default 10000, max 30000), returning as soon as the first
+ // reply lands. On a wait that elapses with no reply, the
+ // response has `reply: null` and `timed_out: true`.
+ // The reply object is compact (headers plus bodies); fetch
+ // `/emails/{id}` with `reply.id` for the fully parsed record,
+ // or `/threads/{thread_id}` for the whole back-and-forth.
+ //
+ // GET /sent-emails/{id}/reply
+ AwaitReply(ctx context.Context, params AwaitReplyParams) (AwaitReplyRes, error)
// CliLogout implements cliLogout operation.
//
// Revokes the OAuth grant used to authenticate the request. API-key
diff --git a/sdk-go/api/oas_unimplemented_gen.go b/sdk-go/api/oas_unimplemented_gen.go
index 81549a1c..db778609 100644
--- a/sdk-go/api/oas_unimplemented_gen.go
+++ b/sdk-go/api/oas_unimplemented_gen.go
@@ -26,6 +26,28 @@ func (UnimplementedHandler) AddDomain(ctx context.Context, req *AddDomainInput)
return r, ht.ErrNotImplemented
}
+// AwaitReply implements awaitReply operation.
+//
+// Returns the first threaded inbound reply to a send, keyed by
+// the inbound email's `reply_to_sent_email_id`. This is the
+// canonical "did a reply arrive for this send?" call: after
+// /send-mail, poll (or long-poll) here instead of hand-rolling
+// an /emails/search loop.
+// By default the call returns immediately with `reply: null`
+// when nothing has arrived yet. Set `wait=true` to long-poll:
+// the server holds the request up to `wait_timeout_ms`
+// (default 10000, max 30000), returning as soon as the first
+// reply lands. On a wait that elapses with no reply, the
+// response has `reply: null` and `timed_out: true`.
+// The reply object is compact (headers plus bodies); fetch
+// `/emails/{id}` with `reply.id` for the fully parsed record,
+// or `/threads/{thread_id}` for the whole back-and-forth.
+//
+// GET /sent-emails/{id}/reply
+func (UnimplementedHandler) AwaitReply(ctx context.Context, params AwaitReplyParams) (r AwaitReplyRes, _ error) {
+ return r, ht.ErrNotImplemented
+}
+
// CliLogout implements cliLogout operation.
//
// Revokes the OAuth grant used to authenticate the request. API-key
diff --git a/sdk-go/api/oas_validators_gen.go b/sdk-go/api/oas_validators_gen.go
index 5417a137..9df63f72 100644
--- a/sdk-go/api/oas_validators_gen.go
+++ b/sdk-go/api/oas_validators_gen.go
@@ -478,6 +478,30 @@ func (s AgentSignupVerifyResultTokenType) Validate() error {
}
}
+func (s *AwaitReplyBadRequest) Validate() error {
+ alias := (*ErrorResponse)(s)
+ if err := alias.Validate(); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (s *AwaitReplyNotFound) Validate() error {
+ alias := (*ErrorResponse)(s)
+ if err := alias.Validate(); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (s *AwaitReplyUnauthorized) Validate() error {
+ alias := (*ErrorResponse)(s)
+ if err := alias.Validate(); err != nil {
+ return err
+ }
+ return nil
+}
+
func (s *CliLoginPollResult) Validate() error {
if s == nil {
return validate.ErrNilPointer
diff --git a/sdk-python/src/primitive/api/api/sending/await_reply.py b/sdk-python/src/primitive/api/api/sending/await_reply.py
new file mode 100644
index 00000000..15f637f1
--- /dev/null
+++ b/sdk-python/src/primitive/api/api/sending/await_reply.py
@@ -0,0 +1,299 @@
+from http import HTTPStatus
+from typing import Any, cast
+from urllib.parse import quote
+
+import httpx
+
+from ...client import AuthenticatedClient, Client
+from ...types import Response, UNSET
+from ... import errors
+
+from ...models.await_reply_response_200 import AwaitReplyResponse200
+from ...models.error_response import ErrorResponse
+from ...types import UNSET, Unset
+from typing import cast
+from uuid import UUID
+
+
+
+def _get_kwargs(
+ id: UUID,
+ *,
+ wait: bool | Unset = UNSET,
+ wait_timeout_ms: int | Unset = UNSET,
+
+) -> dict[str, Any]:
+
+
+
+
+ params: dict[str, Any] = {}
+
+ params["wait"] = wait
+
+ params["wait_timeout_ms"] = wait_timeout_ms
+
+
+ params = {k: v for k, v in params.items() if v is not UNSET and v is not None}
+
+
+ _kwargs: dict[str, Any] = {
+ "method": "get",
+ "url": "/sent-emails/{id}/reply".format(id=quote(str(id), safe=""),),
+ "params": params,
+ }
+
+
+ return _kwargs
+
+
+
+def _parse_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> AwaitReplyResponse200 | ErrorResponse | None:
+ if response.status_code == 200:
+ response_200 = AwaitReplyResponse200.from_dict(response.json())
+
+
+
+ return response_200
+
+ if response.status_code == 400:
+ response_400 = ErrorResponse.from_dict(response.json())
+
+
+
+ return response_400
+
+ if response.status_code == 401:
+ response_401 = ErrorResponse.from_dict(response.json())
+
+
+
+ return response_401
+
+ if response.status_code == 404:
+ response_404 = ErrorResponse.from_dict(response.json())
+
+
+
+ return response_404
+
+ if client.raise_on_unexpected_status:
+ raise errors.UnexpectedStatus(response.status_code, response.content)
+ else:
+ return None
+
+
+def _build_response(*, client: AuthenticatedClient | Client, response: httpx.Response) -> Response[AwaitReplyResponse200 | ErrorResponse]:
+ return Response(
+ status_code=HTTPStatus(response.status_code),
+ content=response.content,
+ headers=response.headers,
+ parsed=_parse_response(client=client, response=response),
+ )
+
+
+def sync_detailed(
+ id: UUID,
+ *,
+ client: AuthenticatedClient | Client,
+ wait: bool | Unset = UNSET,
+ wait_timeout_ms: int | Unset = UNSET,
+
+) -> Response[AwaitReplyResponse200 | ErrorResponse]:
+ r""" Get (or wait for) the reply to a sent email
+
+ Returns the first threaded inbound reply to a send, keyed by
+ the inbound email's `reply_to_sent_email_id`. This is the
+ canonical \"did a reply arrive for this send?\" call: after
+ /send-mail, poll (or long-poll) here instead of hand-rolling
+ an /emails/search loop.
+
+ By default the call returns immediately with `reply: null`
+ when nothing has arrived yet. Set `wait=true` to long-poll:
+ the server holds the request up to `wait_timeout_ms`
+ (default 10000, max 30000), returning as soon as the first
+ reply lands. On a wait that elapses with no reply, the
+ response has `reply: null` and `timed_out: true`.
+
+ The reply object is compact (headers plus bodies); fetch
+ `/emails/{id}` with `reply.id` for the fully parsed record,
+ or `/threads/{thread_id}` for the whole back-and-forth.
+
+ Args:
+ id (UUID):
+ wait (bool | Unset):
+ wait_timeout_ms (int | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[AwaitReplyResponse200 | ErrorResponse]
+ """
+
+
+ kwargs = _get_kwargs(
+ id=id,
+wait=wait,
+wait_timeout_ms=wait_timeout_ms,
+
+ )
+
+ response = client.get_httpx_client().request(
+ **kwargs,
+ )
+
+ return _build_response(client=client, response=response)
+
+def sync(
+ id: UUID,
+ *,
+ client: AuthenticatedClient | Client,
+ wait: bool | Unset = UNSET,
+ wait_timeout_ms: int | Unset = UNSET,
+
+) -> AwaitReplyResponse200 | ErrorResponse | None:
+ r""" Get (or wait for) the reply to a sent email
+
+ Returns the first threaded inbound reply to a send, keyed by
+ the inbound email's `reply_to_sent_email_id`. This is the
+ canonical \"did a reply arrive for this send?\" call: after
+ /send-mail, poll (or long-poll) here instead of hand-rolling
+ an /emails/search loop.
+
+ By default the call returns immediately with `reply: null`
+ when nothing has arrived yet. Set `wait=true` to long-poll:
+ the server holds the request up to `wait_timeout_ms`
+ (default 10000, max 30000), returning as soon as the first
+ reply lands. On a wait that elapses with no reply, the
+ response has `reply: null` and `timed_out: true`.
+
+ The reply object is compact (headers plus bodies); fetch
+ `/emails/{id}` with `reply.id` for the fully parsed record,
+ or `/threads/{thread_id}` for the whole back-and-forth.
+
+ Args:
+ id (UUID):
+ wait (bool | Unset):
+ wait_timeout_ms (int | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ AwaitReplyResponse200 | ErrorResponse
+ """
+
+
+ return sync_detailed(
+ id=id,
+client=client,
+wait=wait,
+wait_timeout_ms=wait_timeout_ms,
+
+ ).parsed
+
+async def asyncio_detailed(
+ id: UUID,
+ *,
+ client: AuthenticatedClient | Client,
+ wait: bool | Unset = UNSET,
+ wait_timeout_ms: int | Unset = UNSET,
+
+) -> Response[AwaitReplyResponse200 | ErrorResponse]:
+ r""" Get (or wait for) the reply to a sent email
+
+ Returns the first threaded inbound reply to a send, keyed by
+ the inbound email's `reply_to_sent_email_id`. This is the
+ canonical \"did a reply arrive for this send?\" call: after
+ /send-mail, poll (or long-poll) here instead of hand-rolling
+ an /emails/search loop.
+
+ By default the call returns immediately with `reply: null`
+ when nothing has arrived yet. Set `wait=true` to long-poll:
+ the server holds the request up to `wait_timeout_ms`
+ (default 10000, max 30000), returning as soon as the first
+ reply lands. On a wait that elapses with no reply, the
+ response has `reply: null` and `timed_out: true`.
+
+ The reply object is compact (headers plus bodies); fetch
+ `/emails/{id}` with `reply.id` for the fully parsed record,
+ or `/threads/{thread_id}` for the whole back-and-forth.
+
+ Args:
+ id (UUID):
+ wait (bool | Unset):
+ wait_timeout_ms (int | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ Response[AwaitReplyResponse200 | ErrorResponse]
+ """
+
+
+ kwargs = _get_kwargs(
+ id=id,
+wait=wait,
+wait_timeout_ms=wait_timeout_ms,
+
+ )
+
+ response = await client.get_async_httpx_client().request(
+ **kwargs
+ )
+
+ return _build_response(client=client, response=response)
+
+async def asyncio(
+ id: UUID,
+ *,
+ client: AuthenticatedClient | Client,
+ wait: bool | Unset = UNSET,
+ wait_timeout_ms: int | Unset = UNSET,
+
+) -> AwaitReplyResponse200 | ErrorResponse | None:
+ r""" Get (or wait for) the reply to a sent email
+
+ Returns the first threaded inbound reply to a send, keyed by
+ the inbound email's `reply_to_sent_email_id`. This is the
+ canonical \"did a reply arrive for this send?\" call: after
+ /send-mail, poll (or long-poll) here instead of hand-rolling
+ an /emails/search loop.
+
+ By default the call returns immediately with `reply: null`
+ when nothing has arrived yet. Set `wait=true` to long-poll:
+ the server holds the request up to `wait_timeout_ms`
+ (default 10000, max 30000), returning as soon as the first
+ reply lands. On a wait that elapses with no reply, the
+ response has `reply: null` and `timed_out: true`.
+
+ The reply object is compact (headers plus bodies); fetch
+ `/emails/{id}` with `reply.id` for the fully parsed record,
+ or `/threads/{thread_id}` for the whole back-and-forth.
+
+ Args:
+ id (UUID):
+ wait (bool | Unset):
+ wait_timeout_ms (int | Unset):
+
+ Raises:
+ errors.UnexpectedStatus: If the server returns an undocumented status code and Client.raise_on_unexpected_status is True.
+ httpx.TimeoutException: If the request takes longer than Client.timeout.
+
+ Returns:
+ AwaitReplyResponse200 | ErrorResponse
+ """
+
+
+ return (await asyncio_detailed(
+ id=id,
+client=client,
+wait=wait,
+wait_timeout_ms=wait_timeout_ms,
+
+ )).parsed
diff --git a/sdk-python/src/primitive/api/models/__init__.py b/sdk-python/src/primitive/api/models/__init__.py
index 85afe978..c953df84 100644
--- a/sdk-python/src/primitive/api/models/__init__.py
+++ b/sdk-python/src/primitive/api/models/__init__.py
@@ -18,6 +18,8 @@
from .agent_signup_verify_result import AgentSignupVerifyResult
from .agent_signup_verify_result_auth_method import AgentSignupVerifyResultAuthMethod
from .agent_signup_verify_result_token_type import AgentSignupVerifyResultTokenType
+from .await_reply_response_200 import AwaitReplyResponse200
+from .await_reply_result import AwaitReplyResult
from .cli_login_poll_result import CliLoginPollResult
from .cli_login_poll_result_auth_method import CliLoginPollResultAuthMethod
from .cli_login_poll_result_token_type import CliLoginPollResultTokenType
@@ -275,6 +277,7 @@
from .replay_delivery_response_200 import ReplayDeliveryResponse200
from .replay_email_webhooks_response_200 import ReplayEmailWebhooksResponse200
from .replay_result import ReplayResult
+from .reply_email import ReplyEmail
from .reply_input import ReplyInput
from .reply_to_email_response_200 import ReplyToEmailResponse200
from .resend_agent_signup_verification_input import ResendAgentSignupVerificationInput
@@ -473,6 +476,8 @@
"AgentSignupVerifyResult",
"AgentSignupVerifyResultAuthMethod",
"AgentSignupVerifyResultTokenType",
+ "AwaitReplyResponse200",
+ "AwaitReplyResult",
"CliLoginPollResult",
"CliLoginPollResultAuthMethod",
"CliLoginPollResultTokenType",
@@ -730,6 +735,7 @@
"ReplayDeliveryResponse200",
"ReplayEmailWebhooksResponse200",
"ReplayResult",
+ "ReplyEmail",
"ReplyInput",
"ReplyToEmailResponse200",
"ResendAgentSignupVerificationInput",
diff --git a/sdk-python/src/primitive/api/models/await_reply_response_200.py b/sdk-python/src/primitive/api/models/await_reply_response_200.py
new file mode 100644
index 00000000..9aa264f4
--- /dev/null
+++ b/sdk-python/src/primitive/api/models/await_reply_response_200.py
@@ -0,0 +1,101 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+
+if TYPE_CHECKING:
+ from ..models.await_reply_result import AwaitReplyResult
+
+
+
+
+
+T = TypeVar("T", bound="AwaitReplyResponse200")
+
+
+
+@_attrs_define
+class AwaitReplyResponse200:
+ """
+ Attributes:
+ success (bool):
+ data (AwaitReplyResult | Unset): Result of `/sent-emails/{id}/reply`. `reply` is null when no
+ reply has arrived yet (no-wait call, or the wait timed out).
+ """
+
+ success: bool
+ data: AwaitReplyResult | Unset = UNSET
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.await_reply_result import AwaitReplyResult
+ success = self.success
+
+ data: dict[str, Any] | Unset = UNSET
+ if not isinstance(self.data, Unset):
+ data = self.data.to_dict()
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "success": success,
+ })
+ if data is not UNSET:
+ field_dict["data"] = data
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.await_reply_result import AwaitReplyResult
+ d = dict(src_dict)
+ success = d.pop("success")
+
+ _data = d.pop("data", UNSET)
+ data: AwaitReplyResult | Unset
+ if isinstance(_data, Unset):
+ data = UNSET
+ else:
+ data = AwaitReplyResult.from_dict(_data)
+
+
+
+
+ await_reply_response_200 = cls(
+ success=success,
+ data=data,
+ )
+
+
+ await_reply_response_200.additional_properties = d
+ return await_reply_response_200
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties
diff --git a/sdk-python/src/primitive/api/models/await_reply_result.py b/sdk-python/src/primitive/api/models/await_reply_result.py
new file mode 100644
index 00000000..26e9fbe9
--- /dev/null
+++ b/sdk-python/src/primitive/api/models/await_reply_result.py
@@ -0,0 +1,113 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from typing import cast
+from uuid import UUID
+
+if TYPE_CHECKING:
+ from ..models.reply_email import ReplyEmail
+
+
+
+
+
+T = TypeVar("T", bound="AwaitReplyResult")
+
+
+
+@_attrs_define
+class AwaitReplyResult:
+ """ Result of `/sent-emails/{id}/reply`. `reply` is null when no
+ reply has arrived yet (no-wait call, or the wait timed out).
+
+ Attributes:
+ sent_email_id (UUID): The send this lookup was keyed on (echoes the path id).
+ reply (None | ReplyEmail):
+ waited (bool): Whether the call ran in long-poll mode (`wait=true`).
+ timed_out (bool): True only when a `wait=true` call elapsed its timeout with no reply.
+ """
+
+ sent_email_id: UUID
+ reply: None | ReplyEmail
+ waited: bool
+ timed_out: bool
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ from ..models.reply_email import ReplyEmail
+ sent_email_id = str(self.sent_email_id)
+
+ reply: dict[str, Any] | None
+ if isinstance(self.reply, ReplyEmail):
+ reply = self.reply.to_dict()
+ else:
+ reply = self.reply
+
+ waited = self.waited
+
+ timed_out = self.timed_out
+
+
+ field_dict: dict[str, Any] = {}
+
+ field_dict.update({
+ "sent_email_id": sent_email_id,
+ "reply": reply,
+ "waited": waited,
+ "timed_out": timed_out,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ from ..models.reply_email import ReplyEmail
+ d = dict(src_dict)
+ sent_email_id = UUID(d.pop("sent_email_id"))
+
+
+
+
+ def _parse_reply(data: object) -> None | ReplyEmail:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, dict):
+ raise TypeError()
+ reply_type_1 = ReplyEmail.from_dict(data)
+
+
+
+ return reply_type_1
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(None | ReplyEmail, data)
+
+ reply = _parse_reply(d.pop("reply"))
+
+
+ waited = d.pop("waited")
+
+ timed_out = d.pop("timed_out")
+
+ await_reply_result = cls(
+ sent_email_id=sent_email_id,
+ reply=reply,
+ waited=waited,
+ timed_out=timed_out,
+ )
+
+ return await_reply_result
+
diff --git a/sdk-python/src/primitive/api/models/reply_email.py b/sdk-python/src/primitive/api/models/reply_email.py
new file mode 100644
index 00000000..9f4d07c3
--- /dev/null
+++ b/sdk-python/src/primitive/api/models/reply_email.py
@@ -0,0 +1,243 @@
+from __future__ import annotations
+
+from collections.abc import Mapping
+from typing import Any, TypeVar, BinaryIO, TextIO, TYPE_CHECKING, Generator
+
+from attrs import define as _attrs_define
+from attrs import field as _attrs_field
+
+from ..types import UNSET, Unset
+
+from dateutil.parser import isoparse
+from typing import cast
+from uuid import UUID
+import datetime
+
+
+
+
+
+
+T = TypeVar("T", bound="ReplyEmail")
+
+
+
+@_attrs_define
+class ReplyEmail:
+ """ A threaded inbound reply to one of the org's sends, keyed by
+ the inbound email's `reply_to_sent_email_id`. Compact on
+ purpose: enough to read the reply and decide what to do
+ next, with `/emails/{id}` available for the fully parsed
+ detail.
+
+ Attributes:
+ id (UUID): Inbound email row id; usable with `/emails/{id}`.
+ thread_id (None | UUID): Conversation thread id; usable with `/threads/{id}`.
+ reply_to_sent_email_id (None | UUID): The sent-email id this inbound message replied to.
+ from_email (str): Sender of the reply (From header when present, else envelope sender).
+ to_email (str): Recipient address the reply arrived at.
+ subject (None | str):
+ body_text (None | str): Plain-text body of the reply, when present.
+ body_html (None | str): HTML body of the reply, when present.
+ received_at (datetime.datetime | None):
+ status (str): Inbound processing status of the reply row. Typically an
+ `EmailStatus` value, but left as an open string here to
+ match the server contract, which does not narrow it.
+ """
+
+ id: UUID
+ thread_id: None | UUID
+ reply_to_sent_email_id: None | UUID
+ from_email: str
+ to_email: str
+ subject: None | str
+ body_text: None | str
+ body_html: None | str
+ received_at: datetime.datetime | None
+ status: str
+ additional_properties: dict[str, Any] = _attrs_field(init=False, factory=dict)
+
+
+
+
+
+ def to_dict(self) -> dict[str, Any]:
+ id = str(self.id)
+
+ thread_id: None | str
+ if isinstance(self.thread_id, UUID):
+ thread_id = str(self.thread_id)
+ else:
+ thread_id = self.thread_id
+
+ reply_to_sent_email_id: None | str
+ if isinstance(self.reply_to_sent_email_id, UUID):
+ reply_to_sent_email_id = str(self.reply_to_sent_email_id)
+ else:
+ reply_to_sent_email_id = self.reply_to_sent_email_id
+
+ from_email = self.from_email
+
+ to_email = self.to_email
+
+ subject: None | str
+ subject = self.subject
+
+ body_text: None | str
+ body_text = self.body_text
+
+ body_html: None | str
+ body_html = self.body_html
+
+ received_at: None | str
+ if isinstance(self.received_at, datetime.datetime):
+ received_at = self.received_at.isoformat()
+ else:
+ received_at = self.received_at
+
+ status = self.status
+
+
+ field_dict: dict[str, Any] = {}
+ field_dict.update(self.additional_properties)
+ field_dict.update({
+ "id": id,
+ "thread_id": thread_id,
+ "reply_to_sent_email_id": reply_to_sent_email_id,
+ "from_email": from_email,
+ "to_email": to_email,
+ "subject": subject,
+ "body_text": body_text,
+ "body_html": body_html,
+ "received_at": received_at,
+ "status": status,
+ })
+
+ return field_dict
+
+
+
+ @classmethod
+ def from_dict(cls: type[T], src_dict: Mapping[str, Any]) -> T:
+ d = dict(src_dict)
+ id = UUID(d.pop("id"))
+
+
+
+
+ def _parse_thread_id(data: object) -> None | UUID:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ thread_id_type_0 = UUID(data)
+
+
+
+ return thread_id_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(None | UUID, data)
+
+ thread_id = _parse_thread_id(d.pop("thread_id"))
+
+
+ def _parse_reply_to_sent_email_id(data: object) -> None | UUID:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ reply_to_sent_email_id_type_0 = UUID(data)
+
+
+
+ return reply_to_sent_email_id_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(None | UUID, data)
+
+ reply_to_sent_email_id = _parse_reply_to_sent_email_id(d.pop("reply_to_sent_email_id"))
+
+
+ from_email = d.pop("from_email")
+
+ to_email = d.pop("to_email")
+
+ def _parse_subject(data: object) -> None | str:
+ if data is None:
+ return data
+ return cast(None | str, data)
+
+ subject = _parse_subject(d.pop("subject"))
+
+
+ def _parse_body_text(data: object) -> None | str:
+ if data is None:
+ return data
+ return cast(None | str, data)
+
+ body_text = _parse_body_text(d.pop("body_text"))
+
+
+ def _parse_body_html(data: object) -> None | str:
+ if data is None:
+ return data
+ return cast(None | str, data)
+
+ body_html = _parse_body_html(d.pop("body_html"))
+
+
+ def _parse_received_at(data: object) -> datetime.datetime | None:
+ if data is None:
+ return data
+ try:
+ if not isinstance(data, str):
+ raise TypeError()
+ received_at_type_0 = isoparse(data)
+
+
+
+ return received_at_type_0
+ except (TypeError, ValueError, AttributeError, KeyError):
+ pass
+ return cast(datetime.datetime | None, data)
+
+ received_at = _parse_received_at(d.pop("received_at"))
+
+
+ status = d.pop("status")
+
+ reply_email = cls(
+ id=id,
+ thread_id=thread_id,
+ reply_to_sent_email_id=reply_to_sent_email_id,
+ from_email=from_email,
+ to_email=to_email,
+ subject=subject,
+ body_text=body_text,
+ body_html=body_html,
+ received_at=received_at,
+ status=status,
+ )
+
+
+ reply_email.additional_properties = d
+ return reply_email
+
+ @property
+ def additional_keys(self) -> list[str]:
+ return list(self.additional_properties.keys())
+
+ def __getitem__(self, key: str) -> Any:
+ return self.additional_properties[key]
+
+ def __setitem__(self, key: str, value: Any) -> None:
+ self.additional_properties[key] = value
+
+ def __delitem__(self, key: str) -> None:
+ del self.additional_properties[key]
+
+ def __contains__(self, key: str) -> bool:
+ return key in self.additional_properties