@develemail/sdk 0.1.1 → 0.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/README.md +157 -0
- package/dist/index.cjs +557 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +528 -14
- package/dist/index.d.ts +528 -14
- package/dist/index.js +553 -25
- package/dist/index.js.map +1 -1
- package/package.json +19 -3
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts"],"sourcesContent":["export interface DevelEmailConfig {\n apiKey: string;\n baseUrl: string;\n}\n\nexport interface SendEmailInput {\n from: string;\n to: string | string[];\n subject: string;\n html?: string;\n text?: string;\n tags?: string[];\n metadata?: Record<string, unknown>;\n}\n\nexport interface EmailResponse {\n id: string;\n status: string;\n}\n\nexport class DevelEmailError extends Error {\n constructor(\n public readonly status: number,\n message: string,\n ) {\n super(message);\n this.name = 'DevelEmailError';\n }\n}\n\nclass EmailsNamespace {\n constructor(private readonly config: DevelEmailConfig) {}\n\n async send(input: SendEmailInput): Promise<EmailResponse> {\n return this.request<EmailResponse>('POST', '/v1/emails', input);\n }\n\n async get(id: string): Promise<EmailResponse> {\n return this.request<EmailResponse>('GET', `/v1/emails/${id}`);\n }\n\n private async request<T>(\n method: string,\n path: string,\n body?: unknown,\n ): Promise<T> {\n const res = await fetch(`${this.config.baseUrl}${path}`, {\n method,\n headers: {\n Authorization: `Bearer ${this.config.apiKey}`,\n 'Content-Type': 'application/json',\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!res.ok) {\n const data = await res.json().catch(() => ({}));\n throw new DevelEmailError(\n res.status,\n (data as { message?: string }).message ?? res.statusText,\n );\n }\n\n return res.json() as Promise<T>;\n }\n}\n\nexport class DevelEmail {\n readonly emails: EmailsNamespace;\n\n constructor(config: DevelEmailConfig) {\n this.emails = new EmailsNamespace(config);\n }\n}\n\nexport interface WebhookEvent {\n event: string;\n emailId: string | null;\n status: string | null;\n recipient: string | null;\n timestamp: string;\n metadata: Record<string, unknown>;\n}\n\nexport async function verifyWebhookSignature(\n payload: string,\n signature: string,\n secret: string,\n): Promise<boolean> {\n const expected = signature.startsWith('sha256=') ? signature.slice(7) : signature;\n\n const enc = new TextEncoder();\n const key = await globalThis.crypto.subtle.importKey(\n 'raw',\n enc.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n );\n\n const mac = await globalThis.crypto.subtle.sign('HMAC', key, enc.encode(payload));\n const computed = Array.from(new Uint8Array(mac))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n\n if (computed.length !== expected.length) return false;\n let diff = 0;\n for (let i = 0; i < computed.length; i++) {\n diff |= computed.charCodeAt(i) ^ expected.charCodeAt(i);\n }\n return diff === 0;\n}\n"],"mappings":";AAoBO,IAAM,kBAAN,cAA8B,MAAM;AAAA,EACzC,YACkB,QAChB,SACA;AACA,UAAM,OAAO;AAHG;AAIhB,SAAK,OAAO;AAAA,EACd;AAAA,EALkB;AAMpB;AAEA,IAAM,kBAAN,MAAsB;AAAA,EACpB,YAA6B,QAA0B;AAA1B;AAAA,EAA2B;AAAA,EAA3B;AAAA,EAE7B,MAAM,KAAK,OAA+C;AACxD,WAAO,KAAK,QAAuB,QAAQ,cAAc,KAAK;AAAA,EAChE;AAAA,EAEA,MAAM,IAAI,IAAoC;AAC5C,WAAO,KAAK,QAAuB,OAAO,cAAc,EAAE,EAAE;AAAA,EAC9D;AAAA,EAEA,MAAc,QACZ,QACA,MACA,MACY;AACZ,UAAM,MAAM,MAAM,MAAM,GAAG,KAAK,OAAO,OAAO,GAAG,IAAI,IAAI;AAAA,MACvD;AAAA,MACA,SAAS;AAAA,QACP,eAAe,UAAU,KAAK,OAAO,MAAM;AAAA,QAC3C,gBAAgB;AAAA,MAClB;AAAA,MACA,MAAM,SAAS,SAAY,KAAK,UAAU,IAAI,IAAI;AAAA,IACpD,CAAC;AAED,QAAI,CAAC,IAAI,IAAI;AACX,YAAM,OAAO,MAAM,IAAI,KAAK,EAAE,MAAM,OAAO,CAAC,EAAE;AAC9C,YAAM,IAAI;AAAA,QACR,IAAI;AAAA,QACH,KAA8B,WAAW,IAAI;AAAA,MAChD;AAAA,IACF;AAEA,WAAO,IAAI,KAAK;AAAA,EAClB;AACF;AAEO,IAAM,aAAN,MAAiB;AAAA,EACb;AAAA,EAET,YAAY,QAA0B;AACpC,SAAK,SAAS,IAAI,gBAAgB,MAAM;AAAA,EAC1C;AACF;AAWA,eAAsB,uBACpB,SACA,WACA,QACkB;AAClB,QAAM,WAAW,UAAU,WAAW,SAAS,IAAI,UAAU,MAAM,CAAC,IAAI;AAExE,QAAM,MAAM,IAAI,YAAY;AAC5B,QAAM,MAAM,MAAM,WAAW,OAAO,OAAO;AAAA,IACzC;AAAA,IACA,IAAI,OAAO,MAAM;AAAA,IACjB,EAAE,MAAM,QAAQ,MAAM,UAAU;AAAA,IAChC;AAAA,IACA,CAAC,MAAM;AAAA,EACT;AAEA,QAAM,MAAM,MAAM,WAAW,OAAO,OAAO,KAAK,QAAQ,KAAK,IAAI,OAAO,OAAO,CAAC;AAChF,QAAM,WAAW,MAAM,KAAK,IAAI,WAAW,GAAG,CAAC,EAC5C,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAC1C,KAAK,EAAE;AAEV,MAAI,SAAS,WAAW,SAAS,OAAQ,QAAO;AAChD,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ,KAAK;AACxC,YAAQ,SAAS,WAAW,CAAC,IAAI,SAAS,WAAW,CAAC;AAAA,EACxD;AACA,SAAO,SAAS;AAClB;","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/errors.ts","../src/client.ts","../../core/src/reserved-domains.ts","../src/attachment-encoding.ts","../src/emails.ts","../src/domains.ts","../src/templates.ts","../src/campaigns.ts","../src/contacts.ts","../src/lists.ts","../src/sms.ts","../src/webhook.ts","../src/types.ts","../src/index.ts"],"sourcesContent":["export class DevelEmailError extends Error {\n constructor(\n public readonly status: number,\n message: string,\n public readonly code?: string,\n public readonly details?: Record<string, unknown>,\n ) {\n super(message);\n this.name = 'DevelEmailError';\n }\n}\n","import { DevelEmailError } from './errors.js';\nimport type { DevelEmailConfig } from './types.js';\n\nconst DEFAULT_MAX_RETRIES = 3;\nconst BASE_DELAY_MS = 500;\nconst MAX_DELAY_MS = 30_000;\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nfunction isRetryable(status: number): boolean {\n return status >= 500 || status === 429;\n}\n\ninterface ParsedError {\n message: string;\n code?: string;\n details?: Record<string, unknown>;\n}\n\nfunction parseErrorBody(body: unknown): ParsedError {\n if (typeof body === 'object' && body !== null) {\n const b = body as Record<string, unknown>;\n const { message, error, statusCode, ...rest } = b;\n return {\n message: typeof message === 'string' ? message : 'Unknown error',\n code: typeof error === 'string' ? error : undefined,\n details: Object.keys(rest).length > 0 ? rest : undefined,\n };\n }\n return { message: 'Unknown error' };\n}\n\nexport class HttpClient {\n private readonly baseUrl: string;\n private readonly apiKey: string;\n private readonly maxRetries: number;\n\n constructor(config: DevelEmailConfig) {\n this.baseUrl = config.baseUrl.replace(/\\/+$/, '');\n this.apiKey = config.apiKey;\n this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;\n }\n\n async get<T>(path: string): Promise<T> {\n return this.request<T>('GET', path);\n }\n\n async post<T>(\n path: string,\n body: unknown,\n extraHeaders?: Record<string, string>,\n ): Promise<T> {\n return this.request<T>('POST', path, body, extraHeaders);\n }\n\n async put<T>(\n path: string,\n body: unknown,\n extraHeaders?: Record<string, string>,\n ): Promise<T> {\n return this.request<T>('PUT', path, body, extraHeaders);\n }\n\n async patch<T>(\n path: string,\n body: unknown,\n extraHeaders?: Record<string, string>,\n ): Promise<T> {\n return this.request<T>('PATCH', path, body, extraHeaders);\n }\n\n async delete<T>(\n path: string,\n extraHeaders?: Record<string, string>,\n ): Promise<T> {\n return this.request<T>('DELETE', path, undefined, extraHeaders);\n }\n\n private async request<T>(\n method: string,\n path: string,\n body?: unknown,\n extraHeaders?: Record<string, string>,\n ): Promise<T> {\n const url = `${this.baseUrl}${path}`;\n const headers: Record<string, string> = {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n ...extraHeaders,\n };\n const init: RequestInit = {\n method,\n headers,\n body: body !== undefined ? JSON.stringify(body) : undefined,\n };\n\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= this.maxRetries; attempt++) {\n let res: Response;\n try {\n res = await fetch(url, init);\n } catch (err) {\n lastError = err;\n if (attempt < this.maxRetries) {\n await sleep(this.backoff(attempt));\n continue;\n }\n throw new DevelEmailError(\n 0,\n err instanceof Error ? err.message : 'Network error',\n 'network_error',\n );\n }\n\n if (res.ok) {\n if (res.status === 204) return undefined as T;\n return res.json() as Promise<T>;\n }\n\n const errorBody = await res.json().catch(() => ({}));\n const parsed = parseErrorBody(errorBody);\n\n if (isRetryable(res.status) && attempt < this.maxRetries) {\n const retryAfter = res.headers.get('Retry-After');\n const delay = retryAfter\n ? parseInt(retryAfter, 10) * 1000\n : this.backoff(attempt);\n await sleep(delay);\n lastError = new DevelEmailError(\n res.status,\n parsed.message,\n parsed.code,\n parsed.details,\n );\n continue;\n }\n\n throw new DevelEmailError(\n res.status,\n parsed.message,\n parsed.code,\n parsed.details,\n );\n }\n\n if (lastError instanceof DevelEmailError) throw lastError;\n throw new DevelEmailError(\n 0,\n lastError instanceof Error ? lastError.message : 'Request failed',\n 'network_error',\n );\n }\n\n private backoff(attempt: number): number {\n const delay = BASE_DELAY_MS * 2 ** attempt;\n const jitter = delay * 0.2 * Math.random();\n return Math.min(delay + jitter, MAX_DELAY_MS);\n }\n}\n","export const RESERVED_DOMAINS = ['example.com', 'example.net', 'example.org'];\n\nexport const RESERVED_TLDS = ['test', 'example', 'invalid', 'localhost'];\n\nexport function isReservedDomain(domain: string): boolean {\n const normalized = domain.trim().toLowerCase().replace(/\\.$/, '');\n if (!normalized) return false;\n\n if (RESERVED_DOMAINS.includes(normalized)) return true;\n\n const tld = normalized.split('.').pop() ?? '';\n return RESERVED_TLDS.includes(tld);\n}\n","import type { AttachmentInput, WireAttachmentInput } from './types.js';\n\n/**\n * A `string` is treated as already-base64 (matching the wire format) and\n * passed through untouched. A `Uint8Array` (covers Node `Buffer`) is\n * base64-encoded here before the request goes out. Pure and exported so the\n * encoding path is directly unit-testable without mocking `fetch`.\n */\nexport function encodeAttachmentContent(content: string | Uint8Array): string {\n return typeof content === 'string'\n ? content\n : Buffer.from(content).toString('base64');\n}\n\n/**\n * Converts a `send()`/`batch()` caller's ergonomic attachment list into the\n * wire shape `AttachmentInput.content` is base64-encoded via\n * `encodeAttachmentContent`, everything else passes through.\n */\nexport function encodeAttachments(\n attachments: AttachmentInput[] | undefined,\n): WireAttachmentInput[] | undefined {\n if (!attachments) return undefined;\n return attachments.map((attachment) => ({\n filename: attachment.filename,\n contentType: attachment.contentType,\n content: encodeAttachmentContent(attachment.content),\n }));\n}\n","import { isReservedDomain } from '@develemail/core';\nimport type { HttpClient } from './client.js';\nimport { DevelEmailError } from './errors.js';\nimport { encodeAttachments } from './attachment-encoding.js';\nimport type {\n SendEmailInput,\n SendOptions,\n EmailResponse,\n BatchEmailResponse,\n BatchEmailResultItem,\n} from './types.js';\n\n// Converts the ergonomic `attachments` field (content: string | Uint8Array)\n// to the wire shape (content: always base64 string) right before the\n// request is serialized — every other field passes through untouched.\nfunction toWirePayload(input: SendEmailInput): unknown {\n return { ...input, attachments: encodeAttachments(input.attachments) };\n}\n\nfunction extractDomain(email: string): string {\n return email.split('@')[1] ?? '';\n}\n\n// Mirrors apps/api/src/domains/emails/errors.ts's ReservedRecipientDomainError\n// message so a caller sees the same wording whether the API or the SDK caught it.\nfunction reservedRecipientError(recipient: string): DevelEmailError {\n const domain = extractDomain(recipient);\n return new DevelEmailError(\n 400,\n `Recipient '${recipient}' uses reserved domain '${domain}', which cannot receive mail`,\n 'reserved_recipient_domain',\n { recipient, domain },\n );\n}\n\nfunction findReservedRecipient(input: SendEmailInput): string | null {\n const toAddresses = Array.isArray(input.to) ? input.to : [input.to];\n return (\n toAddresses.find((addr) => isReservedDomain(extractDomain(addr))) ?? null\n );\n}\n\nexport class Emails {\n constructor(private readonly http: HttpClient) {}\n\n async send(\n input: SendEmailInput,\n options?: SendOptions,\n ): Promise<EmailResponse> {\n const reserved = findReservedRecipient(input);\n if (reserved) throw reservedRecipientError(reserved);\n\n const key = options?.idempotencyKey ?? crypto.randomUUID();\n return this.http.post<EmailResponse>('/v1/emails', toWirePayload(input), {\n 'Idempotency-Key': key,\n });\n }\n\n // Rejects reserved recipients client-side but, matching the server's\n // per-item batch semantics, does not fail the whole batch: deliverable\n // items still go out, and each reserved item is named in `results` with\n // an `error` instead of being silently dropped.\n async batch(\n emails: SendEmailInput[],\n options?: SendOptions,\n ): Promise<BatchEmailResponse> {\n const rejections = new Map<number, BatchEmailResultItem>();\n emails.forEach((email, index) => {\n const reserved = findReservedRecipient(email);\n if (reserved) {\n rejections.set(index, {\n index,\n error: reservedRecipientError(reserved).message,\n });\n }\n });\n\n const deliverable = emails.filter((_, index) => !rejections.has(index));\n\n if (deliverable.length === 0) {\n return {\n results: emails.map((_, index) => rejections.get(index)!),\n created: 0,\n errors: rejections.size,\n };\n }\n\n const key = options?.idempotencyKey ?? crypto.randomUUID();\n const response = await this.http.post<BatchEmailResponse>(\n '/v1/emails/batch',\n { emails: deliverable.map(toWirePayload) },\n { 'Idempotency-Key': key },\n );\n\n const results: BatchEmailResultItem[] = [];\n let sent = 0;\n for (let index = 0; index < emails.length; index++) {\n const rejection = rejections.get(index);\n results.push(rejection ?? { ...response.results[sent++]!, index });\n }\n\n return {\n results,\n created: response.created,\n errors: response.errors + rejections.size,\n limitReached: response.limitReached,\n };\n }\n\n async get(id: string): Promise<EmailResponse> {\n return this.http.get<EmailResponse>(`/v1/emails/${encodeURIComponent(id)}`);\n }\n}\n","import type { HttpClient } from './client.js';\nimport type { Domain, DomainCreateInput } from './types.js';\n\nexport class Domains {\n constructor(private readonly http: HttpClient) {}\n\n async list(): Promise<Domain[]> {\n return this.http.get<Domain[]>('/domains');\n }\n\n async get(id: string): Promise<Domain> {\n return this.http.get<Domain>(`/domains/${encodeURIComponent(id)}`);\n }\n\n async create(input: DomainCreateInput): Promise<Domain> {\n return this.http.post<Domain>('/domains', input);\n }\n\n async delete(id: string): Promise<void> {\n await this.http.delete<void>(`/domains/${encodeURIComponent(id)}`);\n }\n\n async verify(id: string): Promise<Domain> {\n return this.http.post<Domain>(\n `/domains/${encodeURIComponent(id)}/verify`,\n undefined,\n );\n }\n}\n","import type { HttpClient } from './client.js';\nimport type {\n Template,\n TemplateCreateInput,\n TemplateUpdateInput,\n} from './types.js';\n\nexport class Templates {\n constructor(private readonly http: HttpClient) {}\n\n async list(): Promise<Template[]> {\n return this.http.get<Template[]>('/templates');\n }\n\n async get(id: string): Promise<Template> {\n return this.http.get<Template>(`/templates/${encodeURIComponent(id)}`);\n }\n\n async create(input: TemplateCreateInput): Promise<Template> {\n return this.http.post<Template>('/templates', input);\n }\n\n async update(id: string, input: TemplateUpdateInput): Promise<Template> {\n return this.http.put<Template>(\n `/templates/${encodeURIComponent(id)}`,\n input,\n );\n }\n\n async delete(id: string): Promise<void> {\n await this.http.delete<void>(`/templates/${encodeURIComponent(id)}`);\n }\n}\n","import type { HttpClient } from './client.js';\nimport type {\n Campaign,\n CampaignCreateInput,\n CampaignListQuery,\n CampaignProviderStats,\n CampaignStats,\n CampaignUpdateInput,\n} from './types.js';\n\nfunction toQueryString(query: CampaignListQuery): string {\n const params = new URLSearchParams();\n params.set('projectId', query.projectId);\n if (query.status) params.set('status', query.status);\n if (query.limit !== undefined) params.set('limit', String(query.limit));\n if (query.offset !== undefined) params.set('offset', String(query.offset));\n return params.toString();\n}\n\nexport class Campaigns {\n constructor(private readonly http: HttpClient) {}\n\n async list(query: CampaignListQuery): Promise<Campaign[]> {\n return this.http.get<Campaign[]>(`/campaigns?${toQueryString(query)}`);\n }\n\n async get(id: string): Promise<Campaign> {\n return this.http.get<Campaign>(`/campaigns/${encodeURIComponent(id)}`);\n }\n\n async create(input: CampaignCreateInput): Promise<Campaign> {\n return this.http.post<Campaign>('/campaigns', input);\n }\n\n async update(id: string, input: CampaignUpdateInput): Promise<Campaign> {\n return this.http.patch<Campaign>(\n `/campaigns/${encodeURIComponent(id)}`,\n input,\n );\n }\n\n async send(id: string): Promise<Campaign> {\n return this.http.post<Campaign>(\n `/campaigns/${encodeURIComponent(id)}/send`,\n undefined,\n );\n }\n\n async pause(id: string): Promise<Campaign> {\n return this.http.post<Campaign>(\n `/campaigns/${encodeURIComponent(id)}/pause`,\n undefined,\n );\n }\n\n async resume(id: string): Promise<Campaign> {\n return this.http.post<Campaign>(\n `/campaigns/${encodeURIComponent(id)}/resume`,\n undefined,\n );\n }\n\n async cancel(id: string): Promise<Campaign & { note: string }> {\n return this.http.post<Campaign & { note: string }>(\n `/campaigns/${encodeURIComponent(id)}/cancel`,\n undefined,\n );\n }\n\n async duplicate(id: string): Promise<Campaign> {\n return this.http.post<Campaign>(\n `/campaigns/${encodeURIComponent(id)}/duplicate`,\n undefined,\n );\n }\n\n async delete(id: string): Promise<void> {\n await this.http.delete<void>(`/campaigns/${encodeURIComponent(id)}`);\n }\n\n async stats(id: string): Promise<CampaignStats> {\n return this.http.get<CampaignStats>(\n `/campaigns/${encodeURIComponent(id)}/stats`,\n );\n }\n\n async providerStats(id: string): Promise<CampaignProviderStats[]> {\n return this.http.get<CampaignProviderStats[]>(\n `/campaigns/${encodeURIComponent(id)}/provider-stats`,\n );\n }\n}\n","import type { HttpClient } from './client.js';\nimport type {\n Contact,\n ContactBulkInput,\n ContactBulkResponse,\n ContactCreateInput,\n ContactListItem,\n ContactListQuery,\n ContactListResponse,\n ContactUpdateInput,\n} from './types.js';\n\nfunction toQueryString(query: ContactListQuery): string {\n const params = new URLSearchParams();\n params.set('projectId', query.projectId);\n if (query.search) params.set('search', query.search);\n if (query.tags) {\n const tags = query.tags.filter(Boolean);\n if (tags.length > 0) params.set('tags', tags.join(','));\n }\n if (query.tagMode) params.set('tagMode', query.tagMode);\n if (query.limit !== undefined) params.set('limit', String(query.limit));\n if (query.offset !== undefined) params.set('offset', String(query.offset));\n return params.toString();\n}\n\nexport class Contacts {\n constructor(private readonly http: HttpClient) {}\n\n async list(query: ContactListQuery): Promise<ContactListResponse> {\n return this.http.get<ContactListResponse>(\n `/contacts?${toQueryString(query)}`,\n );\n }\n\n async get(id: string): Promise<Contact> {\n return this.http.get<Contact>(`/contacts/${encodeURIComponent(id)}`);\n }\n\n async create(input: ContactCreateInput): Promise<Contact> {\n return this.http.post<Contact>('/contacts', input);\n }\n\n async update(id: string, input: ContactUpdateInput): Promise<Contact> {\n return this.http.patch<Contact>(\n `/contacts/${encodeURIComponent(id)}`,\n input,\n );\n }\n\n async delete(id: string): Promise<void> {\n await this.http.delete<void>(`/contacts/${encodeURIComponent(id)}`);\n }\n\n async bulkCreate(input: ContactBulkInput): Promise<ContactBulkResponse> {\n return this.http.post<ContactBulkResponse>('/contacts/bulk', input);\n }\n\n async tags(projectId: string): Promise<string[]> {\n const params = new URLSearchParams();\n params.set('projectId', projectId);\n return this.http.get<string[]>(`/contacts/tags?${params.toString()}`);\n }\n\n async lists(contactId: string): Promise<ContactListItem[]> {\n return this.http.get<ContactListItem[]>(\n `/contacts/${encodeURIComponent(contactId)}/lists`,\n );\n }\n\n /** @deprecated Use `lists.addContacts` instead. */\n async addToList(contactId: string, listId: string): Promise<void> {\n await this.http.post<{ added: number }>(\n `/lists/${encodeURIComponent(listId)}/contacts`,\n { contactIds: [contactId] },\n );\n }\n\n /** @deprecated Use `lists.removeContact` instead. */\n async removeFromList(contactId: string, listId: string): Promise<void> {\n await this.http.delete<void>(\n `/lists/${encodeURIComponent(listId)}/contacts/${encodeURIComponent(contactId)}`,\n );\n }\n}\n","import type { HttpClient } from './client.js';\nimport type {\n List,\n ListCreateInput,\n ListMembersQuery,\n ListMembersResponse,\n ListUpdateInput,\n ListWithCount,\n} from './types.js';\n\nfunction toQueryString(query: ListMembersQuery): string {\n const params = new URLSearchParams();\n if (query.search) params.set('search', query.search);\n if (query.limit !== undefined) params.set('limit', String(query.limit));\n if (query.offset !== undefined) params.set('offset', String(query.offset));\n return params.toString();\n}\n\nexport class Lists {\n constructor(private readonly http: HttpClient) {}\n\n async list(projectId: string): Promise<ListWithCount[]> {\n const params = new URLSearchParams();\n params.set('projectId', projectId);\n return this.http.get<ListWithCount[]>(`/lists?${params.toString()}`);\n }\n\n async get(id: string): Promise<List> {\n return this.http.get<List>(`/lists/${encodeURIComponent(id)}`);\n }\n\n async create(input: ListCreateInput): Promise<List> {\n return this.http.post<List>('/lists', input);\n }\n\n async update(id: string, input: ListUpdateInput): Promise<List> {\n return this.http.patch<List>(`/lists/${encodeURIComponent(id)}`, input);\n }\n\n async delete(id: string): Promise<void> {\n await this.http.delete<void>(`/lists/${encodeURIComponent(id)}`);\n }\n\n async listContacts(\n id: string,\n query: ListMembersQuery = {},\n ): Promise<ListMembersResponse> {\n return this.http.get<ListMembersResponse>(\n `/lists/${encodeURIComponent(id)}/contacts?${toQueryString(query)}`,\n );\n }\n\n async addContacts(\n id: string,\n contactIds: string[],\n ): Promise<{ added: number }> {\n return this.http.post<{ added: number }>(\n `/lists/${encodeURIComponent(id)}/contacts`,\n { contactIds },\n );\n }\n\n async removeContact(id: string, contactId: string): Promise<void> {\n await this.http.delete<void>(\n `/lists/${encodeURIComponent(id)}/contacts/${encodeURIComponent(contactId)}`,\n );\n }\n}\n","import type { HttpClient } from './client.js';\nimport type {\n SendSmsInput,\n SmsListQuery,\n SmsListResponse,\n SmsMessageResponse,\n} from './types.js';\n\nfunction toQueryString(query: SmsListQuery): string {\n const params = new URLSearchParams();\n if (query.status) params.set('status', query.status);\n if (query.limit !== undefined) params.set('limit', String(query.limit));\n if (query.cursor) params.set('cursor', query.cursor);\n return params.toString();\n}\n\nexport class Sms {\n constructor(private readonly http: HttpClient) {}\n\n async send(input: SendSmsInput): Promise<SmsMessageResponse> {\n return this.http.post<SmsMessageResponse>('/v1/sms', input);\n }\n\n async get(id: string): Promise<SmsMessageResponse> {\n return this.http.get<SmsMessageResponse>(\n `/v1/sms/${encodeURIComponent(id)}`,\n );\n }\n\n async list(query: SmsListQuery = {}): Promise<SmsListResponse> {\n const qs = toQueryString(query);\n return this.http.get<SmsListResponse>(`/v1/sms${qs ? `?${qs}` : ''}`);\n }\n}\n","export async function verifyWebhookSignature(\n payload: string,\n signature: string,\n secret: string,\n): Promise<boolean> {\n const expected = signature.startsWith('sha256=')\n ? signature.slice(7)\n : signature;\n\n const enc = new TextEncoder();\n const key = await globalThis.crypto.subtle.importKey(\n 'raw',\n enc.encode(secret),\n { name: 'HMAC', hash: 'SHA-256' },\n false,\n ['sign'],\n );\n\n const mac = await globalThis.crypto.subtle.sign(\n 'HMAC',\n key,\n enc.encode(payload),\n );\n const computed = Array.from(new Uint8Array(mac))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('');\n\n if (computed.length !== expected.length) return false;\n let diff = 0;\n for (let i = 0; i < computed.length; i++) {\n diff |= computed.charCodeAt(i) ^ expected.charCodeAt(i);\n }\n return diff === 0;\n}\n","export interface DevelEmailConfig {\n apiKey: string;\n baseUrl: string;\n maxRetries?: number;\n}\n\n/**\n * Wire-format attachment shape — what actually goes over HTTP (`content` is\n * already base64). Mirrors `apps/api/src/domains/emails/types.ts`'s\n * `AttachmentInput` field-for-field; kept as a distinct name from the\n * ergonomic `AttachmentInput` below so the DTO contract test can assert the\n * wire shape while `emails.send()`/`emails.batch()` callers get\n * base64/Buffer ergonomics. Exported only for `apps/api`'s DTO contract\n * test to import — not part of the ergonomic public surface callers build\n * requests with.\n */\nexport interface WireAttachmentInput {\n filename: string;\n content: string;\n contentType: string;\n}\n\n/**\n * Ergonomic attachment input for `emails.send()` / `emails.batch()`.\n * `content` accepts a `Uint8Array` (covers Node `Buffer`) — the SDK\n * base64-encodes it before the request goes out — or an already-base64\n * `string`, matching the wire format directly.\n *\n * Server caps: max 10 attachments per email, 5 MiB per file (decoded),\n * 7 MiB combined decoded size per email.\n */\nexport interface AttachmentInput {\n filename: string;\n content: string | Uint8Array;\n contentType: string;\n}\n\n/**\n * Deliberately different from `apps/api/src/domains/emails/types.ts`'s\n * `SendEmailInput` in `attachments` only: this is the ergonomic pre-request\n * shape (`AttachmentInput.content: string | Uint8Array`) while the api's\n * `z.infer`'d type is the post-parse wire shape (`content: string`,\n * already base64). Every other field matches exactly — see\n * `apps/api/src/sdk-dto-contract.test.ts`'s `Omit<..., 'attachments'>`\n * assertion. See `apps/api/src/sdk-dto-contract-discovery.test.ts`'s\n * registry for the enforcement.\n */\nexport interface SendEmailInput {\n from: string;\n to: string | string[];\n subject?: string;\n html?: string;\n text?: string;\n tags?: string[];\n metadata?: Record<string, unknown>;\n template?: string;\n variables?: Record<string, string>;\n send_at?: string;\n attachments?: AttachmentInput[];\n}\n\nexport interface SendOptions {\n idempotencyKey?: string;\n}\n\n/**\n * Mirrors `apps/api/src/domains/emails/types.ts`'s server-side copy of this\n * shape. Not imported from there: this package is published to npm for\n * external consumers and can't depend on the private api app. Keep both\n * copies in sync by hand when the wire shape changes; same for\n * `BatchEmailResultItem` / `BatchEmailResponse` below.\n */\nexport interface EmailResponse {\n id: string;\n status: string;\n duplicate?: boolean;\n}\n\nexport interface BatchEmailResultItem {\n index: number;\n id?: string;\n status?: string;\n duplicate?: boolean;\n error?: string;\n}\n\nexport interface BatchEmailResponse {\n results: BatchEmailResultItem[];\n created: number;\n errors: number;\n limitReached?: boolean;\n}\n\nexport interface Domain {\n id: string;\n organizationId: string;\n name: string;\n verificationStatus: string;\n spfStatus: string | null;\n dkimStatus: string | null;\n dmarcStatus: string | null;\n ptrStatus: string | null;\n mxStatus: string | null;\n returnPathStatus: string | null;\n dmarcPolicy: string | null;\n dkimPublicKey: string;\n dkimSelector: string;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface Template {\n id: string;\n organizationId: string;\n name: string;\n subject: string;\n html: string;\n text?: string | null;\n variables?: string[];\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface DomainCreateInput {\n name: string;\n dkimSelector?: string;\n}\n\nexport interface TemplateCreateInput {\n name: string;\n subject: string;\n html: string;\n text?: string;\n variables?: string[];\n}\n\nexport interface TemplateUpdateInput {\n name?: string;\n subject?: string;\n html?: string;\n text?: string;\n variables?: string[];\n}\n\n/**\n * Every status an email can be in. `delivered` means the recipient's mail\n * gateway accepted the message with a 2xx response — it does not mean the\n * message reached the inbox; it can still be filtered or quarantined\n * afterward.\n */\nexport const EMAIL_STATUSES = [\n 'queued',\n 'rendering',\n 'submitted_to_postfix',\n 'deferred',\n 'sent',\n 'delivered',\n 'bounced',\n 'rejected',\n 'failed',\n 'suppressed',\n 'cancelled',\n 'scheduled',\n 'quarantined',\n] as const;\n\nexport type EmailStatus = (typeof EMAIL_STATUSES)[number];\n\n/**\n * Every event type the server currently emits, including as a webhook's\n * `event` field. `WebhookEvent.event` stays typed as `string` (not this\n * union) because the server may add new event types over time — treat an\n * unrecognized value as informational, not an error. See\n * `docs/webhooks.md`: a project's webhook receives every event type below\n * automatically, with no per-type opt-in.\n */\nexport const EMAIL_EVENT_TYPES = [\n 'queued',\n 'rendering_started',\n 'rendering_completed',\n 'submitted_to_postfix',\n 'deferred',\n 'sent',\n 'delivered',\n 'bounced',\n 'rejected',\n 'failed',\n 'suppressed',\n 'cancelled',\n 'retry_scheduled',\n 'open',\n 'click',\n 'quarantined',\n] as const;\n\nexport type EmailEventType = (typeof EMAIL_EVENT_TYPES)[number];\n\n/**\n * `metadata` shape for `delivered` / `deferred` / `bounced` webhook events\n * and lifecycle-timeline entries — written by the Postfix log follower.\n */\nexport interface DeliveryEventData {\n queueId: string;\n relay: string;\n response: string;\n timestamp: string;\n}\n\n/**\n * Mirrors `apps/api/src/domains/webhooks/types.ts`'s `WebhookPayload`\n * (different name, same shape) — see that file for why this isn't a shared\n * import.\n */\nexport interface WebhookEvent {\n event: string;\n emailId: string | null;\n status: string | null;\n recipient: string | null;\n timestamp: string;\n metadata: Record<string, unknown>;\n}\n\nexport type CampaignStatus =\n | 'draft'\n | 'scheduled'\n | 'sending'\n | 'paused'\n | 'sent'\n | 'cancelled';\n\nexport interface Campaign {\n id: string;\n projectId: string;\n listId: string | null;\n tagFilters: string[] | null;\n tagFilterMode: 'and' | 'or' | null;\n templateId: string | null;\n name: string;\n subject: string;\n fromAddress: string;\n fromName: string | null;\n rawHtml: string | null;\n rawText: string | null;\n status: CampaignStatus;\n scheduledFor: string | null;\n sentAt: string | null;\n totalRecipients: number | null;\n summarizedStats: {\n delivered?: number;\n deliveryUnknown?: number;\n opened?: number;\n clicked?: number;\n bounced?: number;\n unsubscribed?: number;\n } | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Deliberately different from `apps/api/src/domains/campaigns/types.ts`'s\n * `CampaignListQuery` in `limit`/`offset` optionality, not a bug: this type\n * describes what a caller may omit before the request is sent, while the\n * api's `z.infer`'d type describes the post-parse shape after `.default()`\n * has filled those fields in. Both are correct for what they represent — see\n * `apps/api/src/sdk-dto-contract-discovery.test.ts`'s registry for the\n * enforcement.\n */\nexport interface CampaignListQuery {\n projectId: string;\n status?: CampaignStatus;\n limit?: number;\n offset?: number;\n}\n\nexport interface CampaignCreateInput {\n projectId: string;\n listId?: string;\n tagFilters?: string[];\n tagFilterMode?: 'and' | 'or';\n templateId?: string;\n name: string;\n subject: string;\n fromAddress: string;\n fromName?: string;\n rawHtml?: string;\n rawText?: string;\n scheduledFor?: string;\n}\n\nexport interface CampaignUpdateInput {\n listId?: string | null;\n tagFilters?: string[] | null;\n tagFilterMode?: 'and' | 'or';\n templateId?: string | null;\n name?: string;\n subject?: string;\n fromAddress?: string;\n fromName?: string;\n rawHtml?: string;\n rawText?: string;\n scheduledFor?: string;\n}\n\n/**\n * Mirrors `apps/api/src/domains/campaigns/types.ts`'s server-side copy of\n * this shape (and `CampaignProviderStats` below) — see that file for why\n * this isn't a shared import.\n */\nexport interface CampaignStats {\n campaignId: string;\n totalRecipients: number;\n delivered: number;\n deliveryUnknown: number;\n opened: number;\n clicked: number;\n bounced: number;\n unsubscribed: number;\n openRate: number;\n clickRate: number;\n bounceRate: number;\n links: Array<{ url: string; clicks: number }>;\n}\n\nexport interface CampaignProviderStats {\n provider: string;\n opens: number;\n clicks: number;\n total: number;\n}\n\nexport interface List {\n id: string;\n projectId: string;\n name: string;\n description: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Deliberately different from `apps/api/src/domains/lists/types.ts`'s\n * `ListWithCount` in `createdAt`/`updatedAt` (inherited from `List` above),\n * not a bug: this describes what a client receives after the wire\n * round-trip (`string`), while the api's type is the server-side shape held\n * before JSON serialization (`Date`, via drizzle's `$inferSelect`). See\n * `apps/api/src/sdk-dto-contract-discovery.test.ts`'s registry for the\n * enforcement.\n */\nexport interface ListWithCount extends List {\n memberCount: number;\n}\n\nexport interface ListCreateInput {\n projectId: string;\n name: string;\n description?: string;\n}\n\nexport interface ListUpdateInput {\n name?: string;\n description?: string;\n}\n\nexport interface ListMembersQuery {\n search?: string;\n limit?: number;\n offset?: number;\n}\n\nexport interface ListMembersResponse {\n data: Contact[];\n total: number;\n}\n\nexport interface Contact {\n id: string;\n projectId: string;\n email: string;\n firstName: string | null;\n lastName: string | null;\n country: string | null;\n tags: string[];\n unsubscribedAt: string | null;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Deliberately different from `apps/api/src/domains/contacts/types.ts`'s\n * `ContactListQuery` in `tags`/`tagMode`, not a bug: the api type is\n * `z.infer<typeof ContactListQuerySchema>` — `tags` is post-transform\n * `string[]` and `tagMode` is post-`.default()` required — while this is the\n * pre-request shape callers build, where both stay optional. See\n * `apps/api/src/sdk-dto-contract-discovery.test.ts`'s registry for the\n * enforcement.\n */\nexport interface ContactListQuery {\n projectId: string;\n search?: string;\n tags?: string[];\n tagMode?: 'and' | 'or';\n limit?: number;\n offset?: number;\n}\n\nexport interface ContactListResponse {\n data: Contact[];\n total: number;\n}\n\nexport interface ContactCreateInput {\n projectId: string;\n email: string;\n firstName?: string;\n lastName?: string;\n tags?: string[];\n}\n\nexport interface ContactUpdateInput {\n unsubscribe: boolean;\n}\n\nexport interface ContactBulkContactInput {\n email: string;\n firstName?: string;\n lastName?: string;\n country?: string;\n tags?: string[];\n}\n\nexport interface ContactBulkInput {\n projectId: string;\n contacts: ContactBulkContactInput[];\n}\n\nexport interface ContactBulkResponse {\n inserted: number;\n updated: number;\n skipped: number;\n}\n\n/**\n * Deliberately different from `apps/api/src/domains/contacts/types.ts`'s\n * `ContactListItem` in `addedAt`, not a bug: this describes what a client\n * receives after the wire round-trip (`string`), while the api's type is\n * the server-side shape held before JSON serialization (`Date`). See\n * `apps/api/src/sdk-dto-contract-discovery.test.ts`'s registry for the\n * enforcement.\n */\nexport interface ContactListItem {\n id: string;\n name: string;\n memberCount: number;\n addedAt: string;\n}\n\n/**\n * Mirrors `apps/api/src/domains/sms/repo.types.ts`'s `smsStatusEnum` values\n * (`packages/db/src/schema/enums.ts`). Kept as a local literal union rather\n * than an import — this package can't depend on `@develemail/db`, same\n * reason `EMAIL_STATUSES` above is hand-copied instead of imported.\n */\nexport const SMS_STATUSES = [\n 'queued',\n 'sending',\n 'sent',\n 'delivered',\n 'deferred',\n 'failed',\n 'suppressed',\n] as const;\n\nexport type SmsStatus = (typeof SMS_STATUSES)[number];\n\n/**\n * Mirrors `apps/api/src/domains/sms/types.ts`'s `z.infer`'d `SendSmsInput`\n * field-for-field — unlike `SendEmailInput`, there's no ergonomic wire\n * conversion needed here, so this is asserted equal (not\n * `DELIBERATELY_DIFFERENT`) in `apps/api/src/sdk-dto-contract.test.ts`.\n * Provide exactly one of `body` or `templateName` — the server 400s\n * otherwise; that XOR is a runtime `.refine()`, not expressible in the type.\n */\nexport interface SendSmsInput {\n to: string;\n from?: string;\n body?: string;\n templateName?: string;\n variables?: Record<string, string>;\n tags?: string[];\n metadata?: Record<string, unknown>;\n}\n\n/**\n * Mirrors `apps/api/src/domains/sms/types.ts`'s server-side copy of this\n * shape field-for-field. Not imported from there: this package is published\n * to npm for external consumers and can't depend on the private api app.\n * Keep both copies in sync by hand when the wire shape changes; same for\n * `SmsListResponse` below.\n */\nexport interface SmsMessageResponse {\n id: string;\n to: string;\n from: string | null;\n body: string;\n status: string;\n tags: string[];\n metadata: Record<string, unknown>;\n createdAt: string;\n updatedAt: string;\n}\n\nexport interface SmsListResponse {\n data: SmsMessageResponse[];\n nextCursor: string | null;\n}\n\nexport interface SmsListQuery {\n status?: SmsStatus;\n limit?: number;\n cursor?: string;\n}\n","import { HttpClient } from './client.js';\nimport { Emails } from './emails.js';\nimport { Domains } from './domains.js';\nimport { Templates } from './templates.js';\nimport { Campaigns } from './campaigns.js';\nimport { Contacts } from './contacts.js';\nimport { Lists } from './lists.js';\nimport { Sms } from './sms.js';\nimport type { DevelEmailConfig } from './types.js';\n\nexport class DevelEmail {\n readonly emails: Emails;\n readonly domains: Domains;\n readonly templates: Templates;\n readonly campaigns: Campaigns;\n readonly contacts: Contacts;\n readonly lists: Lists;\n readonly sms: Sms;\n\n constructor(config: DevelEmailConfig) {\n const http = new HttpClient(config);\n this.emails = new Emails(http);\n this.domains = new Domains(http);\n this.templates = new Templates(http);\n this.campaigns = new Campaigns(http);\n this.contacts = new Contacts(http);\n this.lists = new Lists(http);\n this.sms = new Sms(http);\n }\n}\n\nexport { DevelEmailError } from './errors.js';\nexport { verifyWebhookSignature } from './webhook.js';\nexport { EMAIL_STATUSES, EMAIL_EVENT_TYPES, SMS_STATUSES } from './types.js';\nexport type {\n DevelEmailConfig,\n SendEmailInput,\n AttachmentInput,\n WireAttachmentInput,\n SendOptions,\n EmailResponse,\n EmailStatus,\n EmailEventType,\n DeliveryEventData,\n BatchEmailResultItem,\n BatchEmailResponse,\n Domain,\n DomainCreateInput,\n Template,\n TemplateCreateInput,\n TemplateUpdateInput,\n WebhookEvent,\n CampaignStatus,\n Campaign,\n CampaignListQuery,\n CampaignCreateInput,\n CampaignUpdateInput,\n CampaignStats,\n CampaignProviderStats,\n Contact,\n ContactListQuery,\n ContactListResponse,\n ContactCreateInput,\n ContactUpdateInput,\n ContactBulkContactInput,\n ContactBulkInput,\n ContactBulkResponse,\n ContactListItem,\n List,\n ListWithCount,\n ListCreateInput,\n ListUpdateInput,\n ListMembersQuery,\n ListMembersResponse,\n SmsStatus,\n SendSmsInput,\n SmsMessageResponse,\n SmsListResponse,\n SmsListQuery,\n} from './types.js';\n"],"mappings":"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","names":["toQueryString","toQueryString","toQueryString"]}
|
package/package.json
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@develemail/sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Node.js/TypeScript client SDK for the DevelEmail transactional email API",
|
|
4
5
|
"type": "module",
|
|
6
|
+
"license": "MIT",
|
|
5
7
|
"exports": {
|
|
6
8
|
".": {
|
|
7
9
|
"types": "./dist/index.d.ts",
|
|
@@ -11,8 +13,22 @@
|
|
|
11
13
|
},
|
|
12
14
|
"main": "./dist/index.cjs",
|
|
13
15
|
"types": "./dist/index.d.ts",
|
|
14
|
-
"files": [
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
15
19
|
"scripts": {
|
|
16
20
|
"build": "tsup"
|
|
17
|
-
}
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@develemail/core": "workspace:*"
|
|
24
|
+
},
|
|
25
|
+
"engines": {
|
|
26
|
+
"node": ">=18"
|
|
27
|
+
},
|
|
28
|
+
"keywords": [
|
|
29
|
+
"develemail",
|
|
30
|
+
"email",
|
|
31
|
+
"transactional",
|
|
32
|
+
"sdk"
|
|
33
|
+
]
|
|
18
34
|
}
|