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

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 CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
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.
4
4
 
5
+ ## npm package link
6
+
7
+ https://www.npmjs.com/package/med-scribe-alliance-ts-sdk
8
+
9
+
5
10
  ## Installation
6
11
 
7
12
  ```bash
package/dist/index.d.ts CHANGED
@@ -10,12 +10,14 @@ export declare enum SessionStatus {
10
10
  }
11
11
  export declare enum TemplateStatus {
12
12
  SUCCESS = "success",
13
- FAILED = "failed",
14
- PROCESSING = "processing"
13
+ PARTIAL_SUCCESS = "partial_success",
14
+ FAILURE = "failure",
15
+ IN_PROGRESS = "in-progress"
15
16
  }
16
17
  export declare enum UploadType {
17
18
  CHUNKED = "chunked",
18
- SINGLE = "single"
19
+ SINGLE = "single",
20
+ STREAM = "stream"
19
21
  }
20
22
  export declare enum CommunicationProtocol {
21
23
  WEBSOCKET = "websocket",
@@ -130,7 +132,7 @@ export type SDKResult<T = void> = {
130
132
  * Transport layer types
131
133
  */
132
134
  export interface TransportRequest {
133
- method: "GET" | "POST" | "PUT" | "DELETE";
135
+ method: "GET" | "POST" | "PUT" | "PATCH" | "DELETE";
134
136
  url: string;
135
137
  headers?: Record<string, string>;
136
138
  body?: any;
@@ -215,6 +217,7 @@ export interface EndpointsInfo {
215
217
  webhooks_url?: string;
216
218
  authorization_endpoint?: string;
217
219
  token_endpoint?: string;
220
+ templates_url?: string;
218
221
  }
219
222
  export interface AuthenticationInfo {
220
223
  supported_methods: string[];
@@ -267,14 +270,23 @@ export interface ResolvedConfig {
267
270
  webhookDelivery: boolean;
268
271
  clientSdkDelivery: boolean;
269
272
  }
273
+ export interface PatientDetails {
274
+ name?: string;
275
+ age?: string;
276
+ gender?: string;
277
+ mobile?: number;
278
+ }
270
279
  export interface CreateSessionRequest {
271
280
  templates: string[];
272
281
  model?: string;
273
282
  language_hint?: string[];
274
- transcript_language?: string[];
283
+ transcript_language?: string;
275
284
  upload_type: string;
276
285
  communication_protocol: string;
277
286
  additional_data?: Record<string, any>;
287
+ session_mode?: string;
288
+ patient_details?: PatientDetails;
289
+ txn_id?: string;
278
290
  }
279
291
  export interface CreateSessionResponse {
280
292
  session_id: string;
@@ -282,9 +294,11 @@ export interface CreateSessionResponse {
282
294
  created_at: string;
283
295
  expires_at: string;
284
296
  upload_url: string;
297
+ patient_details?: PatientDetails;
285
298
  }
286
299
  export interface EndSessionRequest {
287
300
  audio_files_sent: number;
301
+ audio_files_uploaded: number;
288
302
  }
289
303
  export interface EndSessionResponse {
290
304
  session_id: string;
@@ -298,14 +312,15 @@ export interface GetSessionStatusResponse {
298
312
  status: SessionStatus;
299
313
  created_at: string;
300
314
  expires_at?: string;
315
+ expired_at?: string;
301
316
  completed_at?: string;
302
317
  model_used?: string;
303
318
  language_detected?: string;
304
- audio_files_received?: number;
305
- audio_files?: string[];
319
+ audio_files_received: number;
320
+ audio_files: string[];
306
321
  audio_files_processed?: number;
307
- additional_data?: Record<string, any>;
308
- templates?: TemplatesOutput;
322
+ additional_data: Record<string, any>;
323
+ templates?: TemplateEntry[];
309
324
  transcript?: string;
310
325
  processing_errors?: ProcessingError[];
311
326
  error?: {
@@ -313,15 +328,24 @@ export interface GetSessionStatusResponse {
313
328
  message: string;
314
329
  details?: Record<string, any>;
315
330
  };
316
- }
317
- export interface TemplatesOutput {
318
- [templateId: string]: TemplateEntry;
331
+ patient_details?: PatientDetails;
332
+ message?: string;
319
333
  }
320
334
  export interface TemplateEntry {
335
+ [templateId: string]: TemplateEntryData;
336
+ }
337
+ export interface TemplateEntryData {
321
338
  status: TemplateStatus;
322
339
  data?: any;
323
340
  fhir?: any;
324
341
  error?: TemplateError;
342
+ document_id?: string;
343
+ document_type?: string;
344
+ publish?: boolean;
345
+ presigned_url?: string;
346
+ presigned_url_expires_at?: string;
347
+ errors?: any[];
348
+ warnings?: any[];
325
349
  }
326
350
  export interface TemplateError {
327
351
  code: string;
@@ -337,15 +361,38 @@ export interface PollOptions {
337
361
  intervalMs?: number;
338
362
  onProgress?: (status: GetSessionStatusResponse) => void;
339
363
  }
364
+ export interface PatchSessionRequest {
365
+ user_status?: string;
366
+ processing_status?: string;
367
+ patient_details?: PatientDetails;
368
+ additional_data?: Record<string, any>;
369
+ language_hint?: string[];
370
+ transcript_language?: string;
371
+ templates?: string[];
372
+ }
373
+ export interface PatchSessionResponse {
374
+ session_id: string;
375
+ status: string;
376
+ message: string;
377
+ }
378
+ export interface ProcessTemplateResponse {
379
+ session_id: string;
380
+ template_id: string;
381
+ status: string;
382
+ message: string;
383
+ }
340
384
  export interface RecordingOptions {
341
385
  templates: string[];
342
386
  model?: string;
343
387
  languageHint?: string[];
344
- transcriptLanguage?: string[];
388
+ transcriptLanguage?: string;
345
389
  uploadType?: string;
346
390
  communicationProtocol?: string;
347
391
  additionalData?: Record<string, any>;
348
392
  deviceId?: string;
393
+ sessionMode?: string;
394
+ patientDetails?: PatientDetails;
395
+ txnId?: string;
349
396
  }
350
397
  export interface RecorderConfig {
351
398
  accessToken?: string;
@@ -616,14 +663,31 @@ export declare class ScribeClient {
616
663
  * Pass `poll` options to keep checking until the session reaches a
617
664
  * terminal state (completed, partial, failed, expired) or times out.
618
665
  *
666
+ * Pass `templateId` to filter status for a specific template.
619
667
  */
620
668
  getSessionStatus(sessionId?: string, options?: {
621
669
  poll?: PollOptions;
670
+ templateId?: string;
622
671
  }): Promise<SDKResult<GetSessionStatusResponse>>;
623
672
  /**
624
673
  * Get the current active session, if any.
625
674
  */
626
675
  getCurrentSession(): CreateSessionResponse | null;
676
+ /**
677
+ * Patch/update a session (e.g., update user_status or processing_status).
678
+ * Uses the current active session if no sessionId is provided.
679
+ */
680
+ updateSession(request: PatchSessionRequest, sessionId?: string): Promise<SDKResult<PatchSessionResponse>>;
681
+ /**
682
+ * Trigger processing for a specific template in a session.
683
+ * Uses the current active session if no sessionId is provided.
684
+ */
685
+ processTemplate(templateId: string, sessionId?: string): Promise<SDKResult<ProcessTemplateResponse>>;
686
+ /**
687
+ * Cancel a session by setting both user_status and processing_status to 'cancelled'.
688
+ * Uses the current active session if no sessionId is provided.
689
+ */
690
+ cancelSession(sessionId?: string): Promise<SDKResult<PatchSessionResponse>>;
627
691
  /**
628
692
  * Get the resolved discovery config.
629
693
  * Returns error if discovery hasn't been fetched yet.
@@ -727,6 +791,9 @@ export declare class Validator {
727
791
  validateGetSessionStatusResponse(data: unknown): void;
728
792
  validateSessionId(sessionId: unknown): void;
729
793
  validateRecordingOptions(data: unknown): void;
794
+ validatePatchSessionRequest(data: unknown): void;
795
+ validatePatchSessionResponse(data: unknown): void;
796
+ validateProcessTemplateResponse(data: unknown): void;
730
797
  /**
731
798
  * Cross-validates recording options against the server's declared capabilities.
732
799
  * Throws ValidationError with a descriptive message if any check fails.
@@ -795,8 +862,17 @@ export declare class SessionManager {
795
862
  /**
796
863
  * Get the status of a session.
797
864
  * If no sessionId is provided, queries the current session.
865
+ * Pass templateId to filter status for a specific template.
866
+ */
867
+ getSessionStatus(baseUrl: string, sessionId?: string, templateId?: string): Promise<GetSessionStatusResponse>;
868
+ /**
869
+ * Patch an existing session (e.g., update user_status or processing_status).
870
+ */
871
+ patchSession(baseUrl: string, request: PatchSessionRequest, sessionId?: string): Promise<PatchSessionResponse>;
872
+ /**
873
+ * Trigger processing for a specific template in a session.
798
874
  */
799
- getSessionStatus(baseUrl: string, sessionId?: string): Promise<GetSessionStatusResponse>;
875
+ processTemplate(baseUrl: string, templateId: string, sessionId?: string): Promise<ProcessTemplateResponse>;
800
876
  /**
801
877
  * Poll for session completion.
802
878
  * Keeps checking getSessionStatus until the session reaches a terminal state
package/dist/index.mjs CHANGED
@@ -5,9 +5,9 @@ import * as n from "@breezystack/lamejs";
5
5
  var r = "/.well-known/medscribealliance", i = 3600 * 1e3, a = /* @__PURE__ */ function(e) {
6
6
  return e.CREATED = "created", e.RECORDING = "recording", e.INITIALIZED = "initialized", e.PROCESSING = "processing", e.COMPLETED = "completed", e.PARTIAL = "partial", e.FAILED = "failed", e.EXPIRED = "expired", e;
7
7
  }({}), o = /* @__PURE__ */ function(e) {
8
- return e.SUCCESS = "success", e.FAILED = "failed", e.PROCESSING = "processing", e;
8
+ return e.SUCCESS = "success", e.PARTIAL_SUCCESS = "partial_success", e.FAILURE = "failure", e.IN_PROGRESS = "in-progress", e;
9
9
  }({}), s = /* @__PURE__ */ function(e) {
10
- return e.CHUNKED = "chunked", e.SINGLE = "single", e;
10
+ return e.CHUNKED = "chunked", e.SINGLE = "single", e.STREAM = "stream", e;
11
11
  }({}), c = /* @__PURE__ */ function(e) {
12
12
  return e.WEBSOCKET = "websocket", e.HTTP = "http", e.RPC = "rpc", e;
13
13
  }({}), l = /* @__PURE__ */ function(e) {
@@ -160,33 +160,64 @@ var r = "/.well-known/medscribealliance", i = 3600 * 1e3, a = /* @__PURE__ */ fu
160
160
  communication_protocol: e.string().min(1, "communication_protocol is required"),
161
161
  model: e.string().optional(),
162
162
  language_hint: e.array(e.string().max(2, "language_hint items must be at most 2 characters")).optional(),
163
- transcript_language: e.array(e.string().max(2, "transcript_language items must be at most 2 characters")).optional(),
164
- additional_data: e.record(e.string(), e.any()).optional()
165
- }), k = e.object({ audio_files_sent: e.number().int().min(0, "audio_files_sent must be a non-negative integer") }), A = e.object({
163
+ transcript_language: e.string().optional(),
164
+ additional_data: e.record(e.string(), e.any()).optional(),
165
+ session_mode: e.string().optional(),
166
+ patient_details: e.object({
167
+ name: e.string().optional(),
168
+ age: e.string().optional(),
169
+ gender: e.string().optional(),
170
+ mobile: e.number().optional()
171
+ }).optional(),
172
+ txn_id: e.string().optional()
173
+ }), k = e.object({
174
+ audio_files_sent: e.number().int().min(0, "audio_files_sent must be a non-negative integer"),
175
+ audio_files_uploaded: e.number().int().min(0, "audio_files_uploaded must be a non-negative integer")
176
+ }), ee = e.object({
177
+ user_status: e.string().optional(),
178
+ processing_status: e.string().optional(),
179
+ patient_details: e.object({
180
+ name: e.string().optional(),
181
+ age: e.string().optional(),
182
+ gender: e.string().optional(),
183
+ mobile: e.number().optional()
184
+ }).optional(),
185
+ additional_data: e.record(e.string(), e.any()).optional(),
186
+ language_hint: e.array(e.string()).optional(),
187
+ transcript_language: e.string().optional(),
188
+ templates: e.array(e.string()).optional()
189
+ }), te = e.object({
166
190
  session_id: e.string().min(1, "session_id is required"),
167
191
  status: e.string(),
168
192
  created_at: e.string(),
169
193
  expires_at: e.string(),
170
- upload_url: e.string().min(1, "upload_url is required")
171
- }), ee = e.object({
194
+ upload_url: e.string().min(1, "upload_url is required"),
195
+ patient_details: e.object({
196
+ name: e.string().optional(),
197
+ age: e.string().optional(),
198
+ gender: e.string().optional(),
199
+ mobile: e.number().optional()
200
+ }).optional()
201
+ }), ne = e.object({
172
202
  session_id: e.string().min(1, "session_id is required"),
173
203
  status: e.string(),
174
204
  message: e.string(),
175
205
  audio_files_received: e.number().int(),
176
206
  audio_files: e.array(e.string())
177
- }), te = e.object({
207
+ }), A = e.object({
178
208
  session_id: e.string().min(1, "session_id is required"),
179
209
  status: e.string(),
180
210
  created_at: e.string(),
181
211
  expires_at: e.string().optional(),
212
+ expired_at: e.string().optional(),
182
213
  completed_at: e.string().optional(),
183
214
  model_used: e.string().optional(),
184
215
  language_detected: e.string().optional(),
185
216
  audio_files_received: e.number().int(),
186
217
  audio_files: e.array(e.string()),
187
218
  audio_files_processed: e.number().int().optional(),
188
- additional_data: e.record(e.string(), e.any()).optional(),
189
- templates: e.record(e.string(), e.any()).optional(),
219
+ additional_data: e.record(e.string(), e.any()),
220
+ templates: e.array(e.record(e.string(), e.any())).optional(),
190
221
  transcript: e.string().nullable().optional(),
191
222
  processing_errors: e.array(e.object({
192
223
  type: e.string(),
@@ -197,17 +228,41 @@ var r = "/.well-known/medscribealliance", i = 3600 * 1e3, a = /* @__PURE__ */ fu
197
228
  code: e.string(),
198
229
  message: e.string(),
199
230
  details: e.record(e.string(), e.any()).optional()
200
- }).optional()
201
- }), j = e.string().min(1, "Session ID is required"), M = e.object({
231
+ }).optional(),
232
+ patient_details: e.object({
233
+ name: e.string().optional(),
234
+ age: e.string().optional(),
235
+ gender: e.string().optional(),
236
+ mobile: e.number().optional()
237
+ }).optional(),
238
+ message: e.string().optional()
239
+ }), j = e.object({
240
+ session_id: e.string().min(1, "session_id is required"),
241
+ status: e.string(),
242
+ message: e.string()
243
+ }), M = e.object({
244
+ session_id: e.string().min(1, "session_id is required"),
245
+ template_id: e.string(),
246
+ status: e.string(),
247
+ message: e.string()
248
+ }), N = e.string().min(1, "Session ID is required"), P = e.object({
202
249
  templates: e.array(e.string()).min(1, "templates must contain at least one item").max(2, "templates cannot have more than 2 items"),
203
250
  uploadType: e.string().optional(),
204
251
  communicationProtocol: e.string().optional(),
205
252
  model: e.string().optional(),
206
253
  languageHint: e.array(e.string().max(2, "languageHint items must be at most 2 characters")).optional(),
207
- transcriptLanguage: e.array(e.string().max(2, "transcriptLanguage items must be at most 2 characters")).optional(),
254
+ transcriptLanguage: e.string().optional(),
208
255
  deviceId: e.string().optional(),
209
- additionalData: e.record(e.string(), e.any()).optional()
210
- }), N = class {
256
+ additionalData: e.record(e.string(), e.any()).optional(),
257
+ sessionMode: e.string().optional(),
258
+ patientDetails: e.object({
259
+ name: e.string().optional(),
260
+ age: e.string().optional(),
261
+ gender: e.string().optional(),
262
+ mobile: e.number().optional()
263
+ }).optional(),
264
+ txnId: e.string().optional()
265
+ }), F = class {
211
266
  validateDiscoveryResponse(e) {
212
267
  this.parseWithValidationError(D, e, "Invalid discovery response");
213
268
  }
@@ -218,19 +273,28 @@ var r = "/.well-known/medscribealliance", i = 3600 * 1e3, a = /* @__PURE__ */ fu
218
273
  this.parseWithValidationError(k, e, "Invalid EndSessionRequest");
219
274
  }
220
275
  validateCreateSessionResponse(e) {
221
- this.parseWithValidationError(A, e, "Invalid CreateSessionResponse");
276
+ this.parseWithValidationError(te, e, "Invalid CreateSessionResponse");
222
277
  }
223
278
  validateEndSessionResponse(e) {
224
- this.parseWithValidationError(ee, e, "Invalid EndSessionResponse");
279
+ this.parseWithValidationError(ne, e, "Invalid EndSessionResponse");
225
280
  }
226
281
  validateGetSessionStatusResponse(e) {
227
- this.parseWithValidationError(te, e, "Invalid GetSessionStatusResponse");
282
+ this.parseWithValidationError(A, e, "Invalid GetSessionStatusResponse");
228
283
  }
229
284
  validateSessionId(e) {
230
- this.parseWithValidationError(j, e, "Invalid session ID");
285
+ this.parseWithValidationError(N, e, "Invalid session ID");
231
286
  }
232
287
  validateRecordingOptions(e) {
233
- this.parseWithValidationError(M, e, "Invalid RecordingOptions");
288
+ this.parseWithValidationError(P, e, "Invalid RecordingOptions");
289
+ }
290
+ validatePatchSessionRequest(e) {
291
+ this.parseWithValidationError(ee, e, "Invalid PatchSessionRequest");
292
+ }
293
+ validatePatchSessionResponse(e) {
294
+ this.parseWithValidationError(j, e, "Invalid PatchSessionResponse");
295
+ }
296
+ validateProcessTemplateResponse(e) {
297
+ this.parseWithValidationError(M, e, "Invalid ProcessTemplateResponse");
234
298
  }
235
299
  validateAgainstDiscovery(e, t) {
236
300
  try {
@@ -273,26 +337,26 @@ var r = "/.well-known/medscribealliance", i = 3600 * 1e3, a = /* @__PURE__ */ fu
273
337
  };
274
338
  //#endregion
275
339
  //#region src/utils/retry.ts
276
- async function P(e, t = {}) {
340
+ async function I(e, t = {}) {
277
341
  let { maxRetries: n = 3, delayMs: r = f, onRetry: i } = t, a = null;
278
342
  for (let t = 0; t <= n; t++) try {
279
343
  return await e();
280
344
  } catch (e) {
281
- if (a = e instanceof Error ? e : Error(String(e)), F(e?.httpStatus ?? e?.statusCode ?? e?.status)) throw a;
345
+ if (a = e instanceof Error ? e : Error(String(e)), L(e?.httpStatus ?? e?.statusCode ?? e?.status)) throw a;
282
346
  if (t >= n || i && i(t + 1, a) === !1) break;
283
- await I(r);
347
+ await R(r);
284
348
  }
285
349
  throw a ?? /* @__PURE__ */ Error("Retry failed: unknown error");
286
350
  }
287
- function F(e) {
351
+ function L(e) {
288
352
  return typeof e == "number" ? e >= 400 && e < 500 && e !== 408 && e !== 429 : !1;
289
353
  }
290
- function I(e) {
354
+ function R(e) {
291
355
  return new Promise((t) => setTimeout(t, e));
292
356
  }
293
357
  //#endregion
294
358
  //#region src/transport/http-transport.ts
295
- var L = class {
359
+ var z = class {
296
360
  constructor(e) {
297
361
  this.tokenRefreshPromise = null, this.accessToken = e.accessToken, this.debug = e.debug ?? !1, this.onUnauthorized = e.onUnauthorized;
298
362
  }
@@ -301,7 +365,7 @@ var L = class {
301
365
  }
302
366
  async request(e) {
303
367
  try {
304
- return await P(() => this.executeRequest(e), this.getRetryOptions());
368
+ return await I(() => this.executeRequest(e), this.getRetryOptions());
305
369
  } catch (t) {
306
370
  throw t instanceof p ? t : new x(`Network error: ${t instanceof Error ? t.message : "Unknown error"}`, {
307
371
  url: e.url,
@@ -405,7 +469,7 @@ var L = class {
405
469
  this.debug && console.log(`[ScribeSDK] Retry attempt ${e}:`, t.message);
406
470
  } };
407
471
  }
408
- }, R = class {
472
+ }, B = class {
409
473
  constructor(e) {
410
474
  this.pendingRequests = /* @__PURE__ */ new Map(), this.correlationCounter = 0, this.tokenRefreshPromise = null, this.bridge = e.bridge, this.accessToken = e.accessToken, this.debug = e.debug ?? !1, this.onUnauthorized = e.onUnauthorized, this.bridge.onResponse((e) => {
411
475
  this.handleResponse(e);
@@ -416,7 +480,7 @@ var L = class {
416
480
  }
417
481
  async request(e) {
418
482
  try {
419
- return await P(() => this.executeRequest(e), this.getRetryOptions());
483
+ return await I(() => this.executeRequest(e), this.getRetryOptions());
420
484
  } catch (t) {
421
485
  throw t instanceof p ? t : new x(`IPC error: ${t instanceof Error ? t.message : "Unknown error"}`, {
422
486
  url: e.url,
@@ -557,7 +621,7 @@ var L = class {
557
621
  };
558
622
  //#endregion
559
623
  //#region src/discovery/resolved-config.ts
560
- function z(e) {
624
+ function V(e) {
561
625
  try {
562
626
  let t = /* @__PURE__ */ new Map(), n = e.models ?? [];
563
627
  for (let e of n) e.id && typeof e.max_session_duration_seconds == "number" && t.set(e.id, e.max_session_duration_seconds);
@@ -581,7 +645,7 @@ function z(e) {
581
645
  }
582
646
  //#endregion
583
647
  //#region src/discovery/discovery-manager.ts
584
- var B = class {
648
+ var H = class {
585
649
  constructor(e, t, n = !1) {
586
650
  this.cachedDocument = null, this.resolvedConfig = null, this.cacheTimestamp = 0, this.cacheTtlMs = i, this.transport = e, this.validator = t, this.debug = n;
587
651
  }
@@ -595,7 +659,7 @@ var B = class {
595
659
  url: n
596
660
  });
597
661
  this.validator.validateDiscoveryResponse(i.data);
598
- let a = i.data, o = z(a);
662
+ let a = i.data, o = V(a);
599
663
  return this.cachedDocument = a, this.resolvedConfig = o, this.cacheTimestamp = Date.now(), this.debug && console.log("[ScribeSDK] Discovery complete:", a.service?.name ?? a.protocol), o;
600
664
  } catch (t) {
601
665
  throw t instanceof h ? t : new h(`Failed to fetch discovery document: ${t instanceof Error ? t.message : "Unknown error"}`, { baseUrl: e });
@@ -645,7 +709,7 @@ var B = class {
645
709
  isCacheValid() {
646
710
  return Date.now() - this.cacheTimestamp < this.cacheTtlMs;
647
711
  }
648
- }, V = class {
712
+ }, U = class {
649
713
  constructor(e, t, n = !1) {
650
714
  this.currentSession = null, this.transport = e, this.validator = t, this.debug = n;
651
715
  }
@@ -681,23 +745,56 @@ var B = class {
681
745
  throw e instanceof p ? e : new p(`Failed to end session: ${e instanceof Error ? e.message : "Unknown error"}`);
682
746
  }
683
747
  }
684
- async getSessionStatus(e, t) {
748
+ async getSessionStatus(e, t, n) {
685
749
  try {
686
- let n = t ?? this.currentSession?.session_id;
687
- if (!n) throw new p("No active session. Provide a sessionId or start a session first.");
688
- this.validator.validateSessionId(n);
689
- let r = `${e}/sessions/${n}`;
690
- this.debug && console.log("[ScribeSDK] Getting session status:", n);
691
- let i = await this.transport.request({
750
+ let r = t ?? this.currentSession?.session_id;
751
+ if (!r) throw new p("No active session. Provide a sessionId or start a session first.");
752
+ this.validator.validateSessionId(r);
753
+ let i = `${e}/sessions/${r}`;
754
+ n && (i += `?template_id=${encodeURIComponent(n)}`), this.debug && console.log("[ScribeSDK] Getting session status:", r);
755
+ let a = await this.transport.request({
692
756
  method: "GET",
693
- url: r,
757
+ url: i,
694
758
  acceptStatuses: [410]
695
759
  });
696
- return this.validator.validateGetSessionStatusResponse(i.data), this.debug && console.log("[ScribeSDK] Session status:", n, i.data.status), i.data;
760
+ return this.validator.validateGetSessionStatusResponse(a.data), this.debug && console.log("[ScribeSDK] Session status:", r, a.data.status), a.data;
697
761
  } catch (e) {
698
762
  throw e instanceof p ? e : new p(`Failed to get session status: ${e instanceof Error ? e.message : "Unknown error"}`);
699
763
  }
700
764
  }
765
+ async patchSession(e, t, n) {
766
+ try {
767
+ let r = n ?? this.currentSession?.session_id;
768
+ if (!r) throw new p("No active session. Provide a sessionId or start a session first.");
769
+ this.validator.validateSessionId(r), this.validator.validatePatchSessionRequest(t);
770
+ let i = `${e}/sessions/${r}`;
771
+ this.debug && console.log("[ScribeSDK] Patching session:", r, t);
772
+ let a = await this.transport.request({
773
+ method: "PATCH",
774
+ url: i,
775
+ body: t
776
+ });
777
+ return this.validator.validatePatchSessionResponse(a.data), this.debug && console.log("[ScribeSDK] Session patched:", r, a.data.status), a.data;
778
+ } catch (e) {
779
+ throw e instanceof p ? e : new p(`Failed to patch session: ${e instanceof Error ? e.message : "Unknown error"}`);
780
+ }
781
+ }
782
+ async processTemplate(e, t, n) {
783
+ try {
784
+ let r = n ?? this.currentSession?.session_id;
785
+ if (!r) throw new p("No active session. Provide a sessionId or start a session first.");
786
+ this.validator.validateSessionId(r);
787
+ let i = `${e}/sessions/${r}/process/template/${encodeURIComponent(t)}`;
788
+ this.debug && console.log("[ScribeSDK] Processing template:", t, "for session:", r);
789
+ let a = await this.transport.request({
790
+ method: "POST",
791
+ url: i
792
+ });
793
+ return this.validator.validateProcessTemplateResponse(a.data), this.debug && console.log("[ScribeSDK] Template processing triggered:", t, a.data.status), a.data;
794
+ } catch (e) {
795
+ throw e instanceof p ? e : new p(`Failed to process template: ${e instanceof Error ? e.message : "Unknown error"}`);
796
+ }
797
+ }
701
798
  async pollForCompletion(e, t, n) {
702
799
  try {
703
800
  let r = t ?? this.currentSession?.session_id;
@@ -737,13 +834,13 @@ var B = class {
737
834
  sleep(e) {
738
835
  return new Promise((t) => setTimeout(t, e));
739
836
  }
740
- }, H = 1024, U = 16e3;
741
- H / U, U / H;
742
- var W = {
837
+ }, W = 1024, G = 16e3;
838
+ W / G, G / W;
839
+ var K = {
743
840
  m4a: "audio/m4a",
744
841
  wav: "audio/wav",
745
842
  mp3: "audio/mpeg"
746
- }, G = class {
843
+ }, q = class {
747
844
  constructor(e, t) {
748
845
  this.vadPast = [], this.lastClipIndex = 0, this.clipPoints = [0], this.silDurationAcc = 0, this.micVad = null, this.micStream = null, this.isLoading = !0, this.isRecording = !1, this.noSpeechStartTime = null, this.lastWarningTime = null;
749
846
  let n = e.samplingRate;
@@ -872,7 +969,7 @@ var W = {
872
969
  } catch {}
873
970
  this.micStream = null;
874
971
  }
875
- }, K = class {
972
+ }, J = class {
876
973
  constructor(e, t) {
877
974
  this.currentSampleLength = 0, this.currentFrameLength = 0, this.samplingRate = e, this.incrementalAllocationSize = Math.floor(e * t), this.buffer = new Float32Array(this.incrementalAllocationSize);
878
975
  }
@@ -922,7 +1019,7 @@ var W = {
922
1019
  formatTimestamp(e) {
923
1020
  return `${Math.floor(e / 60).toString().padStart(2, "0")}:${(e % 60).toFixed(6).padStart(9, "0")}`;
924
1021
  }
925
- }, q = class {
1022
+ }, Y = class {
926
1023
  constructor() {
927
1024
  this.chunks = [], this.successfulUploads = [], this.totalRawSamples = 0, this.totalRawFrames = 0, this.totalInsertedSamples = 0, this.totalInsertedFrames = 0;
928
1025
  }
@@ -1007,7 +1104,7 @@ var W = {
1007
1104
  };
1008
1105
  //#endregion
1009
1106
  //#region src/audio/mp3-encoder.ts
1010
- function J(e, t = U, r = 128) {
1107
+ function X(e, t = G, r = 128) {
1011
1108
  try {
1012
1109
  let i = new n.Mp3Encoder(1, t, r), a = new Int16Array(e.length);
1013
1110
  for (let t = 0; t < e.length; t++) {
@@ -1017,14 +1114,14 @@ function J(e, t = U, r = 128) {
1017
1114
  let o = [], s = i.encodeBuffer(a);
1018
1115
  s && s.length > 0 && o.push(s);
1019
1116
  let c = i.flush();
1020
- return c && c.length > 0 && o.push(c), o.length === 0 ? null : new Blob(o, { type: W.mp3 });
1117
+ return c && c.length > 0 && o.push(c), o.length === 0 ? null : new Blob(o, { type: K.mp3 });
1021
1118
  } catch (e) {
1022
1119
  return console.error("[ScribeSDK] MP3 encoding failed:", e), null;
1023
1120
  }
1024
1121
  }
1025
1122
  //#endregion
1026
1123
  //#region src/worker/worker-manager.ts
1027
- var Y = class {
1124
+ var re = class {
1028
1125
  constructor(e, t, n, r) {
1029
1126
  if (this.worker = null, this.port = null, this.useWorker = !1, this.uploadUrl = "", this.uploadHeaders = {}, this.pendingUploads = /* @__PURE__ */ new Set(), this.allUploadsResolver = null, this.callbackRegistry = e, this.fileManager = t, this.transport = n, !r?.forceMainThread && typeof SharedWorker < "u" && r?.workerScriptUrl) try {
1030
1127
  this.worker = new SharedWorker(r.workerScriptUrl, { name: "scribe-sdk-worker" }), this.port = this.worker.port, this.port.onmessage = (e) => {
@@ -1118,7 +1215,7 @@ var Y = class {
1118
1215
  async doMainThreadUpload(e, t, n) {
1119
1216
  let r = null;
1120
1217
  try {
1121
- if (r = J(e), !r) {
1218
+ if (r = X(e), !r) {
1122
1219
  this.fileManager.markFailure(n, new Blob(), "MP3 encoding failed"), this.callbackRegistry.dispatch("onUploadEvent", {
1123
1220
  type: "failed",
1124
1221
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
@@ -1162,9 +1259,9 @@ var Y = class {
1162
1259
  }
1163
1260
  });
1164
1261
  }
1165
- }, X = class {
1262
+ }, Z = class {
1166
1263
  constructor(e, t, n, r) {
1167
- this._isPaused = !1, this.initialized = !1, this.callbackRegistry = e, this.bufferManager = new K(U, 25), this.fileManager = new q();
1264
+ this._isPaused = !1, this.initialized = !1, this.callbackRegistry = e, this.bufferManager = new J(G, 25), this.fileManager = new Y();
1168
1265
  let i = {
1169
1266
  prefChunkLength: n?.prefChunkLength ?? 10,
1170
1267
  despChunkLength: n?.despChunkLength ?? 20,
@@ -1175,7 +1272,7 @@ var Y = class {
1175
1272
  shortSilenceThreshold: n?.shortSilenceThreshold,
1176
1273
  longSilenceThreshold: n?.longSilenceThreshold
1177
1274
  };
1178
- this.vadClient = new G(i, e), this.workerManager = new Y(e, this.fileManager, t, r), this.wireVadCallbacks();
1275
+ this.vadClient = new q(i, e), this.workerManager = new re(e, this.fileManager, t, r), this.wireVadCallbacks();
1179
1276
  }
1180
1277
  initialize(e, t) {
1181
1278
  try {
@@ -1283,7 +1380,7 @@ var Y = class {
1283
1380
  flushRemainingAudio() {
1284
1381
  this.bufferManager.getCurrentSampleLength() > 0 && this.handleClipPoint();
1285
1382
  }
1286
- }, Z = class {
1383
+ }, ie = class {
1287
1384
  constructor(e, t) {
1288
1385
  this.mediaRecorder = null, this.audioChunks = [], this.micStream = null, this._isPaused = !1, this.uploadUrl = "", this.uploadHeaders = {}, this.callbackRegistry = e, this.transport = t;
1289
1386
  }
@@ -1422,7 +1519,10 @@ var Y = class {
1422
1519
  model: t.model,
1423
1520
  language_hint: t.languageHint,
1424
1521
  transcript_language: t.transcriptLanguage,
1425
- additional_data: t.additionalData
1522
+ additional_data: t.additionalData,
1523
+ session_mode: t.sessionMode,
1524
+ patient_details: t.patientDetails,
1525
+ txn_id: t.txnId
1426
1526
  };
1427
1527
  try {
1428
1528
  let i;
@@ -1447,7 +1547,7 @@ var Y = class {
1447
1547
  } catch (e) {
1448
1548
  throw this.cleanupRecordingState(), this.dispatchStartError("validation_error", "recorder_init_failed", e), e;
1449
1549
  }
1450
- this.recorder instanceof X && this.applyDiscoveryOverrides(this.recorder);
1550
+ this.recorder instanceof Z && this.applyDiscoveryOverrides(this.recorder);
1451
1551
  try {
1452
1552
  await this.recorder.start(t.deviceId);
1453
1553
  } catch (e) {
@@ -1479,7 +1579,7 @@ var Y = class {
1479
1579
  } catch (e) {
1480
1580
  throw this.cleanupRecordingState(), this.dispatchStartError("validation_error", "recorder_init_failed", e), e;
1481
1581
  }
1482
- this.recorder instanceof X && this.applyDiscoveryOverrides(this.recorder);
1582
+ this.recorder instanceof Z && this.applyDiscoveryOverrides(this.recorder);
1483
1583
  try {
1484
1584
  await this.recorder.start(n?.deviceId);
1485
1585
  } catch (e) {
@@ -1513,11 +1613,14 @@ var Y = class {
1513
1613
  try {
1514
1614
  let e = await this.recorder.stop();
1515
1615
  if (this.preserveRetryContext(), this.activeSession) try {
1516
- let t = await this.sessionManager.endSession(this.activeBaseUrl, { audio_files_sent: e.totalFiles }, this.activeSession.session_id);
1616
+ let t = e.totalFiles - e.failedUploads.length, n = await this.sessionManager.endSession(this.activeBaseUrl, {
1617
+ audio_files_sent: e.totalFiles,
1618
+ audio_files_uploaded: t
1619
+ }, this.activeSession.session_id);
1517
1620
  this.callbackRegistry.dispatch("onSessionEvent", {
1518
1621
  type: "ended",
1519
1622
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1520
- data: t
1623
+ data: n
1521
1624
  });
1522
1625
  } catch (e) {
1523
1626
  console.error("[ScribeSDK] Failed to end session:", e), this.callbackRegistry.dispatch("onError", {
@@ -1547,7 +1650,7 @@ var Y = class {
1547
1650
  }
1548
1651
  }
1549
1652
  updateAuthToken(e) {
1550
- this.recorder && this.recorder instanceof X && this.recorder.updateAuthToken(e), this.transport.setAuthToken(e);
1653
+ this.recorder && this.recorder instanceof Z && this.recorder.updateAuthToken(e), this.transport.setAuthToken(e);
1551
1654
  }
1552
1655
  reset() {
1553
1656
  this.recorder && this.recorder.reset(), this.retryContext = null, this.cleanupRecordingState();
@@ -1605,7 +1708,7 @@ var Y = class {
1605
1708
  };
1606
1709
  }
1607
1710
  createRecorder(e) {
1608
- return e === "single" ? new Z(this.callbackRegistry, this.transport) : new X(this.callbackRegistry, this.transport, void 0, this.config.workerConfig);
1711
+ return e === "single" ? new ie(this.callbackRegistry, this.transport) : new Z(this.callbackRegistry, this.transport, void 0, this.config.workerConfig);
1609
1712
  }
1610
1713
  buildUploadHeaders(e) {
1611
1714
  let t = {};
@@ -1628,7 +1731,7 @@ var Y = class {
1628
1731
  });
1629
1732
  }
1630
1733
  preserveRetryContext() {
1631
- if (!(this.recorder instanceof X)) return;
1734
+ if (!(this.recorder instanceof Z)) return;
1632
1735
  let e = this.recorder.getFileManager().getFailedChunksWithBlobs();
1633
1736
  if (e.length === 0 || !this.activeSession?.upload_url) {
1634
1737
  this.retryContext = null;
@@ -1645,14 +1748,14 @@ var Y = class {
1645
1748
  cleanupRecordingState() {
1646
1749
  this.recorder = null, this.activeSession = null, this.activeBaseUrl = "", this._isRecording = !1, this._isStarting = !1;
1647
1750
  }
1648
- }, ne = class {
1751
+ }, ae = class {
1649
1752
  constructor(e) {
1650
1753
  this.isInitialized = !1, this.validateConfig(e), this.config = {
1651
1754
  debug: !1,
1652
1755
  autoDiscovery: !0,
1653
1756
  mode: l.DIRECT,
1654
1757
  ...e
1655
- }, this.callbackRegistry = new w(), this.validator = new N(), this.transport = this.createTransport(), this.discoveryManager = new B(this.transport, this.validator, this.config.debug), this.sessionManager = new V(this.transport, this.validator, this.config.debug), this.recordingManager = new Q(this.callbackRegistry, this.sessionManager, this.discoveryManager, this.transport, {
1758
+ }, this.callbackRegistry = new w(), this.validator = new F(), this.transport = this.createTransport(), this.discoveryManager = new H(this.transport, this.validator, this.config.debug), this.sessionManager = new U(this.transport, this.validator, this.config.debug), this.recordingManager = new Q(this.callbackRegistry, this.sessionManager, this.discoveryManager, this.transport, {
1656
1759
  debug: this.config.debug,
1657
1760
  workerConfig: this.resolveWorkerConfig()
1658
1761
  });
@@ -1708,11 +1811,28 @@ var Y = class {
1708
1811
  }
1709
1812
  async getSessionStatus(e, t) {
1710
1813
  let n = this.getEffectiveBaseUrl();
1711
- return t?.poll ? this.wrapResult(() => this.sessionManager.pollForCompletion(n, e, t.poll)) : this.wrapResult(() => this.sessionManager.getSessionStatus(n, e));
1814
+ return t?.poll ? this.wrapResult(() => this.sessionManager.pollForCompletion(n, e, t.poll)) : this.wrapResult(() => this.sessionManager.getSessionStatus(n, e, t?.templateId));
1712
1815
  }
1713
1816
  getCurrentSession() {
1714
1817
  return this.recordingManager.getActiveSession() ?? this.sessionManager.getCurrentSession();
1715
1818
  }
1819
+ async updateSession(e, t) {
1820
+ let n = this.getEffectiveBaseUrl();
1821
+ return this.wrapResult(() => this.sessionManager.patchSession(n, e, t));
1822
+ }
1823
+ async processTemplate(e, t) {
1824
+ let n = this.getEffectiveBaseUrl();
1825
+ return this.wrapResult(() => this.sessionManager.processTemplate(n, e, t));
1826
+ }
1827
+ async cancelSession(e) {
1828
+ if (this.recordingManager.isRecording()) try {
1829
+ await this.recordingManager.stop();
1830
+ } catch {}
1831
+ return this.recordingManager.reset(), this.sessionManager.clearCurrentSession(), this.updateSession({
1832
+ user_status: "cancelled",
1833
+ processing_status: "cancelled"
1834
+ }, e);
1835
+ }
1716
1836
  getDiscoveryConfig() {
1717
1837
  try {
1718
1838
  return {
@@ -1774,14 +1894,14 @@ var Y = class {
1774
1894
  }) : Promise.resolve(void 0);
1775
1895
  if (this.config.mode === l.IPC) {
1776
1896
  if (!this.config.ipcTransport) throw new m("ipcTransport (IpcBridge) is required when mode is \"ipc\"");
1777
- return new R({
1897
+ return new B({
1778
1898
  bridge: this.config.ipcTransport,
1779
1899
  accessToken: this.config.accessToken,
1780
1900
  debug: this.config.debug,
1781
1901
  onUnauthorized: e
1782
1902
  });
1783
1903
  }
1784
- return new L({
1904
+ return new z({
1785
1905
  accessToken: this.config.accessToken,
1786
1906
  debug: this.config.debug,
1787
1907
  onUnauthorized: e
@@ -1805,7 +1925,7 @@ var Y = class {
1805
1925
  if (!e.baseUrl) throw new m("baseUrl is required");
1806
1926
  }
1807
1927
  }, $ = "worker.bundle.js";
1808
- function re() {
1928
+ function oe() {
1809
1929
  if (typeof window < "u" && window.__MEDSCRIBE_WORKER_URL__) return window.__MEDSCRIBE_WORKER_URL__;
1810
1930
  if (typeof document < "u" && document.currentScript) {
1811
1931
  let e = document.currentScript.src;
@@ -1813,11 +1933,11 @@ function re() {
1813
1933
  }
1814
1934
  return `/${$}`;
1815
1935
  }
1816
- async function ie(e) {
1936
+ async function se(e) {
1817
1937
  let t = e ?? `https://cdn.jsdelivr.net/npm/med-scribe-alliance-ts-sdk/dist/${$}`, n = await fetch(t);
1818
1938
  if (!n.ok) throw Error(`Failed to fetch worker script: ${n.status} ${n.statusText}`);
1819
1939
  let r = await n.text(), i = new Blob([r], { type: "application/javascript" });
1820
1940
  return URL.createObjectURL(i);
1821
1941
  }
1822
1942
  //#endregion
1823
- export { g as AuthenticationError, w as CallbackRegistry, c as CommunicationProtocol, h as DiscoveryError, B as DiscoveryManager, u as ErrorCode, _ as ForbiddenError, d as HttpStatus, L as HttpTransport, R as IpcTransport, b as RateLimitError, Q as RecordingManager, ne as ScribeClient, p as ScribeError, y as SessionExpiredError, V as SessionManager, v as SessionNotFoundError, a as SessionStatus, o as TemplateStatus, x as TransportError, l as TransportMode, C as UploadError, s as UploadType, m as ValidationError, N as Validator, S as WorkerError, ie as createWorkerBlobUrl, re as getWorkerUrl };
1943
+ export { g as AuthenticationError, w as CallbackRegistry, c as CommunicationProtocol, h as DiscoveryError, H as DiscoveryManager, u as ErrorCode, _ as ForbiddenError, d as HttpStatus, z as HttpTransport, B as IpcTransport, b as RateLimitError, Q as RecordingManager, ae as ScribeClient, p as ScribeError, y as SessionExpiredError, U as SessionManager, v as SessionNotFoundError, a as SessionStatus, o as TemplateStatus, x as TransportError, l as TransportMode, C as UploadError, s as UploadType, m as ValidationError, F as Validator, S as WorkerError, se as createWorkerBlobUrl, oe as getWorkerUrl };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "med-scribe-alliance-ts-sdk",
3
- "version": "2.0.2",
3
+ "version": "2.0.4",
4
4
  "description": "TypeScript SDK for the MedScribe Alliance Protocol",
5
5
  "main": "dist/index.mjs",
6
6
  "module": "dist/index.mjs",