@creativeorange/azure-text-to-speech 3.0.0 → 3.0.1

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.
@@ -4,6 +4,193 @@ var __publicField = (obj, key, value) => {
4
4
  __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
5
5
  return value;
6
6
  };
7
+ const DEFAULT_TOKEN_LIFETIME_MS = 8 * 60 * 1e3;
8
+ function createSpeechAuthorizationProvider(options) {
9
+ var _a;
10
+ const hasTokenEndpoint = typeof options.tokenEndpoint === "string" && options.tokenEndpoint.trim() !== "";
11
+ const hasProvider = typeof options.getAuthorizationToken === "function";
12
+ if (hasTokenEndpoint && hasProvider) {
13
+ throw new Error(
14
+ "Provide either tokenEndpoint or getAuthorizationToken, not both."
15
+ );
16
+ }
17
+ if (!hasTokenEndpoint && !hasProvider) {
18
+ throw new Error(
19
+ "A tokenEndpoint or getAuthorizationToken provider is required."
20
+ );
21
+ }
22
+ if (hasProvider) {
23
+ return options.getAuthorizationToken;
24
+ }
25
+ const tokenEndpoint = options.tokenEndpoint.trim();
26
+ const requestOptions = (_a = options.tokenRequestOptions) != null ? _a : {};
27
+ return async () => {
28
+ var _a2, _b, _c;
29
+ let response;
30
+ try {
31
+ response = await fetch(tokenEndpoint, {
32
+ method: "GET",
33
+ cache: (_a2 = requestOptions.cache) != null ? _a2 : "no-store",
34
+ credentials: (_b = requestOptions.credentials) != null ? _b : "same-origin",
35
+ headers: {
36
+ Accept: "application/json",
37
+ ...(_c = requestOptions.headers) != null ? _c : {}
38
+ }
39
+ });
40
+ } catch {
41
+ throw createSafeError(
42
+ "Could not reach the speech token endpoint.",
43
+ "TOKEN_ENDPOINT_UNREACHABLE"
44
+ );
45
+ }
46
+ if (!response.ok) {
47
+ throw createSafeError(
48
+ `Speech token endpoint returned HTTP ${response.status}.`,
49
+ "TOKEN_ENDPOINT_HTTP_ERROR"
50
+ );
51
+ }
52
+ let payload;
53
+ try {
54
+ payload = await response.json();
55
+ } catch {
56
+ throw createSafeError(
57
+ "Speech token endpoint returned invalid JSON.",
58
+ "TOKEN_ENDPOINT_INVALID_JSON"
59
+ );
60
+ }
61
+ return validateSpeechAuthorization(payload);
62
+ };
63
+ }
64
+ function validateSpeechAuthorization(value) {
65
+ if (!value || typeof value !== "object") {
66
+ throw createSafeError(
67
+ "Speech authorization response must be an object.",
68
+ "TOKEN_INVALID_RESPONSE"
69
+ );
70
+ }
71
+ const candidate = value;
72
+ const token = typeof candidate.token === "string" ? candidate.token.trim() : "";
73
+ const region = typeof candidate.region === "string" ? candidate.region.trim() : "";
74
+ if (token === "") {
75
+ throw createSafeError(
76
+ "Speech authorization token is missing or empty.",
77
+ "TOKEN_EMPTY"
78
+ );
79
+ }
80
+ if (region === "") {
81
+ throw createSafeError(
82
+ "Speech authorization region is missing or empty.",
83
+ "TOKEN_REGION_MISSING"
84
+ );
85
+ }
86
+ return { token, region };
87
+ }
88
+ function createSafeError(message, code) {
89
+ const error = new Error(sanitizeErrorText(message));
90
+ error.message = sanitizeErrorText(message);
91
+ if (code) {
92
+ error.code = code;
93
+ }
94
+ return error;
95
+ }
96
+ function toSafeErrorDetail(error) {
97
+ if (typeof error === "string") {
98
+ const message = error.trim() !== "" ? sanitizeErrorText(error) : "An unexpected speech error occurred.";
99
+ return { message };
100
+ }
101
+ if (error && typeof error === "object") {
102
+ const candidate = error;
103
+ const rawMessage = [
104
+ typeof candidate.message === "string" ? candidate.message : "",
105
+ typeof candidate.errorDetails === "string" ? candidate.errorDetails : "",
106
+ typeof candidate.reason === "string" ? candidate.reason : ""
107
+ ].filter((part) => part.trim() !== "").join(" ");
108
+ const message = rawMessage !== "" ? sanitizeErrorText(rawMessage) : "An unexpected speech error occurred.";
109
+ const detail = { message };
110
+ if (typeof candidate.code === "string" && candidate.code.trim() !== "") {
111
+ detail.code = candidate.code;
112
+ } else if (typeof candidate.code === "number") {
113
+ detail.code = String(candidate.code);
114
+ }
115
+ return detail;
116
+ }
117
+ return {
118
+ message: "An unexpected speech error occurred."
119
+ };
120
+ }
121
+ function sanitizeErrorText(message) {
122
+ return message.replace(/Authorization\s*:\s*Bearer\s+\S+/gi, "Authorization: Bearer [redacted]").replace(/Bearer\s+\S+/gi, "Bearer [redacted]").replace(
123
+ /authorization[_-]?token["']?\s*[:=]\s*["']?[^"',\s}]+/gi,
124
+ "authorizationToken=[redacted]"
125
+ ).replace(
126
+ /access[_-]?token["']?\s*[:=]\s*["']?[^"',\s}]+/gi,
127
+ "accessToken=[redacted]"
128
+ ).replace(
129
+ /["']token["']\s*:\s*["'][^"']+["']/gi,
130
+ '"token":"[redacted]"'
131
+ ).replace(
132
+ /token["']?\s*[:=]\s*["']?[^"',\s}]+/gi,
133
+ "token=[redacted]"
134
+ );
135
+ }
136
+ function isLikelyAuthorizationError(error) {
137
+ var _a;
138
+ const detail = toSafeErrorDetail(error);
139
+ const haystack = `${detail.message} ${(_a = detail.code) != null ? _a : ""}`.toLowerCase();
140
+ return haystack.includes("unauthorized") || haystack.includes("authentication") || haystack.includes("authorization") || haystack.includes("invalid token") || haystack.includes("token expired") || haystack.includes("expired token") || haystack.includes("403") || haystack.includes("401") || detail.code === "TOKEN_REFRESH_ERROR";
141
+ }
142
+ class SpeechAuthorizationManager {
143
+ constructor(options) {
144
+ __publicField(this, "authorization");
145
+ __publicField(this, "authorizationExpiresAt", 0);
146
+ __publicField(this, "authorizationRequest");
147
+ __publicField(this, "provider");
148
+ __publicField(this, "tokenLifetimeMs");
149
+ this.provider = createSpeechAuthorizationProvider(options);
150
+ this.tokenLifetimeMs = options.tokenLifetimeMs && options.tokenLifetimeMs > 0 ? options.tokenLifetimeMs : DEFAULT_TOKEN_LIFETIME_MS;
151
+ }
152
+ getTokenLifetimeMs() {
153
+ return this.tokenLifetimeMs;
154
+ }
155
+ async getAuthorization() {
156
+ if (this.authorization && Date.now() < this.authorizationExpiresAt) {
157
+ return this.authorization;
158
+ }
159
+ if (this.authorizationRequest) {
160
+ return this.authorizationRequest;
161
+ }
162
+ this.authorizationRequest = this.fetchAuthorization().then((authorization) => {
163
+ this.authorization = authorization;
164
+ this.authorizationExpiresAt = Date.now() + this.tokenLifetimeMs;
165
+ return authorization;
166
+ }).finally(() => {
167
+ this.authorizationRequest = void 0;
168
+ });
169
+ return this.authorizationRequest;
170
+ }
171
+ async refreshAuthorization() {
172
+ this.authorization = void 0;
173
+ this.authorizationExpiresAt = 0;
174
+ if (this.authorizationRequest) {
175
+ return this.authorizationRequest;
176
+ }
177
+ return this.getAuthorization();
178
+ }
179
+ clearAuthorization() {
180
+ this.authorization = void 0;
181
+ this.authorizationExpiresAt = 0;
182
+ }
183
+ async fetchAuthorization() {
184
+ try {
185
+ const authorization = await this.provider();
186
+ return validateSpeechAuthorization(authorization);
187
+ } catch (error) {
188
+ this.clearAuthorization();
189
+ const detail = toSafeErrorDetail(error);
190
+ throw createSafeError(detail.message, detail.code);
191
+ }
192
+ }
193
+ }
7
194
  var ws = {};
8
195
  var getRandomValues;
9
196
  var rnds8 = new Uint8Array(16);
@@ -1079,7 +1266,7 @@ class Timeout {
1079
1266
  throw new Error(message);
1080
1267
  }
1081
1268
  });
1082
- const clearTimeout = (timerId) => {
1269
+ const clearTimeout2 = (timerId) => {
1083
1270
  const id = Math.random();
1084
1271
  unhandledRequests.set(id, timerId);
1085
1272
  scheduledTimeoutFunctions.set(timerId, id);
@@ -1104,7 +1291,7 @@ class Timeout {
1104
1291
  return timerId;
1105
1292
  };
1106
1293
  return {
1107
- clearTimeout,
1294
+ clearTimeout: clearTimeout2,
1108
1295
  setTimeout: setTimeout2
1109
1296
  };
1110
1297
  }
@@ -8350,170 +8537,24 @@ class RestMessageAdapter {
8350
8537
  return Object.keys(params).map((k) => encodeURIComponent(k) + "=" + encodeURIComponent(params[k])).join("&");
8351
8538
  }
8352
8539
  }
8353
- const DEFAULT_TOKEN_LIFETIME_MS = 8 * 60 * 1e3;
8354
- function createSpeechAuthorizationProvider(options) {
8355
- var _a;
8356
- const hasTokenEndpoint = typeof options.tokenEndpoint === "string" && options.tokenEndpoint.trim() !== "";
8357
- const hasProvider = typeof options.getAuthorizationToken === "function";
8358
- if (hasTokenEndpoint && hasProvider) {
8359
- throw new Error(
8360
- "Provide either tokenEndpoint or getAuthorizationToken, not both."
8361
- );
8362
- }
8363
- if (!hasTokenEndpoint && !hasProvider) {
8364
- throw new Error(
8365
- "A tokenEndpoint or getAuthorizationToken provider is required."
8366
- );
8367
- }
8368
- if (hasProvider) {
8369
- return options.getAuthorizationToken;
8370
- }
8371
- const tokenEndpoint = options.tokenEndpoint.trim();
8372
- const requestOptions = (_a = options.tokenRequestOptions) != null ? _a : {};
8373
- return async () => {
8374
- var _a2, _b;
8375
- let response;
8376
- try {
8377
- response = await fetch(tokenEndpoint, {
8378
- method: "GET",
8379
- credentials: (_a2 = requestOptions.credentials) != null ? _a2 : "same-origin",
8380
- headers: {
8381
- Accept: "application/json",
8382
- ...(_b = requestOptions.headers) != null ? _b : {}
8383
- }
8384
- });
8385
- } catch {
8386
- throw createSafeError(
8387
- "Could not reach the speech token endpoint.",
8388
- "TOKEN_ENDPOINT_UNREACHABLE"
8389
- );
8390
- }
8391
- if (!response.ok) {
8392
- throw createSafeError(
8393
- `Speech token endpoint returned HTTP ${response.status}.`,
8394
- "TOKEN_ENDPOINT_HTTP_ERROR"
8395
- );
8396
- }
8397
- let payload;
8398
- try {
8399
- payload = await response.json();
8400
- } catch {
8401
- throw createSafeError(
8402
- "Speech token endpoint returned invalid JSON.",
8403
- "TOKEN_ENDPOINT_INVALID_JSON"
8404
- );
8405
- }
8406
- return validateSpeechAuthorization(payload);
8407
- };
8408
- }
8409
- function validateSpeechAuthorization(value) {
8410
- if (!value || typeof value !== "object") {
8411
- throw createSafeError(
8412
- "Speech authorization response must be an object.",
8413
- "TOKEN_INVALID_RESPONSE"
8414
- );
8415
- }
8416
- const candidate = value;
8417
- const token = typeof candidate.token === "string" ? candidate.token.trim() : "";
8418
- const region = typeof candidate.region === "string" ? candidate.region.trim() : "";
8419
- if (token === "") {
8420
- throw createSafeError(
8421
- "Speech authorization token is missing or empty.",
8422
- "TOKEN_EMPTY"
8423
- );
8424
- }
8425
- if (region === "") {
8426
- throw createSafeError(
8427
- "Speech authorization region is missing or empty.",
8428
- "TOKEN_REGION_MISSING"
8429
- );
8430
- }
8431
- return { token, region };
8432
- }
8433
- function createSafeError(message, code) {
8434
- const error = new Error(message);
8435
- error.message = message;
8436
- if (code) {
8437
- error.code = code;
8438
- }
8439
- return error;
8440
- }
8441
- function toSafeErrorDetail(error) {
8442
- if (error && typeof error === "object") {
8443
- const candidate = error;
8444
- const message = typeof candidate.message === "string" && candidate.message.trim() !== "" ? sanitizeErrorText(candidate.message) : "An unexpected speech error occurred.";
8445
- const detail = { message };
8446
- if (typeof candidate.code === "string" && candidate.code.trim() !== "") {
8447
- detail.code = candidate.code;
8448
- }
8449
- return detail;
8450
- }
8451
- return {
8452
- message: "An unexpected speech error occurred."
8453
- };
8454
- }
8455
- function sanitizeErrorText(message) {
8456
- return message.replace(/Bearer\s+\S+/gi, "Bearer [redacted]").replace(/token["']?\s*[:=]\s*["']?[^"',\s}]+/gi, "token=[redacted]");
8457
- }
8458
- class SpeechAuthorizationManager {
8459
- constructor(options) {
8460
- __publicField(this, "authorization");
8461
- __publicField(this, "authorizationExpiresAt", 0);
8462
- __publicField(this, "authorizationRequest");
8463
- __publicField(this, "provider");
8464
- __publicField(this, "tokenLifetimeMs");
8465
- this.provider = createSpeechAuthorizationProvider(options);
8466
- this.tokenLifetimeMs = options.tokenLifetimeMs && options.tokenLifetimeMs > 0 ? options.tokenLifetimeMs : DEFAULT_TOKEN_LIFETIME_MS;
8467
- }
8468
- async getAuthorization() {
8469
- if (this.authorization && Date.now() < this.authorizationExpiresAt) {
8470
- return this.authorization;
8471
- }
8472
- if (this.authorizationRequest) {
8473
- return this.authorizationRequest;
8474
- }
8475
- this.authorizationRequest = this.fetchAuthorization().then((authorization) => {
8476
- this.authorization = authorization;
8477
- this.authorizationExpiresAt = Date.now() + this.tokenLifetimeMs;
8478
- return authorization;
8479
- }).finally(() => {
8480
- this.authorizationRequest = void 0;
8481
- });
8482
- return this.authorizationRequest;
8483
- }
8484
- clearAuthorization() {
8485
- this.authorization = void 0;
8486
- this.authorizationExpiresAt = 0;
8487
- this.authorizationRequest = void 0;
8488
- }
8489
- async fetchAuthorization() {
8490
- try {
8491
- const authorization = await this.provider();
8492
- return validateSpeechAuthorization(authorization);
8493
- } catch (error) {
8494
- this.clearAuthorization();
8495
- throw createSafeError(
8496
- toSafeErrorDetail(error).message,
8497
- error == null ? void 0 : error.code
8498
- );
8499
- }
8500
- }
8501
- }
8502
8540
  class SpeechToText {
8503
8541
  constructor(options) {
8504
- __publicField(this, "region");
8542
+ __publicField(this, "region", "");
8505
8543
  __publicField(this, "sourceLanguage");
8506
8544
  __publicField(this, "targetLanguage");
8507
8545
  __publicField(this, "recognizer");
8508
8546
  __publicField(this, "authorizationManager");
8509
- var _a, _b, _c;
8547
+ __publicField(this, "authorizationRefreshIntervalMs");
8548
+ __publicField(this, "authorizationRefreshTimer");
8549
+ __publicField(this, "stopPromise");
8550
+ var _a;
8510
8551
  if (!options || typeof options.sourceLanguage !== "string" || options.sourceLanguage.trim() === "") {
8511
8552
  throw new Error("A sourceLanguage is required.");
8512
8553
  }
8513
8554
  this.authorizationManager = new SpeechAuthorizationManager(options);
8514
- this.region = (_b = (_a = options.region) == null ? void 0 : _a.trim()) != null ? _b : "";
8555
+ this.authorizationRefreshIntervalMs = options.tokenLifetimeMs && options.tokenLifetimeMs > 0 ? options.tokenLifetimeMs : DEFAULT_TOKEN_LIFETIME_MS;
8515
8556
  this.sourceLanguage = options.sourceLanguage;
8516
- this.targetLanguage = (_c = options.targetLanguage) != null ? _c : options.sourceLanguage;
8557
+ this.targetLanguage = (_a = options.targetLanguage) != null ? _a : options.sourceLanguage;
8517
8558
  }
8518
8559
  async start() {
8519
8560
  await this.registerBindings(document);
@@ -8527,9 +8568,15 @@ class SpeechToText {
8527
8568
  const currentNode = nodes[i];
8528
8569
  if (currentNode.attributes) {
8529
8570
  if (currentNode.attributes.getNamedItem("co-stt.start")) {
8530
- await this.handleStartModifier(currentNode, currentNode.attributes.getNamedItem("co-stt.start"));
8571
+ await this.handleStartModifier(
8572
+ currentNode,
8573
+ currentNode.attributes.getNamedItem("co-stt.start")
8574
+ );
8531
8575
  } else if (currentNode.attributes.getNamedItem("co-stt.stop")) {
8532
- await this.handleStopModifier(currentNode, currentNode.attributes.getNamedItem("co-stt.stop"));
8576
+ await this.handleStopModifier(
8577
+ currentNode,
8578
+ currentNode.attributes.getNamedItem("co-stt.stop")
8579
+ );
8533
8580
  }
8534
8581
  }
8535
8582
  if (currentNode.childNodes.length > 0) {
@@ -8553,12 +8600,13 @@ class SpeechToText {
8553
8600
  async handleStartModifier(node, attr) {
8554
8601
  node.addEventListener("click", async (_) => {
8555
8602
  try {
8603
+ await this.stop();
8556
8604
  const speechConfig = await this.createSpeechTranslationConfig();
8557
8605
  const audioConfig = AudioConfig.fromDefaultMicrophoneInput();
8558
8606
  this.recognizer = new TranslationRecognizer(speechConfig, audioConfig);
8559
8607
  document.dispatchEvent(new CustomEvent("COAzureSTTStartedRecording", {}));
8560
- const prevResults = [];
8561
- this.recognizer.recognizing = (sender, event) => {
8608
+ const prevResults = {};
8609
+ this.recognizer.recognizing = (_sender, event) => {
8562
8610
  const result = event.result;
8563
8611
  if (result && result.reason === ResultReason.TranslatingSpeech) {
8564
8612
  const translation = result.translations.get(this.targetLanguage);
@@ -8576,36 +8624,105 @@ class SpeechToText {
8576
8624
  };
8577
8625
  this.recognizer.startContinuousRecognitionAsync(
8578
8626
  () => {
8627
+ this.scheduleAuthorizationRefresh();
8579
8628
  },
8580
8629
  (err) => {
8630
+ if (isLikelyAuthorizationError(err)) {
8631
+ this.authorizationManager.clearAuthorization();
8632
+ }
8581
8633
  this.dispatchError(err, "RECOGNITION_ERROR");
8582
- this.stop();
8634
+ void this.stop();
8583
8635
  }
8584
8636
  );
8585
8637
  } catch (error) {
8638
+ this.clearAuthorizationRefreshTimer();
8639
+ if (isLikelyAuthorizationError(error)) {
8640
+ this.authorizationManager.clearAuthorization();
8641
+ }
8586
8642
  this.dispatchError(error);
8587
8643
  await this.stop();
8588
8644
  }
8589
8645
  });
8590
8646
  }
8591
- async handleStopModifier(node, attr) {
8647
+ async handleStopModifier(node, _attr) {
8592
8648
  node.addEventListener("click", async (_) => {
8593
8649
  await this.stop();
8594
8650
  });
8595
8651
  }
8596
8652
  async stop() {
8597
- if (this.recognizer !== void 0) {
8653
+ if (this.stopPromise) {
8654
+ return this.stopPromise;
8655
+ }
8656
+ this.clearAuthorizationRefreshTimer();
8657
+ const recognizer = this.recognizer;
8658
+ if (!recognizer) {
8659
+ return;
8660
+ }
8661
+ this.recognizer = void 0;
8662
+ this.stopPromise = this.stopRecognizer(recognizer).finally(() => {
8663
+ this.stopPromise = void 0;
8664
+ document.dispatchEvent(
8665
+ new CustomEvent("COAzureSTTStoppedRecording", {})
8666
+ );
8667
+ });
8668
+ return this.stopPromise;
8669
+ }
8670
+ scheduleAuthorizationRefresh() {
8671
+ this.clearAuthorizationRefreshTimer();
8672
+ this.authorizationRefreshTimer = setTimeout(async () => {
8673
+ if (!this.recognizer) {
8674
+ return;
8675
+ }
8598
8676
  try {
8599
- this.recognizer.stopContinuousRecognitionAsync();
8600
- } catch {
8677
+ const authorization = await this.authorizationManager.refreshAuthorization();
8678
+ if (!this.recognizer) {
8679
+ return;
8680
+ }
8681
+ this.recognizer.authorizationToken = authorization.token;
8682
+ this.region = authorization.region;
8683
+ this.scheduleAuthorizationRefresh();
8684
+ } catch (error) {
8685
+ this.dispatchError(error, "TOKEN_REFRESH_ERROR");
8686
+ await this.stop();
8601
8687
  }
8688
+ }, this.authorizationRefreshIntervalMs);
8689
+ }
8690
+ clearAuthorizationRefreshTimer() {
8691
+ if (!this.authorizationRefreshTimer) {
8692
+ return;
8693
+ }
8694
+ clearTimeout(this.authorizationRefreshTimer);
8695
+ this.authorizationRefreshTimer = void 0;
8696
+ }
8697
+ stopRecognizer(recognizer) {
8698
+ return new Promise((resolve) => {
8699
+ let closed = false;
8700
+ const closeOnce = () => {
8701
+ if (closed) {
8702
+ resolve();
8703
+ return;
8704
+ }
8705
+ closed = true;
8706
+ try {
8707
+ recognizer.close();
8708
+ } catch {
8709
+ } finally {
8710
+ resolve();
8711
+ }
8712
+ };
8602
8713
  try {
8603
- this.recognizer.close();
8714
+ recognizer.stopContinuousRecognitionAsync(
8715
+ () => {
8716
+ closeOnce();
8717
+ },
8718
+ () => {
8719
+ closeOnce();
8720
+ }
8721
+ );
8604
8722
  } catch {
8723
+ closeOnce();
8605
8724
  }
8606
- this.recognizer = void 0;
8607
- }
8608
- document.dispatchEvent(new CustomEvent("COAzureSTTStoppedRecording", {}));
8725
+ });
8609
8726
  }
8610
8727
  dispatchError(error, code) {
8611
8728
  const detail = toSafeErrorDetail(error);
@@ -8623,7 +8740,7 @@ class SpeechToText {
8623
8740
  }
8624
8741
  class TextToSpeech {
8625
8742
  constructor(options) {
8626
- __publicField(this, "region");
8743
+ __publicField(this, "region", "");
8627
8744
  __publicField(this, "voice");
8628
8745
  __publicField(this, "rate");
8629
8746
  __publicField(this, "pitch");
@@ -8650,16 +8767,16 @@ class TextToSpeech {
8650
8767
  __publicField(this, "activePrefetchedAudioUrl", "");
8651
8768
  __publicField(this, "playbackSegments", []);
8652
8769
  __publicField(this, "authorizationManager");
8653
- var _a, _b, _c, _d, _e;
8770
+ __publicField(this, "stopPromise");
8771
+ var _a, _b, _c;
8654
8772
  if (!options || typeof options.voice !== "string" || options.voice.trim() === "") {
8655
8773
  throw new Error("A voice is required.");
8656
8774
  }
8657
8775
  this.authorizationManager = new SpeechAuthorizationManager(options);
8658
- this.region = (_b = (_a = options.region) == null ? void 0 : _a.trim()) != null ? _b : "";
8659
8776
  this.voice = options.voice;
8660
- this.rate = (_c = options.rate) != null ? _c : 0;
8661
- this.pitch = (_d = options.pitch) != null ? _d : 0;
8662
- this.url = (_e = options.url) != null ? _e : "";
8777
+ this.rate = (_a = options.rate) != null ? _a : 0;
8778
+ this.pitch = (_b = options.pitch) != null ? _b : 0;
8779
+ this.url = (_c = options.url) != null ? _c : "";
8663
8780
  }
8664
8781
  async start() {
8665
8782
  await this.registerBindings(document);
@@ -8688,17 +8805,35 @@ class TextToSpeech {
8688
8805
  const currentNode = nodes[i];
8689
8806
  if (currentNode.attributes) {
8690
8807
  if (currentNode.attributes.getNamedItem("co-tts.id")) {
8691
- await this.handleIdModifier(currentNode, currentNode.attributes.getNamedItem("co-tts.id"));
8808
+ await this.handleIdModifier(
8809
+ currentNode,
8810
+ currentNode.attributes.getNamedItem("co-tts.id")
8811
+ );
8692
8812
  } else if (currentNode.attributes.getNamedItem("co-tts.ajax")) {
8693
- await this.handleAjaxModifier(currentNode, currentNode.attributes.getNamedItem("co-tts.ajax"));
8813
+ await this.handleAjaxModifier(
8814
+ currentNode,
8815
+ currentNode.attributes.getNamedItem("co-tts.ajax")
8816
+ );
8694
8817
  } else if (currentNode.attributes.getNamedItem("co-tts")) {
8695
- await this.handleDefault(currentNode, currentNode.attributes.getNamedItem("co-tts"));
8818
+ await this.handleDefault(
8819
+ currentNode,
8820
+ currentNode.attributes.getNamedItem("co-tts")
8821
+ );
8696
8822
  } else if (currentNode.attributes.getNamedItem("co-tts.stop")) {
8697
- await this.handleStopModifier(currentNode, currentNode.attributes.getNamedItem("co-tts.stop"));
8823
+ await this.handleStopModifier(
8824
+ currentNode,
8825
+ currentNode.attributes.getNamedItem("co-tts.stop")
8826
+ );
8698
8827
  } else if (currentNode.attributes.getNamedItem("co-tts.resume")) {
8699
- await this.handleResumeModifier(currentNode, currentNode.attributes.getNamedItem("co-tts.resume"));
8828
+ await this.handleResumeModifier(
8829
+ currentNode,
8830
+ currentNode.attributes.getNamedItem("co-tts.resume")
8831
+ );
8700
8832
  } else if (currentNode.attributes.getNamedItem("co-tts.pause")) {
8701
- await this.handlePauseModifier(currentNode, currentNode.attributes.getNamedItem("co-tts.pause"));
8833
+ await this.handlePauseModifier(
8834
+ currentNode,
8835
+ currentNode.attributes.getNamedItem("co-tts.pause")
8836
+ );
8702
8837
  }
8703
8838
  }
8704
8839
  if (currentNode.childNodes.length > 0) {
@@ -8708,8 +8843,8 @@ class TextToSpeech {
8708
8843
  }
8709
8844
  async handleIdModifier(node, attr) {
8710
8845
  node.addEventListener("click", async (_) => {
8711
- var _a, _b, _c, _d;
8712
- this.stopPlayer();
8846
+ var _a, _b, _c, _d, _e, _f;
8847
+ await this.stopPlayer();
8713
8848
  await this.createInterval();
8714
8849
  const referenceDiv = document.getElementById(attr.value);
8715
8850
  this.clickedNode = referenceDiv;
@@ -8722,10 +8857,11 @@ class TextToSpeech {
8722
8857
  this.textToRead = (_c = (_b = referenceDiv.innerText) != null ? _b : referenceDiv.textContent) != null ? _c : "";
8723
8858
  }
8724
8859
  if (referenceDiv.hasAttribute("co-tts.highlight")) {
8725
- if (((_d = referenceDiv.attributes.getNamedItem("co-tts.highlight")) == null ? void 0 : _d.value) !== "") {
8726
- const newReferenceDiv = document.getElementById(referenceDiv.attributes.getNamedItem("co-tts.highlight").value);
8860
+ const highlightTarget = (_e = (_d = referenceDiv.attributes.getNamedItem("co-tts.highlight")) == null ? void 0 : _d.value) != null ? _e : "";
8861
+ if (highlightTarget !== "") {
8862
+ const newReferenceDiv = document.getElementById(highlightTarget);
8727
8863
  this.highlightDiv = newReferenceDiv;
8728
- this.originalHighlightDivInnerHTML = newReferenceDiv.innerHTML;
8864
+ this.originalHighlightDivInnerHTML = (_f = newReferenceDiv == null ? void 0 : newReferenceDiv.innerHTML) != null ? _f : "";
8729
8865
  } else {
8730
8866
  this.highlightDiv = referenceDiv;
8731
8867
  this.originalHighlightDivInnerHTML = referenceDiv.innerHTML;
@@ -8736,7 +8872,7 @@ class TextToSpeech {
8736
8872
  }
8737
8873
  async handleAjaxModifier(node, attr) {
8738
8874
  node.addEventListener("click", async (_) => {
8739
- this.stopPlayer();
8875
+ await this.stopPlayer();
8740
8876
  await this.createInterval();
8741
8877
  this.clickedNode = node;
8742
8878
  const response = await fetch(attr.value, {
@@ -8748,22 +8884,23 @@ class TextToSpeech {
8748
8884
  }
8749
8885
  async handleDefault(node, attr) {
8750
8886
  node.addEventListener("click", async (_) => {
8751
- var _a, _b, _c;
8752
- this.stopPlayer();
8887
+ var _a, _b, _c, _d, _e;
8888
+ await this.stopPlayer();
8753
8889
  await this.createInterval();
8754
8890
  this.clickedNode = node;
8755
8891
  if (node.hasAttribute("co-tts.highlight")) {
8756
- if (((_a = node.attributes.getNamedItem("co-tts.highlight")) == null ? void 0 : _a.value) !== "") {
8757
- const newReferenceDiv = document.getElementById(node.attributes.getNamedItem("co-tts.highlight").value);
8892
+ const highlightTarget = (_b = (_a = node.attributes.getNamedItem("co-tts.highlight")) == null ? void 0 : _a.value) != null ? _b : "";
8893
+ if (highlightTarget !== "") {
8894
+ const newReferenceDiv = document.getElementById(highlightTarget);
8758
8895
  this.highlightDiv = newReferenceDiv;
8759
- this.originalHighlightDivInnerHTML = newReferenceDiv.innerHTML;
8896
+ this.originalHighlightDivInnerHTML = (_c = newReferenceDiv == null ? void 0 : newReferenceDiv.innerHTML) != null ? _c : "";
8760
8897
  } else {
8761
8898
  this.highlightDiv = node;
8762
8899
  this.originalHighlightDivInnerHTML = node.innerHTML;
8763
8900
  }
8764
8901
  }
8765
8902
  if (attr.value === "") {
8766
- this.textToRead = (_c = (_b = node.innerText) != null ? _b : node.textContent) != null ? _c : "";
8903
+ this.textToRead = (_e = (_d = node.innerText) != null ? _d : node.textContent) != null ? _e : "";
8767
8904
  } else {
8768
8905
  this.textToRead = attr.value;
8769
8906
  }
@@ -8772,12 +8909,14 @@ class TextToSpeech {
8772
8909
  }
8773
8910
  async handleWithoutClick(node, attr) {
8774
8911
  var _a, _b, _c;
8775
- this.stopPlayer();
8912
+ await this.stopPlayer();
8776
8913
  await this.createInterval();
8777
8914
  this.clickedNode = node;
8778
8915
  if (node.hasAttribute("co-tts.highlight")) {
8779
8916
  if (((_a = node.attributes.getNamedItem("co-tts.highlight")) == null ? void 0 : _a.value) !== "") {
8780
- const newReferenceDiv = document.getElementById(node.attributes.getNamedItem("co-tts.highlight").value);
8917
+ const newReferenceDiv = document.getElementById(
8918
+ node.attributes.getNamedItem("co-tts.highlight").value
8919
+ );
8781
8920
  this.highlightDiv = newReferenceDiv;
8782
8921
  if (newReferenceDiv !== null) {
8783
8922
  this.originalHighlightDivInnerHTML = newReferenceDiv.innerHTML;
@@ -8794,52 +8933,86 @@ class TextToSpeech {
8794
8933
  }
8795
8934
  await this.startSynthesizer(node, attr);
8796
8935
  }
8797
- async handleStopModifier(node, attr) {
8936
+ async handleStopModifier(node, _attr) {
8798
8937
  node.addEventListener("click", async (_) => {
8799
8938
  await this.stopPlayer();
8800
8939
  document.dispatchEvent(new CustomEvent("COAzureTTSStoppedPlaying", {}));
8801
8940
  });
8802
8941
  }
8803
- async handlePauseModifier(node, attr) {
8942
+ async handlePauseModifier(node, _attr) {
8804
8943
  node.addEventListener("click", async (_) => {
8944
+ if (!this.player || typeof this.player.pause !== "function") {
8945
+ return;
8946
+ }
8805
8947
  await this.clearInterval();
8806
8948
  await this.player.pause();
8807
8949
  document.dispatchEvent(new CustomEvent("COAzureTTSPausedPlaying", {}));
8808
8950
  });
8809
8951
  }
8810
- async handleResumeModifier(node, attr) {
8952
+ async handleResumeModifier(node, _attr) {
8811
8953
  node.addEventListener("click", async (_) => {
8954
+ if (!this.player) {
8955
+ return;
8956
+ }
8812
8957
  await this.createInterval();
8813
- await this.player.resume();
8958
+ if (typeof this.player.resume === "function") {
8959
+ await this.player.resume();
8960
+ } else if (typeof this.player.play === "function") {
8961
+ await this.player.play();
8962
+ } else {
8963
+ return;
8964
+ }
8814
8965
  document.dispatchEvent(new CustomEvent("COAzureTTSResumedPlaying", {}));
8815
8966
  });
8816
8967
  }
8817
8968
  async stopPlayer() {
8969
+ if (this.stopPromise) {
8970
+ return this.stopPromise;
8971
+ }
8972
+ this.stopPromise = this.performStopPlayer().finally(() => {
8973
+ this.stopPromise = void 0;
8974
+ });
8975
+ return this.stopPromise;
8976
+ }
8977
+ async performStopPlayer() {
8818
8978
  await this.clearInterval();
8819
8979
  if (this.highlightDiv !== void 0) {
8820
8980
  this.highlightDiv.innerHTML = this.originalHighlightDivInnerHTML;
8821
8981
  }
8982
+ this.resetPlaybackSegments();
8983
+ const player = this.player;
8984
+ const activePrefetchedAudioUrl = this.activePrefetchedAudioUrl;
8985
+ const synthesizer = this.synthesizer;
8822
8986
  this.textToRead = "";
8823
8987
  this.currentWord = "";
8824
8988
  this.originalHighlightDivInnerHTML = "";
8825
8989
  this.wordBoundryList = [];
8826
8990
  this.wordEncounters = [];
8827
- this.resetPlaybackSegments();
8828
8991
  this.playbackSegments = [];
8829
- if (this.player !== void 0) {
8830
- this.player.pause();
8831
- }
8832
- if (this.activePrefetchedAudioUrl !== "") {
8833
- URL.revokeObjectURL(this.activePrefetchedAudioUrl);
8834
- this.activePrefetchedAudioUrl = "";
8835
- }
8836
- this.closeSynthesizer();
8837
- this.player = void 0;
8838
- this.audioConfig = void 0;
8839
- this.speechConfig = void 0;
8840
8992
  this.highlightDiv = void 0;
8841
8993
  this.prevTextOffset = 0;
8842
8994
  this.playbackTextOffsetBase = void 0;
8995
+ this.audioConfig = void 0;
8996
+ this.speechConfig = void 0;
8997
+ if (this.player === player) {
8998
+ this.player = void 0;
8999
+ }
9000
+ if (this.activePrefetchedAudioUrl === activePrefetchedAudioUrl) {
9001
+ this.activePrefetchedAudioUrl = "";
9002
+ }
9003
+ if (this.synthesizer === synthesizer) {
9004
+ this.synthesizer = void 0;
9005
+ }
9006
+ if (player !== void 0 && typeof player.pause === "function") {
9007
+ try {
9008
+ player.pause();
9009
+ } catch {
9010
+ }
9011
+ }
9012
+ if (activePrefetchedAudioUrl !== "") {
9013
+ URL.revokeObjectURL(activePrefetchedAudioUrl);
9014
+ }
9015
+ this.closeResource(synthesizer);
8843
9016
  }
8844
9017
  async createSpeechConfig() {
8845
9018
  const authorization = await this.authorizationManager.getAuthorization();
@@ -8852,13 +9025,13 @@ class TextToSpeech {
8852
9025
  this.region = authorization.region;
8853
9026
  return speechConfig;
8854
9027
  }
8855
- async startSynthesizer(node, attr) {
9028
+ async startSynthesizer(_node, _attr) {
8856
9029
  try {
8857
9030
  this.speechConfig = await this.createSpeechConfig();
8858
9031
  this.player = new SpeakerAudioDestination();
8859
9032
  this.audioConfig = AudioConfig.fromSpeakerOutput(this.player);
8860
9033
  this.synthesizer = new SpeechSynthesizer(this.speechConfig, this.audioConfig);
8861
- this.synthesizer.wordBoundary = (s, e) => {
9034
+ this.synthesizer.wordBoundary = (_s, e) => {
8862
9035
  this.wordBoundryList.push(e);
8863
9036
  };
8864
9037
  const playbackChain = this.collectPlaybackChain(this.clickedNode);
@@ -8869,19 +9042,23 @@ class TextToSpeech {
8869
9042
  this.playbackSegments = [];
8870
9043
  }
8871
9044
  this.player.onAudioEnd = async () => {
9045
+ var _a;
9046
+ const clickedNode = this.clickedNode;
8872
9047
  const wasChainedPlayback = this.playbackSegments.length > 0;
8873
- this.stopPlayer();
9048
+ const nextNodeId = ((_a = clickedNode == null ? void 0 : clickedNode.hasAttribute) == null ? void 0 : _a.call(clickedNode, "co-tts.next")) ? clickedNode.getAttribute("co-tts.next") : null;
9049
+ await this.stopPlayer();
8874
9050
  if (wasChainedPlayback) {
8875
9051
  document.dispatchEvent(new CustomEvent("COAzureTTSFinishedPlaying", {}));
8876
9052
  return;
8877
9053
  }
8878
- if (this.clickedNode.hasAttribute("co-tts.next")) {
8879
- const nextNode = document.getElementById(this.clickedNode.getAttribute("co-tts.next"));
9054
+ if (nextNodeId) {
9055
+ const nextNode = document.getElementById(nextNodeId);
8880
9056
  if (nextNode && await this.playPrefetchedNode(nextNode)) {
8881
9057
  return;
8882
9058
  }
8883
- if (nextNode && nextNode.attributes.getNamedItem("co-tts.text")) {
8884
- this.handleWithoutClick(nextNode, nextNode.attributes.getNamedItem("co-tts.text"));
9059
+ const nextTextAttr = nextNode == null ? void 0 : nextNode.attributes.getNamedItem("co-tts.text");
9060
+ if (nextNode && nextTextAttr) {
9061
+ await this.handleWithoutClick(nextNode, nextTextAttr);
8885
9062
  } else if (nextNode) {
8886
9063
  nextNode.dispatchEvent(new Event("click"));
8887
9064
  }
@@ -8893,7 +9070,7 @@ class TextToSpeech {
8893
9070
  document.dispatchEvent(new CustomEvent("COAzureTTSStartedPlaying", {}));
8894
9071
  };
8895
9072
  if (!isChainedPlayback) {
8896
- this.prefetchNextNode(this.clickedNode);
9073
+ void this.prefetchNextNode(this.clickedNode);
8897
9074
  }
8898
9075
  this.synthesizer.speakSsmlAsync(
8899
9076
  this.buildSSML(this.textToRead),
@@ -8901,12 +9078,18 @@ class TextToSpeech {
8901
9078
  this.closeSynthesizer();
8902
9079
  },
8903
9080
  (error) => {
9081
+ if (isLikelyAuthorizationError(error)) {
9082
+ this.authorizationManager.clearAuthorization();
9083
+ }
8904
9084
  this.dispatchError(error, "SYNTHESIS_ERROR");
8905
9085
  this.closeSynthesizer();
8906
- this.stopPlayer();
9086
+ void this.stopPlayer();
8907
9087
  }
8908
9088
  );
8909
9089
  } catch (error) {
9090
+ if (isLikelyAuthorizationError(error)) {
9091
+ this.authorizationManager.clearAuthorization();
9092
+ }
8910
9093
  this.dispatchError(error);
8911
9094
  await this.stopPlayer();
8912
9095
  }
@@ -8960,7 +9143,9 @@ class TextToSpeech {
8960
9143
  return void 0;
8961
9144
  }
8962
9145
  if (((_a = node.attributes.getNamedItem("co-tts.highlight")) == null ? void 0 : _a.value) !== "") {
8963
- return document.getElementById(node.attributes.getNamedItem("co-tts.highlight").value);
9146
+ return document.getElementById(
9147
+ node.attributes.getNamedItem("co-tts.highlight").value
9148
+ );
8964
9149
  }
8965
9150
  return node;
8966
9151
  }
@@ -8972,7 +9157,7 @@ class TextToSpeech {
8972
9157
  });
8973
9158
  }
8974
9159
  updateChainedHighlight(wordBoundary) {
8975
- var _a;
9160
+ var _a, _b;
8976
9161
  if (~[".", ",", "!", "?", "*", "(", ")", "&", "\\", "/", "^", "[", "]", "<", ">", ":"].indexOf(wordBoundary.text)) {
8977
9162
  wordBoundary = (_a = this.previousWordBoundary) != null ? _a : void 0;
8978
9163
  }
@@ -8983,7 +9168,10 @@ class TextToSpeech {
8983
9168
  if (this.playbackTextOffsetBase === void 0) {
8984
9169
  this.playbackTextOffsetBase = wordBoundary.textOffset;
8985
9170
  }
8986
- const normalizedTextOffset = Math.max(0, wordBoundary.textOffset - this.playbackTextOffsetBase);
9171
+ const normalizedTextOffset = Math.max(
9172
+ 0,
9173
+ wordBoundary.textOffset - ((_b = this.playbackTextOffsetBase) != null ? _b : 0)
9174
+ );
8987
9175
  const segment = this.playbackSegments.find((candidate) => normalizedTextOffset >= candidate.start && normalizedTextOffset < candidate.end);
8988
9176
  this.resetPlaybackSegments();
8989
9177
  if (!(segment == null ? void 0 : segment.highlightDiv)) {
@@ -8991,7 +9179,11 @@ class TextToSpeech {
8991
9179
  return;
8992
9180
  }
8993
9181
  const relativeTextOffset = normalizedTextOffset - segment.start;
8994
- const currentOffset = this.getPosition(segment.originalHighlightDivInnerHTML, wordBoundary.text, relativeTextOffset);
9182
+ const currentOffset = this.getPosition(
9183
+ segment.originalHighlightDivInnerHTML,
9184
+ wordBoundary.text,
9185
+ relativeTextOffset
9186
+ );
8995
9187
  if (currentOffset === Number.MAX_SAFE_INTEGER) {
8996
9188
  this.previousWordBoundary = wordBoundary;
8997
9189
  return;
@@ -9055,9 +9247,9 @@ class TextToSpeech {
9055
9247
  const prefetchPromise = (async () => {
9056
9248
  try {
9057
9249
  const speechConfig = await this.createSpeechConfig();
9058
- synthesizer = new SpeechSynthesizer(speechConfig, null);
9250
+ synthesizer = new SpeechSynthesizer(speechConfig, void 0);
9059
9251
  const wordBoundryList = [];
9060
- synthesizer.wordBoundary = (s, e) => {
9252
+ synthesizer.wordBoundary = (_s, e) => {
9061
9253
  wordBoundryList.push(e);
9062
9254
  };
9063
9255
  return await new Promise((resolve) => {
@@ -9085,6 +9277,9 @@ class TextToSpeech {
9085
9277
  (error) => {
9086
9278
  this.closeResource(synthesizer);
9087
9279
  synthesizer = void 0;
9280
+ if (isLikelyAuthorizationError(error)) {
9281
+ this.authorizationManager.clearAuthorization();
9282
+ }
9088
9283
  this.dispatchError(error, "PREFETCH_ERROR");
9089
9284
  resolve(null);
9090
9285
  }
@@ -9093,6 +9288,9 @@ class TextToSpeech {
9093
9288
  } catch (error) {
9094
9289
  this.closeResource(synthesizer);
9095
9290
  synthesizer = void 0;
9291
+ if (isLikelyAuthorizationError(error)) {
9292
+ this.authorizationManager.clearAuthorization();
9293
+ }
9096
9294
  this.dispatchError(error);
9097
9295
  return null;
9098
9296
  }
@@ -9122,7 +9320,9 @@ class TextToSpeech {
9122
9320
  this.wordBoundaryOffset = 0;
9123
9321
  if (node.hasAttribute("co-tts.highlight")) {
9124
9322
  if (((_c = node.attributes.getNamedItem("co-tts.highlight")) == null ? void 0 : _c.value) !== "") {
9125
- const newReferenceDiv = document.getElementById(node.attributes.getNamedItem("co-tts.highlight").value);
9323
+ const newReferenceDiv = document.getElementById(
9324
+ node.attributes.getNamedItem("co-tts.highlight").value
9325
+ );
9126
9326
  this.highlightDiv = newReferenceDiv;
9127
9327
  if (newReferenceDiv !== null) {
9128
9328
  this.originalHighlightDivInnerHTML = newReferenceDiv.innerHTML;
@@ -9141,14 +9341,18 @@ class TextToSpeech {
9141
9341
  document.dispatchEvent(new CustomEvent("COAzureTTSStartedPlaying", {}));
9142
9342
  }, { once: true });
9143
9343
  audio.addEventListener("ended", async () => {
9144
- this.stopPlayer();
9145
- if (this.clickedNode.hasAttribute("co-tts.next")) {
9146
- const nextNode = document.getElementById(this.clickedNode.getAttribute("co-tts.next"));
9344
+ var _a2;
9345
+ const clickedNode = this.clickedNode;
9346
+ const nextNodeId = ((_a2 = clickedNode == null ? void 0 : clickedNode.hasAttribute) == null ? void 0 : _a2.call(clickedNode, "co-tts.next")) ? clickedNode.getAttribute("co-tts.next") : null;
9347
+ await this.stopPlayer();
9348
+ if (nextNodeId) {
9349
+ const nextNode = document.getElementById(nextNodeId);
9147
9350
  if (nextNode && await this.playPrefetchedNode(nextNode)) {
9148
9351
  return;
9149
9352
  }
9150
- if (nextNode && nextNode.attributes.getNamedItem("co-tts.text")) {
9151
- this.handleWithoutClick(nextNode, nextNode.attributes.getNamedItem("co-tts.text"));
9353
+ const nextTextAttr = nextNode == null ? void 0 : nextNode.attributes.getNamedItem("co-tts.text");
9354
+ if (nextNode && nextTextAttr) {
9355
+ await this.handleWithoutClick(nextNode, nextTextAttr);
9152
9356
  } else if (nextNode) {
9153
9357
  nextNode.dispatchEvent(new Event("click"));
9154
9358
  }
@@ -9161,9 +9365,9 @@ class TextToSpeech {
9161
9365
  new Error("Prefetched audio resource closed unexpectedly."),
9162
9366
  "AUDIO_RESOURCE_ERROR"
9163
9367
  );
9164
- this.stopPlayer();
9368
+ void this.stopPlayer();
9165
9369
  }, { once: true });
9166
- this.prefetchNextNode(node);
9370
+ void this.prefetchNextNode(node);
9167
9371
  await audio.play();
9168
9372
  return true;
9169
9373
  } catch (error) {
@@ -9300,4 +9504,4 @@ class TextToSpeech {
9300
9504
  );
9301
9505
  }
9302
9506
  }
9303
- export { SpeechToText, TextToSpeech };
9507
+ export { DEFAULT_TOKEN_LIFETIME_MS, SpeechAuthorizationManager, SpeechToText, TextToSpeech, createSpeechAuthorizationProvider, isLikelyAuthorizationError, sanitizeErrorText, toSafeErrorDetail, validateSpeechAuthorization };