@volley/recognition-client-sdk-node22 0.1.424
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 +344 -0
- package/dist/browser.bundled.d.ts +1280 -0
- package/dist/browser.d.ts +10 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/config-builder.d.ts +134 -0
- package/dist/config-builder.d.ts.map +1 -0
- package/dist/errors.d.ts +41 -0
- package/dist/errors.d.ts.map +1 -0
- package/dist/factory.d.ts +36 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/index.bundled.d.ts +2572 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10199 -0
- package/dist/index.js.map +7 -0
- package/dist/recog-client-sdk.browser.d.ts +10 -0
- package/dist/recog-client-sdk.browser.d.ts.map +1 -0
- package/dist/recog-client-sdk.browser.js +5746 -0
- package/dist/recog-client-sdk.browser.js.map +7 -0
- package/dist/recognition-client.d.ts +128 -0
- package/dist/recognition-client.d.ts.map +1 -0
- package/dist/recognition-client.types.d.ts +271 -0
- package/dist/recognition-client.types.d.ts.map +1 -0
- package/dist/simplified-vgf-recognition-client.d.ts +178 -0
- package/dist/simplified-vgf-recognition-client.d.ts.map +1 -0
- package/dist/utils/audio-ring-buffer.d.ts +69 -0
- package/dist/utils/audio-ring-buffer.d.ts.map +1 -0
- package/dist/utils/message-handler.d.ts +45 -0
- package/dist/utils/message-handler.d.ts.map +1 -0
- package/dist/utils/url-builder.d.ts +28 -0
- package/dist/utils/url-builder.d.ts.map +1 -0
- package/dist/vgf-recognition-mapper.d.ts +66 -0
- package/dist/vgf-recognition-mapper.d.ts.map +1 -0
- package/dist/vgf-recognition-state.d.ts +91 -0
- package/dist/vgf-recognition-state.d.ts.map +1 -0
- package/package.json +74 -0
- package/src/browser.ts +24 -0
- package/src/config-builder.spec.ts +265 -0
- package/src/config-builder.ts +240 -0
- package/src/errors.ts +84 -0
- package/src/factory.spec.ts +215 -0
- package/src/factory.ts +47 -0
- package/src/index.ts +127 -0
- package/src/recognition-client.spec.ts +889 -0
- package/src/recognition-client.ts +844 -0
- package/src/recognition-client.types.ts +338 -0
- package/src/simplified-vgf-recognition-client.integration.spec.ts +718 -0
- package/src/simplified-vgf-recognition-client.spec.ts +1525 -0
- package/src/simplified-vgf-recognition-client.ts +524 -0
- package/src/utils/audio-ring-buffer.spec.ts +335 -0
- package/src/utils/audio-ring-buffer.ts +170 -0
- package/src/utils/message-handler.spec.ts +311 -0
- package/src/utils/message-handler.ts +131 -0
- package/src/utils/url-builder.spec.ts +252 -0
- package/src/utils/url-builder.ts +92 -0
- package/src/vgf-recognition-mapper.spec.ts +78 -0
- package/src/vgf-recognition-mapper.ts +232 -0
- package/src/vgf-recognition-state.ts +102 -0
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration Builder for Recognition Client
|
|
3
|
+
*
|
|
4
|
+
* Simple builder pattern for RealTimeTwoWayWebSocketRecognitionClientConfig
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type {
|
|
8
|
+
RealTimeTwoWayWebSocketRecognitionClientConfig,
|
|
9
|
+
RecognitionCallbackUrl
|
|
10
|
+
} from './recognition-client.types.js';
|
|
11
|
+
import type {
|
|
12
|
+
ASRRequestConfig,
|
|
13
|
+
GameContextV1,
|
|
14
|
+
TranscriptionResultV1,
|
|
15
|
+
MetadataResultV1,
|
|
16
|
+
ErrorResultV1,
|
|
17
|
+
Stage
|
|
18
|
+
} from '@recog/shared-types';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Builder for RealTimeTwoWayWebSocketRecognitionClientConfig
|
|
22
|
+
*
|
|
23
|
+
* Provides a fluent API for building client configurations.
|
|
24
|
+
*
|
|
25
|
+
* Example:
|
|
26
|
+
* ```typescript
|
|
27
|
+
* import { STAGES } from '@recog/shared-types';
|
|
28
|
+
*
|
|
29
|
+
* const config = new ConfigBuilder()
|
|
30
|
+
* .stage(STAGES.STAGING) // Recommended: automatic environment selection
|
|
31
|
+
* .asrRequestConfig({
|
|
32
|
+
* provider: RecognitionProvider.DEEPGRAM,
|
|
33
|
+
* model: 'nova-2-general'
|
|
34
|
+
* })
|
|
35
|
+
* .onTranscript((result) => console.log(result))
|
|
36
|
+
* .build();
|
|
37
|
+
* ```
|
|
38
|
+
*/
|
|
39
|
+
export class ConfigBuilder {
|
|
40
|
+
private config: Partial<RealTimeTwoWayWebSocketRecognitionClientConfig> = {};
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Set the WebSocket URL (advanced usage)
|
|
44
|
+
* For standard environments, use stage() instead
|
|
45
|
+
*/
|
|
46
|
+
url(url: string): this {
|
|
47
|
+
this.config.url = url;
|
|
48
|
+
return this;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Set the stage for automatic environment selection (recommended)
|
|
53
|
+
* @param stage - STAGES.LOCAL | STAGES.DEV | STAGES.STAGING | STAGES.PRODUCTION
|
|
54
|
+
* @example
|
|
55
|
+
* ```typescript
|
|
56
|
+
* import { STAGES } from '@recog/shared-types';
|
|
57
|
+
* builder.stage(STAGES.STAGING)
|
|
58
|
+
* ```
|
|
59
|
+
*/
|
|
60
|
+
stage(stage: Stage | string): this {
|
|
61
|
+
this.config.stage = stage;
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Set ASR request configuration
|
|
67
|
+
*/
|
|
68
|
+
asrRequestConfig(config: ASRRequestConfig): this {
|
|
69
|
+
this.config.asrRequestConfig = config;
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Set game context
|
|
75
|
+
*/
|
|
76
|
+
gameContext(context: GameContextV1): this {
|
|
77
|
+
this.config.gameContext = context;
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Set game ID directly (takes precedence over gameContext.gameId)
|
|
83
|
+
* Use this when you only need to identify the game without full context.
|
|
84
|
+
*/
|
|
85
|
+
gameId(id: string): this {
|
|
86
|
+
this.config.gameId = id;
|
|
87
|
+
return this;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Set audio utterance ID
|
|
92
|
+
*/
|
|
93
|
+
audioUtteranceId(id: string): this {
|
|
94
|
+
this.config.audioUtteranceId = id;
|
|
95
|
+
return this;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Set callback URLs
|
|
100
|
+
*/
|
|
101
|
+
callbackUrls(urls: RecognitionCallbackUrl[]): this {
|
|
102
|
+
this.config.callbackUrls = urls;
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Set user ID
|
|
108
|
+
*/
|
|
109
|
+
userId(id: string): this {
|
|
110
|
+
this.config.userId = id;
|
|
111
|
+
return this;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Set game session ID
|
|
116
|
+
*/
|
|
117
|
+
gameSessionId(id: string): this {
|
|
118
|
+
this.config.gameSessionId = id;
|
|
119
|
+
return this;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Set device ID
|
|
124
|
+
*/
|
|
125
|
+
deviceId(id: string): this {
|
|
126
|
+
this.config.deviceId = id;
|
|
127
|
+
return this;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Set account ID
|
|
132
|
+
*/
|
|
133
|
+
accountId(id: string): this {
|
|
134
|
+
this.config.accountId = id;
|
|
135
|
+
return this;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Set question answer ID
|
|
140
|
+
*/
|
|
141
|
+
questionAnswerId(id: string): this {
|
|
142
|
+
this.config.questionAnswerId = id;
|
|
143
|
+
return this;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/**
|
|
147
|
+
* Set platform
|
|
148
|
+
*/
|
|
149
|
+
platform(platform: string): this {
|
|
150
|
+
this.config.platform = platform;
|
|
151
|
+
return this;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
* Set transcript callback
|
|
156
|
+
*/
|
|
157
|
+
onTranscript(callback: (result: TranscriptionResultV1) => void): this {
|
|
158
|
+
this.config.onTranscript = callback;
|
|
159
|
+
return this;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Set metadata callback
|
|
164
|
+
*/
|
|
165
|
+
onMetadata(callback: (metadata: MetadataResultV1) => void): this {
|
|
166
|
+
this.config.onMetadata = callback;
|
|
167
|
+
return this;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Set error callback
|
|
172
|
+
*/
|
|
173
|
+
onError(callback: (error: ErrorResultV1) => void): this {
|
|
174
|
+
this.config.onError = callback;
|
|
175
|
+
return this;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Set connected callback
|
|
180
|
+
*/
|
|
181
|
+
onConnected(callback: () => void): this {
|
|
182
|
+
this.config.onConnected = callback;
|
|
183
|
+
return this;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Set disconnected callback
|
|
188
|
+
*/
|
|
189
|
+
onDisconnected(callback: (code: number, reason: string) => void): this {
|
|
190
|
+
this.config.onDisconnected = callback;
|
|
191
|
+
return this;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
/**
|
|
195
|
+
* Set high water mark
|
|
196
|
+
*/
|
|
197
|
+
highWaterMark(bytes: number): this {
|
|
198
|
+
this.config.highWaterMark = bytes;
|
|
199
|
+
return this;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* Set low water mark
|
|
204
|
+
*/
|
|
205
|
+
lowWaterMark(bytes: number): this {
|
|
206
|
+
this.config.lowWaterMark = bytes;
|
|
207
|
+
return this;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Set max buffer duration in seconds
|
|
212
|
+
*/
|
|
213
|
+
maxBufferDurationSec(seconds: number): this {
|
|
214
|
+
this.config.maxBufferDurationSec = seconds;
|
|
215
|
+
return this;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Set chunks per second
|
|
220
|
+
*/
|
|
221
|
+
chunksPerSecond(chunks: number): this {
|
|
222
|
+
this.config.chunksPerSecond = chunks;
|
|
223
|
+
return this;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/**
|
|
227
|
+
* Set logger function
|
|
228
|
+
*/
|
|
229
|
+
logger(logger: (level: 'debug' | 'info' | 'warn' | 'error', message: string, data?: any) => void): this {
|
|
230
|
+
this.config.logger = logger;
|
|
231
|
+
return this;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Build the configuration
|
|
236
|
+
*/
|
|
237
|
+
build(): RealTimeTwoWayWebSocketRecognitionClientConfig {
|
|
238
|
+
return this.config as RealTimeTwoWayWebSocketRecognitionClientConfig;
|
|
239
|
+
}
|
|
240
|
+
}
|
package/src/errors.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SDK Error Classes
|
|
3
|
+
*
|
|
4
|
+
* Typed error classes that extend native Error with recognition-specific metadata
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { ErrorTypeV1 } from '@recog/shared-types';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Base class for all recognition SDK errors
|
|
11
|
+
*/
|
|
12
|
+
export class RecognitionError extends Error {
|
|
13
|
+
public readonly errorType: ErrorTypeV1;
|
|
14
|
+
public readonly timestamp: number;
|
|
15
|
+
|
|
16
|
+
constructor(errorType: ErrorTypeV1, message: string) {
|
|
17
|
+
super(message);
|
|
18
|
+
this.name = 'RecognitionError';
|
|
19
|
+
this.errorType = errorType;
|
|
20
|
+
this.timestamp = Date.now();
|
|
21
|
+
|
|
22
|
+
// Maintains proper stack trace for where error was thrown (only available on V8)
|
|
23
|
+
if (Error.captureStackTrace) {
|
|
24
|
+
Error.captureStackTrace(this, this.constructor);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Connection error - thrown when WebSocket connection fails after all retry attempts
|
|
31
|
+
*/
|
|
32
|
+
export class ConnectionError extends RecognitionError {
|
|
33
|
+
public readonly attempts: number;
|
|
34
|
+
public readonly url: string;
|
|
35
|
+
public readonly underlyingError?: Error;
|
|
36
|
+
|
|
37
|
+
constructor(message: string, attempts: number, url: string, underlyingError?: Error) {
|
|
38
|
+
super(ErrorTypeV1.CONNECTION_ERROR, message);
|
|
39
|
+
this.name = 'ConnectionError';
|
|
40
|
+
this.attempts = attempts;
|
|
41
|
+
this.url = url;
|
|
42
|
+
if (underlyingError !== undefined) {
|
|
43
|
+
this.underlyingError = underlyingError;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Timeout error - thrown when operations exceed timeout limits
|
|
50
|
+
*/
|
|
51
|
+
export class TimeoutError extends RecognitionError {
|
|
52
|
+
public readonly timeoutMs: number;
|
|
53
|
+
public readonly operation: string;
|
|
54
|
+
|
|
55
|
+
constructor(message: string, timeoutMs: number, operation: string) {
|
|
56
|
+
super(ErrorTypeV1.TIMEOUT_ERROR, message);
|
|
57
|
+
this.name = 'TimeoutError';
|
|
58
|
+
this.timeoutMs = timeoutMs;
|
|
59
|
+
this.operation = operation;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Validation error - thrown when invalid configuration or input is provided
|
|
65
|
+
*/
|
|
66
|
+
export class ValidationError extends RecognitionError {
|
|
67
|
+
public readonly field?: string;
|
|
68
|
+
public readonly expected?: string;
|
|
69
|
+
public readonly received?: string;
|
|
70
|
+
|
|
71
|
+
constructor(message: string, field?: string, expected?: string, received?: string) {
|
|
72
|
+
super(ErrorTypeV1.VALIDATION_ERROR, message);
|
|
73
|
+
this.name = 'ValidationError';
|
|
74
|
+
if (field !== undefined) {
|
|
75
|
+
this.field = field;
|
|
76
|
+
}
|
|
77
|
+
if (expected !== undefined) {
|
|
78
|
+
this.expected = expected;
|
|
79
|
+
}
|
|
80
|
+
if (received !== undefined) {
|
|
81
|
+
this.received = received;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unit tests for Factory functions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { createClient, createClientWithBuilder } from './factory.js';
|
|
6
|
+
import { ConfigBuilder } from './config-builder.js';
|
|
7
|
+
import { RecognitionProvider, RecognitionContextTypeV1 } from '@recog/shared-types';
|
|
8
|
+
|
|
9
|
+
// Mock the RealTimeTwoWayWebSocketRecognitionClient
|
|
10
|
+
jest.mock('./recognition-client.js', () => ({
|
|
11
|
+
RealTimeTwoWayWebSocketRecognitionClient: jest.fn().mockImplementation((config) => ({
|
|
12
|
+
config,
|
|
13
|
+
connect: jest.fn(),
|
|
14
|
+
disconnect: jest.fn(),
|
|
15
|
+
sendAudio: jest.fn(),
|
|
16
|
+
startRecognition: jest.fn(),
|
|
17
|
+
stopRecognition: jest.fn()
|
|
18
|
+
}))
|
|
19
|
+
}));
|
|
20
|
+
|
|
21
|
+
describe('Factory Functions', () => {
|
|
22
|
+
describe('createClient', () => {
|
|
23
|
+
it('should create client with config object', () => {
|
|
24
|
+
const config = {
|
|
25
|
+
url: 'ws://localhost:3101/ws/v1/recognize',
|
|
26
|
+
audioUtteranceId: 'test-id',
|
|
27
|
+
asrRequestConfig: {
|
|
28
|
+
provider: RecognitionProvider.DEEPGRAM,
|
|
29
|
+
model: 'nova-2-general',
|
|
30
|
+
language: 'en-US',
|
|
31
|
+
sampleRate: 16000,
|
|
32
|
+
encoding: 'linear16'
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
const client = createClient(config);
|
|
37
|
+
expect(client).toBeDefined();
|
|
38
|
+
expect(client.connect).toBeDefined();
|
|
39
|
+
expect(client.sendAudio).toBeDefined();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it('should create client with minimal config', () => {
|
|
43
|
+
const config = {
|
|
44
|
+
url: 'ws://localhost:3101/ws/v1/recognize',
|
|
45
|
+
audioUtteranceId: 'test-id'
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
const client = createClient(config);
|
|
49
|
+
expect(client).toBeDefined();
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('should create client with callbacks', () => {
|
|
53
|
+
const onTranscript = jest.fn();
|
|
54
|
+
const onError = jest.fn();
|
|
55
|
+
const onConnected = jest.fn();
|
|
56
|
+
|
|
57
|
+
const config = {
|
|
58
|
+
url: 'ws://localhost:3101/ws/v1/recognize',
|
|
59
|
+
audioUtteranceId: 'test-id',
|
|
60
|
+
onTranscript,
|
|
61
|
+
onError,
|
|
62
|
+
onConnected
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
const client = createClient(config);
|
|
66
|
+
expect(client).toBeDefined();
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
describe('createClientWithBuilder', () => {
|
|
71
|
+
it('should create client using builder pattern', () => {
|
|
72
|
+
const client = createClientWithBuilder((builder) =>
|
|
73
|
+
builder
|
|
74
|
+
.url('ws://localhost:3101/ws/v1/recognize')
|
|
75
|
+
.audioUtteranceId('test-id')
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
expect(client).toBeDefined();
|
|
79
|
+
expect(client.connect).toBeDefined();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
it('should create client with multiple builder methods', () => {
|
|
83
|
+
const onTranscript = jest.fn();
|
|
84
|
+
const onError = jest.fn();
|
|
85
|
+
|
|
86
|
+
const client = createClientWithBuilder((builder) =>
|
|
87
|
+
builder
|
|
88
|
+
.url('ws://localhost:3101/ws/v1/recognize')
|
|
89
|
+
.audioUtteranceId('test-id')
|
|
90
|
+
.userId('user-123')
|
|
91
|
+
.gameSessionId('session-456')
|
|
92
|
+
.onTranscript(onTranscript)
|
|
93
|
+
.onError(onError)
|
|
94
|
+
);
|
|
95
|
+
|
|
96
|
+
expect(client).toBeDefined();
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
it('should create client with ASR config via builder', () => {
|
|
100
|
+
const client = createClientWithBuilder((builder) =>
|
|
101
|
+
builder
|
|
102
|
+
.url('ws://localhost:3101/ws/v1/recognize')
|
|
103
|
+
.audioUtteranceId('test-id')
|
|
104
|
+
.asrRequestConfig({
|
|
105
|
+
provider: RecognitionProvider.DEEPGRAM,
|
|
106
|
+
model: 'nova-2-general',
|
|
107
|
+
language: 'en-US',
|
|
108
|
+
sampleRate: 16000,
|
|
109
|
+
encoding: 'linear16'
|
|
110
|
+
})
|
|
111
|
+
);
|
|
112
|
+
|
|
113
|
+
expect(client).toBeDefined();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should create client with game context via builder', () => {
|
|
117
|
+
const client = createClientWithBuilder((builder) =>
|
|
118
|
+
builder
|
|
119
|
+
.url('ws://localhost:3101/ws/v1/recognize')
|
|
120
|
+
.audioUtteranceId('test-id')
|
|
121
|
+
.gameContext({
|
|
122
|
+
type: RecognitionContextTypeV1.GAME_CONTEXT as const,
|
|
123
|
+
gameId: 'test-game',
|
|
124
|
+
gamePhase: 'test-phase'
|
|
125
|
+
})
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
expect(client).toBeDefined();
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
it('should create client with all optional fields via builder', () => {
|
|
132
|
+
const onTranscript = jest.fn();
|
|
133
|
+
const onMetadata = jest.fn();
|
|
134
|
+
const onError = jest.fn();
|
|
135
|
+
const onConnected = jest.fn();
|
|
136
|
+
const onDisconnected = jest.fn();
|
|
137
|
+
const logger = jest.fn();
|
|
138
|
+
|
|
139
|
+
const client = createClientWithBuilder((builder) =>
|
|
140
|
+
builder
|
|
141
|
+
.url('ws://localhost:3101/ws/v1/recognize')
|
|
142
|
+
.audioUtteranceId('test-id')
|
|
143
|
+
.userId('user-123')
|
|
144
|
+
.gameSessionId('session-456')
|
|
145
|
+
.deviceId('device-789')
|
|
146
|
+
.accountId('account-abc')
|
|
147
|
+
.questionAnswerId('qa-xyz')
|
|
148
|
+
.platform('ios')
|
|
149
|
+
.asrRequestConfig({
|
|
150
|
+
provider: RecognitionProvider.DEEPGRAM,
|
|
151
|
+
model: 'nova-2-general',
|
|
152
|
+
language: 'en-US',
|
|
153
|
+
sampleRate: 16000,
|
|
154
|
+
encoding: 'linear16'
|
|
155
|
+
})
|
|
156
|
+
.gameContext({
|
|
157
|
+
type: RecognitionContextTypeV1.GAME_CONTEXT as const,
|
|
158
|
+
gameId: 'test-game',
|
|
159
|
+
gamePhase: 'test-phase'
|
|
160
|
+
})
|
|
161
|
+
.onTranscript(onTranscript)
|
|
162
|
+
.onMetadata(onMetadata)
|
|
163
|
+
.onError(onError)
|
|
164
|
+
.onConnected(onConnected)
|
|
165
|
+
.onDisconnected(onDisconnected)
|
|
166
|
+
.highWaterMark(1000)
|
|
167
|
+
.lowWaterMark(500)
|
|
168
|
+
.maxBufferDurationSec(10)
|
|
169
|
+
.chunksPerSecond(50)
|
|
170
|
+
.logger(logger)
|
|
171
|
+
);
|
|
172
|
+
|
|
173
|
+
expect(client).toBeDefined();
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('should accept builder as parameter', () => {
|
|
177
|
+
const builder = new ConfigBuilder();
|
|
178
|
+
const client = createClientWithBuilder((b) => b.url('ws://localhost:3101').audioUtteranceId('test-id'));
|
|
179
|
+
expect(client).toBeDefined();
|
|
180
|
+
});
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
describe('Factory Function Equivalence', () => {
|
|
184
|
+
it('should produce equivalent clients from config and builder', () => {
|
|
185
|
+
const config = {
|
|
186
|
+
url: 'ws://localhost:3101/ws/v1/recognize',
|
|
187
|
+
audioUtteranceId: 'test-id',
|
|
188
|
+
userId: 'user-123'
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
const clientFromConfig = createClient(config);
|
|
192
|
+
const clientFromBuilder = createClientWithBuilder((builder) =>
|
|
193
|
+
builder
|
|
194
|
+
.url('ws://localhost:3101/ws/v1/recognize')
|
|
195
|
+
.audioUtteranceId('test-id')
|
|
196
|
+
.userId('user-123')
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
expect(clientFromConfig).toBeDefined();
|
|
200
|
+
expect(clientFromBuilder).toBeDefined();
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
it('should handle empty config gracefully', () => {
|
|
204
|
+
const config = {
|
|
205
|
+
url: 'ws://localhost:3101/ws/v1/recognize',
|
|
206
|
+
audioUtteranceId: 'test-id'
|
|
207
|
+
};
|
|
208
|
+
|
|
209
|
+
const client = createClient(config);
|
|
210
|
+
expect(client).toBeDefined();
|
|
211
|
+
expect(typeof client.connect).toBe('function');
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
});
|
|
215
|
+
});
|
package/src/factory.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Factory function for creating Recognition Client instances
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { RealTimeTwoWayWebSocketRecognitionClient } from './recognition-client.js';
|
|
6
|
+
import { ConfigBuilder } from './config-builder.js';
|
|
7
|
+
import type { IRecognitionClient, RealTimeTwoWayWebSocketRecognitionClientConfig } from './recognition-client.types.js';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Create a recognition client from a configuration object
|
|
11
|
+
*
|
|
12
|
+
* Example:
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const client = createClient({
|
|
15
|
+
* url: 'ws://localhost:3101/ws/v1/recognize',
|
|
16
|
+
* audioUtteranceId: 'unique-id',
|
|
17
|
+
* onTranscript: (result) => console.log(result)
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*
|
|
21
|
+
* @param config - Client configuration
|
|
22
|
+
* @returns Configured recognition client instance
|
|
23
|
+
*/
|
|
24
|
+
export function createClient(config: RealTimeTwoWayWebSocketRecognitionClientConfig): IRecognitionClient {
|
|
25
|
+
return new RealTimeTwoWayWebSocketRecognitionClient(config);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Create a recognition client using the builder pattern
|
|
30
|
+
*
|
|
31
|
+
* Example:
|
|
32
|
+
* ```typescript
|
|
33
|
+
* const client = createClientWithBuilder((builder) =>
|
|
34
|
+
* builder
|
|
35
|
+
* .url('ws://localhost:3101/ws/v1/recognize')
|
|
36
|
+
* .onTranscript((result) => console.log(result))
|
|
37
|
+
* .onError((error) => console.error(error))
|
|
38
|
+
* );
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export function createClientWithBuilder(
|
|
42
|
+
configure: (builder: ConfigBuilder) => ConfigBuilder
|
|
43
|
+
): IRecognitionClient {
|
|
44
|
+
const builder = new ConfigBuilder();
|
|
45
|
+
const config = configure(builder).build();
|
|
46
|
+
return new RealTimeTwoWayWebSocketRecognitionClient(config);
|
|
47
|
+
}
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Export RealTimeTwoWayWebSocketRecognitionClient (primary SDK)
|
|
2
|
+
export {
|
|
3
|
+
RealTimeTwoWayWebSocketRecognitionClient,
|
|
4
|
+
type RealTimeTwoWayWebSocketRecognitionClientConfig,
|
|
5
|
+
type TranscriptionResult,
|
|
6
|
+
isNormalDisconnection
|
|
7
|
+
} from './recognition-client.js';
|
|
8
|
+
|
|
9
|
+
// Export interfaces for dependency injection and testing
|
|
10
|
+
export {
|
|
11
|
+
type IRecognitionClient,
|
|
12
|
+
type IRecognitionClientConfig,
|
|
13
|
+
type IRecognitionClientStats,
|
|
14
|
+
type RecognitionCallbackUrl,
|
|
15
|
+
ClientState
|
|
16
|
+
} from './recognition-client.types.js';
|
|
17
|
+
|
|
18
|
+
// Export configuration builder
|
|
19
|
+
export { ConfigBuilder } from './config-builder.js';
|
|
20
|
+
|
|
21
|
+
// Export factory functions
|
|
22
|
+
export { createClient, createClientWithBuilder } from './factory.js';
|
|
23
|
+
|
|
24
|
+
// Export error classes
|
|
25
|
+
export {
|
|
26
|
+
RecognitionError,
|
|
27
|
+
ConnectionError,
|
|
28
|
+
TimeoutError,
|
|
29
|
+
ValidationError
|
|
30
|
+
} from './errors.js';
|
|
31
|
+
|
|
32
|
+
// Export error types from shared-types
|
|
33
|
+
export { ErrorTypeV1 } from '@recog/shared-types';
|
|
34
|
+
|
|
35
|
+
// Export error exception types for advanced error handling
|
|
36
|
+
export type {
|
|
37
|
+
RecognitionException,
|
|
38
|
+
ConnectionException,
|
|
39
|
+
TimeoutException,
|
|
40
|
+
ValidationException,
|
|
41
|
+
AuthenticationException,
|
|
42
|
+
ProviderException,
|
|
43
|
+
QuotaExceededException,
|
|
44
|
+
UnknownException
|
|
45
|
+
} from '@recog/shared-types';
|
|
46
|
+
|
|
47
|
+
// Export error helper functions
|
|
48
|
+
export {
|
|
49
|
+
isExceptionImmediatelyAvailable,
|
|
50
|
+
getUserFriendlyMessage
|
|
51
|
+
} from '@recog/shared-types';
|
|
52
|
+
|
|
53
|
+
// Export VGF state management (new simplified interface)
|
|
54
|
+
export {
|
|
55
|
+
SimplifiedVGFRecognitionClient,
|
|
56
|
+
createSimplifiedVGFClient,
|
|
57
|
+
type ISimplifiedVGFRecognitionClient,
|
|
58
|
+
type SimplifiedVGFClientConfig
|
|
59
|
+
} from './simplified-vgf-recognition-client.js';
|
|
60
|
+
|
|
61
|
+
export {
|
|
62
|
+
type RecognitionState,
|
|
63
|
+
RecognitionVGFStateSchema,
|
|
64
|
+
RecordingStatus,
|
|
65
|
+
TranscriptionStatus,
|
|
66
|
+
type RecordingStatusType,
|
|
67
|
+
type TranscriptionStatusType,
|
|
68
|
+
createInitialRecognitionState,
|
|
69
|
+
isValidRecordingStatusTransition
|
|
70
|
+
} from './vgf-recognition-state.js';
|
|
71
|
+
|
|
72
|
+
export { resetRecognitionVGFState } from './vgf-recognition-mapper.js';
|
|
73
|
+
|
|
74
|
+
// Re-export WebSocket protocol types for advanced usage
|
|
75
|
+
export { AudioEncoding } from '@recog/websocket';
|
|
76
|
+
|
|
77
|
+
// Re-export necessary types from shared-types
|
|
78
|
+
export {
|
|
79
|
+
// Recognition context types
|
|
80
|
+
type GameContextV1,
|
|
81
|
+
type SlotMap,
|
|
82
|
+
RecognitionContextTypeV1,
|
|
83
|
+
ControlSignalTypeV1,
|
|
84
|
+
ControlSignalTypeV1 as ControlSignal, // Alias for backward compatibility
|
|
85
|
+
|
|
86
|
+
// Result types
|
|
87
|
+
type TranscriptionResultV1,
|
|
88
|
+
type FunctionCallResultV1,
|
|
89
|
+
type MetadataResultV1,
|
|
90
|
+
type ErrorResultV1,
|
|
91
|
+
RecognitionResultTypeV1,
|
|
92
|
+
ClientControlActionV1,
|
|
93
|
+
|
|
94
|
+
// ASR configuration types
|
|
95
|
+
type ASRRequestConfig,
|
|
96
|
+
type ASRRequestV1,
|
|
97
|
+
FinalTranscriptStability,
|
|
98
|
+
createDefaultASRConfig,
|
|
99
|
+
RecognitionProvider,
|
|
100
|
+
DeepgramModel,
|
|
101
|
+
ElevenLabsModel,
|
|
102
|
+
FireworksModel,
|
|
103
|
+
GoogleModel,
|
|
104
|
+
GeminiModel,
|
|
105
|
+
OpenAIModel,
|
|
106
|
+
Language,
|
|
107
|
+
SampleRate,
|
|
108
|
+
|
|
109
|
+
// Stage/Environment types
|
|
110
|
+
STAGES,
|
|
111
|
+
type Stage
|
|
112
|
+
} from '@recog/shared-types';
|
|
113
|
+
|
|
114
|
+
// Re-export shared config helpers so consumers don't depend on internal package
|
|
115
|
+
export {
|
|
116
|
+
getRecognitionServiceBase,
|
|
117
|
+
getRecognitionServiceHttpBase,
|
|
118
|
+
getRecognitionServiceWsBase,
|
|
119
|
+
getRecognitionServiceHost,
|
|
120
|
+
getRecognitionConductorBase,
|
|
121
|
+
getRecognitionConductorHttpBase,
|
|
122
|
+
getRecognitionConductorWsBase,
|
|
123
|
+
getRecognitionConductorHost,
|
|
124
|
+
normalizeStage,
|
|
125
|
+
RECOGNITION_SERVICE_BASES,
|
|
126
|
+
RECOGNITION_CONDUCTOR_BASES
|
|
127
|
+
} from '@recog/shared-config';
|