@absolutejs/voice 0.0.22-beta.372 → 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
@@ -1519,6 +1519,24 @@ app.use(
1519
1519
  );
1520
1520
  ```
1521
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
+
1522
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.
1523
1541
 
1524
1542
  ```ts
@@ -4627,6 +4627,42 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
4627
4627
  }
4628
4628
  return uniqueRealCallProfileActions(actions);
4629
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
+ };
4630
4666
  var buildVoiceRealCallProfileReadinessCheck = (report, options = {}) => {
4631
4667
  const { issues, warnings } = buildRealCallProfileReadinessIssues(report, options);
4632
4668
  const status = issues.length > 0 ? "fail" : warnings.length > 0 && options.failOnWarnings === true ? "fail" : warnings.length > 0 ? "warn" : "pass";
@@ -5245,6 +5281,7 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
5245
5281
  });
5246
5282
  const actionPath = (actionId) => `${path}${realCallProfileActionPaths[actionId]}`;
5247
5283
  const loadReport = () => loadVoiceRealCallProfileHistoryRouteReport(options);
5284
+ const asyncActionIds = new Set(options.asyncActionIds ?? []);
5248
5285
  const listActions = async () => {
5249
5286
  const report = await loadReport();
5250
5287
  const actions = buildVoiceRealCallProfileRecoveryActions(report, {
@@ -5260,6 +5297,67 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
5260
5297
  }));
5261
5298
  return { actions, generatedAt: new Date().toISOString(), report };
5262
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
+ };
5263
5361
  const runAction = async (actionId) => {
5264
5362
  const report = await loadReport();
5265
5363
  const handler = options.handlers?.[actionId];
@@ -5272,10 +5370,19 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
5272
5370
  status: "fail"
5273
5371
  };
5274
5372
  }
5275
- const result = await handler({ actionId, report });
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);
5276
5380
  return {
5277
5381
  actionId,
5278
5382
  generatedAt: new Date().toISOString(),
5383
+ job: result?.job,
5384
+ jobId: result?.jobId,
5385
+ jobStatus: result?.jobStatus,
5279
5386
  message: result?.message,
5280
5387
  ok: result?.ok ?? true,
5281
5388
  report: result?.report,
@@ -5283,6 +5390,24 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
5283
5390
  };
5284
5391
  };
5285
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
+ });
5286
5411
  for (const actionId of Object.keys(realCallProfileActionPaths)) {
5287
5412
  routes.post(actionPath(actionId), async ({ set }) => {
5288
5413
  const result = await runAction(actionId);
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, 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';
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, VoiceRealCallProfileRecoveryAction, VoiceRealCallProfileRecoveryActionHandler, VoiceRealCallProfileRecoveryActionHandlerInput, VoiceRealCallProfileRecoveryActionId, VoiceRealCallProfileRecoveryActionResult, VoiceRealCallProfileRecoveryActionRoutesOptions, 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
@@ -16096,6 +16096,42 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
16096
16096
  }
16097
16097
  return uniqueRealCallProfileActions(actions);
16098
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
+ };
16099
16135
  var buildVoiceRealCallProfileReadinessCheck = (report, options = {}) => {
16100
16136
  const { issues, warnings } = buildRealCallProfileReadinessIssues(report, options);
16101
16137
  const status = issues.length > 0 ? "fail" : warnings.length > 0 && options.failOnWarnings === true ? "fail" : warnings.length > 0 ? "warn" : "pass";
@@ -16714,6 +16750,7 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
16714
16750
  });
16715
16751
  const actionPath = (actionId) => `${path}${realCallProfileActionPaths[actionId]}`;
16716
16752
  const loadReport = () => loadVoiceRealCallProfileHistoryRouteReport(options);
16753
+ const asyncActionIds = new Set(options.asyncActionIds ?? []);
16717
16754
  const listActions = async () => {
16718
16755
  const report = await loadReport();
16719
16756
  const actions = buildVoiceRealCallProfileRecoveryActions(report, {
@@ -16729,6 +16766,67 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
16729
16766
  }));
16730
16767
  return { actions, generatedAt: new Date().toISOString(), report };
16731
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
+ };
16732
16830
  const runAction = async (actionId) => {
16733
16831
  const report = await loadReport();
16734
16832
  const handler = options.handlers?.[actionId];
@@ -16741,10 +16839,19 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
16741
16839
  status: "fail"
16742
16840
  };
16743
16841
  }
16744
- const result = await handler({ actionId, report });
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);
16745
16849
  return {
16746
16850
  actionId,
16747
16851
  generatedAt: new Date().toISOString(),
16852
+ job: result?.job,
16853
+ jobId: result?.jobId,
16854
+ jobStatus: result?.jobStatus,
16748
16855
  message: result?.message,
16749
16856
  ok: result?.ok ?? true,
16750
16857
  report: result?.report,
@@ -16752,6 +16859,24 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
16752
16859
  };
16753
16860
  };
16754
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
+ });
16755
16880
  for (const actionId of Object.keys(realCallProfileActionPaths)) {
16756
16881
  routes.post(actionPath(actionId), async ({ set }) => {
16757
16882
  const result = await runAction(actionId);
@@ -38932,6 +39057,7 @@ export {
38932
39057
  createVoiceIntegrationHTTPSink,
38933
39058
  createVoiceIntegrationEvent,
38934
39059
  createVoiceIncidentBundleRoutes,
39060
+ createVoiceInMemoryRealCallProfileRecoveryJobStore,
38935
39061
  createVoiceHubSpotTaskUpdateSink,
38936
39062
  createVoiceHubSpotTaskSyncSinks,
38937
39063
  createVoiceHubSpotTaskSink,
@@ -384,14 +384,45 @@ export type VoiceRealCallProfileRecoveryActionHandlerInput = {
384
384
  export type VoiceRealCallProfileRecoveryActionResult = {
385
385
  actionId: VoiceRealCallProfileRecoveryActionId;
386
386
  generatedAt: string;
387
+ job?: VoiceRealCallProfileRecoveryJob;
388
+ jobId?: string;
389
+ jobStatus?: VoiceRealCallProfileRecoveryJobStatus;
387
390
  message?: string;
388
391
  ok: boolean;
389
392
  report?: VoiceRealCallProfileHistoryReport;
390
393
  status: VoiceProofTrendStatus;
391
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
+ };
392
421
  export type VoiceRealCallProfileRecoveryActionHandler = (input: VoiceRealCallProfileRecoveryActionHandlerInput) => Promise<Partial<VoiceRealCallProfileRecoveryActionResult> | void> | Partial<VoiceRealCallProfileRecoveryActionResult> | void;
393
422
  export type VoiceRealCallProfileRecoveryActionRoutesOptions = VoiceRealCallProfileRecoveryActionOptions & Omit<VoiceRealCallProfileHistoryRoutesOptions, 'htmlPath' | 'markdownPath'> & {
423
+ asyncActionIds?: readonly VoiceRealCallProfileRecoveryActionId[];
394
424
  handlers?: Partial<Record<VoiceRealCallProfileRecoveryActionId, VoiceRealCallProfileRecoveryActionHandler>>;
425
+ jobStore?: VoiceRealCallProfileRecoveryJobStore;
395
426
  };
396
427
  export declare const DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS: number;
397
428
  export declare const DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS: ({
@@ -427,6 +458,10 @@ export declare const buildVoiceProofTrendProfileSummaries: (input: VoiceProofTre
427
458
  export declare const buildVoiceProofTrendReportFromRealCallProfiles: (options: VoiceProofTrendRealCallProfileReportOptions) => VoiceProofTrendReport;
428
459
  export declare const buildVoiceRealCallProfileDefaults: (input: VoiceRealCallProfileHistoryReport | VoiceProofTrendReport, options?: VoiceRealCallProfileDefaultsOptions) => VoiceRealCallProfileDefaultsReport;
429
460
  export declare const buildVoiceRealCallProfileRecoveryActions: (report: VoiceRealCallProfileHistoryReport, options?: VoiceRealCallProfileRecoveryActionOptions) => VoiceRealCallProfileRecoveryAction[];
461
+ export declare const createVoiceInMemoryRealCallProfileRecoveryJobStore: (options?: {
462
+ idPrefix?: string;
463
+ now?: () => Date;
464
+ }) => VoiceRealCallProfileRecoveryJobStore;
430
465
  export declare const buildVoiceRealCallProfileReadinessCheck: (report: VoiceRealCallProfileHistoryReport, options?: VoiceRealCallProfileReadinessCheckOptions) => VoiceProductionReadinessCheck;
431
466
  export declare const resolveVoiceRealCallProfileProviderRoute: <TProvider extends string = string>(options: VoiceRealCallProfileProviderRouteOptions<TProvider>) => TProvider | undefined;
432
467
  export declare const buildVoiceRealCallProfileHistoryReport: (options?: VoiceRealCallProfileHistoryOptions) => VoiceRealCallProfileHistoryReport;
@@ -2214,6 +2214,42 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
2214
2214
  }
2215
2215
  return uniqueRealCallProfileActions(actions);
2216
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
+ };
2217
2253
  var buildVoiceRealCallProfileReadinessCheck = (report, options = {}) => {
2218
2254
  const { issues, warnings } = buildRealCallProfileReadinessIssues(report, options);
2219
2255
  const status = issues.length > 0 ? "fail" : warnings.length > 0 && options.failOnWarnings === true ? "fail" : warnings.length > 0 ? "warn" : "pass";
@@ -2832,6 +2868,7 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
2832
2868
  });
2833
2869
  const actionPath = (actionId) => `${path}${realCallProfileActionPaths[actionId]}`;
2834
2870
  const loadReport = () => loadVoiceRealCallProfileHistoryRouteReport(options);
2871
+ const asyncActionIds = new Set(options.asyncActionIds ?? []);
2835
2872
  const listActions = async () => {
2836
2873
  const report = await loadReport();
2837
2874
  const actions = buildVoiceRealCallProfileRecoveryActions(report, {
@@ -2847,6 +2884,67 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
2847
2884
  }));
2848
2885
  return { actions, generatedAt: new Date().toISOString(), report };
2849
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
+ };
2850
2948
  const runAction = async (actionId) => {
2851
2949
  const report = await loadReport();
2852
2950
  const handler = options.handlers?.[actionId];
@@ -2859,10 +2957,19 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
2859
2957
  status: "fail"
2860
2958
  };
2861
2959
  }
2862
- const result = await handler({ actionId, report });
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);
2863
2967
  return {
2864
2968
  actionId,
2865
2969
  generatedAt: new Date().toISOString(),
2970
+ job: result?.job,
2971
+ jobId: result?.jobId,
2972
+ jobStatus: result?.jobStatus,
2866
2973
  message: result?.message,
2867
2974
  ok: result?.ok ?? true,
2868
2975
  report: result?.report,
@@ -2870,6 +2977,24 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
2870
2977
  };
2871
2978
  };
2872
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
+ });
2873
2998
  for (const actionId of Object.keys(realCallProfileActionPaths)) {
2874
2999
  routes.post(actionPath(actionId), async ({ set }) => {
2875
3000
  const result = await runAction(actionId);
package/dist/vue/index.js CHANGED
@@ -2135,6 +2135,42 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
2135
2135
  }
2136
2136
  return uniqueRealCallProfileActions(actions);
2137
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
+ };
2138
2174
  var buildVoiceRealCallProfileReadinessCheck = (report, options = {}) => {
2139
2175
  const { issues, warnings } = buildRealCallProfileReadinessIssues(report, options);
2140
2176
  const status = issues.length > 0 ? "fail" : warnings.length > 0 && options.failOnWarnings === true ? "fail" : warnings.length > 0 ? "warn" : "pass";
@@ -2753,6 +2789,7 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
2753
2789
  });
2754
2790
  const actionPath = (actionId) => `${path}${realCallProfileActionPaths[actionId]}`;
2755
2791
  const loadReport = () => loadVoiceRealCallProfileHistoryRouteReport(options);
2792
+ const asyncActionIds = new Set(options.asyncActionIds ?? []);
2756
2793
  const listActions = async () => {
2757
2794
  const report = await loadReport();
2758
2795
  const actions = buildVoiceRealCallProfileRecoveryActions(report, {
@@ -2768,6 +2805,67 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
2768
2805
  }));
2769
2806
  return { actions, generatedAt: new Date().toISOString(), report };
2770
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
+ };
2771
2869
  const runAction = async (actionId) => {
2772
2870
  const report = await loadReport();
2773
2871
  const handler = options.handlers?.[actionId];
@@ -2780,10 +2878,19 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
2780
2878
  status: "fail"
2781
2879
  };
2782
2880
  }
2783
- const result = await handler({ actionId, report });
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);
2784
2888
  return {
2785
2889
  actionId,
2786
2890
  generatedAt: new Date().toISOString(),
2891
+ job: result?.job,
2892
+ jobId: result?.jobId,
2893
+ jobStatus: result?.jobStatus,
2787
2894
  message: result?.message,
2788
2895
  ok: result?.ok ?? true,
2789
2896
  report: result?.report,
@@ -2791,6 +2898,24 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
2791
2898
  };
2792
2899
  };
2793
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
+ });
2794
2919
  for (const actionId of Object.keys(realCallProfileActionPaths)) {
2795
2920
  routes.post(actionPath(actionId), async ({ set }) => {
2796
2921
  const result = await runAction(actionId);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.372",
3
+ "version": "0.0.22-beta.373",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",