@channlize/core 0.1.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,8 +1,74 @@
1
+ /**
2
+ * Helpers shared by `@channlize/core`, `@channlize/react` and
3
+ * `@channlize/mcp`: defaults, key detection, environment variables, event
4
+ * keys and the API's error shape. Core is the single source for these.
5
+ */
6
+ /** Default API base URL. */
7
+ declare const DEFAULT_BASE_URL = "https://api.channlize.com";
8
+ /** Default request timeout, in milliseconds. */
9
+ declare const DEFAULT_TIMEOUT = 10000;
10
+ /** Log tracking severities, lowest first. */
11
+ declare const EVENT_SEVERITIES: readonly ["info", "warning", "error"];
12
+ /**
13
+ * Valid Events key (same rule as the API): lowercase letters, digits,
14
+ * dots, underscores and dashes, e.g. `user.subscribed`. At most 100
15
+ * characters.
16
+ */
17
+ declare const EVENT_KEY_PATTERN: RegExp;
18
+ /** Whether `event` is a valid Events key for `notify`. */
19
+ declare function isValidEventKey(event: unknown): event is string;
20
+ type KeyKind = 'widget' | 'server';
21
+ /**
22
+ * `wk_…` is the public widget key (browser: contact form, chat, browser
23
+ * log tracking); anything else is a server API key (`ch_live_…`).
24
+ */
25
+ declare function keyKind(key: string): KeyKind;
26
+ /** The `CHANNLIZE_*` environment variables, trimmed (empty → undefined). */
27
+ interface ChannlizeEnv {
28
+ /** `CHANNLIZE_SERVER_API_KEY` */
29
+ serverApiKey?: string;
30
+ /** `CHANNLIZE_WIDGET_KEY` */
31
+ widgetKey?: string;
32
+ /** `CHANNLIZE_API_KEY` (either kind of key) */
33
+ apiKey?: string;
34
+ /** `CHANNLIZE_PROJECT_ID` */
35
+ projectId?: string;
36
+ /** `CHANNLIZE_BASE_URL` */
37
+ baseUrl?: string;
38
+ /** `CHANNLIZE_TIMEOUT` (milliseconds, unparsed) */
39
+ timeout?: string;
40
+ }
41
+ /**
42
+ * Reads the `CHANNLIZE_*` environment variables. Safe in browsers and edge
43
+ * runtimes without `process` (everything is undefined there).
44
+ */
45
+ declare function readChannlizeEnv(env?: Record<string, string | undefined> | undefined): ChannlizeEnv;
46
+ /** A failed API response, parsed from its JSON body. */
47
+ interface ApiErrorInfo {
48
+ status: number;
49
+ /** Human-readable text (field messages joined with `, `). */
50
+ message: string;
51
+ /** Machine-readable code: the body's `code`, else its `error` (e.g. `NOT_FOUND`). */
52
+ code?: string;
53
+ /** `requestId` from the body, to quote to support. */
54
+ requestId?: string;
55
+ /** The parsed body (e.g. `limit`, `used`, `resetAt` on a plan-limit 429). */
56
+ body: Record<string, unknown>;
57
+ }
58
+ /**
59
+ * Parses the API's error shape (`api/lib/api/error.ts`):
60
+ * `{ statusCode, error: "NOT_FOUND", message: string | string[], requestId? }`.
61
+ * A few legacy routes put the human text in `error`.
62
+ */
63
+ declare function parseApiError(status: number, body: unknown, statusText?: string): ApiErrorInfo;
64
+
1
65
  /**
2
66
  * Core types for Channlize SDK
3
67
  */
4
- /** Severity for tracked events (Slack routing uses project settings). */
5
- type EventSeverity = 'info' | 'warning' | 'error';
68
+
69
+ /** Severity for log tracking (`trackEvent` / `trackServerEvent`); Slack alerts use project settings. */
70
+ type EventSeverity = (typeof EVENT_SEVERITIES)[number];
71
+ /** Options for log tracking (`trackEvent` / `trackServerEvent`). */
6
72
  interface TrackEventOptions {
7
73
  properties?: Record<string, unknown>;
8
74
  severity?: EventSeverity;
@@ -11,20 +77,78 @@ interface TrackEventOptions {
11
77
  userAgent?: string;
12
78
  }
13
79
  interface ChannlizeConfig {
14
- /** Widget key used for public SDK endpoints (contact form, chat, browser event tracking) */
80
+ /** Widget key used for public SDK endpoints (contact form, chat, browser log tracking) */
15
81
  apiKey: string;
16
82
  /** Base URL for the Channlize API */
17
83
  baseUrl?: string;
18
- /** Project ID (required for server-side `trackServerEvent`) */
84
+ /** Project ID (required for server-side `trackServerEvent` and `notify`) */
19
85
  projectId: string;
20
86
  /** Request timeout in milliseconds */
21
87
  timeout?: number;
22
88
  /**
23
- * Organization API key for server-side `trackServerEvent` (`POST /v1/events`).
24
- * Do not expose in browser bundles.
89
+ * Organization (server) API key, `ch_live_…`, for `trackServerEvent`
90
+ * (`POST /v1/events`) and `notify` (`POST /v1/notify`, needs the `write`
91
+ * scope). Do not expose in browser bundles.
25
92
  */
26
93
  serverApiKey?: string;
27
94
  }
95
+ /**
96
+ * Events (notify Slack from code). Augment this interface to type event
97
+ * keys and their data across your app:
98
+ *
99
+ * ```ts
100
+ * declare module '@channlize/core' {
101
+ * interface ChannlizeEvents {
102
+ * 'user.subscribed': { username: string; plan: string };
103
+ * }
104
+ * }
105
+ * ```
106
+ *
107
+ * Or pass a map as a type argument: `createNotifier<AppEvents>()`.
108
+ */
109
+ interface ChannlizeEvents {
110
+ }
111
+ /** A declared event key (autocompleted) or any other key. */
112
+ type NotifyEventName<TEvents extends object = ChannlizeEvents> = (keyof TEvents & string) | (string & {});
113
+ /** The declared data for a key, or any object for undeclared keys. */
114
+ type NotifyEventData<TEvents extends object = ChannlizeEvents, K = string> = K extends keyof TEvents ? TEvents[K] : Record<string, unknown>;
115
+ interface NotifyOptions {
116
+ /**
117
+ * Retry-safe sends: a key already used on the project returns the first
118
+ * delivery (`duplicate: true`) and posts nothing. Sent as `Idempotency-Key`.
119
+ */
120
+ idempotencyKey?: string;
121
+ /** Slack channel ID to post to instead of the event's channel, for this call. */
122
+ channel?: string;
123
+ }
124
+ interface NotifyResponse {
125
+ success: boolean;
126
+ /** Delivery ID (see Events → Recent deliveries in the dashboard). */
127
+ id: string;
128
+ event: string;
129
+ /**
130
+ * `queued`: will be posted to Slack. `skipped`: not posted (see `reason`):
131
+ * the event is disabled, is new (saved as a draft to configure), or there
132
+ * is no Slack workspace / channel. With `duplicate`, the first call's status.
133
+ */
134
+ status: 'queued' | 'skipped' | 'sent' | 'failed';
135
+ reason?: string;
136
+ duplicate?: boolean;
137
+ }
138
+ /** `createNotifier` options; each falls back to an environment variable. */
139
+ interface NotifierConfig {
140
+ /**
141
+ * Server API key (`ch_live_…`, write scope). Default:
142
+ * `CHANNLIZE_SERVER_API_KEY`, else `CHANNLIZE_API_KEY`.
143
+ */
144
+ serverApiKey?: string;
145
+ /** Project ID. Default: `CHANNLIZE_PROJECT_ID`. */
146
+ projectId?: string;
147
+ /** API base URL. Default: `CHANNLIZE_BASE_URL`, else `https://api.channlize.com`. */
148
+ baseUrl?: string;
149
+ /** Request timeout in ms (default 10000). */
150
+ timeout?: number;
151
+ }
28
152
  interface ContactFormData {
29
153
  /** Contact's name */
30
154
  name: string;
@@ -46,11 +170,15 @@ interface ChatMessage {
46
170
  id: string;
47
171
  /** Message content */
48
172
  content: string;
49
- /** Message timestamp */
173
+ /**
174
+ * Message timestamp. The API sends an ISO 8601 string, which
175
+ * `ChannlizeClient` passes through as is; `@channlize/react` converts it
176
+ * to a `Date`. Wrap it in `new Date(...)` before using `Date` methods.
177
+ */
50
178
  timestamp: Date;
51
179
  /** Message author (user or agent) */
52
180
  author: 'user' | 'agent';
53
- /** Author metadata */
181
+ /** Author metadata (`name` / `email` can be `null` in message history) */
54
182
  authorData?: {
55
183
  name?: string;
56
184
  email?: string;
@@ -74,15 +202,23 @@ interface FileAttachment {
74
202
  interface ChatSession {
75
203
  /** Session ID */
76
204
  id: string;
77
- /** Session status */
205
+ /**
206
+ * Session status. `createChatSession` answers `active`; `getChatSession`
207
+ * and `closeChatSession` answer the conversation's status (`open`,
208
+ * `pending`, `resolved` or `closed`).
209
+ */
78
210
  status: 'active' | 'closed' | 'waiting';
79
- /** Messages in the session */
211
+ /**
212
+ * Messages in the session. Only `createChatSession` returns it (empty);
213
+ * `getChatSession`, `closeChatSession` and `sendMessage` return a session
214
+ * summary without it. Load history with `getChatMessages`.
215
+ */
80
216
  messages: ChatMessage[];
81
217
  /** Session metadata */
82
218
  metadata?: Record<string, unknown>;
83
- /** Created timestamp */
219
+ /** Created timestamp (an ISO 8601 string on the wire; not sent by `closeChatSession`) */
84
220
  createdAt: Date;
85
- /** Updated timestamp */
221
+ /** Updated timestamp (an ISO 8601 string on the wire) */
86
222
  updatedAt: Date;
87
223
  }
88
224
  interface ApiResponse<T = unknown> {
@@ -119,7 +255,7 @@ interface CreateChatSessionResponse {
119
255
  interface SendMessageResponse {
120
256
  /** The sent message */
121
257
  message: ChatMessage;
122
- /** Updated session */
258
+ /** The session (the API sends only `id` and `status`) */
123
259
  session: ChatSession;
124
260
  }
125
261
  /**
@@ -128,6 +264,13 @@ interface SendMessageResponse {
128
264
  declare class ChannlizeError extends Error {
129
265
  statusCode?: number | undefined;
130
266
  code?: string | undefined;
267
+ /** The API's `requestId` for a failed response, to quote to support. */
268
+ requestId?: string;
269
+ /**
270
+ * The API's JSON error body, e.g. `limit`, `used`, `resetAt` and
271
+ * `upgradeUrl` on a plan-limit 429. Undefined for network errors.
272
+ */
273
+ details?: Record<string, unknown>;
131
274
  constructor(message: string, statusCode?: number | undefined, code?: string | undefined);
132
275
  }
133
276
  declare class ValidationError extends ChannlizeError {
@@ -137,20 +280,39 @@ declare class ValidationError extends ChannlizeError {
137
280
  declare class AuthenticationError extends ChannlizeError {
138
281
  constructor(message?: string);
139
282
  }
283
+ /**
284
+ * A 429. `code` is `PLAN_LIMIT_REACHED` when the organization is past its
285
+ * plan's limit for the billing period (the API's 110 % hard cap), else
286
+ * `RATE_LIMIT_ERROR`.
287
+ */
140
288
  declare class RateLimitError extends ChannlizeError {
141
- constructor(message?: string);
289
+ constructor(message?: string, code?: string);
290
+ }
291
+ /**
292
+ * What `trackEvent` / `trackServerEvent` resolve with. When the API refuses
293
+ * the event with a 429 (rate limit or plan limit), the call resolves with
294
+ * `success: false` and `dropped` instead of throwing: log tracking never
295
+ * breaks the app that calls it.
296
+ */
297
+ interface TrackEventResult {
298
+ success: boolean;
299
+ id: string;
300
+ /** Set when the event was refused and not stored. */
301
+ dropped?: 'plan_limit' | 'rate_limit';
142
302
  }
143
303
 
144
304
  /**
145
305
  * Channlize API Client
146
- * Provides methods to interact with the Channlize platform
306
+ * Provides methods to interact with the Channlize platform.
307
+ *
308
+ * `TEvents` types `notify()` event keys and data (defaults to the
309
+ * augmentable `ChannlizeEvents` interface; any string key is accepted).
147
310
  */
148
- declare class ChannlizeClient {
311
+ declare class ChannlizeClient<TEvents extends object = ChannlizeEvents> {
149
312
  private readonly config;
150
313
  constructor(config: ChannlizeConfig);
151
314
  private validateConfig;
152
315
  private makeRequest;
153
- private handleErrorResponse;
154
316
  /**
155
317
  * Submit a contact form
156
318
  */
@@ -178,23 +340,53 @@ declare class ChannlizeClient {
178
340
  */
179
341
  closeChatSession(sessionId: string): Promise<ChatSession>;
180
342
  /**
181
- * Track a product or UX event from the browser (uses widget key → POST /public/events).
343
+ * Log tracking: record a log line from the browser (widget key →
344
+ * `POST /public/events`). Shown under Log tracking in the dashboard.
182
345
  */
183
- trackEvent(name: string, options?: TrackEventOptions): Promise<{
184
- success: boolean;
185
- id: string;
186
- }>;
346
+ trackEvent(name: string, options?: TrackEventOptions): Promise<TrackEventResult>;
347
+ private sendBrowserEvent;
187
348
  /**
188
- * Track an event from a trusted server using the organization API key (POST /v1/events).
349
+ * Log tracking from a trusted server, using the organization API key
350
+ * (`POST /v1/events`). Shown under Log tracking in the dashboard.
189
351
  */
190
352
  trackServerEvent(name: string, options?: {
191
353
  properties?: Record<string, unknown>;
192
354
  severity?: EventSeverity;
193
- }): Promise<{
194
- success: boolean;
195
- id: string;
196
- }>;
355
+ }): Promise<TrackEventResult>;
356
+ /**
357
+ * Log tracking must never break the caller: a 429 (rate limit, or the
358
+ * plan's limit for the billing period) resolves with `success: false`
359
+ * and `dropped` instead of throwing, with one console warning per client.
360
+ */
361
+ private nonFatalTracking;
362
+ private warnedDropped;
363
+ private sendServerEvent;
364
+ /**
365
+ * Events: post a Slack message from your server when something happens
366
+ * (`POST /v1/notify`). The event key picks the channel and message
367
+ * template configured under Events in the dashboard; `data` fills the
368
+ * template's `{{field}}` placeholders. Needs `serverApiKey` (write scope)
369
+ * and `projectId` — never call it from browser code.
370
+ *
371
+ * An unknown key is saved as a disabled draft and answered with
372
+ * `status: 'skipped'`, so it never throws for a missing setup.
373
+ */
374
+ notify<K extends NotifyEventName<TEvents>>(event: K, data?: NotifyEventData<TEvents, K>, options?: NotifyOptions): Promise<NotifyResponse>;
197
375
  }
198
376
 
199
- export { AuthenticationError, ChannlizeClient, ChannlizeError, RateLimitError, ValidationError, ChannlizeClient as default };
200
- export type { ApiResponse, ChannlizeConfig, ChatMessage, ChatSession, ContactFormData, CreateChatSessionResponse, CreateContactResponse, EventSeverity, FileAttachment, SendMessageResponse, TrackEventOptions };
377
+ type Notifier<TEvents extends object = ChannlizeEvents> = <K extends NotifyEventName<TEvents>>(event: K, data?: NotifyEventData<TEvents, K>, options?: NotifyOptions) => Promise<NotifyResponse>;
378
+ /**
379
+ * Events: a standalone server-side `notify(event, data)` function. Reads
380
+ * the server key from `CHANNLIZE_SERVER_API_KEY` or `CHANNLIZE_API_KEY`, and
381
+ * `CHANNLIZE_PROJECT_ID`, unless given — when it is called, so creating it
382
+ * at module load never throws.
383
+ *
384
+ * ```ts
385
+ * const notify = createNotifier();
386
+ * await notify('user.subscribed', { username: 'ada', plan: 'Pro' });
387
+ * ```
388
+ */
389
+ declare function createNotifier<TEvents extends object = ChannlizeEvents>(config?: NotifierConfig): Notifier<TEvents>;
390
+
391
+ export { AuthenticationError, ChannlizeClient, ChannlizeError, DEFAULT_BASE_URL, DEFAULT_TIMEOUT, EVENT_KEY_PATTERN, EVENT_SEVERITIES, RateLimitError, ValidationError, createNotifier, ChannlizeClient as default, isValidEventKey, keyKind, parseApiError, readChannlizeEnv };
392
+ export type { ApiErrorInfo, ApiResponse, ChannlizeConfig, ChannlizeEnv, ChannlizeEvents, ChatMessage, ChatSession, ContactFormData, CreateChatSessionResponse, CreateContactResponse, EventSeverity, FileAttachment, KeyKind, Notifier, NotifierConfig, NotifyEventData, NotifyEventName, NotifyOptions, NotifyResponse, SendMessageResponse, TrackEventOptions, TrackEventResult };