@medalsocial/sdk 1.3.0 → 1.4.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/dist/openapi/medal-social.openapi.json +114 -40
- package/dist/pilot/index.d.mts +64 -324
- package/dist/pilot/index.d.ts +64 -324
- package/dist/pilot/index.js +5 -5
- package/dist/pilot/index.js.map +1 -1
- package/dist/pilot/index.mjs +5 -5
- package/dist/pilot/index.mjs.map +1 -1
- package/dist/src/index.d.mts +31 -3
- package/dist/src/index.d.ts +31 -3
- package/dist/src/index.js +8 -2
- package/dist/src/index.js.map +1 -1
- package/dist/src/index.mjs +8 -2
- package/dist/src/index.mjs.map +1 -1
- package/dist/src/openapi.generated.d.mts +22 -1
- package/dist/src/openapi.generated.d.ts +22 -1
- package/dist/src/openapi.generated.js.map +1 -1
- package/openapi/medal-social.openapi.yaml +38 -3
- package/package.json +14 -14
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 /** Send a transactional email using a template. Returns a queued job ID (HTTP 202). */\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 /** Send the same template to multiple recipients (max 100). Returns HTTP 202. */\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\n// Re-export all types\nexport { MedalApiError } from \"./types/common\";\nexport type { ApiResponse, PaginatedResponse, PaginationOptions } from \"./types/common\";\nexport type {\n SendEmailInput,\n EmailSendResult,\n EmailSend,\n BatchSendInput,\n BatchSendSummary,\n BatchSendResult,\n EmailTemplate,\n EmailTemplateDetail,\n GetTemplateOptions,\n} from \"./types/emails\";\nexport type {\n Contact,\n ContactCreateResult,\n ContactUpdateResult,\n ContactRemoveResult,\n ContactNoteResult,\n ContactStatus,\n EmailStatus,\n CreateContactInput,\n UpdateContactInput,\n ListContactsOptions,\n ImportContactInput,\n ImportContactsResult,\n Activity,\n AddNoteInput,\n} from \"./types/contacts\";\nexport type {\n Deal,\n DealCreateResult,\n DealUpdateResult,\n DealRemoveResult,\n DealStatus,\n CreateDealInput,\n UpdateDealInput,\n ListDealsOptions,\n} from \"./types/deals\";\nexport type {\n GdprExport,\n ConsentType,\n RecordConsentInput,\n ConsentRecord,\n ConsentResult,\n ContactConsents,\n CookieConsentInput,\n CookieCategoryConsent,\n} from \"./types/gdpr\";\nexport type {\n Post,\n PostType,\n PostVariant,\n PostDetail,\n Channel,\n CreatePostInput,\n UpdatePostInput,\n SchedulePostInput,\n ListPostsOptions,\n ScheduleResult,\n PublishResult,\n} from \"./types/posts\";\nexport type { Workspace } from \"./types/workspaces\";\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 CreateWebhookInput,\n ListDeliveriesOptions,\n UpdateWebhookInput,\n WebhookDeleteResult,\n WebhookDelivery,\n WebhookEndpoint,\n WebhookTestResult,\n} from \"./types/webhooks\";\n\n// Webhook event verification + typed events\nexport {\n DEFAULT_WEBHOOK_TOLERANCE_MS,\n verifyWebhookSignature,\n WebhookVerificationError,\n} from \"./webhook-events\";\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\";\nexport type {\n paths as OpenApiPaths,\n components as OpenApiComponents,\n operations as OpenApiOperations,\n} from \"./openapi.generated\";\n\n// Resource class re-exports (for advanced usage)\nexport { Emails } from \"./resources/emails\";\nexport { Contacts } from \"./resources/contacts\";\nexport { Deals } from \"./resources/deals\";\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 { BaseClient } from \"./client\";\nexport type { RequestOptions } from \"./client\";\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/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":[]}
|
|
@@ -712,9 +712,18 @@ interface components {
|
|
|
712
712
|
[key: string]: string;
|
|
713
713
|
};
|
|
714
714
|
contact_id?: string;
|
|
715
|
+
idempotency_key?: string;
|
|
716
|
+
/** Format: email */
|
|
717
|
+
copy_to?: string;
|
|
718
|
+
/** Format: email */
|
|
719
|
+
copy_reply_to?: string;
|
|
715
720
|
};
|
|
716
721
|
EmailSendResult: {
|
|
717
|
-
id
|
|
722
|
+
/** @description Email send id — poll GET /api/v1/emails/{id} with it. */
|
|
723
|
+
id: string | null;
|
|
724
|
+
/** @description Send id of the copy_to copy, or null when no copy was requested. */
|
|
725
|
+
copy_id: string | null;
|
|
726
|
+
contact_id: string | null;
|
|
718
727
|
status: string;
|
|
719
728
|
};
|
|
720
729
|
EmailSend: {
|
|
@@ -756,6 +765,18 @@ interface components {
|
|
|
756
765
|
total: number;
|
|
757
766
|
queued: number;
|
|
758
767
|
failed: number;
|
|
768
|
+
/** @description Per-recipient outcome, in request order. */
|
|
769
|
+
results: components["schemas"]["BatchSendRecipientResult"][];
|
|
770
|
+
};
|
|
771
|
+
BatchSendRecipientResult: {
|
|
772
|
+
/** Format: email */
|
|
773
|
+
email: string;
|
|
774
|
+
/** @description Email send id — poll GET /api/v1/emails/{id} with it. Null when not queued. */
|
|
775
|
+
id: string | null;
|
|
776
|
+
/** @enum {string} */
|
|
777
|
+
status: "queued" | "failed";
|
|
778
|
+
/** @description Failure reason for recipients that were not queued. */
|
|
779
|
+
error: string | null;
|
|
759
780
|
};
|
|
760
781
|
EmailTemplate: {
|
|
761
782
|
id: string;
|
|
@@ -712,9 +712,18 @@ interface components {
|
|
|
712
712
|
[key: string]: string;
|
|
713
713
|
};
|
|
714
714
|
contact_id?: string;
|
|
715
|
+
idempotency_key?: string;
|
|
716
|
+
/** Format: email */
|
|
717
|
+
copy_to?: string;
|
|
718
|
+
/** Format: email */
|
|
719
|
+
copy_reply_to?: string;
|
|
715
720
|
};
|
|
716
721
|
EmailSendResult: {
|
|
717
|
-
id
|
|
722
|
+
/** @description Email send id — poll GET /api/v1/emails/{id} with it. */
|
|
723
|
+
id: string | null;
|
|
724
|
+
/** @description Send id of the copy_to copy, or null when no copy was requested. */
|
|
725
|
+
copy_id: string | null;
|
|
726
|
+
contact_id: string | null;
|
|
718
727
|
status: string;
|
|
719
728
|
};
|
|
720
729
|
EmailSend: {
|
|
@@ -756,6 +765,18 @@ interface components {
|
|
|
756
765
|
total: number;
|
|
757
766
|
queued: number;
|
|
758
767
|
failed: number;
|
|
768
|
+
/** @description Per-recipient outcome, in request order. */
|
|
769
|
+
results: components["schemas"]["BatchSendRecipientResult"][];
|
|
770
|
+
};
|
|
771
|
+
BatchSendRecipientResult: {
|
|
772
|
+
/** Format: email */
|
|
773
|
+
email: string;
|
|
774
|
+
/** @description Email send id — poll GET /api/v1/emails/{id} with it. Null when not queued. */
|
|
775
|
+
id: string | null;
|
|
776
|
+
/** @enum {string} */
|
|
777
|
+
status: "queued" | "failed";
|
|
778
|
+
/** @description Failure reason for recipients that were not queued. */
|
|
779
|
+
error: string | null;
|
|
759
780
|
};
|
|
760
781
|
EmailTemplate: {
|
|
761
782
|
id: string;
|