@medalsocial/sdk 1.4.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +178 -2
- package/dist/openapi/medal-social.openapi.json +1180 -21
- package/dist/src/index.d.mts +886 -187
- package/dist/src/index.d.ts +886 -187
- package/dist/src/index.js +360 -13
- package/dist/src/index.js.map +1 -1
- package/dist/src/index.mjs +354 -13
- package/dist/src/index.mjs.map +1 -1
- package/dist/src/openapi.generated.d.mts +597 -0
- package/dist/src/openapi.generated.d.ts +597 -0
- package/dist/src/openapi.generated.js.map +1 -1
- package/openapi/medal-social.openapi.yaml +700 -0
- package/package.json +1 -1
- package/skills/resources/SKILL.md +3 -2
package/dist/src/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/types/common.ts","../../src/client.ts","../../src/resources/contacts.ts","../../src/resources/deals.ts","../../src/resources/emails.ts","../../src/resources/gdpr.ts","../../src/resources/helpdesk.ts","../../src/resources/posts.ts","../../src/resources/webhooks.ts","../../src/resources/workspaces.ts","../../src/webhook-events.ts","../../src/index.ts"],"sourcesContent":["/** Successful API response wrapper */\nexport interface ApiResponse<T> {\n data: T;\n}\n\n/** Paginated API response */\nexport interface PaginatedResponse<T> {\n data: T[];\n pagination: {\n has_more: boolean;\n next_cursor: string | null;\n };\n}\n\n/** API error thrown by the client */\nexport class MedalApiError extends Error {\n readonly status: number;\n readonly code: string;\n readonly details?: unknown;\n\n constructor(status: number, code: string, message: string, details?: unknown) {\n super(message);\n this.name = \"MedalApiError\";\n this.status = status;\n this.code = code;\n this.details = details;\n }\n}\n\n/** Pagination options for list endpoints */\nexport interface PaginationOptions {\n limit?: number;\n cursor?: string;\n}\n","import { MedalApiError } from \"./types/common\";\n\n/** Configuration for the low-level HTTP client. */\nexport interface ClientConfig {\n baseUrl: string;\n token: string;\n workspaceId?: string;\n timeout: number;\n userAgent: string;\n}\n\n/** Per-request options for write operations. */\nexport interface RequestOptions {\n /**\n * Idempotency key sent as the `Idempotency-Key` header. Retries with the\n * same key return the original result instead of repeating the operation.\n * Required by some endpoints for capability-scoped tokens (e.g. helpdesk\n * replies, webhook creation).\n */\n idempotencyKey?: string;\n /**\n * Capability confirmation token sent as the `X-Capability-Confirmation`\n * header. Required alongside `idempotencyKey` when a token granted a\n * capability-style scope directly (e.g. `helpdesk.webhook.manage`) executes\n * a confirmable write route. Obtain one from\n * `POST /api/v1/capability-confirmations`. API keys with legacy scopes do\n * not need it.\n */\n capabilityConfirmation?: string;\n}\n\n/**\n * Low-level HTTP client used by all resource classes.\n * Handles authentication, retries, timeout, and error parsing.\n */\nexport class BaseClient {\n /** Resolved client configuration. */\n readonly config: ClientConfig;\n\n constructor(config: ClientConfig) {\n this.config = config;\n }\n\n /** Execute an authenticated GET request and return the parsed JSON body. */\n async get<T>(path: string, params?: Record<string, string | undefined>): Promise<T> {\n const url = this.buildUrl(path, params);\n return this.request<T>(url, { method: \"GET\" });\n }\n\n /** Execute an authenticated POST request with a JSON body. */\n async post<T>(path: string, body?: unknown, options?: RequestOptions): Promise<T> {\n return this.request<T>(this.buildUrl(path), {\n method: \"POST\",\n headers: this.writeHeaders(options),\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n }\n\n /** Execute an authenticated PATCH request with a JSON body. */\n async patch<T>(path: string, body: unknown, options?: RequestOptions): Promise<T> {\n return this.request<T>(this.buildUrl(path), {\n method: \"PATCH\",\n headers: this.writeHeaders(options),\n body: JSON.stringify(body),\n });\n }\n\n /** Execute an authenticated DELETE request. */\n async delete<T>(path: string, options?: RequestOptions): Promise<T> {\n return this.request<T>(this.buildUrl(path), {\n method: \"DELETE\",\n headers: this.writeHeaders(options),\n });\n }\n\n private writeHeaders(options?: RequestOptions): Record<string, string> {\n const headers: Record<string, string> = { \"content-type\": \"application/json\" };\n if (options?.idempotencyKey) {\n headers[\"idempotency-key\"] = options.idempotencyKey;\n }\n if (options?.capabilityConfirmation) {\n headers[\"x-capability-confirmation\"] = options.capabilityConfirmation;\n }\n return headers;\n }\n\n private buildUrl(path: string, params?: Record<string, string | undefined>): string {\n const url = new URL(`${this.config.baseUrl}${path}`);\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n url.searchParams.set(key, value);\n }\n }\n }\n return url.toString();\n }\n\n private async request<T>(url: string, init: RequestInit): Promise<T> {\n const maxAttempts = 3;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n const headers = new Headers(init.headers);\n headers.set(\"authorization\", `Bearer ${this.config.token}`);\n if (this.config.workspaceId) {\n headers.set(\"x-workspace-id\", this.config.workspaceId);\n }\n try {\n headers.set(\"user-agent\", this.config.userAgent);\n } catch {\n // Browsers disallow setting user-agent\n }\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.timeout);\n\n let res: Response;\n try {\n res = await fetch(url, { ...init, headers, signal: controller.signal });\n } finally {\n clearTimeout(timeout);\n }\n\n // Retry on 429 / 5xx (but not on the final attempt)\n if (\n (res.status === 429 || (res.status >= 500 && res.status <= 599)) &&\n attempt < maxAttempts\n ) {\n const retryAfter = res.headers.get(\"retry-after\");\n let delayMs = 0;\n if (retryAfter) {\n const seconds = Number(retryAfter);\n delayMs = Number.isFinite(seconds) ? seconds * 1000 : 0;\n }\n if (delayMs <= 0) {\n delayMs = 250 * attempt;\n }\n await new Promise((r) => setTimeout(r, delayMs));\n continue;\n }\n\n // Parse response\n const text = await res.text();\n let parsed: unknown;\n try {\n parsed = text ? JSON.parse(text) : undefined;\n } catch {\n parsed = text;\n }\n\n if (!res.ok) {\n const body = parsed as\n | { error?: { code?: string; message?: string; details?: unknown } }\n | undefined;\n throw new MedalApiError(\n res.status,\n body?.error?.code ?? \"UNKNOWN_ERROR\",\n body?.error?.message ?? `HTTP ${res.status}: ${res.statusText}`,\n body?.error?.details,\n );\n }\n\n return parsed as T;\n }\n\n /* v8 ignore next -- unreachable: loop always returns or throws */\n throw new Error(\"Request failed after retries\");\n }\n}\n","import type { BaseClient } from \"../client\";\nimport type { ApiResponse, PaginatedResponse, PaginationOptions } from \"../types/common\";\nimport type {\n Activity,\n AddNoteInput,\n Contact,\n ContactCreateResult,\n ContactNoteResult,\n ContactRemoveResult,\n ContactUpdateResult,\n CreateContactInput,\n ImportContactInput,\n ImportContactsResult,\n ListContactsOptions,\n UpdateContactInput,\n} from \"../types/contacts\";\n\n/** Manage contacts in the workspace CRM. */\nexport class Contacts {\n constructor(private client: BaseClient) {}\n\n /** List contacts with cursor-based pagination and optional filters. */\n async list(options?: ListContactsOptions): Promise<PaginatedResponse<Contact>> {\n const params: Record<string, string | undefined> = {};\n if (options?.limit !== undefined) params.limit = String(options.limit);\n if (options?.cursor) params.cursor = options.cursor;\n if (options?.status) params.status = options.status;\n if (options?.email_status) params.email_status = options.email_status;\n if (options?.label_ids) params.label_ids = options.label_ids.join(\",\");\n if (options?.search) params.search = options.search;\n return this.client.get(\"/api/v1/contacts\", params);\n }\n\n /** Create a new contact. Email must be unique in the workspace. */\n async create(input: CreateContactInput): Promise<ApiResponse<ContactCreateResult>> {\n return this.client.post(\"/api/v1/contacts\", input);\n }\n\n /** Get a contact by ID. */\n async get(id: string): Promise<ApiResponse<Contact>> {\n return this.client.get(`/api/v1/contacts/${encodeURIComponent(id)}`);\n }\n\n /** Update one or more fields on a contact. */\n async update(id: string, input: UpdateContactInput): Promise<ApiResponse<ContactUpdateResult>> {\n return this.client.patch(`/api/v1/contacts/${encodeURIComponent(id)}`, input);\n }\n\n /** Permanently delete a contact. */\n async remove(id: string): Promise<ApiResponse<ContactRemoveResult>> {\n return this.client.delete(`/api/v1/contacts/${encodeURIComponent(id)}`);\n }\n\n /** Get the activity timeline for a contact. */\n async activities(id: string, options?: PaginationOptions): Promise<PaginatedResponse<Activity>> {\n const params: Record<string, string | undefined> = {};\n if (options?.limit !== undefined) params.limit = String(options.limit);\n if (options?.cursor) params.cursor = options.cursor;\n return this.client.get(`/api/v1/contacts/${encodeURIComponent(id)}/activities`, params);\n }\n\n /** Add a note to a contact's timeline. */\n async addNote(id: string, input: AddNoteInput): Promise<ApiResponse<ContactNoteResult>> {\n return this.client.post(`/api/v1/contacts/${encodeURIComponent(id)}/notes`, input);\n }\n\n /** Bulk import contacts (max 500). Duplicates are skipped. */\n async import(contacts: ImportContactInput[]): Promise<ApiResponse<ImportContactsResult>> {\n return this.client.post(\"/api/v1/contacts/import\", { contacts });\n }\n}\n","import type { BaseClient } from \"../client\";\nimport type { ApiResponse, PaginatedResponse } from \"../types/common\";\nimport type {\n CreateDealInput,\n Deal,\n DealCreateResult,\n DealRemoveResult,\n DealUpdateResult,\n ListDealsOptions,\n UpdateDealInput,\n} from \"../types/deals\";\n\n/** Manage sponsorship deals in the workspace. */\nexport class Deals {\n constructor(private client: BaseClient) {}\n\n /** List deals with cursor-based pagination and optional filters. */\n async list(options?: ListDealsOptions): Promise<PaginatedResponse<Deal>> {\n const params: Record<string, string | undefined> = {};\n if (options?.limit !== undefined) params.limit = String(options.limit);\n if (options?.cursor) params.cursor = options.cursor;\n if (options?.status) params.status = options.status;\n if (options?.search) params.search = options.search;\n return this.client.get(\"/api/v1/deals\", params);\n }\n\n /** Create a new deal. */\n async create(input: CreateDealInput): Promise<ApiResponse<DealCreateResult>> {\n return this.client.post(\"/api/v1/deals\", input);\n }\n\n /** Get a deal by ID. */\n async get(id: string): Promise<ApiResponse<Deal>> {\n return this.client.get(`/api/v1/deals/${encodeURIComponent(id)}`);\n }\n\n /** Update one or more fields on a deal. Set contact_id to null to unlink. */\n async update(id: string, input: UpdateDealInput): Promise<ApiResponse<DealUpdateResult>> {\n return this.client.patch(`/api/v1/deals/${encodeURIComponent(id)}`, input);\n }\n\n /** Permanently delete a deal. */\n async remove(id: string): Promise<ApiResponse<DealRemoveResult>> {\n return this.client.delete(`/api/v1/deals/${encodeURIComponent(id)}`);\n }\n}\n","import type { BaseClient } from \"../client\";\nimport type { ApiResponse } from \"../types/common\";\nimport type {\n BatchSendInput,\n BatchSendSummary,\n EmailSend,\n EmailSendResult,\n EmailTemplate,\n EmailTemplateDetail,\n GetTemplateOptions,\n SendEmailInput,\n} from \"../types/emails\";\n\n/** Manage email templates stored in the workspace. */\nclass EmailTemplates {\n constructor(private client: BaseClient) {}\n\n /** List all active email templates in the workspace. */\n async list(): Promise<ApiResponse<EmailTemplate[]>> {\n return this.client.get(\"/api/v1/emails/templates\");\n }\n\n /** Get a specific email template by slug, optionally with locale resolution. */\n async get(slug: string, options?: GetTemplateOptions): Promise<ApiResponse<EmailTemplateDetail>> {\n const params: Record<string, string | undefined> = {};\n if (options?.locale) params.locale = options.locale;\n if (options?.fallback_locale) params.fallback_locale = options.fallback_locale;\n return this.client.get(`/api/v1/emails/templates/${encodeURIComponent(slug)}`, params);\n }\n}\n\n/** Send transactional emails and manage templates. */\nexport class Emails {\n readonly templates: EmailTemplates;\n\n constructor(private client: BaseClient) {\n this.templates = new EmailTemplates(client);\n }\n\n /**\n * Send a transactional email using a template (HTTP 202). The returned `id`\n * is an email send id — poll `emails.get(id)` with it to track delivery.\n */\n async send(input: SendEmailInput): Promise<ApiResponse<EmailSendResult>> {\n return this.client.post(\"/api/v1/emails\", input);\n }\n\n /** Get the delivery status of a sent email. */\n async get(id: string): Promise<ApiResponse<EmailSend>> {\n return this.client.get(`/api/v1/emails/${encodeURIComponent(id)}`);\n }\n\n /**\n * Send the same template to multiple recipients (max 100, HTTP 202). Each\n * queued recipient gets its own send id in `results` for `emails.get(id)`.\n */\n async batch(input: BatchSendInput): Promise<ApiResponse<BatchSendSummary>> {\n return this.client.post(\"/api/v1/emails/batch\", input);\n }\n}\n","import type { BaseClient } from \"../client\";\nimport type { ApiResponse } from \"../types/common\";\nimport type {\n ConsentRecord,\n ConsentResult,\n CookieConsentInput,\n GdprExport,\n RecordConsentInput,\n} from \"../types/gdpr\";\n\n/** Manage GDPR compliance — data exports, consent records, and cookie consent. */\nexport class Gdpr {\n constructor(private client: BaseClient) {}\n\n /** Request a workspace data export. Runs asynchronously. */\n async requestExport(): Promise<ApiResponse<{ request_id: string; status: string }>> {\n return this.client.post(\"/api/v1/gdpr/export\");\n }\n\n /** List all workspace export requests. */\n async listExports(): Promise<ApiResponse<GdprExport[]>> {\n return this.client.get(\"/api/v1/gdpr/exports\");\n }\n\n /** Get the status of a specific export. */\n async getExport(id: string): Promise<ApiResponse<GdprExport>> {\n return this.client.get(`/api/v1/gdpr/exports/${encodeURIComponent(id)}`);\n }\n\n /** Record a GDPR consent decision for a contact by email. */\n async recordConsent(input: RecordConsentInput): Promise<ApiResponse<ConsentResult>> {\n return this.client.post(\"/api/v1/gdpr/consent\", input);\n }\n\n /** Get all consent records for a contact by email. */\n async getConsent(email: string): Promise<ApiResponse<ConsentRecord[]>> {\n return this.client.get(`/api/v1/gdpr/consent/${encodeURIComponent(email)}`);\n }\n\n /** Record cookie consent from an external site (legacy endpoint). */\n async cookieConsent(input: CookieConsentInput): Promise<{ success: boolean; logId?: string }> {\n return this.client.post(\"/api/cookie-consent\", input);\n }\n}\n","import type { BaseClient, RequestOptions } from \"../client\";\nimport type { ApiResponse, PaginatedResponse, PaginationOptions } from \"../types/common\";\nimport type {\n Conversation,\n ConversationMessage,\n ConversationUpdateResult,\n CreateReplyInput,\n ListConversationsOptions,\n ReplyCreateResult,\n UpdateConversationInput,\n} from \"../types/helpdesk\";\n\n/** Browse and manage helpdesk conversations. */\nclass HelpdeskConversations {\n constructor(private client: BaseClient) {}\n\n /** List/search conversations with cursor-based pagination and optional filters. */\n async list(options?: ListConversationsOptions): Promise<PaginatedResponse<Conversation>> {\n const params: Record<string, string | undefined> = {};\n if (options?.limit !== undefined) params.limit = String(options.limit);\n if (options?.cursor) params.cursor = options.cursor;\n if (options?.status) params.status = options.status;\n if (options?.assignee_user_id) params.assignee_user_id = options.assignee_user_id;\n if (options?.requester) params.requester = options.requester;\n if (options?.query) params.query = options.query;\n if (options?.channels) params.channels = options.channels.join(\",\");\n return this.client.get(\"/api/v1/helpdesk/conversations\", params);\n }\n\n /** Get a conversation by ID. */\n async get(id: string): Promise<ApiResponse<Conversation>> {\n return this.client.get(`/api/v1/helpdesk/conversations/${encodeURIComponent(id)}`);\n }\n\n /** Update a conversation's status and/or assignee (pass `assignee_user_id: null` to unassign). */\n async update(\n id: string,\n input: UpdateConversationInput,\n options?: RequestOptions,\n ): Promise<ApiResponse<ConversationUpdateResult>> {\n return this.client.patch(\n `/api/v1/helpdesk/conversations/${encodeURIComponent(id)}`,\n input,\n options,\n );\n }\n\n /** Read a conversation's messages with cursor-based pagination. */\n async messages(\n id: string,\n options?: PaginationOptions,\n ): Promise<PaginatedResponse<ConversationMessage>> {\n const params: Record<string, string | undefined> = {};\n if (options?.limit !== undefined) params.limit = String(options.limit);\n if (options?.cursor) params.cursor = options.cursor;\n return this.client.get(\n `/api/v1/helpdesk/conversations/${encodeURIComponent(id)}/messages`,\n params,\n );\n }\n}\n\n/** Send operator replies (or internal notes) into conversations. */\nclass HelpdeskReplies {\n constructor(private client: BaseClient) {}\n\n /**\n * Send an operator reply or internal note. Returns HTTP 201.\n *\n * Pass an `idempotencyKey` so retried requests do not create duplicate\n * messages — it is REQUIRED for capability-scoped tokens.\n */\n async create(\n input: CreateReplyInput,\n options?: RequestOptions,\n ): Promise<ApiResponse<ReplyCreateResult>> {\n return this.client.post(\"/api/v1/helpdesk/replies\", input, options);\n }\n}\n\n/** Helpdesk bridge — read conversations, reply, and manage assignment/status. */\nexport class Helpdesk {\n readonly conversations: HelpdeskConversations;\n readonly replies: HelpdeskReplies;\n\n constructor(client: BaseClient) {\n this.conversations = new HelpdeskConversations(client);\n this.replies = new HelpdeskReplies(client);\n }\n}\n","import type { BaseClient } from \"../client\";\nimport type { ApiResponse, PaginatedResponse } from \"../types/common\";\nimport type {\n Channel,\n CreatePostInput,\n ListPostsOptions,\n Post,\n PostDetail,\n PublishResult,\n SchedulePostInput,\n ScheduleResult,\n UpdatePostInput,\n} from \"../types/posts\";\n\n/** Create and publish posts across connected channels. */\nexport class Posts {\n constructor(private client: BaseClient) {}\n\n /** List posts with cursor-based pagination and optional filters. */\n async list(options?: ListPostsOptions): Promise<PaginatedResponse<Post>> {\n const params: Record<string, string | undefined> = {};\n if (options?.limit !== undefined) params.limit = String(options.limit);\n if (options?.cursor) params.cursor = options.cursor;\n if (options?.status) params.status = options.status;\n if (options?.type) params.type = options.type;\n return this.client.get(\"/api/v1/posts\", params);\n }\n\n /** Create a new post with content and target channels. */\n async create(input: CreatePostInput): Promise<ApiResponse<{ id: string }>> {\n return this.client.post(\"/api/v1/posts\", input);\n }\n\n /** Get a post by ID, including its per-channel variants. */\n async get(id: string): Promise<ApiResponse<PostDetail>> {\n return this.client.get(`/api/v1/posts/${encodeURIComponent(id)}`);\n }\n\n /** Update a draft post's title or content. */\n async update(id: string, input: UpdatePostInput): Promise<ApiResponse<{ success: boolean }>> {\n return this.client.patch(`/api/v1/posts/${encodeURIComponent(id)}`, input);\n }\n\n /** Delete a post. */\n async remove(id: string): Promise<ApiResponse<{ success: boolean }>> {\n return this.client.delete(`/api/v1/posts/${encodeURIComponent(id)}`);\n }\n\n /** Schedule a post for future publication. */\n async schedule(id: string, input: SchedulePostInput): Promise<ApiResponse<ScheduleResult>> {\n return this.client.post(`/api/v1/posts/${encodeURIComponent(id)}/schedule`, input);\n }\n\n /** Publish a post immediately to all target channels. */\n async publish(id: string): Promise<ApiResponse<PublishResult>> {\n return this.client.post(`/api/v1/posts/${encodeURIComponent(id)}/publish`);\n }\n\n /** List connected publishing channels for this workspace. */\n async channels(): Promise<ApiResponse<Channel[]>> {\n return this.client.get(\"/api/v1/posts/channels\");\n }\n}\n","import type { BaseClient, RequestOptions } from \"../client\";\nimport type { ApiResponse } from \"../types/common\";\nimport type {\n CreateWebhookInput,\n ListDeliveriesOptions,\n UpdateWebhookInput,\n WebhookDeleteResult,\n WebhookDelivery,\n WebhookEndpoint,\n WebhookTestResult,\n} from \"../types/webhooks\";\n\n/** Manage webhook endpoints and inspect their deliveries. */\nexport class Webhooks {\n constructor(private client: BaseClient) {}\n\n /** List all webhook endpoints in the workspace. */\n async list(): Promise<ApiResponse<WebhookEndpoint[]>> {\n return this.client.get(\"/api/v1/webhooks\");\n }\n\n /**\n * Create a webhook endpoint. Returns HTTP 201.\n *\n * **The response's `data.secret` contains the signing secret EXACTLY ONCE.**\n * It can never be retrieved again — store it securely immediately. You need\n * it to verify the `X-Medal-Signature` header on incoming deliveries (see\n * `verifyWebhookSignature`).\n *\n * `secret` is typed optional because an idempotent replay (retrying with the\n * same `Idempotency-Key`, `X-Idempotent-Replayed: true`) returns the existing\n * endpoint WITHOUT the secret — handle that case (rotate if you lost it).\n */\n async create(\n input: CreateWebhookInput,\n options?: RequestOptions,\n ): Promise<ApiResponse<WebhookEndpoint>> {\n return this.client.post(\"/api/v1/webhooks\", input, options);\n }\n\n /** Get a webhook endpoint by ID. */\n async get(id: string): Promise<ApiResponse<WebhookEndpoint>> {\n return this.client.get(`/api/v1/webhooks/${encodeURIComponent(id)}`);\n }\n\n /** Update a webhook endpoint (name, url, event types, filters, enabled). */\n async update(\n id: string,\n input: UpdateWebhookInput,\n options?: RequestOptions,\n ): Promise<ApiResponse<WebhookEndpoint>> {\n return this.client.patch(`/api/v1/webhooks/${encodeURIComponent(id)}`, input, options);\n }\n\n /**\n * Permanently delete a webhook endpoint (stops all outbound deliveries).\n * Capability-scoped tokens must pass `idempotencyKey` — the API requires\n * `Idempotency-Key` + `X-Capability-Confirmation` for direct capability\n * grants on this route. API keys with legacy scopes may omit it.\n */\n async delete(id: string, options?: RequestOptions): Promise<ApiResponse<WebhookDeleteResult>> {\n return this.client.delete(`/api/v1/webhooks/${encodeURIComponent(id)}`, options);\n }\n\n /** List recent deliveries for an endpoint (most recent first). */\n async deliveries(\n id: string,\n options?: ListDeliveriesOptions,\n ): Promise<ApiResponse<WebhookDelivery[]>> {\n const params: Record<string, string | undefined> = {};\n if (options?.limit !== undefined) params.limit = String(options.limit);\n return this.client.get(`/api/v1/webhooks/${encodeURIComponent(id)}/deliveries`, params);\n }\n\n /** Queue a signed `test.ping` delivery to the endpoint. Returns HTTP 202. */\n async test(id: string): Promise<ApiResponse<WebhookTestResult>> {\n return this.client.post(`/api/v1/webhooks/${encodeURIComponent(id)}/test`);\n }\n}\n","import type { BaseClient } from \"../client\";\nimport type { ApiResponse } from \"../types/common\";\nimport type { Workspace } from \"../types/workspaces\";\n\n/** Access workspaces for the authenticated credential. */\nexport class Workspaces {\n constructor(private client: BaseClient) {}\n\n /** List workspaces accessible to the current API key or OAuth token. */\n async list(): Promise<ApiResponse<Workspace[]>> {\n return this.client.get(\"/api/v1/me/workspaces\");\n }\n}\n","/**\n * Webhook event types and signature verification for the Medal Social\n * outbound webhook bridge.\n *\n * Every delivery is an HTTP POST with headers:\n * - `X-Medal-Timestamp` — Unix milliseconds when the request was signed\n * - `X-Medal-Signature` — `sha256=<base64(HMAC-SHA256(\"{timestamp}.{rawBody}\", secret))>`\n * - `X-Medal-Event` — the event type\n * - `X-Medal-Delivery-Id` / `Idempotency-Key` — unique delivery ID (deduplicate on this)\n *\n * Use {@link verifyWebhookSignature} to authenticate a delivery and get the\n * parsed, typed event back. Uses Web Crypto (`crypto.subtle`) so it works in\n * Node.js 18+, Deno, Bun, Cloudflare Workers, and browsers.\n */\n\n/** Snapshot of a conversation included in every helpdesk webhook event. */\nexport interface WebhookConversationSnapshot {\n id: string;\n channel: string;\n channelConnectionId: string | null;\n status: string;\n subject: string | null;\n assigneeUserId: string | null;\n contactId: string | null;\n visitorName: string | null;\n visitorEmail: string | null;\n externalConversationId: string | null;\n channelAccountId: string | null;\n messageCount: number;\n /** Unix timestamp in milliseconds. */\n lastMessageAt: number;\n /** Unix timestamp in milliseconds. */\n createdAt: number;\n}\n\n/** Snapshot of a message included in helpdesk message events. */\nexport interface WebhookMessageSnapshot {\n id: string;\n authorType: \"visitor\" | \"operator\" | \"ai\" | \"system\";\n messageType: \"chat\" | \"email\" | \"note\";\n body: string;\n authorUserId: string | null;\n authorName: string | null;\n externalMessageId: string | null;\n deliveryStatus: string | null;\n deliveryError: string | null;\n /** Unix timestamp in milliseconds. */\n createdAt: number;\n}\n\n/** Fields present in the `data` of every helpdesk event. */\ninterface HelpdeskEventData {\n /** Channel type at the top level, for quick filtering. */\n channel: string;\n channelConnectionId: string | null;\n conversation: WebhookConversationSnapshot;\n}\n\n/** Envelope fields shared by all webhook events. */\ninterface WebhookEventBase {\n /** Unique delivery/event ID — use for deduplication. */\n id: string;\n /** Unix timestamp in milliseconds when the event was created. */\n created_at: number;\n workspace_id: string;\n}\n\n/** A new conversation was created. */\nexport interface ConversationCreatedEvent extends WebhookEventBase {\n type: \"helpdesk.conversation_created\";\n data: HelpdeskEventData;\n}\n\n/** A conversation was assigned or unassigned. */\nexport interface ConversationAssignedEvent extends WebhookEventBase {\n type: \"helpdesk.conversation_assigned\";\n data: HelpdeskEventData & {\n assigneeUserId: string | null;\n previousAssigneeUserId: string | null;\n };\n}\n\n/** A conversation's status changed (open / snoozed / closed). */\nexport interface ConversationStatusChangedEvent extends WebhookEventBase {\n type: \"helpdesk.conversation_status_changed\";\n data: HelpdeskEventData & {\n status: string;\n previousStatus: string;\n };\n}\n\n/** A message arrived from the visitor/customer. */\nexport interface MessageReceivedEvent extends WebhookEventBase {\n type: \"helpdesk.message_received\";\n data: HelpdeskEventData & { message: WebhookMessageSnapshot };\n}\n\n/** A message was sent by an operator, AI, or the system. */\nexport interface MessageSentEvent extends WebhookEventBase {\n type: \"helpdesk.message_sent\";\n data: HelpdeskEventData & { message: WebhookMessageSnapshot };\n}\n\n/** The delivery status of an outbound message changed (sent / delivered / failed …). */\nexport interface MessageDeliveryUpdatedEvent extends WebhookEventBase {\n type: \"helpdesk.message_delivery_updated\";\n data: HelpdeskEventData & { message: WebhookMessageSnapshot };\n}\n\n/** A `test.ping` delivery queued via `medal.webhooks.test(id)`. Carries sample data. */\nexport interface TestPingEvent extends WebhookEventBase {\n type: \"test.ping\";\n data: Record<string, unknown>;\n}\n\n/**\n * Discriminated union of all webhook events, keyed on `type`.\n *\n * @example\n * ```ts\n * switch (event.type) {\n * case 'helpdesk.message_received':\n * console.log(event.data.message.body);\n * break;\n * case 'helpdesk.conversation_status_changed':\n * console.log(event.data.previousStatus, '→', event.data.status);\n * break;\n * }\n * ```\n */\nexport type WebhookEvent =\n | ConversationCreatedEvent\n | ConversationAssignedEvent\n | ConversationStatusChangedEvent\n | MessageReceivedEvent\n | MessageSentEvent\n | MessageDeliveryUpdatedEvent\n | TestPingEvent;\n\n/** Machine-readable reason a webhook verification failed. */\nexport type WebhookVerificationErrorCode =\n | \"malformed_header\"\n | \"timestamp_out_of_tolerance\"\n | \"invalid_signature\"\n | \"invalid_payload\";\n\n/** Thrown by {@link verifyWebhookSignature} when a delivery cannot be authenticated. */\nexport class WebhookVerificationError extends Error {\n readonly code: WebhookVerificationErrorCode;\n\n constructor(code: WebhookVerificationErrorCode, message: string) {\n super(message);\n this.name = \"WebhookVerificationError\";\n this.code = code;\n }\n}\n\n/** Input for {@link verifyWebhookSignature}. */\nexport interface VerifyWebhookSignatureInput {\n /** The RAW request body string, exactly as received (do not re-serialize parsed JSON). */\n payload: string;\n /** Value of the `X-Medal-Timestamp` header (Unix milliseconds). */\n timestamp: string;\n /** Value of the `X-Medal-Signature` header (`sha256=<base64>`). */\n signature: string;\n /** The endpoint signing secret (`whsec_…`) returned once at creation time. */\n secret: string;\n /** Max allowed clock skew between now and the signed timestamp. Default 5 minutes. */\n toleranceMs?: number;\n}\n\n/** Default allowed clock skew for webhook verification (5 minutes). */\nexport const DEFAULT_WEBHOOK_TOLERANCE_MS = 5 * 60 * 1000;\n\nfunction base64ToBytes(base64: string): Uint8Array<ArrayBuffer> {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n\n/**\n * Verify a webhook delivery's signature and timestamp, then return the parsed\n * typed event.\n *\n * Recomputes `HMAC-SHA256(\"{timestamp}.{payload}\", secret)` with Web Crypto\n * and compares it against the signature in constant time. Deliveries whose\n * timestamp deviates from the current time by more than `toleranceMs`\n * (default 5 minutes) are rejected to prevent replay attacks.\n *\n * @throws {WebhookVerificationError} if the headers are malformed, the\n * timestamp is outside the tolerance window, the signature does not match,\n * or the payload is not valid JSON.\n *\n * @example\n * ```ts\n * const event = await verifyWebhookSignature({\n * payload: rawBody,\n * timestamp: req.headers['x-medal-timestamp'],\n * signature: req.headers['x-medal-signature'],\n * secret: process.env.MEDAL_WEBHOOK_SECRET,\n * });\n * ```\n */\nexport async function verifyWebhookSignature(\n input: VerifyWebhookSignatureInput,\n): Promise<WebhookEvent> {\n const { payload, timestamp, signature, secret } = input;\n const toleranceMs = input.toleranceMs ?? DEFAULT_WEBHOOK_TOLERANCE_MS;\n\n if (typeof signature !== \"string\" || !signature.startsWith(\"sha256=\")) {\n throw new WebhookVerificationError(\n \"malformed_header\",\n \"Signature header must be in the form 'sha256=<base64>'\",\n );\n }\n\n const timestampMs = Number(timestamp);\n if (typeof timestamp !== \"string\" || timestamp === \"\" || !Number.isFinite(timestampMs)) {\n throw new WebhookVerificationError(\n \"malformed_header\",\n \"Timestamp header must be a Unix-milliseconds number string\",\n );\n }\n if (Math.abs(Date.now() - timestampMs) > toleranceMs) {\n throw new WebhookVerificationError(\n \"timestamp_out_of_tolerance\",\n `Timestamp is outside the allowed tolerance of ${toleranceMs}ms`,\n );\n }\n\n let signatureBytes: Uint8Array<ArrayBuffer>;\n try {\n signatureBytes = base64ToBytes(signature.slice(\"sha256=\".length));\n } catch {\n throw new WebhookVerificationError(\"invalid_signature\", \"Signature is not valid base64\");\n }\n\n const encoder = new TextEncoder();\n const key = await crypto.subtle.importKey(\n \"raw\",\n encoder.encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"verify\"],\n );\n // crypto.subtle.verify performs a constant-time comparison internally.\n const valid = await crypto.subtle.verify(\n \"HMAC\",\n key,\n signatureBytes,\n encoder.encode(`${timestamp}.${payload}`),\n );\n if (!valid) {\n throw new WebhookVerificationError(\"invalid_signature\", \"Signature does not match the payload\");\n }\n\n try {\n return JSON.parse(payload) as WebhookEvent;\n } catch {\n throw new WebhookVerificationError(\"invalid_payload\", \"Payload is not valid JSON\");\n }\n}\n","/**\n * Official TypeScript SDK for the Medal Social API.\n *\n * Provides typed access to posts, emails, contacts, deals, GDPR compliance,\n * helpdesk conversations, webhooks, and workspace management. Works in\n * Node.js, Deno, Bun, Cloudflare Workers, and modern browsers.\n *\n * @example\n * ```ts\n * import { Medal } from \"@medalsocial/sdk\";\n *\n * const medal = new Medal(\"medal_xxx\");\n * const { data: post } = await medal.posts.create({\n * content: \"Hello world!\",\n * channel_ids: [\"ch_1\"],\n * });\n * ```\n *\n * @module\n */\nimport { BaseClient } from \"./client\";\nimport { Contacts } from \"./resources/contacts\";\nimport { Deals } from \"./resources/deals\";\nimport { Emails } from \"./resources/emails\";\nimport { Gdpr } from \"./resources/gdpr\";\nimport { Helpdesk } from \"./resources/helpdesk\";\nimport { Posts } from \"./resources/posts\";\nimport { Webhooks } from \"./resources/webhooks\";\nimport { Workspaces } from \"./resources/workspaces\";\n\n/** Options for configuring the {@link Medal} client. */\nexport interface MedalOptions {\n /** Override the base URL (defaults to https://io.medalsocial.com). */\n baseUrl?: string;\n /** Request timeout in ms (default 30000). */\n timeout?: number;\n /**\n * Workspace ID — required for OAuth access tokens, ignored for API keys.\n * API keys are scoped to a single workspace, so the workspace is inferred.\n * OAuth tokens can access multiple workspaces, so you must specify which one.\n */\n workspaceId?: string;\n}\n\n/**\n * Medal Social SDK client.\n *\n * Supports both API key and OAuth access token authentication:\n *\n * @example API Key (recommended for server-side)\n * ```ts\n * import { Medal } from '@medalsocial/sdk';\n *\n * // API keys start with medal_ and are scoped to one workspace\n * const medal = new Medal('medal_xxx');\n * ```\n *\n * @example OAuth Access Token\n * ```ts\n * // OAuth tokens require a workspaceId\n * const medal = new Medal('oauth_access_token', {\n * workspaceId: 'workspace_id_here',\n * });\n * ```\n *\n * @example Full usage\n * ```ts\n * const medal = new Medal('medal_xxx');\n *\n * // Posts — create, schedule, publish\n * const { data: post } = await medal.posts.create({\n * content: 'Hello world!',\n * channel_ids: ['ch_1'],\n * });\n * await medal.posts.schedule(post.id, { scheduled_at: '2026-03-15T10:00:00Z' });\n *\n * // Emails — send transactional emails\n * await medal.emails.send({\n * template_slug: 'welcome',\n * to: 'user@example.com',\n * variables: { name: 'John' },\n * });\n *\n * // Contacts, Deals, GDPR, Workspaces\n * const contacts = await medal.contacts.list({ status: 'lead' });\n * const { data: deal } = await medal.deals.create({ title: 'Acme', value: 50000 });\n * await medal.gdpr.recordConsent({ email: 'u@x.com', consent_type: 'marketing_email', granted: true });\n * const { data: workspaces } = await medal.workspaces.list();\n * ```\n */\nexport class Medal {\n readonly emails: Emails;\n readonly contacts: Contacts;\n readonly deals: Deals;\n readonly gdpr: Gdpr;\n readonly helpdesk: Helpdesk;\n readonly posts: Posts;\n readonly webhooks: Webhooks;\n readonly workspaces: Workspaces;\n\n constructor(token: string, options?: MedalOptions) {\n if (!token) {\n throw new Error(\n \"Authentication token is required. Pass your medal_xxx API key or OAuth access token as the first argument.\",\n );\n }\n\n const client = new BaseClient({\n baseUrl: (options?.baseUrl ?? \"https://io.medalsocial.com\").replace(/\\/$/, \"\"),\n token,\n workspaceId: options?.workspaceId,\n timeout: options?.timeout ?? 30000,\n userAgent: \"medalsocial-sdk/1.0.0 (+https://github.com/Medal-Social/MedalSocial)\",\n });\n\n this.emails = new Emails(client);\n this.contacts = new Contacts(client);\n this.deals = new Deals(client);\n this.gdpr = new Gdpr(client);\n this.helpdesk = new Helpdesk(client);\n this.posts = new Posts(client);\n this.webhooks = new Webhooks(client);\n this.workspaces = new Workspaces(client);\n }\n}\n\nexport type { RequestOptions } from \"./client\";\nexport { BaseClient } from \"./client\";\nexport type {\n components as OpenApiComponents,\n operations as OpenApiOperations,\n paths as OpenApiPaths,\n} from \"./openapi.generated\";\n// Resource class re-exports (for advanced usage)\nexport { Contacts } from \"./resources/contacts\";\nexport { Deals } from \"./resources/deals\";\nexport { Emails } from \"./resources/emails\";\nexport { Gdpr } from \"./resources/gdpr\";\nexport { Helpdesk } from \"./resources/helpdesk\";\nexport { Posts } from \"./resources/posts\";\nexport { Webhooks } from \"./resources/webhooks\";\nexport { Workspaces } from \"./resources/workspaces\";\nexport type { ApiResponse, PaginatedResponse, PaginationOptions } from \"./types/common\";\n// Re-export all types\nexport { MedalApiError } from \"./types/common\";\nexport type {\n Activity,\n AddNoteInput,\n Contact,\n ContactCreateResult,\n ContactNoteResult,\n ContactRemoveResult,\n ContactStatus,\n ContactUpdateResult,\n CreateContactInput,\n EmailStatus,\n ImportContactInput,\n ImportContactsResult,\n ListContactsOptions,\n UpdateContactInput,\n} from \"./types/contacts\";\nexport type {\n CreateDealInput,\n Deal,\n DealCreateResult,\n DealRemoveResult,\n DealStatus,\n DealUpdateResult,\n ListDealsOptions,\n UpdateDealInput,\n} from \"./types/deals\";\nexport type {\n BatchSendInput,\n BatchSendResult,\n BatchSendSummary,\n EmailSend,\n EmailSendResult,\n EmailTemplate,\n EmailTemplateDetail,\n GetTemplateOptions,\n SendEmailInput,\n} from \"./types/emails\";\nexport type {\n ConsentRecord,\n ConsentResult,\n ConsentType,\n ContactConsents,\n CookieCategoryConsent,\n CookieConsentInput,\n GdprExport,\n RecordConsentInput,\n} from \"./types/gdpr\";\nexport type {\n Conversation,\n ConversationMessage,\n ConversationStatus,\n ConversationUpdateResult,\n CreateReplyInput,\n HelpdeskMessageType,\n ListConversationsOptions,\n MessageAuthorType,\n ReplyCreateResult,\n UpdateConversationInput,\n} from \"./types/helpdesk\";\nexport type {\n Channel,\n CreatePostInput,\n ListPostsOptions,\n Post,\n PostDetail,\n PostType,\n PostVariant,\n PublishResult,\n SchedulePostInput,\n ScheduleResult,\n UpdatePostInput,\n} from \"./types/posts\";\nexport type {\n CreateWebhookInput,\n ListDeliveriesOptions,\n UpdateWebhookInput,\n WebhookDeleteResult,\n WebhookDelivery,\n WebhookEndpoint,\n WebhookTestResult,\n} from \"./types/webhooks\";\nexport type { Workspace } from \"./types/workspaces\";\nexport type {\n ConversationAssignedEvent,\n ConversationCreatedEvent,\n ConversationStatusChangedEvent,\n MessageDeliveryUpdatedEvent,\n MessageReceivedEvent,\n MessageSentEvent,\n TestPingEvent,\n VerifyWebhookSignatureInput,\n WebhookConversationSnapshot,\n WebhookEvent,\n WebhookMessageSnapshot,\n WebhookVerificationErrorCode,\n} from \"./webhook-events\";\n// Webhook event verification + typed events\nexport {\n DEFAULT_WEBHOOK_TOLERANCE_MS,\n verifyWebhookSignature,\n WebhookVerificationError,\n} from \"./webhook-events\";\n\n/** Convenience factory — equivalent to `new Medal(apiKey, options)`. */\nexport function createMedalClient(apiKey: string, options?: MedalOptions): Medal {\n return new Medal(apiKey, options);\n}\n\nexport default Medal;\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../../src/types/capabilities.ts","../../src/capability-confirmer.ts","../../src/types/common.ts","../../src/client.ts","../../src/resources/capability-confirmations.ts","../../src/resources/channels.ts","../../src/resources/contacts.ts","../../src/resources/deals.ts","../../src/resources/emails.ts","../../src/resources/gdpr.ts","../../src/resources/helpdesk.ts","../../src/resources/posts.ts","../../src/resources/scan.ts","../../src/resources/webhooks.ts","../../src/resources/workspaces.ts","../../src/webhook-events.ts","../../src/index.ts"],"sourcesContent":["import type { CreateConnectLinkInput } from \"./channels\";\nimport type { CreateReplyInput, UpdateConversationInput } from \"./helpdesk\";\nimport type { CreateWebhookInput, UpdateWebhookInput } from \"./webhooks\";\n\n/**\n * Capability confirmation types.\n *\n * Medal's confirmable write routes require BOTH an `Idempotency-Key` and an\n * `X-Capability-Confirmation` token whenever the calling credential holds the\n * capability scope *directly* — which is the case for every correctly-scoped\n * partner key and OAuth grant. (API keys carrying only legacy scopes are\n * exempt.) The token is minted by `POST /api/v1/capability-confirmations` and\n * is bound to the workspace, the auth subject, the HTTP method + path, the\n * capability's required scopes, and the idempotency key.\n */\n\n/**\n * Confirmable capability ids backing the write routes this SDK exposes.\n *\n * Mirrors the server-side capability registry. Each id maps to exactly one\n * method + path template — see {@link CAPABILITY_ROUTES}.\n */\nexport const CAPABILITY_IDS = [\n \"channel.connect_link.create.execute\",\n \"channel.connect_link.revoke.execute\",\n \"channel.connection.disconnect.execute\",\n \"helpdesk.conversation.reply.execute\",\n \"helpdesk.conversation.update.execute\",\n \"helpdesk.webhook.create.execute\",\n \"helpdesk.webhook.update.execute\",\n \"helpdesk.webhook.delete.execute\",\n] as const;\n\n/** A confirmable capability id backing an SDK write route. */\nexport type CapabilityId = (typeof CAPABILITY_IDS)[number];\n\n/** The API route a capability confirms, as registered server-side. */\nexport interface CapabilityRoute {\n method: \"POST\" | \"PATCH\" | \"DELETE\";\n /** Path template; `{id}` is filled from `path_params.id`. */\n path_template: string;\n}\n\n/**\n * Method + path template for each confirmable capability.\n *\n * The server resolves the same mapping from its capability registry — this\n * copy exists so the SDK can build human-readable previews and supply\n * `path_params` without a round trip.\n */\nexport const CAPABILITY_ROUTES: Record<CapabilityId, CapabilityRoute> = {\n \"channel.connect_link.create.execute\": {\n method: \"POST\",\n path_template: \"/api/v1/channels/connect-links\",\n },\n \"channel.connect_link.revoke.execute\": {\n method: \"DELETE\",\n path_template: \"/api/v1/channels/connect-links/{id}\",\n },\n \"channel.connection.disconnect.execute\": {\n method: \"DELETE\",\n path_template: \"/api/v1/channels/connections/{id}\",\n },\n \"helpdesk.conversation.reply.execute\": {\n method: \"POST\",\n path_template: \"/api/v1/helpdesk/replies\",\n },\n \"helpdesk.conversation.update.execute\": {\n method: \"PATCH\",\n path_template: \"/api/v1/helpdesk/conversations/{id}\",\n },\n \"helpdesk.webhook.create.execute\": {\n method: \"POST\",\n path_template: \"/api/v1/webhooks\",\n },\n \"helpdesk.webhook.update.execute\": {\n method: \"PATCH\",\n path_template: \"/api/v1/webhooks/{id}\",\n },\n \"helpdesk.webhook.delete.execute\": {\n method: \"DELETE\",\n path_template: \"/api/v1/webhooks/{id}\",\n },\n};\n\n/** Primitive accepted as a capability path parameter value. */\nexport type CapabilityPathParamValue = string | number | boolean;\n\n/** Input for `POST /api/v1/capability-confirmations`. */\nexport interface IssueCapabilityConfirmationInput {\n /**\n * Capability to confirm. Unknown ids are rejected with\n * `CAPABILITY_NOT_FOUND`; read-only or non-confirmable capabilities with\n * `CAPABILITY_NOT_CONFIRMABLE`.\n */\n capability_id: CapabilityId | (string & {});\n /**\n * Concrete `/api/v1/...` path the token should be bound to. Optional when\n * the capability has exactly one API target (all capabilities in\n * {@link CAPABILITY_ROUTES} do); required when it has several. Must match a\n * path built from the capability's own templates.\n */\n api_path?: string;\n /** Values for the capability path template's parameters, e.g. `{ id: 'wh_1' }`. */\n path_params?: Record<string, CapabilityPathParamValue>;\n /**\n * The exact `Idempotency-Key` you will send on the confirmed write. The\n * token is bound to it — a mismatch is rejected. Required for every\n * capability in {@link CAPABILITY_ROUTES}.\n */\n idempotency_key?: string;\n /**\n * Human-readable description of the action being approved (1–4000 chars).\n * This is the text your user saw and approved, and it is retained for audit.\n */\n preview_summary: string;\n /**\n * Must be `true`.\n *\n * **This asserts that a human on your side approved this specific action.**\n * Do not send it to rubber-stamp unattended writes — it is the audit record\n * that a person, not a script, authorised the change.\n */\n user_approved: true;\n}\n\n/** A minted capability confirmation token. */\nexport interface CapabilityConfirmation {\n /** Send this as the `X-Capability-Confirmation` header on the write. */\n confirmation_token: string;\n token_type: \"medal_capability_confirmation\";\n capability_id: string;\n /** HTTP method the token is bound to. */\n method: string;\n /** Concrete API path the token is bound to. */\n path: string;\n /** Capability scopes the token was minted against. */\n required_scopes: string[];\n /** Idempotency key the token is bound to, or `null` if it was minted unbound. */\n idempotency_key: string | null;\n /** Lifetime in seconds (60–900). */\n expires_in: number;\n /** ISO-8601 expiry timestamp. */\n expires_at: string;\n /** Echo of the submitted `preview_summary`. */\n preview_summary: string;\n}\n\n/**\n * Request body type for each confirmable capability.\n *\n * `undefined` for routes that take no request body (the `DELETE` routes).\n */\nexport interface CapabilityWriteBodies {\n \"channel.connect_link.create.execute\": CreateConnectLinkInput;\n \"channel.connect_link.revoke.execute\": undefined;\n \"channel.connection.disconnect.execute\": undefined;\n \"helpdesk.conversation.reply.execute\": CreateReplyInput;\n \"helpdesk.conversation.update.execute\": UpdateConversationInput;\n \"helpdesk.webhook.create.execute\": CreateWebhookInput;\n \"helpdesk.webhook.update.execute\": UpdateWebhookInput;\n \"helpdesk.webhook.delete.execute\": undefined;\n}\n\n/**\n * A capability paired with the request body for that exact route.\n *\n * Modelled as a discriminated union rather than two independent parameters so\n * the pair cannot be decoupled: passing a `helpdesk.conversation.reply.execute`\n * id alongside a webhook payload is a compile error, even when the id's static\n * type is the full {@link CapabilityId} union.\n */\nexport type CapabilityWriteRequest = {\n [K in CapabilityId]: {\n /** Capability about to be confirmed. */\n capabilityId: K;\n /** The request body of the pending write, or `undefined` for `DELETE` routes. */\n body: CapabilityWriteBodies[K];\n };\n}[CapabilityId];\n\n/** Fields common to every {@link AutoConfirmContext} variant. */\ninterface AutoConfirmContextBase {\n /** HTTP method of the write. */\n method: string;\n /** Resolved API path of the write (path params substituted + encoded). */\n path: string;\n /** Path parameters used to resolve `path`, if any. */\n pathParams?: Record<string, CapabilityPathParamValue>;\n /** Idempotency key that will be bound to the token and sent on the write. */\n idempotencyKey: string;\n}\n\n/**\n * Context handed to an {@link AutoConfirmOptions.previewSummary} callback.\n *\n * A discriminated union on `capabilityId` — narrow on it to get the exact\n * `body` type for that route:\n *\n * ```ts\n * previewSummary: (ctx) => {\n * if (ctx.capabilityId === 'helpdesk.conversation.reply.execute') {\n * // ctx.body is CreateReplyInput here\n * return `Reply to ${ctx.body.conversation_id}: ${ctx.body.body}`;\n * }\n * return `${ctx.method} ${ctx.path}`;\n * }\n * ```\n *\n * `body` is the **exact object you passed to the SDK method**, by reference\n * and unmodified — it is your own payload, so there is nothing to redact and\n * nothing crosses a tenant boundary. Treat it as read-only: mutating it from\n * the callback would change what is actually sent.\n */\nexport type AutoConfirmContext = AutoConfirmContextBase & CapabilityWriteRequest;\n\n/**\n * Opt-in auto-confirmation.\n *\n * When configured, the SDK mints an idempotency key and a confirmation token\n * for you before each confirmable write, then attaches both headers.\n *\n * **This is not a bypass.** Every minted token carries\n * `user_approved: true`, which asserts that *your own user* approved that\n * specific action — the `preview_summary` you return is the audit record of\n * what they approved. Only enable this on a code path where a human really did\n * approve the write. Never wire it into unattended automation.\n */\nexport interface AutoConfirmOptions {\n /**\n * Build the `preview_summary` for the pending write. Must return a\n * non-empty string describing what the user approved; returning blank text\n * throws instead of asserting an approval that has no description.\n *\n * The context includes the pending request `body`, so the summary can name\n * the specific action rather than the route — narrow on\n * `context.capabilityId` to get the exact payload type. Prefer a\n * payload-aware summary: `\"Reply to conv_1: 'Refund issued'\"` is an audit\n * record, `\"POST /api/v1/helpdesk/replies\"` is not.\n *\n * The server caps `preview_summary` at 4000 characters, so summarise the\n * payload rather than serialising it wholesale.\n */\n previewSummary: (context: AutoConfirmContext) => string;\n}\n","import type { RequestOptions } from \"./client\";\nimport type { CapabilityConfirmations } from \"./resources/capability-confirmations\";\nimport type {\n AutoConfirmOptions,\n CapabilityPathParamValue,\n CapabilityWriteRequest,\n} from \"./types/capabilities\";\nimport { CAPABILITY_ROUTES } from \"./types/capabilities\";\n\nfunction newIdempotencyKey(): string {\n const cryptoRef = globalThis.crypto;\n if (typeof cryptoRef?.randomUUID === \"function\") {\n return cryptoRef.randomUUID();\n }\n /* v8 ignore next 2 -- fallback for runtimes without WebCrypto randomUUID */\n return `idem_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 12)}`;\n}\n\nfunction resolvePath(\n template: string,\n pathParams?: Record<string, CapabilityPathParamValue>,\n): string {\n return template.replace(/\\{([^}/]+)\\}/g, (_match, name: string) => {\n const value = pathParams?.[name];\n return value === undefined ? `{${name}}` : encodeURIComponent(String(value));\n });\n}\n\n/**\n * Resolves the `Idempotency-Key` + `X-Capability-Confirmation` pair required\n * by confirmable write routes.\n *\n * Auto-confirmation is OFF unless the integrator opts in — either globally via\n * the `Medal` constructor's `autoConfirmCapabilities`, or per call via\n * `{ autoConfirm: { previewSummary } }`. When it is off this is a pass-through:\n * whatever headers the caller supplied are what gets sent.\n */\nexport class CapabilityConfirmer {\n constructor(\n private confirmations: CapabilityConfirmations,\n private defaults?: AutoConfirmOptions,\n ) {}\n\n /**\n * Return the request options to use for a confirmable write, minting the\n * idempotency key and confirmation token first when auto-confirm is active.\n *\n * `body` is the pending request payload (`undefined` for `DELETE` routes).\n * It is handed to the `previewSummary` callback by reference so the summary\n * can describe the specific action, not just the route — it is the caller's\n * own payload, so it is passed through unmodified and unredacted.\n */\n async prepare(\n request: CapabilityWriteRequest,\n pathParams?: Record<string, CapabilityPathParamValue>,\n options?: RequestOptions,\n ): Promise<RequestOptions | undefined> {\n const auto =\n options?.autoConfirm === false ? undefined : (options?.autoConfirm ?? this.defaults);\n if (!auto) return options;\n // Nothing to mint — the caller already brought both halves.\n if (options?.idempotencyKey && options?.capabilityConfirmation) return options;\n\n const route = CAPABILITY_ROUTES[request.capabilityId];\n const idempotencyKey = options?.idempotencyKey ?? newIdempotencyKey();\n const path = resolvePath(route.path_template, pathParams);\n\n const previewSummary = auto.previewSummary({\n ...request,\n method: route.method,\n path,\n ...(pathParams ? { pathParams } : {}),\n idempotencyKey,\n });\n if (typeof previewSummary !== \"string\" || previewSummary.trim() === \"\") {\n throw new Error(\n `autoConfirm.previewSummary must return a non-empty summary for ${request.capabilityId}. ` +\n \"The summary is the audit record of what your user approved — refusing to assert \" +\n \"user_approved: true without one.\",\n );\n }\n\n const { data } = await this.confirmations.create({\n capability_id: request.capabilityId,\n ...(pathParams ? { path_params: pathParams } : {}),\n idempotency_key: idempotencyKey,\n preview_summary: previewSummary,\n user_approved: true,\n });\n\n return {\n ...options,\n idempotencyKey,\n capabilityConfirmation: data.confirmation_token,\n };\n }\n}\n","/** Successful API response wrapper */\nexport interface ApiResponse<T> {\n data: T;\n}\n\n/** Paginated API response */\nexport interface PaginatedResponse<T> {\n data: T[];\n pagination: {\n has_more: boolean;\n next_cursor: string | null;\n };\n}\n\n/** API error thrown by the client */\nexport class MedalApiError extends Error {\n readonly status: number;\n readonly code: string;\n readonly details?: unknown;\n\n constructor(status: number, code: string, message: string, details?: unknown) {\n super(message);\n this.name = \"MedalApiError\";\n this.status = status;\n this.code = code;\n this.details = details;\n }\n}\n\n/** Pagination options for list endpoints */\nexport interface PaginationOptions {\n limit?: number;\n cursor?: string;\n}\n","import type { AutoConfirmOptions } from \"./types/capabilities\";\nimport { MedalApiError } from \"./types/common\";\n\n/** Configuration for the low-level HTTP client. */\nexport interface ClientConfig {\n baseUrl: string;\n token: string;\n workspaceId?: string;\n timeout: number;\n userAgent: string;\n}\n\n/** Per-request options for write operations. */\nexport interface RequestOptions {\n /**\n * Idempotency key sent as the `Idempotency-Key` header. Retries with the\n * same key return the original result instead of repeating the operation.\n * Required by some endpoints for capability-scoped tokens (e.g. helpdesk\n * replies, webhook creation).\n */\n idempotencyKey?: string;\n /**\n * Capability confirmation token sent as the `X-Capability-Confirmation`\n * header. Required alongside `idempotencyKey` when a token granted a\n * capability-style scope directly (e.g. `helpdesk.webhook.manage`) executes\n * a confirmable write route. Obtain one from\n * `POST /api/v1/capability-confirmations`. API keys with legacy scopes do\n * not need it.\n */\n capabilityConfirmation?: string;\n /**\n * Opt in to (or out of) automatic capability confirmation for this call.\n *\n * Supply `{ previewSummary }` to have the SDK mint the idempotency key and\n * the `X-Capability-Confirmation` token itself; pass `false` to suppress a\n * client-level `autoConfirmCapabilities` default. Defaults to the client\n * setting, which itself defaults to OFF.\n *\n * Auto-confirmation sends `user_approved: true` on your behalf, asserting\n * that a human on your side approved this exact action — only use it where\n * that is true.\n *\n * Ignored on routes that do not require a capability confirmation.\n */\n autoConfirm?: AutoConfirmOptions | false;\n}\n\n/**\n * Low-level HTTP client used by all resource classes.\n * Handles authentication, retries, timeout, and error parsing.\n */\nexport class BaseClient {\n /** Resolved client configuration. */\n readonly config: ClientConfig;\n\n constructor(config: ClientConfig) {\n this.config = config;\n }\n\n /** Execute an authenticated GET request and return the parsed JSON body. */\n async get<T>(path: string, params?: Record<string, string | undefined>): Promise<T> {\n const url = this.buildUrl(path, params);\n return this.request<T>(url, { method: \"GET\" });\n }\n\n /** Execute an authenticated POST request with a JSON body. */\n async post<T>(path: string, body?: unknown, options?: RequestOptions): Promise<T> {\n return this.request<T>(this.buildUrl(path), {\n method: \"POST\",\n headers: this.writeHeaders(options),\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n }\n\n /** Execute an authenticated PATCH request with a JSON body. */\n async patch<T>(path: string, body: unknown, options?: RequestOptions): Promise<T> {\n return this.request<T>(this.buildUrl(path), {\n method: \"PATCH\",\n headers: this.writeHeaders(options),\n body: JSON.stringify(body),\n });\n }\n\n /** Execute an authenticated DELETE request. */\n async delete<T>(path: string, options?: RequestOptions): Promise<T> {\n return this.request<T>(this.buildUrl(path), {\n method: \"DELETE\",\n headers: this.writeHeaders(options),\n });\n }\n\n private writeHeaders(options?: RequestOptions): Record<string, string> {\n const headers: Record<string, string> = { \"content-type\": \"application/json\" };\n if (options?.idempotencyKey) {\n headers[\"idempotency-key\"] = options.idempotencyKey;\n }\n if (options?.capabilityConfirmation) {\n headers[\"x-capability-confirmation\"] = options.capabilityConfirmation;\n }\n return headers;\n }\n\n private buildUrl(path: string, params?: Record<string, string | undefined>): string {\n const url = new URL(`${this.config.baseUrl}${path}`);\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n url.searchParams.set(key, value);\n }\n }\n }\n return url.toString();\n }\n\n private async request<T>(url: string, init: RequestInit): Promise<T> {\n const maxAttempts = 3;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n const headers = new Headers(init.headers);\n headers.set(\"authorization\", `Bearer ${this.config.token}`);\n if (this.config.workspaceId) {\n headers.set(\"x-workspace-id\", this.config.workspaceId);\n }\n try {\n headers.set(\"user-agent\", this.config.userAgent);\n } catch {\n // Browsers disallow setting user-agent\n }\n\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.config.timeout);\n\n let res: Response;\n try {\n res = await fetch(url, { ...init, headers, signal: controller.signal });\n } finally {\n clearTimeout(timeout);\n }\n\n // Retry on 429 / 5xx (but not on the final attempt)\n if (\n (res.status === 429 || (res.status >= 500 && res.status <= 599)) &&\n attempt < maxAttempts\n ) {\n const retryAfter = res.headers.get(\"retry-after\");\n let delayMs = 0;\n if (retryAfter) {\n const seconds = Number(retryAfter);\n delayMs = Number.isFinite(seconds) ? seconds * 1000 : 0;\n }\n if (delayMs <= 0) {\n delayMs = 250 * attempt;\n }\n await new Promise((r) => setTimeout(r, delayMs));\n continue;\n }\n\n // Parse response\n const text = await res.text();\n let parsed: unknown;\n try {\n parsed = text ? JSON.parse(text) : undefined;\n } catch {\n parsed = text;\n }\n\n if (!res.ok) {\n const body = parsed as\n | { error?: { code?: string; message?: string; details?: unknown } }\n | undefined;\n throw new MedalApiError(\n res.status,\n body?.error?.code ?? \"UNKNOWN_ERROR\",\n body?.error?.message ?? `HTTP ${res.status}: ${res.statusText}`,\n body?.error?.details,\n );\n }\n\n return parsed as T;\n }\n\n /* v8 ignore next -- unreachable: loop always returns or throws */\n throw new Error(\"Request failed after retries\");\n }\n}\n","import type { BaseClient } from \"../client\";\nimport type {\n CapabilityConfirmation,\n IssueCapabilityConfirmationInput,\n} from \"../types/capabilities\";\nimport type { ApiResponse } from \"../types/common\";\n\n/**\n * Mint short-lived capability confirmation tokens.\n *\n * Medal's confirmable write routes (connect links, channel connections,\n * helpdesk replies/updates, webhook endpoint writes) require BOTH an\n * `Idempotency-Key` and an `X-Capability-Confirmation` header when the calling\n * credential holds the capability scope *directly* — which is the case for\n * every correctly-scoped partner key. This resource issues that header value.\n *\n * @example Explicit flow\n * ```ts\n * const idempotencyKey = crypto.randomUUID();\n * const { data: confirmation } = await medal.capabilityConfirmations.create({\n * capability_id: 'channel.connect_link.create.execute',\n * idempotency_key: idempotencyKey,\n * preview_summary: 'Mint a Telegram connect link for Acme Support',\n * user_approved: true, // a human on your side approved this exact action\n * });\n *\n * await medal.channels.connectLinks.create(\n * { channel_type: 'telegram_inbox', label: 'Acme Support' },\n * { idempotencyKey, capabilityConfirmation: confirmation.confirmation_token },\n * );\n * ```\n */\nexport class CapabilityConfirmations {\n constructor(private client: BaseClient) {}\n\n /**\n * Issue a confirmation token for one pending write.\n *\n * The token is bound to the workspace, the auth subject, the capability's\n * method + path, its required scopes, and `idempotency_key` — so it is\n * usable exactly once, for exactly the write it describes, and expires\n * within 15 minutes.\n *\n * Setting `user_approved: true` asserts that a human on your side approved\n * this specific action. `preview_summary` is what they approved, and is\n * retained for audit — write it for a human reader, not a log parser.\n */\n async create(\n input: IssueCapabilityConfirmationInput,\n ): Promise<ApiResponse<CapabilityConfirmation>> {\n return this.client.post(\"/api/v1/capability-confirmations\", input);\n }\n}\n","import { CapabilityConfirmer } from \"../capability-confirmer\";\nimport type { BaseClient, RequestOptions } from \"../client\";\nimport type {\n ChannelConnection,\n ChannelConnectionDisconnectResult,\n ConnectLink,\n ConnectLinkCreateResult,\n ConnectLinkRevokeResult,\n CreateConnectLinkInput,\n ListConnectLinksOptions,\n} from \"../types/channels\";\nimport type { ApiResponse, PaginatedResponse, PaginationOptions } from \"../types/common\";\nimport { CapabilityConfirmations } from \"./capability-confirmations\";\n\n/** Mint, list, and revoke hosted connect links. */\nclass ChannelConnectLinks {\n constructor(\n private client: BaseClient,\n private confirmer: CapabilityConfirmer,\n ) {}\n\n /**\n * Mint a single-use hosted connect link. Returns HTTP 201.\n *\n * **The response's `data.url` contains the one-time link token EXACTLY\n * ONCE.** Send it to the person who should connect their account — an\n * idempotent replay (same `Idempotency-Key`) returns the link WITHOUT\n * `url`, so store it immediately (or revoke and mint a new link if lost).\n *\n * Requires the `channel.connect.manage` scope; OAuth callers additionally\n * need the workspace `admin` role.\n */\n async create(\n input: CreateConnectLinkInput,\n options?: RequestOptions,\n ): Promise<ApiResponse<ConnectLinkCreateResult>> {\n const resolved = await this.confirmer.prepare(\n { capabilityId: \"channel.connect_link.create.execute\", body: input },\n undefined,\n options,\n );\n return this.client.post(\"/api/v1/channels/connect-links\", input, resolved);\n }\n\n /**\n * List the workspace's connect links (tokens are never returned), newest\n * first, with cursor-based pagination.\n *\n * `limit` defaults to 50 server-side and is capped at 100. Follow\n * `pagination.next_cursor` while `pagination.has_more` is true.\n *\n * The `channel_type` / `status` filters are applied **within** each page,\n * so a page may hold fewer than `limit` items while `has_more` is still\n * true — drive the loop off `has_more`, never off the item count.\n */\n async list(options?: ListConnectLinksOptions): Promise<PaginatedResponse<ConnectLink>> {\n const params: Record<string, string | undefined> = {};\n if (options?.limit !== undefined) params.limit = String(options.limit);\n if (options?.cursor) params.cursor = options.cursor;\n if (options?.channel_type) params.channel_type = options.channel_type;\n if (options?.status) params.status = options.status;\n return this.client.get(\"/api/v1/channels/connect-links\", params);\n }\n\n /** Revoke a pending connect link so it can no longer be consumed. */\n async revoke(\n id: string,\n options?: RequestOptions,\n ): Promise<ApiResponse<ConnectLinkRevokeResult>> {\n const resolved = await this.confirmer.prepare(\n { capabilityId: \"channel.connect_link.revoke.execute\", body: undefined },\n { id },\n options,\n );\n return this.client.delete(`/api/v1/channels/connect-links/${encodeURIComponent(id)}`, resolved);\n }\n}\n\n/** List and disconnect the workspace's channel connections. */\nclass ChannelConnections {\n constructor(\n private client: BaseClient,\n private confirmer: CapabilityConfirmer,\n ) {}\n\n /**\n * List the workspace's channel connections (generic, channel-agnostic\n * shape), newest first, with cursor-based pagination.\n *\n * `limit` defaults to 50 server-side and is capped at 100. Follow\n * `pagination.next_cursor` while `pagination.has_more` is true. Rows that\n * are not projectable as connections are dropped within the page, so a page\n * may hold fewer than `limit` items while `has_more` is still true — drive\n * the loop off `has_more`, never off the item count.\n */\n async list(options?: PaginationOptions): Promise<PaginatedResponse<ChannelConnection>> {\n const params: Record<string, string | undefined> = {};\n if (options?.limit !== undefined) params.limit = String(options.limit);\n if (options?.cursor) params.cursor = options.cursor;\n return this.client.get(\"/api/v1/channels/connections\", params);\n }\n\n /**\n * Disconnect a connected channel account (best-effort platform logout, then\n * local revoke). Emits a `helpdesk.channel_disconnected` webhook event with\n * `reason: \"api_disconnect\"` if the account was previously connected.\n */\n async disconnect(\n id: string,\n options?: RequestOptions,\n ): Promise<ApiResponse<ChannelConnectionDisconnectResult>> {\n const resolved = await this.confirmer.prepare(\n { capabilityId: \"channel.connection.disconnect.execute\", body: undefined },\n { id },\n options,\n );\n return this.client.delete(`/api/v1/channels/connections/${encodeURIComponent(id)}`, resolved);\n }\n}\n\n/**\n * Partner channel connect — mint hosted connect links that let an external\n * person (no Medal account required) attach a channel account (e.g.\n * `telegram_inbox`) to the workspace's helpdesk, and manage the resulting\n * connections.\n */\nexport class Channels {\n readonly connectLinks: ChannelConnectLinks;\n readonly connections: ChannelConnections;\n\n constructor(client: BaseClient, confirmer?: CapabilityConfirmer) {\n // Direct consumers (`new Channels(client)`) get a confirmer with no\n // client-level default: auto-confirm stays off unless a call opts in via\n // `{ autoConfirm: { previewSummary } }`.\n const resolved = confirmer ?? new CapabilityConfirmer(new CapabilityConfirmations(client));\n this.connectLinks = new ChannelConnectLinks(client, resolved);\n this.connections = new ChannelConnections(client, resolved);\n }\n}\n","import type { BaseClient } from \"../client\";\nimport type { ApiResponse, PaginatedResponse, PaginationOptions } from \"../types/common\";\nimport type {\n Activity,\n AddNoteInput,\n Contact,\n ContactCreateResult,\n ContactNoteResult,\n ContactRemoveResult,\n ContactUpdateResult,\n CreateContactInput,\n ImportContactInput,\n ImportContactsResult,\n ListContactsOptions,\n UpdateContactInput,\n} from \"../types/contacts\";\n\n/** Manage contacts in the workspace CRM. */\nexport class Contacts {\n constructor(private client: BaseClient) {}\n\n /** List contacts with cursor-based pagination and optional filters. */\n async list(options?: ListContactsOptions): Promise<PaginatedResponse<Contact>> {\n const params: Record<string, string | undefined> = {};\n if (options?.limit !== undefined) params.limit = String(options.limit);\n if (options?.cursor) params.cursor = options.cursor;\n if (options?.status) params.status = options.status;\n if (options?.email_status) params.email_status = options.email_status;\n if (options?.label_ids) params.label_ids = options.label_ids.join(\",\");\n if (options?.search) params.search = options.search;\n return this.client.get(\"/api/v1/contacts\", params);\n }\n\n /** Create a new contact. Email must be unique in the workspace. */\n async create(input: CreateContactInput): Promise<ApiResponse<ContactCreateResult>> {\n return this.client.post(\"/api/v1/contacts\", input);\n }\n\n /** Get a contact by ID. */\n async get(id: string): Promise<ApiResponse<Contact>> {\n return this.client.get(`/api/v1/contacts/${encodeURIComponent(id)}`);\n }\n\n /** Update one or more fields on a contact. */\n async update(id: string, input: UpdateContactInput): Promise<ApiResponse<ContactUpdateResult>> {\n return this.client.patch(`/api/v1/contacts/${encodeURIComponent(id)}`, input);\n }\n\n /** Permanently delete a contact. */\n async remove(id: string): Promise<ApiResponse<ContactRemoveResult>> {\n return this.client.delete(`/api/v1/contacts/${encodeURIComponent(id)}`);\n }\n\n /** Get the activity timeline for a contact. */\n async activities(id: string, options?: PaginationOptions): Promise<PaginatedResponse<Activity>> {\n const params: Record<string, string | undefined> = {};\n if (options?.limit !== undefined) params.limit = String(options.limit);\n if (options?.cursor) params.cursor = options.cursor;\n return this.client.get(`/api/v1/contacts/${encodeURIComponent(id)}/activities`, params);\n }\n\n /** Add a note to a contact's timeline. */\n async addNote(id: string, input: AddNoteInput): Promise<ApiResponse<ContactNoteResult>> {\n return this.client.post(`/api/v1/contacts/${encodeURIComponent(id)}/notes`, input);\n }\n\n /** Bulk import contacts (max 500). Duplicates are skipped. */\n async import(contacts: ImportContactInput[]): Promise<ApiResponse<ImportContactsResult>> {\n return this.client.post(\"/api/v1/contacts/import\", { contacts });\n }\n}\n","import type { BaseClient } from \"../client\";\nimport type { ApiResponse, PaginatedResponse } from \"../types/common\";\nimport type {\n CreateDealInput,\n Deal,\n DealCreateResult,\n DealRemoveResult,\n DealUpdateResult,\n ListDealsOptions,\n UpdateDealInput,\n} from \"../types/deals\";\n\n/** Manage sponsorship deals in the workspace. */\nexport class Deals {\n constructor(private client: BaseClient) {}\n\n /** List deals with cursor-based pagination and optional filters. */\n async list(options?: ListDealsOptions): Promise<PaginatedResponse<Deal>> {\n const params: Record<string, string | undefined> = {};\n if (options?.limit !== undefined) params.limit = String(options.limit);\n if (options?.cursor) params.cursor = options.cursor;\n if (options?.status) params.status = options.status;\n if (options?.search) params.search = options.search;\n return this.client.get(\"/api/v1/deals\", params);\n }\n\n /** Create a new deal. */\n async create(input: CreateDealInput): Promise<ApiResponse<DealCreateResult>> {\n return this.client.post(\"/api/v1/deals\", input);\n }\n\n /** Get a deal by ID. */\n async get(id: string): Promise<ApiResponse<Deal>> {\n return this.client.get(`/api/v1/deals/${encodeURIComponent(id)}`);\n }\n\n /** Update one or more fields on a deal. Set contact_id to null to unlink. */\n async update(id: string, input: UpdateDealInput): Promise<ApiResponse<DealUpdateResult>> {\n return this.client.patch(`/api/v1/deals/${encodeURIComponent(id)}`, input);\n }\n\n /** Permanently delete a deal. */\n async remove(id: string): Promise<ApiResponse<DealRemoveResult>> {\n return this.client.delete(`/api/v1/deals/${encodeURIComponent(id)}`);\n }\n}\n","import type { BaseClient } from \"../client\";\nimport type { ApiResponse } from \"../types/common\";\nimport type {\n BatchSendInput,\n BatchSendSummary,\n EmailSend,\n EmailSendResult,\n EmailTemplate,\n EmailTemplateDetail,\n GetTemplateOptions,\n SendEmailInput,\n} from \"../types/emails\";\n\n/** Manage email templates stored in the workspace. */\nclass EmailTemplates {\n constructor(private client: BaseClient) {}\n\n /** List all active email templates in the workspace. */\n async list(): Promise<ApiResponse<EmailTemplate[]>> {\n return this.client.get(\"/api/v1/emails/templates\");\n }\n\n /** Get a specific email template by slug, optionally with locale resolution. */\n async get(slug: string, options?: GetTemplateOptions): Promise<ApiResponse<EmailTemplateDetail>> {\n const params: Record<string, string | undefined> = {};\n if (options?.locale) params.locale = options.locale;\n if (options?.fallback_locale) params.fallback_locale = options.fallback_locale;\n return this.client.get(`/api/v1/emails/templates/${encodeURIComponent(slug)}`, params);\n }\n}\n\n/** Send transactional emails and manage templates. */\nexport class Emails {\n readonly templates: EmailTemplates;\n\n constructor(private client: BaseClient) {\n this.templates = new EmailTemplates(client);\n }\n\n /**\n * Send a transactional email using a template (HTTP 202). The returned `id`\n * is an email send id — poll `emails.get(id)` with it to track delivery.\n */\n async send(input: SendEmailInput): Promise<ApiResponse<EmailSendResult>> {\n return this.client.post(\"/api/v1/emails\", input);\n }\n\n /** Get the delivery status of a sent email. */\n async get(id: string): Promise<ApiResponse<EmailSend>> {\n return this.client.get(`/api/v1/emails/${encodeURIComponent(id)}`);\n }\n\n /**\n * Send the same template to multiple recipients (max 100, HTTP 202). Each\n * queued recipient gets its own send id in `results` for `emails.get(id)`.\n */\n async batch(input: BatchSendInput): Promise<ApiResponse<BatchSendSummary>> {\n return this.client.post(\"/api/v1/emails/batch\", input);\n }\n}\n","import type { BaseClient } from \"../client\";\nimport type { ApiResponse } from \"../types/common\";\nimport type {\n ConsentRecord,\n ConsentResult,\n CookieConsentInput,\n GdprExport,\n RecordConsentInput,\n} from \"../types/gdpr\";\n\n/** Manage GDPR compliance — data exports, consent records, and cookie consent. */\nexport class Gdpr {\n constructor(private client: BaseClient) {}\n\n /** Request a workspace data export. Runs asynchronously. */\n async requestExport(): Promise<ApiResponse<{ request_id: string; status: string }>> {\n return this.client.post(\"/api/v1/gdpr/export\");\n }\n\n /** List all workspace export requests. */\n async listExports(): Promise<ApiResponse<GdprExport[]>> {\n return this.client.get(\"/api/v1/gdpr/exports\");\n }\n\n /** Get the status of a specific export. */\n async getExport(id: string): Promise<ApiResponse<GdprExport>> {\n return this.client.get(`/api/v1/gdpr/exports/${encodeURIComponent(id)}`);\n }\n\n /** Record a GDPR consent decision for a contact by email. */\n async recordConsent(input: RecordConsentInput): Promise<ApiResponse<ConsentResult>> {\n return this.client.post(\"/api/v1/gdpr/consent\", input);\n }\n\n /** Get all consent records for a contact by email. */\n async getConsent(email: string): Promise<ApiResponse<ConsentRecord[]>> {\n return this.client.get(`/api/v1/gdpr/consent/${encodeURIComponent(email)}`);\n }\n\n /** Record cookie consent from an external site (legacy endpoint). */\n async cookieConsent(input: CookieConsentInput): Promise<{ success: boolean; logId?: string }> {\n return this.client.post(\"/api/cookie-consent\", input);\n }\n}\n","import { CapabilityConfirmer } from \"../capability-confirmer\";\nimport type { BaseClient, RequestOptions } from \"../client\";\nimport type { ApiResponse, PaginatedResponse, PaginationOptions } from \"../types/common\";\nimport type {\n Conversation,\n ConversationMessage,\n ConversationUpdateResult,\n CreateReplyInput,\n ListConversationsOptions,\n ReplyCreateResult,\n UpdateConversationInput,\n} from \"../types/helpdesk\";\nimport { CapabilityConfirmations } from \"./capability-confirmations\";\n\n/** Browse and manage helpdesk conversations. */\nclass HelpdeskConversations {\n constructor(\n private client: BaseClient,\n private confirmer: CapabilityConfirmer,\n ) {}\n\n /** List/search conversations with cursor-based pagination and optional filters. */\n async list(options?: ListConversationsOptions): Promise<PaginatedResponse<Conversation>> {\n const params: Record<string, string | undefined> = {};\n if (options?.limit !== undefined) params.limit = String(options.limit);\n if (options?.cursor) params.cursor = options.cursor;\n if (options?.status) params.status = options.status;\n if (options?.assignee_user_id) params.assignee_user_id = options.assignee_user_id;\n if (options?.requester) params.requester = options.requester;\n if (options?.query) params.query = options.query;\n if (options?.channels) params.channels = options.channels.join(\",\");\n return this.client.get(\"/api/v1/helpdesk/conversations\", params);\n }\n\n /** Get a conversation by ID. */\n async get(id: string): Promise<ApiResponse<Conversation>> {\n return this.client.get(`/api/v1/helpdesk/conversations/${encodeURIComponent(id)}`);\n }\n\n /** Update a conversation's status and/or assignee (pass `assignee_user_id: null` to unassign). */\n async update(\n id: string,\n input: UpdateConversationInput,\n options?: RequestOptions,\n ): Promise<ApiResponse<ConversationUpdateResult>> {\n const resolved = await this.confirmer.prepare(\n { capabilityId: \"helpdesk.conversation.update.execute\", body: input },\n { id },\n options,\n );\n return this.client.patch(\n `/api/v1/helpdesk/conversations/${encodeURIComponent(id)}`,\n input,\n resolved,\n );\n }\n\n /** Read a conversation's messages with cursor-based pagination. */\n async messages(\n id: string,\n options?: PaginationOptions,\n ): Promise<PaginatedResponse<ConversationMessage>> {\n const params: Record<string, string | undefined> = {};\n if (options?.limit !== undefined) params.limit = String(options.limit);\n if (options?.cursor) params.cursor = options.cursor;\n return this.client.get(\n `/api/v1/helpdesk/conversations/${encodeURIComponent(id)}/messages`,\n params,\n );\n }\n}\n\n/** Send operator replies (or internal notes) into conversations. */\nclass HelpdeskReplies {\n constructor(\n private client: BaseClient,\n private confirmer: CapabilityConfirmer,\n ) {}\n\n /**\n * Send an operator reply or internal note. Returns HTTP 201.\n *\n * Pass an `idempotencyKey` so retried requests do not create duplicate\n * messages — it is REQUIRED for capability-scoped tokens.\n */\n async create(\n input: CreateReplyInput,\n options?: RequestOptions,\n ): Promise<ApiResponse<ReplyCreateResult>> {\n const resolved = await this.confirmer.prepare(\n { capabilityId: \"helpdesk.conversation.reply.execute\", body: input },\n undefined,\n options,\n );\n return this.client.post(\"/api/v1/helpdesk/replies\", input, resolved);\n }\n}\n\n/** Helpdesk bridge — read conversations, reply, and manage assignment/status. */\nexport class Helpdesk {\n readonly conversations: HelpdeskConversations;\n readonly replies: HelpdeskReplies;\n\n constructor(client: BaseClient, confirmer?: CapabilityConfirmer) {\n // Direct consumers (`new Helpdesk(client)`) get a confirmer with no\n // client-level default: auto-confirm stays off unless a call opts in via\n // `{ autoConfirm: { previewSummary } }`.\n const resolved = confirmer ?? new CapabilityConfirmer(new CapabilityConfirmations(client));\n this.conversations = new HelpdeskConversations(client, resolved);\n this.replies = new HelpdeskReplies(client, resolved);\n }\n}\n","import type { BaseClient } from \"../client\";\nimport type { ApiResponse, PaginatedResponse } from \"../types/common\";\nimport type {\n Channel,\n CreatePostInput,\n ListPostsOptions,\n Post,\n PostDetail,\n PublishResult,\n SchedulePostInput,\n ScheduleResult,\n UpdatePostInput,\n} from \"../types/posts\";\n\n/** Create and publish posts across connected channels. */\nexport class Posts {\n constructor(private client: BaseClient) {}\n\n /** List posts with cursor-based pagination and optional filters. */\n async list(options?: ListPostsOptions): Promise<PaginatedResponse<Post>> {\n const params: Record<string, string | undefined> = {};\n if (options?.limit !== undefined) params.limit = String(options.limit);\n if (options?.cursor) params.cursor = options.cursor;\n if (options?.status) params.status = options.status;\n if (options?.type) params.type = options.type;\n return this.client.get(\"/api/v1/posts\", params);\n }\n\n /** Create a new post with content and target channels. */\n async create(input: CreatePostInput): Promise<ApiResponse<{ id: string }>> {\n return this.client.post(\"/api/v1/posts\", input);\n }\n\n /** Get a post by ID, including its per-channel variants. */\n async get(id: string): Promise<ApiResponse<PostDetail>> {\n return this.client.get(`/api/v1/posts/${encodeURIComponent(id)}`);\n }\n\n /** Update a draft post's title or content. */\n async update(id: string, input: UpdatePostInput): Promise<ApiResponse<{ success: boolean }>> {\n return this.client.patch(`/api/v1/posts/${encodeURIComponent(id)}`, input);\n }\n\n /** Delete a post. */\n async remove(id: string): Promise<ApiResponse<{ success: boolean }>> {\n return this.client.delete(`/api/v1/posts/${encodeURIComponent(id)}`);\n }\n\n /** Schedule a post for future publication. */\n async schedule(id: string, input: SchedulePostInput): Promise<ApiResponse<ScheduleResult>> {\n return this.client.post(`/api/v1/posts/${encodeURIComponent(id)}/schedule`, input);\n }\n\n /** Publish a post immediately to all target channels. */\n async publish(id: string): Promise<ApiResponse<PublishResult>> {\n return this.client.post(`/api/v1/posts/${encodeURIComponent(id)}/publish`);\n }\n\n /** List connected publishing channels for this workspace. */\n async channels(): Promise<ApiResponse<Channel[]>> {\n return this.client.get(\"/api/v1/posts/channels\");\n }\n}\n","import type { BaseClient } from \"../client\";\nimport type { ApiResponse } from \"../types/common\";\nimport type {\n ScanCompany,\n ScanCreateInput,\n ScanCreateResult,\n ScanJob,\n WaitForScanOptions,\n} from \"../types/scan\";\n\nconst sleep = (ms: number) => new Promise<void>((resolve) => setTimeout(resolve, ms));\n\n/**\n * Company & website scans (Nettsjekk) — score a Norwegian company's web\n * presence (performance, SEO, GDPR consent, AI visibility, mail auth) from a\n * URL, an organisation number, or a company name.\n */\nexport class Scan {\n constructor(private client: BaseClient) {}\n\n /**\n * Queue a scan. Provide exactly one of `url`, `orgnr`, or `name`.\n * Runs asynchronously — poll with `get()` or use `waitForResult()`.\n *\n * @throws Error before any request when zero or several selectors are set —\n * the server would reject the body anyway; failing locally is clearer.\n */\n async create(input: ScanCreateInput): Promise<ApiResponse<ScanCreateResult>> {\n const entries = ([\"url\", \"orgnr\", \"name\"] as const).filter(\n (key) => input[key] !== undefined && input[key] !== \"\",\n );\n if (entries.length !== 1) {\n throw new Error(\"scan.create requires exactly one of url, orgnr, or name\");\n }\n // Send only the effective selector — blank strings from form state must\n // not ride along in the payload (they would echo back in ScanJob.input).\n const key = entries[0];\n return this.client.post(\"/api/v1/scan\", { [key]: input[key] });\n }\n\n /** Get a scan job's status and, once done, its findings payload. */\n async get(id: string): Promise<ApiResponse<ScanJob>> {\n return this.client.get(`/api/v1/scan/${encodeURIComponent(id)}`);\n }\n\n /** Search the Norwegian company registry by name (typeahead, top 5 hits). */\n async companies(q: string): Promise<ApiResponse<ScanCompany[]>> {\n return this.client.get(\"/api/v1/scan/companies\", { q });\n }\n\n /**\n * Poll a scan until it settles. Resolves with the job for both `done` and\n * `failed` (check `job.error`); throws only when the deadline passes while\n * the scan is still pending/running.\n */\n async waitForResult(id: string, options: WaitForScanOptions = {}): Promise<ScanJob> {\n const rawInterval = options.intervalMs ?? 2500;\n const rawTimeout = options.timeoutMs ?? 120_000;\n // Guard against NaN — it would disable the deadline and poll forever.\n // An explicit zero/negative timeout is preserved: one poll, then timeout\n // (callers passing an exhausted outer budget expect immediate expiry).\n const intervalMs = Number.isFinite(rawInterval) && rawInterval > 0 ? rawInterval : 2500;\n const timeoutMs = Number.isFinite(rawTimeout) ? rawTimeout : 120_000;\n const deadline = Date.now() + timeoutMs;\n let lastStatus = \"pending\";\n for (;;) {\n const { data } = await this.get(id);\n if (data.status === \"done\" || data.status === \"failed\") return data;\n lastStatus = data.status;\n // Sleep only up to the remaining budget, and re-check the deadline\n // after sleeping so no extra poll is issued once time is up.\n const remaining = deadline - Date.now();\n if (remaining <= 0) break;\n await sleep(Math.min(intervalMs, remaining));\n if (Date.now() >= deadline) break;\n }\n throw new Error(`Scan ${id} timed out after ${timeoutMs}ms (status: ${lastStatus})`);\n }\n}\n","import { CapabilityConfirmer } from \"../capability-confirmer\";\nimport type { BaseClient, RequestOptions } from \"../client\";\nimport type { ApiResponse } from \"../types/common\";\nimport type {\n CreateWebhookInput,\n ListDeliveriesOptions,\n UpdateWebhookInput,\n WebhookDeleteResult,\n WebhookDelivery,\n WebhookEndpoint,\n WebhookTestResult,\n} from \"../types/webhooks\";\nimport { CapabilityConfirmations } from \"./capability-confirmations\";\n\n/** Manage webhook endpoints and inspect their deliveries. */\nexport class Webhooks {\n private confirmer: CapabilityConfirmer;\n\n constructor(\n private client: BaseClient,\n confirmer?: CapabilityConfirmer,\n ) {\n // Direct consumers (`new Webhooks(client)`) get a confirmer with no\n // client-level default: auto-confirm stays off unless a call opts in via\n // `{ autoConfirm: { previewSummary } }`.\n this.confirmer = confirmer ?? new CapabilityConfirmer(new CapabilityConfirmations(client));\n }\n\n /** List all webhook endpoints in the workspace. */\n async list(): Promise<ApiResponse<WebhookEndpoint[]>> {\n return this.client.get(\"/api/v1/webhooks\");\n }\n\n /**\n * Create a webhook endpoint. Returns HTTP 201.\n *\n * **The response's `data.secret` contains the signing secret EXACTLY ONCE.**\n * It can never be retrieved again — store it securely immediately. You need\n * it to verify the `X-Medal-Signature` header on incoming deliveries (see\n * `verifyWebhookSignature`).\n *\n * `secret` is typed optional because an idempotent replay (retrying with the\n * same `Idempotency-Key`, `X-Idempotent-Replayed: true`) returns the existing\n * endpoint WITHOUT the secret — handle that case (rotate if you lost it).\n */\n async create(\n input: CreateWebhookInput,\n options?: RequestOptions,\n ): Promise<ApiResponse<WebhookEndpoint>> {\n const resolved = await this.confirmer.prepare(\n { capabilityId: \"helpdesk.webhook.create.execute\", body: input },\n undefined,\n options,\n );\n return this.client.post(\"/api/v1/webhooks\", input, resolved);\n }\n\n /** Get a webhook endpoint by ID. */\n async get(id: string): Promise<ApiResponse<WebhookEndpoint>> {\n return this.client.get(`/api/v1/webhooks/${encodeURIComponent(id)}`);\n }\n\n /** Update a webhook endpoint (name, url, event types, filters, enabled). */\n async update(\n id: string,\n input: UpdateWebhookInput,\n options?: RequestOptions,\n ): Promise<ApiResponse<WebhookEndpoint>> {\n const resolved = await this.confirmer.prepare(\n { capabilityId: \"helpdesk.webhook.update.execute\", body: input },\n { id },\n options,\n );\n return this.client.patch(`/api/v1/webhooks/${encodeURIComponent(id)}`, input, resolved);\n }\n\n /**\n * Permanently delete a webhook endpoint (stops all outbound deliveries).\n * Capability-scoped tokens must pass `idempotencyKey` — the API requires\n * `Idempotency-Key` + `X-Capability-Confirmation` for direct capability\n * grants on this route. API keys with legacy scopes may omit it.\n */\n async delete(id: string, options?: RequestOptions): Promise<ApiResponse<WebhookDeleteResult>> {\n const resolved = await this.confirmer.prepare(\n { capabilityId: \"helpdesk.webhook.delete.execute\", body: undefined },\n { id },\n options,\n );\n return this.client.delete(`/api/v1/webhooks/${encodeURIComponent(id)}`, resolved);\n }\n\n /** List recent deliveries for an endpoint (most recent first). */\n async deliveries(\n id: string,\n options?: ListDeliveriesOptions,\n ): Promise<ApiResponse<WebhookDelivery[]>> {\n const params: Record<string, string | undefined> = {};\n if (options?.limit !== undefined) params.limit = String(options.limit);\n return this.client.get(`/api/v1/webhooks/${encodeURIComponent(id)}/deliveries`, params);\n }\n\n /** Queue a signed `test.ping` delivery to the endpoint. Returns HTTP 202. */\n async test(id: string): Promise<ApiResponse<WebhookTestResult>> {\n return this.client.post(`/api/v1/webhooks/${encodeURIComponent(id)}/test`);\n }\n}\n","import type { BaseClient } from \"../client\";\nimport type { ApiResponse } from \"../types/common\";\nimport type { Workspace } from \"../types/workspaces\";\n\n/** Access workspaces for the authenticated credential. */\nexport class Workspaces {\n constructor(private client: BaseClient) {}\n\n /** List workspaces accessible to the current API key or OAuth token. */\n async list(): Promise<ApiResponse<Workspace[]>> {\n return this.client.get(\"/api/v1/me/workspaces\");\n }\n}\n","/**\n * Webhook event types and signature verification for the Medal Social\n * outbound webhook bridge.\n *\n * Every delivery is an HTTP POST with headers:\n * - `X-Medal-Timestamp` — Unix milliseconds when the request was signed\n * - `X-Medal-Signature` — `sha256=<base64(HMAC-SHA256(\"{timestamp}.{rawBody}\", secret))>`\n * - `X-Medal-Event` — the event type\n * - `X-Medal-Delivery-Id` / `Idempotency-Key` — unique delivery ID (deduplicate on this)\n *\n * Use {@link verifyWebhookSignature} to authenticate a delivery and get the\n * parsed, typed event back. Uses Web Crypto (`crypto.subtle`) so it works in\n * Node.js 18+, Deno, Bun, Cloudflare Workers, and browsers.\n */\n\n/** Snapshot of a conversation included in every helpdesk webhook event. */\nexport interface WebhookConversationSnapshot {\n id: string;\n channel: string;\n channelConnectionId: string | null;\n status: string;\n subject: string | null;\n assigneeUserId: string | null;\n contactId: string | null;\n visitorName: string | null;\n visitorEmail: string | null;\n externalConversationId: string | null;\n channelAccountId: string | null;\n messageCount: number;\n /** Unix timestamp in milliseconds. */\n lastMessageAt: number;\n /** Unix timestamp in milliseconds. */\n createdAt: number;\n}\n\n/** Snapshot of a message included in helpdesk message events. */\nexport interface WebhookMessageSnapshot {\n id: string;\n authorType: \"visitor\" | \"operator\" | \"ai\" | \"system\";\n messageType: \"chat\" | \"email\" | \"note\";\n body: string;\n authorUserId: string | null;\n authorName: string | null;\n externalMessageId: string | null;\n deliveryStatus: string | null;\n deliveryError: string | null;\n /** Unix timestamp in milliseconds. */\n createdAt: number;\n}\n\n/** Fields present in the `data` of every helpdesk event. */\ninterface HelpdeskEventData {\n /** Channel type at the top level, for quick filtering. */\n channel: string;\n channelConnectionId: string | null;\n conversation: WebhookConversationSnapshot;\n}\n\n/** Envelope fields shared by all webhook events. */\ninterface WebhookEventBase {\n /** Unique delivery/event ID — use for deduplication. */\n id: string;\n /** Unix timestamp in milliseconds when the event was created. */\n created_at: number;\n workspace_id: string;\n}\n\n/** A new conversation was created. */\nexport interface ConversationCreatedEvent extends WebhookEventBase {\n type: \"helpdesk.conversation_created\";\n data: HelpdeskEventData;\n}\n\n/** A conversation was assigned or unassigned. */\nexport interface ConversationAssignedEvent extends WebhookEventBase {\n type: \"helpdesk.conversation_assigned\";\n data: HelpdeskEventData & {\n assigneeUserId: string | null;\n previousAssigneeUserId: string | null;\n };\n}\n\n/** A conversation's status changed (open / snoozed / closed). */\nexport interface ConversationStatusChangedEvent extends WebhookEventBase {\n type: \"helpdesk.conversation_status_changed\";\n data: HelpdeskEventData & {\n status: string;\n previousStatus: string;\n };\n}\n\n/** A message arrived from the visitor/customer. */\nexport interface MessageReceivedEvent extends WebhookEventBase {\n type: \"helpdesk.message_received\";\n data: HelpdeskEventData & { message: WebhookMessageSnapshot };\n}\n\n/** A message was sent by an operator, AI, or the system. */\nexport interface MessageSentEvent extends WebhookEventBase {\n type: \"helpdesk.message_sent\";\n data: HelpdeskEventData & { message: WebhookMessageSnapshot };\n}\n\n/** The delivery status of an outbound message changed (sent / delivered / failed …). */\nexport interface MessageDeliveryUpdatedEvent extends WebhookEventBase {\n type: \"helpdesk.message_delivery_updated\";\n data: HelpdeskEventData & { message: WebhookMessageSnapshot };\n}\n\n/**\n * Fields present in the `data` of channel lifecycle events. Unlike message\n * events there is no conversation snapshot — the payload is channel-generic.\n * `channel` / `channelConnectionId` sit at the top level so endpoint channel\n * filters match exactly like message events.\n */\nexport interface WebhookChannelLifecycleData {\n /** Helpdesk channel type (e.g. `telegram`), or `null` for non-helpdesk channels. */\n channel: string | null;\n channelConnectionId: string | null;\n /** Connector channel type (e.g. `telegram_inbox`). */\n channel_type: string;\n /** Adapter-defined stable connection ref (matches `consumed_connection_ref` on the connect link). */\n connection_ref: string;\n label: string | null;\n masked_identity: string | null;\n}\n\n/** A channel account was connected to the workspace (e.g. via a partner connect link). */\nexport interface ChannelConnectedEvent extends WebhookEventBase {\n type: \"helpdesk.channel_connected\";\n data: WebhookChannelLifecycleData;\n}\n\n/** Why a channel account was disconnected. */\nexport type ChannelDisconnectReason = \"api_disconnect\" | \"user_revoked\" | \"member_disconnect\";\n\n/** A previously connected channel account was removed from the workspace. */\nexport interface ChannelDisconnectedEvent extends WebhookEventBase {\n type: \"helpdesk.channel_disconnected\";\n data: WebhookChannelLifecycleData & {\n /** Why the account went away. */\n reason?: ChannelDisconnectReason;\n };\n}\n\n/** A `test.ping` delivery queued via `medal.webhooks.test(id)`. Carries sample data. */\nexport interface TestPingEvent extends WebhookEventBase {\n type: \"test.ping\";\n data: Record<string, unknown>;\n}\n\n/**\n * Discriminated union of all webhook events, keyed on `type`.\n *\n * @example\n * ```ts\n * switch (event.type) {\n * case 'helpdesk.message_received':\n * console.log(event.data.message.body);\n * break;\n * case 'helpdesk.conversation_status_changed':\n * console.log(event.data.previousStatus, '→', event.data.status);\n * break;\n * }\n * ```\n */\nexport type WebhookEvent =\n | ConversationCreatedEvent\n | ConversationAssignedEvent\n | ConversationStatusChangedEvent\n | MessageReceivedEvent\n | MessageSentEvent\n | MessageDeliveryUpdatedEvent\n | ChannelConnectedEvent\n | ChannelDisconnectedEvent\n | TestPingEvent;\n\n/** Machine-readable reason a webhook verification failed. */\nexport type WebhookVerificationErrorCode =\n | \"malformed_header\"\n | \"timestamp_out_of_tolerance\"\n | \"invalid_signature\"\n | \"invalid_payload\";\n\n/** Thrown by {@link verifyWebhookSignature} when a delivery cannot be authenticated. */\nexport class WebhookVerificationError extends Error {\n readonly code: WebhookVerificationErrorCode;\n\n constructor(code: WebhookVerificationErrorCode, message: string) {\n super(message);\n this.name = \"WebhookVerificationError\";\n this.code = code;\n }\n}\n\n/** Input for {@link verifyWebhookSignature}. */\nexport interface VerifyWebhookSignatureInput {\n /** The RAW request body string, exactly as received (do not re-serialize parsed JSON). */\n payload: string;\n /** Value of the `X-Medal-Timestamp` header (Unix milliseconds). */\n timestamp: string;\n /** Value of the `X-Medal-Signature` header (`sha256=<base64>`). */\n signature: string;\n /** The endpoint signing secret (`whsec_…`) returned once at creation time. */\n secret: string;\n /** Max allowed clock skew between now and the signed timestamp. Default 5 minutes. */\n toleranceMs?: number;\n}\n\n/** Default allowed clock skew for webhook verification (5 minutes). */\nexport const DEFAULT_WEBHOOK_TOLERANCE_MS = 5 * 60 * 1000;\n\nfunction base64ToBytes(base64: string): Uint8Array<ArrayBuffer> {\n const binary = atob(base64);\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n bytes[i] = binary.charCodeAt(i);\n }\n return bytes;\n}\n\n/**\n * Verify a webhook delivery's signature and timestamp, then return the parsed\n * typed event.\n *\n * Recomputes `HMAC-SHA256(\"{timestamp}.{payload}\", secret)` with Web Crypto\n * and compares it against the signature in constant time. Deliveries whose\n * timestamp deviates from the current time by more than `toleranceMs`\n * (default 5 minutes) are rejected to prevent replay attacks.\n *\n * @throws {WebhookVerificationError} if the headers are malformed, the\n * timestamp is outside the tolerance window, the signature does not match,\n * or the payload is not valid JSON.\n *\n * @example\n * ```ts\n * const event = await verifyWebhookSignature({\n * payload: rawBody,\n * timestamp: req.headers['x-medal-timestamp'],\n * signature: req.headers['x-medal-signature'],\n * secret: process.env.MEDAL_WEBHOOK_SECRET,\n * });\n * ```\n */\nexport async function verifyWebhookSignature(\n input: VerifyWebhookSignatureInput,\n): Promise<WebhookEvent> {\n const { payload, timestamp, signature, secret } = input;\n const toleranceMs = input.toleranceMs ?? DEFAULT_WEBHOOK_TOLERANCE_MS;\n\n if (typeof signature !== \"string\" || !signature.startsWith(\"sha256=\")) {\n throw new WebhookVerificationError(\n \"malformed_header\",\n \"Signature header must be in the form 'sha256=<base64>'\",\n );\n }\n\n const timestampMs = Number(timestamp);\n if (typeof timestamp !== \"string\" || timestamp === \"\" || !Number.isFinite(timestampMs)) {\n throw new WebhookVerificationError(\n \"malformed_header\",\n \"Timestamp header must be a Unix-milliseconds number string\",\n );\n }\n if (Math.abs(Date.now() - timestampMs) > toleranceMs) {\n throw new WebhookVerificationError(\n \"timestamp_out_of_tolerance\",\n `Timestamp is outside the allowed tolerance of ${toleranceMs}ms`,\n );\n }\n\n let signatureBytes: Uint8Array<ArrayBuffer>;\n try {\n signatureBytes = base64ToBytes(signature.slice(\"sha256=\".length));\n } catch {\n throw new WebhookVerificationError(\"invalid_signature\", \"Signature is not valid base64\");\n }\n\n const encoder = new TextEncoder();\n const key = await crypto.subtle.importKey(\n \"raw\",\n encoder.encode(secret),\n { name: \"HMAC\", hash: \"SHA-256\" },\n false,\n [\"verify\"],\n );\n // crypto.subtle.verify performs a constant-time comparison internally.\n const valid = await crypto.subtle.verify(\n \"HMAC\",\n key,\n signatureBytes,\n encoder.encode(`${timestamp}.${payload}`),\n );\n if (!valid) {\n throw new WebhookVerificationError(\"invalid_signature\", \"Signature does not match the payload\");\n }\n\n try {\n return JSON.parse(payload) as WebhookEvent;\n } catch {\n throw new WebhookVerificationError(\"invalid_payload\", \"Payload is not valid JSON\");\n }\n}\n","/**\n * Official TypeScript SDK for the Medal Social API.\n *\n * Provides typed access to posts, emails, contacts, deals, GDPR compliance,\n * helpdesk conversations, partner channel connect, webhooks, and workspace\n * management. Works in\n * Node.js, Deno, Bun, Cloudflare Workers, and modern browsers.\n *\n * @example\n * ```ts\n * import { Medal } from \"@medalsocial/sdk\";\n *\n * const medal = new Medal(\"medal_xxx\");\n * const { data: post } = await medal.posts.create({\n * content: \"Hello world!\",\n * channel_ids: [\"ch_1\"],\n * });\n * ```\n *\n * @module\n */\nimport { CapabilityConfirmer } from \"./capability-confirmer\";\nimport { BaseClient } from \"./client\";\nimport { CapabilityConfirmations } from \"./resources/capability-confirmations\";\nimport { Channels } from \"./resources/channels\";\nimport { Contacts } from \"./resources/contacts\";\nimport { Deals } from \"./resources/deals\";\nimport { Emails } from \"./resources/emails\";\nimport { Gdpr } from \"./resources/gdpr\";\nimport { Helpdesk } from \"./resources/helpdesk\";\nimport { Posts } from \"./resources/posts\";\nimport { Scan } from \"./resources/scan\";\nimport { Webhooks } from \"./resources/webhooks\";\nimport { Workspaces } from \"./resources/workspaces\";\nimport type { AutoConfirmOptions } from \"./types/capabilities\";\n\n/** Options for configuring the {@link Medal} client. */\nexport interface MedalOptions {\n /** Override the base URL (defaults to https://io.medalsocial.com). */\n baseUrl?: string;\n /** Request timeout in ms (default 30000). */\n timeout?: number;\n /**\n * Workspace ID — required for OAuth access tokens, ignored for API keys.\n * API keys are scoped to a single workspace, so the workspace is inferred.\n * OAuth tokens can access multiple workspaces, so you must specify which one.\n */\n workspaceId?: string;\n /**\n * Opt in to automatic capability confirmation for confirmable writes.\n * **Defaults to OFF.**\n *\n * Medal's confirmable write routes (connect links, channel connections,\n * helpdesk replies/updates, webhook endpoint writes) require BOTH an\n * `Idempotency-Key` and an `X-Capability-Confirmation` token whenever the\n * credential holds the capability scope directly — which is the case for\n * every correctly-scoped partner key. With this option set, the SDK mints\n * both for you before each such write instead of making you hand-roll\n * `POST /api/v1/capability-confirmations`.\n *\n * **Read before enabling:** each minted token carries `user_approved: true`,\n * which asserts to Medal that *a human on your side approved that specific\n * action*, and the `previewSummary` you return is retained as the audit\n * record of what they approved. Enable it only on code paths where that is\n * genuinely true — never to rubber-stamp unattended writes. Pass\n * `{ autoConfirm: false }` on an individual call to opt out again, or use\n * `medal.capabilityConfirmations.create(...)` for full manual control.\n *\n * @example\n * ```ts\n * const medal = new Medal('medal_xxx', {\n * autoConfirmCapabilities: {\n * previewSummary: (ctx) =>\n * `${operator.email} approved ${ctx.method} ${ctx.path}`,\n * },\n * });\n * ```\n */\n autoConfirmCapabilities?: AutoConfirmOptions;\n}\n\n/**\n * Medal Social SDK client.\n *\n * Supports both API key and OAuth access token authentication:\n *\n * @example API Key (recommended for server-side)\n * ```ts\n * import { Medal } from '@medalsocial/sdk';\n *\n * // API keys start with medal_ and are scoped to one workspace\n * const medal = new Medal('medal_xxx');\n * ```\n *\n * @example OAuth Access Token\n * ```ts\n * // OAuth tokens require a workspaceId\n * const medal = new Medal('oauth_access_token', {\n * workspaceId: 'workspace_id_here',\n * });\n * ```\n *\n * @example Full usage\n * ```ts\n * const medal = new Medal('medal_xxx');\n *\n * // Posts — create, schedule, publish\n * const { data: post } = await medal.posts.create({\n * content: 'Hello world!',\n * channel_ids: ['ch_1'],\n * });\n * await medal.posts.schedule(post.id, { scheduled_at: '2026-03-15T10:00:00Z' });\n *\n * // Emails — send transactional emails\n * await medal.emails.send({\n * template_slug: 'welcome',\n * to: 'user@example.com',\n * variables: { name: 'John' },\n * });\n *\n * // Contacts, Deals, GDPR, Workspaces\n * const contacts = await medal.contacts.list({ status: 'lead' });\n * const { data: deal } = await medal.deals.create({ title: 'Acme', value: 50000 });\n * await medal.gdpr.recordConsent({ email: 'u@x.com', consent_type: 'marketing_email', granted: true });\n * const { data: workspaces } = await medal.workspaces.list();\n * ```\n */\nexport class Medal {\n readonly capabilityConfirmations: CapabilityConfirmations;\n readonly channels: Channels;\n readonly emails: Emails;\n readonly contacts: Contacts;\n readonly deals: Deals;\n readonly gdpr: Gdpr;\n readonly helpdesk: Helpdesk;\n readonly posts: Posts;\n readonly scan: Scan;\n readonly webhooks: Webhooks;\n readonly workspaces: Workspaces;\n\n constructor(token: string, options?: MedalOptions) {\n if (!token) {\n throw new Error(\n \"Authentication token is required. Pass your medal_xxx API key or OAuth access token as the first argument.\",\n );\n }\n\n const client = new BaseClient({\n baseUrl: (options?.baseUrl ?? \"https://io.medalsocial.com\").replace(/\\/$/, \"\"),\n token,\n workspaceId: options?.workspaceId,\n timeout: options?.timeout ?? 30000,\n userAgent: \"medalsocial-sdk/1.0.0 (+https://github.com/Medal-Social/MedalSocial)\",\n });\n\n this.capabilityConfirmations = new CapabilityConfirmations(client);\n const confirmer = new CapabilityConfirmer(\n this.capabilityConfirmations,\n options?.autoConfirmCapabilities,\n );\n\n this.channels = new Channels(client, confirmer);\n this.emails = new Emails(client);\n this.contacts = new Contacts(client);\n this.deals = new Deals(client);\n this.gdpr = new Gdpr(client);\n this.helpdesk = new Helpdesk(client, confirmer);\n this.posts = new Posts(client);\n this.scan = new Scan(client);\n this.webhooks = new Webhooks(client, confirmer);\n this.workspaces = new Workspaces(client);\n }\n}\n\nexport { CapabilityConfirmer } from \"./capability-confirmer\";\nexport type { RequestOptions } from \"./client\";\nexport { BaseClient } from \"./client\";\nexport type {\n components as OpenApiComponents,\n operations as OpenApiOperations,\n paths as OpenApiPaths,\n} from \"./openapi.generated\";\n// Resource class re-exports (for advanced usage)\nexport { CapabilityConfirmations } from \"./resources/capability-confirmations\";\nexport { Channels } from \"./resources/channels\";\nexport { Contacts } from \"./resources/contacts\";\nexport { Deals } from \"./resources/deals\";\nexport { Emails } from \"./resources/emails\";\nexport { Gdpr } from \"./resources/gdpr\";\nexport { Helpdesk } from \"./resources/helpdesk\";\nexport { Posts } from \"./resources/posts\";\nexport { Scan } from \"./resources/scan\";\nexport { Webhooks } from \"./resources/webhooks\";\nexport { Workspaces } from \"./resources/workspaces\";\nexport type {\n AutoConfirmContext,\n AutoConfirmOptions,\n CapabilityConfirmation,\n CapabilityId,\n CapabilityPathParamValue,\n CapabilityRoute,\n CapabilityWriteBodies,\n CapabilityWriteRequest,\n IssueCapabilityConfirmationInput,\n} from \"./types/capabilities\";\nexport { CAPABILITY_IDS, CAPABILITY_ROUTES } from \"./types/capabilities\";\nexport type {\n ChannelConnection,\n ChannelConnectionDisconnectResult,\n ChannelConnectionState,\n ConnectLink,\n ConnectLinkCreateResult,\n ConnectLinkRevokeResult,\n ConnectLinkStatus,\n CreateConnectLinkInput,\n ListConnectLinksOptions,\n} from \"./types/channels\";\nexport type { ApiResponse, PaginatedResponse, PaginationOptions } from \"./types/common\";\n// Re-export all types\nexport { MedalApiError } from \"./types/common\";\nexport type {\n Activity,\n AddNoteInput,\n Contact,\n ContactCreateResult,\n ContactNoteResult,\n ContactRemoveResult,\n ContactStatus,\n ContactUpdateResult,\n CreateContactInput,\n EmailStatus,\n ImportContactInput,\n ImportContactsResult,\n ListContactsOptions,\n UpdateContactInput,\n} from \"./types/contacts\";\nexport type {\n CreateDealInput,\n Deal,\n DealCreateResult,\n DealRemoveResult,\n DealStatus,\n DealUpdateResult,\n ListDealsOptions,\n UpdateDealInput,\n} from \"./types/deals\";\nexport type {\n BatchSendInput,\n BatchSendResult,\n BatchSendSummary,\n EmailSend,\n EmailSendResult,\n EmailTemplate,\n EmailTemplateDetail,\n GetTemplateOptions,\n SendEmailInput,\n} from \"./types/emails\";\nexport type {\n ConsentRecord,\n ConsentResult,\n ConsentType,\n ContactConsents,\n CookieCategoryConsent,\n CookieConsentInput,\n GdprExport,\n RecordConsentInput,\n} from \"./types/gdpr\";\nexport type {\n Conversation,\n ConversationMessage,\n ConversationStatus,\n ConversationUpdateResult,\n CreateReplyInput,\n HelpdeskMessageType,\n ListConversationsOptions,\n MessageAuthorType,\n MessageDeliveryStatus,\n ReplyCreateResult,\n UpdateConversationInput,\n} from \"./types/helpdesk\";\nexport type {\n Channel,\n CreatePostInput,\n ListPostsOptions,\n Post,\n PostDetail,\n PostType,\n PostVariant,\n PublishResult,\n SchedulePostInput,\n ScheduleResult,\n UpdatePostInput,\n} from \"./types/posts\";\nexport type {\n ScanCompany,\n ScanCreateInput,\n ScanCreateResult,\n ScanJob,\n ScanResultPayload,\n ScanStatus,\n ScanSubScores,\n WaitForScanOptions,\n} from \"./types/scan\";\nexport type {\n CreateWebhookInput,\n ListDeliveriesOptions,\n UpdateWebhookInput,\n WebhookDeleteResult,\n WebhookDelivery,\n WebhookEndpoint,\n WebhookTestResult,\n} from \"./types/webhooks\";\nexport type { Workspace } from \"./types/workspaces\";\nexport type {\n ChannelConnectedEvent,\n ChannelDisconnectedEvent,\n ChannelDisconnectReason,\n ConversationAssignedEvent,\n ConversationCreatedEvent,\n ConversationStatusChangedEvent,\n MessageDeliveryUpdatedEvent,\n MessageReceivedEvent,\n MessageSentEvent,\n TestPingEvent,\n VerifyWebhookSignatureInput,\n WebhookChannelLifecycleData,\n WebhookConversationSnapshot,\n WebhookEvent,\n WebhookMessageSnapshot,\n WebhookVerificationErrorCode,\n} from \"./webhook-events\";\n// Webhook event verification + typed events\nexport {\n DEFAULT_WEBHOOK_TOLERANCE_MS,\n verifyWebhookSignature,\n WebhookVerificationError,\n} from \"./webhook-events\";\n\n/** Convenience factory — equivalent to `new Medal(apiKey, options)`. */\nexport function createMedalClient(apiKey: string, options?: MedalOptions): Medal {\n return new Medal(apiKey, options);\n}\n\nexport default Medal;\n"],"mappings":"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","names":["key"]}
|