@absolutejs/voice 0.0.22-beta.34 → 0.0.22-beta.35

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.
@@ -3,6 +3,7 @@ export * from './benchmark';
3
3
  export * from './corrected';
4
4
  export * from './duplex';
5
5
  export * from './fixtures';
6
+ export * from './ioProviderSimulator';
6
7
  export * from './providerSimulator';
7
8
  export * from './resilience';
8
9
  export * from './review';
@@ -3510,6 +3510,123 @@ var loadVoiceTestFixtures = async (fixtureDirectory) => {
3510
3510
  }
3511
3511
  return fixtures;
3512
3512
  };
3513
+ // src/testing/ioProviderSimulator.ts
3514
+ var defaultFailureMessage = (input) => `Simulated ${input.provider} ${input.kind.toUpperCase()} ${input.operation} failure.`;
3515
+ var resolveRecoveryElapsedMs = (value, provider) => {
3516
+ if (typeof value === "number") {
3517
+ return value;
3518
+ }
3519
+ return value?.[provider] ?? 25;
3520
+ };
3521
+ var createHealth = (input) => ({
3522
+ consecutiveFailures: input.status === "healthy" ? 0 : 1,
3523
+ lastFailureAt: input.status === "healthy" ? undefined : input.now,
3524
+ provider: input.provider,
3525
+ status: input.status,
3526
+ suppressedUntil: input.suppressedUntil
3527
+ });
3528
+ var resolveFallback = async (options, provider) => {
3529
+ const configured = typeof options.fallback === "function" ? await options.fallback(provider) : options.fallback;
3530
+ return (configured ?? options.providers).find((candidate) => candidate !== provider);
3531
+ };
3532
+ var createVoiceIOProviderFailureSimulator = (options) => {
3533
+ if (options.providers.length === 0) {
3534
+ throw new Error("At least one provider is required.");
3535
+ }
3536
+ const now = options.now ?? Date.now;
3537
+ const operation = options.operation ?? "open";
3538
+ const cooldownMs = Math.max(0, options.cooldownMs ?? 30000);
3539
+ const emit = async (event) => {
3540
+ await options.onProviderEvent?.(event);
3541
+ };
3542
+ const run = async (provider, mode) => {
3543
+ if (!options.providers.includes(provider)) {
3544
+ throw new Error(`${provider} is not configured for simulation.`);
3545
+ }
3546
+ const startedAt = now();
3547
+ const sessionId = options.sessionId?.({ mode, now: startedAt, provider }) ?? `${options.kind}-provider-sim-${startedAt}`;
3548
+ if (mode === "recovery") {
3549
+ await emit({
3550
+ at: startedAt,
3551
+ attempt: 0,
3552
+ elapsedMs: resolveRecoveryElapsedMs(options.recoveryElapsedMs, provider),
3553
+ kind: options.kind,
3554
+ latencyBudgetMs: options.latencyBudgets?.[provider],
3555
+ operation,
3556
+ provider,
3557
+ providerHealth: createHealth({
3558
+ now: startedAt,
3559
+ provider,
3560
+ status: "healthy"
3561
+ }),
3562
+ selectedProvider: provider,
3563
+ status: "success"
3564
+ });
3565
+ return {
3566
+ mode,
3567
+ provider,
3568
+ sessionId,
3569
+ status: "simulated"
3570
+ };
3571
+ }
3572
+ const fallbackProvider = await resolveFallback(options, provider);
3573
+ const suppressedUntil = startedAt + cooldownMs;
3574
+ await emit({
3575
+ at: startedAt,
3576
+ attempt: 0,
3577
+ elapsedMs: options.failureElapsedMs ?? 10,
3578
+ error: (options.failureMessage ?? defaultFailureMessage)({
3579
+ kind: options.kind,
3580
+ operation,
3581
+ provider
3582
+ }),
3583
+ fallbackProvider,
3584
+ kind: options.kind,
3585
+ latencyBudgetMs: options.latencyBudgets?.[provider],
3586
+ operation,
3587
+ provider,
3588
+ providerHealth: createHealth({
3589
+ now: startedAt,
3590
+ provider,
3591
+ status: "suppressed",
3592
+ suppressedUntil
3593
+ }),
3594
+ selectedProvider: provider,
3595
+ status: "error",
3596
+ suppressedUntil
3597
+ });
3598
+ if (fallbackProvider) {
3599
+ await emit({
3600
+ at: startedAt + 1,
3601
+ attempt: 1,
3602
+ elapsedMs: resolveRecoveryElapsedMs(options.recoveryElapsedMs, fallbackProvider),
3603
+ fallbackProvider,
3604
+ kind: options.kind,
3605
+ latencyBudgetMs: options.latencyBudgets?.[fallbackProvider],
3606
+ operation,
3607
+ provider: fallbackProvider,
3608
+ providerHealth: createHealth({
3609
+ now: startedAt + 1,
3610
+ provider: fallbackProvider,
3611
+ status: "healthy"
3612
+ }),
3613
+ selectedProvider: provider,
3614
+ status: "fallback"
3615
+ });
3616
+ }
3617
+ return {
3618
+ fallbackProvider,
3619
+ mode,
3620
+ provider,
3621
+ sessionId,
3622
+ status: "simulated",
3623
+ suppressedUntil
3624
+ };
3625
+ };
3626
+ return {
3627
+ run
3628
+ };
3629
+ };
3513
3630
  // src/modelAdapters.ts
3514
3631
  var OUTPUT_SCHEMA = {
3515
3632
  additionalProperties: false,
@@ -8551,6 +8668,7 @@ export {
8551
8668
  getDefaultTTSBenchmarkFixtures,
8552
8669
  evaluateSTTBenchmarkAcceptance,
8553
8670
  createVoiceProviderFailureSimulator,
8671
+ createVoiceIOProviderFailureSimulator,
8554
8672
  createVoiceCallReviewRecorder,
8555
8673
  createVoiceCallReviewFromLiveTelephonyReport,
8556
8674
  createTelephonyVoiceTestFixtures,
@@ -0,0 +1,37 @@
1
+ import type { VoiceIOProviderRouterEvent } from '../providerAdapters';
2
+ export type VoiceIOProviderFailureSimulationMode = 'failure' | 'recovery';
3
+ export type VoiceIOProviderFailureSimulationKind = 'stt' | 'tts';
4
+ export type VoiceIOProviderFailureSimulationOperation = 'open' | 'send';
5
+ export type VoiceIOProviderFailureSimulationResult<TProvider extends string = string> = {
6
+ fallbackProvider?: TProvider;
7
+ mode: VoiceIOProviderFailureSimulationMode;
8
+ provider: TProvider;
9
+ sessionId: string;
10
+ status: 'simulated';
11
+ suppressedUntil?: number;
12
+ };
13
+ export type VoiceIOProviderFailureSimulatorOptions<TProvider extends string = string> = {
14
+ cooldownMs?: number;
15
+ fallback?: readonly TProvider[] | ((provider: TProvider) => readonly TProvider[] | Promise<readonly TProvider[]>);
16
+ failureElapsedMs?: number;
17
+ failureMessage?: (input: {
18
+ kind: VoiceIOProviderFailureSimulationKind;
19
+ operation: VoiceIOProviderFailureSimulationOperation;
20
+ provider: TProvider;
21
+ }) => string;
22
+ kind: VoiceIOProviderFailureSimulationKind;
23
+ latencyBudgets?: Partial<Record<TProvider, number>>;
24
+ now?: () => number;
25
+ onProviderEvent?: (event: VoiceIOProviderRouterEvent<TProvider>) => Promise<void> | void;
26
+ operation?: VoiceIOProviderFailureSimulationOperation;
27
+ providers: readonly TProvider[];
28
+ recoveryElapsedMs?: number | Partial<Record<TProvider, number>>;
29
+ sessionId?: (input: {
30
+ mode: VoiceIOProviderFailureSimulationMode;
31
+ now: number;
32
+ provider: TProvider;
33
+ }) => string;
34
+ };
35
+ export declare const createVoiceIOProviderFailureSimulator: <TProvider extends string>(options: VoiceIOProviderFailureSimulatorOptions<TProvider>) => {
36
+ run: (provider: TProvider, mode: VoiceIOProviderFailureSimulationMode) => Promise<VoiceIOProviderFailureSimulationResult<TProvider>>;
37
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.34",
3
+ "version": "0.0.22-beta.35",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",