@absolutejs/voice 0.0.22-beta.371 → 0.0.22-beta.373

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/README.md CHANGED
@@ -1504,6 +1504,39 @@ createVoiceProductionReadinessRoutes({
1504
1504
 
1505
1505
  The readiness check includes recovery actions from `buildVoiceRealCallProfileRecoveryActions(...)`, so failed gates can point operators at the profile history report, browser/phone proof, missing provider-role evidence, operations records, and production-readiness refresh instead of only saying "failed."
1506
1506
 
1507
+ Mount `createVoiceRealCallProfileRecoveryActionRoutes(...)` when those actions should be executable. The package owns the route contract and result shape; the app supplies safe handlers:
1508
+
1509
+ ```ts
1510
+ app.use(
1511
+ createVoiceRealCallProfileRecoveryActionRoutes({
1512
+ handlers: {
1513
+ 'collect-browser-proof': async () => runBrowserProfileProof(),
1514
+ 'collect-phone-proof': async () => runPhoneProfileProof(),
1515
+ refresh: async () => refreshReadinessProof()
1516
+ },
1517
+ source: buildRealCallHistory
1518
+ })
1519
+ );
1520
+ ```
1521
+
1522
+ For longer-running proof collection, add a job store and mark selected actions async. The POST returns a `jobId` with `jobStatus: "queued"`, and the app can poll `${path}/actions/:jobId`:
1523
+
1524
+ ```ts
1525
+ const recoveryJobs = createVoiceInMemoryRealCallProfileRecoveryJobStore();
1526
+
1527
+ app.use(
1528
+ createVoiceRealCallProfileRecoveryActionRoutes({
1529
+ asyncActionIds: ['collect-browser-proof', 'collect-phone-proof'],
1530
+ handlers: {
1531
+ 'collect-browser-proof': async () => runBrowserProfileProof(),
1532
+ 'collect-phone-proof': async () => runPhoneProfileProof()
1533
+ },
1534
+ jobStore: recoveryJobs,
1535
+ source: buildRealCallHistory
1536
+ })
1537
+ );
1538
+ ```
1539
+
1507
1540
  Use `createVoiceProfileTraceTagger(...)` when the app already has a trace store and needs every appended trace to carry a benchmark profile label. It wraps any `VoiceTraceEventStore`, preserves the underlying store behavior, and adds `profileId`/`benchmarkProfileId` metadata and payload fields that real-call profile history can ingest later.
1508
1541
 
1509
1542
  ```ts
@@ -4571,11 +4571,13 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
4571
4571
  {
4572
4572
  description: "Open the current real-call profile history report and profile defaults.",
4573
4573
  href: options.href ?? "/voice/real-call-profile-history",
4574
+ id: "refresh",
4574
4575
  label: "Open real-call profile history"
4575
4576
  },
4576
4577
  {
4577
4578
  description: "Refresh production readiness after collecting or replaying profile evidence.",
4578
4579
  href: options.productionReadinessHref ?? "/production-readiness",
4580
+ id: "refresh",
4579
4581
  label: "Refresh production readiness"
4580
4582
  }
4581
4583
  ];
@@ -4589,11 +4591,13 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
4589
4591
  actions.push({
4590
4592
  description: "Run browser profile proof to collect microphone, WebSocket, live-latency, and provider traces for missing profiles.",
4591
4593
  href: options.browserProofHref ?? "/voice/browser-call-profiles",
4594
+ id: "collect-browser-proof",
4592
4595
  label: "Run browser profile proof"
4593
4596
  });
4594
4597
  actions.push({
4595
4598
  description: "Run phone profile proof when required profiles depend on carrier, telephony media, or noisy-call evidence.",
4596
4599
  href: options.phoneProofHref ?? "/api/voice/phone/smoke",
4600
+ id: "collect-phone-proof",
4597
4601
  label: "Run phone profile proof"
4598
4602
  });
4599
4603
  }
@@ -4601,6 +4605,7 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
4601
4605
  actions.push({
4602
4606
  description: "Collect fresh real-call profile traces because the current history artifact is stale.",
4603
4607
  href: options.browserProofHref ?? "/voice/browser-call-profiles",
4608
+ id: "collect-browser-proof",
4604
4609
  label: "Collect fresh profile evidence"
4605
4610
  });
4606
4611
  }
@@ -4608,6 +4613,7 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
4608
4613
  actions.push({
4609
4614
  description: "Collect missing LLM/STT/TTS provider-role evidence so profile defaults can become actionable.",
4610
4615
  href: options.sourceHref ?? "/api/voice/real-call-profile-history",
4616
+ id: "collect-provider-role-evidence",
4611
4617
  label: "Collect missing provider-role evidence"
4612
4618
  });
4613
4619
  }
@@ -4615,11 +4621,48 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
4615
4621
  actions.push({
4616
4622
  description: "Open operations records to inspect the sessions behind failing or warning profile evidence.",
4617
4623
  href: options.operationsRecordsHref ?? "/voice-operations",
4624
+ id: "refresh",
4618
4625
  label: "Open operations records"
4619
4626
  });
4620
4627
  }
4621
4628
  return uniqueRealCallProfileActions(actions);
4622
4629
  };
4630
+ var createVoiceInMemoryRealCallProfileRecoveryJobStore = (options = {}) => {
4631
+ const jobs = new Map;
4632
+ const now = () => (options.now ?? (() => new Date))().toISOString();
4633
+ const createId = () => `${options.idPrefix ?? "voice-recovery-job"}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
4634
+ return {
4635
+ create(input) {
4636
+ const createdAt = input.createdAt ?? now();
4637
+ const job = {
4638
+ actionId: input.actionId,
4639
+ createdAt,
4640
+ id: input.id ?? createId(),
4641
+ message: input.message,
4642
+ status: input.status ?? "queued",
4643
+ updatedAt: createdAt
4644
+ };
4645
+ jobs.set(job.id, job);
4646
+ return job;
4647
+ },
4648
+ get(id) {
4649
+ return jobs.get(id);
4650
+ },
4651
+ update(id, update) {
4652
+ const existing = jobs.get(id);
4653
+ if (!existing) {
4654
+ return;
4655
+ }
4656
+ const next = {
4657
+ ...existing,
4658
+ ...update,
4659
+ updatedAt: update.updatedAt ?? now()
4660
+ };
4661
+ jobs.set(id, next);
4662
+ return next;
4663
+ }
4664
+ };
4665
+ };
4623
4666
  var buildVoiceRealCallProfileReadinessCheck = (report, options = {}) => {
4624
4667
  const { issues, warnings } = buildRealCallProfileReadinessIssues(report, options);
4625
4668
  const status = issues.length > 0 ? "fail" : warnings.length > 0 && options.failOnWarnings === true ? "fail" : warnings.length > 0 ? "warn" : "pass";
@@ -5217,6 +5260,165 @@ var createVoiceRealCallProfileHistoryRoutes = (options = {}) => {
5217
5260
  }
5218
5261
  return routes;
5219
5262
  };
5263
+ var realCallProfileActionPaths = {
5264
+ "collect-browser-proof": "/collect-browser-proof",
5265
+ "collect-phone-proof": "/collect-phone-proof",
5266
+ "collect-provider-role-evidence": "/collect-provider-role-evidence",
5267
+ refresh: "/refresh"
5268
+ };
5269
+ var loadVoiceRealCallProfileHistoryRouteReport = async (options) => {
5270
+ const { source, ...routeOptions } = options;
5271
+ const sourceOptions = source === undefined ? routeOptions : typeof source === "function" ? await source() : source;
5272
+ return buildVoiceRealCallProfileHistoryReport({
5273
+ ...routeOptions,
5274
+ ...sourceOptions
5275
+ });
5276
+ };
5277
+ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
5278
+ const path = options.path ?? "/api/voice/real-call-profile-history";
5279
+ const routes = new Elysia({
5280
+ name: options.name ?? "absolutejs-voice-real-call-profile-recovery-actions"
5281
+ });
5282
+ const actionPath = (actionId) => `${path}${realCallProfileActionPaths[actionId]}`;
5283
+ const loadReport = () => loadVoiceRealCallProfileHistoryRouteReport(options);
5284
+ const asyncActionIds = new Set(options.asyncActionIds ?? []);
5285
+ const listActions = async () => {
5286
+ const report = await loadReport();
5287
+ const actions = buildVoiceRealCallProfileRecoveryActions(report, {
5288
+ ...options,
5289
+ browserProofHref: options.browserProofHref ?? actionPath("collect-browser-proof"),
5290
+ phoneProofHref: options.phoneProofHref ?? actionPath("collect-phone-proof"),
5291
+ sourceHref: options.sourceHref ?? actionPath("collect-provider-role-evidence"),
5292
+ productionReadinessHref: options.productionReadinessHref ?? actionPath("refresh")
5293
+ }).map((action) => ({
5294
+ ...action,
5295
+ href: action.id === "collect-browser-proof" ? actionPath("collect-browser-proof") : action.id === "collect-phone-proof" ? actionPath("collect-phone-proof") : action.id === "collect-provider-role-evidence" ? actionPath("collect-provider-role-evidence") : action.href,
5296
+ method: action.id === "refresh" && (action.label === "Open real-call profile history" || action.label === "Open operations records") ? "GET" : "POST"
5297
+ }));
5298
+ return { actions, generatedAt: new Date().toISOString(), report };
5299
+ };
5300
+ const runActionHandler = async (actionId, report) => {
5301
+ const handler = options.handlers?.[actionId];
5302
+ if (!handler) {
5303
+ return;
5304
+ }
5305
+ return await handler({ actionId, report });
5306
+ };
5307
+ const runActionAsJob = async (actionId, report) => {
5308
+ const job = await options.jobStore?.create({
5309
+ actionId,
5310
+ message: `Queued real-call profile recovery action: ${actionId}.`,
5311
+ status: "queued"
5312
+ });
5313
+ if (!job) {
5314
+ return;
5315
+ }
5316
+ queueMicrotask(() => {
5317
+ (async () => {
5318
+ const startedAt = new Date().toISOString();
5319
+ await options.jobStore?.update(job.id, {
5320
+ message: `Running real-call profile recovery action: ${actionId}.`,
5321
+ startedAt,
5322
+ status: "running",
5323
+ updatedAt: startedAt
5324
+ });
5325
+ try {
5326
+ const result = await runActionHandler(actionId, report);
5327
+ const completedAt = new Date().toISOString();
5328
+ const ok = result?.ok ?? true;
5329
+ const status = result?.jobStatus ?? (result?.status === "fail" || ok === false ? "fail" : "pass");
5330
+ await options.jobStore?.update(job.id, {
5331
+ completedAt,
5332
+ message: result?.message ?? `Completed real-call profile recovery action: ${actionId}.`,
5333
+ ok,
5334
+ report: result?.report,
5335
+ status,
5336
+ updatedAt: completedAt
5337
+ });
5338
+ } catch (error) {
5339
+ const completedAt = new Date().toISOString();
5340
+ await options.jobStore?.update(job.id, {
5341
+ completedAt,
5342
+ message: error instanceof Error ? error.message : `Failed real-call profile recovery action: ${actionId}.`,
5343
+ ok: false,
5344
+ status: "fail",
5345
+ updatedAt: completedAt
5346
+ });
5347
+ }
5348
+ })();
5349
+ });
5350
+ return {
5351
+ actionId,
5352
+ generatedAt: new Date().toISOString(),
5353
+ job,
5354
+ jobId: job.id,
5355
+ jobStatus: job.status,
5356
+ message: job.message,
5357
+ ok: true,
5358
+ status: "pass"
5359
+ };
5360
+ };
5361
+ const runAction = async (actionId) => {
5362
+ const report = await loadReport();
5363
+ const handler = options.handlers?.[actionId];
5364
+ if (!handler) {
5365
+ return {
5366
+ actionId,
5367
+ generatedAt: new Date().toISOString(),
5368
+ message: `No handler configured for real-call profile recovery action: ${actionId}.`,
5369
+ ok: false,
5370
+ status: "fail"
5371
+ };
5372
+ }
5373
+ if (options.jobStore && asyncActionIds.has(actionId)) {
5374
+ const queued = await runActionAsJob(actionId, report);
5375
+ if (queued) {
5376
+ return queued;
5377
+ }
5378
+ }
5379
+ const result = await runActionHandler(actionId, report);
5380
+ return {
5381
+ actionId,
5382
+ generatedAt: new Date().toISOString(),
5383
+ job: result?.job,
5384
+ jobId: result?.jobId,
5385
+ jobStatus: result?.jobStatus,
5386
+ message: result?.message,
5387
+ ok: result?.ok ?? true,
5388
+ report: result?.report,
5389
+ status: result?.status ?? "pass"
5390
+ };
5391
+ };
5392
+ routes.get(`${path}/actions`, async () => Response.json(await listActions(), { headers: options.headers }));
5393
+ routes.get(`${path}/actions/:jobId`, async ({
5394
+ params,
5395
+ set
5396
+ }) => {
5397
+ const jobId = params.jobId ?? "";
5398
+ const job = await options.jobStore?.get(jobId);
5399
+ if (!job) {
5400
+ set.status = 404;
5401
+ return Response.json({
5402
+ jobId,
5403
+ message: `No real-call profile recovery job found for id: ${jobId}.`,
5404
+ ok: false
5405
+ }, { headers: options.headers });
5406
+ }
5407
+ return Response.json({ job, ok: job.ok ?? job.status !== "fail" }, {
5408
+ headers: options.headers
5409
+ });
5410
+ });
5411
+ for (const actionId of Object.keys(realCallProfileActionPaths)) {
5412
+ routes.post(actionPath(actionId), async ({ set }) => {
5413
+ const result = await runAction(actionId);
5414
+ if (!result.ok) {
5415
+ set.status = 501;
5416
+ }
5417
+ return Response.json(result, { headers: options.headers });
5418
+ });
5419
+ }
5420
+ return routes;
5421
+ };
5220
5422
  var createVoiceProofTrendRoutes = (options) => {
5221
5423
  const path = options.path ?? "/api/voice/proof-trends";
5222
5424
  const routes = new Elysia({
package/dist/index.d.ts CHANGED
@@ -30,12 +30,12 @@ export { assertVoicePlatformCoverage, buildVoicePlatformCoverageSummary, createV
30
30
  export { assertVoiceCompetitiveCoverage, buildVoiceCompetitiveCoverageReport, createVoiceCompetitiveCoverageRoutes, evaluateVoiceCompetitiveCoverage, renderVoiceCompetitiveCoverageHTML, renderVoiceCompetitiveCoverageMarkdown } from './competitiveCoverage';
31
31
  export type { VoiceCompetitiveCoverageAssertionInput, VoiceCompetitiveCoverageAssertionReport, VoiceCompetitiveCoverageIssue, VoiceCompetitiveCoverageLevel, VoiceCompetitiveCoverageReport, VoiceCompetitiveCoverageReportInput, VoiceCompetitiveCoverageRoutesOptions, VoiceCompetitiveCoverageStatus, VoiceCompetitiveCoverageSummary, VoiceCompetitiveDepthLevel, VoiceCompetitiveEvidence, VoiceCompetitiveSurface } from './competitiveCoverage';
32
32
  export type { VoicePlatformCoverageAssertionInput, VoicePlatformCoverageAssertionReport, VoicePlatformCoverageEvidence, VoicePlatformCoverageRoutesOptions, VoicePlatformCoverageStatus, VoicePlatformCoverageSummary, VoicePlatformCoverageSummaryInput, VoicePlatformCoverageSurface } from './platformCoverage';
33
- export { assertVoiceProofTrendEvidence, buildEmptyVoiceProofTrendReport, buildVoiceProofTrendProfileSummaries, buildVoiceProofTrendRecommendationReport, buildVoiceProofTrendReportFromRealCallProfiles, buildVoiceProofTrendReport, buildVoiceRealCallProfileEvidenceFromTraceEvents, buildVoiceRealCallProfileDefaults, buildVoiceRealCallProfileHistoryReport, buildVoiceRealCallProfileReadinessCheck, buildVoiceRealCallProfileRecoveryActions, createVoiceProofTrendRecommendationRoutes, createVoiceProofTrendRoutes, createVoiceRealCallProfileHistoryRoutes, DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS, DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS, evaluateVoiceProofTrendEvidence, formatVoiceProofTrendAge, loadVoiceRealCallProfileEvidenceFromTraceStore, normalizeVoiceProofTrendReport, readVoiceProofTrendReportFile, renderVoiceProofTrendRecommendationHTML, renderVoiceProofTrendRecommendationMarkdown, renderVoiceRealCallProfileHistoryHTML, renderVoiceRealCallProfileHistoryMarkdown, resolveVoiceRealCallProfileProviderRoute } from './proofTrends';
33
+ export { assertVoiceProofTrendEvidence, buildEmptyVoiceProofTrendReport, buildVoiceProofTrendProfileSummaries, buildVoiceProofTrendRecommendationReport, buildVoiceProofTrendReportFromRealCallProfiles, buildVoiceProofTrendReport, buildVoiceRealCallProfileEvidenceFromTraceEvents, buildVoiceRealCallProfileDefaults, buildVoiceRealCallProfileHistoryReport, buildVoiceRealCallProfileReadinessCheck, buildVoiceRealCallProfileRecoveryActions, createVoiceInMemoryRealCallProfileRecoveryJobStore, createVoiceProofTrendRecommendationRoutes, createVoiceProofTrendRoutes, createVoiceRealCallProfileHistoryRoutes, createVoiceRealCallProfileRecoveryActionRoutes, DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS, DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS, evaluateVoiceProofTrendEvidence, formatVoiceProofTrendAge, loadVoiceRealCallProfileEvidenceFromTraceStore, normalizeVoiceProofTrendReport, readVoiceProofTrendReportFile, renderVoiceProofTrendRecommendationHTML, renderVoiceProofTrendRecommendationMarkdown, renderVoiceRealCallProfileHistoryHTML, renderVoiceRealCallProfileHistoryMarkdown, resolveVoiceRealCallProfileProviderRoute } from './proofTrends';
34
34
  export { applyVoiceProfileSwitchGuard, buildVoiceProfileSwitchReadinessReport, buildVoiceProfileSwitchLiveDecisionReport, createVoiceProfileSwitchLiveDecisionRoutes, createVoiceProfileSwitchPolicyProofRoutes, createVoiceProfileSwitchReadinessRoutes, recommendVoiceProfileSwitch, renderVoiceProfileSwitchLiveDecisionHTML, renderVoiceProfileSwitchPolicyProofHTML, renderVoiceProfileSwitchReadinessHTML, runVoiceProfileSwitchPolicyProof } from './profileSwitchRecommendation';
35
35
  export type { VoiceProfileSwitchGuardAction, VoiceProfileSwitchGuardDecision, VoiceProfileSwitchGuardMode, VoiceProfileSwitchGuardOptions, VoiceProfileSwitchObservedSignals, VoiceProfileSwitchLiveDecisionEvidence, VoiceProfileSwitchLiveDecisionReport, VoiceProfileSwitchLiveDecisionReportOptions, VoiceProfileSwitchLiveDecisionRoutesOptions, VoiceProfileSwitchLiveDecisionSession, VoiceProfileSwitchPolicyProofCase, VoiceProfileSwitchPolicyProofCaseResult, VoiceProfileSwitchPolicyProofOptions, VoiceProfileSwitchPolicyProofReport, VoiceProfileSwitchPolicyProofRoutesOptions, VoiceProfileSwitchReadinessIssue, VoiceProfileSwitchReadinessOptions, VoiceProfileSwitchReadinessReport, VoiceProfileSwitchReadinessRoutesOptions, VoiceProfileSwitchReadinessStatus, VoiceProfileSwitchRecommendation, VoiceProfileSwitchRecommendationOptions } from './profileSwitchRecommendation';
36
36
  export { buildVoiceProviderDecisionTraceReport, createVoiceProviderDecisionTraceEvent, createVoiceProviderDecisionTraceRoutes, listVoiceProviderDecisionTraces, renderVoiceProviderDecisionTraceHTML, renderVoiceProviderDecisionTraceMarkdown } from './providerDecisionTraces';
37
37
  export type { VoiceProviderDecisionStatus, VoiceProviderDecisionSurfaceReport, VoiceProviderDecisionTrace, VoiceProviderDecisionTraceInput, VoiceProviderDecisionTraceIssue, VoiceProviderDecisionTraceReport, VoiceProviderDecisionTraceReportOptions, VoiceProviderDecisionTraceRoutesOptions } from './providerDecisionTraces';
38
- export type { VoiceProofTrendAssertionInput, VoiceProofTrendAssertionReport, VoiceProofTrendCycle, VoiceProofTrendProfileDefinition, VoiceProofTrendProfileRecommendation, VoiceProofTrendProfileSummaryOptions, VoiceProofTrendProfileSummary, VoiceProofTrendProviderRecommendation, VoiceProofTrendProviderSummary, VoiceProofTrendRecommendation, VoiceProofTrendRecommendationOptions, VoiceProofTrendRecommendationReport, VoiceProofTrendRecommendationRoutesOptions, VoiceProofTrendRecommendationStatus, VoiceProofTrendRecommendationSurface, VoiceProofTrendRealCallProfileEvidence, VoiceProofTrendRealCallProfileReportOptions, VoiceProofTrendReport, VoiceProofTrendReportInput, VoiceProofTrendRoutesOptions, VoiceProofTrendRuntimeChannelSummary, VoiceProofTrendStatus, VoiceProofTrendSummary, VoiceRealCallProfileDefault, VoiceRealCallProfileDefaultsOptions, VoiceRealCallProfileDefaultsReport, VoiceRealCallProfileHistoryOptions, VoiceRealCallProfileHistoryReport, VoiceRealCallProfileHistoryRoutesOptions, VoiceRealCallProfileProviderRouteOptions, VoiceRealCallProfileReadinessCheckOptions, VoiceRealCallProfileRecoveryActionOptions, VoiceRealCallProfileTraceEvidenceOptions, VoiceRealCallProfileTraceStoreEvidenceOptions } from './proofTrends';
38
+ export type { VoiceProofTrendAssertionInput, VoiceProofTrendAssertionReport, VoiceProofTrendCycle, VoiceProofTrendProfileDefinition, VoiceProofTrendProfileRecommendation, VoiceProofTrendProfileSummaryOptions, VoiceProofTrendProfileSummary, VoiceProofTrendProviderRecommendation, VoiceProofTrendProviderSummary, VoiceProofTrendRecommendation, VoiceProofTrendRecommendationOptions, VoiceProofTrendRecommendationReport, VoiceProofTrendRecommendationRoutesOptions, VoiceProofTrendRecommendationStatus, VoiceProofTrendRecommendationSurface, VoiceProofTrendRealCallProfileEvidence, VoiceProofTrendRealCallProfileReportOptions, VoiceProofTrendReport, VoiceProofTrendReportInput, VoiceProofTrendRoutesOptions, VoiceProofTrendRuntimeChannelSummary, VoiceProofTrendStatus, VoiceProofTrendSummary, VoiceRealCallProfileDefault, VoiceRealCallProfileDefaultsOptions, VoiceRealCallProfileDefaultsReport, VoiceRealCallProfileHistoryOptions, VoiceRealCallProfileHistoryReport, VoiceRealCallProfileHistoryRoutesOptions, VoiceRealCallProfileProviderRouteOptions, VoiceRealCallProfileReadinessCheckOptions, VoiceRealCallProfileRecoveryActionOptions, VoiceRealCallProfileRecoveryAction, VoiceRealCallProfileRecoveryActionHandler, VoiceRealCallProfileRecoveryActionHandlerInput, VoiceRealCallProfileRecoveryActionId, VoiceRealCallProfileRecoveryActionResult, VoiceRealCallProfileRecoveryActionRoutesOptions, VoiceRealCallProfileRecoveryJob, VoiceRealCallProfileRecoveryJobCreateInput, VoiceRealCallProfileRecoveryJobStatus, VoiceRealCallProfileRecoveryJobStore, VoiceRealCallProfileRecoveryJobUpdate, VoiceRealCallProfileTraceEvidenceOptions, VoiceRealCallProfileTraceStoreEvidenceOptions } from './proofTrends';
39
39
  export { assertVoiceSloCalibration, buildVoiceSloCalibrationReport, buildVoiceSloReadinessThresholdReport, createVoiceSloReadinessThresholdOptions, createVoiceSloReadinessThresholdRoutes, createVoiceSloThresholdProfile, createVoiceSloCalibrationRoutes, renderVoiceSloCalibrationMarkdown, renderVoiceSloReadinessThresholdHTML, renderVoiceSloReadinessThresholdMarkdown } from './sloCalibration';
40
40
  export type { VoiceSloCalibrationMetricKey, VoiceSloCalibrationOptions, VoiceSloCalibrationReport, VoiceSloCalibrationRoutesOptions, VoiceSloCalibrationSample, VoiceSloCalibrationStatus, VoiceSloCalibrationThreshold, VoiceSloCalibrationThresholds, VoiceSloReadinessThresholdReport, VoiceSloReadinessThresholdReportOptions, VoiceSloReadinessThresholdOptions, VoiceSloReadinessThresholdRoutesOptions, VoiceSloThresholdProfile } from './sloCalibration';
41
41
  export { assertVoiceLiveOpsControlEvidence, assertVoiceLiveOpsEvidence, buildVoiceLiveOpsControlState, createVoiceLiveOpsController, createVoiceLiveOpsRoutes, createVoiceMemoryLiveOpsControlStore, evaluateVoiceLiveOpsControlEvidence, evaluateVoiceLiveOpsEvidence, getVoiceLiveOpsControlStatus, VOICE_LIVE_OPS_ACTIONS } from './liveOps';
package/dist/index.js CHANGED
@@ -16040,11 +16040,13 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
16040
16040
  {
16041
16041
  description: "Open the current real-call profile history report and profile defaults.",
16042
16042
  href: options.href ?? "/voice/real-call-profile-history",
16043
+ id: "refresh",
16043
16044
  label: "Open real-call profile history"
16044
16045
  },
16045
16046
  {
16046
16047
  description: "Refresh production readiness after collecting or replaying profile evidence.",
16047
16048
  href: options.productionReadinessHref ?? "/production-readiness",
16049
+ id: "refresh",
16048
16050
  label: "Refresh production readiness"
16049
16051
  }
16050
16052
  ];
@@ -16058,11 +16060,13 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
16058
16060
  actions.push({
16059
16061
  description: "Run browser profile proof to collect microphone, WebSocket, live-latency, and provider traces for missing profiles.",
16060
16062
  href: options.browserProofHref ?? "/voice/browser-call-profiles",
16063
+ id: "collect-browser-proof",
16061
16064
  label: "Run browser profile proof"
16062
16065
  });
16063
16066
  actions.push({
16064
16067
  description: "Run phone profile proof when required profiles depend on carrier, telephony media, or noisy-call evidence.",
16065
16068
  href: options.phoneProofHref ?? "/api/voice/phone/smoke",
16069
+ id: "collect-phone-proof",
16066
16070
  label: "Run phone profile proof"
16067
16071
  });
16068
16072
  }
@@ -16070,6 +16074,7 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
16070
16074
  actions.push({
16071
16075
  description: "Collect fresh real-call profile traces because the current history artifact is stale.",
16072
16076
  href: options.browserProofHref ?? "/voice/browser-call-profiles",
16077
+ id: "collect-browser-proof",
16073
16078
  label: "Collect fresh profile evidence"
16074
16079
  });
16075
16080
  }
@@ -16077,6 +16082,7 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
16077
16082
  actions.push({
16078
16083
  description: "Collect missing LLM/STT/TTS provider-role evidence so profile defaults can become actionable.",
16079
16084
  href: options.sourceHref ?? "/api/voice/real-call-profile-history",
16085
+ id: "collect-provider-role-evidence",
16080
16086
  label: "Collect missing provider-role evidence"
16081
16087
  });
16082
16088
  }
@@ -16084,11 +16090,48 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
16084
16090
  actions.push({
16085
16091
  description: "Open operations records to inspect the sessions behind failing or warning profile evidence.",
16086
16092
  href: options.operationsRecordsHref ?? "/voice-operations",
16093
+ id: "refresh",
16087
16094
  label: "Open operations records"
16088
16095
  });
16089
16096
  }
16090
16097
  return uniqueRealCallProfileActions(actions);
16091
16098
  };
16099
+ var createVoiceInMemoryRealCallProfileRecoveryJobStore = (options = {}) => {
16100
+ const jobs = new Map;
16101
+ const now = () => (options.now ?? (() => new Date))().toISOString();
16102
+ const createId3 = () => `${options.idPrefix ?? "voice-recovery-job"}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
16103
+ return {
16104
+ create(input) {
16105
+ const createdAt = input.createdAt ?? now();
16106
+ const job = {
16107
+ actionId: input.actionId,
16108
+ createdAt,
16109
+ id: input.id ?? createId3(),
16110
+ message: input.message,
16111
+ status: input.status ?? "queued",
16112
+ updatedAt: createdAt
16113
+ };
16114
+ jobs.set(job.id, job);
16115
+ return job;
16116
+ },
16117
+ get(id) {
16118
+ return jobs.get(id);
16119
+ },
16120
+ update(id, update) {
16121
+ const existing = jobs.get(id);
16122
+ if (!existing) {
16123
+ return;
16124
+ }
16125
+ const next = {
16126
+ ...existing,
16127
+ ...update,
16128
+ updatedAt: update.updatedAt ?? now()
16129
+ };
16130
+ jobs.set(id, next);
16131
+ return next;
16132
+ }
16133
+ };
16134
+ };
16092
16135
  var buildVoiceRealCallProfileReadinessCheck = (report, options = {}) => {
16093
16136
  const { issues, warnings } = buildRealCallProfileReadinessIssues(report, options);
16094
16137
  const status = issues.length > 0 ? "fail" : warnings.length > 0 && options.failOnWarnings === true ? "fail" : warnings.length > 0 ? "warn" : "pass";
@@ -16686,6 +16729,165 @@ var createVoiceRealCallProfileHistoryRoutes = (options = {}) => {
16686
16729
  }
16687
16730
  return routes;
16688
16731
  };
16732
+ var realCallProfileActionPaths = {
16733
+ "collect-browser-proof": "/collect-browser-proof",
16734
+ "collect-phone-proof": "/collect-phone-proof",
16735
+ "collect-provider-role-evidence": "/collect-provider-role-evidence",
16736
+ refresh: "/refresh"
16737
+ };
16738
+ var loadVoiceRealCallProfileHistoryRouteReport = async (options) => {
16739
+ const { source, ...routeOptions } = options;
16740
+ const sourceOptions = source === undefined ? routeOptions : typeof source === "function" ? await source() : source;
16741
+ return buildVoiceRealCallProfileHistoryReport({
16742
+ ...routeOptions,
16743
+ ...sourceOptions
16744
+ });
16745
+ };
16746
+ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
16747
+ const path = options.path ?? "/api/voice/real-call-profile-history";
16748
+ const routes = new Elysia22({
16749
+ name: options.name ?? "absolutejs-voice-real-call-profile-recovery-actions"
16750
+ });
16751
+ const actionPath = (actionId) => `${path}${realCallProfileActionPaths[actionId]}`;
16752
+ const loadReport = () => loadVoiceRealCallProfileHistoryRouteReport(options);
16753
+ const asyncActionIds = new Set(options.asyncActionIds ?? []);
16754
+ const listActions = async () => {
16755
+ const report = await loadReport();
16756
+ const actions = buildVoiceRealCallProfileRecoveryActions(report, {
16757
+ ...options,
16758
+ browserProofHref: options.browserProofHref ?? actionPath("collect-browser-proof"),
16759
+ phoneProofHref: options.phoneProofHref ?? actionPath("collect-phone-proof"),
16760
+ sourceHref: options.sourceHref ?? actionPath("collect-provider-role-evidence"),
16761
+ productionReadinessHref: options.productionReadinessHref ?? actionPath("refresh")
16762
+ }).map((action) => ({
16763
+ ...action,
16764
+ href: action.id === "collect-browser-proof" ? actionPath("collect-browser-proof") : action.id === "collect-phone-proof" ? actionPath("collect-phone-proof") : action.id === "collect-provider-role-evidence" ? actionPath("collect-provider-role-evidence") : action.href,
16765
+ method: action.id === "refresh" && (action.label === "Open real-call profile history" || action.label === "Open operations records") ? "GET" : "POST"
16766
+ }));
16767
+ return { actions, generatedAt: new Date().toISOString(), report };
16768
+ };
16769
+ const runActionHandler = async (actionId, report) => {
16770
+ const handler = options.handlers?.[actionId];
16771
+ if (!handler) {
16772
+ return;
16773
+ }
16774
+ return await handler({ actionId, report });
16775
+ };
16776
+ const runActionAsJob = async (actionId, report) => {
16777
+ const job = await options.jobStore?.create({
16778
+ actionId,
16779
+ message: `Queued real-call profile recovery action: ${actionId}.`,
16780
+ status: "queued"
16781
+ });
16782
+ if (!job) {
16783
+ return;
16784
+ }
16785
+ queueMicrotask(() => {
16786
+ (async () => {
16787
+ const startedAt = new Date().toISOString();
16788
+ await options.jobStore?.update(job.id, {
16789
+ message: `Running real-call profile recovery action: ${actionId}.`,
16790
+ startedAt,
16791
+ status: "running",
16792
+ updatedAt: startedAt
16793
+ });
16794
+ try {
16795
+ const result = await runActionHandler(actionId, report);
16796
+ const completedAt = new Date().toISOString();
16797
+ const ok = result?.ok ?? true;
16798
+ const status = result?.jobStatus ?? (result?.status === "fail" || ok === false ? "fail" : "pass");
16799
+ await options.jobStore?.update(job.id, {
16800
+ completedAt,
16801
+ message: result?.message ?? `Completed real-call profile recovery action: ${actionId}.`,
16802
+ ok,
16803
+ report: result?.report,
16804
+ status,
16805
+ updatedAt: completedAt
16806
+ });
16807
+ } catch (error) {
16808
+ const completedAt = new Date().toISOString();
16809
+ await options.jobStore?.update(job.id, {
16810
+ completedAt,
16811
+ message: error instanceof Error ? error.message : `Failed real-call profile recovery action: ${actionId}.`,
16812
+ ok: false,
16813
+ status: "fail",
16814
+ updatedAt: completedAt
16815
+ });
16816
+ }
16817
+ })();
16818
+ });
16819
+ return {
16820
+ actionId,
16821
+ generatedAt: new Date().toISOString(),
16822
+ job,
16823
+ jobId: job.id,
16824
+ jobStatus: job.status,
16825
+ message: job.message,
16826
+ ok: true,
16827
+ status: "pass"
16828
+ };
16829
+ };
16830
+ const runAction = async (actionId) => {
16831
+ const report = await loadReport();
16832
+ const handler = options.handlers?.[actionId];
16833
+ if (!handler) {
16834
+ return {
16835
+ actionId,
16836
+ generatedAt: new Date().toISOString(),
16837
+ message: `No handler configured for real-call profile recovery action: ${actionId}.`,
16838
+ ok: false,
16839
+ status: "fail"
16840
+ };
16841
+ }
16842
+ if (options.jobStore && asyncActionIds.has(actionId)) {
16843
+ const queued = await runActionAsJob(actionId, report);
16844
+ if (queued) {
16845
+ return queued;
16846
+ }
16847
+ }
16848
+ const result = await runActionHandler(actionId, report);
16849
+ return {
16850
+ actionId,
16851
+ generatedAt: new Date().toISOString(),
16852
+ job: result?.job,
16853
+ jobId: result?.jobId,
16854
+ jobStatus: result?.jobStatus,
16855
+ message: result?.message,
16856
+ ok: result?.ok ?? true,
16857
+ report: result?.report,
16858
+ status: result?.status ?? "pass"
16859
+ };
16860
+ };
16861
+ routes.get(`${path}/actions`, async () => Response.json(await listActions(), { headers: options.headers }));
16862
+ routes.get(`${path}/actions/:jobId`, async ({
16863
+ params,
16864
+ set
16865
+ }) => {
16866
+ const jobId = params.jobId ?? "";
16867
+ const job = await options.jobStore?.get(jobId);
16868
+ if (!job) {
16869
+ set.status = 404;
16870
+ return Response.json({
16871
+ jobId,
16872
+ message: `No real-call profile recovery job found for id: ${jobId}.`,
16873
+ ok: false
16874
+ }, { headers: options.headers });
16875
+ }
16876
+ return Response.json({ job, ok: job.ok ?? job.status !== "fail" }, {
16877
+ headers: options.headers
16878
+ });
16879
+ });
16880
+ for (const actionId of Object.keys(realCallProfileActionPaths)) {
16881
+ routes.post(actionPath(actionId), async ({ set }) => {
16882
+ const result = await runAction(actionId);
16883
+ if (!result.ok) {
16884
+ set.status = 501;
16885
+ }
16886
+ return Response.json(result, { headers: options.headers });
16887
+ });
16888
+ }
16889
+ return routes;
16890
+ };
16689
16891
  var createVoiceProofTrendRoutes = (options) => {
16690
16892
  const path = options.path ?? "/api/voice/proof-trends";
16691
16893
  const routes = new Elysia22({
@@ -38757,6 +38959,7 @@ export {
38757
38959
  createVoiceRealtimeProviderContractRoutes,
38758
38960
  createVoiceRealtimeProviderContractMatrixPreset,
38759
38961
  createVoiceRealtimeChannelRoutes,
38962
+ createVoiceRealCallProfileRecoveryActionRoutes,
38760
38963
  createVoiceRealCallProfileHistoryRoutes,
38761
38964
  createVoiceReadinessProfile,
38762
38965
  createVoiceQualityRoutes,
@@ -38854,6 +39057,7 @@ export {
38854
39057
  createVoiceIntegrationHTTPSink,
38855
39058
  createVoiceIntegrationEvent,
38856
39059
  createVoiceIncidentBundleRoutes,
39060
+ createVoiceInMemoryRealCallProfileRecoveryJobStore,
38857
39061
  createVoiceHubSpotTaskUpdateSink,
38858
39062
  createVoiceHubSpotTaskSyncSinks,
38859
39063
  createVoiceHubSpotTaskSink,
@@ -356,6 +356,10 @@ export type VoiceRealCallProfileHistoryRoutesOptions = Omit<VoiceRealCallProfile
356
356
  source?: (() => Promise<VoiceRealCallProfileHistoryOptions> | VoiceRealCallProfileHistoryOptions) | VoiceRealCallProfileHistoryOptions;
357
357
  title?: string;
358
358
  };
359
+ export type VoiceRealCallProfileRecoveryActionId = 'collect-browser-proof' | 'collect-phone-proof' | 'collect-provider-role-evidence' | 'refresh';
360
+ export type VoiceRealCallProfileRecoveryAction = VoiceProductionReadinessAction & {
361
+ id: VoiceRealCallProfileRecoveryActionId;
362
+ };
359
363
  export type VoiceRealCallProfileReadinessCheckOptions = {
360
364
  browserProofHref?: string;
361
365
  failOnWarnings?: boolean;
@@ -373,6 +377,53 @@ export type VoiceRealCallProfileReadinessCheckOptions = {
373
377
  sourceHref?: string;
374
378
  };
375
379
  export type VoiceRealCallProfileRecoveryActionOptions = VoiceRealCallProfileReadinessCheckOptions;
380
+ export type VoiceRealCallProfileRecoveryActionHandlerInput = {
381
+ actionId: VoiceRealCallProfileRecoveryActionId;
382
+ report: VoiceRealCallProfileHistoryReport;
383
+ };
384
+ export type VoiceRealCallProfileRecoveryActionResult = {
385
+ actionId: VoiceRealCallProfileRecoveryActionId;
386
+ generatedAt: string;
387
+ job?: VoiceRealCallProfileRecoveryJob;
388
+ jobId?: string;
389
+ jobStatus?: VoiceRealCallProfileRecoveryJobStatus;
390
+ message?: string;
391
+ ok: boolean;
392
+ report?: VoiceRealCallProfileHistoryReport;
393
+ status: VoiceProofTrendStatus;
394
+ };
395
+ export type VoiceRealCallProfileRecoveryJobStatus = 'fail' | 'pass' | 'queued' | 'running';
396
+ export type VoiceRealCallProfileRecoveryJob = {
397
+ actionId: VoiceRealCallProfileRecoveryActionId;
398
+ completedAt?: string;
399
+ createdAt: string;
400
+ id: string;
401
+ message?: string;
402
+ ok?: boolean;
403
+ report?: VoiceRealCallProfileHistoryReport;
404
+ startedAt?: string;
405
+ status: VoiceRealCallProfileRecoveryJobStatus;
406
+ updatedAt: string;
407
+ };
408
+ export type VoiceRealCallProfileRecoveryJobCreateInput = {
409
+ actionId: VoiceRealCallProfileRecoveryActionId;
410
+ createdAt?: string;
411
+ id?: string;
412
+ message?: string;
413
+ status?: VoiceRealCallProfileRecoveryJobStatus;
414
+ };
415
+ export type VoiceRealCallProfileRecoveryJobUpdate = Partial<Pick<VoiceRealCallProfileRecoveryJob, 'completedAt' | 'message' | 'ok' | 'report' | 'startedAt' | 'status' | 'updatedAt'>>;
416
+ export type VoiceRealCallProfileRecoveryJobStore = {
417
+ create(input: VoiceRealCallProfileRecoveryJobCreateInput): Promise<VoiceRealCallProfileRecoveryJob> | VoiceRealCallProfileRecoveryJob;
418
+ get(id: string): Promise<VoiceRealCallProfileRecoveryJob | undefined> | VoiceRealCallProfileRecoveryJob | undefined;
419
+ update(id: string, update: VoiceRealCallProfileRecoveryJobUpdate): Promise<VoiceRealCallProfileRecoveryJob | undefined> | VoiceRealCallProfileRecoveryJob | undefined;
420
+ };
421
+ export type VoiceRealCallProfileRecoveryActionHandler = (input: VoiceRealCallProfileRecoveryActionHandlerInput) => Promise<Partial<VoiceRealCallProfileRecoveryActionResult> | void> | Partial<VoiceRealCallProfileRecoveryActionResult> | void;
422
+ export type VoiceRealCallProfileRecoveryActionRoutesOptions = VoiceRealCallProfileRecoveryActionOptions & Omit<VoiceRealCallProfileHistoryRoutesOptions, 'htmlPath' | 'markdownPath'> & {
423
+ asyncActionIds?: readonly VoiceRealCallProfileRecoveryActionId[];
424
+ handlers?: Partial<Record<VoiceRealCallProfileRecoveryActionId, VoiceRealCallProfileRecoveryActionHandler>>;
425
+ jobStore?: VoiceRealCallProfileRecoveryJobStore;
426
+ };
376
427
  export declare const DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS: number;
377
428
  export declare const DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS: ({
378
429
  description: string;
@@ -406,7 +457,11 @@ export declare const loadVoiceRealCallProfileEvidenceFromTraceStore: (options: V
406
457
  export declare const buildVoiceProofTrendProfileSummaries: (input: VoiceProofTrendReport | readonly VoiceProofTrendReport[], options?: VoiceProofTrendProfileSummaryOptions) => VoiceProofTrendProfileSummary[];
407
458
  export declare const buildVoiceProofTrendReportFromRealCallProfiles: (options: VoiceProofTrendRealCallProfileReportOptions) => VoiceProofTrendReport;
408
459
  export declare const buildVoiceRealCallProfileDefaults: (input: VoiceRealCallProfileHistoryReport | VoiceProofTrendReport, options?: VoiceRealCallProfileDefaultsOptions) => VoiceRealCallProfileDefaultsReport;
409
- export declare const buildVoiceRealCallProfileRecoveryActions: (report: VoiceRealCallProfileHistoryReport, options?: VoiceRealCallProfileRecoveryActionOptions) => VoiceProductionReadinessAction[];
460
+ export declare const buildVoiceRealCallProfileRecoveryActions: (report: VoiceRealCallProfileHistoryReport, options?: VoiceRealCallProfileRecoveryActionOptions) => VoiceRealCallProfileRecoveryAction[];
461
+ export declare const createVoiceInMemoryRealCallProfileRecoveryJobStore: (options?: {
462
+ idPrefix?: string;
463
+ now?: () => Date;
464
+ }) => VoiceRealCallProfileRecoveryJobStore;
410
465
  export declare const buildVoiceRealCallProfileReadinessCheck: (report: VoiceRealCallProfileHistoryReport, options?: VoiceRealCallProfileReadinessCheckOptions) => VoiceProductionReadinessCheck;
411
466
  export declare const resolveVoiceRealCallProfileProviderRoute: <TProvider extends string = string>(options: VoiceRealCallProfileProviderRouteOptions<TProvider>) => TProvider | undefined;
412
467
  export declare const buildVoiceRealCallProfileHistoryReport: (options?: VoiceRealCallProfileHistoryOptions) => VoiceRealCallProfileHistoryReport;
@@ -473,6 +528,34 @@ export declare const createVoiceRealCallProfileHistoryRoutes: (options?: VoiceRe
473
528
  standaloneSchema: {};
474
529
  response: {};
475
530
  }>;
531
+ export declare const createVoiceRealCallProfileRecoveryActionRoutes: (options?: VoiceRealCallProfileRecoveryActionRoutesOptions) => Elysia<"", {
532
+ decorator: {};
533
+ store: {};
534
+ derive: {};
535
+ resolve: {};
536
+ }, {
537
+ typebox: {};
538
+ error: {};
539
+ }, {
540
+ schema: {};
541
+ standaloneSchema: {};
542
+ macro: {};
543
+ macroFn: {};
544
+ parser: {};
545
+ response: {};
546
+ }, {}, {
547
+ derive: {};
548
+ resolve: {};
549
+ schema: {};
550
+ standaloneSchema: {};
551
+ response: {};
552
+ }, {
553
+ derive: {};
554
+ resolve: {};
555
+ schema: {};
556
+ standaloneSchema: {};
557
+ response: {};
558
+ }>;
476
559
  export declare const createVoiceProofTrendRoutes: (options: VoiceProofTrendRoutesOptions) => Elysia<"", {
477
560
  decorator: {};
478
561
  store: {};
@@ -2158,11 +2158,13 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
2158
2158
  {
2159
2159
  description: "Open the current real-call profile history report and profile defaults.",
2160
2160
  href: options.href ?? "/voice/real-call-profile-history",
2161
+ id: "refresh",
2161
2162
  label: "Open real-call profile history"
2162
2163
  },
2163
2164
  {
2164
2165
  description: "Refresh production readiness after collecting or replaying profile evidence.",
2165
2166
  href: options.productionReadinessHref ?? "/production-readiness",
2167
+ id: "refresh",
2166
2168
  label: "Refresh production readiness"
2167
2169
  }
2168
2170
  ];
@@ -2176,11 +2178,13 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
2176
2178
  actions.push({
2177
2179
  description: "Run browser profile proof to collect microphone, WebSocket, live-latency, and provider traces for missing profiles.",
2178
2180
  href: options.browserProofHref ?? "/voice/browser-call-profiles",
2181
+ id: "collect-browser-proof",
2179
2182
  label: "Run browser profile proof"
2180
2183
  });
2181
2184
  actions.push({
2182
2185
  description: "Run phone profile proof when required profiles depend on carrier, telephony media, or noisy-call evidence.",
2183
2186
  href: options.phoneProofHref ?? "/api/voice/phone/smoke",
2187
+ id: "collect-phone-proof",
2184
2188
  label: "Run phone profile proof"
2185
2189
  });
2186
2190
  }
@@ -2188,6 +2192,7 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
2188
2192
  actions.push({
2189
2193
  description: "Collect fresh real-call profile traces because the current history artifact is stale.",
2190
2194
  href: options.browserProofHref ?? "/voice/browser-call-profiles",
2195
+ id: "collect-browser-proof",
2191
2196
  label: "Collect fresh profile evidence"
2192
2197
  });
2193
2198
  }
@@ -2195,6 +2200,7 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
2195
2200
  actions.push({
2196
2201
  description: "Collect missing LLM/STT/TTS provider-role evidence so profile defaults can become actionable.",
2197
2202
  href: options.sourceHref ?? "/api/voice/real-call-profile-history",
2203
+ id: "collect-provider-role-evidence",
2198
2204
  label: "Collect missing provider-role evidence"
2199
2205
  });
2200
2206
  }
@@ -2202,11 +2208,48 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
2202
2208
  actions.push({
2203
2209
  description: "Open operations records to inspect the sessions behind failing or warning profile evidence.",
2204
2210
  href: options.operationsRecordsHref ?? "/voice-operations",
2211
+ id: "refresh",
2205
2212
  label: "Open operations records"
2206
2213
  });
2207
2214
  }
2208
2215
  return uniqueRealCallProfileActions(actions);
2209
2216
  };
2217
+ var createVoiceInMemoryRealCallProfileRecoveryJobStore = (options = {}) => {
2218
+ const jobs = new Map;
2219
+ const now = () => (options.now ?? (() => new Date))().toISOString();
2220
+ const createId = () => `${options.idPrefix ?? "voice-recovery-job"}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
2221
+ return {
2222
+ create(input) {
2223
+ const createdAt = input.createdAt ?? now();
2224
+ const job = {
2225
+ actionId: input.actionId,
2226
+ createdAt,
2227
+ id: input.id ?? createId(),
2228
+ message: input.message,
2229
+ status: input.status ?? "queued",
2230
+ updatedAt: createdAt
2231
+ };
2232
+ jobs.set(job.id, job);
2233
+ return job;
2234
+ },
2235
+ get(id) {
2236
+ return jobs.get(id);
2237
+ },
2238
+ update(id, update) {
2239
+ const existing = jobs.get(id);
2240
+ if (!existing) {
2241
+ return;
2242
+ }
2243
+ const next = {
2244
+ ...existing,
2245
+ ...update,
2246
+ updatedAt: update.updatedAt ?? now()
2247
+ };
2248
+ jobs.set(id, next);
2249
+ return next;
2250
+ }
2251
+ };
2252
+ };
2210
2253
  var buildVoiceRealCallProfileReadinessCheck = (report, options = {}) => {
2211
2254
  const { issues, warnings } = buildRealCallProfileReadinessIssues(report, options);
2212
2255
  const status = issues.length > 0 ? "fail" : warnings.length > 0 && options.failOnWarnings === true ? "fail" : warnings.length > 0 ? "warn" : "pass";
@@ -2804,6 +2847,165 @@ var createVoiceRealCallProfileHistoryRoutes = (options = {}) => {
2804
2847
  }
2805
2848
  return routes;
2806
2849
  };
2850
+ var realCallProfileActionPaths = {
2851
+ "collect-browser-proof": "/collect-browser-proof",
2852
+ "collect-phone-proof": "/collect-phone-proof",
2853
+ "collect-provider-role-evidence": "/collect-provider-role-evidence",
2854
+ refresh: "/refresh"
2855
+ };
2856
+ var loadVoiceRealCallProfileHistoryRouteReport = async (options) => {
2857
+ const { source, ...routeOptions } = options;
2858
+ const sourceOptions = source === undefined ? routeOptions : typeof source === "function" ? await source() : source;
2859
+ return buildVoiceRealCallProfileHistoryReport({
2860
+ ...routeOptions,
2861
+ ...sourceOptions
2862
+ });
2863
+ };
2864
+ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
2865
+ const path = options.path ?? "/api/voice/real-call-profile-history";
2866
+ const routes = new Elysia({
2867
+ name: options.name ?? "absolutejs-voice-real-call-profile-recovery-actions"
2868
+ });
2869
+ const actionPath = (actionId) => `${path}${realCallProfileActionPaths[actionId]}`;
2870
+ const loadReport = () => loadVoiceRealCallProfileHistoryRouteReport(options);
2871
+ const asyncActionIds = new Set(options.asyncActionIds ?? []);
2872
+ const listActions = async () => {
2873
+ const report = await loadReport();
2874
+ const actions = buildVoiceRealCallProfileRecoveryActions(report, {
2875
+ ...options,
2876
+ browserProofHref: options.browserProofHref ?? actionPath("collect-browser-proof"),
2877
+ phoneProofHref: options.phoneProofHref ?? actionPath("collect-phone-proof"),
2878
+ sourceHref: options.sourceHref ?? actionPath("collect-provider-role-evidence"),
2879
+ productionReadinessHref: options.productionReadinessHref ?? actionPath("refresh")
2880
+ }).map((action) => ({
2881
+ ...action,
2882
+ href: action.id === "collect-browser-proof" ? actionPath("collect-browser-proof") : action.id === "collect-phone-proof" ? actionPath("collect-phone-proof") : action.id === "collect-provider-role-evidence" ? actionPath("collect-provider-role-evidence") : action.href,
2883
+ method: action.id === "refresh" && (action.label === "Open real-call profile history" || action.label === "Open operations records") ? "GET" : "POST"
2884
+ }));
2885
+ return { actions, generatedAt: new Date().toISOString(), report };
2886
+ };
2887
+ const runActionHandler = async (actionId, report) => {
2888
+ const handler = options.handlers?.[actionId];
2889
+ if (!handler) {
2890
+ return;
2891
+ }
2892
+ return await handler({ actionId, report });
2893
+ };
2894
+ const runActionAsJob = async (actionId, report) => {
2895
+ const job = await options.jobStore?.create({
2896
+ actionId,
2897
+ message: `Queued real-call profile recovery action: ${actionId}.`,
2898
+ status: "queued"
2899
+ });
2900
+ if (!job) {
2901
+ return;
2902
+ }
2903
+ queueMicrotask(() => {
2904
+ (async () => {
2905
+ const startedAt = new Date().toISOString();
2906
+ await options.jobStore?.update(job.id, {
2907
+ message: `Running real-call profile recovery action: ${actionId}.`,
2908
+ startedAt,
2909
+ status: "running",
2910
+ updatedAt: startedAt
2911
+ });
2912
+ try {
2913
+ const result = await runActionHandler(actionId, report);
2914
+ const completedAt = new Date().toISOString();
2915
+ const ok = result?.ok ?? true;
2916
+ const status = result?.jobStatus ?? (result?.status === "fail" || ok === false ? "fail" : "pass");
2917
+ await options.jobStore?.update(job.id, {
2918
+ completedAt,
2919
+ message: result?.message ?? `Completed real-call profile recovery action: ${actionId}.`,
2920
+ ok,
2921
+ report: result?.report,
2922
+ status,
2923
+ updatedAt: completedAt
2924
+ });
2925
+ } catch (error) {
2926
+ const completedAt = new Date().toISOString();
2927
+ await options.jobStore?.update(job.id, {
2928
+ completedAt,
2929
+ message: error instanceof Error ? error.message : `Failed real-call profile recovery action: ${actionId}.`,
2930
+ ok: false,
2931
+ status: "fail",
2932
+ updatedAt: completedAt
2933
+ });
2934
+ }
2935
+ })();
2936
+ });
2937
+ return {
2938
+ actionId,
2939
+ generatedAt: new Date().toISOString(),
2940
+ job,
2941
+ jobId: job.id,
2942
+ jobStatus: job.status,
2943
+ message: job.message,
2944
+ ok: true,
2945
+ status: "pass"
2946
+ };
2947
+ };
2948
+ const runAction = async (actionId) => {
2949
+ const report = await loadReport();
2950
+ const handler = options.handlers?.[actionId];
2951
+ if (!handler) {
2952
+ return {
2953
+ actionId,
2954
+ generatedAt: new Date().toISOString(),
2955
+ message: `No handler configured for real-call profile recovery action: ${actionId}.`,
2956
+ ok: false,
2957
+ status: "fail"
2958
+ };
2959
+ }
2960
+ if (options.jobStore && asyncActionIds.has(actionId)) {
2961
+ const queued = await runActionAsJob(actionId, report);
2962
+ if (queued) {
2963
+ return queued;
2964
+ }
2965
+ }
2966
+ const result = await runActionHandler(actionId, report);
2967
+ return {
2968
+ actionId,
2969
+ generatedAt: new Date().toISOString(),
2970
+ job: result?.job,
2971
+ jobId: result?.jobId,
2972
+ jobStatus: result?.jobStatus,
2973
+ message: result?.message,
2974
+ ok: result?.ok ?? true,
2975
+ report: result?.report,
2976
+ status: result?.status ?? "pass"
2977
+ };
2978
+ };
2979
+ routes.get(`${path}/actions`, async () => Response.json(await listActions(), { headers: options.headers }));
2980
+ routes.get(`${path}/actions/:jobId`, async ({
2981
+ params,
2982
+ set
2983
+ }) => {
2984
+ const jobId = params.jobId ?? "";
2985
+ const job = await options.jobStore?.get(jobId);
2986
+ if (!job) {
2987
+ set.status = 404;
2988
+ return Response.json({
2989
+ jobId,
2990
+ message: `No real-call profile recovery job found for id: ${jobId}.`,
2991
+ ok: false
2992
+ }, { headers: options.headers });
2993
+ }
2994
+ return Response.json({ job, ok: job.ok ?? job.status !== "fail" }, {
2995
+ headers: options.headers
2996
+ });
2997
+ });
2998
+ for (const actionId of Object.keys(realCallProfileActionPaths)) {
2999
+ routes.post(actionPath(actionId), async ({ set }) => {
3000
+ const result = await runAction(actionId);
3001
+ if (!result.ok) {
3002
+ set.status = 501;
3003
+ }
3004
+ return Response.json(result, { headers: options.headers });
3005
+ });
3006
+ }
3007
+ return routes;
3008
+ };
2807
3009
  var createVoiceProofTrendRoutes = (options) => {
2808
3010
  const path = options.path ?? "/api/voice/proof-trends";
2809
3011
  const routes = new Elysia({
package/dist/vue/index.js CHANGED
@@ -2079,11 +2079,13 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
2079
2079
  {
2080
2080
  description: "Open the current real-call profile history report and profile defaults.",
2081
2081
  href: options.href ?? "/voice/real-call-profile-history",
2082
+ id: "refresh",
2082
2083
  label: "Open real-call profile history"
2083
2084
  },
2084
2085
  {
2085
2086
  description: "Refresh production readiness after collecting or replaying profile evidence.",
2086
2087
  href: options.productionReadinessHref ?? "/production-readiness",
2088
+ id: "refresh",
2087
2089
  label: "Refresh production readiness"
2088
2090
  }
2089
2091
  ];
@@ -2097,11 +2099,13 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
2097
2099
  actions.push({
2098
2100
  description: "Run browser profile proof to collect microphone, WebSocket, live-latency, and provider traces for missing profiles.",
2099
2101
  href: options.browserProofHref ?? "/voice/browser-call-profiles",
2102
+ id: "collect-browser-proof",
2100
2103
  label: "Run browser profile proof"
2101
2104
  });
2102
2105
  actions.push({
2103
2106
  description: "Run phone profile proof when required profiles depend on carrier, telephony media, or noisy-call evidence.",
2104
2107
  href: options.phoneProofHref ?? "/api/voice/phone/smoke",
2108
+ id: "collect-phone-proof",
2105
2109
  label: "Run phone profile proof"
2106
2110
  });
2107
2111
  }
@@ -2109,6 +2113,7 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
2109
2113
  actions.push({
2110
2114
  description: "Collect fresh real-call profile traces because the current history artifact is stale.",
2111
2115
  href: options.browserProofHref ?? "/voice/browser-call-profiles",
2116
+ id: "collect-browser-proof",
2112
2117
  label: "Collect fresh profile evidence"
2113
2118
  });
2114
2119
  }
@@ -2116,6 +2121,7 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
2116
2121
  actions.push({
2117
2122
  description: "Collect missing LLM/STT/TTS provider-role evidence so profile defaults can become actionable.",
2118
2123
  href: options.sourceHref ?? "/api/voice/real-call-profile-history",
2124
+ id: "collect-provider-role-evidence",
2119
2125
  label: "Collect missing provider-role evidence"
2120
2126
  });
2121
2127
  }
@@ -2123,11 +2129,48 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
2123
2129
  actions.push({
2124
2130
  description: "Open operations records to inspect the sessions behind failing or warning profile evidence.",
2125
2131
  href: options.operationsRecordsHref ?? "/voice-operations",
2132
+ id: "refresh",
2126
2133
  label: "Open operations records"
2127
2134
  });
2128
2135
  }
2129
2136
  return uniqueRealCallProfileActions(actions);
2130
2137
  };
2138
+ var createVoiceInMemoryRealCallProfileRecoveryJobStore = (options = {}) => {
2139
+ const jobs = new Map;
2140
+ const now = () => (options.now ?? (() => new Date))().toISOString();
2141
+ const createId = () => `${options.idPrefix ?? "voice-recovery-job"}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
2142
+ return {
2143
+ create(input) {
2144
+ const createdAt = input.createdAt ?? now();
2145
+ const job = {
2146
+ actionId: input.actionId,
2147
+ createdAt,
2148
+ id: input.id ?? createId(),
2149
+ message: input.message,
2150
+ status: input.status ?? "queued",
2151
+ updatedAt: createdAt
2152
+ };
2153
+ jobs.set(job.id, job);
2154
+ return job;
2155
+ },
2156
+ get(id) {
2157
+ return jobs.get(id);
2158
+ },
2159
+ update(id, update) {
2160
+ const existing = jobs.get(id);
2161
+ if (!existing) {
2162
+ return;
2163
+ }
2164
+ const next = {
2165
+ ...existing,
2166
+ ...update,
2167
+ updatedAt: update.updatedAt ?? now()
2168
+ };
2169
+ jobs.set(id, next);
2170
+ return next;
2171
+ }
2172
+ };
2173
+ };
2131
2174
  var buildVoiceRealCallProfileReadinessCheck = (report, options = {}) => {
2132
2175
  const { issues, warnings } = buildRealCallProfileReadinessIssues(report, options);
2133
2176
  const status = issues.length > 0 ? "fail" : warnings.length > 0 && options.failOnWarnings === true ? "fail" : warnings.length > 0 ? "warn" : "pass";
@@ -2725,6 +2768,165 @@ var createVoiceRealCallProfileHistoryRoutes = (options = {}) => {
2725
2768
  }
2726
2769
  return routes;
2727
2770
  };
2771
+ var realCallProfileActionPaths = {
2772
+ "collect-browser-proof": "/collect-browser-proof",
2773
+ "collect-phone-proof": "/collect-phone-proof",
2774
+ "collect-provider-role-evidence": "/collect-provider-role-evidence",
2775
+ refresh: "/refresh"
2776
+ };
2777
+ var loadVoiceRealCallProfileHistoryRouteReport = async (options) => {
2778
+ const { source, ...routeOptions } = options;
2779
+ const sourceOptions = source === undefined ? routeOptions : typeof source === "function" ? await source() : source;
2780
+ return buildVoiceRealCallProfileHistoryReport({
2781
+ ...routeOptions,
2782
+ ...sourceOptions
2783
+ });
2784
+ };
2785
+ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
2786
+ const path = options.path ?? "/api/voice/real-call-profile-history";
2787
+ const routes = new Elysia({
2788
+ name: options.name ?? "absolutejs-voice-real-call-profile-recovery-actions"
2789
+ });
2790
+ const actionPath = (actionId) => `${path}${realCallProfileActionPaths[actionId]}`;
2791
+ const loadReport = () => loadVoiceRealCallProfileHistoryRouteReport(options);
2792
+ const asyncActionIds = new Set(options.asyncActionIds ?? []);
2793
+ const listActions = async () => {
2794
+ const report = await loadReport();
2795
+ const actions = buildVoiceRealCallProfileRecoveryActions(report, {
2796
+ ...options,
2797
+ browserProofHref: options.browserProofHref ?? actionPath("collect-browser-proof"),
2798
+ phoneProofHref: options.phoneProofHref ?? actionPath("collect-phone-proof"),
2799
+ sourceHref: options.sourceHref ?? actionPath("collect-provider-role-evidence"),
2800
+ productionReadinessHref: options.productionReadinessHref ?? actionPath("refresh")
2801
+ }).map((action) => ({
2802
+ ...action,
2803
+ href: action.id === "collect-browser-proof" ? actionPath("collect-browser-proof") : action.id === "collect-phone-proof" ? actionPath("collect-phone-proof") : action.id === "collect-provider-role-evidence" ? actionPath("collect-provider-role-evidence") : action.href,
2804
+ method: action.id === "refresh" && (action.label === "Open real-call profile history" || action.label === "Open operations records") ? "GET" : "POST"
2805
+ }));
2806
+ return { actions, generatedAt: new Date().toISOString(), report };
2807
+ };
2808
+ const runActionHandler = async (actionId, report) => {
2809
+ const handler = options.handlers?.[actionId];
2810
+ if (!handler) {
2811
+ return;
2812
+ }
2813
+ return await handler({ actionId, report });
2814
+ };
2815
+ const runActionAsJob = async (actionId, report) => {
2816
+ const job = await options.jobStore?.create({
2817
+ actionId,
2818
+ message: `Queued real-call profile recovery action: ${actionId}.`,
2819
+ status: "queued"
2820
+ });
2821
+ if (!job) {
2822
+ return;
2823
+ }
2824
+ queueMicrotask(() => {
2825
+ (async () => {
2826
+ const startedAt = new Date().toISOString();
2827
+ await options.jobStore?.update(job.id, {
2828
+ message: `Running real-call profile recovery action: ${actionId}.`,
2829
+ startedAt,
2830
+ status: "running",
2831
+ updatedAt: startedAt
2832
+ });
2833
+ try {
2834
+ const result = await runActionHandler(actionId, report);
2835
+ const completedAt = new Date().toISOString();
2836
+ const ok = result?.ok ?? true;
2837
+ const status = result?.jobStatus ?? (result?.status === "fail" || ok === false ? "fail" : "pass");
2838
+ await options.jobStore?.update(job.id, {
2839
+ completedAt,
2840
+ message: result?.message ?? `Completed real-call profile recovery action: ${actionId}.`,
2841
+ ok,
2842
+ report: result?.report,
2843
+ status,
2844
+ updatedAt: completedAt
2845
+ });
2846
+ } catch (error) {
2847
+ const completedAt = new Date().toISOString();
2848
+ await options.jobStore?.update(job.id, {
2849
+ completedAt,
2850
+ message: error instanceof Error ? error.message : `Failed real-call profile recovery action: ${actionId}.`,
2851
+ ok: false,
2852
+ status: "fail",
2853
+ updatedAt: completedAt
2854
+ });
2855
+ }
2856
+ })();
2857
+ });
2858
+ return {
2859
+ actionId,
2860
+ generatedAt: new Date().toISOString(),
2861
+ job,
2862
+ jobId: job.id,
2863
+ jobStatus: job.status,
2864
+ message: job.message,
2865
+ ok: true,
2866
+ status: "pass"
2867
+ };
2868
+ };
2869
+ const runAction = async (actionId) => {
2870
+ const report = await loadReport();
2871
+ const handler = options.handlers?.[actionId];
2872
+ if (!handler) {
2873
+ return {
2874
+ actionId,
2875
+ generatedAt: new Date().toISOString(),
2876
+ message: `No handler configured for real-call profile recovery action: ${actionId}.`,
2877
+ ok: false,
2878
+ status: "fail"
2879
+ };
2880
+ }
2881
+ if (options.jobStore && asyncActionIds.has(actionId)) {
2882
+ const queued = await runActionAsJob(actionId, report);
2883
+ if (queued) {
2884
+ return queued;
2885
+ }
2886
+ }
2887
+ const result = await runActionHandler(actionId, report);
2888
+ return {
2889
+ actionId,
2890
+ generatedAt: new Date().toISOString(),
2891
+ job: result?.job,
2892
+ jobId: result?.jobId,
2893
+ jobStatus: result?.jobStatus,
2894
+ message: result?.message,
2895
+ ok: result?.ok ?? true,
2896
+ report: result?.report,
2897
+ status: result?.status ?? "pass"
2898
+ };
2899
+ };
2900
+ routes.get(`${path}/actions`, async () => Response.json(await listActions(), { headers: options.headers }));
2901
+ routes.get(`${path}/actions/:jobId`, async ({
2902
+ params,
2903
+ set
2904
+ }) => {
2905
+ const jobId = params.jobId ?? "";
2906
+ const job = await options.jobStore?.get(jobId);
2907
+ if (!job) {
2908
+ set.status = 404;
2909
+ return Response.json({
2910
+ jobId,
2911
+ message: `No real-call profile recovery job found for id: ${jobId}.`,
2912
+ ok: false
2913
+ }, { headers: options.headers });
2914
+ }
2915
+ return Response.json({ job, ok: job.ok ?? job.status !== "fail" }, {
2916
+ headers: options.headers
2917
+ });
2918
+ });
2919
+ for (const actionId of Object.keys(realCallProfileActionPaths)) {
2920
+ routes.post(actionPath(actionId), async ({ set }) => {
2921
+ const result = await runAction(actionId);
2922
+ if (!result.ok) {
2923
+ set.status = 501;
2924
+ }
2925
+ return Response.json(result, { headers: options.headers });
2926
+ });
2927
+ }
2928
+ return routes;
2929
+ };
2728
2930
  var createVoiceProofTrendRoutes = (options) => {
2729
2931
  const path = options.path ?? "/api/voice/proof-trends";
2730
2932
  const routes = new Elysia({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.371",
3
+ "version": "0.0.22-beta.373",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",