@corti/dictation-web 0.3.0-rc → 0.4.0-rc

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.
Files changed (201) hide show
  1. package/README.md +9 -4
  2. package/dist/bundle.js +3098 -1630
  3. package/dist/components/audio-visualiser.d.ts +5 -3
  4. package/dist/components/audio-visualiser.js +38 -46
  5. package/dist/components/audio-visualiser.js.map +1 -1
  6. package/dist/components/corti-dictation.d.ts +122 -0
  7. package/dist/components/corti-dictation.js +234 -0
  8. package/dist/components/corti-dictation.js.map +1 -0
  9. package/dist/components/device-selector.d.ts +14 -0
  10. package/dist/components/device-selector.js +75 -0
  11. package/dist/components/device-selector.js.map +1 -0
  12. package/dist/components/language-selector.d.ts +15 -0
  13. package/dist/components/language-selector.js +74 -0
  14. package/dist/components/language-selector.js.map +1 -0
  15. package/dist/components/recording-button.d.ts +29 -0
  16. package/dist/components/recording-button.js +217 -0
  17. package/dist/components/recording-button.js.map +1 -0
  18. package/dist/components/settings-menu.d.ts +9 -15
  19. package/dist/components/settings-menu.js +48 -161
  20. package/dist/components/settings-menu.js.map +1 -1
  21. package/dist/constants.d.ts +8 -2
  22. package/dist/constants.js +38 -12
  23. package/dist/constants.js.map +1 -1
  24. package/dist/contexts/dictation-context.d.ts +99 -0
  25. package/dist/contexts/dictation-context.js +257 -0
  26. package/dist/contexts/dictation-context.js.map +1 -0
  27. package/dist/controllers/DictationController.d.ts +35 -0
  28. package/dist/controllers/DictationController.js +130 -0
  29. package/dist/controllers/DictationController.js.map +1 -0
  30. package/dist/controllers/MediaController.d.ts +31 -0
  31. package/dist/controllers/MediaController.js +99 -0
  32. package/dist/controllers/MediaController.js.map +1 -0
  33. package/dist/controllers/devices-controller.d.ts +26 -0
  34. package/dist/controllers/devices-controller.js +99 -0
  35. package/dist/controllers/devices-controller.js.map +1 -0
  36. package/dist/controllers/dictation-controller.d.ts +28 -0
  37. package/dist/controllers/dictation-controller.js +141 -0
  38. package/dist/controllers/dictation-controller.js.map +1 -0
  39. package/dist/controllers/languages-controller.d.ts +26 -0
  40. package/dist/controllers/languages-controller.js +83 -0
  41. package/dist/controllers/languages-controller.js.map +1 -0
  42. package/dist/controllers/media-controller.d.ts +24 -0
  43. package/dist/controllers/media-controller.js +115 -0
  44. package/dist/controllers/media-controller.js.map +1 -0
  45. package/dist/index.d.ts +9 -1
  46. package/dist/index.js +29 -3
  47. package/dist/index.js.map +1 -1
  48. package/dist/package.json +14 -0
  49. package/dist/src/components/audio-visualiser.d.ts +14 -0
  50. package/dist/src/components/audio-visualiser.js +57 -0
  51. package/dist/src/components/audio-visualiser.js.map +1 -0
  52. package/dist/src/components/corti-dictation.d.ts +123 -0
  53. package/dist/src/components/corti-dictation.js +224 -0
  54. package/dist/src/components/corti-dictation.js.map +1 -0
  55. package/dist/src/components/device-selector.d.ts +24 -0
  56. package/dist/src/components/device-selector.js +106 -0
  57. package/dist/src/components/device-selector.js.map +1 -0
  58. package/dist/src/components/language-selector.d.ts +24 -0
  59. package/dist/src/components/language-selector.js +100 -0
  60. package/dist/src/components/language-selector.js.map +1 -0
  61. package/dist/src/components/recording-button.d.ts +37 -0
  62. package/dist/src/components/recording-button.js +203 -0
  63. package/dist/src/components/recording-button.js.map +1 -0
  64. package/dist/src/components/settings-menu.d.ts +16 -0
  65. package/dist/src/components/settings-menu.js +80 -0
  66. package/dist/src/components/settings-menu.js.map +1 -0
  67. package/dist/src/constants.d.ts +4 -0
  68. package/dist/src/constants.js +37 -0
  69. package/dist/src/constants.js.map +1 -0
  70. package/dist/src/contexts/dictation-context.d.ts +97 -0
  71. package/dist/src/contexts/dictation-context.js +208 -0
  72. package/dist/src/contexts/dictation-context.js.map +1 -0
  73. package/dist/src/controllers/DictationController.d.ts +35 -0
  74. package/dist/src/controllers/DictationController.js +130 -0
  75. package/dist/src/controllers/DictationController.js.map +1 -0
  76. package/dist/src/controllers/MediaController.d.ts +31 -0
  77. package/dist/src/controllers/MediaController.js +99 -0
  78. package/dist/src/controllers/MediaController.js.map +1 -0
  79. package/dist/src/icons/icons.d.ts +17 -0
  80. package/dist/src/icons/icons.js +158 -0
  81. package/dist/src/icons/icons.js.map +1 -0
  82. package/dist/src/styles/ComponentStyles.d.ts +2 -0
  83. package/dist/src/styles/ComponentStyles.js +18 -0
  84. package/dist/src/styles/ComponentStyles.js.map +1 -0
  85. package/dist/src/styles/audio-visualiser.d.ts +2 -0
  86. package/dist/src/styles/audio-visualiser.js +33 -0
  87. package/dist/src/styles/audio-visualiser.js.map +1 -0
  88. package/dist/src/styles/buttons.d.ts +2 -0
  89. package/dist/src/styles/buttons.js +52 -0
  90. package/dist/src/styles/buttons.js.map +1 -0
  91. package/dist/src/styles/callout.d.ts +2 -0
  92. package/dist/src/styles/callout.js +23 -0
  93. package/dist/src/styles/callout.js.map +1 -0
  94. package/dist/src/styles/default-theme.d.ts +2 -0
  95. package/dist/src/styles/default-theme.js +50 -0
  96. package/dist/src/styles/default-theme.js.map +1 -0
  97. package/dist/src/styles/recording-button.d.ts +2 -0
  98. package/dist/src/styles/recording-button.js +8 -0
  99. package/dist/src/styles/recording-button.js.map +1 -0
  100. package/dist/src/styles/select.d.ts +2 -0
  101. package/dist/src/styles/select.js +36 -0
  102. package/dist/src/styles/select.js.map +1 -0
  103. package/dist/src/styles/settings-menu.d.ts +2 -0
  104. package/dist/src/styles/settings-menu.js +34 -0
  105. package/dist/src/styles/settings-menu.js.map +1 -0
  106. package/dist/src/types.d.ts +7 -0
  107. package/dist/src/types.js +2 -0
  108. package/dist/src/types.js.map +1 -0
  109. package/dist/src/utils/auth.d.ts +9 -0
  110. package/dist/src/utils/auth.js +21 -0
  111. package/dist/src/utils/auth.js.map +1 -0
  112. package/dist/src/utils/converters.d.ts +4 -0
  113. package/dist/src/utils/converters.js +8 -0
  114. package/dist/src/utils/converters.js.map +1 -0
  115. package/dist/src/utils/devices.d.ts +26 -0
  116. package/dist/src/utils/devices.js +53 -0
  117. package/dist/src/utils/devices.js.map +1 -0
  118. package/dist/src/utils/events.d.ts +44 -0
  119. package/dist/src/utils/events.js +88 -0
  120. package/dist/src/utils/events.js.map +1 -0
  121. package/dist/src/utils/languages.d.ts +7 -0
  122. package/dist/src/utils/languages.js +29 -0
  123. package/dist/src/utils/languages.js.map +1 -0
  124. package/dist/src/utils/media.d.ts +6 -0
  125. package/dist/src/utils/media.js +39 -0
  126. package/dist/src/utils/media.js.map +1 -0
  127. package/dist/src/utils/token.d.ts +13 -0
  128. package/dist/src/utils/token.js +60 -0
  129. package/dist/src/utils/token.js.map +1 -0
  130. package/dist/src/utils/validation.d.ts +1 -0
  131. package/dist/src/utils/validation.js +7 -0
  132. package/dist/src/utils/validation.js.map +1 -0
  133. package/dist/stories/audio-visualiser.stories.d.ts +39 -0
  134. package/dist/stories/audio-visualiser.stories.js +71 -0
  135. package/dist/stories/audio-visualiser.stories.js.map +1 -0
  136. package/dist/stories/corti-dictation.stories.d.ts +27 -0
  137. package/dist/stories/corti-dictation.stories.js +129 -0
  138. package/dist/stories/corti-dictation.stories.js.map +1 -0
  139. package/dist/stories/device-selector.stories.d.ts +18 -0
  140. package/dist/stories/device-selector.stories.js +84 -0
  141. package/dist/stories/device-selector.stories.js.map +1 -0
  142. package/dist/stories/language-selector.stories.d.ts +18 -0
  143. package/dist/stories/language-selector.stories.js +53 -0
  144. package/dist/stories/language-selector.stories.js.map +1 -0
  145. package/dist/stories/recording-button.stories.d.ts +27 -0
  146. package/dist/stories/recording-button.stories.js +90 -0
  147. package/dist/stories/recording-button.stories.js.map +1 -0
  148. package/dist/stories/settings-menu.stories.d.ts +23 -0
  149. package/dist/stories/settings-menu.stories.js +156 -0
  150. package/dist/stories/settings-menu.stories.js.map +1 -0
  151. package/dist/styles/ComponentStyles.js +5 -39
  152. package/dist/styles/ComponentStyles.js.map +1 -1
  153. package/dist/styles/audio-visualiser.d.ts +2 -0
  154. package/dist/styles/audio-visualiser.js +33 -0
  155. package/dist/styles/audio-visualiser.js.map +1 -0
  156. package/dist/styles/buttons.js +19 -26
  157. package/dist/styles/buttons.js.map +1 -1
  158. package/dist/styles/callout.js +7 -17
  159. package/dist/styles/callout.js.map +1 -1
  160. package/dist/styles/component-styles.d.ts +2 -0
  161. package/dist/styles/component-styles.js +22 -0
  162. package/dist/styles/component-styles.js.map +1 -0
  163. package/dist/styles/default-theme.d.ts +2 -0
  164. package/dist/styles/default-theme.js +14 -0
  165. package/dist/styles/default-theme.js.map +1 -0
  166. package/dist/styles/recording-button.d.ts +2 -0
  167. package/dist/styles/recording-button.js +8 -0
  168. package/dist/styles/recording-button.js.map +1 -0
  169. package/dist/styles/select.js +9 -9
  170. package/dist/styles/select.js.map +1 -1
  171. package/dist/styles/settings-menu.d.ts +2 -0
  172. package/dist/styles/settings-menu.js +34 -0
  173. package/dist/styles/settings-menu.js.map +1 -0
  174. package/dist/tsconfig.stories.tsbuildinfo +1 -0
  175. package/dist/types.d.ts +6 -8
  176. package/dist/types.js.map +1 -1
  177. package/dist/utils/auth.d.ts +9 -0
  178. package/dist/utils/auth.js +21 -0
  179. package/dist/utils/auth.js.map +1 -0
  180. package/dist/utils/converters.d.ts +4 -0
  181. package/dist/utils/converters.js +8 -0
  182. package/dist/utils/converters.js.map +1 -0
  183. package/dist/utils/devices.d.ts +26 -0
  184. package/dist/utils/devices.js +53 -0
  185. package/dist/utils/devices.js.map +1 -0
  186. package/dist/utils/events.d.ts +44 -0
  187. package/dist/utils/events.js +88 -0
  188. package/dist/utils/events.js.map +1 -0
  189. package/dist/utils/languages.d.ts +8 -0
  190. package/dist/utils/languages.js +29 -0
  191. package/dist/utils/languages.js.map +1 -0
  192. package/dist/utils/media.d.ts +6 -0
  193. package/dist/utils/media.js +39 -0
  194. package/dist/utils/media.js.map +1 -0
  195. package/dist/utils/token.d.ts +13 -0
  196. package/dist/utils/token.js +60 -0
  197. package/dist/utils/token.js.map +1 -0
  198. package/dist/utils/validation.d.ts +1 -0
  199. package/dist/utils/validation.js +7 -0
  200. package/dist/utils/validation.js.map +1 -0
  201. package/package.json +29 -55
@@ -0,0 +1,53 @@
1
+ /**
2
+ * Requests access to the microphone.
3
+ *
4
+ * This function checks if the microphone permission is in "prompt" state, then requests
5
+ * access and stops any active tracks immediately.
6
+ *
7
+ * @returns A promise that resolves when the permission request is complete.
8
+ * @throws Error if microphone access is denied or unavailable.
9
+ */
10
+ export async function requestMicAccess() {
11
+ if (!navigator.permissions) {
12
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
13
+ stream.getTracks().forEach((track) => {
14
+ track.stop();
15
+ });
16
+ return;
17
+ }
18
+ const permissionStatus = await navigator.permissions.query({
19
+ name: "microphone",
20
+ });
21
+ if (permissionStatus.state === "denied") {
22
+ throw new Error("Microphone permission is denied");
23
+ }
24
+ if (permissionStatus.state === "prompt") {
25
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
26
+ stream.getTracks().forEach((track) => {
27
+ track.stop();
28
+ });
29
+ }
30
+ }
31
+ /**
32
+ * Retrieves available audio input devices.
33
+ *
34
+ * This function uses the mediaDevices API to enumerate devices and filters out those
35
+ * which are audio inputs. In some browsers, you may need to request user media before
36
+ * device labels are populated.
37
+ *
38
+ * @returns A promise that resolves with an object containing:
39
+ * - `devices`: an array of MediaDeviceInfo objects for audio inputs.
40
+ * - `defaultDevice`: the first audio input device, if available.
41
+ * @throws Error if mediaDevices API is unavailable or device enumeration fails.
42
+ */
43
+ export async function getAudioDevices() {
44
+ if (!navigator.mediaDevices?.enumerateDevices) {
45
+ throw new Error("MediaDevices API is not available");
46
+ }
47
+ await requestMicAccess();
48
+ const devices = await navigator.mediaDevices.enumerateDevices();
49
+ const audioDevices = devices.filter((device) => device.kind === "audioinput");
50
+ const defaultDevice = audioDevices.length > 0 ? audioDevices[0] : undefined;
51
+ return { defaultDevice, devices: audioDevices };
52
+ }
53
+ //# sourceMappingURL=devices.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"devices.js","sourceRoot":"","sources":["../../../src/utils/devices.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,gBAAgB;IACpC,IAAI,CAAC,SAAS,CAAC,WAAW,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAE1E,MAAM,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YACnC,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,CAAC,CAAC,CAAC;QAEH,OAAO;IACT,CAAC;IAED,MAAM,gBAAgB,GAAG,MAAM,SAAS,CAAC,WAAW,CAAC,KAAK,CAAC;QACzD,IAAI,EAAE,YAA8B;KACrC,CAAC,CAAC;IAEH,IAAI,gBAAgB,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAC;IACrD,CAAC;IAED,IAAI,gBAAgB,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QAE1E,MAAM,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YACnC,KAAK,CAAC,IAAI,EAAE,CAAC;QACf,CAAC,CAAC,CAAC;IACL,CAAC;AACH,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe;IAInC,IAAI,CAAC,SAAS,CAAC,YAAY,EAAE,gBAAgB,EAAE,CAAC;QAC9C,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC;IACvD,CAAC;IAED,MAAM,gBAAgB,EAAE,CAAC;IAEzB,MAAM,OAAO,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,gBAAgB,EAAE,CAAC;IAChE,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,YAAY,CAAC,CAAC;IAC9E,MAAM,aAAa,GAAG,YAAY,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAE5E,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC;AAClD,CAAC","sourcesContent":["/**\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.\n *\n * @returns A promise that resolves when the permission request is complete.\n * @throws Error if microphone access is denied or unavailable.\n */\nexport async function requestMicAccess(): Promise<void> {\n if (!navigator.permissions) {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n\n stream.getTracks().forEach((track) => {\n track.stop();\n });\n\n return;\n }\n\n const permissionStatus = await navigator.permissions.query({\n name: \"microphone\" as PermissionName,\n });\n\n if (permissionStatus.state === \"denied\") {\n throw new Error(\"Microphone permission is denied\");\n }\n\n if (permissionStatus.state === \"prompt\") {\n const stream = await navigator.mediaDevices.getUserMedia({ audio: true });\n\n stream.getTracks().forEach((track) => {\n track.stop();\n });\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 * - `defaultDevice`: the first audio input device, if available.\n * @throws Error if mediaDevices API is unavailable or device enumeration fails.\n */\nexport async function getAudioDevices(): Promise<{\n devices: MediaDeviceInfo[];\n defaultDevice?: MediaDeviceInfo;\n}> {\n if (!navigator.mediaDevices?.enumerateDevices) {\n throw new Error(\"MediaDevices API is not available\");\n }\n\n await requestMicAccess();\n\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\n return { defaultDevice, devices: audioDevices };\n}\n"]}
@@ -0,0 +1,44 @@
1
+ import type { Corti } from "@corti/sdk";
2
+ import type { RecordingState } from "../types.js";
3
+ export type LanguagesChangedEventDetail = {
4
+ languages: string[];
5
+ selectedLanguage: string | undefined;
6
+ };
7
+ export type LanguageChangedEventDetail = {
8
+ language: string;
9
+ };
10
+ export type RecordingDevicesChangedEventDetail = {
11
+ devices: MediaDeviceInfo[];
12
+ selectedDevice: MediaDeviceInfo | undefined;
13
+ };
14
+ export type RecordingStateChangedEventDetail = {
15
+ state: RecordingState;
16
+ };
17
+ export type AudioLevelChangedEventDetail = {
18
+ audioLevel: number;
19
+ };
20
+ export type TranscriptEventDetail = Corti.TranscribeTranscriptMessage;
21
+ export type CommandEventDetail = Corti.TranscribeCommandMessage;
22
+ export type UsageEventDetail = Corti.TranscribeUsageMessage;
23
+ export type ErrorEventDetail = {
24
+ message: string;
25
+ };
26
+ export declare function languagesChangedEvent(languages: string[], selectedLanguage: string | undefined): CustomEvent<LanguagesChangedEventDetail>;
27
+ /**
28
+ * @deprecated Use languagesChangedEvent instead. This event is kept for backward compatibility.
29
+ */
30
+ export declare function languageChangedEvent(language: string): CustomEvent<LanguageChangedEventDetail>;
31
+ export declare function recordingDevicesChangedEvent(devices: MediaDeviceInfo[], selectedDevice: MediaDeviceInfo | undefined): CustomEvent<RecordingDevicesChangedEventDetail>;
32
+ export declare function recordingStateChangedEvent(state: RecordingState): CustomEvent<RecordingStateChangedEventDetail>;
33
+ export declare function transcriptEvent(detail: TranscriptEventDetail): CustomEvent<TranscriptEventDetail>;
34
+ export declare function commandEvent(detail: CommandEventDetail): CustomEvent<CommandEventDetail>;
35
+ export declare function usageEvent(detail: UsageEventDetail): CustomEvent<UsageEventDetail>;
36
+ export declare function errorEvent(error: unknown): CustomEvent<ErrorEventDetail>;
37
+ export declare function streamClosedEvent(detail: unknown): CustomEvent;
38
+ export declare function readyEvent(): CustomEvent;
39
+ export declare function audioLevelChangedEvent(audioLevel: number): CustomEvent<AudioLevelChangedEventDetail>;
40
+ export type NetworkActivityEventDetail = {
41
+ direction: "sent" | "received";
42
+ data: unknown;
43
+ };
44
+ export declare function networkActivityEvent(direction: "sent" | "received", data: unknown): CustomEvent<NetworkActivityEventDetail>;
@@ -0,0 +1,88 @@
1
+ export function languagesChangedEvent(languages, selectedLanguage) {
2
+ return new CustomEvent("languages-changed", {
3
+ bubbles: true,
4
+ composed: true,
5
+ detail: { languages, selectedLanguage },
6
+ });
7
+ }
8
+ /**
9
+ * @deprecated Use languagesChangedEvent instead. This event is kept for backward compatibility.
10
+ */
11
+ export function languageChangedEvent(language) {
12
+ return new CustomEvent("language-changed", {
13
+ bubbles: true,
14
+ composed: true,
15
+ detail: { language },
16
+ });
17
+ }
18
+ export function recordingDevicesChangedEvent(devices, selectedDevice) {
19
+ return new CustomEvent("recording-devices-changed", {
20
+ bubbles: true,
21
+ composed: true,
22
+ detail: { devices, selectedDevice },
23
+ });
24
+ }
25
+ export function recordingStateChangedEvent(state) {
26
+ return new CustomEvent("recording-state-changed", {
27
+ bubbles: true,
28
+ composed: true,
29
+ detail: { state },
30
+ });
31
+ }
32
+ export function transcriptEvent(detail) {
33
+ return new CustomEvent("transcript", {
34
+ bubbles: true,
35
+ composed: true,
36
+ detail,
37
+ });
38
+ }
39
+ export function commandEvent(detail) {
40
+ return new CustomEvent("command", {
41
+ bubbles: true,
42
+ composed: true,
43
+ detail,
44
+ });
45
+ }
46
+ export function usageEvent(detail) {
47
+ return new CustomEvent("usage", {
48
+ bubbles: true,
49
+ composed: true,
50
+ detail,
51
+ });
52
+ }
53
+ export function errorEvent(error) {
54
+ const message = error instanceof Error && error.message ? error.message : String(error);
55
+ return new CustomEvent("error", {
56
+ bubbles: false,
57
+ composed: true,
58
+ detail: { message },
59
+ });
60
+ }
61
+ export function streamClosedEvent(detail) {
62
+ return new CustomEvent("stream-closed", {
63
+ bubbles: true,
64
+ composed: true,
65
+ detail,
66
+ });
67
+ }
68
+ export function readyEvent() {
69
+ return new CustomEvent("ready", {
70
+ bubbles: true,
71
+ composed: true,
72
+ });
73
+ }
74
+ export function audioLevelChangedEvent(audioLevel) {
75
+ return new CustomEvent("audio-level-changed", {
76
+ bubbles: true,
77
+ composed: true,
78
+ detail: { audioLevel },
79
+ });
80
+ }
81
+ export function networkActivityEvent(direction, data) {
82
+ return new CustomEvent("network-activity", {
83
+ bubbles: true,
84
+ composed: true,
85
+ detail: { data, direction },
86
+ });
87
+ }
88
+ //# sourceMappingURL=events.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"events.js","sourceRoot":"","sources":["../../../src/utils/events.ts"],"names":[],"mappings":"AAiCA,MAAM,UAAU,qBAAqB,CACnC,SAAmB,EACnB,gBAAoC;IAEpC,OAAO,IAAI,WAAW,CAAC,mBAAmB,EAAE;QAC1C,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,EAAE,SAAS,EAAE,gBAAgB,EAAE;KACxC,CAAC,CAAC;AACL,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,oBAAoB,CAClC,QAAgB;IAEhB,OAAO,IAAI,WAAW,CAAC,kBAAkB,EAAE;QACzC,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,EAAE,QAAQ,EAAE;KACrB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,OAA0B,EAC1B,cAA2C;IAE3C,OAAO,IAAI,WAAW,CAAC,2BAA2B,EAAE;QAClD,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,EAAE,OAAO,EAAE,cAAc,EAAE;KACpC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,0BAA0B,CACxC,KAAqB;IAErB,OAAO,IAAI,WAAW,CAAC,yBAAyB,EAAE;QAChD,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,EAAE,KAAK,EAAE;KAClB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,eAAe,CAC7B,MAA6B;IAE7B,OAAO,IAAI,WAAW,CAAC,YAAY,EAAE;QACnC,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;QACd,MAAM;KACP,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,MAA0B;IAE1B,OAAO,IAAI,WAAW,CAAC,SAAS,EAAE;QAChC,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;QACd,MAAM;KACP,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,UAAU,CACxB,MAAwB;IAExB,OAAO,IAAI,WAAW,CAAC,OAAO,EAAE;QAC9B,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;QACd,MAAM;KACP,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAc;IACvC,MAAM,OAAO,GACX,KAAK,YAAY,KAAK,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAE1E,OAAO,IAAI,WAAW,CAAC,OAAO,EAAE;QAC9B,OAAO,EAAE,KAAK;QACd,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,EAAE,OAAO,EAAE;KACpB,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,iBAAiB,CAAC,MAAe;IAC/C,OAAO,IAAI,WAAW,CAAC,eAAe,EAAE;QACtC,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;QACd,MAAM;KACP,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,IAAI,WAAW,CAAC,OAAO,EAAE;QAC9B,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;KACf,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,sBAAsB,CACpC,UAAkB;IAElB,OAAO,IAAI,WAAW,CAAC,qBAAqB,EAAE;QAC5C,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,EAAE,UAAU,EAAE;KACvB,CAAC,CAAC;AACL,CAAC;AAOD,MAAM,UAAU,oBAAoB,CAClC,SAA8B,EAC9B,IAAa;IAEb,OAAO,IAAI,WAAW,CAAC,kBAAkB,EAAE;QACzC,OAAO,EAAE,IAAI;QACb,QAAQ,EAAE,IAAI;QACd,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE;KAC5B,CAAC,CAAC;AACL,CAAC","sourcesContent":["import type { Corti } from \"@corti/sdk\";\nimport type { RecordingState } from \"../types.js\";\n\nexport type LanguagesChangedEventDetail = {\n languages: string[];\n selectedLanguage: string | undefined;\n};\n\nexport type LanguageChangedEventDetail = {\n language: string;\n};\n\nexport type RecordingDevicesChangedEventDetail = {\n devices: MediaDeviceInfo[];\n selectedDevice: MediaDeviceInfo | undefined;\n};\n\nexport type RecordingStateChangedEventDetail = {\n state: RecordingState;\n};\n\nexport type AudioLevelChangedEventDetail = {\n audioLevel: number;\n};\n\nexport type TranscriptEventDetail = Corti.TranscribeTranscriptMessage;\nexport type CommandEventDetail = Corti.TranscribeCommandMessage;\nexport type UsageEventDetail = Corti.TranscribeUsageMessage;\n\nexport type ErrorEventDetail = {\n message: string;\n};\n\nexport function languagesChangedEvent(\n languages: string[],\n selectedLanguage: string | undefined,\n): CustomEvent<LanguagesChangedEventDetail> {\n return new CustomEvent(\"languages-changed\", {\n bubbles: true,\n composed: true,\n detail: { languages, selectedLanguage },\n });\n}\n\n/**\n * @deprecated Use languagesChangedEvent instead. This event is kept for backward compatibility.\n */\nexport function languageChangedEvent(\n language: string,\n): CustomEvent<LanguageChangedEventDetail> {\n return new CustomEvent(\"language-changed\", {\n bubbles: true,\n composed: true,\n detail: { language },\n });\n}\n\nexport function recordingDevicesChangedEvent(\n devices: MediaDeviceInfo[],\n selectedDevice: MediaDeviceInfo | undefined,\n): CustomEvent<RecordingDevicesChangedEventDetail> {\n return new CustomEvent(\"recording-devices-changed\", {\n bubbles: true,\n composed: true,\n detail: { devices, selectedDevice },\n });\n}\n\nexport function recordingStateChangedEvent(\n state: RecordingState,\n): CustomEvent<RecordingStateChangedEventDetail> {\n return new CustomEvent(\"recording-state-changed\", {\n bubbles: true,\n composed: true,\n detail: { state },\n });\n}\n\nexport function transcriptEvent(\n detail: TranscriptEventDetail,\n): CustomEvent<TranscriptEventDetail> {\n return new CustomEvent(\"transcript\", {\n bubbles: true,\n composed: true,\n detail,\n });\n}\n\nexport function commandEvent(\n detail: CommandEventDetail,\n): CustomEvent<CommandEventDetail> {\n return new CustomEvent(\"command\", {\n bubbles: true,\n composed: true,\n detail,\n });\n}\n\nexport function usageEvent(\n detail: UsageEventDetail,\n): CustomEvent<UsageEventDetail> {\n return new CustomEvent(\"usage\", {\n bubbles: true,\n composed: true,\n detail,\n });\n}\n\nexport function errorEvent(error: unknown): CustomEvent<ErrorEventDetail> {\n const message =\n error instanceof Error && error.message ? error.message : String(error);\n\n return new CustomEvent(\"error\", {\n bubbles: false,\n composed: true,\n detail: { message },\n });\n}\n\nexport function streamClosedEvent(detail: unknown): CustomEvent {\n return new CustomEvent(\"stream-closed\", {\n bubbles: true,\n composed: true,\n detail,\n });\n}\n\nexport function readyEvent(): CustomEvent {\n return new CustomEvent(\"ready\", {\n bubbles: true,\n composed: true,\n });\n}\n\nexport function audioLevelChangedEvent(\n audioLevel: number,\n): CustomEvent<AudioLevelChangedEventDetail> {\n return new CustomEvent(\"audio-level-changed\", {\n bubbles: true,\n composed: true,\n detail: { audioLevel },\n });\n}\n\nexport type NetworkActivityEventDetail = {\n direction: \"sent\" | \"received\";\n data: unknown;\n};\n\nexport function networkActivityEvent(\n direction: \"sent\" | \"received\",\n data: unknown,\n): CustomEvent<NetworkActivityEventDetail> {\n return new CustomEvent(\"network-activity\", {\n bubbles: true,\n composed: true,\n detail: { data, direction },\n });\n}\n"]}
@@ -0,0 +1,7 @@
1
+ export declare const DEFAULT_LANGUAGES_BY_REGION: Record<string, string[]>;
2
+ export declare function getLanguageName(languageCode: string): string;
3
+ export declare function checkIfDefaultLanguagesList(languages?: string[]): boolean;
4
+ export declare function getLanguagesByRegion(region?: string): {
5
+ languages: string[];
6
+ defaultLanguage: string | undefined;
7
+ };
@@ -0,0 +1,29 @@
1
+ import { LANGUAGES_SUPPORTED_EU, LANGUAGES_SUPPORTED_US, } from "../constants.js";
2
+ export const DEFAULT_LANGUAGES_BY_REGION = {
3
+ default: LANGUAGES_SUPPORTED_EU,
4
+ eu: LANGUAGES_SUPPORTED_EU,
5
+ us: LANGUAGES_SUPPORTED_US,
6
+ };
7
+ export function getLanguageName(languageCode) {
8
+ try {
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
+ catch {
17
+ return languageCode;
18
+ }
19
+ }
20
+ export function checkIfDefaultLanguagesList(languages = []) {
21
+ return Object.values(DEFAULT_LANGUAGES_BY_REGION).some((languageList) => languageList === languages);
22
+ }
23
+ export function getLanguagesByRegion(region) {
24
+ const languages = DEFAULT_LANGUAGES_BY_REGION[region || "default"] ||
25
+ DEFAULT_LANGUAGES_BY_REGION["default"];
26
+ const defaultLanguage = languages?.[0];
27
+ return { defaultLanguage, languages };
28
+ }
29
+ //# sourceMappingURL=languages.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"languages.js","sourceRoot":"","sources":["../../../src/utils/languages.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,CAAC,MAAM,2BAA2B,GAA6B;IACnE,OAAO,EAAE,sBAAsB;IAC/B,EAAE,EAAE,sBAAsB;IAC1B,EAAE,EAAE,sBAAsB;CAC3B,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,YAAoB;IAClD,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,SAAS,CAAC,QAAQ,IAAI,IAAI,CAAC;QAC9C,MAAM,YAAY,GAAG,IAAI,IAAI,CAAC,YAAY,CAAC,CAAC,UAAU,CAAC,EAAE;YACvD,IAAI,EAAE,UAAU;SACjB,CAAC,CAAC;QACH,MAAM,YAAY,GAAG,YAAY,CAAC,EAAE,CAAC,YAAY,CAAC,CAAC;QAEnD,OAAO,YAAY,IAAI,YAAY,CAAC;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,YAAY,CAAC;IACtB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAC,YAAsB,EAAE;IAClE,OAAO,MAAM,CAAC,MAAM,CAAC,2BAA2B,CAAC,CAAC,IAAI,CACpD,CAAC,YAAY,EAAE,EAAE,CAAC,YAAY,KAAK,SAAS,CAC7C,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,oBAAoB,CAAC,MAAe;IAIlD,MAAM,SAAS,GACb,2BAA2B,CAAC,MAAM,IAAI,SAAS,CAAC;QAChD,2BAA2B,CAAC,SAAS,CAAC,CAAC;IACzC,MAAM,eAAe,GAAG,SAAS,EAAE,CAAC,CAAC,CAAC,CAAC;IAEvC,OAAO,EAAE,eAAe,EAAE,SAAS,EAAE,CAAC;AACxC,CAAC","sourcesContent":["import {\n LANGUAGES_SUPPORTED_EU,\n LANGUAGES_SUPPORTED_US,\n} from \"../constants.js\";\n\nexport const DEFAULT_LANGUAGES_BY_REGION: Record<string, string[]> = {\n default: LANGUAGES_SUPPORTED_EU,\n eu: LANGUAGES_SUPPORTED_EU,\n us: LANGUAGES_SUPPORTED_US,\n};\n\nexport function getLanguageName(languageCode: string): string {\n try {\n const userLocale = navigator.language || \"en\";\n const displayNames = new Intl.DisplayNames([userLocale], {\n type: \"language\",\n });\n const languageName = displayNames.of(languageCode);\n\n return languageName || languageCode;\n } catch {\n return languageCode;\n }\n}\n\nexport function checkIfDefaultLanguagesList(languages: string[] = []): boolean {\n return Object.values(DEFAULT_LANGUAGES_BY_REGION).some(\n (languageList) => languageList === languages,\n );\n}\n\nexport function getLanguagesByRegion(region?: string): {\n languages: string[];\n defaultLanguage: string | undefined;\n} {\n const languages =\n DEFAULT_LANGUAGES_BY_REGION[region || \"default\"] ||\n DEFAULT_LANGUAGES_BY_REGION[\"default\"];\n const defaultLanguage = languages?.[0];\n\n return { defaultLanguage, languages };\n}\n"]}
@@ -0,0 +1,6 @@
1
+ export declare function getMediaStream(deviceId?: string, debug_displayAudio?: boolean): Promise<MediaStream>;
2
+ export declare function createAudioAnalyzer(mediaStream: MediaStream): {
3
+ audioContext: AudioContext;
4
+ analyser: AnalyserNode;
5
+ };
6
+ export declare function calculateAudioLevel(analyser: AnalyserNode): number;
@@ -0,0 +1,39 @@
1
+ export async function getMediaStream(deviceId, debug_displayAudio) {
2
+ if (debug_displayAudio) {
3
+ const stream = await navigator.mediaDevices.getDisplayMedia({
4
+ audio: true,
5
+ video: true,
6
+ });
7
+ stream.getTracks().forEach((track) => {
8
+ if (track.kind === "video") {
9
+ stream.removeTrack(track);
10
+ }
11
+ });
12
+ return stream;
13
+ }
14
+ if (!deviceId) {
15
+ throw new Error("No device ID provided");
16
+ }
17
+ const constraints = deviceId !== "default"
18
+ ? { audio: { deviceId: { exact: deviceId } } }
19
+ : { audio: true };
20
+ return await navigator.mediaDevices.getUserMedia(constraints);
21
+ }
22
+ export function createAudioAnalyzer(mediaStream) {
23
+ const audioContext = new AudioContext();
24
+ const source = audioContext.createMediaStreamSource(mediaStream);
25
+ const analyser = audioContext.createAnalyser();
26
+ analyser.fftSize = 8192;
27
+ source.connect(analyser);
28
+ return { analyser, audioContext };
29
+ }
30
+ export function calculateAudioLevel(analyser) {
31
+ const dataArray = new Uint8Array(analyser.fftSize);
32
+ analyser.getByteTimeDomainData(dataArray);
33
+ const sumSquares = Array.from(dataArray).reduce((sum, value) => {
34
+ const normalized = (value - 128) / 128;
35
+ return sum + normalized * normalized;
36
+ }, 0);
37
+ return Math.sqrt(sumSquares / dataArray.length);
38
+ }
39
+ //# sourceMappingURL=media.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"media.js","sourceRoot":"","sources":["../../../src/utils/media.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,KAAK,UAAU,cAAc,CAClC,QAAiB,EACjB,kBAA4B;IAE5B,IAAI,kBAAkB,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,YAAY,CAAC,eAAe,CAAC;YAC1D,KAAK,EAAE,IAAI;YACX,KAAK,EAAE,IAAI;SACZ,CAAC,CAAC;QAEH,MAAM,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,EAAE;YACnC,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;gBAC3B,MAAM,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,OAAO,MAAM,CAAC;IAChB,CAAC;IAED,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,MAAM,IAAI,KAAK,CAAC,uBAAuB,CAAC,CAAC;IAC3C,CAAC;IAED,MAAM,WAAW,GACf,QAAQ,KAAK,SAAS;QACpB,CAAC,CAAC,EAAE,KAAK,EAAE,EAAE,QAAQ,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,EAAE;QAC9C,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAEtB,OAAO,MAAM,SAAS,CAAC,YAAY,CAAC,YAAY,CAAC,WAAW,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,WAAwB;IAI1D,MAAM,YAAY,GAAG,IAAI,YAAY,EAAE,CAAC;IACxC,MAAM,MAAM,GAAG,YAAY,CAAC,uBAAuB,CAAC,WAAW,CAAC,CAAC;IACjE,MAAM,QAAQ,GAAG,YAAY,CAAC,cAAc,EAAE,CAAC;IAE/C,QAAQ,CAAC,OAAO,GAAG,IAAI,CAAC;IAExB,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IAEzB,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,QAAsB;IACxD,MAAM,SAAS,GAAG,IAAI,UAAU,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC;IACnD,QAAQ,CAAC,qBAAqB,CAAC,SAAS,CAAC,CAAC;IAE1C,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE;QAC7D,MAAM,UAAU,GAAG,CAAC,KAAK,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;QACvC,OAAO,GAAG,GAAG,UAAU,GAAG,UAAU,CAAC;IACvC,CAAC,EAAE,CAAC,CAAC,CAAC;IAEN,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;AAClD,CAAC","sourcesContent":["export async function getMediaStream(\n deviceId?: string,\n debug_displayAudio?: boolean,\n): Promise<MediaStream> {\n if (debug_displayAudio) {\n const stream = await navigator.mediaDevices.getDisplayMedia({\n audio: true,\n video: true,\n });\n\n stream.getTracks().forEach((track) => {\n if (track.kind === \"video\") {\n stream.removeTrack(track);\n }\n });\n\n return stream;\n }\n\n if (!deviceId) {\n throw new Error(\"No device ID provided\");\n }\n\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 createAudioAnalyzer(mediaStream: MediaStream): {\n audioContext: AudioContext;\n analyser: AnalyserNode;\n} {\n const audioContext = new AudioContext();\n const source = audioContext.createMediaStreamSource(mediaStream);\n const analyser = audioContext.createAnalyser();\n\n analyser.fftSize = 8192;\n\n source.connect(analyser);\n\n return { analyser, audioContext };\n}\n\nexport function calculateAudioLevel(analyser: AnalyserNode): number {\n const dataArray = new Uint8Array(analyser.fftSize);\n analyser.getByteTimeDomainData(dataArray);\n\n const sumSquares = Array.from(dataArray).reduce((sum, value) => {\n const normalized = (value - 128) / 128;\n return sum + normalized * normalized;\n }, 0);\n\n return Math.sqrt(sumSquares / dataArray.length);\n}\n"]}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Decodes a JWT token and extracts environment and tenant information.
3
+ *
4
+ * @param token - The JWT token to decode
5
+ * @returns Object containing environment, tenant, accessToken, and expiresAt
6
+ * @throws Error if token format is invalid or cannot be decoded
7
+ */
8
+ export declare function decodeToken(token: string): {
9
+ accessToken: string;
10
+ environment: string;
11
+ expiresAt: number | undefined;
12
+ tenant: string;
13
+ };
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Decodes a JWT token and extracts environment and tenant information.
3
+ *
4
+ * @param token - The JWT token to decode
5
+ * @returns Object containing environment, tenant, accessToken, and expiresAt
6
+ * @throws Error if token format is invalid or cannot be decoded
7
+ */
8
+ export function decodeToken(token) {
9
+ // Validate the token structure (should contain at least header and payload parts)
10
+ const parts = token.split(".");
11
+ if (parts.length < 2) {
12
+ throw new Error("Invalid token format");
13
+ }
14
+ // Retrieve the payload (second part) of the JWT token
15
+ const base64Url = parts[1];
16
+ // Replace URL-safe characters to match standard base64 encoding
17
+ const base64 = base64Url.replace(/-/g, "+").replace(/_/g, "/");
18
+ // Decode the base64 string into a JSON string
19
+ let jsonPayload;
20
+ try {
21
+ jsonPayload = decodeURIComponent(atob(base64)
22
+ .split("")
23
+ .map((c) => "%" + ("00" + c.charCodeAt(0).toString(16)).slice(-2))
24
+ .join(""));
25
+ }
26
+ catch (error) {
27
+ throw new Error("Failed to decode token payload");
28
+ }
29
+ // Parse the JSON string to obtain token details
30
+ let tokenDetails;
31
+ try {
32
+ tokenDetails = JSON.parse(jsonPayload);
33
+ }
34
+ catch (error) {
35
+ throw new Error("Invalid JSON payload in token");
36
+ }
37
+ // Extract the issuer URL from the token details
38
+ const issuerUrl = tokenDetails.iss;
39
+ if (!issuerUrl) {
40
+ throw new Error("Token payload does not contain an issuer (iss) field");
41
+ }
42
+ // Regex to extract environment and tenant from issuer URL:
43
+ // Expected format: https://keycloak.{environment}.corti.app/realms/{tenant}
44
+ const regex = /^https:\/\/(keycloak|auth)\.([^.]+)\.corti\.app\/realms\/([^/]+)/;
45
+ const match = issuerUrl.match(regex);
46
+ if (!match) {
47
+ throw new Error("Access token does not match expected format");
48
+ }
49
+ // If the issuer URL matches the expected pattern, return the extracted values along with the token
50
+ const expiresAt = tokenDetails.exp && typeof tokenDetails.exp === "number"
51
+ ? tokenDetails.exp
52
+ : undefined;
53
+ return {
54
+ accessToken: token,
55
+ environment: match[2],
56
+ expiresAt,
57
+ tenant: match[3],
58
+ };
59
+ }
60
+ //# sourceMappingURL=token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token.js","sourceRoot":"","sources":["../../../src/utils/token.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,kFAAkF;IAClF,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAC/B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrB,MAAM,IAAI,KAAK,CAAC,sBAAsB,CAAC,CAAC;IAC1C,CAAC;IAED,sDAAsD;IACtD,MAAM,SAAS,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;IAE3B,gEAAgE;IAChE,MAAM,MAAM,GAAG,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAE/D,8CAA8C;IAC9C,IAAI,WAAmB,CAAC;IACxB,IAAI,CAAC;QACH,WAAW,GAAG,kBAAkB,CAC9B,IAAI,CAAC,MAAM,CAAC;aACT,KAAK,CAAC,EAAE,CAAC;aACT,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;aACjE,IAAI,CAAC,EAAE,CAAC,CACZ,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IACpD,CAAC;IAED,gDAAgD;IAChD,IAAI,YAAmE,CAAC;IACxE,IAAI,CAAC;QACH,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACzC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC;IACnD,CAAC;IAED,gDAAgD;IAChD,MAAM,SAAS,GAAW,YAAY,CAAC,GAAG,CAAC;IAC3C,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,sDAAsD,CAAC,CAAC;IAC1E,CAAC;IAED,2DAA2D;IAC3D,4EAA4E;IAC5E,MAAM,KAAK,GACT,kEAAkE,CAAC;IACrE,MAAM,KAAK,GAAG,SAAS,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAErC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IAED,mGAAmG;IACnG,MAAM,SAAS,GACb,YAAY,CAAC,GAAG,IAAI,OAAO,YAAY,CAAC,GAAG,KAAK,QAAQ;QACtD,CAAC,CAAC,YAAY,CAAC,GAAG;QAClB,CAAC,CAAC,SAAS,CAAC;IAEhB,OAAO;QACL,WAAW,EAAE,KAAK;QAClB,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC;QACrB,SAAS;QACT,MAAM,EAAE,KAAK,CAAC,CAAC,CAAC;KACjB,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Decodes a JWT token and extracts environment and tenant information.\n *\n * @param token - The JWT token to decode\n * @returns Object containing environment, tenant, accessToken, and expiresAt\n * @throws Error if token format is invalid or cannot be decoded\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; exp?: number; [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 const regex =\n /^https:\\/\\/(keycloak|auth)\\.([^.]+)\\.corti\\.app\\/realms\\/([^/]+)/;\n const match = issuerUrl.match(regex);\n\n if (!match) {\n throw new Error(\"Access token does not match expected format\");\n }\n\n // If the issuer URL matches the expected pattern, return the extracted values along with the token\n const expiresAt =\n tokenDetails.exp && typeof tokenDetails.exp === \"number\"\n ? tokenDetails.exp\n : undefined;\n\n return {\n accessToken: token,\n environment: match[2],\n expiresAt,\n tenant: match[3],\n };\n}\n"]}
@@ -0,0 +1 @@
1
+ export declare function normalizeToRange(value: number, min?: number, max?: number): number;
@@ -0,0 +1,7 @@
1
+ export function normalizeToRange(value, min = 0, max = 1) {
2
+ if (Number.isNaN(value) || !Number.isFinite(value)) {
3
+ return min;
4
+ }
5
+ return Math.max(min, Math.min(max, value));
6
+ }
7
+ //# sourceMappingURL=validation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validation.js","sourceRoot":"","sources":["../../../src/utils/validation.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,gBAAgB,CAC9B,KAAa,EACb,MAAc,CAAC,EACf,MAAc,CAAC;IAEf,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QACnD,OAAO,GAAG,CAAC;IACb,CAAC;IAED,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;AAC7C,CAAC","sourcesContent":["export function normalizeToRange(\n value: number,\n min: number = 0,\n max: number = 1,\n): number {\n if (Number.isNaN(value) || !Number.isFinite(value)) {\n return min;\n }\n\n return Math.max(min, Math.min(max, value));\n}\n"]}
@@ -0,0 +1,39 @@
1
+ import { type TemplateResult } from "lit";
2
+ import "../src/components/audio-visualiser.js";
3
+ import "../src/contexts/dictation-context.js";
4
+ declare const _default: {
5
+ argTypes: {
6
+ active: {
7
+ control: string;
8
+ description: string;
9
+ };
10
+ level: {
11
+ control: {
12
+ max: number;
13
+ min: number;
14
+ step: number;
15
+ type: string;
16
+ };
17
+ description: string;
18
+ };
19
+ };
20
+ component: string;
21
+ title: string;
22
+ };
23
+ export default _default;
24
+ interface Story<T> {
25
+ (args: T): TemplateResult;
26
+ args?: Partial<T>;
27
+ argTypes?: Record<string, unknown>;
28
+ }
29
+ interface AudioVisualiserArgTypes {
30
+ level?: number;
31
+ active?: boolean;
32
+ }
33
+ export declare const Default: Story<AudioVisualiserArgTypes>;
34
+ export declare const Inactive: Story<AudioVisualiserArgTypes>;
35
+ export declare const Low: Story<AudioVisualiserArgTypes>;
36
+ export declare const Medium: Story<AudioVisualiserArgTypes>;
37
+ export declare const High: Story<AudioVisualiserArgTypes>;
38
+ export declare const Full: Story<AudioVisualiserArgTypes>;
39
+ export declare const Silent: Story<AudioVisualiserArgTypes>;
@@ -0,0 +1,71 @@
1
+ import { html } from "lit";
2
+ import "../src/components/audio-visualiser.js";
3
+ import "../src/contexts/dictation-context.js";
4
+ export default {
5
+ argTypes: {
6
+ active: {
7
+ control: "boolean",
8
+ description: "Whether the visualiser is active",
9
+ },
10
+ level: {
11
+ control: { max: 1, min: 0, step: 0.01, type: "range" },
12
+ description: "Audio level from 0 to 1",
13
+ },
14
+ },
15
+ component: "audio-visualiser",
16
+ title: "AudioVisualiser",
17
+ };
18
+ const AudioVisualiserTemplate = ({ level = 0, active = true, }) => {
19
+ if (!active) {
20
+ return html `
21
+ <dictation-context-provider ?noWrapper=${true}>
22
+ <div style="height: 100px;">
23
+ <audio-visualiser level=${level}></audio-visualiser>
24
+ </div>
25
+ </dictation-context-provider>
26
+ `;
27
+ }
28
+ return html `
29
+ <dictation-context-provider ?noWrapper=${true}>
30
+ <div style="height: 100px;">
31
+ <audio-visualiser level=${level} active></audio-visualiser>
32
+ </div>
33
+ </dictation-context-provider>
34
+ `;
35
+ };
36
+ export const Default = AudioVisualiserTemplate.bind({});
37
+ Default.args = {
38
+ active: true,
39
+ level: 0.5,
40
+ };
41
+ export const Inactive = AudioVisualiserTemplate.bind({});
42
+ Inactive.args = {
43
+ active: false,
44
+ level: 0.5,
45
+ };
46
+ export const Low = AudioVisualiserTemplate.bind({});
47
+ Low.args = {
48
+ active: true,
49
+ level: 0.2,
50
+ };
51
+ export const Medium = AudioVisualiserTemplate.bind({});
52
+ Medium.args = {
53
+ active: true,
54
+ level: 0.5,
55
+ };
56
+ export const High = AudioVisualiserTemplate.bind({});
57
+ High.args = {
58
+ active: true,
59
+ level: 0.8,
60
+ };
61
+ export const Full = AudioVisualiserTemplate.bind({});
62
+ Full.args = {
63
+ active: true,
64
+ level: 1.0,
65
+ };
66
+ export const Silent = AudioVisualiserTemplate.bind({});
67
+ Silent.args = {
68
+ active: true,
69
+ level: 0,
70
+ };
71
+ //# sourceMappingURL=audio-visualiser.stories.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"audio-visualiser.stories.js","sourceRoot":"","sources":["../../stories/audio-visualiser.stories.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAuB,MAAM,KAAK,CAAC;AAEhD,OAAO,uCAAuC,CAAC;AAC/C,OAAO,sCAAsC,CAAC;AAE9C,eAAe;IACb,QAAQ,EAAE;QACR,MAAM,EAAE;YACN,OAAO,EAAE,SAAS;YAClB,WAAW,EAAE,kCAAkC;SAChD;QACD,KAAK,EAAE;YACL,OAAO,EAAE,EAAE,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,OAAO,EAAE;YACtD,WAAW,EAAE,yBAAyB;SACvC;KACF;IACD,SAAS,EAAE,kBAAkB;IAC7B,KAAK,EAAE,iBAAiB;CACzB,CAAC;AAaF,MAAM,uBAAuB,GAAmC,CAAC,EAC/D,KAAK,GAAG,CAAC,EACT,MAAM,GAAG,IAAI,GACW,EAAE,EAAE;IAC5B,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,IAAI,CAAA;+CACgC,IAAI;;oCAEf,KAAK;;;KAGpC,CAAC;IACJ,CAAC;IAED,OAAO,IAAI,CAAA;6CACgC,IAAI;;kCAEf,KAAK;;;GAGpC,CAAC;AACJ,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,OAAO,GAAG,uBAAuB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACxD,OAAO,CAAC,IAAI,GAAG;IACb,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,GAAG;CACX,CAAC;AAEF,MAAM,CAAC,MAAM,QAAQ,GAAG,uBAAuB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACzD,QAAQ,CAAC,IAAI,GAAG;IACd,MAAM,EAAE,KAAK;IACb,KAAK,EAAE,GAAG;CACX,CAAC;AAEF,MAAM,CAAC,MAAM,GAAG,GAAG,uBAAuB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACpD,GAAG,CAAC,IAAI,GAAG;IACT,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,GAAG;CACX,CAAC;AAEF,MAAM,CAAC,MAAM,MAAM,GAAG,uBAAuB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACvD,MAAM,CAAC,IAAI,GAAG;IACZ,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,GAAG;CACX,CAAC;AAEF,MAAM,CAAC,MAAM,IAAI,GAAG,uBAAuB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACrD,IAAI,CAAC,IAAI,GAAG;IACV,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,GAAG;CACX,CAAC;AAEF,MAAM,CAAC,MAAM,IAAI,GAAG,uBAAuB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACrD,IAAI,CAAC,IAAI,GAAG;IACV,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,GAAG;CACX,CAAC;AAEF,MAAM,CAAC,MAAM,MAAM,GAAG,uBAAuB,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AACvD,MAAM,CAAC,IAAI,GAAG;IACZ,MAAM,EAAE,IAAI;IACZ,KAAK,EAAE,CAAC;CACT,CAAC","sourcesContent":["import { html, type TemplateResult } from \"lit\";\n\nimport \"../src/components/audio-visualiser.js\";\nimport \"../src/contexts/dictation-context.js\";\n\nexport default {\n argTypes: {\n active: {\n control: \"boolean\",\n description: \"Whether the visualiser is active\",\n },\n level: {\n control: { max: 1, min: 0, step: 0.01, type: \"range\" },\n description: \"Audio level from 0 to 1\",\n },\n },\n component: \"audio-visualiser\",\n title: \"AudioVisualiser\",\n};\n\ninterface Story<T> {\n (args: T): TemplateResult;\n args?: Partial<T>;\n argTypes?: Record<string, unknown>;\n}\n\ninterface AudioVisualiserArgTypes {\n level?: number;\n active?: boolean;\n}\n\nconst AudioVisualiserTemplate: Story<AudioVisualiserArgTypes> = ({\n level = 0,\n active = true,\n}: AudioVisualiserArgTypes) => {\n if (!active) {\n return html`\n <dictation-context-provider ?noWrapper=${true}>\n <div style=\"height: 100px;\">\n <audio-visualiser level=${level}></audio-visualiser>\n </div>\n </dictation-context-provider>\n `;\n }\n\n return html`\n <dictation-context-provider ?noWrapper=${true}>\n <div style=\"height: 100px;\">\n <audio-visualiser level=${level} active></audio-visualiser>\n </div>\n </dictation-context-provider>\n `;\n};\n\nexport const Default = AudioVisualiserTemplate.bind({});\nDefault.args = {\n active: true,\n level: 0.5,\n};\n\nexport const Inactive = AudioVisualiserTemplate.bind({});\nInactive.args = {\n active: false,\n level: 0.5,\n};\n\nexport const Low = AudioVisualiserTemplate.bind({});\nLow.args = {\n active: true,\n level: 0.2,\n};\n\nexport const Medium = AudioVisualiserTemplate.bind({});\nMedium.args = {\n active: true,\n level: 0.5,\n};\n\nexport const High = AudioVisualiserTemplate.bind({});\nHigh.args = {\n active: true,\n level: 0.8,\n};\n\nexport const Full = AudioVisualiserTemplate.bind({});\nFull.args = {\n active: true,\n level: 1.0,\n};\n\nexport const Silent = AudioVisualiserTemplate.bind({});\nSilent.args = {\n active: true,\n level: 0,\n};\n"]}
@@ -0,0 +1,27 @@
1
+ import { type TemplateResult } from "lit";
2
+ import "../src/components/corti-dictation.js";
3
+ declare const _default: {
4
+ argTypes: {
5
+ accessToken: {
6
+ control: string;
7
+ description: string;
8
+ };
9
+ };
10
+ component: string;
11
+ title: string;
12
+ };
13
+ export default _default;
14
+ interface Story<T> {
15
+ (args: T): TemplateResult;
16
+ args?: Partial<T>;
17
+ argTypes?: Record<string, unknown>;
18
+ }
19
+ interface StoryArgs {
20
+ accessToken?: string;
21
+ }
22
+ export declare const DefaultValues: Story<StoryArgs>;
23
+ export declare const OnlyLanguageSettings: Story<StoryArgs>;
24
+ export declare const OnlyDeviceSettings: Story<StoryArgs>;
25
+ export declare const NoSettings: Story<StoryArgs>;
26
+ export declare const WithCustomLanguages: Story<StoryArgs>;
27
+ export declare const WithLanguagesAttribute: Story<StoryArgs>;