@workwae/sdk 0.1.0-alpha.1 → 0.1.0-alpha.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. package/README.md +7 -7
  2. package/client.d.ts +1 -1
  3. package/contract/accounts/models.d.ts +85 -45
  4. package/contract/accounts/routes.d.ts +191 -29
  5. package/contract/ai/models.d.ts +0 -1
  6. package/contract/ai/routes.d.ts +9 -0
  7. package/contract/audit-log/models.d.ts +19 -5
  8. package/contract/audit-log/routes.d.ts +10 -1
  9. package/contract/calendar/models.d.ts +249 -74
  10. package/contract/calendar/routes.d.ts +574 -30
  11. package/contract/connect/models.d.ts +28 -16
  12. package/contract/connect/routes.d.ts +46 -7
  13. package/contract/contacts/models.d.ts +0 -10
  14. package/contract/contacts/routes.d.ts +14 -0
  15. package/contract/email-validation/models.d.ts +119 -0
  16. package/contract/email-validation/routes.d.ts +106 -0
  17. package/contract/errors.d.ts +28 -20
  18. package/contract/events/models.d.ts +139 -79
  19. package/contract/events/routes.d.ts +54 -44
  20. package/contract/exports/routes.d.ts +10 -0
  21. package/contract/identities/models.d.ts +7 -9
  22. package/contract/identities/routes.d.ts +79 -10
  23. package/contract/limits.d.ts +21 -73
  24. package/contract/mail/models.d.ts +91 -48
  25. package/contract/mail/routes.d.ts +458 -18
  26. package/contract/mcp-keys/models.d.ts +125 -0
  27. package/contract/mcp-keys/routes.d.ts +151 -0
  28. package/contract/meetings/models.d.ts +28 -33
  29. package/contract/meetings/routes.d.ts +44 -25
  30. package/contract/oauth-apps/models.d.ts +0 -6
  31. package/contract/oauth-apps/routes.d.ts +8 -0
  32. package/contract/org-connections/models.d.ts +83 -39
  33. package/contract/org-connections/routes.d.ts +320 -43
  34. package/contract/plans/credit-packs.d.ts +30 -0
  35. package/contract/plans/models.d.ts +208 -0
  36. package/contract/primitives.d.ts +7 -62
  37. package/contract/public.d.ts +6 -0
  38. package/contract/reasons.d.ts +532 -21
  39. package/contract/router.d.ts +6425 -3212
  40. package/contract/scheduling/models.d.ts +405 -0
  41. package/contract/scheduling/routes.d.ts +756 -0
  42. package/contract/send/models.d.ts +82 -45
  43. package/contract/send/routes.d.ts +281 -32
  44. package/contract/settings/models.d.ts +73 -13
  45. package/contract/settings/routes.d.ts +56 -4
  46. package/contract/suppressions/models.d.ts +21 -28
  47. package/contract/suppressions/routes.d.ts +62 -14
  48. package/contract/templates/models.d.ts +0 -14
  49. package/contract/templates/routes.d.ts +30 -6
  50. package/contract/threads/models.d.ts +0 -5
  51. package/contract/threads/routes.d.ts +40 -0
  52. package/contract/tracking-domain/models.d.ts +41 -0
  53. package/contract/tracking-domain/routes.d.ts +193 -0
  54. package/contract/usage/models.d.ts +98 -126
  55. package/contract/usage/routes.d.ts +48 -20
  56. package/contract/webhooks/models.d.ts +45 -30
  57. package/contract/webhooks/routes.d.ts +52 -9
  58. package/contract/webhooks/signing.d.ts +0 -16
  59. package/index.js +1 -4334
  60. package/package.json +6 -7
  61. package/index.js.map +0 -59
package/index.js.map DELETED
@@ -1,59 +0,0 @@
1
- {
2
- "version": 3,
3
- "sources": ["../../contract/src/accounts/models.ts", "../../contract/src/limits.ts", "../../contract/src/primitives.ts", "../../contract/src/settings/models.ts", "../../contract/src/ai/models.ts", "../../contract/src/audit-log/models.ts", "../../contract/src/calendar/models.ts", "../../contract/src/meetings/models.ts", "../../contract/src/connect/models.ts", "../../contract/src/contacts/models.ts", "../../contract/src/errors.ts", "../../contract/src/reasons.ts", "../../contract/src/templates/models.ts", "../../contract/src/events/models.ts", "../../contract/src/mail/models.ts", "../../contract/src/send/models.ts", "../../contract/src/suppressions/models.ts", "../../contract/src/exports/models.ts", "../../contract/src/identities/models.ts", "../../contract/src/oauth-apps/models.ts", "../../contract/src/org-connections/models.ts", "../../contract/src/accounts/routes.ts", "../../contract/src/ai/routes.ts", "../../contract/src/audit-log/routes.ts", "../../contract/src/calendar/routes.ts", "../../contract/src/connect/routes.ts", "../../contract/src/contacts/routes.ts", "../../contract/src/events/routes.ts", "../../contract/src/exports/routes.ts", "../../contract/src/identities/routes.ts", "../../contract/src/mail/routes.ts", "../../contract/src/meetings/routes.ts", "../../contract/src/oauth-apps/routes.ts", "../../contract/src/org-connections/routes.ts", "../../contract/src/send/routes.ts", "../../contract/src/settings/routes.ts", "../../contract/src/suppressions/routes.ts", "../../contract/src/templates/routes.ts", "../../contract/src/threads/routes.ts", "../../contract/src/threads/models.ts", "../../contract/src/usage/models.ts", "../../contract/src/usage/routes.ts", "../../contract/src/webhooks/routes.ts", "../../contract/src/webhooks/models.ts", "../../contract/src/router.ts", "../../contract/src/webhooks/signing.ts", "../src/client.ts", "../src/errors.ts", "../src/pagination.ts", "../src/webhooks.ts"],
4
- "sourcesContent": [
5
- "import * as z from \"zod\";\nimport {\n MAX_DISPLAY_NAME_LENGTH,\n MAX_EMAIL_LENGTH,\n MAX_FILTER_QUERY_LENGTH,\n MAX_HOST_LENGTH,\n MAX_PORT,\n MAX_SECRET_LENGTH,\n MAX_TOKEN_TTL_SECONDS,\n MAX_URL_LENGTH,\n MIN_TOKEN_TTL_SECONDS,\n} from \"../limits.ts\";\nimport {\n AccountIdInput,\n Email,\n ExternalRef,\n Id,\n named,\n Page,\n Paged,\n QueryBoolean,\n Timestamp,\n trimmed,\n} from \"../primitives.ts\";\nimport { EffectiveSettings, SettingsOverride } from \"../settings/models.ts\";\n\nexport const OAuthProvider = named(\"OAuthProvider\", z.enum([\"google\", \"microsoft\"]));\nexport type OAuthProvider = z.infer<typeof OAuthProvider>;\n/** Microsoft 365 cloud. GCC (moderate) is \"global\"; GCC High, DoD and 21Vianet have their own. */\nexport const MicrosoftCloud = named(\n \"MicrosoftCloud\",\n z.enum([\"global\", \"gcc-high\", \"dod\", \"china\"]),\n);\nexport type MicrosoftCloud = z.infer<typeof MicrosoftCloud>;\nexport const AccountProvider = named(\"AccountProvider\", z.enum([\"gmail\", \"graph\", \"imap\"]));\nexport type AccountProvider = z.infer<typeof AccountProvider>;\nexport const AccountStatus = named(\n \"AccountStatus\",\n z.enum([\"active\", \"paused\", \"reauth_required\", \"disabled\"]),\n);\nexport type AccountStatus = z.infer<typeof AccountStatus>;\n/** The statuses a caller may set; the others are set by the platform. */\nexport const SettableAccountStatus = named(\n \"SettableAccountStatus\",\n AccountStatus.extract([\"active\", \"paused\"]),\n);\nexport type SettableAccountStatus = z.infer<typeof SettableAccountStatus>;\nexport const RuntimeState = named(\n \"RuntimeState\",\n z.enum([\"pending\", \"connecting\", \"connected\", \"error\", \"stopped\"]),\n);\nexport type RuntimeState = z.infer<typeof RuntimeState>;\n\nexport const AccountRuntime = named(\n \"AccountRuntime\",\n z.object({\n state: RuntimeState,\n detail: z.string().nullable(),\n ownerInstanceId: Id.nullable(),\n updatedAt: Timestamp,\n }),\n);\nexport type AccountRuntime = z.infer<typeof AccountRuntime>;\n\n/** tls: implicit TLS (993/465). starttls: upgrade after connect (143/587). none: plaintext,\n * accepted only by instances that allow it (local test servers). */\nexport const MailSecurity = named(\"MailSecurity\", z.enum([\"tls\", \"starttls\", \"none\"]));\nexport type MailSecurity = z.infer<typeof MailSecurity>;\n\nexport const MailServer = named(\n \"MailServer\",\n z.object({\n host: z.string(),\n port: z.number().int(),\n security: MailSecurity,\n /** Login name. */\n user: z.string(),\n }),\n);\nexport type MailServer = z.infer<typeof MailServer>;\n\n/** imap_password: DAV logs in with the IMAP password (what app passwords cover on iCloud, Fastmail\n * and Yahoo); dav_password: with a separate one. */\nexport const DavAuth = named(\"DavAuth\", z.enum([\"imap_password\", \"dav_password\"]));\nexport type DavAuth = z.infer<typeof DavAuth>;\n\n/**\n * CalDAV and CardDAV of an IMAP account: the calendar and address book home sets (null: that half\n * is not used) and the login.\n */\nexport const DavSettings = named(\n \"DavSettings\",\n z.object({\n calendarUrl: z.string().nullable(),\n contactsUrl: z.string().nullable(),\n user: z.string(),\n auth: DavAuth,\n }),\n);\nexport type DavSettings = z.infer<typeof DavSettings>;\n\n/** password, or OAuth tokens from this provider (XOAUTH2). */\nexport const ImapAuth = named(\"ImapAuth\", z.enum([\"password\", \"google\", \"microsoft\"]));\nexport type ImapAuth = z.infer<typeof ImapAuth>;\n\n/** An IMAP account's servers; secrets are never returned. */\nexport const ImapSettings = named(\n \"ImapSettings\",\n z.object({\n imap: MailServer,\n /** Null: the account cannot send. */\n smtp: MailServer.nullable(),\n auth: ImapAuth,\n /** A copy of what is sent is appended to Sent (servers that do not file it themselves). */\n appendSent: z.boolean(),\n /** Null: no calendar and no contacts. */\n dav: DavSettings.nullable(),\n }),\n);\nexport type ImapSettings = z.infer<typeof ImapSettings>;\n\n/**\n * How an account authenticates:\n * - oauth: its own user grant (a refresh token from a connect flow).\n * - password: an IMAP/SMTP password.\n * - google_delegation / microsoft_app: the organization connection `orgConnectionId` (Google\n * domain-wide delegation, Microsoft app-only); nobody signed in.\n * - shared_mailbox: the delegated grant of account `delegateAccountId`, opening a mailbox that\n * account's user has access to.\n */\nexport const AccountAuthMethod = named(\n \"AccountAuthMethod\",\n z.enum([\"oauth\", \"password\", \"google_delegation\", \"microsoft_app\", \"shared_mailbox\"]),\n);\nexport type AccountAuthMethod = z.infer<typeof AccountAuthMethod>;\n\nexport const AccountAuth = named(\n \"AccountAuth\",\n z.object({\n method: AccountAuthMethod,\n orgConnectionId: Id.nullable(),\n delegateAccountId: Id.nullable(),\n }),\n);\nexport type AccountAuth = z.infer<typeof AccountAuth>;\n\nexport const Account = named(\n \"Account\",\n z.object({\n id: Id,\n externalRef: z.string().nullable(),\n provider: AccountProvider,\n email: z.string(),\n displayName: z.string().nullable(),\n oauthAppId: Id.nullable(),\n /** Microsoft accounts only. */\n cloud: MicrosoftCloud.nullable(),\n status: AccountStatus,\n statusReason: z.string().nullable(),\n settings: EffectiveSettings,\n settingsOverride: SettingsOverride,\n runtime: AccountRuntime.nullable(),\n /** IMAP accounts only. */\n imap: ImapSettings.nullable(),\n auth: AccountAuth,\n /** When the first mail sync finished (account.initialized); null while it is still running. */\n initializedAt: Timestamp.nullable(),\n /** When the first calendar sync finished (calendar.initialized); null while it is still running\n * or while calendar sync is off. */\n calendarInitializedAt: Timestamp.nullable(),\n /** When the first contacts sync finished (contacts.initialized); null while it is still running\n * or while contacts sync is off. */\n contactsInitializedAt: Timestamp.nullable(),\n createdAt: Timestamp,\n updatedAt: Timestamp,\n }),\n);\nexport type Account = z.infer<typeof Account>;\n\nexport const AccountPage = Page(Account);\nexport type AccountPage = z.infer<typeof AccountPage>;\n\nexport const ListAccountsQuery = named(\n \"ListAccountsQuery\",\n z.object({\n ...Paged,\n externalRef: z.string().optional(),\n /** Part of the email address or the external reference, case-insensitively. */\n q: trimmed(MAX_FILTER_QUERY_LENGTH).optional(),\n status: AccountStatus.optional(),\n /** Accounts authenticating through this organization connection. */\n orgConnectionId: Id.optional(),\n /** Shared mailbox accounts opened with this account's grant. */\n delegateAccountId: Id.optional(),\n }),\n);\nexport type ListAccountsQuery = z.infer<typeof ListAccountsQuery>;\n\n/** Headless connect with tokens the tenant already holds (typically from its own OAuth app). */\nexport const CreateAccount = named(\n \"CreateAccount\",\n z.object({\n provider: OAuthProvider,\n /** Microsoft with the platform app only; a tenant app carries its own cloud. */\n microsoftCloud: MicrosoftCloud.default(\"global\"),\n refreshToken: z.string().min(1),\n /** Tenant OAuth app that issued the token; omit for the platform app. */\n oauthAppId: Id.optional(),\n externalRef: ExternalRef.optional(),\n settings: SettingsOverride.optional(),\n /** Microsoft: the token carries Mail.ReadWrite.Shared, so the account can open shared\n * mailboxes (refreshes keep asking for it). Needs the plan's sharedMailboxes module\n * (403, reason plan_module_unavailable). */\n sharedMailboxesEnabled: z.boolean().optional(),\n }),\n);\nexport type CreateAccount = z.infer<typeof CreateAccount>;\n\nexport const UpdateAccount = named(\n \"UpdateAccount\",\n z.object({\n externalRef: ExternalRef.nullable().optional(),\n status: SettableAccountStatus.optional(),\n settings: SettingsOverride.optional(),\n }),\n);\nexport type UpdateAccount = z.infer<typeof UpdateAccount>;\n\nexport const DeleteAccountQuery = named(\n \"DeleteAccountQuery\",\n z.object({ purge: QueryBoolean.default(false) }),\n);\nexport type DeleteAccountQuery = z.infer<typeof DeleteAccountQuery>;\n\n/** The path's account and the query's options, as a DELETE takes them. */\nexport const DeleteAccountInput = named(\n \"DeleteAccountInput\",\n z.object({ params: AccountIdInput, query: DeleteAccountQuery }),\n);\nexport type DeleteAccountInput = z.infer<typeof DeleteAccountInput>;\n\nexport const MintAccountTokenRequest = named(\n \"MintAccountTokenRequest\",\n z.object({\n ttlSeconds: z.number().int().min(MIN_TOKEN_TTL_SECONDS).max(MAX_TOKEN_TTL_SECONDS).default(900),\n }),\n);\nexport type MintAccountTokenRequest = z.infer<typeof MintAccountTokenRequest>;\n\n/** Short-lived token limited to one account, for a tenant's own frontend. */\nexport const AccountToken = named(\n \"AccountToken\",\n z.object({ token: z.string(), expiresAt: Timestamp }),\n);\nexport type AccountToken = z.infer<typeof AccountToken>;\n\n// IMAP/SMTP accounts.\n\nexport const MailServerInput = named(\n \"MailServerInput\",\n z.object({\n host: z.string().min(1).max(MAX_HOST_LENGTH),\n port: z.number().int().min(1).max(MAX_PORT),\n security: MailSecurity,\n /** Defaults to the account's address. */\n user: z.string().min(1).max(MAX_EMAIL_LENGTH).optional(),\n }),\n);\nexport type MailServerInput = z.infer<typeof MailServerInput>;\n\nconst Password = z.string().min(1).max(MAX_SECRET_LENGTH);\n\nconst DavUrl = z.url({ protocol: /^https?$/ }).max(MAX_URL_LENGTH);\n\n/**\n * CalDAV and CardDAV for the account. A URL may be any URL on the server (its root, the\n * principal, a calendar); the principal's calendar or address book home set is what is stored.\n * null turns that half off. Left out: discovered from the address (a built-in provider table,\n * /.well-known/caldav and /.well-known/carddav, then _caldavs._tcp and _carddavs._tcp SRV\n * records), or on an update of an account that has DAV settings, kept as stored.\n */\nexport const DavInput = named(\n \"DavInput\",\n z.object({\n calendarUrl: DavUrl.nullable().optional(),\n contactsUrl: DavUrl.nullable().optional(),\n /** Defaults to the account's address. */\n user: z.string().min(1).max(MAX_EMAIL_LENGTH).optional(),\n /** A DAV password of its own; left out, DAV logs in with the IMAP password. On update, null\n * goes back to the IMAP password. */\n password: Password.nullable().optional(),\n }),\n);\nexport type DavInput = z.infer<typeof DavInput>;\n\n/** An IMAP/SMTP account and its login, as the API and the hosted page's form take it. */\nexport const ImapAccountInput = named(\n \"ImapAccountInput\",\n z.object({\n email: Email,\n displayName: z.string().max(MAX_DISPLAY_NAME_LENGTH).optional(),\n password: Password,\n /** When SMTP needs another password than IMAP. */\n smtpPassword: Password.optional(),\n /** Omit both to autodiscover them from the address. */\n imap: MailServerInput.optional(),\n /** null: the account receives only. Omit (with imap given) to autodiscover just SMTP. */\n smtp: MailServerInput.nullable().optional(),\n /** Append sent mail to Sent. Defaults to true unless the server is known to file it (Gmail,\n * Microsoft). */\n appendSent: z.boolean().optional(),\n /** Calendar and contacts over CalDAV and CardDAV; omit for an account without them. */\n dav: DavInput.optional(),\n }),\n);\nexport type ImapAccountInput = z.infer<typeof ImapAccountInput>;\n\nexport const CreateImapAccount = named(\n \"CreateImapAccount\",\n ImapAccountInput.extend({\n externalRef: ExternalRef.optional(),\n settings: SettingsOverride.optional(),\n }),\n);\nexport type CreateImapAccount = z.infer<typeof CreateImapAccount>;\n\nexport const UpdateImapSettings = named(\n \"UpdateImapSettings\",\n z.object({\n password: Password.optional(),\n smtpPassword: Password.nullable().optional(),\n imap: MailServerInput.optional(),\n smtp: MailServerInput.nullable().optional(),\n appendSent: z.boolean().optional(),\n dav: DavInput.nullable().optional(),\n }),\n);\nexport type UpdateImapSettings = z.infer<typeof UpdateImapSettings>;\n\n/** Where DAV context URLs were found: the built-in provider table, /.well-known, or SRV records. */\nexport const DavDiscoverySource = named(\n \"DavDiscoverySource\",\n z.enum([\"provider\", \"well-known\", \"srv\"]),\n);\nexport type DavDiscoverySource = z.infer<typeof DavDiscoverySource>;\n\n/** DAV context URLs found for an address before logging in; setup follows them to the home sets. */\nexport const DiscoveredDav = named(\n \"DiscoveredDav\",\n z.object({\n source: DavDiscoverySource,\n calendarUrl: z.string().nullable(),\n contactsUrl: z.string().nullable(),\n }),\n);\nexport type DiscoveredDav = z.infer<typeof DiscoveredDav>;\n\n/** Where mail server settings were found. */\nexport const AutoconfigSource = named(\n \"AutoconfigSource\",\n z.enum([\"provider\", \"autoconfig\", \"ispdb\", \"srv\", \"mx\"]),\n);\nexport type AutoconfigSource = z.infer<typeof AutoconfigSource>;\n\n/** Servers found for an address; `oauth` names the provider whose sign-in reaches this mailbox,\n * which should be preferred over a password where the provider offers it. */\nexport const DiscoveredSettings = named(\n \"DiscoveredSettings\",\n z.object({\n source: AutoconfigSource,\n imap: MailServer,\n smtp: MailServer.nullable(),\n oauth: OAuthProvider.nullable(),\n /** CalDAV and CardDAV, when any source names them; null otherwise. */\n dav: DiscoveredDav.nullable(),\n }),\n);\nexport type DiscoveredSettings = z.infer<typeof DiscoveredSettings>;\n\nexport const AutoconfigQuery = named(\"AutoconfigQuery\", z.object({ email: Email }));\nexport type AutoconfigQuery = z.infer<typeof AutoconfigQuery>;\n",
6
- "// Every cap the contract's schemas enforce, and the ones the board's and the CLI's forms mirror.\n// Each holds wherever its field appears. Operational limits only the server needs (rate limits,\n// request body bytes) live in @workwae/core/limits.\n\n// Shared fields.\n/** The longest address the capped fields take: a 64-character local part, \"@\", and a\n * 255-character domain (RFC 5321 section 4.5.3.1). */\nexport const MAX_EMAIL_LENGTH = 320;\n/** A name a tenant gives what it registers: an API key, an app, a connection, a plan. */\nexport const MAX_NAME_LENGTH = 100;\n/** The caller's own reference stored with an account or template. */\nexport const MAX_EXTERNAL_REF_LENGTH = 255;\n/** An account's display name. */\nexport const MAX_DISPLAY_NAME_LENGTH = 255;\n/** The display name next to an address: a recipient's, an attendee's, an identity's. */\nexport const MAX_ADDRESS_NAME_LENGTH = 256;\n/** A password or client secret. */\nexport const MAX_SECRET_LENGTH = 1024;\n/** A free-text note or description an admin attaches. */\nexport const MAX_NOTE_LENGTH = 500;\n/** A listing's text filter. */\nexport const MAX_FILTER_QUERY_LENGTH = 200;\n/** A URL the caller gives: a DAV server, a meeting's join link. */\nexport const MAX_URL_LENGTH = 2048;\n/** An IANA time zone name. */\nexport const MAX_TIME_ZONE_LENGTH = 64;\n/** An opaque pagination cursor. */\nexport const MAX_CURSOR_LENGTH = 512;\n/** A listing's page size, where the listing names no other. */\nexport const MAX_PAGE_SIZE = 200;\nexport const DEFAULT_PAGE_SIZE = 50;\n/** An id a provider issues (a thread id, an attachment id), as a path segment takes it. */\nexport const MAX_PROVIDER_ID_LENGTH = 1024;\n/** A host name (RFC 1035): a server's, or a domain's. */\nexport const MAX_HOST_LENGTH = 253;\n/** The highest TCP port. */\nexport const MAX_PORT = 65_535;\n/** The `state` a redirect flow echoes back. */\nexport const MAX_STATE_LENGTH = 1024;\n/** Shortest and longest life of a token or a hosted session the caller asks for. */\nexport const MIN_TOKEN_TTL_SECONDS = 60;\nexport const MAX_TOKEN_TTL_SECONDS = 86_400;\n\n// Settings.\n/** Redirect URIs a tenant's allowlist holds. */\nexport const MAX_REDIRECT_URIS = 50;\n/** The longest undo window for sends. */\nexport const MAX_UNDO_SEND_SECONDS = 60;\n/** The range a tenant's event retention may be set within. */\nexport const MIN_EVENT_RETENTION_DAYS = 7;\nexport const MAX_EVENT_RETENTION_DAYS = 30;\n\n// Mail.\n// 25 MB of attachments is what both Gmail and Microsoft accept per message.\nexport const MAX_ATTACHMENT_BYTES = 25 * 1024 * 1024;\n/** RFC 5322's line limit; also the longest Message-ID a mail merge entry takes. */\nexport const MAX_SUBJECT_LENGTH = 998;\nexport const MAX_MESSAGE_ID_LENGTH = 998;\n/** Longest html or text body a message takes (characters): what a template may render, so a send\n * gets no more inline than it could through a template. */\nexport const MAX_BODY_LENGTH = 2 * 1024 * 1024;\n/** Recipients of each of to, cc and bcc. */\nexport const MAX_RECIPIENTS = 500;\nexport const MAX_REPLY_TO = 10;\nexport const MAX_ATTACHMENTS = 50;\nexport const MAX_FILENAME_LENGTH = 255;\nexport const MAX_CONTENT_TYPE_LENGTH = 255;\nexport const MAX_CONTENT_ID_LENGTH = 255;\n/** A send's own `reference`. */\nexport const MAX_SEND_REFERENCE_LENGTH = 255;\n/** Mailboxes one message update adds or removes. */\nexport const MAX_MAILBOX_CHANGES = 50;\n/** The longest search query search.messages takes. */\nexport const MAX_SEARCH_QUERY_LENGTH = 500;\n/** Hits one search page holds: a provider search reads a page of the provider's per call. */\nexport const MAX_SEARCH_PAGE_SIZE = 100;\nexport const DEFAULT_SEARCH_PAGE_SIZE = 25;\n/** Threads one page holds: each summary aggregates every message of its thread. */\nexport const MAX_THREAD_PAGE_SIZE = 100;\nexport const DEFAULT_THREAD_PAGE_SIZE = 25;\n\n// Identities.\nexport const MAX_SIGNATURE_HTML_LENGTH = 100_000;\nexport const MAX_SIGNATURE_TEXT_LENGTH = 20_000;\n\n// Templates and mail merge.\n/** Longest template name (after trimming) and description the API accepts. */\nexport const MAX_TEMPLATE_NAME_LENGTH = 255;\nexport const MAX_TEMPLATE_DESCRIPTION_LENGTH = 1000;\n/** Longest subject, preview line and body (html, text) source a template stores. */\nexport const MAX_TEMPLATE_SUBJECT_LENGTH = 2000;\nexport const MAX_TEMPLATE_PREVIEW_TEXT_LENGTH = 2000;\nexport const MAX_TEMPLATE_BODY_LENGTH = 1_000_000;\n/** Most entries one mail merge call takes; split larger lists over several calls. */\nexport const MAX_MAIL_MERGE_ENTRIES = 100;\n/** Most attachment bytes a mail merge queues in total (the attachments times the entries): every\n * copy is sealed with its own attachments. */\nexport const MAX_MAIL_MERGE_ATTACHMENT_BYTES = 50 * 1024 * 1024;\n// Rendering runs on the API's request path, so one render is bounded however the template and the\n// params are written. The limits sit well above real mail.\n/** Largest params object (serialized as JSON) one render takes: 400 reason params_too_large. */\nexport const MAX_RENDER_PARAMS_BYTES = 256 * 1024;\n/** Block iterations (each, with, if/unless bodies, ...) one render may run before it fails with\n * template_render_failed. */\nexport const MAX_RENDER_ITERATIONS = 10_000;\n/** Longest Markdown (after rendering, values escaped) converted to HTML; beyond it the render, or\n * a send of the content as it is, fails with template_render_failed. Converting takes about 2 ms\n * per 1,000 characters at worst, so this keeps one conversion under about 200 ms. */\nexport const MAX_MARKDOWN_LENGTH = 100_000;\n\n// Suppressions.\n/** How many addresses one call adding entries to a suppression list takes. */\nexport const MAX_SUPPRESSION_BATCH = 1000;\nexport const MAX_SUPPRESSION_LIST_DESCRIPTION_LENGTH = 500;\n/** The reason given with an address the API suppresses. */\nexport const MAX_SUPPRESSION_REASON_LENGTH = 200;\n\n// Calendar.\n/** Attendees one event write may name; also the most an iMIP message from a CalDAV account goes\n * to, so email never reaches more people than the API would have let a caller invite. */\nexport const MAX_EVENT_ATTENDEES = 500;\nexport const MAX_EVENT_SUBJECT_LENGTH = 255;\nexport const MAX_EVENT_LOCATION_LENGTH = 255;\nexport const MAX_EVENT_BODY_LENGTH = 1_000_000;\n/** Longest note sent with a cancellation or an answer. */\nexport const MAX_EVENT_COMMENT_LENGTH = 2000;\n/** RFC 5545 recurrence lines one event takes, and the longest. */\nexport const MAX_RECURRENCE_LINES = 20;\nexport const MAX_RECURRENCE_LINE_LENGTH = 1000;\n/** Four weeks. */\nexport const MAX_REMINDER_MINUTES = 40_320;\n/** Attendees one availability question takes. */\nexport const MAX_AVAILABILITY_ATTENDEES = 20;\n/** The longest range an availability question spans. */\nexport const MAX_AVAILABILITY_DAYS = 62;\n/** Shortest and longest suggested slot, and step between suggestions. */\nexport const MIN_SLOT_MINUTES = 5;\nexport const MAX_SLOT_MINUTES = 1440;\n/** Most free slots one availability question suggests. */\nexport const MAX_SUGGESTIONS = 100;\n/** The longest range one event listing spans. */\nexport const MAX_EVENT_RANGE_DAYS = 400;\n/** A page of events. */\nexport const MAX_CALENDAR_EVENT_PAGE_SIZE = 500;\nexport const DEFAULT_CALENDAR_EVENT_PAGE_SIZE = 100;\n\n// Contacts.\n/** Email addresses, and phone numbers, one contact takes. */\nexport const MAX_CONTACT_ENTRIES = 20;\n/** Longest name, organization, job title or department; phone number; notes. */\nexport const MAX_CONTACT_FIELD_LENGTH = 256;\nexport const MAX_CONTACT_PHONE_LENGTH = 64;\nexport const MAX_CONTACT_NOTES_LENGTH = 10_000;\n/** A page of contacts. */\nexport const MAX_CONTACT_PAGE_SIZE = 500;\nexport const DEFAULT_CONTACT_PAGE_SIZE = 100;\n\n// Webhooks.\n/** Most values one list filter takes. */\nexport const MAX_WEBHOOK_FILTER_VALUES = 100;\n/** A subjectContains filter value. */\nexport const MAX_SUBJECT_FILTER_LENGTH = 200;\n/** Most events one range replay queues; ask for a narrower range beyond it. */\nexport const MAX_REPLAY_EVENTS = 1000;\n/** A page of an endpoint's delivery log. */\nexport const MAX_WEBHOOK_ATTEMPT_PAGE_SIZE = 500;\nexport const DEFAULT_WEBHOOK_ATTEMPT_PAGE_SIZE = 50;\n/** Signatures in a webhook-signature header that a verifier checks; any after them are ignored. */\nexport const MAX_SIGNATURE_CANDIDATES = 8;\n/** How long a rotated-out signing secret still signs deliveries when the rotation names no grace. */\nexport const DEFAULT_WEBHOOK_SECRET_GRACE_SECONDS = 24 * 60 * 60;\n/** The longest grace a signing secret rotation may give the old secret. */\nexport const MAX_WEBHOOK_SECRET_GRACE_SECONDS = 7 * 24 * 60 * 60;\n\n// AI.\nexport const MAX_DRAFT_INSTRUCTIONS_LENGTH = 2000;\n/** The longest current draft a draft request carries. */\nexport const MAX_DRAFT_CONTEXT_LENGTH = 20_000;\n\n// Meetings.\n/** Longest client or account id a meeting service issues. */\nexport const MAX_MEETING_APP_ID_LENGTH = 200;\nexport const MAX_REFRESH_TOKEN_LENGTH = 4096;\n\n// Organization connections.\n/** Longest certificate or key file (PEM, or Google's JSON key). */\nexport const MAX_KEY_FILE_LENGTH = 20_000;\n/** Longest directory search. */\nexport const MAX_DIRECTORY_QUERY_LENGTH = 100;\n/** Directory entries one page lists at most, and when no limit is given. */\nexport const MAX_DIRECTORY_PAGE_SIZE = 200;\nexport const DEFAULT_DIRECTORY_PAGE_SIZE = 100;\n/** Mailboxes one addAccounts request takes. */\nexport const MAX_ADD_MAILBOXES = 100;\n/** An Entra application id or directory (tenant) id. */\nexport const MAX_ENTRA_ID_LENGTH = 100;\n\n// Billing.\n/** A Stripe price id. */\nexport const MAX_STRIPE_ID_LENGTH = 255;\n\n// Usage.\n/** UTC days one usage read spans at most, both ends included. */\nexport const MAX_USAGE_RANGE_DAYS = 366;\n",
7
- "// Scalars and helpers every domain shares.\nimport type { OpenAPI } from \"@orpc/contract\";\nimport * as z from \"zod\";\nimport {\n DEFAULT_PAGE_SIZE,\n MAX_ADDRESS_NAME_LENGTH,\n MAX_CURSOR_LENGTH,\n MAX_EMAIL_LENGTH,\n MAX_EXTERNAL_REF_LENGTH,\n MAX_NAME_LENGTH,\n MAX_PAGE_SIZE,\n MAX_PROVIDER_ID_LENGTH,\n} from \"./limits.ts\";\n\n/** Every schema registered as an OpenAPI component, by its name. The API's document generator\n * emits each under components/schemas and refers to it with $ref wherever it appears. */\nexport const openApiComponents = new Map<string, z.ZodType>();\n/** The component name of every registered schema: what Page and List name theirs after. */\nconst componentNames = new WeakMap<z.ZodType, string>();\n\n/** Registers `schema` as the OpenAPI component `name`, which is its TypeScript name too. */\nexport function named<T extends z.ZodType>(name: string, schema: T): T {\n if (openApiComponents.has(name)) throw new Error(`OpenAPI component ${name} registered twice`);\n openApiComponents.set(name, schema);\n componentNames.set(schema, name);\n return schema;\n}\n\nfunction componentName(schema: z.ZodType, wrapper: string): string {\n const name = componentNames.get(schema);\n if (name === undefined) throw new Error(`${wrapper}() of a schema that is not named()`);\n return name;\n}\n\n/** A uuid: every id workwae issues. */\nexport const Id = z.uuid();\n/** An opaque non-uuid id: one a provider issues (thread, attachment, directory user). */\nexport const ProviderId = z.string().min(1).max(MAX_PROVIDER_ID_LENGTH);\n/** An event's sequence id, as decimal digits: the webhook-id header and the dedupe key. */\nexport const EventId = named(\"EventId\", z.string().regex(/^[0-9]{1,19}$/, \"Expected an event id\"));\n/** Opaque pagination cursor. */\nexport const Cursor = z.string().min(1).max(MAX_CURSOR_LENGTH);\nexport const Email = z.email().max(MAX_EMAIL_LENGTH);\n// One mechanism for every date-time, in and out. A handler returns a Date (the input type says\n// so), /rpc carries it as a Date, /v1 sends it as ISO 8601 text (the OpenAPI document says\n// `string, format: date-time`), and a client validating the answer through the contract (the\n// SDK) gets a Date back: ISO text is read into one before the date check. DateOnly is text both\n// ways and needs none of this.\n/** Every date-time a response carries. */\nexport const Timestamp = z.preprocess<unknown, z.ZodDate, Date>(\n (value) => (typeof value === \"string\" ? new Date(value) : value),\n z.date(),\n);\n/** A date-time a query string or a request body carries: a Date, or ISO 8601 text. */\nexport const QueryTimestamp = z.preprocess<unknown, z.ZodDate, Date | string>(\n (value) => (typeof value === \"string\" ? new Date(value) : value),\n z.date(),\n);\n/** A calendar date without a time, YYYY-MM-DD. */\nexport const DateOnly = z.iso.date();\n\n/** Non-empty text, trimmed, of at most `max` characters. */\nexport function trimmed(max: number) {\n return z.string().trim().min(1).max(max);\n}\n\n/** See MAX_NAME_LENGTH. */\nexport const Name = z.string().min(1).max(MAX_NAME_LENGTH);\nexport const ExternalRef = z.string().max(MAX_EXTERNAL_REF_LENGTH);\n\n/** An address with its display name, as a message, an event or a contact carries it. */\nexport const Address = named(\n \"Address\",\n z.object({ name: z.string().nullable(), address: z.string() }),\n);\nexport type Address = z.infer<typeof Address>;\n\n/** An address a request names; the name is optional. */\nexport const AddressInput = named(\n \"AddressInput\",\n z.object({ name: z.string().max(MAX_ADDRESS_NAME_LENGTH).optional(), address: Email }),\n);\nexport type AddressInput = z.infer<typeof AddressInput>;\n\n/** A query-string flag: `true` and `false` arrive as text. */\nexport const QueryBoolean = z\n .union([z.boolean(), z.enum([\"true\", \"false\"])])\n .transform((v) => v === true || v === \"true\");\n\n/** A cursor-paged list: the shape every paged /v1 list answers with. */\nexport interface Page<T> {\n items: T[];\n /** Pass back as `cursor` for the next page; null on the last one. */\n nextCursor: string | null;\n}\n/** The fields of a page of `item`, for a page that adds envelope fields of its own (SearchPage). */\nexport const pageFields = <T extends z.ZodType>(item: T) => ({\n items: z.array(item),\n nextCursor: Cursor.nullable(),\n});\n/** The page of a named entity `X`, registered as the component `XPage`. */\nexport const Page = <T extends z.ZodType>(item: T) =>\n named(`${componentName(item, \"Page\")}Page`, z.object(pageFields(item)));\n\n/**\n * The one cursor loop every paged reader runs (the SDK's pages and change feed, the board's\n * listings): pages from `cursor` on, each fetched with the cursor `next` read off the page\n * before, until `next` answers undefined.\n */\nexport async function* followCursor<P>(\n fetch: (cursor: string | undefined) => PromiseLike<P>,\n cursor: string | undefined,\n next: (page: P) => string | undefined,\n): AsyncGenerator<P, void, undefined> {\n let at = cursor;\n for (;;) {\n const page = await fetch(at);\n yield page;\n at = next(page);\n if (at === undefined) return;\n }\n}\n\n/** The fields of a list of `item`, for a list that adds envelope fields of its own. */\nexport const listFields = <T extends z.ZodType>(item: T) => ({ items: z.array(item) });\n/** A small bounded list of a named entity `X`, registered as the component `XList`. */\nexport const List = <T extends z.ZodType>(item: T) =>\n named(`${componentName(item, \"List\")}List`, z.object(listFields(item)));\n\n/**\n * The API error reason a refinement's issue answers with instead of invalid_input, carried in the\n * zod issue's `params.reason`. The gate answers a validation failure whose issues all carry the\n * same reason with that reason.\n */\nexport function issueReason(issue: unknown): string | null {\n if (typeof issue !== \"object\" || issue === null || !(\"params\" in issue)) return null;\n const { params } = issue;\n if (typeof params !== \"object\" || params === null || !(\"reason\" in params)) return null;\n return typeof params.reason === \"string\" ? params.reason : null;\n}\n\n/** A day in milliseconds: what a range's span in days is checked against (withDateRange). */\nexport const DAY_MS = 86_400_000;\n\nfunction instant(value: unknown): number | null {\n if (value instanceof Date) return value.getTime();\n if (typeof value !== \"string\") return null;\n const ms = Date.parse(value);\n return Number.isNaN(ms) ? null : ms;\n}\n\n/**\n * `schema` refined so its `to` field comes after its `from` field (on or after it when\n * `inclusive`, as date-only ranges are), spanning at most `maxSpanMs`. Either end left out is not\n * checked. A violation answers invalid_range (issueReason), so services need not check again.\n * Apply it last: zod refuses to extend a refined object.\n */\nexport function withDateRange<T extends z.ZodObject, K extends keyof z.output<T> & string>(\n schema: T,\n range: { from: K; to: K; maxSpanMs?: number; inclusive?: boolean },\n): T {\n return schema.superRefine((value, ctx) => {\n const from = instant(value[range.from]);\n const to = instant(value[range.to]);\n if (from === null || to === null) return;\n const span = to - from;\n const params = { reason: \"invalid_range\" };\n if (span < 0 || (span === 0 && !range.inclusive))\n ctx.addIssue({\n code: \"custom\",\n path: [range.to],\n message: `${range.to} must be ${range.inclusive ? \"on or after\" : \"after\"} ${range.from}`,\n params,\n });\n else if (range.maxSpanMs !== undefined && span > range.maxSpanMs)\n ctx.addIssue({\n code: \"custom\",\n path: [range.to],\n message:\n range.maxSpanMs % DAY_MS === 0\n ? `The range may span at most ${range.maxSpanMs / DAY_MS} days`\n : `The range may span at most ${range.maxSpanMs} ms`,\n params,\n });\n });\n}\n\n/** A page size of at most `max`, `fallback` when omitted. */\nexport function pageLimit(max: number, fallback: number) {\n return z.coerce.number().int().min(1).max(max).default(fallback);\n}\n\n/** A page size; listings that allow more or fewer say so with their own pageLimit. */\nexport const Limit = pageLimit(MAX_PAGE_SIZE, DEFAULT_PAGE_SIZE);\n\n/** The paging fields of a listing that takes the default page size. */\nexport const Paged = { limit: Limit, cursor: Cursor.optional() };\n\n/** The account a route is scoped to: /v1/accounts/{accountId}/... */\nexport const AccountIdInput = named(\"AccountIdInput\", z.object({ accountId: Id }));\nexport type AccountIdInput = z.infer<typeof AccountIdInput>;\n\n/**\n * A download the API streams: the handler answers the bytes as a ReadableStream, with their type,\n * name and size in the response headers, and a client receives them as a File (which is what the\n * SDK's response validation then sees, so it passes too). For /v1 only: the RPC protocol carries\n * a file as multipart, so a download the board reads (a contact photo) stays a z.file().\n */\nexport const StreamedFile = z\n .custom<ReadableStream<Uint8Array>>(\n (value) => value instanceof ReadableStream || value instanceof Blob,\n )\n // Identity: the stream is sent as it is. The cast is the wire's doing, typing what clients get.\n .transform((stream) => stream as unknown as File);\n\n/** Whether a procedure's output is a file, its bytes the response body, rather than JSON. */\nexport function isFileOutput(schema: unknown): boolean {\n return schema instanceof z.ZodFile || schema === StreamedFile;\n}\n\ntype Operation = OpenAPI.OperationObject;\n\n/**\n * A route's `spec` for an operation that takes no bearer: the token in its path is the credential\n * (the hosted connect page's routes).\n */\nexport const publicOperation = (operation: Operation): Operation => ({\n ...operation,\n security: [],\n});\n\n/**\n * A route's `spec` for a file output, which the generator documents as any media type and nothing\n * more: names the media type (a wildcard where the type is the file's own), the\n * Content-Disposition the handler sets, and any further headers.\n */\nexport function fileResponse(file: {\n mediaType: string;\n description: string;\n disposition: \"attachment\" | \"inline\";\n headers?: Record<string, { description: string; schema: { type: \"string\" } }>;\n}): (operation: Operation) => Operation {\n return (operation) => {\n const ok = operation.responses?.[\"200\"];\n if (!ok || \"$ref\" in ok)\n throw new Error(`OpenAPI: no 200 response for ${operation.operationId}`);\n return {\n ...operation,\n responses: {\n ...operation.responses,\n 200: {\n ...ok,\n description: file.description,\n content: {\n [file.mediaType]: { schema: { type: \"string\", contentMediaType: file.mediaType } },\n },\n headers: {\n \"content-disposition\": {\n description: `Always \\`${file.disposition}; filename=\"...\"\\``,\n schema: { type: \"string\" },\n },\n ...file.headers,\n },\n },\n },\n };\n };\n}\n",
8
- "import * as z from \"zod\";\nimport {\n MAX_EVENT_RETENTION_DAYS,\n MAX_REDIRECT_URIS,\n MAX_UNDO_SEND_SECONDS,\n MIN_EVENT_RETENTION_DAYS,\n} from \"../limits.ts\";\nimport { named } from \"../primitives.ts\";\n\nexport const BodyStorage = named(\"BodyStorage\", z.enum([\"none\", \"cache\", \"full\"]));\nexport type BodyStorage = z.infer<typeof BodyStorage>;\n\n/** null syncWindowDays = full mailbox history. */\nexport const EffectiveSettings = named(\n \"EffectiveSettings\",\n z.object({\n bodyStorage: BodyStorage,\n syncWindowDays: z.number().int().positive().nullable(),\n calendarEnabled: z.boolean(),\n /** Contacts sync (Google People, Microsoft 365 contacts, CardDAV). IMAP accounts have calendar\n * and contacts only through their DAV settings; without them both stay off. */\n contactsEnabled: z.boolean(),\n /** Undo window for sends: a send or draft-send without a later sendAt waits this many seconds,\n * during which cancelling its outbox entry undoes it. */\n undoSendSeconds: z.number().int().min(0).max(MAX_UNDO_SEND_SECONDS),\n /** Open tracking for sends: a 1x1 pixel appended to the HTML part. A send's own `tracking`\n * wins over it. Text parts are never changed. */\n trackOpens: z.boolean(),\n /** Click tracking for sends: http(s) links in the HTML part go through a redirect workwae\n * serves. A send's own `tracking` wins over it. Text parts are never changed. */\n trackClicks: z.boolean(),\n /** With click tracking, also add one link people cannot see or reach (display:none,\n * aria-hidden): only machines follow it, so a hit on it marks the hit, and its fingerprint, as\n * a scanner. It changes the HTML recipients get, and an assistive tool or plain-text conversion\n * that ignores those hints could still show it. A send's own `tracking.honeypot` wins over it;\n * off by default. */\n trackingHoneypot: z.boolean(),\n }),\n);\nexport type EffectiveSettings = z.infer<typeof EffectiveSettings>;\n\n/** Keys present override the tenant default; absent keys inherit it. */\nexport const SettingsOverride = named(\"SettingsOverride\", EffectiveSettings.partial());\nexport type SettingsOverride = z.infer<typeof SettingsOverride>;\n\n/** Hosts an allowlist entry may name over plain http: local development only. */\nconst LOOPBACK_HOSTS = new Set([\"localhost\", \"127.0.0.1\"]);\n\n/**\n * Why `uri` cannot go on the redirect URI allowlist, or null when it can: entries are absolute\n * https URLs, plain http only for local development hosts.\n */\nexport function redirectUriProblem(uri: string): string | null {\n const url = URL.parse(uri);\n if (!url) return \"Not an absolute URL\";\n if (url.protocol === \"https:\" || (url.protocol === \"http:\" && LOOPBACK_HOSTS.has(url.hostname)))\n return null;\n return \"Redirect URIs must use https (http only for localhost)\";\n}\n\n/** off: detected opt-outs are ignored; review: AI-classified replies wait in\n * GET /v1/suppression-reviews for a person, while feedback-loop complaints, which are certain,\n * suppress at once; suppress: the address goes on the list at once. Auto-replies saying the\n * person is no longer at the address (source inactive) wait for review under both review and\n * suppress. Unsubscribe links and one-click unsubscribe always suppress, whatever this says\n * (RFC 8058, Gmail and Yahoo sender rules). */\nexport const OptOutHandling = named(\"OptOutHandling\", z.enum([\"off\", \"review\", \"suppress\"]));\nexport type OptOutHandling = z.infer<typeof OptOutHandling>;\n\nexport const TenantSettings = named(\n \"TenantSettings\",\n EffectiveSettings.extend({\n optOutHandling: OptOutHandling,\n eventRetentionDays: z\n .number()\n .int()\n .min(MIN_EVENT_RETENTION_DAYS)\n .max(MAX_EVENT_RETENTION_DAYS),\n redirectUris: z.array(z.url()).max(MAX_REDIRECT_URIS),\n /** AI reads replies to your sends (subject, the start of the text with quoted history removed,\n * and which standard auto-reply headers it carries) and classifies them: opt-out request,\n * auto-reply (with its category), delivery failure or human reply (the message's\n * `classification`, the message.classified event). An out-of-office reply's text is read a\n * second time for its return date. Takes effect only where the deployment has AI configured\n * (GATEWAE_API_KEY); off until the tenant turns it on, since the reply text goes to a third\n * party. */\n aiReplyClassification: z.boolean(),\n }),\n);\nexport type TenantSettings = z.infer<typeof TenantSettings>;\n\n/** Keys present change; absent keys stay. */\nexport const UpdateTenantSettings = named(\"UpdateTenantSettings\", TenantSettings.partial());\nexport type UpdateTenantSettings = z.infer<typeof UpdateTenantSettings>;\n",
9
- "import * as z from \"zod\";\nimport { MAX_DRAFT_CONTEXT_LENGTH, MAX_DRAFT_INSTRUCTIONS_LENGTH } from \"../limits.ts\";\nimport { Id, named, trimmed } from \"../primitives.ts\";\n\nexport const AiDraftFormat = named(\"AiDraftFormat\", z.enum([\"text\", \"markdown\"]));\nexport type AiDraftFormat = z.infer<typeof AiDraftFormat>;\n\nexport const AiDraftContext = named(\n \"AiDraftContext\",\n z\n .object({\n /** With replyToMessageId: the account holding the message being answered. */\n accountId: Id.optional(),\n /** The message being answered; its sender, subject and own text (quoted history removed,\n * cut to a few thousand characters) are given to the model. */\n replyToMessageId: Id.optional(),\n /** What the user wrote so far, to rewrite or continue. */\n currentDraft: z.string().max(MAX_DRAFT_CONTEXT_LENGTH).optional(),\n })\n .refine((c) => !c.replyToMessageId || c.accountId, {\n message: \"replyToMessageId needs accountId\",\n path: [\"accountId\"],\n }),\n);\nexport type AiDraftContext = z.infer<typeof AiDraftContext>;\n\nexport const CreateAiDraft = named(\n \"CreateAiDraft\",\n z.object({\n /** What to write, in the user's words. */\n instructions: trimmed(MAX_DRAFT_INSTRUCTIONS_LENGTH),\n context: AiDraftContext.optional(),\n format: AiDraftFormat,\n }),\n);\nexport type CreateAiDraft = z.infer<typeof CreateAiDraft>;\n\n/** Email text for a person to edit; nothing is sent or saved. */\nexport const AiDraft = named(\"AiDraft\", z.object({ text: z.string() }));\nexport type AiDraft = z.infer<typeof AiDraft>;\n",
10
- "import * as z from \"zod\";\nimport { MAX_FILTER_QUERY_LENGTH } from \"../limits.ts\";\nimport { Id, named, Page, Paged, QueryTimestamp, Timestamp, withDateRange } from \"../primitives.ts\";\n\nexport const AuditActorType = named(\n \"AuditActorType\",\n z.enum([\"user\", \"apiKey\", \"accountToken\", \"connectSession\"]),\n);\nexport type AuditActorType = z.infer<typeof AuditActorType>;\n\nexport const AuditActor = named(\n \"AuditActor\",\n z.object({\n type: AuditActorType,\n id: Id,\n /** User email or API key prefix at the time. */\n label: z.string().nullable(),\n }),\n);\nexport type AuditActor = z.infer<typeof AuditActor>;\n\n/** Where the request came in: the public API, or the board. */\nexport const AuditSurface = named(\"AuditSurface\", z.enum([\"v1\", \"rpc\"]));\nexport type AuditSurface = z.infer<typeof AuditSurface>;\n\n/** success: a 2xx status. */\nexport const AuditOutcome = named(\"AuditOutcome\", z.enum([\"success\", \"failure\"]));\nexport type AuditOutcome = z.infer<typeof AuditOutcome>;\n\nexport const AuditEntry = named(\n \"AuditEntry\",\n z.object({\n id: Id,\n createdAt: Timestamp,\n actor: AuditActor,\n /** Procedure path, e.g. accounts.create. */\n action: z.string(),\n surface: AuditSurface,\n /** Ids the request named; nothing else of its input is kept. */\n targets: z.record(z.string(), z.union([z.string(), z.array(z.string())])),\n ip: z.string().nullable(),\n userAgent: z.string().nullable(),\n status: z.number().int(),\n errorReason: z.string().nullable(),\n /** The request's X-Request-Id; null for entries written before request ids were kept. */\n requestId: z.string().nullable(),\n }),\n);\nexport type AuditEntry = z.infer<typeof AuditEntry>;\n\nexport const AuditEntryPage = Page(AuditEntry);\nexport type AuditEntryPage = z.infer<typeof AuditEntryPage>;\n\n/** from and to bound createdAt, both included. */\nexport const ListAuditLogQuery = named(\n \"ListAuditLogQuery\",\n withDateRange(\n z.object({\n ...Paged,\n actorType: AuditActorType.optional(),\n actorId: Id.optional(),\n action: z.string().min(1).max(MAX_FILTER_QUERY_LENGTH).optional(),\n accountId: Id.optional(),\n outcome: AuditOutcome.optional(),\n from: QueryTimestamp.optional(),\n to: QueryTimestamp.optional(),\n }),\n { from: \"from\", to: \"to\", inclusive: true },\n ),\n);\nexport type ListAuditLogQuery = z.infer<typeof ListAuditLogQuery>;\n",
11
- "import * as z from \"zod\";\nimport {\n DEFAULT_CALENDAR_EVENT_PAGE_SIZE,\n MAX_AVAILABILITY_ATTENDEES,\n MAX_AVAILABILITY_DAYS,\n MAX_CALENDAR_EVENT_PAGE_SIZE,\n MAX_EVENT_ATTENDEES,\n MAX_EVENT_BODY_LENGTH,\n MAX_EVENT_COMMENT_LENGTH,\n MAX_EVENT_LOCATION_LENGTH,\n MAX_EVENT_RANGE_DAYS,\n MAX_EVENT_SUBJECT_LENGTH,\n MAX_RECURRENCE_LINE_LENGTH,\n MAX_RECURRENCE_LINES,\n MAX_REMINDER_MINUTES,\n MAX_SLOT_MINUTES,\n MAX_SUGGESTIONS,\n MAX_TIME_ZONE_LENGTH,\n MAX_URL_LENGTH,\n MIN_SLOT_MINUTES,\n} from \"../limits.ts\";\nimport { MeetingService } from \"../meetings/models.ts\";\nimport {\n AccountIdInput,\n Address,\n AddressInput,\n Cursor,\n DAY_MS,\n DateOnly,\n Email,\n Id,\n List,\n named,\n Page,\n pageLimit,\n QueryBoolean,\n QueryTimestamp,\n Timestamp,\n withDateRange,\n} from \"../primitives.ts\";\n\n/** freebusy: only times are visible (Google freeBusyReader). */\nexport const CalendarAccess = named(\n \"CalendarAccess\",\n z.enum([\"owner\", \"writer\", \"reader\", \"freebusy\"]),\n);\nexport type CalendarAccess = z.infer<typeof CalendarAccess>;\n\nexport const Calendar = named(\n \"Calendar\",\n z.object({\n id: Id,\n name: z.string(),\n description: z.string().nullable(),\n /** For a calendar shared with the account, the person who shared it. */\n owner: Address.nullable(),\n isPrimary: z.boolean(),\n access: CalendarAccess,\n /** Events can be created and changed (owner or writer). */\n canEdit: z.boolean(),\n /** \"#rrggbb\". */\n color: z.string().nullable(),\n /** IANA zone all-day events are anchored in. */\n timeZone: z.string().nullable(),\n /** Hidden from the user's own calendar list; still synced. */\n isHidden: z.boolean(),\n }),\n);\nexport type Calendar = z.infer<typeof Calendar>;\n\nexport const CalendarList = List(Calendar);\nexport type CalendarList = z.infer<typeof CalendarList>;\n\n/** A calendar field a calendar.updated event names as changed. */\nexport const CalendarChangedField = named(\"CalendarChangedField\", Calendar.keyof().exclude([\"id\"]));\nexport type CalendarChangedField = z.infer<typeof CalendarChangedField>;\n\n/**\n * single: one-off. series: a recurring event's definition (times of its first occurrence, the\n * rule). occurrence: an unchanged instance of a series. exception: an instance changed on its own.\n */\nexport const EventKind = named(\n \"EventKind\",\n z.enum([\"single\", \"series\", \"occurrence\", \"exception\"]),\n);\nexport type EventKind = z.infer<typeof EventKind>;\n\nexport const AttendeeType = named(\"AttendeeType\", z.enum([\"required\", \"optional\", \"resource\"]));\nexport type AttendeeType = z.infer<typeof AttendeeType>;\nexport const ResponseStatus = named(\n \"ResponseStatus\",\n z.enum([\"none\", \"organizer\", \"accepted\", \"tentative\", \"declined\", \"needs_action\"]),\n);\nexport type ResponseStatus = z.infer<typeof ResponseStatus>;\nexport const EventStatus = named(\"EventStatus\", z.enum([\"confirmed\", \"tentative\", \"cancelled\"]));\nexport type EventStatus = z.infer<typeof EventStatus>;\nexport const ShowAs = named(\n \"ShowAs\",\n z.enum([\"free\", \"busy\", \"tentative\", \"oof\", \"working_elsewhere\", \"unknown\"]),\n);\nexport type ShowAs = z.infer<typeof ShowAs>;\nexport const Sensitivity = named(\n \"Sensitivity\",\n z.enum([\"normal\", \"personal\", \"private\", \"confidential\"]),\n);\nexport type Sensitivity = z.infer<typeof Sensitivity>;\n\nexport const Attendee = named(\n \"Attendee\",\n Address.extend({ type: AttendeeType, response: ResponseStatus }),\n);\nexport type Attendee = z.infer<typeof Attendee>;\n\nexport const EventTime = named(\n \"EventTime\",\n z.object({\n /** The instant. All-day events: midnight of `date` in the calendar's time zone. */\n dateTime: Timestamp,\n /** All-day events only; an end date is exclusive. */\n date: DateOnly.nullable(),\n /** IANA zone the event was scheduled in; null for all-day events. */\n timeZone: z.string().nullable(),\n }),\n);\nexport type EventTime = z.infer<typeof EventTime>;\n\nexport const CalendarEvent = named(\n \"CalendarEvent\",\n z.object({\n id: Id,\n calendarId: Id,\n kind: EventKind,\n /** The series an occurrence or exception belongs to (GET it for the rule). */\n seriesId: Id.nullable(),\n /** Where an occurrence or exception sits in its series, as first scheduled. */\n originalStart: Timestamp.nullable(),\n subject: z.string().nullable(),\n snippet: z.string().nullable(),\n location: z.string().nullable(),\n start: EventTime,\n end: EventTime,\n isAllDay: z.boolean(),\n organizer: Address.nullable(),\n attendees: z.array(Attendee),\n isOrganizer: z.boolean(),\n /** The account's own answer to the invitation. */\n selfResponse: ResponseStatus,\n status: EventStatus,\n showAs: ShowAs,\n sensitivity: Sensitivity,\n onlineMeetingUrl: z.string().nullable(),\n onlineMeetingProvider: z.string().nullable(),\n iCalUid: z.string().nullable(),\n /** Series only: RFC 5545 RRULE/RDATE/EXDATE lines. */\n recurrence: z.array(z.string()).nullable(),\n recurrenceTimeZone: z.string().nullable(),\n /** Series only: original starts of occurrences removed from the series. */\n cancelledStarts: z.array(Timestamp).nullable(),\n categories: z.array(z.string()),\n hasAttachments: z.boolean(),\n reminderMinutes: z.number().int().nullable(),\n webLink: z.string().nullable(),\n updatedAt: Timestamp,\n }),\n);\nexport type CalendarEvent = z.infer<typeof CalendarEvent>;\n\nexport const CalendarEventPage = Page(CalendarEvent);\nexport type CalendarEventPage = z.infer<typeof CalendarEventPage>;\n\n/** An event field a calendar_event.updated event names as changed. */\nexport const CalendarEventChangedField = named(\n \"CalendarEventChangedField\",\n CalendarEvent.keyof().exclude([\"id\", \"calendarId\", \"seriesId\", \"updatedAt\"]),\n);\nexport type CalendarEventChangedField = z.infer<typeof CalendarEventChangedField>;\n\nexport const BodyContentType = named(\"BodyContentType\", z.enum([\"text\", \"html\"]));\nexport type BodyContentType = z.infer<typeof BodyContentType>;\n\nexport const EventBody = named(\n \"EventBody\",\n z.object({ contentType: BodyContentType, content: z.string() }),\n);\nexport type EventBody = z.infer<typeof EventBody>;\n\nexport const CalendarEventDetail = named(\n \"CalendarEventDetail\",\n CalendarEvent.extend({\n /** Fetched from the provider on request; null when the event has none. */\n body: EventBody.nullable(),\n }),\n);\nexport type CalendarEventDetail = z.infer<typeof CalendarEventDetail>;\n\n/** A time of day in a zone (wall-clock time, no offset), or a whole day. */\nexport const EventTimeInput = named(\n \"EventTimeInput\",\n z.union([\n z.object({\n dateTime: z.iso.datetime({ local: true }),\n timeZone: z.string().min(1).max(MAX_TIME_ZONE_LENGTH),\n }),\n z.object({ date: DateOnly }),\n ]),\n);\nexport type EventTimeInput = z.infer<typeof EventTimeInput>;\n\nexport const AttendeeInput = named(\n \"AttendeeInput\",\n AddressInput.extend({ type: AttendeeType.default(\"required\") }),\n);\nexport type AttendeeInput = z.infer<typeof AttendeeInput>;\n\nconst RecurrenceLine = z\n .string()\n .max(MAX_RECURRENCE_LINE_LENGTH)\n .regex(/^(RRULE|RDATE|EXDATE)[:;]/, \"Expected an RRULE, RDATE or EXDATE line\");\n\nconst EventFields = {\n subject: z.string().max(MAX_EVENT_SUBJECT_LENGTH),\n body: EventBody.extend({ content: z.string().max(MAX_EVENT_BODY_LENGTH) }),\n location: z.string().max(MAX_EVENT_LOCATION_LENGTH),\n start: EventTimeInput,\n end: EventTimeInput,\n attendees: z.array(AttendeeInput).max(MAX_EVENT_ATTENDEES),\n /** RFC 5545 lines without DTSTART; the rule is evaluated in start.timeZone. */\n recurrence: z.array(RecurrenceLine).min(1).max(MAX_RECURRENCE_LINES),\n showAs: ShowAs.exclude([\"unknown\"]),\n sensitivity: Sensitivity,\n reminderMinutes: z.number().int().min(0).max(MAX_REMINDER_MINUTES).nullable(),\n /** A join link from another service (Zoom, Webex, ...). Google keeps it as an add-on\n * conference; Microsoft as the location's link, with a join line added to a body sent along. */\n onlineMeetingUrl: z.url({ protocol: /^https$/ }).max(MAX_URL_LENGTH),\n};\n\n/** Whether attendees hear about the change. Microsoft always notifies for a meeting the account\n * organizes, so false is refused there (provider_unsupported). A CalDAV server without RFC 6638\n * scheduling tells nobody, so workwae mails the iMIP message from the account's SMTP server, for\n * a meeting the account organizes: provider_unsupported, before anything is written, when the\n * account has no SMTP server. */\nconst Notify = z.boolean().default(true);\n\nexport const CreateCalendarEvent = named(\n \"CreateCalendarEvent\",\n z.object({\n /** The calendar the event goes in. */\n calendarId: Id,\n subject: EventFields.subject.optional(),\n body: EventFields.body.optional(),\n location: EventFields.location.optional(),\n start: EventFields.start,\n end: EventFields.end,\n attendees: EventFields.attendees.default([]),\n recurrence: EventFields.recurrence.optional(),\n showAs: EventFields.showAs.optional(),\n sensitivity: EventFields.sensitivity.optional(),\n reminderMinutes: EventFields.reminderMinutes.optional(),\n /** Teams (Microsoft) or Meet (Google) link; set at creation only. */\n onlineMeeting: z.boolean().default(false),\n /** Not together with onlineMeeting (multiple_meeting_options). */\n onlineMeetingUrl: EventFields.onlineMeetingUrl.optional(),\n /** A Zoom or Webex meeting workwae creates for the event, hosted by the account's user; its\n * join link becomes onlineMeetingUrl. Not together with onlineMeeting or onlineMeetingUrl\n * (multiple_meeting_options); needs the plan's meetings module (plan_module_unavailable). */\n onlineMeetingService: MeetingService.optional(),\n notify: Notify,\n }),\n);\nexport type CreateCalendarEvent = z.infer<typeof CreateCalendarEvent>;\n\n/** create's input: the account, and an event with at most one of onlineMeeting,\n * onlineMeetingUrl and onlineMeetingService (multiple_meeting_options). */\nexport const CreateCalendarEventInput = AccountIdInput.extend(\n CreateCalendarEvent.shape,\n).superRefine((input, ctx) => {\n const options = [\n input.onlineMeeting,\n input.onlineMeetingUrl !== undefined,\n input.onlineMeetingService !== undefined,\n ].filter(Boolean).length;\n if (options > 1)\n ctx.addIssue({\n code: \"custom\",\n path: [\"onlineMeetingService\"],\n message: \"Give one of onlineMeeting, onlineMeetingUrl and onlineMeetingService\",\n params: { reason: \"multiple_meeting_options\" },\n });\n});\n\n/** Fields present change; absent fields stay. An occurrence becomes an exception. */\nexport const UpdateCalendarEvent = named(\n \"UpdateCalendarEvent\",\n z.object({\n subject: EventFields.subject.optional(),\n body: EventFields.body.optional(),\n location: EventFields.location.optional(),\n start: EventFields.start.optional(),\n end: EventFields.end.optional(),\n /** Replaces the whole list. */\n attendees: EventFields.attendees.optional(),\n /** Series and singles only; a single with a rule becomes a series. */\n recurrence: EventFields.recurrence.optional(),\n showAs: EventFields.showAs.optional(),\n sensitivity: EventFields.sensitivity.optional(),\n reminderMinutes: EventFields.reminderMinutes.optional(),\n /** null removes it: on Google the event's conference, on Microsoft the location's link. */\n onlineMeetingUrl: EventFields.onlineMeetingUrl.nullable().optional(),\n notify: Notify,\n }),\n);\nexport type UpdateCalendarEvent = z.infer<typeof UpdateCalendarEvent>;\n\nexport const DeleteCalendarEventQuery = named(\n \"DeleteCalendarEventQuery\",\n z.object({\n notify: QueryBoolean.default(true),\n /** Sent with the cancellation when the account organizes the meeting (Microsoft only). */\n comment: z.string().max(MAX_EVENT_COMMENT_LENGTH).optional(),\n }),\n);\nexport type DeleteCalendarEventQuery = z.infer<typeof DeleteCalendarEventQuery>;\n\nexport const RsvpResponse = named(\"RsvpResponse\", z.enum([\"accepted\", \"tentative\", \"declined\"]));\nexport type RsvpResponse = z.infer<typeof RsvpResponse>;\n\nexport const RespondToCalendarEventRequest = named(\n \"RespondToCalendarEventRequest\",\n z.object({\n response: RsvpResponse,\n comment: z.string().max(MAX_EVENT_COMMENT_LENGTH).optional(),\n /** Tell the organizer. */\n notify: z.boolean().default(true),\n }),\n);\nexport type RespondToCalendarEventRequest = z.infer<typeof RespondToCalendarEventRequest>;\n\nexport const CalendarEventIdInput = named(\n \"CalendarEventIdInput\",\n AccountIdInput.extend({ eventId: Id }),\n);\nexport type CalendarEventIdInput = z.infer<typeof CalendarEventIdInput>;\n\n/** The path's event and the query's options, as a DELETE takes them. */\nexport const DeleteCalendarEventInput = named(\n \"DeleteCalendarEventInput\",\n z.object({ params: CalendarEventIdInput, query: DeleteCalendarEventQuery }),\n);\nexport type DeleteCalendarEventInput = z.infer<typeof DeleteCalendarEventInput>;\n\nexport const ListCalendarEventsQuery = named(\n \"ListCalendarEventsQuery\",\n z.object({\n start: QueryTimestamp,\n end: QueryTimestamp,\n calendarId: Id.optional(),\n limit: pageLimit(MAX_CALENDAR_EVENT_PAGE_SIZE, DEFAULT_CALENDAR_EVENT_PAGE_SIZE),\n cursor: Cursor.optional(),\n }),\n);\nexport type ListCalendarEventsQuery = z.infer<typeof ListCalendarEventsQuery>;\n\n/** list's input: the account, and a range ending after it starts, of at most\n * MAX_EVENT_RANGE_DAYS (invalid_range). */\nexport const ListCalendarEventsInput = withDateRange(\n AccountIdInput.extend(ListCalendarEventsQuery.shape),\n { from: \"start\", to: \"end\", maxSpanMs: MAX_EVENT_RANGE_DAYS * DAY_MS },\n);\n\n/** How a busy block shows. Google reports every block as busy; free time is never listed.\n * working_elsewhere does not block a suggested slot; the others do. */\nexport const BusyStatus = named(\n \"BusyStatus\",\n z.enum([\"busy\", \"tentative\", \"oof\", \"working_elsewhere\", \"unknown\"]),\n);\nexport type BusyStatus = z.infer<typeof BusyStatus>;\n\nexport const BusyBlock = named(\n \"BusyBlock\",\n z.object({ start: Timestamp, end: Timestamp, status: BusyStatus }),\n);\nexport type BusyBlock = z.infer<typeof BusyBlock>;\n\nexport const AttendeeAvailability = named(\n \"AttendeeAvailability\",\n z.object({\n address: z.string(),\n busy: z.array(BusyBlock),\n /** Why the provider could not tell (unknown address, calendar not shared); busy is empty then\n * and the attendee does not constrain the suggestions. */\n error: z.string().nullable(),\n }),\n);\nexport type AttendeeAvailability = z.infer<typeof AttendeeAvailability>;\n\nexport const Weekday = named(\"Weekday\", z.enum([\"mon\", \"tue\", \"wed\", \"thu\", \"fri\", \"sat\", \"sun\"]));\nexport type Weekday = z.infer<typeof Weekday>;\n\nconst TimeOfDay = z.string().regex(/^([01]\\d|2[0-3]):[0-5]\\d$/, \"Expected HH:MM\");\n\n/** Only suggest inside these hours on these days (in timeZone); end after start\n * (invalid_working_hours). */\nexport const WorkingHours = named(\n \"WorkingHours\",\n z\n .object({\n start: TimeOfDay,\n end: TimeOfDay,\n days: z.array(Weekday).min(1).default([\"mon\", \"tue\", \"wed\", \"thu\", \"fri\"]),\n })\n .refine((hours) => hours.end > hours.start, {\n message: \"workingHours end must be after start\",\n path: [\"end\"],\n params: { reason: \"invalid_working_hours\" },\n }),\n);\nexport type WorkingHours = z.infer<typeof WorkingHours>;\n\nconst SlotMinutes = z.number().int().min(MIN_SLOT_MINUTES).max(MAX_SLOT_MINUTES).default(30);\n\nexport const FindAvailabilityRequest = named(\n \"FindAvailabilityRequest\",\n z.object({\n attendees: z.array(Email).min(1).max(MAX_AVAILABILITY_ATTENDEES),\n start: QueryTimestamp,\n end: QueryTimestamp,\n /** Length of a suggested slot. */\n durationMinutes: SlotMinutes,\n /** Suggestions start on multiples of this many minutes after midnight in timeZone. */\n stepMinutes: SlotMinutes,\n /** IANA zone the working hours and the step are read in. */\n timeZone: z.string().min(1).max(MAX_TIME_ZONE_LENGTH).default(\"UTC\"),\n /** Omitted: any time in range. */\n workingHours: WorkingHours.optional(),\n maxSuggestions: z.number().int().min(0).max(MAX_SUGGESTIONS).default(10),\n /** The account's own calendar counts as an attendee. */\n includeAccount: z.boolean().default(true),\n }),\n);\nexport type FindAvailabilityRequest = z.infer<typeof FindAvailabilityRequest>;\n\n/** find's input: the account, and a range ending after it starts, of at most\n * MAX_AVAILABILITY_DAYS (invalid_range). */\nexport const FindAvailabilityInput = withDateRange(\n AccountIdInput.extend(FindAvailabilityRequest.shape),\n { from: \"start\", to: \"end\", maxSpanMs: MAX_AVAILABILITY_DAYS * DAY_MS },\n);\n\nexport const TimeSlot = named(\"TimeSlot\", z.object({ start: Timestamp, end: Timestamp }));\nexport type TimeSlot = z.infer<typeof TimeSlot>;\n\nexport const Availability = named(\n \"Availability\",\n z.object({\n attendees: z.array(AttendeeAvailability),\n /** Common free slots, earliest first. */\n suggestions: z.array(TimeSlot),\n }),\n);\nexport type Availability = z.infer<typeof Availability>;\n",
12
- "// Meetings workwae creates at Zoom and Webex for calendar events: each account's own grant at a\n// service (connected through a hosted link), and the tenant's meeting apps (its own sign-in\n// clients, and the server apps that create meetings for every mailbox of an organization).\nimport * as z from \"zod\";\nimport { ConnectSessionStatus, RedirectState, SessionTtlSeconds } from \"../connect/models.ts\";\nimport {\n MAX_MEETING_APP_ID_LENGTH,\n MAX_REFRESH_TOKEN_LENGTH,\n MAX_SECRET_LENGTH,\n} from \"../limits.ts\";\nimport { AccountIdInput, Email, Id, List, Name, named, Timestamp } from \"../primitives.ts\";\n\nexport const MeetingService = named(\"MeetingService\", z.enum([\"zoom\", \"webex\"]));\nexport type MeetingService = z.infer<typeof MeetingService>;\n\n/** reauth_required: the service refused the grant (revoked, expired); connect again. Mail and\n * calendar sync are not affected. */\nexport const MeetingConnectionStatus = named(\n \"MeetingConnectionStatus\",\n z.enum([\"active\", \"reauth_required\"]),\n);\nexport type MeetingConnectionStatus = z.infer<typeof MeetingConnectionStatus>;\n\nexport const MeetingConnection = named(\n \"MeetingConnection\",\n z.object({\n service: MeetingService,\n /** The service user the grant acts as; meetings created with it are theirs. */\n email: z.string(),\n displayName: z.string().nullable(),\n /** The tenant sign-in app that issued the grant; null for the platform app. */\n meetingAppId: Id.nullable(),\n status: MeetingConnectionStatus,\n /** Why the grant needs reconnecting (e.g. invalid_grant). */\n statusReason: z.string().nullable(),\n createdAt: Timestamp,\n updatedAt: Timestamp,\n }),\n);\nexport type MeetingConnection = z.infer<typeof MeetingConnection>;\n\n/** At most one per service. */\nexport const MeetingConnectionList = List(MeetingConnection);\nexport type MeetingConnectionList = z.infer<typeof MeetingConnectionList>;\n\n/**\n * zoom_oauth / webex_oauth: the tenant's own sign-in app for per-account grants, instead of the\n * platform's. zoom_s2s: a Zoom Server-to-Server OAuth app. webex_service_app: a Webex Service App\n * authorized by an organization administrator. A server app creates meetings for every account\n * without a grant of its own, hosted by the service user with the mailbox's address.\n */\nexport const MeetingAppKind = named(\n \"MeetingAppKind\",\n z.enum([\"zoom_oauth\", \"zoom_s2s\", \"webex_oauth\", \"webex_service_app\"]),\n);\nexport type MeetingAppKind = z.infer<typeof MeetingAppKind>;\n\n/** Server apps only: unverified until used or tested, then the outcome of the last of those. */\nexport const MeetingAppStatus = named(\n \"MeetingAppStatus\",\n z.enum([\"unverified\", \"active\", \"failing\"]),\n);\nexport type MeetingAppStatus = z.infer<typeof MeetingAppStatus>;\n\nexport const MeetingApp = named(\n \"MeetingApp\",\n z.object({\n id: Id,\n kind: MeetingAppKind,\n service: MeetingService,\n name: z.string(),\n clientId: z.string(),\n /** zoom_s2s only. */\n zoomAccountId: z.string().nullable(),\n /** Null for sign-in apps, which have nothing to test until someone signs in. */\n status: MeetingAppStatus.nullable(),\n statusDetail: z.string().nullable(),\n checkedAt: Timestamp.nullable(),\n /** The scopes to grant the app at the service. */\n scopes: z.array(z.string()),\n /** Sign-in apps: the redirect URI to register at the service. */\n redirectUri: z.string().nullable(),\n createdAt: Timestamp,\n }),\n);\nexport type MeetingApp = z.infer<typeof MeetingApp>;\n\nexport const MeetingAppList = List(MeetingApp);\nexport type MeetingAppList = z.infer<typeof MeetingAppList>;\n\nconst ClientId = z.string().min(1).max(MAX_MEETING_APP_ID_LENGTH);\nconst ClientSecret = z.string().min(1).max(MAX_SECRET_LENGTH);\n\nexport const CreateMeetingApp = named(\n \"CreateMeetingApp\",\n z.discriminatedUnion(\"kind\", [\n z.object({\n kind: z.literal(\"zoom_oauth\"),\n name: Name,\n clientId: ClientId,\n clientSecret: ClientSecret,\n }),\n z.object({\n kind: z.literal(\"zoom_s2s\"),\n name: Name,\n /** The Zoom account id shown on the app's credentials page. */\n accountId: z.string().min(1).max(MAX_MEETING_APP_ID_LENGTH),\n clientId: ClientId,\n clientSecret: ClientSecret,\n }),\n z.object({\n kind: z.literal(\"webex_oauth\"),\n name: Name,\n clientId: ClientId,\n clientSecret: ClientSecret,\n }),\n z.object({\n kind: z.literal(\"webex_service_app\"),\n name: Name,\n clientId: ClientId,\n clientSecret: ClientSecret,\n /** The refresh token the Webex developer portal generates for the authorized organization. */\n refreshToken: z.string().min(1).max(MAX_REFRESH_TOKEN_LENGTH),\n }),\n ]),\n);\nexport type CreateMeetingApp = z.infer<typeof CreateMeetingApp>;\n\nexport const MeetingAppCheck = named(\n \"MeetingAppCheck\",\n z.object({ name: z.string(), isOk: z.boolean(), detail: z.string() }),\n);\nexport type MeetingAppCheck = z.infer<typeof MeetingAppCheck>;\n\nexport const MeetingAppTestResult = named(\n \"MeetingAppTestResult\",\n z.object({ app: MeetingApp, checks: z.array(MeetingAppCheck) }),\n);\nexport type MeetingAppTestResult = z.infer<typeof MeetingAppTestResult>;\n\nexport const MeetingConnectSessionPublic = named(\n \"MeetingConnectSessionPublic\",\n z.object({\n tenantName: z.string(),\n service: MeetingService,\n /** The mailbox whose meetings the grant will host. */\n accountEmail: z.string(),\n status: ConnectSessionStatus,\n expiresAt: Timestamp,\n }),\n);\nexport type MeetingConnectSessionPublic = z.infer<typeof MeetingConnectSessionPublic>;\n\nexport const MeetingAppIdInput = named(\"MeetingAppIdInput\", z.object({ appId: Id }));\nexport type MeetingAppIdInput = z.infer<typeof MeetingAppIdInput>;\n\nexport const TestMeetingAppRequest = named(\n \"TestMeetingAppRequest\",\n z.object({ user: Email.optional() }),\n);\nexport type TestMeetingAppRequest = z.infer<typeof TestMeetingAppRequest>;\n\nexport const MeetingConnectionInput = named(\n \"MeetingConnectionInput\",\n AccountIdInput.extend({ service: MeetingService }),\n);\nexport type MeetingConnectionInput = z.infer<typeof MeetingConnectionInput>;\n\nexport const CreateMeetingConnectSession = named(\n \"CreateMeetingConnectSession\",\n z.object({\n service: MeetingService,\n /** Where the browser returns with the outcome. Omitted: workwae's confirmation page. */\n redirectUri: z.url().optional(),\n /** A tenant sign-in app (zoom_oauth, webex_oauth) to use instead of the platform app. */\n meetingAppId: Id.optional(),\n /** Echoed back to redirectUri. */\n state: RedirectState.optional(),\n ttlSeconds: SessionTtlSeconds,\n }),\n);\nexport type CreateMeetingConnectSession = z.infer<typeof CreateMeetingConnectSession>;\n",
13
- "import * as z from \"zod\";\nimport { MicrosoftCloud, OAuthProvider } from \"../accounts/models.ts\";\nimport { MAX_STATE_LENGTH, MAX_TOKEN_TTL_SECONDS, MIN_TOKEN_TTL_SECONDS } from \"../limits.ts\";\nimport { Email, ExternalRef, Id, named, Timestamp } from \"../primitives.ts\";\nimport { BodyStorage } from \"../settings/models.ts\";\n\n/** How an OAuth-connected mailbox is read: the provider's API, or IMAP and SMTP with XOAUTH2. */\nexport const MailAccess = named(\"MailAccess\", z.enum([\"api\", \"imap\"]));\nexport type MailAccess = z.infer<typeof MailAccess>;\n\nexport const ConnectOptions = named(\n \"ConnectOptions\",\n z.object({\n /** Calendar and contacts scopes are only asked for when the tenant's plan includes the module. */\n calendarEnabled: z.boolean().optional(),\n contactsEnabled: z.boolean().optional(),\n bodyStorage: BodyStorage.optional(),\n /** OAuth sign-ins only. \"imap\" creates an IMAP account authenticated with the grant; it has no\n * calendar and no contacts. Google needs the tenant's own Google OAuth app for it\n * (google_imap_requires_own_app). */\n mailAccess: MailAccess.optional(),\n /** Microsoft sign-ins read through the API: also request Mail.ReadWrite.Shared and\n * Mail.Send.Shared (Calendars.ReadWrite.Shared with calendar), so the account can open the\n * shared mailboxes its user has access to (POST /v1/accounts/{accountId}/shared-mailboxes).\n * Needs the plan's sharedMailboxes module (plan_module_unavailable). */\n sharedMailboxesEnabled: z.boolean().optional(),\n }),\n);\nexport type ConnectOptions = z.infer<typeof ConnectOptions>;\n\n/** What a hosted connect page offers: an OAuth sign-in, or the IMAP/SMTP form. */\nexport const ConnectProvider = named(\"ConnectProvider\", z.enum([\"google\", \"microsoft\", \"imap\"]));\nexport type ConnectProvider = z.infer<typeof ConnectProvider>;\n\n/** Where a hosted session (account or meeting connect) stands. */\nexport const ConnectSessionStatus = named(\n \"ConnectSessionStatus\",\n z.enum([\"pending\", \"completed\", \"failed\"]),\n);\nexport type ConnectSessionStatus = z.infer<typeof ConnectSessionStatus>;\n\n/**\n * Why a connect flow failed: the `error` a connect redirect carries (status=error, OAuth and\n * meeting sign-ins, administrator consent, the hosted IMAP form's plan and billing failures) and\n * a failed session's `error`. Not an API reason: these travel in redirect URLs. Every code an\n * OAuth failure carries is one (the API checks this where they flow into a redirect).\n */\nexport const ConnectErrorCode = named(\n \"ConnectErrorCode\",\n z.enum([\n // The session itself.\n \"session_used\",\n \"session_expired\",\n \"provider_not_allowed\",\n // The sign-in, the grant and the identity it names.\n \"access_denied\",\n \"access_token_rejected\",\n \"provider_error\",\n \"provider_unavailable\",\n \"provider_not_configured\",\n \"unsupported_provider\",\n \"token_exchange_failed\",\n \"invalid_client\",\n \"invalid_grant\",\n \"missing_refresh_token\",\n \"scope_denied\",\n \"identity_failed\",\n \"identity_unavailable\",\n \"credential_conflict\",\n \"credential_missing\",\n \"delegate_missing\",\n // The account it connects.\n \"account_exists\",\n \"account_mismatch\",\n \"account_not_found\",\n // The tenant's OAuth and meeting apps.\n \"unknown_oauth_app\",\n \"oauth_app_mismatch\",\n \"oauth_app_secret_unreadable\",\n \"google_imap_requires_own_app\",\n \"unknown_meeting_app\",\n \"meeting_app_mismatch\",\n \"meeting_app_secret_unreadable\",\n // Organization connections and administrator consent.\n \"consent_failed\",\n \"consent_required\",\n \"consent_revoked\",\n \"consent_unverified\",\n \"directory_already_connected\",\n \"directory_mismatch\",\n \"directory_unavailable\",\n \"invalid_certificate\",\n \"invalid_service_account_key\",\n \"org_connection_not_found\",\n \"org_connection_secret_unreadable\",\n // The tenant's plan and billing.\n \"plan_limit_accounts\",\n \"plan_module_unavailable\",\n \"billing_past_due\",\n \"internal_error\",\n ]),\n);\nexport type ConnectErrorCode = z.infer<typeof ConnectErrorCode>;\n\nexport const ConnectSessionPublic = named(\n \"ConnectSessionPublic\",\n z.object({\n tenantName: z.string(),\n providers: z.array(ConnectProvider),\n microsoftCloud: MicrosoftCloud,\n status: ConnectSessionStatus,\n reauthEmail: z.string().nullable(),\n /** The address the session was created for; the IMAP form starts with it. */\n loginHint: z.string().nullable(),\n expiresAt: Timestamp,\n }),\n);\nexport type ConnectSessionPublic = z.infer<typeof ConnectSessionPublic>;\n\n/** A hosted connect session as its creator sees it: where it stands, and what it connected. */\nexport const ConnectSession = named(\n \"ConnectSession\",\n z.object({\n id: Id,\n /** Pending until a sign-in completes it or fails it; a pending one past expiresAt is unusable. */\n status: ConnectSessionStatus,\n /** Why it failed, once failed: the error its redirect carried. */\n error: ConnectErrorCode.nullable(),\n /** The account it connected or reconnected, once completed. */\n accountId: Id.nullable(),\n /** That account's address; null until completed, or once the account is deleted. */\n email: z.string().nullable(),\n expiresAt: Timestamp,\n createdAt: Timestamp,\n }),\n);\nexport type ConnectSession = z.infer<typeof ConnectSession>;\n\n/** The `state` a redirect flow echoes back. */\nexport const RedirectState = z.string().max(MAX_STATE_LENGTH);\n/** How long a hosted session stays usable. */\nexport const SessionTtlSeconds = z\n .number()\n .int()\n .min(MIN_TOKEN_TTL_SECONDS)\n .max(MAX_TOKEN_TTL_SECONDS)\n .default(3600);\n\nexport const CreateConnectSession = named(\n \"CreateConnectSession\",\n z.object({\n /** Where the browser returns with the outcome. Omitted: workwae's confirmation page. */\n redirectUri: z.url().optional(),\n /** \"imap\" adds the IMAP/SMTP form for any other mailbox. */\n providers: z.array(ConnectProvider).min(1).default([\"google\", \"microsoft\"]),\n /** Cloud used for Microsoft sign-in with the platform app (ignored for a tenant app). */\n microsoftCloud: MicrosoftCloud.default(\"global\"),\n /** Tenant OAuth apps to use instead of the platform apps, per provider. */\n oauthAppIds: z.object({ google: Id.optional(), microsoft: Id.optional() }).optional(),\n externalRef: ExternalRef.optional(),\n /** The address the owner should sign in with: prefills the provider sign-in and the IMAP\n * form. */\n loginHint: Email.optional(),\n /** Echoed back to redirectUri. */\n state: RedirectState.optional(),\n /** Re-authorize this account instead of creating a new one. Without it, a mailbox the\n * tenant already has is refused: the redirect carries error=account_exists (OAuth), or\n * the IMAP form answers 409 account_exists. */\n accountId: Id.optional(),\n options: ConnectOptions.optional(),\n ttlSeconds: SessionTtlSeconds,\n }),\n);\nexport type CreateConnectSession = z.infer<typeof CreateConnectSession>;\n\n/** A hosted session's page, to send its owner to. */\nexport const SessionLink = named(\n \"SessionLink\",\n z.object({ id: Id, url: z.url(), expiresAt: Timestamp }),\n);\nexport type SessionLink = z.infer<typeof SessionLink>;\n\nexport const ConnectSessionIdInput = named(\"ConnectSessionIdInput\", z.object({ sessionId: Id }));\nexport type ConnectSessionIdInput = z.infer<typeof ConnectSessionIdInput>;\n\nexport const StartOAuthRequest = named(\n \"StartOAuthRequest\",\n z.object({\n provider: OAuthProvider,\n redirectUri: z.url(),\n microsoftCloud: MicrosoftCloud.default(\"global\"),\n oauthAppId: Id.optional(),\n externalRef: ExternalRef.optional(),\n state: RedirectState.optional(),\n accountId: Id.optional(),\n options: ConnectOptions.optional(),\n }),\n);\nexport type StartOAuthRequest = z.infer<typeof StartOAuthRequest>;\n\n/** Where to send the user to start the headless OAuth flow. */\nexport const OAuthAuthorization = named(\"OAuthAuthorization\", z.object({ authorizeUrl: z.url() }));\nexport type OAuthAuthorization = z.infer<typeof OAuthAuthorization>;\n\n/** A hosted page's session, by the token in its URL. */\nexport const SessionTokenInput = named(\"SessionTokenInput\", z.object({ token: z.string().min(1) }));\nexport type SessionTokenInput = z.infer<typeof SessionTokenInput>;\n\n/** Where the hosted page sends the browser next (the tenant's redirectUri). */\nexport const HostedImapResult = named(\"HostedImapResult\", z.object({ redirectUrl: z.url() }));\nexport type HostedImapResult = z.infer<typeof HostedImapResult>;\n",
14
- "import * as z from \"zod\";\nimport {\n DEFAULT_CONTACT_PAGE_SIZE,\n MAX_CONTACT_ENTRIES,\n MAX_CONTACT_FIELD_LENGTH,\n MAX_CONTACT_NOTES_LENGTH,\n MAX_CONTACT_PAGE_SIZE,\n MAX_CONTACT_PHONE_LENGTH,\n MAX_FILTER_QUERY_LENGTH,\n} from \"../limits.ts\";\nimport {\n AccountIdInput,\n Address,\n AddressInput,\n Cursor,\n Id,\n List,\n named,\n Page,\n pageLimit,\n Timestamp,\n trimmed,\n} from \"../primitives.ts\";\n\nexport const ContactEmailType = named(\"ContactEmailType\", z.enum([\"home\", \"work\", \"other\"]));\nexport type ContactEmailType = z.infer<typeof ContactEmailType>;\n/** Microsoft 365 contacts have mobile, home and work numbers only. */\nexport const ContactPhoneType = named(\n \"ContactPhoneType\",\n z.enum([\"mobile\", \"home\", \"work\", \"other\"]),\n);\nexport type ContactPhoneType = z.infer<typeof ContactPhoneType>;\n\n/** type is null where the provider keeps none (Microsoft 365 addresses). */\nexport const ContactEmail = named(\n \"ContactEmail\",\n Address.pick({ address: true }).extend({ type: ContactEmailType.nullable() }),\n);\nexport type ContactEmail = z.infer<typeof ContactEmail>;\nexport const ContactPhone = named(\n \"ContactPhone\",\n z.object({ number: z.string(), type: ContactPhoneType.nullable() }),\n);\nexport type ContactPhone = z.infer<typeof ContactPhone>;\n\n/** A Microsoft 365 contact folder. Google accounts have none (their contacts carry folderId null). */\nexport const ContactFolder = named(\n \"ContactFolder\",\n z.object({\n id: Id,\n name: z.string(),\n /** The mailbox's own Contacts folder, where contacts go when no folder is named. */\n isDefault: z.boolean(),\n }),\n);\nexport type ContactFolder = z.infer<typeof ContactFolder>;\n\nexport const ContactFolderList = List(ContactFolder);\nexport type ContactFolderList = z.infer<typeof ContactFolderList>;\n\n/** YYYY-MM-DD, or --MM-DD for a birthday without a year (Google). */\nconst Birthday = z.string().regex(/^(\\d{4}|--)-\\d{2}-\\d{2}$/, \"Expected YYYY-MM-DD or --MM-DD\");\n\nexport const Contact = named(\n \"Contact\",\n z.object({\n id: Id,\n folderId: Id.nullable(),\n displayName: z.string().nullable(),\n givenName: z.string().nullable(),\n middleName: z.string().nullable(),\n familyName: z.string().nullable(),\n nickname: z.string().nullable(),\n emails: z.array(ContactEmail),\n phones: z.array(ContactPhone),\n organization: z.string().nullable(),\n jobTitle: z.string().nullable(),\n department: z.string().nullable(),\n /** YYYY-MM-DD, or --MM-DD for a birthday without a year (Google). */\n birthday: z.string().nullable(),\n notes: z.string().nullable(),\n /** Whether GET .../photo has a picture to return; null where the provider does not say without\n * asking for the photo itself (Microsoft 365). */\n hasPhoto: z.boolean().nullable(),\n updatedAt: Timestamp,\n }),\n);\nexport type Contact = z.infer<typeof Contact>;\n\nexport const ContactPage = Page(Contact);\nexport type ContactPage = z.infer<typeof ContactPage>;\n\n/** A contact field a contact.updated event names as changed; `photo` is the photo itself (GET\n * .../photo), which can change while hasPhoto stays true. */\nexport const ContactChangedField = named(\n \"ContactChangedField\",\n z.enum([...Contact.keyof().exclude([\"id\", \"updatedAt\"]).options, \"photo\"]),\n);\nexport type ContactChangedField = z.infer<typeof ContactChangedField>;\n\nexport const ContactEmailInput = named(\n \"ContactEmailInput\",\n AddressInput.pick({ address: true }).extend({ type: ContactEmailType.optional() }),\n);\nexport type ContactEmailInput = z.infer<typeof ContactEmailInput>;\nexport const ContactPhoneInput = named(\n \"ContactPhoneInput\",\n z.object({\n number: trimmed(MAX_CONTACT_PHONE_LENGTH),\n type: ContactPhoneType.optional(),\n }),\n);\nexport type ContactPhoneInput = z.infer<typeof ContactPhoneInput>;\n\nconst ContactFields = {\n displayName: trimmed(MAX_CONTACT_FIELD_LENGTH),\n givenName: trimmed(MAX_CONTACT_FIELD_LENGTH),\n middleName: trimmed(MAX_CONTACT_FIELD_LENGTH),\n familyName: trimmed(MAX_CONTACT_FIELD_LENGTH),\n nickname: trimmed(MAX_CONTACT_FIELD_LENGTH),\n organization: trimmed(MAX_CONTACT_FIELD_LENGTH),\n jobTitle: trimmed(MAX_CONTACT_FIELD_LENGTH),\n department: trimmed(MAX_CONTACT_FIELD_LENGTH),\n birthday: Birthday,\n notes: z.string().max(MAX_CONTACT_NOTES_LENGTH),\n};\n\n/** A new contact needs at least a name, an organization, an address or a number, so it can be\n * found again (400 otherwise). */\nexport const CreateContact = named(\n \"CreateContact\",\n z.object({\n /** Microsoft 365 only; omitted puts the contact in the default folder. */\n folderId: Id.optional(),\n displayName: ContactFields.displayName.optional(),\n givenName: ContactFields.givenName.optional(),\n middleName: ContactFields.middleName.optional(),\n familyName: ContactFields.familyName.optional(),\n nickname: ContactFields.nickname.optional(),\n emails: z.array(ContactEmailInput).max(MAX_CONTACT_ENTRIES).optional(),\n phones: z.array(ContactPhoneInput).max(MAX_CONTACT_ENTRIES).optional(),\n organization: ContactFields.organization.optional(),\n jobTitle: ContactFields.jobTitle.optional(),\n department: ContactFields.department.optional(),\n birthday: ContactFields.birthday.optional(),\n notes: ContactFields.notes.optional(),\n }),\n);\nexport type CreateContact = z.infer<typeof CreateContact>;\n\n/** create's input: the account, and a contact with a name, an organization, an email address or\n * a phone number (contact_unidentifiable). */\nexport const CreateContactInput = AccountIdInput.extend(CreateContact.shape).refine(\n (c) =>\n c.displayName !== undefined ||\n c.givenName !== undefined ||\n c.familyName !== undefined ||\n c.organization !== undefined ||\n (c.emails?.length ?? 0) > 0 ||\n (c.phones?.length ?? 0) > 0,\n {\n message: \"A contact needs a name, an organization, an email address or a phone number\",\n params: { reason: \"contact_unidentifiable\" },\n },\n);\n\n/** Fields present change (null clears); absent fields stay. emails and phones replace the list. */\nexport const UpdateContact = named(\n \"UpdateContact\",\n z.object({\n displayName: ContactFields.displayName.nullable().optional(),\n givenName: ContactFields.givenName.nullable().optional(),\n middleName: ContactFields.middleName.nullable().optional(),\n familyName: ContactFields.familyName.nullable().optional(),\n nickname: ContactFields.nickname.nullable().optional(),\n emails: z.array(ContactEmailInput).max(MAX_CONTACT_ENTRIES).optional(),\n phones: z.array(ContactPhoneInput).max(MAX_CONTACT_ENTRIES).optional(),\n organization: ContactFields.organization.nullable().optional(),\n jobTitle: ContactFields.jobTitle.nullable().optional(),\n department: ContactFields.department.nullable().optional(),\n birthday: ContactFields.birthday.nullable().optional(),\n notes: ContactFields.notes.nullable().optional(),\n }),\n);\nexport type UpdateContact = z.infer<typeof UpdateContact>;\n\nexport const ContactIdInput = named(\"ContactIdInput\", AccountIdInput.extend({ contactId: Id }));\nexport type ContactIdInput = z.infer<typeof ContactIdInput>;\n\nexport const ListContactsQuery = named(\n \"ListContactsQuery\",\n z.object({\n q: trimmed(MAX_FILTER_QUERY_LENGTH).optional(),\n folderId: Id.optional(),\n limit: pageLimit(MAX_CONTACT_PAGE_SIZE, DEFAULT_CONTACT_PAGE_SIZE),\n cursor: Cursor.optional(),\n }),\n);\nexport type ListContactsQuery = z.infer<typeof ListContactsQuery>;\n",
15
- "// How routes declare the errors they answer with. Every route is built on `base`, which declares\n// the errors any route can answer with (input validation, authentication and access, rate limits,\n// load shedding, body size, internal failures); a route adds its own with `.errors(...)`, built\n// from `errors({ reason: \"condition\" })` and the shared fragments below. The condition is the\n// declared error's default message, so the OpenAPI document lists, per route and status, each\n// reason's `code` with the condition it is answered on.\nimport { oc } from \"@orpc/contract\";\nimport {\n type ErrorReason,\n REASONS,\n type ReasonDataSchema,\n type ReasonDefinition,\n type ReasonStatus,\n type ReasonTable,\n} from \"./reasons.ts\";\n\n/** A declared error: its reason's status and data schema, with the condition as its message. */\nexport type DeclaredError<R extends ErrorReason> = {\n status: ReasonStatus<R>;\n message: string;\n} & (ReasonDataSchema<R> extends undefined ? unknown : { data: ReasonDataSchema<R> });\n\nexport type DeclaredErrors<C> = { [R in keyof C & ErrorReason]: DeclaredError<R> };\n\n/**\n * The oRPC error map for `conditions` (reason -> when it is answered, one sentence), each with its\n * reason's status and data schema from `table`. errors() below and the console's wrap it; they\n * are declared functions with named return types so declarations reference the table by name\n * instead of inlining it into every route.\n */\nexport function errorMap(table: ReasonTable, conditions: Record<string, string | undefined>) {\n const map: Record<string, { status: number; message: string; data?: unknown }> = {};\n for (const [reason, message] of Object.entries(conditions)) {\n const definition = table[reason] as ReasonDefinition;\n map[reason] = {\n status: definition.status,\n message: message as string,\n ...(definition.data !== undefined && { data: definition.data }),\n };\n }\n return map;\n}\n\n/** The error map of a /v1 route; console routes use console/reasons.ts's, which knows theirs. */\nexport function errors<const C extends { [R in ErrorReason]?: string }>(\n conditions: C,\n): DeclaredErrors<C> {\n return errorMap(REASONS, conditions) as DeclaredErrors<C>;\n}\n\n/** What any route can answer with, whoever calls it and whatever it does. */\nexport const GLOBAL_ERRORS = errors({\n invalid_input:\n \"The request does not match the operation's input schema (a malformed body included); data.issues names each problem.\",\n unauthenticated:\n \"No usable credential: none was sent, or it is malformed, unknown, revoked or an expired account token.\",\n api_key_expired:\n \"The API key is past its expiry (or the grace of the rotation that replaced it).\",\n missing_scope: \"The API key lacks the scope the operation needs.\",\n role_forbidden: \"The member's role does not allow the operation.\",\n account_token_forbidden: \"An account token called an operation account tokens cannot call.\",\n rate_limited:\n \"The tenant used up its plan's request rate; Retry-After says when the window ends.\",\n too_many_requests:\n \"The credential has too many requests in flight at once; retry after Retry-After.\",\n overloaded: \"The API is shedding load; retry after Retry-After.\",\n payload_too_large: \"The request body is larger than the API accepts.\",\n internal_error: \"An unexpected failure on our side.\",\n // Only POST /v1 operations read Idempotency-Key, but every route is built on `base`.\n invalid_idempotency_key:\n \"POST only: the Idempotency-Key header is not 1 to 255 printable ASCII characters.\",\n idempotency_key_reused:\n \"POST only: the Idempotency-Key was used in the last 24 hours with another method, path or body.\",\n idempotency_key_in_progress:\n \"POST only: the request first sent with this Idempotency-Key has not been answered yet.\",\n});\n\n/** The builder every route starts from: oc with GLOBAL_ERRORS declared. */\nexport const base = oc.errors(GLOBAL_ERRORS);\n\n// Access the gate enforces beyond scopes, for the board-only and owner-only routes.\nconst BOARD_SESSION_ONLY = \"The caller is not a board session (only board sessions may call this).\";\nexport const SESSION_ONLY = errors({ session_required: BOARD_SESSION_ONLY });\nexport const OWNER_ONLY = errors({\n session_required: BOARD_SESSION_ONLY,\n owner_required: \"The caller does not own the organization.\",\n});\nexport const PLATFORM_ONLY = errors({\n session_required: BOARD_SESSION_ONLY,\n platform_admin_required: \"The caller is not a platform administrator.\",\n email_verification_required:\n \"The platform administrator has not verified their email address yet.\",\n});\n\n/** The account a path names: missing, deleted, or another account than an account token's. */\nexport const ACCOUNT_NOT_FOUND = errors({\n account_not_found:\n \"The account does not exist, or the caller is an account token for another account.\",\n});\n\n/** The account states that keep a route from reaching the provider; `account` names the account\n * and may narrow when, e.g. \"With source=provider, the account\". */\nexport function accountState(account = \"The account\") {\n return errors({\n account_paused: `${account} is paused.`,\n account_disabled: `${account} is disabled.`,\n account_reauth_required: `${account} must be reconnected: its stored grant or login no longer works.`,\n account_misconfigured: `${account}'s stored grant cannot be used until an administrator fixes what it relies on (the tenant's OAuth app or organization connection is refused, missing or unreadable).`,\n });\n}\n\n/** What any provider call answers when it fails. A route the provider can refuse adds\n * `provider_forbidden` with its own condition, and one reading an item `provider_not_found`. */\nexport const PROVIDER_FAILURES = errors({\n provider_throttled: \"The provider asked us to slow down (with Retry-After when it named a wait).\",\n provider_unavailable:\n \"The provider could not be reached (with Retry-After when it named a wait).\",\n});\n\n/** What asking for stored bodies through `field` refuses. */\nexport function bodyStorage(field: string) {\n return errors({\n storage_unavailable: `${field} is cache or full and no object store is configured.`,\n plan_limit_storage: `${field} is cache or full and the tenant's plan does not include body storage.`,\n });\n}\n\n/** A route of a module the tenant's plan may lack, e.g. planModule(\"calendar\"). */\nexport function planModule(module: string) {\n return errors({ plan_module_unavailable: `The tenant's plan does not include ${module}.` });\n}\n\nexport const PLAN_LIMIT_ACCOUNTS = errors({\n plan_limit_accounts: \"The tenant already has as many accounts as its plan allows.\",\n});\n\nexport const BILLING_PAST_DUE = errors({\n billing_past_due:\n \"The tenant's payment is past due beyond the grace period (sends already queued or scheduled still go out).\",\n});\n\nexport const INVALID_CURSOR = errors({ invalid_cursor: \"The cursor is not one this list issued.\" });\n",
16
- "// Every reason the API refuses with. An API error's oRPC `code` is its reason, and its HTTP status\n// is the reason's, one status per reason everywhere:\n// { \"defined\": true, \"code\": \"plan_limit_accounts\", \"status\": 403, \"message\": \"...\", \"data\"? }\n// `data` is present only for the reasons that declare a schema for it here. Routes declare which\n// reasons they answer with (errors.ts), core's coded errors type their codes against this table\n// (ReasonCode), and the SDK's and board's error typing derive from it.\n//\n// Status rules: 400 the request itself is wrong; 404 a resource the path names does not exist\n// (`<entity>_not_found`); 422 the body or query names something that does not exist\n// (`unknown_<entity>`) or could not be resolved; 409 the resource's state forbids it; 403 the\n// caller or the tenant's plan may not; 502 an upstream (provider, Stripe, AI gateway) failed.\nimport * as z from \"zod\";\nimport { Id, named } from \"./primitives.ts\";\nimport { TemplateField } from \"./templates/models.ts\";\n\n/** The HTTP statuses API errors answer with. */\nexport type ErrorStatus =\n | 400\n | 401\n | 402\n | 403\n | 404\n | 409\n | 410\n | 413\n | 422\n | 429\n | 500\n | 502\n | 503\n | 507;\n\nexport interface ReasonDefinition {\n readonly status: ErrorStatus;\n /** The schema of the error's `data`, for a reason that carries structured extras. */\n readonly data?: z.ZodType;\n}\nexport type ReasonTable = Record<string, ReasonDefinition>;\n\n/** One input problem: where in the input (`path`, empty for the input as a whole) and what. */\nexport const InputIssue = named(\n \"InputIssue\",\n z.object({ path: z.array(z.union([z.string(), z.number()])), message: z.string() }),\n);\nexport type InputIssue = z.infer<typeof InputIssue>;\n\nexport const InvalidInputData = named(\n \"InvalidInputData\",\n z.object({ issues: z.array(InputIssue) }),\n);\nexport type InvalidInputData = z.infer<typeof InvalidInputData>;\n\n/** The ids a request named that the tenant does not have. */\nexport const UnknownIdsData = named(\"UnknownIdsData\", z.object({ ids: z.array(Id) }));\nexport type UnknownIdsData = z.infer<typeof UnknownIdsData>;\n\n/** The template content field that did not compile or render. */\nexport const TemplateFieldData = named(\"TemplateFieldData\", z.object({ field: TemplateField }));\nexport type TemplateFieldData = z.infer<typeof TemplateFieldData>;\n\nexport const REASONS = {\n // ---- The request itself, and the HTTP layer.\n invalid_input: { status: 400, data: InvalidInputData },\n invalid_cursor: { status: 400 },\n invalid_range: { status: 400 },\n payload_too_large: { status: 413 },\n // A provider's push or Stripe's webhook that does not parse, or whose signature does not hold.\n invalid_payload: { status: 400 },\n invalid_signature: { status: 400 },\n route_not_found: { status: 404 },\n internal_error: { status: 500 },\n // A POST's Idempotency-Key: malformed, sent again with another request, or its first request\n // still running.\n invalid_idempotency_key: { status: 400 },\n idempotency_key_reused: { status: 422 },\n idempotency_key_in_progress: { status: 409 },\n\n // ---- Load and rate limits.\n rate_limited: { status: 429 },\n too_many_requests: { status: 429 },\n overloaded: { status: 503 },\n\n // ---- Who is calling.\n unauthenticated: { status: 401 },\n // An API key past its expiry (one it was created with, or the grace of a rotation).\n api_key_expired: { status: 401 },\n missing_scope: { status: 403 },\n role_forbidden: { status: 403 },\n account_token_forbidden: { status: 403 },\n session_required: { status: 403 },\n owner_required: { status: 403 },\n platform_admin_required: { status: 403 },\n email_verification_required: { status: 403 },\n console_only: { status: 403 },\n\n // ---- The tenant's plan, and an instance without an object store.\n plan_limit_accounts: { status: 403 },\n plan_limit_sends: { status: 403 },\n plan_limit_webhooks: { status: 403 },\n plan_limit_storage: { status: 403 },\n plan_module_unavailable: { status: 403 },\n storage_unavailable: { status: 400 },\n tenant_not_found: { status: 404 },\n\n // ---- Billing: Stripe is our upstream, like a provider.\n billing_past_due: { status: 402 },\n billing_disabled: { status: 404 },\n billing_unavailable: { status: 502 },\n billing_subscription_exists: { status: 409 },\n billing_customer_missing: { status: 409 },\n plan_not_billable: { status: 409 },\n\n // ---- Accounts and their state.\n account_not_found: { status: 404 },\n unknown_account: { status: 422, data: UnknownIdsData },\n account_paused: { status: 409 },\n account_disabled: { status: 409 },\n account_reauth_required: { status: 409 },\n // The account's stored grant cannot be used for a reason reconnecting does not fix: the\n // tenant's OAuth app or organization connection is refused, missing or unreadable.\n account_misconfigured: { status: 409 },\n calendar_disabled: { status: 409 },\n contacts_disabled: { status: 409 },\n\n // ---- What the mail, calendar or contacts provider answered.\n provider_not_found: { status: 404 },\n provider_throttled: { status: 429 },\n provider_unavailable: { status: 502 },\n provider_forbidden: { status: 403 },\n provider_conflict: { status: 409 },\n provider_unsupported: { status: 400 },\n provider_rejected: { status: 400 },\n // The server's reply to a sent message was lost; it may have accepted it, so nothing resends.\n outcome_unknown: { status: 502 },\n\n // ---- Mail: messages, mailboxes, threads, identities.\n message_not_found: { status: 404 },\n unknown_mailbox: { status: 422, data: UnknownIdsData },\n mailbox_not_label: { status: 400 },\n thread_not_found: { status: 404 },\n identity_not_found: { status: 404 },\n identities_managed_by_provider: { status: 400 },\n identity_exists: { status: 409 },\n identity_not_custom: { status: 400 },\n\n // ---- Sending and the outbox.\n draft_not_found: { status: 404 },\n // The provider accepted a new draft but did not answer it back.\n draft_lost: { status: 502 },\n send_not_found: { status: 404 },\n attachments_too_large: { status: 400 },\n not_a_draft: { status: 400 },\n unknown_reply_target: { status: 422 },\n from_not_allowed: { status: 400 },\n tracking_unsupported: { status: 400 },\n honeypot_needs_click_tracking: { status: 400 },\n list_send_recipients: { status: 400 },\n suppressed: { status: 400 },\n no_recipients: { status: 400 },\n list_unsubscribe_unavailable: { status: 400 },\n send_not_reschedulable: { status: 409 },\n send_not_cancellable: { status: 409 },\n\n // ---- Suppression lists.\n suppression_list_not_found: { status: 404 },\n suppression_entry_not_found: { status: 404 },\n suppression_review_not_found: { status: 404 },\n suppression_list_exists: { status: 409 },\n suppression_list_not_empty: { status: 409 },\n\n // ---- Templates.\n template_not_found: { status: 404 },\n unknown_template: { status: 422 },\n template_and_inline_fields: { status: 400 },\n invalid_template: { status: 400, data: TemplateFieldData },\n template_account_mismatch: { status: 400 },\n template_render_failed: { status: 400, data: TemplateFieldData },\n params_too_large: { status: 400 },\n template_name_taken: { status: 409 },\n\n // ---- Calendar and contacts.\n calendar_not_found: { status: 404 },\n calendar_event_not_found: { status: 404 },\n contact_not_found: { status: 404 },\n photo_not_found: { status: 404 },\n unknown_calendar: { status: 422 },\n unknown_contact_folder: { status: 422 },\n calendar_read_only: { status: 403 },\n organizer_cannot_respond: { status: 409 },\n invalid_time_zone: { status: 400 },\n invalid_working_hours: { status: 400 },\n mixed_event_times: { status: 400 },\n invalid_recurrence: { status: 400 },\n recurrence_on_instance: { status: 400 },\n contact_unidentifiable: { status: 400 },\n\n // ---- Meetings.\n multiple_meeting_options: { status: 400 },\n meeting_service_not_connected: { status: 409 },\n meeting_service_reauth_required: { status: 409 },\n meeting_host_missing: { status: 409 },\n meeting_recurrence_unsupported: { status: 400 },\n meeting_service_rejected: { status: 400 },\n meeting_deleted: { status: 409 },\n meeting_service_unavailable: { status: 502 },\n meeting_app_not_found: { status: 404 },\n unknown_meeting_app: { status: 422 },\n meeting_connection_not_found: { status: 404 },\n meeting_connect_session_not_found: { status: 404 },\n meeting_app_exists: { status: 409 },\n meeting_app_in_use: { status: 409 },\n meeting_app_mismatch: { status: 400 },\n meeting_app_secret_unreadable: { status: 400 },\n not_testable: { status: 400 },\n\n // ---- IMAP accounts, DAV and hosted connect pages.\n autodiscovery_failed: { status: 422 },\n password_required: { status: 400 },\n oauth_servers_fixed: { status: 400 },\n dav_discovery_failed: { status: 400 },\n dav_unsupported: { status: 400 },\n // A server (IMAP, SMTP, CalDAV or CardDAV) refused the login a settings check tried.\n login_failed: { status: 400 },\n // The egress policy: a server resolving to a private or loopback address, a plaintext login.\n server_not_allowed: { status: 400 },\n plaintext_not_allowed: { status: 400 },\n not_dav_server: { status: 400 },\n not_imap_account: { status: 400 },\n password_not_stored: { status: 400 },\n password_unsupported: { status: 400 },\n connect_session_not_found: { status: 404 },\n session_used: { status: 409 },\n session_expired: { status: 400 },\n provider_not_allowed: { status: 400 },\n redirect_uri_not_allowed: { status: 400 },\n\n // ---- Connecting accounts and OAuth.\n access_denied: { status: 400 },\n access_token_rejected: { status: 400 },\n account_exists: { status: 409 },\n account_mismatch: { status: 409 },\n consent_failed: { status: 400 },\n consent_revoked: { status: 400 },\n consent_unverified: { status: 400 },\n credential_conflict: { status: 400 },\n credential_missing: { status: 400 },\n identity_failed: { status: 400 },\n identity_unavailable: { status: 400 },\n invalid_client: { status: 400 },\n invalid_grant: { status: 400 },\n missing_refresh_token: { status: 400 },\n unknown_oauth_app: { status: 422 },\n oauth_app_not_found: { status: 404 },\n oauth_app_mismatch: { status: 400 },\n oauth_app_in_use: { status: 409 },\n oauth_app_secret_unreadable: { status: 400 },\n google_imap_requires_own_app: { status: 400 },\n org_connection_account: { status: 400 },\n shared_mailbox_account: { status: 400 },\n gmail_push_unsupported: { status: 400 },\n push_unavailable: { status: 400 },\n cloud_required: { status: 400 },\n provider_error: { status: 400 },\n provider_not_configured: { status: 400 },\n unsupported_provider: { status: 400 },\n scope_denied: { status: 400 },\n token_exchange_failed: { status: 400 },\n\n // ---- Organization connections and shared mailboxes.\n org_connection_not_found: { status: 404 },\n org_connection_secret_unreadable: { status: 400 },\n consent_required: { status: 409 },\n delegate_missing: { status: 400 },\n directory_unavailable: { status: 409 },\n directory_already_connected: { status: 409 },\n directory_mismatch: { status: 400 },\n directory_id_not_allowed: { status: 400 },\n credential_mismatch: { status: 400 },\n connection_in_use: { status: 409 },\n invalid_certificate: { status: 400 },\n invalid_service_account_key: { status: 400 },\n not_microsoft: { status: 400 },\n user_required: { status: 400 },\n shared_mailbox_unsupported: { status: 400 },\n scope_missing: { status: 400 },\n // The delegating account's user cannot open the shared mailbox the body names.\n shared_mailbox_inaccessible: { status: 422 },\n\n // ---- Webhooks, the event log and the webhook inbox tester.\n webhook_endpoint_not_found: { status: 404 },\n endpoint_disabled: { status: 409 },\n event_not_found: { status: 404 },\n replay_range_too_large: { status: 400 },\n mailbox_outside_accounts: { status: 400 },\n https_required: { status: 400 },\n\n // ---- Exports and erasure.\n export_not_found: { status: 404 },\n export_not_ready: { status: 409 },\n export_failed: { status: 409 },\n export_running: { status: 409 },\n export_in_progress: { status: 409 },\n export_expired: { status: 410 },\n // Stored parts failed their integrity check: our fault, not the caller's.\n export_corrupt: { status: 500 },\n confirmation_mismatch: { status: 400 },\n erase_scheduled: { status: 409 },\n erase_started: { status: 409 },\n erase_not_found: { status: 404 },\n\n // ---- AI: the gateway is our upstream, like a provider; a refusal is about what was asked.\n ai_disabled: { status: 400 },\n ai_unavailable: { status: 502 },\n ai_suspended: { status: 502 },\n ai_refused: { status: 400 },\n // context.replyToMessageId names a message the account does not have.\n unknown_message: { status: 422 },\n} as const satisfies Record<string, ReasonDefinition>;\n\nexport type Reasons = typeof REASONS;\n/** A reason the /v1 API answers with. The workspace's ErrorReason (index.ts) adds the console's. */\nexport type ErrorReason = keyof Reasons;\n/** The HTTP status `R` answers with. */\nexport type ReasonStatus<R extends ErrorReason> = Reasons[R][\"status\"];\n/** The schema of `R`'s data, or undefined for a reason without data. */\nexport type ReasonDataSchema<R extends ErrorReason> = Reasons[R] extends {\n data: infer S extends z.ZodType;\n}\n ? S\n : undefined;\n/** The data an error with reason `R` carries (undefined for a reason without data). */\nexport type ReasonData<R extends ErrorReason> =\n ReasonDataSchema<R> extends z.ZodType ? z.output<ReasonDataSchema<R>> : undefined;\n\n/** The reason checks over a table: the /v1 one below, the console's merged one in console/. */\nexport function reasonGuards<T extends ReasonTable>(table: T) {\n const isReason = (code: unknown): code is keyof T & string =>\n typeof code === \"string\" && Object.hasOwn(table, code);\n return {\n isReason,\n /**\n * The reason of an API error: the `code` of an oRPC error (or any `{ code }` error body) when\n * it is in the table, else null. The one way every app reads a refusal's reason.\n */\n reasonOf(error: unknown): (keyof T & string) | null {\n if (typeof error !== \"object\" || error === null || !(\"code\" in error)) return null;\n return isReason(error.code) ? error.code : null;\n },\n };\n}\n\nconst v1Guards = reasonGuards(REASONS);\nexport const isErrorReason: (code: unknown) => code is ErrorReason = v1Guards.isReason;\n/**\n * The reason of an API error: the `code` of an oRPC error (or any `{ code }` error body) when it\n * is one of REASONS, else null. The one way every app reads a refusal's reason.\n */\nexport const reasonOf: (error: unknown) => ErrorReason | null = v1Guards.reasonOf;\n",
17
- "// Stored templates, and what rendering one takes and answers.\nimport * as z from \"zod\";\nimport {\n MAX_TEMPLATE_BODY_LENGTH,\n MAX_TEMPLATE_DESCRIPTION_LENGTH,\n MAX_TEMPLATE_NAME_LENGTH,\n MAX_TEMPLATE_PREVIEW_TEXT_LENGTH,\n MAX_TEMPLATE_SUBJECT_LENGTH,\n} from \"../limits.ts\";\nimport { ExternalRef, Id, named, Page, Paged, Timestamp, trimmed } from \"../primitives.ts\";\n\n/** handlebars: written as Handlebars (API, board, EmailEngine import). react-email: compiled from\n * a react-email component and uploaded by `workwae templates push`; the next push overwrites it.\n * Both render the same way. */\nexport const TemplateSource = named(\"TemplateSource\", z.enum([\"handlebars\", \"react-email\"]));\nexport type TemplateSource = z.infer<typeof TemplateSource>;\n\n/** What the html field holds. markdown: Markdown, converted to HTML after Handlebars renders it;\n * `{{...}}` values are escaped for HTML and Markdown first, so params add text, never markup. Raw\n * HTML the author writes in the Markdown stays, as do `{{{...}}}` values. Without text, the plain\n * text part is the rendered Markdown without the author's tags, its values as given. */\nexport const TemplateFormat = named(\"TemplateFormat\", z.enum([\"html\", \"markdown\"]));\nexport type TemplateFormat = z.infer<typeof TemplateFormat>;\n\n/** The content fields Handlebars compiles and renders, which a template error names. */\nexport const TemplateField = named(\n \"TemplateField\",\n z.enum([\"subject\", \"html\", \"text\", \"previewText\"]),\n);\nexport type TemplateField = z.infer<typeof TemplateField>;\n\n/** The rendered fields of a template, as Handlebars source. subject and text render without HTML\n * escaping; html and previewText escape `{{...}}` and leave `{{{...}}}` raw. */\nexport const TemplateFields = named(\n \"TemplateFields\",\n z.object({\n subject: z.string().max(MAX_TEMPLATE_SUBJECT_LENGTH).nullable(),\n /** HTML, or Markdown when format is markdown. */\n html: z.string().max(MAX_TEMPLATE_BODY_LENGTH).nullable(),\n text: z.string().max(MAX_TEMPLATE_BODY_LENGTH).nullable(),\n /** The inbox preview line, injected at the top of the HTML body as a hidden block. */\n previewText: z.string().max(MAX_TEMPLATE_PREVIEW_TEXT_LENGTH).nullable(),\n format: TemplateFormat,\n }),\n);\nexport type TemplateFields = z.infer<typeof TemplateFields>;\n\nexport const TemplateSummary = named(\n \"TemplateSummary\",\n z.object({\n id: Id,\n /** The one account that may use it; null: every account of the tenant. */\n accountId: Id.nullable(),\n name: z.string(),\n description: z.string().nullable(),\n source: TemplateSource,\n externalRef: z.string().nullable(),\n createdAt: Timestamp,\n updatedAt: Timestamp,\n }),\n);\nexport type TemplateSummary = z.infer<typeof TemplateSummary>;\n\nexport const Template = named(\"Template\", TemplateSummary.extend(TemplateFields.shape));\nexport type Template = z.infer<typeof Template>;\n\nexport const TemplateSummaryPage = Page(TemplateSummary);\nexport type TemplateSummaryPage = z.infer<typeof TemplateSummaryPage>;\n\n/** Values for `{{params.*}}`; `{{account.email}}` and `{{account.name}}` are the sending account's.\n * A send naming a listId also gets `{{rcpt.unsubscribeUrl}}`, `{{rcpt.address}}` and\n * `{{rcpt.name}}` (empty strings otherwise). At most MAX_RENDER_PARAMS_BYTES as JSON. */\nexport const RenderParams = named(\"RenderParams\", z.record(z.string(), z.unknown()));\nexport type RenderParams = z.infer<typeof RenderParams>;\n\nexport const RenderedTemplate = named(\n \"RenderedTemplate\",\n z.object({\n subject: z.string().nullable(),\n /** With the preview text block injected, as it would be sent. */\n html: z.string().nullable(),\n text: z.string().nullable(),\n previewText: z.string().nullable(),\n }),\n);\nexport type RenderedTemplate = z.infer<typeof RenderedTemplate>;\n\nexport const TemplateIdInput = named(\"TemplateIdInput\", z.object({ templateId: Id }));\nexport type TemplateIdInput = z.infer<typeof TemplateIdInput>;\n\nconst TemplateName = trimmed(MAX_TEMPLATE_NAME_LENGTH);\nconst TemplateDescription = z.string().max(MAX_TEMPLATE_DESCRIPTION_LENGTH);\n\nexport const ListTemplatesQuery = named(\n \"ListTemplatesQuery\",\n z.object({\n ...Paged,\n accountId: Id.optional(),\n usableBy: Id.optional(),\n name: z.string().max(MAX_TEMPLATE_NAME_LENGTH).optional(),\n query: z.string().trim().max(MAX_TEMPLATE_NAME_LENGTH).optional(),\n }),\n);\nexport type ListTemplatesQuery = z.infer<typeof ListTemplatesQuery>;\n\nexport const CreateTemplate = named(\n \"CreateTemplate\",\n z.object({\n /** Bind it to one account, which alone may use it; omitted: every account. */\n accountId: Id.optional(),\n name: TemplateName,\n description: TemplateDescription.optional(),\n subject: TemplateFields.shape.subject.unwrap().optional(),\n html: TemplateFields.shape.html.unwrap().optional(),\n text: TemplateFields.shape.text.unwrap().optional(),\n previewText: TemplateFields.shape.previewText.unwrap().optional(),\n format: TemplateFormat.default(\"html\"),\n source: TemplateSource.default(\"handlebars\"),\n externalRef: ExternalRef.optional(),\n }),\n);\nexport type CreateTemplate = z.infer<typeof CreateTemplate>;\n\nexport const UpdateTemplate = named(\n \"UpdateTemplate\",\n z.object({\n name: TemplateName.optional(),\n description: TemplateDescription.nullable().optional(),\n subject: TemplateFields.shape.subject.optional(),\n html: TemplateFields.shape.html.optional(),\n text: TemplateFields.shape.text.optional(),\n previewText: TemplateFields.shape.previewText.optional(),\n format: TemplateFormat.optional(),\n source: TemplateSource.optional(),\n externalRef: ExternalRef.nullable().optional(),\n }),\n);\nexport type UpdateTemplate = z.infer<typeof UpdateTemplate>;\n\n/** A stored template (templateId) or inline fields, not both: a template replaces them all. */\nexport const RenderTemplateRequest = named(\n \"RenderTemplateRequest\",\n z\n .object({\n templateId: Id.optional(),\n accountId: Id.optional(),\n subject: z.string().max(MAX_TEMPLATE_SUBJECT_LENGTH).optional(),\n html: z.string().max(MAX_TEMPLATE_BODY_LENGTH).optional(),\n text: z.string().max(MAX_TEMPLATE_BODY_LENGTH).optional(),\n previewText: z.string().max(MAX_TEMPLATE_PREVIEW_TEXT_LENGTH).optional(),\n /** What the inline html holds; a stored template's own format applies to it. */\n format: TemplateFormat.optional(),\n params: RenderParams.default({}),\n })\n .superRefine((request, ctx) => {\n const { templateId, subject, html, text, previewText, format } = request;\n if (templateId === undefined) return;\n if ([subject, html, text, previewText, format].some((field) => field !== undefined))\n ctx.addIssue({\n code: \"custom\",\n path: [\"templateId\"],\n message: \"Render either a template or inline fields, not both\",\n params: { reason: \"template_and_inline_fields\" },\n });\n }),\n);\nexport type RenderTemplateRequest = z.infer<typeof RenderTemplateRequest>;\n",
18
- "// Every event type, its `data` and its scope, in one registry (EVENTS); the type list, the change\n// feed's and the webhook body's envelope (Event) and the samples are all derived from it.\nimport * as z from \"zod\";\nimport { AccountProvider, MicrosoftCloud } from \"../accounts/models.ts\";\nimport {\n Calendar,\n CalendarChangedField,\n CalendarEvent,\n CalendarEventChangedField,\n EventKind,\n} from \"../calendar/models.ts\";\nimport { Contact, ContactChangedField } from \"../contacts/models.ts\";\nimport {\n Mailbox,\n MailboxChangedField,\n MessageChangedField,\n MessageClassification,\n MessageSummary,\n} from \"../mail/models.ts\";\nimport { MeetingService } from \"../meetings/models.ts\";\nimport { Cursor, EventId, Id, Limit, named, ProviderId, Timestamp } from \"../primitives.ts\";\nimport { TrackingEvent } from \"../send/models.ts\";\nimport { SuppressionSource } from \"../suppressions/models.ts\";\n\n// Data of each event. An event's own account is the envelope's accountId and is not repeated here.\n\nexport const AccountConnectedData = named(\n \"AccountConnectedData\",\n z.object({\n email: z.string(),\n provider: AccountProvider,\n cloud: MicrosoftCloud.nullable(),\n externalRef: z.string().nullable(),\n /** An existing account took the new sign-in rather than a new account being made. */\n reauthorized: z.boolean(),\n }),\n);\nexport type AccountConnectedData = z.infer<typeof AccountConnectedData>;\n\n/** imap and dav: the account's IMAP or DAV connection settings; credentials: its password. */\nexport const AccountUpdatedField = named(\n \"AccountUpdatedField\",\n z.enum([\"status\", \"externalRef\", \"settings\", \"imap\", \"dav\", \"credentials\"]),\n);\nexport type AccountUpdatedField = z.infer<typeof AccountUpdatedField>;\n\nexport const AccountUpdatedData = named(\n \"AccountUpdatedData\",\n z.object({ fields: z.array(AccountUpdatedField) }),\n);\nexport type AccountUpdatedData = z.infer<typeof AccountUpdatedData>;\n\nexport const AccountDeletedData = named(\n \"AccountDeletedData\",\n z.object({\n email: z.string(),\n externalRef: z.string().nullable(),\n /** The deletion asked for an immediate purge rather than the retention period. */\n purge: z.boolean(),\n }),\n);\nexport type AccountDeletedData = z.infer<typeof AccountDeletedData>;\n\nexport const AccountReauthRequiredData = named(\n \"AccountReauthRequiredData\",\n AccountConnectedData.omit({ reauthorized: true }).extend({\n /** The provider's refusal, e.g. invalid_grant. */\n reason: z.string(),\n }),\n);\nexport type AccountReauthRequiredData = z.infer<typeof AccountReauthRequiredData>;\n\nexport const AccountInitializedData = named(\n \"AccountInitializedData\",\n z.object({ mailboxes: z.number().int(), messages: z.number().int() }),\n);\nexport type AccountInitializedData = z.infer<typeof AccountInitializedData>;\n\nexport const AccountPurgedData = named(\n \"AccountPurgedData\",\n z.object({\n /** The purged account: the event itself names none, since it outlives the account. */\n accountId: Id,\n externalRef: z.string().nullable(),\n }),\n);\nexport type AccountPurgedData = z.infer<typeof AccountPurgedData>;\n\nexport const MailboxData = named(\"MailboxData\", z.object({ mailbox: Mailbox }));\nexport type MailboxData = z.infer<typeof MailboxData>;\n\nexport const MailboxUpdatedData = named(\n \"MailboxUpdatedData\",\n MailboxData.extend({ changes: z.array(MailboxChangedField) }),\n);\nexport type MailboxUpdatedData = z.infer<typeof MailboxUpdatedData>;\n\n/** A mailbox a message is in, as events name it: roles tell inbound mail from sent and drafts. */\nexport const MailboxRef = named(\"MailboxRef\", Mailbox.pick({ id: true, name: true, role: true }));\nexport type MailboxRef = z.infer<typeof MailboxRef>;\n\nexport const MessageData = named(\n \"MessageData\",\n z.object({ message: MessageSummary, mailboxes: z.array(MailboxRef) }),\n);\nexport type MessageData = z.infer<typeof MessageData>;\n\nexport const MessageUpdatedData = named(\n \"MessageUpdatedData\",\n MessageData.extend({ changes: z.array(MessageChangedField) }),\n);\nexport type MessageUpdatedData = z.infer<typeof MessageUpdatedData>;\n\nexport const MessageDeletedData = named(\n \"MessageDeletedData\",\n MessageData.extend({\n messageId: Id,\n providerMessageId: ProviderId,\n }),\n);\nexport type MessageDeletedData = z.infer<typeof MessageDeletedData>;\n\nexport const MessageClassifiedData = named(\n \"MessageClassifiedData\",\n MessageData.extend({ classification: MessageClassification }),\n);\nexport type MessageClassifiedData = z.infer<typeof MessageClassifiedData>;\n\nexport const BounceRecipient = named(\n \"BounceRecipient\",\n z.object({\n address: z.string(),\n /** RFC 3463 enhanced status code (e.g. 5.1.1), when the notice carries one. */\n status: z.string().nullable(),\n /** What the rejecting server said. */\n diagnostic: z.string().nullable(),\n }),\n);\nexport type BounceRecipient = z.infer<typeof BounceRecipient>;\n\nexport const MessageBouncedData = named(\n \"MessageBouncedData\",\n z.object({\n /** The notice itself, as indexed. */\n messageId: Id,\n /** The outbox entry the notice answers, when it answers one of our sends. */\n outboxId: Id.nullable(),\n reference: z.string().nullable(),\n /** The Message-ID of the bounced message, when the notice names it. */\n originalMessageId: z.string().nullable(),\n recipients: z.array(BounceRecipient),\n }),\n);\nexport type MessageBouncedData = z.infer<typeof MessageBouncedData>;\n\nexport const TrackingHitData = named(\n \"TrackingHitData\",\n TrackingEvent.omit({ id: true, kind: true, linkIndex: true, ip: true, headers: true }).extend({\n outboxId: Id,\n reference: z.string().nullable(),\n /** The account's sent copy, once its sync has indexed and linked it; null until then. */\n messageId: Id.nullable(),\n }),\n);\nexport type TrackingHitData = z.infer<typeof TrackingHitData>;\n\nexport const SendError = named(\"SendError\", z.object({ code: z.string(), message: z.string() }));\nexport type SendError = z.infer<typeof SendError>;\n\nconst SendFields = {\n /** The outbox entry. */\n outboxId: Id,\n reference: z.string().nullable(),\n};\n\nexport const SendSentData = named(\n \"SendSentData\",\n z.object({\n ...SendFields,\n attempt: z.number().int(),\n /** The provider's id for the sent message; null where it gives none. */\n providerMessageId: ProviderId.nullable(),\n internetMessageId: z.string().nullable(),\n sentAt: Timestamp,\n }),\n);\nexport type SendSentData = z.infer<typeof SendSentData>;\n\nexport const SendRetryingData = named(\n \"SendRetryingData\",\n z.object({\n ...SendFields,\n attempt: z.number().int(),\n nextAttemptAt: Timestamp,\n error: SendError,\n }),\n);\nexport type SendRetryingData = z.infer<typeof SendRetryingData>;\n\nexport const SendFailedData = named(\n \"SendFailedData\",\n z.object({ ...SendFields, attempt: z.number().int(), error: SendError }),\n);\nexport type SendFailedData = z.infer<typeof SendFailedData>;\n\nexport const SendRescheduledData = named(\n \"SendRescheduledData\",\n z.object({ ...SendFields, sendAt: Timestamp, previousSendAt: Timestamp }),\n);\nexport type SendRescheduledData = z.infer<typeof SendRescheduledData>;\n\nexport const SuppressionCreatedData = named(\n \"SuppressionCreatedData\",\n z.object({ listId: z.string(), address: z.string(), source: SuppressionSource }),\n);\nexport type SuppressionCreatedData = z.infer<typeof SuppressionCreatedData>;\n\nexport const CalendarInitializedData = named(\n \"CalendarInitializedData\",\n z.object({ calendars: z.number().int(), events: z.number().int() }),\n);\nexport type CalendarInitializedData = z.infer<typeof CalendarInitializedData>;\n\nexport const CalendarData = named(\"CalendarData\", z.object({ calendar: Calendar }));\nexport type CalendarData = z.infer<typeof CalendarData>;\n\nexport const CalendarUpdatedData = named(\n \"CalendarUpdatedData\",\n CalendarData.extend({ changes: z.array(CalendarChangedField) }),\n);\nexport type CalendarUpdatedData = z.infer<typeof CalendarUpdatedData>;\n\nexport const CalendarEventData = named(\"CalendarEventData\", z.object({ event: CalendarEvent }));\nexport type CalendarEventData = z.infer<typeof CalendarEventData>;\n\nexport const CalendarEventUpdatedData = named(\n \"CalendarEventUpdatedData\",\n CalendarEventData.extend({ changes: z.array(CalendarEventChangedField) }),\n);\nexport type CalendarEventUpdatedData = z.infer<typeof CalendarEventUpdatedData>;\n\nexport const CalendarEventDeletedData = named(\n \"CalendarEventDeletedData\",\n z.object({ eventId: Id, calendarId: Id, kind: EventKind, seriesId: Id.nullable() }),\n);\nexport type CalendarEventDeletedData = z.infer<typeof CalendarEventDeletedData>;\n\nexport const ContactsInitializedData = named(\n \"ContactsInitializedData\",\n z.object({ contacts: z.number().int() }),\n);\nexport type ContactsInitializedData = z.infer<typeof ContactsInitializedData>;\n\nexport const ContactData = named(\"ContactData\", z.object({ contact: Contact }));\nexport type ContactData = z.infer<typeof ContactData>;\n\nexport const ContactUpdatedData = named(\n \"ContactUpdatedData\",\n ContactData.extend({ changes: z.array(ContactChangedField) }),\n);\nexport type ContactUpdatedData = z.infer<typeof ContactUpdatedData>;\n\nexport const ContactDeletedData = named(\n \"ContactDeletedData\",\n z.object({ contactId: Id, folderId: Id.nullable() }),\n);\nexport type ContactDeletedData = z.infer<typeof ContactDeletedData>;\n\nexport const WebhookTestData = named(\"WebhookTestData\", z.object({ endpointId: Id }));\nexport type WebhookTestData = z.infer<typeof WebhookTestData>;\n\nexport const ExportCompletedData = named(\n \"ExportCompletedData\",\n z.object({\n exportId: Id,\n bytes: z.number().int(),\n /** sha256 hex of the .tar.gz, to check a download. */\n sha256: z.string(),\n /** The download is available until then. */\n expiresAt: Timestamp,\n }),\n);\nexport type ExportCompletedData = z.infer<typeof ExportCompletedData>;\n\nexport const ExportFailedData = named(\n \"ExportFailedData\",\n z.object({ exportId: Id, error: z.string() }),\n);\nexport type ExportFailedData = z.infer<typeof ExportFailedData>;\n\nexport const MeetingConnectionConnectedData = named(\n \"MeetingConnectionConnectedData\",\n z.object({\n service: MeetingService,\n /** The service user the grant acts as. */\n email: z.string(),\n /** The account had a connection to the service already. */\n reconnected: z.boolean(),\n }),\n);\nexport type MeetingConnectionConnectedData = z.infer<typeof MeetingConnectionConnectedData>;\n\nexport const MeetingConnectionReauthRequiredData = named(\n \"MeetingConnectionReauthRequiredData\",\n MeetingConnectionConnectedData.omit({ reconnected: true }).extend({\n /** The service's refusal, e.g. invalid_grant. */\n reason: z.string(),\n }),\n);\nexport type MeetingConnectionReauthRequiredData = z.infer<\n typeof MeetingConnectionReauthRequiredData\n>;\n\n/**\n * Which accounts an event's envelope names. account: always the account it concerns; tenant:\n * never (accountId is null); either: an account, or null for the whole tenant.\n */\nexport type EventScope = \"account\" | \"tenant\" | \"either\";\n\nfunction defineEvent<const S extends EventScope, const D extends z.ZodObject>(\n scope: S,\n data: D,\n description: string,\n) {\n return { scope, data, description };\n}\n\n/** Every event type: its scope, its `data` and what it announces. */\nexport const EVENTS = {\n \"account.connected\": defineEvent(\n \"account\",\n AccountConnectedData,\n \"An account was connected, or an existing account signed in again (reauthorized).\",\n ),\n \"account.updated\": defineEvent(\n \"account\",\n AccountUpdatedData,\n \"An account's status, externalRef, settings or connection changed.\",\n ),\n \"account.deleted\": defineEvent(\n \"account\",\n AccountDeletedData,\n \"An account was deleted; its data is purged after the retention period, or at once with purge.\",\n ),\n \"account.reauth_required\": defineEvent(\n \"account\",\n AccountReauthRequiredData,\n \"The provider refused the account's grant: the account must sign in again.\",\n ),\n \"account.initialized\": defineEvent(\n \"account\",\n AccountInitializedData,\n \"The account's first mail sync finished; nothing before it is announced message by message.\",\n ),\n \"account.purged\": defineEvent(\n \"tenant\",\n AccountPurgedData,\n \"A deleted account's data is gone for good (retention, or an immediate purge). The event names no account, since it outlives the account it reports on.\",\n ),\n \"mailbox.created\": defineEvent(\"account\", MailboxData, \"A mailbox (folder or label) appeared.\"),\n \"mailbox.updated\": defineEvent(\n \"account\",\n MailboxUpdatedData,\n \"A mailbox was renamed, moved or given another role. Counts change silently.\",\n ),\n \"mailbox.deleted\": defineEvent(\"account\", MailboxData, \"A mailbox went away.\"),\n \"message.created\": defineEvent(\n \"account\",\n MessageData,\n \"A message was indexed: received, sent, drafted or moved in from outside the sync window.\",\n ),\n \"message.updated\": defineEvent(\n \"account\",\n MessageUpdatedData,\n \"A message changed: read, flagged, moved, or linked to the outbox entry it is a copy of.\",\n ),\n \"message.deleted\": defineEvent(\n \"account\",\n MessageDeletedData,\n \"A message was removed; carries it and its mailboxes as last indexed.\",\n ),\n \"message.bounced\": defineEvent(\n \"account\",\n MessageBouncedData,\n \"A delivery status notification reporting failed recipients reached the account; carries the outbox id when it answers one of our sends.\",\n ),\n \"message.classified\": defineEvent(\n \"account\",\n MessageClassifiedData,\n \"AI classified a reply to one of our sends (tenant setting aiReplyClassification): carries the message, its mailboxes and the classification.\",\n ),\n \"message.opened\": defineEvent(\n \"account\",\n TrackingHitData,\n \"A recipient's client (or a proxy fetching for it) loaded the open-tracking pixel of a send. Carries the actor, its reasons and the derived signals (client, device, location, referer host, sec-fetch tuple, timing); the raw headers are only on the tracking list.\",\n ),\n \"message.clicked\": defineEvent(\n \"account\",\n TrackingHitData,\n \"A tracked link of a send was followed; carries the same as message.opened.\",\n ),\n \"send.sent\": defineEvent(\"account\", SendSentData, \"The provider accepted a queued send.\"),\n \"send.retrying\": defineEvent(\n \"account\",\n SendRetryingData,\n \"An attempt failed and the send is queued again for nextAttemptAt.\",\n ),\n \"send.failed\": defineEvent(\n \"account\",\n SendFailedData,\n \"The send failed for good: refused, or out of attempts.\",\n ),\n \"send.rescheduled\": defineEvent(\n \"account\",\n SendRescheduledData,\n \"A queued send got a new sendAt before its first attempt.\",\n ),\n \"suppression.created\": defineEvent(\n \"account\",\n SuppressionCreatedData,\n \"An address went onto a suppression list: the recipient unsubscribed (source unsubscribe, listId the send's), a permanent bounce said the address is gone (source bounce, listId global), or a detected opt-out was suppressed, at once or on approval (source reply or complaint, listId the send's or global; source inactive, on approval only, listId global). Only a change is announced; API adds are audited instead. The account is the one whose send it concerns.\",\n ),\n \"calendar.initialized\": defineEvent(\n \"account\",\n CalendarInitializedData,\n \"The account's first calendar sync finished; nothing before it is announced event by event.\",\n ),\n \"calendar.created\": defineEvent(\"account\", CalendarData, \"A calendar appeared.\"),\n \"calendar.updated\": defineEvent(\"account\", CalendarUpdatedData, \"A calendar changed.\"),\n \"calendar.deleted\": defineEvent(\"account\", CalendarData, \"A calendar went away.\"),\n \"calendar_event.created\": defineEvent(\n \"account\",\n CalendarEventData,\n \"A single event, series or exception appeared. Unmodified occurrences of a series are never announced; an occurrence changed on its own is announced as a new exception.\",\n ),\n \"calendar_event.updated\": defineEvent(\n \"account\",\n CalendarEventUpdatedData,\n \"A single event, series or exception changed; a change to a series is one update of the series.\",\n ),\n \"calendar_event.deleted\": defineEvent(\n \"account\",\n CalendarEventDeletedData,\n \"A single event, series or exception went away.\",\n ),\n \"contacts.initialized\": defineEvent(\n \"account\",\n ContactsInitializedData,\n \"The account's first contacts sync finished; nothing before it is announced contact by contact.\",\n ),\n \"contact.created\": defineEvent(\"account\", ContactData, \"A contact appeared.\"),\n \"contact.updated\": defineEvent(\"account\", ContactUpdatedData, \"A contact changed.\"),\n \"contact.deleted\": defineEvent(\"account\", ContactDeletedData, \"A contact went away.\"),\n \"export.completed\": defineEvent(\n \"either\",\n ExportCompletedData,\n \"A data export finished and can be downloaded until data.expiresAt. accountId is null for an export of the whole tenant.\",\n ),\n \"export.failed\": defineEvent(\n \"either\",\n ExportFailedData,\n \"A data export failed. accountId is null for an export of the whole tenant.\",\n ),\n \"meeting_connection.connected\": defineEvent(\n \"account\",\n MeetingConnectionConnectedData,\n \"An account connected (or reconnected) its own grant at a meeting service (Zoom, Webex).\",\n ),\n \"meeting_connection.reauth_required\": defineEvent(\n \"account\",\n MeetingConnectionReauthRequiredData,\n \"The service refused the account's meeting grant; meetings need a new connect. Mail and calendar sync go on.\",\n ),\n \"webhook.test\": defineEvent(\n \"tenant\",\n WebhookTestData,\n \"Sent by the test action to the endpoint it names, whatever that endpoint's filters.\",\n ),\n};\n\nexport type EventType = keyof typeof EVENTS;\ntype EventDefinition<T extends EventType> = (typeof EVENTS)[T];\n\n/** Every event type, in the registry's order. */\nexport const EVENT_TYPES = Object.keys(EVENTS) as EventType[];\nexport const EventType = named(\"EventType\", z.enum(EVENT_TYPES));\n\n/** The type the test action sends when it is given none. */\nexport const TEST_EVENT_TYPE = \"webhook.test\" satisfies EventType;\n\n/** The `data` of an event of type T. */\nexport type EventData<T extends EventType = EventType> = {\n [K in T]: z.infer<EventDefinition<K>[\"data\"]>;\n}[T];\n/** What an emitter passes as the `data` of an event of type T. */\nexport type EventDataInput<T extends EventType = EventType> = {\n [K in T]: z.input<EventDefinition<K>[\"data\"]>;\n}[T];\n\n/** The envelope accountId of an event of type T. */\nexport type EventAccountId<T extends EventType> = {\n account: string;\n tenant: null;\n either: string | null;\n}[EventDefinition<T>[\"scope\"]];\n\n/** Whether `type` is announced without an account (the envelope's accountId is always null). */\nexport function isAccountlessEventType(type: EventType): boolean {\n return EVENTS[type].scope === \"tenant\";\n}\n\n/** `data` checked against the schema of `type`; throws a ZodError when it does not match. */\nexport function parseEventData<T extends EventType>(type: T, data: unknown): EventData<T> {\n return EVENTS[type].data.parse(data) as EventData<T>;\n}\n\nconst ENVELOPE_ACCOUNT_ID = { account: Id, tenant: z.null(), either: Id.nullable() } as const;\n\n/** The envelope schema of events of type T. */\nexport type EventEnvelope<T extends EventType> = z.ZodObject<{\n id: typeof EventId;\n type: z.ZodLiteral<T>;\n accountId: (typeof ENVELOPE_ACCOUNT_ID)[EventDefinition<T>[\"scope\"]];\n createdAt: typeof Timestamp;\n data: EventDefinition<T>[\"data\"];\n isTest: z.ZodExactOptional<z.ZodLiteral<true>>;\n}>;\n\nfunction envelope<T extends EventType>(type: T): EventEnvelope<T> {\n const { scope, data, description }: EventDefinition<T> = EVENTS[type];\n // account.connected -> AccountConnectedEvent, calendar_event.created -> CalendarEventCreatedEvent\n const name = type.replace(/(?:^|[._])([a-z])/g, (_, letter: string) => letter.toUpperCase());\n return named(\n `${name}Event`,\n z\n .object({\n /** Stable event id: the webhook-id header and the dedupe key. Replays keep it. */\n id: EventId,\n type: z.literal(type),\n // TypeScript does not narrow the lookup by T's scope.\n accountId: ENVELOPE_ACCOUNT_ID[scope] as EventEnvelope<T>[\"shape\"][\"accountId\"],\n createdAt: Timestamp,\n data,\n /** Present, and true, on a delivery sent by the test action only; never in the change\n * feed. An envelope marker: absent rather than false. */\n isTest: z.literal(true).exactOptional(),\n })\n .meta({ description }),\n );\n}\n\ntype EventVariant = { [T in EventType]: EventEnvelope<T> }[EventType];\n\n/**\n * One event: an item of the change feed, and the JSON body POSTed to webhook endpoints. `type`\n * says what `data` holds.\n */\nexport const Event = named(\n \"Event\",\n // The variants are built from the registry; the tuple type is what z.discriminatedUnion wants.\n z.discriminatedUnion(\"type\", EVENT_TYPES.map(envelope) as [EventVariant, ...EventVariant[]]),\n);\nexport type Event = z.infer<typeof Event>;\n/** An event of one type. */\nexport type EventOf<T extends EventType> = Extract<Event, { type: T }>;\n\nexport const ListChangesQuery = named(\n \"ListChangesQuery\",\n z.object({\n cursor: Cursor.optional(),\n limit: Limit,\n /** Event types to return: a list, or one comma-separated string. Omitted: every type. */\n types: z\n .union([z.string(), z.array(EventType)])\n .transform((v) => (Array.isArray(v) ? v : v.split(\",\")))\n .pipe(z.array(EventType))\n .optional(),\n }),\n);\nexport type ListChangesQuery = z.infer<typeof ListChangesQuery>;\n\n/**\n * A page of the change feed: pass nextCursor back to continue; an empty page means caught up. The\n * feed has no end, only a present, so nextCursor is never null: keep polling from it.\n */\nexport const EventFeedPage = named(\n \"EventFeedPage\",\n z.object({ items: z.array(Event), nextCursor: Cursor }),\n);\nexport type EventFeedPage = z.infer<typeof EventFeedPage>;\n",
19
- "import * as z from \"zod\";\nimport {\n DEFAULT_SEARCH_PAGE_SIZE,\n MAX_MAILBOX_CHANGES,\n MAX_SEARCH_PAGE_SIZE,\n MAX_SEARCH_QUERY_LENGTH,\n} from \"../limits.ts\";\nimport {\n AccountIdInput,\n Address,\n Cursor,\n DateOnly,\n Id,\n List,\n named,\n Page,\n Paged,\n ProviderId,\n pageFields,\n pageLimit,\n QueryBoolean,\n QueryTimestamp,\n Timestamp,\n trimmed,\n} from \"../primitives.ts\";\n\nexport const MailboxRole = named(\n \"MailboxRole\",\n z.enum([\"inbox\", \"sent\", \"drafts\", \"trash\", \"junk\", \"archive\", \"all\", \"important\", \"custom\"]),\n);\nexport type MailboxRole = z.infer<typeof MailboxRole>;\n\n/** folder: a message is in exactly one (Microsoft). label: a message can carry several (Gmail). */\nexport const MailboxKind = named(\"MailboxKind\", z.enum([\"folder\", \"label\"]));\nexport type MailboxKind = z.infer<typeof MailboxKind>;\n\nexport const Mailbox = named(\n \"Mailbox\",\n z.object({\n id: Id,\n name: z.string(),\n /** \"/\"-separated from the top level. */\n path: z.string(),\n parentId: Id.nullable(),\n role: MailboxRole,\n kind: MailboxKind,\n totalCount: z.number().int().nullable(),\n unreadCount: z.number().int().nullable(),\n }),\n);\nexport type Mailbox = z.infer<typeof Mailbox>;\n\nexport const MailboxList = List(Mailbox);\nexport type MailboxList = z.infer<typeof MailboxList>;\n\n/** The Mailbox fields mailbox.updated names in `changes` (the counts move without an event). */\nexport const MailboxChangedField = named(\n \"MailboxChangedField\",\n z.enum([\"name\", \"path\", \"parentId\", \"role\", \"kind\"]),\n);\nexport type MailboxChangedField = z.infer<typeof MailboxChangedField>;\n\n/**\n * outbound: the message is in a mailbox with role `sent`, or its From is the account's own address\n * or one of its identities (so drafts are outbound too). inbound: everything else.\n */\nexport const MessageDirection = named(\"MessageDirection\", z.enum([\"inbound\", \"outbound\"]));\nexport type MessageDirection = z.infer<typeof MessageDirection>;\n\n/**\n * The priority mail clients mark with \"!\" (high) or a down arrow (low). Sent as\n * X-Priority, X-MSMail-Priority, Importance and Priority headers; read from Graph's `importance`\n * and from those headers on Gmail and IMAP.\n */\nexport const MessagePriority = named(\"MessagePriority\", z.enum([\"high\", \"normal\", \"low\"]));\nexport type MessagePriority = z.infer<typeof MessagePriority>;\n\nexport const MessageSummary = named(\n \"MessageSummary\",\n z.object({\n id: Id,\n threadId: ProviderId.nullable(),\n /** RFC 5322 Message-ID. */\n internetMessageId: z.string().nullable(),\n mailboxIds: z.array(Id),\n subject: z.string().nullable(),\n from: Address.nullable(),\n to: z.array(Address),\n cc: z.array(Address),\n snippet: z.string().nullable(),\n receivedAt: Timestamp.nullable(),\n sentAt: Timestamp.nullable(),\n isRead: z.boolean(),\n isFlagged: z.boolean(),\n isDraft: z.boolean(),\n hasAttachments: z.boolean(),\n /** Microsoft categories; Gmail inbox tabs (personal, social, promotions, updates, forums). */\n categories: z.array(z.string()),\n direction: MessageDirection,\n /** The outbox entry this message is a copy of, when it was sent through the API (the sent copy,\n * and the received copy of a message sent to the account itself); null otherwise. Kept after the\n * entry itself is deleted by outbox retention. */\n outboxId: Id.nullable(),\n /** The `reference` the entry was queued with, kept with the link. */\n reference: z.string().nullable(),\n /** The message's priority (MessagePriority). Null for a message indexed before workwae read\n * priorities, until the provider reports the message again. Gmail and IMAP read normal for a\n * message carrying no priority header. */\n importance: MessagePriority.nullable(),\n }),\n);\nexport type MessageSummary = z.infer<typeof MessageSummary>;\n\n/** The Message fields message.updated names in `changes`. `reference` changes only with\n * outboxId and is not named on its own. */\nexport const MessageChangedField = named(\n \"MessageChangedField\",\n z.enum([\n \"threadId\",\n \"internetMessageId\",\n \"subject\",\n \"from\",\n \"to\",\n \"cc\",\n \"bcc\",\n \"replyTo\",\n \"snippet\",\n \"receivedAt\",\n \"sentAt\",\n \"isRead\",\n \"isFlagged\",\n \"isDraft\",\n \"hasAttachments\",\n \"categories\",\n \"mailboxIds\",\n \"direction\",\n \"outboxId\",\n \"importance\",\n ]),\n);\nexport type MessageChangedField = z.infer<typeof MessageChangedField>;\n\nexport const MessageSummaryPage = Page(MessageSummary);\nexport type MessageSummaryPage = z.infer<typeof MessageSummaryPage>;\n\nexport const Attachment = named(\n \"Attachment\",\n z.object({\n id: ProviderId,\n filename: z.string().nullable(),\n contentType: z.string(),\n size: z.number().int().nullable(),\n isInline: z.boolean(),\n contentId: z.string().nullable(),\n }),\n);\nexport type Attachment = z.infer<typeof Attachment>;\n\n/** What AI made of a reply to one of your sends (see the tenant setting aiReplyClassification). */\nexport const ReplyKind = named(\n \"ReplyKind\",\n z.enum([\"opt_out\", \"auto_reply\", \"bounce\", \"human_reply\"]),\n);\nexport type ReplyKind = z.infer<typeof ReplyKind>;\n\n/** What kind of automatic answer an auto_reply is. out_of_office: away for a while;\n * left_company: the person no longer works there, or the mailbox is unmonitored; address_changed:\n * gives a new address to use; ticket_acknowledgment: an automated receipt or ticket number;\n * challenge_response: asks the sender to verify before the mail is delivered; other: any other\n * automatic answer. */\nexport const AutoReplyCategory = named(\n \"AutoReplyCategory\",\n z.enum([\n \"out_of_office\",\n \"left_company\",\n \"address_changed\",\n \"ticket_acknowledgment\",\n \"challenge_response\",\n \"other\",\n ]),\n);\nexport type AutoReplyCategory = z.infer<typeof AutoReplyCategory>;\n\nexport const MessageClassification = named(\n \"MessageClassification\",\n z.object({\n /** opt_out: asks to stop receiving email; auto_reply: an out-of-office or other automatic\n * answer; bounce: a delivery failure notice; human_reply: anything else a person wrote. */\n kind: ReplyKind,\n /** Each kind's probability, 0 to 1. */\n probabilities: z.record(z.string(), z.number()),\n /** Probability the message asks to stop receiving email, 0 to 1. At 0.9 or more the sender's\n * address is handled per the tenant's opt-out setting. */\n optOutProbability: z.number(),\n /** What kind of auto-reply it is; null unless kind is auto_reply. left_company and\n * address_changed queue the sender's address for review (source inactive) unless the tenant's\n * opt-out setting is off; they never suppress it at once. */\n autoReplyCategory: AutoReplyCategory.nullable(),\n /** An out_of_office reply's return date as the reply states it, resolved against the day it\n * was sent on the sender's calendar (its Date header's zone, else UTC); null when it names\n * none, or one before that day or over a year after. */\n returnDate: DateOnly.nullable(),\n /** Addresses a left_company or address_changed reply from the send's own recipient names in\n * its own text, other than the account's and the send's recipients', lowercased, in order of\n * appearance, at most 5; empty for every other reply. Read from the text as written, never\n * from the model. */\n alternateContacts: z.array(z.string()),\n /** The outbox entry the message answers. */\n outboxId: Id.nullable(),\n /** The model that classified it. */\n model: z.string(),\n classifiedAt: Timestamp,\n }),\n);\nexport type MessageClassification = z.infer<typeof MessageClassification>;\n\n/** Served from stored content when the account stores bodies (bodyStorage cache or full),\n * otherwise fetched from the provider on request; null parts are absent from the message. */\nexport const MessageBody = named(\n \"MessageBody\",\n z.object({ text: z.string().nullable(), html: z.string().nullable() }),\n);\nexport type MessageBody = z.infer<typeof MessageBody>;\n\nexport const Message = named(\n \"Message\",\n MessageSummary.extend({\n bcc: z.array(Address),\n replyTo: z.array(Address),\n body: MessageBody,\n attachments: z.array(Attachment),\n /** For a reply to one of your sends, what AI made of it (message.classified announces it);\n * null for every other message, and until the reply is classified. */\n classification: MessageClassification.nullable(),\n }),\n);\nexport type Message = z.infer<typeof Message>;\n\n/** Where a search looks: the index, the provider, or the index first (see messages.search). */\nexport const SearchSource = named(\"SearchSource\", z.enum([\"auto\", \"index\", \"provider\"]));\nexport type SearchSource = z.infer<typeof SearchSource>;\n/** Which source answered a search. */\nexport const SearchResultSource = named(\"SearchResultSource\", SearchSource.exclude([\"auto\"]));\nexport type SearchResultSource = z.infer<typeof SearchResultSource>;\n\n/** A search result. `id` is null for a provider result the index does not hold (a message older\n * than the sync window); such a result cannot be opened through the API. */\nexport const SearchHit = named(\"SearchHit\", MessageSummary.extend({ id: Id.nullable() }));\nexport type SearchHit = z.infer<typeof SearchHit>;\n\n/** A search page, with the source that answered; later pages (through nextCursor) stay with it. */\nexport const SearchPage = named(\n \"SearchPage\",\n z.object({ ...pageFields(SearchHit), source: SearchResultSource }),\n);\nexport type SearchPage = z.infer<typeof SearchPage>;\n\n/** Stored message content, for the whole tenant or one account. */\nexport const BodyStorageUsage = named(\n \"BodyStorageUsage\",\n z.object({\n /** Whether an object store is configured; without one only bodyStorage \"none\" is accepted. */\n available: z.boolean(),\n storedMessages: z.number().int(),\n storedBytes: z.number().int(),\n /** The part of storedBytes held by accounts in \"cache\" mode, evicted beyond the budget. */\n cachedBytes: z.number().int(),\n /** Per-tenant budget for cached content, in bytes. */\n cacheBudgetBytes: z.number().int(),\n /** Cached content not read for this many days is evicted. */\n cacheMaxAgeDays: z.number().int(),\n }),\n);\nexport type BodyStorageUsage = z.infer<typeof BodyStorageUsage>;\n\nexport const MessageIdInput = named(\"MessageIdInput\", AccountIdInput.extend({ messageId: Id }));\nexport type MessageIdInput = z.infer<typeof MessageIdInput>;\n\nexport const AttachmentIdInput = named(\n \"AttachmentIdInput\",\n MessageIdInput.extend({ attachmentId: ProviderId }),\n);\nexport type AttachmentIdInput = z.infer<typeof AttachmentIdInput>;\n\nexport const ListMessagesQuery = named(\n \"ListMessagesQuery\",\n z.object({\n mailboxId: Id.optional(),\n unread: QueryBoolean.optional(),\n importance: MessagePriority.optional(),\n ...Paged,\n }),\n);\nexport type ListMessagesQuery = z.infer<typeof ListMessagesQuery>;\n\nexport const SearchMessagesQuery = named(\n \"SearchMessagesQuery\",\n z.object({\n q: trimmed(MAX_SEARCH_QUERY_LENGTH),\n mailboxId: Id.optional(),\n /** Received at or after. */\n after: QueryTimestamp.optional(),\n /** Received before. */\n before: QueryTimestamp.optional(),\n source: SearchSource.default(\"auto\"),\n limit: pageLimit(MAX_SEARCH_PAGE_SIZE, DEFAULT_SEARCH_PAGE_SIZE),\n cursor: Cursor.optional(),\n }),\n);\nexport type SearchMessagesQuery = z.infer<typeof SearchMessagesQuery>;\n\nexport const UpdateMessage = named(\n \"UpdateMessage\",\n z.object({\n isRead: z.boolean().optional(),\n isFlagged: z.boolean().optional(),\n mailboxId: Id.optional(),\n addMailboxIds: z.array(Id).max(MAX_MAILBOX_CHANGES).optional(),\n removeMailboxIds: z.array(Id).max(MAX_MAILBOX_CHANGES).optional(),\n }),\n);\nexport type UpdateMessage = z.infer<typeof UpdateMessage>;\n\nexport const DeleteMessageQuery = named(\n \"DeleteMessageQuery\",\n z.object({\n /** Delete outright instead of moving to Trash. */\n permanent: QueryBoolean.default(false),\n }),\n);\nexport type DeleteMessageQuery = z.infer<typeof DeleteMessageQuery>;\n\n/** The path's message and the query's options, as a DELETE takes them. */\nexport const DeleteMessageInput = named(\n \"DeleteMessageInput\",\n z.object({ params: MessageIdInput, query: DeleteMessageQuery }),\n);\nexport type DeleteMessageInput = z.infer<typeof DeleteMessageInput>;\n",
20
- "// Composing, sending and the outbox: drafts and sends, mail merges, and the opens and clicks of\n// tracked sends.\nimport * as z from \"zod\";\nimport {\n MAX_ATTACHMENTS,\n MAX_BODY_LENGTH,\n MAX_CONTENT_ID_LENGTH,\n MAX_CONTENT_TYPE_LENGTH,\n MAX_EMAIL_LENGTH,\n MAX_FILENAME_LENGTH,\n MAX_MAIL_MERGE_ENTRIES,\n MAX_MESSAGE_ID_LENGTH,\n MAX_RECIPIENTS,\n MAX_REPLY_TO,\n MAX_SEND_REFERENCE_LENGTH,\n MAX_SUBJECT_LENGTH,\n MAX_TEMPLATE_PREVIEW_TEXT_LENGTH,\n} from \"../limits.ts\";\nimport { MessagePriority } from \"../mail/models.ts\";\nimport {\n AccountIdInput,\n Address,\n AddressInput,\n Id,\n List,\n named,\n Page,\n Paged,\n ProviderId,\n QueryTimestamp,\n Timestamp,\n} from \"../primitives.ts\";\nimport { ListId } from \"../suppressions/models.ts\";\nimport { RenderParams, TemplateFormat } from \"../templates/models.ts\";\n\nexport const AttachmentInput = named(\n \"AttachmentInput\",\n z.object({\n filename: z.string().min(1).max(MAX_FILENAME_LENGTH),\n contentType: z.string().min(1).max(MAX_CONTENT_TYPE_LENGTH),\n /** Base64. */\n content: z.base64(),\n /** Set to reference the attachment inline from the HTML body (cid:...). */\n contentId: z.string().max(MAX_CONTENT_ID_LENGTH).optional(),\n }),\n);\nexport type AttachmentInput = z.infer<typeof AttachmentInput>;\n\nexport const Compose = named(\n \"Compose\",\n z.object({\n to: z.array(AddressInput).max(MAX_RECIPIENTS).default([]),\n cc: z.array(AddressInput).max(MAX_RECIPIENTS).default([]),\n bcc: z.array(AddressInput).max(MAX_RECIPIENTS).default([]),\n replyTo: z.array(AddressInput).max(MAX_REPLY_TO).default([]),\n subject: z.string().max(MAX_SUBJECT_LENGTH).optional(),\n text: z.string().max(MAX_BODY_LENGTH).optional(),\n html: z.string().max(MAX_BODY_LENGTH).optional(),\n attachments: z.array(AttachmentInput).max(MAX_ATTACHMENTS).default([]),\n /** Our message id being answered: sets In-Reply-To/References and keeps the thread. */\n inReplyToMessageId: Id.optional(),\n /** One of the account's identities (GET .../identities); omitted sends as the account itself.\n * The name defaults to the identity's. */\n from: AddressInput.optional(),\n /** Appends the sender identity's signature to the text and HTML bodies. Omitted follows the\n * account's signByDefault (mail settings) when sending or creating a draft; a draft update adds\n * one only when this is true. */\n signature: z.boolean().optional(),\n /** Writes the priority headers (see MessagePriority); normal writes none. A draft update\n * replaces the whole message, so it takes the priority given (normal when omitted). */\n priority: MessagePriority.default(\"normal\"),\n }),\n);\nexport type Compose = z.infer<typeof Compose>;\n\n/** What composing with templates adds to a draft or a send. */\nexport const ComposeWithTemplate = named(\n \"ComposeWithTemplate\",\n Compose.extend({\n /** A stored template (the tenant's, or one bound to this account). Its subject, html, text,\n * previewText and format are the message's: the inline ones cannot be given with it. */\n template: Id.optional(),\n /** Renders the inline subject, html, text and previewText (a template is always rendered). */\n render: z.object({ params: RenderParams.default({}) }).optional(),\n /** Inline preview line (Handlebars like html), injected at the top of the HTML body. */\n previewText: z.string().max(MAX_TEMPLATE_PREVIEW_TEXT_LENGTH).optional(),\n /** What the inline html holds (see TemplateFormat); markdown is converted to HTML whether or\n * not it is rendered. Default html. */\n format: TemplateFormat.optional(),\n }),\n);\nexport type ComposeWithTemplate = z.infer<typeof ComposeWithTemplate>;\n\nexport const OutboxStatus = named(\n \"OutboxStatus\",\n z.enum([\"queued\", \"sending\", \"sent\", \"failed\", \"cancelled\"]),\n);\nexport type OutboxStatus = z.infer<typeof OutboxStatus>;\n\nexport const OutboxEntry = named(\n \"OutboxEntry\",\n z.object({\n /** The outbox entry's id: outboxId in send.* events, mail merge results and messages. */\n id: Id,\n accountId: Id,\n status: OutboxStatus,\n reference: z.string().nullable(),\n sendAt: Timestamp,\n attempt: z.number().int(),\n lastError: z.string().nullable(),\n /** The provider's id for the sent message, when its send answer names one (Gmail). */\n providerMessageId: ProviderId.nullable(),\n /** RFC 5322 Message-ID the message goes out with; message.bounced events name it too. Some\n * providers replace it (consumer Gmail does on every send): once the account's sync indexes the\n * Sent copy, this becomes the Message-ID that copy carries, which is what recipients got. A\n * send.sent recorded before that carries the one workwae composed. */\n internetMessageId: z.string().nullable(),\n sentAt: Timestamp.nullable(),\n createdAt: Timestamp,\n /** Whether the entry tracks opens and clicks: its send's `tracking`, else the account's\n * trackOpens and trackClicks. Always false for a message without an HTML part, and for a\n * Gmail or Microsoft 365 draft-send. */\n trackOpens: z.boolean(),\n trackClicks: z.boolean(),\n /** Whether its HTML carries the honeypot link: its send's `tracking.honeypot`, else the\n * account's trackingHoneypot; only ever with trackClicks. */\n trackHoneypot: z.boolean(),\n /** Pixel loads and tracked link follows so far, split by classification: machine is a hit\n * classified proxy, prefetch or scanner; human is every other (human or unknown). */\n humanOpenCount: z.number().int(),\n machineOpenCount: z.number().int(),\n humanClickCount: z.number().int(),\n machineClickCount: z.number().int(),\n /** The first and the latest open not classified as a machine. */\n firstOpenedAt: Timestamp.nullable(),\n lastOpenedAt: Timestamp.nullable(),\n }),\n);\nexport type OutboxEntry = z.infer<typeof OutboxEntry>;\n\n/** What queueing a send answers: the entry, and until when cancelling it undoes the send. */\nexport const QueuedSend = named(\n \"QueuedSend\",\n OutboxEntry.extend({\n /** The entry's sendAt when that is in the future: until then DELETE .../outbox/{outboxId}\n * cancels it. Set whenever the account's undo window (undoSendSeconds) or a later sendAt\n * applies; null when the message goes out right away. */\n undoUntil: Timestamp.nullable(),\n }),\n);\nexport type QueuedSend = z.infer<typeof QueuedSend>;\n\n/** Per-send tracking; an omitted key follows the account's trackOpens / trackClicks /\n * trackingHoneypot. `honeypot` only comes with click tracking: true with clicks off is refused. */\nexport const SendTracking = named(\n \"SendTracking\",\n z.object({\n opens: z.boolean().optional(),\n clicks: z.boolean().optional(),\n honeypot: z.boolean().optional(),\n }),\n);\nexport type SendTracking = z.infer<typeof SendTracking>;\n\n/** How and when a send or draft-send goes out. */\nexport const SendOptions = named(\n \"SendOptions\",\n z.object({\n /** Scheduled send; omitted or past = as soon as possible. Never earlier than the account's\n * undo window (undoSendSeconds) from now. */\n sendAt: QueryTimestamp.optional(),\n /** Your identifier, echoed in send.* events. */\n reference: z.string().max(MAX_SEND_REFERENCE_LENGTH).optional(),\n /** Open and click tracking for this send; an omitted key follows the account's trackOpens,\n * trackClicks and trackingHoneypot. Only the HTML part is rewritten, and one MIME goes to\n * every recipient. */\n tracking: SendTracking.optional(),\n }),\n);\nexport type SendOptions = z.infer<typeof SendOptions>;\n\nconst ListOption = {\n /** A suppression list (a hostname label, not \"global\"; GET /v1/suppressions). The message gets\n * one-click unsubscribe for it and is not sent to an address on it or on the global list. */\n listId: ListId.optional(),\n};\n\n/** One recipient of a mail merge. Checked one by one, so a bad entry fails alone (see\n * MailMergeResult); `to.address` and `messageId` are therefore not refused by the schema. */\nexport const MailMergeEntry = named(\n \"MailMergeEntry\",\n z.object({\n to: AddressInput.extend({ address: z.string().max(MAX_EMAIL_LENGTH) }),\n /** Renders this copy's subject, html, text and previewText; an entry without params sends\n * inline content as it is (a template is always rendered). */\n params: RenderParams.optional(),\n /** RFC 5322 Message-ID for this copy (`<local@domain>`) instead of a generated one. */\n messageId: z.string().max(MAX_MESSAGE_ID_LENGTH).optional(),\n /** Overrides the call's sendAt for this copy. */\n sendAt: QueryTimestamp.optional(),\n }),\n);\nexport type MailMergeEntry = z.infer<typeof MailMergeEntry>;\n\nexport const SendMessageRequest = named(\n \"SendMessageRequest\",\n ComposeWithTemplate.extend(SendOptions.shape).extend(ListOption),\n);\nexport type SendMessageRequest = z.infer<typeof SendMessageRequest>;\n\n/** The send body without to, cc, bcc and render: an unknown field is refused. */\nexport const MailMergeRequest = named(\n \"MailMergeRequest\",\n ComposeWithTemplate.omit({ to: true, cc: true, bcc: true, render: true })\n .extend(SendOptions.shape)\n .extend({\n ...ListOption,\n /** One message per entry, each addressed to its `to` alone (see MailMergeEntry). */\n entries: z.array(MailMergeEntry).min(1).max(MAX_MAIL_MERGE_ENTRIES),\n })\n .strict(),\n);\nexport type MailMergeRequest = z.infer<typeof MailMergeRequest>;\n\nexport const MailMergeSuccess = named(\n \"MailMergeSuccess\",\n z.object({\n success: z.literal(true),\n to: Address,\n /** The outbox entry (GET .../outbox/{outboxId}); send.* events carry it. */\n outboxId: Id,\n messageId: z.string(),\n sendAt: Timestamp,\n /** As on a single send: until then cancelling the entry undoes it; null when it goes out now. */\n undoUntil: Timestamp.nullable(),\n }),\n);\nexport type MailMergeSuccess = z.infer<typeof MailMergeSuccess>;\n\nexport const MailMergeFailure = named(\n \"MailMergeFailure\",\n z.object({\n success: z.literal(false),\n to: Address,\n /** Why this entry was not queued: invalid_recipient, invalid_message_id, duplicate_message_id,\n * params_too_large, template_render_failed, plan_limit_sends, suppressed, internal_error, or a\n * compose reason. */\n reason: z.string(),\n error: z.string(),\n /** The HTTP status the same failure answers on a single send. */\n status: z.number().int(),\n }),\n);\nexport type MailMergeFailure = z.infer<typeof MailMergeFailure>;\n\nexport const MailMergeResult = named(\n \"MailMergeResult\",\n z.discriminatedUnion(\"success\", [MailMergeSuccess, MailMergeFailure]),\n);\nexport type MailMergeResult = z.infer<typeof MailMergeResult>;\n\n/** What a mail merge answers: one result per entry, in the order given. */\nexport const MailMergeResultList = List(MailMergeResult);\nexport type MailMergeResultList = z.infer<typeof MailMergeResultList>;\n\nexport const OutboxIdInput = named(\"OutboxIdInput\", AccountIdInput.extend({ outboxId: Id }));\nexport type OutboxIdInput = z.infer<typeof OutboxIdInput>;\n\nexport const OutboxEntryPage = Page(OutboxEntry);\nexport type OutboxEntryPage = z.infer<typeof OutboxEntryPage>;\n\nexport const ListOutboxQuery = named(\n \"ListOutboxQuery\",\n z.object({ status: OutboxStatus.optional(), ...Paged }),\n);\nexport type ListOutboxQuery = z.infer<typeof ListOutboxQuery>;\n\nexport const RescheduleSendRequest = named(\n \"RescheduleSendRequest\",\n z.object({ sendAt: QueryTimestamp }),\n);\nexport type RescheduleSendRequest = z.infer<typeof RescheduleSendRequest>;\n\nexport const ListTrackingEventsQuery = named(\"ListTrackingEventsQuery\", z.object(Paged));\nexport type ListTrackingEventsQuery = z.infer<typeof ListTrackingEventsQuery>;\n\n// Tracking.\n\nexport const TrackingEventKind = named(\"TrackingEventKind\", z.enum([\"open\", \"click\"]));\nexport type TrackingEventKind = z.infer<typeof TrackingEventKind>;\n\n/** Who is behind a hit. proxy: fetches for a person who opened the message (Gmail's image\n * proxy); prefetch: fetches whether or not anyone reads it (Apple Mail Privacy Protection);\n * scanner: a security gateway or bot; unknown: some signal against a person, not enough to say. */\nexport const TrackingActor = named(\n \"TrackingActor\",\n z.enum([\"human\", \"proxy\", \"prefetch\", \"scanner\", \"unknown\"]),\n);\nexport type TrackingActor = z.infer<typeof TrackingActor>;\n\n/** The mail client behind a hit, from its user agent, the Referer / Origin host it came from and\n * the fingerprint rules it matched. gmail_proxy: Gmail's image proxy (the reader's own device is\n * hidden); apple_mail_privacy: Apple Mail loading through Mail Privacy Protection's relay;\n * webmail: a self-hosted webmail (Roundcube, SOGo, Horde, a webmail.* host). */\nexport const TrackingClient = named(\n \"TrackingClient\",\n z.enum([\n \"gmail_proxy\",\n \"gmail_web\",\n \"gmail_app\",\n \"outlook_web\",\n \"outlook_desktop\",\n \"outlook_mobile\",\n \"apple_mail\",\n \"apple_mail_privacy\",\n \"yahoo\",\n \"aol\",\n \"thunderbird\",\n \"proton\",\n \"fastmail\",\n \"zoho\",\n \"icloud_web\",\n \"webmail\",\n \"unknown\",\n ]),\n);\nexport type TrackingClient = z.infer<typeof TrackingClient>;\nexport const TrackingDevice = named(\n \"TrackingDevice\",\n z.enum([\"desktop\", \"mobile\", \"tablet\", \"bot\", \"unknown\"]),\n);\nexport type TrackingDevice = z.infer<typeof TrackingDevice>;\nexport const TrackingOs = named(\n \"TrackingOs\",\n z.enum([\"windows\", \"macos\", \"ios\", \"ipados\", \"android\", \"linux\", \"chromeos\"]),\n);\nexport type TrackingOs = z.infer<typeof TrackingOs>;\nexport const TrackingBrowser = named(\n \"TrackingBrowser\",\n z.enum([\"chrome\", \"edge\", \"firefox\", \"safari\", \"opera\", \"samsung\"]),\n);\nexport type TrackingBrowser = z.infer<typeof TrackingBrowser>;\n\n/** Fetch metadata the browser sent (sec-fetch-*), lower-cased; null where absent. */\nexport const TrackingSecFetch = named(\n \"TrackingSecFetch\",\n z.object({\n /** image for a rendered pixel, document for a link followed. */\n dest: z.string().nullable(),\n mode: z.string().nullable(),\n /** cross-site, same-site, same-origin or none (typed or opened from outside a page). */\n site: z.string().nullable(),\n /** true: a navigation the user started (sec-fetch-user ?1). */\n user: z.boolean().nullable(),\n }),\n);\nexport type TrackingSecFetch = z.infer<typeof TrackingSecFetch>;\n\n/** What a hit's request showed, derived when it was recorded; carried by the list API and by\n * message.opened / message.clicked. */\nexport const TrackingSignals = named(\n \"TrackingSignals\",\n z.object({\n /** GET or HEAD. */\n method: z.string(),\n /** The host of the Referer (the full value is only in the event's headers) and of the Origin;\n * android-app:// referrers give the app's package name. */\n refererHost: z.string().nullable(),\n originHost: z.string().nullable(),\n client: TrackingClient,\n device: TrackingDevice,\n os: TrackingOs.nullable(),\n browser: TrackingBrowser.nullable(),\n /** Cloudflare's visitor location (behind a trusted proxy only): country always, the rest with\n * the zone's \"Add visitor location headers\" managed transform on. country is ISO 3166-1\n * alpha-2 (T1 for Tor), timezone an IANA zone. */\n country: z.string().nullable(),\n region: z.string().nullable(),\n city: z.string().nullable(),\n timezone: z.string().nullable(),\n latitude: z.number().nullable(),\n longitude: z.number().nullable(),\n /** Since the send; null when the send was not recorded yet. */\n secondsAfterSend: z.number().nullable(),\n /** Since the send's previous hit of either kind; null for the first. */\n secondsSincePrevious: z.number().nullable(),\n /** The hit's number among the send's opens and clicks, from 1. */\n sequence: z.number().int(),\n /** If-None-Match or If-Modified-Since: a cache revalidating its copy. */\n isConditional: z.boolean(),\n /** A Range request. */\n isRange: z.boolean(),\n /** A prefetch or preview purpose header (Sec-Purpose, Purpose). */\n isPrefetch: z.boolean(),\n secFetch: TrackingSecFetch,\n }),\n);\nexport type TrackingSignals = z.infer<typeof TrackingSignals>;\n\n/** One pixel load or link follow of a tracked send. */\nexport const TrackingEvent = named(\n \"TrackingEvent\",\n z.object({\n id: Id,\n kind: TrackingEventKind,\n /** Clicks: the link's position among the message's distinct tracked links, from 0; null for\n * the honeypot link. */\n linkIndex: z.number().int().nullable(),\n /** Clicks: where the link led; null for the honeypot link. */\n url: z.string().nullable(),\n occurredAt: Timestamp,\n userAgent: z.string().nullable(),\n ip: z.string().nullable(),\n actor: TrackingActor,\n /** Stable codes for what decided the actor: ua_google_image_proxy, cidr_apple_mpp,\n * seconds_after_send, burst_clicks, honeypot, referer_webmail, sec_fetch_user,\n * img_cross_site, conditional_request, range_request, head_request, accept_generic,\n * no_accept_language, origin_script, fingerprint_label, ... */\n reasons: z.array(z.string()),\n /** actor is proxy, prefetch or scanner. */\n isMachine: z.boolean(),\n ...TrackingSignals.shape,\n /** The request headers, lower-cased name to value: each value cut at 1024 characters, at\n * most 64, never Cookie, Authorization or Proxy-Authorization, and the forwarding and cf-*\n * headers only when they came through the API's trusted proxy. */\n headers: z.record(z.string(), z.string()),\n }),\n);\nexport type TrackingEvent = z.infer<typeof TrackingEvent>;\n\nexport const TrackingEventPage = Page(TrackingEvent);\nexport type TrackingEventPage = z.infer<typeof TrackingEventPage>;\n",
21
- "// Tenant suppression lists: addresses a send naming a list must not go to. \"global\" is the list\n// every such send consults (permanent bounces land there); any other id is a named list, consulted\n// only by sends that name it. A named list is created by POST /v1/suppressions, or by the first\n// send or add naming it.\nimport * as z from \"zod\";\nimport {\n MAX_EMAIL_LENGTH,\n MAX_SUPPRESSION_BATCH,\n MAX_SUPPRESSION_LIST_DESCRIPTION_LENGTH,\n MAX_SUPPRESSION_REASON_LENGTH,\n} from \"../limits.ts\";\nimport {\n Email,\n Id,\n List,\n Name,\n named,\n Page,\n Paged,\n QueryBoolean,\n Timestamp,\n trimmed,\n} from \"../primitives.ts\";\n\n/** The list every send that names a list consults. Not a name a send can give. */\nexport const GLOBAL_LIST_ID = \"global\";\n/** The built-in global list's name; it cannot be renamed. */\nexport const GLOBAL_LIST_NAME = \"Everyone (global)\";\n/** A hostname label, as EmailEngine's listId: letters, digits and inner hyphens, 1 to 63. */\nexport const LIST_ID_PATTERN = /^[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?$/;\n\n/** A list id as the suppression routes take it: a named list or \"global\". Case-insensitive. */\nexport const SuppressionListId = z.string().trim().toLowerCase().regex(LIST_ID_PATTERN);\n/** A list a send names: a hostname label other than \"global\". */\nexport const ListId = SuppressionListId.refine((id) => id !== GLOBAL_LIST_ID, {\n message: `\"${GLOBAL_LIST_ID}\" is reserved`,\n});\n\nconst Reason = trimmed(MAX_SUPPRESSION_REASON_LENGTH);\nconst ListName = Name.trim().min(1);\nconst ListDescription = z.string().trim().max(MAX_SUPPRESSION_LIST_DESCRIPTION_LENGTH);\n\n/** unsubscribe: the recipient's one-click POST or the confirm page; bounce: a permanent bounce\n * saying the address is gone; api: POST /v1/suppressions/{listId}/entries; reply: a reply asking to opt\n * out; complaint: an abuse report (ARF) from the recipient's provider; inactive: an auto-reply\n * saying the person is no longer at this address. reply, complaint and inactive are detected, and\n * land per the tenant's optOutHandling. */\nexport const SuppressionSource = named(\n \"SuppressionSource\",\n z.enum([\"unsubscribe\", \"bounce\", \"api\", \"reply\", \"complaint\", \"inactive\"]),\n);\nexport type SuppressionSource = z.infer<typeof SuppressionSource>;\n\n/** Opt-outs detected in mail rather than stated by a link: see optOutHandling. inactive (an\n * auto-reply saying the person left or moved to another address) always waits for review. */\nexport const DetectedOptOutSource = named(\n \"DetectedOptOutSource\",\n SuppressionSource.extract([\"reply\", \"complaint\", \"inactive\"]),\n);\nexport type DetectedOptOutSource = z.infer<typeof DetectedOptOutSource>;\n\nexport const SuppressionEntry = named(\n \"SuppressionEntry\",\n z.object({\n /** Trimmed and lowercased; matching is on this form. */\n address: z.string(),\n source: SuppressionSource,\n /** The bounce's status code, or the reason given to the API. */\n reason: z.string().nullable(),\n createdAt: Timestamp,\n }),\n);\nexport type SuppressionEntry = z.infer<typeof SuppressionEntry>;\n\nexport const SuppressionEntryPage = Page(SuppressionEntry);\nexport type SuppressionEntryPage = z.infer<typeof SuppressionEntryPage>;\n\n/** Addresses on a list by source. */\nexport const SuppressionCounts = named(\n \"SuppressionCounts\",\n z.object({\n unsubscribe: z.number().int(),\n bounce: z.number().int(),\n api: z.number().int(),\n reply: z.number().int(),\n complaint: z.number().int(),\n inactive: z.number().int(),\n }),\n);\nexport type SuppressionCounts = z.infer<typeof SuppressionCounts>;\n\nexport const SuppressionList = named(\n \"SuppressionList\",\n z.object({\n /** What sends name as listId; \"global\" for the global list. Fixed once created. */\n id: z.string(),\n name: z.string(),\n description: z.string().nullable(),\n /** Addresses on the list. */\n count: z.number().int(),\n /** count by source. */\n counts: SuppressionCounts,\n /** null for the global list, which every tenant has. */\n createdAt: Timestamp.nullable(),\n }),\n);\nexport type SuppressionList = z.infer<typeof SuppressionList>;\n\nexport const SuppressionListList = List(SuppressionList);\nexport type SuppressionListList = z.infer<typeof SuppressionListList>;\n\n/** A detected opt-out waiting for a person (optOutHandling \"review\"). */\nexport const SuppressionReview = named(\n \"SuppressionReview\",\n z.object({\n id: Id,\n /** The list approving adds the address to: the send's, or global. */\n listId: z.string(),\n address: z.string(),\n source: DetectedOptOutSource,\n /** The account and message the opt-out was detected in. */\n accountId: Id,\n messageId: Id,\n /** How sure the detection was, 0 to 1. */\n probability: z.number(),\n /** For inactive, the addresses the auto-reply names to write to instead; empty otherwise. */\n alternateContacts: z.array(z.string()),\n createdAt: Timestamp,\n }),\n);\nexport type SuppressionReview = z.infer<typeof SuppressionReview>;\n\nexport const SuppressionReviewPage = Page(SuppressionReview);\nexport type SuppressionReviewPage = z.infer<typeof SuppressionReviewPage>;\n\nexport const ListIdInput = named(\"ListIdInput\", z.object({ listId: ListId }));\nexport type ListIdInput = z.infer<typeof ListIdInput>;\nexport const SuppressionListIdInput = named(\n \"SuppressionListIdInput\",\n z.object({ listId: SuppressionListId }),\n);\nexport type SuppressionListIdInput = z.infer<typeof SuppressionListIdInput>;\nexport const ReviewIdInput = named(\"ReviewIdInput\", z.object({ reviewId: Id }));\nexport type ReviewIdInput = z.infer<typeof ReviewIdInput>;\n\nexport const CreateSuppressionList = named(\n \"CreateSuppressionList\",\n z.object({\n id: ListId,\n name: ListName,\n description: ListDescription.nullable().optional(),\n }),\n);\nexport type CreateSuppressionList = z.infer<typeof CreateSuppressionList>;\n\nexport const UpdateSuppressionList = named(\n \"UpdateSuppressionList\",\n z.object({\n name: ListName.optional(),\n description: ListDescription.nullable().optional(),\n }),\n);\nexport type UpdateSuppressionList = z.infer<typeof UpdateSuppressionList>;\n\nexport const DeleteSuppressionListQuery = named(\n \"DeleteSuppressionListQuery\",\n z.object({ withEntries: QueryBoolean.default(false) }),\n);\nexport type DeleteSuppressionListQuery = z.infer<typeof DeleteSuppressionListQuery>;\n\n/** The path's list and the query's options, as a DELETE takes them. */\nexport const DeleteSuppressionListInput = named(\n \"DeleteSuppressionListInput\",\n z.object({ params: ListIdInput, query: DeleteSuppressionListQuery }),\n);\nexport type DeleteSuppressionListInput = z.infer<typeof DeleteSuppressionListInput>;\n\nexport const ListSuppressionEntriesQuery = named(\n \"ListSuppressionEntriesQuery\",\n z.object({\n address: z.string().trim().max(MAX_EMAIL_LENGTH).optional(),\n source: SuppressionSource.optional(),\n ...Paged,\n }),\n);\nexport type ListSuppressionEntriesQuery = z.infer<typeof ListSuppressionEntriesQuery>;\n\n/** Addresses to put on a list; a repeated address counts once. */\nexport const AddSuppressionEntriesRequest = named(\n \"AddSuppressionEntriesRequest\",\n z.object({\n addresses: z.array(Email).min(1).max(MAX_SUPPRESSION_BATCH),\n reason: Reason.optional(),\n }),\n);\nexport type AddSuppressionEntriesRequest = z.infer<typeof AddSuppressionEntriesRequest>;\n\n/** An entry of a list, by its address. Any stored address can be released, including one an\n * older rule let in. */\nexport const SuppressionEntryInput = named(\n \"SuppressionEntryInput\",\n SuppressionListIdInput.extend({ address: trimmed(MAX_EMAIL_LENGTH) }),\n);\nexport type SuppressionEntryInput = z.infer<typeof SuppressionEntryInput>;\n\nexport const ListSuppressionReviewsQuery = named(\n \"ListSuppressionReviewsQuery\",\n z.object({ listId: SuppressionListId.optional(), ...Paged }),\n);\nexport type ListSuppressionReviewsQuery = z.infer<typeof ListSuppressionReviewsQuery>;\n\n/** added: false when the address was on the list already, which is left as it was. */\nexport const SuppressionAdded = named(\"SuppressionAdded\", z.object({ added: z.boolean() }));\nexport type SuppressionAdded = z.infer<typeof SuppressionAdded>;\n\n/** added: addresses put on the list; alreadyListed: those on it already, left as they were. */\nexport const SuppressionEntriesAdded = named(\n \"SuppressionEntriesAdded\",\n z.object({ added: z.number().int(), alreadyListed: z.number().int() }),\n);\nexport type SuppressionEntriesAdded = z.infer<typeof SuppressionEntriesAdded>;\n",
22
- "import * as z from \"zod\";\nimport { Id, named, Page, Paged, Timestamp } from \"../primitives.ts\";\n\nexport const ExportStatus = named(\n \"ExportStatus\",\n z.enum([\"queued\", \"running\", \"completed\", \"failed\", \"expired\"]),\n);\nexport type ExportStatus = z.infer<typeof ExportStatus>;\n\nexport const DataExport = named(\n \"DataExport\",\n z.object({\n id: Id,\n /** Null: the whole tenant. */\n accountId: Id.nullable(),\n /** The account's email; null for a tenant export or once the account is deleted. */\n accountEmail: z.string().nullable(),\n status: ExportStatus,\n /** Size of the .tar.gz; 0 until completed. */\n bytes: z.number().int(),\n /** sha256 hex of the .tar.gz, to check a download. */\n sha256: z.string().nullable(),\n /** Files in the archive per section. */\n contents: z.record(z.string(), z.number().int()),\n error: z.string().nullable(),\n createdAt: Timestamp,\n startedAt: Timestamp.nullable(),\n completedAt: Timestamp.nullable(),\n /** When the file is deleted; set once completed. */\n expiresAt: Timestamp.nullable(),\n }),\n);\nexport type DataExport = z.infer<typeof DataExport>;\n\nexport const DataExportPage = Page(DataExport);\nexport type DataExportPage = z.infer<typeof DataExportPage>;\n\nexport const CreateDataExport = named(\n \"CreateDataExport\",\n z.object({\n /** Omitted: the whole tenant. */\n accountId: Id.optional(),\n }),\n);\nexport type CreateDataExport = z.infer<typeof CreateDataExport>;\n\nexport const ListDataExportsQuery = named(\"ListDataExportsQuery\", z.object(Paged));\nexport type ListDataExportsQuery = z.infer<typeof ListDataExportsQuery>;\n\nexport const DataExportIdInput = named(\"DataExportIdInput\", z.object({ exportId: Id }));\nexport type DataExportIdInput = z.infer<typeof DataExportIdInput>;\n",
23
- "import * as z from \"zod\";\nimport {\n MAX_ADDRESS_NAME_LENGTH,\n MAX_SIGNATURE_HTML_LENGTH,\n MAX_SIGNATURE_TEXT_LENGTH,\n} from \"../limits.ts\";\nimport {\n AccountIdInput,\n Address,\n AddressInput,\n Id,\n listFields,\n named,\n QueryBoolean,\n Timestamp,\n} from \"../primitives.ts\";\n\n/** primary: the account's own address. provider: reported by the provider (Gmail send-as\n * addresses, Microsoft proxy addresses). custom: added through the API (IMAP aliases, Microsoft\n * mailboxes the account may send as). */\nexport const IdentitySource = named(\"IdentitySource\", z.enum([\"primary\", \"provider\", \"custom\"]));\nexport type IdentitySource = z.infer<typeof IdentitySource>;\n\n/** At least one part is set; a missing part is derived from the other when it is applied. */\nexport const Signature = named(\n \"Signature\",\n z.object({ html: z.string().nullable(), text: z.string().nullable() }),\n);\nexport type Signature = z.infer<typeof Signature>;\n\nexport const SignatureInput = named(\n \"SignatureInput\",\n z\n .object({\n html: z.string().max(MAX_SIGNATURE_HTML_LENGTH).optional(),\n text: z.string().max(MAX_SIGNATURE_TEXT_LENGTH).optional(),\n })\n .refine((s) => s.html !== undefined || s.text !== undefined, {\n message: \"A signature needs html or text\",\n }),\n);\nexport type SignatureInput = z.infer<typeof SignatureInput>;\n\nexport const Identity = named(\n \"Identity\",\n Address.extend({\n id: Id,\n source: IdentitySource,\n /** Ours; applied on send and draft creation (see Compose.signature). */\n signature: Signature.nullable(),\n /** Gmail's own signature for the address, read with the send-as list; applied when no\n * signature of ours is set. Always null for other providers. */\n providerSignature: Signature.nullable(),\n }),\n);\nexport type Identity = z.infer<typeof Identity>;\n\n/** The account's identities, with when the provider's were last read (null before the first read). */\nexport const IdentityList = named(\n \"IdentityList\",\n z.object({ ...listFields(Identity), refreshedAt: Timestamp.nullable() }),\n);\nexport type IdentityList = z.infer<typeof IdentityList>;\n\nexport const MailSettings = named(\n \"MailSettings\",\n z.object({\n /** Sends and new drafts carry the sender identity's signature unless Compose.signature is\n * false. */\n signByDefault: z.boolean(),\n }),\n);\nexport type MailSettings = z.infer<typeof MailSettings>;\n\nexport const UpdateMailSettings = named(\"UpdateMailSettings\", MailSettings.partial());\nexport type UpdateMailSettings = z.infer<typeof UpdateMailSettings>;\n\nexport const IdentityIdInput = named(\"IdentityIdInput\", AccountIdInput.extend({ identityId: Id }));\nexport type IdentityIdInput = z.infer<typeof IdentityIdInput>;\n\nexport const ListIdentitiesQuery = named(\n \"ListIdentitiesQuery\",\n z.object({ refresh: QueryBoolean.optional() }),\n);\nexport type ListIdentitiesQuery = z.infer<typeof ListIdentitiesQuery>;\n\nexport const CreateIdentity = named(\n \"CreateIdentity\",\n AddressInput.extend({ signature: SignatureInput.optional() }),\n);\nexport type CreateIdentity = z.infer<typeof CreateIdentity>;\n\nexport const UpdateIdentity = named(\n \"UpdateIdentity\",\n z.object({\n name: z.string().max(MAX_ADDRESS_NAME_LENGTH).nullable().optional(),\n signature: SignatureInput.nullable().optional(),\n }),\n);\nexport type UpdateIdentity = z.infer<typeof UpdateIdentity>;\n",
24
- "import * as z from \"zod\";\nimport { MicrosoftCloud, OAuthProvider } from \"../accounts/models.ts\";\nimport { Id, List, Name, named, Timestamp } from \"../primitives.ts\";\n\n/** A Pub/Sub topic id as users.watch takes it: projects/<project id>/topics/<topic>. */\nexport const PUBSUB_TOPIC_PATTERN =\n /^projects\\/[a-z][a-z0-9.:-]{4,61}[a-z0-9]\\/topics\\/(?!goog)[A-Za-z][A-Za-z0-9._~+%-]{2,254}$/;\n\n/**\n * Gmail push for the accounts of a tenant Google app: users.watch publishes to `topic`, which\n * must be in the Cloud project of the app's OAuth client, and the tenant's push subscription\n * delivers to the app's gmailPushEndpoint with OIDC tokens issued for `serviceAccount`.\n */\nexport const GmailPushSettings = named(\n \"GmailPushSettings\",\n z.object({\n topic: z.string().regex(PUBSUB_TOPIC_PATTERN, \"Expected projects/<project>/topics/<topic>\"),\n serviceAccount: z\n .email()\n .regex(/\\.gserviceaccount\\.com$/i, \"Expected a Google service account email\"),\n }),\n);\nexport type GmailPushSettings = z.infer<typeof GmailPushSettings>;\n\nexport const OAuthApp = named(\n \"OAuthApp\",\n z.object({\n id: Id,\n provider: OAuthProvider,\n name: z.string(),\n clientId: z.string(),\n /** Microsoft apps only. */\n cloud: MicrosoftCloud.nullable(),\n authority: z.string().nullable(),\n /** Google apps only; null while the app's accounts are polled. */\n gmailPush: GmailPushSettings.nullable(),\n /** Google apps when the instance has PUSH_BASE_URL: the push subscription's endpoint, which is\n * also the audience its OIDC tokens must carry. Null otherwise. */\n gmailPushEndpoint: z.url().nullable(),\n createdAt: Timestamp,\n }),\n);\nexport type OAuthApp = z.infer<typeof OAuthApp>;\n\nexport const OAuthAppList = List(OAuthApp);\nexport type OAuthAppList = z.infer<typeof OAuthAppList>;\n\nexport const CreateOAuthApp = named(\n \"CreateOAuthApp\",\n z.object({\n provider: OAuthProvider,\n /** Required for Microsoft apps: each cloud needs its own app registration. */\n cloud: MicrosoftCloud.optional(),\n name: Name,\n clientId: z.string().min(1),\n clientSecret: z.string().min(1),\n /** Microsoft only: directory (tenant) id or \"common\". */\n authority: z.string().optional(),\n }),\n);\nexport type CreateOAuthApp = z.infer<typeof CreateOAuthApp>;\n\nexport const UpdateOAuthApp = named(\n \"UpdateOAuthApp\",\n z.object({\n name: Name.optional(),\n clientSecret: z.string().min(1).optional(),\n /** Microsoft only: directory (tenant) id or \"common\". */\n authority: z.string().min(1).optional(),\n /** Google only: where users.watch publishes and who signs the pushes; null removes it. */\n gmailPush: GmailPushSettings.nullable().optional(),\n }),\n);\nexport type UpdateOAuthApp = z.infer<typeof UpdateOAuthApp>;\n\nexport const OAuthAppIdInput = named(\"OAuthAppIdInput\", z.object({ appId: Id }));\nexport type OAuthAppIdInput = z.infer<typeof OAuthAppIdInput>;\n",
25
- "// Organization-wide access: Google Workspace domain-wide delegation and Microsoft app-only\n// connections, the accounts added through them without a user sign-in, their directory, and\n// shared mailboxes opened with a user's delegated grant.\nimport * as z from \"zod\";\nimport { MicrosoftCloud } from \"../accounts/models.ts\";\nimport { RedirectState } from \"../connect/models.ts\";\nimport {\n DEFAULT_DIRECTORY_PAGE_SIZE,\n MAX_ADD_MAILBOXES,\n MAX_DIRECTORY_PAGE_SIZE,\n MAX_DIRECTORY_QUERY_LENGTH,\n MAX_DISPLAY_NAME_LENGTH,\n MAX_ENTRA_ID_LENGTH,\n MAX_HOST_LENGTH,\n MAX_KEY_FILE_LENGTH,\n MAX_SECRET_LENGTH,\n} from \"../limits.ts\";\nimport {\n Cursor,\n Email,\n ExternalRef,\n Id,\n List,\n Name,\n named,\n Page,\n ProviderId,\n pageLimit,\n Timestamp,\n} from \"../primitives.ts\";\nimport { SettingsOverride } from \"../settings/models.ts\";\n\nexport const OrgConnectionKind = named(\n \"OrgConnectionKind\",\n z.enum([\"google_delegation\", \"microsoft_app\"]),\n);\nexport type OrgConnectionKind = z.infer<typeof OrgConnectionKind>;\n\n/** pending_consent: no Microsoft directory has consented yet. unverified: registered or changed\n * and not tested since. active / failing: the outcome of the last test or consent. */\nexport const OrgConnectionStatus = named(\n \"OrgConnectionStatus\",\n z.enum([\"pending_consent\", \"unverified\", \"active\", \"failing\"]),\n);\nexport type OrgConnectionStatus = z.infer<typeof OrgConnectionStatus>;\n\n/** platform: the platform's Entra app for the cloud, authorized through admin consent.\n * client_secret / certificate: the tenant's own app registration. */\nexport const MicrosoftAppCredential = named(\n \"MicrosoftAppCredential\",\n z.enum([\"platform\", \"client_secret\", \"certificate\"]),\n);\nexport type MicrosoftAppCredential = z.infer<typeof MicrosoftAppCredential>;\n\nexport const GoogleDelegation = named(\n \"GoogleDelegation\",\n z.object({\n domain: z.string(),\n serviceAccountEmail: z.string(),\n /** The admin impersonated to list the directory; null: no directory listing. */\n directoryAdmin: z.string().nullable(),\n /** The OAuth scopes to authorize for clientId, in the Admin console's order. */\n scopes: z.array(z.string()),\n }),\n);\nexport type GoogleDelegation = z.infer<typeof GoogleDelegation>;\n\nexport const GraphPermission = named(\n \"GraphPermission\",\n z.object({ name: z.string(), isRequired: z.boolean() }),\n);\nexport type GraphPermission = z.infer<typeof GraphPermission>;\n\nexport const MicrosoftAppAccess = named(\n \"MicrosoftAppAccess\",\n z.object({\n cloud: MicrosoftCloud,\n credentialType: MicrosoftAppCredential,\n /** The consented Entra directory (tenant) id; null until admin consent. */\n directoryId: z.string().nullable(),\n /** Graph application permissions to grant: the required ones, then those for calendar,\n * mailbox settings, contacts and the directory. */\n permissions: z.array(GraphPermission),\n }),\n);\nexport type MicrosoftAppAccess = z.infer<typeof MicrosoftAppAccess>;\n\nexport const OrgConnection = named(\n \"OrgConnection\",\n z.object({\n id: Id,\n kind: OrgConnectionKind,\n name: z.string(),\n /** Google: the service account's client id, authorized in the Admin console under Security >\n * API controls > Domain-wide delegation. Microsoft: the Entra application id. */\n clientId: z.string(),\n status: OrgConnectionStatus,\n statusDetail: z.string().nullable(),\n checkedAt: Timestamp.nullable(),\n google: GoogleDelegation.nullable(),\n microsoft: MicrosoftAppAccess.nullable(),\n /** Live accounts authenticating through this connection. */\n accounts: z.number().int(),\n createdAt: Timestamp,\n updatedAt: Timestamp,\n }),\n);\nexport type OrgConnection = z.infer<typeof OrgConnection>;\n\nexport const OrgConnectionList = List(OrgConnection);\nexport type OrgConnectionList = z.infer<typeof OrgConnectionList>;\n\nconst Pem = z.string().min(1).max(MAX_KEY_FILE_LENGTH);\n/** The service account key file (JSON) as downloaded from Google Cloud. */\nconst ServiceAccountKey = z.string().min(2).max(MAX_KEY_FILE_LENGTH);\nconst EntraId = z.string().min(1).max(MAX_ENTRA_ID_LENGTH);\nconst ClientSecret = z.string().min(1).max(MAX_SECRET_LENGTH);\n\nexport const CreateOrgConnection = named(\n \"CreateOrgConnection\",\n z.discriminatedUnion(\"kind\", [\n z.object({\n kind: z.literal(\"google_delegation\"),\n name: Name,\n serviceAccountKey: ServiceAccountKey,\n /** The Workspace primary domain, which the directory is listed for. */\n domain: z.string().min(3).max(MAX_HOST_LENGTH),\n /** Also authorize Google Calendar (default true); without it calendar sync fails for these\n * accounts while mail keeps working. */\n calendarEnabled: z.boolean().default(true),\n /** Also authorize Google Contacts (default false); without it contacts sync fails for these\n * accounts while mail keeps working. */\n contactsEnabled: z.boolean().default(false),\n /** An admin of the Workspace to impersonate for listing the directory (adds the\n * admin.directory.user.readonly scope). Omit to add accounts by address only. */\n directoryAdmin: Email.optional(),\n }),\n z.object({\n kind: z.literal(\"microsoft_app\"),\n name: Name,\n cloud: MicrosoftCloud.default(\"global\"),\n credential: z.discriminatedUnion(\"type\", [\n z.object({ type: z.literal(\"platform\") }),\n z.object({\n type: z.literal(\"client_secret\"),\n clientId: EntraId,\n clientSecret: ClientSecret,\n }),\n z.object({\n type: z.literal(\"certificate\"),\n clientId: EntraId,\n /** The certificate uploaded to the app registration (PEM). */\n certificate: Pem,\n /** Its private key, PKCS#8 PEM (\"BEGIN PRIVATE KEY\"). */\n privateKey: Pem,\n }),\n ]),\n /** Tenant apps only: the directory (tenant) id of an app already consented there. Omit to\n * have admin consent name it (POST .../consent). A platform connection refuses it: its\n * directory is only ever the one an administrator signed in to while consenting. */\n directoryId: EntraId.optional(),\n }),\n ]),\n);\nexport type CreateOrgConnection = z.infer<typeof CreateOrgConnection>;\n\nexport const UpdateOrgConnection = named(\n \"UpdateOrgConnection\",\n z.object({\n name: Name.optional(),\n serviceAccountKey: ServiceAccountKey.optional(),\n calendarEnabled: z.boolean().optional(),\n contactsEnabled: z.boolean().optional(),\n directoryAdmin: Email.nullable().optional(),\n clientSecret: ClientSecret.optional(),\n certificate: Pem.optional(),\n privateKey: Pem.optional(),\n directoryId: EntraId.optional(),\n }),\n);\nexport type UpdateOrgConnection = z.infer<typeof UpdateOrgConnection>;\n\nexport const OrgConnectionCheck = named(\n \"OrgConnectionCheck\",\n z.object({\n name: z.string(),\n isOk: z.boolean(),\n /** A failed required check fails the test; optional ones only limit calendar, contacts or the\n * directory. */\n isRequired: z.boolean(),\n detail: z.string(),\n }),\n);\nexport type OrgConnectionCheck = z.infer<typeof OrgConnectionCheck>;\n\nexport const OrgConnectionTestResult = named(\n \"OrgConnectionTestResult\",\n z.object({ connection: OrgConnection, checks: z.array(OrgConnectionCheck) }),\n);\nexport type OrgConnectionTestResult = z.infer<typeof OrgConnectionTestResult>;\n\nexport const DirectoryEntry = named(\n \"DirectoryEntry\",\n z.object({\n /** Provider user id (Entra object id, Google user id). */\n id: ProviderId,\n email: z.string(),\n displayName: z.string().nullable(),\n /** The live account already added for this mailbox, if any. */\n accountId: Id.nullable(),\n }),\n);\nexport type DirectoryEntry = z.infer<typeof DirectoryEntry>;\n\nexport const DirectoryEntryPage = Page(DirectoryEntry);\nexport type DirectoryEntryPage = z.infer<typeof DirectoryEntryPage>;\n\nexport const AddMailboxInput = named(\n \"AddMailboxInput\",\n z.object({\n email: Email,\n displayName: z.string().max(MAX_DISPLAY_NAME_LENGTH).optional(),\n externalRef: ExternalRef.optional(),\n }),\n);\nexport type AddMailboxInput = z.infer<typeof AddMailboxInput>;\n\nexport const AddMailboxesRequest = named(\n \"AddMailboxesRequest\",\n z.object({\n mailboxes: z.array(AddMailboxInput).min(1).max(MAX_ADD_MAILBOXES),\n settings: SettingsOverride.optional(),\n }),\n);\nexport type AddMailboxesRequest = z.infer<typeof AddMailboxesRequest>;\n\n/** created: a new account. exists: a live account for the mailbox was already there.\n * failed: see error. */\nexport const AddedMailboxStatus = named(\n \"AddedMailboxStatus\",\n z.enum([\"created\", \"exists\", \"failed\"]),\n);\nexport type AddedMailboxStatus = z.infer<typeof AddedMailboxStatus>;\n\n/** Why one mailbox was not added: `reason` is the reason the API would refuse it with (REASONS). */\nexport const AddedMailboxError = named(\n \"AddedMailboxError\",\n z.object({ reason: z.string(), message: z.string() }),\n);\nexport type AddedMailboxError = z.infer<typeof AddedMailboxError>;\n\nexport const AddedMailbox = named(\n \"AddedMailbox\",\n z.object({\n email: z.string(),\n status: AddedMailboxStatus,\n accountId: Id.nullable(),\n error: AddedMailboxError.nullable(),\n }),\n);\nexport type AddedMailbox = z.infer<typeof AddedMailbox>;\n\n/** One result per requested mailbox, in request order. */\nexport const AddedMailboxList = List(AddedMailbox);\nexport type AddedMailboxList = z.infer<typeof AddedMailboxList>;\n\nexport const OrgConnectionIdInput = named(\"OrgConnectionIdInput\", z.object({ connectionId: Id }));\nexport type OrgConnectionIdInput = z.infer<typeof OrgConnectionIdInput>;\n\nexport const StartConsentRequest = named(\n \"StartConsentRequest\",\n z.object({ redirectUri: z.url(), state: RedirectState.optional() }),\n);\nexport type StartConsentRequest = z.infer<typeof StartConsentRequest>;\n\nexport const ConsentLink = named(\"ConsentLink\", z.object({ consentUrl: z.url() }));\nexport type ConsentLink = z.infer<typeof ConsentLink>;\n\nexport const TestOrgConnectionRequest = named(\n \"TestOrgConnectionRequest\",\n z.object({ user: Email.optional() }),\n);\nexport type TestOrgConnectionRequest = z.infer<typeof TestOrgConnectionRequest>;\n\nexport const ListDirectoryEntriesQuery = named(\n \"ListDirectoryEntriesQuery\",\n z.object({\n cursor: Cursor.optional(),\n limit: pageLimit(MAX_DIRECTORY_PAGE_SIZE, DEFAULT_DIRECTORY_PAGE_SIZE),\n /** Matches the start of names and addresses. */\n query: z.string().max(MAX_DIRECTORY_QUERY_LENGTH).optional(),\n }),\n);\nexport type ListDirectoryEntriesQuery = z.infer<typeof ListDirectoryEntriesQuery>;\n\nexport const OpenSharedMailboxRequest = named(\n \"OpenSharedMailboxRequest\",\n z.object({\n email: Email,\n displayName: z.string().max(MAX_DISPLAY_NAME_LENGTH).optional(),\n externalRef: ExternalRef.optional(),\n settings: SettingsOverride.optional(),\n }),\n);\nexport type OpenSharedMailboxRequest = z.infer<typeof OpenSharedMailboxRequest>;\n",
26
- "import * as z from \"zod\";\nimport {\n ACCOUNT_NOT_FOUND,\n BILLING_PAST_DUE,\n base,\n bodyStorage,\n errors,\n INVALID_CURSOR,\n PLAN_LIMIT_ACCOUNTS,\n PROVIDER_FAILURES,\n planModule,\n} from \"../errors.ts\";\nimport { AccountIdInput } from \"../primitives.ts\";\nimport {\n Account,\n AccountPage,\n AccountToken,\n AutoconfigQuery,\n CreateAccount,\n CreateImapAccount,\n DeleteAccountInput,\n DiscoveredSettings,\n ListAccountsQuery,\n MintAccountTokenRequest,\n UpdateAccount,\n UpdateImapSettings,\n} from \"./models.ts\";\n\n/** What checking a password account's mail servers refuses (IMAP and SMTP, before storing). */\nexport const MAIL_SETTINGS_CHECK = errors({\n login_failed: \"A server (IMAP, SMTP, CalDAV or CardDAV) refuses the login.\",\n server_not_allowed: \"A server resolves to a private or loopback address.\",\n plaintext_not_allowed: \"A server is named with security none (a plaintext login).\",\n});\n\n/** A new password account whose servers were left out. */\nexport const AUTODISCOVERY_FAILED = errors({\n autodiscovery_failed: \"imap was left out and autodiscovery found no IMAP server for the address.\",\n});\n\n/** What resolving and checking DAV settings refuses. */\nexport const DAV_SETTINGS_CHECK = errors({\n dav_discovery_failed: \"Neither a CalDAV nor a CardDAV server was found or answered.\",\n not_dav_server:\n \"A named CalDAV or CardDAV URL is no DAV server (it answers 404, 403, or not as one).\",\n});\n\n/** What resolving the OAuth client of a sign-in or refresh refuses. */\nexport const OAUTH_CLIENT = errors({\n unknown_oauth_app: \"oauthAppId names no OAuth app of the tenant.\",\n oauth_app_mismatch: \"The OAuth app is for the other provider.\",\n oauth_app_secret_unreadable: \"The OAuth app's client secret cannot be decrypted; replace it.\",\n provider_not_configured:\n \"No OAuth app is given and the platform has none for the provider (and cloud).\",\n});\n\nexport const accounts = {\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts\",\n tags: [\"Accounts\"],\n summary: \"List accounts\",\n description:\n \"Newest first. q matches part of the email address or the external reference, case-insensitively; externalRef matches it exactly.\",\n })\n .errors(INVALID_CURSOR)\n .input(ListAccountsQuery)\n .output(AccountPage),\n\n get: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}\",\n tags: [\"Accounts\"],\n summary: \"Get an account\",\n })\n .errors(ACCOUNT_NOT_FOUND)\n .input(AccountIdInput)\n .output(Account),\n\n /** Headless connect with tokens the tenant already holds (typically from its own OAuth app). */\n create: base\n .route({\n method: \"POST\",\n path: \"/v1/accounts\",\n tags: [\"Accounts\"],\n summary: \"Connect an account from an existing refresh token\",\n description: \"The address is the provider's (Google's userinfo, Graph's /me).\",\n successStatus: 201,\n })\n .errors({\n ...bodyStorage(\"settings.bodyStorage\"),\n ...planModule(\"shared mailboxes (sharedMailboxesEnabled: true)\"),\n ...PLAN_LIMIT_ACCOUNTS,\n ...BILLING_PAST_DUE,\n ...OAUTH_CLIENT,\n ...errors({\n invalid_grant: \"The provider refuses the refresh token (revoked, expired or never valid).\",\n invalid_client: \"The provider refuses the OAuth app's client credentials.\",\n token_exchange_failed:\n \"The provider's token endpoint refuses the refresh for another reason.\",\n scope_denied: \"The grant lacks a scope the account needs.\",\n access_token_rejected: \"The provider refuses the access token the refresh returned.\",\n identity_failed: \"The provider's identity answer names no address.\",\n identity_unavailable: \"Google has not verified the account's address.\",\n provider_unavailable: \"The provider's token or identity endpoint could not be reached.\",\n }),\n })\n .input(CreateAccount)\n .output(Account),\n\n update: base\n .route({\n method: \"PATCH\",\n path: \"/v1/accounts/{accountId}\",\n tags: [\"Accounts\"],\n summary: \"Update an account\",\n description:\n \"Changing settings.bodyStorage, calendarEnabled or syncWindowDays restarts the account's syncs: full stores every indexed message and backfills, none deletes stored content. status only moves between active and paused; only a new grant clears reauth_required and disabled.\",\n })\n .errors({\n ...ACCOUNT_NOT_FOUND,\n ...bodyStorage(\"settings.bodyStorage\"),\n ...errors({\n account_reauth_required: \"status is changed on an account that must be reconnected.\",\n account_disabled: \"status is changed on a disabled account.\",\n }),\n })\n .input(AccountIdInput.extend(UpdateAccount.shape))\n .output(Account),\n\n delete: base\n .route({\n method: \"DELETE\",\n path: \"/v1/accounts/{accountId}\",\n tags: [\"Accounts\"],\n summary: \"Delete an account\",\n description:\n \"Stops syncing and removes the credential at once. The account's data is purged for good after the retention period (default 30 days), or as soon as the maintenance role gets to it with ?purge=true; account.purged announces it. Its events are left to age out of the event log (within 31 days). purge=true also purges an account that is already deleted.\",\n successStatus: 204,\n inputStructure: \"detailed\",\n })\n .errors(\n errors({\n account_not_found: \"The account does not exist, or (without purge) is already deleted.\",\n }),\n )\n .input(DeleteAccountInput)\n .output(z.void()),\n\n /** Short-lived token limited to one account, for a tenant's own frontend. */\n mintToken: base\n .route({\n method: \"POST\",\n path: \"/v1/accounts/{accountId}/tokens\",\n tags: [\"Accounts\"],\n summary: \"Mint an account-scoped token\",\n description: \"The token is returned once; it is not retrievable later.\",\n })\n .errors(ACCOUNT_NOT_FOUND)\n .input(AccountIdInput.extend(MintAccountTokenRequest.shape))\n .output(AccountToken),\n};\n\n// IMAP/SMTP accounts: create with a password, and change their servers and login (the account's\n// `imap` settings). OAuth IMAP accounts come from the OAuth connect flows with\n// options.mailAccess = \"imap\".\nexport const imapAccounts = {\n create: base\n .route({\n method: \"POST\",\n path: \"/v1/imap-accounts\",\n tags: [\"Accounts\"],\n summary: \"Connect an IMAP/SMTP account with a password\",\n description:\n \"The login is checked before anything is stored, for DAV too. Giving dav switches settings.calendarEnabled and contactsEnabled on for the halves found unless settings names them.\",\n successStatus: 201,\n })\n .errors({\n ...MAIL_SETTINGS_CHECK,\n ...AUTODISCOVERY_FAILED,\n ...DAV_SETTINGS_CHECK,\n ...PROVIDER_FAILURES,\n ...bodyStorage(\"settings.bodyStorage\"),\n ...PLAN_LIMIT_ACCOUNTS,\n ...BILLING_PAST_DUE,\n })\n .input(CreateImapAccount)\n .output(Account),\n};\n\nexport const imapSettings = {\n update: base\n .route({\n method: \"PATCH\",\n path: \"/v1/accounts/{accountId}/imap-settings\",\n tags: [\"Accounts\"],\n summary: \"Change an IMAP account's servers or password\",\n description:\n \"Present fields replace the stored ones and the result is checked like a new account. An account in reauth_required becomes active again. A stored password is never sent to a new server or tried for another login: changing the IMAP server (host, port, security or user) needs password in the same request, changing the SMTP server (host, port, security or user) needs smtpPassword (or password when SMTP uses the IMAP password), switching SMTP from its own password to the IMAP one (smtpPassword: null) needs password, and adding DAV settings or changing their URLs, user or password source needs the password DAV logs in with (dav.password, or password when DAV uses the IMAP password). Sending dav: null removes the calendar and contacts; a CalDAV or CardDAV half the account did not have before switches settings.calendarEnabled or contactsEnabled on, unless the account's settings already name that key (an earlier opt-out stays); dav fields left out keep their stored values, or are discovered for an account without DAV settings. An account that signs in with OAuth always uses its provider's servers.\",\n })\n .errors({\n ...ACCOUNT_NOT_FOUND,\n ...MAIL_SETTINGS_CHECK,\n ...DAV_SETTINGS_CHECK,\n ...PROVIDER_FAILURES,\n ...errors({\n not_imap_account: \"The account reads mail through a provider's API, not IMAP.\",\n password_required: \"A server, login user or password source changes without its password.\",\n password_not_stored: \"The account has no stored password and none is sent.\",\n dav_unsupported: \"dav is given for an account that signs in with OAuth.\",\n oauth_servers_fixed: \"The servers of an account that signs in with OAuth are changed.\",\n password_unsupported: \"A password is sent for an account that signs in with OAuth.\",\n account_reauth_required:\n \"The OAuth account's stored grant no longer works, so its servers cannot be checked.\",\n credential_missing: \"The OAuth account has no stored credential.\",\n credential_conflict: \"The OAuth account's credential kept changing while it was refreshed.\",\n invalid_client: \"The provider refuses the OAuth account's client credentials.\",\n token_exchange_failed: \"The provider's token endpoint refuses the OAuth account's refresh.\",\n provider_not_configured: \"The platform OAuth app the account signed in with is gone.\",\n oauth_app_secret_unreadable:\n \"The client secret of the account's OAuth app cannot be decrypted; replace it.\",\n }),\n })\n .input(AccountIdInput.extend(UpdateImapSettings.shape))\n .output(Account),\n};\n\nexport const autoconfig = {\n lookup: base\n .route({\n method: \"GET\",\n path: \"/v1/autoconfig\",\n tags: [\"Accounts\"],\n summary: \"Find IMAP, SMTP and DAV settings for an address\",\n description:\n \"dav carries CalDAV and CardDAV context URLs when a source names them; they need the login to resolve to the account's home sets, which creating the account does.\",\n })\n .errors(\n errors({\n autodiscovery_failed:\n \"No IMAP settings were found for the address; ask the user for the servers then.\",\n }),\n )\n .input(AutoconfigQuery)\n .output(DiscoveredSettings),\n};\n",
27
- "// AI through the deployment's gateway (GATEWAE_API_KEY): drafting email text. Off where the\n// deployment has no gateway configured (console.me's aiEnabled tells the board).\nimport { accountState, base, errors, PROVIDER_FAILURES, planModule } from \"../errors.ts\";\nimport { AiDraft, CreateAiDraft } from \"./models.ts\";\n\nexport const ai = {\n draft: base\n .route({\n method: \"POST\",\n path: \"/v1/ai/draft\",\n tags: [\"AI\"],\n summary: \"Draft email text with AI\",\n description:\n \"Writes an email body from instructions, optionally answering a message or reworking a draft, in plain text or Markdown. Nothing is sent or saved: the text is for a person to edit. Needs the write scope; the tenant may ask for AI_DRAFTS_PER_MINUTE drafts a minute (beyond that, rate_limited with Retry-After).\",\n })\n .errors({\n ...planModule(\"AI\"),\n ...accountState(\"The account of the message being answered\"),\n ...PROVIDER_FAILURES,\n ...errors({\n ai_disabled: \"The deployment has no AI gateway configured.\",\n unknown_account:\n \"context.accountId names an account the tenant does not have; data.ids lists it.\",\n unknown_message: \"context.replyToMessageId names a message the account does not have.\",\n provider_not_found: \"The provider no longer has the message being answered.\",\n provider_forbidden: \"The provider refused to read the message being answered.\",\n ai_refused: \"The model declines the instructions.\",\n ai_unavailable: \"The AI gateway fails or does not answer in time.\",\n ai_suspended:\n \"The AI gateway refuses the deployment's key or account, until an operator fixes it.\",\n }),\n })\n .input(CreateAiDraft)\n .output(AiDraft),\n};\n",
28
- "import { base, errors, INVALID_CURSOR } from \"../errors.ts\";\nimport { AuditEntryPage, ListAuditLogQuery } from \"./models.ts\";\n\nexport const auditLog = {\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/audit-log\",\n tags: [\"Audit log\"],\n summary: \"Read the audit log\",\n description:\n \"Every mutating request on /v1 and from the board, newest first. Needs the admin scope. action matches exactly, or as a prefix when it ends with a dot (accounts.). outcome success is a 2xx status.\",\n })\n .errors({\n ...INVALID_CURSOR,\n ...errors({ invalid_range: \"to is before from.\" }),\n })\n .input(ListAuditLogQuery)\n .output(AuditEntryPage),\n};\n",
29
- "// Calendar procedures. All are account-scoped (/v1/accounts/{accountId}/...) and also callable\n// with an account token for that account.\nimport * as z from \"zod\";\nimport {\n ACCOUNT_NOT_FOUND,\n accountState,\n base,\n errors,\n INVALID_CURSOR,\n PROVIDER_FAILURES,\n planModule,\n} from \"../errors.ts\";\nimport { MAX_AVAILABILITY_DAYS, MAX_EVENT_ATTENDEES, MAX_EVENT_RANGE_DAYS } from \"../limits.ts\";\nimport { AccountIdInput } from \"../primitives.ts\";\nimport {\n Availability,\n CalendarEvent,\n CalendarEventDetail,\n CalendarEventIdInput,\n CalendarEventPage,\n CalendarList,\n CreateCalendarEventInput,\n DeleteCalendarEventInput,\n FindAvailabilityInput,\n ListCalendarEventsInput,\n RespondToCalendarEventRequest,\n UpdateCalendarEvent,\n} from \"./models.ts\";\n\n/** What every calendar procedure answers before its own work: the plan, the account, its sync. */\nconst CALENDAR_ACCOUNT = {\n ...planModule(\"calendar\"),\n ...ACCOUNT_NOT_FOUND,\n ...errors({\n calendar_disabled:\n \"The account's calendar sync is off, or it is an IMAP account without CalDAV settings.\",\n }),\n};\n\n/** What reaching the account's calendar provider answers. */\nconst CALENDAR_PROVIDER = {\n ...accountState(),\n ...PROVIDER_FAILURES,\n ...errors({\n provider_forbidden:\n \"The provider refused the account access (e.g. the grant lacks calendar access).\",\n provider_not_found: \"The event or calendar is gone at the provider.\",\n provider_unsupported:\n \"The provider cannot express the request (e.g. a rule Microsoft has no pattern for), or an IMAP account whose CalDAV server does not schedule has no SMTP server to mail the iTIP message from.\",\n provider_rejected: `The provider refused the request, or more than ${MAX_EVENT_ATTENDEES} attendees would be mailed an iTIP message.`,\n }),\n};\n\n/** What a write to the provider adds. */\nconst CALENDAR_WRITE = {\n ...CALENDAR_PROVIDER,\n ...errors({\n provider_conflict: \"The event changed at the provider meanwhile.\",\n calendar_read_only: \"The account can only read the event's calendar.\",\n }),\n};\n\n/** An event's times and rule, as create and update check them. */\nconst EVENT_TIMES = errors({\n invalid_time_zone: \"A timed start or end names an unknown time zone.\",\n mixed_event_times: \"One end is timed and the other all-day.\",\n invalid_range: \"end is not after start.\",\n invalid_recurrence: \"recurrence has no RRULE or RDATE line, or does not parse as RFC 5545.\",\n});\n\nconst EVENT_NOT_FOUND = errors({\n calendar_event_not_found: \"The event does not exist in the account's synced calendars.\",\n});\n\n/** What the meeting service of an event's Zoom or Webex meeting answers. */\nconst MEETING_SERVICE = errors({\n meeting_service_not_connected:\n \"The account has no connection to the service and the tenant no server app it may use (a password IMAP account may not use one).\",\n meeting_service_reauth_required:\n \"The account's connection or the tenant's server app was refused and must be connected or fixed again.\",\n meeting_recurrence_unsupported: \"The service cannot repeat a meeting by the event's rule.\",\n meeting_service_rejected: \"The service refused the meeting.\",\n meeting_service_unavailable: \"The service could not be reached.\",\n});\n\nexport const calendars = {\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}/calendars\",\n tags: [\"Calendar\"],\n summary: \"List calendars\",\n })\n .errors(CALENDAR_ACCOUNT)\n .input(AccountIdInput)\n .output(CalendarList),\n};\n\nexport const calendarEvents = {\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}/calendar-events\",\n tags: [\"Calendar\"],\n summary: \"List events in a time range, by start\",\n description:\n \"Returns singles, occurrences and exceptions overlapping [start, end), not series definitions. Only the sync window (by default 90 days back to 365 days ahead) is indexed.\",\n })\n .errors({\n ...CALENDAR_ACCOUNT,\n ...INVALID_CURSOR,\n ...errors({\n invalid_range: `end is not after start, or the range spans more than ${MAX_EVENT_RANGE_DAYS} days.`,\n unknown_calendar: \"calendarId names no synced calendar of the account.\",\n }),\n })\n .input(ListCalendarEventsInput)\n .output(CalendarEventPage),\n\n get: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}/calendar-events/{eventId}\",\n tags: [\"Calendar\"],\n summary: \"Get an event with its body\",\n description: \"Works for every kind, including a series (its recurrence rule).\",\n })\n .errors({ ...CALENDAR_ACCOUNT, ...EVENT_NOT_FOUND, ...CALENDAR_PROVIDER })\n .input(CalendarEventIdInput)\n .output(CalendarEventDetail),\n\n create: base\n .route({\n method: \"POST\",\n path: \"/v1/accounts/{accountId}/calendar-events\",\n tags: [\"Calendar\"],\n summary: \"Create an event or a recurring series\",\n description:\n \"onlineMeeting asks the provider for a Teams (Microsoft) or Meet (Google) link; onlineMeetingUrl attaches a link from another service (Zoom, Webex, ...), read back as onlineMeetingUrl. On Microsoft that link is the location's link (location defaults to the URL) and a join line is added to a body sent along. onlineMeetingService has workwae create a Zoom or Webex meeting (recurring for a series) hosted by the account's own grant at the service, else by the tenant's server app as the service user with the mailbox's address, and attaches its join link the same way. The server app hosts only accounts whose address the provider verified (Gmail, Microsoft, IMAP signed in with OAuth): a password IMAP account's address is whatever was typed, so it needs its own grant. The meeting is created only once the account is active, and deleted again if anything fails before its link is saved. On an IMAP account whose CalDAV server does not schedule, the invitation is mailed from the account's SMTP server when notify is true and there are attendees; a missing SMTP server is refused before anything is created, and a send that fails after the event is created is logged and the event stands.\",\n successStatus: 201,\n })\n .errors({\n ...CALENDAR_ACCOUNT,\n ...CALENDAR_WRITE,\n ...EVENT_TIMES,\n ...MEETING_SERVICE,\n ...errors({\n plan_module_unavailable:\n \"The tenant's plan does not include calendar, or onlineMeetingService is given and it does not include meetings.\",\n calendar_not_found: \"calendarId names no synced calendar of the account.\",\n calendar_event_not_found: \"The provider no longer has the event when it is read back.\",\n multiple_meeting_options:\n \"More than one of onlineMeeting, onlineMeetingUrl and onlineMeetingService is given.\",\n meeting_host_missing: \"The tenant's server app has no user with the mailbox's address.\",\n }),\n })\n .input(CreateCalendarEventInput)\n .output(CalendarEventDetail),\n\n update: base\n .route({\n method: \"PATCH\",\n path: \"/v1/accounts/{accountId}/calendar-events/{eventId}\",\n tags: [\"Calendar\"],\n summary: \"Change an event, one occurrence, or a whole series\",\n description:\n \"Addressing an occurrence changes only that instance; addressing the series changes every occurrence. onlineMeetingUrl replaces a link from another service (as on create); null removes it (on Google, whatever conference the event has; on Microsoft, the location's link, leaving a Teams meeting alone). For an event whose Zoom or Webex meeting workwae created, a new subject, start, end or recurrence moves that meeting too, and an onlineMeetingUrl other than its own join link deletes it (sending that link back replaces nothing); changing one occurrence leaves the meeting's series as it is. A missing or refused meeting connection is reported before anything changes; a service failure after the event changed is reported with the event changed (repeat the request). On an IMAP account whose CalDAV server does not schedule, an update of a meeting the account organizes is mailed from its SMTP server when it changes start, end, recurrence, location or attendees, to the attendees workwae has indexed for it and those the request names; a missing SMTP server or too many attendees is refused before anything changes, and a send that fails after the change is logged and the change stands.\",\n })\n .errors({\n ...CALENDAR_ACCOUNT,\n ...EVENT_NOT_FOUND,\n ...CALENDAR_WRITE,\n ...EVENT_TIMES,\n ...MEETING_SERVICE,\n ...errors({\n recurrence_on_instance: \"recurrence is given for an occurrence or exception.\",\n meeting_deleted: \"The event's meeting is gone at the service when it is moved.\",\n }),\n })\n .input(CalendarEventIdInput.extend(UpdateCalendarEvent.shape))\n .output(CalendarEventDetail),\n\n delete: base\n .route({\n method: \"DELETE\",\n path: \"/v1/accounts/{accountId}/calendar-events/{eventId}\",\n tags: [\"Calendar\"],\n summary: \"Delete an event, one occurrence, or a whole series\",\n description:\n \"Cancels the meeting for its attendees when the account organizes it. A Zoom or Webex meeting workwae created for the event (a series, not one occurrence) is deleted after the provider event: a provider refusal leaves both, and once the event is gone a meeting the service cannot delete (connection gone or refused, service unreachable) is logged and stays at the service while the request still succeeds. On an IMAP account whose CalDAV server does not schedule, the cancellation is mailed from the account's SMTP server to the attendees workwae has indexed; a missing SMTP server or too many attendees is refused before anything is deleted, and a send that fails after the deletion is logged.\",\n successStatus: 204,\n inputStructure: \"detailed\",\n })\n .errors({ ...CALENDAR_ACCOUNT, ...EVENT_NOT_FOUND, ...CALENDAR_WRITE })\n .input(DeleteCalendarEventInput)\n .output(z.void()),\n\n respond: base\n .route({\n method: \"POST\",\n path: \"/v1/accounts/{accountId}/calendar-events/{eventId}/respond\",\n tags: [\"Calendar\"],\n summary: \"Accept, tentatively accept or decline an invitation\",\n description:\n \"Addressing an occurrence answers that instance; the series answers all of them. On an IMAP account whose CalDAV server does not schedule, the answer is mailed to the organizer from the account's SMTP server; a missing SMTP server is refused before anything changes, and a send that fails after the answer is recorded is logged.\",\n })\n .errors({\n ...CALENDAR_ACCOUNT,\n ...EVENT_NOT_FOUND,\n ...CALENDAR_PROVIDER,\n ...errors({\n provider_conflict: \"The event changed at the provider meanwhile.\",\n organizer_cannot_respond:\n \"The account organizes the event, so there is no invitation to answer.\",\n }),\n })\n .input(CalendarEventIdInput.extend(RespondToCalendarEventRequest.shape))\n .output(CalendarEvent),\n};\n\nexport const availability = {\n find: base\n .route({\n method: \"POST\",\n path: \"/v1/accounts/{accountId}/availability/find\",\n tags: [\"Calendar\"],\n summary: \"Find busy times and common free slots\",\n description:\n \"A read sent as a POST, the question not fitting a URL. One provider request covers every attendee (Microsoft getSchedule, Google freeBusy.query); the answer is cached briefly per account, attendees and range.\",\n })\n .errors({\n ...CALENDAR_ACCOUNT,\n ...CALENDAR_PROVIDER,\n ...errors({\n invalid_range: `end is not after start, or the range spans more than ${MAX_AVAILABILITY_DAYS} days.`,\n invalid_time_zone: \"timeZone is unknown.\",\n invalid_working_hours: \"workingHours does not end after it starts.\",\n }),\n })\n .input(FindAvailabilityInput)\n .output(Availability),\n};\n",
30
- "import { AutoconfigQuery, DiscoveredSettings, ImapAccountInput } from \"../accounts/models.ts\";\nimport {\n AUTODISCOVERY_FAILED,\n DAV_SETTINGS_CHECK,\n MAIL_SETTINGS_CHECK,\n OAUTH_CLIENT,\n} from \"../accounts/routes.ts\";\nimport { base, bodyStorage, errors, PROVIDER_FAILURES, planModule } from \"../errors.ts\";\nimport { publicOperation } from \"../primitives.ts\";\nimport {\n ConnectSession,\n ConnectSessionIdInput,\n ConnectSessionPublic,\n CreateConnectSession,\n HostedImapResult,\n OAuthAuthorization,\n SessionLink,\n SessionTokenInput,\n StartOAuthRequest,\n} from \"./models.ts\";\n\n/** What starting a connect for the tenant refuses before anyone signs in. */\nconst CONNECT_REQUEST = errors({\n redirect_uri_not_allowed: \"redirectUri is not on the tenant allowlist (settings.redirectUris).\",\n billing_past_due:\n \"accountId is not given and the tenant's payment is past due beyond the grace period.\",\n unknown_account: \"accountId names no live account of the tenant; data.ids names it.\",\n org_connection_account:\n \"accountId names an account that authenticates through an organization connection (test the connection to restore it).\",\n shared_mailbox_account:\n \"accountId names a shared mailbox (reconnect the account that opened it).\",\n});\n\nconst CONNECT_SESSION_NOT_FOUND = errors({\n connect_session_not_found: \"No session has this id (or token).\",\n});\n\n/** A hosted session the IMAP form may no longer act on. */\nconst HOSTED_IMAP_SESSION = {\n ...CONNECT_SESSION_NOT_FOUND,\n ...errors({\n session_used: \"The session already completed or failed.\",\n session_expired: \"The session is past expiresAt.\",\n redirect_uri_not_allowed: \"The session's return address is no longer on the tenant allowlist.\",\n provider_not_allowed: \"The session does not offer the IMAP form.\",\n }),\n};\n\nexport const connectSessions = {\n /** Hosted flow: returns a link to the hosted connect page. */\n create: base\n .route({\n method: \"POST\",\n path: \"/v1/connect-sessions\",\n tags: [\"Connect\"],\n summary: \"Create a hosted connect session\",\n description:\n \"Returns a link to the hosted connect page. Its OAuth sign-ins pass a Continue page on the API origin naming the tenant and provider, and must finish in the browser that pressed Continue (an HttpOnly cookie on the API origin); a callback in any other browser renders an error page and connects nothing. Without redirectUri the owner ends on workwae's own confirmation page, which needs no allowlist entry; follow the outcome with GET /v1/connect-sessions/{sessionId} or the account.connected event. A failed sign-in returns with status=error and error set to a ConnectErrorCode.\",\n successStatus: 201,\n })\n .errors({\n ...CONNECT_REQUEST,\n ...bodyStorage(\"options.bodyStorage\"),\n ...errors({\n unknown_oauth_app: \"oauthAppIds names no OAuth app of the tenant.\",\n oauth_app_mismatch: \"An OAuth app in oauthAppIds is for the other provider.\",\n account_mismatch: \"providers leaves out the sign-in the account reconnects with.\",\n google_imap_requires_own_app:\n \"providers includes google with options.mailAccess imap (given, or kept by the account being reconnected) and no Google app (oauthAppIds, or the reconnected account's own): Google over IMAP needs the tenant's own Google OAuth app.\",\n }),\n })\n .input(CreateConnectSession)\n .output(SessionLink),\n\n get: base\n .route({\n method: \"GET\",\n path: \"/v1/connect-sessions/{sessionId}\",\n tags: [\"Connect\"],\n summary: \"Read a hosted connect session's outcome\",\n })\n .errors(CONNECT_SESSION_NOT_FOUND)\n .input(ConnectSessionIdInput)\n .output(ConnectSession),\n};\n\n/** Headless flow: the URL to send the user to (see the description). */\nexport const oauthAuthorizations = {\n create: base\n .route({\n method: \"POST\",\n path: \"/v1/oauth-authorizations\",\n tags: [\"Connect\"],\n summary: \"Start a headless OAuth connect\",\n description:\n \"authorizeUrl is a page on the API origin naming the tenant and the provider; only its Continue button (a form POST, accepted only from the API or board origin) leads on to the provider. Continuing works once and binds the sign-in to that browser with an HttpOnly cookie scoped to the callback; a callback arriving in any other browser renders an error page and connects nothing, so send the user's own browser to it. A failed sign-in returns with status=error and error set to a ConnectErrorCode.\",\n })\n .errors({\n ...CONNECT_REQUEST,\n ...bodyStorage(\"options.bodyStorage\"),\n ...planModule(\"shared mailboxes (options.sharedMailboxesEnabled: true)\"),\n ...OAUTH_CLIENT,\n ...errors({\n account_mismatch:\n \"The account given as accountId signs in with another provider, or with a password.\",\n google_imap_requires_own_app:\n \"provider google with options.mailAccess imap (given, or kept by the account being reconnected) and no Google app (oauthAppId, or the reconnected account's own): Google over IMAP needs the tenant's own Google OAuth app.\",\n }),\n })\n .input(StartOAuthRequest)\n .output(OAuthAuthorization),\n};\n\n// Unauthenticated, by the hosted session's token (the credential): what the hosted connect page\n// reads and submits. Every route the hosted pages call is under /v1/hosted/.\nconst HOSTED_TAGS = [\"Hosted pages\"];\n\nexport const hostedConnectSessions = {\n get: base\n .route({\n method: \"GET\",\n path: \"/v1/hosted/connect-sessions/{token}\",\n tags: HOSTED_TAGS,\n summary: \"Read a hosted connect session\",\n spec: publicOperation,\n })\n .errors(CONNECT_SESSION_NOT_FOUND)\n .input(SessionTokenInput)\n .output(ConnectSessionPublic),\n\n createImapAccount: base\n .route({\n method: \"POST\",\n path: \"/v1/hosted/connect-sessions/{token}/imap-accounts\",\n tags: HOSTED_TAGS,\n summary: \"Connect an IMAP account from the hosted page\",\n description:\n \"When the tenant's plan allows no more accounts, or its payment is past due beyond the grace period, the session fails and redirectUrl carries status=error&error=plan_limit_accounts (or billing_past_due), as the OAuth callback does. Giving dav switches settings.calendarEnabled and contactsEnabled on for the halves found unless the session's options name them, as POST /v1/imap-accounts does. A reconnect session replaces the password only: the account keeps its stored servers and DAV settings, and any sent here are ignored. Its DAV login is checked again: with the new password when DAV uses the IMAP password, otherwise with dav.password when given (which then replaces the stored DAV password) or the stored one.\",\n spec: publicOperation,\n })\n .errors({\n ...HOSTED_IMAP_SESSION,\n ...MAIL_SETTINGS_CHECK,\n ...AUTODISCOVERY_FAILED,\n ...DAV_SETTINGS_CHECK,\n ...PROVIDER_FAILURES,\n ...errors({\n account_exists:\n \"The tenant already has a live IMAP account with this address and the session was not created to reconnect it (accountId).\",\n account_not_found: \"The account a reconnect session was created for was deleted.\",\n account_mismatch:\n \"A reconnect session's account has another address, or is not an IMAP account.\",\n password_required:\n \"A reconnect session's DAV has a password of its own, none is stored and dav.password is left out.\",\n }),\n })\n .input(SessionTokenInput.extend(ImapAccountInput.shape))\n .output(HostedImapResult),\n\n autoconfig: base\n .route({\n method: \"GET\",\n path: \"/v1/hosted/connect-sessions/{token}/autoconfig\",\n tags: HOSTED_TAGS,\n summary: \"Find IMAP and SMTP settings from the hosted page\",\n spec: publicOperation,\n })\n .errors({\n ...HOSTED_IMAP_SESSION,\n ...errors({ autodiscovery_failed: \"No IMAP settings were found for the address.\" }),\n })\n .input(SessionTokenInput.extend(AutoconfigQuery.shape))\n .output(DiscoveredSettings),\n};\n",
31
- "// Contact procedures. All are account-scoped (/v1/accounts/{accountId}/...) and also callable with\n// an account token for that account.\nimport * as z from \"zod\";\nimport {\n ACCOUNT_NOT_FOUND,\n accountState,\n base,\n errors,\n INVALID_CURSOR,\n PROVIDER_FAILURES,\n planModule,\n} from \"../errors.ts\";\nimport { AccountIdInput, fileResponse } from \"../primitives.ts\";\nimport {\n Contact,\n ContactFolderList,\n ContactIdInput,\n ContactPage,\n CreateContactInput,\n ListContactsQuery,\n UpdateContact,\n} from \"./models.ts\";\n\n/** What every contacts procedure answers before its own work: the plan, the account, its sync. */\nconst CONTACTS_ACCOUNT = {\n ...planModule(\"contacts\"),\n ...ACCOUNT_NOT_FOUND,\n ...errors({\n contacts_disabled:\n \"The account's contacts sync is off, or it is an IMAP account without CardDAV settings.\",\n }),\n};\n\nconst CONTACT_NOT_FOUND = errors({ contact_not_found: \"The contact does not exist.\" });\n\n/** What reaching the account's contacts provider answers. */\nconst CONTACTS_PROVIDER = {\n ...accountState(),\n ...PROVIDER_FAILURES,\n ...errors({\n provider_forbidden:\n \"The provider refused the account access (e.g. the grant lacks contacts access).\",\n provider_not_found: \"The contact is gone at the provider (the index drops it).\",\n provider_conflict: \"The contact changed at the provider meanwhile.\",\n provider_rejected: \"The provider refused the request.\",\n }),\n};\n\n/** What writing a contact checks. */\nconst CONTACT_WRITE = {\n ...CONTACTS_PROVIDER,\n ...errors({\n contact_unidentifiable:\n \"The contact would have no name, organization, email address or phone number.\",\n provider_unsupported:\n 'The provider cannot store what was given (a folder on Google, or on Microsoft 365 more than 3 email addresses, more than one mobile number or an \"other\" number).',\n }),\n};\n\nexport const contactFolders = {\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}/contact-folders\",\n tags: [\"Contacts\"],\n summary: \"List contact folders\",\n description:\n \"Microsoft 365 contact folders, the default folder first; empty for Google accounts.\",\n })\n .errors(CONTACTS_ACCOUNT)\n .input(AccountIdInput)\n .output(ContactFolderList),\n};\n\nexport const contacts = {\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}/contacts\",\n tags: [\"Contacts\"],\n summary: \"List or search contacts, by name\",\n description:\n \"Reads the index. q matches part of any name, the organization or any email address, case-insensitively.\",\n })\n .errors({\n ...CONTACTS_ACCOUNT,\n ...INVALID_CURSOR,\n ...errors({ unknown_contact_folder: \"folderId names no contact folder of the account.\" }),\n })\n .input(AccountIdInput.extend(ListContactsQuery.shape))\n .output(ContactPage),\n\n get: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}/contacts/{contactId}\",\n tags: [\"Contacts\"],\n summary: \"Get a contact\",\n description: \"Reads the index.\",\n })\n .errors({ ...CONTACTS_ACCOUNT, ...CONTACT_NOT_FOUND })\n .input(ContactIdInput)\n .output(Contact),\n\n photo: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}/contacts/{contactId}/photo\",\n tags: [\"Contacts\"],\n summary: \"Download a contact's photo\",\n description: \"Fetched from the provider on first request and cached until the photo changes.\",\n spec: fileResponse({\n mediaType: \"image/*\",\n description: \"The photo as the provider stores it (image/jpeg, image/png, ...)\",\n disposition: \"inline\",\n }),\n })\n .errors({\n ...CONTACTS_ACCOUNT,\n ...CONTACT_NOT_FOUND,\n ...CONTACTS_PROVIDER,\n ...errors({ photo_not_found: \"The contact has no photo.\" }),\n })\n .input(ContactIdInput)\n .output(z.file()),\n\n create: base\n .route({\n method: \"POST\",\n path: \"/v1/accounts/{accountId}/contacts\",\n tags: [\"Contacts\"],\n summary: \"Create a contact\",\n description: \"Written to the provider, then to the index, so it is listed at once.\",\n successStatus: 201,\n })\n .errors({\n ...CONTACTS_ACCOUNT,\n ...CONTACT_WRITE,\n ...errors({\n unknown_contact_folder: \"folderId names no contact folder of the account.\",\n contact_not_found: \"The provider's answer could not be read back into the index.\",\n }),\n })\n .input(CreateContactInput)\n .output(Contact),\n\n update: base\n .route({\n method: \"PATCH\",\n path: \"/v1/accounts/{accountId}/contacts/{contactId}\",\n tags: [\"Contacts\"],\n summary: \"Change a contact\",\n description: \"Fields present change (null clears); emails and phones replace the whole list.\",\n })\n .errors({ ...CONTACTS_ACCOUNT, ...CONTACT_NOT_FOUND, ...CONTACT_WRITE })\n .input(ContactIdInput.extend(UpdateContact.shape))\n .output(Contact),\n\n delete: base\n .route({\n method: \"DELETE\",\n path: \"/v1/accounts/{accountId}/contacts/{contactId}\",\n tags: [\"Contacts\"],\n summary: \"Delete a contact\",\n successStatus: 204,\n })\n .errors({ ...CONTACTS_ACCOUNT, ...CONTACT_NOT_FOUND, ...CONTACTS_PROVIDER })\n .input(ContactIdInput)\n .output(z.void()),\n};\n",
32
- "import { base, INVALID_CURSOR } from \"../errors.ts\";\nimport { EventFeedPage, ListChangesQuery } from \"./models.ts\";\n\nexport const changes = {\n /**\n * The change feed. Pass the returned cursor back to continue; an empty page means caught up.\n * Omit the cursor to start from the oldest retained event.\n */\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/changes\",\n tags: [\"Changes\"],\n summary: \"Read the change feed\",\n description:\n \"Events oldest first. Pass nextCursor back as cursor to continue; it is never null, since the feed has no end, only a present: an empty page means caught up, so poll again from the same cursor later.\",\n })\n .errors(INVALID_CURSOR)\n .input(ListChangesQuery)\n .output(EventFeedPage),\n};\n",
33
- "// Data exports of the tenant or one account.\nimport * as z from \"zod\";\nimport { base, errors, INVALID_CURSOR } from \"../errors.ts\";\nimport { fileResponse, StreamedFile } from \"../primitives.ts\";\nimport {\n CreateDataExport,\n DataExport,\n DataExportIdInput,\n DataExportPage,\n ListDataExportsQuery,\n} from \"./models.ts\";\n\nconst EXPORT_NOT_FOUND = errors({ export_not_found: \"The export does not exist.\" });\n\nexport const exports = {\n create: base\n .route({\n method: \"POST\",\n path: \"/v1/exports\",\n tags: [\"Exports\"],\n summary: \"Export the tenant or one account\",\n description: `Builds a gzip-compressed tar in the background: accounts without secrets, mailboxes, message metadata (JSON lines), stored message bodies as .eml, calendars and events as JSON and .ics, and for a tenant export its webhooks (without signing secrets), templates and settings. Follow it with GET /v1/exports/{exportId}, or the export.completed and export.failed events. Requires the admin scope.`,\n successStatus: 202,\n })\n .errors(\n errors({\n storage_unavailable: \"No object store is configured.\",\n unknown_account: \"accountId names an account the tenant does not have; data.ids lists it.\",\n export_in_progress:\n \"An export of the same scope (the tenant, or the same account) is queued or running.\",\n }),\n )\n .input(CreateDataExport)\n .output(DataExport),\n\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/exports\",\n tags: [\"Exports\"],\n summary: \"List exports, newest first\",\n description: \"Requires the admin scope.\",\n })\n .errors(INVALID_CURSOR)\n .input(ListDataExportsQuery)\n .output(DataExportPage),\n\n get: base\n .route({\n method: \"GET\",\n path: \"/v1/exports/{exportId}\",\n tags: [\"Exports\"],\n summary: \"Get an export\",\n description: \"Requires the admin scope.\",\n })\n .errors(EXPORT_NOT_FOUND)\n .input(DataExportIdInput)\n .output(DataExport),\n\n download: base\n .route({\n method: \"GET\",\n path: \"/v1/exports/{exportId}/download\",\n tags: [\"Exports\"],\n summary: \"Download an export (application/gzip)\",\n description: `Streams the decrypted .tar.gz; compare it with the export's sha256. Requires the admin scope.`,\n spec: fileResponse({\n mediaType: \"application/gzip\",\n description: \"The export as a gzip-compressed tar\",\n disposition: \"attachment\",\n headers: {\n \"x-export-sha256\": {\n description: \"sha256 hex of the body, the export's sha256\",\n schema: { type: \"string\" },\n },\n },\n }),\n })\n .errors({\n ...EXPORT_NOT_FOUND,\n ...errors({\n export_not_ready: \"The export is queued or running.\",\n export_failed: \"The export failed.\",\n export_expired: \"The export's file was deleted.\",\n storage_unavailable: \"No object store is configured.\",\n export_corrupt: \"A stored part of the export fails its integrity check.\",\n }),\n })\n .input(DataExportIdInput)\n .output(StreamedFile),\n\n delete: base\n .route({\n method: \"DELETE\",\n path: \"/v1/exports/{exportId}\",\n tags: [\"Exports\"],\n summary: \"Delete an export and its file\",\n description: \"Requires the admin scope.\",\n successStatus: 204,\n })\n .errors({ ...EXPORT_NOT_FOUND, ...errors({ export_running: \"The export is being built.\" }) })\n .input(DataExportIdInput)\n .output(z.void()),\n};\n",
34
- "// Send-as identities, their signatures and the account's mail settings. Account-scoped\n// (/v1/accounts/{accountId}/...) and also callable with an account token for that account.\nimport * as z from \"zod\";\nimport { ACCOUNT_NOT_FOUND, base, errors, PROVIDER_FAILURES } from \"../errors.ts\";\nimport { AccountIdInput } from \"../primitives.ts\";\nimport {\n CreateIdentity,\n Identity,\n IdentityIdInput,\n IdentityList,\n ListIdentitiesQuery,\n MailSettings,\n UpdateIdentity,\n UpdateMailSettings,\n} from \"./models.ts\";\n\nconst IDENTITY_NOT_FOUND = errors({ identity_not_found: \"The identity does not exist.\" });\n\nexport const identities = {\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}/identities\",\n tags: [\"Identities\"],\n summary: \"List the addresses the account may send as\",\n description:\n \"The account's own address, the provider's (Gmail send-as addresses with their Gmail signatures in one users.settings.sendAs request; Microsoft proxy addresses from /me) and custom ones. The provider's list is read when the cached one is a day old, or with refresh=true at most once a minute; a paused or disconnected account serves the cached list.\",\n })\n .errors({\n ...ACCOUNT_NOT_FOUND,\n ...errors({\n account_reauth_required:\n \"Reading the provider's list found that the account must be reconnected.\",\n }),\n ...PROVIDER_FAILURES,\n })\n .input(AccountIdInput.extend(ListIdentitiesQuery.shape))\n .output(IdentityList),\n\n create: base\n .route({\n method: \"POST\",\n path: \"/v1/accounts/{accountId}/identities\",\n tags: [\"Identities\"],\n summary: \"Add a custom identity\",\n description:\n \"For IMAP aliases, and Microsoft mailboxes the account has Send As permission on (Graph cannot list those). Sending as it is checked by the provider when the message goes out.\",\n successStatus: 201,\n })\n .errors({\n ...ACCOUNT_NOT_FOUND,\n ...errors({\n identities_managed_by_provider:\n \"The account is a Gmail account (add send-as addresses in Gmail).\",\n identity_exists: \"The address is already an identity of the account.\",\n }),\n })\n .input(AccountIdInput.extend(CreateIdentity.shape))\n .output(Identity),\n\n update: base\n .route({\n method: \"PATCH\",\n path: \"/v1/accounts/{accountId}/identities/{identityId}\",\n tags: [\"Identities\"],\n summary: \"Change an identity's signature or name\",\n description:\n \"signature: null removes ours (Gmail's own then applies again). Only custom identities take a name; the others carry the provider's.\",\n })\n .errors({\n ...ACCOUNT_NOT_FOUND,\n ...IDENTITY_NOT_FOUND,\n ...errors({\n identity_not_custom: \"A name is given for a primary or provider identity.\",\n }),\n })\n .input(IdentityIdInput.extend(UpdateIdentity.shape))\n .output(Identity),\n\n delete: base\n .route({\n method: \"DELETE\",\n path: \"/v1/accounts/{accountId}/identities/{identityId}\",\n tags: [\"Identities\"],\n summary: \"Remove a custom identity\",\n successStatus: 204,\n })\n .errors({\n ...ACCOUNT_NOT_FOUND,\n ...IDENTITY_NOT_FOUND,\n ...errors({\n identity_not_custom:\n \"The identity is the primary or a provider identity (those follow the provider).\",\n }),\n })\n .input(IdentityIdInput)\n .output(z.void()),\n};\n\nexport const mailSettings = {\n get: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}/mail-settings\",\n tags: [\"Identities\"],\n summary: \"Get the account's mail settings\",\n })\n .errors(ACCOUNT_NOT_FOUND)\n .input(AccountIdInput)\n .output(MailSettings),\n\n update: base\n .route({\n method: \"PATCH\",\n path: \"/v1/accounts/{accountId}/mail-settings\",\n tags: [\"Identities\"],\n summary: \"Update the account's mail settings\",\n })\n .errors(ACCOUNT_NOT_FOUND)\n .input(AccountIdInput.extend(UpdateMailSettings.shape))\n .output(MailSettings),\n};\n",
35
- "// Mailbox and message procedures. All are account-scoped (/v1/accounts/{accountId}/...) and also\n// callable with an account token for that account.\nimport * as z from \"zod\";\nimport {\n ACCOUNT_NOT_FOUND,\n accountState,\n base,\n errors,\n INVALID_CURSOR,\n PROVIDER_FAILURES,\n} from \"../errors.ts\";\nimport { AccountIdInput, fileResponse, StreamedFile, withDateRange } from \"../primitives.ts\";\nimport {\n AttachmentIdInput,\n DeleteMessageInput,\n ListMessagesQuery,\n MailboxList,\n Message,\n MessageIdInput,\n MessageSummary,\n MessageSummaryPage,\n SearchMessagesQuery,\n SearchPage,\n UpdateMessage,\n} from \"./models.ts\";\n\n/** A mailboxId (or addMailboxIds, removeMailboxIds) the account does not have. */\nexport const UNKNOWN_MAILBOX = errors({\n unknown_mailbox: \"A mailbox id names no live mailbox of the account; data.ids lists them.\",\n});\n\n/** What a change made at the provider answers when the provider refuses it. */\nexport const PROVIDER_CHANGE = {\n ...PROVIDER_FAILURES,\n ...errors({\n provider_not_found: \"The provider no longer has the item.\",\n provider_forbidden: \"The provider refused the change for lack of permission.\",\n provider_rejected: \"The provider rejected the change as invalid.\",\n provider_unsupported: \"The provider does not support the change.\",\n provider_conflict: \"The provider refused the change because of the item's state.\",\n }),\n};\n\n// What reading a message answers: the provider is needed without stored content, and for drafts.\nconst MESSAGE_READ = {\n ...ACCOUNT_NOT_FOUND,\n ...errors({ message_not_found: \"The message does not exist.\" }),\n ...accountState(\"The provider is needed and the account\"),\n ...PROVIDER_FAILURES,\n ...errors({\n provider_not_found: \"The provider no longer has the message or the attachment.\",\n provider_forbidden: \"The provider refused to serve the message.\",\n }),\n};\n\nexport const mailboxes = {\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}/mailboxes\",\n tags: [\"Mail\"],\n summary: \"List mailboxes (folders or labels)\",\n })\n .errors(ACCOUNT_NOT_FOUND)\n .input(AccountIdInput)\n .output(MailboxList),\n};\n\nexport const messages = {\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}/messages\",\n tags: [\"Mail\"],\n summary: \"List messages, newest first\",\n description:\n \"Covers the account's sync window. Without mailboxId, lists every mailbox. importance keeps the messages with that priority; messages indexed before priorities were read (importance null) match none.\",\n })\n .errors({ ...ACCOUNT_NOT_FOUND, ...INVALID_CURSOR, ...UNKNOWN_MAILBOX })\n .input(AccountIdInput.extend(ListMessagesQuery.shape))\n .output(MessageSummaryPage),\n\n get: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}/messages/{messageId}\",\n tags: [\"Mail\"],\n summary: \"Get a message with its body\",\n description:\n 'With bodyStorage cache or full the body comes from stored content (cache fetches and stores the raw message on a miss), and attachment ids are MIME part numbers (\"1.2\"); otherwise it is read from the provider. Drafts are always read from the provider.',\n })\n .errors(MESSAGE_READ)\n .input(MessageIdInput)\n .output(Message),\n\n raw: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}/messages/{messageId}/raw\",\n tags: [\"Mail\"],\n summary: \"Download the message as RFC 5322 (message/rfc822)\",\n description: \"Served from stored content when the account stores bodies.\",\n spec: fileResponse({\n mediaType: \"message/rfc822\",\n description: \"The message as message/rfc822\",\n disposition: \"attachment\",\n }),\n })\n .errors(MESSAGE_READ)\n .input(MessageIdInput)\n .output(StreamedFile),\n\n attachment: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}/messages/{messageId}/attachments/{attachmentId}\",\n tags: [\"Mail\"],\n summary: \"Download an attachment\",\n description:\n \"Served from stored content when the account stores bodies; an id the stored message does not have is asked of the provider, which answers provider_not_found when it has no such attachment either.\",\n spec: fileResponse({\n mediaType: \"*/*\",\n description: \"The attachment, with the Content-Type it was sent with\",\n disposition: \"attachment\",\n }),\n })\n .errors(MESSAGE_READ)\n .input(AttachmentIdInput)\n .output(StreamedFile),\n\n update: base\n .route({\n method: \"PATCH\",\n path: \"/v1/accounts/{accountId}/messages/{messageId}\",\n tags: [\"Mail\"],\n summary: \"Change flags, move, or change labels\",\n description:\n \"mailboxId moves the message (Microsoft folders, or Gmail: replaces the message's folder-like labels). addMailboxIds/removeMailboxIds apply Gmail labels.\",\n })\n .errors({\n ...ACCOUNT_NOT_FOUND,\n ...errors({\n message_not_found: \"The message does not exist.\",\n mailbox_not_label: \"addMailboxIds or removeMailboxIds names a mailbox that is not a label.\",\n }),\n ...UNKNOWN_MAILBOX,\n ...accountState(),\n ...PROVIDER_CHANGE,\n })\n .input(MessageIdInput.extend(UpdateMessage.shape))\n .output(MessageSummary),\n\n delete: base\n .route({\n method: \"DELETE\",\n path: \"/v1/accounts/{accountId}/messages/{messageId}\",\n tags: [\"Mail\"],\n summary: \"Delete a message\",\n description: \"Moves it to Trash; ?permanent=true deletes it outright.\",\n successStatus: 204,\n inputStructure: \"detailed\",\n })\n .errors({\n ...ACCOUNT_NOT_FOUND,\n ...errors({ message_not_found: \"The message does not exist.\" }),\n ...accountState(),\n ...PROVIDER_CHANGE,\n })\n .input(DeleteMessageInput)\n .output(z.void()),\n};\n\nexport const search = {\n messages: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}/search/messages\",\n tags: [\"Mail\"],\n summary: \"Search messages\",\n description: [\n 'source=index searches the index with full-text search (q in web search syntax: words, \"phrases\", OR, -word) over subject, sender and recipient names and addresses, the snippet, and the body text of stored messages (bodyStorage cache or full), best matches first.',\n \"source=provider passes q to the provider unchanged (Gmail search syntax, Microsoft KQL, IMAP SEARCH TEXT), newest first; results the index holds carry their id, others id null.\",\n \"source=auto (default) asks the provider when the index cannot cover the request: `after` lies before the sync window, or the index found nothing while it does not hold everything (the account has a sync window, or bodyStorage is not full). Otherwise, and whenever the provider cannot be asked (inactive account, rate limit, provider error), the index answers.\",\n \"The response names the source that answered; nextCursor stays with it.\",\n \"A provider search of a Gmail account counts against the account's Gmail searches per minute; past them it answers rate_limited with Retry-After.\",\n ].join(\" \"),\n })\n .errors({\n ...ACCOUNT_NOT_FOUND,\n ...errors({ invalid_range: \"before is not after after.\" }),\n ...errors({\n invalid_cursor:\n \"The cursor is invalid, was issued for another account, or is a provider cursor older than an hour.\",\n }),\n ...UNKNOWN_MAILBOX,\n ...accountState(\"With source=provider, the account\"),\n ...PROVIDER_FAILURES,\n ...errors({\n provider_forbidden: \"With source=provider, the provider refused the search.\",\n provider_rejected: \"With source=provider, the provider rejected q.\",\n provider_unsupported: \"With source=provider, the provider cannot run the search.\",\n }),\n })\n .input(\n withDateRange(AccountIdInput.extend(SearchMessagesQuery.shape), {\n from: \"after\",\n to: \"before\",\n }),\n )\n .output(SearchPage),\n};\n",
36
- "import * as z from \"zod\";\nimport { SessionLink, SessionTokenInput } from \"../connect/models.ts\";\nimport { ACCOUNT_NOT_FOUND, base, errors, planModule } from \"../errors.ts\";\nimport { AccountIdInput, publicOperation } from \"../primitives.ts\";\nimport {\n CreateMeetingApp,\n CreateMeetingConnectSession,\n MeetingApp,\n MeetingAppIdInput,\n MeetingAppList,\n MeetingAppTestResult,\n MeetingConnectionInput,\n MeetingConnectionList,\n MeetingConnectSessionPublic,\n TestMeetingAppRequest,\n} from \"./models.ts\";\n\nconst APP_TAGS = [\"Meeting apps\"];\nconst CONNECTION_TAGS = [\"Meeting connections\"];\nconst MEETINGS = planModule(\"Zoom and Webex meetings\");\nconst APP_NOT_FOUND = errors({ meeting_app_not_found: \"The app does not exist.\" });\n\nexport const meetingApps = {\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/meeting-apps\",\n tags: APP_TAGS,\n summary: \"List meeting apps\",\n })\n .errors(MEETINGS)\n .output(MeetingAppList),\n\n create: base\n .route({\n method: \"POST\",\n path: \"/v1/meeting-apps\",\n tags: APP_TAGS,\n summary: \"Register a meeting app\",\n description: `A sign-in app (zoom_oauth, webex_oauth) is named by meeting connect sessions in place of the platform's; register \\`redirectUri\\` at the service. A server app (zoom_s2s, webex_service_app) starts unverified; test it.`,\n successStatus: 201,\n })\n .errors({\n ...MEETINGS,\n ...errors({ meeting_app_exists: \"The tenant already has a server app for the service.\" }),\n })\n .input(CreateMeetingApp)\n .output(MeetingApp),\n\n test: base\n .route({\n method: \"POST\",\n path: \"/v1/meeting-apps/{appId}/test\",\n tags: APP_TAGS,\n summary: \"Test a meeting server app\",\n description: `Requests a token the way meetings will and, with \\`user\\`, looks that address up as a host; the app becomes active or failing.`,\n })\n .errors({\n ...MEETINGS,\n ...APP_NOT_FOUND,\n ...errors({ not_testable: \"The app is a sign-in app, which only account connects use.\" }),\n })\n .input(MeetingAppIdInput.extend(TestMeetingAppRequest.shape))\n .output(MeetingAppTestResult),\n\n delete: base\n .route({\n method: \"DELETE\",\n path: \"/v1/meeting-apps/{appId}\",\n tags: APP_TAGS,\n summary: \"Delete a meeting app\",\n description:\n \"Meetings already created stay at the service. Allowed without the meetings module, so a tenant can remove an app it no longer uses.\",\n successStatus: 204,\n })\n .errors({\n ...APP_NOT_FOUND,\n ...errors({\n meeting_app_in_use: \"Account connections were issued through the sign-in app.\",\n }),\n })\n .input(MeetingAppIdInput)\n .output(z.void()),\n};\n\nexport const meetingConnections = {\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}/meeting-connections\",\n tags: CONNECTION_TAGS,\n summary: \"List an account's meeting connections\",\n })\n .errors({ ...MEETINGS, ...ACCOUNT_NOT_FOUND })\n .input(AccountIdInput)\n .output(MeetingConnectionList),\n\n delete: base\n .route({\n method: \"DELETE\",\n path: \"/v1/accounts/{accountId}/meeting-connections/{service}\",\n tags: CONNECTION_TAGS,\n summary: \"Remove a meeting connection\",\n description:\n \"Deletes the grant (and revokes it at Zoom); meetings created with it stay. Later events use the tenant's server app, if any. Allowed without the meetings module, so a tenant can remove a grant it no longer uses.\",\n successStatus: 204,\n })\n .errors({\n ...ACCOUNT_NOT_FOUND,\n ...errors({ meeting_connection_not_found: \"The account has no connection to the service.\" }),\n })\n .input(MeetingConnectionInput)\n .output(z.void()),\n};\n\nexport const meetingConnectSessions = {\n /** Returns the hosted page's link; the session itself is only read by its token. */\n create: base\n .route({\n method: \"POST\",\n path: \"/v1/accounts/{accountId}/meeting-connect-sessions\",\n tags: CONNECTION_TAGS,\n summary: \"Create a hosted meeting connect session\",\n description:\n \"Returns a link to the hosted page where the account's user signs in to the service; the browser then returns to redirectUri with status=success|error, service, error and state, or without redirectUri to workwae's own confirmation page, which needs no allowlist entry. The sign-in passes a Continue page on the API origin naming the tenant, the service and the account, and must finish in the browser that pressed Continue (an HttpOnly cookie on the API origin); a callback in any other browser renders an error page and connects nothing. A session yields at most one grant: once one sign-in completed it, the others end with error=session_used, and one completing after expiresAt ends with error=session_expired. Connecting again replaces the account's grant for the service.\",\n })\n .errors({\n ...MEETINGS,\n ...ACCOUNT_NOT_FOUND,\n ...errors({\n redirect_uri_not_allowed: \"redirectUri is not on the tenant's allowlist.\",\n unknown_meeting_app: \"meetingAppId names no meeting app of the tenant.\",\n meeting_app_mismatch: \"meetingAppId is not a sign-in app of the service.\",\n meeting_app_secret_unreadable:\n \"The meetingAppId app's secret cannot be decrypted; register the app again.\",\n provider_not_configured:\n \"No meetingAppId is given and the platform has no app for the service.\",\n }),\n })\n .input(AccountIdInput.extend(CreateMeetingConnectSession.shape))\n .output(SessionLink),\n};\n\n/** Unauthenticated: the hosted page reads its session by the token in its URL. */\nexport const hostedMeetingConnectSessions = {\n get: base\n .route({\n method: \"GET\",\n path: \"/v1/hosted/meeting-connect-sessions/{token}\",\n tags: [\"Hosted pages\"],\n summary: \"Read a hosted meeting connect session\",\n spec: publicOperation,\n })\n .errors(\n errors({\n meeting_connect_session_not_found:\n \"No session has this token, or its account no longer exists.\",\n }),\n )\n .input(SessionTokenInput)\n .output(MeetingConnectSessionPublic),\n};\n",
37
- "import * as z from \"zod\";\nimport { base, errors } from \"../errors.ts\";\nimport {\n CreateOAuthApp,\n OAuthApp,\n OAuthAppIdInput,\n OAuthAppList,\n UpdateOAuthApp,\n} from \"./models.ts\";\n\nconst NOT_FOUND = errors({ oauth_app_not_found: \"The OAuth app does not exist.\" });\n\nexport const oauthApps = {\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/oauth-apps\",\n tags: [\"OAuth apps\"],\n summary: \"List tenant OAuth apps\",\n })\n .output(OAuthAppList),\n\n create: base\n .route({\n method: \"POST\",\n path: \"/v1/oauth-apps\",\n tags: [\"OAuth apps\"],\n summary: \"Register a tenant OAuth app\",\n successStatus: 201,\n })\n .errors(\n errors({\n cloud_required: \"provider is microsoft and no cloud is given.\",\n not_microsoft: \"cloud or authority is given for a Google app.\",\n }),\n )\n .input(CreateOAuthApp)\n .output(OAuthApp),\n\n update: base\n .route({\n method: \"PATCH\",\n path: \"/v1/oauth-apps/{appId}\",\n tags: [\"OAuth apps\"],\n summary: \"Change a tenant OAuth app: name, client secret, authority or Gmail push\",\n description:\n \"Accounts on the app use the new secret from their next token refresh. gmailPush (Google apps) makes the app's accounts watch the topic with users.watch instead of being polled; null stops their watches and returns them to polling. Changing it wakes the app's accounts so it applies at once, and saving it again retries a watch Gmail refused.\",\n })\n .errors({\n ...NOT_FOUND,\n ...errors({\n not_microsoft: \"authority is given for a Google app.\",\n gmail_push_unsupported: \"gmailPush is given for a Microsoft app.\",\n push_unavailable: \"gmailPush is set and the instance has no PUSH_BASE_URL.\",\n }),\n })\n .input(OAuthAppIdInput.extend(UpdateOAuthApp.shape))\n .output(OAuthApp),\n\n delete: base\n .route({\n method: \"DELETE\",\n path: \"/v1/oauth-apps/{appId}\",\n tags: [\"OAuth apps\"],\n summary: \"Delete a tenant OAuth app\",\n successStatus: 204,\n })\n .errors({\n ...NOT_FOUND,\n ...errors({ oauth_app_in_use: \"Live accounts still use the app.\" }),\n })\n .input(OAuthAppIdInput)\n .output(z.void()),\n};\n",
38
- "import * as z from \"zod\";\nimport { Account } from \"../accounts/models.ts\";\nimport {\n accountState,\n BILLING_PAST_DUE,\n base,\n bodyStorage,\n errors,\n INVALID_CURSOR,\n PLAN_LIMIT_ACCOUNTS,\n PROVIDER_FAILURES,\n planModule,\n} from \"../errors.ts\";\nimport { AccountIdInput } from \"../primitives.ts\";\nimport {\n AddedMailboxList,\n AddMailboxesRequest,\n ConsentLink,\n CreateOrgConnection,\n DirectoryEntryPage,\n ListDirectoryEntriesQuery,\n OpenSharedMailboxRequest,\n OrgConnection,\n OrgConnectionIdInput,\n OrgConnectionList,\n OrgConnectionTestResult,\n StartConsentRequest,\n TestOrgConnectionRequest,\n UpdateOrgConnection,\n} from \"./models.ts\";\n\nconst NOT_FOUND = errors({\n org_connection_not_found: \"The organization connection does not exist.\",\n});\nconst CONSENT_REQUIRED = errors({\n consent_required: \"No Microsoft directory has consented to the app yet.\",\n});\nconst CREDENTIALS = errors({\n invalid_service_account_key: \"serviceAccountKey is not a usable Google service account key.\",\n invalid_certificate:\n \"The certificate or private key is not a usable PEM certificate and unencrypted PKCS#8 RSA key.\",\n directory_id_not_allowed: \"A directoryId is given for a platform connection.\",\n});\n\nconst TAGS = [\"Organization connections\"];\n\nexport const orgConnections = {\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/org-connections\",\n tags: TAGS,\n summary: \"List organization connections\",\n })\n .output(OrgConnectionList),\n\n create: base\n .route({\n method: \"POST\",\n path: \"/v1/org-connections\",\n tags: TAGS,\n summary: \"Register an organization connection\",\n description:\n \"Google: the service account key is checked and sealed; authorize the returned clientId for the returned scopes in the Admin console, then test. Microsoft: a platform connection starts in pending_consent (POST .../consent); a tenant app with a directoryId starts unverified.\",\n successStatus: 201,\n })\n .errors({\n ...CREDENTIALS,\n ...errors({\n provider_not_configured: \"A platform connection names a cloud the platform has no app for.\",\n }),\n })\n .input(CreateOrgConnection)\n .output(OrgConnection),\n\n get: base\n .route({\n method: \"GET\",\n path: \"/v1/org-connections/{connectionId}\",\n tags: TAGS,\n summary: \"Get an organization connection\",\n })\n .errors(NOT_FOUND)\n .input(OrgConnectionIdInput)\n .output(OrgConnection),\n\n update: base\n .route({\n method: \"PATCH\",\n path: \"/v1/org-connections/{connectionId}\",\n tags: TAGS,\n summary: \"Update an organization connection\",\n description:\n \"Replacing a credential or the authorized scopes makes the connection unverified until the next test.\",\n })\n .errors({\n ...NOT_FOUND,\n ...CREDENTIALS,\n ...errors({\n credential_mismatch:\n \"A field does not apply to this connection's kind or credential type, or a certificate is replaced without its private key.\",\n }),\n })\n .input(OrgConnectionIdInput.extend(UpdateOrgConnection.shape))\n .output(OrgConnection),\n\n delete: base\n .route({\n method: \"DELETE\",\n path: \"/v1/org-connections/{connectionId}\",\n tags: TAGS,\n summary: \"Delete an organization connection\",\n successStatus: 204,\n })\n .errors({\n ...NOT_FOUND,\n ...errors({ connection_in_use: \"Live accounts still authenticate through the connection.\" }),\n })\n .input(OrgConnectionIdInput)\n .output(z.void()),\n\n consent: base\n .route({\n method: \"POST\",\n path: \"/v1/org-connections/{connectionId}/consent\",\n tags: TAGS,\n summary: \"Start Microsoft admin consent\",\n description:\n \"Returns the URL an administrator of the directory grants consent at. Afterwards the browser returns to redirectUri with status=success|error, connection_id, error and state; the connection records the consenting directory and is tested. A tenant app uses /adminconsent. The platform app is consented through a sign-in (authorize with prompt=admin_consent) and records the directory named by the sign-in's ID token; it can only be started from the board, and the board user who started it has to be signed in, in the browser that returns, for the directory to be recorded. Errors on return include access_denied, consent_failed, consent_unverified, directory_mismatch and directory_already_connected (another platform connection holds the directory).\",\n })\n .errors({\n ...NOT_FOUND,\n ...errors({\n not_microsoft: \"The connection is a Google connection.\",\n redirect_uri_not_allowed:\n \"redirectUri is neither on the tenant allowlist (settings.redirectUris) nor the board.\",\n session_required:\n \"A platform connection's consent is started by a caller that is not a board session.\",\n provider_not_configured:\n \"A platform connection's cloud has no platform app (the platform's configuration changed).\",\n }),\n })\n .input(OrgConnectionIdInput.extend(StartConsentRequest.shape))\n .output(ConsentLink),\n\n test: base\n .route({\n method: \"POST\",\n path: \"/v1/org-connections/{connectionId}/test\",\n tags: TAGS,\n summary: \"Test an organization connection\",\n description:\n \"Requests a token the way accounts will and reports each check; the connection becomes active or failing. A passing test returns accounts that were moved to reauth_required to active. Google impersonates `user` (default: the directory admin).\",\n })\n .errors({\n ...NOT_FOUND,\n ...CONSENT_REQUIRED,\n ...errors({\n user_required: \"A Google connection has neither a user nor a directory admin to test as.\",\n }),\n })\n .input(OrgConnectionIdInput.extend(TestOrgConnectionRequest.shape))\n .output(OrgConnectionTestResult),\n\n directoryEntries: base\n .route({\n method: \"GET\",\n path: \"/v1/org-connections/{connectionId}/directory-entries\",\n tags: TAGS,\n summary: \"List the directory's mailboxes\",\n description:\n \"Microsoft: Graph /users (needs User.Read.All). Google: the Admin SDK users.list as the directory admin (needs admin.directory.user.readonly). `query` matches the start of names and addresses. A nextCursor is good for an hour, on this connection only.\",\n })\n .errors({\n ...NOT_FOUND,\n ...CONSENT_REQUIRED,\n ...INVALID_CURSOR,\n ...PROVIDER_FAILURES,\n ...errors({\n directory_unavailable:\n \"The connection may not list the directory: there is no directory admin, the permission or scope is not granted, or the connection cannot get a token (test it).\",\n provider_rejected: \"The provider rejected the listing (e.g. the query).\",\n provider_not_found: \"The provider no longer has the directory.\",\n }),\n })\n .input(OrgConnectionIdInput.extend(ListDirectoryEntriesQuery.shape))\n .output(DirectoryEntryPage),\n\n addAccounts: base\n .route({\n method: \"POST\",\n path: \"/v1/org-connections/{connectionId}/accounts\",\n tags: TAGS,\n summary: \"Add mailboxes as accounts\",\n description:\n \"Each mailbox is checked through the connection before its account is created (Google: a delegated token for it; Microsoft: its inbox). items holds one result per mailbox, in request order. Per-mailbox failures are reported there with the reason the API would answer with, e.g. invalid_grant (no such user), consent_revoked (the scopes or permissions are not granted), provider_forbidden or provider_not_found (no mailbox access), plan_limit_accounts (the plan's account limit was reached part way through; the mailboxes before it are created).\",\n })\n .errors({\n ...NOT_FOUND,\n ...CONSENT_REQUIRED,\n ...bodyStorage(\"settings.bodyStorage\"),\n ...BILLING_PAST_DUE,\n })\n .input(OrgConnectionIdInput.extend(AddMailboxesRequest.shape))\n .output(AddedMailboxList),\n};\n\nexport const sharedMailboxes = {\n create: base\n .route({\n method: \"POST\",\n path: \"/v1/accounts/{accountId}/shared-mailboxes\",\n tags: [\"Shared mailboxes\"],\n summary: \"Open a shared mailbox with an account's grant\",\n description:\n \"Creates (or re-points) an account for a shared mailbox the delegating account's user can access, authenticated with that account's grant: Graph addresses it as /users/{email}; an Exchange IMAP account logs in as user\\\\shared with XOAUTH2. Gmail has no delegated shared mailboxes: add them through a Google domain-wide delegation connection.\",\n successStatus: 201,\n })\n .errors({\n ...planModule(\"shared mailboxes\"),\n ...bodyStorage(\"settings.bodyStorage\"),\n ...PLAN_LIMIT_ACCOUNTS,\n ...BILLING_PAST_DUE,\n ...accountState(\"The delegating account\"),\n ...PROVIDER_FAILURES,\n ...errors({\n account_not_found: \"The delegating account does not exist.\",\n shared_mailbox_unsupported:\n \"The delegating account is Gmail, password IMAP, or itself shared or organization-authenticated, or the mailbox is its own.\",\n scope_missing:\n \"The delegating account's grant lacks the shared mailbox scope (reconnect it with options.sharedMailboxesEnabled).\",\n shared_mailbox_inaccessible:\n \"The delegating account's user cannot open the mailbox (no access, no such mailbox, or the login is refused).\",\n account_exists: \"The mailbox is already an account authenticated another way.\",\n }),\n })\n .input(AccountIdInput.extend(OpenSharedMailboxRequest.shape))\n .output(Account),\n};\n",
39
- "// Draft, send and outbox procedures. All are account-scoped (/v1/accounts/{accountId}/...) and also\n// callable with an account token for that account.\nimport * as z from \"zod\";\nimport {\n ACCOUNT_NOT_FOUND,\n accountState,\n BILLING_PAST_DUE,\n base,\n errors,\n INVALID_CURSOR,\n PROVIDER_FAILURES,\n} from \"../errors.ts\";\nimport {\n MAX_MAIL_MERGE_ATTACHMENT_BYTES,\n MAX_MAIL_MERGE_ENTRIES,\n MAX_MARKDOWN_LENGTH,\n MAX_RENDER_ITERATIONS,\n MAX_RENDER_PARAMS_BYTES,\n} from \"../limits.ts\";\nimport { MessageIdInput, MessageSummary } from \"../mail/models.ts\";\nimport { PROVIDER_CHANGE } from \"../mail/routes.ts\";\nimport { AccountIdInput } from \"../primitives.ts\";\nimport {\n ComposeWithTemplate,\n ListOutboxQuery,\n ListTrackingEventsQuery,\n MailMergeRequest,\n MailMergeResultList,\n OutboxEntry,\n OutboxEntryPage,\n OutboxIdInput,\n QueuedSend,\n RescheduleSendRequest,\n SendMessageRequest,\n SendOptions,\n TrackingEventPage,\n} from \"./models.ts\";\n\n// What naming a list does, shared by both ways of sending.\nconst LIST =\n \"With listId, content is always rendered, `{{rcpt.unsubscribeUrl}}`, `{{rcpt.address}}` and `{{rcpt.name}}` are the recipient's, and the message carries List-Unsubscribe with that same URL and List-Unsubscribe-Post: List-Unsubscribe=One-Click (RFC 8058). Click tracking never rewrites a List-Unsubscribe URL, so the body's link stays as written. A recipient on that list or on the global list is not sent to, at queue time and again at delivery (send.failed with code suppressed). Without listId no list is consulted. Whether the provider's DKIM signature covers the List-Unsubscribe headers is up to its signing.\";\n\n// How undo works, shared by both ways of sending.\nconst UNDO =\n \"A message without a sendAt later than the account's undo window (undoSendSeconds) from now waits out the window; undoUntil says until when cancelling the entry (DELETE .../outbox/{outboxId}) undoes the send.\";\n\n// What delivery guarantees, shared by both ways of sending.\nconst DELIVERY =\n \"Delivery is at-least-once, except outcome_unknown (below), and without order across retries: an account's entries are first tried in queue order, but one backing off after a failed attempt does not hold up the later ones. A retry first looks for a copy that already went out. When no SMTP reply comes after the final dot was handed to the operating system (the connection dropped or timed out, or the attempt ran out of time), the server may have accepted the message, so it is not sent again: send.failed carries code outcome_unknown and the client app decides whether to resend.\";\n\n// How tracking works, shared by both ways of sending.\nconst TRACKING =\n \"With tracking, the HTML part gets a 1x1 pixel (opens) and its http(s) links point at workwae's redirect (clicks), reported as message.opened and message.clicked and counted on the outbox entry; text parts are left as they are. With clicks, tracking.honeypot (else the account's trackingHoneypot) also adds one hidden link only machines follow; it does nothing without clicks, so asking for it with clicks off is refused rather than ignored. Tracking is per message, not per recipient: every recipient gets the same MIME.\";\n\n// How a mail merge fans out.\nconst MAIL_MERGE = `Each of at most ${MAX_MAIL_MERGE_ENTRIES} entries becomes its own outbox entry and message, addressed to its to alone, with its own Message-ID, events, bounce matching and tracking; the answer has one result per entry, in order. Content is rendered per entry with its params (a template always; inline content only for entries that carry params, or with listId). An entry that cannot be queued fails alone, its result naming the reason (invalid_recipient, invalid_message_id, duplicate_message_id, template_render_failed, plan_limit_sends once the day's sends run out, suppressed when listId is given and the address is on that list or the global list, internal_error), while the others go ahead; the call itself succeeds. The body is the send body without to, cc, bcc and render: an unknown field is refused.`;\n\n// What composing answers, shared by drafts and sends. Provider failures only happen when the\n// identities or the draft had to be read or written.\nconst COMPOSE_ERRORS = {\n ...ACCOUNT_NOT_FOUND,\n ...errors({\n from_not_allowed: \"from is not one of the account's identities.\",\n attachments_too_large: \"The attachments exceed the provider's limit.\",\n unknown_reply_target: \"inReplyToMessageId names no message of the account.\",\n }),\n ...accountState(),\n ...PROVIDER_FAILURES,\n};\n\n// What composing with a template answers, shared by drafts and sends.\nconst TEMPLATE_ERRORS = errors({\n unknown_template: \"template names no template of the tenant.\",\n template_account_mismatch: \"The template is bound to another account.\",\n template_and_inline_fields:\n \"template comes with an inline subject, html, text, previewText or format.\",\n invalid_template:\n \"Inline content to render is not valid Handlebars or uses partials or decorators; data.field names the field.\",\n params_too_large: `params exceed ${MAX_RENDER_PARAMS_BYTES} bytes as JSON.`,\n template_render_failed: `Rendering fails (a missing helper, more than ${MAX_RENDER_ITERATIONS} block iterations, a field rendered past its limit, Markdown longer than ${MAX_MARKDOWN_LENGTH} characters, rendered or not); data.field names the field.`,\n});\nconst RENDERED_ONCE =\n \"Content is rendered when the request is taken, so later template edits never change it.\";\n\n// What both ways of sending answer about tracking.\nconst TRACKING_ERRORS = errors({\n honeypot_needs_click_tracking: \"tracking.honeypot is true and click tracking is off.\",\n plan_module_unavailable:\n \"Tracking is asked for and the tenant's plan does not include it (nor do the account's tracking defaults apply then).\",\n});\nconst LIST_UNSUBSCRIBE_UNAVAILABLE = errors({\n list_unsubscribe_unavailable: \"listId is given and TRACKING_BASE_URL is not https.\",\n});\nconst PLAN_LIMIT_SENDS = errors({\n plan_limit_sends: \"The tenant already queued as many sends today (UTC) as its plan allows.\",\n});\n\nconst DRAFT_NOT_FOUND = errors({ draft_not_found: \"The message does not exist or is no draft.\" });\n\nexport const drafts = {\n create: base\n .route({\n method: \"POST\",\n path: \"/v1/accounts/{accountId}/drafts\",\n tags: [\"Mail\"],\n summary: \"Create a draft\",\n description: RENDERED_ONCE,\n successStatus: 201,\n })\n .errors({\n ...COMPOSE_ERRORS,\n ...TEMPLATE_ERRORS,\n ...PROVIDER_CHANGE,\n ...errors({ draft_lost: \"The provider took the draft but did not answer it back.\" }),\n })\n .input(AccountIdInput.extend(ComposeWithTemplate.shape))\n .output(MessageSummary),\n\n update: base\n .route({\n method: \"PUT\",\n path: \"/v1/accounts/{accountId}/drafts/{messageId}\",\n tags: [\"Mail\"],\n summary: \"Replace a draft's content\",\n description: RENDERED_ONCE,\n })\n .errors({ ...COMPOSE_ERRORS, ...TEMPLATE_ERRORS, ...PROVIDER_CHANGE, ...DRAFT_NOT_FOUND })\n .input(MessageIdInput.extend(ComposeWithTemplate.shape))\n .output(MessageSummary),\n\n delete: base\n .route({\n method: \"DELETE\",\n path: \"/v1/accounts/{accountId}/drafts/{messageId}\",\n tags: [\"Mail\"],\n summary: \"Delete a draft\",\n successStatus: 204,\n })\n .errors({ ...ACCOUNT_NOT_FOUND, ...DRAFT_NOT_FOUND, ...accountState(), ...PROVIDER_CHANGE })\n .input(MessageIdInput)\n .output(z.void()),\n\n send: base\n .route({\n method: \"POST\",\n path: \"/v1/accounts/{accountId}/drafts/{messageId}/send\",\n tags: [\"Mail\"],\n summary: \"Send a draft\",\n description: `${UNDO} ${TRACKING} A Gmail or Microsoft 365 draft is sent by the provider as it is stored, so it is never tracked (the account's defaults do not apply); an IMAP draft is. A cancelled draft-send leaves the draft in place.`,\n successStatus: 201,\n })\n .errors({\n ...ACCOUNT_NOT_FOUND,\n ...DRAFT_NOT_FOUND,\n ...accountState(),\n ...errors({\n not_a_draft: \"The message stopped being a draft while the send was queued.\",\n no_recipients: \"The draft has no to, cc or bcc recipients (as last indexed).\",\n tracking_unsupported:\n \"Tracking (opens, clicks or honeypot) is asked for a Gmail or Microsoft 365 draft.\",\n }),\n ...TRACKING_ERRORS,\n ...PLAN_LIMIT_SENDS,\n ...BILLING_PAST_DUE,\n })\n .input(MessageIdInput.extend(SendOptions.shape))\n .output(QueuedSend),\n};\n\n// A send's recipients come with it, so having none is refused with the input.\nconst SEND_INPUT = AccountIdInput.extend(SendMessageRequest.shape)\n .strict()\n .superRefine((send, ctx) => {\n if (send.to.length + send.cc.length + send.bcc.length === 0)\n ctx.addIssue({\n code: \"custom\",\n path: [\"to\"],\n message: \"The message has no recipients (to, cc or bcc)\",\n params: { reason: \"no_recipients\" },\n });\n });\n\nconst SEND_NOT_FOUND = errors({ send_not_found: \"The account has no such outbox entry.\" });\n\nexport const outbox = {\n create: base\n .route({\n method: \"POST\",\n path: \"/v1/accounts/{accountId}/outbox\",\n tags: [\"Mail\"],\n summary: \"Send a message\",\n description: `Queues the message as an outbox entry; delivery is reported with send.sent, send.retrying and send.failed events carrying its id as outboxId, and a later bounce with message.bounced. ${DELIVERY} ${UNDO} ${TRACKING} ${LIST} For one message per recipient, see POST .../mail-merges. ${RENDERED_ONCE} An unknown field is refused.`,\n successStatus: 201,\n })\n .errors({\n ...COMPOSE_ERRORS,\n ...TEMPLATE_ERRORS,\n ...errors({\n no_recipients: \"to, cc and bcc are all empty.\",\n list_send_recipients:\n \"listId is given and the message has not exactly one to and no cc or bcc.\",\n suppressed: \"listId is given and the recipient is on that list or the global list.\",\n }),\n ...TRACKING_ERRORS,\n ...LIST_UNSUBSCRIBE_UNAVAILABLE,\n ...PLAN_LIMIT_SENDS,\n ...BILLING_PAST_DUE,\n })\n .input(SEND_INPUT)\n .output(QueuedSend),\n\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}/outbox\",\n tags: [\"Mail\"],\n summary: \"List queued and recent sends, newest first\",\n description: \"status keeps the entries in that status.\",\n })\n .errors({ ...ACCOUNT_NOT_FOUND, ...INVALID_CURSOR })\n .input(AccountIdInput.extend(ListOutboxQuery.shape))\n .output(OutboxEntryPage),\n\n get: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}/outbox/{outboxId}\",\n tags: [\"Mail\"],\n summary: \"Get a send\",\n description:\n \"One entry with its tracking counts, for as long as the outbox keeps it: a sent message's outboxId names it.\",\n })\n .errors({ ...ACCOUNT_NOT_FOUND, ...SEND_NOT_FOUND })\n .input(OutboxIdInput)\n .output(OutboxEntry),\n\n cancel: base\n .route({\n method: \"DELETE\",\n path: \"/v1/accounts/{accountId}/outbox/{outboxId}\",\n tags: [\"Mail\"],\n summary: \"Cancel a queued send\",\n description: \"Undoes a send while it waits for its sendAt.\",\n successStatus: 204,\n })\n .errors({\n ...ACCOUNT_NOT_FOUND,\n ...SEND_NOT_FOUND,\n ...errors({\n send_not_cancellable:\n \"The entry is no longer queued: it is being sent, was sent, failed for good or was cancelled (the message names which).\",\n }),\n })\n .input(OutboxIdInput)\n .output(z.void()),\n\n reschedule: base\n .route({\n method: \"PATCH\",\n path: \"/v1/accounts/{accountId}/outbox/{outboxId}\",\n tags: [\"Mail\"],\n summary: \"Reschedule a queued send\",\n description:\n \"Moves sendAt, earlier or later; a past sendAt sends as soon as possible. Announced as send.rescheduled.\",\n })\n .errors({\n ...ACCOUNT_NOT_FOUND,\n ...SEND_NOT_FOUND,\n ...errors({\n send_not_reschedulable:\n \"The entry is no longer queued (it is being sent, was sent, failed for good or was cancelled), or it is queued again after a failed attempt; the message names which.\",\n }),\n })\n .input(OutboxIdInput.extend(RescheduleSendRequest.shape))\n .output(OutboxEntry),\n\n tracking: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}/outbox/{outboxId}/tracking\",\n tags: [\"Mail\"],\n summary: \"List a send's opens and clicks\",\n description:\n \"Newest first. At most 1000 are kept per send (the counts on the entry keep going), each for the tracking retention period. Each event carries what its request showed: the method (GET or HEAD), the Referer and Origin hosts, the mail client (Gmail's image proxy, web or app; Outlook on the web, desktop or mobile; Apple Mail and its Mail Privacy Protection; Yahoo, AOL, Thunderbird, Proton, Fastmail, Zoho, iCloud, a self-hosted webmail; else unknown), the device, OS and browser families, Cloudflare's visitor location (country, region, city, timezone, latitude and longitude, behind a trusted proxy only), the seconds after the send and since the send's previous hit, its sequence number, whether it was conditional, a Range request or a prefetch, the sec-fetch tuple, and the request headers (lower-cased, values cut at 1024 characters, at most 64, never Cookie, Authorization or Proxy-Authorization, forwarding and cf-* headers only from the trusted proxy; the full Referer is only here). Full addresses and headers stay with the tenant for the retention period.\",\n })\n .errors({ ...ACCOUNT_NOT_FOUND, ...INVALID_CURSOR, ...SEND_NOT_FOUND })\n .input(OutboxIdInput.extend(ListTrackingEventsQuery.shape))\n .output(TrackingEventPage),\n};\n\nexport const mailMerges = {\n create: base\n .route({\n method: \"POST\",\n path: \"/v1/accounts/{accountId}/mail-merges\",\n tags: [\"Mail\"],\n summary: \"Send one message per recipient (mail merge)\",\n description: `${MAIL_MERGE} ${DELIVERY} ${UNDO} ${TRACKING} ${LIST} What holds for the whole call is checked once and refuses it. ${RENDERED_ONCE} Answers 200: the merge itself is not kept, its entries are in the outbox.`,\n })\n .errors({\n ...COMPOSE_ERRORS,\n ...TEMPLATE_ERRORS,\n ...errors({\n attachments_too_large: `The attachments exceed the provider's limit, or the attachments times the entries exceed ${MAX_MAIL_MERGE_ATTACHMENT_BYTES} bytes.`,\n }),\n ...TRACKING_ERRORS,\n ...LIST_UNSUBSCRIBE_UNAVAILABLE,\n ...BILLING_PAST_DUE,\n })\n .input(AccountIdInput.extend(MailMergeRequest.shape).strict())\n .output(MailMergeResultList),\n};\n",
40
- "import { base, bodyStorage, errors } from \"../errors.ts\";\nimport { TenantSettings, UpdateTenantSettings } from \"./models.ts\";\n\nexport const settings = {\n get: base\n .route({\n method: \"GET\",\n path: \"/v1/settings\",\n tags: [\"Settings\"],\n summary: \"Get tenant settings\",\n })\n .output(TenantSettings),\n\n update: base\n .route({\n method: \"PATCH\",\n path: \"/v1/settings\",\n tags: [\"Settings\"],\n summary: \"Update tenant settings\",\n description:\n \"bodyStorage applies to every account without its own override; changing it restarts their syncs (full stores and backfills every indexed message, none deletes stored content).\",\n })\n .errors({\n ...bodyStorage(\"bodyStorage\"),\n ...errors({\n redirect_uri_not_allowed: \"A redirect URI is not absolute https (http only for localhost).\",\n }),\n })\n .input(UpdateTenantSettings)\n .output(TenantSettings),\n};\n",
41
- "import * as z from \"zod\";\nimport { base, errors, INVALID_CURSOR } from \"../errors.ts\";\nimport { MAX_SUPPRESSION_BATCH } from \"../limits.ts\";\nimport {\n AddSuppressionEntriesRequest,\n CreateSuppressionList,\n DeleteSuppressionListInput,\n ListIdInput,\n ListSuppressionEntriesQuery,\n ListSuppressionReviewsQuery,\n ReviewIdInput,\n SuppressionAdded,\n SuppressionEntriesAdded,\n SuppressionEntryInput,\n SuppressionEntryPage,\n SuppressionList,\n SuppressionListIdInput,\n SuppressionListList,\n SuppressionReviewPage,\n UpdateSuppressionList,\n} from \"./models.ts\";\n\nconst LIST_NOT_FOUND = errors({\n suppression_list_not_found: \"The list does not exist (the global list has none to change).\",\n});\nconst REVIEW_NOT_FOUND = errors({\n suppression_review_not_found: \"The review does not exist.\",\n});\n\nexport const suppressions = {\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/suppressions\",\n tags: [\"Suppressions\"],\n summary: \"List suppression lists\",\n description:\n \"The global list first, then every named list by listId, with its counts by source.\",\n })\n .output(SuppressionListList),\n\n create: base\n .route({\n method: \"POST\",\n path: \"/v1/suppressions\",\n tags: [\"Suppressions\"],\n summary: \"Create a suppression list\",\n description:\n \"id is what sends name as listId; it cannot change later, the name and description can. A send or add naming a list that does not exist creates it too, named after its id.\",\n successStatus: 201,\n })\n .errors(errors({ suppression_list_exists: \"A list with that id exists.\" }))\n .input(CreateSuppressionList)\n .output(SuppressionList),\n\n update: base\n .route({\n method: \"PATCH\",\n path: \"/v1/suppressions/{listId}\",\n tags: [\"Suppressions\"],\n summary: \"Update a suppression list\",\n description:\n \"Only the fields given change; description null clears it. The global list cannot be changed.\",\n })\n .errors(LIST_NOT_FOUND)\n .input(ListIdInput.extend(UpdateSuppressionList.shape))\n .output(SuppressionList),\n\n delete: base\n .route({\n method: \"DELETE\",\n path: \"/v1/suppressions/{listId}\",\n tags: [\"Suppressions\"],\n summary: \"Delete a suppression list\",\n description:\n \"Deletes the list and its pending reviews and, with ?withEntries=true, every address on it: later sends naming it reach those addresses again (unless the global list holds them), and the next one naming it creates it anew. The global list cannot be deleted.\",\n successStatus: 204,\n inputStructure: \"detailed\",\n })\n .errors({\n ...LIST_NOT_FOUND,\n ...errors({\n suppression_list_not_empty: \"The list holds addresses and withEntries is not true.\",\n }),\n })\n .input(DeleteSuppressionListInput)\n .output(z.void()),\n\n entries: {\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/suppressions/{listId}/entries\",\n tags: [\"Suppressions\"],\n summary: \"List suppressed addresses\",\n description:\n \"Addresses on one list, by address; a list without addresses is empty, not missing. address keeps those containing it, source those that came from it.\",\n })\n .errors(INVALID_CURSOR)\n .input(SuppressionListIdInput.extend(ListSuppressionEntriesQuery.shape))\n .output(SuppressionEntryPage),\n\n add: base\n .route({\n method: \"POST\",\n path: \"/v1/suppressions/{listId}/entries\",\n tags: [\"Suppressions\"],\n summary: \"Suppress addresses\",\n description: `Puts up to ${MAX_SUPPRESSION_BATCH} addresses on the list in one call; a repeated address counts once. added counts the addresses put on the list, alreadyListed those that were on it already, which are left as they were. A list that does not exist is created, named after its listId. Answers 200: entries are listed, not fetched one by one. Emits no suppression.created: that event reports what recipients and bounces did.`,\n })\n .input(SuppressionListIdInput.extend(AddSuppressionEntriesRequest.shape))\n .output(SuppressionEntriesAdded),\n\n remove: base\n .route({\n method: \"DELETE\",\n path: \"/v1/suppressions/{listId}/entries/{address}\",\n tags: [\"Suppressions\"],\n summary: \"Release an address\",\n description:\n \"Later sends naming the list reach the address again (unless another list they consult holds it).\",\n successStatus: 204,\n })\n .errors(errors({ suppression_entry_not_found: \"The address is not on the list.\" }))\n .input(SuppressionEntryInput)\n .output(z.void()),\n },\n};\n\nexport const suppressionReviews = {\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/suppression-reviews\",\n tags: [\"Suppressions\"],\n summary: \"List opt-outs to review\",\n description:\n \"Detected opt-outs waiting for a person, newest first; listId keeps one list's. Holds AI-classified opt-out replies while optOutHandling is review, and auto-replies saying the person is no longer at the address (source inactive, on the global list) while it is review or suppress. A detection of an address already on its list, or already waiting, is not queued again.\",\n })\n .errors(INVALID_CURSOR)\n .input(ListSuppressionReviewsQuery)\n .output(SuppressionReviewPage),\n\n approve: base\n .route({\n method: \"POST\",\n path: \"/v1/suppression-reviews/{reviewId}/approve\",\n tags: [\"Suppressions\"],\n summary: \"Approve an opt-out\",\n description:\n \"Puts the address on the review's list with the review's source and removes the review. added is false when the address was on the list already. Emits suppression.created when it was not.\",\n })\n .errors(REVIEW_NOT_FOUND)\n .input(ReviewIdInput)\n .output(SuppressionAdded),\n\n dismiss: base\n .route({\n method: \"POST\",\n path: \"/v1/suppression-reviews/{reviewId}/dismiss\",\n tags: [\"Suppressions\"],\n summary: \"Dismiss an opt-out\",\n description:\n \"Removes the review without suppressing anything; a later detection of the same address queues it again.\",\n successStatus: 204,\n })\n .errors(REVIEW_NOT_FOUND)\n .input(ReviewIdInput)\n .output(z.void()),\n};\n",
42
- "// Stored message templates. Tenant-scoped (/v1/templates), each usable by every account or bound\n// to one. Sends name one with `template` (see outbox.create).\nimport * as z from \"zod\";\nimport { base, errors, INVALID_CURSOR } from \"../errors.ts\";\nimport { MAX_MARKDOWN_LENGTH, MAX_RENDER_ITERATIONS, MAX_RENDER_PARAMS_BYTES } from \"../limits.ts\";\nimport {\n CreateTemplate,\n ListTemplatesQuery,\n RenderedTemplate,\n RenderTemplateRequest,\n Template,\n TemplateIdInput,\n TemplateSummaryPage,\n UpdateTemplate,\n} from \"./models.ts\";\n\nconst NOT_FOUND = errors({ template_not_found: \"The template does not exist.\" });\nconst SYNTAX = errors({\n invalid_template:\n \"A field is not valid Handlebars or uses partials or decorators (data names the field, the message is the parser's).\",\n});\nconst NAME_TAKEN = errors({\n template_name_taken:\n \"The scope (the tenant, or the bound account) already has a template of that name.\",\n});\nconst UNKNOWN_ACCOUNT = errors({\n unknown_account: \"The accountId names an account the tenant does not have (data lists it).\",\n});\n\nexport const templates = {\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/templates\",\n tags: [\"Templates\"],\n summary: \"List templates\",\n description:\n \"Newest first, without their content (GET /v1/templates/{templateId} has it). accountId lists those bound to that account; usableBy those the account may send with (the tenant's shared ones and its own); name the ones of that exact name, one per scope; query those whose name contains it, ignoring case.\",\n })\n .errors(INVALID_CURSOR)\n .input(ListTemplatesQuery)\n .output(TemplateSummaryPage),\n\n get: base\n .route({\n method: \"GET\",\n path: \"/v1/templates/{templateId}\",\n tags: [\"Templates\"],\n summary: \"Get a template\",\n })\n .errors(NOT_FOUND)\n .input(TemplateIdInput)\n .output(Template),\n\n create: base\n .route({\n method: \"POST\",\n path: \"/v1/templates\",\n tags: [\"Templates\"],\n summary: \"Create a template\",\n description: \"Every field is checked to compile as Handlebars.\",\n successStatus: 201,\n })\n .errors({ ...SYNTAX, ...UNKNOWN_ACCOUNT, ...NAME_TAKEN })\n .input(CreateTemplate)\n .output(Template),\n\n update: base\n .route({\n method: \"PATCH\",\n path: \"/v1/templates/{templateId}\",\n tags: [\"Templates\"],\n summary: \"Update a template\",\n description: \"Only the fields given change; queued sends keep what they were rendered with.\",\n })\n .errors({ ...NOT_FOUND, ...SYNTAX, ...NAME_TAKEN })\n .input(TemplateIdInput.extend(UpdateTemplate.shape))\n .output(Template),\n\n delete: base\n .route({\n method: \"DELETE\",\n path: \"/v1/templates/{templateId}\",\n tags: [\"Templates\"],\n summary: \"Delete a template\",\n description: \"Queued sends keep their rendered content.\",\n successStatus: 204,\n })\n .errors(NOT_FOUND)\n .input(TemplateIdInput)\n .output(z.void()),\n};\n\n// Rendering creates nothing: the answer is the rendered content, kept nowhere.\nexport const templateRenders = {\n create: base\n .route({\n method: \"POST\",\n path: \"/v1/template-renders\",\n tags: [\"Templates\"],\n summary: \"Render a template without sending\",\n description:\n \"Renders a stored template (templateId) or inline fields with params, as a send would. account.email and account.name come from accountId, else from the template's own account, else render empty.\",\n })\n .errors({\n ...SYNTAX,\n ...UNKNOWN_ACCOUNT,\n ...errors({\n template_and_inline_fields: \"The templateId comes with inline fields or format.\",\n unknown_template: \"The templateId names no template of the tenant.\",\n template_account_mismatch: \"The template is bound to another account than accountId.\",\n params_too_large: `The params exceed ${MAX_RENDER_PARAMS_BYTES} bytes as JSON.`,\n template_render_failed: `Rendering fails: a missing helper, more than ${MAX_RENDER_ITERATIONS} block iterations, a field rendered past its limit, or Markdown longer than ${MAX_MARKDOWN_LENGTH} characters (data names the field).`,\n }),\n })\n .input(RenderTemplateRequest)\n .output(RenderedTemplate),\n};\n",
43
- "// Thread procedures, built from the mail index. Account-scoped (/v1/accounts/{accountId}/...) and\n// also callable with an account token for that account.\nimport * as z from \"zod\";\nimport { ACCOUNT_NOT_FOUND, accountState, base, errors, INVALID_CURSOR } from \"../errors.ts\";\nimport { PROVIDER_CHANGE, UNKNOWN_MAILBOX } from \"../mail/routes.ts\";\nimport { AccountIdInput } from \"../primitives.ts\";\nimport {\n ListThreadsQuery,\n Thread,\n ThreadIdInput,\n ThreadSummaryPage,\n UpdateThread,\n} from \"./models.ts\";\n\nconst THREAD_NOT_FOUND = errors({\n thread_not_found: \"The account has no message in the thread.\",\n});\n\n// What every action shares: the per-message provider operations and how they fail.\nconst ACTION_ERRORS = {\n ...ACCOUNT_NOT_FOUND,\n ...THREAD_NOT_FOUND,\n ...accountState(),\n ...PROVIDER_CHANGE,\n};\nconst PART_WAY =\n \"A failure part way leaves the messages done so far changed; repeating the call finishes the rest.\";\n\nexport const threads = {\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}/threads\",\n tags: [\"Mail\"],\n summary: \"List threads, latest activity first\",\n description:\n \"Covers the account's sync window. With mailboxId, lists threads with a message in that mailbox, ordered by their latest message there; each summary still describes the whole thread.\",\n })\n .errors({ ...ACCOUNT_NOT_FOUND, ...INVALID_CURSOR, ...UNKNOWN_MAILBOX })\n .input(AccountIdInput.extend(ListThreadsQuery.shape))\n .output(ThreadSummaryPage),\n\n get: base\n .route({\n method: \"GET\",\n path: \"/v1/accounts/{accountId}/threads/{threadId}\",\n tags: [\"Mail\"],\n summary: \"Get a thread with its messages, oldest first\",\n })\n .errors({ ...ACCOUNT_NOT_FOUND, ...THREAD_NOT_FOUND })\n .input(ThreadIdInput)\n .output(Thread),\n\n update: base\n .route({\n method: \"PATCH\",\n path: \"/v1/accounts/{accountId}/threads/{threadId}\",\n tags: [\"Mail\"],\n summary: \"Mark a thread read or unread, or move it\",\n description: `Applies the change to every message of the thread through the message operations; messages already in that state are skipped. mailboxId moves each message there (Gmail: replaces its folder-like labels). ${PART_WAY}`,\n })\n .errors({ ...ACTION_ERRORS, ...UNKNOWN_MAILBOX })\n .input(ThreadIdInput.extend(UpdateThread.shape))\n .output(Thread),\n\n delete: base\n .route({\n method: \"DELETE\",\n path: \"/v1/accounts/{accountId}/threads/{threadId}\",\n tags: [\"Mail\"],\n summary: \"Move a thread to Trash\",\n description: `Moves every message of the thread that is not already there to Trash. ${PART_WAY}`,\n successStatus: 204,\n })\n .errors(ACTION_ERRORS)\n .input(ThreadIdInput)\n .output(z.void()),\n};\n",
44
- "import * as z from \"zod\";\nimport { DEFAULT_THREAD_PAGE_SIZE, MAX_THREAD_PAGE_SIZE } from \"../limits.ts\";\nimport { MessageSummary } from \"../mail/models.ts\";\nimport {\n AccountIdInput,\n Address,\n Cursor,\n Id,\n named,\n Page,\n ProviderId,\n pageLimit,\n Timestamp,\n} from \"../primitives.ts\";\n\n/**\n * A conversation: the indexed messages sharing a threadId (Gmail thread, Microsoft conversation,\n * IMAP server thread or References root). Messages without a threadId belong to no thread.\n */\nexport const ThreadSummary = named(\n \"ThreadSummary\",\n z.object({\n /** The messages' threadId. */\n id: ProviderId,\n /** The subject of the thread's first message that has one. */\n subject: z.string().nullable(),\n /** Of the latest message. */\n snippet: z.string().nullable(),\n /** Distinct senders, in the order they first wrote. */\n participants: z.array(Address),\n messageCount: z.number().int(),\n unreadCount: z.number().int(),\n isFlagged: z.boolean(),\n hasAttachments: z.boolean(),\n hasDrafts: z.boolean(),\n /** Every mailbox holding one of the messages. */\n mailboxIds: z.array(Id),\n /** The latest message (by receivedAt) and when it arrived. */\n latestMessageId: Id,\n lastMessageAt: Timestamp.nullable(),\n }),\n);\nexport type ThreadSummary = z.infer<typeof ThreadSummary>;\n\nexport const Thread = named(\n \"Thread\",\n ThreadSummary.extend({\n /** Oldest first, by receivedAt; messages without one come last. */\n messages: z.array(MessageSummary),\n }),\n);\nexport type Thread = z.infer<typeof Thread>;\n\nexport const ThreadSummaryPage = Page(ThreadSummary);\nexport type ThreadSummaryPage = z.infer<typeof ThreadSummaryPage>;\n\n/** A message's threadId, percent-encoded in the path (IMAP thread ids can contain \"/\"). */\nexport const ThreadIdInput = named(\n \"ThreadIdInput\",\n AccountIdInput.extend({ threadId: ProviderId }),\n);\nexport type ThreadIdInput = z.infer<typeof ThreadIdInput>;\n\nexport const ListThreadsQuery = named(\n \"ListThreadsQuery\",\n z.object({\n mailboxId: Id.optional(),\n limit: pageLimit(MAX_THREAD_PAGE_SIZE, DEFAULT_THREAD_PAGE_SIZE),\n cursor: Cursor.optional(),\n }),\n);\nexport type ListThreadsQuery = z.infer<typeof ListThreadsQuery>;\n\nexport const UpdateThread = named(\n \"UpdateThread\",\n z.object({ isRead: z.boolean().optional(), mailboxId: Id.optional() }),\n);\nexport type UpdateThread = z.infer<typeof UpdateThread>;\n",
45
- "// A tenant's plan and its usage against it.\nimport * as z from \"zod\";\nimport { MAX_STRIPE_ID_LENGTH, MAX_USAGE_RANGE_DAYS } from \"../limits.ts\";\nimport { DateOnly, Id, named, withDateRange } from \"../primitives.ts\";\n\n/** The optional capabilities a plan includes. Mail is always included. */\nexport const PlanModules = named(\n \"PlanModules\",\n z.object({\n calendar: z.boolean(),\n contacts: z.boolean(),\n /** Open and click tracking on sends. */\n tracking: z.boolean(),\n /** Reply classification and drafts. */\n ai: z.boolean(),\n /** Zoom and Webex meetings. */\n meetings: z.boolean(),\n sharedMailboxes: z.boolean(),\n }),\n);\nexport type PlanModules = z.infer<typeof PlanModules>;\nexport type PlanModule = keyof PlanModules;\n\n/** What the base fee covers; null = all of it (no overage billed). */\nexport const PlanIncluded = named(\n \"PlanIncluded\",\n z.object({\n accounts: z.number().int().min(0).nullable(),\n sendsPerMonth: z.number().int().min(0).nullable(),\n aiCallsPerMonth: z.number().int().min(0).nullable(),\n storageBytes: z.number().int().min(0).nullable(),\n }),\n);\nexport type PlanIncluded = z.infer<typeof PlanIncluded>;\n\n/** Minor units of the currency (cents for usd). */\nconst Amount = z.number().int().min(0);\n/** A Stripe price id; null when the component is not billed. */\nconst StripePrice = z\n .string()\n .regex(/^price_[A-Za-z0-9]+$/)\n .max(MAX_STRIPE_ID_LENGTH)\n .nullable();\n\nexport const PlanStripePrices = named(\n \"PlanStripePrices\",\n z.object({\n basePrice: StripePrice,\n accountPrice: StripePrice,\n sendsPrice: StripePrice,\n aiCallsPrice: StripePrice,\n storagePrice: StripePrice,\n }),\n);\nexport type PlanStripePrices = z.infer<typeof PlanStripePrices>;\n\nexport const PlanPricing = named(\n \"PlanPricing\",\n z.object({\n /** ISO 4217, lowercase as Stripe writes it. */\n currency: z.string().regex(/^[a-z]{3}$/),\n baseMonthly: Amount,\n /** Each account beyond included.accounts, per month. */\n perAccountMonthly: Amount,\n /** Per 1,000 sends beyond included.sendsPerMonth. */\n sendsPer1k: Amount,\n /** Per 1,000 AI calls beyond included.aiCallsPerMonth. */\n aiCallsPer1k: Amount,\n /** Per GB-month stored beyond included.storageBytes. */\n storagePerGbMonth: Amount,\n stripe: PlanStripePrices,\n }),\n);\nexport type PlanPricing = z.infer<typeof PlanPricing>;\n\n/** Count limits: null = unlimited. They are abuse ceilings; usage between included and a limit\n * is billed as overage. */\nexport const PlanLimits = named(\n \"PlanLimits\",\n z.object({\n maxAccounts: z.number().int().min(0).nullable(),\n sendsPerDay: z.number().int().min(0).nullable(),\n /** The whole tenant, every credential together. */\n apiCallsPerMinute: z.number().int().min(1).nullable(),\n /** Each credential (API key, board user, account token) on its own. */\n apiCallsPerMinutePerKey: z.number().int().min(1).nullable(),\n webhookEndpoints: z.number().int().min(0).nullable(),\n bodyStorageAllowed: z.boolean(),\n storageBytes: z.number().int().min(0).nullable(),\n modules: PlanModules,\n included: PlanIncluded,\n /** null: the plan is not sold through Stripe. */\n pricing: PlanPricing.nullable(),\n }),\n);\nexport type PlanLimits = z.infer<typeof PlanLimits>;\n\n/** The plan a tenant runs under; id null = no plan assigned, the platform defaults apply. */\nexport const EffectivePlan = named(\n \"EffectivePlan\",\n z.object({ id: Id.nullable(), name: z.string(), limits: PlanLimits }),\n);\nexport type EffectivePlan = z.infer<typeof EffectivePlan>;\n\nexport const UsageDay = named(\n \"UsageDay\",\n z.object({\n /** UTC day. */\n day: DateOnly,\n /** Highest count of active accounts sampled that day. */\n liveAccounts: z.number().int(),\n /** Calls per API scope. */\n apiCalls: z.record(z.string(), z.number().int()),\n /** Messages the send role delivered (the plan's sendsPerDay counts queued ones). */\n sends: z.number().int(),\n /** Successful webhook deliveries. */\n webhookDeliveries: z.number().int(),\n /** Answers from the AI gateway: reply classifications and drafts. */\n aiCalls: z.number().int(),\n /** From the day's object store listing; null until it ran. */\n storedBytes: z.number().int().nullable(),\n }),\n);\nexport type UsageDay = z.infer<typeof UsageDay>;\n\n/** Where the tenant stands against its plan right now. */\nexport const CurrentUsage = named(\n \"CurrentUsage\",\n z.object({\n /** Not deleted, whatever their status: what the plan's maxAccounts counts. */\n accounts: z.number().int(),\n webhookEndpoints: z.number().int(),\n /** Queued today (UTC): what the plan's sendsPerDay counts. */\n sendsToday: z.number().int(),\n /** Last listing plus content stored since. */\n storedBytes: z.number().int(),\n }),\n);\nexport type CurrentUsage = z.infer<typeof CurrentUsage>;\n\nexport const Usage = named(\n \"Usage\",\n z.object({\n plan: EffectivePlan,\n current: CurrentUsage,\n /** Oldest first; days without any usage are absent. */\n days: z.array(UsageDay),\n }),\n);\nexport type Usage = z.infer<typeof Usage>;\n\nconst DAY_MS = 86_400_000;\n\n/** UTC days, both ends included: from defaults to 30 days before to, to to today. */\nexport const UsageQuery = named(\n \"UsageQuery\",\n withDateRange(z.object({ from: DateOnly.optional(), to: DateOnly.optional() }), {\n from: \"from\",\n to: \"to\",\n inclusive: true,\n maxSpanMs: (MAX_USAGE_RANGE_DAYS - 1) * DAY_MS,\n }).superRefine((q, ctx) => {\n // to left out is today: the range from `from` up to it is held to the same span.\n if (q.from === undefined || q.to !== undefined) return;\n const span = Date.parse(new Date().toISOString().slice(0, 10)) - Date.parse(q.from);\n if (span < 0 || span > (MAX_USAGE_RANGE_DAYS - 1) * DAY_MS)\n ctx.addIssue({\n code: \"custom\",\n path: [\"from\"],\n message:\n span < 0\n ? \"from must be on or before today when to is left out\"\n : `The range may span at most ${MAX_USAGE_RANGE_DAYS} days`,\n params: { reason: \"invalid_range\" },\n });\n }),\n);\nexport type UsageQuery = z.infer<typeof UsageQuery>;\n",
46
- "import { base, errors } from \"../errors.ts\";\nimport { MAX_USAGE_RANGE_DAYS } from \"../limits.ts\";\nimport { Usage, UsageQuery } from \"./models.ts\";\n\nexport const usage = {\n get: base\n .route({\n method: \"GET\",\n path: \"/v1/usage\",\n tags: [\"Usage\"],\n summary: \"Read usage and plan limits\",\n description:\n \"Per UTC day: live accounts (sampled), API calls by scope, sends, webhook deliveries, AI calls and stored bytes (listed once a day). from and to default to the last 30 days; today's counters are live.\",\n })\n .errors(\n errors({\n invalid_range: `from is after to (or after today, with to left out), or the range spans more than ${MAX_USAGE_RANGE_DAYS} days.`,\n }),\n )\n .input(UsageQuery)\n .output(Usage),\n};\n",
47
- "import * as z from \"zod\";\nimport { base, errors, INVALID_CURSOR } from \"../errors.ts\";\nimport {\n DEFAULT_WEBHOOK_SECRET_GRACE_SECONDS,\n MAX_REPLAY_EVENTS,\n MAX_WEBHOOK_SECRET_GRACE_SECONDS,\n} from \"../limits.ts\";\nimport {\n CreateWebhookEndpoint,\n FailedDeliveriesQuery,\n FailedDeliveryCount,\n ListWebhookAttemptsInput,\n ReplayEventInput,\n ReplayRangeRequest,\n ReplayResult,\n RotateWebhookSecretRequest,\n SendTestEventRequest,\n TestEventSent,\n UpdateWebhookEndpoint,\n WebhookAttemptPage,\n WebhookEndpoint,\n WebhookEndpointIdInput,\n WebhookEndpointList,\n WebhookEndpointWithSecret,\n WebhookSecret,\n} from \"./models.ts\";\n\nconst ENDPOINT_NOT_FOUND = errors({\n webhook_endpoint_not_found: \"The endpoint does not exist.\",\n});\nconst ENDPOINT_DISABLED = errors({ endpoint_disabled: \"The endpoint is disabled.\" });\nconst HTTPS_REQUIRED = errors({ https_required: \"url is not https.\" });\nconst WEBHOOK_FILTER_ERRORS = errors({\n unknown_account:\n \"filters.accountIds names an account the tenant does not have; data.ids lists them.\",\n unknown_mailbox:\n \"filters.message.mailboxIds names a mailbox the tenant does not have; data.ids lists them.\",\n mailbox_outside_accounts:\n \"filters.message.mailboxIds names a mailbox of an account that filters.accountIds leaves out.\",\n});\n\nexport const webhooks = {\n list: base\n .route({\n method: \"GET\",\n path: \"/v1/webhooks\",\n tags: [\"Webhooks\"],\n summary: \"List webhook endpoints\",\n })\n .output(WebhookEndpointList),\n\n create: base\n .route({\n method: \"POST\",\n path: \"/v1/webhooks\",\n tags: [\"Webhooks\"],\n summary: \"Create a webhook endpoint\",\n description: \"The signing secret is returned once.\",\n successStatus: 201,\n })\n .errors({\n ...HTTPS_REQUIRED,\n ...WEBHOOK_FILTER_ERRORS,\n ...errors({\n plan_limit_webhooks: \"The tenant already has as many endpoints as its plan allows.\",\n }),\n })\n .input(CreateWebhookEndpoint)\n .output(WebhookEndpointWithSecret),\n\n update: base\n .route({\n method: \"PATCH\",\n path: \"/v1/webhooks/{endpointId}\",\n tags: [\"Webhooks\"],\n summary: \"Update a webhook endpoint\",\n description:\n \"The mailbox check runs whenever filters.message.mailboxIds or filters.accountIds changes.\",\n })\n .errors({ ...ENDPOINT_NOT_FOUND, ...HTTPS_REQUIRED, ...WEBHOOK_FILTER_ERRORS })\n .input(WebhookEndpointIdInput.extend(UpdateWebhookEndpoint.shape))\n .output(WebhookEndpoint),\n\n delete: base\n .route({\n method: \"DELETE\",\n path: \"/v1/webhooks/{endpointId}\",\n tags: [\"Webhooks\"],\n summary: \"Delete a webhook endpoint\",\n successStatus: 204,\n })\n .errors(ENDPOINT_NOT_FOUND)\n .input(WebhookEndpointIdInput)\n .output(z.void()),\n\n rotateSecret: base\n .route({\n method: \"POST\",\n path: \"/v1/webhooks/{endpointId}/rotate-secret\",\n tags: [\"Webhooks\"],\n summary: \"Rotate the signing secret\",\n description: `Deliveries are signed with the new secret at once. For graceSeconds (default ${DEFAULT_WEBHOOK_SECRET_GRACE_SECONDS}, at most ${MAX_WEBHOOK_SECRET_GRACE_SECONDS}) they also carry a signature by the old one, in the same webhook-signature header, so receivers can switch secrets without refusing a delivery; 0 stops the old secret at once. A rotation during another's grace ends that grace: only the secret it replaces is kept.`,\n })\n .errors(ENDPOINT_NOT_FOUND)\n .input(RotateWebhookSecretRequest.safeExtend(WebhookEndpointIdInput.shape))\n .output(WebhookSecret),\n\n test: base\n .route({\n method: \"POST\",\n path: \"/v1/webhooks/{endpointId}/test\",\n tags: [\"Webhooks\"],\n summary: \"Send a test event\",\n description: `Queues one event of eventType for delivery to this endpoint only, whatever its filters, signed like any other, with \"isTest\": true in its body; its attempts show in the delivery log. It carries the sample data for its type unless data is given, which must match the type's data. Test events are never in the change feed.`,\n successStatus: 202,\n })\n .errors({\n ...ENDPOINT_NOT_FOUND,\n ...ENDPOINT_DISABLED,\n ...errors({\n unknown_account: \"accountId names an account the tenant does not have; data.ids lists it.\",\n }),\n })\n .input(SendTestEventRequest.safeExtend(WebhookEndpointIdInput.shape))\n .output(TestEventSent),\n\n attempts: base\n .route({\n method: \"GET\",\n path: \"/v1/webhooks/{endpointId}/attempts\",\n tags: [\"Webhooks\"],\n summary: \"Read the delivery log\",\n description:\n \"Delivery attempts to this endpoint, newest first: of the last 500 within 7 days, those matching the filters. A cursor stays valid while its attempt is in the log.\",\n })\n .errors({\n ...ENDPOINT_NOT_FOUND,\n ...INVALID_CURSOR,\n ...errors({ invalid_range: \"until is not after since.\" }),\n })\n .input(ListWebhookAttemptsInput)\n .output(WebhookAttemptPage),\n\n replay: base\n .route({\n method: \"POST\",\n path: \"/v1/webhooks/{endpointId}/replay\",\n tags: [\"Webhooks\"],\n summary: \"Replay a time range\",\n description: `Queues every event in [since, until) that the endpoint would receive with its current filters again, with the same id and body as the first delivery and a fresh signature. Events the endpoint already has queued are not queued twice. Events past the tenant's eventRetentionDays cannot be replayed.`,\n successStatus: 202,\n })\n .errors({\n ...ENDPOINT_NOT_FOUND,\n ...ENDPOINT_DISABLED,\n ...errors({\n invalid_range: \"until is not after since.\",\n replay_range_too_large: `The range holds more than ${MAX_REPLAY_EVENTS} events.`,\n }),\n })\n .input(ReplayRangeRequest.safeExtend(WebhookEndpointIdInput.shape))\n .output(ReplayResult),\n\n replayEvent: base\n .route({\n method: \"POST\",\n path: \"/v1/webhooks/{endpointId}/events/{eventId}/replay\",\n tags: [\"Webhooks\"],\n summary: \"Replay one event\",\n description: `Queues the event again for this endpoint, whatever its filters, with the same id and body as the first delivery and a fresh signature; not twice if the endpoint already has it queued. Events past the tenant's eventRetentionDays cannot be replayed.`,\n successStatus: 202,\n })\n .errors({\n ...ENDPOINT_NOT_FOUND,\n ...ENDPOINT_DISABLED,\n ...errors({ event_not_found: \"The event is unknown or no longer retained.\" }),\n })\n .input(ReplayEventInput)\n .output(ReplayResult),\n\n countFailed: base\n .route({\n method: \"GET\",\n path: \"/v1/webhooks/{endpointId}/failed-deliveries/count\",\n tags: [\"Webhooks\"],\n summary: \"Count failed deliveries\",\n description:\n \"How many events replay-failed would queue now: those the endpoint gave up on (retries exhausted, or given up when it was disabled) that are still retained and not queued again, optionally only those created in [since, until).\",\n })\n .errors({\n ...ENDPOINT_NOT_FOUND,\n ...errors({ invalid_range: \"until is not after since.\" }),\n })\n .input(FailedDeliveriesQuery.safeExtend(WebhookEndpointIdInput.shape))\n .output(FailedDeliveryCount),\n\n replayFailed: base\n .route({\n method: \"POST\",\n path: \"/v1/webhooks/{endpointId}/replay-failed\",\n tags: [\"Webhooks\"],\n summary: \"Replay failed deliveries\",\n description: `Queues every event the endpoint gave up on again, once each, optionally only those created in [since, until), with the same id and body as the first delivery and a fresh signature. The failed deliveries are replaced by the replays (their attempts stay in the delivery log), so calling again does not send them twice. Events past the tenant's eventRetentionDays cannot be replayed.`,\n successStatus: 202,\n })\n .errors({\n ...ENDPOINT_NOT_FOUND,\n ...ENDPOINT_DISABLED,\n ...errors({\n invalid_range: \"until is not after since.\",\n replay_range_too_large: `More than ${MAX_REPLAY_EVENTS} events failed; replay a narrower range.`,\n }),\n })\n .input(FailedDeliveriesQuery.safeExtend(WebhookEndpointIdInput.shape))\n .output(ReplayResult),\n};\n",
48
- "// Webhook endpoints, their filters, deliveries and the delivery log. The body an endpoint receives\n// is an Event (events/models.ts); signatures are in signing.ts.\nimport * as z from \"zod\";\nimport { EVENTS, EventType, TEST_EVENT_TYPE } from \"../events/models.ts\";\nimport {\n DEFAULT_WEBHOOK_ATTEMPT_PAGE_SIZE,\n DEFAULT_WEBHOOK_SECRET_GRACE_SECONDS,\n MAX_EMAIL_LENGTH,\n MAX_NOTE_LENGTH,\n MAX_SUBJECT_FILTER_LENGTH,\n MAX_WEBHOOK_ATTEMPT_PAGE_SIZE,\n MAX_WEBHOOK_FILTER_VALUES,\n MAX_WEBHOOK_SECRET_GRACE_SECONDS,\n} from \"../limits.ts\";\nimport { MailboxRole, MessageDirection } from \"../mail/models.ts\";\nimport {\n Cursor,\n EventId,\n Id,\n List,\n named,\n Page,\n pageLimit,\n QueryTimestamp,\n Timestamp,\n withDateRange,\n} from \"../primitives.ts\";\n\n/** \"ada@example.com\", or \"@example.com\" for every address at exactly that domain. */\nconst ADDRESS_PATTERN = /^(?:[^\\s@]+)?@[^\\s@.]+(?:\\.[^\\s@.]+)+$/;\n\n/** Standard Webhooks (https://www.standardwebhooks.com/) headers every delivery carries. */\nexport const WEBHOOK_HEADERS = {\n id: \"webhook-id\",\n timestamp: \"webhook-timestamp\",\n signature: \"webhook-signature\",\n} as const;\n/** What a signing secret starts with; the base64 key follows. */\nexport const WEBHOOK_SECRET_PREFIX = \"whsec_\";\n\nconst AddressPattern = z\n .string()\n .trim()\n .toLowerCase()\n .max(MAX_EMAIL_LENGTH)\n .regex(ADDRESS_PATTERN, \"Expected an address or @domain\");\n\n/**\n * Criteria about the message an event concerns, applied to message.* and send.* events. Unset\n * criteria (empty lists, null) match everything; every set criterion must match, and any one\n * value of a list is enough. A set criterion the event's data cannot answer does not match.\n */\nexport const WebhookMessageFilters = named(\n \"WebhookMessageFilters\",\n z.object({\n /** With mailboxRoles, one criterion: the message is in one of these mailboxes, or in a\n * mailbox with one of these roles. Ids must be mailboxes of the tenant, of the accounts\n * accountIds names when it names any. */\n mailboxIds: z.array(Id),\n mailboxRoles: z.array(MailboxRole),\n /** The sender: lowercased addresses and \"@domain\"s. */\n from: z.array(z.string()),\n /** The recipients (to and cc; a bounce's failed recipients): lowercased addresses and\n * \"@domain\"s. */\n to: z.array(z.string()),\n /** Case-insensitive substrings of the subject. */\n subjectContains: z.array(z.string()),\n hasAttachments: z.boolean().nullable(),\n /** outbound: in the sent mailbox or from one of the account's own addresses (its address and\n * identities), and every send.*, message.bounced, message.opened and message.clicked;\n * inbound: every other message. */\n direction: MessageDirection.nullable(),\n }),\n);\nexport type WebhookMessageFilters = z.infer<typeof WebhookMessageFilters>;\n\n/** Which events an endpoint receives. Test events and replays of one picked event ignore them. */\nexport const WebhookFilters = named(\n \"WebhookFilters\",\n z.object({\n /** Empty = every event type, including types added later. */\n eventTypes: z.array(EventType),\n /** Empty = every account. Otherwise only events about these accounts are delivered, so events\n * that concern no account are not either. Ids must be accounts of the tenant. */\n accountIds: z.array(Id),\n message: WebhookMessageFilters,\n }),\n);\nexport type WebhookFilters = z.infer<typeof WebhookFilters>;\n\n/** Message criteria as create and update take them: an omitted one is unset on create and left as\n * it is on update; null clears hasAttachments and direction. */\nexport const WebhookMessageFiltersInput = named(\n \"WebhookMessageFiltersInput\",\n z.object({\n mailboxIds: z.array(Id).max(MAX_WEBHOOK_FILTER_VALUES).optional(),\n mailboxRoles: z.array(MailboxRole).max(MailboxRole.options.length).optional(),\n from: z.array(AddressPattern).max(MAX_WEBHOOK_FILTER_VALUES).optional(),\n to: z.array(AddressPattern).max(MAX_WEBHOOK_FILTER_VALUES).optional(),\n subjectContains: z\n .array(z.string().trim().min(1).max(MAX_SUBJECT_FILTER_LENGTH))\n .max(MAX_WEBHOOK_FILTER_VALUES)\n .optional(),\n hasAttachments: z.boolean().nullable().optional(),\n direction: MessageDirection.nullable().optional(),\n }),\n);\nexport type WebhookMessageFiltersInput = z.infer<typeof WebhookMessageFiltersInput>;\n\n/** Filters as create and update take them: an omitted one is unset on create and left as it is\n * on update. */\nexport const WebhookFiltersInput = named(\n \"WebhookFiltersInput\",\n z.object({\n eventTypes: z.array(EventType).max(MAX_WEBHOOK_FILTER_VALUES).optional(),\n accountIds: z.array(Id).max(MAX_WEBHOOK_FILTER_VALUES).optional(),\n message: WebhookMessageFiltersInput.optional(),\n }),\n);\nexport type WebhookFiltersInput = z.infer<typeof WebhookFiltersInput>;\n\nexport const WebhookEndpoint = named(\n \"WebhookEndpoint\",\n z.object({\n id: Id,\n url: z.url(),\n description: z.string().nullable(),\n filters: WebhookFilters,\n isEnabled: z.boolean(),\n disabledReason: z.string().nullable(),\n lastSuccessAt: Timestamp.nullable(),\n failingSince: Timestamp.nullable(),\n /** While a rotation's grace lasts, deliveries are also signed with the replaced secret, until\n * this time; null when there is none. */\n previousSecretExpiresAt: Timestamp.nullable(),\n createdAt: Timestamp,\n }),\n);\nexport type WebhookEndpoint = z.infer<typeof WebhookEndpoint>;\n\nexport const WebhookEndpointList = List(WebhookEndpoint);\nexport type WebhookEndpointList = z.infer<typeof WebhookEndpointList>;\n\n/** A new endpoint with its signing secret, which is returned only this once. */\nexport const WebhookEndpointWithSecret = named(\n \"WebhookEndpointWithSecret\",\n z.object({ endpoint: WebhookEndpoint, secret: z.string() }),\n);\nexport type WebhookEndpointWithSecret = z.infer<typeof WebhookEndpointWithSecret>;\n\nexport const WebhookSecret = named(\n \"WebhookSecret\",\n z.object({\n secret: z.string(),\n /** Until when deliveries still carry a signature by the replaced secret too; null when the\n * rotation gave it no grace. */\n previousSecretExpiresAt: Timestamp.nullable(),\n }),\n);\nexport type WebhookSecret = z.infer<typeof WebhookSecret>;\n\n/** How long the replaced secret keeps signing deliveries alongside the new one; 0 = not at all. */\nexport const RotateWebhookSecretRequest = named(\n \"RotateWebhookSecretRequest\",\n z.object({\n graceSeconds: z\n .number()\n .int()\n .min(0)\n .max(MAX_WEBHOOK_SECRET_GRACE_SECONDS)\n .default(DEFAULT_WEBHOOK_SECRET_GRACE_SECONDS),\n }),\n);\nexport type RotateWebhookSecretRequest = z.infer<typeof RotateWebhookSecretRequest>;\n\nexport const WebhookEndpointIdInput = named(\"WebhookEndpointIdInput\", z.object({ endpointId: Id }));\nexport type WebhookEndpointIdInput = z.infer<typeof WebhookEndpointIdInput>;\n\nexport const CreateWebhookEndpoint = named(\n \"CreateWebhookEndpoint\",\n z.object({\n url: z.url(),\n description: z.string().max(MAX_NOTE_LENGTH).optional(),\n /** Omitted: every event. */\n filters: WebhookFiltersInput.optional(),\n }),\n);\nexport type CreateWebhookEndpoint = z.infer<typeof CreateWebhookEndpoint>;\n\nexport const UpdateWebhookEndpoint = named(\n \"UpdateWebhookEndpoint\",\n z.object({\n url: z.url().optional(),\n description: z.string().max(MAX_NOTE_LENGTH).nullable().optional(),\n filters: WebhookFiltersInput.optional(),\n isEnabled: z.boolean().optional(),\n }),\n);\nexport type UpdateWebhookEndpoint = z.infer<typeof UpdateWebhookEndpoint>;\n\nexport const SendTestEventRequest = named(\n \"SendTestEventRequest\",\n z\n .object({\n eventType: EventType.default(TEST_EVENT_TYPE),\n /** Defaults to a sample account id for account events; account-less types (webhook.test,\n * account.purged) are delivered without one, as the real events are. */\n accountId: Id.optional(),\n /** Replaces the sample data; it must match eventType's data. */\n data: z.looseObject({}).optional(),\n })\n .superRefine((input, ctx) => {\n if (input.data === undefined) return;\n const parsed = EVENTS[input.eventType].data.safeParse(input.data);\n if (parsed.success) return;\n for (const issue of parsed.error.issues)\n ctx.addIssue({ code: \"custom\", message: issue.message, path: [\"data\", ...issue.path] });\n }),\n);\nexport type SendTestEventRequest = z.infer<typeof SendTestEventRequest>;\n\nexport const TestEventSent = named(\"TestEventSent\", z.object({ eventId: EventId }));\nexport type TestEventSent = z.infer<typeof TestEventSent>;\n\nexport const WebhookAttemptResult = named(\"WebhookAttemptResult\", z.enum([\"succeeded\", \"failed\"]));\nexport type WebhookAttemptResult = z.infer<typeof WebhookAttemptResult>;\n\n/** One delivery attempt, newest first in the endpoint's delivery log. */\nexport const WebhookAttempt = named(\n \"WebhookAttempt\",\n z.object({\n /** The delivery the attempt belongs to; each retry of it is another attempt. */\n id: Id,\n /** The event id: the webhook-id header and the body's id. Replays keep it. */\n eventId: EventId,\n /** The type in the delivered body. */\n eventType: EventType,\n accountId: Id.nullable(),\n attempt: z.number().int(),\n /** The HTTP status the endpoint answered; null when no response arrived. */\n statusCode: z.number().int().nullable(),\n /** Why the attempt failed; null on success. */\n error: z.string().nullable(),\n /** The start of the response body, up to 1 KB. */\n responseExcerpt: z.string().nullable(),\n durationMs: z.number().int(),\n /** Queued by a replay rather than by the event itself. */\n isReplay: z.boolean(),\n /** A test event sent from the board or POST /v1/webhooks/{endpointId}/test. */\n isTest: z.boolean(),\n occurredAt: Timestamp,\n }),\n);\nexport type WebhookAttempt = z.infer<typeof WebhookAttempt>;\n\nexport const WebhookAttemptPage = Page(WebhookAttempt);\nexport type WebhookAttemptPage = z.infer<typeof WebhookAttemptPage>;\n\nexport const ListWebhookAttemptsQuery = named(\n \"ListWebhookAttemptsQuery\",\n z.object({\n limit: pageLimit(MAX_WEBHOOK_ATTEMPT_PAGE_SIZE, DEFAULT_WEBHOOK_ATTEMPT_PAGE_SIZE),\n cursor: Cursor.optional(),\n eventType: EventType.optional(),\n eventId: EventId.optional(),\n accountId: Id.optional(),\n result: WebhookAttemptResult.optional(),\n /** Attempts at or after this time. */\n since: QueryTimestamp.optional(),\n /** Attempts before this time. */\n until: QueryTimestamp.optional(),\n }),\n);\nexport type ListWebhookAttemptsQuery = z.infer<typeof ListWebhookAttemptsQuery>;\n\n/** attempts' input: the endpoint, and a window whose until (when given with since) comes after\n * since (invalid_range). */\nexport const ListWebhookAttemptsInput = withDateRange(\n WebhookEndpointIdInput.extend(ListWebhookAttemptsQuery.shape),\n { from: \"since\", to: \"until\" },\n);\n\n/** The event to replay, whatever the endpoint's filters. */\nexport const ReplayEventInput = named(\n \"ReplayEventInput\",\n WebhookEndpointIdInput.extend({ eventId: EventId }),\n);\nexport type ReplayEventInput = z.infer<typeof ReplayEventInput>;\n\n/** Every event in [since, until) the endpoint receives with its current filters; until after\n * since (invalid_range). */\nexport const ReplayRangeRequest = named(\n \"ReplayRangeRequest\",\n withDateRange(z.object({ since: QueryTimestamp, until: QueryTimestamp }), {\n from: \"since\",\n to: \"until\",\n }),\n);\nexport type ReplayRangeRequest = z.infer<typeof ReplayRangeRequest>;\n\nexport const ReplayResult = named(\n \"ReplayResult\",\n z.object({\n /** Deliveries queued. */\n queued: z.number().int(),\n /** Events skipped because a delivery to this endpoint was already queued. */\n alreadyQueued: z.number().int(),\n }),\n);\nexport type ReplayResult = z.infer<typeof ReplayResult>;\n\n/** The failed deliveries to replay: those of events created in [since, until), either end open. */\nexport const FailedDeliveriesQuery = named(\n \"FailedDeliveriesQuery\",\n withDateRange(z.object({ since: QueryTimestamp.optional(), until: QueryTimestamp.optional() }), {\n from: \"since\",\n to: \"until\",\n }),\n);\nexport type FailedDeliveriesQuery = z.infer<typeof FailedDeliveriesQuery>;\n\nexport const FailedDeliveryCount = named(\n \"FailedDeliveryCount\",\n z.object({\n /** Events the endpoint gave up on, still retained and not queued again yet: what\n * replay-failed would queue. */\n count: z.number().int(),\n }),\n);\nexport type FailedDeliveryCount = z.infer<typeof FailedDeliveryCount>;\n",
49
- "// The /v1 contract (OpenAPIHandler): tenants, authenticated with an API key (or an account token\n// for the account-scoped routes). The board's /rpc router adds the console on top of it\n// (app-router.ts); this module never imports the console, so the published SDK carries none of it.\nimport { accounts, autoconfig, imapAccounts, imapSettings } from \"./accounts/routes.ts\";\nimport { ai } from \"./ai/routes.ts\";\nimport { auditLog } from \"./audit-log/routes.ts\";\nimport { availability, calendarEvents, calendars } from \"./calendar/routes.ts\";\nimport { connectSessions, hostedConnectSessions, oauthAuthorizations } from \"./connect/routes.ts\";\nimport { contactFolders, contacts } from \"./contacts/routes.ts\";\nimport { changes } from \"./events/routes.ts\";\nimport { exports } from \"./exports/routes.ts\";\nimport { identities, mailSettings } from \"./identities/routes.ts\";\nimport { mailboxes, messages, search } from \"./mail/routes.ts\";\nimport {\n hostedMeetingConnectSessions,\n meetingApps,\n meetingConnections,\n meetingConnectSessions,\n} from \"./meetings/routes.ts\";\nimport { oauthApps } from \"./oauth-apps/routes.ts\";\nimport { orgConnections, sharedMailboxes } from \"./org-connections/routes.ts\";\nimport { drafts, mailMerges, outbox } from \"./send/routes.ts\";\nimport { settings } from \"./settings/routes.ts\";\nimport { suppressionReviews, suppressions } from \"./suppressions/routes.ts\";\nimport { templateRenders, templates } from \"./templates/routes.ts\";\nimport { threads } from \"./threads/routes.ts\";\nimport { usage } from \"./usage/routes.ts\";\nimport { webhooks } from \"./webhooks/routes.ts\";\n\n/** The /v1 surface: every procedure except the board-only console. The SDK is typed by it. */\nexport const v1Contract = {\n accounts,\n mailboxes,\n messages,\n search,\n threads,\n drafts,\n outbox,\n mailMerges,\n templates,\n templateRenders,\n suppressions,\n suppressionReviews,\n identities,\n mailSettings,\n calendars,\n calendarEvents,\n availability,\n meetingConnections,\n meetingConnectSessions,\n meetingApps,\n contacts,\n contactFolders,\n webhooks,\n changes,\n settings,\n oauthApps,\n connectSessions,\n oauthAuthorizations,\n orgConnections,\n sharedMailboxes,\n imapAccounts,\n imapSettings,\n autoconfig,\n hostedConnectSessions,\n hostedMeetingConnectSessions,\n exports,\n usage,\n ai,\n auditLog,\n};\nexport type V1Contract = typeof v1Contract;\n",
50
- "// Standard Webhooks signatures (https://www.standardwebhooks.com/): what the platform signs\n// deliveries with and what receivers (the SDK, the webhook tester) verify. WebCrypto only, so it\n// runs unchanged in Bun, Node 20+, Deno, browsers and edge runtimes.\nimport { MAX_SIGNATURE_CANDIDATES } from \"../limits.ts\";\nimport { WEBHOOK_HEADERS, WEBHOOK_SECRET_PREFIX } from \"./models.ts\";\n\n/** Allowed clock skew between the platform and a receiver, per the specification. */\nexport const WEBHOOK_TOLERANCE_SECONDS = 300;\n\n/** A fetch `Headers`, or a plain record such as Node's `req.headers` (any key case). */\nexport type WebhookHeaders = Headers | Record<string, string | string[] | undefined>;\n\nexport interface VerifyWebhookOptions {\n /** Default WEBHOOK_TOLERANCE_SECONDS. */\n toleranceSeconds?: number;\n /** The receiver's clock; default the current time. */\n now?: Date;\n}\n\n/** Why a delivery was refused: payload is a signed body that is not an event. */\nexport type WebhookVerificationFailure = \"missing_headers\" | \"timestamp\" | \"signature\" | \"payload\";\n\n/** What each failure says, as WebhookVerificationError's message. */\nexport const WEBHOOK_VERIFICATION_MESSAGES: Record<WebhookVerificationFailure, string> = {\n missing_headers: \"The webhook headers are missing\",\n timestamp: \"The webhook timestamp is outside the tolerance\",\n signature: \"No webhook signature matches the secret\",\n payload: \"The webhook body is not a workwae event\",\n};\n\nexport class WebhookVerificationError extends Error {\n constructor(\n readonly failure: WebhookVerificationFailure,\n message: string = WEBHOOK_VERIFICATION_MESSAGES[failure],\n ) {\n super(message);\n this.name = \"WebhookVerificationError\";\n }\n}\n\nconst encoder = new TextEncoder();\n\nfunction header(headers: WebhookHeaders, name: string): string | null {\n if (headers instanceof Headers) return headers.get(name);\n for (const [key, value] of Object.entries(headers))\n if (key.toLowerCase() === name) return Array.isArray(value) ? value.join(\" \") : (value ?? null);\n return null;\n}\n\n/** Decodes standard base64; null when the text is not base64. */\nfunction fromBase64(text: string): Uint8Array<ArrayBuffer> | null {\n try {\n return Uint8Array.from(atob(text), (c) => c.charCodeAt(0));\n } catch {\n return null;\n }\n}\n\n/** The HMAC-SHA256 of `${id}.${timestamp}.${body}` under the secret's key. */\nasync function mac(\n secret: string,\n id: string,\n timestamp: string,\n body: string | Uint8Array | ArrayBuffer,\n): Promise<Uint8Array> {\n const keyBytes = fromBase64(\n secret.startsWith(WEBHOOK_SECRET_PREFIX) ? secret.slice(WEBHOOK_SECRET_PREFIX.length) : secret,\n );\n // A bad secret is a configuration error, not a forged delivery: say so loudly.\n if (!keyBytes || keyBytes.length === 0) throw new TypeError(\"The webhook secret is not base64\");\n const key = await crypto.subtle.importKey(\n \"raw\",\n keyBytes,\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"sign\"],\n );\n const prefix = encoder.encode(`${id}.${timestamp}.`);\n const payload = typeof body === \"string\" ? encoder.encode(body) : new Uint8Array(body);\n const signed = new Uint8Array(prefix.length + payload.length);\n signed.set(prefix);\n signed.set(payload, prefix.length);\n return new Uint8Array(await crypto.subtle.sign(\"HMAC\", key, signed));\n}\n\n/** The webhook-signature header value for a delivery: `v1,<base64 HMAC>`. */\nexport async function signWebhook(\n secret: string,\n msg: { id: string; timestamp: number; body: string },\n): Promise<string> {\n const digest = await mac(secret, msg.id, String(msg.timestamp), msg.body);\n return `v1,${btoa(String.fromCharCode(...digest))}`;\n}\n\n/** Whether two arrays of the same length are equal, in a time that does not depend on where they\n * differ. */\nfunction equalInConstantTime(a: Uint8Array, b: Uint8Array): boolean {\n let difference = 0;\n for (let i = 0; i < a.length; i++) difference |= (a[i] ?? 0) ^ (b[i] ?? 0);\n return difference === 0;\n}\n\n/**\n * Why the delivery's signature does not verify, or null when it does: it is signed with `secret`\n * and its timestamp is within the tolerance. Pass the raw request body exactly as received:\n * re-serialized JSON does not verify. The body itself is not looked at.\n */\nexport async function checkWebhookSignature(\n secret: string,\n headers: WebhookHeaders,\n body: string | Uint8Array | ArrayBuffer,\n options: VerifyWebhookOptions = {},\n): Promise<Exclude<WebhookVerificationFailure, \"payload\"> | null> {\n const id = header(headers, WEBHOOK_HEADERS.id);\n const timestamp = header(headers, WEBHOOK_HEADERS.timestamp);\n const signatures = header(headers, WEBHOOK_HEADERS.signature);\n if (!id || !timestamp || !signatures) return \"missing_headers\";\n if (!/^[0-9]{1,15}$/.test(timestamp)) return \"timestamp\";\n const nowSeconds = (options.now ?? new Date()).getTime() / 1000;\n const tolerance = options.toleranceSeconds ?? WEBHOOK_TOLERANCE_SECONDS;\n if (Math.abs(nowSeconds - Number(timestamp)) > tolerance) return \"timestamp\";\n\n // One HMAC, compared with each candidate; only the first few are looked at, so a forged header\n // costs the same however many signatures it lists.\n const expected = await mac(secret, id, timestamp, body);\n for (const candidate of signatures.split(\" \", MAX_SIGNATURE_CANDIDATES)) {\n const [version, value] = candidate.split(\",\", 2);\n if (version !== \"v1\" || !value) continue;\n const given = fromBase64(value);\n if (given?.length === expected.length && equalInConstantTime(given, expected)) return null;\n }\n return \"signature\";\n}\n\n/**\n * True when the delivery is signed with `secret` and its timestamp is within the tolerance.\n * Pass the raw request body exactly as received: re-serialized JSON does not verify.\n */\nexport async function verifyWebhook(\n secret: string,\n headers: WebhookHeaders,\n body: string | Uint8Array | ArrayBuffer,\n options: VerifyWebhookOptions = {},\n): Promise<boolean> {\n return (await checkWebhookSignature(secret, headers, body, options)) === null;\n}\n",
51
- "// The typed /v1 client: oRPC's OpenAPILink over the contract, which carries each procedure's\n// method, path and input structure, with every answer validated through the contract's output\n// schema. That validation is what turns the ISO date-times of the JSON into Dates (the contract's\n// Timestamp reads both) and marks a refusal the route declares as a defined error.\nimport { createORPCClient, ORPCError } from \"@orpc/client\";\nimport type { ContractRouterClient } from \"@orpc/contract\";\nimport { ResponseValidationPlugin } from \"@orpc/contract/plugins\";\nimport { OpenAPILink } from \"@orpc/openapi-client/fetch\";\nimport { type V1Contract, v1Contract } from \"@workwae/contract/public\";\n\n/** Per call, as `{ context }`: `workwae.send.create(input, { context: { idempotencyKey } })`. */\nexport interface CallContext {\n /** The POST's Idempotency-Key. Without one, each POST call sends a key of its own, the same on\n * every automatic retry. Pass one to make retries of your own (a later process, a timeout)\n * answer what the first attempt did. */\n idempotencyKey?: string;\n}\n\n/** Every /v1 procedure, typed from the contract: `workwae.accounts.get({ accountId })`. */\nexport type WorkwaeClient = ContractRouterClient<V1Contract, CallContext>;\n\nexport interface RetryOptions {\n /** Further attempts after a 429 or 503. Default 2. */\n maxRetries?: number;\n /** Longest single wait. A Retry-After beyond it is not waited for: the error is thrown. Default\n * 60 000 ms. */\n maxDelayMs?: number;\n /** How to wait between attempts; it should reject when `signal` aborts. Default: a timer. */\n wait?: (ms: number, signal?: AbortSignal) => Promise<void>;\n}\n\nconst DEFAULT_BASE_URL = \"https://api.workwae.com\";\n\nexport interface ClientOptions {\n /** The API origin; the /v1 paths are appended to it, so a path prefix is kept. Defaults to the\n * hosted API; set it only to go through a proxy or gateway of your own. */\n baseUrl?: string;\n /** An API key (`wk_...`) or an account token (`wat_...`), or a function returning one per\n * request, for tokens that are refreshed. */\n apiKey?: string | (() => string | Promise<string>);\n /** Extra headers sent with every request. */\n headers?: Record<string, string>;\n /** Replaces the global fetch (a proxy agent, instrumentation, tests). Only this call shape is\n * used, so a plain function works where a runtime's `typeof fetch` carries extra members. */\n fetch?: (request: Request, init?: RequestInit) => Promise<Response>;\n retry?: RetryOptions;\n}\n\n/**\n * Retry-After as milliseconds: delta seconds or an HTTP date; null when absent or unreadable.\n * Deliberately not core's utils/retry.ts: the published SDK runs without core, Node 20 included.\n */\nfunction parseRetryAfter(value: string | null): number | null {\n if (value === null) return null;\n const trimmed = value.trim();\n if (/^\\d+(\\.\\d+)?$/.test(trimmed)) return Math.round(Number(trimmed) * 1000);\n const at = Date.parse(trimmed);\n return Number.isNaN(at) ? null : Math.max(0, at - Date.now());\n}\n\n// Executor form rather than Promise.withResolvers, which Node 20 (still a supported SDK runtime)\n// does not have.\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise((resolve, reject) => {\n if (signal?.aborted) {\n reject(signal.reason);\n return;\n }\n const onAbort = () => {\n clearTimeout(timer);\n reject(signal?.reason);\n };\n const timer = setTimeout(() => {\n signal?.removeEventListener(\"abort\", onAbort);\n resolve();\n }, ms);\n signal?.addEventListener(\"abort\", onAbort, { once: true });\n });\n}\n\nconst BACKOFF_START_MS = 500;\n\n/** Where the transport leaves what it saw of a call's answer, for the call's error to carry. */\nconst SEEN = Symbol(\"workwae.seen\");\n\n/** The call's context inside the link: the caller's, plus what the transport saw. */\ninterface CallSeen extends CallContext {\n [SEEN]?: { requestId: string | undefined };\n}\n\n/**\n * `send`, again after a 429 or a 503 while attempts remain. The API answers those before acting\n * on the request (rate limit, overload), so sending the same request again cannot apply it twice;\n * a POST also carries one Idempotency-Key on every attempt. The wait is Retry-After when the\n * answer names one, else an exponential backoff with full jitter on its upper half, which keeps\n * clients that failed together from retrying together. Any other answer, or the last one, is\n * returned for the link to decode.\n */\nfunction retrying(\n send: (request: Request, init?: RequestInit) => Promise<Response>,\n options: RetryOptions = {},\n): (\n request: Request,\n init: RequestInit,\n call: { signal?: AbortSignal; context: CallSeen },\n) => Promise<Response> {\n const maxRetries = options.maxRetries ?? 2;\n const maxDelayMs = options.maxDelayMs ?? 60_000;\n const wait = options.wait ?? sleep;\n return async (request, init, { signal, context }) => {\n // One key for every attempt, so an attempt the API did act on is never acted on again.\n if (request.method === \"POST\" && !request.headers.has(\"idempotency-key\"))\n request.headers.set(\"idempotency-key\", crypto.randomUUID());\n for (let attempt = 0; ; attempt++) {\n const last = attempt >= maxRetries;\n // A request's body can be read once: every attempt that may be followed by another sends a\n // copy.\n const response = await send(last ? request : request.clone(), init);\n const seen = context[SEEN];\n if (seen) seen.requestId = response.headers.get(\"x-request-id\") ?? undefined;\n if (last || (response.status !== 429 && response.status !== 503)) return response;\n const retryAfterMs = parseRetryAfter(response.headers.get(\"retry-after\"));\n if (retryAfterMs !== null && retryAfterMs > maxDelayMs) return response;\n await response.body?.cancel();\n const backoff = BACKOFF_START_MS * 2 ** attempt * (0.5 + Math.random() / 2);\n // The caller's signal rather than the request's, which only follows it.\n await wait(retryAfterMs ?? Math.min(backoff, maxDelayMs), signal);\n signal?.throwIfAborted();\n }\n };\n}\n\n/** A typed client for the workwae /v1 API. */\nexport function createClient(options: ClientOptions): WorkwaeClient {\n const { apiKey } = options;\n const link = new OpenAPILink<CallSeen>(v1Contract, {\n url: options.baseUrl ?? DEFAULT_BASE_URL,\n headers: async ({ context }) => {\n const key = typeof apiKey === \"function\" ? await apiKey() : apiKey;\n return {\n ...options.headers,\n ...(key && { authorization: `Bearer ${key}` }),\n ...(context.idempotencyKey && { \"idempotency-key\": context.idempotencyKey }),\n };\n },\n fetch: retrying(options.fetch ?? ((request, init) => fetch(request, init)), options.retry),\n interceptors: [\n // An API error carries the X-Request-Id of the answer it came in (ORPCError.requestId).\n async ({ next, ...call }) => {\n const seen = { requestId: undefined as string | undefined };\n try {\n return await next({ ...call, context: { ...call.context, [SEEN]: seen } });\n } catch (error) {\n if (error instanceof ORPCError) error.requestId = seen.requestId;\n throw error;\n }\n },\n ],\n clientInterceptors: [\n // A failure whose body does not decode (a proxy's page sent without a content type, say)\n // still becomes an ORPCError keyed by its status, not a parse error that hides the status.\n async ({ next }) => {\n const response = await next();\n if (response.status >= 400) {\n const read = response.body;\n response.body = () => read().catch(() => undefined);\n }\n return response;\n },\n ],\n plugins: [new ResponseValidationPlugin(v1Contract)],\n });\n return createORPCClient<WorkwaeClient>(link);\n}\n",
52
- "// API errors as the client throws them: oRPC's ORPCError, whose `code` is the stable reason\n// (packages/contract/src/reasons.ts) and whose `data` is that reason's data, when it has any. A\n// refusal the procedure declares arrives with `defined: true`, so `safe()` + `isDefinedError()`\n// narrow it to the procedure's own reasons; `isApiError()` checks for any (or one) reason. Every\n// error the API answered carries the answer's X-Request-Id as `requestId`, for support.\nimport { ORPCError, type ORPCErrorCode } from \"@orpc/client\";\nimport { type ErrorReason, isErrorReason, type ReasonData } from \"@workwae/contract/public\";\n\nexport { isDefinedError, ORPCError, safe } from \"@orpc/client\";\nexport type { ErrorReason } from \"@workwae/contract/public\";\n\ndeclare module \"@orpc/client\" {\n interface ORPCError<TCode extends ORPCErrorCode, TData> {\n /** The X-Request-Id of the answer the error came in; undefined when no answer named one. */\n requestId?: string;\n }\n}\n\n/** An API error with reason `R`; over a union of reasons, the union of each one's error, so\n * checking `code` narrows `data` to that reason's. */\ntype ApiError<R extends ErrorReason> = R extends ErrorReason ? ORPCError<R, ReasonData<R>> : never;\n\n/** True for an API error carrying a reason, and with `reason`, only for that reason. */\nexport function isApiError<R extends ErrorReason = ErrorReason>(\n error: unknown,\n reason?: R,\n): error is ApiError<R> {\n return (\n error instanceof ORPCError &&\n isErrorReason(error.code) &&\n (reason === undefined || error.code === reason)\n );\n}\n",
53
- "// Cursor helpers. They take the procedure itself (`workwae.accounts.list`), so the item type and\n// the accepted filters come from the contract like everywhere else. Both run the contract's one\n// cursor loop (followCursor); they differ only in where a list ends.\n\nimport { type Event, type EventFeedPage, followCursor, type Page } from \"@workwae/contract/public\";\n\n/** Per-request options forwarded to every call a helper makes. */\nexport interface CallOptions {\n signal?: AbortSignal;\n}\n\n/** A procedure that takes a cursor in its input. */\nexport type CursorCall<TInput, TOutput> = (\n input: TInput,\n options?: CallOptions,\n) => PromiseLike<TOutput>;\n\n/** Every page of a list, from `input.cursor` (or the start) to the last page. */\nexport function pages<TInput extends { cursor?: string }, TItem>(\n list: CursorCall<TInput, Page<TItem>>,\n input: NoInfer<TInput>,\n options?: CallOptions,\n): AsyncGenerator<Page<TItem>, void, undefined> {\n return followCursor(\n (cursor) => list({ ...input, cursor }, options),\n input.cursor,\n (page) => page.nextCursor ?? undefined,\n );\n}\n\n/**\n * Every item of a list, following `nextCursor` until the last page:\n * `for await (const account of paginate(workwae.accounts.list, { limit: 100 }))`.\n */\nexport async function* paginate<TInput extends { cursor?: string }, TItem>(\n list: CursorCall<TInput, Page<TItem>>,\n input: NoInfer<TInput>,\n options?: CallOptions,\n): AsyncGenerator<TItem, void, undefined> {\n for await (const page of pages(list, input, options)) yield* page.items;\n}\n\n/**\n * Reads the change feed from `input.cursor` until it is caught up (an empty page). `cursor` moves\n * past a page only once its last event has been consumed, so persisting it after processing\n * gives at-least-once delivery: stopping mid-page replays that page next time.\n */\nexport class ChangeFeed<TInput extends { cursor?: string }> implements AsyncIterable<Event> {\n #cursor: string | undefined;\n\n constructor(\n private readonly list: CursorCall<TInput, EventFeedPage>,\n private readonly input: TInput,\n private readonly options?: CallOptions,\n ) {\n this.#cursor = input.cursor;\n }\n\n /** Where to resume: pass it as `cursor` next time. Undefined until the first page is read when\n * no cursor was given. */\n get cursor(): string | undefined {\n return this.#cursor;\n }\n\n async *[Symbol.asyncIterator](): AsyncGenerator<Event, void, undefined> {\n const feed = followCursor(\n (cursor) => this.list({ ...this.input, cursor }, this.options),\n this.#cursor,\n // The feed has no last page: an empty one means caught up.\n (page) => (page.items.length === 0 ? undefined : page.nextCursor),\n );\n for await (const page of feed) {\n yield* page.items;\n this.#cursor = page.nextCursor;\n }\n }\n}\n\n/** `const feed = changes(workwae.changes.list, { cursor: saved })`; iterate, then save `feed.cursor`. */\nexport function changes<TInput extends { cursor?: string }>(\n list: CursorCall<TInput, EventFeedPage>,\n input: NoInfer<TInput>,\n options?: CallOptions,\n): ChangeFeed<TInput> {\n return new ChangeFeed(list, input, options);\n}\n",
54
- "// Receiving webhooks: Standard Webhooks verification (the contract's, the scheme workwae signs\n// with) and the typed event in the body.\nimport {\n checkWebhookSignature,\n Event,\n EventId,\n EventType,\n Id,\n Timestamp,\n type VerifyWebhookOptions,\n type WebhookHeaders,\n WebhookVerificationError,\n} from \"@workwae/contract/public\";\nimport * as z from \"zod\";\n\nexport {\n checkWebhookSignature,\n MAX_SIGNATURE_CANDIDATES,\n type VerifyWebhookOptions,\n verifyWebhook,\n WEBHOOK_TOLERANCE_SECONDS,\n type WebhookHeaders,\n WebhookVerificationError,\n type WebhookVerificationFailure,\n} from \"@workwae/contract/public\";\n\n/** An event of a type this SDK knows, its data checked against that type's schema. Check\n * `event.type` to narrow `event.data`. */\nexport type KnownEvent = Event & { known: true };\n\n/** An event of a type added to the platform after this build: its data is passed on unchecked. */\nexport interface UnknownEvent {\n id: string;\n type: string;\n accountId: string | null;\n createdAt: Date;\n data: { [key: string]: unknown };\n isTest?: true;\n known: false;\n}\n\n/** What parseWebhook returns. Check `known` first: a known event then narrows on `type`. */\nexport type WebhookEvent = KnownEvent | UnknownEvent;\n\nconst LaterEvent = z.looseObject({\n id: EventId,\n type: z.string(),\n accountId: Id.nullable(),\n createdAt: Timestamp,\n data: z.looseObject({}),\n isTest: z.literal(true).exactOptional(),\n});\n\n/**\n * Verifies the delivery, then returns its event with its dates as Dates; throws\n * WebhookVerificationError otherwise. Pass the raw request body exactly as received. A known type\n * whose body does not match its schema is refused (failure \"payload\"); a type added after this\n * build is returned with `known: false`. Envelope fields added after this build are kept.\n */\nexport async function parseWebhook(\n secret: string,\n headers: WebhookHeaders,\n body: string | Uint8Array | ArrayBuffer,\n options: VerifyWebhookOptions = {},\n): Promise<WebhookEvent> {\n const failure = await checkWebhookSignature(secret, headers, body, options);\n if (failure) throw new WebhookVerificationError(failure);\n let json: unknown;\n try {\n json = JSON.parse(typeof body === \"string\" ? body : new TextDecoder().decode(body));\n } catch {\n throw new WebhookVerificationError(\"payload\", \"The webhook body is not JSON\");\n }\n const type = typeof json === \"object\" && json !== null && \"type\" in json ? json.type : undefined;\n if (EventType.safeParse(type).success) {\n const parsed = Event.safeParse(json);\n if (parsed.success) return { ...(json as object), ...parsed.data, known: true };\n } else {\n const later = LaterEvent.safeParse(json);\n if (later.success) return { ...later.data, known: false };\n }\n throw new WebhookVerificationError(\"payload\");\n}\n"
55
- ],
56
- "mappings": "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",
57
- "debugId": "2876276784BC8B1464756E2164756E21",
58
- "names": []
59
- }