@caitdesk/client 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/README.md +193 -0
- package/dist/api.d.ts +12 -0
- package/dist/api.d.ts.map +1 -0
- package/dist/api.js +50 -0
- package/dist/api.js.map +1 -0
- package/dist/client.d.ts +39 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +127 -0
- package/dist/client.js.map +1 -0
- package/dist/constants.d.ts +70 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +77 -0
- package/dist/constants.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +127 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/ws.d.ts +38 -0
- package/dist/ws.d.ts.map +1 -0
- package/dist/ws.js +180 -0
- package/dist/ws.js.map +1 -0
- package/package.json +23 -0
package/README.md
ADDED
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
# @caitdesk/client
|
|
2
|
+
|
|
3
|
+
Official TypeScript client for the CaitDesk captioner API. Provides typed REST and WebSocket interfaces for third-party captioning applications.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @caitdesk/client
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```ts
|
|
14
|
+
import { CaitDeskClient } from '@caitdesk/client';
|
|
15
|
+
|
|
16
|
+
const client = new CaitDeskClient({
|
|
17
|
+
apiUrl: 'https://api.caitdesk.com',
|
|
18
|
+
apiKey: 'cait_sk_...',
|
|
19
|
+
onStatusChange: (status) => console.log('Connection:', status),
|
|
20
|
+
onSlotChange: (status) => console.log('Slot:', status),
|
|
21
|
+
onCaptionAck: (ack) => console.log('Ack seq:', ack.seq),
|
|
22
|
+
onError: (err) => console.error('Error:', err.code, err.message),
|
|
23
|
+
onEventEnded: () => console.log('Event ended'),
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
// List your assigned events
|
|
27
|
+
const events = await client.getEvents();
|
|
28
|
+
|
|
29
|
+
// Connect to an event
|
|
30
|
+
await client.connect(events[0].id);
|
|
31
|
+
|
|
32
|
+
// Send captions
|
|
33
|
+
client.append('Hello, world!');
|
|
34
|
+
client.append(' More text.');
|
|
35
|
+
|
|
36
|
+
// Control the event
|
|
37
|
+
client.start(); // Start the event
|
|
38
|
+
client.pause(); // Pause captions
|
|
39
|
+
client.resume(); // Resume captions
|
|
40
|
+
client.stop(); // End the event
|
|
41
|
+
|
|
42
|
+
// Disconnect when done
|
|
43
|
+
client.disconnect();
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## API Reference
|
|
47
|
+
|
|
48
|
+
### CaitDeskClient
|
|
49
|
+
|
|
50
|
+
#### Constructor
|
|
51
|
+
|
|
52
|
+
```ts
|
|
53
|
+
new CaitDeskClient(config: CaitDeskConfig)
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
#### Properties
|
|
57
|
+
|
|
58
|
+
| Property | Type | Description |
|
|
59
|
+
| ------------ | ------------------ | ---------------------------------------- |
|
|
60
|
+
| `status` | `ConnectionStatus` | Current WebSocket connection status |
|
|
61
|
+
| `slotStatus` | `SlotStatus` | Current slot status (active or waiting) |
|
|
62
|
+
|
|
63
|
+
#### REST Methods
|
|
64
|
+
|
|
65
|
+
```ts
|
|
66
|
+
client.getMe(): Promise<User>
|
|
67
|
+
client.getEvents(): Promise<Event[]>
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
- `getMe()` — returns the authenticated user's info
|
|
71
|
+
- `getEvents()` — returns events assigned to you as captioner (scheduled and live only)
|
|
72
|
+
|
|
73
|
+
#### Connection
|
|
74
|
+
|
|
75
|
+
```ts
|
|
76
|
+
client.connect(eventId: string): Promise<void>
|
|
77
|
+
client.disconnect(): void
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`connect()` fetches a stream ticket and opens a WebSocket connection. If already connected, the previous connection is closed first. Handles reconnection automatically on unexpected disconnects.
|
|
81
|
+
|
|
82
|
+
#### Sending Captions
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
client.append(text: string): void // Append text (max 10,000 chars)
|
|
86
|
+
client.delete(count: number): void // Delete characters from end (max 100,000)
|
|
87
|
+
client.sync(text: string): void // Full text sync (max 100,000 chars)
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
All methods auto-inject `eventId` and `timestamp`. Throws if not connected.
|
|
91
|
+
|
|
92
|
+
#### Event Control
|
|
93
|
+
|
|
94
|
+
```ts
|
|
95
|
+
client.start(): void // Transition event from scheduled to live
|
|
96
|
+
client.stop(): void // End the event
|
|
97
|
+
client.pause(): void // Pause caption display
|
|
98
|
+
client.resume(): void // Resume caption display
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
#### Slot Management
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
client.releaseSlot(): void // Yield active slot to next waiting captioner
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
### Configuration
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
interface CaitDeskConfig {
|
|
111
|
+
apiUrl: string;
|
|
112
|
+
apiKey: string;
|
|
113
|
+
onStatusChange?: (status: ConnectionStatus) => void;
|
|
114
|
+
onSlotChange?: (status: SlotStatus, detail?: SlotDetail) => void;
|
|
115
|
+
onCaptionAck?: (ack: CaptionAck) => void;
|
|
116
|
+
onControlAck?: (ack: ControlAck) => void;
|
|
117
|
+
onError?: (error: ServerError) => void;
|
|
118
|
+
onEventEnded?: (eventId: string) => void;
|
|
119
|
+
onWaitingCountChange?: (count: number) => void;
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
| Callback | When it fires |
|
|
124
|
+
| ---------------------- | ------------------------------------------------------- |
|
|
125
|
+
| `onStatusChange` | Connection state changes (connecting/connected/etc.) |
|
|
126
|
+
| `onSlotChange` | You become the active captioner or enter the wait queue |
|
|
127
|
+
| `onCaptionAck` | Server acknowledges a caption message (with `seq`) |
|
|
128
|
+
| `onControlAck` | Server acknowledges a control action |
|
|
129
|
+
| `onError` | Server sends an error message |
|
|
130
|
+
| `onEventEnded` | The event has ended (server-initiated) |
|
|
131
|
+
| `onWaitingCountChange` | Number of waiting captioners changed (active slot only) |
|
|
132
|
+
|
|
133
|
+
### Types
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
interface User { id: string; email: string; name: string | null }
|
|
137
|
+
interface Event { id: string; organizationId: string; title: string; description: string | null; scheduledStart: string; scheduledEnd: string | null; status: string; clientName: string | null }
|
|
138
|
+
interface CaptionAck { type: 'ack'; timestamp: number; seq: number }
|
|
139
|
+
interface ControlAck { type: 'ack'; action: string }
|
|
140
|
+
interface ServerError { type: 'error'; code: string; message: string; details?: Record<string, unknown> }
|
|
141
|
+
interface SlotDetail { position?: number; activeSince?: string }
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### Constants
|
|
145
|
+
|
|
146
|
+
```ts
|
|
147
|
+
import { ERROR_CODE, RATE_LIMITS, CONNECTION_DEFAULTS } from '@caitdesk/client';
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Error Handling
|
|
151
|
+
|
|
152
|
+
Errors are delivered via the `onError` callback. Some errors are terminal:
|
|
153
|
+
|
|
154
|
+
| Code | Terminal | Meaning | Action |
|
|
155
|
+
| ----------------- | -------- | ---------------------------------------- | --------------------------- |
|
|
156
|
+
| `WS_AUTH_FAILED` | Yes | API key or ticket is invalid | Check credentials |
|
|
157
|
+
| `WS_SLOT_FULL` | Yes | Too many captioners connected | Try again later |
|
|
158
|
+
| `WS_NOT_ACTIVE` | No | You sent captions but aren't active yet | Wait for `onSlotChange` |
|
|
159
|
+
| `WS_INVALID_MESSAGE` | No | Malformed message | Check message format |
|
|
160
|
+
| `RATE_LIMITED` | No | Too many messages/second | Reduce send rate |
|
|
161
|
+
| `NETWORK_ERROR` | No | Connection or ticket refresh failed | Client retries automatically |
|
|
162
|
+
|
|
163
|
+
Terminal errors close the connection without reconnection.
|
|
164
|
+
|
|
165
|
+
## Reconnection
|
|
166
|
+
|
|
167
|
+
The client reconnects automatically on unexpected disconnects using exponential backoff (1s initial, 30s max, 1.5x multiplier). During reconnection:
|
|
168
|
+
|
|
169
|
+
1. A fresh ticket is fetched via the REST API
|
|
170
|
+
2. A new WebSocket connection is established
|
|
171
|
+
3. The slot system restores your position (same user ID = seamless takeover)
|
|
172
|
+
|
|
173
|
+
The client does **not** reconnect when:
|
|
174
|
+
- You call `disconnect()`
|
|
175
|
+
- The event ends (`event_ended` message)
|
|
176
|
+
- Authentication fails (close code `1008`)
|
|
177
|
+
- The slot queue is full (close code `1013`)
|
|
178
|
+
|
|
179
|
+
## Slot System
|
|
180
|
+
|
|
181
|
+
Each event has one active captioner slot and a waiting queue (max 2 waiters).
|
|
182
|
+
|
|
183
|
+
| Status | Meaning | Can send captions? |
|
|
184
|
+
| --------- | ------------------------------------ | ------------------ |
|
|
185
|
+
| `active` | You hold the active slot | Yes |
|
|
186
|
+
| `waiting` | You're in the queue | No |
|
|
187
|
+
| `unknown` | Not connected or status not received | No |
|
|
188
|
+
|
|
189
|
+
When the active captioner disconnects or calls `releaseSlot()`, the next waiter is promoted automatically. You'll receive a `onSlotChange('active')` callback when promoted.
|
|
190
|
+
|
|
191
|
+
## License
|
|
192
|
+
|
|
193
|
+
Proprietary. See LICENSE for details.
|
package/dist/api.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { User, Event, Ticket } from './types';
|
|
2
|
+
export declare class ApiClient {
|
|
3
|
+
private readonly baseUrl;
|
|
4
|
+
private readonly apiKey;
|
|
5
|
+
private readonly timeoutMs;
|
|
6
|
+
constructor(baseUrl: string, apiKey: string);
|
|
7
|
+
getMe(): Promise<User>;
|
|
8
|
+
getEvents(): Promise<Event[]>;
|
|
9
|
+
getTicket(eventId: string): Promise<Ticket>;
|
|
10
|
+
private request;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=api.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.d.ts","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AAanD,qBAAa,SAAS;IACpB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;IACjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAS;gBAEvB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;IAMrC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,SAAS,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;IAI7B,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;YAInC,OAAO;CA+BtB"}
|
package/dist/api.js
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { CONNECTION_DEFAULTS } from './constants';
|
|
2
|
+
export class ApiClient {
|
|
3
|
+
baseUrl;
|
|
4
|
+
apiKey;
|
|
5
|
+
timeoutMs;
|
|
6
|
+
constructor(baseUrl, apiKey) {
|
|
7
|
+
this.baseUrl = baseUrl.replace(/\/+$/, '');
|
|
8
|
+
this.apiKey = apiKey;
|
|
9
|
+
this.timeoutMs = CONNECTION_DEFAULTS.REQUEST_TIMEOUT_MS;
|
|
10
|
+
}
|
|
11
|
+
async getMe() {
|
|
12
|
+
return this.request('GET', '/api/v1/me');
|
|
13
|
+
}
|
|
14
|
+
async getEvents() {
|
|
15
|
+
return this.request('GET', '/api/v1/me/events');
|
|
16
|
+
}
|
|
17
|
+
async getTicket(eventId) {
|
|
18
|
+
return this.request('POST', `/api/v1/me/events/${eventId}/stream/ticket`);
|
|
19
|
+
}
|
|
20
|
+
async request(method, path) {
|
|
21
|
+
const controller = new AbortController();
|
|
22
|
+
const timer = setTimeout(() => controller.abort(), this.timeoutMs);
|
|
23
|
+
try {
|
|
24
|
+
const response = await fetch(`${this.baseUrl}${path}`, {
|
|
25
|
+
method,
|
|
26
|
+
headers: {
|
|
27
|
+
'x-api-key': this.apiKey,
|
|
28
|
+
'Content-Type': 'application/json',
|
|
29
|
+
},
|
|
30
|
+
signal: controller.signal,
|
|
31
|
+
});
|
|
32
|
+
const body = (await response.json());
|
|
33
|
+
if (!response.ok) {
|
|
34
|
+
const err = body;
|
|
35
|
+
throw new Error(err.error?.message ?? `HTTP ${response.status}`);
|
|
36
|
+
}
|
|
37
|
+
return body.data;
|
|
38
|
+
}
|
|
39
|
+
catch (error) {
|
|
40
|
+
if (error instanceof DOMException && error.name === 'AbortError') {
|
|
41
|
+
throw new Error(`Request timed out after ${this.timeoutMs}ms`);
|
|
42
|
+
}
|
|
43
|
+
throw error;
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
clearTimeout(timer);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=api.js.map
|
package/dist/api.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api.js","sourceRoot":"","sources":["../src/api.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAclD,MAAM,OAAO,SAAS;IACH,OAAO,CAAS;IAChB,MAAM,CAAS;IACf,SAAS,CAAS;IAEnC,YAAY,OAAe,EAAE,MAAc;QACzC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC3C,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,SAAS,GAAG,mBAAmB,CAAC,kBAAkB,CAAC;IAC1D,CAAC;IAED,KAAK,CAAC,KAAK;QACT,OAAO,IAAI,CAAC,OAAO,CAAO,KAAK,EAAE,YAAY,CAAC,CAAC;IACjD,CAAC;IAED,KAAK,CAAC,SAAS;QACb,OAAO,IAAI,CAAC,OAAO,CAAU,KAAK,EAAE,mBAAmB,CAAC,CAAC;IAC3D,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,OAAe;QAC7B,OAAO,IAAI,CAAC,OAAO,CAAS,MAAM,EAAE,qBAAqB,OAAO,gBAAgB,CAAC,CAAC;IACpF,CAAC;IAEO,KAAK,CAAC,OAAO,CAAI,MAAc,EAAE,IAAY;QACnD,MAAM,UAAU,GAAG,IAAI,eAAe,EAAE,CAAC;QACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;QAEnE,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,IAAI,CAAC,OAAO,GAAG,IAAI,EAAE,EAAE;gBACrD,MAAM;gBACN,OAAO,EAAE;oBACP,WAAW,EAAE,IAAI,CAAC,MAAM;oBACxB,cAAc,EAAE,kBAAkB;iBACnC;gBACD,MAAM,EAAE,UAAU,CAAC,MAAM;aAC1B,CAAC,CAAC;YAEH,MAAM,IAAI,GAAG,CAAC,MAAM,QAAQ,CAAC,IAAI,EAAE,CAA6C,CAAC;YAEjF,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,GAAG,GAAG,IAAwB,CAAC;gBACrC,MAAM,IAAI,KAAK,CAAC,GAAG,CAAC,KAAK,EAAE,OAAO,IAAI,QAAQ,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;YACnE,CAAC;YAED,OAAQ,IAA8B,CAAC,IAAI,CAAC;QAC9C,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,IAAI,KAAK,YAAY,YAAY,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;gBACjE,MAAM,IAAI,KAAK,CAAC,2BAA2B,IAAI,CAAC,SAAS,IAAI,CAAC,CAAC;YACjE,CAAC;YACD,MAAM,KAAK,CAAC;QACd,CAAC;gBAAS,CAAC;YACT,YAAY,CAAC,KAAK,CAAC,CAAC;QACtB,CAAC;IACH,CAAC;CACF"}
|
package/dist/client.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { CaitDeskConfig, User, Event, ConnectionStatus, SlotStatus } from './types';
|
|
2
|
+
export declare class CaitDeskClient {
|
|
3
|
+
private readonly api;
|
|
4
|
+
private ws;
|
|
5
|
+
private eventId;
|
|
6
|
+
private readonly config;
|
|
7
|
+
constructor(config: CaitDeskConfig);
|
|
8
|
+
/** Current WebSocket connection status */
|
|
9
|
+
get status(): ConnectionStatus;
|
|
10
|
+
/** Current slot status (active, waiting, or unknown) */
|
|
11
|
+
get slotStatus(): SlotStatus;
|
|
12
|
+
/** Get the authenticated user's info */
|
|
13
|
+
getMe(): Promise<User>;
|
|
14
|
+
/** List events assigned to the authenticated user as captioner */
|
|
15
|
+
getEvents(): Promise<Event[]>;
|
|
16
|
+
/** Connect to an event's WebSocket gateway */
|
|
17
|
+
connect(eventId: string): Promise<void>;
|
|
18
|
+
/** Disconnect from the WebSocket gateway */
|
|
19
|
+
disconnect(): void;
|
|
20
|
+
/** Append text to the current caption stream */
|
|
21
|
+
append(text: string): void;
|
|
22
|
+
/** Delete characters from the end of the caption stream */
|
|
23
|
+
delete(count: number): void;
|
|
24
|
+
/** Sync the full caption text state (used for reconnection or full-text edits) */
|
|
25
|
+
sync(text: string): void;
|
|
26
|
+
/** Start the event (transitions from scheduled to live) */
|
|
27
|
+
start(): void;
|
|
28
|
+
/** Stop the event (transitions from live to ended) */
|
|
29
|
+
stop(): void;
|
|
30
|
+
/** Pause caption display */
|
|
31
|
+
pause(): void;
|
|
32
|
+
/** Resume caption display */
|
|
33
|
+
resume(): void;
|
|
34
|
+
/** Release the active slot to the next waiting captioner */
|
|
35
|
+
releaseSlot(): void;
|
|
36
|
+
private sendControl;
|
|
37
|
+
private requireConnection;
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EACV,cAAc,EACd,IAAI,EACJ,KAAK,EACL,gBAAgB,EAChB,UAAU,EAEX,MAAM,SAAS,CAAC;AAIjB,qBAAa,cAAc;IACzB,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAY;IAChC,OAAO,CAAC,EAAE,CAAyB;IACnC,OAAO,CAAC,OAAO,CAAuB;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAiB;gBAE5B,MAAM,EAAE,cAAc;IAKlC,0CAA0C;IAC1C,IAAI,MAAM,IAAI,gBAAgB,CAE7B;IAED,wDAAwD;IACxD,IAAI,UAAU,IAAI,UAAU,CAE3B;IAMD,wCAAwC;IAClC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,kEAAkE;IAC5D,SAAS,IAAI,OAAO,CAAC,KAAK,EAAE,CAAC;IAQnC,8CAA8C;IACxC,OAAO,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAoB7C,4CAA4C;IAC5C,UAAU,IAAI,IAAI;IAUlB,gDAAgD;IAChD,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAQ1B,2DAA2D;IAC3D,MAAM,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAQ3B,kFAAkF;IAClF,IAAI,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI;IAYxB,2DAA2D;IAC3D,KAAK,IAAI,IAAI;IAIb,sDAAsD;IACtD,IAAI,IAAI,IAAI;IAIZ,4BAA4B;IAC5B,KAAK,IAAI,IAAI;IAIb,6BAA6B;IAC7B,MAAM,IAAI,IAAI;IAQd,4DAA4D;IAC5D,WAAW,IAAI,IAAI;IASnB,OAAO,CAAC,WAAW;IAKnB,OAAO,CAAC,iBAAiB;CAM1B"}
|
package/dist/client.js
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { CONTROL_ACTION, RATE_LIMITS } from './constants';
|
|
2
|
+
import { ApiClient } from './api';
|
|
3
|
+
import { WsClient } from './ws';
|
|
4
|
+
const noop = () => { };
|
|
5
|
+
export class CaitDeskClient {
|
|
6
|
+
api;
|
|
7
|
+
ws = null;
|
|
8
|
+
eventId = null;
|
|
9
|
+
config;
|
|
10
|
+
constructor(config) {
|
|
11
|
+
this.config = config;
|
|
12
|
+
this.api = new ApiClient(config.apiUrl, config.apiKey);
|
|
13
|
+
}
|
|
14
|
+
/** Current WebSocket connection status */
|
|
15
|
+
get status() {
|
|
16
|
+
return this.ws?.status ?? 'disconnected';
|
|
17
|
+
}
|
|
18
|
+
/** Current slot status (active, waiting, or unknown) */
|
|
19
|
+
get slotStatus() {
|
|
20
|
+
return this.ws?.slotStatus ?? 'unknown';
|
|
21
|
+
}
|
|
22
|
+
// -----------------------------------------------------------------------
|
|
23
|
+
// REST
|
|
24
|
+
// -----------------------------------------------------------------------
|
|
25
|
+
/** Get the authenticated user's info */
|
|
26
|
+
async getMe() {
|
|
27
|
+
return this.api.getMe();
|
|
28
|
+
}
|
|
29
|
+
/** List events assigned to the authenticated user as captioner */
|
|
30
|
+
async getEvents() {
|
|
31
|
+
return this.api.getEvents();
|
|
32
|
+
}
|
|
33
|
+
// -----------------------------------------------------------------------
|
|
34
|
+
// Connection
|
|
35
|
+
// -----------------------------------------------------------------------
|
|
36
|
+
/** Connect to an event's WebSocket gateway */
|
|
37
|
+
async connect(eventId) {
|
|
38
|
+
this.ws?.disconnect();
|
|
39
|
+
this.eventId = eventId;
|
|
40
|
+
const ticket = await this.api.getTicket(eventId);
|
|
41
|
+
this.ws = new WsClient({
|
|
42
|
+
onStatusChange: this.config.onStatusChange ?? noop,
|
|
43
|
+
onSlotChange: this.config.onSlotChange ?? noop,
|
|
44
|
+
onCaptionAck: this.config.onCaptionAck ?? noop,
|
|
45
|
+
onControlAck: this.config.onControlAck ?? noop,
|
|
46
|
+
onError: this.config.onError ?? noop,
|
|
47
|
+
onEventEnded: this.config.onEventEnded ?? noop,
|
|
48
|
+
onWaitingCountChange: this.config.onWaitingCountChange ?? noop,
|
|
49
|
+
refreshTicket: () => this.api.getTicket(eventId),
|
|
50
|
+
});
|
|
51
|
+
this.ws.connect(ticket);
|
|
52
|
+
}
|
|
53
|
+
/** Disconnect from the WebSocket gateway */
|
|
54
|
+
disconnect() {
|
|
55
|
+
this.ws?.disconnect();
|
|
56
|
+
this.ws = null;
|
|
57
|
+
this.eventId = null;
|
|
58
|
+
}
|
|
59
|
+
// -----------------------------------------------------------------------
|
|
60
|
+
// Captions
|
|
61
|
+
// -----------------------------------------------------------------------
|
|
62
|
+
/** Append text to the current caption stream */
|
|
63
|
+
append(text) {
|
|
64
|
+
const { ws, eventId } = this.requireConnection();
|
|
65
|
+
if (text.length > RATE_LIMITS.MAX_APPEND_LENGTH) {
|
|
66
|
+
throw new Error(`Text length ${text.length} exceeds maximum of ${RATE_LIMITS.MAX_APPEND_LENGTH}`);
|
|
67
|
+
}
|
|
68
|
+
ws.send({ type: 'append', eventId, timestamp: Date.now(), text });
|
|
69
|
+
}
|
|
70
|
+
/** Delete characters from the end of the caption stream */
|
|
71
|
+
delete(count) {
|
|
72
|
+
const { ws, eventId } = this.requireConnection();
|
|
73
|
+
if (count > RATE_LIMITS.MAX_DELETE_COUNT) {
|
|
74
|
+
throw new Error(`Delete count ${count} exceeds maximum of ${RATE_LIMITS.MAX_DELETE_COUNT}`);
|
|
75
|
+
}
|
|
76
|
+
ws.send({ type: 'delete', eventId, timestamp: Date.now(), count });
|
|
77
|
+
}
|
|
78
|
+
/** Sync the full caption text state (used for reconnection or full-text edits) */
|
|
79
|
+
sync(text) {
|
|
80
|
+
const { ws, eventId } = this.requireConnection();
|
|
81
|
+
if (text.length > RATE_LIMITS.MAX_SYNC_LENGTH) {
|
|
82
|
+
throw new Error(`Text length ${text.length} exceeds maximum of ${RATE_LIMITS.MAX_SYNC_LENGTH}`);
|
|
83
|
+
}
|
|
84
|
+
ws.send({ type: 'sync', eventId, timestamp: Date.now(), text });
|
|
85
|
+
}
|
|
86
|
+
// -----------------------------------------------------------------------
|
|
87
|
+
// Event control
|
|
88
|
+
// -----------------------------------------------------------------------
|
|
89
|
+
/** Start the event (transitions from scheduled to live) */
|
|
90
|
+
start() {
|
|
91
|
+
this.sendControl(CONTROL_ACTION.START);
|
|
92
|
+
}
|
|
93
|
+
/** Stop the event (transitions from live to ended) */
|
|
94
|
+
stop() {
|
|
95
|
+
this.sendControl(CONTROL_ACTION.STOP);
|
|
96
|
+
}
|
|
97
|
+
/** Pause caption display */
|
|
98
|
+
pause() {
|
|
99
|
+
this.sendControl(CONTROL_ACTION.PAUSE);
|
|
100
|
+
}
|
|
101
|
+
/** Resume caption display */
|
|
102
|
+
resume() {
|
|
103
|
+
this.sendControl(CONTROL_ACTION.RESUME);
|
|
104
|
+
}
|
|
105
|
+
// -----------------------------------------------------------------------
|
|
106
|
+
// Slot management
|
|
107
|
+
// -----------------------------------------------------------------------
|
|
108
|
+
/** Release the active slot to the next waiting captioner */
|
|
109
|
+
releaseSlot() {
|
|
110
|
+
const { ws } = this.requireConnection();
|
|
111
|
+
ws.releaseSlot();
|
|
112
|
+
}
|
|
113
|
+
// -----------------------------------------------------------------------
|
|
114
|
+
// Private
|
|
115
|
+
// -----------------------------------------------------------------------
|
|
116
|
+
sendControl(action) {
|
|
117
|
+
const { ws, eventId } = this.requireConnection();
|
|
118
|
+
ws.send({ type: 'control', eventId, action });
|
|
119
|
+
}
|
|
120
|
+
requireConnection() {
|
|
121
|
+
if (!this.ws || !this.eventId || this.ws.status === 'disconnected') {
|
|
122
|
+
throw new Error('Not connected. Call connect(eventId) first.');
|
|
123
|
+
}
|
|
124
|
+
return { ws: this.ws, eventId: this.eventId };
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Protocol constants inlined from @caitdesk/shared.
|
|
3
|
+
* Keep in sync with packages/shared/src/constants/.
|
|
4
|
+
*/
|
|
5
|
+
/** Session actions (gateway <-> captioner slot management) */
|
|
6
|
+
export declare const SESSION_ACTION: {
|
|
7
|
+
readonly SLOT_GRANTED: "slot:granted";
|
|
8
|
+
readonly SLOT_OCCUPIED: "slot:occupied";
|
|
9
|
+
readonly SLOT_REQUESTED: "slot:requested";
|
|
10
|
+
readonly SLOT_REQUEST_CANCELLED: "slot:request_cancelled";
|
|
11
|
+
readonly SLOT_RELEASE: "slot:release";
|
|
12
|
+
};
|
|
13
|
+
/** Control actions sent by captioner to manage event state */
|
|
14
|
+
export declare const CONTROL_ACTION: {
|
|
15
|
+
readonly START: "event:start";
|
|
16
|
+
readonly STOP: "event:stop";
|
|
17
|
+
readonly PAUSE: "event:pause";
|
|
18
|
+
readonly RESUME: "event:resume";
|
|
19
|
+
};
|
|
20
|
+
/** Error codes returned by the API and gateway */
|
|
21
|
+
export declare const ERROR_CODE: {
|
|
22
|
+
readonly UNAUTHORIZED: "UNAUTHORIZED";
|
|
23
|
+
readonly FORBIDDEN: "FORBIDDEN";
|
|
24
|
+
readonly NOT_FOUND: "NOT_FOUND";
|
|
25
|
+
readonly GONE: "GONE";
|
|
26
|
+
readonly VALIDATION_ERROR: "VALIDATION_ERROR";
|
|
27
|
+
readonly RATE_LIMITED: "RATE_LIMITED";
|
|
28
|
+
readonly INTERNAL_ERROR: "INTERNAL_ERROR";
|
|
29
|
+
readonly WS_AUTH_FAILED: "WS_AUTH_FAILED";
|
|
30
|
+
readonly WS_INVALID_MESSAGE: "WS_INVALID_MESSAGE";
|
|
31
|
+
readonly WS_EVENT_NOT_FOUND: "WS_EVENT_NOT_FOUND";
|
|
32
|
+
readonly WS_CONNECTION_ERROR: "WS_CONNECTION_ERROR";
|
|
33
|
+
readonly WS_SLOT_FULL: "WS_SLOT_FULL";
|
|
34
|
+
readonly WS_NOT_ACTIVE: "WS_NOT_ACTIVE";
|
|
35
|
+
readonly NETWORK_ERROR: "NETWORK_ERROR";
|
|
36
|
+
};
|
|
37
|
+
/** Rate limits enforced by the gateway */
|
|
38
|
+
export declare const RATE_LIMITS: {
|
|
39
|
+
/** Maximum caption messages per second per connection */
|
|
40
|
+
readonly MAX_MESSAGES_PER_SECOND: 50;
|
|
41
|
+
/** Maximum text length for append messages */
|
|
42
|
+
readonly MAX_APPEND_LENGTH: 10000;
|
|
43
|
+
/** Maximum text length for sync messages */
|
|
44
|
+
readonly MAX_SYNC_LENGTH: 100000;
|
|
45
|
+
/** Maximum delete count */
|
|
46
|
+
readonly MAX_DELETE_COUNT: 100000;
|
|
47
|
+
/** Allowed timestamp drift in milliseconds (±30s) */
|
|
48
|
+
readonly MAX_TIMESTAMP_DRIFT_MS: 30000;
|
|
49
|
+
};
|
|
50
|
+
/** Default connection parameters */
|
|
51
|
+
export declare const CONNECTION_DEFAULTS: {
|
|
52
|
+
/** Initial reconnect delay in ms */
|
|
53
|
+
readonly RECONNECT_DELAY_MS: 1000;
|
|
54
|
+
/** Maximum reconnect delay in ms */
|
|
55
|
+
readonly RECONNECT_DELAY_MAX_MS: 30000;
|
|
56
|
+
/** Reconnect delay multiplier (exponential backoff) */
|
|
57
|
+
readonly RECONNECT_MULTIPLIER: 1.5;
|
|
58
|
+
/** HTTP request timeout in ms */
|
|
59
|
+
readonly REQUEST_TIMEOUT_MS: 10000;
|
|
60
|
+
};
|
|
61
|
+
/** WebSocket close codes with special meaning */
|
|
62
|
+
export declare const WS_CLOSE_CODE: {
|
|
63
|
+
/** Normal closure (event ended, slot released) */
|
|
64
|
+
readonly NORMAL: 1000;
|
|
65
|
+
/** Authentication failed — do not reconnect */
|
|
66
|
+
readonly AUTH_FAILED: 1008;
|
|
67
|
+
/** Slot queue full — do not reconnect */
|
|
68
|
+
readonly SLOT_FULL: 1013;
|
|
69
|
+
};
|
|
70
|
+
//# sourceMappingURL=constants.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,8DAA8D;AAC9D,eAAO,MAAM,cAAc;;;;;;CAMjB,CAAC;AAEX,8DAA8D;AAC9D,eAAO,MAAM,cAAc;;;;;CAKjB,CAAC;AAEX,kDAAkD;AAClD,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;CA4Bb,CAAC;AAEX,0CAA0C;AAC1C,eAAO,MAAM,WAAW;IACtB,yDAAyD;;IAEzD,8CAA8C;;IAE9C,4CAA4C;;IAE5C,2BAA2B;;IAE3B,qDAAqD;;CAE7C,CAAC;AAEX,oCAAoC;AACpC,eAAO,MAAM,mBAAmB;IAC9B,oCAAoC;;IAEpC,oCAAoC;;IAEpC,uDAAuD;;IAEvD,iCAAiC;;CAEzB,CAAC;AAEX,iDAAiD;AACjD,eAAO,MAAM,aAAa;IACxB,kDAAkD;;IAElD,+CAA+C;;IAE/C,yCAAyC;;CAEjC,CAAC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Protocol constants inlined from @caitdesk/shared.
|
|
3
|
+
* Keep in sync with packages/shared/src/constants/.
|
|
4
|
+
*/
|
|
5
|
+
/** Session actions (gateway <-> captioner slot management) */
|
|
6
|
+
export const SESSION_ACTION = {
|
|
7
|
+
SLOT_GRANTED: 'slot:granted',
|
|
8
|
+
SLOT_OCCUPIED: 'slot:occupied',
|
|
9
|
+
SLOT_REQUESTED: 'slot:requested',
|
|
10
|
+
SLOT_REQUEST_CANCELLED: 'slot:request_cancelled',
|
|
11
|
+
SLOT_RELEASE: 'slot:release',
|
|
12
|
+
};
|
|
13
|
+
/** Control actions sent by captioner to manage event state */
|
|
14
|
+
export const CONTROL_ACTION = {
|
|
15
|
+
START: 'event:start',
|
|
16
|
+
STOP: 'event:stop',
|
|
17
|
+
PAUSE: 'event:pause',
|
|
18
|
+
RESUME: 'event:resume',
|
|
19
|
+
};
|
|
20
|
+
/** Error codes returned by the API and gateway */
|
|
21
|
+
export const ERROR_CODE = {
|
|
22
|
+
// Auth
|
|
23
|
+
UNAUTHORIZED: 'UNAUTHORIZED',
|
|
24
|
+
FORBIDDEN: 'FORBIDDEN',
|
|
25
|
+
// Resource
|
|
26
|
+
NOT_FOUND: 'NOT_FOUND',
|
|
27
|
+
GONE: 'GONE',
|
|
28
|
+
// Validation
|
|
29
|
+
VALIDATION_ERROR: 'VALIDATION_ERROR',
|
|
30
|
+
// Rate limiting
|
|
31
|
+
RATE_LIMITED: 'RATE_LIMITED',
|
|
32
|
+
// Service
|
|
33
|
+
INTERNAL_ERROR: 'INTERNAL_ERROR',
|
|
34
|
+
// WebSocket
|
|
35
|
+
WS_AUTH_FAILED: 'WS_AUTH_FAILED',
|
|
36
|
+
WS_INVALID_MESSAGE: 'WS_INVALID_MESSAGE',
|
|
37
|
+
WS_EVENT_NOT_FOUND: 'WS_EVENT_NOT_FOUND',
|
|
38
|
+
WS_CONNECTION_ERROR: 'WS_CONNECTION_ERROR',
|
|
39
|
+
WS_SLOT_FULL: 'WS_SLOT_FULL',
|
|
40
|
+
WS_NOT_ACTIVE: 'WS_NOT_ACTIVE',
|
|
41
|
+
// Client-side
|
|
42
|
+
NETWORK_ERROR: 'NETWORK_ERROR',
|
|
43
|
+
};
|
|
44
|
+
/** Rate limits enforced by the gateway */
|
|
45
|
+
export const RATE_LIMITS = {
|
|
46
|
+
/** Maximum caption messages per second per connection */
|
|
47
|
+
MAX_MESSAGES_PER_SECOND: 50,
|
|
48
|
+
/** Maximum text length for append messages */
|
|
49
|
+
MAX_APPEND_LENGTH: 10_000,
|
|
50
|
+
/** Maximum text length for sync messages */
|
|
51
|
+
MAX_SYNC_LENGTH: 100_000,
|
|
52
|
+
/** Maximum delete count */
|
|
53
|
+
MAX_DELETE_COUNT: 100_000,
|
|
54
|
+
/** Allowed timestamp drift in milliseconds (±30s) */
|
|
55
|
+
MAX_TIMESTAMP_DRIFT_MS: 30_000,
|
|
56
|
+
};
|
|
57
|
+
/** Default connection parameters */
|
|
58
|
+
export const CONNECTION_DEFAULTS = {
|
|
59
|
+
/** Initial reconnect delay in ms */
|
|
60
|
+
RECONNECT_DELAY_MS: 1_000,
|
|
61
|
+
/** Maximum reconnect delay in ms */
|
|
62
|
+
RECONNECT_DELAY_MAX_MS: 30_000,
|
|
63
|
+
/** Reconnect delay multiplier (exponential backoff) */
|
|
64
|
+
RECONNECT_MULTIPLIER: 1.5,
|
|
65
|
+
/** HTTP request timeout in ms */
|
|
66
|
+
REQUEST_TIMEOUT_MS: 10_000,
|
|
67
|
+
};
|
|
68
|
+
/** WebSocket close codes with special meaning */
|
|
69
|
+
export const WS_CLOSE_CODE = {
|
|
70
|
+
/** Normal closure (event ended, slot released) */
|
|
71
|
+
NORMAL: 1000,
|
|
72
|
+
/** Authentication failed — do not reconnect */
|
|
73
|
+
AUTH_FAILED: 1008,
|
|
74
|
+
/** Slot queue full — do not reconnect */
|
|
75
|
+
SLOT_FULL: 1013,
|
|
76
|
+
};
|
|
77
|
+
//# sourceMappingURL=constants.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,8DAA8D;AAC9D,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,YAAY,EAAE,cAAc;IAC5B,aAAa,EAAE,eAAe;IAC9B,cAAc,EAAE,gBAAgB;IAChC,sBAAsB,EAAE,wBAAwB;IAChD,YAAY,EAAE,cAAc;CACpB,CAAC;AAEX,8DAA8D;AAC9D,MAAM,CAAC,MAAM,cAAc,GAAG;IAC5B,KAAK,EAAE,aAAa;IACpB,IAAI,EAAE,YAAY;IAClB,KAAK,EAAE,aAAa;IACpB,MAAM,EAAE,cAAc;CACd,CAAC;AAEX,kDAAkD;AAClD,MAAM,CAAC,MAAM,UAAU,GAAG;IACxB,OAAO;IACP,YAAY,EAAE,cAAc;IAC5B,SAAS,EAAE,WAAW;IAEtB,WAAW;IACX,SAAS,EAAE,WAAW;IACtB,IAAI,EAAE,MAAM;IAEZ,aAAa;IACb,gBAAgB,EAAE,kBAAkB;IAEpC,gBAAgB;IAChB,YAAY,EAAE,cAAc;IAE5B,UAAU;IACV,cAAc,EAAE,gBAAgB;IAEhC,YAAY;IACZ,cAAc,EAAE,gBAAgB;IAChC,kBAAkB,EAAE,oBAAoB;IACxC,kBAAkB,EAAE,oBAAoB;IACxC,mBAAmB,EAAE,qBAAqB;IAC1C,YAAY,EAAE,cAAc;IAC5B,aAAa,EAAE,eAAe;IAE9B,cAAc;IACd,aAAa,EAAE,eAAe;CACtB,CAAC;AAEX,0CAA0C;AAC1C,MAAM,CAAC,MAAM,WAAW,GAAG;IACzB,yDAAyD;IACzD,uBAAuB,EAAE,EAAE;IAC3B,8CAA8C;IAC9C,iBAAiB,EAAE,MAAM;IACzB,4CAA4C;IAC5C,eAAe,EAAE,OAAO;IACxB,2BAA2B;IAC3B,gBAAgB,EAAE,OAAO;IACzB,qDAAqD;IACrD,sBAAsB,EAAE,MAAM;CACtB,CAAC;AAEX,oCAAoC;AACpC,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,oCAAoC;IACpC,kBAAkB,EAAE,KAAK;IACzB,oCAAoC;IACpC,sBAAsB,EAAE,MAAM;IAC9B,uDAAuD;IACvD,oBAAoB,EAAE,GAAG;IACzB,iCAAiC;IACjC,kBAAkB,EAAE,MAAM;CAClB,CAAC;AAEX,iDAAiD;AACjD,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,kDAAkD;IAClD,MAAM,EAAE,IAAI;IACZ,+CAA+C;IAC/C,WAAW,EAAE,IAAI;IACjB,yCAAyC;IACzC,SAAS,EAAE,IAAI;CACP,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { CaitDeskClient } from './client';
|
|
2
|
+
export type { CaitDeskConfig, User, Event, Ticket, ConnectionStatus, SlotStatus, SlotDetail, CaptionAck, ControlAck, ServerError, ControlActionValue, ErrorCodeValue, } from './types';
|
|
3
|
+
export { ERROR_CODE, RATE_LIMITS, CONNECTION_DEFAULTS, SESSION_ACTION, CONTROL_ACTION, WS_CLOSE_CODE, } from './constants';
|
|
4
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE1C,YAAY,EACV,cAAc,EACd,IAAI,EACJ,KAAK,EACL,MAAM,EACN,gBAAgB,EAChB,UAAU,EACV,UAAU,EACV,UAAU,EACV,UAAU,EACV,WAAW,EACX,kBAAkB,EAClB,cAAc,GACf,MAAM,SAAS,CAAC;AAEjB,OAAO,EACL,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,cAAc,EACd,aAAa,GACd,MAAM,aAAa,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAiB1C,OAAO,EACL,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,cAAc,EACd,aAAa,GACd,MAAM,aAAa,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type { SESSION_ACTION, CONTROL_ACTION, ERROR_CODE } from './constants';
|
|
2
|
+
export interface CaitDeskConfig {
|
|
3
|
+
/** Base URL of the CaitDesk API (e.g. "https://api.caitdesk.com") */
|
|
4
|
+
apiUrl: string;
|
|
5
|
+
/** API key for authentication (starts with "cait_sk_") */
|
|
6
|
+
apiKey: string;
|
|
7
|
+
/** Called when the WebSocket connection status changes */
|
|
8
|
+
onStatusChange?: (status: ConnectionStatus) => void;
|
|
9
|
+
/** Called when the slot status changes (active / waiting) */
|
|
10
|
+
onSlotChange?: (status: SlotStatus, detail?: SlotDetail) => void;
|
|
11
|
+
/** Called when a caption message is acknowledged by the server */
|
|
12
|
+
onCaptionAck?: (ack: CaptionAck) => void;
|
|
13
|
+
/** Called when a control action is acknowledged by the server */
|
|
14
|
+
onControlAck?: (ack: ControlAck) => void;
|
|
15
|
+
/** Called when the server reports an error */
|
|
16
|
+
onError?: (error: ServerError) => void;
|
|
17
|
+
/** Called when the event ends (server-initiated) */
|
|
18
|
+
onEventEnded?: (eventId: string) => void;
|
|
19
|
+
/** Called when the number of waiting captioners changes (active captioner only) */
|
|
20
|
+
onWaitingCountChange?: (count: number) => void;
|
|
21
|
+
}
|
|
22
|
+
export interface User {
|
|
23
|
+
id: string;
|
|
24
|
+
email: string;
|
|
25
|
+
name: string | null;
|
|
26
|
+
}
|
|
27
|
+
export interface Event {
|
|
28
|
+
id: string;
|
|
29
|
+
organizationId: string;
|
|
30
|
+
title: string;
|
|
31
|
+
description: string | null;
|
|
32
|
+
scheduledStart: string;
|
|
33
|
+
scheduledEnd: string | null;
|
|
34
|
+
status: string;
|
|
35
|
+
clientName: string | null;
|
|
36
|
+
}
|
|
37
|
+
export interface Ticket {
|
|
38
|
+
ticket: string;
|
|
39
|
+
expiresIn: number;
|
|
40
|
+
gatewayUrl: string;
|
|
41
|
+
}
|
|
42
|
+
export type ConnectionStatus = 'disconnected' | 'connecting' | 'connected' | 'reconnecting';
|
|
43
|
+
export type SlotStatus = 'unknown' | 'active' | 'waiting';
|
|
44
|
+
export interface SlotDetail {
|
|
45
|
+
/** Queue position (1-based, only when waiting) */
|
|
46
|
+
position?: number;
|
|
47
|
+
/** ISO timestamp of when the active captioner connected */
|
|
48
|
+
activeSince?: string;
|
|
49
|
+
}
|
|
50
|
+
export interface AppendMessage {
|
|
51
|
+
type: 'append';
|
|
52
|
+
eventId: string;
|
|
53
|
+
timestamp: number;
|
|
54
|
+
text: string;
|
|
55
|
+
}
|
|
56
|
+
export interface DeleteMessage {
|
|
57
|
+
type: 'delete';
|
|
58
|
+
eventId: string;
|
|
59
|
+
timestamp: number;
|
|
60
|
+
count: number;
|
|
61
|
+
}
|
|
62
|
+
export interface SyncMessage {
|
|
63
|
+
type: 'sync';
|
|
64
|
+
eventId: string;
|
|
65
|
+
timestamp: number;
|
|
66
|
+
text: string;
|
|
67
|
+
}
|
|
68
|
+
export interface ControlMessage {
|
|
69
|
+
type: 'control';
|
|
70
|
+
eventId: string;
|
|
71
|
+
action: ControlActionValue;
|
|
72
|
+
}
|
|
73
|
+
export interface SessionReleaseMessage {
|
|
74
|
+
type: 'session';
|
|
75
|
+
action: typeof SESSION_ACTION.SLOT_RELEASE;
|
|
76
|
+
}
|
|
77
|
+
export type OutgoingMessage = AppendMessage | DeleteMessage | SyncMessage | ControlMessage | SessionReleaseMessage;
|
|
78
|
+
export interface ConnectedMessage {
|
|
79
|
+
type: 'connected';
|
|
80
|
+
eventId: string;
|
|
81
|
+
message: string;
|
|
82
|
+
}
|
|
83
|
+
export interface CaptionAck {
|
|
84
|
+
type: 'ack';
|
|
85
|
+
timestamp: number;
|
|
86
|
+
seq: number;
|
|
87
|
+
}
|
|
88
|
+
export interface ControlAck {
|
|
89
|
+
type: 'ack';
|
|
90
|
+
action: string;
|
|
91
|
+
}
|
|
92
|
+
export interface ServerError {
|
|
93
|
+
type: 'error';
|
|
94
|
+
code: ErrorCodeValue;
|
|
95
|
+
message: string;
|
|
96
|
+
details?: Record<string, unknown>;
|
|
97
|
+
}
|
|
98
|
+
export interface EventEndedMessage {
|
|
99
|
+
type: 'event_ended';
|
|
100
|
+
eventId: string;
|
|
101
|
+
message: string;
|
|
102
|
+
}
|
|
103
|
+
export interface SlotGrantedMessage {
|
|
104
|
+
type: 'session';
|
|
105
|
+
action: typeof SESSION_ACTION.SLOT_GRANTED;
|
|
106
|
+
}
|
|
107
|
+
export interface SlotOccupiedMessage {
|
|
108
|
+
type: 'session';
|
|
109
|
+
action: typeof SESSION_ACTION.SLOT_OCCUPIED;
|
|
110
|
+
position: number;
|
|
111
|
+
activeSince: string;
|
|
112
|
+
}
|
|
113
|
+
export interface SlotRequestedMessage {
|
|
114
|
+
type: 'session';
|
|
115
|
+
action: typeof SESSION_ACTION.SLOT_REQUESTED;
|
|
116
|
+
waitingCount: number;
|
|
117
|
+
}
|
|
118
|
+
export interface SlotRequestCancelledMessage {
|
|
119
|
+
type: 'session';
|
|
120
|
+
action: typeof SESSION_ACTION.SLOT_REQUEST_CANCELLED;
|
|
121
|
+
waitingCount: number;
|
|
122
|
+
}
|
|
123
|
+
export type SessionMessage = SlotGrantedMessage | SlotOccupiedMessage | SlotRequestedMessage | SlotRequestCancelledMessage;
|
|
124
|
+
export type IncomingMessage = ConnectedMessage | CaptionAck | ControlAck | ServerError | EventEndedMessage | SessionMessage;
|
|
125
|
+
export type ControlActionValue = (typeof CONTROL_ACTION)[keyof typeof CONTROL_ACTION];
|
|
126
|
+
export type ErrorCodeValue = (typeof ERROR_CODE)[keyof typeof ERROR_CODE];
|
|
127
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
|
package/dist/ws.d.ts
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import type { ConnectionStatus, SlotStatus, SlotDetail, CaptionAck, ControlAck, ServerError, Ticket } from './types';
|
|
2
|
+
export interface WsClientCallbacks {
|
|
3
|
+
onStatusChange: (status: ConnectionStatus) => void;
|
|
4
|
+
onSlotChange: (status: SlotStatus, detail?: SlotDetail) => void;
|
|
5
|
+
onCaptionAck: (ack: CaptionAck) => void;
|
|
6
|
+
onControlAck: (ack: ControlAck) => void;
|
|
7
|
+
onError: (error: ServerError) => void;
|
|
8
|
+
onEventEnded: (eventId: string) => void;
|
|
9
|
+
onWaitingCountChange: (count: number) => void;
|
|
10
|
+
refreshTicket: () => Promise<Ticket>;
|
|
11
|
+
}
|
|
12
|
+
export declare class WsClient {
|
|
13
|
+
private ws;
|
|
14
|
+
private _status;
|
|
15
|
+
private _slotStatus;
|
|
16
|
+
private reconnectDelay;
|
|
17
|
+
private reconnectTimer;
|
|
18
|
+
private intentionalClose;
|
|
19
|
+
private gatewayUrl;
|
|
20
|
+
private ticket;
|
|
21
|
+
private readonly cb;
|
|
22
|
+
constructor(callbacks: WsClientCallbacks);
|
|
23
|
+
get status(): ConnectionStatus;
|
|
24
|
+
get slotStatus(): SlotStatus;
|
|
25
|
+
connect(ticket: Ticket): void;
|
|
26
|
+
disconnect(): void;
|
|
27
|
+
send(message: object): void;
|
|
28
|
+
releaseSlot(): void;
|
|
29
|
+
private openSocket;
|
|
30
|
+
private handleMessage;
|
|
31
|
+
private handleSession;
|
|
32
|
+
private handleClose;
|
|
33
|
+
private scheduleReconnect;
|
|
34
|
+
private clearReconnectTimer;
|
|
35
|
+
private setStatus;
|
|
36
|
+
private setSlotStatus;
|
|
37
|
+
}
|
|
38
|
+
//# sourceMappingURL=ws.d.ts.map
|
package/dist/ws.d.ts.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ws.d.ts","sourceRoot":"","sources":["../src/ws.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gBAAgB,EAChB,UAAU,EACV,UAAU,EAEV,UAAU,EACV,UAAU,EACV,WAAW,EAEX,MAAM,EACP,MAAM,SAAS,CAAC;AAcjB,MAAM,WAAW,iBAAiB;IAChC,cAAc,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACnD,YAAY,EAAE,CAAC,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,UAAU,KAAK,IAAI,CAAC;IAChE,YAAY,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,CAAC;IACxC,YAAY,EAAE,CAAC,GAAG,EAAE,UAAU,KAAK,IAAI,CAAC;IACxC,OAAO,EAAE,CAAC,KAAK,EAAE,WAAW,KAAK,IAAI,CAAC;IACtC,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,oBAAoB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC9C,aAAa,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CACtC;AAED,qBAAa,QAAQ;IACnB,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,OAAO,CAAoC;IACnD,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,cAAc,CAAkD;IACxE,OAAO,CAAC,cAAc,CAA8C;IACpE,OAAO,CAAC,gBAAgB,CAAS;IACjC,OAAO,CAAC,UAAU,CAAM;IACxB,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAoB;gBAE3B,SAAS,EAAE,iBAAiB;IAIxC,IAAI,MAAM,IAAI,gBAAgB,CAE7B;IAED,IAAI,UAAU,IAAI,UAAU,CAE3B;IAED,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAO7B,UAAU,IAAI,IAAI;IAWlB,IAAI,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAM3B,WAAW,IAAI,IAAI;IAQnB,OAAO,CAAC,UAAU;IAyBlB,OAAO,CAAC,aAAa;IAuCrB,OAAO,CAAC,aAAa;IAoBrB,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,iBAAiB;IAwBzB,OAAO,CAAC,mBAAmB;IAO3B,OAAO,CAAC,SAAS;IAOjB,OAAO,CAAC,aAAa;CAOtB"}
|
package/dist/ws.js
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { SESSION_ACTION, ERROR_CODE, CONNECTION_DEFAULTS, WS_CLOSE_CODE } from './constants';
|
|
2
|
+
/** Terminal error codes that should not trigger reconnection */
|
|
3
|
+
const TERMINAL_CODES = new Set([
|
|
4
|
+
ERROR_CODE.WS_AUTH_FAILED,
|
|
5
|
+
ERROR_CODE.WS_SLOT_FULL,
|
|
6
|
+
]);
|
|
7
|
+
/** Close codes that should not trigger reconnection */
|
|
8
|
+
const TERMINAL_CLOSE_CODES = new Set([
|
|
9
|
+
WS_CLOSE_CODE.AUTH_FAILED,
|
|
10
|
+
WS_CLOSE_CODE.SLOT_FULL,
|
|
11
|
+
]);
|
|
12
|
+
export class WsClient {
|
|
13
|
+
ws = null;
|
|
14
|
+
_status = 'disconnected';
|
|
15
|
+
_slotStatus = 'unknown';
|
|
16
|
+
reconnectDelay = CONNECTION_DEFAULTS.RECONNECT_DELAY_MS;
|
|
17
|
+
reconnectTimer = null;
|
|
18
|
+
intentionalClose = false;
|
|
19
|
+
gatewayUrl = '';
|
|
20
|
+
ticket = '';
|
|
21
|
+
cb;
|
|
22
|
+
constructor(callbacks) {
|
|
23
|
+
this.cb = callbacks;
|
|
24
|
+
}
|
|
25
|
+
get status() {
|
|
26
|
+
return this._status;
|
|
27
|
+
}
|
|
28
|
+
get slotStatus() {
|
|
29
|
+
return this._slotStatus;
|
|
30
|
+
}
|
|
31
|
+
connect(ticket) {
|
|
32
|
+
this.intentionalClose = false;
|
|
33
|
+
this.gatewayUrl = ticket.gatewayUrl;
|
|
34
|
+
this.ticket = ticket.ticket;
|
|
35
|
+
this.openSocket();
|
|
36
|
+
}
|
|
37
|
+
disconnect() {
|
|
38
|
+
this.intentionalClose = true;
|
|
39
|
+
this.clearReconnectTimer();
|
|
40
|
+
if (this.ws) {
|
|
41
|
+
this.ws.close(1000);
|
|
42
|
+
this.ws = null;
|
|
43
|
+
}
|
|
44
|
+
this.setStatus('disconnected');
|
|
45
|
+
this.setSlotStatus('unknown');
|
|
46
|
+
}
|
|
47
|
+
send(message) {
|
|
48
|
+
if (this.ws && this.ws.readyState === WebSocket.OPEN) {
|
|
49
|
+
this.ws.send(JSON.stringify(message));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
releaseSlot() {
|
|
53
|
+
this.send({ type: 'session', action: SESSION_ACTION.SLOT_RELEASE });
|
|
54
|
+
}
|
|
55
|
+
// -----------------------------------------------------------------------
|
|
56
|
+
// Private
|
|
57
|
+
// -----------------------------------------------------------------------
|
|
58
|
+
openSocket() {
|
|
59
|
+
this.setStatus('connecting');
|
|
60
|
+
const url = new URL(this.gatewayUrl);
|
|
61
|
+
url.searchParams.set('ticket', this.ticket);
|
|
62
|
+
this.ws = new WebSocket(url.toString());
|
|
63
|
+
this.ws.onopen = () => {
|
|
64
|
+
this.reconnectDelay = CONNECTION_DEFAULTS.RECONNECT_DELAY_MS;
|
|
65
|
+
this.setStatus('connected');
|
|
66
|
+
};
|
|
67
|
+
this.ws.onmessage = (event) => {
|
|
68
|
+
this.handleMessage(event.data);
|
|
69
|
+
};
|
|
70
|
+
this.ws.onclose = (event) => {
|
|
71
|
+
this.handleClose(event);
|
|
72
|
+
};
|
|
73
|
+
this.ws.onerror = () => {
|
|
74
|
+
// The close event fires after error, which handles reconnection
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
handleMessage(data) {
|
|
78
|
+
let msg;
|
|
79
|
+
try {
|
|
80
|
+
msg = JSON.parse(data);
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
switch (msg.type) {
|
|
86
|
+
case 'connected':
|
|
87
|
+
// Connection confirmed, status already set in onopen
|
|
88
|
+
break;
|
|
89
|
+
case 'session':
|
|
90
|
+
this.handleSession(msg);
|
|
91
|
+
break;
|
|
92
|
+
case 'ack':
|
|
93
|
+
if ('seq' in msg) {
|
|
94
|
+
this.cb.onCaptionAck(msg);
|
|
95
|
+
}
|
|
96
|
+
else if ('action' in msg) {
|
|
97
|
+
this.cb.onControlAck(msg);
|
|
98
|
+
}
|
|
99
|
+
break;
|
|
100
|
+
case 'error':
|
|
101
|
+
this.cb.onError(msg);
|
|
102
|
+
if (TERMINAL_CODES.has(msg.code)) {
|
|
103
|
+
this.intentionalClose = true;
|
|
104
|
+
}
|
|
105
|
+
break;
|
|
106
|
+
case 'event_ended':
|
|
107
|
+
this.cb.onEventEnded(msg.eventId);
|
|
108
|
+
this.intentionalClose = true;
|
|
109
|
+
break;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
handleSession(msg) {
|
|
113
|
+
switch (msg.action) {
|
|
114
|
+
case SESSION_ACTION.SLOT_GRANTED:
|
|
115
|
+
this.setSlotStatus('active');
|
|
116
|
+
break;
|
|
117
|
+
case SESSION_ACTION.SLOT_OCCUPIED:
|
|
118
|
+
this.setSlotStatus('waiting', {
|
|
119
|
+
position: msg.position,
|
|
120
|
+
activeSince: msg.activeSince,
|
|
121
|
+
});
|
|
122
|
+
break;
|
|
123
|
+
case SESSION_ACTION.SLOT_REQUESTED:
|
|
124
|
+
case SESSION_ACTION.SLOT_REQUEST_CANCELLED:
|
|
125
|
+
this.cb.onWaitingCountChange(msg.waitingCount);
|
|
126
|
+
break;
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
handleClose(event) {
|
|
130
|
+
this.ws = null;
|
|
131
|
+
if (this.intentionalClose || TERMINAL_CLOSE_CODES.has(event.code)) {
|
|
132
|
+
this.setStatus('disconnected');
|
|
133
|
+
this.setSlotStatus('unknown');
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
// Attempt reconnection
|
|
137
|
+
this.setStatus('reconnecting');
|
|
138
|
+
this.scheduleReconnect();
|
|
139
|
+
}
|
|
140
|
+
scheduleReconnect() {
|
|
141
|
+
this.clearReconnectTimer();
|
|
142
|
+
this.reconnectTimer = setTimeout(async () => {
|
|
143
|
+
try {
|
|
144
|
+
const newTicket = await this.cb.refreshTicket();
|
|
145
|
+
this.ticket = newTicket.ticket;
|
|
146
|
+
this.gatewayUrl = newTicket.gatewayUrl;
|
|
147
|
+
this.openSocket();
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
this.cb.onError({
|
|
151
|
+
type: 'error',
|
|
152
|
+
code: ERROR_CODE.NETWORK_ERROR,
|
|
153
|
+
message: 'Failed to refresh connection ticket',
|
|
154
|
+
});
|
|
155
|
+
this.reconnectDelay = Math.min(this.reconnectDelay * CONNECTION_DEFAULTS.RECONNECT_MULTIPLIER, CONNECTION_DEFAULTS.RECONNECT_DELAY_MAX_MS);
|
|
156
|
+
this.scheduleReconnect();
|
|
157
|
+
}
|
|
158
|
+
}, this.reconnectDelay);
|
|
159
|
+
}
|
|
160
|
+
clearReconnectTimer() {
|
|
161
|
+
if (this.reconnectTimer != null) {
|
|
162
|
+
clearTimeout(this.reconnectTimer);
|
|
163
|
+
this.reconnectTimer = null;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
setStatus(status) {
|
|
167
|
+
if (this._status !== status) {
|
|
168
|
+
this._status = status;
|
|
169
|
+
this.cb.onStatusChange(status);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
setSlotStatus(status, detail) {
|
|
173
|
+
const changed = this._slotStatus !== status;
|
|
174
|
+
this._slotStatus = status;
|
|
175
|
+
if (changed) {
|
|
176
|
+
this.cb.onSlotChange(status, detail);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=ws.js.map
|
package/dist/ws.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ws.js","sourceRoot":"","sources":["../src/ws.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@caitdesk/client",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Official TypeScript client for the CaitDesk captioner API",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": {
|
|
8
|
+
"types": "./dist/index.d.ts",
|
|
9
|
+
"default": "./dist/index.js"
|
|
10
|
+
}
|
|
11
|
+
},
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"files": ["dist", "README.md"],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsc",
|
|
17
|
+
"typecheck": "tsc --noEmit",
|
|
18
|
+
"prepublishOnly": "bun run build"
|
|
19
|
+
},
|
|
20
|
+
"devDependencies": {
|
|
21
|
+
"typescript": "^5.7.2"
|
|
22
|
+
}
|
|
23
|
+
}
|