@corti/dictation-web 0.3.0 → 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,21 @@
1
+ /**
2
+ * Extracts the initial access token from auth config
3
+ * @throws Error if token is missing or invalid
4
+ */
5
+ export async function getInitialToken(config) {
6
+ const initialToken = "accessToken" in config
7
+ ? {
8
+ accessToken: config.accessToken,
9
+ refreshToken: config.refreshToken,
10
+ }
11
+ : await config.refreshAccessToken();
12
+ if (!initialToken?.accessToken ||
13
+ typeof initialToken.accessToken !== "string") {
14
+ throw new Error("Access token is required and must be a string");
15
+ }
16
+ return {
17
+ accessToken: initialToken.accessToken,
18
+ refreshToken: initialToken.refreshToken,
19
+ };
20
+ }
21
+ //# sourceMappingURL=auth.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/utils/auth.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,MAA2B;IAE3B,MAAM,YAAY,GAChB,aAAa,IAAI,MAAM;QACrB,CAAC,CAAC;YACE,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,YAAY,EAAE,MAAM,CAAC,YAAY;SAClC;QACH,CAAC,CAAC,MAAM,MAAM,CAAC,kBAAkB,EAAE,CAAC;IAExC,IACE,CAAC,YAAY,EAAE,WAAW;QAC1B,OAAO,YAAY,CAAC,WAAW,KAAK,QAAQ,EAC5C,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC;IACnE,CAAC;IAED,OAAO;QACL,WAAW,EAAE,YAAY,CAAC,WAAW;QACrC,YAAY,EAAE,YAAY,CAAC,YAAY;KACxC,CAAC;AACJ,CAAC","sourcesContent":["import type { Corti } from \"@corti/sdk\";\n\n/**\n * Extracts the initial access token from auth config\n * @throws Error if token is missing or invalid\n */\nexport async function getInitialToken(\n config: Corti.BearerOptions,\n): Promise<{ accessToken: string; refreshToken?: string }> {\n const initialToken =\n \"accessToken\" in config\n ? {\n accessToken: config.accessToken,\n refreshToken: config.refreshToken,\n }\n : await config.refreshAccessToken();\n\n if (\n !initialToken?.accessToken ||\n typeof initialToken.accessToken !== \"string\"\n ) {\n throw new Error(\"Access token is required and must be a string\");\n }\n\n return {\n accessToken: initialToken.accessToken,\n refreshToken: initialToken.refreshToken,\n };\n}\n"]}
@@ -0,0 +1,4 @@
1
+ export declare const commaSeparatedConverter: {
2
+ fromAttribute: (value: string | null) => string[] | undefined;
3
+ toAttribute: (value: string[] | undefined) => string | undefined;
4
+ };
@@ -0,0 +1,8 @@
1
+ export const commaSeparatedConverter = {
2
+ fromAttribute: (value) => value
3
+ ?.split(",")
4
+ .map((s) => s.trim())
5
+ .filter(Boolean),
6
+ toAttribute: (value) => value?.join(","),
7
+ };
8
+ //# sourceMappingURL=converters.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"converters.js","sourceRoot":"","sources":["../../src/utils/converters.ts"],"names":[],"mappings":"AAAA,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,aAAa,EAAE,CAAC,KAAoB,EAAE,EAAE,CACtC,KAAK;QACH,EAAE,KAAK,CAAC,GAAG,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,OAAO,CAAC;IACpB,WAAW,EAAE,CAAC,KAA2B,EAAE,EAAE,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC;CAC/D,CAAC","sourcesContent":["export const commaSeparatedConverter = {\n fromAttribute: (value: string | null) =>\n value\n ?.split(\",\")\n .map((s) => s.trim())\n .filter(Boolean),\n toAttribute: (value: string[] | undefined) => value?.join(\",\"),\n};\n"]}
@@ -0,0 +1,26 @@
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 declare function requestMicAccess(): Promise<void>;
11
+ /**
12
+ * Retrieves available audio input devices.
13
+ *
14
+ * This function uses the mediaDevices API to enumerate devices and filters out those
15
+ * which are audio inputs. In some browsers, you may need to request user media before
16
+ * device labels are populated.
17
+ *
18
+ * @returns A promise that resolves with an object containing:
19
+ * - `devices`: an array of MediaDeviceInfo objects for audio inputs.
20
+ * - `defaultDevice`: the first audio input device, if available.
21
+ * @throws Error if mediaDevices API is unavailable or device enumeration fails.
22
+ */
23
+ export declare function getAudioDevices(): Promise<{
24
+ devices: MediaDeviceInfo[];
25
+ defaultDevice?: MediaDeviceInfo;
26
+ }>;
@@ -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: Corti.TranscribeSupportedLanguage[];
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: Corti.TranscribeSupportedLanguage[], 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,SAA8C,EAC9C,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: Corti.TranscribeSupportedLanguage[];\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: Corti.TranscribeSupportedLanguage[],\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,8 @@
1
+ import type { Corti } from "@corti/sdk";
2
+ export declare const DEFAULT_LANGUAGES_BY_REGION: Record<string, Corti.TranscribeSupportedLanguage[]>;
3
+ export declare function getLanguageName(languageCode: string): string;
4
+ export declare function checkIfDefaultLanguagesList(languages?: Corti.TranscribeSupportedLanguage[]): boolean;
5
+ export declare function getLanguagesByRegion(region?: string): {
6
+ languages: Corti.TranscribeSupportedLanguage[];
7
+ defaultLanguage: string | undefined;
8
+ };
@@ -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":"AACA,OAAO,EACL,sBAAsB,EACtB,sBAAsB,GACvB,MAAM,iBAAiB,CAAC;AAEzB,MAAM,CAAC,MAAM,2BAA2B,GAGpC;IACF,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,CACzC,YAAiD,EAAE;IAEnD,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 type { Corti } from \"@corti/sdk\";\nimport {\n LANGUAGES_SUPPORTED_EU,\n LANGUAGES_SUPPORTED_US,\n} from \"../constants.js\";\n\nexport const DEFAULT_LANGUAGES_BY_REGION: Record<\n string,\n Corti.TranscribeSupportedLanguage[]\n> = {\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(\n languages: Corti.TranscribeSupportedLanguage[] = [],\n): boolean {\n return Object.values(DEFAULT_LANGUAGES_BY_REGION).some(\n (languageList) => languageList === languages,\n );\n}\n\nexport function getLanguagesByRegion(region?: string): {\n languages: Corti.TranscribeSupportedLanguage[];\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"]}
package/package.json CHANGED
@@ -2,15 +2,19 @@
2
2
  "name": "@corti/dictation-web",
3
3
  "description": "Web component for Corti Dictation",
4
4
  "author": "Corti ApS",
5
- "version": "0.3.0",
5
+ "version": "0.4.0-rc",
6
6
  "license": "MIT",
7
7
  "type": "module",
8
8
  "main": "dist/index.js",
9
9
  "module": "dist/index.js",
10
+ "types": "dist/index.d.ts",
10
11
  "exports": {
11
- "import": "./dist/index.js",
12
- "browser": "./dist/bundle.js",
13
- "default": "./dist/bundle.js"
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.js",
15
+ "browser": "./dist/bundle.js",
16
+ "default": "./dist/bundle.js"
17
+ }
14
18
  },
15
19
  "jsdelivr": "./dist/bundle.js",
16
20
  "browser": "./dist/bundle.js",
@@ -18,11 +22,11 @@
18
22
  "dist"
19
23
  ],
20
24
  "bugs": {
21
- "url": "https://help.corti.app",
25
+ "url": "https://docs.corti.ai",
22
26
  "email": "help@corti.ai"
23
27
  },
24
- "repository": "github:corticph/dictation-web-sdk",
25
- "homepage": "https://help.corti.app/en/articles/10714657-introducing-the-corti-dictation-browser-sdk",
28
+ "repository": "github:corticph/dictation-web",
29
+ "homepage": "https://docs.corti.ai/stt/dictation-web",
26
30
  "keywords": [
27
31
  "corti",
28
32
  "dictation",
@@ -42,79 +46,49 @@
42
46
  "release": "npm run build && npm run build:bundle && npm publish --access public",
43
47
  "start": "npm run build && npm run build:bundle && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"web-dev-server\"",
44
48
  "prepublish": "tsc && npm run analyze -- --exclude dist",
45
- "lint": "eslint --ext .ts,.tsx src --ignore-path .gitignore && prettier \"src/**/*.ts\" --check --ignore-path .gitignore",
46
- "format": "eslint --ext .ts,.tsx src --fix --ignore-path .gitignore && prettier \"src/**/*.ts\" --write --ignore-path .gitignore",
49
+ "lint": "biome check .",
50
+ "format": "biome format --write .",
51
+ "biome:check": "biome check .",
52
+ "biome:format": "biome format --write .",
53
+ "biome:fix": "biome check --write .",
47
54
  "prepare": "husky && husky install",
48
55
  "test": "tsc && wtr --coverage",
49
56
  "test:watch": "tsc && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"wtr --watch\"",
50
- "storybook": "tsc && npm run analyze -- --exclude dist && concurrently -k -r \"tsc --watch --preserveWatchOutput\" \"storybook dev -p 8080\"",
51
- "storybook:build": "tsc && npm run analyze -- --exclude dist && storybook build"
57
+ "storybook": "npm run analyze -- --exclude dist && storybook dev -p 8080",
58
+ "storybook:build": "tsc && tsc -p tsconfig.stories.json && npm run analyze -- --exclude dist && storybook build"
52
59
  },
53
60
  "dependencies": {
54
- "@corti/sdk": "^0.5.0",
55
- "lit": "^3.1.4"
61
+ "@corti/sdk": "^0.8.0-rc",
62
+ "@lit/context": "^1.1.6",
63
+ "lit": "^3.3.1"
56
64
  },
57
65
  "devDependencies": {
66
+ "@biomejs/biome": "^2.3.6",
58
67
  "@custom-elements-manifest/analyzer": "^0.10.3",
59
- "@open-wc/eslint-config": "^12.0.3",
60
68
  "@open-wc/testing": "^4.0.0",
61
- "@storybook/addon-a11y": "^7.6.20",
62
- "@storybook/addon-essentials": "^7.6.20",
63
- "@storybook/addon-links": "^7.6.20",
64
- "@storybook/web-components": "^7.6.20",
69
+ "@storybook/addon-a11y": "10.1.5",
70
+ "@storybook/addon-docs": "^10.1.5",
71
+ "@storybook/addon-links": "10.1.5",
72
+ "@storybook/web-components": "10.1.5",
73
+ "@storybook/web-components-vite": "^10.1.5",
65
74
  "@types/mocha": "^10.0.7",
66
- "@typescript-eslint/eslint-plugin": "^7.18.0",
67
- "@typescript-eslint/parser": "^7.18.0",
68
75
  "@web/dev-server": "^0.4.6",
69
76
  "@web/storybook-builder": "^0.1.16",
70
77
  "@web/storybook-framework-web-components": "^0.1.2",
71
78
  "@web/test-runner": "^0.18.2",
72
79
  "concurrently": "^8.2.2",
73
80
  "esbuild": "^0.25.0",
74
- "eslint": "^8.57.0",
75
- "eslint-config-prettier": "^9.1.0",
76
- "eslint-plugin-html": "^8.1.2",
77
81
  "husky": "^8.0.0",
78
82
  "lint-staged": "^15.2.7",
79
- "prettier": "^3.3.2",
80
83
  "sinon": "^19.0.2",
81
- "storybook": "^7.6.20",
84
+ "storybook": "10.1.5",
82
85
  "tslib": "^2.6.3",
83
86
  "typescript": "^5.5.3"
84
87
  },
85
88
  "customElements": "custom-elements.json",
86
- "eslintConfig": {
87
- "parser": "@typescript-eslint/parser",
88
- "extends": [
89
- "@open-wc",
90
- "prettier"
91
- ],
92
- "plugins": [
93
- "@typescript-eslint"
94
- ],
95
- "rules": {
96
- "no-unused-vars": "off",
97
- "@typescript-eslint/no-unused-vars": [
98
- "error"
99
- ],
100
- "import/no-unresolved": "off",
101
- "import/extensions": [
102
- "error",
103
- "always",
104
- {
105
- "ignorePackages": true
106
- }
107
- ]
108
- }
109
- },
110
- "prettier": {
111
- "singleQuote": true,
112
- "arrowParens": "avoid"
113
- },
114
89
  "lint-staged": {
115
90
  "*.ts": [
116
- "eslint --fix",
117
- "prettier --write"
91
+ "biome check --write"
118
92
  ]
119
93
  }
120
94
  }