@hipnation-truth/sdk 0.1.1 → 0.1.3

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/index.d.mts CHANGED
@@ -251,7 +251,7 @@ declare class EhrProviderProxy {
251
251
  * @param path — path relative to the provider root (e.g., "/patients/123/")
252
252
  * @param params — optional query parameters
253
253
  */
254
- get<T = unknown>(path: string, params?: Record<string, string | number | boolean | undefined>): Promise<T>;
254
+ get<T = unknown>(path: string, params?: Record<string, unknown>): Promise<T>;
255
255
  /**
256
256
  * POST request to the EHR proxy.
257
257
  */
package/dist/index.d.ts CHANGED
@@ -251,7 +251,7 @@ declare class EhrProviderProxy {
251
251
  * @param path — path relative to the provider root (e.g., "/patients/123/")
252
252
  * @param params — optional query parameters
253
253
  */
254
- get<T = unknown>(path: string, params?: Record<string, string | number | boolean | undefined>): Promise<T>;
254
+ get<T = unknown>(path: string, params?: Record<string, unknown>): Promise<T>;
255
255
  /**
256
256
  * POST request to the EHR proxy.
257
257
  */
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/resources/appointments.ts","../src/resources/dialpad.ts","../src/resources/ehr.ts","../src/resources/patients.ts","../src/tracking/tracker.ts","../src/tracking/events.ts","../src/types/config.ts"],"sourcesContent":["/**\n * @hipnation-truth/sdk\n *\n * HIPnation Truth Platform SDK. Provides resource-based data access\n * (patients, appointments) backed by Convex, and fire-and-forget event\n * tracking to the Truth API.\n *\n * @example\n * ```ts\n * import { TruthClient } from '@hipnation-truth/sdk';\n *\n * const truth = new TruthClient({\n * apiKey: 'hn_live_...',\n * environment: 'production',\n * source: 'communication-hub.backend',\n * sourceVersion: 'git:abcd1234',\n * tenantId: 'org_123',\n * });\n *\n * // Data access\n * const patient = await truth.patients.get('patient_123');\n * const appointments = await truth.appointments.list({ patientId: 'patient_123' });\n *\n * // Event tracking\n * truth.identify('user_456', 'user');\n * truth.track('conversation.message_sent.v1', {\n * channel: 'sms',\n * direction: 'outbound',\n * message_chars: 140,\n * has_attachment: false,\n * provider_system: 'dialpad',\n * });\n *\n * // Graceful shutdown\n * await truth.flush();\n * ```\n */\n\n// Client\nexport { TruthClient } from \"./client\";\n// Resources — Data (Convex)\nexport { AppointmentResource } from \"./resources/appointments\";\nexport type {\n CallStatusResponse,\n DialpadNumberInfo,\n DialpadUser,\n InitiateCallResponse,\n SendSmsParams,\n SendSmsResponse,\n VoicemailAuthResponse,\n} from \"./resources/dialpad\";\n// Resources — Messages Proxy\nexport {\n DialpadProxyError,\n DialpadResource,\n MessagesResource,\n} from \"./resources/dialpad\";\n// Resources — EHR Proxy\nexport { EhrProviderProxy, EhrProxyError, EhrResource } from \"./resources/ehr\";\nexport { PatientResource } from \"./resources/patients\";\nexport type {\n AuthEventType,\n AuthLoginFailedPayload,\n AuthLoginSucceededPayload,\n CallConnectedPayload,\n CallEndedPayload,\n CallEventType,\n CallInitiatedPayload,\n CallMissedPayload,\n ConversationAttachmentDownloadedPayload,\n ConversationAttachmentUploadedPayload,\n ConversationCreatedPayload,\n ConversationEventType,\n ConversationMarkedReadPayload,\n ConversationMessageReceivedPayload,\n ConversationMessageSentPayload,\n EventActor,\n EventCompliance,\n EventEnvelope,\n EventPayloadMap,\n EventSubject,\n EventType,\n NotificationDeliveredPayload,\n NotificationEventType,\n NotificationOpenedPayload,\n NotificationSentPayload,\n ProviderEventType,\n ProviderSyncFailedPayload,\n ProviderSyncStartedPayload,\n ProviderSyncSucceededPayload,\n ReminderEventType,\n ReminderScheduledPayload,\n ReminderTriggeredPayload,\n SecurityAccessDeniedPayload,\n SecurityEventType,\n TaskAssignedPayload,\n TaskCreatedPayload,\n TaskEventType,\n TaskStatusChangedPayload,\n TrackOptions,\n TranslationCompletedPayload,\n TranslationEventType,\n TranslationRequestedPayload,\n} from \"./tracking/events\";\nexport {\n AUTH_EVENTS,\n CALL_EVENTS,\n CONVERSATION_EVENTS,\n EVENT_TYPES,\n NOTIFICATION_EVENTS,\n PROVIDER_EVENTS,\n REMINDER_EVENTS,\n SECURITY_EVENTS,\n TASK_EVENTS,\n TRANSLATION_EVENTS,\n} from \"./tracking/events\";\n// Tracking\nexport { generateUuidV7, Tracker } from \"./tracking/tracker\";\nexport type { Appointment, AppointmentListOptions } from \"./types/appointment\";\nexport type {\n ActorContext,\n Environment,\n PaginatedResult,\n TruthClientConfig,\n} from \"./types/config\";\n// Types\nexport { ENVIRONMENTS } from \"./types/config\";\nexport type { Patient, PatientListOptions } from \"./types/patient\";\n","/**\n * TruthClient -- main entry point for the @hipnation-truth/sdk package.\n *\n * Provides:\n * - `.patients` Resource-based patient data access (Convex-backed)\n * - `.appointments` Resource-based appointment data access (Convex-backed)\n * - `.ehr` EHR proxy access (Elation, Hint)\n * - `.messages` Messaging proxy access (Dialpad)\n * - `.track()` Fire-and-forget event tracking (batched HTTP -> Truth API)\n * - `.identify()` Set default actor context for subsequent events\n * - `.flush()` Force flush of buffered events (for graceful shutdown)\n */\n\nimport { ConvexHttpClient } from \"convex/browser\";\nimport { AppointmentResource } from \"./resources/appointments\";\nimport { MessagesResource } from \"./resources/dialpad\";\nimport { EhrResource } from \"./resources/ehr\";\nimport { PatientResource } from \"./resources/patients\";\nimport type {\n EventPayloadMap,\n EventType,\n TrackOptions,\n} from \"./tracking/events\";\nimport {\n DEFAULT_BATCH_SIZE,\n DEFAULT_FLUSH_INTERVAL_MS,\n Tracker,\n} from \"./tracking/tracker\";\nimport type { ActorContext, TruthClientConfig } from \"./types/config\";\n\n// ---------------------------------------------------------------------------\n// Environment -> Convex URL mapping\n// ---------------------------------------------------------------------------\n\nconst CONVEX_URLS: Record<string, string> = {\n local: \"http://localhost:3210\",\n staging: \"https://staging-truth.convex.cloud\",\n uat: \"https://uat-truth.convex.cloud\",\n production: \"https://truth.convex.cloud\",\n};\n\n// ---------------------------------------------------------------------------\n// TruthClient\n// ---------------------------------------------------------------------------\n\nclass TruthClient {\n /** Patient data resource (Convex-backed) */\n readonly patients: PatientResource;\n\n /** Appointment data resource (Convex-backed) */\n readonly appointments: AppointmentResource;\n\n /** EHR proxy — typed access to Elation and Hint APIs through Truth */\n readonly ehr: EhrResource;\n\n /** Messaging proxy — typed access to Dialpad APIs through Truth */\n readonly messages: MessagesResource;\n\n private readonly convex: ConvexHttpClient;\n private readonly tracker: Tracker;\n\n constructor(config: TruthClientConfig) {\n // Resolve Convex URL\n const convexUrl =\n config.convexUrl ?? CONVEX_URLS[config.environment] ?? CONVEX_URLS.local;\n\n // Initialize Convex HTTP client for data access\n this.convex = new ConvexHttpClient(convexUrl);\n\n // Initialize event tracker\n this.tracker = new Tracker({\n apiKey: config.apiKey,\n environment: config.environment,\n source: config.source ?? \"unknown\",\n sourceVersion: config.sourceVersion ?? \"unknown\",\n tenantId: config.tenantId ?? \"\",\n batchSize: config.batchSize ?? DEFAULT_BATCH_SIZE,\n flushIntervalMs: config.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS,\n apiBaseUrl: config.apiBaseUrl,\n });\n\n const apiUrl = this.tracker.apiUrl;\n\n // Initialize resources\n this.patients = new PatientResource(this.convex);\n this.appointments = new AppointmentResource(this.convex);\n this.ehr = new EhrResource(apiUrl);\n this.messages = new MessagesResource(apiUrl);\n }\n\n /**\n * The resolved Truth API base URL for this environment.\n * Use this when making HTTP calls to Truth's proxy endpoints\n * (e.g., EHR proxy, messages proxy).\n *\n * @example\n * ```ts\n * const url = `${truth.apiBaseUrl}/api/ehr/elation/patients/123`;\n * ```\n */\n get apiBaseUrl(): string {\n return this.tracker.apiUrl;\n }\n\n /**\n * Track an event. Fire-and-forget -- the event is buffered internally\n * and flushed in batches to the Truth API.\n *\n * @example\n * ```ts\n * truth.track('conversation.message_sent.v1', {\n * channel: 'sms',\n * direction: 'outbound',\n * message_chars: 140,\n * has_attachment: false,\n * provider_system: 'dialpad',\n * });\n * ```\n */\n track<T extends EventType>(\n eventType: T,\n payload: EventPayloadMap[T],\n options?: TrackOptions,\n ): void {\n this.tracker.track(eventType, payload, options);\n }\n\n /**\n * Set the default actor context for all subsequent tracked events.\n * Can be overridden per-event via TrackOptions.\n *\n * @example\n * ```ts\n * truth.identify('user_123', 'user');\n * ```\n */\n identify(actorId: string, actorType: ActorContext[\"actorType\"]): void {\n this.tracker.setActor({ actorId, actorType });\n }\n\n /**\n * Flush all buffered events immediately. Returns a Promise that resolves\n * when the flush completes. Use this for graceful shutdown.\n *\n * @example\n * ```ts\n * process.on('SIGTERM', async () => {\n * await truth.flush();\n * process.exit(0);\n * });\n * ```\n */\n async flush(): Promise<void> {\n await this.tracker.flush();\n }\n\n /**\n * Gracefully shut down the client. Flushes all pending events and\n * releases resources.\n */\n async destroy(): Promise<void> {\n await this.tracker.shutdown();\n }\n}\n\nexport { TruthClient };\n","/**\n * AppointmentResource provides data access to normalized appointment records\n * backed by Convex.\n */\n\nimport type { ConvexHttpClient } from \"convex/browser\";\nimport type { Appointment, AppointmentListOptions } from \"../types/appointment\";\nimport type { PaginatedResult } from \"../types/config\";\n\nclass AppointmentResource {\n private readonly convex: ConvexHttpClient;\n\n constructor(convexClient: ConvexHttpClient) {\n this.convex = convexClient;\n }\n\n /**\n * Get an appointment by its Truth platform ID.\n */\n async get(id: string): Promise<Appointment | null> {\n try {\n const result = await this.convex.query(\n \"appointments:getById\" as never,\n { id } as never,\n );\n return (result as Appointment) ?? null;\n } catch {\n return null;\n }\n }\n\n /**\n * List appointments with optional filters, pagination, and limit.\n */\n async list(\n options?: AppointmentListOptions,\n ): Promise<PaginatedResult<Appointment>> {\n try {\n const result = await this.convex.query(\n \"appointments:list\" as never,\n {\n patientId: options?.patientId,\n startDate: options?.startDate,\n endDate: options?.endDate,\n status: options?.status,\n limit: options?.limit,\n cursor: options?.cursor,\n } as never,\n );\n\n const typed = result as PaginatedResult<Appointment> | undefined;\n\n return typed ?? { data: [], cursor: null, hasMore: false };\n } catch {\n return { data: [], cursor: null, hasMore: false };\n }\n }\n}\n\nexport { AppointmentResource };\n","/**\n * Dialpad resource — typed access to Truth's Dialpad proxy endpoints.\n *\n * @example\n * ```ts\n * const sms = await truth.messages.dialpad.sendSms({ from_number, to_number, message });\n * const call = await truth.messages.dialpad.initiateCall(userId, phoneNumber);\n * await truth.messages.dialpad.hangupCall(callId);\n * const url = await truth.messages.dialpad.authenticateVoicemail(voicemailLink);\n * ```\n */\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface SendSmsParams {\n from_number: string;\n to_number: string;\n message?: string;\n media?: string;\n}\n\ninterface SendSmsResponse {\n id: string;\n message_status: string;\n [key: string]: unknown;\n}\n\ninterface InitiateCallResponse {\n call_id: number;\n [key: string]: unknown;\n}\n\ninterface CallStatusResponse {\n state: string;\n [key: string]: unknown;\n}\n\ninterface DialpadUser {\n id: number;\n emails: string[];\n first_name?: string;\n last_name?: string;\n [key: string]: unknown;\n}\n\ninterface DialpadUserListResponse {\n items: DialpadUser[];\n}\n\ninterface DialpadNumberInfo {\n user_id?: number;\n type?: string;\n [key: string]: unknown;\n}\n\ninterface VoicemailAuthResponse {\n success: boolean;\n authenticated_url: string | null;\n error?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Dialpad Resource\n// ---------------------------------------------------------------------------\n\nclass DialpadResource {\n private readonly baseUrl: string;\n\n constructor(apiBaseUrl: string) {\n this.baseUrl = apiBaseUrl;\n }\n\n /**\n * Send an SMS or MMS message via Dialpad.\n */\n async sendSms(params: SendSmsParams): Promise<SendSmsResponse> {\n const body = {\n to_numbers: [params.to_number],\n from_number: params.from_number,\n infer_country_code: false,\n ...(params.message ? { text: params.message } : {}),\n ...(params.media ? { media: params.media } : {}),\n };\n\n return this.post<SendSmsResponse>(\"/sms\", body);\n }\n\n /**\n * Initiate an outbound call from a Dialpad user to a phone number.\n */\n async initiateCall(\n userId: number,\n phoneNumber: string,\n ): Promise<InitiateCallResponse> {\n return this.post<InitiateCallResponse>(`/users/${userId}/initiate_call`, {\n phone_number: phoneNumber,\n });\n }\n\n /**\n * Hang up an active call.\n */\n async hangupCall(callId: number): Promise<void> {\n await this.put(`/call/${callId}/actions/hangup`);\n }\n\n /**\n * Get the status of a call.\n */\n async getCallStatus(callId: number): Promise<CallStatusResponse | null> {\n try {\n return await this.get<CallStatusResponse>(`/call/${callId}`);\n } catch (error) {\n if (error instanceof DialpadProxyError && error.status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Get a Dialpad user by their user ID.\n */\n async getUser(userId: string | number): Promise<DialpadUser | null> {\n try {\n return await this.get<DialpadUser>(`/users/${userId}`);\n } catch (error) {\n if (error instanceof DialpadProxyError && error.status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Find a Dialpad user by email.\n */\n async getUserByEmail(email: string): Promise<DialpadUser | null> {\n const result = await this.get<DialpadUserListResponse>(\"/users\", {\n email,\n });\n return result.items?.[0] ?? null;\n }\n\n /**\n * Find a Dialpad user by phone number.\n */\n async getUserByPhoneNumber(phoneNumber: string): Promise<DialpadUser | null> {\n const result = await this.get<DialpadUserListResponse>(\"/users\", {\n number: phoneNumber,\n });\n return result.items?.[0] ?? null;\n }\n\n /**\n * Get information about a Dialpad phone number.\n */\n async getNumberInfo(phoneNumber: string): Promise<DialpadNumberInfo | null> {\n try {\n const cleanNumber = phoneNumber.replace(/[^\\d+]/g, \"\");\n return await this.get<DialpadNumberInfo>(\n `/numbers/${encodeURIComponent(cleanNumber)}`,\n );\n } catch (error) {\n if (error instanceof DialpadProxyError && error.status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Authenticate a voicemail download URL. Truth appends the Dialpad API key,\n * follows redirects, and returns the clean URL for client-side playback.\n */\n async authenticateVoicemail(voicemailLink: string): Promise<string | null> {\n const url = `${this.baseUrl}/api/messages/dialpad/voicemail/authenticate`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ voicemail_link: voicemailLink }),\n });\n\n const result = (await response.json()) as VoicemailAuthResponse;\n\n if (!response.ok || !result.success) {\n return null;\n }\n\n return result.authenticated_url;\n }\n\n // -----------------------------------------------------------------------\n // Internal HTTP helpers\n // -----------------------------------------------------------------------\n\n private async get<T>(\n path: string,\n params?: Record<string, string | number | boolean | undefined>,\n ): Promise<T> {\n const url = new URL(`/api/messages/dialpad${path}`, this.baseUrl);\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n const response = await fetch(url.toString(), {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n });\n\n if (!response.ok) {\n throw new DialpadProxyError(\"GET\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n private async post<T>(path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}/api/messages/dialpad${path}`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n throw new DialpadProxyError(\"POST\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n private async put<T = void>(path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}/api/messages/dialpad${path}`;\n\n const response = await fetch(url, {\n method: \"PUT\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n throw new DialpadProxyError(\"PUT\", path, response.status);\n }\n\n if (response.headers.get(\"content-type\")?.includes(\"json\")) {\n return (await response.json()) as T;\n }\n\n return undefined as T;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Messages Resource — namespace for messaging providers\n// ---------------------------------------------------------------------------\n\nclass MessagesResource {\n readonly dialpad: DialpadResource;\n\n constructor(apiBaseUrl: string) {\n this.dialpad = new DialpadResource(apiBaseUrl);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Error\n// ---------------------------------------------------------------------------\n\nclass DialpadProxyError extends Error {\n readonly method: string;\n readonly path: string;\n readonly status: number;\n\n constructor(method: string, path: string, status: number) {\n super(\n `Dialpad proxy error: ${method} /api/messages/dialpad${path} returned ${status}`,\n );\n this.name = \"DialpadProxyError\";\n this.method = method;\n this.path = path;\n this.status = status;\n }\n}\n\nexport { DialpadResource, DialpadProxyError, MessagesResource };\nexport type {\n SendSmsParams,\n SendSmsResponse,\n InitiateCallResponse,\n CallStatusResponse,\n DialpadUser,\n DialpadNumberInfo,\n VoicemailAuthResponse,\n};\n","/**\n * EHR proxy resource — typed access to Truth's EHR proxy endpoints.\n *\n * Provides per-provider proxy methods so consumers never construct\n * proxy URLs manually.\n *\n * @example\n * ```ts\n * const patient = await truth.ehr.elation.get('/patients/123/');\n * const notes = await truth.ehr.elation.post('/non_visit_notes/', noteData);\n * const hintPatient = await truth.ehr.hint.get('/provider/patients/456');\n * ```\n */\n\n// ---------------------------------------------------------------------------\n// Provider proxy\n// ---------------------------------------------------------------------------\n\nclass EhrProviderProxy {\n private readonly baseUrl: string;\n private readonly provider: string;\n\n constructor(apiBaseUrl: string, provider: string) {\n this.baseUrl = apiBaseUrl;\n this.provider = provider;\n }\n\n /**\n * GET request to the EHR proxy.\n * @param path — path relative to the provider root (e.g., \"/patients/123/\")\n * @param params — optional query parameters\n */\n async get<T = unknown>(\n path: string,\n params?: Record<string, string | number | boolean | undefined>,\n ): Promise<T> {\n const url = new URL(`/api/ehr/${this.provider}${path}`, this.baseUrl);\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n const response = await fetch(url.toString(), {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n });\n\n if (!response.ok) {\n throw new EhrProxyError(this.provider, \"GET\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n /**\n * POST request to the EHR proxy.\n */\n async post<T = unknown>(path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}/api/ehr/${this.provider}${path}`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n throw new EhrProxyError(this.provider, \"POST\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n /**\n * PUT request to the EHR proxy.\n */\n async put<T = unknown>(path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}/api/ehr/${this.provider}${path}`;\n\n const response = await fetch(url, {\n method: \"PUT\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n throw new EhrProxyError(this.provider, \"PUT\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n /**\n * PATCH request to the EHR proxy.\n */\n async patch<T = unknown>(path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}/api/ehr/${this.provider}${path}`;\n\n const response = await fetch(url, {\n method: \"PATCH\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n throw new EhrProxyError(this.provider, \"PATCH\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n /**\n * DELETE request to the EHR proxy.\n */\n async delete<T = unknown>(path: string): Promise<T> {\n const url = `${this.baseUrl}/api/ehr/${this.provider}${path}`;\n\n const response = await fetch(url, {\n method: \"DELETE\",\n headers: { Accept: \"application/json\" },\n });\n\n if (!response.ok) {\n throw new EhrProxyError(this.provider, \"DELETE\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n}\n\n// ---------------------------------------------------------------------------\n// EHR Resource — exposes per-provider proxies\n// ---------------------------------------------------------------------------\n\nclass EhrResource {\n /** Elation EHR proxy */\n readonly elation: EhrProviderProxy;\n\n /** Hint Health proxy */\n readonly hint: EhrProviderProxy;\n\n constructor(apiBaseUrl: string) {\n this.elation = new EhrProviderProxy(apiBaseUrl, \"elation\");\n this.hint = new EhrProviderProxy(apiBaseUrl, \"hint\");\n }\n}\n\n// ---------------------------------------------------------------------------\n// Error\n// ---------------------------------------------------------------------------\n\nclass EhrProxyError extends Error {\n readonly provider: string;\n readonly method: string;\n readonly path: string;\n readonly status: number;\n\n constructor(provider: string, method: string, path: string, status: number) {\n super(\n `EHR proxy error: ${method} /api/ehr/${provider}${path} returned ${status}`,\n );\n this.name = \"EhrProxyError\";\n this.provider = provider;\n this.method = method;\n this.path = path;\n this.status = status;\n }\n}\n\nexport { EhrResource, EhrProviderProxy, EhrProxyError };\n","/**\n * PatientResource provides data access to normalized patient records\n * backed by Convex.\n */\n\nimport type { ConvexHttpClient } from \"convex/browser\";\nimport type { PaginatedResult } from \"../types/config\";\nimport type { Patient, PatientListOptions } from \"../types/patient\";\n\nclass PatientResource {\n private readonly convex: ConvexHttpClient;\n\n constructor(convexClient: ConvexHttpClient) {\n this.convex = convexClient;\n }\n\n /**\n * Get a patient by their Truth platform ID.\n */\n async get(id: string): Promise<Patient | null> {\n try {\n const result = await this.convex.query(\n \"patients:getById\" as never,\n {\n id,\n } as never,\n );\n return (result as Patient) ?? null;\n } catch {\n return null;\n }\n }\n\n /**\n * Get a patient by their Elation EHR ID.\n */\n async getByElationId(elationId: string): Promise<Patient | null> {\n try {\n const result = await this.convex.query(\n \"patients:getByElationId\" as never,\n { elationId } as never,\n );\n return (result as Patient) ?? null;\n } catch {\n return null;\n }\n }\n\n /**\n * Get a patient by their Hint EHR ID.\n */\n async getByHintId(hintId: string): Promise<Patient | null> {\n try {\n const result = await this.convex.query(\n \"patients:getByHintId\" as never,\n {\n hintId,\n } as never,\n );\n return (result as Patient) ?? null;\n } catch {\n return null;\n }\n }\n\n /**\n * List patients with optional search, pagination, and limit.\n */\n async list(options?: PatientListOptions): Promise<PaginatedResult<Patient>> {\n try {\n const result = await this.convex.query(\n \"patients:list\" as never,\n {\n search: options?.search,\n limit: options?.limit,\n cursor: options?.cursor,\n } as never,\n );\n\n const typed = result as PaginatedResult<Patient> | undefined;\n\n return typed ?? { data: [], cursor: null, hasMore: false };\n } catch {\n return { data: [], cursor: null, hasMore: false };\n }\n }\n}\n\nexport { PatientResource };\n","/**\n * Event tracker with batching, retry, and flush support.\n *\n * Buffers events in an internal queue and flushes them to the Truth API\n * endpoint. Flushes occur when the buffer reaches `batchSize` or every\n * `flushIntervalMs` milliseconds, whichever comes first.\n */\n\nimport type { ActorContext } from \"../types/config\";\nimport type {\n EventEnvelope,\n EventPayloadMap,\n EventType,\n TrackOptions,\n} from \"./events\";\n\n// ---------------------------------------------------------------------------\n// UUID v7 helper (no external dependency)\n// ---------------------------------------------------------------------------\n\n/**\n * Generates a UUID v7 string. Uses crypto.randomUUID where available,\n * falling back to a timestamp + random bytes implementation.\n *\n * UUID v7 layout (RFC 9562):\n * 48 bits - unix timestamp (ms)\n * 4 bits - version (0b0111)\n * 12 bits - random\n * 2 bits - variant (0b10)\n * 62 bits - random\n */\nfunction generateUuidV7(): string {\n const now = Date.now();\n\n // 6 bytes of timestamp\n const timeBytes = new Uint8Array(6);\n let ts = now;\n for (let i = 5; i >= 0; i--) {\n timeBytes[i] = ts & 0xff;\n ts = Math.floor(ts / 256);\n }\n\n // 10 bytes of random\n const randomBytes = new Uint8Array(10);\n if (\n typeof globalThis.crypto !== \"undefined\" &&\n globalThis.crypto.getRandomValues\n ) {\n globalThis.crypto.getRandomValues(randomBytes);\n } else {\n for (let i = 0; i < 10; i++) {\n randomBytes[i] = Math.floor(Math.random() * 256);\n }\n }\n\n // Assemble 16 bytes\n const bytes = new Uint8Array(16);\n bytes.set(timeBytes, 0);\n bytes.set(randomBytes, 6);\n\n // Set version (bits 48-51 to 0b0111)\n bytes[6] = (bytes[6] & 0x0f) | 0x70;\n\n // Set variant (bits 64-65 to 0b10)\n bytes[8] = (bytes[8] & 0x3f) | 0x80;\n\n // Format as hex string with dashes\n const hex = Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n\n return [\n hex.slice(0, 8),\n hex.slice(8, 12),\n hex.slice(12, 16),\n hex.slice(16, 20),\n hex.slice(20, 32),\n ].join(\"-\");\n}\n\n// ---------------------------------------------------------------------------\n// Environment-based API URL resolution\n// ---------------------------------------------------------------------------\n\nconst API_URLS: Record<string, string> = {\n local: \"http://localhost:3000\",\n staging: \"https://app.sandbox.communication-hub.com\",\n sandbox: \"https://app.sandbox.communication-hub.com\",\n uat: \"https://app.sandbox.communication-hub.com\",\n production: \"https://app.truth.communication-hub.com\",\n};\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_BATCH_SIZE = 25;\nconst DEFAULT_FLUSH_INTERVAL_MS = 5_000;\nconst MAX_RETRIES = 3;\nconst BASE_RETRY_DELAY_MS = 500;\n\n// ---------------------------------------------------------------------------\n// Tracker configuration\n// ---------------------------------------------------------------------------\n\ninterface TrackerConfig {\n apiKey: string;\n environment: string;\n source: string;\n sourceVersion: string;\n tenantId: string;\n batchSize: number;\n flushIntervalMs: number;\n apiBaseUrl?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Tracker class\n// ---------------------------------------------------------------------------\n\nclass Tracker {\n private readonly config: TrackerConfig;\n readonly apiUrl: string;\n private queue: EventEnvelope[] = [];\n private flushTimer: ReturnType<typeof setInterval> | null = null;\n private defaultActor: ActorContext | undefined;\n private isFlushing = false;\n private isShutdown = false;\n\n constructor(config: TrackerConfig) {\n this.config = config;\n this.apiUrl =\n config.apiBaseUrl ?? API_URLS[config.environment] ?? API_URLS.local;\n\n this.startFlushInterval();\n this.registerShutdownHooks();\n }\n\n /**\n * Set the default actor context for subsequent events.\n */\n setActor(actor: ActorContext): void {\n this.defaultActor = actor;\n }\n\n /**\n * Enqueue a typed event for delivery. This is fire-and-forget from\n * the caller's perspective -- events are buffered and flushed in batches.\n */\n track<T extends EventType>(\n eventType: T,\n payload: EventPayloadMap[T],\n options?: TrackOptions,\n ): void {\n if (this.isShutdown) {\n return;\n }\n\n const now = new Date().toISOString();\n\n const envelope: EventEnvelope = {\n event_id: generateUuidV7(),\n event_type: eventType,\n schema_version: 1,\n occurred_at: options?.occurredAt ?? now,\n received_at: now,\n source: this.config.source,\n source_version: this.config.sourceVersion,\n tenant_id: options?.tenantId ?? this.config.tenantId,\n actor:\n options?.actor ??\n (this.defaultActor\n ? {\n actor_id: this.defaultActor.actorId,\n actor_type: this.defaultActor.actorType,\n }\n : undefined),\n subject: options?.subject,\n compliance: options?.compliance,\n payload: payload as unknown as Record<string, unknown>,\n };\n\n this.queue.push(envelope);\n\n if (this.queue.length >= this.config.batchSize) {\n void this.flush();\n }\n }\n\n /**\n * Force an immediate flush of all buffered events.\n * Returns a promise that resolves when the flush completes.\n */\n async flush(): Promise<void> {\n if (this.queue.length === 0 || this.isFlushing) {\n return;\n }\n\n this.isFlushing = true;\n const batch = this.queue.splice(0, this.config.batchSize);\n\n try {\n await this.sendBatch(batch);\n } catch {\n // Re-queue events that failed to send (prepend to maintain ordering)\n this.queue.unshift(...batch);\n } finally {\n this.isFlushing = false;\n }\n\n // If there are still events in the queue, flush again\n if (this.queue.length >= this.config.batchSize) {\n await this.flush();\n }\n }\n\n /**\n * Gracefully shut down the tracker. Flushes remaining events and\n * clears the flush interval.\n */\n async shutdown(): Promise<void> {\n this.isShutdown = true;\n this.stopFlushInterval();\n await this.flush();\n }\n\n /**\n * Send a batch of events to the Truth API with exponential backoff retry.\n */\n private async sendBatch(batch: EventEnvelope[]): Promise<void> {\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {\n try {\n const response = await fetch(`${this.apiUrl}/api/events/ingest`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.config.apiKey}`,\n },\n body: JSON.stringify({ events: batch }),\n });\n\n if (response.ok) {\n return;\n }\n\n // Don't retry 4xx client errors (except 429)\n if (\n response.status >= 400 &&\n response.status < 500 &&\n response.status !== 429\n ) {\n return;\n }\n\n lastError = new Error(\n `HTTP ${response.status}: ${response.statusText}`,\n );\n } catch (error) {\n lastError = error;\n }\n\n // Exponential backoff with jitter\n if (attempt < MAX_RETRIES) {\n const delay = BASE_RETRY_DELAY_MS * 2 ** attempt;\n const jitter = Math.random() * delay * 0.5;\n await sleep(delay + jitter);\n }\n }\n\n throw lastError;\n }\n\n private startFlushInterval(): void {\n if (this.config.flushIntervalMs > 0) {\n this.flushTimer = setInterval(() => {\n void this.flush();\n }, this.config.flushIntervalMs);\n\n // Unref the timer so it doesn't prevent Node.js from exiting\n if (typeof this.flushTimer === \"object\" && \"unref\" in this.flushTimer) {\n this.flushTimer.unref();\n }\n }\n }\n\n private stopFlushInterval(): void {\n if (this.flushTimer !== null) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n }\n\n private registerShutdownHooks(): void {\n // Only register in Node.js environments\n if (typeof globalThis.process !== \"undefined\" && globalThis.process.on) {\n const shutdownHandler = () => {\n void this.shutdown();\n };\n\n globalThis.process.on(\"beforeExit\", shutdownHandler);\n globalThis.process.on(\"SIGTERM\", shutdownHandler);\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport {\n Tracker,\n generateUuidV7,\n DEFAULT_BATCH_SIZE,\n DEFAULT_FLUSH_INTERVAL_MS,\n};\nexport type { TrackerConfig };\n","/**\n * Typed event definitions for the Truth Platform event store.\n *\n * All 26 event types from the Communication Hub -> Truth Event Store Contract.\n * Events are grouped by domain and include typed payload interfaces.\n */\n\n// ---------------------------------------------------------------------------\n// Event type constants\n// ---------------------------------------------------------------------------\n\nconst CONVERSATION_EVENTS = {\n created: \"conversation.created.v1\",\n messageSent: \"conversation.message_sent.v1\",\n messageReceived: \"conversation.message_received.v1\",\n markedRead: \"conversation.marked_read.v1\",\n attachmentUploaded: \"conversation.attachment_uploaded.v1\",\n attachmentDownloaded: \"conversation.attachment_downloaded.v1\",\n} as const;\n\nconst CALL_EVENTS = {\n initiated: \"call.initiated.v1\",\n connected: \"call.connected.v1\",\n ended: \"call.ended.v1\",\n missed: \"call.missed.v1\",\n} as const;\n\nconst TASK_EVENTS = {\n created: \"task.created.v1\",\n assigned: \"task.assigned.v1\",\n statusChanged: \"task.status_changed.v1\",\n} as const;\n\nconst REMINDER_EVENTS = {\n scheduled: \"reminder.scheduled.v1\",\n triggered: \"reminder.triggered.v1\",\n} as const;\n\nconst TRANSLATION_EVENTS = {\n requested: \"translation.requested.v1\",\n completed: \"translation.completed.v1\",\n} as const;\n\nconst NOTIFICATION_EVENTS = {\n sent: \"notification.sent.v1\",\n delivered: \"notification.delivered.v1\",\n opened: \"notification.opened.v1\",\n} as const;\n\nconst PROVIDER_EVENTS = {\n syncStarted: \"provider.sync_started.v1\",\n syncSucceeded: \"provider.sync_succeeded.v1\",\n syncFailed: \"provider.sync_failed.v1\",\n} as const;\n\nconst AUTH_EVENTS = {\n loginSucceeded: \"auth.login_succeeded.v1\",\n loginFailed: \"auth.login_failed.v1\",\n} as const;\n\nconst SECURITY_EVENTS = {\n accessDenied: \"security.access_denied.v1\",\n} as const;\n\n/**\n * All event type constants grouped by domain.\n */\nconst EVENT_TYPES = {\n conversation: CONVERSATION_EVENTS,\n call: CALL_EVENTS,\n task: TASK_EVENTS,\n reminder: REMINDER_EVENTS,\n translation: TRANSLATION_EVENTS,\n notification: NOTIFICATION_EVENTS,\n provider: PROVIDER_EVENTS,\n auth: AUTH_EVENTS,\n security: SECURITY_EVENTS,\n} as const;\n\n// ---------------------------------------------------------------------------\n// Event type union\n// ---------------------------------------------------------------------------\n\ntype ConversationEventType =\n (typeof CONVERSATION_EVENTS)[keyof typeof CONVERSATION_EVENTS];\ntype CallEventType = (typeof CALL_EVENTS)[keyof typeof CALL_EVENTS];\ntype TaskEventType = (typeof TASK_EVENTS)[keyof typeof TASK_EVENTS];\ntype ReminderEventType = (typeof REMINDER_EVENTS)[keyof typeof REMINDER_EVENTS];\ntype TranslationEventType =\n (typeof TRANSLATION_EVENTS)[keyof typeof TRANSLATION_EVENTS];\ntype NotificationEventType =\n (typeof NOTIFICATION_EVENTS)[keyof typeof NOTIFICATION_EVENTS];\ntype ProviderEventType = (typeof PROVIDER_EVENTS)[keyof typeof PROVIDER_EVENTS];\ntype AuthEventType = (typeof AUTH_EVENTS)[keyof typeof AUTH_EVENTS];\ntype SecurityEventType = (typeof SECURITY_EVENTS)[keyof typeof SECURITY_EVENTS];\n\n/**\n * Union of all 26 registered event type strings.\n */\ntype EventType =\n | ConversationEventType\n | CallEventType\n | TaskEventType\n | ReminderEventType\n | TranslationEventType\n | NotificationEventType\n | ProviderEventType\n | AuthEventType\n | SecurityEventType;\n\n// ---------------------------------------------------------------------------\n// Payload interfaces (per the contract doc)\n// ---------------------------------------------------------------------------\n\ninterface ConversationCreatedPayload {\n channel: string;\n origin_system: string;\n participant_count: number;\n}\n\ninterface ConversationMessageSentPayload {\n channel: string;\n direction: string;\n message_chars: number;\n has_attachment: boolean;\n provider_system: string;\n}\n\ninterface ConversationMessageReceivedPayload {\n channel: string;\n direction: string;\n message_chars: number;\n provider_system: string;\n}\n\ninterface ConversationMarkedReadPayload {\n read_by_actor_id: string;\n unread_count_before: number;\n unread_count_after: number;\n}\n\ninterface ConversationAttachmentUploadedPayload {\n attachment_id: string;\n mime_type: string;\n size_bytes: number;\n storage_class: string;\n}\n\ninterface ConversationAttachmentDownloadedPayload {\n attachment_id: string;\n download_actor_type: string;\n access_path: string;\n}\n\ninterface CallInitiatedPayload {\n direction: string;\n provider_system: string;\n from_number_ref: string;\n to_number_ref: string;\n}\n\ninterface CallConnectedPayload {\n provider_system: string;\n ring_duration_ms: number;\n}\n\ninterface CallEndedPayload {\n provider_system: string;\n duration_ms: number;\n end_reason: string;\n disposition: string;\n}\n\ninterface CallMissedPayload {\n provider_system: string;\n miss_reason: string;\n}\n\ninterface TaskCreatedPayload {\n task_id: string;\n created_by: string;\n assigned_to: string;\n priority: string;\n due_at: string;\n}\n\ninterface TaskAssignedPayload {\n task_id: string;\n assigned_to: string;\n assigned_by: string;\n}\n\ninterface TaskStatusChangedPayload {\n task_id: string;\n status_from: string;\n status_to: string;\n changed_by: string;\n}\n\ninterface ReminderScheduledPayload {\n reminder_id: string;\n conversation_id: string;\n scheduled_for: string;\n scheduled_by: string;\n}\n\ninterface ReminderTriggeredPayload {\n reminder_id: string;\n trigger_result: string;\n notification_attempted: boolean;\n}\n\ninterface TranslationRequestedPayload {\n target_language: string;\n source_language: string;\n char_count: number;\n mode: string;\n}\n\ninterface TranslationCompletedPayload {\n target_language: string;\n provider: string;\n latency_ms: number;\n success: boolean;\n error_code?: string;\n}\n\ninterface NotificationSentPayload {\n notification_id: string;\n channel: string;\n platform: string;\n recipient_ref: string;\n success: boolean;\n}\n\ninterface NotificationDeliveredPayload {\n notification_id: string;\n platform: string;\n delivered_at: string;\n}\n\ninterface NotificationOpenedPayload {\n notification_id: string;\n platform: string;\n opened_at: string;\n}\n\ninterface ProviderSyncStartedPayload {\n provider_system: string;\n operation: string;\n scope: string;\n batch_id: string;\n}\n\ninterface ProviderSyncSucceededPayload {\n provider_system: string;\n operation: string;\n batch_id: string;\n records_processed: number;\n duration_ms: number;\n}\n\ninterface ProviderSyncFailedPayload {\n provider_system: string;\n operation: string;\n batch_id: string;\n error_code: string;\n retryable: boolean;\n}\n\ninterface AuthLoginSucceededPayload {\n auth_provider: string;\n platform: string;\n session_ref: string;\n}\n\ninterface AuthLoginFailedPayload {\n auth_provider: string;\n platform: string;\n failure_code: string;\n}\n\ninterface SecurityAccessDeniedPayload {\n resource: string;\n policy: string;\n reason_code: string;\n actor_id: string;\n}\n\n// ---------------------------------------------------------------------------\n// Event type -> payload mapping\n// ---------------------------------------------------------------------------\n\n/**\n * Maps each event type string to its required payload interface.\n */\ninterface EventPayloadMap {\n \"conversation.created.v1\": ConversationCreatedPayload;\n \"conversation.message_sent.v1\": ConversationMessageSentPayload;\n \"conversation.message_received.v1\": ConversationMessageReceivedPayload;\n \"conversation.marked_read.v1\": ConversationMarkedReadPayload;\n \"conversation.attachment_uploaded.v1\": ConversationAttachmentUploadedPayload;\n \"conversation.attachment_downloaded.v1\": ConversationAttachmentDownloadedPayload;\n \"call.initiated.v1\": CallInitiatedPayload;\n \"call.connected.v1\": CallConnectedPayload;\n \"call.ended.v1\": CallEndedPayload;\n \"call.missed.v1\": CallMissedPayload;\n \"task.created.v1\": TaskCreatedPayload;\n \"task.assigned.v1\": TaskAssignedPayload;\n \"task.status_changed.v1\": TaskStatusChangedPayload;\n \"reminder.scheduled.v1\": ReminderScheduledPayload;\n \"reminder.triggered.v1\": ReminderTriggeredPayload;\n \"translation.requested.v1\": TranslationRequestedPayload;\n \"translation.completed.v1\": TranslationCompletedPayload;\n \"notification.sent.v1\": NotificationSentPayload;\n \"notification.delivered.v1\": NotificationDeliveredPayload;\n \"notification.opened.v1\": NotificationOpenedPayload;\n \"provider.sync_started.v1\": ProviderSyncStartedPayload;\n \"provider.sync_succeeded.v1\": ProviderSyncSucceededPayload;\n \"provider.sync_failed.v1\": ProviderSyncFailedPayload;\n \"auth.login_succeeded.v1\": AuthLoginSucceededPayload;\n \"auth.login_failed.v1\": AuthLoginFailedPayload;\n \"security.access_denied.v1\": SecurityAccessDeniedPayload;\n}\n\n// ---------------------------------------------------------------------------\n// Event envelope\n// ---------------------------------------------------------------------------\n\n/**\n * Subject references for the event. Uses tokenized references only -- no PHI.\n */\ninterface EventSubject {\n patient_ref?: string;\n conversation_id?: string;\n task_id?: string;\n call_id?: string;\n}\n\n/**\n * Actor who triggered the event.\n */\ninterface EventActor {\n actor_id: string;\n actor_type: \"user\" | \"system\" | \"webhook\";\n}\n\n/**\n * Compliance metadata for the event.\n */\ninterface EventCompliance {\n pii_level: \"none\" | \"limited\" | \"full\";\n contains_phi: boolean;\n consent_context: string;\n retention_class: string;\n}\n\n/**\n * Canonical event envelope. Every tracked event is wrapped in this structure\n * before being sent to the Truth API.\n */\ninterface EventEnvelope {\n event_id: string;\n event_type: string;\n schema_version: number;\n occurred_at: string;\n received_at: string;\n source: string;\n source_version: string;\n tenant_id: string;\n actor?: EventActor;\n subject?: EventSubject;\n compliance?: EventCompliance;\n payload: Record<string, unknown>;\n}\n\n// ---------------------------------------------------------------------------\n// Track options (per-call overrides)\n// ---------------------------------------------------------------------------\n\n/**\n * Optional overrides when calling truth.track().\n */\ninterface TrackOptions {\n /** Override the default actor for this event */\n actor?: EventActor;\n\n /** Subject references for this event */\n subject?: EventSubject;\n\n /** Compliance metadata for this event */\n compliance?: EventCompliance;\n\n /** Override the default tenant ID for this event */\n tenantId?: string;\n\n /** Override the occurred_at timestamp (ISO 8601) */\n occurredAt?: string;\n}\n\nexport {\n EVENT_TYPES,\n CONVERSATION_EVENTS,\n CALL_EVENTS,\n TASK_EVENTS,\n REMINDER_EVENTS,\n TRANSLATION_EVENTS,\n NOTIFICATION_EVENTS,\n PROVIDER_EVENTS,\n AUTH_EVENTS,\n SECURITY_EVENTS,\n};\n\nexport type {\n EventType,\n ConversationEventType,\n CallEventType,\n TaskEventType,\n ReminderEventType,\n TranslationEventType,\n NotificationEventType,\n ProviderEventType,\n AuthEventType,\n SecurityEventType,\n EventPayloadMap,\n EventEnvelope,\n EventActor,\n EventSubject,\n EventCompliance,\n TrackOptions,\n ConversationCreatedPayload,\n ConversationMessageSentPayload,\n ConversationMessageReceivedPayload,\n ConversationMarkedReadPayload,\n ConversationAttachmentUploadedPayload,\n ConversationAttachmentDownloadedPayload,\n CallInitiatedPayload,\n CallConnectedPayload,\n CallEndedPayload,\n CallMissedPayload,\n TaskCreatedPayload,\n TaskAssignedPayload,\n TaskStatusChangedPayload,\n ReminderScheduledPayload,\n ReminderTriggeredPayload,\n TranslationRequestedPayload,\n TranslationCompletedPayload,\n NotificationSentPayload,\n NotificationDeliveredPayload,\n NotificationOpenedPayload,\n ProviderSyncStartedPayload,\n ProviderSyncSucceededPayload,\n ProviderSyncFailedPayload,\n AuthLoginSucceededPayload,\n AuthLoginFailedPayload,\n SecurityAccessDeniedPayload,\n};\n","/**\n * Configuration interfaces for the Truth SDK.\n */\n\n/**\n * Environment options for the Truth platform.\n */\nconst ENVIRONMENTS = {\n local: \"local\",\n staging: \"staging\",\n sandbox: \"sandbox\",\n uat: \"uat\",\n production: \"production\",\n} as const;\n\ntype Environment = (typeof ENVIRONMENTS)[keyof typeof ENVIRONMENTS];\n\n/**\n * Configuration for initializing a TruthClient.\n */\ninterface TruthClientConfig {\n /** API key for authenticating with the Truth platform (e.g. \"hn_live_...\") */\n apiKey: string;\n\n /** Target environment */\n environment: Environment;\n\n /** Override the default Convex URL for data access */\n convexUrl?: string;\n\n /** Event source identifier (e.g. \"communication-hub.backend\") */\n source?: string;\n\n /** Git SHA or version string for event source versioning */\n sourceVersion?: string;\n\n /** Default tenant (organization) ID for events */\n tenantId?: string;\n\n /** Number of events to buffer before flushing (default: 25) */\n batchSize?: number;\n\n /** Interval in milliseconds between automatic flushes (default: 5000) */\n flushIntervalMs?: number;\n\n /** Base URL for the Truth API (overrides environment-based default) */\n apiBaseUrl?: string;\n}\n\n/**\n * Actor context attached to tracked events.\n */\ninterface ActorContext {\n actorId: string;\n actorType: \"user\" | \"system\" | \"webhook\";\n}\n\n/**\n * Paginated result wrapper for list operations.\n */\ninterface PaginatedResult<T> {\n data: T[];\n cursor: string | null;\n hasMore: boolean;\n}\n\nexport { ENVIRONMENTS };\nexport type { Environment, TruthClientConfig, ActorContext, PaginatedResult };\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/resources/appointments.ts","../src/resources/dialpad.ts","../src/resources/ehr.ts","../src/resources/patients.ts","../src/tracking/tracker.ts","../src/tracking/events.ts","../src/types/config.ts"],"sourcesContent":["/**\n * @hipnation-truth/sdk\n *\n * HIPnation Truth Platform SDK. Provides resource-based data access\n * (patients, appointments) backed by Convex, and fire-and-forget event\n * tracking to the Truth API.\n *\n * @example\n * ```ts\n * import { TruthClient } from '@hipnation-truth/sdk';\n *\n * const truth = new TruthClient({\n * apiKey: 'hn_live_...',\n * environment: 'production',\n * source: 'communication-hub.backend',\n * sourceVersion: 'git:abcd1234',\n * tenantId: 'org_123',\n * });\n *\n * // Data access\n * const patient = await truth.patients.get('patient_123');\n * const appointments = await truth.appointments.list({ patientId: 'patient_123' });\n *\n * // Event tracking\n * truth.identify('user_456', 'user');\n * truth.track('conversation.message_sent.v1', {\n * channel: 'sms',\n * direction: 'outbound',\n * message_chars: 140,\n * has_attachment: false,\n * provider_system: 'dialpad',\n * });\n *\n * // Graceful shutdown\n * await truth.flush();\n * ```\n */\n\n// Client\nexport { TruthClient } from \"./client\";\n// Resources — Data (Convex)\nexport { AppointmentResource } from \"./resources/appointments\";\nexport type {\n CallStatusResponse,\n DialpadNumberInfo,\n DialpadUser,\n InitiateCallResponse,\n SendSmsParams,\n SendSmsResponse,\n VoicemailAuthResponse,\n} from \"./resources/dialpad\";\n// Resources — Messages Proxy\nexport {\n DialpadProxyError,\n DialpadResource,\n MessagesResource,\n} from \"./resources/dialpad\";\n// Resources — EHR Proxy\nexport { EhrProviderProxy, EhrProxyError, EhrResource } from \"./resources/ehr\";\nexport { PatientResource } from \"./resources/patients\";\nexport type {\n AuthEventType,\n AuthLoginFailedPayload,\n AuthLoginSucceededPayload,\n CallConnectedPayload,\n CallEndedPayload,\n CallEventType,\n CallInitiatedPayload,\n CallMissedPayload,\n ConversationAttachmentDownloadedPayload,\n ConversationAttachmentUploadedPayload,\n ConversationCreatedPayload,\n ConversationEventType,\n ConversationMarkedReadPayload,\n ConversationMessageReceivedPayload,\n ConversationMessageSentPayload,\n EventActor,\n EventCompliance,\n EventEnvelope,\n EventPayloadMap,\n EventSubject,\n EventType,\n NotificationDeliveredPayload,\n NotificationEventType,\n NotificationOpenedPayload,\n NotificationSentPayload,\n ProviderEventType,\n ProviderSyncFailedPayload,\n ProviderSyncStartedPayload,\n ProviderSyncSucceededPayload,\n ReminderEventType,\n ReminderScheduledPayload,\n ReminderTriggeredPayload,\n SecurityAccessDeniedPayload,\n SecurityEventType,\n TaskAssignedPayload,\n TaskCreatedPayload,\n TaskEventType,\n TaskStatusChangedPayload,\n TrackOptions,\n TranslationCompletedPayload,\n TranslationEventType,\n TranslationRequestedPayload,\n} from \"./tracking/events\";\nexport {\n AUTH_EVENTS,\n CALL_EVENTS,\n CONVERSATION_EVENTS,\n EVENT_TYPES,\n NOTIFICATION_EVENTS,\n PROVIDER_EVENTS,\n REMINDER_EVENTS,\n SECURITY_EVENTS,\n TASK_EVENTS,\n TRANSLATION_EVENTS,\n} from \"./tracking/events\";\n// Tracking\nexport { generateUuidV7, Tracker } from \"./tracking/tracker\";\nexport type { Appointment, AppointmentListOptions } from \"./types/appointment\";\nexport type {\n ActorContext,\n Environment,\n PaginatedResult,\n TruthClientConfig,\n} from \"./types/config\";\n// Types\nexport { ENVIRONMENTS } from \"./types/config\";\nexport type { Patient, PatientListOptions } from \"./types/patient\";\n","/**\n * TruthClient -- main entry point for the @hipnation-truth/sdk package.\n *\n * Provides:\n * - `.patients` Resource-based patient data access (Convex-backed)\n * - `.appointments` Resource-based appointment data access (Convex-backed)\n * - `.ehr` EHR proxy access (Elation, Hint)\n * - `.messages` Messaging proxy access (Dialpad)\n * - `.track()` Fire-and-forget event tracking (batched HTTP -> Truth API)\n * - `.identify()` Set default actor context for subsequent events\n * - `.flush()` Force flush of buffered events (for graceful shutdown)\n */\n\nimport { ConvexHttpClient } from \"convex/browser\";\nimport { AppointmentResource } from \"./resources/appointments\";\nimport { MessagesResource } from \"./resources/dialpad\";\nimport { EhrResource } from \"./resources/ehr\";\nimport { PatientResource } from \"./resources/patients\";\nimport type {\n EventPayloadMap,\n EventType,\n TrackOptions,\n} from \"./tracking/events\";\nimport {\n DEFAULT_BATCH_SIZE,\n DEFAULT_FLUSH_INTERVAL_MS,\n Tracker,\n} from \"./tracking/tracker\";\nimport type { ActorContext, TruthClientConfig } from \"./types/config\";\n\n// ---------------------------------------------------------------------------\n// Environment -> Convex URL mapping\n// ---------------------------------------------------------------------------\n\nconst CONVEX_URLS: Record<string, string> = {\n local: \"http://localhost:3210\",\n staging: \"https://staging-truth.convex.cloud\",\n uat: \"https://uat-truth.convex.cloud\",\n production: \"https://truth.convex.cloud\",\n};\n\n// ---------------------------------------------------------------------------\n// TruthClient\n// ---------------------------------------------------------------------------\n\nclass TruthClient {\n /** Patient data resource (Convex-backed) */\n readonly patients: PatientResource;\n\n /** Appointment data resource (Convex-backed) */\n readonly appointments: AppointmentResource;\n\n /** EHR proxy — typed access to Elation and Hint APIs through Truth */\n readonly ehr: EhrResource;\n\n /** Messaging proxy — typed access to Dialpad APIs through Truth */\n readonly messages: MessagesResource;\n\n private readonly convex: ConvexHttpClient;\n private readonly tracker: Tracker;\n\n constructor(config: TruthClientConfig) {\n // Resolve Convex URL\n const convexUrl =\n config.convexUrl ?? CONVEX_URLS[config.environment] ?? CONVEX_URLS.local;\n\n // Initialize Convex HTTP client for data access\n this.convex = new ConvexHttpClient(convexUrl);\n\n // Initialize event tracker\n this.tracker = new Tracker({\n apiKey: config.apiKey,\n environment: config.environment,\n source: config.source ?? \"unknown\",\n sourceVersion: config.sourceVersion ?? \"unknown\",\n tenantId: config.tenantId ?? \"\",\n batchSize: config.batchSize ?? DEFAULT_BATCH_SIZE,\n flushIntervalMs: config.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS,\n apiBaseUrl: config.apiBaseUrl,\n });\n\n const apiUrl = this.tracker.apiUrl;\n\n // Initialize resources\n this.patients = new PatientResource(this.convex);\n this.appointments = new AppointmentResource(this.convex);\n this.ehr = new EhrResource(apiUrl);\n this.messages = new MessagesResource(apiUrl);\n }\n\n /**\n * The resolved Truth API base URL for this environment.\n * Use this when making HTTP calls to Truth's proxy endpoints\n * (e.g., EHR proxy, messages proxy).\n *\n * @example\n * ```ts\n * const url = `${truth.apiBaseUrl}/api/ehr/elation/patients/123`;\n * ```\n */\n get apiBaseUrl(): string {\n return this.tracker.apiUrl;\n }\n\n /**\n * Track an event. Fire-and-forget -- the event is buffered internally\n * and flushed in batches to the Truth API.\n *\n * @example\n * ```ts\n * truth.track('conversation.message_sent.v1', {\n * channel: 'sms',\n * direction: 'outbound',\n * message_chars: 140,\n * has_attachment: false,\n * provider_system: 'dialpad',\n * });\n * ```\n */\n track<T extends EventType>(\n eventType: T,\n payload: EventPayloadMap[T],\n options?: TrackOptions,\n ): void {\n this.tracker.track(eventType, payload, options);\n }\n\n /**\n * Set the default actor context for all subsequent tracked events.\n * Can be overridden per-event via TrackOptions.\n *\n * @example\n * ```ts\n * truth.identify('user_123', 'user');\n * ```\n */\n identify(actorId: string, actorType: ActorContext[\"actorType\"]): void {\n this.tracker.setActor({ actorId, actorType });\n }\n\n /**\n * Flush all buffered events immediately. Returns a Promise that resolves\n * when the flush completes. Use this for graceful shutdown.\n *\n * @example\n * ```ts\n * process.on('SIGTERM', async () => {\n * await truth.flush();\n * process.exit(0);\n * });\n * ```\n */\n async flush(): Promise<void> {\n await this.tracker.flush();\n }\n\n /**\n * Gracefully shut down the client. Flushes all pending events and\n * releases resources.\n */\n async destroy(): Promise<void> {\n await this.tracker.shutdown();\n }\n}\n\nexport { TruthClient };\n","/**\n * AppointmentResource provides data access to normalized appointment records\n * backed by Convex.\n */\n\nimport type { ConvexHttpClient } from \"convex/browser\";\nimport type { Appointment, AppointmentListOptions } from \"../types/appointment\";\nimport type { PaginatedResult } from \"../types/config\";\n\nclass AppointmentResource {\n private readonly convex: ConvexHttpClient;\n\n constructor(convexClient: ConvexHttpClient) {\n this.convex = convexClient;\n }\n\n /**\n * Get an appointment by its Truth platform ID.\n */\n async get(id: string): Promise<Appointment | null> {\n try {\n const result = await this.convex.query(\n \"appointments:getById\" as never,\n { id } as never,\n );\n return (result as Appointment) ?? null;\n } catch {\n return null;\n }\n }\n\n /**\n * List appointments with optional filters, pagination, and limit.\n */\n async list(\n options?: AppointmentListOptions,\n ): Promise<PaginatedResult<Appointment>> {\n try {\n const result = await this.convex.query(\n \"appointments:list\" as never,\n {\n patientId: options?.patientId,\n startDate: options?.startDate,\n endDate: options?.endDate,\n status: options?.status,\n limit: options?.limit,\n cursor: options?.cursor,\n } as never,\n );\n\n const typed = result as PaginatedResult<Appointment> | undefined;\n\n return typed ?? { data: [], cursor: null, hasMore: false };\n } catch {\n return { data: [], cursor: null, hasMore: false };\n }\n }\n}\n\nexport { AppointmentResource };\n","/**\n * Dialpad resource — typed access to Truth's Dialpad proxy endpoints.\n *\n * @example\n * ```ts\n * const sms = await truth.messages.dialpad.sendSms({ from_number, to_number, message });\n * const call = await truth.messages.dialpad.initiateCall(userId, phoneNumber);\n * await truth.messages.dialpad.hangupCall(callId);\n * const url = await truth.messages.dialpad.authenticateVoicemail(voicemailLink);\n * ```\n */\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface SendSmsParams {\n from_number: string;\n to_number: string;\n message?: string;\n media?: string;\n}\n\ninterface SendSmsResponse {\n id: string;\n message_status: string;\n [key: string]: unknown;\n}\n\ninterface InitiateCallResponse {\n call_id: number;\n [key: string]: unknown;\n}\n\ninterface CallStatusResponse {\n state: string;\n [key: string]: unknown;\n}\n\ninterface DialpadUser {\n id: number;\n emails: string[];\n first_name?: string;\n last_name?: string;\n [key: string]: unknown;\n}\n\ninterface DialpadUserListResponse {\n items: DialpadUser[];\n}\n\ninterface DialpadNumberInfo {\n user_id?: number;\n type?: string;\n [key: string]: unknown;\n}\n\ninterface VoicemailAuthResponse {\n success: boolean;\n authenticated_url: string | null;\n error?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Dialpad Resource\n// ---------------------------------------------------------------------------\n\nclass DialpadResource {\n private readonly baseUrl: string;\n\n constructor(apiBaseUrl: string) {\n this.baseUrl = apiBaseUrl;\n }\n\n /**\n * Send an SMS or MMS message via Dialpad.\n */\n async sendSms(params: SendSmsParams): Promise<SendSmsResponse> {\n const body = {\n to_numbers: [params.to_number],\n from_number: params.from_number,\n infer_country_code: false,\n ...(params.message ? { text: params.message } : {}),\n ...(params.media ? { media: params.media } : {}),\n };\n\n return this.post<SendSmsResponse>(\"/sms\", body);\n }\n\n /**\n * Initiate an outbound call from a Dialpad user to a phone number.\n */\n async initiateCall(\n userId: number,\n phoneNumber: string,\n ): Promise<InitiateCallResponse> {\n return this.post<InitiateCallResponse>(`/users/${userId}/initiate_call`, {\n phone_number: phoneNumber,\n });\n }\n\n /**\n * Hang up an active call.\n */\n async hangupCall(callId: number): Promise<void> {\n await this.put(`/call/${callId}/actions/hangup`);\n }\n\n /**\n * Get the status of a call.\n */\n async getCallStatus(callId: number): Promise<CallStatusResponse | null> {\n try {\n return await this.get<CallStatusResponse>(`/call/${callId}`);\n } catch (error) {\n if (error instanceof DialpadProxyError && error.status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Get a Dialpad user by their user ID.\n */\n async getUser(userId: string | number): Promise<DialpadUser | null> {\n try {\n return await this.get<DialpadUser>(`/users/${userId}`);\n } catch (error) {\n if (error instanceof DialpadProxyError && error.status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Find a Dialpad user by email.\n */\n async getUserByEmail(email: string): Promise<DialpadUser | null> {\n const result = await this.get<DialpadUserListResponse>(\"/users\", {\n email,\n });\n return result.items?.[0] ?? null;\n }\n\n /**\n * Find a Dialpad user by phone number.\n */\n async getUserByPhoneNumber(phoneNumber: string): Promise<DialpadUser | null> {\n const result = await this.get<DialpadUserListResponse>(\"/users\", {\n number: phoneNumber,\n });\n return result.items?.[0] ?? null;\n }\n\n /**\n * Get information about a Dialpad phone number.\n */\n async getNumberInfo(phoneNumber: string): Promise<DialpadNumberInfo | null> {\n try {\n const cleanNumber = phoneNumber.replace(/[^\\d+]/g, \"\");\n return await this.get<DialpadNumberInfo>(\n `/numbers/${encodeURIComponent(cleanNumber)}`,\n );\n } catch (error) {\n if (error instanceof DialpadProxyError && error.status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Authenticate a voicemail download URL. Truth appends the Dialpad API key,\n * follows redirects, and returns the clean URL for client-side playback.\n */\n async authenticateVoicemail(voicemailLink: string): Promise<string | null> {\n const url = `${this.baseUrl}/api/messages/dialpad/voicemail/authenticate`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ voicemail_link: voicemailLink }),\n });\n\n const result = (await response.json()) as VoicemailAuthResponse;\n\n if (!response.ok || !result.success) {\n return null;\n }\n\n return result.authenticated_url;\n }\n\n // -----------------------------------------------------------------------\n // Internal HTTP helpers\n // -----------------------------------------------------------------------\n\n private async get<T>(\n path: string,\n params?: Record<string, unknown>,\n ): Promise<T> {\n const url = new URL(`/api/messages/dialpad${path}`, this.baseUrl);\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n const response = await fetch(url.toString(), {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n });\n\n if (!response.ok) {\n throw new DialpadProxyError(\"GET\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n private async post<T>(path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}/api/messages/dialpad${path}`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n throw new DialpadProxyError(\"POST\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n private async put<T = void>(path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}/api/messages/dialpad${path}`;\n\n const response = await fetch(url, {\n method: \"PUT\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n throw new DialpadProxyError(\"PUT\", path, response.status);\n }\n\n if (response.headers.get(\"content-type\")?.includes(\"json\")) {\n return (await response.json()) as T;\n }\n\n return undefined as T;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Messages Resource — namespace for messaging providers\n// ---------------------------------------------------------------------------\n\nclass MessagesResource {\n readonly dialpad: DialpadResource;\n\n constructor(apiBaseUrl: string) {\n this.dialpad = new DialpadResource(apiBaseUrl);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Error\n// ---------------------------------------------------------------------------\n\nclass DialpadProxyError extends Error {\n readonly method: string;\n readonly path: string;\n readonly status: number;\n\n constructor(method: string, path: string, status: number) {\n super(\n `Dialpad proxy error: ${method} /api/messages/dialpad${path} returned ${status}`,\n );\n this.name = \"DialpadProxyError\";\n this.method = method;\n this.path = path;\n this.status = status;\n }\n}\n\nexport { DialpadResource, DialpadProxyError, MessagesResource };\nexport type {\n SendSmsParams,\n SendSmsResponse,\n InitiateCallResponse,\n CallStatusResponse,\n DialpadUser,\n DialpadNumberInfo,\n VoicemailAuthResponse,\n};\n","/**\n * EHR proxy resource — typed access to Truth's EHR proxy endpoints.\n *\n * Provides per-provider proxy methods so consumers never construct\n * proxy URLs manually.\n *\n * @example\n * ```ts\n * const patient = await truth.ehr.elation.get('/patients/123/');\n * const notes = await truth.ehr.elation.post('/non_visit_notes/', noteData);\n * const hintPatient = await truth.ehr.hint.get('/provider/patients/456');\n * ```\n */\n\n// ---------------------------------------------------------------------------\n// Provider proxy\n// ---------------------------------------------------------------------------\n\nclass EhrProviderProxy {\n private readonly baseUrl: string;\n private readonly provider: string;\n\n constructor(apiBaseUrl: string, provider: string) {\n this.baseUrl = apiBaseUrl;\n this.provider = provider;\n }\n\n /**\n * GET request to the EHR proxy.\n * @param path — path relative to the provider root (e.g., \"/patients/123/\")\n * @param params — optional query parameters\n */\n async get<T = unknown>(\n path: string,\n params?: Record<string, unknown>,\n ): Promise<T> {\n const url = new URL(`/api/ehr/${this.provider}${path}`, this.baseUrl);\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n const response = await fetch(url.toString(), {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n });\n\n if (!response.ok) {\n throw new EhrProxyError(this.provider, \"GET\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n /**\n * POST request to the EHR proxy.\n */\n async post<T = unknown>(path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}/api/ehr/${this.provider}${path}`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n throw new EhrProxyError(this.provider, \"POST\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n /**\n * PUT request to the EHR proxy.\n */\n async put<T = unknown>(path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}/api/ehr/${this.provider}${path}`;\n\n const response = await fetch(url, {\n method: \"PUT\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n throw new EhrProxyError(this.provider, \"PUT\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n /**\n * PATCH request to the EHR proxy.\n */\n async patch<T = unknown>(path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}/api/ehr/${this.provider}${path}`;\n\n const response = await fetch(url, {\n method: \"PATCH\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n throw new EhrProxyError(this.provider, \"PATCH\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n /**\n * DELETE request to the EHR proxy.\n */\n async delete<T = unknown>(path: string): Promise<T> {\n const url = `${this.baseUrl}/api/ehr/${this.provider}${path}`;\n\n const response = await fetch(url, {\n method: \"DELETE\",\n headers: { Accept: \"application/json\" },\n });\n\n if (!response.ok) {\n throw new EhrProxyError(this.provider, \"DELETE\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n}\n\n// ---------------------------------------------------------------------------\n// EHR Resource — exposes per-provider proxies\n// ---------------------------------------------------------------------------\n\nclass EhrResource {\n /** Elation EHR proxy */\n readonly elation: EhrProviderProxy;\n\n /** Hint Health proxy */\n readonly hint: EhrProviderProxy;\n\n constructor(apiBaseUrl: string) {\n this.elation = new EhrProviderProxy(apiBaseUrl, \"elation\");\n this.hint = new EhrProviderProxy(apiBaseUrl, \"hint\");\n }\n}\n\n// ---------------------------------------------------------------------------\n// Error\n// ---------------------------------------------------------------------------\n\nclass EhrProxyError extends Error {\n readonly provider: string;\n readonly method: string;\n readonly path: string;\n readonly status: number;\n\n constructor(provider: string, method: string, path: string, status: number) {\n super(\n `EHR proxy error: ${method} /api/ehr/${provider}${path} returned ${status}`,\n );\n this.name = \"EhrProxyError\";\n this.provider = provider;\n this.method = method;\n this.path = path;\n this.status = status;\n }\n}\n\nexport { EhrResource, EhrProviderProxy, EhrProxyError };\n","/**\n * PatientResource provides data access to normalized patient records\n * backed by Convex.\n */\n\nimport type { ConvexHttpClient } from \"convex/browser\";\nimport type { PaginatedResult } from \"../types/config\";\nimport type { Patient, PatientListOptions } from \"../types/patient\";\n\nclass PatientResource {\n private readonly convex: ConvexHttpClient;\n\n constructor(convexClient: ConvexHttpClient) {\n this.convex = convexClient;\n }\n\n /**\n * Get a patient by their Truth platform ID.\n */\n async get(id: string): Promise<Patient | null> {\n try {\n const result = await this.convex.query(\n \"patients:getById\" as never,\n {\n id,\n } as never,\n );\n return (result as Patient) ?? null;\n } catch {\n return null;\n }\n }\n\n /**\n * Get a patient by their Elation EHR ID.\n */\n async getByElationId(elationId: string): Promise<Patient | null> {\n try {\n const result = await this.convex.query(\n \"patients:getByElationId\" as never,\n { elationId } as never,\n );\n return (result as Patient) ?? null;\n } catch {\n return null;\n }\n }\n\n /**\n * Get a patient by their Hint EHR ID.\n */\n async getByHintId(hintId: string): Promise<Patient | null> {\n try {\n const result = await this.convex.query(\n \"patients:getByHintId\" as never,\n {\n hintId,\n } as never,\n );\n return (result as Patient) ?? null;\n } catch {\n return null;\n }\n }\n\n /**\n * List patients with optional search, pagination, and limit.\n */\n async list(options?: PatientListOptions): Promise<PaginatedResult<Patient>> {\n try {\n const result = await this.convex.query(\n \"patients:list\" as never,\n {\n search: options?.search,\n limit: options?.limit,\n cursor: options?.cursor,\n } as never,\n );\n\n const typed = result as PaginatedResult<Patient> | undefined;\n\n return typed ?? { data: [], cursor: null, hasMore: false };\n } catch {\n return { data: [], cursor: null, hasMore: false };\n }\n }\n}\n\nexport { PatientResource };\n","/**\n * Event tracker with batching, retry, and flush support.\n *\n * Buffers events in an internal queue and flushes them to the Truth API\n * endpoint. Flushes occur when the buffer reaches `batchSize` or every\n * `flushIntervalMs` milliseconds, whichever comes first.\n */\n\nimport type { ActorContext } from \"../types/config\";\nimport type {\n EventEnvelope,\n EventPayloadMap,\n EventType,\n TrackOptions,\n} from \"./events\";\n\n// ---------------------------------------------------------------------------\n// UUID v7 helper (no external dependency)\n// ---------------------------------------------------------------------------\n\n/**\n * Generates a UUID v7 string. Uses crypto.randomUUID where available,\n * falling back to a timestamp + random bytes implementation.\n *\n * UUID v7 layout (RFC 9562):\n * 48 bits - unix timestamp (ms)\n * 4 bits - version (0b0111)\n * 12 bits - random\n * 2 bits - variant (0b10)\n * 62 bits - random\n */\nfunction generateUuidV7(): string {\n const now = Date.now();\n\n // 6 bytes of timestamp\n const timeBytes = new Uint8Array(6);\n let ts = now;\n for (let i = 5; i >= 0; i--) {\n timeBytes[i] = ts & 0xff;\n ts = Math.floor(ts / 256);\n }\n\n // 10 bytes of random\n const randomBytes = new Uint8Array(10);\n if (\n typeof globalThis.crypto !== \"undefined\" &&\n globalThis.crypto.getRandomValues\n ) {\n globalThis.crypto.getRandomValues(randomBytes);\n } else {\n for (let i = 0; i < 10; i++) {\n randomBytes[i] = Math.floor(Math.random() * 256);\n }\n }\n\n // Assemble 16 bytes\n const bytes = new Uint8Array(16);\n bytes.set(timeBytes, 0);\n bytes.set(randomBytes, 6);\n\n // Set version (bits 48-51 to 0b0111)\n bytes[6] = (bytes[6] & 0x0f) | 0x70;\n\n // Set variant (bits 64-65 to 0b10)\n bytes[8] = (bytes[8] & 0x3f) | 0x80;\n\n // Format as hex string with dashes\n const hex = Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n\n return [\n hex.slice(0, 8),\n hex.slice(8, 12),\n hex.slice(12, 16),\n hex.slice(16, 20),\n hex.slice(20, 32),\n ].join(\"-\");\n}\n\n// ---------------------------------------------------------------------------\n// Environment-based API URL resolution\n// ---------------------------------------------------------------------------\n\nconst API_URLS: Record<string, string> = {\n local: \"http://localhost:3000\",\n staging: \"https://app.sandbox.communication-hub.com\",\n sandbox: \"https://app.sandbox.communication-hub.com\",\n uat: \"https://app.sandbox.communication-hub.com\",\n production: \"https://app.truth.communication-hub.com\",\n};\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_BATCH_SIZE = 25;\nconst DEFAULT_FLUSH_INTERVAL_MS = 5_000;\nconst MAX_RETRIES = 3;\nconst BASE_RETRY_DELAY_MS = 500;\n\n// ---------------------------------------------------------------------------\n// Tracker configuration\n// ---------------------------------------------------------------------------\n\ninterface TrackerConfig {\n apiKey: string;\n environment: string;\n source: string;\n sourceVersion: string;\n tenantId: string;\n batchSize: number;\n flushIntervalMs: number;\n apiBaseUrl?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Tracker class\n// ---------------------------------------------------------------------------\n\nclass Tracker {\n private readonly config: TrackerConfig;\n readonly apiUrl: string;\n private queue: EventEnvelope[] = [];\n private flushTimer: ReturnType<typeof setInterval> | null = null;\n private defaultActor: ActorContext | undefined;\n private isFlushing = false;\n private isShutdown = false;\n\n constructor(config: TrackerConfig) {\n this.config = config;\n this.apiUrl =\n config.apiBaseUrl ?? API_URLS[config.environment] ?? API_URLS.local;\n\n this.startFlushInterval();\n this.registerShutdownHooks();\n }\n\n /**\n * Set the default actor context for subsequent events.\n */\n setActor(actor: ActorContext): void {\n this.defaultActor = actor;\n }\n\n /**\n * Enqueue a typed event for delivery. This is fire-and-forget from\n * the caller's perspective -- events are buffered and flushed in batches.\n */\n track<T extends EventType>(\n eventType: T,\n payload: EventPayloadMap[T],\n options?: TrackOptions,\n ): void {\n if (this.isShutdown) {\n return;\n }\n\n const now = new Date().toISOString();\n\n const envelope: EventEnvelope = {\n event_id: generateUuidV7(),\n event_type: eventType,\n schema_version: 1,\n occurred_at: options?.occurredAt ?? now,\n received_at: now,\n source: this.config.source,\n source_version: this.config.sourceVersion,\n tenant_id: options?.tenantId ?? this.config.tenantId,\n actor:\n options?.actor ??\n (this.defaultActor\n ? {\n actor_id: this.defaultActor.actorId,\n actor_type: this.defaultActor.actorType,\n }\n : undefined),\n subject: options?.subject,\n compliance: options?.compliance,\n payload: payload as unknown as Record<string, unknown>,\n };\n\n this.queue.push(envelope);\n\n if (this.queue.length >= this.config.batchSize) {\n void this.flush();\n }\n }\n\n /**\n * Force an immediate flush of all buffered events.\n * Returns a promise that resolves when the flush completes.\n */\n async flush(): Promise<void> {\n if (this.queue.length === 0 || this.isFlushing) {\n return;\n }\n\n this.isFlushing = true;\n const batch = this.queue.splice(0, this.config.batchSize);\n\n try {\n await this.sendBatch(batch);\n } catch {\n // Re-queue events that failed to send (prepend to maintain ordering)\n this.queue.unshift(...batch);\n } finally {\n this.isFlushing = false;\n }\n\n // If there are still events in the queue, flush again\n if (this.queue.length >= this.config.batchSize) {\n await this.flush();\n }\n }\n\n /**\n * Gracefully shut down the tracker. Flushes remaining events and\n * clears the flush interval.\n */\n async shutdown(): Promise<void> {\n this.isShutdown = true;\n this.stopFlushInterval();\n await this.flush();\n }\n\n /**\n * Send a batch of events to the Truth API with exponential backoff retry.\n */\n private async sendBatch(batch: EventEnvelope[]): Promise<void> {\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {\n try {\n const response = await fetch(`${this.apiUrl}/api/events/ingest`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.config.apiKey}`,\n },\n body: JSON.stringify({ events: batch }),\n });\n\n if (response.ok) {\n return;\n }\n\n // Don't retry 4xx client errors (except 429)\n if (\n response.status >= 400 &&\n response.status < 500 &&\n response.status !== 429\n ) {\n return;\n }\n\n lastError = new Error(\n `HTTP ${response.status}: ${response.statusText}`,\n );\n } catch (error) {\n lastError = error;\n }\n\n // Exponential backoff with jitter\n if (attempt < MAX_RETRIES) {\n const delay = BASE_RETRY_DELAY_MS * 2 ** attempt;\n const jitter = Math.random() * delay * 0.5;\n await sleep(delay + jitter);\n }\n }\n\n throw lastError;\n }\n\n private startFlushInterval(): void {\n if (this.config.flushIntervalMs > 0) {\n this.flushTimer = setInterval(() => {\n void this.flush();\n }, this.config.flushIntervalMs);\n\n // Unref the timer so it doesn't prevent Node.js from exiting\n if (typeof this.flushTimer === \"object\" && \"unref\" in this.flushTimer) {\n this.flushTimer.unref();\n }\n }\n }\n\n private stopFlushInterval(): void {\n if (this.flushTimer !== null) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n }\n\n private registerShutdownHooks(): void {\n // Only register in Node.js environments\n if (typeof globalThis.process !== \"undefined\" && globalThis.process.on) {\n const shutdownHandler = () => {\n void this.shutdown();\n };\n\n globalThis.process.on(\"beforeExit\", shutdownHandler);\n globalThis.process.on(\"SIGTERM\", shutdownHandler);\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport {\n Tracker,\n generateUuidV7,\n DEFAULT_BATCH_SIZE,\n DEFAULT_FLUSH_INTERVAL_MS,\n};\nexport type { TrackerConfig };\n","/**\n * Typed event definitions for the Truth Platform event store.\n *\n * All 26 event types from the Communication Hub -> Truth Event Store Contract.\n * Events are grouped by domain and include typed payload interfaces.\n */\n\n// ---------------------------------------------------------------------------\n// Event type constants\n// ---------------------------------------------------------------------------\n\nconst CONVERSATION_EVENTS = {\n created: \"conversation.created.v1\",\n messageSent: \"conversation.message_sent.v1\",\n messageReceived: \"conversation.message_received.v1\",\n markedRead: \"conversation.marked_read.v1\",\n attachmentUploaded: \"conversation.attachment_uploaded.v1\",\n attachmentDownloaded: \"conversation.attachment_downloaded.v1\",\n} as const;\n\nconst CALL_EVENTS = {\n initiated: \"call.initiated.v1\",\n connected: \"call.connected.v1\",\n ended: \"call.ended.v1\",\n missed: \"call.missed.v1\",\n} as const;\n\nconst TASK_EVENTS = {\n created: \"task.created.v1\",\n assigned: \"task.assigned.v1\",\n statusChanged: \"task.status_changed.v1\",\n} as const;\n\nconst REMINDER_EVENTS = {\n scheduled: \"reminder.scheduled.v1\",\n triggered: \"reminder.triggered.v1\",\n} as const;\n\nconst TRANSLATION_EVENTS = {\n requested: \"translation.requested.v1\",\n completed: \"translation.completed.v1\",\n} as const;\n\nconst NOTIFICATION_EVENTS = {\n sent: \"notification.sent.v1\",\n delivered: \"notification.delivered.v1\",\n opened: \"notification.opened.v1\",\n} as const;\n\nconst PROVIDER_EVENTS = {\n syncStarted: \"provider.sync_started.v1\",\n syncSucceeded: \"provider.sync_succeeded.v1\",\n syncFailed: \"provider.sync_failed.v1\",\n} as const;\n\nconst AUTH_EVENTS = {\n loginSucceeded: \"auth.login_succeeded.v1\",\n loginFailed: \"auth.login_failed.v1\",\n} as const;\n\nconst SECURITY_EVENTS = {\n accessDenied: \"security.access_denied.v1\",\n} as const;\n\n/**\n * All event type constants grouped by domain.\n */\nconst EVENT_TYPES = {\n conversation: CONVERSATION_EVENTS,\n call: CALL_EVENTS,\n task: TASK_EVENTS,\n reminder: REMINDER_EVENTS,\n translation: TRANSLATION_EVENTS,\n notification: NOTIFICATION_EVENTS,\n provider: PROVIDER_EVENTS,\n auth: AUTH_EVENTS,\n security: SECURITY_EVENTS,\n} as const;\n\n// ---------------------------------------------------------------------------\n// Event type union\n// ---------------------------------------------------------------------------\n\ntype ConversationEventType =\n (typeof CONVERSATION_EVENTS)[keyof typeof CONVERSATION_EVENTS];\ntype CallEventType = (typeof CALL_EVENTS)[keyof typeof CALL_EVENTS];\ntype TaskEventType = (typeof TASK_EVENTS)[keyof typeof TASK_EVENTS];\ntype ReminderEventType = (typeof REMINDER_EVENTS)[keyof typeof REMINDER_EVENTS];\ntype TranslationEventType =\n (typeof TRANSLATION_EVENTS)[keyof typeof TRANSLATION_EVENTS];\ntype NotificationEventType =\n (typeof NOTIFICATION_EVENTS)[keyof typeof NOTIFICATION_EVENTS];\ntype ProviderEventType = (typeof PROVIDER_EVENTS)[keyof typeof PROVIDER_EVENTS];\ntype AuthEventType = (typeof AUTH_EVENTS)[keyof typeof AUTH_EVENTS];\ntype SecurityEventType = (typeof SECURITY_EVENTS)[keyof typeof SECURITY_EVENTS];\n\n/**\n * Union of all 26 registered event type strings.\n */\ntype EventType =\n | ConversationEventType\n | CallEventType\n | TaskEventType\n | ReminderEventType\n | TranslationEventType\n | NotificationEventType\n | ProviderEventType\n | AuthEventType\n | SecurityEventType;\n\n// ---------------------------------------------------------------------------\n// Payload interfaces (per the contract doc)\n// ---------------------------------------------------------------------------\n\ninterface ConversationCreatedPayload {\n channel: string;\n origin_system: string;\n participant_count: number;\n}\n\ninterface ConversationMessageSentPayload {\n channel: string;\n direction: string;\n message_chars: number;\n has_attachment: boolean;\n provider_system: string;\n}\n\ninterface ConversationMessageReceivedPayload {\n channel: string;\n direction: string;\n message_chars: number;\n provider_system: string;\n}\n\ninterface ConversationMarkedReadPayload {\n read_by_actor_id: string;\n unread_count_before: number;\n unread_count_after: number;\n}\n\ninterface ConversationAttachmentUploadedPayload {\n attachment_id: string;\n mime_type: string;\n size_bytes: number;\n storage_class: string;\n}\n\ninterface ConversationAttachmentDownloadedPayload {\n attachment_id: string;\n download_actor_type: string;\n access_path: string;\n}\n\ninterface CallInitiatedPayload {\n direction: string;\n provider_system: string;\n from_number_ref: string;\n to_number_ref: string;\n}\n\ninterface CallConnectedPayload {\n provider_system: string;\n ring_duration_ms: number;\n}\n\ninterface CallEndedPayload {\n provider_system: string;\n duration_ms: number;\n end_reason: string;\n disposition: string;\n}\n\ninterface CallMissedPayload {\n provider_system: string;\n miss_reason: string;\n}\n\ninterface TaskCreatedPayload {\n task_id: string;\n created_by: string;\n assigned_to: string;\n priority: string;\n due_at: string;\n}\n\ninterface TaskAssignedPayload {\n task_id: string;\n assigned_to: string;\n assigned_by: string;\n}\n\ninterface TaskStatusChangedPayload {\n task_id: string;\n status_from: string;\n status_to: string;\n changed_by: string;\n}\n\ninterface ReminderScheduledPayload {\n reminder_id: string;\n conversation_id: string;\n scheduled_for: string;\n scheduled_by: string;\n}\n\ninterface ReminderTriggeredPayload {\n reminder_id: string;\n trigger_result: string;\n notification_attempted: boolean;\n}\n\ninterface TranslationRequestedPayload {\n target_language: string;\n source_language: string;\n char_count: number;\n mode: string;\n}\n\ninterface TranslationCompletedPayload {\n target_language: string;\n provider: string;\n latency_ms: number;\n success: boolean;\n error_code?: string;\n}\n\ninterface NotificationSentPayload {\n notification_id: string;\n channel: string;\n platform: string;\n recipient_ref: string;\n success: boolean;\n}\n\ninterface NotificationDeliveredPayload {\n notification_id: string;\n platform: string;\n delivered_at: string;\n}\n\ninterface NotificationOpenedPayload {\n notification_id: string;\n platform: string;\n opened_at: string;\n}\n\ninterface ProviderSyncStartedPayload {\n provider_system: string;\n operation: string;\n scope: string;\n batch_id: string;\n}\n\ninterface ProviderSyncSucceededPayload {\n provider_system: string;\n operation: string;\n batch_id: string;\n records_processed: number;\n duration_ms: number;\n}\n\ninterface ProviderSyncFailedPayload {\n provider_system: string;\n operation: string;\n batch_id: string;\n error_code: string;\n retryable: boolean;\n}\n\ninterface AuthLoginSucceededPayload {\n auth_provider: string;\n platform: string;\n session_ref: string;\n}\n\ninterface AuthLoginFailedPayload {\n auth_provider: string;\n platform: string;\n failure_code: string;\n}\n\ninterface SecurityAccessDeniedPayload {\n resource: string;\n policy: string;\n reason_code: string;\n actor_id: string;\n}\n\n// ---------------------------------------------------------------------------\n// Event type -> payload mapping\n// ---------------------------------------------------------------------------\n\n/**\n * Maps each event type string to its required payload interface.\n */\ninterface EventPayloadMap {\n \"conversation.created.v1\": ConversationCreatedPayload;\n \"conversation.message_sent.v1\": ConversationMessageSentPayload;\n \"conversation.message_received.v1\": ConversationMessageReceivedPayload;\n \"conversation.marked_read.v1\": ConversationMarkedReadPayload;\n \"conversation.attachment_uploaded.v1\": ConversationAttachmentUploadedPayload;\n \"conversation.attachment_downloaded.v1\": ConversationAttachmentDownloadedPayload;\n \"call.initiated.v1\": CallInitiatedPayload;\n \"call.connected.v1\": CallConnectedPayload;\n \"call.ended.v1\": CallEndedPayload;\n \"call.missed.v1\": CallMissedPayload;\n \"task.created.v1\": TaskCreatedPayload;\n \"task.assigned.v1\": TaskAssignedPayload;\n \"task.status_changed.v1\": TaskStatusChangedPayload;\n \"reminder.scheduled.v1\": ReminderScheduledPayload;\n \"reminder.triggered.v1\": ReminderTriggeredPayload;\n \"translation.requested.v1\": TranslationRequestedPayload;\n \"translation.completed.v1\": TranslationCompletedPayload;\n \"notification.sent.v1\": NotificationSentPayload;\n \"notification.delivered.v1\": NotificationDeliveredPayload;\n \"notification.opened.v1\": NotificationOpenedPayload;\n \"provider.sync_started.v1\": ProviderSyncStartedPayload;\n \"provider.sync_succeeded.v1\": ProviderSyncSucceededPayload;\n \"provider.sync_failed.v1\": ProviderSyncFailedPayload;\n \"auth.login_succeeded.v1\": AuthLoginSucceededPayload;\n \"auth.login_failed.v1\": AuthLoginFailedPayload;\n \"security.access_denied.v1\": SecurityAccessDeniedPayload;\n}\n\n// ---------------------------------------------------------------------------\n// Event envelope\n// ---------------------------------------------------------------------------\n\n/**\n * Subject references for the event. Uses tokenized references only -- no PHI.\n */\ninterface EventSubject {\n patient_ref?: string;\n conversation_id?: string;\n task_id?: string;\n call_id?: string;\n}\n\n/**\n * Actor who triggered the event.\n */\ninterface EventActor {\n actor_id: string;\n actor_type: \"user\" | \"system\" | \"webhook\";\n}\n\n/**\n * Compliance metadata for the event.\n */\ninterface EventCompliance {\n pii_level: \"none\" | \"limited\" | \"full\";\n contains_phi: boolean;\n consent_context: string;\n retention_class: string;\n}\n\n/**\n * Canonical event envelope. Every tracked event is wrapped in this structure\n * before being sent to the Truth API.\n */\ninterface EventEnvelope {\n event_id: string;\n event_type: string;\n schema_version: number;\n occurred_at: string;\n received_at: string;\n source: string;\n source_version: string;\n tenant_id: string;\n actor?: EventActor;\n subject?: EventSubject;\n compliance?: EventCompliance;\n payload: Record<string, unknown>;\n}\n\n// ---------------------------------------------------------------------------\n// Track options (per-call overrides)\n// ---------------------------------------------------------------------------\n\n/**\n * Optional overrides when calling truth.track().\n */\ninterface TrackOptions {\n /** Override the default actor for this event */\n actor?: EventActor;\n\n /** Subject references for this event */\n subject?: EventSubject;\n\n /** Compliance metadata for this event */\n compliance?: EventCompliance;\n\n /** Override the default tenant ID for this event */\n tenantId?: string;\n\n /** Override the occurred_at timestamp (ISO 8601) */\n occurredAt?: string;\n}\n\nexport {\n EVENT_TYPES,\n CONVERSATION_EVENTS,\n CALL_EVENTS,\n TASK_EVENTS,\n REMINDER_EVENTS,\n TRANSLATION_EVENTS,\n NOTIFICATION_EVENTS,\n PROVIDER_EVENTS,\n AUTH_EVENTS,\n SECURITY_EVENTS,\n};\n\nexport type {\n EventType,\n ConversationEventType,\n CallEventType,\n TaskEventType,\n ReminderEventType,\n TranslationEventType,\n NotificationEventType,\n ProviderEventType,\n AuthEventType,\n SecurityEventType,\n EventPayloadMap,\n EventEnvelope,\n EventActor,\n EventSubject,\n EventCompliance,\n TrackOptions,\n ConversationCreatedPayload,\n ConversationMessageSentPayload,\n ConversationMessageReceivedPayload,\n ConversationMarkedReadPayload,\n ConversationAttachmentUploadedPayload,\n ConversationAttachmentDownloadedPayload,\n CallInitiatedPayload,\n CallConnectedPayload,\n CallEndedPayload,\n CallMissedPayload,\n TaskCreatedPayload,\n TaskAssignedPayload,\n TaskStatusChangedPayload,\n ReminderScheduledPayload,\n ReminderTriggeredPayload,\n TranslationRequestedPayload,\n TranslationCompletedPayload,\n NotificationSentPayload,\n NotificationDeliveredPayload,\n NotificationOpenedPayload,\n ProviderSyncStartedPayload,\n ProviderSyncSucceededPayload,\n ProviderSyncFailedPayload,\n AuthLoginSucceededPayload,\n AuthLoginFailedPayload,\n SecurityAccessDeniedPayload,\n};\n","/**\n * Configuration interfaces for the Truth SDK.\n */\n\n/**\n * Environment options for the Truth platform.\n */\nconst ENVIRONMENTS = {\n local: \"local\",\n staging: \"staging\",\n sandbox: \"sandbox\",\n uat: \"uat\",\n production: \"production\",\n} as const;\n\ntype Environment = (typeof ENVIRONMENTS)[keyof typeof ENVIRONMENTS];\n\n/**\n * Configuration for initializing a TruthClient.\n */\ninterface TruthClientConfig {\n /** API key for authenticating with the Truth platform (e.g. \"hn_live_...\") */\n apiKey: string;\n\n /** Target environment */\n environment: Environment;\n\n /** Override the default Convex URL for data access */\n convexUrl?: string;\n\n /** Event source identifier (e.g. \"communication-hub.backend\") */\n source?: string;\n\n /** Git SHA or version string for event source versioning */\n sourceVersion?: string;\n\n /** Default tenant (organization) ID for events */\n tenantId?: string;\n\n /** Number of events to buffer before flushing (default: 25) */\n batchSize?: number;\n\n /** Interval in milliseconds between automatic flushes (default: 5000) */\n flushIntervalMs?: number;\n\n /** Base URL for the Truth API (overrides environment-based default) */\n apiBaseUrl?: string;\n}\n\n/**\n * Actor context attached to tracked events.\n */\ninterface ActorContext {\n actorId: string;\n actorType: \"user\" | \"system\" | \"webhook\";\n}\n\n/**\n * Paginated result wrapper for list operations.\n */\ninterface PaginatedResult<T> {\n data: T[];\n cursor: string | null;\n hasMore: boolean;\n}\n\nexport { ENVIRONMENTS };\nexport type { Environment, TruthClientConfig, ActorContext, PaginatedResult };\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACaA,qBAAiC;;;ACJjC,IAAM,sBAAN,MAA0B;AAAA,EAGxB,YAAY,cAAgC;AAC1C,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKM,IAAI,IAAyC;AAAA;AACjD,UAAI;AACF,cAAM,SAAS,MAAM,KAAK,OAAO;AAAA,UAC/B;AAAA,UACA,EAAE,GAAG;AAAA,QACP;AACA,eAAQ,0BAA0B;AAAA,MACpC,SAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAKM,KACJ,SACuC;AAAA;AACvC,UAAI;AACF,cAAM,SAAS,MAAM,KAAK,OAAO;AAAA,UAC/B;AAAA,UACA;AAAA,YACE,WAAW,mCAAS;AAAA,YACpB,WAAW,mCAAS;AAAA,YACpB,SAAS,mCAAS;AAAA,YAClB,QAAQ,mCAAS;AAAA,YACjB,OAAO,mCAAS;AAAA,YAChB,QAAQ,mCAAS;AAAA,UACnB;AAAA,QACF;AAEA,cAAM,QAAQ;AAEd,eAAO,wBAAS,EAAE,MAAM,CAAC,GAAG,QAAQ,MAAM,SAAS,MAAM;AAAA,MAC3D,SAAQ;AACN,eAAO,EAAE,MAAM,CAAC,GAAG,QAAQ,MAAM,SAAS,MAAM;AAAA,MAClD;AAAA,IACF;AAAA;AACF;;;ACUA,IAAM,kBAAN,MAAsB;AAAA,EAGpB,YAAY,YAAoB;AAC9B,SAAK,UAAU;AAAA,EACjB;AAAA;AAAA;AAAA;AAAA,EAKM,QAAQ,QAAiD;AAAA;AAC7D,YAAM,OAAO;AAAA,QACX,YAAY,CAAC,OAAO,SAAS;AAAA,QAC7B,aAAa,OAAO;AAAA,QACpB,oBAAoB;AAAA,SAChB,OAAO,UAAU,EAAE,MAAM,OAAO,QAAQ,IAAI,CAAC,IAC7C,OAAO,QAAQ,EAAE,OAAO,OAAO,MAAM,IAAI,CAAC;AAGhD,aAAO,KAAK,KAAsB,QAAQ,IAAI;AAAA,IAChD;AAAA;AAAA;AAAA;AAAA;AAAA,EAKM,aACJ,QACA,aAC+B;AAAA;AAC/B,aAAO,KAAK,KAA2B,UAAU,MAAM,kBAAkB;AAAA,QACvE,cAAc;AAAA,MAChB,CAAC;AAAA,IACH;AAAA;AAAA;AAAA;AAAA;AAAA,EAKM,WAAW,QAA+B;AAAA;AAC9C,YAAM,KAAK,IAAI,SAAS,MAAM,iBAAiB;AAAA,IACjD;AAAA;AAAA;AAAA;AAAA;AAAA,EAKM,cAAc,QAAoD;AAAA;AACtE,UAAI;AACF,eAAO,MAAM,KAAK,IAAwB,SAAS,MAAM,EAAE;AAAA,MAC7D,SAAS,OAAO;AACd,YAAI,iBAAiB,qBAAqB,MAAM,WAAW,KAAK;AAC9D,iBAAO;AAAA,QACT;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAKM,QAAQ,QAAsD;AAAA;AAClE,UAAI;AACF,eAAO,MAAM,KAAK,IAAiB,UAAU,MAAM,EAAE;AAAA,MACvD,SAAS,OAAO;AACd,YAAI,iBAAiB,qBAAqB,MAAM,WAAW,KAAK;AAC9D,iBAAO;AAAA,QACT;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAKM,eAAe,OAA4C;AAAA;AA3InE;AA4II,YAAM,SAAS,MAAM,KAAK,IAA6B,UAAU;AAAA,QAC/D;AAAA,MACF,CAAC;AACD,cAAO,kBAAO,UAAP,mBAAe,OAAf,YAAqB;AAAA,IAC9B;AAAA;AAAA;AAAA;AAAA;AAAA,EAKM,qBAAqB,aAAkD;AAAA;AArJ/E;AAsJI,YAAM,SAAS,MAAM,KAAK,IAA6B,UAAU;AAAA,QAC/D,QAAQ;AAAA,MACV,CAAC;AACD,cAAO,kBAAO,UAAP,mBAAe,OAAf,YAAqB;AAAA,IAC9B;AAAA;AAAA;AAAA;AAAA;AAAA,EAKM,cAAc,aAAwD;AAAA;AAC1E,UAAI;AACF,cAAM,cAAc,YAAY,QAAQ,WAAW,EAAE;AACrD,eAAO,MAAM,KAAK;AAAA,UAChB,YAAY,mBAAmB,WAAW,CAAC;AAAA,QAC7C;AAAA,MACF,SAAS,OAAO;AACd,YAAI,iBAAiB,qBAAqB,MAAM,WAAW,KAAK;AAC9D,iBAAO;AAAA,QACT;AACA,cAAM;AAAA,MACR;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMM,sBAAsB,eAA+C;AAAA;AACzE,YAAM,MAAM,GAAG,KAAK,OAAO;AAE3B,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QAChC,QAAQ;AAAA,QACR,SAAS,EAAE,gBAAgB,mBAAmB;AAAA,QAC9C,MAAM,KAAK,UAAU,EAAE,gBAAgB,cAAc,CAAC;AAAA,MACxD,CAAC;AAED,YAAM,SAAU,MAAM,SAAS,KAAK;AAEpC,UAAI,CAAC,SAAS,MAAM,CAAC,OAAO,SAAS;AACnC,eAAO;AAAA,MACT;AAEA,aAAO,OAAO;AAAA,IAChB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMc,IACZ,MACA,QACY;AAAA;AACZ,YAAM,MAAM,IAAI,IAAI,wBAAwB,IAAI,IAAI,KAAK,OAAO;AAChE,UAAI,QAAQ;AACV,mBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,cAAI,UAAU,QAAW;AACvB,gBAAI,aAAa,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,UACzC;AAAA,QACF;AAAA,MACF;AAEA,YAAM,WAAW,MAAM,MAAM,IAAI,SAAS,GAAG;AAAA,QAC3C,QAAQ;AAAA,QACR,SAAS,EAAE,QAAQ,mBAAmB;AAAA,MACxC,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,kBAAkB,OAAO,MAAM,SAAS,MAAM;AAAA,MAC1D;AAEA,aAAQ,MAAM,SAAS,KAAK;AAAA,IAC9B;AAAA;AAAA,EAEc,KAAQ,MAAc,MAA4B;AAAA;AAC9D,YAAM,MAAM,GAAG,KAAK,OAAO,wBAAwB,IAAI;AAEvD,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QAChC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,QAAQ;AAAA,QACV;AAAA,QACA,MAAM,SAAS,SAAY,KAAK,UAAU,IAAI,IAAI;AAAA,MACpD,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,kBAAkB,QAAQ,MAAM,SAAS,MAAM;AAAA,MAC3D;AAEA,aAAQ,MAAM,SAAS,KAAK;AAAA,IAC9B;AAAA;AAAA,EAEc,IAAc,MAAc,MAA4B;AAAA;AAnPxE;AAoPI,YAAM,MAAM,GAAG,KAAK,OAAO,wBAAwB,IAAI;AAEvD,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QAChC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,QAAQ;AAAA,QACV;AAAA,QACA,MAAM,SAAS,SAAY,KAAK,UAAU,IAAI,IAAI;AAAA,MACpD,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,kBAAkB,OAAO,MAAM,SAAS,MAAM;AAAA,MAC1D;AAEA,WAAI,cAAS,QAAQ,IAAI,cAAc,MAAnC,mBAAsC,SAAS,SAAS;AAC1D,eAAQ,MAAM,SAAS,KAAK;AAAA,MAC9B;AAEA,aAAO;AAAA,IACT;AAAA;AACF;AAMA,IAAM,mBAAN,MAAuB;AAAA,EAGrB,YAAY,YAAoB;AAC9B,SAAK,UAAU,IAAI,gBAAgB,UAAU;AAAA,EAC/C;AACF;AAMA,IAAM,oBAAN,cAAgC,MAAM;AAAA,EAKpC,YAAY,QAAgB,MAAc,QAAgB;AACxD;AAAA,MACE,wBAAwB,MAAM,yBAAyB,IAAI,aAAa,MAAM;AAAA,IAChF;AACA,SAAK,OAAO;AACZ,SAAK,SAAS;AACd,SAAK,OAAO;AACZ,SAAK,SAAS;AAAA,EAChB;AACF;;;ACvRA,IAAM,mBAAN,MAAuB;AAAA,EAIrB,YAAY,YAAoB,UAAkB;AAChD,SAAK,UAAU;AACf,SAAK,WAAW;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOM,IACJ,MACA,QACY;AAAA;AACZ,YAAM,MAAM,IAAI,IAAI,YAAY,KAAK,QAAQ,GAAG,IAAI,IAAI,KAAK,OAAO;AACpE,UAAI,QAAQ;AACV,mBAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,GAAG;AACjD,cAAI,UAAU,QAAW;AACvB,gBAAI,aAAa,IAAI,KAAK,OAAO,KAAK,CAAC;AAAA,UACzC;AAAA,QACF;AAAA,MACF;AAEA,YAAM,WAAW,MAAM,MAAM,IAAI,SAAS,GAAG;AAAA,QAC3C,QAAQ;AAAA,QACR,SAAS,EAAE,QAAQ,mBAAmB;AAAA,MACxC,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,cAAc,KAAK,UAAU,OAAO,MAAM,SAAS,MAAM;AAAA,MACrE;AAEA,aAAQ,MAAM,SAAS,KAAK;AAAA,IAC9B;AAAA;AAAA;AAAA;AAAA;AAAA,EAKM,KAAkB,MAAc,MAA4B;AAAA;AAChE,YAAM,MAAM,GAAG,KAAK,OAAO,YAAY,KAAK,QAAQ,GAAG,IAAI;AAE3D,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QAChC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,QAAQ;AAAA,QACV;AAAA,QACA,MAAM,SAAS,SAAY,KAAK,UAAU,IAAI,IAAI;AAAA,MACpD,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,cAAc,KAAK,UAAU,QAAQ,MAAM,SAAS,MAAM;AAAA,MACtE;AAEA,aAAQ,MAAM,SAAS,KAAK;AAAA,IAC9B;AAAA;AAAA;AAAA;AAAA;AAAA,EAKM,IAAiB,MAAc,MAA4B;AAAA;AAC/D,YAAM,MAAM,GAAG,KAAK,OAAO,YAAY,KAAK,QAAQ,GAAG,IAAI;AAE3D,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QAChC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,QAAQ;AAAA,QACV;AAAA,QACA,MAAM,SAAS,SAAY,KAAK,UAAU,IAAI,IAAI;AAAA,MACpD,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,cAAc,KAAK,UAAU,OAAO,MAAM,SAAS,MAAM;AAAA,MACrE;AAEA,aAAQ,MAAM,SAAS,KAAK;AAAA,IAC9B;AAAA;AAAA;AAAA;AAAA;AAAA,EAKM,MAAmB,MAAc,MAA4B;AAAA;AACjE,YAAM,MAAM,GAAG,KAAK,OAAO,YAAY,KAAK,QAAQ,GAAG,IAAI;AAE3D,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QAChC,QAAQ;AAAA,QACR,SAAS;AAAA,UACP,gBAAgB;AAAA,UAChB,QAAQ;AAAA,QACV;AAAA,QACA,MAAM,SAAS,SAAY,KAAK,UAAU,IAAI,IAAI;AAAA,MACpD,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,cAAc,KAAK,UAAU,SAAS,MAAM,SAAS,MAAM;AAAA,MACvE;AAEA,aAAQ,MAAM,SAAS,KAAK;AAAA,IAC9B;AAAA;AAAA;AAAA;AAAA;AAAA,EAKM,OAAoB,MAA0B;AAAA;AAClD,YAAM,MAAM,GAAG,KAAK,OAAO,YAAY,KAAK,QAAQ,GAAG,IAAI;AAE3D,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QAChC,QAAQ;AAAA,QACR,SAAS,EAAE,QAAQ,mBAAmB;AAAA,MACxC,CAAC;AAED,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,IAAI,cAAc,KAAK,UAAU,UAAU,MAAM,SAAS,MAAM;AAAA,MACxE;AAEA,aAAQ,MAAM,SAAS,KAAK;AAAA,IAC9B;AAAA;AACF;AAMA,IAAM,cAAN,MAAkB;AAAA,EAOhB,YAAY,YAAoB;AAC9B,SAAK,UAAU,IAAI,iBAAiB,YAAY,SAAS;AACzD,SAAK,OAAO,IAAI,iBAAiB,YAAY,MAAM;AAAA,EACrD;AACF;AAMA,IAAM,gBAAN,cAA4B,MAAM;AAAA,EAMhC,YAAY,UAAkB,QAAgB,MAAc,QAAgB;AAC1E;AAAA,MACE,oBAAoB,MAAM,aAAa,QAAQ,GAAG,IAAI,aAAa,MAAM;AAAA,IAC3E;AACA,SAAK,OAAO;AACZ,SAAK,WAAW;AAChB,SAAK,SAAS;AACd,SAAK,OAAO;AACZ,SAAK,SAAS;AAAA,EAChB;AACF;;;AC1KA,IAAM,kBAAN,MAAsB;AAAA,EAGpB,YAAY,cAAgC;AAC1C,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA,EAKM,IAAI,IAAqC;AAAA;AAC7C,UAAI;AACF,cAAM,SAAS,MAAM,KAAK,OAAO;AAAA,UAC/B;AAAA,UACA;AAAA,YACE;AAAA,UACF;AAAA,QACF;AACA,eAAQ,0BAAsB;AAAA,MAChC,SAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAKM,eAAe,WAA4C;AAAA;AAC/D,UAAI;AACF,cAAM,SAAS,MAAM,KAAK,OAAO;AAAA,UAC/B;AAAA,UACA,EAAE,UAAU;AAAA,QACd;AACA,eAAQ,0BAAsB;AAAA,MAChC,SAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAKM,YAAY,QAAyC;AAAA;AACzD,UAAI;AACF,cAAM,SAAS,MAAM,KAAK,OAAO;AAAA,UAC/B;AAAA,UACA;AAAA,YACE;AAAA,UACF;AAAA,QACF;AACA,eAAQ,0BAAsB;AAAA,MAChC,SAAQ;AACN,eAAO;AAAA,MACT;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAKM,KAAK,SAAiE;AAAA;AAC1E,UAAI;AACF,cAAM,SAAS,MAAM,KAAK,OAAO;AAAA,UAC/B;AAAA,UACA;AAAA,YACE,QAAQ,mCAAS;AAAA,YACjB,OAAO,mCAAS;AAAA,YAChB,QAAQ,mCAAS;AAAA,UACnB;AAAA,QACF;AAEA,cAAM,QAAQ;AAEd,eAAO,wBAAS,EAAE,MAAM,CAAC,GAAG,QAAQ,MAAM,SAAS,MAAM;AAAA,MAC3D,SAAQ;AACN,eAAO,EAAE,MAAM,CAAC,GAAG,QAAQ,MAAM,SAAS,MAAM;AAAA,MAClD;AAAA,IACF;AAAA;AACF;;;ACvDA,SAAS,iBAAyB;AAChC,QAAM,MAAM,KAAK,IAAI;AAGrB,QAAM,YAAY,IAAI,WAAW,CAAC;AAClC,MAAI,KAAK;AACT,WAAS,IAAI,GAAG,KAAK,GAAG,KAAK;AAC3B,cAAU,CAAC,IAAI,KAAK;AACpB,SAAK,KAAK,MAAM,KAAK,GAAG;AAAA,EAC1B;AAGA,QAAM,cAAc,IAAI,WAAW,EAAE;AACrC,MACE,OAAO,WAAW,WAAW,eAC7B,WAAW,OAAO,iBAClB;AACA,eAAW,OAAO,gBAAgB,WAAW;AAAA,EAC/C,OAAO;AACL,aAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,kBAAY,CAAC,IAAI,KAAK,MAAM,KAAK,OAAO,IAAI,GAAG;AAAA,IACjD;AAAA,EACF;AAGA,QAAM,QAAQ,IAAI,WAAW,EAAE;AAC/B,QAAM,IAAI,WAAW,CAAC;AACtB,QAAM,IAAI,aAAa,CAAC;AAGxB,QAAM,CAAC,IAAK,MAAM,CAAC,IAAI,KAAQ;AAG/B,QAAM,CAAC,IAAK,MAAM,CAAC,IAAI,KAAQ;AAG/B,QAAM,MAAM,MAAM,KAAK,KAAK,EACzB,IAAI,CAAC,MAAM,EAAE,SAAS,EAAE,EAAE,SAAS,GAAG,GAAG,CAAC,EAC1C,KAAK,EAAE;AAEV,SAAO;AAAA,IACL,IAAI,MAAM,GAAG,CAAC;AAAA,IACd,IAAI,MAAM,GAAG,EAAE;AAAA,IACf,IAAI,MAAM,IAAI,EAAE;AAAA,IAChB,IAAI,MAAM,IAAI,EAAE;AAAA,IAChB,IAAI,MAAM,IAAI,EAAE;AAAA,EAClB,EAAE,KAAK,GAAG;AACZ;AAMA,IAAM,WAAmC;AAAA,EACvC,OAAO;AAAA,EACP,SAAS;AAAA,EACT,SAAS;AAAA,EACT,KAAK;AAAA,EACL,YAAY;AACd;AAMA,IAAM,qBAAqB;AAC3B,IAAM,4BAA4B;AAClC,IAAM,cAAc;AACpB,IAAM,sBAAsB;AAqB5B,IAAM,UAAN,MAAc;AAAA,EASZ,YAAY,QAAuB;AANnC,SAAQ,QAAyB,CAAC;AAClC,SAAQ,aAAoD;AAE5D,SAAQ,aAAa;AACrB,SAAQ,aAAa;AA/HvB;AAkII,SAAK,SAAS;AACd,SAAK,UACH,kBAAO,eAAP,YAAqB,SAAS,OAAO,WAAW,MAAhD,YAAqD,SAAS;AAEhE,SAAK,mBAAmB;AACxB,SAAK,sBAAsB;AAAA,EAC7B;AAAA;AAAA;AAAA;AAAA,EAKA,SAAS,OAA2B;AAClC,SAAK,eAAe;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,MACE,WACA,SACA,SACM;AAzJV;AA0JI,QAAI,KAAK,YAAY;AACnB;AAAA,IACF;AAEA,UAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AAEnC,UAAM,WAA0B;AAAA,MAC9B,UAAU,eAAe;AAAA,MACzB,YAAY;AAAA,MACZ,gBAAgB;AAAA,MAChB,cAAa,wCAAS,eAAT,YAAuB;AAAA,MACpC,aAAa;AAAA,MACb,QAAQ,KAAK,OAAO;AAAA,MACpB,gBAAgB,KAAK,OAAO;AAAA,MAC5B,YAAW,wCAAS,aAAT,YAAqB,KAAK,OAAO;AAAA,MAC5C,QACE,wCAAS,UAAT,YACC,KAAK,eACF;AAAA,QACE,UAAU,KAAK,aAAa;AAAA,QAC5B,YAAY,KAAK,aAAa;AAAA,MAChC,IACA;AAAA,MACN,SAAS,mCAAS;AAAA,MAClB,YAAY,mCAAS;AAAA,MACrB;AAAA,IACF;AAEA,SAAK,MAAM,KAAK,QAAQ;AAExB,QAAI,KAAK,MAAM,UAAU,KAAK,OAAO,WAAW;AAC9C,WAAK,KAAK,MAAM;AAAA,IAClB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMM,QAAuB;AAAA;AAC3B,UAAI,KAAK,MAAM,WAAW,KAAK,KAAK,YAAY;AAC9C;AAAA,MACF;AAEA,WAAK,aAAa;AAClB,YAAM,QAAQ,KAAK,MAAM,OAAO,GAAG,KAAK,OAAO,SAAS;AAExD,UAAI;AACF,cAAM,KAAK,UAAU,KAAK;AAAA,MAC5B,SAAQ;AAEN,aAAK,MAAM,QAAQ,GAAG,KAAK;AAAA,MAC7B,UAAE;AACA,aAAK,aAAa;AAAA,MACpB;AAGA,UAAI,KAAK,MAAM,UAAU,KAAK,OAAO,WAAW;AAC9C,cAAM,KAAK,MAAM;AAAA,MACnB;AAAA,IACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMM,WAA0B;AAAA;AAC9B,WAAK,aAAa;AAClB,WAAK,kBAAkB;AACvB,YAAM,KAAK,MAAM;AAAA,IACnB;AAAA;AAAA;AAAA;AAAA;AAAA,EAKc,UAAU,OAAuC;AAAA;AAC7D,UAAI;AAEJ,eAAS,UAAU,GAAG,WAAW,aAAa,WAAW;AACvD,YAAI;AACF,gBAAM,WAAW,MAAM,MAAM,GAAG,KAAK,MAAM,sBAAsB;AAAA,YAC/D,QAAQ;AAAA,YACR,SAAS;AAAA,cACP,gBAAgB;AAAA,cAChB,eAAe,UAAU,KAAK,OAAO,MAAM;AAAA,YAC7C;AAAA,YACA,MAAM,KAAK,UAAU,EAAE,QAAQ,MAAM,CAAC;AAAA,UACxC,CAAC;AAED,cAAI,SAAS,IAAI;AACf;AAAA,UACF;AAGA,cACE,SAAS,UAAU,OACnB,SAAS,SAAS,OAClB,SAAS,WAAW,KACpB;AACA;AAAA,UACF;AAEA,sBAAY,IAAI;AAAA,YACd,QAAQ,SAAS,MAAM,KAAK,SAAS,UAAU;AAAA,UACjD;AAAA,QACF,SAAS,OAAO;AACd,sBAAY;AAAA,QACd;AAGA,YAAI,UAAU,aAAa;AACzB,gBAAM,QAAQ,sBAAsB,SAAK;AACzC,gBAAM,SAAS,KAAK,OAAO,IAAI,QAAQ;AACvC,gBAAM,MAAM,QAAQ,MAAM;AAAA,QAC5B;AAAA,MACF;AAEA,YAAM;AAAA,IACR;AAAA;AAAA,EAEQ,qBAA2B;AACjC,QAAI,KAAK,OAAO,kBAAkB,GAAG;AACnC,WAAK,aAAa,YAAY,MAAM;AAClC,aAAK,KAAK,MAAM;AAAA,MAClB,GAAG,KAAK,OAAO,eAAe;AAG9B,UAAI,OAAO,KAAK,eAAe,YAAY,WAAW,KAAK,YAAY;AACrE,aAAK,WAAW,MAAM;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AAAA,EAEQ,oBAA0B;AAChC,QAAI,KAAK,eAAe,MAAM;AAC5B,oBAAc,KAAK,UAAU;AAC7B,WAAK,aAAa;AAAA,IACpB;AAAA,EACF;AAAA,EAEQ,wBAA8B;AAEpC,QAAI,OAAO,WAAW,YAAY,eAAe,WAAW,QAAQ,IAAI;AACtE,YAAM,kBAAkB,MAAM;AAC5B,aAAK,KAAK,SAAS;AAAA,MACrB;AAEA,iBAAW,QAAQ,GAAG,cAAc,eAAe;AACnD,iBAAW,QAAQ,GAAG,WAAW,eAAe;AAAA,IAClD;AAAA,EACF;AACF;AAMA,SAAS,MAAM,IAA2B;AACxC,SAAO,IAAI,QAAQ,CAAC,YAAY,WAAW,SAAS,EAAE,CAAC;AACzD;;;ALvRA,IAAM,cAAsC;AAAA,EAC1C,OAAO;AAAA,EACP,SAAS;AAAA,EACT,KAAK;AAAA,EACL,YAAY;AACd;AAMA,IAAM,cAAN,MAAkB;AAAA,EAgBhB,YAAY,QAA2B;AA7DzC;AA+DI,UAAM,aACJ,kBAAO,cAAP,YAAoB,YAAY,OAAO,WAAW,MAAlD,YAAuD,YAAY;AAGrE,SAAK,SAAS,IAAI,gCAAiB,SAAS;AAG5C,SAAK,UAAU,IAAI,QAAQ;AAAA,MACzB,QAAQ,OAAO;AAAA,MACf,aAAa,OAAO;AAAA,MACpB,SAAQ,YAAO,WAAP,YAAiB;AAAA,MACzB,gBAAe,YAAO,kBAAP,YAAwB;AAAA,MACvC,WAAU,YAAO,aAAP,YAAmB;AAAA,MAC7B,YAAW,YAAO,cAAP,YAAoB;AAAA,MAC/B,kBAAiB,YAAO,oBAAP,YAA0B;AAAA,MAC3C,YAAY,OAAO;AAAA,IACrB,CAAC;AAED,UAAM,SAAS,KAAK,QAAQ;AAG5B,SAAK,WAAW,IAAI,gBAAgB,KAAK,MAAM;AAC/C,SAAK,eAAe,IAAI,oBAAoB,KAAK,MAAM;AACvD,SAAK,MAAM,IAAI,YAAY,MAAM;AACjC,SAAK,WAAW,IAAI,iBAAiB,MAAM;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,IAAI,aAAqB;AACvB,WAAO,KAAK,QAAQ;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBA,MACE,WACA,SACA,SACM;AACN,SAAK,QAAQ,MAAM,WAAW,SAAS,OAAO;AAAA,EAChD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,SAAS,SAAiB,WAA4C;AACpE,SAAK,QAAQ,SAAS,EAAE,SAAS,UAAU,CAAC;AAAA,EAC9C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcM,QAAuB;AAAA;AAC3B,YAAM,KAAK,QAAQ,MAAM;AAAA,IAC3B;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMM,UAAyB;AAAA;AAC7B,YAAM,KAAK,QAAQ,SAAS;AAAA,IAC9B;AAAA;AACF;;;AMxJA,IAAM,sBAAsB;AAAA,EAC1B,SAAS;AAAA,EACT,aAAa;AAAA,EACb,iBAAiB;AAAA,EACjB,YAAY;AAAA,EACZ,oBAAoB;AAAA,EACpB,sBAAsB;AACxB;AAEA,IAAM,cAAc;AAAA,EAClB,WAAW;AAAA,EACX,WAAW;AAAA,EACX,OAAO;AAAA,EACP,QAAQ;AACV;AAEA,IAAM,cAAc;AAAA,EAClB,SAAS;AAAA,EACT,UAAU;AAAA,EACV,eAAe;AACjB;AAEA,IAAM,kBAAkB;AAAA,EACtB,WAAW;AAAA,EACX,WAAW;AACb;AAEA,IAAM,qBAAqB;AAAA,EACzB,WAAW;AAAA,EACX,WAAW;AACb;AAEA,IAAM,sBAAsB;AAAA,EAC1B,MAAM;AAAA,EACN,WAAW;AAAA,EACX,QAAQ;AACV;AAEA,IAAM,kBAAkB;AAAA,EACtB,aAAa;AAAA,EACb,eAAe;AAAA,EACf,YAAY;AACd;AAEA,IAAM,cAAc;AAAA,EAClB,gBAAgB;AAAA,EAChB,aAAa;AACf;AAEA,IAAM,kBAAkB;AAAA,EACtB,cAAc;AAChB;AAKA,IAAM,cAAc;AAAA,EAClB,cAAc;AAAA,EACd,MAAM;AAAA,EACN,MAAM;AAAA,EACN,UAAU;AAAA,EACV,aAAa;AAAA,EACb,cAAc;AAAA,EACd,UAAU;AAAA,EACV,MAAM;AAAA,EACN,UAAU;AACZ;;;ACtEA,IAAM,eAAe;AAAA,EACnB,OAAO;AAAA,EACP,SAAS;AAAA,EACT,SAAS;AAAA,EACT,KAAK;AAAA,EACL,YAAY;AACd;","names":[]}
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts","../src/resources/appointments.ts","../src/resources/dialpad.ts","../src/resources/ehr.ts","../src/resources/patients.ts","../src/tracking/tracker.ts","../src/tracking/events.ts","../src/types/config.ts"],"sourcesContent":["/**\n * TruthClient -- main entry point for the @hipnation-truth/sdk package.\n *\n * Provides:\n * - `.patients` Resource-based patient data access (Convex-backed)\n * - `.appointments` Resource-based appointment data access (Convex-backed)\n * - `.ehr` EHR proxy access (Elation, Hint)\n * - `.messages` Messaging proxy access (Dialpad)\n * - `.track()` Fire-and-forget event tracking (batched HTTP -> Truth API)\n * - `.identify()` Set default actor context for subsequent events\n * - `.flush()` Force flush of buffered events (for graceful shutdown)\n */\n\nimport { ConvexHttpClient } from \"convex/browser\";\nimport { AppointmentResource } from \"./resources/appointments\";\nimport { MessagesResource } from \"./resources/dialpad\";\nimport { EhrResource } from \"./resources/ehr\";\nimport { PatientResource } from \"./resources/patients\";\nimport type {\n EventPayloadMap,\n EventType,\n TrackOptions,\n} from \"./tracking/events\";\nimport {\n DEFAULT_BATCH_SIZE,\n DEFAULT_FLUSH_INTERVAL_MS,\n Tracker,\n} from \"./tracking/tracker\";\nimport type { ActorContext, TruthClientConfig } from \"./types/config\";\n\n// ---------------------------------------------------------------------------\n// Environment -> Convex URL mapping\n// ---------------------------------------------------------------------------\n\nconst CONVEX_URLS: Record<string, string> = {\n local: \"http://localhost:3210\",\n staging: \"https://staging-truth.convex.cloud\",\n uat: \"https://uat-truth.convex.cloud\",\n production: \"https://truth.convex.cloud\",\n};\n\n// ---------------------------------------------------------------------------\n// TruthClient\n// ---------------------------------------------------------------------------\n\nclass TruthClient {\n /** Patient data resource (Convex-backed) */\n readonly patients: PatientResource;\n\n /** Appointment data resource (Convex-backed) */\n readonly appointments: AppointmentResource;\n\n /** EHR proxy — typed access to Elation and Hint APIs through Truth */\n readonly ehr: EhrResource;\n\n /** Messaging proxy — typed access to Dialpad APIs through Truth */\n readonly messages: MessagesResource;\n\n private readonly convex: ConvexHttpClient;\n private readonly tracker: Tracker;\n\n constructor(config: TruthClientConfig) {\n // Resolve Convex URL\n const convexUrl =\n config.convexUrl ?? CONVEX_URLS[config.environment] ?? CONVEX_URLS.local;\n\n // Initialize Convex HTTP client for data access\n this.convex = new ConvexHttpClient(convexUrl);\n\n // Initialize event tracker\n this.tracker = new Tracker({\n apiKey: config.apiKey,\n environment: config.environment,\n source: config.source ?? \"unknown\",\n sourceVersion: config.sourceVersion ?? \"unknown\",\n tenantId: config.tenantId ?? \"\",\n batchSize: config.batchSize ?? DEFAULT_BATCH_SIZE,\n flushIntervalMs: config.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS,\n apiBaseUrl: config.apiBaseUrl,\n });\n\n const apiUrl = this.tracker.apiUrl;\n\n // Initialize resources\n this.patients = new PatientResource(this.convex);\n this.appointments = new AppointmentResource(this.convex);\n this.ehr = new EhrResource(apiUrl);\n this.messages = new MessagesResource(apiUrl);\n }\n\n /**\n * The resolved Truth API base URL for this environment.\n * Use this when making HTTP calls to Truth's proxy endpoints\n * (e.g., EHR proxy, messages proxy).\n *\n * @example\n * ```ts\n * const url = `${truth.apiBaseUrl}/api/ehr/elation/patients/123`;\n * ```\n */\n get apiBaseUrl(): string {\n return this.tracker.apiUrl;\n }\n\n /**\n * Track an event. Fire-and-forget -- the event is buffered internally\n * and flushed in batches to the Truth API.\n *\n * @example\n * ```ts\n * truth.track('conversation.message_sent.v1', {\n * channel: 'sms',\n * direction: 'outbound',\n * message_chars: 140,\n * has_attachment: false,\n * provider_system: 'dialpad',\n * });\n * ```\n */\n track<T extends EventType>(\n eventType: T,\n payload: EventPayloadMap[T],\n options?: TrackOptions,\n ): void {\n this.tracker.track(eventType, payload, options);\n }\n\n /**\n * Set the default actor context for all subsequent tracked events.\n * Can be overridden per-event via TrackOptions.\n *\n * @example\n * ```ts\n * truth.identify('user_123', 'user');\n * ```\n */\n identify(actorId: string, actorType: ActorContext[\"actorType\"]): void {\n this.tracker.setActor({ actorId, actorType });\n }\n\n /**\n * Flush all buffered events immediately. Returns a Promise that resolves\n * when the flush completes. Use this for graceful shutdown.\n *\n * @example\n * ```ts\n * process.on('SIGTERM', async () => {\n * await truth.flush();\n * process.exit(0);\n * });\n * ```\n */\n async flush(): Promise<void> {\n await this.tracker.flush();\n }\n\n /**\n * Gracefully shut down the client. Flushes all pending events and\n * releases resources.\n */\n async destroy(): Promise<void> {\n await this.tracker.shutdown();\n }\n}\n\nexport { TruthClient };\n","/**\n * AppointmentResource provides data access to normalized appointment records\n * backed by Convex.\n */\n\nimport type { ConvexHttpClient } from \"convex/browser\";\nimport type { Appointment, AppointmentListOptions } from \"../types/appointment\";\nimport type { PaginatedResult } from \"../types/config\";\n\nclass AppointmentResource {\n private readonly convex: ConvexHttpClient;\n\n constructor(convexClient: ConvexHttpClient) {\n this.convex = convexClient;\n }\n\n /**\n * Get an appointment by its Truth platform ID.\n */\n async get(id: string): Promise<Appointment | null> {\n try {\n const result = await this.convex.query(\n \"appointments:getById\" as never,\n { id } as never,\n );\n return (result as Appointment) ?? null;\n } catch {\n return null;\n }\n }\n\n /**\n * List appointments with optional filters, pagination, and limit.\n */\n async list(\n options?: AppointmentListOptions,\n ): Promise<PaginatedResult<Appointment>> {\n try {\n const result = await this.convex.query(\n \"appointments:list\" as never,\n {\n patientId: options?.patientId,\n startDate: options?.startDate,\n endDate: options?.endDate,\n status: options?.status,\n limit: options?.limit,\n cursor: options?.cursor,\n } as never,\n );\n\n const typed = result as PaginatedResult<Appointment> | undefined;\n\n return typed ?? { data: [], cursor: null, hasMore: false };\n } catch {\n return { data: [], cursor: null, hasMore: false };\n }\n }\n}\n\nexport { AppointmentResource };\n","/**\n * Dialpad resource — typed access to Truth's Dialpad proxy endpoints.\n *\n * @example\n * ```ts\n * const sms = await truth.messages.dialpad.sendSms({ from_number, to_number, message });\n * const call = await truth.messages.dialpad.initiateCall(userId, phoneNumber);\n * await truth.messages.dialpad.hangupCall(callId);\n * const url = await truth.messages.dialpad.authenticateVoicemail(voicemailLink);\n * ```\n */\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface SendSmsParams {\n from_number: string;\n to_number: string;\n message?: string;\n media?: string;\n}\n\ninterface SendSmsResponse {\n id: string;\n message_status: string;\n [key: string]: unknown;\n}\n\ninterface InitiateCallResponse {\n call_id: number;\n [key: string]: unknown;\n}\n\ninterface CallStatusResponse {\n state: string;\n [key: string]: unknown;\n}\n\ninterface DialpadUser {\n id: number;\n emails: string[];\n first_name?: string;\n last_name?: string;\n [key: string]: unknown;\n}\n\ninterface DialpadUserListResponse {\n items: DialpadUser[];\n}\n\ninterface DialpadNumberInfo {\n user_id?: number;\n type?: string;\n [key: string]: unknown;\n}\n\ninterface VoicemailAuthResponse {\n success: boolean;\n authenticated_url: string | null;\n error?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Dialpad Resource\n// ---------------------------------------------------------------------------\n\nclass DialpadResource {\n private readonly baseUrl: string;\n\n constructor(apiBaseUrl: string) {\n this.baseUrl = apiBaseUrl;\n }\n\n /**\n * Send an SMS or MMS message via Dialpad.\n */\n async sendSms(params: SendSmsParams): Promise<SendSmsResponse> {\n const body = {\n to_numbers: [params.to_number],\n from_number: params.from_number,\n infer_country_code: false,\n ...(params.message ? { text: params.message } : {}),\n ...(params.media ? { media: params.media } : {}),\n };\n\n return this.post<SendSmsResponse>(\"/sms\", body);\n }\n\n /**\n * Initiate an outbound call from a Dialpad user to a phone number.\n */\n async initiateCall(\n userId: number,\n phoneNumber: string,\n ): Promise<InitiateCallResponse> {\n return this.post<InitiateCallResponse>(`/users/${userId}/initiate_call`, {\n phone_number: phoneNumber,\n });\n }\n\n /**\n * Hang up an active call.\n */\n async hangupCall(callId: number): Promise<void> {\n await this.put(`/call/${callId}/actions/hangup`);\n }\n\n /**\n * Get the status of a call.\n */\n async getCallStatus(callId: number): Promise<CallStatusResponse | null> {\n try {\n return await this.get<CallStatusResponse>(`/call/${callId}`);\n } catch (error) {\n if (error instanceof DialpadProxyError && error.status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Get a Dialpad user by their user ID.\n */\n async getUser(userId: string | number): Promise<DialpadUser | null> {\n try {\n return await this.get<DialpadUser>(`/users/${userId}`);\n } catch (error) {\n if (error instanceof DialpadProxyError && error.status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Find a Dialpad user by email.\n */\n async getUserByEmail(email: string): Promise<DialpadUser | null> {\n const result = await this.get<DialpadUserListResponse>(\"/users\", {\n email,\n });\n return result.items?.[0] ?? null;\n }\n\n /**\n * Find a Dialpad user by phone number.\n */\n async getUserByPhoneNumber(phoneNumber: string): Promise<DialpadUser | null> {\n const result = await this.get<DialpadUserListResponse>(\"/users\", {\n number: phoneNumber,\n });\n return result.items?.[0] ?? null;\n }\n\n /**\n * Get information about a Dialpad phone number.\n */\n async getNumberInfo(phoneNumber: string): Promise<DialpadNumberInfo | null> {\n try {\n const cleanNumber = phoneNumber.replace(/[^\\d+]/g, \"\");\n return await this.get<DialpadNumberInfo>(\n `/numbers/${encodeURIComponent(cleanNumber)}`,\n );\n } catch (error) {\n if (error instanceof DialpadProxyError && error.status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Authenticate a voicemail download URL. Truth appends the Dialpad API key,\n * follows redirects, and returns the clean URL for client-side playback.\n */\n async authenticateVoicemail(voicemailLink: string): Promise<string | null> {\n const url = `${this.baseUrl}/api/messages/dialpad/voicemail/authenticate`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ voicemail_link: voicemailLink }),\n });\n\n const result = (await response.json()) as VoicemailAuthResponse;\n\n if (!response.ok || !result.success) {\n return null;\n }\n\n return result.authenticated_url;\n }\n\n // -----------------------------------------------------------------------\n // Internal HTTP helpers\n // -----------------------------------------------------------------------\n\n private async get<T>(\n path: string,\n params?: Record<string, string | number | boolean | undefined>,\n ): Promise<T> {\n const url = new URL(`/api/messages/dialpad${path}`, this.baseUrl);\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n const response = await fetch(url.toString(), {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n });\n\n if (!response.ok) {\n throw new DialpadProxyError(\"GET\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n private async post<T>(path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}/api/messages/dialpad${path}`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n throw new DialpadProxyError(\"POST\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n private async put<T = void>(path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}/api/messages/dialpad${path}`;\n\n const response = await fetch(url, {\n method: \"PUT\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n throw new DialpadProxyError(\"PUT\", path, response.status);\n }\n\n if (response.headers.get(\"content-type\")?.includes(\"json\")) {\n return (await response.json()) as T;\n }\n\n return undefined as T;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Messages Resource — namespace for messaging providers\n// ---------------------------------------------------------------------------\n\nclass MessagesResource {\n readonly dialpad: DialpadResource;\n\n constructor(apiBaseUrl: string) {\n this.dialpad = new DialpadResource(apiBaseUrl);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Error\n// ---------------------------------------------------------------------------\n\nclass DialpadProxyError extends Error {\n readonly method: string;\n readonly path: string;\n readonly status: number;\n\n constructor(method: string, path: string, status: number) {\n super(\n `Dialpad proxy error: ${method} /api/messages/dialpad${path} returned ${status}`,\n );\n this.name = \"DialpadProxyError\";\n this.method = method;\n this.path = path;\n this.status = status;\n }\n}\n\nexport { DialpadResource, DialpadProxyError, MessagesResource };\nexport type {\n SendSmsParams,\n SendSmsResponse,\n InitiateCallResponse,\n CallStatusResponse,\n DialpadUser,\n DialpadNumberInfo,\n VoicemailAuthResponse,\n};\n","/**\n * EHR proxy resource — typed access to Truth's EHR proxy endpoints.\n *\n * Provides per-provider proxy methods so consumers never construct\n * proxy URLs manually.\n *\n * @example\n * ```ts\n * const patient = await truth.ehr.elation.get('/patients/123/');\n * const notes = await truth.ehr.elation.post('/non_visit_notes/', noteData);\n * const hintPatient = await truth.ehr.hint.get('/provider/patients/456');\n * ```\n */\n\n// ---------------------------------------------------------------------------\n// Provider proxy\n// ---------------------------------------------------------------------------\n\nclass EhrProviderProxy {\n private readonly baseUrl: string;\n private readonly provider: string;\n\n constructor(apiBaseUrl: string, provider: string) {\n this.baseUrl = apiBaseUrl;\n this.provider = provider;\n }\n\n /**\n * GET request to the EHR proxy.\n * @param path — path relative to the provider root (e.g., \"/patients/123/\")\n * @param params — optional query parameters\n */\n async get<T = unknown>(\n path: string,\n params?: Record<string, string | number | boolean | undefined>,\n ): Promise<T> {\n const url = new URL(`/api/ehr/${this.provider}${path}`, this.baseUrl);\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n const response = await fetch(url.toString(), {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n });\n\n if (!response.ok) {\n throw new EhrProxyError(this.provider, \"GET\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n /**\n * POST request to the EHR proxy.\n */\n async post<T = unknown>(path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}/api/ehr/${this.provider}${path}`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n throw new EhrProxyError(this.provider, \"POST\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n /**\n * PUT request to the EHR proxy.\n */\n async put<T = unknown>(path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}/api/ehr/${this.provider}${path}`;\n\n const response = await fetch(url, {\n method: \"PUT\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n throw new EhrProxyError(this.provider, \"PUT\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n /**\n * PATCH request to the EHR proxy.\n */\n async patch<T = unknown>(path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}/api/ehr/${this.provider}${path}`;\n\n const response = await fetch(url, {\n method: \"PATCH\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n throw new EhrProxyError(this.provider, \"PATCH\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n /**\n * DELETE request to the EHR proxy.\n */\n async delete<T = unknown>(path: string): Promise<T> {\n const url = `${this.baseUrl}/api/ehr/${this.provider}${path}`;\n\n const response = await fetch(url, {\n method: \"DELETE\",\n headers: { Accept: \"application/json\" },\n });\n\n if (!response.ok) {\n throw new EhrProxyError(this.provider, \"DELETE\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n}\n\n// ---------------------------------------------------------------------------\n// EHR Resource — exposes per-provider proxies\n// ---------------------------------------------------------------------------\n\nclass EhrResource {\n /** Elation EHR proxy */\n readonly elation: EhrProviderProxy;\n\n /** Hint Health proxy */\n readonly hint: EhrProviderProxy;\n\n constructor(apiBaseUrl: string) {\n this.elation = new EhrProviderProxy(apiBaseUrl, \"elation\");\n this.hint = new EhrProviderProxy(apiBaseUrl, \"hint\");\n }\n}\n\n// ---------------------------------------------------------------------------\n// Error\n// ---------------------------------------------------------------------------\n\nclass EhrProxyError extends Error {\n readonly provider: string;\n readonly method: string;\n readonly path: string;\n readonly status: number;\n\n constructor(provider: string, method: string, path: string, status: number) {\n super(\n `EHR proxy error: ${method} /api/ehr/${provider}${path} returned ${status}`,\n );\n this.name = \"EhrProxyError\";\n this.provider = provider;\n this.method = method;\n this.path = path;\n this.status = status;\n }\n}\n\nexport { EhrResource, EhrProviderProxy, EhrProxyError };\n","/**\n * PatientResource provides data access to normalized patient records\n * backed by Convex.\n */\n\nimport type { ConvexHttpClient } from \"convex/browser\";\nimport type { PaginatedResult } from \"../types/config\";\nimport type { Patient, PatientListOptions } from \"../types/patient\";\n\nclass PatientResource {\n private readonly convex: ConvexHttpClient;\n\n constructor(convexClient: ConvexHttpClient) {\n this.convex = convexClient;\n }\n\n /**\n * Get a patient by their Truth platform ID.\n */\n async get(id: string): Promise<Patient | null> {\n try {\n const result = await this.convex.query(\n \"patients:getById\" as never,\n {\n id,\n } as never,\n );\n return (result as Patient) ?? null;\n } catch {\n return null;\n }\n }\n\n /**\n * Get a patient by their Elation EHR ID.\n */\n async getByElationId(elationId: string): Promise<Patient | null> {\n try {\n const result = await this.convex.query(\n \"patients:getByElationId\" as never,\n { elationId } as never,\n );\n return (result as Patient) ?? null;\n } catch {\n return null;\n }\n }\n\n /**\n * Get a patient by their Hint EHR ID.\n */\n async getByHintId(hintId: string): Promise<Patient | null> {\n try {\n const result = await this.convex.query(\n \"patients:getByHintId\" as never,\n {\n hintId,\n } as never,\n );\n return (result as Patient) ?? null;\n } catch {\n return null;\n }\n }\n\n /**\n * List patients with optional search, pagination, and limit.\n */\n async list(options?: PatientListOptions): Promise<PaginatedResult<Patient>> {\n try {\n const result = await this.convex.query(\n \"patients:list\" as never,\n {\n search: options?.search,\n limit: options?.limit,\n cursor: options?.cursor,\n } as never,\n );\n\n const typed = result as PaginatedResult<Patient> | undefined;\n\n return typed ?? { data: [], cursor: null, hasMore: false };\n } catch {\n return { data: [], cursor: null, hasMore: false };\n }\n }\n}\n\nexport { PatientResource };\n","/**\n * Event tracker with batching, retry, and flush support.\n *\n * Buffers events in an internal queue and flushes them to the Truth API\n * endpoint. Flushes occur when the buffer reaches `batchSize` or every\n * `flushIntervalMs` milliseconds, whichever comes first.\n */\n\nimport type { ActorContext } from \"../types/config\";\nimport type {\n EventEnvelope,\n EventPayloadMap,\n EventType,\n TrackOptions,\n} from \"./events\";\n\n// ---------------------------------------------------------------------------\n// UUID v7 helper (no external dependency)\n// ---------------------------------------------------------------------------\n\n/**\n * Generates a UUID v7 string. Uses crypto.randomUUID where available,\n * falling back to a timestamp + random bytes implementation.\n *\n * UUID v7 layout (RFC 9562):\n * 48 bits - unix timestamp (ms)\n * 4 bits - version (0b0111)\n * 12 bits - random\n * 2 bits - variant (0b10)\n * 62 bits - random\n */\nfunction generateUuidV7(): string {\n const now = Date.now();\n\n // 6 bytes of timestamp\n const timeBytes = new Uint8Array(6);\n let ts = now;\n for (let i = 5; i >= 0; i--) {\n timeBytes[i] = ts & 0xff;\n ts = Math.floor(ts / 256);\n }\n\n // 10 bytes of random\n const randomBytes = new Uint8Array(10);\n if (\n typeof globalThis.crypto !== \"undefined\" &&\n globalThis.crypto.getRandomValues\n ) {\n globalThis.crypto.getRandomValues(randomBytes);\n } else {\n for (let i = 0; i < 10; i++) {\n randomBytes[i] = Math.floor(Math.random() * 256);\n }\n }\n\n // Assemble 16 bytes\n const bytes = new Uint8Array(16);\n bytes.set(timeBytes, 0);\n bytes.set(randomBytes, 6);\n\n // Set version (bits 48-51 to 0b0111)\n bytes[6] = (bytes[6] & 0x0f) | 0x70;\n\n // Set variant (bits 64-65 to 0b10)\n bytes[8] = (bytes[8] & 0x3f) | 0x80;\n\n // Format as hex string with dashes\n const hex = Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n\n return [\n hex.slice(0, 8),\n hex.slice(8, 12),\n hex.slice(12, 16),\n hex.slice(16, 20),\n hex.slice(20, 32),\n ].join(\"-\");\n}\n\n// ---------------------------------------------------------------------------\n// Environment-based API URL resolution\n// ---------------------------------------------------------------------------\n\nconst API_URLS: Record<string, string> = {\n local: \"http://localhost:3000\",\n staging: \"https://app.sandbox.communication-hub.com\",\n sandbox: \"https://app.sandbox.communication-hub.com\",\n uat: \"https://app.sandbox.communication-hub.com\",\n production: \"https://app.truth.communication-hub.com\",\n};\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_BATCH_SIZE = 25;\nconst DEFAULT_FLUSH_INTERVAL_MS = 5_000;\nconst MAX_RETRIES = 3;\nconst BASE_RETRY_DELAY_MS = 500;\n\n// ---------------------------------------------------------------------------\n// Tracker configuration\n// ---------------------------------------------------------------------------\n\ninterface TrackerConfig {\n apiKey: string;\n environment: string;\n source: string;\n sourceVersion: string;\n tenantId: string;\n batchSize: number;\n flushIntervalMs: number;\n apiBaseUrl?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Tracker class\n// ---------------------------------------------------------------------------\n\nclass Tracker {\n private readonly config: TrackerConfig;\n readonly apiUrl: string;\n private queue: EventEnvelope[] = [];\n private flushTimer: ReturnType<typeof setInterval> | null = null;\n private defaultActor: ActorContext | undefined;\n private isFlushing = false;\n private isShutdown = false;\n\n constructor(config: TrackerConfig) {\n this.config = config;\n this.apiUrl =\n config.apiBaseUrl ?? API_URLS[config.environment] ?? API_URLS.local;\n\n this.startFlushInterval();\n this.registerShutdownHooks();\n }\n\n /**\n * Set the default actor context for subsequent events.\n */\n setActor(actor: ActorContext): void {\n this.defaultActor = actor;\n }\n\n /**\n * Enqueue a typed event for delivery. This is fire-and-forget from\n * the caller's perspective -- events are buffered and flushed in batches.\n */\n track<T extends EventType>(\n eventType: T,\n payload: EventPayloadMap[T],\n options?: TrackOptions,\n ): void {\n if (this.isShutdown) {\n return;\n }\n\n const now = new Date().toISOString();\n\n const envelope: EventEnvelope = {\n event_id: generateUuidV7(),\n event_type: eventType,\n schema_version: 1,\n occurred_at: options?.occurredAt ?? now,\n received_at: now,\n source: this.config.source,\n source_version: this.config.sourceVersion,\n tenant_id: options?.tenantId ?? this.config.tenantId,\n actor:\n options?.actor ??\n (this.defaultActor\n ? {\n actor_id: this.defaultActor.actorId,\n actor_type: this.defaultActor.actorType,\n }\n : undefined),\n subject: options?.subject,\n compliance: options?.compliance,\n payload: payload as unknown as Record<string, unknown>,\n };\n\n this.queue.push(envelope);\n\n if (this.queue.length >= this.config.batchSize) {\n void this.flush();\n }\n }\n\n /**\n * Force an immediate flush of all buffered events.\n * Returns a promise that resolves when the flush completes.\n */\n async flush(): Promise<void> {\n if (this.queue.length === 0 || this.isFlushing) {\n return;\n }\n\n this.isFlushing = true;\n const batch = this.queue.splice(0, this.config.batchSize);\n\n try {\n await this.sendBatch(batch);\n } catch {\n // Re-queue events that failed to send (prepend to maintain ordering)\n this.queue.unshift(...batch);\n } finally {\n this.isFlushing = false;\n }\n\n // If there are still events in the queue, flush again\n if (this.queue.length >= this.config.batchSize) {\n await this.flush();\n }\n }\n\n /**\n * Gracefully shut down the tracker. Flushes remaining events and\n * clears the flush interval.\n */\n async shutdown(): Promise<void> {\n this.isShutdown = true;\n this.stopFlushInterval();\n await this.flush();\n }\n\n /**\n * Send a batch of events to the Truth API with exponential backoff retry.\n */\n private async sendBatch(batch: EventEnvelope[]): Promise<void> {\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {\n try {\n const response = await fetch(`${this.apiUrl}/api/events/ingest`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.config.apiKey}`,\n },\n body: JSON.stringify({ events: batch }),\n });\n\n if (response.ok) {\n return;\n }\n\n // Don't retry 4xx client errors (except 429)\n if (\n response.status >= 400 &&\n response.status < 500 &&\n response.status !== 429\n ) {\n return;\n }\n\n lastError = new Error(\n `HTTP ${response.status}: ${response.statusText}`,\n );\n } catch (error) {\n lastError = error;\n }\n\n // Exponential backoff with jitter\n if (attempt < MAX_RETRIES) {\n const delay = BASE_RETRY_DELAY_MS * 2 ** attempt;\n const jitter = Math.random() * delay * 0.5;\n await sleep(delay + jitter);\n }\n }\n\n throw lastError;\n }\n\n private startFlushInterval(): void {\n if (this.config.flushIntervalMs > 0) {\n this.flushTimer = setInterval(() => {\n void this.flush();\n }, this.config.flushIntervalMs);\n\n // Unref the timer so it doesn't prevent Node.js from exiting\n if (typeof this.flushTimer === \"object\" && \"unref\" in this.flushTimer) {\n this.flushTimer.unref();\n }\n }\n }\n\n private stopFlushInterval(): void {\n if (this.flushTimer !== null) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n }\n\n private registerShutdownHooks(): void {\n // Only register in Node.js environments\n if (typeof globalThis.process !== \"undefined\" && globalThis.process.on) {\n const shutdownHandler = () => {\n void this.shutdown();\n };\n\n globalThis.process.on(\"beforeExit\", shutdownHandler);\n globalThis.process.on(\"SIGTERM\", shutdownHandler);\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport {\n Tracker,\n generateUuidV7,\n DEFAULT_BATCH_SIZE,\n DEFAULT_FLUSH_INTERVAL_MS,\n};\nexport type { TrackerConfig };\n","/**\n * Typed event definitions for the Truth Platform event store.\n *\n * All 26 event types from the Communication Hub -> Truth Event Store Contract.\n * Events are grouped by domain and include typed payload interfaces.\n */\n\n// ---------------------------------------------------------------------------\n// Event type constants\n// ---------------------------------------------------------------------------\n\nconst CONVERSATION_EVENTS = {\n created: \"conversation.created.v1\",\n messageSent: \"conversation.message_sent.v1\",\n messageReceived: \"conversation.message_received.v1\",\n markedRead: \"conversation.marked_read.v1\",\n attachmentUploaded: \"conversation.attachment_uploaded.v1\",\n attachmentDownloaded: \"conversation.attachment_downloaded.v1\",\n} as const;\n\nconst CALL_EVENTS = {\n initiated: \"call.initiated.v1\",\n connected: \"call.connected.v1\",\n ended: \"call.ended.v1\",\n missed: \"call.missed.v1\",\n} as const;\n\nconst TASK_EVENTS = {\n created: \"task.created.v1\",\n assigned: \"task.assigned.v1\",\n statusChanged: \"task.status_changed.v1\",\n} as const;\n\nconst REMINDER_EVENTS = {\n scheduled: \"reminder.scheduled.v1\",\n triggered: \"reminder.triggered.v1\",\n} as const;\n\nconst TRANSLATION_EVENTS = {\n requested: \"translation.requested.v1\",\n completed: \"translation.completed.v1\",\n} as const;\n\nconst NOTIFICATION_EVENTS = {\n sent: \"notification.sent.v1\",\n delivered: \"notification.delivered.v1\",\n opened: \"notification.opened.v1\",\n} as const;\n\nconst PROVIDER_EVENTS = {\n syncStarted: \"provider.sync_started.v1\",\n syncSucceeded: \"provider.sync_succeeded.v1\",\n syncFailed: \"provider.sync_failed.v1\",\n} as const;\n\nconst AUTH_EVENTS = {\n loginSucceeded: \"auth.login_succeeded.v1\",\n loginFailed: \"auth.login_failed.v1\",\n} as const;\n\nconst SECURITY_EVENTS = {\n accessDenied: \"security.access_denied.v1\",\n} as const;\n\n/**\n * All event type constants grouped by domain.\n */\nconst EVENT_TYPES = {\n conversation: CONVERSATION_EVENTS,\n call: CALL_EVENTS,\n task: TASK_EVENTS,\n reminder: REMINDER_EVENTS,\n translation: TRANSLATION_EVENTS,\n notification: NOTIFICATION_EVENTS,\n provider: PROVIDER_EVENTS,\n auth: AUTH_EVENTS,\n security: SECURITY_EVENTS,\n} as const;\n\n// ---------------------------------------------------------------------------\n// Event type union\n// ---------------------------------------------------------------------------\n\ntype ConversationEventType =\n (typeof CONVERSATION_EVENTS)[keyof typeof CONVERSATION_EVENTS];\ntype CallEventType = (typeof CALL_EVENTS)[keyof typeof CALL_EVENTS];\ntype TaskEventType = (typeof TASK_EVENTS)[keyof typeof TASK_EVENTS];\ntype ReminderEventType = (typeof REMINDER_EVENTS)[keyof typeof REMINDER_EVENTS];\ntype TranslationEventType =\n (typeof TRANSLATION_EVENTS)[keyof typeof TRANSLATION_EVENTS];\ntype NotificationEventType =\n (typeof NOTIFICATION_EVENTS)[keyof typeof NOTIFICATION_EVENTS];\ntype ProviderEventType = (typeof PROVIDER_EVENTS)[keyof typeof PROVIDER_EVENTS];\ntype AuthEventType = (typeof AUTH_EVENTS)[keyof typeof AUTH_EVENTS];\ntype SecurityEventType = (typeof SECURITY_EVENTS)[keyof typeof SECURITY_EVENTS];\n\n/**\n * Union of all 26 registered event type strings.\n */\ntype EventType =\n | ConversationEventType\n | CallEventType\n | TaskEventType\n | ReminderEventType\n | TranslationEventType\n | NotificationEventType\n | ProviderEventType\n | AuthEventType\n | SecurityEventType;\n\n// ---------------------------------------------------------------------------\n// Payload interfaces (per the contract doc)\n// ---------------------------------------------------------------------------\n\ninterface ConversationCreatedPayload {\n channel: string;\n origin_system: string;\n participant_count: number;\n}\n\ninterface ConversationMessageSentPayload {\n channel: string;\n direction: string;\n message_chars: number;\n has_attachment: boolean;\n provider_system: string;\n}\n\ninterface ConversationMessageReceivedPayload {\n channel: string;\n direction: string;\n message_chars: number;\n provider_system: string;\n}\n\ninterface ConversationMarkedReadPayload {\n read_by_actor_id: string;\n unread_count_before: number;\n unread_count_after: number;\n}\n\ninterface ConversationAttachmentUploadedPayload {\n attachment_id: string;\n mime_type: string;\n size_bytes: number;\n storage_class: string;\n}\n\ninterface ConversationAttachmentDownloadedPayload {\n attachment_id: string;\n download_actor_type: string;\n access_path: string;\n}\n\ninterface CallInitiatedPayload {\n direction: string;\n provider_system: string;\n from_number_ref: string;\n to_number_ref: string;\n}\n\ninterface CallConnectedPayload {\n provider_system: string;\n ring_duration_ms: number;\n}\n\ninterface CallEndedPayload {\n provider_system: string;\n duration_ms: number;\n end_reason: string;\n disposition: string;\n}\n\ninterface CallMissedPayload {\n provider_system: string;\n miss_reason: string;\n}\n\ninterface TaskCreatedPayload {\n task_id: string;\n created_by: string;\n assigned_to: string;\n priority: string;\n due_at: string;\n}\n\ninterface TaskAssignedPayload {\n task_id: string;\n assigned_to: string;\n assigned_by: string;\n}\n\ninterface TaskStatusChangedPayload {\n task_id: string;\n status_from: string;\n status_to: string;\n changed_by: string;\n}\n\ninterface ReminderScheduledPayload {\n reminder_id: string;\n conversation_id: string;\n scheduled_for: string;\n scheduled_by: string;\n}\n\ninterface ReminderTriggeredPayload {\n reminder_id: string;\n trigger_result: string;\n notification_attempted: boolean;\n}\n\ninterface TranslationRequestedPayload {\n target_language: string;\n source_language: string;\n char_count: number;\n mode: string;\n}\n\ninterface TranslationCompletedPayload {\n target_language: string;\n provider: string;\n latency_ms: number;\n success: boolean;\n error_code?: string;\n}\n\ninterface NotificationSentPayload {\n notification_id: string;\n channel: string;\n platform: string;\n recipient_ref: string;\n success: boolean;\n}\n\ninterface NotificationDeliveredPayload {\n notification_id: string;\n platform: string;\n delivered_at: string;\n}\n\ninterface NotificationOpenedPayload {\n notification_id: string;\n platform: string;\n opened_at: string;\n}\n\ninterface ProviderSyncStartedPayload {\n provider_system: string;\n operation: string;\n scope: string;\n batch_id: string;\n}\n\ninterface ProviderSyncSucceededPayload {\n provider_system: string;\n operation: string;\n batch_id: string;\n records_processed: number;\n duration_ms: number;\n}\n\ninterface ProviderSyncFailedPayload {\n provider_system: string;\n operation: string;\n batch_id: string;\n error_code: string;\n retryable: boolean;\n}\n\ninterface AuthLoginSucceededPayload {\n auth_provider: string;\n platform: string;\n session_ref: string;\n}\n\ninterface AuthLoginFailedPayload {\n auth_provider: string;\n platform: string;\n failure_code: string;\n}\n\ninterface SecurityAccessDeniedPayload {\n resource: string;\n policy: string;\n reason_code: string;\n actor_id: string;\n}\n\n// ---------------------------------------------------------------------------\n// Event type -> payload mapping\n// ---------------------------------------------------------------------------\n\n/**\n * Maps each event type string to its required payload interface.\n */\ninterface EventPayloadMap {\n \"conversation.created.v1\": ConversationCreatedPayload;\n \"conversation.message_sent.v1\": ConversationMessageSentPayload;\n \"conversation.message_received.v1\": ConversationMessageReceivedPayload;\n \"conversation.marked_read.v1\": ConversationMarkedReadPayload;\n \"conversation.attachment_uploaded.v1\": ConversationAttachmentUploadedPayload;\n \"conversation.attachment_downloaded.v1\": ConversationAttachmentDownloadedPayload;\n \"call.initiated.v1\": CallInitiatedPayload;\n \"call.connected.v1\": CallConnectedPayload;\n \"call.ended.v1\": CallEndedPayload;\n \"call.missed.v1\": CallMissedPayload;\n \"task.created.v1\": TaskCreatedPayload;\n \"task.assigned.v1\": TaskAssignedPayload;\n \"task.status_changed.v1\": TaskStatusChangedPayload;\n \"reminder.scheduled.v1\": ReminderScheduledPayload;\n \"reminder.triggered.v1\": ReminderTriggeredPayload;\n \"translation.requested.v1\": TranslationRequestedPayload;\n \"translation.completed.v1\": TranslationCompletedPayload;\n \"notification.sent.v1\": NotificationSentPayload;\n \"notification.delivered.v1\": NotificationDeliveredPayload;\n \"notification.opened.v1\": NotificationOpenedPayload;\n \"provider.sync_started.v1\": ProviderSyncStartedPayload;\n \"provider.sync_succeeded.v1\": ProviderSyncSucceededPayload;\n \"provider.sync_failed.v1\": ProviderSyncFailedPayload;\n \"auth.login_succeeded.v1\": AuthLoginSucceededPayload;\n \"auth.login_failed.v1\": AuthLoginFailedPayload;\n \"security.access_denied.v1\": SecurityAccessDeniedPayload;\n}\n\n// ---------------------------------------------------------------------------\n// Event envelope\n// ---------------------------------------------------------------------------\n\n/**\n * Subject references for the event. Uses tokenized references only -- no PHI.\n */\ninterface EventSubject {\n patient_ref?: string;\n conversation_id?: string;\n task_id?: string;\n call_id?: string;\n}\n\n/**\n * Actor who triggered the event.\n */\ninterface EventActor {\n actor_id: string;\n actor_type: \"user\" | \"system\" | \"webhook\";\n}\n\n/**\n * Compliance metadata for the event.\n */\ninterface EventCompliance {\n pii_level: \"none\" | \"limited\" | \"full\";\n contains_phi: boolean;\n consent_context: string;\n retention_class: string;\n}\n\n/**\n * Canonical event envelope. Every tracked event is wrapped in this structure\n * before being sent to the Truth API.\n */\ninterface EventEnvelope {\n event_id: string;\n event_type: string;\n schema_version: number;\n occurred_at: string;\n received_at: string;\n source: string;\n source_version: string;\n tenant_id: string;\n actor?: EventActor;\n subject?: EventSubject;\n compliance?: EventCompliance;\n payload: Record<string, unknown>;\n}\n\n// ---------------------------------------------------------------------------\n// Track options (per-call overrides)\n// ---------------------------------------------------------------------------\n\n/**\n * Optional overrides when calling truth.track().\n */\ninterface TrackOptions {\n /** Override the default actor for this event */\n actor?: EventActor;\n\n /** Subject references for this event */\n subject?: EventSubject;\n\n /** Compliance metadata for this event */\n compliance?: EventCompliance;\n\n /** Override the default tenant ID for this event */\n tenantId?: string;\n\n /** Override the occurred_at timestamp (ISO 8601) */\n occurredAt?: string;\n}\n\nexport {\n EVENT_TYPES,\n CONVERSATION_EVENTS,\n CALL_EVENTS,\n TASK_EVENTS,\n REMINDER_EVENTS,\n TRANSLATION_EVENTS,\n NOTIFICATION_EVENTS,\n PROVIDER_EVENTS,\n AUTH_EVENTS,\n SECURITY_EVENTS,\n};\n\nexport type {\n EventType,\n ConversationEventType,\n CallEventType,\n TaskEventType,\n ReminderEventType,\n TranslationEventType,\n NotificationEventType,\n ProviderEventType,\n AuthEventType,\n SecurityEventType,\n EventPayloadMap,\n EventEnvelope,\n EventActor,\n EventSubject,\n EventCompliance,\n TrackOptions,\n ConversationCreatedPayload,\n ConversationMessageSentPayload,\n ConversationMessageReceivedPayload,\n ConversationMarkedReadPayload,\n ConversationAttachmentUploadedPayload,\n ConversationAttachmentDownloadedPayload,\n CallInitiatedPayload,\n CallConnectedPayload,\n CallEndedPayload,\n CallMissedPayload,\n TaskCreatedPayload,\n TaskAssignedPayload,\n TaskStatusChangedPayload,\n ReminderScheduledPayload,\n ReminderTriggeredPayload,\n TranslationRequestedPayload,\n TranslationCompletedPayload,\n NotificationSentPayload,\n NotificationDeliveredPayload,\n NotificationOpenedPayload,\n ProviderSyncStartedPayload,\n ProviderSyncSucceededPayload,\n ProviderSyncFailedPayload,\n AuthLoginSucceededPayload,\n AuthLoginFailedPayload,\n SecurityAccessDeniedPayload,\n};\n","/**\n * Configuration interfaces for the Truth SDK.\n */\n\n/**\n * Environment options for the Truth platform.\n */\nconst ENVIRONMENTS = {\n local: \"local\",\n staging: \"staging\",\n sandbox: \"sandbox\",\n uat: \"uat\",\n production: \"production\",\n} as const;\n\ntype Environment = (typeof ENVIRONMENTS)[keyof typeof ENVIRONMENTS];\n\n/**\n * Configuration for initializing a TruthClient.\n */\ninterface TruthClientConfig {\n /** API key for authenticating with the Truth platform (e.g. \"hn_live_...\") */\n apiKey: string;\n\n /** Target environment */\n environment: Environment;\n\n /** Override the default Convex URL for data access */\n convexUrl?: string;\n\n /** Event source identifier (e.g. \"communication-hub.backend\") */\n source?: string;\n\n /** Git SHA or version string for event source versioning */\n sourceVersion?: string;\n\n /** Default tenant (organization) ID for events */\n tenantId?: string;\n\n /** Number of events to buffer before flushing (default: 25) */\n batchSize?: number;\n\n /** Interval in milliseconds between automatic flushes (default: 5000) */\n flushIntervalMs?: number;\n\n /** Base URL for the Truth API (overrides environment-based default) */\n apiBaseUrl?: string;\n}\n\n/**\n * Actor context attached to tracked events.\n */\ninterface ActorContext {\n actorId: string;\n actorType: \"user\" | \"system\" | \"webhook\";\n}\n\n/**\n * Paginated result wrapper for list operations.\n */\ninterface PaginatedResult<T> {\n data: T[];\n cursor: string | null;\n hasMore: boolean;\n}\n\nexport { ENVIRONMENTS };\nexport type { Environment, TruthClientConfig, ActorContext, PaginatedResult };\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/client.ts","../src/resources/appointments.ts","../src/resources/dialpad.ts","../src/resources/ehr.ts","../src/resources/patients.ts","../src/tracking/tracker.ts","../src/tracking/events.ts","../src/types/config.ts"],"sourcesContent":["/**\n * TruthClient -- main entry point for the @hipnation-truth/sdk package.\n *\n * Provides:\n * - `.patients` Resource-based patient data access (Convex-backed)\n * - `.appointments` Resource-based appointment data access (Convex-backed)\n * - `.ehr` EHR proxy access (Elation, Hint)\n * - `.messages` Messaging proxy access (Dialpad)\n * - `.track()` Fire-and-forget event tracking (batched HTTP -> Truth API)\n * - `.identify()` Set default actor context for subsequent events\n * - `.flush()` Force flush of buffered events (for graceful shutdown)\n */\n\nimport { ConvexHttpClient } from \"convex/browser\";\nimport { AppointmentResource } from \"./resources/appointments\";\nimport { MessagesResource } from \"./resources/dialpad\";\nimport { EhrResource } from \"./resources/ehr\";\nimport { PatientResource } from \"./resources/patients\";\nimport type {\n EventPayloadMap,\n EventType,\n TrackOptions,\n} from \"./tracking/events\";\nimport {\n DEFAULT_BATCH_SIZE,\n DEFAULT_FLUSH_INTERVAL_MS,\n Tracker,\n} from \"./tracking/tracker\";\nimport type { ActorContext, TruthClientConfig } from \"./types/config\";\n\n// ---------------------------------------------------------------------------\n// Environment -> Convex URL mapping\n// ---------------------------------------------------------------------------\n\nconst CONVEX_URLS: Record<string, string> = {\n local: \"http://localhost:3210\",\n staging: \"https://staging-truth.convex.cloud\",\n uat: \"https://uat-truth.convex.cloud\",\n production: \"https://truth.convex.cloud\",\n};\n\n// ---------------------------------------------------------------------------\n// TruthClient\n// ---------------------------------------------------------------------------\n\nclass TruthClient {\n /** Patient data resource (Convex-backed) */\n readonly patients: PatientResource;\n\n /** Appointment data resource (Convex-backed) */\n readonly appointments: AppointmentResource;\n\n /** EHR proxy — typed access to Elation and Hint APIs through Truth */\n readonly ehr: EhrResource;\n\n /** Messaging proxy — typed access to Dialpad APIs through Truth */\n readonly messages: MessagesResource;\n\n private readonly convex: ConvexHttpClient;\n private readonly tracker: Tracker;\n\n constructor(config: TruthClientConfig) {\n // Resolve Convex URL\n const convexUrl =\n config.convexUrl ?? CONVEX_URLS[config.environment] ?? CONVEX_URLS.local;\n\n // Initialize Convex HTTP client for data access\n this.convex = new ConvexHttpClient(convexUrl);\n\n // Initialize event tracker\n this.tracker = new Tracker({\n apiKey: config.apiKey,\n environment: config.environment,\n source: config.source ?? \"unknown\",\n sourceVersion: config.sourceVersion ?? \"unknown\",\n tenantId: config.tenantId ?? \"\",\n batchSize: config.batchSize ?? DEFAULT_BATCH_SIZE,\n flushIntervalMs: config.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS,\n apiBaseUrl: config.apiBaseUrl,\n });\n\n const apiUrl = this.tracker.apiUrl;\n\n // Initialize resources\n this.patients = new PatientResource(this.convex);\n this.appointments = new AppointmentResource(this.convex);\n this.ehr = new EhrResource(apiUrl);\n this.messages = new MessagesResource(apiUrl);\n }\n\n /**\n * The resolved Truth API base URL for this environment.\n * Use this when making HTTP calls to Truth's proxy endpoints\n * (e.g., EHR proxy, messages proxy).\n *\n * @example\n * ```ts\n * const url = `${truth.apiBaseUrl}/api/ehr/elation/patients/123`;\n * ```\n */\n get apiBaseUrl(): string {\n return this.tracker.apiUrl;\n }\n\n /**\n * Track an event. Fire-and-forget -- the event is buffered internally\n * and flushed in batches to the Truth API.\n *\n * @example\n * ```ts\n * truth.track('conversation.message_sent.v1', {\n * channel: 'sms',\n * direction: 'outbound',\n * message_chars: 140,\n * has_attachment: false,\n * provider_system: 'dialpad',\n * });\n * ```\n */\n track<T extends EventType>(\n eventType: T,\n payload: EventPayloadMap[T],\n options?: TrackOptions,\n ): void {\n this.tracker.track(eventType, payload, options);\n }\n\n /**\n * Set the default actor context for all subsequent tracked events.\n * Can be overridden per-event via TrackOptions.\n *\n * @example\n * ```ts\n * truth.identify('user_123', 'user');\n * ```\n */\n identify(actorId: string, actorType: ActorContext[\"actorType\"]): void {\n this.tracker.setActor({ actorId, actorType });\n }\n\n /**\n * Flush all buffered events immediately. Returns a Promise that resolves\n * when the flush completes. Use this for graceful shutdown.\n *\n * @example\n * ```ts\n * process.on('SIGTERM', async () => {\n * await truth.flush();\n * process.exit(0);\n * });\n * ```\n */\n async flush(): Promise<void> {\n await this.tracker.flush();\n }\n\n /**\n * Gracefully shut down the client. Flushes all pending events and\n * releases resources.\n */\n async destroy(): Promise<void> {\n await this.tracker.shutdown();\n }\n}\n\nexport { TruthClient };\n","/**\n * AppointmentResource provides data access to normalized appointment records\n * backed by Convex.\n */\n\nimport type { ConvexHttpClient } from \"convex/browser\";\nimport type { Appointment, AppointmentListOptions } from \"../types/appointment\";\nimport type { PaginatedResult } from \"../types/config\";\n\nclass AppointmentResource {\n private readonly convex: ConvexHttpClient;\n\n constructor(convexClient: ConvexHttpClient) {\n this.convex = convexClient;\n }\n\n /**\n * Get an appointment by its Truth platform ID.\n */\n async get(id: string): Promise<Appointment | null> {\n try {\n const result = await this.convex.query(\n \"appointments:getById\" as never,\n { id } as never,\n );\n return (result as Appointment) ?? null;\n } catch {\n return null;\n }\n }\n\n /**\n * List appointments with optional filters, pagination, and limit.\n */\n async list(\n options?: AppointmentListOptions,\n ): Promise<PaginatedResult<Appointment>> {\n try {\n const result = await this.convex.query(\n \"appointments:list\" as never,\n {\n patientId: options?.patientId,\n startDate: options?.startDate,\n endDate: options?.endDate,\n status: options?.status,\n limit: options?.limit,\n cursor: options?.cursor,\n } as never,\n );\n\n const typed = result as PaginatedResult<Appointment> | undefined;\n\n return typed ?? { data: [], cursor: null, hasMore: false };\n } catch {\n return { data: [], cursor: null, hasMore: false };\n }\n }\n}\n\nexport { AppointmentResource };\n","/**\n * Dialpad resource — typed access to Truth's Dialpad proxy endpoints.\n *\n * @example\n * ```ts\n * const sms = await truth.messages.dialpad.sendSms({ from_number, to_number, message });\n * const call = await truth.messages.dialpad.initiateCall(userId, phoneNumber);\n * await truth.messages.dialpad.hangupCall(callId);\n * const url = await truth.messages.dialpad.authenticateVoicemail(voicemailLink);\n * ```\n */\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\ninterface SendSmsParams {\n from_number: string;\n to_number: string;\n message?: string;\n media?: string;\n}\n\ninterface SendSmsResponse {\n id: string;\n message_status: string;\n [key: string]: unknown;\n}\n\ninterface InitiateCallResponse {\n call_id: number;\n [key: string]: unknown;\n}\n\ninterface CallStatusResponse {\n state: string;\n [key: string]: unknown;\n}\n\ninterface DialpadUser {\n id: number;\n emails: string[];\n first_name?: string;\n last_name?: string;\n [key: string]: unknown;\n}\n\ninterface DialpadUserListResponse {\n items: DialpadUser[];\n}\n\ninterface DialpadNumberInfo {\n user_id?: number;\n type?: string;\n [key: string]: unknown;\n}\n\ninterface VoicemailAuthResponse {\n success: boolean;\n authenticated_url: string | null;\n error?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Dialpad Resource\n// ---------------------------------------------------------------------------\n\nclass DialpadResource {\n private readonly baseUrl: string;\n\n constructor(apiBaseUrl: string) {\n this.baseUrl = apiBaseUrl;\n }\n\n /**\n * Send an SMS or MMS message via Dialpad.\n */\n async sendSms(params: SendSmsParams): Promise<SendSmsResponse> {\n const body = {\n to_numbers: [params.to_number],\n from_number: params.from_number,\n infer_country_code: false,\n ...(params.message ? { text: params.message } : {}),\n ...(params.media ? { media: params.media } : {}),\n };\n\n return this.post<SendSmsResponse>(\"/sms\", body);\n }\n\n /**\n * Initiate an outbound call from a Dialpad user to a phone number.\n */\n async initiateCall(\n userId: number,\n phoneNumber: string,\n ): Promise<InitiateCallResponse> {\n return this.post<InitiateCallResponse>(`/users/${userId}/initiate_call`, {\n phone_number: phoneNumber,\n });\n }\n\n /**\n * Hang up an active call.\n */\n async hangupCall(callId: number): Promise<void> {\n await this.put(`/call/${callId}/actions/hangup`);\n }\n\n /**\n * Get the status of a call.\n */\n async getCallStatus(callId: number): Promise<CallStatusResponse | null> {\n try {\n return await this.get<CallStatusResponse>(`/call/${callId}`);\n } catch (error) {\n if (error instanceof DialpadProxyError && error.status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Get a Dialpad user by their user ID.\n */\n async getUser(userId: string | number): Promise<DialpadUser | null> {\n try {\n return await this.get<DialpadUser>(`/users/${userId}`);\n } catch (error) {\n if (error instanceof DialpadProxyError && error.status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Find a Dialpad user by email.\n */\n async getUserByEmail(email: string): Promise<DialpadUser | null> {\n const result = await this.get<DialpadUserListResponse>(\"/users\", {\n email,\n });\n return result.items?.[0] ?? null;\n }\n\n /**\n * Find a Dialpad user by phone number.\n */\n async getUserByPhoneNumber(phoneNumber: string): Promise<DialpadUser | null> {\n const result = await this.get<DialpadUserListResponse>(\"/users\", {\n number: phoneNumber,\n });\n return result.items?.[0] ?? null;\n }\n\n /**\n * Get information about a Dialpad phone number.\n */\n async getNumberInfo(phoneNumber: string): Promise<DialpadNumberInfo | null> {\n try {\n const cleanNumber = phoneNumber.replace(/[^\\d+]/g, \"\");\n return await this.get<DialpadNumberInfo>(\n `/numbers/${encodeURIComponent(cleanNumber)}`,\n );\n } catch (error) {\n if (error instanceof DialpadProxyError && error.status === 404) {\n return null;\n }\n throw error;\n }\n }\n\n /**\n * Authenticate a voicemail download URL. Truth appends the Dialpad API key,\n * follows redirects, and returns the clean URL for client-side playback.\n */\n async authenticateVoicemail(voicemailLink: string): Promise<string | null> {\n const url = `${this.baseUrl}/api/messages/dialpad/voicemail/authenticate`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({ voicemail_link: voicemailLink }),\n });\n\n const result = (await response.json()) as VoicemailAuthResponse;\n\n if (!response.ok || !result.success) {\n return null;\n }\n\n return result.authenticated_url;\n }\n\n // -----------------------------------------------------------------------\n // Internal HTTP helpers\n // -----------------------------------------------------------------------\n\n private async get<T>(\n path: string,\n params?: Record<string, unknown>,\n ): Promise<T> {\n const url = new URL(`/api/messages/dialpad${path}`, this.baseUrl);\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n const response = await fetch(url.toString(), {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n });\n\n if (!response.ok) {\n throw new DialpadProxyError(\"GET\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n private async post<T>(path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}/api/messages/dialpad${path}`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n throw new DialpadProxyError(\"POST\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n private async put<T = void>(path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}/api/messages/dialpad${path}`;\n\n const response = await fetch(url, {\n method: \"PUT\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n throw new DialpadProxyError(\"PUT\", path, response.status);\n }\n\n if (response.headers.get(\"content-type\")?.includes(\"json\")) {\n return (await response.json()) as T;\n }\n\n return undefined as T;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Messages Resource — namespace for messaging providers\n// ---------------------------------------------------------------------------\n\nclass MessagesResource {\n readonly dialpad: DialpadResource;\n\n constructor(apiBaseUrl: string) {\n this.dialpad = new DialpadResource(apiBaseUrl);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Error\n// ---------------------------------------------------------------------------\n\nclass DialpadProxyError extends Error {\n readonly method: string;\n readonly path: string;\n readonly status: number;\n\n constructor(method: string, path: string, status: number) {\n super(\n `Dialpad proxy error: ${method} /api/messages/dialpad${path} returned ${status}`,\n );\n this.name = \"DialpadProxyError\";\n this.method = method;\n this.path = path;\n this.status = status;\n }\n}\n\nexport { DialpadResource, DialpadProxyError, MessagesResource };\nexport type {\n SendSmsParams,\n SendSmsResponse,\n InitiateCallResponse,\n CallStatusResponse,\n DialpadUser,\n DialpadNumberInfo,\n VoicemailAuthResponse,\n};\n","/**\n * EHR proxy resource — typed access to Truth's EHR proxy endpoints.\n *\n * Provides per-provider proxy methods so consumers never construct\n * proxy URLs manually.\n *\n * @example\n * ```ts\n * const patient = await truth.ehr.elation.get('/patients/123/');\n * const notes = await truth.ehr.elation.post('/non_visit_notes/', noteData);\n * const hintPatient = await truth.ehr.hint.get('/provider/patients/456');\n * ```\n */\n\n// ---------------------------------------------------------------------------\n// Provider proxy\n// ---------------------------------------------------------------------------\n\nclass EhrProviderProxy {\n private readonly baseUrl: string;\n private readonly provider: string;\n\n constructor(apiBaseUrl: string, provider: string) {\n this.baseUrl = apiBaseUrl;\n this.provider = provider;\n }\n\n /**\n * GET request to the EHR proxy.\n * @param path — path relative to the provider root (e.g., \"/patients/123/\")\n * @param params — optional query parameters\n */\n async get<T = unknown>(\n path: string,\n params?: Record<string, unknown>,\n ): Promise<T> {\n const url = new URL(`/api/ehr/${this.provider}${path}`, this.baseUrl);\n if (params) {\n for (const [key, value] of Object.entries(params)) {\n if (value !== undefined) {\n url.searchParams.set(key, String(value));\n }\n }\n }\n\n const response = await fetch(url.toString(), {\n method: \"GET\",\n headers: { Accept: \"application/json\" },\n });\n\n if (!response.ok) {\n throw new EhrProxyError(this.provider, \"GET\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n /**\n * POST request to the EHR proxy.\n */\n async post<T = unknown>(path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}/api/ehr/${this.provider}${path}`;\n\n const response = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n throw new EhrProxyError(this.provider, \"POST\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n /**\n * PUT request to the EHR proxy.\n */\n async put<T = unknown>(path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}/api/ehr/${this.provider}${path}`;\n\n const response = await fetch(url, {\n method: \"PUT\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n throw new EhrProxyError(this.provider, \"PUT\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n /**\n * PATCH request to the EHR proxy.\n */\n async patch<T = unknown>(path: string, body?: unknown): Promise<T> {\n const url = `${this.baseUrl}/api/ehr/${this.provider}${path}`;\n\n const response = await fetch(url, {\n method: \"PATCH\",\n headers: {\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n },\n body: body !== undefined ? JSON.stringify(body) : undefined,\n });\n\n if (!response.ok) {\n throw new EhrProxyError(this.provider, \"PATCH\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n\n /**\n * DELETE request to the EHR proxy.\n */\n async delete<T = unknown>(path: string): Promise<T> {\n const url = `${this.baseUrl}/api/ehr/${this.provider}${path}`;\n\n const response = await fetch(url, {\n method: \"DELETE\",\n headers: { Accept: \"application/json\" },\n });\n\n if (!response.ok) {\n throw new EhrProxyError(this.provider, \"DELETE\", path, response.status);\n }\n\n return (await response.json()) as T;\n }\n}\n\n// ---------------------------------------------------------------------------\n// EHR Resource — exposes per-provider proxies\n// ---------------------------------------------------------------------------\n\nclass EhrResource {\n /** Elation EHR proxy */\n readonly elation: EhrProviderProxy;\n\n /** Hint Health proxy */\n readonly hint: EhrProviderProxy;\n\n constructor(apiBaseUrl: string) {\n this.elation = new EhrProviderProxy(apiBaseUrl, \"elation\");\n this.hint = new EhrProviderProxy(apiBaseUrl, \"hint\");\n }\n}\n\n// ---------------------------------------------------------------------------\n// Error\n// ---------------------------------------------------------------------------\n\nclass EhrProxyError extends Error {\n readonly provider: string;\n readonly method: string;\n readonly path: string;\n readonly status: number;\n\n constructor(provider: string, method: string, path: string, status: number) {\n super(\n `EHR proxy error: ${method} /api/ehr/${provider}${path} returned ${status}`,\n );\n this.name = \"EhrProxyError\";\n this.provider = provider;\n this.method = method;\n this.path = path;\n this.status = status;\n }\n}\n\nexport { EhrResource, EhrProviderProxy, EhrProxyError };\n","/**\n * PatientResource provides data access to normalized patient records\n * backed by Convex.\n */\n\nimport type { ConvexHttpClient } from \"convex/browser\";\nimport type { PaginatedResult } from \"../types/config\";\nimport type { Patient, PatientListOptions } from \"../types/patient\";\n\nclass PatientResource {\n private readonly convex: ConvexHttpClient;\n\n constructor(convexClient: ConvexHttpClient) {\n this.convex = convexClient;\n }\n\n /**\n * Get a patient by their Truth platform ID.\n */\n async get(id: string): Promise<Patient | null> {\n try {\n const result = await this.convex.query(\n \"patients:getById\" as never,\n {\n id,\n } as never,\n );\n return (result as Patient) ?? null;\n } catch {\n return null;\n }\n }\n\n /**\n * Get a patient by their Elation EHR ID.\n */\n async getByElationId(elationId: string): Promise<Patient | null> {\n try {\n const result = await this.convex.query(\n \"patients:getByElationId\" as never,\n { elationId } as never,\n );\n return (result as Patient) ?? null;\n } catch {\n return null;\n }\n }\n\n /**\n * Get a patient by their Hint EHR ID.\n */\n async getByHintId(hintId: string): Promise<Patient | null> {\n try {\n const result = await this.convex.query(\n \"patients:getByHintId\" as never,\n {\n hintId,\n } as never,\n );\n return (result as Patient) ?? null;\n } catch {\n return null;\n }\n }\n\n /**\n * List patients with optional search, pagination, and limit.\n */\n async list(options?: PatientListOptions): Promise<PaginatedResult<Patient>> {\n try {\n const result = await this.convex.query(\n \"patients:list\" as never,\n {\n search: options?.search,\n limit: options?.limit,\n cursor: options?.cursor,\n } as never,\n );\n\n const typed = result as PaginatedResult<Patient> | undefined;\n\n return typed ?? { data: [], cursor: null, hasMore: false };\n } catch {\n return { data: [], cursor: null, hasMore: false };\n }\n }\n}\n\nexport { PatientResource };\n","/**\n * Event tracker with batching, retry, and flush support.\n *\n * Buffers events in an internal queue and flushes them to the Truth API\n * endpoint. Flushes occur when the buffer reaches `batchSize` or every\n * `flushIntervalMs` milliseconds, whichever comes first.\n */\n\nimport type { ActorContext } from \"../types/config\";\nimport type {\n EventEnvelope,\n EventPayloadMap,\n EventType,\n TrackOptions,\n} from \"./events\";\n\n// ---------------------------------------------------------------------------\n// UUID v7 helper (no external dependency)\n// ---------------------------------------------------------------------------\n\n/**\n * Generates a UUID v7 string. Uses crypto.randomUUID where available,\n * falling back to a timestamp + random bytes implementation.\n *\n * UUID v7 layout (RFC 9562):\n * 48 bits - unix timestamp (ms)\n * 4 bits - version (0b0111)\n * 12 bits - random\n * 2 bits - variant (0b10)\n * 62 bits - random\n */\nfunction generateUuidV7(): string {\n const now = Date.now();\n\n // 6 bytes of timestamp\n const timeBytes = new Uint8Array(6);\n let ts = now;\n for (let i = 5; i >= 0; i--) {\n timeBytes[i] = ts & 0xff;\n ts = Math.floor(ts / 256);\n }\n\n // 10 bytes of random\n const randomBytes = new Uint8Array(10);\n if (\n typeof globalThis.crypto !== \"undefined\" &&\n globalThis.crypto.getRandomValues\n ) {\n globalThis.crypto.getRandomValues(randomBytes);\n } else {\n for (let i = 0; i < 10; i++) {\n randomBytes[i] = Math.floor(Math.random() * 256);\n }\n }\n\n // Assemble 16 bytes\n const bytes = new Uint8Array(16);\n bytes.set(timeBytes, 0);\n bytes.set(randomBytes, 6);\n\n // Set version (bits 48-51 to 0b0111)\n bytes[6] = (bytes[6] & 0x0f) | 0x70;\n\n // Set variant (bits 64-65 to 0b10)\n bytes[8] = (bytes[8] & 0x3f) | 0x80;\n\n // Format as hex string with dashes\n const hex = Array.from(bytes)\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n\n return [\n hex.slice(0, 8),\n hex.slice(8, 12),\n hex.slice(12, 16),\n hex.slice(16, 20),\n hex.slice(20, 32),\n ].join(\"-\");\n}\n\n// ---------------------------------------------------------------------------\n// Environment-based API URL resolution\n// ---------------------------------------------------------------------------\n\nconst API_URLS: Record<string, string> = {\n local: \"http://localhost:3000\",\n staging: \"https://app.sandbox.communication-hub.com\",\n sandbox: \"https://app.sandbox.communication-hub.com\",\n uat: \"https://app.sandbox.communication-hub.com\",\n production: \"https://app.truth.communication-hub.com\",\n};\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst DEFAULT_BATCH_SIZE = 25;\nconst DEFAULT_FLUSH_INTERVAL_MS = 5_000;\nconst MAX_RETRIES = 3;\nconst BASE_RETRY_DELAY_MS = 500;\n\n// ---------------------------------------------------------------------------\n// Tracker configuration\n// ---------------------------------------------------------------------------\n\ninterface TrackerConfig {\n apiKey: string;\n environment: string;\n source: string;\n sourceVersion: string;\n tenantId: string;\n batchSize: number;\n flushIntervalMs: number;\n apiBaseUrl?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Tracker class\n// ---------------------------------------------------------------------------\n\nclass Tracker {\n private readonly config: TrackerConfig;\n readonly apiUrl: string;\n private queue: EventEnvelope[] = [];\n private flushTimer: ReturnType<typeof setInterval> | null = null;\n private defaultActor: ActorContext | undefined;\n private isFlushing = false;\n private isShutdown = false;\n\n constructor(config: TrackerConfig) {\n this.config = config;\n this.apiUrl =\n config.apiBaseUrl ?? API_URLS[config.environment] ?? API_URLS.local;\n\n this.startFlushInterval();\n this.registerShutdownHooks();\n }\n\n /**\n * Set the default actor context for subsequent events.\n */\n setActor(actor: ActorContext): void {\n this.defaultActor = actor;\n }\n\n /**\n * Enqueue a typed event for delivery. This is fire-and-forget from\n * the caller's perspective -- events are buffered and flushed in batches.\n */\n track<T extends EventType>(\n eventType: T,\n payload: EventPayloadMap[T],\n options?: TrackOptions,\n ): void {\n if (this.isShutdown) {\n return;\n }\n\n const now = new Date().toISOString();\n\n const envelope: EventEnvelope = {\n event_id: generateUuidV7(),\n event_type: eventType,\n schema_version: 1,\n occurred_at: options?.occurredAt ?? now,\n received_at: now,\n source: this.config.source,\n source_version: this.config.sourceVersion,\n tenant_id: options?.tenantId ?? this.config.tenantId,\n actor:\n options?.actor ??\n (this.defaultActor\n ? {\n actor_id: this.defaultActor.actorId,\n actor_type: this.defaultActor.actorType,\n }\n : undefined),\n subject: options?.subject,\n compliance: options?.compliance,\n payload: payload as unknown as Record<string, unknown>,\n };\n\n this.queue.push(envelope);\n\n if (this.queue.length >= this.config.batchSize) {\n void this.flush();\n }\n }\n\n /**\n * Force an immediate flush of all buffered events.\n * Returns a promise that resolves when the flush completes.\n */\n async flush(): Promise<void> {\n if (this.queue.length === 0 || this.isFlushing) {\n return;\n }\n\n this.isFlushing = true;\n const batch = this.queue.splice(0, this.config.batchSize);\n\n try {\n await this.sendBatch(batch);\n } catch {\n // Re-queue events that failed to send (prepend to maintain ordering)\n this.queue.unshift(...batch);\n } finally {\n this.isFlushing = false;\n }\n\n // If there are still events in the queue, flush again\n if (this.queue.length >= this.config.batchSize) {\n await this.flush();\n }\n }\n\n /**\n * Gracefully shut down the tracker. Flushes remaining events and\n * clears the flush interval.\n */\n async shutdown(): Promise<void> {\n this.isShutdown = true;\n this.stopFlushInterval();\n await this.flush();\n }\n\n /**\n * Send a batch of events to the Truth API with exponential backoff retry.\n */\n private async sendBatch(batch: EventEnvelope[]): Promise<void> {\n let lastError: unknown;\n\n for (let attempt = 0; attempt <= MAX_RETRIES; attempt++) {\n try {\n const response = await fetch(`${this.apiUrl}/api/events/ingest`, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n Authorization: `Bearer ${this.config.apiKey}`,\n },\n body: JSON.stringify({ events: batch }),\n });\n\n if (response.ok) {\n return;\n }\n\n // Don't retry 4xx client errors (except 429)\n if (\n response.status >= 400 &&\n response.status < 500 &&\n response.status !== 429\n ) {\n return;\n }\n\n lastError = new Error(\n `HTTP ${response.status}: ${response.statusText}`,\n );\n } catch (error) {\n lastError = error;\n }\n\n // Exponential backoff with jitter\n if (attempt < MAX_RETRIES) {\n const delay = BASE_RETRY_DELAY_MS * 2 ** attempt;\n const jitter = Math.random() * delay * 0.5;\n await sleep(delay + jitter);\n }\n }\n\n throw lastError;\n }\n\n private startFlushInterval(): void {\n if (this.config.flushIntervalMs > 0) {\n this.flushTimer = setInterval(() => {\n void this.flush();\n }, this.config.flushIntervalMs);\n\n // Unref the timer so it doesn't prevent Node.js from exiting\n if (typeof this.flushTimer === \"object\" && \"unref\" in this.flushTimer) {\n this.flushTimer.unref();\n }\n }\n }\n\n private stopFlushInterval(): void {\n if (this.flushTimer !== null) {\n clearInterval(this.flushTimer);\n this.flushTimer = null;\n }\n }\n\n private registerShutdownHooks(): void {\n // Only register in Node.js environments\n if (typeof globalThis.process !== \"undefined\" && globalThis.process.on) {\n const shutdownHandler = () => {\n void this.shutdown();\n };\n\n globalThis.process.on(\"beforeExit\", shutdownHandler);\n globalThis.process.on(\"SIGTERM\", shutdownHandler);\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n}\n\nexport {\n Tracker,\n generateUuidV7,\n DEFAULT_BATCH_SIZE,\n DEFAULT_FLUSH_INTERVAL_MS,\n};\nexport type { TrackerConfig };\n","/**\n * Typed event definitions for the Truth Platform event store.\n *\n * All 26 event types from the Communication Hub -> Truth Event Store Contract.\n * Events are grouped by domain and include typed payload interfaces.\n */\n\n// ---------------------------------------------------------------------------\n// Event type constants\n// ---------------------------------------------------------------------------\n\nconst CONVERSATION_EVENTS = {\n created: \"conversation.created.v1\",\n messageSent: \"conversation.message_sent.v1\",\n messageReceived: \"conversation.message_received.v1\",\n markedRead: \"conversation.marked_read.v1\",\n attachmentUploaded: \"conversation.attachment_uploaded.v1\",\n attachmentDownloaded: \"conversation.attachment_downloaded.v1\",\n} as const;\n\nconst CALL_EVENTS = {\n initiated: \"call.initiated.v1\",\n connected: \"call.connected.v1\",\n ended: \"call.ended.v1\",\n missed: \"call.missed.v1\",\n} as const;\n\nconst TASK_EVENTS = {\n created: \"task.created.v1\",\n assigned: \"task.assigned.v1\",\n statusChanged: \"task.status_changed.v1\",\n} as const;\n\nconst REMINDER_EVENTS = {\n scheduled: \"reminder.scheduled.v1\",\n triggered: \"reminder.triggered.v1\",\n} as const;\n\nconst TRANSLATION_EVENTS = {\n requested: \"translation.requested.v1\",\n completed: \"translation.completed.v1\",\n} as const;\n\nconst NOTIFICATION_EVENTS = {\n sent: \"notification.sent.v1\",\n delivered: \"notification.delivered.v1\",\n opened: \"notification.opened.v1\",\n} as const;\n\nconst PROVIDER_EVENTS = {\n syncStarted: \"provider.sync_started.v1\",\n syncSucceeded: \"provider.sync_succeeded.v1\",\n syncFailed: \"provider.sync_failed.v1\",\n} as const;\n\nconst AUTH_EVENTS = {\n loginSucceeded: \"auth.login_succeeded.v1\",\n loginFailed: \"auth.login_failed.v1\",\n} as const;\n\nconst SECURITY_EVENTS = {\n accessDenied: \"security.access_denied.v1\",\n} as const;\n\n/**\n * All event type constants grouped by domain.\n */\nconst EVENT_TYPES = {\n conversation: CONVERSATION_EVENTS,\n call: CALL_EVENTS,\n task: TASK_EVENTS,\n reminder: REMINDER_EVENTS,\n translation: TRANSLATION_EVENTS,\n notification: NOTIFICATION_EVENTS,\n provider: PROVIDER_EVENTS,\n auth: AUTH_EVENTS,\n security: SECURITY_EVENTS,\n} as const;\n\n// ---------------------------------------------------------------------------\n// Event type union\n// ---------------------------------------------------------------------------\n\ntype ConversationEventType =\n (typeof CONVERSATION_EVENTS)[keyof typeof CONVERSATION_EVENTS];\ntype CallEventType = (typeof CALL_EVENTS)[keyof typeof CALL_EVENTS];\ntype TaskEventType = (typeof TASK_EVENTS)[keyof typeof TASK_EVENTS];\ntype ReminderEventType = (typeof REMINDER_EVENTS)[keyof typeof REMINDER_EVENTS];\ntype TranslationEventType =\n (typeof TRANSLATION_EVENTS)[keyof typeof TRANSLATION_EVENTS];\ntype NotificationEventType =\n (typeof NOTIFICATION_EVENTS)[keyof typeof NOTIFICATION_EVENTS];\ntype ProviderEventType = (typeof PROVIDER_EVENTS)[keyof typeof PROVIDER_EVENTS];\ntype AuthEventType = (typeof AUTH_EVENTS)[keyof typeof AUTH_EVENTS];\ntype SecurityEventType = (typeof SECURITY_EVENTS)[keyof typeof SECURITY_EVENTS];\n\n/**\n * Union of all 26 registered event type strings.\n */\ntype EventType =\n | ConversationEventType\n | CallEventType\n | TaskEventType\n | ReminderEventType\n | TranslationEventType\n | NotificationEventType\n | ProviderEventType\n | AuthEventType\n | SecurityEventType;\n\n// ---------------------------------------------------------------------------\n// Payload interfaces (per the contract doc)\n// ---------------------------------------------------------------------------\n\ninterface ConversationCreatedPayload {\n channel: string;\n origin_system: string;\n participant_count: number;\n}\n\ninterface ConversationMessageSentPayload {\n channel: string;\n direction: string;\n message_chars: number;\n has_attachment: boolean;\n provider_system: string;\n}\n\ninterface ConversationMessageReceivedPayload {\n channel: string;\n direction: string;\n message_chars: number;\n provider_system: string;\n}\n\ninterface ConversationMarkedReadPayload {\n read_by_actor_id: string;\n unread_count_before: number;\n unread_count_after: number;\n}\n\ninterface ConversationAttachmentUploadedPayload {\n attachment_id: string;\n mime_type: string;\n size_bytes: number;\n storage_class: string;\n}\n\ninterface ConversationAttachmentDownloadedPayload {\n attachment_id: string;\n download_actor_type: string;\n access_path: string;\n}\n\ninterface CallInitiatedPayload {\n direction: string;\n provider_system: string;\n from_number_ref: string;\n to_number_ref: string;\n}\n\ninterface CallConnectedPayload {\n provider_system: string;\n ring_duration_ms: number;\n}\n\ninterface CallEndedPayload {\n provider_system: string;\n duration_ms: number;\n end_reason: string;\n disposition: string;\n}\n\ninterface CallMissedPayload {\n provider_system: string;\n miss_reason: string;\n}\n\ninterface TaskCreatedPayload {\n task_id: string;\n created_by: string;\n assigned_to: string;\n priority: string;\n due_at: string;\n}\n\ninterface TaskAssignedPayload {\n task_id: string;\n assigned_to: string;\n assigned_by: string;\n}\n\ninterface TaskStatusChangedPayload {\n task_id: string;\n status_from: string;\n status_to: string;\n changed_by: string;\n}\n\ninterface ReminderScheduledPayload {\n reminder_id: string;\n conversation_id: string;\n scheduled_for: string;\n scheduled_by: string;\n}\n\ninterface ReminderTriggeredPayload {\n reminder_id: string;\n trigger_result: string;\n notification_attempted: boolean;\n}\n\ninterface TranslationRequestedPayload {\n target_language: string;\n source_language: string;\n char_count: number;\n mode: string;\n}\n\ninterface TranslationCompletedPayload {\n target_language: string;\n provider: string;\n latency_ms: number;\n success: boolean;\n error_code?: string;\n}\n\ninterface NotificationSentPayload {\n notification_id: string;\n channel: string;\n platform: string;\n recipient_ref: string;\n success: boolean;\n}\n\ninterface NotificationDeliveredPayload {\n notification_id: string;\n platform: string;\n delivered_at: string;\n}\n\ninterface NotificationOpenedPayload {\n notification_id: string;\n platform: string;\n opened_at: string;\n}\n\ninterface ProviderSyncStartedPayload {\n provider_system: string;\n operation: string;\n scope: string;\n batch_id: string;\n}\n\ninterface ProviderSyncSucceededPayload {\n provider_system: string;\n operation: string;\n batch_id: string;\n records_processed: number;\n duration_ms: number;\n}\n\ninterface ProviderSyncFailedPayload {\n provider_system: string;\n operation: string;\n batch_id: string;\n error_code: string;\n retryable: boolean;\n}\n\ninterface AuthLoginSucceededPayload {\n auth_provider: string;\n platform: string;\n session_ref: string;\n}\n\ninterface AuthLoginFailedPayload {\n auth_provider: string;\n platform: string;\n failure_code: string;\n}\n\ninterface SecurityAccessDeniedPayload {\n resource: string;\n policy: string;\n reason_code: string;\n actor_id: string;\n}\n\n// ---------------------------------------------------------------------------\n// Event type -> payload mapping\n// ---------------------------------------------------------------------------\n\n/**\n * Maps each event type string to its required payload interface.\n */\ninterface EventPayloadMap {\n \"conversation.created.v1\": ConversationCreatedPayload;\n \"conversation.message_sent.v1\": ConversationMessageSentPayload;\n \"conversation.message_received.v1\": ConversationMessageReceivedPayload;\n \"conversation.marked_read.v1\": ConversationMarkedReadPayload;\n \"conversation.attachment_uploaded.v1\": ConversationAttachmentUploadedPayload;\n \"conversation.attachment_downloaded.v1\": ConversationAttachmentDownloadedPayload;\n \"call.initiated.v1\": CallInitiatedPayload;\n \"call.connected.v1\": CallConnectedPayload;\n \"call.ended.v1\": CallEndedPayload;\n \"call.missed.v1\": CallMissedPayload;\n \"task.created.v1\": TaskCreatedPayload;\n \"task.assigned.v1\": TaskAssignedPayload;\n \"task.status_changed.v1\": TaskStatusChangedPayload;\n \"reminder.scheduled.v1\": ReminderScheduledPayload;\n \"reminder.triggered.v1\": ReminderTriggeredPayload;\n \"translation.requested.v1\": TranslationRequestedPayload;\n \"translation.completed.v1\": TranslationCompletedPayload;\n \"notification.sent.v1\": NotificationSentPayload;\n \"notification.delivered.v1\": NotificationDeliveredPayload;\n \"notification.opened.v1\": NotificationOpenedPayload;\n \"provider.sync_started.v1\": ProviderSyncStartedPayload;\n \"provider.sync_succeeded.v1\": ProviderSyncSucceededPayload;\n \"provider.sync_failed.v1\": ProviderSyncFailedPayload;\n \"auth.login_succeeded.v1\": AuthLoginSucceededPayload;\n \"auth.login_failed.v1\": AuthLoginFailedPayload;\n \"security.access_denied.v1\": SecurityAccessDeniedPayload;\n}\n\n// ---------------------------------------------------------------------------\n// Event envelope\n// ---------------------------------------------------------------------------\n\n/**\n * Subject references for the event. Uses tokenized references only -- no PHI.\n */\ninterface EventSubject {\n patient_ref?: string;\n conversation_id?: string;\n task_id?: string;\n call_id?: string;\n}\n\n/**\n * Actor who triggered the event.\n */\ninterface EventActor {\n actor_id: string;\n actor_type: \"user\" | \"system\" | \"webhook\";\n}\n\n/**\n * Compliance metadata for the event.\n */\ninterface EventCompliance {\n pii_level: \"none\" | \"limited\" | \"full\";\n contains_phi: boolean;\n consent_context: string;\n retention_class: string;\n}\n\n/**\n * Canonical event envelope. Every tracked event is wrapped in this structure\n * before being sent to the Truth API.\n */\ninterface EventEnvelope {\n event_id: string;\n event_type: string;\n schema_version: number;\n occurred_at: string;\n received_at: string;\n source: string;\n source_version: string;\n tenant_id: string;\n actor?: EventActor;\n subject?: EventSubject;\n compliance?: EventCompliance;\n payload: Record<string, unknown>;\n}\n\n// ---------------------------------------------------------------------------\n// Track options (per-call overrides)\n// ---------------------------------------------------------------------------\n\n/**\n * Optional overrides when calling truth.track().\n */\ninterface TrackOptions {\n /** Override the default actor for this event */\n actor?: EventActor;\n\n /** Subject references for this event */\n subject?: EventSubject;\n\n /** Compliance metadata for this event */\n compliance?: EventCompliance;\n\n /** Override the default tenant ID for this event */\n tenantId?: string;\n\n /** Override the occurred_at timestamp (ISO 8601) */\n occurredAt?: string;\n}\n\nexport {\n EVENT_TYPES,\n CONVERSATION_EVENTS,\n CALL_EVENTS,\n TASK_EVENTS,\n REMINDER_EVENTS,\n TRANSLATION_EVENTS,\n NOTIFICATION_EVENTS,\n PROVIDER_EVENTS,\n AUTH_EVENTS,\n SECURITY_EVENTS,\n};\n\nexport type {\n EventType,\n ConversationEventType,\n CallEventType,\n TaskEventType,\n ReminderEventType,\n TranslationEventType,\n NotificationEventType,\n ProviderEventType,\n AuthEventType,\n SecurityEventType,\n EventPayloadMap,\n EventEnvelope,\n EventActor,\n EventSubject,\n EventCompliance,\n TrackOptions,\n ConversationCreatedPayload,\n ConversationMessageSentPayload,\n ConversationMessageReceivedPayload,\n ConversationMarkedReadPayload,\n ConversationAttachmentUploadedPayload,\n ConversationAttachmentDownloadedPayload,\n CallInitiatedPayload,\n CallConnectedPayload,\n CallEndedPayload,\n CallMissedPayload,\n TaskCreatedPayload,\n TaskAssignedPayload,\n TaskStatusChangedPayload,\n ReminderScheduledPayload,\n ReminderTriggeredPayload,\n TranslationRequestedPayload,\n TranslationCompletedPayload,\n NotificationSentPayload,\n NotificationDeliveredPayload,\n NotificationOpenedPayload,\n ProviderSyncStartedPayload,\n ProviderSyncSucceededPayload,\n ProviderSyncFailedPayload,\n AuthLoginSucceededPayload,\n AuthLoginFailedPayload,\n SecurityAccessDeniedPayload,\n};\n","/**\n * Configuration interfaces for the Truth SDK.\n */\n\n/**\n * Environment options for the Truth platform.\n */\nconst ENVIRONMENTS = {\n local: \"local\",\n staging: \"staging\",\n sandbox: \"sandbox\",\n uat: \"uat\",\n production: \"production\",\n} as const;\n\ntype Environment = (typeof ENVIRONMENTS)[keyof typeof ENVIRONMENTS];\n\n/**\n * Configuration for initializing a TruthClient.\n */\ninterface TruthClientConfig {\n /** API key for authenticating with the Truth platform (e.g. \"hn_live_...\") */\n apiKey: string;\n\n /** Target environment */\n environment: Environment;\n\n /** Override the default Convex URL for data access */\n convexUrl?: string;\n\n /** Event source identifier (e.g. \"communication-hub.backend\") */\n source?: string;\n\n /** Git SHA or version string for event source versioning */\n sourceVersion?: string;\n\n /** Default tenant (organization) ID for events */\n tenantId?: string;\n\n /** Number of events to buffer before flushing (default: 25) */\n batchSize?: number;\n\n /** Interval in milliseconds between automatic flushes (default: 5000) */\n flushIntervalMs?: number;\n\n /** Base URL for the Truth API (overrides environment-based default) */\n apiBaseUrl?: string;\n}\n\n/**\n * Actor context attached to tracked events.\n */\ninterface ActorContext {\n actorId: string;\n actorType: \"user\" | \"system\" | \"webhook\";\n}\n\n/**\n * Paginated result wrapper for list operations.\n */\ninterface PaginatedResult<T> {\n data: T[];\n cursor: string | null;\n hasMore: boolean;\n}\n\nexport { ENVIRONMENTS };\nexport type { Environment, TruthClientConfig, ActorContext, PaginatedResult };\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hipnation-truth/sdk",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "HIPnation Truth Platform SDK",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -32,8 +32,10 @@
32
32
  "dev": "tsup --watch",
33
33
  "typecheck": "tsc --noEmit"
34
34
  },
35
+ "dependencies": {
36
+ "convex": "^1.31.0"
37
+ },
35
38
  "peerDependencies": {
36
- "convex": "^1.31.0",
37
39
  "react": ">=18"
38
40
  },
39
41
  "peerDependenciesMeta": {
@@ -41,11 +43,9 @@
41
43
  "optional": true
42
44
  }
43
45
  },
44
- "dependencies": {},
45
46
  "devDependencies": {
46
47
  "@repo/tsconfig": "workspace:*",
47
48
  "@types/react": "^19.0.0",
48
- "convex": "^1.31.7",
49
49
  "react": "^19.0.0",
50
50
  "tsup": "^8.0.0",
51
51
  "typescript": "5.9.3"