med-scribe-alliance-ts-sdk 2.0.0 → 2.0.2

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.
Files changed (118) hide show
  1. package/README.md +237 -285
  2. package/dist/index.d.ts +1067 -17
  3. package/dist/index.mjs +1823 -0
  4. package/dist/worker.bundle.js +14 -0
  5. package/package.json +19 -5
  6. package/dist/audio/audio-buffer-manager.d.ts +0 -60
  7. package/dist/audio/audio-buffer-manager.d.ts.map +0 -1
  8. package/dist/audio/audio-buffer-manager.js +0 -109
  9. package/dist/audio/audio-file-manager.d.ts +0 -85
  10. package/dist/audio/audio-file-manager.d.ts.map +0 -1
  11. package/dist/audio/audio-file-manager.js +0 -159
  12. package/dist/audio/constants.d.ts +0 -31
  13. package/dist/audio/constants.d.ts.map +0 -1
  14. package/dist/audio/constants.js +0 -39
  15. package/dist/audio/index.d.ts +0 -7
  16. package/dist/audio/index.d.ts.map +0 -1
  17. package/dist/audio/index.js +0 -5
  18. package/dist/audio/mp3-encoder.d.ts +0 -17
  19. package/dist/audio/mp3-encoder.d.ts.map +0 -1
  20. package/dist/audio/mp3-encoder.js +0 -45
  21. package/dist/audio/vad-client.d.ts +0 -119
  22. package/dist/audio/vad-client.d.ts.map +0 -1
  23. package/dist/audio/vad-client.js +0 -326
  24. package/dist/callbacks/callback-registry.d.ts +0 -37
  25. package/dist/callbacks/callback-registry.d.ts.map +0 -1
  26. package/dist/callbacks/callback-registry.js +0 -72
  27. package/dist/client.d.ts +0 -168
  28. package/dist/client.d.ts.map +0 -1
  29. package/dist/client.js +0 -367
  30. package/dist/constants/index.d.ts +0 -82
  31. package/dist/constants/index.d.ts.map +0 -1
  32. package/dist/constants/index.js +0 -98
  33. package/dist/discovery/discovery-manager.d.ts +0 -43
  34. package/dist/discovery/discovery-manager.d.ts.map +0 -1
  35. package/dist/discovery/discovery-manager.js +0 -126
  36. package/dist/discovery/resolved-config.d.ts +0 -11
  37. package/dist/discovery/resolved-config.d.ts.map +0 -1
  38. package/dist/discovery/resolved-config.js +0 -40
  39. package/dist/index.d.ts.map +0 -1
  40. package/dist/index.js +0 -22
  41. package/dist/recording/chunked-recorder.d.ts +0 -98
  42. package/dist/recording/chunked-recorder.d.ts.map +0 -1
  43. package/dist/recording/chunked-recorder.js +0 -255
  44. package/dist/recording/index.d.ts +0 -5
  45. package/dist/recording/index.d.ts.map +0 -1
  46. package/dist/recording/index.js +0 -3
  47. package/dist/recording/recording-manager.d.ts +0 -143
  48. package/dist/recording/recording-manager.d.ts.map +0 -1
  49. package/dist/recording/recording-manager.js +0 -491
  50. package/dist/recording/single-recorder.d.ts +0 -58
  51. package/dist/recording/single-recorder.d.ts.map +0 -1
  52. package/dist/recording/single-recorder.js +0 -203
  53. package/dist/session/session-manager.d.ts +0 -55
  54. package/dist/session/session-manager.d.ts.map +0 -1
  55. package/dist/session/session-manager.js +0 -196
  56. package/dist/transport/http-transport.d.ts +0 -48
  57. package/dist/transport/http-transport.d.ts.map +0 -1
  58. package/dist/transport/http-transport.js +0 -227
  59. package/dist/transport/ipc-transport.d.ts +0 -61
  60. package/dist/transport/ipc-transport.d.ts.map +0 -1
  61. package/dist/transport/ipc-transport.js +0 -272
  62. package/dist/transport/transport.interface.d.ts +0 -9
  63. package/dist/transport/transport.interface.d.ts.map +0 -1
  64. package/dist/transport/transport.interface.js +0 -8
  65. package/dist/types/callbacks.d.ts +0 -113
  66. package/dist/types/callbacks.d.ts.map +0 -1
  67. package/dist/types/callbacks.js +0 -4
  68. package/dist/types/common.d.ts +0 -25
  69. package/dist/types/common.d.ts.map +0 -1
  70. package/dist/types/common.js +0 -4
  71. package/dist/types/config.d.ts +0 -24
  72. package/dist/types/config.d.ts.map +0 -1
  73. package/dist/types/config.js +0 -4
  74. package/dist/types/discovery.d.ts +0 -77
  75. package/dist/types/discovery.d.ts.map +0 -1
  76. package/dist/types/discovery.js +0 -4
  77. package/dist/types/index.d.ts +0 -12
  78. package/dist/types/index.d.ts.map +0 -1
  79. package/dist/types/index.js +0 -4
  80. package/dist/types/recording.d.ts +0 -66
  81. package/dist/types/recording.d.ts.map +0 -1
  82. package/dist/types/recording.js +0 -4
  83. package/dist/types/session.d.ts +0 -75
  84. package/dist/types/session.d.ts.map +0 -1
  85. package/dist/types/session.js +0 -4
  86. package/dist/types/transport.d.ts +0 -49
  87. package/dist/types/transport.d.ts.map +0 -1
  88. package/dist/types/transport.js +0 -4
  89. package/dist/types/worker.d.ts +0 -39
  90. package/dist/types/worker.d.ts.map +0 -1
  91. package/dist/types/worker.js +0 -4
  92. package/dist/utils/errors.d.ts +0 -49
  93. package/dist/utils/errors.d.ts.map +0 -1
  94. package/dist/utils/errors.js +0 -98
  95. package/dist/utils/retry.d.ts +0 -22
  96. package/dist/utils/retry.d.ts.map +0 -1
  97. package/dist/utils/retry.js +0 -58
  98. package/dist/validation/schemas/discovery-schema.d.ts +0 -59
  99. package/dist/validation/schemas/discovery-schema.d.ts.map +0 -1
  100. package/dist/validation/schemas/discovery-schema.js +0 -69
  101. package/dist/validation/schemas/request-schema.d.ts +0 -20
  102. package/dist/validation/schemas/request-schema.d.ts.map +0 -1
  103. package/dist/validation/schemas/request-schema.js +0 -23
  104. package/dist/validation/schemas/session-schema.d.ts +0 -63
  105. package/dist/validation/schemas/session-schema.d.ts.map +0 -1
  106. package/dist/validation/schemas/session-schema.js +0 -78
  107. package/dist/validation/validator.d.ts +0 -34
  108. package/dist/validation/validator.d.ts.map +0 -1
  109. package/dist/validation/validator.js +0 -114
  110. package/dist/worker/index.d.ts +0 -3
  111. package/dist/worker/index.d.ts.map +0 -1
  112. package/dist/worker/index.js +0 -1
  113. package/dist/worker/shared-worker.d.ts +0 -17
  114. package/dist/worker/shared-worker.d.ts.map +0 -1
  115. package/dist/worker/shared-worker.js +0 -194
  116. package/dist/worker/worker-manager.d.ts +0 -88
  117. package/dist/worker/worker-manager.d.ts.map +0 -1
  118. package/dist/worker/worker-manager.js +0 -270
package/README.md CHANGED
@@ -1,382 +1,334 @@
1
+ # MedScribe Alliance TS SDK
1
2
 
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
3
+ TypeScript SDK for the [MedScribe Alliance Protocol](https://github.com/MedScribeAlliance/scribe-emr-protocol) — handles discovery, recording, audio chunking (VAD), MP3 compression, upload, session lifecycle, and output retrieval.
15
4
 
16
5
  ## Installation
17
6
 
18
7
  ```bash
19
- npm install scribe-standard-sdk
8
+ npm install med-scribe-alliance-ts-sdk
20
9
  ```
21
10
 
11
+ Peer dependencies (installed automatically):
12
+
13
+ - `@ricky0123/vad-web` — Voice Activity Detection
14
+ - `@breezystack/lamejs` — MP3 encoding
15
+ - `zod` — Schema validation
16
+
22
17
  ## Quick Start
23
18
 
24
- ```typescript
25
- import { ScribeClient } from 'scribe-standard-sdk';
19
+ ```ts
20
+ import { ScribeClient } from 'med-scribe-alliance-ts-sdk';
26
21
 
27
- // Initialize the SDK
28
22
  const client = new ScribeClient({
29
- apiKey: 'your-api-key',
30
- baseUrl: 'https://api.scribe.example.com',
31
- debug: true, // Optional: enable debug logging
23
+ baseUrl: 'https://api.example.com/voice/api/v2',
24
+ accessToken: 'your-bearer-token',
25
+ });
26
+
27
+ // Register callbacks
28
+ client.registerCallback('onUploadEvent', (event) => {
29
+ if (event.type === 'progress') {
30
+ console.log(`Uploaded ${event.data.successCount}/${event.data.totalCount}`);
31
+ }
32
32
  });
33
33
 
34
- // Initialize (performs discovery)
35
- await client.init();
34
+ client.registerCallback('onError', (event) => {
35
+ console.error(`[${event.error.code}] ${event.error.message}`);
36
+ });
36
37
 
37
- // Start a recording session
38
- const session = await client.startRecording({
39
- templates: ['soap', 'medications'],
40
- languageHint: ['en'],
41
- model: 'pro',
38
+ // Start recording — creates session, starts mic, begins chunked upload
39
+ const result = await client.startRecording({
40
+ templates: ['soap', 'prescription'],
41
+ uploadType: 'chunked',
42
42
  });
43
43
 
44
- console.log('Session created:', session.session_id);
45
- console.log('Upload audio to:', session.upload_url);
44
+ if (!result.success) {
45
+ console.error(result.error);
46
+ }
47
+
48
+ // ... user speaks ...
46
49
 
47
- // ... Upload audio chunks to session.upload_url ...
50
+ // Stop recording — flushes remaining audio, waits for uploads, ends session
51
+ const stopResult = await client.endRecording();
48
52
 
49
- // End the recording session
50
- const endResponse = await client.endRecording();
51
- console.log('Session ended, processing started');
53
+ if (stopResult.success) {
54
+ console.log(`${stopResult.data.totalFiles} files uploaded`);
55
+ console.log(`${stopResult.data.failedUploads.length} failed`);
56
+ }
52
57
 
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);
58
+ // Poll for results
59
+ const status = await client.getSessionStatus(result.data.session_id, {
60
+ poll: {
61
+ maxAttempts: 60,
62
+ intervalMs: 2000,
63
+ onProgress: (s) => console.log(`Status: ${s.status}`),
59
64
  },
60
65
  });
61
-
62
- // Access the results
63
- if (result.status === 'completed') {
64
- console.log('Transcript:', result.transcript);
65
- console.log('Templates:', result.templates);
66
- }
67
66
  ```
68
67
 
69
- ## Core API
68
+ ## Configuration
70
69
 
71
- ### ScribeClient
70
+ ```ts
71
+ interface ScribeSDKConfig {
72
+ /** Base URL of the scribe service (required) */
73
+ baseUrl: string;
72
74
 
73
- The main SDK client class.
75
+ /** Bearer token for authentication */
76
+ accessToken?: string;
74
77
 
75
- #### Constructor
78
+ /** Transport mode: 'direct' (HTTP) or 'ipc' (Electron). Default: 'direct' */
79
+ mode?: 'direct' | 'ipc';
76
80
 
77
- ```typescript
78
- new ScribeClient(config: ScribeSDKConfig)
79
- ```
81
+ /** IPC bridge — required when mode is 'ipc' */
82
+ ipcTransport?: IpcBridge;
80
83
 
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`)
84
+ /** SharedWorker: true (require), false (disable), 'auto' (detect). Default: 'auto' */
85
+ useWorker?: boolean | 'auto';
86
86
 
87
- #### Methods
87
+ /** URL to worker.bundle.js. Use getWorkerUrl() to resolve. */
88
+ workerScriptUrl?: string;
88
89
 
89
- ##### `init(): Promise<void>`
90
+ /** Enable debug logging. Default: false */
91
+ debug?: boolean;
90
92
 
91
- Initialize the SDK and perform service discovery.
93
+ /** Auto-fetch discovery document on init. Default: true */
94
+ autoDiscovery?: boolean;
95
+ }
96
+ ```
92
97
 
93
- ```typescript
94
- await client.init();
98
+ ## API Reference
99
+
100
+ ### Lifecycle
101
+
102
+ | Method | Returns | Description |
103
+ |---|---|---|
104
+ | `init()` | `SDKResult<void>` | Fetch discovery document. Called automatically by `startRecording`. |
105
+ | `reset()` | `Promise<void>` | Stop recording, clear all state and caches. |
106
+
107
+ ### Recording
108
+
109
+ | Method | Returns | Description |
110
+ |---|---|---|
111
+ | `startRecording(options)` | `SDKResult<CreateSessionResponse>` | Create session + start mic + begin upload. |
112
+ | `startRecordingWithSession(session, options?)` | `SDKResult<void>` | Attach recorder to an existing session. |
113
+ | `pauseRecording()` | `void` | Pause VAD (mic stays open, no chunks created). |
114
+ | `resumeRecording()` | `void` | Resume VAD processing. |
115
+ | `endRecording()` | `SDKResult<StopRecordingResult>` | Stop mic, flush audio, wait for uploads, end session. |
116
+ | `isRecording()` | `boolean` | Whether a recording is active. |
117
+ | `isRecordingPaused()` | `boolean` | Whether the active recording is paused. |
118
+ | `retryFailedUploads()` | `SDKResult<RetryUploadResult>` | Retry uploads that failed during the last recording. |
119
+ | `hasFailedUploads()` | `boolean` | Whether there are retryable failed uploads. |
120
+
121
+ #### Recording Options
122
+
123
+ ```ts
124
+ interface RecordingOptions {
125
+ templates: string[]; // Template IDs for extraction (required)
126
+ model?: string; // Model ID from discovery
127
+ languageHint?: string[]; // Language codes for audio input
128
+ transcriptLanguage?: string[];// Language codes for transcript output
129
+ uploadType?: string; // 'chunked' | 'single' (default: 'chunked')
130
+ communicationProtocol?: string;// 'http' | 'websocket' (default: 'http')
131
+ additionalData?: Record<string, any>;
132
+ deviceId?: string; // Specific microphone device ID
133
+ }
95
134
  ```
96
135
 
97
- ##### `startRecording(options: RecordingOptions): Promise<CreateSessionResponse>`
136
+ ### Session
98
137
 
99
- Start a new recording session.
138
+ | Method | Returns | Description |
139
+ |---|---|---|
140
+ | `createSession(request)` | `SDKResult<CreateSessionResponse>` | Create a session without starting a recording. |
141
+ | `getSessionStatus(sessionId?, options?)` | `SDKResult<GetSessionStatusResponse>` | Get status. Pass `{ poll: PollOptions }` to poll until completion. |
142
+ | `getCurrentSession()` | `CreateSessionResponse \| null` | Get the active session if any. |
100
143
 
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
144
+ #### Polling
109
145
 
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
146
+ Pass `poll` options to `getSessionStatus` to poll until the session reaches a terminal state:
116
147
 
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',
148
+ ```ts
149
+ const result = await client.getSessionStatus(sessionId, {
150
+ poll: {
151
+ maxAttempts: 60,
152
+ intervalMs: 2000,
153
+ onProgress: (status) => console.log(status.status),
125
154
  },
126
155
  });
127
156
  ```
128
157
 
129
- ##### `endRecording(): Promise<EndSessionResponse>`
130
-
131
- End the current recording session and trigger processing.
158
+ ### Discovery
132
159
 
133
- ```typescript
134
- const response = await client.endRecording();
135
- ```
160
+ | Method | Returns | Description |
161
+ |---|---|---|
162
+ | `getDiscoveryDocument()` | `DiscoveryDocument \| null` | Raw discovery document. |
163
+ | `getDiscoveryConfig()` | `SDKResult<ResolvedConfig>` | Resolved config from discovery. |
164
+ | `refreshDiscovery()` | `SDKResult<ResolvedConfig>` | Force-refresh discovery. |
136
165
 
137
- ##### `getOutputStatus(sessionId?: string): Promise<GetSessionStatusResponse>`
166
+ ### Auth
138
167
 
139
- Get the current status and results of a session.
168
+ | Method | Description |
169
+ |---|---|
170
+ | `setAccessToken(token)` | Update Bearer token. Propagates to transport, recorder, and worker. |
140
171
 
141
- ```typescript
142
- const status = await client.getOutputStatus(session.session_id);
172
+ ### Callbacks
143
173
 
144
- if (status.status === 'completed') {
145
- console.log('Transcript:', status.transcript);
146
- console.log('Templates:', status.templates);
147
- }
148
- ```
174
+ Register with `client.registerCallback(name, handler)`, remove with `client.removeCallback(name, handler)`.
149
175
 
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
176
+ | Callback | Payload | Description |
177
+ |---|---|---|
178
+ | `onRecordingStateChange` | `RecordingStateChangeEvent` | Recording started, paused, resumed, or ended. |
179
+ | `onAudioEvent` | `AudioEvent` | Speech detection, silence warnings, chunk ready. |
180
+ | `onUploadEvent` | `UploadEvent` | Upload progress and failures. |
181
+ | `onSessionEvent` | `SessionEvent` | Session created, ended, status updates. |
182
+ | `onError` | `ErrorEvent` | VAD, worker, transport, or validation errors. |
183
+ | `onTokenRequired` | `TokenRequiredEvent` | 401 received — call `event.resolve(newToken)` to retry. |
156
184
 
157
- ##### `pollForCompletion(sessionId?, options?): Promise<GetSessionStatusResponse>`
185
+ ## Error Handling
158
186
 
159
- Poll for session completion with automatic retries.
187
+ All public async methods return `SDKResult<T>` — errors are returned, not thrown:
160
188
 
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
- });
189
+ ```ts
190
+ type SDKResult<T> =
191
+ | { success: true; data: T }
192
+ | { success: false; error: ScribeError };
169
193
  ```
170
194
 
171
- ##### `getCurrentSession(): CreateSessionResponse | null`
195
+ ```ts
196
+ const result = await client.startRecording({ templates: ['soap'] });
172
197
 
173
- Get the current active session.
198
+ if (!result.success) {
199
+ console.error(result.error.code, result.error.message);
200
+ return;
201
+ }
174
202
 
175
- ```typescript
176
- const currentSession = client.getCurrentSession();
203
+ // result.data is typed as CreateSessionResponse
204
+ console.log(result.data.session_id);
177
205
  ```
178
206
 
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);
207
+ ### Error Classes
208
+
209
+ | Error | HTTP | Description |
210
+ |---|---|---|
211
+ | `ScribeError` | — | Base error class |
212
+ | `ValidationError` | 400 | Invalid request or config |
213
+ | `AuthenticationError` | 401 | Auth failed (after token refresh attempt) |
214
+ | `ForbiddenError` | 403 | Access denied |
215
+ | `SessionNotFoundError` | 404 | Session doesn't exist |
216
+ | `SessionExpiredError` | 410 | Session expired |
217
+ | `RateLimitError` | 429 | Rate limit exceeded |
218
+ | `DiscoveryError` | — | Discovery fetch/parse failed |
219
+ | `TransportError` | — | Network / IPC failure |
220
+ | `WorkerError` | — | SharedWorker failure |
221
+ | `UploadError` | — | Audio upload failure |
222
+
223
+ ### Auto Token Refresh
224
+
225
+ When a 401 is received, the SDK dispatches `onTokenRequired`. Supply a new token to retry the request:
226
+
227
+ ```ts
228
+ client.registerCallback('onTokenRequired', async (event) => {
229
+ const newToken = await refreshMyAuthToken();
230
+ event.resolve(newToken);
231
+ });
187
232
  ```
188
233
 
189
- ## Event System
234
+ Concurrent 401s are deduplicated — only one callback fires regardless of how many requests failed simultaneously.
190
235
 
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
- });
236
+ ## SharedWorker Support
197
237
 
198
- client.on('session:created', (event) => {
199
- console.log('Session created:', event.data);
200
- });
238
+ The SDK offloads MP3 compression and upload to a SharedWorker for better main-thread performance. The worker is bundled separately as `dist/worker.bundle.js`.
201
239
 
202
- client.on('session:ended', (event) => {
203
- console.log('Session ended:', event.data);
204
- });
240
+ ### Setup
205
241
 
206
- client.on('session:status_update', (event) => {
207
- console.log('Status update:', event.data);
208
- });
242
+ ```ts
243
+ import { ScribeClient, getWorkerUrl } from 'med-scribe-alliance-ts-sdk';
209
244
 
210
- client.on('error', (event) => {
211
- console.error('Error:', event.error);
245
+ const client = new ScribeClient({
246
+ baseUrl: 'https://api.example.com',
247
+ workerScriptUrl: getWorkerUrl(), // or a custom path
212
248
  });
213
249
  ```
214
250
 
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
251
+ ### Serving the Worker
249
252
 
250
- You can also use the validator directly for custom validation:
253
+ The worker file must be served as a static asset:
251
254
 
252
- ```typescript
253
- import { schemaValidator } from 'scribe-standard-sdk/utils/validator';
255
+ **Copy to your public directory:**
256
+ ```bash
257
+ cp node_modules/med-scribe-alliance-ts-sdk/dist/worker.bundle.js public/
258
+ ```
254
259
 
255
- // Validate a session ID
256
- try {
257
- schemaValidator.validateSessionId('ses_abc123');
258
- } catch (error) {
259
- console.error('Invalid session ID:', error.message);
260
- }
260
+ **Or use a CDN blob URL (avoids same-origin restrictions):**
261
+ ```ts
262
+ import { createWorkerBlobUrl } from 'med-scribe-alliance-ts-sdk';
261
263
 
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
- }
264
+ const workerUrl = await createWorkerBlobUrl();
265
+ const client = new ScribeClient({
266
+ baseUrl: '...',
267
+ workerScriptUrl: workerUrl,
268
+ });
272
269
  ```
273
270
 
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
- }
271
+ **Or set a global override:**
272
+ ```ts
273
+ window.__MEDSCRIBE_WORKER_URL__ = '/assets/worker.bundle.js';
303
274
  ```
304
275
 
305
- ## Template Output
276
+ If the SharedWorker fails to initialize, the SDK silently falls back to main-thread compression and upload.
306
277
 
307
- When a session completes, the `templates` field contains the extracted data:
278
+ ## Electron / IPC Mode
308
279
 
309
- ```typescript
310
- const status = await client.getOutputStatus(sessionId);
280
+ For Electron apps where network requests must go through the main process:
311
281
 
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
- }
282
+ ```ts
283
+ import { ScribeClient, TransportMode } from 'med-scribe-alliance-ts-sdk';
320
284
 
321
- // Check medications template
322
- const meds = status.templates['medications'];
323
- if (meds.status === 'success') {
324
- console.log('Medications:', meds.data);
325
- }
326
- }
285
+ const client = new ScribeClient({
286
+ baseUrl: 'https://api.example.com',
287
+ mode: TransportMode.IPC,
288
+ ipcTransport: {
289
+ send: (request) => ipcRenderer.send('scribe-request', request),
290
+ onResponse: (handler) => ipcRenderer.on('scribe-response', (_, res) => handler(res)),
291
+ },
292
+ });
327
293
  ```
328
294
 
329
- ## Discovery Document
295
+ IPC mode always uses main-thread compression (SharedWorker can't access the IPC bridge).
330
296
 
331
- The discovery document provides service capabilities:
297
+ ## Two-Step Flow
332
298
 
333
- ```typescript
334
- const discovery = client.getDiscoveryDocument();
299
+ For apps that need to create the session separately from recording:
335
300
 
336
- // Check supported audio formats
337
- console.log('Audio formats:', discovery.capabilities.audio_formats);
301
+ ```ts
302
+ // Step 1: Create session
303
+ const session = await client.createSession({
304
+ templates: ['soap'],
305
+ upload_type: 'chunked',
306
+ communication_protocol: 'http',
307
+ });
338
308
 
339
- // Check max chunk duration
340
- console.log('Max chunk duration:', discovery.capabilities.max_chunk_duration_seconds);
309
+ if (!session.success) return;
341
310
 
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);
311
+ // Step 2: Start recording with the existing session
312
+ await client.startRecordingWithSession(session.data, {
313
+ uploadType: 'chunked',
348
314
  });
349
315
  ```
350
316
 
351
- ## TypeScript Support
317
+ ## Building from Source
352
318
 
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';
319
+ ```bash
320
+ npm install
321
+ npm run build
364
322
  ```
365
323
 
366
- ## Protocol Compliance
324
+ Build output (`dist/`):
367
325
 
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
326
+ | File | Description |
327
+ |---|---|
328
+ | `index.mjs` | Minified ESM bundle |
329
+ | `index.d.ts` | Bundled type declarations |
330
+ | `worker.bundle.js` | Self-contained IIFE SharedWorker |
374
331
 
375
332
  ## License
376
333
 
377
334
  MIT
378
-
379
- ## Contributing
380
-
381
- Contributions are welcome! Please open an issue or submit a pull request.
382
-