@absolutejs/voice 0.0.22-beta.503 → 0.0.22-beta.504

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.
@@ -0,0 +1,42 @@
1
+ export type BrowserNoiseSuppressorOptions = {
2
+ /** Existing AudioContext to reuse. If omitted, a fresh one is created at 48kHz. */
3
+ audioContext?: AudioContext;
4
+ /** Optional message sent to the worklet via port.postMessage on init. */
5
+ initialPort?: Record<string, unknown>;
6
+ /** AudioWorkletNode options forwarded to the constructor. */
7
+ nodeOptions?: AudioWorkletNodeOptions;
8
+ /** Registered AudioWorkletProcessor name to instantiate. */
9
+ processorName: string;
10
+ /** Caller-supplied input stream from getUserMedia or similar. */
11
+ stream: MediaStream;
12
+ /** URL of the AudioWorklet script that registers `processorName`. */
13
+ workletUrl: string;
14
+ };
15
+ export type BrowserNoiseSuppressorHandle = {
16
+ /** The worklet node — operators can postMessage to tune at runtime. */
17
+ node: AudioWorkletNode;
18
+ /** A MediaStream containing the denoised audio track. */
19
+ stream: MediaStream;
20
+ /** Tears down the worklet + closes the AudioContext when this helper created it. */
21
+ stop: () => Promise<void>;
22
+ };
23
+ export declare const applyBrowserNoiseSuppression: (options: BrowserNoiseSuppressorOptions) => Promise<BrowserNoiseSuppressorHandle>;
24
+ export type BrowserNoiseSuppressorPreset = {
25
+ initialPort?: Record<string, unknown>;
26
+ /** Display label for UI affordances. */
27
+ label: string;
28
+ nodeOptions?: AudioWorkletNodeOptions;
29
+ processorName: string;
30
+ workletUrl: string;
31
+ };
32
+ /**
33
+ * Convenience presets pointing at well-known open-source worklets. Operators
34
+ * still install the underlying npm package and copy the worklet file to a
35
+ * URL their site can serve.
36
+ */
37
+ export declare const BROWSER_NOISE_SUPPRESSOR_PRESETS: {
38
+ /** DeepFilterNet 2023 model — best quality open-source pick. */
39
+ readonly deepfilternet: (workletUrl: string) => BrowserNoiseSuppressorPreset;
40
+ /** Jitsi @jitsi/rnnoise-wasm — ships a `rnnoise-processor` worklet. */
41
+ readonly rnnoise: (workletUrl: string) => BrowserNoiseSuppressorPreset;
42
+ };
package/dist/index.d.ts CHANGED
@@ -110,6 +110,8 @@ export { createInMemoryVoiceCallQuota } from "./callQuota";
110
110
  export type { CreateInMemoryVoiceCallQuotaOptions, VoiceCallQuota, VoiceCallQuotaRejection, VoiceCallQuotaResult, VoiceCallQuotaTier, VoiceCallReservation, } from "./callQuota";
111
111
  export { createVoiceBearerAuthVerifier, createVoiceHMACAuthVerifier, createVoiceRouteAuth, } from "./routeAuth";
112
112
  export type { VoiceRouteAuthDecision, VoiceRouteAuthInput, VoiceRouteAuthOptions, VoiceRouteAuthVerifier, } from "./routeAuth";
113
+ export { BROWSER_NOISE_SUPPRESSOR_PRESETS, applyBrowserNoiseSuppression, } from "./client/browserNoiseSuppression";
114
+ export type { BrowserNoiseSuppressorHandle, BrowserNoiseSuppressorOptions, BrowserNoiseSuppressorPreset, } from "./client/browserNoiseSuppression";
113
115
  export { buildVoiceHTMXAttributes, wrapVoiceHTMLInHTMXContainer, wrapVoiceHTMLWithHTMXPolling, } from "./client/htmxAttributes";
114
116
  export type { VoiceHTMXPollingAttributes } from "./client/htmxAttributes";
115
117
  export { createLiveCallViewerFromOptions, renderVoiceCostDashboardFromEvents, renderVoiceCostDashboardHTMX, renderVoiceLiveCallViewerFromState, renderVoiceLiveCallViewerFromViewer, renderVoiceLiveCallViewerHTMX, renderVoiceReplayTimelineFromArtifact, renderVoiceReplayTimelineHTMX, resolveVoiceDashboardRenderers, } from "./client/htmxDashboardRenderers";
package/dist/index.js CHANGED
@@ -7017,13 +7017,13 @@ var getCampaignWindowMinute = (at, offsetMinutes = 0) => {
7017
7017
  minuteOfDay: date.getUTCHours() * 60 + date.getUTCMinutes()
7018
7018
  };
7019
7019
  };
7020
- var isWithinCampaignTimeWindow = (window, at) => {
7021
- const { dayOfWeek, minuteOfDay } = getCampaignWindowMinute(at, window.timeZoneOffsetMinutes ?? 0);
7022
- if (window.daysOfWeek && !window.daysOfWeek.includes(dayOfWeek)) {
7020
+ var isWithinCampaignTimeWindow = (window2, at) => {
7021
+ const { dayOfWeek, minuteOfDay } = getCampaignWindowMinute(at, window2.timeZoneOffsetMinutes ?? 0);
7022
+ if (window2.daysOfWeek && !window2.daysOfWeek.includes(dayOfWeek)) {
7023
7023
  return false;
7024
7024
  }
7025
- const start = normalizeHour(window.startHour) * 60;
7026
- const end = normalizeHour(window.endHour) * 60;
7025
+ const start = normalizeHour(window2.startHour) * 60;
7026
+ const end = normalizeHour(window2.endHour) * 60;
7027
7027
  if (start === end) {
7028
7028
  return true;
7029
7029
  }
@@ -36781,6 +36781,59 @@ var createVoiceRouteAuth = (options) => {
36781
36781
  }
36782
36782
  });
36783
36783
  };
36784
+ // src/client/browserNoiseSuppression.ts
36785
+ var isBrowser = () => typeof window !== "undefined" && typeof window.AudioContext !== "undefined";
36786
+ var applyBrowserNoiseSuppression = async (options) => {
36787
+ if (!isBrowser()) {
36788
+ throw new Error("applyBrowserNoiseSuppression requires a browser environment with AudioContext");
36789
+ }
36790
+ const ownsContext = !options.audioContext;
36791
+ const audioContext = options.audioContext ?? new AudioContext({ sampleRate: 48000 });
36792
+ if (audioContext.state === "suspended") {
36793
+ try {
36794
+ await audioContext.resume();
36795
+ } catch {}
36796
+ }
36797
+ await audioContext.audioWorklet.addModule(options.workletUrl);
36798
+ const source = audioContext.createMediaStreamSource(options.stream);
36799
+ const node = new AudioWorkletNode(audioContext, options.processorName, options.nodeOptions);
36800
+ if (options.initialPort) {
36801
+ node.port.postMessage(options.initialPort);
36802
+ }
36803
+ const destination = audioContext.createMediaStreamDestination();
36804
+ source.connect(node);
36805
+ node.connect(destination);
36806
+ return {
36807
+ node,
36808
+ stop: async () => {
36809
+ try {
36810
+ node.disconnect();
36811
+ } catch {}
36812
+ try {
36813
+ source.disconnect();
36814
+ } catch {}
36815
+ try {
36816
+ destination.disconnect();
36817
+ } catch {}
36818
+ if (ownsContext) {
36819
+ await audioContext.close();
36820
+ }
36821
+ },
36822
+ stream: destination.stream
36823
+ };
36824
+ };
36825
+ var BROWSER_NOISE_SUPPRESSOR_PRESETS = {
36826
+ deepfilternet: (workletUrl) => ({
36827
+ label: "DeepFilterNet",
36828
+ processorName: "deepfilter-suppressor",
36829
+ workletUrl
36830
+ }),
36831
+ rnnoise: (workletUrl) => ({
36832
+ label: "RNNoise",
36833
+ processorName: "rnnoise-processor",
36834
+ workletUrl
36835
+ })
36836
+ };
36784
36837
  // src/client/htmxAttributes.ts
36785
36838
  var escapeAttr = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
36786
36839
  var normalizeHxKey = (key) => key.startsWith("hx-") ? key : `hx-${key}`;
@@ -39020,10 +39073,10 @@ var readRecentJsonFiles = async (directory, limit) => {
39020
39073
  };
39021
39074
  const existingRecords = [];
39022
39075
  for (let index = 0;index < files.length && existingRecords.length < limit; ) {
39023
- const window = files.slice(index, index + limit - existingRecords.length);
39024
- const records = await Promise.all(window.map((file) => readRecentFile(file)));
39076
+ const window2 = files.slice(index, index + limit - existingRecords.length);
39077
+ const records = await Promise.all(window2.map((file) => readRecentFile(file)));
39025
39078
  existingRecords.push(...records.filter(isDefined));
39026
- index += window.length;
39079
+ index += window2.length;
39027
39080
  }
39028
39081
  if (missingPaths.size > 0) {
39029
39082
  await writeRecentJsonFileIndex(directory, (await readRecentJsonFileIndex(directory)).filter((entry) => !missingPaths.has(entry.path)));
@@ -48418,6 +48471,7 @@ export {
48418
48471
  applyVoiceCampaignTelephonyOutcome,
48419
48472
  applyRiskTieredPhraseHintCorrections,
48420
48473
  applyPhraseHintCorrections,
48474
+ applyBrowserNoiseSuppression,
48421
48475
  appendVoiceRealCallProfileRecoveryEvidence,
48422
48476
  appendVoiceProviderRouterTraceEvent,
48423
48477
  appendVoiceIOProviderRouterTraceEvent,
@@ -48431,5 +48485,6 @@ export {
48431
48485
  DEFAULT_VOICE_REDACTION_PATTERNS,
48432
48486
  DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS,
48433
48487
  DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS,
48434
- DEFAULT_VOICE_PRICE_BOOK
48488
+ DEFAULT_VOICE_PRICE_BOOK,
48489
+ BROWSER_NOISE_SUPPRESSOR_PRESETS
48435
48490
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.503",
3
+ "version": "0.0.22-beta.504",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",