UNPKG

sendrly

Version:

Official Sendrly TypeScript/JavaScript SDK - Simple, type-safe email automation for developers

321 lines (320 loc) 15 kB
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) { if (kind === "m") throw new TypeError("Private method is not writable"); if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it"); return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value; }; var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) { if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter"); if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it"); return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver); }; var _Sendrly_instances, _Sendrly_apiKey, _Sendrly_debug, _Sendrly_baseUrl, _Sendrly_timeout, _Sendrly_maxRetries, _Sendrly_fetch, _Sendrly_logger, _Sendrly_log, _Sendrly_logError, _Sendrly_makeRequest; import { validatePayload } from './validation'; import { SendrlyError } from './types'; import { ZodError } from 'zod'; const DEFAULT_BASE_URL = 'https://stebgknkomdhjikpcytk.supabase.co/functions/v1'; const DEFAULT_TIMEOUT = 10000; const DEFAULT_MAX_RETRIES = 3; const DEFAULT_LOGGER = { debug: console.log, error: console.error }; /** * Main Sendrly SDK class for tracking events and managing contacts * @example * // Basic usage - just API key * const sendrly = new Sendrly('your_api_key') * * // Send an event with minimal config * await sendrly.sendEvent({ * contact: { * email: 'user@example.com' * }, * event: { * name: 'signup.completed' * } * }) * * // Advanced usage with full config * const sendrly = new Sendrly({ * apiKey: 'your_api_key', * debug: true, * timeout: 5000 * }) */ export class Sendrly { constructor(config) { _Sendrly_instances.add(this); _Sendrly_apiKey.set(this, void 0); _Sendrly_debug.set(this, void 0); _Sendrly_baseUrl.set(this, void 0); _Sendrly_timeout.set(this, void 0); _Sendrly_maxRetries.set(this, void 0); _Sendrly_fetch.set(this, void 0); _Sendrly_logger.set(this, void 0); // Handle string constructor for simple API key usage if (typeof config === 'string') { __classPrivateFieldSet(this, _Sendrly_apiKey, config, "f"); __classPrivateFieldSet(this, _Sendrly_debug, false, "f"); __classPrivateFieldSet(this, _Sendrly_baseUrl, DEFAULT_BASE_URL, "f"); __classPrivateFieldSet(this, _Sendrly_timeout, DEFAULT_TIMEOUT, "f"); __classPrivateFieldSet(this, _Sendrly_maxRetries, DEFAULT_MAX_RETRIES, "f"); __classPrivateFieldSet(this, _Sendrly_fetch, typeof window !== 'undefined' ? window.fetch.bind(window) : fetch, "f"); __classPrivateFieldSet(this, _Sendrly_logger, DEFAULT_LOGGER, "f"); } else { __classPrivateFieldSet(this, _Sendrly_apiKey, config.apiKey, "f"); __classPrivateFieldSet(this, _Sendrly_debug, config.debug ?? false, "f"); __classPrivateFieldSet(this, _Sendrly_baseUrl, config.baseUrl ?? DEFAULT_BASE_URL, "f"); __classPrivateFieldSet(this, _Sendrly_timeout, config.timeout ?? DEFAULT_TIMEOUT, "f"); __classPrivateFieldSet(this, _Sendrly_maxRetries, config.maxRetries ?? DEFAULT_MAX_RETRIES, "f"); __classPrivateFieldSet(this, _Sendrly_fetch, config.fetch ?? (typeof window !== 'undefined' ? window.fetch.bind(window) : fetch), "f"); __classPrivateFieldSet(this, _Sendrly_logger, config.logger ?? DEFAULT_LOGGER, "f"); } if (__classPrivateFieldGet(this, _Sendrly_debug, "f")) { __classPrivateFieldGet(this, _Sendrly_instances, "m", _Sendrly_log).call(this, 'Initialized with config:', { apiKey: __classPrivateFieldGet(this, _Sendrly_apiKey, "f"), debug: __classPrivateFieldGet(this, _Sendrly_debug, "f"), baseUrl: __classPrivateFieldGet(this, _Sendrly_baseUrl, "f"), timeout: __classPrivateFieldGet(this, _Sendrly_timeout, "f"), maxRetries: __classPrivateFieldGet(this, _Sendrly_maxRetries, "f") }); } if (!__classPrivateFieldGet(this, _Sendrly_apiKey, "f")) { throw new SendrlyError('API key is required', 'INVALID_CONFIG'); } } /** * Send an event for a contact * @example * // Minimal usage * await sendrly.sendEvent({ * contact: { * email: 'user@example.com' * }, * event: { * name: 'signup.completed' * } * }) * * // Full usage with all options * await sendrly.sendEvent({ * contact: { * email: 'sarah@startup.com', * marketing_opt_out: false, * properties: { * name: 'Sarah', * company: 'Startup Inc' * } * }, * event: { * name: 'user.welcome', * properties: { * source: 'signup', * referral: 'google' * } * } * }) */ async sendEvent(payload) { try { __classPrivateFieldGet(this, _Sendrly_instances, "m", _Sendrly_log).call(this, 'Sending event with payload:', payload); const validatedPayload = validatePayload(payload); __classPrivateFieldGet(this, _Sendrly_instances, "m", _Sendrly_log).call(this, 'Payload validated successfully:', validatedPayload); const response = await __classPrivateFieldGet(this, _Sendrly_instances, "m", _Sendrly_makeRequest).call(this, '/event', { method: 'POST', body: JSON.stringify(validatedPayload) }); const data = await response.json(); if (!response.ok || !data.success) { throw new SendrlyError(data.error || 'Failed to send event', 'API_ERROR', response.status); } __classPrivateFieldGet(this, _Sendrly_instances, "m", _Sendrly_log).call(this, 'Event sent successfully:', payload); } catch (error) { __classPrivateFieldGet(this, _Sendrly_instances, "m", _Sendrly_logError).call(this, 'Error sending event:', error); if (error instanceof SendrlyError || error instanceof ZodError) { throw error; } throw new SendrlyError(error instanceof Error ? error.message : 'An unknown error occurred', 'UNKNOWN_ERROR'); } } /** * Get a contact by email address * @example * // Get contact details * const contact = await sendrly.getContact('sarah@startup.com') * console.log(contact.properties.name) // 'Sarah' * * // Handle non-existent contact * try { * const contact = await sendrly.getContact('unknown@email.com') * } catch (error) { * if (error.code === 'NOT_FOUND') { * console.log('Contact does not exist') * } * } */ async getContact(email) { try { __classPrivateFieldGet(this, _Sendrly_instances, "m", _Sendrly_log).call(this, 'Getting contact:', email); const response = await fetch(`${__classPrivateFieldGet(this, _Sendrly_baseUrl, "f")}/find-contact?email=${encodeURIComponent(email)}`, { method: 'GET', headers: { 'Content-Type': 'application/json', apikey: __classPrivateFieldGet(this, _Sendrly_apiKey, "f") } }); const data = await response.json(); if (!response.ok || !data.success) { throw new SendrlyError(data.error || 'Failed to get contact', response.status === 404 ? 'NOT_FOUND' : response.status === 401 ? 'INVALID_API_KEY' : 'API_ERROR'); } return data.contact; } catch (error) { __classPrivateFieldGet(this, _Sendrly_instances, "m", _Sendrly_log).call(this, 'Error getting contact:', error); if (error instanceof SendrlyError) { throw error; } throw new SendrlyError(error instanceof Error ? error.message : 'An unknown error occurred', 'UNKNOWN_ERROR'); } } /** * List all events with a specific name * @example * // List all signup events * const signups = await sendrly.listEvents('user.signup') * console.log(signups[0].event_properties.source) * * // Process completed orders * const orders = await sendrly.listEvents('order.completed') * const totalRevenue = orders.reduce((sum, order) => * sum + order.event_properties.amount, 0 * ) */ async listEvents(eventName) { try { __classPrivateFieldGet(this, _Sendrly_instances, "m", _Sendrly_log).call(this, 'Listing events:', eventName); const response = await fetch(`${__classPrivateFieldGet(this, _Sendrly_baseUrl, "f")}/get-event?event=${encodeURIComponent(eventName)}`, { method: 'GET', headers: { 'Content-Type': 'application/json', apikey: __classPrivateFieldGet(this, _Sendrly_apiKey, "f") } }); const data = await response.json(); if (!response.ok || !data.success) { throw new SendrlyError(data.error || 'Failed to list events', response.status === 401 ? 'INVALID_API_KEY' : 'API_ERROR'); } return data.events; } catch (error) { __classPrivateFieldGet(this, _Sendrly_instances, "m", _Sendrly_log).call(this, 'Error listing events:', error); if (error instanceof SendrlyError) { throw error; } throw new SendrlyError(error instanceof Error ? error.message : 'An unknown error occurred', 'UNKNOWN_ERROR'); } } /** * Delete a contact and all associated data * @example * // Delete a contact * await sendrly.deleteContact('sarah@startup.com') * * // Handle non-existent contact * try { * await sendrly.deleteContact('unknown@email.com') * } catch (error) { * if (error.code === 'NOT_FOUND') { * console.log('Contact already deleted') * } * } */ async deleteContact(email) { try { __classPrivateFieldGet(this, _Sendrly_instances, "m", _Sendrly_log).call(this, 'Deleting contact:', email); const response = await fetch(`${__classPrivateFieldGet(this, _Sendrly_baseUrl, "f")}/delete-contact?email=${encodeURIComponent(email)}`, { method: 'DELETE', headers: { 'Content-Type': 'application/json', apikey: __classPrivateFieldGet(this, _Sendrly_apiKey, "f") } }); const data = await response.json(); if (!response.ok || !data.success) { throw new SendrlyError(data.error || 'Failed to delete contact', response.status === 404 ? 'NOT_FOUND' : response.status === 401 ? 'INVALID_API_KEY' : 'API_ERROR'); } __classPrivateFieldGet(this, _Sendrly_instances, "m", _Sendrly_log).call(this, 'Contact deleted successfully'); } catch (error) { __classPrivateFieldGet(this, _Sendrly_instances, "m", _Sendrly_log).call(this, 'Error deleting contact:', error); if (error instanceof SendrlyError) { throw error; } throw new SendrlyError(error instanceof Error ? error.message : 'An unknown error occurred', 'UNKNOWN_ERROR'); } } } _Sendrly_apiKey = new WeakMap(), _Sendrly_debug = new WeakMap(), _Sendrly_baseUrl = new WeakMap(), _Sendrly_timeout = new WeakMap(), _Sendrly_maxRetries = new WeakMap(), _Sendrly_fetch = new WeakMap(), _Sendrly_logger = new WeakMap(), _Sendrly_instances = new WeakSet(), _Sendrly_log = function _Sendrly_log(message, data) { if (__classPrivateFieldGet(this, _Sendrly_debug, "f")) { __classPrivateFieldGet(this, _Sendrly_logger, "f").debug(`[Sendrly] ${message}`, data); } }, _Sendrly_logError = function _Sendrly_logError(message, error) { if (__classPrivateFieldGet(this, _Sendrly_debug, "f")) { __classPrivateFieldGet(this, _Sendrly_logger, "f").error(`[Sendrly] ${message}`, error); } }, _Sendrly_makeRequest = /** * Makes an API request with retry logic and timeout */ async function _Sendrly_makeRequest(endpoint, options, retryCount = 0) { const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), __classPrivateFieldGet(this, _Sendrly_timeout, "f")); try { const response = await __classPrivateFieldGet(this, _Sendrly_fetch, "f").call(this, `${__classPrivateFieldGet(this, _Sendrly_baseUrl, "f")}${endpoint}`, { ...options, signal: controller.signal, headers: { 'Content-Type': 'application/json', apikey: __classPrivateFieldGet(this, _Sendrly_apiKey, "f"), ...options.headers } }); if (!response.ok && retryCount < __classPrivateFieldGet(this, _Sendrly_maxRetries, "f")) { const error = new SendrlyError('Request failed', 'API_ERROR', response.status); if (error.retryable) { const delay = Math.min(1000 * 2 ** retryCount, 10000); await new Promise((resolve) => setTimeout(resolve, delay)); return __classPrivateFieldGet(this, _Sendrly_instances, "m", _Sendrly_makeRequest).call(this, endpoint, options, retryCount + 1); } } return response; } catch (error) { if (error instanceof Error && error.name === 'AbortError') { throw new SendrlyError('Request timed out', 'TIMEOUT_ERROR'); } if (retryCount < __classPrivateFieldGet(this, _Sendrly_maxRetries, "f")) { const delay = Math.min(1000 * 2 ** retryCount, 10000); await new Promise((resolve) => setTimeout(resolve, delay)); return __classPrivateFieldGet(this, _Sendrly_instances, "m", _Sendrly_makeRequest).call(this, endpoint, options, retryCount + 1); } throw new SendrlyError('Network request failed', 'NETWORK_ERROR'); } finally { clearTimeout(timeoutId); } }; // Default export for easier importing export default Sendrly;