@channlize/core 0.1.0-alpha.1 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md ADDED
@@ -0,0 +1,14 @@
1
+ # @channlize/core
2
+
3
+ ## 0.1.0
4
+
5
+ ### Minor Changes
6
+
7
+ - 9ddf630: Errors thrown by the client now carry the API's human-readable `message`
8
+ (field messages joined for validation failures) instead of the error code,
9
+ and `ChannlizeError.code` is set from the API's `error` code.
10
+
11
+ `CreateContactResponse` gains the fields the API actually returns:
12
+ `success`, `conversationId` and `message`. The old `id`, `status` and
13
+ `slackThreadUrl` fields were never returned and are deprecated. The MCP
14
+ `submit_contact_form` tool now reports `conversationId`.
package/README.md CHANGED
@@ -68,6 +68,12 @@ const messages = await client.getChatMessages(session.id, 50, 0);
68
68
 
69
69
  // Close session
70
70
  await client.closeChatSession(session.id);
71
+
72
+ // Event tracking (browser)
73
+ await client.trackEvent('page.viewed', { properties: { path: '/pricing' } });
74
+
75
+ // Event tracking (server; set serverApiKey on the client)
76
+ await client.trackServerEvent('webhook.received', { severity: 'warning' });
71
77
  ```
72
78
 
73
79
  ### Error Handling
package/dist/index.d.mts CHANGED
@@ -1,15 +1,29 @@
1
1
  /**
2
2
  * Core types for Channlize SDK
3
3
  */
4
+ /** Severity for tracked events (Slack routing uses project settings). */
5
+ type EventSeverity = 'info' | 'warning' | 'error';
6
+ interface TrackEventOptions {
7
+ properties?: Record<string, unknown>;
8
+ severity?: EventSeverity;
9
+ distinctId?: string;
10
+ pageUrl?: string;
11
+ userAgent?: string;
12
+ }
4
13
  interface ChannlizeConfig {
5
- /** API key for authentication */
14
+ /** Widget key used for public SDK endpoints (contact form, chat, browser event tracking) */
6
15
  apiKey: string;
7
16
  /** Base URL for the Channlize API */
8
17
  baseUrl?: string;
9
- /** Project ID */
18
+ /** Project ID (required for server-side `trackServerEvent`) */
10
19
  projectId: string;
11
20
  /** Request timeout in milliseconds */
12
21
  timeout?: number;
22
+ /**
23
+ * Organization API key for server-side `trackServerEvent` (`POST /v1/events`).
24
+ * Do not expose in browser bundles.
25
+ */
26
+ serverApiKey?: string;
13
27
  }
14
28
  interface ContactFormData {
15
29
  /** Contact's name */
@@ -81,12 +95,19 @@ interface ApiResponse<T = unknown> {
81
95
  /** Additional metadata */
82
96
  meta?: Record<string, unknown>;
83
97
  }
98
+ /** Response of `POST /public/contact` (api/app/api/public/contact/route.ts). */
84
99
  interface CreateContactResponse {
85
- /** Contact form submission ID */
100
+ /** Whether the submission was accepted */
101
+ success: boolean;
102
+ /** Conversation the submission was filed under */
103
+ conversationId: string;
104
+ /** Human-readable confirmation to show the visitor */
105
+ message: string;
106
+ /** @deprecated Never returned by the API (always undefined). Use `conversationId`. */
86
107
  id: string;
87
- /** Status of the submission */
108
+ /** @deprecated Never returned by the API (always undefined). */
88
109
  status: 'received' | 'processing' | 'delivered';
89
- /** Slack thread URL if available */
110
+ /** @deprecated Never returned by the API (always undefined). */
90
111
  slackThreadUrl?: string;
91
112
  }
92
113
  interface CreateChatSessionResponse {
@@ -139,7 +160,9 @@ declare class ChannlizeClient {
139
160
  */
140
161
  createChatSession(metadata?: Record<string, unknown>): Promise<CreateChatSessionResponse>;
141
162
  /**
142
- * Send a message in a chat session
163
+ * Send a message in a chat session.
164
+ * When `attachments` are provided the request is sent as multipart/form-data
165
+ * so the files are uploaded alongside the message content.
143
166
  */
144
167
  sendMessage(sessionId: string, content: string, attachments?: File[]): Promise<SendMessageResponse>;
145
168
  /**
@@ -154,6 +177,24 @@ declare class ChannlizeClient {
154
177
  * Close a chat session
155
178
  */
156
179
  closeChatSession(sessionId: string): Promise<ChatSession>;
180
+ /**
181
+ * Track a product or UX event from the browser (uses widget key → POST /public/events).
182
+ */
183
+ trackEvent(name: string, options?: TrackEventOptions): Promise<{
184
+ success: boolean;
185
+ id: string;
186
+ }>;
187
+ /**
188
+ * Track an event from a trusted server using the organization API key (POST /v1/events).
189
+ */
190
+ trackServerEvent(name: string, options?: {
191
+ properties?: Record<string, unknown>;
192
+ severity?: EventSeverity;
193
+ }): Promise<{
194
+ success: boolean;
195
+ id: string;
196
+ }>;
157
197
  }
158
198
 
159
- export { type ApiResponse, AuthenticationError, ChannlizeClient, type ChannlizeConfig, ChannlizeError, type ChatMessage, type ChatSession, type ContactFormData, type CreateChatSessionResponse, type CreateContactResponse, type FileAttachment, RateLimitError, type SendMessageResponse, ValidationError, ChannlizeClient as default };
199
+ export { AuthenticationError, ChannlizeClient, ChannlizeError, RateLimitError, ValidationError, ChannlizeClient as default };
200
+ export type { ApiResponse, ChannlizeConfig, ChatMessage, ChatSession, ContactFormData, CreateChatSessionResponse, CreateContactResponse, EventSeverity, FileAttachment, SendMessageResponse, TrackEventOptions };
package/dist/index.d.ts CHANGED
@@ -1,15 +1,29 @@
1
1
  /**
2
2
  * Core types for Channlize SDK
3
3
  */
4
+ /** Severity for tracked events (Slack routing uses project settings). */
5
+ type EventSeverity = 'info' | 'warning' | 'error';
6
+ interface TrackEventOptions {
7
+ properties?: Record<string, unknown>;
8
+ severity?: EventSeverity;
9
+ distinctId?: string;
10
+ pageUrl?: string;
11
+ userAgent?: string;
12
+ }
4
13
  interface ChannlizeConfig {
5
- /** API key for authentication */
14
+ /** Widget key used for public SDK endpoints (contact form, chat, browser event tracking) */
6
15
  apiKey: string;
7
16
  /** Base URL for the Channlize API */
8
17
  baseUrl?: string;
9
- /** Project ID */
18
+ /** Project ID (required for server-side `trackServerEvent`) */
10
19
  projectId: string;
11
20
  /** Request timeout in milliseconds */
12
21
  timeout?: number;
22
+ /**
23
+ * Organization API key for server-side `trackServerEvent` (`POST /v1/events`).
24
+ * Do not expose in browser bundles.
25
+ */
26
+ serverApiKey?: string;
13
27
  }
14
28
  interface ContactFormData {
15
29
  /** Contact's name */
@@ -81,12 +95,19 @@ interface ApiResponse<T = unknown> {
81
95
  /** Additional metadata */
82
96
  meta?: Record<string, unknown>;
83
97
  }
98
+ /** Response of `POST /public/contact` (api/app/api/public/contact/route.ts). */
84
99
  interface CreateContactResponse {
85
- /** Contact form submission ID */
100
+ /** Whether the submission was accepted */
101
+ success: boolean;
102
+ /** Conversation the submission was filed under */
103
+ conversationId: string;
104
+ /** Human-readable confirmation to show the visitor */
105
+ message: string;
106
+ /** @deprecated Never returned by the API (always undefined). Use `conversationId`. */
86
107
  id: string;
87
- /** Status of the submission */
108
+ /** @deprecated Never returned by the API (always undefined). */
88
109
  status: 'received' | 'processing' | 'delivered';
89
- /** Slack thread URL if available */
110
+ /** @deprecated Never returned by the API (always undefined). */
90
111
  slackThreadUrl?: string;
91
112
  }
92
113
  interface CreateChatSessionResponse {
@@ -139,7 +160,9 @@ declare class ChannlizeClient {
139
160
  */
140
161
  createChatSession(metadata?: Record<string, unknown>): Promise<CreateChatSessionResponse>;
141
162
  /**
142
- * Send a message in a chat session
163
+ * Send a message in a chat session.
164
+ * When `attachments` are provided the request is sent as multipart/form-data
165
+ * so the files are uploaded alongside the message content.
143
166
  */
144
167
  sendMessage(sessionId: string, content: string, attachments?: File[]): Promise<SendMessageResponse>;
145
168
  /**
@@ -154,6 +177,24 @@ declare class ChannlizeClient {
154
177
  * Close a chat session
155
178
  */
156
179
  closeChatSession(sessionId: string): Promise<ChatSession>;
180
+ /**
181
+ * Track a product or UX event from the browser (uses widget key → POST /public/events).
182
+ */
183
+ trackEvent(name: string, options?: TrackEventOptions): Promise<{
184
+ success: boolean;
185
+ id: string;
186
+ }>;
187
+ /**
188
+ * Track an event from a trusted server using the organization API key (POST /v1/events).
189
+ */
190
+ trackServerEvent(name: string, options?: {
191
+ properties?: Record<string, unknown>;
192
+ severity?: EventSeverity;
193
+ }): Promise<{
194
+ success: boolean;
195
+ id: string;
196
+ }>;
157
197
  }
158
198
 
159
- export { type ApiResponse, AuthenticationError, ChannlizeClient, type ChannlizeConfig, ChannlizeError, type ChatMessage, type ChatSession, type ContactFormData, type CreateChatSessionResponse, type CreateContactResponse, type FileAttachment, RateLimitError, type SendMessageResponse, ValidationError, ChannlizeClient as default };
199
+ export { AuthenticationError, ChannlizeClient, ChannlizeError, RateLimitError, ValidationError, ChannlizeClient as default };
200
+ export type { ApiResponse, ChannlizeConfig, ChatMessage, ChatSession, ContactFormData, CreateChatSessionResponse, CreateContactResponse, EventSeverity, FileAttachment, SendMessageResponse, TrackEventOptions };
package/dist/index.js CHANGED
@@ -50,6 +50,8 @@ var ChannlizeError = class extends Error {
50
50
  this.code = code;
51
51
  this.name = "ChannlizeError";
52
52
  }
53
+ statusCode;
54
+ code;
53
55
  };
54
56
  var ValidationError = class extends ChannlizeError {
55
57
  constructor(message, field) {
@@ -57,6 +59,7 @@ var ValidationError = class extends ChannlizeError {
57
59
  this.field = field;
58
60
  this.name = "ValidationError";
59
61
  }
62
+ field;
60
63
  };
61
64
  var AuthenticationError = class extends ChannlizeError {
62
65
  constructor(message = "Authentication failed") {
@@ -92,13 +95,17 @@ var ChannlizeClient = class {
92
95
  const controller = new AbortController();
93
96
  const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
94
97
  try {
98
+ const mergedHeaders = {
99
+ "Content-Type": "application/json",
100
+ ...options.headers
101
+ };
102
+ if (mergedHeaders["Content-Type"] === "") {
103
+ delete mergedHeaders["Content-Type"];
104
+ }
95
105
  const response = await (0, import_cross_fetch.default)(url, {
96
106
  ...options,
97
107
  signal: controller.signal,
98
- headers: {
99
- "Content-Type": "application/json",
100
- ...options.headers
101
- }
108
+ headers: mergedHeaders
102
109
  });
103
110
  clearTimeout(timeoutId);
104
111
  if (!response.ok) {
@@ -128,7 +135,9 @@ var ChannlizeClient = class {
128
135
  } catch {
129
136
  }
130
137
  }
131
- const message = errorData.error || `HTTP ${response.status}: ${response.statusText}`;
138
+ const rawMessage = errorData.message;
139
+ const message = (Array.isArray(rawMessage) ? rawMessage.join(", ") : rawMessage) || `HTTP ${response.status}: ${response.statusText}`;
140
+ const code = errorData.code ?? errorData.error;
132
141
  switch (response.status) {
133
142
  case 401:
134
143
  throw new AuthenticationError(message);
@@ -137,51 +146,77 @@ var ChannlizeClient = class {
137
146
  case 429:
138
147
  throw new RateLimitError(message);
139
148
  default:
140
- throw new ChannlizeError(message, response.status, errorData.code);
149
+ throw new ChannlizeError(message, response.status, code);
141
150
  }
142
151
  }
143
152
  /**
144
153
  * Submit a contact form
145
154
  */
146
155
  async submitContactForm(data) {
147
- const response = await this.makeRequest("/public/contact", {
148
- method: "POST",
149
- body: JSON.stringify({
150
- widgetKey: this.config.apiKey,
151
- // apiKey is actually the widgetKey
152
- subject: data.subject,
153
- message: data.message,
154
- email: data.email,
155
- name: data.name,
156
- pageUrl: data.pageUrl || (typeof window !== "undefined" ? window.location.href : void 0),
157
- userAgent: data.userAgent || (typeof navigator !== "undefined" ? navigator.userAgent : void 0)
158
- })
159
- });
156
+ const response = await this.makeRequest(
157
+ "/public/contact",
158
+ {
159
+ method: "POST",
160
+ body: JSON.stringify({
161
+ widgetKey: this.config.apiKey,
162
+ // apiKey is actually the widgetKey
163
+ subject: data.subject,
164
+ message: data.message,
165
+ email: data.email,
166
+ name: data.name,
167
+ pageUrl: data.pageUrl || (typeof window !== "undefined" ? window.location.href : void 0),
168
+ userAgent: data.userAgent || (typeof navigator !== "undefined" ? navigator.userAgent : void 0)
169
+ })
170
+ }
171
+ );
160
172
  return response.data || response;
161
173
  }
162
174
  /**
163
175
  * Create a new chat session
164
176
  */
165
177
  async createChatSession(metadata) {
166
- const response = await this.makeRequest("/v1/chat/sessions", {
167
- method: "POST",
168
- body: JSON.stringify({
169
- widgetKey: this.config.apiKey,
170
- // apiKey is actually the widgetKey
171
- metadata: {
172
- ...metadata,
173
- pageUrl: typeof window !== "undefined" ? window.location.href : void 0,
174
- userAgent: typeof navigator !== "undefined" ? navigator.userAgent : void 0
175
- }
176
- })
177
- });
178
+ const response = await this.makeRequest(
179
+ "/v1/chat/sessions",
180
+ {
181
+ method: "POST",
182
+ body: JSON.stringify({
183
+ widgetKey: this.config.apiKey,
184
+ // apiKey is actually the widgetKey
185
+ metadata: {
186
+ ...metadata,
187
+ pageUrl: typeof window !== "undefined" ? window.location.href : void 0,
188
+ userAgent: typeof navigator !== "undefined" ? navigator.userAgent : void 0
189
+ }
190
+ })
191
+ }
192
+ );
178
193
  return response.data;
179
194
  }
180
195
  /**
181
- * Send a message in a chat session
196
+ * Send a message in a chat session.
197
+ * When `attachments` are provided the request is sent as multipart/form-data
198
+ * so the files are uploaded alongside the message content.
182
199
  */
183
200
  async sendMessage(sessionId, content, attachments) {
184
201
  const idempotencyKey = `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
202
+ if (attachments && attachments.length > 0) {
203
+ const formData = new FormData();
204
+ formData.append("content", content);
205
+ formData.append("idempotencyKey", idempotencyKey);
206
+ for (const file of attachments) {
207
+ formData.append("attachments", file, file.name);
208
+ }
209
+ const response2 = await this.makeRequest(
210
+ `/v1/chat/sessions/${sessionId}/messages`,
211
+ {
212
+ method: "POST",
213
+ body: formData,
214
+ // Let the browser set Content-Type with boundary for multipart
215
+ headers: { "Content-Type": "" }
216
+ }
217
+ );
218
+ return response2.data;
219
+ }
185
220
  const response = await this.makeRequest(
186
221
  `/v1/chat/sessions/${sessionId}/messages`,
187
222
  {
@@ -198,7 +233,9 @@ var ChannlizeClient = class {
198
233
  * Get chat session details
199
234
  */
200
235
  async getChatSession(sessionId) {
201
- const response = await this.makeRequest(`/v1/chat/sessions/${sessionId}`);
236
+ const response = await this.makeRequest(
237
+ `/v1/chat/sessions/${sessionId}`
238
+ );
202
239
  return response.data;
203
240
  }
204
241
  /**
@@ -220,6 +257,55 @@ var ChannlizeClient = class {
220
257
  );
221
258
  return response.data;
222
259
  }
260
+ /**
261
+ * Track a product or UX event from the browser (uses widget key → POST /public/events).
262
+ */
263
+ async trackEvent(name, options) {
264
+ const res = await this.makeRequest(
265
+ "/public/events",
266
+ {
267
+ method: "POST",
268
+ body: JSON.stringify({
269
+ widgetKey: this.config.apiKey,
270
+ name,
271
+ properties: options?.properties,
272
+ severity: options?.severity,
273
+ distinctId: options?.distinctId,
274
+ pageUrl: options?.pageUrl ?? (typeof window !== "undefined" ? window.location.href : void 0),
275
+ userAgent: options?.userAgent ?? (typeof navigator !== "undefined" ? navigator.userAgent : void 0)
276
+ })
277
+ }
278
+ );
279
+ const data = res.data ?? res;
280
+ return data;
281
+ }
282
+ /**
283
+ * Track an event from a trusted server using the organization API key (POST /v1/events).
284
+ */
285
+ async trackServerEvent(name, options) {
286
+ if (!this.config.serverApiKey) {
287
+ throw new ValidationError(
288
+ "serverApiKey is required for trackServerEvent"
289
+ );
290
+ }
291
+ const res = await this.makeRequest(
292
+ "/v1/events",
293
+ {
294
+ method: "POST",
295
+ body: JSON.stringify({
296
+ projectId: this.config.projectId,
297
+ name,
298
+ properties: options?.properties,
299
+ severity: options?.severity
300
+ }),
301
+ headers: {
302
+ Authorization: `Bearer ${this.config.serverApiKey}`
303
+ }
304
+ }
305
+ );
306
+ const data = res.data ?? res;
307
+ return data;
308
+ }
223
309
  };
224
310
  // Annotate the CommonJS export names for ESM import in node:
225
311
  0 && (module.exports = {
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/types.ts"],"sourcesContent":["/**\n * @channlize/core\n * Core TypeScript SDK for Channlize platform\n */\n\nexport { ChannlizeClient } from './client';\nexport * from './types';\n\n// Re-export for convenience\nexport { ChannlizeClient as default } from './client';\n","import fetch from 'cross-fetch';\nimport type {\n ChannlizeConfig,\n ContactFormData,\n ChatMessage,\n ApiResponse,\n CreateContactResponse,\n CreateChatSessionResponse,\n SendMessageResponse,\n ChatSession,\n} from './types';\nimport {\n ChannlizeError,\n AuthenticationError,\n ValidationError,\n RateLimitError,\n} from './types';\n\n/**\n * Channlize API Client\n * Provides methods to interact with the Channlize platform\n */\nexport class ChannlizeClient {\n private readonly config: Required<ChannlizeConfig>;\n\n constructor(config: ChannlizeConfig) {\n this.config = {\n baseUrl: config.baseUrl || 'https://api.channlize.com',\n timeout: 10000,\n ...config,\n };\n\n this.validateConfig();\n }\n\n private validateConfig(): void {\n if (!this.config.apiKey) {\n throw new ValidationError('Widget key is required');\n }\n }\n\n private async makeRequest<T>(\n endpoint: string,\n options: RequestInit = {}\n ): Promise<ApiResponse<T>> {\n const url = `${this.config.baseUrl}${endpoint}`;\n \n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);\n\n try {\n const response = await fetch(url, {\n ...options,\n signal: controller.signal,\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n await this.handleErrorResponse(response);\n }\n\n const data = await response.json();\n return data as ApiResponse<T>;\n } catch (error) {\n clearTimeout(timeoutId);\n \n if (error instanceof ChannlizeError) {\n throw error;\n }\n \n if (error instanceof Error && error.name === 'AbortError') {\n throw new ChannlizeError('Request timeout', 408, 'TIMEOUT');\n }\n \n throw new ChannlizeError(\n `Network error: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n }\n\n private async handleErrorResponse(response: Response): Promise<never> {\n const contentType = response.headers.get('content-type');\n let errorData: any = {};\n\n if (contentType?.includes('application/json')) {\n try {\n errorData = await response.json();\n } catch {\n // Ignore JSON parsing errors\n }\n }\n\n const message = errorData.error || `HTTP ${response.status}: ${response.statusText}`;\n\n switch (response.status) {\n case 401:\n throw new AuthenticationError(message);\n case 400:\n throw new ValidationError(message, errorData.field);\n case 429:\n throw new RateLimitError(message);\n default:\n throw new ChannlizeError(message, response.status, errorData.code);\n }\n }\n\n /**\n * Submit a contact form\n */\n async submitContactForm(data: ContactFormData): Promise<CreateContactResponse> {\n const response = await this.makeRequest<CreateContactResponse>('/public/contact', {\n method: 'POST',\n body: JSON.stringify({\n widgetKey: this.config.apiKey, // apiKey is actually the widgetKey\n subject: data.subject,\n message: data.message,\n email: data.email,\n name: data.name,\n pageUrl: data.pageUrl || (typeof window !== 'undefined' ? window.location.href : undefined),\n userAgent: data.userAgent || (typeof navigator !== 'undefined' ? navigator.userAgent : undefined),\n }),\n });\n\n return response.data || response;\n }\n\n /**\n * Create a new chat session\n */\n async createChatSession(metadata?: Record<string, unknown>): Promise<CreateChatSessionResponse> {\n const response = await this.makeRequest<CreateChatSessionResponse>('/v1/chat/sessions', {\n method: 'POST',\n body: JSON.stringify({\n widgetKey: this.config.apiKey, // apiKey is actually the widgetKey\n metadata: {\n ...metadata,\n pageUrl: typeof window !== 'undefined' ? window.location.href : undefined,\n userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : undefined,\n },\n }),\n });\n\n return response.data;\n }\n\n /**\n * Send a message in a chat session\n */\n async sendMessage(\n sessionId: string,\n content: string,\n attachments?: File[]\n ): Promise<SendMessageResponse> {\n // Generate idempotency key to prevent duplicate message creation\n const idempotencyKey = `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n \n // For now, we send as JSON. File attachments support can be added later.\n // TODO: Implement file upload support\n const response = await this.makeRequest<SendMessageResponse>(\n `/v1/chat/sessions/${sessionId}/messages`,\n {\n method: 'POST',\n body: JSON.stringify({\n content,\n idempotencyKey,\n }),\n }\n );\n\n return response.data;\n }\n\n /**\n * Get chat session details\n */\n async getChatSession(sessionId: string): Promise<ChatSession> {\n const response = await this.makeRequest<ChatSession>(`/v1/chat/sessions/${sessionId}`);\n return response.data;\n }\n\n /**\n * Get messages for a chat session\n */\n async getChatMessages(sessionId: string, limit = 50, offset = 0): Promise<ChatMessage[]> {\n const response = await this.makeRequest<ChatMessage[]>(\n `/v1/chat/sessions/${sessionId}/messages?limit=${limit}&offset=${offset}`\n );\n return response.data;\n }\n\n /**\n * Close a chat session\n */\n async closeChatSession(sessionId: string): Promise<ChatSession> {\n const response = await this.makeRequest<ChatSession>(\n `/v1/chat/sessions/${sessionId}/close`,\n { method: 'POST' }\n );\n return response.data;\n }\n}\n","/**\n * Core types for Channlize SDK\n */\n\nexport interface ChannlizeConfig {\n /** API key for authentication */\n apiKey: string;\n /** Base URL for the Channlize API */\n baseUrl?: string;\n /** Project ID */\n projectId: string;\n /** Request timeout in milliseconds */\n timeout?: number;\n}\n\nexport interface ContactFormData {\n /** Contact's name */\n name: string;\n /** Contact's email address */\n email: string;\n /** Subject of the inquiry */\n subject?: string;\n /** Message content */\n message: string;\n /** Custom fields */\n customFields?: Record<string, unknown>;\n /** Page URL where the form was submitted */\n pageUrl?: string;\n /** User agent string */\n userAgent?: string;\n}\n\nexport interface ChatMessage {\n /** Unique message ID */\n id: string;\n /** Message content */\n content: string;\n /** Message timestamp */\n timestamp: Date;\n /** Message author (user or agent) */\n author: 'user' | 'agent';\n /** Author metadata */\n authorData?: {\n name?: string;\n email?: string;\n avatarUrl?: string;\n };\n /** Attached files */\n attachments?: FileAttachment[];\n}\n\nexport interface FileAttachment {\n /** File ID */\n id: string;\n /** Original filename */\n name: string;\n /** File size in bytes */\n size: number;\n /** MIME type */\n type: string;\n /** Download URL */\n url: string;\n}\n\nexport interface ChatSession {\n /** Session ID */\n id: string;\n /** Session status */\n status: 'active' | 'closed' | 'waiting';\n /** Messages in the session */\n messages: ChatMessage[];\n /** Session metadata */\n metadata?: Record<string, unknown>;\n /** Created timestamp */\n createdAt: Date;\n /** Updated timestamp */\n updatedAt: Date;\n}\n\nexport interface ApiResponse<T = unknown> {\n /** Response data */\n data: T;\n /** Success status */\n success: boolean;\n /** Error message if any */\n error?: string;\n /** Additional metadata */\n meta?: Record<string, unknown>;\n}\n\nexport interface CreateContactResponse {\n /** Contact form submission ID */\n id: string;\n /** Status of the submission */\n status: 'received' | 'processing' | 'delivered';\n /** Slack thread URL if available */\n slackThreadUrl?: string;\n}\n\nexport interface CreateChatSessionResponse {\n /** Chat session data */\n session: ChatSession;\n /** SSE endpoint for real-time updates */\n sseEndpoint?: string;\n}\n\nexport interface SendMessageResponse {\n /** The sent message */\n message: ChatMessage;\n /** Updated session */\n session: ChatSession;\n}\n\n/**\n * Error types\n */\nexport class ChannlizeError extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n public code?: string\n ) {\n super(message);\n this.name = 'ChannlizeError';\n }\n}\n\nexport class ValidationError extends ChannlizeError {\n constructor(message: string, public field?: string) {\n super(message, 400, 'VALIDATION_ERROR');\n this.name = 'ValidationError';\n }\n}\n\nexport class AuthenticationError extends ChannlizeError {\n constructor(message: string = 'Authentication failed') {\n super(message, 401, 'AUTHENTICATION_ERROR');\n this.name = 'AuthenticationError';\n }\n}\n\nexport class RateLimitError extends ChannlizeError {\n constructor(message: string = 'Rate limit exceeded') {\n super(message, 429, 'RATE_LIMIT_ERROR');\n this.name = 'RateLimitError';\n }\n}\n"],"mappings":"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","names":["fetch"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/client.ts","../src/types.ts"],"sourcesContent":["/**\n * @channlize/core\n * Core TypeScript SDK for Channlize platform\n */\n\nexport { ChannlizeClient } from './client';\nexport * from './types';\n\n// Re-export for convenience\nexport { ChannlizeClient as default } from './client';\n","import fetch from 'cross-fetch';\nimport type {\n ChannlizeConfig,\n ContactFormData,\n ChatMessage,\n ApiResponse,\n CreateContactResponse,\n CreateChatSessionResponse,\n SendMessageResponse,\n ChatSession,\n TrackEventOptions,\n EventSeverity,\n} from './types';\nimport {\n ChannlizeError,\n AuthenticationError,\n ValidationError,\n RateLimitError,\n} from './types';\n\n/**\n * Channlize API Client\n * Provides methods to interact with the Channlize platform\n */\nexport class ChannlizeClient {\n private readonly config: ChannlizeConfig & {\n baseUrl: string;\n timeout: number;\n };\n\n constructor(config: ChannlizeConfig) {\n this.config = {\n baseUrl: config.baseUrl || 'https://api.channlize.com',\n timeout: 10000,\n ...config,\n };\n\n this.validateConfig();\n }\n\n private validateConfig(): void {\n if (!this.config.apiKey) {\n throw new ValidationError('Widget key is required');\n }\n }\n\n private async makeRequest<T>(\n endpoint: string,\n options: RequestInit = {}\n ): Promise<ApiResponse<T>> {\n const url = `${this.config.baseUrl}${endpoint}`;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);\n\n try {\n const mergedHeaders: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...(options.headers as Record<string, string>),\n };\n\n // When Content-Type is explicitly empty (e.g. FormData), remove it so the\n // browser / runtime can set the correct multipart boundary automatically.\n if (mergedHeaders['Content-Type'] === '') {\n delete mergedHeaders['Content-Type'];\n }\n\n const response = await fetch(url, {\n ...options,\n signal: controller.signal,\n headers: mergedHeaders,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n await this.handleErrorResponse(response);\n }\n\n const data = await response.json();\n return data as ApiResponse<T>;\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof ChannlizeError) {\n throw error;\n }\n\n if (error instanceof Error && error.name === 'AbortError') {\n throw new ChannlizeError('Request timeout', 408, 'TIMEOUT');\n }\n\n throw new ChannlizeError(\n `Network error: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n }\n\n private async handleErrorResponse(response: Response): Promise<never> {\n const contentType = response.headers.get('content-type');\n let errorData: any = {};\n\n if (contentType?.includes('application/json')) {\n try {\n errorData = await response.json();\n } catch {\n // Ignore JSON parsing errors\n }\n }\n\n // API error shape (api/lib/api/error.ts):\n // { statusCode, error: \"BAD_REQUEST\", message: string | string[] }\n // `error` is the machine-readable code; `message` is the human text\n // (an array of field messages for validation failures).\n const rawMessage = errorData.message;\n const message =\n (Array.isArray(rawMessage) ? rawMessage.join(', ') : rawMessage) ||\n `HTTP ${response.status}: ${response.statusText}`;\n const code: string | undefined = errorData.code ?? errorData.error;\n\n switch (response.status) {\n case 401:\n throw new AuthenticationError(message);\n case 400:\n throw new ValidationError(message, errorData.field);\n case 429:\n throw new RateLimitError(message);\n default:\n throw new ChannlizeError(message, response.status, code);\n }\n }\n\n /**\n * Submit a contact form\n */\n async submitContactForm(\n data: ContactFormData\n ): Promise<CreateContactResponse> {\n const response = await this.makeRequest<CreateContactResponse>(\n '/public/contact',\n {\n method: 'POST',\n body: JSON.stringify({\n widgetKey: this.config.apiKey, // apiKey is actually the widgetKey\n subject: data.subject,\n message: data.message,\n email: data.email,\n name: data.name,\n pageUrl:\n data.pageUrl ||\n (typeof window !== 'undefined' ? window.location.href : undefined),\n userAgent:\n data.userAgent ||\n (typeof navigator !== 'undefined'\n ? navigator.userAgent\n : undefined),\n }),\n }\n );\n\n return response.data || response;\n }\n\n /**\n * Create a new chat session\n */\n async createChatSession(\n metadata?: Record<string, unknown>\n ): Promise<CreateChatSessionResponse> {\n const response = await this.makeRequest<CreateChatSessionResponse>(\n '/v1/chat/sessions',\n {\n method: 'POST',\n body: JSON.stringify({\n widgetKey: this.config.apiKey, // apiKey is actually the widgetKey\n metadata: {\n ...metadata,\n pageUrl:\n typeof window !== 'undefined' ? window.location.href : undefined,\n userAgent:\n typeof navigator !== 'undefined'\n ? navigator.userAgent\n : undefined,\n },\n }),\n }\n );\n\n return response.data;\n }\n\n /**\n * Send a message in a chat session.\n * When `attachments` are provided the request is sent as multipart/form-data\n * so the files are uploaded alongside the message content.\n */\n async sendMessage(\n sessionId: string,\n content: string,\n attachments?: File[]\n ): Promise<SendMessageResponse> {\n const idempotencyKey = `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n\n if (attachments && attachments.length > 0) {\n const formData = new FormData();\n formData.append('content', content);\n formData.append('idempotencyKey', idempotencyKey);\n for (const file of attachments) {\n formData.append('attachments', file, file.name);\n }\n\n const response = await this.makeRequest<SendMessageResponse>(\n `/v1/chat/sessions/${sessionId}/messages`,\n {\n method: 'POST',\n body: formData,\n // Let the browser set Content-Type with boundary for multipart\n headers: { 'Content-Type': '' },\n }\n );\n\n return response.data;\n }\n\n const response = await this.makeRequest<SendMessageResponse>(\n `/v1/chat/sessions/${sessionId}/messages`,\n {\n method: 'POST',\n body: JSON.stringify({\n content,\n idempotencyKey,\n }),\n }\n );\n\n return response.data;\n }\n\n /**\n * Get chat session details\n */\n async getChatSession(sessionId: string): Promise<ChatSession> {\n const response = await this.makeRequest<ChatSession>(\n `/v1/chat/sessions/${sessionId}`\n );\n return response.data;\n }\n\n /**\n * Get messages for a chat session\n */\n async getChatMessages(\n sessionId: string,\n limit = 50,\n offset = 0\n ): Promise<ChatMessage[]> {\n const response = await this.makeRequest<ChatMessage[]>(\n `/v1/chat/sessions/${sessionId}/messages?limit=${limit}&offset=${offset}`\n );\n return response.data;\n }\n\n /**\n * Close a chat session\n */\n async closeChatSession(sessionId: string): Promise<ChatSession> {\n const response = await this.makeRequest<ChatSession>(\n `/v1/chat/sessions/${sessionId}/close`,\n { method: 'POST' }\n );\n return response.data;\n }\n\n /**\n * Track a product or UX event from the browser (uses widget key → POST /public/events).\n */\n async trackEvent(\n name: string,\n options?: TrackEventOptions\n ): Promise<{ success: boolean; id: string }> {\n const res = await this.makeRequest<{ success: boolean; id: string }>(\n '/public/events',\n {\n method: 'POST',\n body: JSON.stringify({\n widgetKey: this.config.apiKey,\n name,\n properties: options?.properties,\n severity: options?.severity,\n distinctId: options?.distinctId,\n pageUrl:\n options?.pageUrl ??\n (typeof window !== 'undefined' ? window.location.href : undefined),\n userAgent:\n options?.userAgent ??\n (typeof navigator !== 'undefined'\n ? navigator.userAgent\n : undefined),\n }),\n }\n );\n const data =\n (res as ApiResponse<{ success: boolean; id: string }>).data ??\n (res as unknown as { success: boolean; id: string });\n return data;\n }\n\n /**\n * Track an event from a trusted server using the organization API key (POST /v1/events).\n */\n async trackServerEvent(\n name: string,\n options?: { properties?: Record<string, unknown>; severity?: EventSeverity }\n ): Promise<{ success: boolean; id: string }> {\n if (!this.config.serverApiKey) {\n throw new ValidationError(\n 'serverApiKey is required for trackServerEvent'\n );\n }\n const res = await this.makeRequest<{ success: boolean; id: string }>(\n '/v1/events',\n {\n method: 'POST',\n body: JSON.stringify({\n projectId: this.config.projectId,\n name,\n properties: options?.properties,\n severity: options?.severity,\n }),\n headers: {\n Authorization: `Bearer ${this.config.serverApiKey}`,\n },\n }\n );\n const data =\n (res as ApiResponse<{ success: boolean; id: string }>).data ??\n (res as unknown as { success: boolean; id: string });\n return data;\n }\n}\n","/**\n * Core types for Channlize SDK\n */\n\n/** Severity for tracked events (Slack routing uses project settings). */\nexport type EventSeverity = 'info' | 'warning' | 'error';\n\nexport interface TrackEventOptions {\n properties?: Record<string, unknown>;\n severity?: EventSeverity;\n distinctId?: string;\n pageUrl?: string;\n userAgent?: string;\n}\n\nexport interface ChannlizeConfig {\n /** Widget key used for public SDK endpoints (contact form, chat, browser event tracking) */\n apiKey: string;\n /** Base URL for the Channlize API */\n baseUrl?: string;\n /** Project ID (required for server-side `trackServerEvent`) */\n projectId: string;\n /** Request timeout in milliseconds */\n timeout?: number;\n /**\n * Organization API key for server-side `trackServerEvent` (`POST /v1/events`).\n * Do not expose in browser bundles.\n */\n serverApiKey?: string;\n}\n\nexport interface ContactFormData {\n /** Contact's name */\n name: string;\n /** Contact's email address */\n email: string;\n /** Subject of the inquiry */\n subject?: string;\n /** Message content */\n message: string;\n /** Custom fields */\n customFields?: Record<string, unknown>;\n /** Page URL where the form was submitted */\n pageUrl?: string;\n /** User agent string */\n userAgent?: string;\n}\n\nexport interface ChatMessage {\n /** Unique message ID */\n id: string;\n /** Message content */\n content: string;\n /** Message timestamp */\n timestamp: Date;\n /** Message author (user or agent) */\n author: 'user' | 'agent';\n /** Author metadata */\n authorData?: {\n name?: string;\n email?: string;\n avatarUrl?: string;\n };\n /** Attached files */\n attachments?: FileAttachment[];\n}\n\nexport interface FileAttachment {\n /** File ID */\n id: string;\n /** Original filename */\n name: string;\n /** File size in bytes */\n size: number;\n /** MIME type */\n type: string;\n /** Download URL */\n url: string;\n}\n\nexport interface ChatSession {\n /** Session ID */\n id: string;\n /** Session status */\n status: 'active' | 'closed' | 'waiting';\n /** Messages in the session */\n messages: ChatMessage[];\n /** Session metadata */\n metadata?: Record<string, unknown>;\n /** Created timestamp */\n createdAt: Date;\n /** Updated timestamp */\n updatedAt: Date;\n}\n\nexport interface ApiResponse<T = unknown> {\n /** Response data */\n data: T;\n /** Success status */\n success: boolean;\n /** Error message if any */\n error?: string;\n /** Additional metadata */\n meta?: Record<string, unknown>;\n}\n\n/** Response of `POST /public/contact` (api/app/api/public/contact/route.ts). */\nexport interface CreateContactResponse {\n /** Whether the submission was accepted */\n success: boolean;\n /** Conversation the submission was filed under */\n conversationId: string;\n /** Human-readable confirmation to show the visitor */\n message: string;\n /** @deprecated Never returned by the API (always undefined). Use `conversationId`. */\n id: string;\n /** @deprecated Never returned by the API (always undefined). */\n status: 'received' | 'processing' | 'delivered';\n /** @deprecated Never returned by the API (always undefined). */\n slackThreadUrl?: string;\n}\n\nexport interface CreateChatSessionResponse {\n /** Chat session data */\n session: ChatSession;\n /** SSE endpoint for real-time updates */\n sseEndpoint?: string;\n}\n\nexport interface SendMessageResponse {\n /** The sent message */\n message: ChatMessage;\n /** Updated session */\n session: ChatSession;\n}\n\n/**\n * Error types\n */\nexport class ChannlizeError extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n public code?: string\n ) {\n super(message);\n this.name = 'ChannlizeError';\n }\n}\n\nexport class ValidationError extends ChannlizeError {\n constructor(\n message: string,\n public field?: string\n ) {\n super(message, 400, 'VALIDATION_ERROR');\n this.name = 'ValidationError';\n }\n}\n\nexport class AuthenticationError extends ChannlizeError {\n constructor(message: string = 'Authentication failed') {\n super(message, 401, 'AUTHENTICATION_ERROR');\n this.name = 'AuthenticationError';\n }\n}\n\nexport class RateLimitError extends ChannlizeError {\n constructor(message: string = 'Rate limit exceeded') {\n super(message, 429, 'RATE_LIMIT_ERROR');\n this.name = 'RateLimitError';\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACAA,yBAAkB;;;AC2IX,IAAM,iBAAN,cAA6B,MAAM;AAAA,EACxC,YACE,SACO,YACA,MACP;AACA,UAAM,OAAO;AAHN;AACA;AAGP,SAAK,OAAO;AAAA,EACd;AAAA,EALS;AAAA,EACA;AAKX;AAEO,IAAM,kBAAN,cAA8B,eAAe;AAAA,EAClD,YACE,SACO,OACP;AACA,UAAM,SAAS,KAAK,kBAAkB;AAF/B;AAGP,SAAK,OAAO;AAAA,EACd;AAAA,EAJS;AAKX;AAEO,IAAM,sBAAN,cAAkC,eAAe;AAAA,EACtD,YAAY,UAAkB,yBAAyB;AACrD,UAAM,SAAS,KAAK,sBAAsB;AAC1C,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,iBAAN,cAA6B,eAAe;AAAA,EACjD,YAAY,UAAkB,uBAAuB;AACnD,UAAM,SAAS,KAAK,kBAAkB;AACtC,SAAK,OAAO;AAAA,EACd;AACF;;;ADpJO,IAAM,kBAAN,MAAsB;AAAA,EACV;AAAA,EAKjB,YAAY,QAAyB;AACnC,SAAK,SAAS;AAAA,MACZ,SAAS,OAAO,WAAW;AAAA,MAC3B,SAAS;AAAA,MACT,GAAG;AAAA,IACL;AAEA,SAAK,eAAe;AAAA,EACtB;AAAA,EAEQ,iBAAuB;AAC7B,QAAI,CAAC,KAAK,OAAO,QAAQ;AACvB,YAAM,IAAI,gBAAgB,wBAAwB;AAAA,IACpD;AAAA,EACF;AAAA,EAEA,MAAc,YACZ,UACA,UAAuB,CAAC,GACC;AACzB,UAAM,MAAM,GAAG,KAAK,OAAO,OAAO,GAAG,QAAQ;AAE7C,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,KAAK,OAAO,OAAO;AAE1E,QAAI;AACF,YAAM,gBAAwC;AAAA,QAC5C,gBAAgB;AAAA,QAChB,GAAI,QAAQ;AAAA,MACd;AAIA,UAAI,cAAc,cAAc,MAAM,IAAI;AACxC,eAAO,cAAc,cAAc;AAAA,MACrC;AAEA,YAAM,WAAW,UAAM,mBAAAA,SAAM,KAAK;AAAA,QAChC,GAAG;AAAA,QACH,QAAQ,WAAW;AAAA,QACnB,SAAS;AAAA,MACX,CAAC;AAED,mBAAa,SAAS;AAEtB,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,KAAK,oBAAoB,QAAQ;AAAA,MACzC;AAEA,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,aAAO;AAAA,IACT,SAAS,OAAO;AACd,mBAAa,SAAS;AAEtB,UAAI,iBAAiB,gBAAgB;AACnC,cAAM;AAAA,MACR;AAEA,UAAI,iBAAiB,SAAS,MAAM,SAAS,cAAc;AACzD,cAAM,IAAI,eAAe,mBAAmB,KAAK,SAAS;AAAA,MAC5D;AAEA,YAAM,IAAI;AAAA,QACR,kBAAkB,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MAC5E;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,oBAAoB,UAAoC;AACpE,UAAM,cAAc,SAAS,QAAQ,IAAI,cAAc;AACvD,QAAI,YAAiB,CAAC;AAEtB,QAAI,aAAa,SAAS,kBAAkB,GAAG;AAC7C,UAAI;AACF,oBAAY,MAAM,SAAS,KAAK;AAAA,MAClC,QAAQ;AAAA,MAER;AAAA,IACF;AAMA,UAAM,aAAa,UAAU;AAC7B,UAAM,WACH,MAAM,QAAQ,UAAU,IAAI,WAAW,KAAK,IAAI,IAAI,eACrD,QAAQ,SAAS,MAAM,KAAK,SAAS,UAAU;AACjD,UAAM,OAA2B,UAAU,QAAQ,UAAU;AAE7D,YAAQ,SAAS,QAAQ;AAAA,MACvB,KAAK;AACH,cAAM,IAAI,oBAAoB,OAAO;AAAA,MACvC,KAAK;AACH,cAAM,IAAI,gBAAgB,SAAS,UAAU,KAAK;AAAA,MACpD,KAAK;AACH,cAAM,IAAI,eAAe,OAAO;AAAA,MAClC;AACE,cAAM,IAAI,eAAe,SAAS,SAAS,QAAQ,IAAI;AAAA,IAC3D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBACJ,MACgC;AAChC,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU;AAAA,UACnB,WAAW,KAAK,OAAO;AAAA;AAAA,UACvB,SAAS,KAAK;AAAA,UACd,SAAS,KAAK;AAAA,UACd,OAAO,KAAK;AAAA,UACZ,MAAM,KAAK;AAAA,UACX,SACE,KAAK,YACJ,OAAO,WAAW,cAAc,OAAO,SAAS,OAAO;AAAA,UAC1D,WACE,KAAK,cACJ,OAAO,cAAc,cAClB,UAAU,YACV;AAAA,QACR,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO,SAAS,QAAQ;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBACJ,UACoC;AACpC,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU;AAAA,UACnB,WAAW,KAAK,OAAO;AAAA;AAAA,UACvB,UAAU;AAAA,YACR,GAAG;AAAA,YACH,SACE,OAAO,WAAW,cAAc,OAAO,SAAS,OAAO;AAAA,YACzD,WACE,OAAO,cAAc,cACjB,UAAU,YACV;AAAA,UACR;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,YACJ,WACA,SACA,aAC8B;AAC9B,UAAM,iBAAiB,OAAO,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAEnF,QAAI,eAAe,YAAY,SAAS,GAAG;AACzC,YAAM,WAAW,IAAI,SAAS;AAC9B,eAAS,OAAO,WAAW,OAAO;AAClC,eAAS,OAAO,kBAAkB,cAAc;AAChD,iBAAW,QAAQ,aAAa;AAC9B,iBAAS,OAAO,eAAe,MAAM,KAAK,IAAI;AAAA,MAChD;AAEA,YAAMC,YAAW,MAAM,KAAK;AAAA,QAC1B,qBAAqB,SAAS;AAAA,QAC9B;AAAA,UACE,QAAQ;AAAA,UACR,MAAM;AAAA;AAAA,UAEN,SAAS,EAAE,gBAAgB,GAAG;AAAA,QAChC;AAAA,MACF;AAEA,aAAOA,UAAS;AAAA,IAClB;AAEA,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B,qBAAqB,SAAS;AAAA,MAC9B;AAAA,QACE,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU;AAAA,UACnB;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAAe,WAAyC;AAC5D,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B,qBAAqB,SAAS;AAAA,IAChC;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBACJ,WACA,QAAQ,IACR,SAAS,GACe;AACxB,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B,qBAAqB,SAAS,mBAAmB,KAAK,WAAW,MAAM;AAAA,IACzE;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAiB,WAAyC;AAC9D,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B,qBAAqB,SAAS;AAAA,MAC9B,EAAE,QAAQ,OAAO;AAAA,IACnB;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WACJ,MACA,SAC2C;AAC3C,UAAM,MAAM,MAAM,KAAK;AAAA,MACrB;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU;AAAA,UACnB,WAAW,KAAK,OAAO;AAAA,UACvB;AAAA,UACA,YAAY,SAAS;AAAA,UACrB,UAAU,SAAS;AAAA,UACnB,YAAY,SAAS;AAAA,UACrB,SACE,SAAS,YACR,OAAO,WAAW,cAAc,OAAO,SAAS,OAAO;AAAA,UAC1D,WACE,SAAS,cACR,OAAO,cAAc,cAClB,UAAU,YACV;AAAA,QACR,CAAC;AAAA,MACH;AAAA,IACF;AACA,UAAM,OACH,IAAsD,QACtD;AACH,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBACJ,MACA,SAC2C;AAC3C,QAAI,CAAC,KAAK,OAAO,cAAc;AAC7B,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,UAAM,MAAM,MAAM,KAAK;AAAA,MACrB;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU;AAAA,UACnB,WAAW,KAAK,OAAO;AAAA,UACvB;AAAA,UACA,YAAY,SAAS;AAAA,UACrB,UAAU,SAAS;AAAA,QACrB,CAAC;AAAA,QACD,SAAS;AAAA,UACP,eAAe,UAAU,KAAK,OAAO,YAAY;AAAA,QACnD;AAAA,MACF;AAAA,IACF;AACA,UAAM,OACH,IAAsD,QACtD;AACH,WAAO;AAAA,EACT;AACF;","names":["fetch","response"]}
package/dist/index.mjs CHANGED
@@ -9,6 +9,8 @@ var ChannlizeError = class extends Error {
9
9
  this.code = code;
10
10
  this.name = "ChannlizeError";
11
11
  }
12
+ statusCode;
13
+ code;
12
14
  };
13
15
  var ValidationError = class extends ChannlizeError {
14
16
  constructor(message, field) {
@@ -16,6 +18,7 @@ var ValidationError = class extends ChannlizeError {
16
18
  this.field = field;
17
19
  this.name = "ValidationError";
18
20
  }
21
+ field;
19
22
  };
20
23
  var AuthenticationError = class extends ChannlizeError {
21
24
  constructor(message = "Authentication failed") {
@@ -51,13 +54,17 @@ var ChannlizeClient = class {
51
54
  const controller = new AbortController();
52
55
  const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);
53
56
  try {
57
+ const mergedHeaders = {
58
+ "Content-Type": "application/json",
59
+ ...options.headers
60
+ };
61
+ if (mergedHeaders["Content-Type"] === "") {
62
+ delete mergedHeaders["Content-Type"];
63
+ }
54
64
  const response = await fetch(url, {
55
65
  ...options,
56
66
  signal: controller.signal,
57
- headers: {
58
- "Content-Type": "application/json",
59
- ...options.headers
60
- }
67
+ headers: mergedHeaders
61
68
  });
62
69
  clearTimeout(timeoutId);
63
70
  if (!response.ok) {
@@ -87,7 +94,9 @@ var ChannlizeClient = class {
87
94
  } catch {
88
95
  }
89
96
  }
90
- const message = errorData.error || `HTTP ${response.status}: ${response.statusText}`;
97
+ const rawMessage = errorData.message;
98
+ const message = (Array.isArray(rawMessage) ? rawMessage.join(", ") : rawMessage) || `HTTP ${response.status}: ${response.statusText}`;
99
+ const code = errorData.code ?? errorData.error;
91
100
  switch (response.status) {
92
101
  case 401:
93
102
  throw new AuthenticationError(message);
@@ -96,51 +105,77 @@ var ChannlizeClient = class {
96
105
  case 429:
97
106
  throw new RateLimitError(message);
98
107
  default:
99
- throw new ChannlizeError(message, response.status, errorData.code);
108
+ throw new ChannlizeError(message, response.status, code);
100
109
  }
101
110
  }
102
111
  /**
103
112
  * Submit a contact form
104
113
  */
105
114
  async submitContactForm(data) {
106
- const response = await this.makeRequest("/public/contact", {
107
- method: "POST",
108
- body: JSON.stringify({
109
- widgetKey: this.config.apiKey,
110
- // apiKey is actually the widgetKey
111
- subject: data.subject,
112
- message: data.message,
113
- email: data.email,
114
- name: data.name,
115
- pageUrl: data.pageUrl || (typeof window !== "undefined" ? window.location.href : void 0),
116
- userAgent: data.userAgent || (typeof navigator !== "undefined" ? navigator.userAgent : void 0)
117
- })
118
- });
115
+ const response = await this.makeRequest(
116
+ "/public/contact",
117
+ {
118
+ method: "POST",
119
+ body: JSON.stringify({
120
+ widgetKey: this.config.apiKey,
121
+ // apiKey is actually the widgetKey
122
+ subject: data.subject,
123
+ message: data.message,
124
+ email: data.email,
125
+ name: data.name,
126
+ pageUrl: data.pageUrl || (typeof window !== "undefined" ? window.location.href : void 0),
127
+ userAgent: data.userAgent || (typeof navigator !== "undefined" ? navigator.userAgent : void 0)
128
+ })
129
+ }
130
+ );
119
131
  return response.data || response;
120
132
  }
121
133
  /**
122
134
  * Create a new chat session
123
135
  */
124
136
  async createChatSession(metadata) {
125
- const response = await this.makeRequest("/v1/chat/sessions", {
126
- method: "POST",
127
- body: JSON.stringify({
128
- widgetKey: this.config.apiKey,
129
- // apiKey is actually the widgetKey
130
- metadata: {
131
- ...metadata,
132
- pageUrl: typeof window !== "undefined" ? window.location.href : void 0,
133
- userAgent: typeof navigator !== "undefined" ? navigator.userAgent : void 0
134
- }
135
- })
136
- });
137
+ const response = await this.makeRequest(
138
+ "/v1/chat/sessions",
139
+ {
140
+ method: "POST",
141
+ body: JSON.stringify({
142
+ widgetKey: this.config.apiKey,
143
+ // apiKey is actually the widgetKey
144
+ metadata: {
145
+ ...metadata,
146
+ pageUrl: typeof window !== "undefined" ? window.location.href : void 0,
147
+ userAgent: typeof navigator !== "undefined" ? navigator.userAgent : void 0
148
+ }
149
+ })
150
+ }
151
+ );
137
152
  return response.data;
138
153
  }
139
154
  /**
140
- * Send a message in a chat session
155
+ * Send a message in a chat session.
156
+ * When `attachments` are provided the request is sent as multipart/form-data
157
+ * so the files are uploaded alongside the message content.
141
158
  */
142
159
  async sendMessage(sessionId, content, attachments) {
143
160
  const idempotencyKey = `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
161
+ if (attachments && attachments.length > 0) {
162
+ const formData = new FormData();
163
+ formData.append("content", content);
164
+ formData.append("idempotencyKey", idempotencyKey);
165
+ for (const file of attachments) {
166
+ formData.append("attachments", file, file.name);
167
+ }
168
+ const response2 = await this.makeRequest(
169
+ `/v1/chat/sessions/${sessionId}/messages`,
170
+ {
171
+ method: "POST",
172
+ body: formData,
173
+ // Let the browser set Content-Type with boundary for multipart
174
+ headers: { "Content-Type": "" }
175
+ }
176
+ );
177
+ return response2.data;
178
+ }
144
179
  const response = await this.makeRequest(
145
180
  `/v1/chat/sessions/${sessionId}/messages`,
146
181
  {
@@ -157,7 +192,9 @@ var ChannlizeClient = class {
157
192
  * Get chat session details
158
193
  */
159
194
  async getChatSession(sessionId) {
160
- const response = await this.makeRequest(`/v1/chat/sessions/${sessionId}`);
195
+ const response = await this.makeRequest(
196
+ `/v1/chat/sessions/${sessionId}`
197
+ );
161
198
  return response.data;
162
199
  }
163
200
  /**
@@ -179,6 +216,55 @@ var ChannlizeClient = class {
179
216
  );
180
217
  return response.data;
181
218
  }
219
+ /**
220
+ * Track a product or UX event from the browser (uses widget key → POST /public/events).
221
+ */
222
+ async trackEvent(name, options) {
223
+ const res = await this.makeRequest(
224
+ "/public/events",
225
+ {
226
+ method: "POST",
227
+ body: JSON.stringify({
228
+ widgetKey: this.config.apiKey,
229
+ name,
230
+ properties: options?.properties,
231
+ severity: options?.severity,
232
+ distinctId: options?.distinctId,
233
+ pageUrl: options?.pageUrl ?? (typeof window !== "undefined" ? window.location.href : void 0),
234
+ userAgent: options?.userAgent ?? (typeof navigator !== "undefined" ? navigator.userAgent : void 0)
235
+ })
236
+ }
237
+ );
238
+ const data = res.data ?? res;
239
+ return data;
240
+ }
241
+ /**
242
+ * Track an event from a trusted server using the organization API key (POST /v1/events).
243
+ */
244
+ async trackServerEvent(name, options) {
245
+ if (!this.config.serverApiKey) {
246
+ throw new ValidationError(
247
+ "serverApiKey is required for trackServerEvent"
248
+ );
249
+ }
250
+ const res = await this.makeRequest(
251
+ "/v1/events",
252
+ {
253
+ method: "POST",
254
+ body: JSON.stringify({
255
+ projectId: this.config.projectId,
256
+ name,
257
+ properties: options?.properties,
258
+ severity: options?.severity
259
+ }),
260
+ headers: {
261
+ Authorization: `Bearer ${this.config.serverApiKey}`
262
+ }
263
+ }
264
+ );
265
+ const data = res.data ?? res;
266
+ return data;
267
+ }
182
268
  };
183
269
  export {
184
270
  AuthenticationError,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/client.ts","../src/types.ts"],"sourcesContent":["import fetch from 'cross-fetch';\nimport type {\n ChannlizeConfig,\n ContactFormData,\n ChatMessage,\n ApiResponse,\n CreateContactResponse,\n CreateChatSessionResponse,\n SendMessageResponse,\n ChatSession,\n} from './types';\nimport {\n ChannlizeError,\n AuthenticationError,\n ValidationError,\n RateLimitError,\n} from './types';\n\n/**\n * Channlize API Client\n * Provides methods to interact with the Channlize platform\n */\nexport class ChannlizeClient {\n private readonly config: Required<ChannlizeConfig>;\n\n constructor(config: ChannlizeConfig) {\n this.config = {\n baseUrl: config.baseUrl || 'https://api.channlize.com',\n timeout: 10000,\n ...config,\n };\n\n this.validateConfig();\n }\n\n private validateConfig(): void {\n if (!this.config.apiKey) {\n throw new ValidationError('Widget key is required');\n }\n }\n\n private async makeRequest<T>(\n endpoint: string,\n options: RequestInit = {}\n ): Promise<ApiResponse<T>> {\n const url = `${this.config.baseUrl}${endpoint}`;\n \n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);\n\n try {\n const response = await fetch(url, {\n ...options,\n signal: controller.signal,\n headers: {\n 'Content-Type': 'application/json',\n ...options.headers,\n },\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n await this.handleErrorResponse(response);\n }\n\n const data = await response.json();\n return data as ApiResponse<T>;\n } catch (error) {\n clearTimeout(timeoutId);\n \n if (error instanceof ChannlizeError) {\n throw error;\n }\n \n if (error instanceof Error && error.name === 'AbortError') {\n throw new ChannlizeError('Request timeout', 408, 'TIMEOUT');\n }\n \n throw new ChannlizeError(\n `Network error: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n }\n\n private async handleErrorResponse(response: Response): Promise<never> {\n const contentType = response.headers.get('content-type');\n let errorData: any = {};\n\n if (contentType?.includes('application/json')) {\n try {\n errorData = await response.json();\n } catch {\n // Ignore JSON parsing errors\n }\n }\n\n const message = errorData.error || `HTTP ${response.status}: ${response.statusText}`;\n\n switch (response.status) {\n case 401:\n throw new AuthenticationError(message);\n case 400:\n throw new ValidationError(message, errorData.field);\n case 429:\n throw new RateLimitError(message);\n default:\n throw new ChannlizeError(message, response.status, errorData.code);\n }\n }\n\n /**\n * Submit a contact form\n */\n async submitContactForm(data: ContactFormData): Promise<CreateContactResponse> {\n const response = await this.makeRequest<CreateContactResponse>('/public/contact', {\n method: 'POST',\n body: JSON.stringify({\n widgetKey: this.config.apiKey, // apiKey is actually the widgetKey\n subject: data.subject,\n message: data.message,\n email: data.email,\n name: data.name,\n pageUrl: data.pageUrl || (typeof window !== 'undefined' ? window.location.href : undefined),\n userAgent: data.userAgent || (typeof navigator !== 'undefined' ? navigator.userAgent : undefined),\n }),\n });\n\n return response.data || response;\n }\n\n /**\n * Create a new chat session\n */\n async createChatSession(metadata?: Record<string, unknown>): Promise<CreateChatSessionResponse> {\n const response = await this.makeRequest<CreateChatSessionResponse>('/v1/chat/sessions', {\n method: 'POST',\n body: JSON.stringify({\n widgetKey: this.config.apiKey, // apiKey is actually the widgetKey\n metadata: {\n ...metadata,\n pageUrl: typeof window !== 'undefined' ? window.location.href : undefined,\n userAgent: typeof navigator !== 'undefined' ? navigator.userAgent : undefined,\n },\n }),\n });\n\n return response.data;\n }\n\n /**\n * Send a message in a chat session\n */\n async sendMessage(\n sessionId: string,\n content: string,\n attachments?: File[]\n ): Promise<SendMessageResponse> {\n // Generate idempotency key to prevent duplicate message creation\n const idempotencyKey = `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n \n // For now, we send as JSON. File attachments support can be added later.\n // TODO: Implement file upload support\n const response = await this.makeRequest<SendMessageResponse>(\n `/v1/chat/sessions/${sessionId}/messages`,\n {\n method: 'POST',\n body: JSON.stringify({\n content,\n idempotencyKey,\n }),\n }\n );\n\n return response.data;\n }\n\n /**\n * Get chat session details\n */\n async getChatSession(sessionId: string): Promise<ChatSession> {\n const response = await this.makeRequest<ChatSession>(`/v1/chat/sessions/${sessionId}`);\n return response.data;\n }\n\n /**\n * Get messages for a chat session\n */\n async getChatMessages(sessionId: string, limit = 50, offset = 0): Promise<ChatMessage[]> {\n const response = await this.makeRequest<ChatMessage[]>(\n `/v1/chat/sessions/${sessionId}/messages?limit=${limit}&offset=${offset}`\n );\n return response.data;\n }\n\n /**\n * Close a chat session\n */\n async closeChatSession(sessionId: string): Promise<ChatSession> {\n const response = await this.makeRequest<ChatSession>(\n `/v1/chat/sessions/${sessionId}/close`,\n { method: 'POST' }\n );\n return response.data;\n }\n}\n","/**\n * Core types for Channlize SDK\n */\n\nexport interface ChannlizeConfig {\n /** API key for authentication */\n apiKey: string;\n /** Base URL for the Channlize API */\n baseUrl?: string;\n /** Project ID */\n projectId: string;\n /** Request timeout in milliseconds */\n timeout?: number;\n}\n\nexport interface ContactFormData {\n /** Contact's name */\n name: string;\n /** Contact's email address */\n email: string;\n /** Subject of the inquiry */\n subject?: string;\n /** Message content */\n message: string;\n /** Custom fields */\n customFields?: Record<string, unknown>;\n /** Page URL where the form was submitted */\n pageUrl?: string;\n /** User agent string */\n userAgent?: string;\n}\n\nexport interface ChatMessage {\n /** Unique message ID */\n id: string;\n /** Message content */\n content: string;\n /** Message timestamp */\n timestamp: Date;\n /** Message author (user or agent) */\n author: 'user' | 'agent';\n /** Author metadata */\n authorData?: {\n name?: string;\n email?: string;\n avatarUrl?: string;\n };\n /** Attached files */\n attachments?: FileAttachment[];\n}\n\nexport interface FileAttachment {\n /** File ID */\n id: string;\n /** Original filename */\n name: string;\n /** File size in bytes */\n size: number;\n /** MIME type */\n type: string;\n /** Download URL */\n url: string;\n}\n\nexport interface ChatSession {\n /** Session ID */\n id: string;\n /** Session status */\n status: 'active' | 'closed' | 'waiting';\n /** Messages in the session */\n messages: ChatMessage[];\n /** Session metadata */\n metadata?: Record<string, unknown>;\n /** Created timestamp */\n createdAt: Date;\n /** Updated timestamp */\n updatedAt: Date;\n}\n\nexport interface ApiResponse<T = unknown> {\n /** Response data */\n data: T;\n /** Success status */\n success: boolean;\n /** Error message if any */\n error?: string;\n /** Additional metadata */\n meta?: Record<string, unknown>;\n}\n\nexport interface CreateContactResponse {\n /** Contact form submission ID */\n id: string;\n /** Status of the submission */\n status: 'received' | 'processing' | 'delivered';\n /** Slack thread URL if available */\n slackThreadUrl?: string;\n}\n\nexport interface CreateChatSessionResponse {\n /** Chat session data */\n session: ChatSession;\n /** SSE endpoint for real-time updates */\n sseEndpoint?: string;\n}\n\nexport interface SendMessageResponse {\n /** The sent message */\n message: ChatMessage;\n /** Updated session */\n session: ChatSession;\n}\n\n/**\n * Error types\n */\nexport class ChannlizeError extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n public code?: string\n ) {\n super(message);\n this.name = 'ChannlizeError';\n }\n}\n\nexport class ValidationError extends ChannlizeError {\n constructor(message: string, public field?: string) {\n super(message, 400, 'VALIDATION_ERROR');\n this.name = 'ValidationError';\n }\n}\n\nexport class AuthenticationError extends ChannlizeError {\n constructor(message: string = 'Authentication failed') {\n super(message, 401, 'AUTHENTICATION_ERROR');\n this.name = 'AuthenticationError';\n }\n}\n\nexport class RateLimitError extends ChannlizeError {\n constructor(message: string = 'Rate limit exceeded') {\n super(message, 429, 'RATE_LIMIT_ERROR');\n this.name = 'RateLimitError';\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/client.ts","../src/types.ts"],"sourcesContent":["import fetch from 'cross-fetch';\nimport type {\n ChannlizeConfig,\n ContactFormData,\n ChatMessage,\n ApiResponse,\n CreateContactResponse,\n CreateChatSessionResponse,\n SendMessageResponse,\n ChatSession,\n TrackEventOptions,\n EventSeverity,\n} from './types';\nimport {\n ChannlizeError,\n AuthenticationError,\n ValidationError,\n RateLimitError,\n} from './types';\n\n/**\n * Channlize API Client\n * Provides methods to interact with the Channlize platform\n */\nexport class ChannlizeClient {\n private readonly config: ChannlizeConfig & {\n baseUrl: string;\n timeout: number;\n };\n\n constructor(config: ChannlizeConfig) {\n this.config = {\n baseUrl: config.baseUrl || 'https://api.channlize.com',\n timeout: 10000,\n ...config,\n };\n\n this.validateConfig();\n }\n\n private validateConfig(): void {\n if (!this.config.apiKey) {\n throw new ValidationError('Widget key is required');\n }\n }\n\n private async makeRequest<T>(\n endpoint: string,\n options: RequestInit = {}\n ): Promise<ApiResponse<T>> {\n const url = `${this.config.baseUrl}${endpoint}`;\n\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.config.timeout);\n\n try {\n const mergedHeaders: Record<string, string> = {\n 'Content-Type': 'application/json',\n ...(options.headers as Record<string, string>),\n };\n\n // When Content-Type is explicitly empty (e.g. FormData), remove it so the\n // browser / runtime can set the correct multipart boundary automatically.\n if (mergedHeaders['Content-Type'] === '') {\n delete mergedHeaders['Content-Type'];\n }\n\n const response = await fetch(url, {\n ...options,\n signal: controller.signal,\n headers: mergedHeaders,\n });\n\n clearTimeout(timeoutId);\n\n if (!response.ok) {\n await this.handleErrorResponse(response);\n }\n\n const data = await response.json();\n return data as ApiResponse<T>;\n } catch (error) {\n clearTimeout(timeoutId);\n\n if (error instanceof ChannlizeError) {\n throw error;\n }\n\n if (error instanceof Error && error.name === 'AbortError') {\n throw new ChannlizeError('Request timeout', 408, 'TIMEOUT');\n }\n\n throw new ChannlizeError(\n `Network error: ${error instanceof Error ? error.message : 'Unknown error'}`\n );\n }\n }\n\n private async handleErrorResponse(response: Response): Promise<never> {\n const contentType = response.headers.get('content-type');\n let errorData: any = {};\n\n if (contentType?.includes('application/json')) {\n try {\n errorData = await response.json();\n } catch {\n // Ignore JSON parsing errors\n }\n }\n\n // API error shape (api/lib/api/error.ts):\n // { statusCode, error: \"BAD_REQUEST\", message: string | string[] }\n // `error` is the machine-readable code; `message` is the human text\n // (an array of field messages for validation failures).\n const rawMessage = errorData.message;\n const message =\n (Array.isArray(rawMessage) ? rawMessage.join(', ') : rawMessage) ||\n `HTTP ${response.status}: ${response.statusText}`;\n const code: string | undefined = errorData.code ?? errorData.error;\n\n switch (response.status) {\n case 401:\n throw new AuthenticationError(message);\n case 400:\n throw new ValidationError(message, errorData.field);\n case 429:\n throw new RateLimitError(message);\n default:\n throw new ChannlizeError(message, response.status, code);\n }\n }\n\n /**\n * Submit a contact form\n */\n async submitContactForm(\n data: ContactFormData\n ): Promise<CreateContactResponse> {\n const response = await this.makeRequest<CreateContactResponse>(\n '/public/contact',\n {\n method: 'POST',\n body: JSON.stringify({\n widgetKey: this.config.apiKey, // apiKey is actually the widgetKey\n subject: data.subject,\n message: data.message,\n email: data.email,\n name: data.name,\n pageUrl:\n data.pageUrl ||\n (typeof window !== 'undefined' ? window.location.href : undefined),\n userAgent:\n data.userAgent ||\n (typeof navigator !== 'undefined'\n ? navigator.userAgent\n : undefined),\n }),\n }\n );\n\n return response.data || response;\n }\n\n /**\n * Create a new chat session\n */\n async createChatSession(\n metadata?: Record<string, unknown>\n ): Promise<CreateChatSessionResponse> {\n const response = await this.makeRequest<CreateChatSessionResponse>(\n '/v1/chat/sessions',\n {\n method: 'POST',\n body: JSON.stringify({\n widgetKey: this.config.apiKey, // apiKey is actually the widgetKey\n metadata: {\n ...metadata,\n pageUrl:\n typeof window !== 'undefined' ? window.location.href : undefined,\n userAgent:\n typeof navigator !== 'undefined'\n ? navigator.userAgent\n : undefined,\n },\n }),\n }\n );\n\n return response.data;\n }\n\n /**\n * Send a message in a chat session.\n * When `attachments` are provided the request is sent as multipart/form-data\n * so the files are uploaded alongside the message content.\n */\n async sendMessage(\n sessionId: string,\n content: string,\n attachments?: File[]\n ): Promise<SendMessageResponse> {\n const idempotencyKey = `msg_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;\n\n if (attachments && attachments.length > 0) {\n const formData = new FormData();\n formData.append('content', content);\n formData.append('idempotencyKey', idempotencyKey);\n for (const file of attachments) {\n formData.append('attachments', file, file.name);\n }\n\n const response = await this.makeRequest<SendMessageResponse>(\n `/v1/chat/sessions/${sessionId}/messages`,\n {\n method: 'POST',\n body: formData,\n // Let the browser set Content-Type with boundary for multipart\n headers: { 'Content-Type': '' },\n }\n );\n\n return response.data;\n }\n\n const response = await this.makeRequest<SendMessageResponse>(\n `/v1/chat/sessions/${sessionId}/messages`,\n {\n method: 'POST',\n body: JSON.stringify({\n content,\n idempotencyKey,\n }),\n }\n );\n\n return response.data;\n }\n\n /**\n * Get chat session details\n */\n async getChatSession(sessionId: string): Promise<ChatSession> {\n const response = await this.makeRequest<ChatSession>(\n `/v1/chat/sessions/${sessionId}`\n );\n return response.data;\n }\n\n /**\n * Get messages for a chat session\n */\n async getChatMessages(\n sessionId: string,\n limit = 50,\n offset = 0\n ): Promise<ChatMessage[]> {\n const response = await this.makeRequest<ChatMessage[]>(\n `/v1/chat/sessions/${sessionId}/messages?limit=${limit}&offset=${offset}`\n );\n return response.data;\n }\n\n /**\n * Close a chat session\n */\n async closeChatSession(sessionId: string): Promise<ChatSession> {\n const response = await this.makeRequest<ChatSession>(\n `/v1/chat/sessions/${sessionId}/close`,\n { method: 'POST' }\n );\n return response.data;\n }\n\n /**\n * Track a product or UX event from the browser (uses widget key → POST /public/events).\n */\n async trackEvent(\n name: string,\n options?: TrackEventOptions\n ): Promise<{ success: boolean; id: string }> {\n const res = await this.makeRequest<{ success: boolean; id: string }>(\n '/public/events',\n {\n method: 'POST',\n body: JSON.stringify({\n widgetKey: this.config.apiKey,\n name,\n properties: options?.properties,\n severity: options?.severity,\n distinctId: options?.distinctId,\n pageUrl:\n options?.pageUrl ??\n (typeof window !== 'undefined' ? window.location.href : undefined),\n userAgent:\n options?.userAgent ??\n (typeof navigator !== 'undefined'\n ? navigator.userAgent\n : undefined),\n }),\n }\n );\n const data =\n (res as ApiResponse<{ success: boolean; id: string }>).data ??\n (res as unknown as { success: boolean; id: string });\n return data;\n }\n\n /**\n * Track an event from a trusted server using the organization API key (POST /v1/events).\n */\n async trackServerEvent(\n name: string,\n options?: { properties?: Record<string, unknown>; severity?: EventSeverity }\n ): Promise<{ success: boolean; id: string }> {\n if (!this.config.serverApiKey) {\n throw new ValidationError(\n 'serverApiKey is required for trackServerEvent'\n );\n }\n const res = await this.makeRequest<{ success: boolean; id: string }>(\n '/v1/events',\n {\n method: 'POST',\n body: JSON.stringify({\n projectId: this.config.projectId,\n name,\n properties: options?.properties,\n severity: options?.severity,\n }),\n headers: {\n Authorization: `Bearer ${this.config.serverApiKey}`,\n },\n }\n );\n const data =\n (res as ApiResponse<{ success: boolean; id: string }>).data ??\n (res as unknown as { success: boolean; id: string });\n return data;\n }\n}\n","/**\n * Core types for Channlize SDK\n */\n\n/** Severity for tracked events (Slack routing uses project settings). */\nexport type EventSeverity = 'info' | 'warning' | 'error';\n\nexport interface TrackEventOptions {\n properties?: Record<string, unknown>;\n severity?: EventSeverity;\n distinctId?: string;\n pageUrl?: string;\n userAgent?: string;\n}\n\nexport interface ChannlizeConfig {\n /** Widget key used for public SDK endpoints (contact form, chat, browser event tracking) */\n apiKey: string;\n /** Base URL for the Channlize API */\n baseUrl?: string;\n /** Project ID (required for server-side `trackServerEvent`) */\n projectId: string;\n /** Request timeout in milliseconds */\n timeout?: number;\n /**\n * Organization API key for server-side `trackServerEvent` (`POST /v1/events`).\n * Do not expose in browser bundles.\n */\n serverApiKey?: string;\n}\n\nexport interface ContactFormData {\n /** Contact's name */\n name: string;\n /** Contact's email address */\n email: string;\n /** Subject of the inquiry */\n subject?: string;\n /** Message content */\n message: string;\n /** Custom fields */\n customFields?: Record<string, unknown>;\n /** Page URL where the form was submitted */\n pageUrl?: string;\n /** User agent string */\n userAgent?: string;\n}\n\nexport interface ChatMessage {\n /** Unique message ID */\n id: string;\n /** Message content */\n content: string;\n /** Message timestamp */\n timestamp: Date;\n /** Message author (user or agent) */\n author: 'user' | 'agent';\n /** Author metadata */\n authorData?: {\n name?: string;\n email?: string;\n avatarUrl?: string;\n };\n /** Attached files */\n attachments?: FileAttachment[];\n}\n\nexport interface FileAttachment {\n /** File ID */\n id: string;\n /** Original filename */\n name: string;\n /** File size in bytes */\n size: number;\n /** MIME type */\n type: string;\n /** Download URL */\n url: string;\n}\n\nexport interface ChatSession {\n /** Session ID */\n id: string;\n /** Session status */\n status: 'active' | 'closed' | 'waiting';\n /** Messages in the session */\n messages: ChatMessage[];\n /** Session metadata */\n metadata?: Record<string, unknown>;\n /** Created timestamp */\n createdAt: Date;\n /** Updated timestamp */\n updatedAt: Date;\n}\n\nexport interface ApiResponse<T = unknown> {\n /** Response data */\n data: T;\n /** Success status */\n success: boolean;\n /** Error message if any */\n error?: string;\n /** Additional metadata */\n meta?: Record<string, unknown>;\n}\n\n/** Response of `POST /public/contact` (api/app/api/public/contact/route.ts). */\nexport interface CreateContactResponse {\n /** Whether the submission was accepted */\n success: boolean;\n /** Conversation the submission was filed under */\n conversationId: string;\n /** Human-readable confirmation to show the visitor */\n message: string;\n /** @deprecated Never returned by the API (always undefined). Use `conversationId`. */\n id: string;\n /** @deprecated Never returned by the API (always undefined). */\n status: 'received' | 'processing' | 'delivered';\n /** @deprecated Never returned by the API (always undefined). */\n slackThreadUrl?: string;\n}\n\nexport interface CreateChatSessionResponse {\n /** Chat session data */\n session: ChatSession;\n /** SSE endpoint for real-time updates */\n sseEndpoint?: string;\n}\n\nexport interface SendMessageResponse {\n /** The sent message */\n message: ChatMessage;\n /** Updated session */\n session: ChatSession;\n}\n\n/**\n * Error types\n */\nexport class ChannlizeError extends Error {\n constructor(\n message: string,\n public statusCode?: number,\n public code?: string\n ) {\n super(message);\n this.name = 'ChannlizeError';\n }\n}\n\nexport class ValidationError extends ChannlizeError {\n constructor(\n message: string,\n public field?: string\n ) {\n super(message, 400, 'VALIDATION_ERROR');\n this.name = 'ValidationError';\n }\n}\n\nexport class AuthenticationError extends ChannlizeError {\n constructor(message: string = 'Authentication failed') {\n super(message, 401, 'AUTHENTICATION_ERROR');\n this.name = 'AuthenticationError';\n }\n}\n\nexport class RateLimitError extends ChannlizeError {\n constructor(message: string = 'Rate limit exceeded') {\n super(message, 429, 'RATE_LIMIT_ERROR');\n this.name = 'RateLimitError';\n }\n}\n"],"mappings":";AAAA,OAAO,WAAW;;;AC2IX,IAAM,iBAAN,cAA6B,MAAM;AAAA,EACxC,YACE,SACO,YACA,MACP;AACA,UAAM,OAAO;AAHN;AACA;AAGP,SAAK,OAAO;AAAA,EACd;AAAA,EALS;AAAA,EACA;AAKX;AAEO,IAAM,kBAAN,cAA8B,eAAe;AAAA,EAClD,YACE,SACO,OACP;AACA,UAAM,SAAS,KAAK,kBAAkB;AAF/B;AAGP,SAAK,OAAO;AAAA,EACd;AAAA,EAJS;AAKX;AAEO,IAAM,sBAAN,cAAkC,eAAe;AAAA,EACtD,YAAY,UAAkB,yBAAyB;AACrD,UAAM,SAAS,KAAK,sBAAsB;AAC1C,SAAK,OAAO;AAAA,EACd;AACF;AAEO,IAAM,iBAAN,cAA6B,eAAe;AAAA,EACjD,YAAY,UAAkB,uBAAuB;AACnD,UAAM,SAAS,KAAK,kBAAkB;AACtC,SAAK,OAAO;AAAA,EACd;AACF;;;ADpJO,IAAM,kBAAN,MAAsB;AAAA,EACV;AAAA,EAKjB,YAAY,QAAyB;AACnC,SAAK,SAAS;AAAA,MACZ,SAAS,OAAO,WAAW;AAAA,MAC3B,SAAS;AAAA,MACT,GAAG;AAAA,IACL;AAEA,SAAK,eAAe;AAAA,EACtB;AAAA,EAEQ,iBAAuB;AAC7B,QAAI,CAAC,KAAK,OAAO,QAAQ;AACvB,YAAM,IAAI,gBAAgB,wBAAwB;AAAA,IACpD;AAAA,EACF;AAAA,EAEA,MAAc,YACZ,UACA,UAAuB,CAAC,GACC;AACzB,UAAM,MAAM,GAAG,KAAK,OAAO,OAAO,GAAG,QAAQ;AAE7C,UAAM,aAAa,IAAI,gBAAgB;AACvC,UAAM,YAAY,WAAW,MAAM,WAAW,MAAM,GAAG,KAAK,OAAO,OAAO;AAE1E,QAAI;AACF,YAAM,gBAAwC;AAAA,QAC5C,gBAAgB;AAAA,QAChB,GAAI,QAAQ;AAAA,MACd;AAIA,UAAI,cAAc,cAAc,MAAM,IAAI;AACxC,eAAO,cAAc,cAAc;AAAA,MACrC;AAEA,YAAM,WAAW,MAAM,MAAM,KAAK;AAAA,QAChC,GAAG;AAAA,QACH,QAAQ,WAAW;AAAA,QACnB,SAAS;AAAA,MACX,CAAC;AAED,mBAAa,SAAS;AAEtB,UAAI,CAAC,SAAS,IAAI;AAChB,cAAM,KAAK,oBAAoB,QAAQ;AAAA,MACzC;AAEA,YAAM,OAAO,MAAM,SAAS,KAAK;AACjC,aAAO;AAAA,IACT,SAAS,OAAO;AACd,mBAAa,SAAS;AAEtB,UAAI,iBAAiB,gBAAgB;AACnC,cAAM;AAAA,MACR;AAEA,UAAI,iBAAiB,SAAS,MAAM,SAAS,cAAc;AACzD,cAAM,IAAI,eAAe,mBAAmB,KAAK,SAAS;AAAA,MAC5D;AAEA,YAAM,IAAI;AAAA,QACR,kBAAkB,iBAAiB,QAAQ,MAAM,UAAU,eAAe;AAAA,MAC5E;AAAA,IACF;AAAA,EACF;AAAA,EAEA,MAAc,oBAAoB,UAAoC;AACpE,UAAM,cAAc,SAAS,QAAQ,IAAI,cAAc;AACvD,QAAI,YAAiB,CAAC;AAEtB,QAAI,aAAa,SAAS,kBAAkB,GAAG;AAC7C,UAAI;AACF,oBAAY,MAAM,SAAS,KAAK;AAAA,MAClC,QAAQ;AAAA,MAER;AAAA,IACF;AAMA,UAAM,aAAa,UAAU;AAC7B,UAAM,WACH,MAAM,QAAQ,UAAU,IAAI,WAAW,KAAK,IAAI,IAAI,eACrD,QAAQ,SAAS,MAAM,KAAK,SAAS,UAAU;AACjD,UAAM,OAA2B,UAAU,QAAQ,UAAU;AAE7D,YAAQ,SAAS,QAAQ;AAAA,MACvB,KAAK;AACH,cAAM,IAAI,oBAAoB,OAAO;AAAA,MACvC,KAAK;AACH,cAAM,IAAI,gBAAgB,SAAS,UAAU,KAAK;AAAA,MACpD,KAAK;AACH,cAAM,IAAI,eAAe,OAAO;AAAA,MAClC;AACE,cAAM,IAAI,eAAe,SAAS,SAAS,QAAQ,IAAI;AAAA,IAC3D;AAAA,EACF;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBACJ,MACgC;AAChC,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU;AAAA,UACnB,WAAW,KAAK,OAAO;AAAA;AAAA,UACvB,SAAS,KAAK;AAAA,UACd,SAAS,KAAK;AAAA,UACd,OAAO,KAAK;AAAA,UACZ,MAAM,KAAK;AAAA,UACX,SACE,KAAK,YACJ,OAAO,WAAW,cAAc,OAAO,SAAS,OAAO;AAAA,UAC1D,WACE,KAAK,cACJ,OAAO,cAAc,cAClB,UAAU,YACV;AAAA,QACR,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO,SAAS,QAAQ;AAAA,EAC1B;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,kBACJ,UACoC;AACpC,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU;AAAA,UACnB,WAAW,KAAK,OAAO;AAAA;AAAA,UACvB,UAAU;AAAA,YACR,GAAG;AAAA,YACH,SACE,OAAO,WAAW,cAAc,OAAO,SAAS,OAAO;AAAA,YACzD,WACE,OAAO,cAAc,cACjB,UAAU,YACV;AAAA,UACR;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,YACJ,WACA,SACA,aAC8B;AAC9B,UAAM,iBAAiB,OAAO,KAAK,IAAI,CAAC,IAAI,KAAK,OAAO,EAAE,SAAS,EAAE,EAAE,OAAO,GAAG,CAAC,CAAC;AAEnF,QAAI,eAAe,YAAY,SAAS,GAAG;AACzC,YAAM,WAAW,IAAI,SAAS;AAC9B,eAAS,OAAO,WAAW,OAAO;AAClC,eAAS,OAAO,kBAAkB,cAAc;AAChD,iBAAW,QAAQ,aAAa;AAC9B,iBAAS,OAAO,eAAe,MAAM,KAAK,IAAI;AAAA,MAChD;AAEA,YAAMA,YAAW,MAAM,KAAK;AAAA,QAC1B,qBAAqB,SAAS;AAAA,QAC9B;AAAA,UACE,QAAQ;AAAA,UACR,MAAM;AAAA;AAAA,UAEN,SAAS,EAAE,gBAAgB,GAAG;AAAA,QAChC;AAAA,MACF;AAEA,aAAOA,UAAS;AAAA,IAClB;AAEA,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B,qBAAqB,SAAS;AAAA,MAC9B;AAAA,QACE,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU;AAAA,UACnB;AAAA,UACA;AAAA,QACF,CAAC;AAAA,MACH;AAAA,IACF;AAEA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,eAAe,WAAyC;AAC5D,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B,qBAAqB,SAAS;AAAA,IAChC;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,gBACJ,WACA,QAAQ,IACR,SAAS,GACe;AACxB,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B,qBAAqB,SAAS,mBAAmB,KAAK,WAAW,MAAM;AAAA,IACzE;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBAAiB,WAAyC;AAC9D,UAAM,WAAW,MAAM,KAAK;AAAA,MAC1B,qBAAqB,SAAS;AAAA,MAC9B,EAAE,QAAQ,OAAO;AAAA,IACnB;AACA,WAAO,SAAS;AAAA,EAClB;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,WACJ,MACA,SAC2C;AAC3C,UAAM,MAAM,MAAM,KAAK;AAAA,MACrB;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU;AAAA,UACnB,WAAW,KAAK,OAAO;AAAA,UACvB;AAAA,UACA,YAAY,SAAS;AAAA,UACrB,UAAU,SAAS;AAAA,UACnB,YAAY,SAAS;AAAA,UACrB,SACE,SAAS,YACR,OAAO,WAAW,cAAc,OAAO,SAAS,OAAO;AAAA,UAC1D,WACE,SAAS,cACR,OAAO,cAAc,cAClB,UAAU,YACV;AAAA,QACR,CAAC;AAAA,MACH;AAAA,IACF;AACA,UAAM,OACH,IAAsD,QACtD;AACH,WAAO;AAAA,EACT;AAAA;AAAA;AAAA;AAAA,EAKA,MAAM,iBACJ,MACA,SAC2C;AAC3C,QAAI,CAAC,KAAK,OAAO,cAAc;AAC7B,YAAM,IAAI;AAAA,QACR;AAAA,MACF;AAAA,IACF;AACA,UAAM,MAAM,MAAM,KAAK;AAAA,MACrB;AAAA,MACA;AAAA,QACE,QAAQ;AAAA,QACR,MAAM,KAAK,UAAU;AAAA,UACnB,WAAW,KAAK,OAAO;AAAA,UACvB;AAAA,UACA,YAAY,SAAS;AAAA,UACrB,UAAU,SAAS;AAAA,QACrB,CAAC;AAAA,QACD,SAAS;AAAA,UACP,eAAe,UAAU,KAAK,OAAO,YAAY;AAAA,QACnD;AAAA,MACF;AAAA,IACF;AACA,UAAM,OACH,IAAsD,QACtD;AACH,WAAO;AAAA,EACT;AACF;","names":["response"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@channlize/core",
3
- "version": "0.1.0-alpha.1",
3
+ "version": "0.1.0",
4
4
  "description": "Channlize Core SDK - TypeScript API wrapper for Channlize platform",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",
@@ -18,9 +18,9 @@
18
18
  "scripts": {
19
19
  "build": "tsup",
20
20
  "dev": "tsup --watch",
21
- "lint": "eslint src --ext .ts",
22
- "lint:fix": "eslint src --ext .ts --fix",
23
- "type-check": "tsc --noEmit",
21
+ "lint": "eslint src",
22
+ "lint:fix": "eslint src --fix",
23
+ "type-check": "tsc6 --noEmit",
24
24
  "clean": "rm -rf dist"
25
25
  },
26
26
  "keywords": [
@@ -35,12 +35,10 @@
35
35
  "cross-fetch": "^4.0.0"
36
36
  },
37
37
  "devDependencies": {
38
- "@types/node": "^20.11.5",
39
- "@typescript-eslint/eslint-plugin": "^6.21.0",
40
- "@typescript-eslint/parser": "^6.21.0",
41
- "eslint": "^8.56.0",
42
- "tsup": "^8.0.1",
43
- "typescript": "^5.3.3"
38
+ "@types/node": "^26.0.0",
39
+ "eslint": "^10.0.0",
40
+ "tsup": "^9.0.0",
41
+ "typescript": "npm:@typescript/typescript6@^6.0.2"
44
42
  },
45
43
  "publishConfig": {
46
44
  "access": "public"
@@ -50,4 +48,4 @@
50
48
  "url": "git+https://github.com/channlize/sdk.git",
51
49
  "directory": "packages/core"
52
50
  }
53
- }
51
+ }