@ohm_studio/sdk 0.2.0 → 0.5.0

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/dist/index.d.ts CHANGED
@@ -1,8 +1,10 @@
1
1
  import { OHMCoreClient } from "@ohm_studio/sdk-core";
2
- import type { OHMClientOptions } from "@ohm_studio/sdk-core";
2
+ import type { OHMInit } from "@ohm_studio/sdk-core";
3
3
  export * from "@ohm_studio/sdk-core";
4
- export { Recorder, isRecordingSupported } from "./recorder";
5
- export type { RecorderOptions, RecorderState } from "./recorder";
4
+ export { Recorder, RecorderError, isRecordingSupported } from "./recorder";
5
+ export type { RecorderOptions, RecorderState, RecorderErrorCode, MicrophoneInfo, } from "./recorder";
6
+ export { saveRecording, getRecording, listRecordings, removeRecording, clearRecordings, isPersistenceSupported, } from "./persist";
7
+ export type { PersistedRecording } from "./persist";
6
8
  /**
7
9
  * OHM Studio SDK for JavaScript / TypeScript.
8
10
  *
@@ -22,7 +24,7 @@ export type { RecorderOptions, RecorderState } from "./recorder";
22
24
  * });
23
25
  */
24
26
  export declare class OHM extends OHMCoreClient {
25
- constructor(opts: OHMClientOptions);
27
+ constructor(init: OHMInit);
26
28
  protected runMultipart<T>(opts: {
27
29
  path: string;
28
30
  file: any;
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE7D,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAC5D,YAAY,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEjE;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,GAAI,SAAQ,aAAa;gBACxB,IAAI,EAAE,gBAAgB;cAIlB,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE;QACpC,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,GAAG,CAAC;QACV,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACjC,GAAG,OAAO,CAAC,CAAC,CAAC;IAKd;;;;;;;;OAQG;cACa,kBAAkB,CAChC,IAAI,EAAE,OAAO,EACb,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,OAAO,CAAC,QAAQ,CAAC;CAuBrB;AAED,eAAe,GAAG,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAEpD,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAC3E,YAAY,EACV,eAAe,EACf,aAAa,EACb,iBAAiB,EACjB,cAAc,GACf,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,aAAa,EACb,YAAY,EACZ,cAAc,EACd,eAAe,EACf,eAAe,EACf,sBAAsB,GACvB,MAAM,WAAW,CAAC;AACnB,YAAY,EAAE,kBAAkB,EAAE,MAAM,WAAW,CAAC;AAEpD;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,GAAI,SAAQ,aAAa;gBACxB,IAAI,EAAE,OAAO;cAIT,YAAY,CAAC,CAAC,EAAE,IAAI,EAAE;QACpC,IAAI,EAAE,MAAM,CAAC;QACb,IAAI,EAAE,GAAG,CAAC;QACV,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;KACjC,GAAG,OAAO,CAAC,CAAC,CAAC;IAKd;;;;;;;;OAQG;cACa,kBAAkB,CAChC,IAAI,EAAE,OAAO,EACb,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC9B,OAAO,CAAC,QAAQ,CAAC;CAuBrB;AAED,eAAe,GAAG,CAAC"}
package/dist/index.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { OHMCoreClient } from "@ohm_studio/sdk-core";
2
2
  export * from "@ohm_studio/sdk-core";
3
- export { Recorder, isRecordingSupported } from "./recorder";
3
+ export { Recorder, RecorderError, isRecordingSupported } from "./recorder";
4
+ export { saveRecording, getRecording, listRecordings, removeRecording, clearRecordings, isPersistenceSupported, } from "./persist";
4
5
  /**
5
6
  * OHM Studio SDK for JavaScript / TypeScript.
6
7
  *
@@ -20,8 +21,8 @@ export { Recorder, isRecordingSupported } from "./recorder";
20
21
  * });
21
22
  */
22
23
  export class OHM extends OHMCoreClient {
23
- constructor(opts) {
24
- super(opts);
24
+ constructor(init) {
25
+ super(init);
25
26
  }
26
27
  async runMultipart(opts) {
27
28
  const fd = await this.buildMultipartBody(opts.file, opts.fields);
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAG5D;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,GAAI,SAAQ,aAAa;IACpC,YAAY,IAAsB;QAChC,KAAK,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;IAES,KAAK,CAAC,YAAY,CAAI,IAI/B;QACC,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAa,CAAC;QAC7E,OAAO,IAAI,CAAC,UAAU,CAAI,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED;;;;;;;;OAQG;IACO,KAAK,CAAC,kBAAkB,CAChC,IAAa,EACb,MAA+B;QAE/B,MAAM,EAAE,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC1B,IAAI,OAAO,IAAI,KAAK,WAAW,IAAI,IAAI,YAAY,IAAI,EAAE,CAAC;YACxD,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC1B,CAAC;aAAM,IAAI,OAAO,IAAI,KAAK,WAAW,IAAI,IAAI,YAAY,IAAI,EAAE,CAAC;YAC/D,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;QACvC,CAAC;aAAM,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,QAAQ,IAAK,IAAY,EAAE,CAAC;YACzE,sCAAsC;YACtC,MAAM,CAAC,GAAG,IAA6D,CAAC;YACxE,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE;gBAChC,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,0BAA0B;aAC3C,CAAC,CAAC;YACH,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,WAAW,CAAC,CAAC;QACjD,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CACb,yEAAyE,CAC1E,CAAC;QACJ,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;YAClD,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;CACF;AAED,eAAe,GAAG,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAGrD,cAAc,sBAAsB,CAAC;AACrC,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,YAAY,CAAC;AAO3E,OAAO,EACL,aAAa,EACb,YAAY,EACZ,cAAc,EACd,eAAe,EACf,eAAe,EACf,sBAAsB,GACvB,MAAM,WAAW,CAAC;AAGnB;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,OAAO,GAAI,SAAQ,aAAa;IACpC,YAAY,IAAa;QACvB,KAAK,CAAC,IAAI,CAAC,CAAC;IACd,CAAC;IAES,KAAK,CAAC,YAAY,CAAI,IAI/B;QACC,MAAM,EAAE,GAAG,MAAM,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,MAAM,CAAa,CAAC;QAC7E,OAAO,IAAI,CAAC,UAAU,CAAI,MAAM,EAAE,IAAI,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED;;;;;;;;OAQG;IACO,KAAK,CAAC,kBAAkB,CAChC,IAAa,EACb,MAA+B;QAE/B,MAAM,EAAE,GAAG,IAAI,QAAQ,EAAE,CAAC;QAC1B,IAAI,OAAO,IAAI,KAAK,WAAW,IAAI,IAAI,YAAY,IAAI,EAAE,CAAC;YACxD,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QAC1B,CAAC;aAAM,IAAI,OAAO,IAAI,KAAK,WAAW,IAAI,IAAI,YAAY,IAAI,EAAE,CAAC;YAC/D,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,WAAW,CAAC,CAAC;QACvC,CAAC;aAAM,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,QAAQ,IAAK,IAAY,EAAE,CAAC;YACzE,sCAAsC;YACtC,MAAM,CAAC,GAAG,IAA6D,CAAC;YACxE,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE;gBAChC,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,0BAA0B;aAC3C,CAAC,CAAC;YACH,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,IAAI,WAAW,CAAC,CAAC;QACjD,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,KAAK,CACb,yEAAyE,CAC1E,CAAC;QACJ,CAAC;QACD,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,EAAE,CAAC;YAClD,EAAE,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,OAAO,EAAE,CAAC;IACZ,CAAC;CACF;AAED,eAAe,GAAG,CAAC"}
@@ -0,0 +1,70 @@
1
+ /**
2
+ * IndexedDB persistence for recorded audio Blobs — survives tab crashes,
3
+ * browser closes, and connection drops mid-upload. The whole point is to
4
+ * stop doctors from losing their work.
5
+ *
6
+ * Typical clinical-app flow:
7
+ *
8
+ * const blob = await rec.stop();
9
+ * const id = await saveRecording(blob, {
10
+ * metadata: { visitId, doctorId },
11
+ * });
12
+ * try {
13
+ * await ohm.audio.extract({ apiSlug, file: blob });
14
+ * await removeRecording(id); // upload confirmed
15
+ * } catch (e) {
16
+ * // leave it in IndexedDB for next session's recovery flow
17
+ * }
18
+ *
19
+ * // On app mount:
20
+ * const pending = await listRecordings();
21
+ * if (pending.length) showRecoveryDialog(pending);
22
+ *
23
+ * Backed by `idb-keyval` (~600 B). All APIs are SSR-safe — they no-op
24
+ * gracefully when IndexedDB is unavailable (Node, very old browsers,
25
+ * private mode in some Firefox builds).
26
+ */
27
+ export interface PersistedRecording {
28
+ /** Stable unique id assigned by the SDK. */
29
+ id: string;
30
+ /** The audio blob. Pass directly to `ohm.audio.extract({ file })`. */
31
+ blob: Blob;
32
+ /** When the recording was saved (Date.now()). */
33
+ savedAt: number;
34
+ /** Customer-supplied opaque metadata (visitId, doctorId, …). */
35
+ metadata?: Record<string, unknown>;
36
+ }
37
+ /**
38
+ * Save a recording to IndexedDB. Returns its assigned id. The blob is
39
+ * stored as-is — Chrome and Firefox support large Blob values in IDB
40
+ * up to several hundred MB, plenty for a multi-hour consult.
41
+ *
42
+ * No-ops with a generated id when IndexedDB isn't available — the
43
+ * caller's flow keeps working, just without recovery-on-reload.
44
+ */
45
+ export declare function saveRecording(blob: Blob, options?: {
46
+ id?: string;
47
+ metadata?: Record<string, unknown>;
48
+ }): Promise<string>;
49
+ /**
50
+ * Read a single recording back. Returns `null` if not found or IDB unavailable.
51
+ */
52
+ export declare function getRecording(id: string): Promise<PersistedRecording | null>;
53
+ /**
54
+ * Enumerate every saved recording, newest first. Use this on app mount
55
+ * to surface a "we have 1 unsent recording from earlier" recovery prompt.
56
+ */
57
+ export declare function listRecordings(): Promise<PersistedRecording[]>;
58
+ /**
59
+ * Delete a single recording. Call this once your server has confirmed
60
+ * the audio + extracted JSON are saved.
61
+ */
62
+ export declare function removeRecording(id: string): Promise<void>;
63
+ /**
64
+ * Wipe every saved recording. Wire this to logout flows and "clear data"
65
+ * settings so a shared tablet doesn't leak between users.
66
+ */
67
+ export declare function clearRecordings(): Promise<void>;
68
+ /** True when IndexedDB is available in this runtime. */
69
+ export declare function isPersistenceSupported(): boolean;
70
+ //# sourceMappingURL=persist.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persist.d.ts","sourceRoot":"","sources":["../src/persist.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAsBH,MAAM,WAAW,kBAAkB;IACjC,4CAA4C;IAC5C,EAAE,EAAE,MAAM,CAAC;IACX,sEAAsE;IACtE,IAAI,EAAE,IAAI,CAAC;IACX,iDAAiD;IACjD,OAAO,EAAE,MAAM,CAAC;IAChB,gEAAgE;IAChE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAuBD;;;;;;;GAOG;AACH,wBAAsB,aAAa,CACjC,IAAI,EAAE,IAAI,EACV,OAAO,GAAE;IAAE,EAAE,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;CAAO,GAChE,OAAO,CAAC,MAAM,CAAC,CAYjB;AAED;;GAEG;AACH,wBAAsB,YAAY,CAChC,EAAE,EAAE,MAAM,GACT,OAAO,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAKpC;AAED;;;GAGG;AACH,wBAAsB,cAAc,IAAI,OAAO,CAAC,kBAAkB,EAAE,CAAC,CAUpE;AAED;;;GAGG;AACH,wBAAsB,eAAe,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAI/D;AAED;;;GAGG;AACH,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CAIrD;AAED,wDAAwD;AACxD,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD"}
@@ -0,0 +1,119 @@
1
+ /**
2
+ * IndexedDB persistence for recorded audio Blobs — survives tab crashes,
3
+ * browser closes, and connection drops mid-upload. The whole point is to
4
+ * stop doctors from losing their work.
5
+ *
6
+ * Typical clinical-app flow:
7
+ *
8
+ * const blob = await rec.stop();
9
+ * const id = await saveRecording(blob, {
10
+ * metadata: { visitId, doctorId },
11
+ * });
12
+ * try {
13
+ * await ohm.audio.extract({ apiSlug, file: blob });
14
+ * await removeRecording(id); // upload confirmed
15
+ * } catch (e) {
16
+ * // leave it in IndexedDB for next session's recovery flow
17
+ * }
18
+ *
19
+ * // On app mount:
20
+ * const pending = await listRecordings();
21
+ * if (pending.length) showRecoveryDialog(pending);
22
+ *
23
+ * Backed by `idb-keyval` (~600 B). All APIs are SSR-safe — they no-op
24
+ * gracefully when IndexedDB is unavailable (Node, very old browsers,
25
+ * private mode in some Firefox builds).
26
+ */
27
+ import { createStore, set as idbSet, get as idbGet, del as idbDel, keys as idbKeys, clear as idbClear, } from "idb-keyval";
28
+ const STORE_NAME = "ohm-recordings";
29
+ const DB_NAME = "ohm-studio-sdk";
30
+ let _store = null;
31
+ function store() {
32
+ if (typeof indexedDB === "undefined")
33
+ return null;
34
+ if (!_store)
35
+ _store = createStore(DB_NAME, STORE_NAME);
36
+ return _store;
37
+ }
38
+ function newId() {
39
+ // crypto.randomUUID is the right tool when available; fall back to
40
+ // a simple time+random combo for older browsers / tests.
41
+ if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
42
+ return crypto.randomUUID();
43
+ }
44
+ return ("rec_" +
45
+ Date.now().toString(36) +
46
+ "_" +
47
+ Math.random().toString(36).slice(2, 10));
48
+ }
49
+ /**
50
+ * Save a recording to IndexedDB. Returns its assigned id. The blob is
51
+ * stored as-is — Chrome and Firefox support large Blob values in IDB
52
+ * up to several hundred MB, plenty for a multi-hour consult.
53
+ *
54
+ * No-ops with a generated id when IndexedDB isn't available — the
55
+ * caller's flow keeps working, just without recovery-on-reload.
56
+ */
57
+ export async function saveRecording(blob, options = {}) {
58
+ const id = options.id ?? newId();
59
+ const s = store();
60
+ if (!s)
61
+ return id;
62
+ const record = {
63
+ id,
64
+ blob,
65
+ savedAt: Date.now(),
66
+ metadata: options.metadata,
67
+ };
68
+ await idbSet(id, record, s);
69
+ return id;
70
+ }
71
+ /**
72
+ * Read a single recording back. Returns `null` if not found or IDB unavailable.
73
+ */
74
+ export async function getRecording(id) {
75
+ const s = store();
76
+ if (!s)
77
+ return null;
78
+ const r = await idbGet(id, s);
79
+ return r ?? null;
80
+ }
81
+ /**
82
+ * Enumerate every saved recording, newest first. Use this on app mount
83
+ * to surface a "we have 1 unsent recording from earlier" recovery prompt.
84
+ */
85
+ export async function listRecordings() {
86
+ const s = store();
87
+ if (!s)
88
+ return [];
89
+ const ids = (await idbKeys(s));
90
+ const records = await Promise.all(ids.map((k) => idbGet(k, s)));
91
+ return records
92
+ .filter((r) => !!r)
93
+ .sort((a, b) => b.savedAt - a.savedAt);
94
+ }
95
+ /**
96
+ * Delete a single recording. Call this once your server has confirmed
97
+ * the audio + extracted JSON are saved.
98
+ */
99
+ export async function removeRecording(id) {
100
+ const s = store();
101
+ if (!s)
102
+ return;
103
+ await idbDel(id, s);
104
+ }
105
+ /**
106
+ * Wipe every saved recording. Wire this to logout flows and "clear data"
107
+ * settings so a shared tablet doesn't leak between users.
108
+ */
109
+ export async function clearRecordings() {
110
+ const s = store();
111
+ if (!s)
112
+ return;
113
+ await idbClear(s);
114
+ }
115
+ /** True when IndexedDB is available in this runtime. */
116
+ export function isPersistenceSupported() {
117
+ return typeof indexedDB !== "undefined";
118
+ }
119
+ //# sourceMappingURL=persist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persist.js","sourceRoot":"","sources":["../src/persist.ts"],"names":[],"mappings":"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"}
@@ -1,6 +1,7 @@
1
1
  import { type ReactNode } from "react";
2
2
  import type { AudioExtractInput, AudioExtractResult, ExtractInput, ExtractResult, SummarizeInput, SummarizeResult } from "@ohm_studio/sdk-core";
3
3
  import { OHM } from "../index";
4
+ import { RecorderError, type RecorderOptions, type RecorderState } from "../recorder";
4
5
  export declare function OhmProvider({ client, children, }: {
5
6
  client: OHM;
6
7
  children: ReactNode;
@@ -33,4 +34,92 @@ export declare function useOhmSummarize(): {
33
34
  error: Error | null;
34
35
  isPending: boolean;
35
36
  };
37
+ export interface UseRecorderOptions extends Omit<RecorderOptions, "onStateChange" | "onLevel" | "onError"> {
38
+ /**
39
+ * If supplied, on stop the recorded blob is automatically sent to
40
+ * `ohm.audio.extract({ apiSlug, file })` and exposed on `data`/`transcript`.
41
+ * Requires <OhmProvider client={...}> above.
42
+ */
43
+ apiSlug?: string;
44
+ /** Pass-through inputs for auto-extract. */
45
+ extractInputs?: Record<string, unknown>;
46
+ /** Optional language hint. */
47
+ extractLanguage?: string;
48
+ /**
49
+ * Persist the blob to IndexedDB on stop, before extraction. If the
50
+ * extraction succeeds, the persisted copy is removed. If the tab
51
+ * crashes, the recording survives and can be recovered via
52
+ * `listRecordings()`. Pass an object to attach metadata.
53
+ */
54
+ persist?: boolean | {
55
+ metadata?: Record<string, unknown>;
56
+ };
57
+ }
58
+ export interface UseRecorderReturn<T> {
59
+ state: RecorderState;
60
+ isRecording: boolean;
61
+ isPaused: boolean;
62
+ /** Linear RMS 0–1 — wire to a VU meter. */
63
+ level: number;
64
+ /** Recorded duration in seconds (live, ticks every 250ms). */
65
+ durationSec: number;
66
+ /** Resulting blob after stop. */
67
+ blob: Blob | null;
68
+ /** Recorder error, if any. */
69
+ error: RecorderError | null;
70
+ start: () => Promise<void>;
71
+ stop: () => Promise<Blob | null>;
72
+ pause: () => void;
73
+ resume: () => void;
74
+ cancel: () => void;
75
+ reset: () => void;
76
+ extracting: boolean;
77
+ transcript: string | null;
78
+ data: T | null;
79
+ extractError: Error | null;
80
+ /**
81
+ * Id of the IndexedDB-persisted recording (only set when `persist` is
82
+ * enabled). Cleared after a successful auto-extract. Survives even if
83
+ * the page reloads — see `listRecordings()` for the recovery list.
84
+ */
85
+ persistedId: string | null;
86
+ }
87
+ /**
88
+ * `useRecorder` — the one-call recorder hook for clinical apps.
89
+ *
90
+ * const r = useRecorder({ apiSlug: "opd-clinic", silenceAutoStop: { ms: 6000 } });
91
+ * <button onClick={r.isRecording ? r.stop : r.start}>
92
+ * {r.isRecording ? `Stop (${r.durationSec.toFixed(0)}s)` : "Record"}
93
+ * </button>
94
+ * {r.transcript && <pre>{r.transcript}</pre>}
95
+ */
96
+ export declare function useRecorder<T = Record<string, unknown>>(opts?: UseRecorderOptions): UseRecorderReturn<T>;
97
+ /**
98
+ * Live online/offline state via `navigator.onLine` + `online`/`offline`
99
+ * events. Use this to gate uploads and show "we'll send when you're
100
+ * back online" UX in clinical apps that often run on flaky hospital wifi.
101
+ *
102
+ * const { online } = useNetworkStatus();
103
+ * <button disabled={!online}>{online ? "Send" : "Offline"}</button>
104
+ *
105
+ * SSR-safe — returns `online: true` when `navigator` isn't available.
106
+ */
107
+ export declare function useNetworkStatus(): {
108
+ online: boolean;
109
+ };
110
+ import type { PersistedRecording as _PersistedRecording } from "../persist";
111
+ /**
112
+ * Loads the IndexedDB-saved recordings on mount. Use this on app boot
113
+ * to surface a recovery prompt:
114
+ *
115
+ * const { pending, refresh, dismiss } = usePendingRecordings();
116
+ * if (pending.length) showDialog(pending);
117
+ */
118
+ export declare function usePendingRecordings(): {
119
+ pending: _PersistedRecording[];
120
+ loading: boolean;
121
+ refresh: () => Promise<void>;
122
+ /** Drop a single id from the local list (after you've handled it). */
123
+ dismiss: (id: string) => void;
124
+ };
36
125
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,EACZ,aAAa,EACb,cAAc,EACd,eAAe,EAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAa/B,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,QAAQ,GACT,EAAE;IACD,MAAM,EAAE,GAAG,CAAC;IACZ,QAAQ,EAAE,SAAS,CAAC;CACrB,uFAEA;AAoDD,wBAAgB,aAAa,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE;IAC/D,OAAO,EAAE,MAAM,CAAC;CACjB;;;;;WAxCQ,KAAK,GAAG,IAAI;eACR,OAAO;EA4CnB;AAED,wBAAgB,kBAAkB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE;IACpE,OAAO,EAAE,MAAM,CAAC;CACjB;;;;;WAjDQ,KAAK,GAAG,IAAI;eACR,OAAO;EAqDnB;AAED,wBAAgB,eAAe;;;;;WAxDtB,KAAK,GAAG,IAAI;eACR,OAAO;EA2DnB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EASL,KAAK,SAAS,EACf,MAAM,OAAO,CAAC;AACf,OAAO,KAAK,EACV,iBAAiB,EACjB,kBAAkB,EAClB,YAAY,EACZ,aAAa,EACb,cAAc,EACd,eAAe,EAChB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,EAAE,GAAG,EAAE,MAAM,UAAU,CAAC;AAC/B,OAAO,EAEL,aAAa,EACb,KAAK,eAAe,EACpB,KAAK,aAAa,EACnB,MAAM,aAAa,CAAC;AAkBrB,wBAAgB,WAAW,CAAC,EAC1B,MAAM,EACN,QAAQ,GACT,EAAE;IACD,MAAM,EAAE,GAAG,CAAC;IACZ,QAAQ,EAAE,SAAS,CAAC;CACrB,uFAEA;AAoDD,wBAAgB,aAAa,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE;IAC/D,OAAO,EAAE,MAAM,CAAC;CACjB;;;;;WAxCQ,KAAK,GAAG,IAAI;eACR,OAAO;EA4CnB;AAED,wBAAgB,kBAAkB,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,IAAI,EAAE;IACpE,OAAO,EAAE,MAAM,CAAC;CACjB;;;;;WAjDQ,KAAK,GAAG,IAAI;eACR,OAAO;EAqDnB;AAED,wBAAgB,eAAe;;;;;WAxDtB,KAAK,GAAG,IAAI;eACR,OAAO;EA2DnB;AAID,MAAM,WAAW,kBACf,SAAQ,IAAI,CAAC,eAAe,EAAE,eAAe,GAAG,SAAS,GAAG,SAAS,CAAC;IACtE;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,aAAa,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACxC,8BAA8B;IAC9B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB;;;;;OAKG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG;QAAE,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;KAAE,CAAC;CAC5D;AAED,MAAM,WAAW,iBAAiB,CAAC,CAAC;IAClC,KAAK,EAAE,aAAa,CAAC;IACrB,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,8DAA8D;IAC9D,WAAW,EAAE,MAAM,CAAC;IACpB,iCAAiC;IACjC,IAAI,EAAE,IAAI,GAAG,IAAI,CAAC;IAClB,8BAA8B;IAC9B,KAAK,EAAE,aAAa,GAAG,IAAI,CAAC;IAC5B,KAAK,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC3B,IAAI,EAAE,MAAM,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC;IACjC,KAAK,EAAE,MAAM,IAAI,CAAC;IAClB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,KAAK,EAAE,MAAM,IAAI,CAAC;IAElB,UAAU,EAAE,OAAO,CAAC;IACpB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,IAAI,EAAE,CAAC,GAAG,IAAI,CAAC;IACf,YAAY,EAAE,KAAK,GAAG,IAAI,CAAC;IAC3B;;;;OAIG;IACH,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAED;;;;;;;;GAQG;AACH,wBAAgB,WAAW,CAAC,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrD,IAAI,GAAE,kBAAuB,GAC5B,iBAAiB,CAAC,CAAC,CAAC,CAgLtB;AAID;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,IAAI;IAAE,MAAM,EAAE,OAAO,CAAA;CAAE,CAgBtD;AAOD,OAAO,KAAK,EAAE,kBAAkB,IAAI,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAE5E;;;;;;GAMG;AACH,wBAAgB,oBAAoB,IAAI;IACtC,OAAO,EAAE,mBAAmB,EAAE,CAAC;IAC/B,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC7B,sEAAsE;IACtE,OAAO,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CAC/B,CAuBA"}
@@ -1,4 +1,6 @@
1
- import { createContext, createElement, useCallback, useContext, useState, } from "react";
1
+ import { createContext, createElement, useCallback, useContext, useEffect, useMemo, useRef, useState, } from "react";
2
+ import { Recorder, } from "../recorder";
3
+ import { saveRecording, removeRecording, } from "../persist";
2
4
  /**
3
5
  * React hooks for @ohm_studio/sdk. Mirrors `@ohm_studio/sdk-react-native/react` so a
4
6
  * snippet copies cleanly between web and mobile codebases.
@@ -55,4 +57,242 @@ export function useOhmAudioExtract(opts) {
55
57
  export function useOhmSummarize() {
56
58
  return useOhmMutation((c, input) => c.summarize(input));
57
59
  }
60
+ /**
61
+ * `useRecorder` — the one-call recorder hook for clinical apps.
62
+ *
63
+ * const r = useRecorder({ apiSlug: "opd-clinic", silenceAutoStop: { ms: 6000 } });
64
+ * <button onClick={r.isRecording ? r.stop : r.start}>
65
+ * {r.isRecording ? `Stop (${r.durationSec.toFixed(0)}s)` : "Record"}
66
+ * </button>
67
+ * {r.transcript && <pre>{r.transcript}</pre>}
68
+ */
69
+ export function useRecorder(opts = {}) {
70
+ const client = useContext(OhmContext); // optional; only used for auto-extract
71
+ const recRef = useRef(null);
72
+ const [state, setState] = useState("idle");
73
+ const [level, setLevel] = useState(0);
74
+ const [durationSec, setDurationSec] = useState(0);
75
+ const [blob, setBlob] = useState(null);
76
+ const [error, setError] = useState(null);
77
+ const [extracting, setExtracting] = useState(false);
78
+ const [transcript, setTranscript] = useState(null);
79
+ const [data, setData] = useState(null);
80
+ const [extractError, setExtractError] = useState(null);
81
+ const [persistedId, setPersistedId] = useState(null);
82
+ // Stable options ref so the recorder is built once.
83
+ const optsRef = useRef(opts);
84
+ optsRef.current = opts;
85
+ const ensureRecorder = useCallback(() => {
86
+ if (recRef.current)
87
+ return recRef.current;
88
+ const r = new Recorder({
89
+ ...optsRef.current,
90
+ onStateChange: (s) => setState(s),
91
+ onLevel: (rms) => setLevel(rms),
92
+ onError: (e) => setError(e),
93
+ });
94
+ recRef.current = r;
95
+ return r;
96
+ }, []);
97
+ // Tick duration while recording.
98
+ useEffect(() => {
99
+ if (state !== "recording")
100
+ return;
101
+ const id = setInterval(() => {
102
+ const r = recRef.current;
103
+ if (r)
104
+ setDurationSec(r.getDuration() / 1000);
105
+ }, 250);
106
+ return () => clearInterval(id);
107
+ }, [state]);
108
+ // Cleanup on unmount.
109
+ useEffect(() => {
110
+ return () => {
111
+ try {
112
+ recRef.current?.cancel();
113
+ }
114
+ catch {
115
+ /* ignore */
116
+ }
117
+ recRef.current = null;
118
+ };
119
+ }, []);
120
+ const start = useCallback(async () => {
121
+ setError(null);
122
+ setBlob(null);
123
+ setTranscript(null);
124
+ setData(null);
125
+ setExtractError(null);
126
+ setDurationSec(0);
127
+ setPersistedId(null);
128
+ const r = ensureRecorder();
129
+ await r.start();
130
+ }, [ensureRecorder]);
131
+ const stop = useCallback(async () => {
132
+ const r = recRef.current;
133
+ if (!r)
134
+ return null;
135
+ const out = await r.stop();
136
+ setBlob(out);
137
+ setDurationSec(r.getDuration() / 1000);
138
+ // Persist BEFORE extraction so a tab crash mid-upload survives.
139
+ let savedId = null;
140
+ if (optsRef.current.persist) {
141
+ const metadata = typeof optsRef.current.persist === "object"
142
+ ? optsRef.current.persist.metadata
143
+ : undefined;
144
+ try {
145
+ savedId = await saveRecording(out, { metadata });
146
+ setPersistedId(savedId);
147
+ }
148
+ catch {
149
+ // Persistence is best-effort — don't fail the recording flow
150
+ // if IndexedDB rejects the write (private mode, quota exceeded).
151
+ }
152
+ }
153
+ if (optsRef.current.apiSlug && client) {
154
+ setExtracting(true);
155
+ try {
156
+ const res = await client.audio.extract({
157
+ apiSlug: optsRef.current.apiSlug,
158
+ file: out,
159
+ inputs: optsRef.current.extractInputs,
160
+ language: optsRef.current.extractLanguage,
161
+ });
162
+ setTranscript(res.transcript ?? null);
163
+ setData(res.data);
164
+ // Server confirmed — drop the persisted copy.
165
+ if (savedId) {
166
+ await removeRecording(savedId).catch(() => {
167
+ /* ignore */
168
+ });
169
+ setPersistedId(null);
170
+ }
171
+ }
172
+ catch (e) {
173
+ setExtractError(e);
174
+ // Leave the persisted copy in place; caller can retry on next mount.
175
+ }
176
+ finally {
177
+ setExtracting(false);
178
+ }
179
+ }
180
+ return out;
181
+ }, [client]);
182
+ const pause = useCallback(() => recRef.current?.pause(), []);
183
+ const resume = useCallback(() => recRef.current?.resume(), []);
184
+ const cancel = useCallback(() => recRef.current?.cancel(), []);
185
+ const reset = useCallback(() => {
186
+ try {
187
+ recRef.current?.cancel();
188
+ }
189
+ catch {
190
+ /* ignore */
191
+ }
192
+ recRef.current = null;
193
+ setState("idle");
194
+ setLevel(0);
195
+ setDurationSec(0);
196
+ setBlob(null);
197
+ setError(null);
198
+ setTranscript(null);
199
+ setData(null);
200
+ setExtractError(null);
201
+ setPersistedId(null);
202
+ }, []);
203
+ return useMemo(() => ({
204
+ state,
205
+ isRecording: state === "recording",
206
+ isPaused: state === "paused",
207
+ level,
208
+ durationSec,
209
+ blob,
210
+ error,
211
+ start,
212
+ stop,
213
+ pause,
214
+ resume,
215
+ cancel,
216
+ reset,
217
+ extracting,
218
+ transcript,
219
+ data,
220
+ extractError,
221
+ persistedId,
222
+ }), [
223
+ state,
224
+ level,
225
+ durationSec,
226
+ blob,
227
+ error,
228
+ start,
229
+ stop,
230
+ pause,
231
+ resume,
232
+ cancel,
233
+ reset,
234
+ extracting,
235
+ transcript,
236
+ data,
237
+ extractError,
238
+ persistedId,
239
+ ]);
240
+ }
241
+ // ─── useNetworkStatus ──────────────────────────────────────────────
242
+ /**
243
+ * Live online/offline state via `navigator.onLine` + `online`/`offline`
244
+ * events. Use this to gate uploads and show "we'll send when you're
245
+ * back online" UX in clinical apps that often run on flaky hospital wifi.
246
+ *
247
+ * const { online } = useNetworkStatus();
248
+ * <button disabled={!online}>{online ? "Send" : "Offline"}</button>
249
+ *
250
+ * SSR-safe — returns `online: true` when `navigator` isn't available.
251
+ */
252
+ export function useNetworkStatus() {
253
+ const [online, setOnline] = useState(() => typeof navigator === "undefined" ? true : navigator.onLine !== false);
254
+ useEffect(() => {
255
+ if (typeof window === "undefined")
256
+ return;
257
+ const goOnline = () => setOnline(true);
258
+ const goOffline = () => setOnline(false);
259
+ window.addEventListener("online", goOnline);
260
+ window.addEventListener("offline", goOffline);
261
+ return () => {
262
+ window.removeEventListener("online", goOnline);
263
+ window.removeEventListener("offline", goOffline);
264
+ };
265
+ }, []);
266
+ return { online };
267
+ }
268
+ // ─── usePendingRecordings ─────────────────────────────────────────
269
+ import { listRecordings as _listRecordings, } from "../persist";
270
+ /**
271
+ * Loads the IndexedDB-saved recordings on mount. Use this on app boot
272
+ * to surface a recovery prompt:
273
+ *
274
+ * const { pending, refresh, dismiss } = usePendingRecordings();
275
+ * if (pending.length) showDialog(pending);
276
+ */
277
+ export function usePendingRecordings() {
278
+ const [pending, setPending] = useState([]);
279
+ const [loading, setLoading] = useState(true);
280
+ const refresh = useCallback(async () => {
281
+ setLoading(true);
282
+ try {
283
+ const rows = await _listRecordings();
284
+ setPending(rows);
285
+ }
286
+ finally {
287
+ setLoading(false);
288
+ }
289
+ }, []);
290
+ useEffect(() => {
291
+ void refresh();
292
+ }, [refresh]);
293
+ const dismiss = useCallback((id) => {
294
+ setPending((rows) => rows.filter((r) => r.id !== id));
295
+ }, []);
296
+ return { pending, loading, refresh, dismiss };
297
+ }
58
298
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,aAAa,EACb,aAAa,EACb,WAAW,EACX,UAAU,EACV,QAAQ,GAET,MAAM,OAAO,CAAC;AAWf;;;;;;;GAOG;AAEH,MAAM,UAAU,GAAG,aAAa,CAAa,IAAI,CAAC,CAAC;AAEnD,MAAM,UAAU,WAAW,CAAC,EAC1B,MAAM,EACN,QAAQ,GAIT;IACC,OAAO,aAAa,CAAC,UAAU,CAAC,QAAQ,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE,QAAQ,CAAC,CAAC;AACzE,CAAC;AAED,SAAS,SAAS;IAChB,MAAM,CAAC,GAAG,UAAU,CAAC,UAAU,CAAC,CAAC;IACjC,IAAI,CAAC,CAAC,EAAE,CAAC;QACP,MAAM,IAAI,KAAK,CACb,4DAA4D,CAC7D,CAAC;IACJ,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAQD,SAAS,cAAc,CACrB,EAAoD;IAEpD,MAAM,MAAM,GAAG,SAAS,EAAE,CAAC;IAC3B,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAyB;QACzD,IAAI,EAAE,IAAI;QACV,KAAK,EAAE,IAAI;QACX,SAAS,EAAE,KAAK;KACjB,CAAC,CAAC;IACH,MAAM,WAAW,GAAG,WAAW,CAC7B,KAAK,EAAE,KAAa,EAAE,EAAE;QACtB,QAAQ,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACvD,IAAI,CAAC;YACH,MAAM,IAAI,GAAG,MAAM,EAAE,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;YACrC,QAAQ,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;YAClD,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,QAAQ,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC,CAAC;YACvD,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC,EACD,CAAC,MAAM,EAAE,EAAE,CAAC,CACb,CAAC;IACF,OAAO;QACL,GAAG,KAAK;QACR,WAAW;QACX,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE;YACxB,KAAK,WAAW,CAAC,KAAK,CAAC,CAAC;QAC1B,CAAC;QACD,KAAK,EAAE,GAAG,EAAE,CACV,QAAQ,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,CAAC;KAC1D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa,CAA8B,IAE1D;IACC,OAAO,cAAc,CAGnB,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,CAAI,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;AACrE,CAAC;AAED,MAAM,UAAU,kBAAkB,CAA8B,IAE/D;IACC,OAAO,cAAc,CAGnB,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAI,EAAE,GAAG,KAAK,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,eAAe;IAC7B,OAAO,cAAc,CAAkC,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,CAClE,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CACnB,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/react/index.ts"],"names":[],"mappings":"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"}