@corti/dictation-web 0.0.0-rc.359
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/LICENSE +21 -0
- package/README.md +156 -0
- package/dist/CortiDictation.d.ts +51 -0
- package/dist/CortiDictation.js +281 -0
- package/dist/CortiDictation.js.map +1 -0
- package/dist/DictationService.d.ts +16 -0
- package/dist/DictationService.js +88 -0
- package/dist/DictationService.js.map +1 -0
- package/dist/RecorderManager.d.ts +25 -0
- package/dist/RecorderManager.js +145 -0
- package/dist/RecorderManager.js.map +1 -0
- package/dist/audioService.d.ts +6 -0
- package/dist/audioService.js +21 -0
- package/dist/audioService.js.map +1 -0
- package/dist/bundle.js +11064 -0
- package/dist/components/audio-visualiser.d.ts +12 -0
- package/dist/components/audio-visualiser.js +65 -0
- package/dist/components/audio-visualiser.js.map +1 -0
- package/dist/components/settings-menu.d.ts +20 -0
- package/dist/components/settings-menu.js +185 -0
- package/dist/components/settings-menu.js.map +1 -0
- package/dist/constants.d.ts +3 -0
- package/dist/constants.js +16 -0
- package/dist/constants.js.map +1 -0
- package/dist/icons/icons.d.ts +17 -0
- package/dist/icons/icons.js +158 -0
- package/dist/icons/icons.js.map +1 -0
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +2 -0
- package/dist/icons/index.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/styles/ComponentStyles.d.ts +2 -0
- package/dist/styles/ComponentStyles.js +53 -0
- package/dist/styles/ComponentStyles.js.map +1 -0
- package/dist/styles/buttons.d.ts +2 -0
- package/dist/styles/buttons.js +58 -0
- package/dist/styles/buttons.js.map +1 -0
- package/dist/styles/callout.d.ts +2 -0
- package/dist/styles/callout.js +33 -0
- package/dist/styles/callout.js.map +1 -0
- package/dist/styles/select.d.ts +2 -0
- package/dist/styles/select.js +36 -0
- package/dist/styles/select.js.map +1 -0
- package/dist/styles/theme.d.ts +2 -0
- package/dist/styles/theme.js +56 -0
- package/dist/styles/theme.js.map +1 -0
- package/dist/types.d.ts +8 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/utils.d.ts +59 -0
- package/dist/utils.js +179 -0
- package/dist/utils.js.map +1 -0
- package/package.json +120 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { css } from 'lit';
|
|
2
|
+
const ButtonStyles = css `
|
|
3
|
+
/* Default (plain) button styling */
|
|
4
|
+
button,
|
|
5
|
+
.button {
|
|
6
|
+
background: var(--action-plain-background);
|
|
7
|
+
/* border: 1px solid var(--action-plain-border-color); */
|
|
8
|
+
border: none;
|
|
9
|
+
color: var(--component-text-color);
|
|
10
|
+
cursor: pointer;
|
|
11
|
+
padding: 8px;
|
|
12
|
+
border-radius: var(--card-inner-border-radius);
|
|
13
|
+
display: inline-flex;
|
|
14
|
+
gap: 4px;
|
|
15
|
+
align-items: center;
|
|
16
|
+
justify-content: center;
|
|
17
|
+
transition: background 0.3s ease;
|
|
18
|
+
font-family: var(--component-font-family);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
button:hover,
|
|
22
|
+
.button:hover {
|
|
23
|
+
background: var(--action-plain-background-hover);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
button:focus-visible {
|
|
27
|
+
outline: 2px solid var(--action-accent-background);
|
|
28
|
+
outline-offset: 2px;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* Accent variant */
|
|
32
|
+
button.accent,
|
|
33
|
+
.button.accent {
|
|
34
|
+
background: var(--action-accent-background);
|
|
35
|
+
color: var(--action-accent-text-color);
|
|
36
|
+
border: none;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
button.accent:hover,
|
|
40
|
+
.button.accent:hover {
|
|
41
|
+
background: var(--action-accent-background-hover);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* Accent variant */
|
|
45
|
+
button.red,
|
|
46
|
+
.button.red {
|
|
47
|
+
background: var(--action-red-background);
|
|
48
|
+
color: var(--action-red-text-color);
|
|
49
|
+
border: none;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
button.red:hover,
|
|
53
|
+
.button.red:hover {
|
|
54
|
+
background: var(--action-red-background-hover);
|
|
55
|
+
}
|
|
56
|
+
`;
|
|
57
|
+
export default ButtonStyles;
|
|
58
|
+
//# sourceMappingURL=buttons.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"buttons.js","sourceRoot":"","sources":["../../src/styles/buttons.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,YAAY,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAsDvB,CAAC;AAEF,eAAe,YAAY,CAAC","sourcesContent":["import { css } from 'lit';\n\nconst ButtonStyles = css`\n /* Default (plain) button styling */\n button,\n .button {\n background: var(--action-plain-background);\n /* border: 1px solid var(--action-plain-border-color); */\n border: none;\n color: var(--component-text-color);\n cursor: pointer;\n padding: 8px;\n border-radius: var(--card-inner-border-radius);\n display: inline-flex;\n gap: 4px;\n align-items: center;\n justify-content: center;\n transition: background 0.3s ease;\n font-family: var(--component-font-family);\n }\n\n button:hover,\n .button:hover {\n background: var(--action-plain-background-hover);\n }\n\n button:focus-visible {\n outline: 2px solid var(--action-accent-background);\n outline-offset: 2px;\n }\n\n /* Accent variant */\n button.accent,\n .button.accent {\n background: var(--action-accent-background);\n color: var(--action-accent-text-color);\n border: none;\n }\n\n button.accent:hover,\n .button.accent:hover {\n background: var(--action-accent-background-hover);\n }\n\n /* Accent variant */\n button.red,\n .button.red {\n background: var(--action-red-background);\n color: var(--action-red-text-color);\n border: none;\n }\n\n button.red:hover,\n .button.red:hover {\n background: var(--action-red-background-hover);\n }\n`;\n\nexport default ButtonStyles;\n"]}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { css } from 'lit';
|
|
2
|
+
const CalloutStyles = css `
|
|
3
|
+
.callout {
|
|
4
|
+
background: var(--callout-info-background);
|
|
5
|
+
border: 1px solid var(--callout-info-border);
|
|
6
|
+
color: var(--callout-info-text);
|
|
7
|
+
padding: 8px;
|
|
8
|
+
border-radius: var(--card-inner-border-radius);
|
|
9
|
+
display: flex;
|
|
10
|
+
font-size: 0.9rem;
|
|
11
|
+
gap: 8px;
|
|
12
|
+
align-items: center;
|
|
13
|
+
max-width: 100%;
|
|
14
|
+
height: fit-content;
|
|
15
|
+
&.error {
|
|
16
|
+
background: var(--callout-error-background);
|
|
17
|
+
border: 1px solid var(--callout-error-border);
|
|
18
|
+
color: var(--callout-warn-text);
|
|
19
|
+
}
|
|
20
|
+
&.warn {
|
|
21
|
+
background: var(--callout-warn-background);
|
|
22
|
+
border: 1px solid var(--callout-warn-border);
|
|
23
|
+
color: var(--callout-warn-text);
|
|
24
|
+
}
|
|
25
|
+
&.small {
|
|
26
|
+
width: 100%;
|
|
27
|
+
padding: 6px;
|
|
28
|
+
font-size: 0.7rem;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
`;
|
|
32
|
+
export default CalloutStyles;
|
|
33
|
+
//# sourceMappingURL=callout.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"callout.js","sourceRoot":"","sources":["../../src/styles/callout.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,aAAa,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA6BxB,CAAC;AAEF,eAAe,aAAa,CAAC","sourcesContent":["import { css } from 'lit';\n\nconst CalloutStyles = css`\n .callout {\n background: var(--callout-info-background);\n border: 1px solid var(--callout-info-border);\n color: var(--callout-info-text);\n padding: 8px;\n border-radius: var(--card-inner-border-radius);\n display: flex;\n font-size: 0.9rem;\n gap: 8px;\n align-items: center;\n max-width: 100%;\n height: fit-content;\n &.error {\n background: var(--callout-error-background);\n border: 1px solid var(--callout-error-border);\n color: var(--callout-warn-text);\n }\n &.warn {\n background: var(--callout-warn-background);\n border: 1px solid var(--callout-warn-border);\n color: var(--callout-warn-text);\n }\n &.small {\n width: 100%;\n padding: 6px;\n font-size: 0.7rem;\n }\n }\n`;\n\nexport default CalloutStyles;\n"]}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { css } from 'lit';
|
|
2
|
+
const SelectStyles = css `
|
|
3
|
+
label {
|
|
4
|
+
display: block;
|
|
5
|
+
font-size: 0.8rem;
|
|
6
|
+
padding-bottom: 0.5rem;
|
|
7
|
+
font-weight: 500;
|
|
8
|
+
color: var(--component-text-color);
|
|
9
|
+
pointer-events: none;
|
|
10
|
+
}
|
|
11
|
+
select {
|
|
12
|
+
background: var(--card-background);
|
|
13
|
+
color: var(--component-text-color);
|
|
14
|
+
border: 1px solid var(--card-border-color);
|
|
15
|
+
padding: var(--card-padding);
|
|
16
|
+
border-radius: var(--card-inner-border-radius);
|
|
17
|
+
outline: none;
|
|
18
|
+
width: 100%;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
select:disabled {
|
|
22
|
+
opacity: 0.5;
|
|
23
|
+
cursor: not-allowed;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
select:hover {
|
|
27
|
+
background: var(--action-plain-background-hover);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
select:focus-visible {
|
|
31
|
+
outline: 2px solid var(--action-accent-background);
|
|
32
|
+
/* outline-offset: 2px; */
|
|
33
|
+
}
|
|
34
|
+
`;
|
|
35
|
+
export default SelectStyles;
|
|
36
|
+
//# sourceMappingURL=select.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"select.js","sourceRoot":"","sources":["../../src/styles/select.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,YAAY,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgCvB,CAAC;AAEF,eAAe,YAAY,CAAC","sourcesContent":["import { css } from 'lit';\n\nconst SelectStyles = css`\n label {\n display: block;\n font-size: 0.8rem;\n padding-bottom: 0.5rem;\n font-weight: 500;\n color: var(--component-text-color);\n pointer-events: none;\n }\n select {\n background: var(--card-background);\n color: var(--component-text-color);\n border: 1px solid var(--card-border-color);\n padding: var(--card-padding);\n border-radius: var(--card-inner-border-radius);\n outline: none;\n width: 100%;\n }\n\n select:disabled {\n opacity: 0.5;\n cursor: not-allowed;\n }\n\n select:hover {\n background: var(--action-plain-background-hover);\n }\n\n select:focus-visible {\n outline: 2px solid var(--action-accent-background);\n /* outline-offset: 2px; */\n }\n`;\n\nexport default SelectStyles;\n"]}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { css } from 'lit';
|
|
2
|
+
const ThemeStyles = css `
|
|
3
|
+
:host {
|
|
4
|
+
color-scheme: light dark;
|
|
5
|
+
/* Component Defaults */
|
|
6
|
+
--component-font-family:
|
|
7
|
+
-apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui,
|
|
8
|
+
helvetica neue, Cantarell, Ubuntu, roboto, noto, helvetica, arial,
|
|
9
|
+
sans-serif;
|
|
10
|
+
--component-text-color: light-dark(#333, #eee);
|
|
11
|
+
|
|
12
|
+
/* Card Defaults */
|
|
13
|
+
--card-background: light-dark(#fff, #333);
|
|
14
|
+
--card-border-color: light-dark(#ddd, #555);
|
|
15
|
+
--card-padding: 4px;
|
|
16
|
+
--card-border-radius: 8px;
|
|
17
|
+
--card-inner-border-radius: 6px;
|
|
18
|
+
--card-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
|
19
|
+
|
|
20
|
+
/* Actions Defaults */
|
|
21
|
+
--action-plain-border-color: light-dark(#ccc, #555);
|
|
22
|
+
--action-plain-background-hover: light-dark(#ddd, #444);
|
|
23
|
+
|
|
24
|
+
--action-accent-background: light-dark(#007bff, #0056b3);
|
|
25
|
+
--action-accent-background-hover: light-dark(#0056b3, #003d80);
|
|
26
|
+
--action-accent-text-color: #fff;
|
|
27
|
+
|
|
28
|
+
--action-red-background: light-dark(#dc3545, #bd2130);
|
|
29
|
+
--action-red-background-hover: light-dark(#bd2130, #a71c24);
|
|
30
|
+
--action-red-text-color: #fff;
|
|
31
|
+
|
|
32
|
+
/* Callout Defaults */
|
|
33
|
+
--callout-info-background: light-dark(#007bff33, #0056b333);
|
|
34
|
+
--callout-info-border: light-dark(#007bff99, #0056b399);
|
|
35
|
+
--callout-info-text: light-dark(#007bff, #0056b3);
|
|
36
|
+
|
|
37
|
+
--callout-error-background: light-dark(#dc354533, #bd213033);
|
|
38
|
+
--callout-error-border: light-dark(#dc354599, #bd213099);
|
|
39
|
+
--callout-error-text: light-dark(#dc3545, #bd2130);
|
|
40
|
+
|
|
41
|
+
--callout-warn-background: light-dark(#fd7e1433, #e06c1233);
|
|
42
|
+
--callout-warn-border: light-dark(#fd7e1499, #e06c1299);
|
|
43
|
+
--callout-warn-text: light-dark(#fd7e14, #e06c12);
|
|
44
|
+
|
|
45
|
+
/* Visualiser Defaults */
|
|
46
|
+
--visualiser-background: light-dark(#e0e0e0, #fff);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
:host {
|
|
50
|
+
box-sizing: border-box;
|
|
51
|
+
font-family: var(--component-font-family);
|
|
52
|
+
color: var(--component-text-color);
|
|
53
|
+
}
|
|
54
|
+
`;
|
|
55
|
+
export default ThemeStyles;
|
|
56
|
+
//# sourceMappingURL=theme.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"theme.js","sourceRoot":"","sources":["../../src/styles/theme.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,MAAM,WAAW,GAAG,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDtB,CAAC;AAEF,eAAe,WAAW,CAAC","sourcesContent":["import { css } from 'lit';\n\nconst ThemeStyles = css`\n :host {\n color-scheme: light dark;\n /* Component Defaults */\n --component-font-family:\n -apple-system, BlinkMacSystemFont, avenir next, avenir, segoe ui,\n helvetica neue, Cantarell, Ubuntu, roboto, noto, helvetica, arial,\n sans-serif;\n --component-text-color: light-dark(#333, #eee);\n\n /* Card Defaults */\n --card-background: light-dark(#fff, #333);\n --card-border-color: light-dark(#ddd, #555);\n --card-padding: 4px;\n --card-border-radius: 8px;\n --card-inner-border-radius: 6px;\n --card-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);\n\n /* Actions Defaults */\n --action-plain-border-color: light-dark(#ccc, #555);\n --action-plain-background-hover: light-dark(#ddd, #444);\n\n --action-accent-background: light-dark(#007bff, #0056b3);\n --action-accent-background-hover: light-dark(#0056b3, #003d80);\n --action-accent-text-color: #fff;\n\n --action-red-background: light-dark(#dc3545, #bd2130);\n --action-red-background-hover: light-dark(#bd2130, #a71c24);\n --action-red-text-color: #fff;\n\n /* Callout Defaults */\n --callout-info-background: light-dark(#007bff33, #0056b333);\n --callout-info-border: light-dark(#007bff99, #0056b399);\n --callout-info-text: light-dark(#007bff, #0056b3);\n\n --callout-error-background: light-dark(#dc354533, #bd213033);\n --callout-error-border: light-dark(#dc354599, #bd213099);\n --callout-error-text: light-dark(#dc3545, #bd2130);\n\n --callout-warn-background: light-dark(#fd7e1433, #e06c1233);\n --callout-warn-border: light-dark(#fd7e1499, #e06c1299);\n --callout-warn-text: light-dark(#fd7e14, #e06c12);\n\n /* Visualiser Defaults */\n --visualiser-background: light-dark(#e0e0e0, #fff);\n }\n\n :host {\n box-sizing: border-box;\n font-family: var(--component-font-family);\n color: var(--component-text-color);\n }\n`;\n\nexport default ThemeStyles;\n"]}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type Corti } from '@corti/sdk';
|
|
2
|
+
export type RecordingState = 'initializing' | 'recording' | 'stopping' | 'stopped';
|
|
3
|
+
export type ServerConfig = {
|
|
4
|
+
environment?: string;
|
|
5
|
+
tenant?: string;
|
|
6
|
+
expiresAt?: number;
|
|
7
|
+
refreshExpiresAt?: number;
|
|
8
|
+
} & Corti.BearerOptions;
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["import { type Corti } from '@corti/sdk';\n\nexport type RecordingState =\n | 'initializing'\n | 'recording'\n | 'stopping'\n | 'stopped';\n\nexport type ServerConfig = {\n environment?: string;\n tenant?: string;\n expiresAt?: number;\n refreshExpiresAt?: number;\n} & Corti.BearerOptions;\n"]}
|
package/dist/utils.d.ts
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Returns the localized name of a language given its BCP-47 code.
|
|
3
|
+
*
|
|
4
|
+
* @param languageCode - The BCP-47 language code (e.g. "en")
|
|
5
|
+
* @returns The localized language name (e.g. "English") or the original code if unavailable.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getLanguageName(languageCode: string): string;
|
|
8
|
+
/**
|
|
9
|
+
* Requests access to the microphone.
|
|
10
|
+
*
|
|
11
|
+
* This function checks if the microphone permission is in "prompt" state, then requests
|
|
12
|
+
* access and stops any active tracks immediately. It also logs if permission is already granted.
|
|
13
|
+
*
|
|
14
|
+
* @returns A promise that resolves when the permission request is complete.
|
|
15
|
+
*/
|
|
16
|
+
export declare function requestMicAccess(): Promise<void>;
|
|
17
|
+
/**
|
|
18
|
+
* Retrieves available audio input devices.
|
|
19
|
+
*
|
|
20
|
+
* This function uses the mediaDevices API to enumerate devices and filters out those
|
|
21
|
+
* which are audio inputs. In some browsers, you may need to request user media before
|
|
22
|
+
* device labels are populated.
|
|
23
|
+
*
|
|
24
|
+
* @returns A promise that resolves with an object containing:
|
|
25
|
+
* - `devices`: an array of MediaDeviceInfo objects for audio inputs.
|
|
26
|
+
* - `defaultDeviceId`: the deviceId of the first audio input, if available.
|
|
27
|
+
*/
|
|
28
|
+
export declare function getAudioDevices(): Promise<{
|
|
29
|
+
devices: MediaDeviceInfo[];
|
|
30
|
+
defaultDevice?: MediaDeviceInfo;
|
|
31
|
+
}>;
|
|
32
|
+
/**
|
|
33
|
+
* Decodes a JWT token and extracts environment and tenant details from its issuer URL.
|
|
34
|
+
*
|
|
35
|
+
* NOTE: This function is temporarily kept for backward compatibility in return values.
|
|
36
|
+
* The SDK now handles token parsing internally, so this should be removed once we
|
|
37
|
+
* reduce the return results to only include what's necessary.
|
|
38
|
+
*
|
|
39
|
+
* @param token - A JSON Web Token (JWT) string.
|
|
40
|
+
* @returns An object containing:
|
|
41
|
+
* - `environment`: The extracted environment from the issuer URL.
|
|
42
|
+
* - `tenant`: The extracted tenant from the issuer URL.
|
|
43
|
+
* - `accessToken`: The original token string.
|
|
44
|
+
* If the issuer URL doesn't match the expected format, returns undefined.
|
|
45
|
+
*
|
|
46
|
+
* @throws Will throw an error if:
|
|
47
|
+
* - The token format is invalid.
|
|
48
|
+
* - The base64 decoding or URI decoding fails.
|
|
49
|
+
* - The JSON payload is invalid.
|
|
50
|
+
* - The token payload does not contain an issuer (iss) field.
|
|
51
|
+
*/
|
|
52
|
+
export declare function decodeToken(token: string): {
|
|
53
|
+
environment: string;
|
|
54
|
+
tenant: string;
|
|
55
|
+
accessToken: string;
|
|
56
|
+
expiresAt: number | undefined;
|
|
57
|
+
} | undefined;
|
|
58
|
+
export declare function getMediaStream(deviceId?: string): Promise<MediaStream>;
|
|
59
|
+
export declare function getErrorMessage(event: Error): any;
|
package/dist/utils.js
ADDED
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
/**
|
|
3
|
+
* Returns the localized name of a language given its BCP-47 code.
|
|
4
|
+
*
|
|
5
|
+
* @param languageCode - The BCP-47 language code (e.g. "en")
|
|
6
|
+
* @returns The localized language name (e.g. "English") or the original code if unavailable.
|
|
7
|
+
*/
|
|
8
|
+
export function getLanguageName(languageCode) {
|
|
9
|
+
const userLocale = navigator.language || 'en';
|
|
10
|
+
const displayNames = new Intl.DisplayNames([userLocale], {
|
|
11
|
+
type: 'language',
|
|
12
|
+
});
|
|
13
|
+
const languageName = displayNames.of(languageCode);
|
|
14
|
+
return languageName || languageCode;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Requests access to the microphone.
|
|
18
|
+
*
|
|
19
|
+
* This function checks if the microphone permission is in "prompt" state, then requests
|
|
20
|
+
* access and stops any active tracks immediately. It also logs if permission is already granted.
|
|
21
|
+
*
|
|
22
|
+
* @returns A promise that resolves when the permission request is complete.
|
|
23
|
+
*/
|
|
24
|
+
export async function requestMicAccess() {
|
|
25
|
+
try {
|
|
26
|
+
// Fallback if Permissions API is not available
|
|
27
|
+
if (!navigator.permissions) {
|
|
28
|
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
29
|
+
stream.getTracks().forEach(track => track.stop());
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const permissionStatus = await navigator.permissions.query({
|
|
33
|
+
// eslint-disable-next-line no-undef
|
|
34
|
+
name: 'microphone',
|
|
35
|
+
});
|
|
36
|
+
if (permissionStatus.state === 'prompt') {
|
|
37
|
+
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
38
|
+
stream.getTracks().forEach(track => track.stop());
|
|
39
|
+
}
|
|
40
|
+
else if (permissionStatus.state === 'denied') {
|
|
41
|
+
console.warn('Microphone permission is denied.');
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
console.error('Error checking/requesting microphone permission:', error);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Retrieves available audio input devices.
|
|
50
|
+
*
|
|
51
|
+
* This function uses the mediaDevices API to enumerate devices and filters out those
|
|
52
|
+
* which are audio inputs. In some browsers, you may need to request user media before
|
|
53
|
+
* device labels are populated.
|
|
54
|
+
*
|
|
55
|
+
* @returns A promise that resolves with an object containing:
|
|
56
|
+
* - `devices`: an array of MediaDeviceInfo objects for audio inputs.
|
|
57
|
+
* - `defaultDeviceId`: the deviceId of the first audio input, if available.
|
|
58
|
+
*/
|
|
59
|
+
export async function getAudioDevices() {
|
|
60
|
+
if (!navigator.mediaDevices?.enumerateDevices) {
|
|
61
|
+
console.error('Media devices API not supported.');
|
|
62
|
+
return { devices: [] };
|
|
63
|
+
}
|
|
64
|
+
await requestMicAccess();
|
|
65
|
+
try {
|
|
66
|
+
// Optionally: await navigator.mediaDevices.getUserMedia({ audio: true });
|
|
67
|
+
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
68
|
+
const audioDevices = devices.filter(device => device.kind === 'audioinput');
|
|
69
|
+
const defaultDevice = audioDevices.length > 0 ? audioDevices[0] : undefined;
|
|
70
|
+
return { devices: audioDevices, defaultDevice };
|
|
71
|
+
}
|
|
72
|
+
catch (error) {
|
|
73
|
+
console.error('Error enumerating devices:', error);
|
|
74
|
+
return { devices: [] };
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Decodes a JWT token and extracts environment and tenant details from its issuer URL.
|
|
79
|
+
*
|
|
80
|
+
* NOTE: This function is temporarily kept for backward compatibility in return values.
|
|
81
|
+
* The SDK now handles token parsing internally, so this should be removed once we
|
|
82
|
+
* reduce the return results to only include what's necessary.
|
|
83
|
+
*
|
|
84
|
+
* @param token - A JSON Web Token (JWT) string.
|
|
85
|
+
* @returns An object containing:
|
|
86
|
+
* - `environment`: The extracted environment from the issuer URL.
|
|
87
|
+
* - `tenant`: The extracted tenant from the issuer URL.
|
|
88
|
+
* - `accessToken`: The original token string.
|
|
89
|
+
* If the issuer URL doesn't match the expected format, returns undefined.
|
|
90
|
+
*
|
|
91
|
+
* @throws Will throw an error if:
|
|
92
|
+
* - The token format is invalid.
|
|
93
|
+
* - The base64 decoding or URI decoding fails.
|
|
94
|
+
* - The JSON payload is invalid.
|
|
95
|
+
* - The token payload does not contain an issuer (iss) field.
|
|
96
|
+
*/
|
|
97
|
+
export function decodeToken(token) {
|
|
98
|
+
// Validate the token structure (should contain at least header and payload parts)
|
|
99
|
+
const parts = token.split('.');
|
|
100
|
+
if (parts.length < 2) {
|
|
101
|
+
throw new Error('Invalid token format');
|
|
102
|
+
}
|
|
103
|
+
// Retrieve the payload (second part) of the JWT token
|
|
104
|
+
const base64Url = parts[1];
|
|
105
|
+
// Replace URL-safe characters to match standard base64 encoding
|
|
106
|
+
const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');
|
|
107
|
+
// Decode the base64 string into a JSON string
|
|
108
|
+
let jsonPayload;
|
|
109
|
+
try {
|
|
110
|
+
jsonPayload = decodeURIComponent(atob(base64)
|
|
111
|
+
.split('')
|
|
112
|
+
.map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))
|
|
113
|
+
.join(''));
|
|
114
|
+
}
|
|
115
|
+
catch (error) {
|
|
116
|
+
throw new Error('Failed to decode token payload');
|
|
117
|
+
}
|
|
118
|
+
// Parse the JSON string to obtain token details
|
|
119
|
+
let tokenDetails;
|
|
120
|
+
try {
|
|
121
|
+
tokenDetails = JSON.parse(jsonPayload);
|
|
122
|
+
}
|
|
123
|
+
catch (error) {
|
|
124
|
+
throw new Error('Invalid JSON payload in token');
|
|
125
|
+
}
|
|
126
|
+
// Extract the issuer URL from the token details
|
|
127
|
+
const issuerUrl = tokenDetails.iss;
|
|
128
|
+
if (!issuerUrl) {
|
|
129
|
+
throw new Error('Token payload does not contain an issuer (iss) field');
|
|
130
|
+
}
|
|
131
|
+
// Regex to extract environment and tenant from issuer URL:
|
|
132
|
+
// Expected format: https://keycloak.{environment}.corti.app/realms/{tenant}
|
|
133
|
+
// Note: Unnecessary escapes in character classes have been removed.
|
|
134
|
+
const regex = /^https:\/\/(keycloak|auth)\.([^.]+)\.corti\.app\/realms\/([^/]+)/;
|
|
135
|
+
const match = issuerUrl.match(regex);
|
|
136
|
+
// If the issuer URL matches the expected pattern, return the extracted values along with the token
|
|
137
|
+
if (match) {
|
|
138
|
+
const expiresAt = tokenDetails.exp && typeof tokenDetails.exp === 'number'
|
|
139
|
+
? tokenDetails.exp
|
|
140
|
+
: undefined;
|
|
141
|
+
return {
|
|
142
|
+
environment: match[2],
|
|
143
|
+
tenant: match[3],
|
|
144
|
+
accessToken: token,
|
|
145
|
+
expiresAt,
|
|
146
|
+
};
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
export async function getMediaStream(deviceId) {
|
|
150
|
+
if (!deviceId) {
|
|
151
|
+
throw new Error('No device ID provided');
|
|
152
|
+
}
|
|
153
|
+
if (deviceId === 'display_audio') {
|
|
154
|
+
const stream = await navigator.mediaDevices.getDisplayMedia({
|
|
155
|
+
audio: true,
|
|
156
|
+
video: true,
|
|
157
|
+
});
|
|
158
|
+
stream.getTracks().forEach(track => {
|
|
159
|
+
if (track.kind === 'video') {
|
|
160
|
+
stream.removeTrack(track);
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
return stream;
|
|
164
|
+
}
|
|
165
|
+
// Get media stream and initialize audio service.
|
|
166
|
+
const constraints = deviceId !== 'default'
|
|
167
|
+
? { audio: { deviceId: { exact: deviceId } } }
|
|
168
|
+
: { audio: true };
|
|
169
|
+
return await navigator.mediaDevices.getUserMedia(constraints);
|
|
170
|
+
}
|
|
171
|
+
export function getErrorMessage(event) {
|
|
172
|
+
try {
|
|
173
|
+
return JSON.parse(event.message);
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
return event?.message || event;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
//# sourceMappingURL=utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable no-console */\n/**\n * Returns the localized name of a language given its BCP-47 code.\n *\n * @param languageCode - The BCP-47 language code (e.g. \"en\")\n * @returns The localized language name (e.g. \"English\") or the original code if unavailable.\n */\nexport function getLanguageName(languageCode: string): string {\n const userLocale = navigator.language || 'en';\n const displayNames = new Intl.DisplayNames([userLocale], {\n type: 'language',\n });\n const languageName = displayNames.of(languageCode);\n return languageName || languageCode;\n}\n\n/**\n * Requests access to the microphone.\n *\n * This function checks if the microphone permission is in \"prompt\" state, then requests\n * access and stops any active tracks immediately. It also logs if permission is already granted.\n *\n * @returns A promise that resolves when the permission request is complete.\n */\nexport async function requestMicAccess(): Promise<void> {\n try {\n // Fallback if Permissions API is not available\n if (!navigator.permissions) {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n stream.getTracks().forEach(track => track.stop());\n return;\n }\n\n const permissionStatus = await navigator.permissions.query({\n // eslint-disable-next-line no-undef\n name: 'microphone' as PermissionName,\n });\n\n if (permissionStatus.state === 'prompt') {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n stream.getTracks().forEach(track => track.stop());\n } else if (permissionStatus.state === 'denied') {\n console.warn('Microphone permission is denied.');\n }\n } catch (error) {\n console.error('Error checking/requesting microphone permission:', error);\n }\n}\n\n/**\n * Retrieves available audio input devices.\n *\n * This function uses the mediaDevices API to enumerate devices and filters out those\n * which are audio inputs. In some browsers, you may need to request user media before\n * device labels are populated.\n *\n * @returns A promise that resolves with an object containing:\n * - `devices`: an array of MediaDeviceInfo objects for audio inputs.\n * - `defaultDeviceId`: the deviceId of the first audio input, if available.\n */\nexport async function getAudioDevices(): Promise<{\n devices: MediaDeviceInfo[];\n defaultDevice?: MediaDeviceInfo;\n}> {\n if (!navigator.mediaDevices?.enumerateDevices) {\n console.error('Media devices API not supported.');\n return { devices: [] };\n }\n\n await requestMicAccess();\n\n try {\n // Optionally: await navigator.mediaDevices.getUserMedia({ audio: true });\n const devices = await navigator.mediaDevices.enumerateDevices();\n const audioDevices = devices.filter(device => device.kind === 'audioinput');\n const defaultDevice = audioDevices.length > 0 ? audioDevices[0] : undefined;\n return { devices: audioDevices, defaultDevice };\n } catch (error) {\n console.error('Error enumerating devices:', error);\n return { devices: [] };\n }\n}\n\n/**\n * Decodes a JWT token and extracts environment and tenant details from its issuer URL.\n *\n * NOTE: This function is temporarily kept for backward compatibility in return values.\n * The SDK now handles token parsing internally, so this should be removed once we\n * reduce the return results to only include what's necessary.\n *\n * @param token - A JSON Web Token (JWT) string.\n * @returns An object containing:\n * - `environment`: The extracted environment from the issuer URL.\n * - `tenant`: The extracted tenant from the issuer URL.\n * - `accessToken`: The original token string.\n * If the issuer URL doesn't match the expected format, returns undefined.\n *\n * @throws Will throw an error if:\n * - The token format is invalid.\n * - The base64 decoding or URI decoding fails.\n * - The JSON payload is invalid.\n * - The token payload does not contain an issuer (iss) field.\n */\nexport function decodeToken(token: string) {\n // Validate the token structure (should contain at least header and payload parts)\n const parts = token.split('.');\n if (parts.length < 2) {\n throw new Error('Invalid token format');\n }\n\n // Retrieve the payload (second part) of the JWT token\n const base64Url = parts[1];\n\n // Replace URL-safe characters to match standard base64 encoding\n const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');\n\n // Decode the base64 string into a JSON string\n let jsonPayload: string;\n try {\n jsonPayload = decodeURIComponent(\n atob(base64)\n .split('')\n .map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))\n .join(''),\n );\n } catch (error) {\n throw new Error('Failed to decode token payload');\n }\n\n // Parse the JSON string to obtain token details\n let tokenDetails: { iss: string; [key: string]: unknown };\n try {\n tokenDetails = JSON.parse(jsonPayload);\n } catch (error) {\n throw new Error('Invalid JSON payload in token');\n }\n\n // Extract the issuer URL from the token details\n const issuerUrl: string = tokenDetails.iss;\n if (!issuerUrl) {\n throw new Error('Token payload does not contain an issuer (iss) field');\n }\n\n // Regex to extract environment and tenant from issuer URL:\n // Expected format: https://keycloak.{environment}.corti.app/realms/{tenant}\n // Note: Unnecessary escapes in character classes have been removed.\n const regex =\n /^https:\\/\\/(keycloak|auth)\\.([^.]+)\\.corti\\.app\\/realms\\/([^/]+)/;\n const match = issuerUrl.match(regex);\n\n // If the issuer URL matches the expected pattern, return the extracted values along with the token\n if (match) {\n const expiresAt = tokenDetails.exp && typeof tokenDetails.exp === 'number'\n ? tokenDetails.exp\n : undefined;\n\n return {\n environment: match[2],\n tenant: match[3],\n accessToken: token,\n expiresAt,\n };\n }\n}\n\nexport async function getMediaStream(deviceId?: string): Promise<MediaStream> {\n if (!deviceId) {\n throw new Error('No device ID provided');\n }\n\n if (deviceId === 'display_audio') {\n const stream = await navigator.mediaDevices.getDisplayMedia({\n audio: true,\n video: true,\n });\n stream.getTracks().forEach(track => {\n if (track.kind === 'video') {\n stream.removeTrack(track);\n }\n });\n return stream;\n }\n\n // Get media stream and initialize audio service.\n const constraints: MediaStreamConstraints =\n deviceId !== 'default'\n ? { audio: { deviceId: { exact: deviceId } } }\n : { audio: true };\n\n return await navigator.mediaDevices.getUserMedia(constraints);\n}\n\nexport function getErrorMessage(event: Error) {\n try {\n return JSON.parse(event.message);\n } catch {\n return event?.message || event;\n }\n}\n"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@corti/dictation-web",
|
|
3
|
+
"description": "Web component for Corti Dictation",
|
|
4
|
+
"author": "Corti ApS",
|
|
5
|
+
"version": "0.0.0-rc.359",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"module": "dist/index.js",
|
|
10
|
+
"exports": {
|
|
11
|
+
"import": "./dist/index.js",
|
|
12
|
+
"browser": "./dist/bundle.js",
|
|
13
|
+
"default": "./dist/bundle.js"
|
|
14
|
+
},
|
|
15
|
+
"jsdelivr": "./dist/bundle.js",
|
|
16
|
+
"browser": "./dist/bundle.js",
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"bugs": {
|
|
21
|
+
"url": "https://help.corti.app",
|
|
22
|
+
"email": "help@corti.ai"
|
|
23
|
+
},
|
|
24
|
+
"repository": "github:corticph/dictation-web-sdk",
|
|
25
|
+
"homepage": "https://help.corti.app/en/articles/10714657-introducing-the-corti-dictation-browser-sdk",
|
|
26
|
+
"keywords": [
|
|
27
|
+
"corti",
|
|
28
|
+
"dictation",
|
|
29
|
+
"web",
|
|
30
|
+
"sdk",
|
|
31
|
+
"speech",
|
|
32
|
+
"recognition",
|
|
33
|
+
"transcription",
|
|
34
|
+
"audio",
|
|
35
|
+
"medical",
|
|
36
|
+
"healthcare"
|
|
37
|
+
],
|
|
38
|
+
"scripts": {
|
|
39
|
+
"analyze": "cem analyze --litelement",
|
|
40
|
+
"build": "tsc && npm run analyze -- --exclude dist",
|
|
41
|
+
"build:bundle": "esbuild dist/index.js --bundle --outfile=dist/bundle.js --format=esm --platform=browser",
|
|
42
|
+
"release": "npm run build && npm run build:bundle && npm publish --access public",
|
|
43
|
+
"start": "npm run build && npm run build:bundle && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"web-dev-server\"",
|
|
44
|
+
"prepublish": "tsc && npm run analyze -- --exclude dist",
|
|
45
|
+
"lint": "eslint --ext .ts,.tsx src --ignore-path .gitignore && prettier \"src/**/*.ts\" --check --ignore-path .gitignore",
|
|
46
|
+
"format": "eslint --ext .ts,.tsx src --fix --ignore-path .gitignore && prettier \"src/**/*.ts\" --write --ignore-path .gitignore",
|
|
47
|
+
"prepare": "husky && husky install",
|
|
48
|
+
"test": "tsc && wtr --coverage",
|
|
49
|
+
"test:watch": "tsc && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"wtr --watch\"",
|
|
50
|
+
"storybook": "tsc && npm run analyze -- --exclude dist && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"storybook dev -p 8080\"",
|
|
51
|
+
"storybook:build": "tsc && npm run analyze -- --exclude dist && storybook build"
|
|
52
|
+
},
|
|
53
|
+
"dependencies": {
|
|
54
|
+
"@corti/sdk": "^0.0.0-rc.2",
|
|
55
|
+
"lit": "^3.1.4"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@custom-elements-manifest/analyzer": "^0.10.3",
|
|
59
|
+
"@open-wc/eslint-config": "^12.0.3",
|
|
60
|
+
"@open-wc/testing": "^4.0.0",
|
|
61
|
+
"@storybook/addon-a11y": "^7.6.20",
|
|
62
|
+
"@storybook/addon-essentials": "^7.6.20",
|
|
63
|
+
"@storybook/addon-links": "^7.6.20",
|
|
64
|
+
"@storybook/web-components": "^7.6.20",
|
|
65
|
+
"@types/mocha": "^10.0.7",
|
|
66
|
+
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
67
|
+
"@typescript-eslint/parser": "^7.18.0",
|
|
68
|
+
"@web/dev-server": "^0.4.6",
|
|
69
|
+
"@web/storybook-builder": "^0.1.16",
|
|
70
|
+
"@web/storybook-framework-web-components": "^0.1.2",
|
|
71
|
+
"@web/test-runner": "^0.18.2",
|
|
72
|
+
"concurrently": "^8.2.2",
|
|
73
|
+
"esbuild": "^0.25.0",
|
|
74
|
+
"eslint": "^8.57.0",
|
|
75
|
+
"eslint-config-prettier": "^9.1.0",
|
|
76
|
+
"eslint-plugin-html": "^8.1.2",
|
|
77
|
+
"husky": "^8.0.0",
|
|
78
|
+
"lint-staged": "^15.2.7",
|
|
79
|
+
"prettier": "^3.3.2",
|
|
80
|
+
"sinon": "^19.0.2",
|
|
81
|
+
"storybook": "^7.6.20",
|
|
82
|
+
"tslib": "^2.6.3",
|
|
83
|
+
"typescript": "^5.5.3"
|
|
84
|
+
},
|
|
85
|
+
"customElements": "custom-elements.json",
|
|
86
|
+
"eslintConfig": {
|
|
87
|
+
"parser": "@typescript-eslint/parser",
|
|
88
|
+
"extends": [
|
|
89
|
+
"@open-wc",
|
|
90
|
+
"prettier"
|
|
91
|
+
],
|
|
92
|
+
"plugins": [
|
|
93
|
+
"@typescript-eslint"
|
|
94
|
+
],
|
|
95
|
+
"rules": {
|
|
96
|
+
"no-unused-vars": "off",
|
|
97
|
+
"@typescript-eslint/no-unused-vars": [
|
|
98
|
+
"error"
|
|
99
|
+
],
|
|
100
|
+
"import/no-unresolved": "off",
|
|
101
|
+
"import/extensions": [
|
|
102
|
+
"error",
|
|
103
|
+
"always",
|
|
104
|
+
{
|
|
105
|
+
"ignorePackages": true
|
|
106
|
+
}
|
|
107
|
+
]
|
|
108
|
+
}
|
|
109
|
+
},
|
|
110
|
+
"prettier": {
|
|
111
|
+
"singleQuote": true,
|
|
112
|
+
"arrowParens": "avoid"
|
|
113
|
+
},
|
|
114
|
+
"lint-staged": {
|
|
115
|
+
"*.ts": [
|
|
116
|
+
"eslint --fix",
|
|
117
|
+
"prettier --write"
|
|
118
|
+
]
|
|
119
|
+
}
|
|
120
|
+
}
|