@omniloy/sofia-sdk 1.0.9 → 1.0.11

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.
@@ -3,6 +3,9 @@ import { JSX } from 'react/jsx-runtime';
3
3
  import * as React_2 from 'react';
4
4
  import { VariantProps } from 'class-variance-authority';
5
5
 
6
+ /** Where audio stopped flowing, as reported by the recording pipeline. */
7
+ export declare type AudioLossCause = 'mic' | 'network' | 'server';
8
+
6
9
  export declare function Button({ className, variant, size, asChild, isDisabled, isLoading, text, whitespace, rounded, type, ...props }: ButtonProps): JSX.Element;
7
10
 
8
11
  declare type ButtonProps = React_2.ComponentProps<'button'> & VariantProps<typeof buttonVariants> & {
@@ -15,8 +18,8 @@ declare type ButtonProps = React_2.ComponentProps<'button'> & VariantProps<typeo
15
18
  };
16
19
 
17
20
  declare const buttonVariants: (props?: ({
18
- variant?: "report" | "default" | "icon" | "destructive" | "outline" | "secondary" | "ghost" | "empty" | "primary" | null | undefined;
19
- size?: "default" | "icon" | "padding" | "empty" | "sm" | "lg" | null | undefined;
21
+ variant?: "report" | "default" | "destructive" | "outline" | "secondary" | "ghost" | "empty" | "primary" | "icon" | null | undefined;
22
+ size?: "default" | "empty" | "icon" | "sm" | "lg" | "padding" | null | undefined;
20
23
  } & ClassProp) | undefined) => string;
21
24
 
22
25
  declare interface CuratedReport {
@@ -63,6 +66,11 @@ declare interface InsertionPreviewClassNames {
63
66
  cancelButton?: string;
64
67
  }
65
68
 
69
+ /** Coarse area of the widget the clinician touched. */
70
+ export declare type InteractionKind = 'recording' | 'chat' | 'settings' | 'report' | 'transcript' | 'history' | 'widget';
71
+
72
+ export declare type KnownSdkEventName = 'recording.started' | 'recording.stopped' | 'recording.audio_lost' | 'recording.microphone_disconnected' | 'recording.heartbeat' | 'activity.interaction' | 'activity.typing' | 'report.generation_started' | 'report.settled' | 'lifecycle.ready' | 'lifecycle.closed';
73
+
66
74
  export declare enum LanguageCode {
67
75
  ar = "ar",
68
76
  ca = "ca",
@@ -252,8 +260,152 @@ export declare interface OmniscribeProps {
252
260
  * the appropriate action. To change the delivered shape, change templateExtras.
253
261
  */
254
262
  handleExtras?: (extras: Extra[]) => void;
263
+ /**
264
+ * Subscribe to the SDK's activity stream.
265
+ *
266
+ * Called with a typed, PHI-free event whenever something the host asked
267
+ * for happens inside the widget. Payloads carry only enums, booleans and
268
+ * numbers — never clinical content, message text or patient identifiers.
269
+ * Clinical content has its own explicitly scoped channels (`handleReport`,
270
+ * `onReportApply`, `handleExtras`).
271
+ *
272
+ * The primary use case is knowing whether the clinician is working, so the
273
+ * host can run an inactivity timeout:
274
+ * ```
275
+ * onEvent={e => {
276
+ * if (e.name === 'recording.started') idleTimer.cancel();
277
+ * if (e.name === 'recording.stopped') idleTimer.start();
278
+ * if (e.family === 'activity') idleTimer.reset();
279
+ * }}
280
+ * ```
281
+ * Suppress the timer between `report.generation_started` and
282
+ * `report.settled` — generation runs for tens of seconds with no user
283
+ * input, and closing the widget there loses the note.
284
+ *
285
+ * If the host must keep an *external* session alive (an auto-logout on
286
+ * inactivity), key off `recording.heartbeat` instead of the
287
+ * `started`/`stopped` pair. It beats every ~30s while audio is actually
288
+ * flowing to the transcriber, needs no host-side state, and stops by
289
+ * itself the moment a recording silently breaks:
290
+ * ```
291
+ * onEvent={e => {
292
+ * if (e.name === 'recording.heartbeat') session.keepAlive();
293
+ * }}
294
+ * ```
295
+ *
296
+ * Delivered asynchronously on a microtask, so a slow handler cannot block
297
+ * recording. Requires `eventSubscriptions`; without it nothing is sent.
298
+ */
299
+ onEvent?: SdkEventHandler;
300
+ /**
301
+ * Which events `onEvent` should receive. Exact names
302
+ * (`'recording.started'`), family wildcards (`'recording.*'`), or `'*'`.
303
+ *
304
+ * Omitted or empty means no events are delivered — subscription is
305
+ * explicit so the SDK never does work for a listener that does not exist.
306
+ */
307
+ eventSubscriptions?: SdkEventSubscription[];
255
308
  }
256
309
 
310
+ export declare type RecordingMode = 'consultation' | 'dictation';
311
+
312
+ export declare interface SdkEvent<N extends SdkEventName = SdkEventName> {
313
+ /** Fully qualified name, e.g. `'recording.started'`. */
314
+ name: N;
315
+ /** The part of `name` before the dot. */
316
+ family: SdkEventFamily;
317
+ level: 'info' | 'warn' | 'error';
318
+ /** ISO-8601. */
319
+ ts: string;
320
+ /**
321
+ * Monotonic per page load. Restores ordering that the fire-and-forget
322
+ * analytics POSTs cannot guarantee.
323
+ */
324
+ seq: number;
325
+ sdkVersion: string;
326
+ /** Random per-session UUID. Not an identifier for a person. */
327
+ sessionId: string | null;
328
+ payload: SdkEventPayload<N>;
329
+ }
330
+
331
+ /**
332
+ * Public, host-facing SDK event vocabulary.
333
+ *
334
+ * PRIVACY INVARIANT — read before adding an event.
335
+ * No payload field may carry user-, patient-, or clinician-derived text.
336
+ * Every field is a string-literal union, a boolean, or a number. Errors
337
+ * travel as codes, never as messages; reports as counts, never as content.
338
+ * A host that needs clinical content already has purpose-built, explicitly
339
+ * scoped channels for it (`handleReport`, `onReportApply`, `handleExtras`).
340
+ * `sdk-events.types.test.ts` fails the build if an unconstrained `string`
341
+ * appears in `SdkEventPayloadMap`.
342
+ *
343
+ * This vocabulary is deliberately separate from the internal analytics
344
+ * `AppEventName`. Merging them would make every internal telemetry addition
345
+ * a public breaking change.
346
+ */
347
+ export declare type SdkEventFamily = 'recording' | 'activity' | 'report' | 'lifecycle';
348
+
349
+ /** Handler shape for the `onEvent` prop. */
350
+ export declare type SdkEventHandler = (event: SdkEvent) => void;
351
+
352
+ /**
353
+ * Widened on purpose. New event names ship in minor releases, and a closed
354
+ * union would make every addition a type-level break for hosts that switch
355
+ * exhaustively. Hosts wanting exhaustiveness narrow to `KnownSdkEventName`.
356
+ */
357
+ export declare type SdkEventName = KnownSdkEventName | (string & {});
358
+
359
+ declare type SdkEventPayload<N extends SdkEventName> = N extends KnownSdkEventName ? SdkEventPayloadMap[N] : Record<string, unknown>;
360
+
361
+ export declare interface SdkEventPayloadMap {
362
+ 'recording.started': {
363
+ mode: RecordingMode;
364
+ };
365
+ 'recording.stopped': {
366
+ mode: RecordingMode;
367
+ durationSeconds: number;
368
+ };
369
+ 'recording.audio_lost': {
370
+ cause: AudioLossCause;
371
+ /**
372
+ * For `mic` / `network`: length of the gap, reported once audio
373
+ * recovers. For `server`: the recording position at which the socket
374
+ * closed — capture is torn down on the spot, so there is no gap to
375
+ * measure.
376
+ */
377
+ durationSeconds: number;
378
+ };
379
+ 'recording.microphone_disconnected': Record<string, never>;
380
+ /**
381
+ * Audio is actually flowing to the transcriber. Emitted from the
382
+ * audio-chunk send path, throttled — see `recording-heartbeat.ts`.
383
+ * A host that must keep an external session alive while the clinician
384
+ * records should key off this, not off `started`/`stopped`: it needs no
385
+ * host-side state and stops by itself the moment a recording silently
386
+ * breaks.
387
+ */
388
+ 'recording.heartbeat': Record<string, never>;
389
+ 'activity.interaction': {
390
+ kind: InteractionKind;
391
+ };
392
+ 'activity.typing': {
393
+ surface: TypingSurface;
394
+ };
395
+ 'report.generation_started': Record<string, never>;
396
+ 'report.settled': {
397
+ ok: boolean;
398
+ };
399
+ 'lifecycle.ready': Record<string, never>;
400
+ 'lifecycle.closed': Record<string, never>;
401
+ }
402
+
403
+ /**
404
+ * What a host asks for: an exact name, a family wildcard (`'recording.*'`),
405
+ * or everything (`'*'`).
406
+ */
407
+ export declare type SdkEventSubscription = KnownSdkEventName | `${SdkEventFamily}.*` | '*';
408
+
257
409
  /**
258
410
  * Get a value from local storage (decrypted)
259
411
  * @param key - The key to get the value from
@@ -333,6 +485,9 @@ declare type TTranscriptorSelect = {
333
485
  label: string;
334
486
  }[];
335
487
 
488
+ /** Which free-text surface received keystrokes. Never the text itself. */
489
+ export declare type TypingSurface = 'chat' | 'note';
490
+
336
491
  /**
337
492
  * Host-provided callback that returns whatever the doctor has already written
338
493
  * in SINA/HIS, keyed by template property id (e.g. `{ chief_complaint: '...',