@corti/dictation-web 0.1.7 → 0.1.9
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 +37 -31
- package/dist/CortiDictation.d.ts +6 -1
- package/dist/CortiDictation.js +20 -14
- package/dist/CortiDictation.js.map +1 -1
- package/dist/DictationService.d.ts +4 -4
- package/dist/DictationService.js +4 -11
- package/dist/DictationService.js.map +1 -1
- package/dist/RecorderManager.d.ts +2 -2
- package/dist/RecorderManager.js.map +1 -1
- package/dist/bundle.js +57 -80
- package/dist/components/settings-menu.js +3 -4
- package/dist/components/settings-menu.js.map +1 -1
- package/dist/constants.js +1 -1
- package/dist/constants.js.map +1 -1
- package/dist/styles/callout.js +29 -29
- package/dist/styles/callout.js.map +1 -1
- package/dist/styles/theme.js +20 -41
- package/dist/styles/theme.js.map +1 -1
- package/dist/types.d.ts +3 -3
- package/dist/types.js.map +1 -1
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +2 -2
- package/dist/utils.js.map +1 -1
- package/package.json +98 -98
package/dist/bundle.js
CHANGED
|
@@ -659,7 +659,7 @@ function decodeToken(token) {
|
|
|
659
659
|
return {
|
|
660
660
|
environment: match[2],
|
|
661
661
|
tenant: match[3],
|
|
662
|
-
token
|
|
662
|
+
accessToken: token
|
|
663
663
|
};
|
|
664
664
|
}
|
|
665
665
|
}
|
|
@@ -707,15 +707,11 @@ var AudioService = class {
|
|
|
707
707
|
|
|
708
708
|
// dist/DictationService.js
|
|
709
709
|
var DictationService = class extends EventTarget {
|
|
710
|
-
constructor(mediaStream, { dictationConfig,
|
|
710
|
+
constructor(mediaStream, { dictationConfig, serverConfig }) {
|
|
711
711
|
super();
|
|
712
712
|
this.mediaRecorder = new MediaRecorder(mediaStream);
|
|
713
|
-
this.
|
|
713
|
+
this.serverConfig = serverConfig;
|
|
714
714
|
this.dictationConfig = dictationConfig;
|
|
715
|
-
const config = decodeToken(this.authToken);
|
|
716
|
-
if (!config) {
|
|
717
|
-
throw new Error("Invalid token");
|
|
718
|
-
}
|
|
719
715
|
this.mediaRecorder.ondataavailable = (event) => {
|
|
720
716
|
if (this.webSocket?.readyState === WebSocket.OPEN) {
|
|
721
717
|
this.webSocket.send(event.data);
|
|
@@ -730,8 +726,7 @@ var DictationService = class extends EventTarget {
|
|
|
730
726
|
}));
|
|
731
727
|
}
|
|
732
728
|
startRecording() {
|
|
733
|
-
|
|
734
|
-
if (!serverConfig) {
|
|
729
|
+
if (!this.serverConfig) {
|
|
735
730
|
this.dispatchEvent(new CustomEvent("error", {
|
|
736
731
|
detail: "Invalid token",
|
|
737
732
|
bubbles: true,
|
|
@@ -739,7 +734,7 @@ var DictationService = class extends EventTarget {
|
|
|
739
734
|
}));
|
|
740
735
|
return;
|
|
741
736
|
}
|
|
742
|
-
const url = `wss://api.${serverConfig.environment}.corti.app/audio-bridge/v2/transcribe?tenant-name=${serverConfig.tenant}&token=Bearer%20${this.
|
|
737
|
+
const url = `wss://api.${this.serverConfig.environment}.corti.app/audio-bridge/v2/transcribe?tenant-name=${this.serverConfig.tenant}&token=Bearer%20${this.serverConfig.accessToken}`;
|
|
743
738
|
this.webSocket = new WebSocket(url);
|
|
744
739
|
this.webSocket.onopen = () => {
|
|
745
740
|
this.webSocket.send(JSON.stringify({
|
|
@@ -1019,9 +1014,9 @@ var DEFAULT_DICTATION_CONFIG = {
|
|
|
1019
1014
|
// dist/styles/callout.js
|
|
1020
1015
|
var CalloutStyles = i`
|
|
1021
1016
|
.callout {
|
|
1022
|
-
background: var(--callout-
|
|
1023
|
-
border: 1px solid var(--callout-
|
|
1024
|
-
color: var(--callout-
|
|
1017
|
+
background: var(--callout-info-background);
|
|
1018
|
+
border: 1px solid var(--callout-info-border);
|
|
1019
|
+
color: var(--callout-info-text);
|
|
1025
1020
|
padding: 8px;
|
|
1026
1021
|
border-radius: var(--card-inner-border-radius);
|
|
1027
1022
|
display: flex;
|
|
@@ -1030,15 +1025,15 @@ var CalloutStyles = i`
|
|
|
1030
1025
|
align-items: center;
|
|
1031
1026
|
max-width: 100%;
|
|
1032
1027
|
height: fit-content;
|
|
1033
|
-
&.
|
|
1034
|
-
background: var(--callout-
|
|
1035
|
-
border: 1px solid var(--callout-
|
|
1036
|
-
color: var(--callout-
|
|
1028
|
+
&.error {
|
|
1029
|
+
background: var(--callout-error-background);
|
|
1030
|
+
border: 1px solid var(--callout-error-border);
|
|
1031
|
+
color: var(--callout-warn-text);
|
|
1037
1032
|
}
|
|
1038
|
-
&.
|
|
1039
|
-
background: var(--callout-
|
|
1040
|
-
border: 1px solid var(--callout-
|
|
1041
|
-
color: var(--callout-
|
|
1033
|
+
&.warn {
|
|
1034
|
+
background: var(--callout-warn-background);
|
|
1035
|
+
border: 1px solid var(--callout-warn-border);
|
|
1036
|
+
color: var(--callout-warn-text);
|
|
1042
1037
|
}
|
|
1043
1038
|
&.small {
|
|
1044
1039
|
width: 100%;
|
|
@@ -1098,7 +1093,7 @@ var SettingsMenu = class SettingsMenu2 extends r4 {
|
|
|
1098
1093
|
<div id="settings-popover" popover>
|
|
1099
1094
|
<div class="settings-wrapper">
|
|
1100
1095
|
${this.settingsDisabled ? x`
|
|
1101
|
-
<div class="callout
|
|
1096
|
+
<div class="callout warn">
|
|
1102
1097
|
Recording is in progress. Stop recording to change settings.
|
|
1103
1098
|
</div>
|
|
1104
1099
|
` : ""}
|
|
@@ -1175,10 +1170,9 @@ SettingsMenu.styles = [
|
|
|
1175
1170
|
width: 100%;
|
|
1176
1171
|
min-width: 200px;
|
|
1177
1172
|
position-anchor: --settings_popover_btn;
|
|
1178
|
-
position-area: bottom;
|
|
1173
|
+
position-area: bottom span-right;
|
|
1179
1174
|
position-visibility: always;
|
|
1180
|
-
|
|
1181
|
-
transform: translateX(40%);
|
|
1175
|
+
position-try-fallbacks: flip-inline;
|
|
1182
1176
|
overflow-x: hidden;
|
|
1183
1177
|
}
|
|
1184
1178
|
.settings-wrapper {
|
|
@@ -1423,69 +1417,48 @@ IconLoadingSpinner = __decorate3([
|
|
|
1423
1417
|
// dist/styles/theme.js
|
|
1424
1418
|
var ThemeStyles = i`
|
|
1425
1419
|
:host {
|
|
1420
|
+
color-scheme: light dark;
|
|
1426
1421
|
/* Component Defaults */
|
|
1427
1422
|
--component-font-family: 'Segoe UI', Roboto, sans-serif;
|
|
1428
|
-
--component-text-color: #333;
|
|
1423
|
+
--component-text-color: light-dark(#333, #eee);
|
|
1429
1424
|
|
|
1430
1425
|
/* Card Defaults */
|
|
1431
|
-
--card-background: #fff;
|
|
1432
|
-
--card-border-color: #ddd;
|
|
1426
|
+
--card-background: light-dark(#fff, #333);
|
|
1427
|
+
--card-border-color: light-dark(#ddd, #555);
|
|
1433
1428
|
--card-padding: 4px;
|
|
1434
1429
|
--card-border-radius: 8px;
|
|
1435
1430
|
--card-inner-border-radius: 6px;
|
|
1436
1431
|
--card-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
|
1437
1432
|
|
|
1438
1433
|
/* Actions Defaults */
|
|
1439
|
-
--action-plain-border-color: #ccc;
|
|
1440
|
-
--action-plain-background-hover: #ddd;
|
|
1434
|
+
--action-plain-border-color: light-dark(#ccc, #555);
|
|
1435
|
+
--action-plain-background-hover: light-dark(#ddd, #444);
|
|
1441
1436
|
|
|
1442
|
-
--action-accent-background: #007bff;
|
|
1443
|
-
--action-accent-background-hover: #0056b3;
|
|
1437
|
+
--action-accent-background: light-dark(#007bff, #0056b3);
|
|
1438
|
+
--action-accent-background-hover: light-dark(#0056b3, #003d80);
|
|
1444
1439
|
--action-accent-text-color: #fff;
|
|
1445
1440
|
|
|
1446
|
-
--action-red-background: #dc3545;
|
|
1447
|
-
--action-red-background-hover: #bd2130;
|
|
1441
|
+
--action-red-background: light-dark(#dc3545, #bd2130);
|
|
1442
|
+
--action-red-background-hover: light-dark(#bd2130, #a71c24);
|
|
1448
1443
|
--action-red-text-color: #fff;
|
|
1449
1444
|
|
|
1450
1445
|
/* Callout Defaults */
|
|
1451
|
-
--callout-
|
|
1452
|
-
--callout-
|
|
1453
|
-
--callout-
|
|
1446
|
+
--callout-info-background: light-dark(#007bff33, #0056b333);
|
|
1447
|
+
--callout-info-border: light-dark(#007bff99, #0056b399);
|
|
1448
|
+
--callout-info-text: light-dark(#007bff, #0056b3);
|
|
1454
1449
|
|
|
1455
|
-
--callout-
|
|
1456
|
-
--callout-
|
|
1457
|
-
--callout-
|
|
1450
|
+
--callout-error-background: light-dark(#dc354533, #bd213033);
|
|
1451
|
+
--callout-error-border: light-dark(#dc354599, #bd213099);
|
|
1452
|
+
--callout-error-text: light-dark(#dc3545, #bd2130);
|
|
1458
1453
|
|
|
1459
|
-
--callout-
|
|
1460
|
-
--callout-
|
|
1461
|
-
--callout-
|
|
1454
|
+
--callout-warn-background: light-dark(#fd7e1433, #e06c1233);
|
|
1455
|
+
--callout-warn-border: light-dark(#fd7e1499, #e06c1299);
|
|
1456
|
+
--callout-warn-text: light-dark(#fd7e14, #e06c12);
|
|
1462
1457
|
|
|
1463
1458
|
/* Visualiser Defaults */
|
|
1464
|
-
--visualiser-background: #e0e0e0;
|
|
1465
|
-
--visualiser-level-color: #28a745;
|
|
1459
|
+
--visualiser-background: light-dark(#e0e0e0, #fff);
|
|
1466
1460
|
}
|
|
1467
1461
|
|
|
1468
|
-
@media (prefers-color-scheme: dark) {
|
|
1469
|
-
:host {
|
|
1470
|
-
/* Component Dark */
|
|
1471
|
-
--component-text-color: #eee;
|
|
1472
|
-
|
|
1473
|
-
/* Card Dark */
|
|
1474
|
-
--card-background: #333;
|
|
1475
|
-
--card-border-color: #555;
|
|
1476
|
-
|
|
1477
|
-
/* Actions Dark */
|
|
1478
|
-
--action-plain-border-color: #555;
|
|
1479
|
-
--action-plain-background: #333;
|
|
1480
|
-
--action-plain-background-hover: #444;
|
|
1481
|
-
|
|
1482
|
-
--action-accent-background: #0056b3;
|
|
1483
|
-
--action-accent-background-hover: #003d80;
|
|
1484
|
-
|
|
1485
|
-
/* Visualiser Dark */
|
|
1486
|
-
--visualiser-background: #fff;
|
|
1487
|
-
}
|
|
1488
|
-
}
|
|
1489
1462
|
:host {
|
|
1490
1463
|
box-sizing: border-box;
|
|
1491
1464
|
font-family: var(--component-font-family);
|
|
@@ -1611,6 +1584,15 @@ var CortiDictation = class extends r4 {
|
|
|
1611
1584
|
toggleRecording() {
|
|
1612
1585
|
this._toggleRecording();
|
|
1613
1586
|
}
|
|
1587
|
+
setAccessToken(token) {
|
|
1588
|
+
try {
|
|
1589
|
+
const decoded = decodeToken(token);
|
|
1590
|
+
this._serverConfig = decoded;
|
|
1591
|
+
return decoded;
|
|
1592
|
+
} catch (e5) {
|
|
1593
|
+
throw new Error("Invalid token");
|
|
1594
|
+
}
|
|
1595
|
+
}
|
|
1614
1596
|
get selectedDevice() {
|
|
1615
1597
|
return this.recorderManager.selectedDevice || null;
|
|
1616
1598
|
}
|
|
@@ -1623,25 +1605,25 @@ var CortiDictation = class extends r4 {
|
|
|
1623
1605
|
async setRecordingDevice(device) {
|
|
1624
1606
|
this.recorderManager.selectedDevice = device;
|
|
1625
1607
|
this._selectedDevice = device;
|
|
1626
|
-
if (!this.
|
|
1608
|
+
if (!this._serverConfig)
|
|
1627
1609
|
return;
|
|
1628
1610
|
if (this._recordingState === "recording") {
|
|
1629
1611
|
await this.recorderManager.stopRecording();
|
|
1630
1612
|
await this.recorderManager.startRecording({
|
|
1631
1613
|
dictationConfig: this.dictationConfig,
|
|
1632
|
-
|
|
1614
|
+
serverConfig: this._serverConfig
|
|
1633
1615
|
});
|
|
1634
1616
|
}
|
|
1635
1617
|
}
|
|
1636
1618
|
_toggleRecording() {
|
|
1637
|
-
if (!this.
|
|
1619
|
+
if (!this._serverConfig)
|
|
1638
1620
|
return;
|
|
1639
1621
|
if (this._recordingState === "recording") {
|
|
1640
1622
|
this.recorderManager.stopRecording();
|
|
1641
1623
|
} else if (this._recordingState === "stopped") {
|
|
1642
1624
|
this.recorderManager.startRecording({
|
|
1643
1625
|
dictationConfig: this.dictationConfig,
|
|
1644
|
-
|
|
1626
|
+
serverConfig: this._serverConfig,
|
|
1645
1627
|
debug_displayAudio: this.debug_displayAudio
|
|
1646
1628
|
});
|
|
1647
1629
|
}
|
|
@@ -1652,13 +1634,8 @@ var CortiDictation = class extends r4 {
|
|
|
1652
1634
|
this.setRecordingDevice(customEvent.detail.selectedDevice);
|
|
1653
1635
|
}
|
|
1654
1636
|
render() {
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
return x`
|
|
1658
|
-
<div class="wrapper">
|
|
1659
|
-
<div class="callout red small">No Auth Token</div>
|
|
1660
|
-
</div>
|
|
1661
|
-
`;
|
|
1637
|
+
if (!this._serverConfig) {
|
|
1638
|
+
return x` <div style="display: none"></div> `;
|
|
1662
1639
|
}
|
|
1663
1640
|
const isLoading = this._recordingState === "initializing" || this._recordingState === "stopping";
|
|
1664
1641
|
const isRecording = this._recordingState === "recording";
|
|
@@ -1688,12 +1665,12 @@ CortiDictation.styles = [buttons_default, theme_default, ComponentStyles_default
|
|
|
1688
1665
|
__decorate4([
|
|
1689
1666
|
n4({ type: Object })
|
|
1690
1667
|
], CortiDictation.prototype, "dictationConfig", void 0);
|
|
1691
|
-
__decorate4([
|
|
1692
|
-
n4({ type: String })
|
|
1693
|
-
], CortiDictation.prototype, "authToken", void 0);
|
|
1694
1668
|
__decorate4([
|
|
1695
1669
|
n4({ type: Boolean })
|
|
1696
1670
|
], CortiDictation.prototype, "debug_displayAudio", void 0);
|
|
1671
|
+
__decorate4([
|
|
1672
|
+
r6()
|
|
1673
|
+
], CortiDictation.prototype, "_serverConfig", void 0);
|
|
1697
1674
|
__decorate4([
|
|
1698
1675
|
r6()
|
|
1699
1676
|
], CortiDictation.prototype, "_audioLevel", void 0);
|
|
@@ -56,7 +56,7 @@ let SettingsMenu = class SettingsMenu extends LitElement {
|
|
|
56
56
|
<div class="settings-wrapper">
|
|
57
57
|
${this.settingsDisabled
|
|
58
58
|
? html `
|
|
59
|
-
<div class="callout
|
|
59
|
+
<div class="callout warn">
|
|
60
60
|
Recording is in progress. Stop recording to change settings.
|
|
61
61
|
</div>
|
|
62
62
|
`
|
|
@@ -134,10 +134,9 @@ SettingsMenu.styles = [
|
|
|
134
134
|
width: 100%;
|
|
135
135
|
min-width: 200px;
|
|
136
136
|
position-anchor: --settings_popover_btn;
|
|
137
|
-
position-area: bottom;
|
|
137
|
+
position-area: bottom span-right;
|
|
138
138
|
position-visibility: always;
|
|
139
|
-
|
|
140
|
-
transform: translateX(40%);
|
|
139
|
+
position-try-fallbacks: flip-inline;
|
|
141
140
|
overflow-x: hidden;
|
|
142
141
|
}
|
|
143
142
|
.settings-wrapper {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"settings-menu.js","sourceRoot":"","sources":["../../src/components/settings-menu.ts"],"names":[],"mappings":";;;;;;AAAA,kBAAkB;AAClB,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,GAAG,EAAkC,MAAM,KAAK,CAAC;AAC5E,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAEnE,OAAO,YAAY,MAAM,sBAAsB,CAAC;AAChD,OAAO,YAAY,MAAM,qBAAqB,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC/D,OAAO,aAAa,MAAM,sBAAsB,CAAC;AAG1C,IAAM,YAAY,GAAlB,MAAM,YAAa,SAAQ,UAAU;IAa1C;QACE,KAAK,EAAE,CAAC;QATV,qBAAgB,GAAW,EAAE,CAAC;QAG9B,qBAAgB,GAAY,KAAK,CAAC;QAG1B,aAAQ,GAAsB,EAAE,CAAC;QAIvC,SAAS,CAAC,YAAY,CAAC,gBAAgB,CACrC,cAAc,EACd,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,CACpC,CAAC;IACJ,CAAC;IAED,qCAAqC;IACrC,KAAK,CAAC,iBAAiB;QACrB,KAAK,CAAC,iBAAiB,EAAE,CAAC;QAC1B,MAAM,cAAc,GAAG,MAAM,eAAe,EAAE,CAAC;QAC/C,IAAI,CAAC,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC;IACzC,CAAC;IAEO,KAAK,CAAC,mBAAmB;QAC/B,MAAM,cAAc,GAAG,MAAM,eAAe,EAAE,CAAC;QAC/C,IAAI,CAAC,QAAQ,GAAG,cAAc,CAAC,OAAO,CAAC;IACzC,CAAC;
|
|
1
|
+
{"version":3,"file":"settings-menu.js","sourceRoot":"","sources":["../../src/components/settings-menu.ts"],"names":[],"mappings":"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","sourcesContent":["// mic-selector.ts\nimport { LitElement, html, css, TemplateResult, CSSResultGroup } from 'lit';\nimport { customElement, property, state } from 'lit/decorators.js';\n\nimport ButtonStyles from '../styles/buttons.js';\nimport SelectStyles from '../styles/select.js';\nimport { LANGUAGES_SUPPORTED } from '../constants.js';\nimport { getAudioDevices, getLanguageName } from '../utils.js';\nimport CalloutStyles from '../styles/callout.js';\n\n@customElement('settings-menu')\nexport class SettingsMenu extends LitElement {\n @property({ type: String })\n selectedDevice: MediaDeviceInfo | undefined;\n\n @property({ type: String })\n selectedLanguage: string = '';\n\n @property({ type: Boolean })\n settingsDisabled: boolean = false;\n\n @state()\n private _devices: MediaDeviceInfo[] = [];\n\n constructor() {\n super();\n navigator.mediaDevices.addEventListener(\n 'devicechange',\n this.handleDevicesChange.bind(this),\n );\n }\n\n // on load, get the available devices\n async connectedCallback(): Promise<void> {\n super.connectedCallback();\n const deviceResponse = await getAudioDevices();\n this._devices = deviceResponse.devices;\n }\n\n private async handleDevicesChange() {\n const deviceResponse = await getAudioDevices();\n this._devices = deviceResponse.devices;\n }\n\n static styles: CSSResultGroup = [\n css`\n :host {\n display: block;\n font-family: var(--component-font-family);\n }\n /* Retain the anchor-name styling for this component */\n #settings-popover-button {\n anchor-name: --settings_popover_btn;\n }\n [popover] {\n margin: 0;\n padding: 16px;\n border: 0;\n background: var(--card-background);\n border: 1px solid var(--card-border-color);\n border-radius: var(--card-border-radius);\n box-shadow: var(--card-box-shadow);\n z-index: 1000;\n max-width: 260px;\n width: 100%;\n min-width: 200px;\n position-anchor: --settings_popover_btn;\n position-area: bottom span-right;\n position-visibility: always;\n position-try-fallbacks: flip-inline;\n overflow-x: hidden;\n }\n .settings-wrapper {\n display: flex;\n flex-direction: column;\n gap: 20px;\n }\n `,\n ButtonStyles,\n SelectStyles,\n CalloutStyles,\n ];\n\n private _selectDevice(deviceId: string): void {\n // Find the device object\n const device = this._devices.find(d => d.deviceId === deviceId);\n if (!device) {\n return;\n }\n this.selectedDevice = device;\n this.dispatchEvent(\n new CustomEvent('recording-devices-changed', {\n detail: {\n devices: this._devices,\n selectedDevice: device,\n },\n bubbles: true,\n composed: true,\n }),\n );\n }\n\n render(): TemplateResult {\n return html`\n <div class=\"mic-selector\">\n <button id=\"settings-popover-button\" popovertarget=\"settings-popover\">\n <icon-settings></icon-settings>\n </button>\n <div id=\"settings-popover\" popover>\n <div class=\"settings-wrapper\">\n ${this.settingsDisabled\n ? html`\n <div class=\"callout warn\">\n Recording is in progress. Stop recording to change settings.\n </div>\n `\n : ''}\n <div class=\"form-group\">\n <label id=\"device-select-label\" for=\"device-select\">\n Recording Device\n </label>\n <select\n id=\"device-select\"\n aria-labelledby=\"device-select-label\"\n @change=${(e: Event) => {\n this._selectDevice((e.target as HTMLSelectElement).value);\n }}\n ?disabled=${this.settingsDisabled}\n >\n ${this._devices.map(\n device => html`\n <option\n value=${device.deviceId}\n ?selected=${this.selectedDevice === device}\n >\n ${device.label || 'Unknown Device'}\n </option>\n `,\n )}\n </select>\n </div>\n <div class=\"form-group\">\n <label id=\"language-select-label\" for=\"language-select\">\n Dictation Language\n </label>\n <select\n id=\"language-select\"\n aria-labelledby=\"language-select-label\"\n @change=${(e: Event) => {\n this._selectDevice((e.target as HTMLSelectElement).value);\n }}\n ?disabled=${this.settingsDisabled}\n >\n ${LANGUAGES_SUPPORTED.map(\n language => html`\n <option\n value=${language}\n ?selected=${this.selectedLanguage === language}\n >\n ${getLanguageName(language)}\n </option>\n `,\n )}\n </select>\n </div>\n </div>\n </div>\n </div>\n `;\n }\n}\n\ndeclare global {\n interface HTMLElementTagNameMap {\n 'settings-menu': SettingsMenu;\n }\n}\n"]}
|
package/dist/constants.js
CHANGED
package/dist/constants.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAChD,MAAM,CAAC,MAAM,wBAAwB,GAAoB;IACvD,eAAe,EAAE,IAAI;IACrB,cAAc,EAAE,IAAI;IACpB,iBAAiB,EAAE,IAAI;IACvB,oBAAoB,EAAE,IAAI;IAC1B,KAAK,EAAE,QAAQ;CAChB,CAAC","sourcesContent":["import { DictationConfig } from './types.js';\r\n\r\nexport const LANGUAGES_SUPPORTED = ['en', 'da'];\r\nexport const DEFAULT_DICTATION_CONFIG: DictationConfig = {\r\n primaryLanguage: 'en',\r\n interimResults: true,\r\n spokenPunctuation: true,\r\n automaticPunctuation: true,\r\n model: 'others'
|
|
1
|
+
{"version":3,"file":"constants.js","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AAChD,MAAM,CAAC,MAAM,wBAAwB,GAAoB;IACvD,eAAe,EAAE,IAAI;IACrB,cAAc,EAAE,IAAI;IACpB,iBAAiB,EAAE,IAAI;IACvB,oBAAoB,EAAE,IAAI;IAC1B,KAAK,EAAE,QAAQ;CAChB,CAAC","sourcesContent":["import { DictationConfig } from './types.js';\r\n\r\nexport const LANGUAGES_SUPPORTED = ['en', 'da'];\r\nexport const DEFAULT_DICTATION_CONFIG: DictationConfig = {\r\n primaryLanguage: 'en',\r\n interimResults: true,\r\n spokenPunctuation: true,\r\n automaticPunctuation: true,\r\n model: 'others',\r\n};\r\n"]}
|
package/dist/styles/callout.js
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
1
|
import { css } from 'lit';
|
|
2
|
-
const CalloutStyles = css `
|
|
3
|
-
.callout {
|
|
4
|
-
background: var(--callout-
|
|
5
|
-
border: 1px solid var(--callout-
|
|
6
|
-
color: var(--callout-
|
|
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
|
-
&.
|
|
16
|
-
background: var(--callout-
|
|
17
|
-
border: 1px solid var(--callout-
|
|
18
|
-
color: var(--callout-
|
|
19
|
-
}
|
|
20
|
-
&.
|
|
21
|
-
background: var(--callout-
|
|
22
|
-
border: 1px solid var(--callout-
|
|
23
|
-
color: var(--callout-
|
|
24
|
-
}
|
|
25
|
-
&.small {
|
|
26
|
-
width: 100%;
|
|
27
|
-
padding: 6px;
|
|
28
|
-
font-size: 0.7rem;
|
|
29
|
-
}
|
|
30
|
-
}
|
|
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
31
|
`;
|
|
32
32
|
export default CalloutStyles;
|
|
33
33
|
//# sourceMappingURL=callout.js.map
|
|
@@ -1 +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';\
|
|
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"]}
|
package/dist/styles/theme.js
CHANGED
|
@@ -1,69 +1,48 @@
|
|
|
1
1
|
import { css } from 'lit';
|
|
2
2
|
const ThemeStyles = css `
|
|
3
3
|
:host {
|
|
4
|
+
color-scheme: light dark;
|
|
4
5
|
/* Component Defaults */
|
|
5
6
|
--component-font-family: 'Segoe UI', Roboto, sans-serif;
|
|
6
|
-
--component-text-color: #333;
|
|
7
|
+
--component-text-color: light-dark(#333, #eee);
|
|
7
8
|
|
|
8
9
|
/* Card Defaults */
|
|
9
|
-
--card-background: #fff;
|
|
10
|
-
--card-border-color: #ddd;
|
|
10
|
+
--card-background: light-dark(#fff, #333);
|
|
11
|
+
--card-border-color: light-dark(#ddd, #555);
|
|
11
12
|
--card-padding: 4px;
|
|
12
13
|
--card-border-radius: 8px;
|
|
13
14
|
--card-inner-border-radius: 6px;
|
|
14
15
|
--card-box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1);
|
|
15
16
|
|
|
16
17
|
/* Actions Defaults */
|
|
17
|
-
--action-plain-border-color: #ccc;
|
|
18
|
-
--action-plain-background-hover: #ddd;
|
|
18
|
+
--action-plain-border-color: light-dark(#ccc, #555);
|
|
19
|
+
--action-plain-background-hover: light-dark(#ddd, #444);
|
|
19
20
|
|
|
20
|
-
--action-accent-background: #007bff;
|
|
21
|
-
--action-accent-background-hover: #0056b3;
|
|
21
|
+
--action-accent-background: light-dark(#007bff, #0056b3);
|
|
22
|
+
--action-accent-background-hover: light-dark(#0056b3, #003d80);
|
|
22
23
|
--action-accent-text-color: #fff;
|
|
23
24
|
|
|
24
|
-
--action-red-background: #dc3545;
|
|
25
|
-
--action-red-background-hover: #bd2130;
|
|
25
|
+
--action-red-background: light-dark(#dc3545, #bd2130);
|
|
26
|
+
--action-red-background-hover: light-dark(#bd2130, #a71c24);
|
|
26
27
|
--action-red-text-color: #fff;
|
|
27
28
|
|
|
28
29
|
/* Callout Defaults */
|
|
29
|
-
--callout-
|
|
30
|
-
--callout-
|
|
31
|
-
--callout-
|
|
30
|
+
--callout-info-background: light-dark(#007bff33, #0056b333);
|
|
31
|
+
--callout-info-border: light-dark(#007bff99, #0056b399);
|
|
32
|
+
--callout-info-text: light-dark(#007bff, #0056b3);
|
|
32
33
|
|
|
33
|
-
--callout-
|
|
34
|
-
--callout-
|
|
35
|
-
--callout-
|
|
34
|
+
--callout-error-background: light-dark(#dc354533, #bd213033);
|
|
35
|
+
--callout-error-border: light-dark(#dc354599, #bd213099);
|
|
36
|
+
--callout-error-text: light-dark(#dc3545, #bd2130);
|
|
36
37
|
|
|
37
|
-
--callout-
|
|
38
|
-
--callout-
|
|
39
|
-
--callout-
|
|
38
|
+
--callout-warn-background: light-dark(#fd7e1433, #e06c1233);
|
|
39
|
+
--callout-warn-border: light-dark(#fd7e1499, #e06c1299);
|
|
40
|
+
--callout-warn-text: light-dark(#fd7e14, #e06c12);
|
|
40
41
|
|
|
41
42
|
/* Visualiser Defaults */
|
|
42
|
-
--visualiser-background: #e0e0e0;
|
|
43
|
-
--visualiser-level-color: #28a745;
|
|
43
|
+
--visualiser-background: light-dark(#e0e0e0, #fff);
|
|
44
44
|
}
|
|
45
45
|
|
|
46
|
-
@media (prefers-color-scheme: dark) {
|
|
47
|
-
:host {
|
|
48
|
-
/* Component Dark */
|
|
49
|
-
--component-text-color: #eee;
|
|
50
|
-
|
|
51
|
-
/* Card Dark */
|
|
52
|
-
--card-background: #333;
|
|
53
|
-
--card-border-color: #555;
|
|
54
|
-
|
|
55
|
-
/* Actions Dark */
|
|
56
|
-
--action-plain-border-color: #555;
|
|
57
|
-
--action-plain-background: #333;
|
|
58
|
-
--action-plain-background-hover: #444;
|
|
59
|
-
|
|
60
|
-
--action-accent-background: #0056b3;
|
|
61
|
-
--action-accent-background-hover: #003d80;
|
|
62
|
-
|
|
63
|
-
/* Visualiser Dark */
|
|
64
|
-
--visualiser-background: #fff;
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
46
|
:host {
|
|
68
47
|
box-sizing: border-box;
|
|
69
48
|
font-family: var(--component-font-family);
|
package/dist/styles/theme.js.map
CHANGED
|
@@ -1 +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
|
|
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;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAiDtB,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: 'Segoe UI', Roboto, 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
CHANGED
|
@@ -19,8 +19,8 @@ export interface DictationConfig {
|
|
|
19
19
|
}
|
|
20
20
|
export type PartialDictationConfig = Partial<DictationConfig>;
|
|
21
21
|
export interface ServerConfig {
|
|
22
|
-
environment
|
|
23
|
-
tenant
|
|
24
|
-
|
|
22
|
+
environment: string;
|
|
23
|
+
tenant: string;
|
|
24
|
+
accessToken: string;
|
|
25
25
|
}
|
|
26
26
|
export {};
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["export type RecordingState =\n | 'initializing'\n | 'recording'\n | 'stopping'\n | 'stopped';\n\ninterface CommandVariable {\n key: string;\n type: 'enum' | 'string';\n enum?: string[];\n}\n\nexport interface Command {\n id: string;\n phrases: string[];\n variables?: CommandVariable[];\n}\n\nexport interface DictationConfig {\n primaryLanguage: string;\n interimResults: boolean;\n spokenPunctuation: boolean;\n automaticPunctuation: boolean;\n model: string;\n commands?: Command[];\n}\n\nexport type PartialDictationConfig = Partial<DictationConfig>;\n\nexport interface ServerConfig {\n environment
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"","sourcesContent":["export type RecordingState =\n | 'initializing'\n | 'recording'\n | 'stopping'\n | 'stopped';\n\ninterface CommandVariable {\n key: string;\n type: 'enum' | 'string';\n enum?: string[];\n}\n\nexport interface Command {\n id: string;\n phrases: string[];\n variables?: CommandVariable[];\n}\n\nexport interface DictationConfig {\n primaryLanguage: string;\n interimResults: boolean;\n spokenPunctuation: boolean;\n automaticPunctuation: boolean;\n model: string;\n commands?: Command[];\n}\n\nexport type PartialDictationConfig = Partial<DictationConfig>;\n\nexport interface ServerConfig {\n environment: string;\n tenant: string;\n accessToken: string;\n}\n"]}
|
package/dist/utils.d.ts
CHANGED
|
@@ -41,7 +41,7 @@ export declare function getAudioDevices(): Promise<{
|
|
|
41
41
|
* @returns An object containing:
|
|
42
42
|
* - `environment`: The extracted environment from the issuer URL.
|
|
43
43
|
* - `tenant`: The extracted tenant from the issuer URL.
|
|
44
|
-
* - `
|
|
44
|
+
* - `accessToken`: The original token string.
|
|
45
45
|
* If the issuer URL doesn't match the expected format, the function returns the full decoded token details.
|
|
46
46
|
*
|
|
47
47
|
* @throws Will throw an error if:
|
|
@@ -53,6 +53,6 @@ export declare function getAudioDevices(): Promise<{
|
|
|
53
53
|
export declare function decodeToken(token: string): {
|
|
54
54
|
environment: string;
|
|
55
55
|
tenant: string;
|
|
56
|
-
|
|
56
|
+
accessToken: string;
|
|
57
57
|
} | undefined;
|
|
58
58
|
export declare function getMediaStream(deviceId?: string): Promise<MediaStream>;
|
package/dist/utils.js
CHANGED
|
@@ -86,7 +86,7 @@ export async function getAudioDevices() {
|
|
|
86
86
|
* @returns An object containing:
|
|
87
87
|
* - `environment`: The extracted environment from the issuer URL.
|
|
88
88
|
* - `tenant`: The extracted tenant from the issuer URL.
|
|
89
|
-
* - `
|
|
89
|
+
* - `accessToken`: The original token string.
|
|
90
90
|
* If the issuer URL doesn't match the expected format, the function returns the full decoded token details.
|
|
91
91
|
*
|
|
92
92
|
* @throws Will throw an error if:
|
|
@@ -139,7 +139,7 @@ export function decodeToken(token) {
|
|
|
139
139
|
return {
|
|
140
140
|
environment: match[2],
|
|
141
141
|
tenant: match[3],
|
|
142
|
-
token,
|
|
142
|
+
accessToken: token,
|
|
143
143
|
};
|
|
144
144
|
}
|
|
145
145
|
}
|
package/dist/utils.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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","sourcesContent":["/* eslint-disable no-console */\r\n/**\r\n * Returns the localized name of a language given its BCP-47 code.\r\n *\r\n * @param languageCode - The BCP-47 language code (e.g. \"en\")\r\n * @returns The localized language name (e.g. \"English\") or the original code if unavailable.\r\n */\r\nexport function getLanguageName(languageCode: string): string {\r\n const userLocale = navigator.language || 'en';\r\n const displayNames = new Intl.DisplayNames([userLocale], {\r\n type: 'language',\r\n });\r\n const languageName = displayNames.of(languageCode);\r\n return languageName || languageCode;\r\n}\r\n\r\n/**\r\n * Requests access to the microphone.\r\n *\r\n * This function checks if the microphone permission is in \"prompt\" state, then requests\r\n * access and stops any active tracks immediately. It also logs if permission is already granted.\r\n *\r\n * @returns A promise that resolves when the permission request is complete.\r\n */\r\nexport async function requestMicAccess(): Promise<void> {\r\n try {\r\n // Fallback if Permissions API is not available\r\n if (!navigator.permissions) {\r\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\r\n stream.getTracks().forEach(track => track.stop());\r\n return;\r\n }\r\n\r\n const permissionStatus = await navigator.permissions.query({\r\n // eslint-disable-next-line no-undef\r\n name: 'microphone' as PermissionName,\r\n });\r\n\r\n if (permissionStatus.state === 'prompt') {\r\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\r\n stream.getTracks().forEach(track => track.stop());\r\n } else if (permissionStatus.state === 'denied') {\r\n console.warn('Microphone permission is denied.');\r\n }\r\n } catch (error) {\r\n console.error('Error checking/requesting microphone permission:', error);\r\n }\r\n}\r\n\r\n/**\r\n * Retrieves available audio input devices.\r\n *\r\n * This function uses the mediaDevices API to enumerate devices and filters out those\r\n * which are audio inputs. In some browsers, you may need to request user media before\r\n * device labels are populated.\r\n *\r\n * @returns A promise that resolves with an object containing:\r\n * - `devices`: an array of MediaDeviceInfo objects for audio inputs.\r\n * - `defaultDeviceId`: the deviceId of the first audio input, if available.\r\n */\r\nexport async function getAudioDevices(): Promise<{\r\n devices: MediaDeviceInfo[];\r\n defaultDevice?: MediaDeviceInfo;\r\n}> {\r\n if (!navigator.mediaDevices?.enumerateDevices) {\r\n console.error('Media devices API not supported.');\r\n return { devices: [] };\r\n }\r\n\r\n await requestMicAccess();\r\n\r\n try {\r\n // Optionally: await navigator.mediaDevices.getUserMedia({ audio: true });\r\n const devices = await navigator.mediaDevices.enumerateDevices();\r\n const audioDevices = devices.filter(device => device.kind === 'audioinput');\r\n const defaultDevice = audioDevices.length > 0 ? audioDevices[0] : undefined;\r\n return { devices: audioDevices, defaultDevice };\r\n } catch (error) {\r\n console.error('Error enumerating devices:', error);\r\n return { devices: [] };\r\n }\r\n}\r\n\r\n/**\r\n * Decodes a JWT token and extracts environment and tenant details from its issuer URL.\r\n *\r\n * This function assumes the JWT token follows the standard header.payload.signature format.\r\n * It decodes the payload from base64 URL format, parses it as JSON, and then uses a regex\r\n * to extract the `environment` and `tenant` from the issuer URL (iss field) if it matches the pattern:\r\n * https://keycloak.{environment}.corti.app/realms/{tenant}.\r\n *\r\n * @param token - A JSON Web Token (JWT) string.\r\n * @returns An object containing:\r\n * - `environment`: The extracted environment from the issuer URL.\r\n * - `tenant`: The extracted tenant from the issuer URL.\r\n * - `token`: The original token string.\r\n * If the issuer URL doesn't match the expected format, the function returns the full decoded token details.\r\n *\r\n * @throws Will throw an error if:\r\n * - The token format is invalid.\r\n * - The base64 decoding or URI decoding fails.\r\n * - The JSON payload is invalid.\r\n * - The token payload does not contain an issuer (iss) field.\r\n */\r\nexport function decodeToken(token: string) {\r\n // Validate the token structure (should contain at least header and payload parts)\r\n const parts = token.split('.');\r\n if (parts.length < 2) {\r\n throw new Error('Invalid token format');\r\n }\r\n\r\n // Retrieve the payload (second part) of the JWT token\r\n const base64Url = parts[1];\r\n\r\n // Replace URL-safe characters to match standard base64 encoding\r\n const base64 = base64Url.replace(/-/g, '+').replace(/_/g, '/');\r\n\r\n // Decode the base64 string into a JSON string\r\n let jsonPayload: string;\r\n try {\r\n jsonPayload = decodeURIComponent(\r\n atob(base64)\r\n .split('')\r\n .map(c => '%' + ('00' + c.charCodeAt(0).toString(16)).slice(-2))\r\n .join(''),\r\n );\r\n } catch (error) {\r\n throw new Error('Failed to decode token payload');\r\n }\r\n\r\n // Parse the JSON string to obtain token details\r\n let tokenDetails: { iss: string; [key: string]: unknown };\r\n try {\r\n tokenDetails = JSON.parse(jsonPayload);\r\n } catch (error) {\r\n throw new Error('Invalid JSON payload in token');\r\n }\r\n\r\n // Extract the issuer URL from the token details\r\n const issuerUrl: string = tokenDetails.iss;\r\n if (!issuerUrl) {\r\n throw new Error('Token payload does not contain an issuer (iss) field');\r\n }\r\n\r\n // Regex to extract environment and tenant from issuer URL:\r\n // Expected format: https://keycloak.{environment}.corti.app/realms/{tenant}\r\n // Note: Unnecessary escapes in character classes have been removed.\r\n const regex =\r\n /^https:\\/\\/(keycloak|auth)\\.([^.]+)\\.corti\\.app\\/realms\\/([^/]+)/;\r\n const match = issuerUrl.match(regex);\r\n\r\n // If the issuer URL matches the expected pattern, return the extracted values along with the token\r\n if (match) {\r\n return {\r\n environment: match[2],\r\n tenant: match[3],\r\n token,\r\n };\r\n }\r\n}\r\n\r\nexport async function getMediaStream(deviceId?: string): Promise<MediaStream> {\r\n if (!deviceId) {\r\n throw new Error('No device ID provided');\r\n }\r\n\r\n if (deviceId === 'display_audio') {\r\n const stream = await navigator.mediaDevices.getDisplayMedia({\r\n audio: true,\r\n video: true,\r\n });\r\n stream.getTracks().forEach(track => {\r\n if (track.kind === 'video') {\r\n stream.removeTrack(track);\r\n }\r\n });\r\n return stream;\r\n }\r\n\r\n // Get media stream and initialize audio service.\r\n const constraints: MediaStreamConstraints =\r\n deviceId !== 'default'\r\n ? { audio: { deviceId: { exact: deviceId } } }\r\n : { audio: true };\r\n\r\n return await navigator.mediaDevices.getUserMedia(constraints);\r\n}\r\n"]}
|
|
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 * This function assumes the JWT token follows the standard header.payload.signature format.\n * It decodes the payload from base64 URL format, parses it as JSON, and then uses a regex\n * to extract the `environment` and `tenant` from the issuer URL (iss field) if it matches the pattern:\n * https://keycloak.{environment}.corti.app/realms/{tenant}.\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, the function returns the full decoded token details.\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 return {\n environment: match[2],\n tenant: match[3],\n accessToken: token,\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"]}
|