ssml-builder-js 2.10.0 → 2.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/elements.mjs CHANGED
@@ -36,7 +36,7 @@ import {
36
36
  resolveExpressAsStyles,
37
37
  updateEditableText,
38
38
  validateAzureSsml
39
- } from "./chunk-BYIZQL2W.mjs";
39
+ } from "./chunk-FWWMWI2C.mjs";
40
40
  import "./chunk-6S5ODO6A.mjs";
41
41
 
42
42
  // packages/ssml-editor-react/src/ssmlInsertions.ts
package/dist/index.d.mts CHANGED
@@ -44,4 +44,29 @@ declare class AzureTtsClient {
44
44
 
45
45
  declare function synthesizeSpeech(ssml: string, config: TtsConfig): Promise<ArrayBuffer>;
46
46
 
47
- export { AzureTtsClient, type AzureTtsClientOptions, AzureTtsError, type AzureTtsLogger, AzureTtsSdkError, type TtsConfig, synthesizeSpeech };
47
+ interface FetchAzureVoiceCatalogOptions {
48
+ apiKey: string;
49
+ region: string | string[];
50
+ }
51
+ interface AzureVoiceCatalogVoice {
52
+ name: string;
53
+ locale: string;
54
+ secondaryLocales?: readonly string[];
55
+ styles?: readonly string[];
56
+ regions: readonly string[];
57
+ status?: "ga" | "preview" | "deprecated";
58
+ }
59
+ interface FetchedAzureVoiceCatalogMetadata {
60
+ voiceCount: number;
61
+ generatedAt: string;
62
+ apiVersion: string;
63
+ regions: readonly string[];
64
+ }
65
+ interface AzureVoiceCatalog {
66
+ voices: readonly AzureVoiceCatalogVoice[];
67
+ metadata: FetchedAzureVoiceCatalogMetadata;
68
+ }
69
+ /** Fetches and deduplicates the current Azure Speech voice catalog for one or more regions. */
70
+ declare function fetchAzureVoiceCatalog(options: FetchAzureVoiceCatalogOptions): Promise<AzureVoiceCatalog>;
71
+
72
+ export { AzureTtsClient, type AzureTtsClientOptions, AzureTtsError, type AzureTtsLogger, AzureTtsSdkError, type AzureVoiceCatalog, type AzureVoiceCatalogVoice, type FetchAzureVoiceCatalogOptions, type FetchedAzureVoiceCatalogMetadata, type TtsConfig, fetchAzureVoiceCatalog, synthesizeSpeech };
package/dist/index.d.ts CHANGED
@@ -44,4 +44,29 @@ declare class AzureTtsClient {
44
44
 
45
45
  declare function synthesizeSpeech(ssml: string, config: TtsConfig): Promise<ArrayBuffer>;
46
46
 
47
- export { AzureTtsClient, type AzureTtsClientOptions, AzureTtsError, type AzureTtsLogger, AzureTtsSdkError, type TtsConfig, synthesizeSpeech };
47
+ interface FetchAzureVoiceCatalogOptions {
48
+ apiKey: string;
49
+ region: string | string[];
50
+ }
51
+ interface AzureVoiceCatalogVoice {
52
+ name: string;
53
+ locale: string;
54
+ secondaryLocales?: readonly string[];
55
+ styles?: readonly string[];
56
+ regions: readonly string[];
57
+ status?: "ga" | "preview" | "deprecated";
58
+ }
59
+ interface FetchedAzureVoiceCatalogMetadata {
60
+ voiceCount: number;
61
+ generatedAt: string;
62
+ apiVersion: string;
63
+ regions: readonly string[];
64
+ }
65
+ interface AzureVoiceCatalog {
66
+ voices: readonly AzureVoiceCatalogVoice[];
67
+ metadata: FetchedAzureVoiceCatalogMetadata;
68
+ }
69
+ /** Fetches and deduplicates the current Azure Speech voice catalog for one or more regions. */
70
+ declare function fetchAzureVoiceCatalog(options: FetchAzureVoiceCatalogOptions): Promise<AzureVoiceCatalog>;
71
+
72
+ export { AzureTtsClient, type AzureTtsClientOptions, AzureTtsError, type AzureTtsLogger, AzureTtsSdkError, type AzureVoiceCatalog, type AzureVoiceCatalogVoice, type FetchAzureVoiceCatalogOptions, type FetchedAzureVoiceCatalogMetadata, type TtsConfig, fetchAzureVoiceCatalog, synthesizeSpeech };
package/dist/index.js CHANGED
@@ -45,6 +45,7 @@ __export(src_exports, {
45
45
  buildSsml: () => buildSsml,
46
46
  extractSsmlText: () => extractSsmlText,
47
47
  extractSsmlTranslatableText: () => extractSsmlTranslatableText,
48
+ fetchAzureVoiceCatalog: () => fetchAzureVoiceCatalog,
48
49
  fromPlainTextToSsml: () => fromPlainTextToSsml,
49
50
  getAzureVoiceCatalogMetadata: () => getAzureVoiceCatalogMetadata,
50
51
  getBuiltInVoiceCatalogMetadata: () => getBuiltInVoiceCatalogMetadata,
@@ -1501,6 +1502,9 @@ var AZURE_VOICE_DEFINITIONS = [
1501
1502
  },
1502
1503
  { name: "es-ES-ElviraNeural", locale: "es-ES" },
1503
1504
  { name: "fil-PH-AngeloNeural", locale: "fil-PH" },
1505
+ { name: "fil-PH-Angelo:DragonHDLatestNeural", locale: "fil-PH" },
1506
+ { name: "fil-PH-BlessicaNeural", locale: "fil-PH" },
1507
+ { name: "fil-PH-Blessica:DragonHDLatestNeural", locale: "fil-PH" },
1504
1508
  { name: "fr-FR-DeniseNeural", locale: "fr-FR", styles: ["cheerful", "sad"] },
1505
1509
  { name: "fr-FR-HenriNeural", locale: "fr-FR", styles: ["cheerful", "sad"] },
1506
1510
  { name: "id-ID-GadisNeural", locale: "id-ID" },
@@ -1597,6 +1601,18 @@ var ALLOWED_SILENCE_TYPES = /* @__PURE__ */ new Set([
1597
1601
  "Enumerationcomma"
1598
1602
  ]);
1599
1603
  var ALLOWED_VISEME_TYPES = /* @__PURE__ */ new Set(["redlips_front", "FacialExpression"]);
1604
+ var DEFAULT_PREVIEW_TAGS = /* @__PURE__ */ new Set(["mstts:voiceconversion"]);
1605
+ function featureStatusForTag(name, options) {
1606
+ const tagName = canonicalTagName(name);
1607
+ const configured = Object.entries(options.tagStatuses ?? {}).find(
1608
+ ([candidate]) => canonicalTagName(candidate) === tagName
1609
+ )?.[1];
1610
+ if (configured) return configured;
1611
+ if ((options.previewTags ?? [...DEFAULT_PREVIEW_TAGS]).some((candidate) => canonicalTagName(candidate) === tagName))
1612
+ return "preview";
1613
+ if ((options.deprecatedTags ?? []).some((candidate) => canonicalTagName(candidate) === tagName)) return "deprecated";
1614
+ return void 0;
1615
+ }
1600
1616
  function decodeAttribute(value) {
1601
1617
  return value.replace(
1602
1618
  /&(?:amp|apos|gt|lt|quot);/gi,
@@ -1713,9 +1729,9 @@ function isValidAzureAudioDuration(value) {
1713
1729
  return Number(clock[1]) > 0 || Number(clock[2]) > 0 || Number(clock[3]) > 0 || Number(clock[4] ?? 0) > 0;
1714
1730
  }
1715
1731
  function isValidAzureBackgroundAudioDuration(value) {
1716
- const match = /^(\d+(?:\.\d+)?)(ms|s)?$/i.exec(value.trim());
1732
+ const match = /^(\d+)$/.exec(value.trim());
1717
1733
  if (!match) return false;
1718
- const milliseconds = Number(match[1]) * (match[2]?.toLowerCase() === "s" ? 1e3 : 1);
1734
+ const milliseconds = Number(match[1]);
1719
1735
  return Number.isFinite(milliseconds) && milliseconds >= 0 && milliseconds <= 1e4;
1720
1736
  }
1721
1737
  function attr(token, name) {
@@ -1876,6 +1892,25 @@ function validateAudioSource(token, source, diagnostics, options, elementName2)
1876
1892
  }
1877
1893
  function validateElement(token, source, diagnostics, voiceName, options, voiceCatalog) {
1878
1894
  const name = token.name.toLowerCase();
1895
+ const tagStatus = featureStatusForTag(token.name, options);
1896
+ if (tagStatus === "preview")
1897
+ addDiagnostic(
1898
+ diagnostics,
1899
+ source,
1900
+ token.start,
1901
+ `<${token.name}> is an Azure Speech preview feature and may change or require preview access.`,
1902
+ "warning",
1903
+ "azure-preview-tag"
1904
+ );
1905
+ if (tagStatus === "deprecated")
1906
+ addDiagnostic(
1907
+ diagnostics,
1908
+ source,
1909
+ token.start,
1910
+ `<${token.name}> is deprecated by Azure Speech; migrate to a supported alternative.`,
1911
+ "info",
1912
+ "azure-deprecated-tag"
1913
+ );
1879
1914
  if (name === "voice" && !attr(token, "name")?.trim())
1880
1915
  addDiagnostic(diagnostics, source, token.start, '<voice> requires a non-empty "name" attribute.');
1881
1916
  if (name === "break") {
@@ -2087,6 +2122,24 @@ function validateAzureSsml(ssml, options = {}) {
2087
2122
  const name = attr(token, "name")?.trim();
2088
2123
  const language = attr(token, "xml:lang")?.trim() || (speak ? attr(speak, "xml:lang")?.trim() : void 0);
2089
2124
  const definition = name ? voiceCatalog.get(name.toLowerCase()) : void 0;
2125
+ if (name && definition?.status === "preview")
2126
+ addDiagnostic(
2127
+ diagnostics,
2128
+ ssml,
2129
+ token.start,
2130
+ `Voice "${name}" is an Azure Speech preview voice and may change or require preview access.`,
2131
+ "warning",
2132
+ "azure-preview-voice"
2133
+ );
2134
+ if (name && definition?.status === "deprecated")
2135
+ addDiagnostic(
2136
+ diagnostics,
2137
+ ssml,
2138
+ token.start,
2139
+ `Voice "${name}" is deprecated by Azure Speech; migrate to a supported voice.`,
2140
+ "info",
2141
+ "azure-deprecated-voice"
2142
+ );
2090
2143
  if (name && !definition && policySeverity)
2091
2144
  addDiagnostic(
2092
2145
  diagnostics,
@@ -2324,6 +2377,84 @@ var AzureTtsClient = class {
2324
2377
  }
2325
2378
  };
2326
2379
  _options = new WeakMap();
2380
+
2381
+ // packages/azure-tts-client/src/voiceCatalog.ts
2382
+ var AZURE_VOICE_API_VERSION = "2025-10-01";
2383
+ function stringValue(value) {
2384
+ return typeof value === "string" && value.trim() ? value.trim() : void 0;
2385
+ }
2386
+ function stringList(value) {
2387
+ if (!Array.isArray(value)) return [];
2388
+ return [...new Set(value.map(stringValue).filter((item) => item !== void 0))];
2389
+ }
2390
+ function normalizeStatus(value) {
2391
+ const status = stringValue(value)?.toLowerCase();
2392
+ if (status === "preview" || status === "deprecated" || status === "ga") return status;
2393
+ return void 0;
2394
+ }
2395
+ function normalizeRegions(region) {
2396
+ const regions = Array.isArray(region) ? region : [region];
2397
+ const result = [...new Set(regions.map((item) => item.trim()).filter(Boolean))];
2398
+ if (result.length === 0) throw new TypeError("At least one Azure Speech region is required.");
2399
+ return result;
2400
+ }
2401
+ async function fetchRegionVoices(region, apiKey) {
2402
+ const endpoint = `https://${encodeURIComponent(region)}.tts.speech.microsoft.com/cognitiveservices/voices/list`;
2403
+ const response = await fetch(endpoint, {
2404
+ headers: {
2405
+ Accept: "application/json",
2406
+ "Ocp-Apim-Subscription-Key": apiKey
2407
+ }
2408
+ });
2409
+ if (!response.ok) {
2410
+ throw new Error(`Azure List Voices API request failed for region "${region}" with HTTP ${response.status}.`);
2411
+ }
2412
+ const payload = await response.json();
2413
+ if (!Array.isArray(payload)) throw new Error(`Azure List Voices API returned an invalid response for "${region}".`);
2414
+ return payload.filter((item) => Boolean(item && typeof item === "object"));
2415
+ }
2416
+ async function fetchAzureVoiceCatalog(options) {
2417
+ if (!options || typeof options.apiKey !== "string" || !options.apiKey.trim())
2418
+ throw new TypeError("An Azure Speech API key is required.");
2419
+ const regions = normalizeRegions(options.region);
2420
+ const payloads = await Promise.all(regions.map((region) => fetchRegionVoices(region, options.apiKey)));
2421
+ const voices = /* @__PURE__ */ new Map();
2422
+ for (let regionIndex = 0; regionIndex < payloads.length; regionIndex += 1) {
2423
+ const region = regions[regionIndex];
2424
+ for (const record of payloads[regionIndex]) {
2425
+ const name = stringValue(record.ShortName) ?? stringValue(record.Name);
2426
+ const locale = stringValue(record.Locale);
2427
+ if (!name || !locale) continue;
2428
+ const key = name.toLowerCase();
2429
+ const existing = voices.get(key);
2430
+ const secondaryLocales = stringList(record.SecondaryLocaleList);
2431
+ const styles = stringList(record.StyleList);
2432
+ const status = normalizeStatus(record.Status);
2433
+ const merged = {
2434
+ name: existing?.name ?? name,
2435
+ locale: existing?.locale ?? locale,
2436
+ regions: [.../* @__PURE__ */ new Set([...existing?.regions ?? [], region])]
2437
+ };
2438
+ const mergedSecondaryLocales = [.../* @__PURE__ */ new Set([...existing?.secondaryLocales ?? [], ...secondaryLocales])];
2439
+ if (mergedSecondaryLocales.length > 0) merged.secondaryLocales = mergedSecondaryLocales;
2440
+ const mergedStyles = [.../* @__PURE__ */ new Set([...existing?.styles ?? [], ...styles])];
2441
+ if (mergedStyles.length > 0) merged.styles = mergedStyles;
2442
+ if (status) merged.status = status;
2443
+ else if (existing?.status) merged.status = existing.status;
2444
+ voices.set(key, merged);
2445
+ }
2446
+ }
2447
+ const sortedVoices = [...voices.values()].sort((first, second) => first.name.localeCompare(second.name));
2448
+ return {
2449
+ voices: sortedVoices,
2450
+ metadata: {
2451
+ voiceCount: sortedVoices.length,
2452
+ generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
2453
+ apiVersion: AZURE_VOICE_API_VERSION,
2454
+ regions
2455
+ }
2456
+ };
2457
+ }
2327
2458
  // Annotate the CommonJS export names for ESM import in node:
2328
2459
  0 && (module.exports = {
2329
2460
  AzureTtsClient,
@@ -2334,6 +2465,7 @@ _options = new WeakMap();
2334
2465
  buildSsml,
2335
2466
  extractSsmlText,
2336
2467
  extractSsmlTranslatableText,
2468
+ fetchAzureVoiceCatalog,
2337
2469
  fromPlainTextToSsml,
2338
2470
  getAzureVoiceCatalogMetadata,
2339
2471
  getBuiltInVoiceCatalogMetadata,