med-scribe-alliance-ts-sdk 1.0.1
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 +382 -0
- package/dist/api/base.d.ts +43 -0
- package/dist/api/base.d.ts.map +1 -0
- package/dist/api/base.js +115 -0
- package/dist/api/discovery.d.ts +30 -0
- package/dist/api/discovery.d.ts.map +1 -0
- package/dist/api/discovery.js +52 -0
- package/dist/api/session.d.ts +60 -0
- package/dist/api/session.d.ts.map +1 -0
- package/dist/api/session.js +94 -0
- package/dist/audio/audio-buffer-manager.d.ts +53 -0
- package/dist/audio/audio-buffer-manager.d.ts.map +1 -0
- package/dist/audio/audio-buffer-manager.js +109 -0
- package/dist/audio/audio-file-manager.d.ts +48 -0
- package/dist/audio/audio-file-manager.d.ts.map +1 -0
- package/dist/audio/audio-file-manager.js +174 -0
- package/dist/audio/chunked-recorder.d.ts +22 -0
- package/dist/audio/chunked-recorder.d.ts.map +1 -0
- package/dist/audio/chunked-recorder.js +84 -0
- package/dist/audio/constants.d.ts +19 -0
- package/dist/audio/constants.d.ts.map +1 -0
- package/dist/audio/constants.js +22 -0
- package/dist/audio/index.d.ts +10 -0
- package/dist/audio/index.d.ts.map +1 -0
- package/dist/audio/index.js +9 -0
- package/dist/audio/recorder.interface.d.ts +14 -0
- package/dist/audio/recorder.interface.d.ts.map +1 -0
- package/dist/audio/recorder.interface.js +1 -0
- package/dist/audio/single-recorder.d.ts +23 -0
- package/dist/audio/single-recorder.d.ts.map +1 -0
- package/dist/audio/single-recorder.js +93 -0
- package/dist/audio/types.d.ts +37 -0
- package/dist/audio/types.d.ts.map +1 -0
- package/dist/audio/types.js +1 -0
- package/dist/audio/utils.d.ts +2 -0
- package/dist/audio/utils.d.ts.map +1 -0
- package/dist/audio/utils.js +32 -0
- package/dist/audio/vad-web.d.ts +61 -0
- package/dist/audio/vad-web.d.ts.map +1 -0
- package/dist/audio/vad-web.js +285 -0
- package/dist/client.d.ts +106 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +338 -0
- package/dist/constants.d.ts +78 -0
- package/dist/constants.d.ts.map +1 -0
- package/dist/constants.js +88 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/schemas/openapi-schemas.json +405 -0
- package/dist/types/index.d.ts +167 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/utils/errors.d.ts +35 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +59 -0
- package/dist/utils/events.d.ts +9 -0
- package/dist/utils/events.d.ts.map +1 -0
- package/dist/utils/events.js +27 -0
- package/dist/utils/upload.d.ts +27 -0
- package/dist/utils/upload.d.ts.map +1 -0
- package/dist/utils/upload.js +73 -0
- package/dist/utils/validator.d.ts +34 -0
- package/dist/utils/validator.d.ts.map +1 -0
- package/dist/utils/validator.js +101 -0
- package/package.json +40 -0
package/README.md
ADDED
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
|
|
2
|
+
# Scribe EMR Protocol SDK
|
|
3
|
+
|
|
4
|
+
A TypeScript SDK for the [MedScribe Alliance Protocol](https://github.com/MedScribeAlliance/scribe-emr-protocol), providing a clean and type-safe interface for medical transcription services.
|
|
5
|
+
|
|
6
|
+
## Features
|
|
7
|
+
|
|
8
|
+
- ✅ **Protocol Compliant**: Fully implements the MedScribe Alliance Protocol specification
|
|
9
|
+
- ✅ **Type-Safe**: Complete TypeScript definitions for all API interactions
|
|
10
|
+
- ✅ **Auto-Discovery**: Automatic service capability discovery via well-known endpoint
|
|
11
|
+
- ✅ **Schema Validation**: AJV-powered validation against OpenAPI schemas
|
|
12
|
+
- ✅ **Error Handling**: Comprehensive error handling with typed error codes
|
|
13
|
+
- ✅ **Event System**: Built-in event emitter for session lifecycle events
|
|
14
|
+
- ✅ **Polling Support**: Automatic polling for session completion
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install scribe-standard-sdk
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Quick Start
|
|
23
|
+
|
|
24
|
+
```typescript
|
|
25
|
+
import { ScribeClient } from 'scribe-standard-sdk';
|
|
26
|
+
|
|
27
|
+
// Initialize the SDK
|
|
28
|
+
const client = new ScribeClient({
|
|
29
|
+
apiKey: 'your-api-key',
|
|
30
|
+
baseUrl: 'https://api.scribe.example.com',
|
|
31
|
+
debug: true, // Optional: enable debug logging
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
// Initialize (performs discovery)
|
|
35
|
+
await client.init();
|
|
36
|
+
|
|
37
|
+
// Start a recording session
|
|
38
|
+
const session = await client.startRecording({
|
|
39
|
+
templates: ['soap', 'medications'],
|
|
40
|
+
languageHint: ['en'],
|
|
41
|
+
model: 'pro',
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
console.log('Session created:', session.session_id);
|
|
45
|
+
console.log('Upload audio to:', session.upload_url);
|
|
46
|
+
|
|
47
|
+
// ... Upload audio chunks to session.upload_url ...
|
|
48
|
+
|
|
49
|
+
// End the recording session
|
|
50
|
+
const endResponse = await client.endRecording();
|
|
51
|
+
console.log('Session ended, processing started');
|
|
52
|
+
|
|
53
|
+
// Poll for completion
|
|
54
|
+
const result = await client.pollForCompletion(session.session_id, {
|
|
55
|
+
maxAttempts: 60,
|
|
56
|
+
intervalMs: 2000,
|
|
57
|
+
onProgress: (status) => {
|
|
58
|
+
console.log('Status:', status.status);
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Access the results
|
|
63
|
+
if (result.status === 'completed') {
|
|
64
|
+
console.log('Transcript:', result.transcript);
|
|
65
|
+
console.log('Templates:', result.templates);
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Core API
|
|
70
|
+
|
|
71
|
+
### ScribeClient
|
|
72
|
+
|
|
73
|
+
The main SDK client class.
|
|
74
|
+
|
|
75
|
+
#### Constructor
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
new ScribeClient(config: ScribeSDKConfig)
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**Config Options:**
|
|
82
|
+
- `apiKey` (required): Your API key for authentication
|
|
83
|
+
- `baseUrl` (optional): Base URL of the Scribe service
|
|
84
|
+
- `debug` (optional): Enable debug logging (default: `false`)
|
|
85
|
+
- `autoDiscovery` (optional): Auto-fetch service capabilities (default: `true`)
|
|
86
|
+
|
|
87
|
+
#### Methods
|
|
88
|
+
|
|
89
|
+
##### `init(): Promise<void>`
|
|
90
|
+
|
|
91
|
+
Initialize the SDK and perform service discovery.
|
|
92
|
+
|
|
93
|
+
```typescript
|
|
94
|
+
await client.init();
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
##### `startRecording(options: RecordingOptions): Promise<CreateSessionResponse>`
|
|
98
|
+
|
|
99
|
+
Start a new recording session.
|
|
100
|
+
|
|
101
|
+
**Options:**
|
|
102
|
+
- `templates` (required): Array of template IDs to extract (e.g., `['soap', 'medications']`)
|
|
103
|
+
- `model` (optional): Model ID from discovery
|
|
104
|
+
- `languageHint` (optional): Array of ISO 639-1 language codes for audio input (e.g., `['en', 'es']`)
|
|
105
|
+
- `transcriptLanguage` (optional): Array of ISO 639-1 codes for transcript output (e.g., `['en']`)
|
|
106
|
+
- `uploadType` (optional): `'chunked'` or `'single'`
|
|
107
|
+
- `communicationProtocol` (optional): `'http'`, `'websocket'`, or `'rpc'` (default: `'http'`)
|
|
108
|
+
- `additionalData` (optional): Pass-through data for your application
|
|
109
|
+
|
|
110
|
+
**Returns:**
|
|
111
|
+
- `session_id`: Unique session identifier
|
|
112
|
+
- `status`: Session status (`'created'`)
|
|
113
|
+
- `created_at`: ISO 8601 timestamp
|
|
114
|
+
- `expires_at`: ISO 8601 expiry timestamp
|
|
115
|
+
- `upload_url`: URL for uploading audio
|
|
116
|
+
|
|
117
|
+
```typescript
|
|
118
|
+
const session = await client.startRecording({
|
|
119
|
+
templates: ['soap'],
|
|
120
|
+
languageHint: ['en'],
|
|
121
|
+
transcriptLanguage: ['en'],
|
|
122
|
+
additionalData: {
|
|
123
|
+
patient_id: 'pat_123',
|
|
124
|
+
encounter_id: 'enc_456',
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
##### `endRecording(): Promise<EndSessionResponse>`
|
|
130
|
+
|
|
131
|
+
End the current recording session and trigger processing.
|
|
132
|
+
|
|
133
|
+
```typescript
|
|
134
|
+
const response = await client.endRecording();
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
##### `getOutputStatus(sessionId?: string): Promise<GetSessionStatusResponse>`
|
|
138
|
+
|
|
139
|
+
Get the current status and results of a session.
|
|
140
|
+
|
|
141
|
+
```typescript
|
|
142
|
+
const status = await client.getOutputStatus(session.session_id);
|
|
143
|
+
|
|
144
|
+
if (status.status === 'completed') {
|
|
145
|
+
console.log('Transcript:', status.transcript);
|
|
146
|
+
console.log('Templates:', status.templates);
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
**Session Status Values:**
|
|
151
|
+
- `created`: Session created, awaiting audio
|
|
152
|
+
- `processing`: Audio is being processed
|
|
153
|
+
- `completed`: Processing complete, all templates successful
|
|
154
|
+
- `partial`: Processing complete, some templates failed
|
|
155
|
+
- `failed`: Processing failed completely
|
|
156
|
+
|
|
157
|
+
##### `pollForCompletion(sessionId?, options?): Promise<GetSessionStatusResponse>`
|
|
158
|
+
|
|
159
|
+
Poll for session completion with automatic retries.
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
const result = await client.pollForCompletion(session.session_id, {
|
|
163
|
+
maxAttempts: 60, // Maximum polling attempts
|
|
164
|
+
intervalMs: 2000, // Interval between polls (ms)
|
|
165
|
+
onProgress: (status) => {
|
|
166
|
+
console.log('Current status:', status.status);
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
##### `getCurrentSession(): CreateSessionResponse | null`
|
|
172
|
+
|
|
173
|
+
Get the current active session.
|
|
174
|
+
|
|
175
|
+
```typescript
|
|
176
|
+
const currentSession = client.getCurrentSession();
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
##### `getDiscoveryDocument(): DiscoveryDocument | null`
|
|
180
|
+
|
|
181
|
+
Get the cached discovery document.
|
|
182
|
+
|
|
183
|
+
```typescript
|
|
184
|
+
const discovery = client.getDiscoveryDocument();
|
|
185
|
+
console.log('Supported models:', discovery?.models);
|
|
186
|
+
console.log('Supported languages:', discovery?.languages.supported);
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## Event System
|
|
190
|
+
|
|
191
|
+
The SDK emits events for session lifecycle tracking.
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
client.on('discovery:complete', (event) => {
|
|
195
|
+
console.log('Discovery complete:', event.data);
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
client.on('session:created', (event) => {
|
|
199
|
+
console.log('Session created:', event.data);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
client.on('session:ended', (event) => {
|
|
203
|
+
console.log('Session ended:', event.data);
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
client.on('session:status_update', (event) => {
|
|
207
|
+
console.log('Status update:', event.data);
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
client.on('error', (event) => {
|
|
211
|
+
console.error('Error:', event.error);
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Schema Validation
|
|
216
|
+
|
|
217
|
+
The SDK automatically validates all API requests against the OpenAPI schema using AJV. This ensures that:
|
|
218
|
+
|
|
219
|
+
- Request bodies conform to the expected structure
|
|
220
|
+
- Required fields are present
|
|
221
|
+
- Field types match the specification
|
|
222
|
+
- Session IDs follow the correct pattern (`ses_[a-zA-Z0-9]+`)
|
|
223
|
+
- Enum values are valid (e.g., `model`, `upload_type`, `communication_protocol`)
|
|
224
|
+
|
|
225
|
+
Validation happens automatically before any API call:
|
|
226
|
+
|
|
227
|
+
```typescript
|
|
228
|
+
// This will throw a ValidationError if the request is invalid
|
|
229
|
+
try {
|
|
230
|
+
const session = await client.startRecording({
|
|
231
|
+
templates: ['soap', 'medications'],
|
|
232
|
+
model: 'invalid-model', // ❌ Will fail validation if not in enum
|
|
233
|
+
uploadType: 'chunked',
|
|
234
|
+
});
|
|
235
|
+
} catch (error) {
|
|
236
|
+
if (error instanceof ValidationError) {
|
|
237
|
+
console.error('Validation failed:', error.message);
|
|
238
|
+
// Example: "Validation failed for CreateSessionRequest:
|
|
239
|
+
// - /model: must be equal to one of the allowed values (allowed values: pro, lite)"
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
**Validated Operations:**
|
|
245
|
+
- `createSession()`: Validates request body against `CreateSessionRequest` schema
|
|
246
|
+
- `getSessionStatus()`: Validates session ID format
|
|
247
|
+
- `endSession()`: Validates session ID format
|
|
248
|
+
- `pollSessionStatus()`: Validates session ID format
|
|
249
|
+
|
|
250
|
+
You can also use the validator directly for custom validation:
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
import { schemaValidator } from 'scribe-standard-sdk/utils/validator';
|
|
254
|
+
|
|
255
|
+
// Validate a session ID
|
|
256
|
+
try {
|
|
257
|
+
schemaValidator.validateSessionId('ses_abc123');
|
|
258
|
+
} catch (error) {
|
|
259
|
+
console.error('Invalid session ID:', error.message);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
// Validate a create session request
|
|
263
|
+
try {
|
|
264
|
+
schemaValidator.validateCreateSessionRequest({
|
|
265
|
+
templates: ['soap'],
|
|
266
|
+
upload_type: 'chunked',
|
|
267
|
+
communication_protocol: 'http',
|
|
268
|
+
});
|
|
269
|
+
} catch (error) {
|
|
270
|
+
console.error('Invalid request:', error.message);
|
|
271
|
+
}
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
## Error Handling
|
|
275
|
+
|
|
276
|
+
The SDK provides typed error classes for different error scenarios:
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
import {
|
|
280
|
+
ScribeError,
|
|
281
|
+
AuthenticationError,
|
|
282
|
+
SessionNotFoundError,
|
|
283
|
+
SessionExpiredError,
|
|
284
|
+
RateLimitError,
|
|
285
|
+
ValidationError,
|
|
286
|
+
} from 'scribe-standard-sdk';
|
|
287
|
+
|
|
288
|
+
try {
|
|
289
|
+
await client.startRecording({ templates: ['soap'] });
|
|
290
|
+
} catch (error) {
|
|
291
|
+
if (error instanceof ValidationError) {
|
|
292
|
+
console.error('Validation error:', error.message);
|
|
293
|
+
} else if (error instanceof AuthenticationError) {
|
|
294
|
+
console.error('Authentication failed:', error.message);
|
|
295
|
+
} else if (error instanceof SessionExpiredError) {
|
|
296
|
+
console.error('Session expired:', error.details);
|
|
297
|
+
} else if (error instanceof RateLimitError) {
|
|
298
|
+
console.error('Rate limited, retry after:', error.details?.retry_after_seconds);
|
|
299
|
+
} else if (error instanceof ScribeError) {
|
|
300
|
+
console.error('Scribe error:', error.code, error.message);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
## Template Output
|
|
306
|
+
|
|
307
|
+
When a session completes, the `templates` field contains the extracted data:
|
|
308
|
+
|
|
309
|
+
```typescript
|
|
310
|
+
const status = await client.getOutputStatus(sessionId);
|
|
311
|
+
|
|
312
|
+
if (status.templates) {
|
|
313
|
+
// Check SOAP template
|
|
314
|
+
const soap = status.templates['soap'];
|
|
315
|
+
if (soap.status === 'success') {
|
|
316
|
+
console.log('SOAP Note:', soap.data);
|
|
317
|
+
} else {
|
|
318
|
+
console.error('SOAP extraction failed:', soap.error);
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
// Check medications template
|
|
322
|
+
const meds = status.templates['medications'];
|
|
323
|
+
if (meds.status === 'success') {
|
|
324
|
+
console.log('Medications:', meds.data);
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## Discovery Document
|
|
330
|
+
|
|
331
|
+
The discovery document provides service capabilities:
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
const discovery = client.getDiscoveryDocument();
|
|
335
|
+
|
|
336
|
+
// Check supported audio formats
|
|
337
|
+
console.log('Audio formats:', discovery.capabilities.audio_formats);
|
|
338
|
+
|
|
339
|
+
// Check max chunk duration
|
|
340
|
+
console.log('Max chunk duration:', discovery.capabilities.max_chunk_duration_seconds);
|
|
341
|
+
|
|
342
|
+
// Check available models
|
|
343
|
+
discovery.models.forEach((model) => {
|
|
344
|
+
console.log(`Model: ${model.id}`);
|
|
345
|
+
console.log(` Languages: ${model.languages.join(', ')}`);
|
|
346
|
+
console.log(` Max duration: ${model.max_session_duration_seconds}s`);
|
|
347
|
+
console.log(` Features:`, model.features);
|
|
348
|
+
});
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
## TypeScript Support
|
|
352
|
+
|
|
353
|
+
The SDK is written in TypeScript and provides full type definitions:
|
|
354
|
+
|
|
355
|
+
```typescript
|
|
356
|
+
import type {
|
|
357
|
+
ScribeSDKConfig,
|
|
358
|
+
RecordingOptions,
|
|
359
|
+
CreateSessionResponse,
|
|
360
|
+
GetSessionStatusResponse,
|
|
361
|
+
TemplatesOutput,
|
|
362
|
+
DiscoveryDocument,
|
|
363
|
+
} from 'scribe-standard-sdk';
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
## Protocol Compliance
|
|
367
|
+
|
|
368
|
+
This SDK implements the following specifications:
|
|
369
|
+
|
|
370
|
+
- **Spec 04**: Discovery - Service capability discovery via well-known endpoint
|
|
371
|
+
- **Spec 06**: Session Lifecycle - Create, get status, and end sessions
|
|
372
|
+
- **Spec 09**: Extraction & Response - Template output and transcript handling
|
|
373
|
+
- **Spec 11**: Error Handling - Standard error codes and HTTP status mapping
|
|
374
|
+
|
|
375
|
+
## License
|
|
376
|
+
|
|
377
|
+
MIT
|
|
378
|
+
|
|
379
|
+
## Contributing
|
|
380
|
+
|
|
381
|
+
Contributions are welcome! Please open an issue or submit a pull request.
|
|
382
|
+
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Client for Scribe API
|
|
3
|
+
* Handles all HTTP communication with the Scribe service
|
|
4
|
+
*/
|
|
5
|
+
export interface RequestConfig {
|
|
6
|
+
method: 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
|
|
7
|
+
headers?: Record<string, string>;
|
|
8
|
+
body?: any;
|
|
9
|
+
}
|
|
10
|
+
export declare class HttpClient {
|
|
11
|
+
private apiKey?;
|
|
12
|
+
private debug;
|
|
13
|
+
constructor(apiKey?: string, debug?: boolean);
|
|
14
|
+
/**
|
|
15
|
+
* Make an HTTP request
|
|
16
|
+
*/
|
|
17
|
+
request<T>(url: string, config: RequestConfig): Promise<T>;
|
|
18
|
+
/**
|
|
19
|
+
* Handle error responses from the API
|
|
20
|
+
*/
|
|
21
|
+
private handleErrorResponse;
|
|
22
|
+
/**
|
|
23
|
+
* GET request
|
|
24
|
+
*/
|
|
25
|
+
get<T>(url: string, headers?: Record<string, string>): Promise<T>;
|
|
26
|
+
/**
|
|
27
|
+
* POST request
|
|
28
|
+
*/
|
|
29
|
+
post<T>(url: string, body?: any, headers?: Record<string, string>): Promise<T>;
|
|
30
|
+
/**
|
|
31
|
+
* PUT request
|
|
32
|
+
*/
|
|
33
|
+
put<T>(url: string, body?: any, headers?: Record<string, string>): Promise<T>;
|
|
34
|
+
/**
|
|
35
|
+
* PATCH request
|
|
36
|
+
*/
|
|
37
|
+
patch<T>(url: string, body?: any, headers?: Record<string, string>): Promise<T>;
|
|
38
|
+
/**
|
|
39
|
+
* DELETE request
|
|
40
|
+
*/
|
|
41
|
+
delete<T>(url: string, headers?: Record<string, string>): Promise<T>;
|
|
42
|
+
}
|
|
43
|
+
//# sourceMappingURL=base.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"base.d.ts","sourceRoot":"","sources":["../../src/api/base.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,WAAW,aAAa;IAC5B,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,OAAO,GAAG,QAAQ,CAAC;IACpD,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACjC,IAAI,CAAC,EAAE,GAAG,CAAC;CACZ;AAED,qBAAa,UAAU;IACrB,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,KAAK,CAAU;gBAEX,MAAM,CAAC,EAAE,MAAM,EAAE,KAAK,GAAE,OAAe;IAKnD;;OAEG;IACG,OAAO,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,CAAC,CAAC;IAkEhE;;OAEG;YACW,mBAAmB;IA0BjC;;OAEG;IACG,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAIvE;;OAEG;IACG,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAIpF;;OAEG;IACG,GAAG,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAInF;;OAEG;IACG,KAAK,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;IAIrF;;OAEG;IACG,MAAM,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC;CAG3E"}
|
package/dist/api/base.js
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP Client for Scribe API
|
|
3
|
+
* Handles all HTTP communication with the Scribe service
|
|
4
|
+
*/
|
|
5
|
+
import { ScribeError } from '../utils/errors';
|
|
6
|
+
export class HttpClient {
|
|
7
|
+
constructor(apiKey, debug = false) {
|
|
8
|
+
this.apiKey = apiKey;
|
|
9
|
+
this.debug = debug;
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Make an HTTP request
|
|
13
|
+
*/
|
|
14
|
+
async request(url, config) {
|
|
15
|
+
const headers = {
|
|
16
|
+
'Content-Type': 'application/json',
|
|
17
|
+
Accept: 'application/json',
|
|
18
|
+
...config.headers,
|
|
19
|
+
};
|
|
20
|
+
// Add API key header if provided
|
|
21
|
+
if (this.apiKey) {
|
|
22
|
+
headers['X-API-Key'] = this.apiKey;
|
|
23
|
+
}
|
|
24
|
+
const requestInit = {
|
|
25
|
+
method: config.method,
|
|
26
|
+
headers,
|
|
27
|
+
// Include cookies for authentication when API key is not provided
|
|
28
|
+
credentials: 'include',
|
|
29
|
+
};
|
|
30
|
+
if (config.body) {
|
|
31
|
+
requestInit.body = JSON.stringify(config.body);
|
|
32
|
+
}
|
|
33
|
+
if (this.debug) {
|
|
34
|
+
console.log('[ScribeSDK] Request:', {
|
|
35
|
+
url,
|
|
36
|
+
method: config.method,
|
|
37
|
+
headers,
|
|
38
|
+
body: config.body,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
try {
|
|
42
|
+
const response = await fetch(url, requestInit);
|
|
43
|
+
if (this.debug) {
|
|
44
|
+
console.log('[ScribeSDK] Response:', {
|
|
45
|
+
status: response.status,
|
|
46
|
+
statusText: response.statusText,
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
// Handle successful responses
|
|
50
|
+
if (response.ok) {
|
|
51
|
+
const data = await response.json();
|
|
52
|
+
return data;
|
|
53
|
+
}
|
|
54
|
+
// Handle error responses
|
|
55
|
+
await this.handleErrorResponse(response);
|
|
56
|
+
// This line should never be reached, but TypeScript needs it
|
|
57
|
+
throw new ScribeError('Unexpected error occurred');
|
|
58
|
+
}
|
|
59
|
+
catch (error) {
|
|
60
|
+
if (error instanceof ScribeError) {
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
// Network or parsing errors
|
|
64
|
+
throw new ScribeError(`Network error: ${error instanceof Error ? error.message : 'Unknown error'}`, 'network_error');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Handle error responses from the API
|
|
69
|
+
*/
|
|
70
|
+
async handleErrorResponse(response) {
|
|
71
|
+
let errorData = null;
|
|
72
|
+
try {
|
|
73
|
+
errorData = await response.json();
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
// If response is not JSON, create a generic error
|
|
77
|
+
throw new ScribeError(`HTTP ${response.status}: ${response.statusText}`, 'http_error', response.status);
|
|
78
|
+
}
|
|
79
|
+
if (errorData?.error) {
|
|
80
|
+
throw ScribeError.fromApiError(errorData.error, response.status);
|
|
81
|
+
}
|
|
82
|
+
// Fallback error
|
|
83
|
+
throw new ScribeError(`HTTP ${response.status}: ${response.statusText}`, 'http_error', response.status);
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* GET request
|
|
87
|
+
*/
|
|
88
|
+
async get(url, headers) {
|
|
89
|
+
return this.request(url, { method: 'GET', headers });
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* POST request
|
|
93
|
+
*/
|
|
94
|
+
async post(url, body, headers) {
|
|
95
|
+
return this.request(url, { method: 'POST', body, headers });
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* PUT request
|
|
99
|
+
*/
|
|
100
|
+
async put(url, body, headers) {
|
|
101
|
+
return this.request(url, { method: 'PUT', body, headers });
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* PATCH request
|
|
105
|
+
*/
|
|
106
|
+
async patch(url, body, headers) {
|
|
107
|
+
return this.request(url, { method: 'PATCH', body, headers });
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* DELETE request
|
|
111
|
+
*/
|
|
112
|
+
async delete(url, headers) {
|
|
113
|
+
return this.request(url, { method: 'DELETE', headers });
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discovery API
|
|
3
|
+
* Implements the Discovery endpoint (Spec 04)
|
|
4
|
+
*/
|
|
5
|
+
import { DiscoveryDocument } from '../types';
|
|
6
|
+
import { HttpClient } from './base';
|
|
7
|
+
export declare class DiscoveryAPI {
|
|
8
|
+
private httpClient;
|
|
9
|
+
private cachedDiscovery;
|
|
10
|
+
private cacheTimestamp;
|
|
11
|
+
private cacheDuration;
|
|
12
|
+
constructor(httpClient: HttpClient);
|
|
13
|
+
/**
|
|
14
|
+
* Fetch discovery document from the well-known endpoint
|
|
15
|
+
* Implements caching as recommended in Spec 04.8
|
|
16
|
+
*
|
|
17
|
+
* @param baseUrl - The base URL of the Scribe service
|
|
18
|
+
* @param forceRefresh - Force refresh the cache
|
|
19
|
+
*/
|
|
20
|
+
getDiscovery(baseUrl: string, forceRefresh?: boolean): Promise<DiscoveryDocument>;
|
|
21
|
+
/**
|
|
22
|
+
* Clear the discovery cache
|
|
23
|
+
*/
|
|
24
|
+
clearCache(): void;
|
|
25
|
+
/**
|
|
26
|
+
* Get cached discovery document without making a request
|
|
27
|
+
*/
|
|
28
|
+
getCachedDiscovery(): DiscoveryDocument | null;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=discovery.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../../src/api/discovery.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAEpC,qBAAa,YAAY;IACvB,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,eAAe,CAAkC;IACzD,OAAO,CAAC,cAAc,CAAa;IACnC,OAAO,CAAC,aAAa,CAAuB;gBAEhC,UAAU,EAAE,UAAU;IAIlC;;;;;;OAMG;IACG,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,YAAY,GAAE,OAAe,GAAG,OAAO,CAAC,iBAAiB,CAAC;IAqB9F;;OAEG;IACH,UAAU,IAAI,IAAI;IAKlB;;OAEG;IACH,kBAAkB,IAAI,iBAAiB,GAAG,IAAI;CAO/C"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Discovery API
|
|
3
|
+
* Implements the Discovery endpoint (Spec 04)
|
|
4
|
+
*/
|
|
5
|
+
import { WELL_KNOWN_PATH } from '../constants';
|
|
6
|
+
export class DiscoveryAPI {
|
|
7
|
+
constructor(httpClient) {
|
|
8
|
+
this.cachedDiscovery = null;
|
|
9
|
+
this.cacheTimestamp = 0;
|
|
10
|
+
this.cacheDuration = 3600 * 1000; // 1 hour in milliseconds
|
|
11
|
+
this.httpClient = httpClient;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Fetch discovery document from the well-known endpoint
|
|
15
|
+
* Implements caching as recommended in Spec 04.8
|
|
16
|
+
*
|
|
17
|
+
* @param baseUrl - The base URL of the Scribe service
|
|
18
|
+
* @param forceRefresh - Force refresh the cache
|
|
19
|
+
*/
|
|
20
|
+
async getDiscovery(baseUrl, forceRefresh = false) {
|
|
21
|
+
const now = Date.now();
|
|
22
|
+
// Return cached discovery if valid
|
|
23
|
+
if (!forceRefresh && this.cachedDiscovery && now - this.cacheTimestamp < this.cacheDuration) {
|
|
24
|
+
return this.cachedDiscovery;
|
|
25
|
+
}
|
|
26
|
+
// Construct well-known URL
|
|
27
|
+
const discoveryUrl = new URL(WELL_KNOWN_PATH, baseUrl).toString();
|
|
28
|
+
// Fetch discovery document
|
|
29
|
+
const discovery = await this.httpClient.get(discoveryUrl);
|
|
30
|
+
// Cache the discovery document
|
|
31
|
+
this.cachedDiscovery = discovery;
|
|
32
|
+
this.cacheTimestamp = now;
|
|
33
|
+
return discovery;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Clear the discovery cache
|
|
37
|
+
*/
|
|
38
|
+
clearCache() {
|
|
39
|
+
this.cachedDiscovery = null;
|
|
40
|
+
this.cacheTimestamp = 0;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get cached discovery document without making a request
|
|
44
|
+
*/
|
|
45
|
+
getCachedDiscovery() {
|
|
46
|
+
const now = Date.now();
|
|
47
|
+
if (this.cachedDiscovery && now - this.cacheTimestamp < this.cacheDuration) {
|
|
48
|
+
return this.cachedDiscovery;
|
|
49
|
+
}
|
|
50
|
+
return null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session API
|
|
3
|
+
* Implements Session Lifecycle endpoints (Spec 06)
|
|
4
|
+
*/
|
|
5
|
+
import { CreateSessionRequest, CreateSessionResponse, EndSessionResponse, GetSessionStatusResponse } from '../types';
|
|
6
|
+
import { HttpClient } from './base';
|
|
7
|
+
export declare class SessionAPI {
|
|
8
|
+
private httpClient;
|
|
9
|
+
private baseUrl;
|
|
10
|
+
constructor(httpClient: HttpClient, baseUrl: string);
|
|
11
|
+
/**
|
|
12
|
+
* Update the base URL (e.g., after discovery)
|
|
13
|
+
*/
|
|
14
|
+
setBaseUrl(baseUrl: string): void;
|
|
15
|
+
/**
|
|
16
|
+
* Create a new session
|
|
17
|
+
* POST /sessions
|
|
18
|
+
*
|
|
19
|
+
* @param request - Session creation parameters
|
|
20
|
+
* @returns Session creation response with session_id and upload_url
|
|
21
|
+
*/
|
|
22
|
+
createSession(request: CreateSessionRequest): Promise<CreateSessionResponse>;
|
|
23
|
+
/**
|
|
24
|
+
* Get session status
|
|
25
|
+
* GET /sessions/{sessionId}
|
|
26
|
+
*
|
|
27
|
+
* @param sessionId - The session ID
|
|
28
|
+
* @returns Current session status and results (if available)
|
|
29
|
+
*/
|
|
30
|
+
getSessionStatus(sessionId: string): Promise<GetSessionStatusResponse>;
|
|
31
|
+
/**
|
|
32
|
+
* End a session
|
|
33
|
+
* POST /sessions/{sessionId}/end
|
|
34
|
+
*
|
|
35
|
+
* This triggers processing of the uploaded audio.
|
|
36
|
+
* No more audio can be uploaded after this call.
|
|
37
|
+
*
|
|
38
|
+
* @param sessionId - The session ID
|
|
39
|
+
* @returns End session response with processing status
|
|
40
|
+
*/
|
|
41
|
+
endSession(sessionId: string): Promise<EndSessionResponse>;
|
|
42
|
+
/**
|
|
43
|
+
* Poll for session completion
|
|
44
|
+
* Repeatedly checks session status until it's completed, partial, or failed
|
|
45
|
+
*
|
|
46
|
+
* @param sessionId - The session ID
|
|
47
|
+
* @param options - Polling options
|
|
48
|
+
* @returns Final session status
|
|
49
|
+
*/
|
|
50
|
+
pollSessionStatus(sessionId: string, options?: {
|
|
51
|
+
maxAttempts?: number;
|
|
52
|
+
intervalMs?: number;
|
|
53
|
+
onProgress?: (status: GetSessionStatusResponse) => void;
|
|
54
|
+
}): Promise<GetSessionStatusResponse>;
|
|
55
|
+
/**
|
|
56
|
+
* Helper function to sleep
|
|
57
|
+
*/
|
|
58
|
+
private sleep;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=session.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.d.ts","sourceRoot":"","sources":["../../src/api/session.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,kBAAkB,EAClB,wBAAwB,EACzB,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AAGpC,qBAAa,UAAU;IACrB,OAAO,CAAC,UAAU,CAAa;IAC/B,OAAO,CAAC,OAAO,CAAS;gBAEZ,UAAU,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM;IAKnD;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIjC;;;;;;OAMG;IACG,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,OAAO,CAAC,qBAAqB,CAAC;IAQlF;;;;;;OAMG;IACG,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,wBAAwB,CAAC;IAQ5E;;;;;;;;;OASG;IACG,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAKhE;;;;;;;OAOG;IACG,iBAAiB,CACrB,SAAS,EAAE,MAAM,EACjB,OAAO,GAAE;QACP,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,UAAU,CAAC,EAAE,MAAM,CAAC;QACpB,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,wBAAwB,KAAK,IAAI,CAAC;KACpD,GACL,OAAO,CAAC,wBAAwB,CAAC;IAiCpC;;OAEG;IACH,OAAO,CAAC,KAAK;CAGd"}
|