@ephia/dova-sdk 1.0.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/README.md +89 -0
- package/dist/EphiaBinding-BvRmlqqC.d.ts +36 -0
- package/dist/EphiaFloatingButton-CxiF86VW.d.ts +65 -0
- package/dist/EphiaTextarea-B4_CAVUg.d.ts +183 -0
- package/dist/NativeBinding-ChG0GeSz.d.ts +53 -0
- package/dist/TargetBinding-BKGQwUMc.d.ts +89 -0
- package/dist/TiptapBinding-B-agfV2H.d.ts +45 -0
- package/dist/Transport-zdeA4Pou.d.ts +63 -0
- package/dist/audio-state-kZ3KSvux.d.ts +39 -0
- package/dist/chunk-35AJK2IO.js +1 -0
- package/dist/chunk-35AJK2IO.js.map +1 -0
- package/dist/chunk-3LXZODL4.js +886 -0
- package/dist/chunk-3LXZODL4.js.map +1 -0
- package/dist/chunk-5IK5TLSK.js +67 -0
- package/dist/chunk-5IK5TLSK.js.map +1 -0
- package/dist/chunk-7E43RY75.js +9 -0
- package/dist/chunk-7E43RY75.js.map +1 -0
- package/dist/chunk-A5UEXJ5R.js +183 -0
- package/dist/chunk-A5UEXJ5R.js.map +1 -0
- package/dist/chunk-AEE554FT.js +51 -0
- package/dist/chunk-AEE554FT.js.map +1 -0
- package/dist/chunk-DIEWY3IT.js +1332 -0
- package/dist/chunk-DIEWY3IT.js.map +1 -0
- package/dist/chunk-EGIAN7FH.js +18 -0
- package/dist/chunk-EGIAN7FH.js.map +1 -0
- package/dist/chunk-EMOEAPVU.js +486 -0
- package/dist/chunk-EMOEAPVU.js.map +1 -0
- package/dist/chunk-IDC7FHIZ.js +40 -0
- package/dist/chunk-IDC7FHIZ.js.map +1 -0
- package/dist/chunk-ITJFN3VM.js +601 -0
- package/dist/chunk-ITJFN3VM.js.map +1 -0
- package/dist/chunk-K24GNU27.js +22 -0
- package/dist/chunk-K24GNU27.js.map +1 -0
- package/dist/chunk-LXMCRXXF.js +778 -0
- package/dist/chunk-LXMCRXXF.js.map +1 -0
- package/dist/chunk-MJCEOOLW.js +122 -0
- package/dist/chunk-MJCEOOLW.js.map +1 -0
- package/dist/chunk-N7U5M3VZ.js +33 -0
- package/dist/chunk-N7U5M3VZ.js.map +1 -0
- package/dist/chunk-PSYX674B.js +27 -0
- package/dist/chunk-PSYX674B.js.map +1 -0
- package/dist/chunk-RFQRV7ML.js +33 -0
- package/dist/chunk-RFQRV7ML.js.map +1 -0
- package/dist/chunk-THNHRV2B.js +18 -0
- package/dist/chunk-THNHRV2B.js.map +1 -0
- package/dist/chunk-VSLGR64U.js +62 -0
- package/dist/chunk-VSLGR64U.js.map +1 -0
- package/dist/chunk-W2ZP674X.js +346 -0
- package/dist/chunk-W2ZP674X.js.map +1 -0
- package/dist/chunk-YWZUMUYE.js +695 -0
- package/dist/chunk-YWZUMUYE.js.map +1 -0
- package/dist/client-options-Uo6jXO8k.d.ts +64 -0
- package/dist/connection-state-Bk33YprE.d.ts +32 -0
- package/dist/core/bindings/index.d.ts +24 -0
- package/dist/core/bindings/index.js +1025 -0
- package/dist/core/bindings/index.js.map +1 -0
- package/dist/core/index.d.ts +383 -0
- package/dist/core/index.js +1284 -0
- package/dist/core/index.js.map +1 -0
- package/dist/createEphiaClient-BhdZ183V.d.ts +69 -0
- package/dist/devices/speechmike/index.d.ts +148 -0
- package/dist/devices/speechmike/index.js +40 -0
- package/dist/devices/speechmike/index.js.map +1 -0
- package/dist/headless/index.d.ts +10 -0
- package/dist/headless/index.js +25 -0
- package/dist/headless/index.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +119 -0
- package/dist/index.js.map +1 -0
- package/dist/react/index.d.ts +38 -0
- package/dist/react/index.js +70 -0
- package/dist/react/index.js.map +1 -0
- package/dist/rich-editor/index.d.ts +46 -0
- package/dist/rich-editor/index.js +13 -0
- package/dist/rich-editor/index.js.map +1 -0
- package/dist/schema-B2ycPlNB.d.ts +87 -0
- package/dist/session-APaXR48R.d.ts +12 -0
- package/dist/shared/index.d.ts +16 -0
- package/dist/shared/index.js +30 -0
- package/dist/shared/index.js.map +1 -0
- package/dist/style.css +1093 -0
- package/dist/testing/index.d.ts +84 -0
- package/dist/testing/index.js +36 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/types-D5SXPSwR.d.ts +32 -0
- package/dist/ui/index.d.ts +30 -0
- package/dist/ui/index.js +34 -0
- package/dist/ui/index.js.map +1 -0
- package/dist/useEphiaSpeechMike-CjD7DWnh.d.ts +64 -0
- package/package.json +110 -0
- package/src/core/audio/audio-worklet-source.ts +30 -0
- package/src/core/audio/index.ts +3 -0
- package/src/core/audio/voice-level-meter.test.ts +27 -0
- package/src/core/audio/voice-level-meter.ts +270 -0
- package/src/core/bindings/EphiaBinding.ts +41 -0
- package/src/core/bindings/SegmentBindingBridge.test.ts +422 -0
- package/src/core/bindings/SegmentBindingBridge.ts +377 -0
- package/src/core/bindings/TargetBinding.ts +142 -0
- package/src/core/bindings/adapters/NativeAdapter.test.ts +85 -0
- package/src/core/bindings/adapters/NativeAdapter.ts +216 -0
- package/src/core/bindings/adapters/ProseMirrorAdapter.ts +231 -0
- package/src/core/bindings/adapters/index.ts +2 -0
- package/src/core/bindings/binding-factory.ts +78 -0
- package/src/core/bindings/detect-editor-type.ts +87 -0
- package/src/core/bindings/index.ts +13 -0
- package/src/core/bindings/insertion-boundary.test.ts +38 -0
- package/src/core/bindings/insertion-boundary.ts +26 -0
- package/src/core/bindings/native/NativeBinding.test.ts +277 -0
- package/src/core/bindings/native/NativeBinding.ts +239 -0
- package/src/core/bindings/resolver.ts +18 -0
- package/src/core/bindings/targets/codemirror.binding.ts +293 -0
- package/src/core/bindings/targets/contenteditable.binding.ts +452 -0
- package/src/core/bindings/targets/index.ts +10 -0
- package/src/core/bindings/targets/monaco.binding.ts +315 -0
- package/src/core/bindings/targets/tiptap.binding.test.ts +417 -0
- package/src/core/bindings/targets/tiptap.binding.ts +1192 -0
- package/src/core/bindings/tiptap/TiptapBinding.test.ts +63 -0
- package/src/core/bindings/tiptap/TiptapBinding.ts +464 -0
- package/src/core/bindings/types.ts +41 -0
- package/src/core/client/EphiaAudioClient.ts +654 -0
- package/src/core/client/audio-capture.ts +263 -0
- package/src/core/client/client-options.ts +39 -0
- package/src/core/client/client-state.ts +18 -0
- package/src/core/client/constants.ts +23 -0
- package/src/core/client/session-api.ts +415 -0
- package/src/core/connection/connection-state.ts +78 -0
- package/src/core/connection/index.ts +6 -0
- package/src/core/index.ts +47 -0
- package/src/core/operations/textToDocumentOperations.test.ts +69 -0
- package/src/core/operations/textToDocumentOperations.ts +92 -0
- package/src/core/runtime/DictationRuntime.test.ts +578 -0
- package/src/core/runtime/DictationRuntime.ts +434 -0
- package/src/core/runtime/TranscriptApplier.test.ts +355 -0
- package/src/core/runtime/TranscriptApplier.ts +229 -0
- package/src/core/runtime/index.ts +18 -0
- package/src/core/session/index.ts +2 -0
- package/src/core/session/session-machine.test.ts +16 -0
- package/src/core/session/session-machine.ts +59 -0
- package/src/core/targets/EditorContextCollector.ts +71 -0
- package/src/core/targets/TargetManager.test.ts +194 -0
- package/src/core/targets/TargetManager.ts +194 -0
- package/src/core/targets/index.ts +10 -0
- package/src/core/text-processing/index.ts +11 -0
- package/src/core/text-processing/overlap.test.ts +35 -0
- package/src/core/text-processing/overlap.ts +101 -0
- package/src/core/text-processing/voice-formatting.normalizer.test.ts +132 -0
- package/src/core/text-processing/voice-formatting.normalizer.ts +284 -0
- package/src/core/transcript/client-transcript.reducer.ts +366 -0
- package/src/core/transcript/client-transcript.state.ts +25 -0
- package/src/core/transcript/index.ts +19 -0
- package/src/core/transcript/transcript.assembler.test.ts +205 -0
- package/src/core/transcript/transcript.assembler.ts +152 -0
- package/src/core/transcript/transcript.reducer.test.ts +199 -0
- package/src/core/transcript/transcript.reducer.ts +771 -0
- package/src/core/transcript/transcript.state.ts +123 -0
- package/src/core/transport/LiveKitTransport.publish.test.ts +226 -0
- package/src/core/transport/LiveKitTransport.ts +459 -0
- package/src/core/transport/MockTransport.ts +231 -0
- package/src/core/transport/Transport.ts +82 -0
- package/src/debug/sdk-debug-collector.ts +79 -0
- package/src/devices/index.ts +2 -0
- package/src/devices/speechmike/__tests__/EphiaSpeechMikeProvider.test.tsx +99 -0
- package/src/devices/speechmike/__tests__/speechmike-audio-resolver.test.ts +96 -0
- package/src/devices/speechmike/__tests__/speechmike-button-router.test.ts +66 -0
- package/src/devices/speechmike/__tests__/speechmike-device-manager.test.ts +201 -0
- package/src/devices/speechmike/__tests__/speechmike-led-controller.test.ts +68 -0
- package/src/devices/speechmike/browser.ts +80 -0
- package/src/devices/speechmike/constants.ts +74 -0
- package/src/devices/speechmike/dictation-support-loader.ts +81 -0
- package/src/devices/speechmike/index.ts +11 -0
- package/src/devices/speechmike/react/EphiaSpeechMikeContext.ts +34 -0
- package/src/devices/speechmike/react/EphiaSpeechMikeProvider.tsx +287 -0
- package/src/devices/speechmike/react/useEphiaSpeechMike.ts +26 -0
- package/src/devices/speechmike/speechmike-audio-resolver.ts +58 -0
- package/src/devices/speechmike/speechmike-button-router.ts +73 -0
- package/src/devices/speechmike/speechmike-device-manager.ts +461 -0
- package/src/devices/speechmike/speechmike-led-controller.ts +78 -0
- package/src/devices/speechmike/types.ts +96 -0
- package/src/dictation_support.d.ts +31 -0
- package/src/global.d.ts +10 -0
- package/src/headless/createEphiaClient.ts +220 -0
- package/src/headless/index.ts +18 -0
- package/src/index.ts +89 -0
- package/src/react/EphiaAuto.tsx +87 -0
- package/src/react/components/EphiaDictationButton.tsx +88 -0
- package/src/react/components/EphiaStatusBar.tsx +59 -0
- package/src/react/components/EphiaTextarea.tsx +295 -0
- package/src/react/ephia-react.css +318 -0
- package/src/react/hooks/targets/index.ts +3 -0
- package/src/react/hooks/targets/useEphiaCodemirror.ts +35 -0
- package/src/react/hooks/targets/useEphiaMonaco.ts +35 -0
- package/src/react/hooks/targets/useEphiaTiptap.ts +23 -0
- package/src/react/hooks/useEphia.lifecycle.test.tsx +389 -0
- package/src/react/hooks/useEphia.ts +367 -0
- package/src/react/hooks/useEphiaDiscardTarget.ts +53 -0
- package/src/react/hooks/useEphiaServerEvent.ts +33 -0
- package/src/react/hooks/useEphiaTarget.ts +47 -0
- package/src/react/hooks/useEphiaTranscript.ts +22 -0
- package/src/react/index.ts +58 -0
- package/src/react/provider/EphiaContext.ts +63 -0
- package/src/react/provider/EphiaInternalContext.ts +32 -0
- package/src/react/provider/EphiaProvider.tsx +373 -0
- package/src/react/registry/binding-factory.ts +7 -0
- package/src/react/registry/detect-editor-type.ts +2 -0
- package/src/react/registry/events.ts +37 -0
- package/src/react/registry/registries/CodeMirrorInstanceRegistry.ts +24 -0
- package/src/react/registry/registries/MonacoInstanceRegistry.ts +23 -0
- package/src/react/registry/registries/TargetRegistry.ts +327 -0
- package/src/react/registry/registries/TiptapInstanceRegistry.ts +43 -0
- package/src/react/registry/registries/index.ts +5 -0
- package/src/react/store/create-ephia-store.ts +36 -0
- package/src/react/store/types.ts +41 -0
- package/src/react/utils/flash-range.ts +24 -0
- package/src/react/utils/index.ts +1 -0
- package/src/rich-editor/adapters/tiptap.test.ts +86 -0
- package/src/rich-editor/adapters/tiptap.ts +23 -0
- package/src/rich-editor/index.ts +3 -0
- package/src/rich-editor/types.ts +24 -0
- package/src/rich-editor/use-ephia-rich-editor.test.tsx +202 -0
- package/src/rich-editor/use-ephia-rich-editor.ts +47 -0
- package/src/shared/config/endpoint.test.ts +45 -0
- package/src/shared/config/endpoint.ts +39 -0
- package/src/shared/config/schema.ts +32 -0
- package/src/shared/effective-text.ts +13 -0
- package/src/shared/errors/EphiaSdkError.ts +54 -0
- package/src/shared/errors/messages.ts +40 -0
- package/src/shared/index.ts +27 -0
- package/src/shared/state/audio-state.ts +45 -0
- package/src/shared/state/index.ts +2 -0
- package/src/shared/store/document-store.ts +32 -0
- package/src/shared/store/index.ts +2 -0
- package/src/shared/types/editors.ts +28 -0
- package/src/shared/types/session.ts +12 -0
- package/src/style.css +2 -0
- package/src/testing/index.tsx +60 -0
- package/src/ui/assets/ephia-logo.svg +4 -0
- package/src/ui/components/EphiaLogo.tsx +77 -0
- package/src/ui/index.ts +24 -0
- package/src/ui/primitives/Button.tsx +53 -0
- package/src/ui/primitives/Spinner.tsx +21 -0
- package/src/ui/primitives/index.ts +5 -0
- package/src/ui/recorder/EphiaFloatingButton.tsx +489 -0
- package/src/ui/recorder/MinimalProcessingBars.tsx +122 -0
- package/src/ui/recorder/StandardIntensityVisualizer.tsx +148 -0
- package/src/ui/recorder/appearance.ts +9 -0
- package/src/ui/recorder/index.ts +8 -0
- package/src/ui/theme.css +775 -0
package/README.md
ADDED
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
# Ephia SDK
|
|
2
|
+
|
|
3
|
+
Official JavaScript/TypeScript SDK for Ephia medical dictation.
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @ephia/dova-sdk
|
|
9
|
+
# or
|
|
10
|
+
pnpm add @ephia/dova-sdk
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## React quickstart
|
|
14
|
+
|
|
15
|
+
```tsx
|
|
16
|
+
import { EphiaProvider, useEphiaNativeTarget } from "@ephia/dova-sdk/react";
|
|
17
|
+
import { EphiaFloatingButton } from "@ephia/dova-sdk/ui";
|
|
18
|
+
import { useRef } from "react";
|
|
19
|
+
|
|
20
|
+
function ReportTextarea() {
|
|
21
|
+
const ref = useRef<HTMLTextAreaElement>(null);
|
|
22
|
+
useEphiaNativeTarget(ref, { id: "report", label: "Compte rendu" });
|
|
23
|
+
return <textarea ref={ref} placeholder="Dictez votre compte rendu..." />;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export function App() {
|
|
27
|
+
return (
|
|
28
|
+
<EphiaProvider bearerToken={token}>
|
|
29
|
+
<ReportTextarea />
|
|
30
|
+
<EphiaFloatingButton />
|
|
31
|
+
</EphiaProvider>
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## TipTap rich editor
|
|
37
|
+
|
|
38
|
+
```tsx
|
|
39
|
+
import {
|
|
40
|
+
useEphiaRichEditor,
|
|
41
|
+
createTiptapEphiaAdapter,
|
|
42
|
+
} from "@ephia/dova-sdk/rich-editor";
|
|
43
|
+
|
|
44
|
+
useEphiaRichEditor(
|
|
45
|
+
editor ? createTiptapEphiaAdapter(editor) : null,
|
|
46
|
+
{ id: "report", label: "Compte rendu" }
|
|
47
|
+
);
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Entry points
|
|
51
|
+
|
|
52
|
+
| Import | Description |
|
|
53
|
+
|---|---|
|
|
54
|
+
| `@ephia/dova-sdk/react` | Provider, hooks, React components |
|
|
55
|
+
| `@ephia/dova-sdk/rich-editor` | TipTap adapter and `useEphiaRichEditor` |
|
|
56
|
+
| `@ephia/dova-sdk/headless` | `createEphiaClient` for non-React apps |
|
|
57
|
+
| `@ephia/dova-sdk/bindings` | Low-level bindings (`NativeBinding`, `TiptapBinding`) |
|
|
58
|
+
| `@ephia/dova-sdk/ui` | Standalone UI components |
|
|
59
|
+
| `@ephia/dova-sdk/testing` | Test helpers |
|
|
60
|
+
| `@ephia/dova-sdk/speechmike` | Philips SpeechMike support |
|
|
61
|
+
| `@ephia/dova-sdk/style.css` | Default styles |
|
|
62
|
+
|
|
63
|
+
## Production endpoint
|
|
64
|
+
|
|
65
|
+
Default API endpoint:
|
|
66
|
+
|
|
67
|
+
```txt
|
|
68
|
+
https://api.ephia.app
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
## Documentation
|
|
72
|
+
|
|
73
|
+
See the public documentation in `apps/ephia-docs`.
|
|
74
|
+
|
|
75
|
+
## Architecture
|
|
76
|
+
|
|
77
|
+
The SDK V2 follows a backend-first architecture:
|
|
78
|
+
|
|
79
|
+
```txt
|
|
80
|
+
Backend Ephia
|
|
81
|
+
→ segment.preview / segment.operation
|
|
82
|
+
→ SDK
|
|
83
|
+
→ TargetManager
|
|
84
|
+
→ NativeBinding / TiptapBinding
|
|
85
|
+
→ client editor
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
The backend decides the final text, corrections, voice commands, layout and segment revisions.
|
|
89
|
+
The SDK applies the received operations into the right editable target.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { EditorContext, SegmentStage } from 'ephia-protocol';
|
|
2
|
+
|
|
3
|
+
type UpsertSegmentInput = {
|
|
4
|
+
id: string;
|
|
5
|
+
text: string;
|
|
6
|
+
stage: SegmentStage;
|
|
7
|
+
source?: string;
|
|
8
|
+
};
|
|
9
|
+
type PreviewSegmentInput = {
|
|
10
|
+
id: string;
|
|
11
|
+
text: string;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* Interface V2 unifiée pour tous les bindings éditeurs Ephia.
|
|
15
|
+
*
|
|
16
|
+
* Règles :
|
|
17
|
+
* - même segmentId + upsertSegment = update en place (never append)
|
|
18
|
+
* - segmentId connu mais range perdu = warning + no append
|
|
19
|
+
* - removeSegments est idempotent
|
|
20
|
+
* - cleanup visuel ne supprime jamais l'identité segment
|
|
21
|
+
*/
|
|
22
|
+
interface EphiaBinding {
|
|
23
|
+
readonly kind: string;
|
|
24
|
+
/** Stable reference for this binding instance. Used for idempotent lifecycle management. */
|
|
25
|
+
readonly identity?: object | string;
|
|
26
|
+
attach(): void;
|
|
27
|
+
detach(): void;
|
|
28
|
+
getText(): string;
|
|
29
|
+
getEditorContext(targetId?: string): EditorContext;
|
|
30
|
+
previewSegment?(input: PreviewSegmentInput): void;
|
|
31
|
+
upsertSegment(input: UpsertSegmentInput): void;
|
|
32
|
+
removeSegment(id: string): void;
|
|
33
|
+
removeSegments(ids: string[]): void;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export type { EphiaBinding as E, PreviewSegmentInput as P, UpsertSegmentInput as U };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React__default, { ButtonHTMLAttributes, ReactNode } from 'react';
|
|
3
|
+
import { E as EphiaStatus } from './types-D5SXPSwR.js';
|
|
4
|
+
import { E as EphiaSessionOptions } from './session-APaXR48R.js';
|
|
5
|
+
import { T as Transport } from './Transport-zdeA4Pou.js';
|
|
6
|
+
|
|
7
|
+
type ButtonProps = ButtonHTMLAttributes<HTMLButtonElement> & {
|
|
8
|
+
variant?: "primary" | "danger" | "ghost" | "outline";
|
|
9
|
+
size?: "sm" | "md" | "lg";
|
|
10
|
+
isLoading?: boolean;
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
};
|
|
13
|
+
declare function Button({ variant, size, isLoading, children, className, disabled, ...rest }: ButtonProps): react_jsx_runtime.JSX.Element;
|
|
14
|
+
|
|
15
|
+
type SpinnerProps = {
|
|
16
|
+
size?: "sm" | "md" | "lg";
|
|
17
|
+
className?: string;
|
|
18
|
+
};
|
|
19
|
+
declare function Spinner({ size, className }: SpinnerProps): react_jsx_runtime.JSX.Element;
|
|
20
|
+
|
|
21
|
+
/** Border radius presets for {@link EphiaFloatingButton}. */
|
|
22
|
+
type EphiaFloatingButtonBorderRadius = "sm" | "md" | "lg" | "full";
|
|
23
|
+
|
|
24
|
+
type EphiaFloatingButtonPosition = "bottom-right" | "bottom-left" | "bottom-center" | "top-right" | "top-left" | "top-center";
|
|
25
|
+
type EphiaFloatingButtonTheme = "light" | "dark";
|
|
26
|
+
type EphiaFloatingButtonSize = "S" | "M" | "L";
|
|
27
|
+
type EphiaFloatingButtonVariant = "minimal" | "standard";
|
|
28
|
+
type EphiaFloatingButtonInteractionMode = "toggle" | "push-to-talk";
|
|
29
|
+
type EphiaFloatingButtonCustomColors = {
|
|
30
|
+
/** Ink color: logo, visualiseur Standard, texte. Any valid CSS color. */
|
|
31
|
+
primary: string;
|
|
32
|
+
/** Background color. Any valid CSS color. */
|
|
33
|
+
secondary: string;
|
|
34
|
+
};
|
|
35
|
+
interface EphiaFloatingButtonProps {
|
|
36
|
+
/**
|
|
37
|
+
* API URL. Optional override (ex. http://localhost:8000 en dev).
|
|
38
|
+
* Sans override : EPHIA_SDK_ENDPOINT, sinon https://api.ephia.app.
|
|
39
|
+
*/
|
|
40
|
+
apiUrl?: string;
|
|
41
|
+
apiKey?: string;
|
|
42
|
+
bearerToken?: string;
|
|
43
|
+
clientType?: string;
|
|
44
|
+
transport?: Transport;
|
|
45
|
+
position?: EphiaFloatingButtonPosition;
|
|
46
|
+
theme?: EphiaFloatingButtonTheme;
|
|
47
|
+
size?: EphiaFloatingButtonSize;
|
|
48
|
+
variant?: EphiaFloatingButtonVariant;
|
|
49
|
+
colors?: EphiaFloatingButtonCustomColors;
|
|
50
|
+
/** Corner radius of the dictation control. Default `md`. */
|
|
51
|
+
borderRadius?: EphiaFloatingButtonBorderRadius;
|
|
52
|
+
/** Interaction model. `"toggle"` (default): click to start, click to stop. `"push-to-talk"`: hold to record, release to stop. */
|
|
53
|
+
interactionMode?: EphiaFloatingButtonInteractionMode;
|
|
54
|
+
className?: string;
|
|
55
|
+
style?: React__default.CSSProperties;
|
|
56
|
+
sessionOptions?: EphiaSessionOptions;
|
|
57
|
+
onError?: (error: {
|
|
58
|
+
code: string;
|
|
59
|
+
message: string;
|
|
60
|
+
}) => void;
|
|
61
|
+
onStatusChange?: (status: EphiaStatus) => void;
|
|
62
|
+
}
|
|
63
|
+
declare function EphiaFloatingButton({ apiUrl, apiKey, bearerToken, clientType, transport, position, theme, size, variant, borderRadius, interactionMode, colors, className, style, sessionOptions, onError, onStatusChange, }: EphiaFloatingButtonProps): react_jsx_runtime.JSX.Element;
|
|
64
|
+
|
|
65
|
+
export { Button as B, EphiaFloatingButton as E, Spinner as S, type ButtonProps as a, type EphiaFloatingButtonBorderRadius as b, type EphiaFloatingButtonPosition as c, type EphiaFloatingButtonProps as d, type EphiaFloatingButtonSize as e, type EphiaFloatingButtonTheme as f, type SpinnerProps as g };
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
import React__default from 'react';
|
|
3
|
+
import { b as EphiaAudioClientOptions, a as EphiaStartOptions, E as EphiaStartResult } from './client-options-Uo6jXO8k.js';
|
|
4
|
+
import { E as EphiaStatus, b as EphiaError, c as EphiaPartial } from './types-D5SXPSwR.js';
|
|
5
|
+
import { E as EphiaConnectionState } from './connection-state-Bk33YprE.js';
|
|
6
|
+
import { a as EphiaAudioState } from './audio-state-kZ3KSvux.js';
|
|
7
|
+
import { ResetReason, EphiaServerEvent } from 'ephia-protocol';
|
|
8
|
+
import { Editor } from '@tiptap/core';
|
|
9
|
+
|
|
10
|
+
interface EphiaProviderProps {
|
|
11
|
+
children: React__default.ReactNode;
|
|
12
|
+
apiUrl?: string;
|
|
13
|
+
apiKey?: string;
|
|
14
|
+
bearerToken?: string;
|
|
15
|
+
clientType?: string;
|
|
16
|
+
transport?: EphiaAudioClientOptions["transport"];
|
|
17
|
+
options?: {
|
|
18
|
+
language?: string;
|
|
19
|
+
medicalDomain?: string;
|
|
20
|
+
sessionOptions?: EphiaAudioClientOptions["sessionOptions"];
|
|
21
|
+
};
|
|
22
|
+
onError?: (error: {
|
|
23
|
+
code: string;
|
|
24
|
+
message: string;
|
|
25
|
+
}) => void;
|
|
26
|
+
onStatusChange?: (status: EphiaStatus) => void;
|
|
27
|
+
preloadSession?: boolean;
|
|
28
|
+
preloadInitialTargetId?: string;
|
|
29
|
+
noiseFilter?: boolean;
|
|
30
|
+
vadGate?: boolean;
|
|
31
|
+
audioInputDeviceId?: string;
|
|
32
|
+
}
|
|
33
|
+
declare function EphiaProvider({ children, apiUrl, apiKey, bearerToken, clientType, transport, options, onError, onStatusChange, preloadSession, preloadInitialTargetId, noiseFilter, vadGate, audioInputDeviceId, }: EphiaProviderProps): react_jsx_runtime.JSX.Element;
|
|
34
|
+
|
|
35
|
+
interface EphiaAutoProps {
|
|
36
|
+
children: React__default.ReactNode;
|
|
37
|
+
/** CSS selector for target elements. Defaults to [data-ephia-target]. */
|
|
38
|
+
selector?: string;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Scans its descendants for [data-ephia-target] elements (textarea/input only)
|
|
42
|
+
* and registers them automatically as V2 NativeBinding targets.
|
|
43
|
+
*
|
|
44
|
+
* Uses a MutationObserver to handle dynamically added/removed elements.
|
|
45
|
+
*
|
|
46
|
+
* @example
|
|
47
|
+
* <EphiaProvider getToken={getToken}>
|
|
48
|
+
* <EphiaAuto>
|
|
49
|
+
* <textarea data-ephia-target="report" />
|
|
50
|
+
* </EphiaAuto>
|
|
51
|
+
* </EphiaProvider>
|
|
52
|
+
*/
|
|
53
|
+
declare function EphiaAuto({ children, selector }: EphiaAutoProps): react_jsx_runtime.JSX.Element;
|
|
54
|
+
|
|
55
|
+
interface UseEphiaReturn {
|
|
56
|
+
status: EphiaStatus;
|
|
57
|
+
sessionId: string | null;
|
|
58
|
+
activeTargetId: string | null;
|
|
59
|
+
error: {
|
|
60
|
+
code: string;
|
|
61
|
+
message: string;
|
|
62
|
+
} | null;
|
|
63
|
+
isIdle: boolean;
|
|
64
|
+
isRecording: boolean;
|
|
65
|
+
isProcessing: boolean;
|
|
66
|
+
isBusy: boolean;
|
|
67
|
+
hasError: boolean;
|
|
68
|
+
start: (targetId?: string, options?: EphiaStartOptions) => Promise<EphiaStartResult>;
|
|
69
|
+
stop: () => Promise<void>;
|
|
70
|
+
toggle: (targetId?: string, options?: EphiaStartOptions) => Promise<void>;
|
|
71
|
+
pause: () => Promise<void>;
|
|
72
|
+
resume: () => Promise<void>;
|
|
73
|
+
endSession: () => Promise<void>;
|
|
74
|
+
warmupMic: () => Promise<void>;
|
|
75
|
+
setActiveTarget: (id: string) => void;
|
|
76
|
+
resetTarget: (id?: string, reason?: ResetReason) => Promise<void>;
|
|
77
|
+
resetSession: (reason?: ResetReason) => Promise<void>;
|
|
78
|
+
sendEditorContext: (id?: string) => Promise<void>;
|
|
79
|
+
applyServerEvent: (event: EphiaServerEvent) => void;
|
|
80
|
+
}
|
|
81
|
+
declare function useEphia(): UseEphiaReturn;
|
|
82
|
+
/** Re-rend uniquement sur changement de status. */
|
|
83
|
+
declare function useEphiaStatus(): EphiaStatus;
|
|
84
|
+
/** Comme useEphiaStatus mais retourne undefined en dehors d'un EphiaProvider. */
|
|
85
|
+
declare function useOptionalEphiaStatus(): EphiaStatus | undefined;
|
|
86
|
+
/** Re-rend uniquement sur changement d'erreur session (ex. session.error STT). */
|
|
87
|
+
declare function useEphiaError(): EphiaError | null;
|
|
88
|
+
/** Re-rend sur chaque partial — à utiliser uniquement dans les composants d'affichage. */
|
|
89
|
+
declare function useEphiaPartial(): EphiaPartial | null;
|
|
90
|
+
/** Re-rend sur changement de connexion. */
|
|
91
|
+
declare function useEphiaConnection(): EphiaConnectionState;
|
|
92
|
+
/** Comme useEphiaConnection mais retourne undefined en dehors d'un EphiaProvider. */
|
|
93
|
+
declare function useOptionalEphiaConnection(): EphiaConnectionState | undefined;
|
|
94
|
+
/** Re-rend sur changement de niveau audio. */
|
|
95
|
+
declare function useEphiaAudioLevel(): EphiaAudioState;
|
|
96
|
+
/** Re-rend uniquement sur changement d'état parole (VAD gate). */
|
|
97
|
+
declare function useEphiaSpeaking(): boolean;
|
|
98
|
+
|
|
99
|
+
interface UseEphiaNativeTargetOptions {
|
|
100
|
+
id: string;
|
|
101
|
+
mode?: string;
|
|
102
|
+
label?: string;
|
|
103
|
+
enabled?: boolean;
|
|
104
|
+
}
|
|
105
|
+
/** @deprecated Use `UseEphiaNativeTargetOptions` instead. */
|
|
106
|
+
type UseEphiaTargetOptions = UseEphiaNativeTargetOptions;
|
|
107
|
+
/**
|
|
108
|
+
* Registers a textarea or input element as a V2 Ephia target.
|
|
109
|
+
* Creates a NativeBinding and wires it to the TargetManager via context.
|
|
110
|
+
*
|
|
111
|
+
* @example
|
|
112
|
+
* const ref = useRef<HTMLTextAreaElement>(null)
|
|
113
|
+
* useEphiaNativeTarget(ref, { id: 'report', label: 'Compte rendu' })
|
|
114
|
+
* return <textarea ref={ref} />
|
|
115
|
+
*/
|
|
116
|
+
declare function useEphiaNativeTarget<T extends HTMLInputElement | HTMLTextAreaElement>(ref: React.RefObject<T | null>, options: UseEphiaNativeTargetOptions): void;
|
|
117
|
+
/**
|
|
118
|
+
* @deprecated Use `useEphiaNativeTarget` for textarea/input fields.
|
|
119
|
+
*/
|
|
120
|
+
declare const useEphiaTarget: typeof useEphiaNativeTarget;
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* @deprecated Use `useEphiaRichEditor(createTiptapEphiaAdapter(editor), options)`.
|
|
124
|
+
*
|
|
125
|
+
* @example
|
|
126
|
+
* const ref = useEphiaRichEditor(
|
|
127
|
+
* createTiptapEphiaAdapter(editor),
|
|
128
|
+
* { id: 'compte-rendu', label: 'Compte rendu' },
|
|
129
|
+
* );
|
|
130
|
+
*/
|
|
131
|
+
declare function useEphiaTiptap(editor: Editor | null, options: UseEphiaNativeTargetOptions): React.RefObject<HTMLDivElement | null>;
|
|
132
|
+
|
|
133
|
+
interface EphiaDictationButtonRenderProps {
|
|
134
|
+
status: EphiaStatus;
|
|
135
|
+
isRecording: boolean;
|
|
136
|
+
toggle: () => void;
|
|
137
|
+
disabled: boolean;
|
|
138
|
+
}
|
|
139
|
+
interface EphiaDictationButtonProps {
|
|
140
|
+
targetId?: string;
|
|
141
|
+
disabled?: boolean;
|
|
142
|
+
className?: string;
|
|
143
|
+
onError?: (error: unknown) => void;
|
|
144
|
+
/**
|
|
145
|
+
* Render prop — le dev fournit son propre rendu.
|
|
146
|
+
* Si absent, un bouton minimaliste est rendu.
|
|
147
|
+
*
|
|
148
|
+
* @example
|
|
149
|
+
* <EphiaDictationButton>
|
|
150
|
+
* {({ isRecording, toggle }) => (
|
|
151
|
+
* <MyButton onClick={toggle} variant={isRecording ? 'danger' : 'primary'} />
|
|
152
|
+
* )}
|
|
153
|
+
* </EphiaDictationButton>
|
|
154
|
+
*/
|
|
155
|
+
children?: (props: EphiaDictationButtonRenderProps) => React__default.ReactNode;
|
|
156
|
+
}
|
|
157
|
+
declare function EphiaDictationButton({ targetId, disabled, className, onError, children, }: EphiaDictationButtonProps): react_jsx_runtime.JSX.Element;
|
|
158
|
+
|
|
159
|
+
interface EphiaStatusBarRenderProps {
|
|
160
|
+
status: EphiaStatus;
|
|
161
|
+
partialText: string | null;
|
|
162
|
+
}
|
|
163
|
+
interface EphiaStatusBarProps {
|
|
164
|
+
className?: string;
|
|
165
|
+
children?: (props: EphiaStatusBarRenderProps) => React__default.ReactNode;
|
|
166
|
+
}
|
|
167
|
+
declare function EphiaStatusBar({ className, children, }: EphiaStatusBarProps): react_jsx_runtime.JSX.Element | null;
|
|
168
|
+
|
|
169
|
+
interface EphiaTextareaProps extends React__default.TextareaHTMLAttributes<HTMLTextAreaElement> {
|
|
170
|
+
targetId: string;
|
|
171
|
+
mode?: string;
|
|
172
|
+
insertion?: "preview-inline" | "preview-floating" | "final-only" | "none";
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Textarea avec overlay de preview du partial en streaming.
|
|
176
|
+
*
|
|
177
|
+
* Stratégie (Dragon Medical-style) :
|
|
178
|
+
* - La `<textarea>` contient uniquement le texte committed (color: transparent).
|
|
179
|
+
* - L'overlay div par-dessous affiche : texte committed + partial grisé.
|
|
180
|
+
*/
|
|
181
|
+
declare const EphiaTextarea: React__default.ForwardRefExoticComponent<EphiaTextareaProps & React__default.RefAttributes<HTMLTextAreaElement>>;
|
|
182
|
+
|
|
183
|
+
export { EphiaAuto as E, type UseEphiaReturn as U, EphiaDictationButton as a, EphiaProvider as b, type EphiaProviderProps as c, EphiaStatusBar as d, EphiaTextarea as e, useEphiaAudioLevel as f, useEphiaConnection as g, useEphiaError as h, useEphiaNativeTarget as i, useEphiaPartial as j, useEphiaSpeaking as k, useEphiaStatus as l, useEphiaTarget as m, useEphiaTiptap as n, useOptionalEphiaConnection as o, useOptionalEphiaStatus as p, type UseEphiaNativeTargetOptions as q, type UseEphiaTargetOptions as r, useEphia as u };
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { EditorContext } from 'ephia-protocol';
|
|
2
|
+
import { E as EphiaBinding, P as PreviewSegmentInput, U as UpsertSegmentInput } from './EphiaBinding-BvRmlqqC.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Binding V2 pour <textarea> et <input type="text">.
|
|
6
|
+
*
|
|
7
|
+
* Modèle : prefix | segments dictés | preview | suffix
|
|
8
|
+
*
|
|
9
|
+
* Le prefix et le suffix sont verrouillés à l'attach() depuis la sélection
|
|
10
|
+
* courante. Tous les segments dictés sont insérés entre les deux.
|
|
11
|
+
* Même segmentId = mise à jour en place (jamais d'append).
|
|
12
|
+
*/
|
|
13
|
+
declare class NativeBinding implements EphiaBinding {
|
|
14
|
+
readonly kind = "native";
|
|
15
|
+
readonly identity: HTMLInputElement | HTMLTextAreaElement;
|
|
16
|
+
private readonly el;
|
|
17
|
+
private readonly warn;
|
|
18
|
+
private prefix;
|
|
19
|
+
private suffix;
|
|
20
|
+
private readonly segmentTexts;
|
|
21
|
+
private readonly knownSegmentIds;
|
|
22
|
+
private readonly segmentBoundaryPrefixes;
|
|
23
|
+
private previewSegmentId;
|
|
24
|
+
private previewText;
|
|
25
|
+
constructor(el: HTMLInputElement | HTMLTextAreaElement, options?: {
|
|
26
|
+
warn?: (msg: string, details?: Record<string, unknown>) => void;
|
|
27
|
+
});
|
|
28
|
+
attach(): void;
|
|
29
|
+
/**
|
|
30
|
+
* Resync prefix/suffix and clear segment memory from the current DOM value.
|
|
31
|
+
* Called before each dictation so manual edits between sessions are preserved.
|
|
32
|
+
*/
|
|
33
|
+
prepareForDictation(): void;
|
|
34
|
+
detach(): void;
|
|
35
|
+
getText(): string;
|
|
36
|
+
getEditorContext(targetId?: string): EditorContext;
|
|
37
|
+
previewSegment(input: PreviewSegmentInput): void;
|
|
38
|
+
upsertSegment(input: UpsertSegmentInput): void;
|
|
39
|
+
removeSegment(id: string): void;
|
|
40
|
+
removeSegments(ids: string[]): void;
|
|
41
|
+
private _syncInsertionAnchor;
|
|
42
|
+
private _committedText;
|
|
43
|
+
/**
|
|
44
|
+
* Canonical upserts (incl. absorb/merge) may carry the full corrected phrase.
|
|
45
|
+
* Drop segment/binding prefixes that would duplicate its opening.
|
|
46
|
+
*/
|
|
47
|
+
private _reconcileCanonicalSegmentInsertion;
|
|
48
|
+
/** Trim binding.prefix when canonical text already opens with its trailing words. */
|
|
49
|
+
private _trimBindingPrefixOverlap;
|
|
50
|
+
private _render;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export { NativeBinding as N };
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import { DocumentOperation } from 'ephia-protocol';
|
|
2
|
+
|
|
3
|
+
interface SessionAnchor {
|
|
4
|
+
/** Position où la dictée a commencé (immutable pendant la session). */
|
|
5
|
+
readonly initialStart: number;
|
|
6
|
+
/** Fin initiale (égale à initialStart si pas de sélection). */
|
|
7
|
+
readonly initialEnd: number;
|
|
8
|
+
/** True si la session a démarré avec une sélection non-vide. */
|
|
9
|
+
readonly hadSelection: boolean;
|
|
10
|
+
/** Position courante de la fin du texte dicté (mise à jour à chaque insert). */
|
|
11
|
+
end: number;
|
|
12
|
+
/**
|
|
13
|
+
* True tant que la sélection initiale n'a pas encore été supprimée.
|
|
14
|
+
* Le binding la supprimera atomiquement avec le premier insert de texte dicté.
|
|
15
|
+
*/
|
|
16
|
+
selectionPendingDelete: boolean;
|
|
17
|
+
}
|
|
18
|
+
interface BeginSessionOptions {
|
|
19
|
+
/**
|
|
20
|
+
* Si true, la sélection courante (si non vide) sera supprimée au premier
|
|
21
|
+
* insert et remplacée par le texte dicté. Défaut : true.
|
|
22
|
+
*/
|
|
23
|
+
replaceSelection?: boolean;
|
|
24
|
+
}
|
|
25
|
+
interface CommitFinalOptions {
|
|
26
|
+
absorbedSegmentIds?: string[];
|
|
27
|
+
}
|
|
28
|
+
interface TargetBinding {
|
|
29
|
+
kind: string;
|
|
30
|
+
attach(): void;
|
|
31
|
+
detach(): void;
|
|
32
|
+
/**
|
|
33
|
+
* Verrouille un anchor au début d'une session de dictée. Tous les inserts
|
|
34
|
+
* suivants se feront relativement à cet anchor, indépendamment du curseur
|
|
35
|
+
* de l'utilisateur. Si l'utilisateur avait une sélection non-vide, elle
|
|
36
|
+
* sera remplacée (sauf si replaceSelection: false).
|
|
37
|
+
*/
|
|
38
|
+
beginSession?(opts?: BeginSessionOptions): SessionAnchor;
|
|
39
|
+
/** Termine la session et relâche l'anchor. Les textes restent dans le document. */
|
|
40
|
+
endSession?(): void;
|
|
41
|
+
/** Retourne l'anchor courant, ou null si pas de session active. */
|
|
42
|
+
getSessionAnchor?(): SessionAnchor | null;
|
|
43
|
+
/** Position visuelle du point d'insertion (anchor.end pendant la session, curseur sinon). */
|
|
44
|
+
getCursorRect?(): DOMRect | null;
|
|
45
|
+
/**
|
|
46
|
+
* Rectangle englobant d'une plage de texte. Utilisé pour le flash visuel
|
|
47
|
+
* (revised, committed). Retourne null si non supporté ou plage hors vue.
|
|
48
|
+
*/
|
|
49
|
+
getRangeRect?(start: number, end: number): DOMRect | null;
|
|
50
|
+
insertPartial?(segmentId: string, text: string, revision: number): void;
|
|
51
|
+
commitFinal(segmentId: string, text: string, options?: CommitFinalOptions): void;
|
|
52
|
+
clearPartial(segmentId: string): void;
|
|
53
|
+
clearAll?(): void;
|
|
54
|
+
/** Retourne la plage [start, end] d'un segment commis dans le document, ou null si inconnu. */
|
|
55
|
+
getSegmentRange?(segmentId: string): {
|
|
56
|
+
start: number;
|
|
57
|
+
end: number;
|
|
58
|
+
} | null;
|
|
59
|
+
/** Récupère le texte complet du document */
|
|
60
|
+
getText(): string;
|
|
61
|
+
/** Récupère la sélection actuelle */
|
|
62
|
+
getSelection?(): {
|
|
63
|
+
text: string;
|
|
64
|
+
range: {
|
|
65
|
+
start: number;
|
|
66
|
+
end: number;
|
|
67
|
+
};
|
|
68
|
+
} | null;
|
|
69
|
+
/** Récupère la position du curseur */
|
|
70
|
+
getCursorOffset?(): number | null;
|
|
71
|
+
/** Applique une opération structurée au document */
|
|
72
|
+
applyOperation(operation: DocumentOperation): void;
|
|
73
|
+
/**
|
|
74
|
+
* Applique une séquence d'opérations (ex: insert_text/line_break/paragraph_break
|
|
75
|
+
* issue de textToDocumentOperations()). applyOperation() seul ne traite
|
|
76
|
+
* qu'une opération à la fois et n'a pas de notion de curseur implicite entre
|
|
77
|
+
* deux appels — un binding qui veut positionner correctement chaque
|
|
78
|
+
* opération relativement aux précédentes (ex: TipTap, cf. P4) doit fournir
|
|
79
|
+
* sa propre implémentation. Sinon, applyOperationsSequentially() (ci-dessous)
|
|
80
|
+
* sert de filet par défaut.
|
|
81
|
+
*/
|
|
82
|
+
applyOperations?(operations: DocumentOperation[]): void;
|
|
83
|
+
/** Appelé quand un segment passe en état "reviewing" (correction SMART en cours) */
|
|
84
|
+
notifyReviewing?(): void;
|
|
85
|
+
/** Appelé quand la review d'un segment est terminée (corrected ou confirmed) */
|
|
86
|
+
notifyReviewDone?(): void;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export type { TargetBinding as T };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Mark, Editor } from '@tiptap/core';
|
|
2
|
+
import { EditorContext } from 'ephia-protocol';
|
|
3
|
+
import { E as EphiaBinding, P as PreviewSegmentInput, U as UpsertSegmentInput } from './EphiaBinding-BvRmlqqC.js';
|
|
4
|
+
|
|
5
|
+
declare const EphiaV2PreviewMark: Mark<any, any>;
|
|
6
|
+
declare const EphiaV2CommittedMark: Mark<any, any>;
|
|
7
|
+
type TiptapBindingOptions = {
|
|
8
|
+
warn?: (msg: string, details?: Record<string, unknown>) => void;
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Binding V2 pour TipTap.
|
|
12
|
+
*
|
|
13
|
+
* Règles :
|
|
14
|
+
* - même segmentId + upsertSegment = update in place (never append)
|
|
15
|
+
* - segmentId connu mais range perdu = warning + no append
|
|
16
|
+
* - removeSegments idempotent
|
|
17
|
+
* - cleanup visuel ne supprime jamais l'identité segment
|
|
18
|
+
* - le préfixe de boundary SDK est stable sur preview -> provisional -> canonical
|
|
19
|
+
*/
|
|
20
|
+
declare class TiptapBinding implements EphiaBinding {
|
|
21
|
+
readonly kind = "tiptap";
|
|
22
|
+
readonly identity: Editor;
|
|
23
|
+
private readonly editor;
|
|
24
|
+
private readonly warn;
|
|
25
|
+
private readonly knownSegmentIds;
|
|
26
|
+
private readonly insertionPrefixes;
|
|
27
|
+
private readonly visualTimeouts;
|
|
28
|
+
private previewSegmentId;
|
|
29
|
+
constructor(editor: Editor, options?: TiptapBindingOptions);
|
|
30
|
+
attach(): void;
|
|
31
|
+
detach(): void;
|
|
32
|
+
getText(): string;
|
|
33
|
+
getEditorContext(targetId?: string): EditorContext;
|
|
34
|
+
previewSegment(input: PreviewSegmentInput): void;
|
|
35
|
+
upsertSegment(input: UpsertSegmentInput): void;
|
|
36
|
+
removeSegment(id: string): void;
|
|
37
|
+
removeSegments(ids: string[]): void;
|
|
38
|
+
private _clearPreview;
|
|
39
|
+
private _textWithStableBoundary;
|
|
40
|
+
private _scheduleVisualCleanup;
|
|
41
|
+
private _clearVisualTimeout;
|
|
42
|
+
private _removeVisualMarkForSegment;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export { EphiaV2CommittedMark as E, TiptapBinding as T, EphiaV2PreviewMark as a };
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { EphiaClientMessage, EphiaAudioEvent, EphiaServerEvent } from 'ephia-protocol';
|
|
2
|
+
import { b as EphiaSdkError } from './audio-state-kZ3KSvux.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Interface abstraite du transport Ephia Audio.
|
|
6
|
+
*
|
|
7
|
+
* LiveKit est une implémentation. MockTransport en est une autre.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
type TransportConnectParams = {
|
|
11
|
+
livekitUrl: string;
|
|
12
|
+
token: string;
|
|
13
|
+
roomName: string;
|
|
14
|
+
};
|
|
15
|
+
type TransportConnectionStatus = "idle" | "connecting" | "connected" | "reconnecting" | "reconnected" | "disconnected" | "error";
|
|
16
|
+
type TransportState = {
|
|
17
|
+
status: TransportConnectionStatus;
|
|
18
|
+
roomName?: string;
|
|
19
|
+
participantIdentity?: string;
|
|
20
|
+
connectionQuality?: "unknown" | "poor" | "good" | "excellent";
|
|
21
|
+
krispActive?: boolean;
|
|
22
|
+
localAudioPublished: boolean;
|
|
23
|
+
localAudioMuted: boolean;
|
|
24
|
+
reconnectCount: number;
|
|
25
|
+
lastError?: EphiaSdkError;
|
|
26
|
+
};
|
|
27
|
+
interface Transport {
|
|
28
|
+
/** Connecte le transport. */
|
|
29
|
+
connect(params: TransportConnectParams): Promise<void>;
|
|
30
|
+
/** Déconnecte proprement. */
|
|
31
|
+
disconnect(reason?: string): Promise<void>;
|
|
32
|
+
/** Publie une piste audio. */
|
|
33
|
+
publishAudio(track: MediaStreamTrack, options?: {
|
|
34
|
+
enableNoiseFilter?: boolean;
|
|
35
|
+
}): Promise<void>;
|
|
36
|
+
/** Dé-publie l'audio local. */
|
|
37
|
+
unpublishAudio(): Promise<void>;
|
|
38
|
+
/** Envoie un message client vers le serveur. */
|
|
39
|
+
sendMessage(message: EphiaClientMessage): Promise<void>;
|
|
40
|
+
/** Écoute les events Ephia. Retourne un unsubscriber. */
|
|
41
|
+
onEvent(callback: (event: EphiaAudioEvent) => void): () => void;
|
|
42
|
+
/** Écoute les events serveur V2 bruts (sans inférence). Retourne un unsubscriber. */
|
|
43
|
+
onServerEvent(callback: (event: EphiaServerEvent) => void): () => void;
|
|
44
|
+
/** Écoute les changements d'état transport. Retourne un unsubscriber. */
|
|
45
|
+
onTransportState(callback: (state: TransportState) => void): () => void;
|
|
46
|
+
/** Écoute les erreurs transport. Retourne un unsubscriber. */
|
|
47
|
+
onError(callback: (error: EphiaSdkError) => void): () => void;
|
|
48
|
+
/** Retourne l'état courant. */
|
|
49
|
+
getState(): TransportState;
|
|
50
|
+
/** Publication audio locale (pour VAD gate mute/unmute). */
|
|
51
|
+
getLocalAudioPublication?(): {
|
|
52
|
+
mute(): Promise<unknown>;
|
|
53
|
+
unmute(): Promise<unknown>;
|
|
54
|
+
} | null;
|
|
55
|
+
/** Pré-chauffe la connexion WebRTC (DNS + TLS). Non bloquant. Optionnel. */
|
|
56
|
+
prepareConnection?(url: string, token?: string): Promise<void>;
|
|
57
|
+
/** Appel RPC vers le serveur. */
|
|
58
|
+
performRpc?(method: string, payload: unknown, timeout?: number): Promise<string>;
|
|
59
|
+
/** Change le périphérique actif. */
|
|
60
|
+
switchActiveDevice?(kind: MediaDeviceKind, deviceId: string): Promise<boolean>;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export type { Transport as T, TransportState as a, TransportConnectParams as b };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Erreurs typées du SDK Ephia.
|
|
3
|
+
*/
|
|
4
|
+
type EphiaSdkErrorCode = "config.invalid" | "session.create_failed" | "session.token_missing" | "transport.connect_failed" | "transport.reconnecting" | "transport.disconnected" | "transport.not_connected" | "audio.permission_denied" | "audio.no_input_device" | "audio.device_in_use" | "audio.track_publish_failed" | "audio.silence_detected" | "protocol.invalid_event" | "protocol.seq_gap" | "protocol.seq_gap_sync_failed" | "client.invalid_state" | "client.start_failed" | "client.finalization_timeout" | "binding.target_not_found" | "binding.unsupported_editor";
|
|
5
|
+
declare class EphiaSdkError extends Error {
|
|
6
|
+
code: EphiaSdkErrorCode;
|
|
7
|
+
details?: Record<string, unknown> | undefined;
|
|
8
|
+
constructor(code: EphiaSdkErrorCode, message: string, details?: Record<string, unknown> | undefined);
|
|
9
|
+
toJSON(): Record<string, unknown>;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* État audio local (micro, niveau, silence, permission).
|
|
14
|
+
*/
|
|
15
|
+
type EphiaAudioPermission = "unknown" | "prompt" | "granted" | "denied";
|
|
16
|
+
type EphiaAudioState = {
|
|
17
|
+
permission: EphiaAudioPermission;
|
|
18
|
+
inputDeviceId?: string;
|
|
19
|
+
inputDeviceLabel?: string;
|
|
20
|
+
hasInputDevice: boolean;
|
|
21
|
+
level: number;
|
|
22
|
+
rms: number;
|
|
23
|
+
peak: number;
|
|
24
|
+
isSilent: boolean;
|
|
25
|
+
silenceDurationMs: number;
|
|
26
|
+
muted: boolean;
|
|
27
|
+
localAudioPublished: boolean;
|
|
28
|
+
/** true si le VADGate détecte de la parole active */
|
|
29
|
+
speaking: boolean;
|
|
30
|
+
/** True dès que getUserMedia a réussi, même si le transport n'est pas encore connecté. */
|
|
31
|
+
micReady?: boolean;
|
|
32
|
+
error?: {
|
|
33
|
+
code: string;
|
|
34
|
+
message: string;
|
|
35
|
+
};
|
|
36
|
+
};
|
|
37
|
+
declare const initialAudioState: EphiaAudioState;
|
|
38
|
+
|
|
39
|
+
export { type EphiaAudioPermission as E, type EphiaAudioState as a, EphiaSdkError as b, type EphiaSdkErrorCode as c, initialAudioState as i };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=chunk-35AJK2IO.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|