@absolutejs/voice 0.0.22-beta.372 → 0.0.22-beta.374
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 +26 -0
- package/dist/client/index.js +183 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +194 -10
- package/dist/proofTrends.d.ts +44 -0
- package/dist/react/index.js +183 -1
- package/dist/vue/index.js +183 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1519,6 +1519,32 @@ 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
|
+
|
|
1540
|
+
Use the SQLite job store when recovery jobs should survive restarts:
|
|
1541
|
+
|
|
1542
|
+
```ts
|
|
1543
|
+
const recoveryJobs = createVoiceSQLiteRealCallProfileRecoveryJobStore({
|
|
1544
|
+
path: '.voice-runtime/real-call-recovery/jobs.sqlite'
|
|
1545
|
+
});
|
|
1546
|
+
```
|
|
1547
|
+
|
|
1522
1548
|
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
1549
|
|
|
1524
1550
|
```ts
|
package/dist/client/index.js
CHANGED
|
@@ -3907,6 +3907,7 @@ var defineVoicePlatformCoverageElement = (tagName = "absolute-voice-platform-cov
|
|
|
3907
3907
|
};
|
|
3908
3908
|
// src/proofTrends.ts
|
|
3909
3909
|
import { Elysia } from "elysia";
|
|
3910
|
+
import { Database } from "bun:sqlite";
|
|
3910
3911
|
var DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
3911
3912
|
var DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS = [
|
|
3912
3913
|
{
|
|
@@ -4627,6 +4628,98 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
|
|
|
4627
4628
|
}
|
|
4628
4629
|
return uniqueRealCallProfileActions(actions);
|
|
4629
4630
|
};
|
|
4631
|
+
var createVoiceInMemoryRealCallProfileRecoveryJobStore = (options = {}) => {
|
|
4632
|
+
const jobs = new Map;
|
|
4633
|
+
const now = () => (options.now ?? (() => new Date))().toISOString();
|
|
4634
|
+
const createId = () => `${options.idPrefix ?? "voice-recovery-job"}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
4635
|
+
return {
|
|
4636
|
+
create(input) {
|
|
4637
|
+
const createdAt = input.createdAt ?? now();
|
|
4638
|
+
const job = {
|
|
4639
|
+
actionId: input.actionId,
|
|
4640
|
+
createdAt,
|
|
4641
|
+
id: input.id ?? createId(),
|
|
4642
|
+
message: input.message,
|
|
4643
|
+
status: input.status ?? "queued",
|
|
4644
|
+
updatedAt: createdAt
|
|
4645
|
+
};
|
|
4646
|
+
jobs.set(job.id, job);
|
|
4647
|
+
return job;
|
|
4648
|
+
},
|
|
4649
|
+
get(id) {
|
|
4650
|
+
return jobs.get(id);
|
|
4651
|
+
},
|
|
4652
|
+
update(id, update) {
|
|
4653
|
+
const existing = jobs.get(id);
|
|
4654
|
+
if (!existing) {
|
|
4655
|
+
return;
|
|
4656
|
+
}
|
|
4657
|
+
const next = {
|
|
4658
|
+
...existing,
|
|
4659
|
+
...update,
|
|
4660
|
+
updatedAt: update.updatedAt ?? now()
|
|
4661
|
+
};
|
|
4662
|
+
jobs.set(id, next);
|
|
4663
|
+
return next;
|
|
4664
|
+
}
|
|
4665
|
+
};
|
|
4666
|
+
};
|
|
4667
|
+
var normalizeRealCallRecoveryJobTableName = (value) => value.trim().replace(/[^a-zA-Z0-9_]+/g, "_").replace(/^_+|_+$/g, "") || "voice_real_call_profile_recovery_jobs";
|
|
4668
|
+
var createVoiceSQLiteRealCallProfileRecoveryJobStore = (options = {}) => {
|
|
4669
|
+
const database = options.database ?? new Database(options.path ?? ":memory:", {
|
|
4670
|
+
create: true
|
|
4671
|
+
});
|
|
4672
|
+
const tableName = normalizeRealCallRecoveryJobTableName(options.tableName ?? "voice_real_call_profile_recovery_jobs");
|
|
4673
|
+
const now = () => (options.now ?? (() => new Date))().toISOString();
|
|
4674
|
+
const createId = () => `${options.idPrefix ?? "voice-recovery-job"}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
4675
|
+
database.exec("PRAGMA journal_mode = WAL;");
|
|
4676
|
+
database.exec("PRAGMA synchronous = NORMAL;");
|
|
4677
|
+
database.exec("PRAGMA busy_timeout = 5000;");
|
|
4678
|
+
database.exec(`CREATE TABLE IF NOT EXISTS "${tableName}" (
|
|
4679
|
+
id TEXT PRIMARY KEY,
|
|
4680
|
+
sort_at INTEGER NOT NULL,
|
|
4681
|
+
payload TEXT NOT NULL
|
|
4682
|
+
)`);
|
|
4683
|
+
const selectStatement = database.query(`SELECT payload FROM "${tableName}" WHERE id = ?1 LIMIT 1`);
|
|
4684
|
+
const upsertStatement = database.query(`INSERT INTO "${tableName}" (id, sort_at, payload)
|
|
4685
|
+
VALUES (?1, ?2, ?3)
|
|
4686
|
+
ON CONFLICT(id) DO UPDATE SET sort_at = excluded.sort_at, payload = excluded.payload`);
|
|
4687
|
+
const writeJob = (job) => {
|
|
4688
|
+
upsertStatement.run(job.id, Date.parse(job.updatedAt) || Date.now(), JSON.stringify(job));
|
|
4689
|
+
return job;
|
|
4690
|
+
};
|
|
4691
|
+
const readJob = (id) => {
|
|
4692
|
+
const row = selectStatement.get(id);
|
|
4693
|
+
return row ? JSON.parse(row.payload) : undefined;
|
|
4694
|
+
};
|
|
4695
|
+
return {
|
|
4696
|
+
create(input) {
|
|
4697
|
+
const createdAt = input.createdAt ?? now();
|
|
4698
|
+
return writeJob({
|
|
4699
|
+
actionId: input.actionId,
|
|
4700
|
+
createdAt,
|
|
4701
|
+
id: input.id ?? createId(),
|
|
4702
|
+
message: input.message,
|
|
4703
|
+
status: input.status ?? "queued",
|
|
4704
|
+
updatedAt: createdAt
|
|
4705
|
+
});
|
|
4706
|
+
},
|
|
4707
|
+
get(id) {
|
|
4708
|
+
return readJob(id);
|
|
4709
|
+
},
|
|
4710
|
+
update(id, update) {
|
|
4711
|
+
const existing = readJob(id);
|
|
4712
|
+
if (!existing) {
|
|
4713
|
+
return;
|
|
4714
|
+
}
|
|
4715
|
+
return writeJob({
|
|
4716
|
+
...existing,
|
|
4717
|
+
...update,
|
|
4718
|
+
updatedAt: update.updatedAt ?? now()
|
|
4719
|
+
});
|
|
4720
|
+
}
|
|
4721
|
+
};
|
|
4722
|
+
};
|
|
4630
4723
|
var buildVoiceRealCallProfileReadinessCheck = (report, options = {}) => {
|
|
4631
4724
|
const { issues, warnings } = buildRealCallProfileReadinessIssues(report, options);
|
|
4632
4725
|
const status = issues.length > 0 ? "fail" : warnings.length > 0 && options.failOnWarnings === true ? "fail" : warnings.length > 0 ? "warn" : "pass";
|
|
@@ -5245,6 +5338,7 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
|
|
|
5245
5338
|
});
|
|
5246
5339
|
const actionPath = (actionId) => `${path}${realCallProfileActionPaths[actionId]}`;
|
|
5247
5340
|
const loadReport = () => loadVoiceRealCallProfileHistoryRouteReport(options);
|
|
5341
|
+
const asyncActionIds = new Set(options.asyncActionIds ?? []);
|
|
5248
5342
|
const listActions = async () => {
|
|
5249
5343
|
const report = await loadReport();
|
|
5250
5344
|
const actions = buildVoiceRealCallProfileRecoveryActions(report, {
|
|
@@ -5260,6 +5354,67 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
|
|
|
5260
5354
|
}));
|
|
5261
5355
|
return { actions, generatedAt: new Date().toISOString(), report };
|
|
5262
5356
|
};
|
|
5357
|
+
const runActionHandler = async (actionId, report) => {
|
|
5358
|
+
const handler = options.handlers?.[actionId];
|
|
5359
|
+
if (!handler) {
|
|
5360
|
+
return;
|
|
5361
|
+
}
|
|
5362
|
+
return await handler({ actionId, report });
|
|
5363
|
+
};
|
|
5364
|
+
const runActionAsJob = async (actionId, report) => {
|
|
5365
|
+
const job = await options.jobStore?.create({
|
|
5366
|
+
actionId,
|
|
5367
|
+
message: `Queued real-call profile recovery action: ${actionId}.`,
|
|
5368
|
+
status: "queued"
|
|
5369
|
+
});
|
|
5370
|
+
if (!job) {
|
|
5371
|
+
return;
|
|
5372
|
+
}
|
|
5373
|
+
queueMicrotask(() => {
|
|
5374
|
+
(async () => {
|
|
5375
|
+
const startedAt = new Date().toISOString();
|
|
5376
|
+
await options.jobStore?.update(job.id, {
|
|
5377
|
+
message: `Running real-call profile recovery action: ${actionId}.`,
|
|
5378
|
+
startedAt,
|
|
5379
|
+
status: "running",
|
|
5380
|
+
updatedAt: startedAt
|
|
5381
|
+
});
|
|
5382
|
+
try {
|
|
5383
|
+
const result = await runActionHandler(actionId, report);
|
|
5384
|
+
const completedAt = new Date().toISOString();
|
|
5385
|
+
const ok = result?.ok ?? true;
|
|
5386
|
+
const status = result?.jobStatus ?? (result?.status === "fail" || ok === false ? "fail" : "pass");
|
|
5387
|
+
await options.jobStore?.update(job.id, {
|
|
5388
|
+
completedAt,
|
|
5389
|
+
message: result?.message ?? `Completed real-call profile recovery action: ${actionId}.`,
|
|
5390
|
+
ok,
|
|
5391
|
+
report: result?.report,
|
|
5392
|
+
status,
|
|
5393
|
+
updatedAt: completedAt
|
|
5394
|
+
});
|
|
5395
|
+
} catch (error) {
|
|
5396
|
+
const completedAt = new Date().toISOString();
|
|
5397
|
+
await options.jobStore?.update(job.id, {
|
|
5398
|
+
completedAt,
|
|
5399
|
+
message: error instanceof Error ? error.message : `Failed real-call profile recovery action: ${actionId}.`,
|
|
5400
|
+
ok: false,
|
|
5401
|
+
status: "fail",
|
|
5402
|
+
updatedAt: completedAt
|
|
5403
|
+
});
|
|
5404
|
+
}
|
|
5405
|
+
})();
|
|
5406
|
+
});
|
|
5407
|
+
return {
|
|
5408
|
+
actionId,
|
|
5409
|
+
generatedAt: new Date().toISOString(),
|
|
5410
|
+
job,
|
|
5411
|
+
jobId: job.id,
|
|
5412
|
+
jobStatus: job.status,
|
|
5413
|
+
message: job.message,
|
|
5414
|
+
ok: true,
|
|
5415
|
+
status: "pass"
|
|
5416
|
+
};
|
|
5417
|
+
};
|
|
5263
5418
|
const runAction = async (actionId) => {
|
|
5264
5419
|
const report = await loadReport();
|
|
5265
5420
|
const handler = options.handlers?.[actionId];
|
|
@@ -5272,10 +5427,19 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
|
|
|
5272
5427
|
status: "fail"
|
|
5273
5428
|
};
|
|
5274
5429
|
}
|
|
5275
|
-
|
|
5430
|
+
if (options.jobStore && asyncActionIds.has(actionId)) {
|
|
5431
|
+
const queued = await runActionAsJob(actionId, report);
|
|
5432
|
+
if (queued) {
|
|
5433
|
+
return queued;
|
|
5434
|
+
}
|
|
5435
|
+
}
|
|
5436
|
+
const result = await runActionHandler(actionId, report);
|
|
5276
5437
|
return {
|
|
5277
5438
|
actionId,
|
|
5278
5439
|
generatedAt: new Date().toISOString(),
|
|
5440
|
+
job: result?.job,
|
|
5441
|
+
jobId: result?.jobId,
|
|
5442
|
+
jobStatus: result?.jobStatus,
|
|
5279
5443
|
message: result?.message,
|
|
5280
5444
|
ok: result?.ok ?? true,
|
|
5281
5445
|
report: result?.report,
|
|
@@ -5283,6 +5447,24 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
|
|
|
5283
5447
|
};
|
|
5284
5448
|
};
|
|
5285
5449
|
routes.get(`${path}/actions`, async () => Response.json(await listActions(), { headers: options.headers }));
|
|
5450
|
+
routes.get(`${path}/actions/:jobId`, async ({
|
|
5451
|
+
params,
|
|
5452
|
+
set
|
|
5453
|
+
}) => {
|
|
5454
|
+
const jobId = params.jobId ?? "";
|
|
5455
|
+
const job = await options.jobStore?.get(jobId);
|
|
5456
|
+
if (!job) {
|
|
5457
|
+
set.status = 404;
|
|
5458
|
+
return Response.json({
|
|
5459
|
+
jobId,
|
|
5460
|
+
message: `No real-call profile recovery job found for id: ${jobId}.`,
|
|
5461
|
+
ok: false
|
|
5462
|
+
}, { headers: options.headers });
|
|
5463
|
+
}
|
|
5464
|
+
return Response.json({ job, ok: job.ok ?? job.status !== "fail" }, {
|
|
5465
|
+
headers: options.headers
|
|
5466
|
+
});
|
|
5467
|
+
});
|
|
5286
5468
|
for (const actionId of Object.keys(realCallProfileActionPaths)) {
|
|
5287
5469
|
routes.post(actionPath(actionId), async ({ set }) => {
|
|
5288
5470
|
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, createVoiceSQLiteRealCallProfileRecoveryJobStore, 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, VoiceSQLiteRealCallProfileRecoveryJobStoreOptions, 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
|
@@ -15376,6 +15376,7 @@ var createVoiceCompetitiveCoverageRoutes = (options) => {
|
|
|
15376
15376
|
};
|
|
15377
15377
|
// src/proofTrends.ts
|
|
15378
15378
|
import { Elysia as Elysia22 } from "elysia";
|
|
15379
|
+
import { Database } from "bun:sqlite";
|
|
15379
15380
|
var DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
15380
15381
|
var DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS = [
|
|
15381
15382
|
{
|
|
@@ -16096,6 +16097,98 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
|
|
|
16096
16097
|
}
|
|
16097
16098
|
return uniqueRealCallProfileActions(actions);
|
|
16098
16099
|
};
|
|
16100
|
+
var createVoiceInMemoryRealCallProfileRecoveryJobStore = (options = {}) => {
|
|
16101
|
+
const jobs = new Map;
|
|
16102
|
+
const now = () => (options.now ?? (() => new Date))().toISOString();
|
|
16103
|
+
const createId3 = () => `${options.idPrefix ?? "voice-recovery-job"}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
16104
|
+
return {
|
|
16105
|
+
create(input) {
|
|
16106
|
+
const createdAt = input.createdAt ?? now();
|
|
16107
|
+
const job = {
|
|
16108
|
+
actionId: input.actionId,
|
|
16109
|
+
createdAt,
|
|
16110
|
+
id: input.id ?? createId3(),
|
|
16111
|
+
message: input.message,
|
|
16112
|
+
status: input.status ?? "queued",
|
|
16113
|
+
updatedAt: createdAt
|
|
16114
|
+
};
|
|
16115
|
+
jobs.set(job.id, job);
|
|
16116
|
+
return job;
|
|
16117
|
+
},
|
|
16118
|
+
get(id) {
|
|
16119
|
+
return jobs.get(id);
|
|
16120
|
+
},
|
|
16121
|
+
update(id, update) {
|
|
16122
|
+
const existing = jobs.get(id);
|
|
16123
|
+
if (!existing) {
|
|
16124
|
+
return;
|
|
16125
|
+
}
|
|
16126
|
+
const next = {
|
|
16127
|
+
...existing,
|
|
16128
|
+
...update,
|
|
16129
|
+
updatedAt: update.updatedAt ?? now()
|
|
16130
|
+
};
|
|
16131
|
+
jobs.set(id, next);
|
|
16132
|
+
return next;
|
|
16133
|
+
}
|
|
16134
|
+
};
|
|
16135
|
+
};
|
|
16136
|
+
var normalizeRealCallRecoveryJobTableName = (value) => value.trim().replace(/[^a-zA-Z0-9_]+/g, "_").replace(/^_+|_+$/g, "") || "voice_real_call_profile_recovery_jobs";
|
|
16137
|
+
var createVoiceSQLiteRealCallProfileRecoveryJobStore = (options = {}) => {
|
|
16138
|
+
const database = options.database ?? new Database(options.path ?? ":memory:", {
|
|
16139
|
+
create: true
|
|
16140
|
+
});
|
|
16141
|
+
const tableName = normalizeRealCallRecoveryJobTableName(options.tableName ?? "voice_real_call_profile_recovery_jobs");
|
|
16142
|
+
const now = () => (options.now ?? (() => new Date))().toISOString();
|
|
16143
|
+
const createId3 = () => `${options.idPrefix ?? "voice-recovery-job"}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
16144
|
+
database.exec("PRAGMA journal_mode = WAL;");
|
|
16145
|
+
database.exec("PRAGMA synchronous = NORMAL;");
|
|
16146
|
+
database.exec("PRAGMA busy_timeout = 5000;");
|
|
16147
|
+
database.exec(`CREATE TABLE IF NOT EXISTS "${tableName}" (
|
|
16148
|
+
id TEXT PRIMARY KEY,
|
|
16149
|
+
sort_at INTEGER NOT NULL,
|
|
16150
|
+
payload TEXT NOT NULL
|
|
16151
|
+
)`);
|
|
16152
|
+
const selectStatement = database.query(`SELECT payload FROM "${tableName}" WHERE id = ?1 LIMIT 1`);
|
|
16153
|
+
const upsertStatement = database.query(`INSERT INTO "${tableName}" (id, sort_at, payload)
|
|
16154
|
+
VALUES (?1, ?2, ?3)
|
|
16155
|
+
ON CONFLICT(id) DO UPDATE SET sort_at = excluded.sort_at, payload = excluded.payload`);
|
|
16156
|
+
const writeJob = (job) => {
|
|
16157
|
+
upsertStatement.run(job.id, Date.parse(job.updatedAt) || Date.now(), JSON.stringify(job));
|
|
16158
|
+
return job;
|
|
16159
|
+
};
|
|
16160
|
+
const readJob = (id) => {
|
|
16161
|
+
const row = selectStatement.get(id);
|
|
16162
|
+
return row ? JSON.parse(row.payload) : undefined;
|
|
16163
|
+
};
|
|
16164
|
+
return {
|
|
16165
|
+
create(input) {
|
|
16166
|
+
const createdAt = input.createdAt ?? now();
|
|
16167
|
+
return writeJob({
|
|
16168
|
+
actionId: input.actionId,
|
|
16169
|
+
createdAt,
|
|
16170
|
+
id: input.id ?? createId3(),
|
|
16171
|
+
message: input.message,
|
|
16172
|
+
status: input.status ?? "queued",
|
|
16173
|
+
updatedAt: createdAt
|
|
16174
|
+
});
|
|
16175
|
+
},
|
|
16176
|
+
get(id) {
|
|
16177
|
+
return readJob(id);
|
|
16178
|
+
},
|
|
16179
|
+
update(id, update) {
|
|
16180
|
+
const existing = readJob(id);
|
|
16181
|
+
if (!existing) {
|
|
16182
|
+
return;
|
|
16183
|
+
}
|
|
16184
|
+
return writeJob({
|
|
16185
|
+
...existing,
|
|
16186
|
+
...update,
|
|
16187
|
+
updatedAt: update.updatedAt ?? now()
|
|
16188
|
+
});
|
|
16189
|
+
}
|
|
16190
|
+
};
|
|
16191
|
+
};
|
|
16099
16192
|
var buildVoiceRealCallProfileReadinessCheck = (report, options = {}) => {
|
|
16100
16193
|
const { issues, warnings } = buildRealCallProfileReadinessIssues(report, options);
|
|
16101
16194
|
const status = issues.length > 0 ? "fail" : warnings.length > 0 && options.failOnWarnings === true ? "fail" : warnings.length > 0 ? "warn" : "pass";
|
|
@@ -16714,6 +16807,7 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
|
|
|
16714
16807
|
});
|
|
16715
16808
|
const actionPath = (actionId) => `${path}${realCallProfileActionPaths[actionId]}`;
|
|
16716
16809
|
const loadReport = () => loadVoiceRealCallProfileHistoryRouteReport(options);
|
|
16810
|
+
const asyncActionIds = new Set(options.asyncActionIds ?? []);
|
|
16717
16811
|
const listActions = async () => {
|
|
16718
16812
|
const report = await loadReport();
|
|
16719
16813
|
const actions = buildVoiceRealCallProfileRecoveryActions(report, {
|
|
@@ -16729,6 +16823,67 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
|
|
|
16729
16823
|
}));
|
|
16730
16824
|
return { actions, generatedAt: new Date().toISOString(), report };
|
|
16731
16825
|
};
|
|
16826
|
+
const runActionHandler = async (actionId, report) => {
|
|
16827
|
+
const handler = options.handlers?.[actionId];
|
|
16828
|
+
if (!handler) {
|
|
16829
|
+
return;
|
|
16830
|
+
}
|
|
16831
|
+
return await handler({ actionId, report });
|
|
16832
|
+
};
|
|
16833
|
+
const runActionAsJob = async (actionId, report) => {
|
|
16834
|
+
const job = await options.jobStore?.create({
|
|
16835
|
+
actionId,
|
|
16836
|
+
message: `Queued real-call profile recovery action: ${actionId}.`,
|
|
16837
|
+
status: "queued"
|
|
16838
|
+
});
|
|
16839
|
+
if (!job) {
|
|
16840
|
+
return;
|
|
16841
|
+
}
|
|
16842
|
+
queueMicrotask(() => {
|
|
16843
|
+
(async () => {
|
|
16844
|
+
const startedAt = new Date().toISOString();
|
|
16845
|
+
await options.jobStore?.update(job.id, {
|
|
16846
|
+
message: `Running real-call profile recovery action: ${actionId}.`,
|
|
16847
|
+
startedAt,
|
|
16848
|
+
status: "running",
|
|
16849
|
+
updatedAt: startedAt
|
|
16850
|
+
});
|
|
16851
|
+
try {
|
|
16852
|
+
const result = await runActionHandler(actionId, report);
|
|
16853
|
+
const completedAt = new Date().toISOString();
|
|
16854
|
+
const ok = result?.ok ?? true;
|
|
16855
|
+
const status = result?.jobStatus ?? (result?.status === "fail" || ok === false ? "fail" : "pass");
|
|
16856
|
+
await options.jobStore?.update(job.id, {
|
|
16857
|
+
completedAt,
|
|
16858
|
+
message: result?.message ?? `Completed real-call profile recovery action: ${actionId}.`,
|
|
16859
|
+
ok,
|
|
16860
|
+
report: result?.report,
|
|
16861
|
+
status,
|
|
16862
|
+
updatedAt: completedAt
|
|
16863
|
+
});
|
|
16864
|
+
} catch (error) {
|
|
16865
|
+
const completedAt = new Date().toISOString();
|
|
16866
|
+
await options.jobStore?.update(job.id, {
|
|
16867
|
+
completedAt,
|
|
16868
|
+
message: error instanceof Error ? error.message : `Failed real-call profile recovery action: ${actionId}.`,
|
|
16869
|
+
ok: false,
|
|
16870
|
+
status: "fail",
|
|
16871
|
+
updatedAt: completedAt
|
|
16872
|
+
});
|
|
16873
|
+
}
|
|
16874
|
+
})();
|
|
16875
|
+
});
|
|
16876
|
+
return {
|
|
16877
|
+
actionId,
|
|
16878
|
+
generatedAt: new Date().toISOString(),
|
|
16879
|
+
job,
|
|
16880
|
+
jobId: job.id,
|
|
16881
|
+
jobStatus: job.status,
|
|
16882
|
+
message: job.message,
|
|
16883
|
+
ok: true,
|
|
16884
|
+
status: "pass"
|
|
16885
|
+
};
|
|
16886
|
+
};
|
|
16732
16887
|
const runAction = async (actionId) => {
|
|
16733
16888
|
const report = await loadReport();
|
|
16734
16889
|
const handler = options.handlers?.[actionId];
|
|
@@ -16741,10 +16896,19 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
|
|
|
16741
16896
|
status: "fail"
|
|
16742
16897
|
};
|
|
16743
16898
|
}
|
|
16744
|
-
|
|
16899
|
+
if (options.jobStore && asyncActionIds.has(actionId)) {
|
|
16900
|
+
const queued = await runActionAsJob(actionId, report);
|
|
16901
|
+
if (queued) {
|
|
16902
|
+
return queued;
|
|
16903
|
+
}
|
|
16904
|
+
}
|
|
16905
|
+
const result = await runActionHandler(actionId, report);
|
|
16745
16906
|
return {
|
|
16746
16907
|
actionId,
|
|
16747
16908
|
generatedAt: new Date().toISOString(),
|
|
16909
|
+
job: result?.job,
|
|
16910
|
+
jobId: result?.jobId,
|
|
16911
|
+
jobStatus: result?.jobStatus,
|
|
16748
16912
|
message: result?.message,
|
|
16749
16913
|
ok: result?.ok ?? true,
|
|
16750
16914
|
report: result?.report,
|
|
@@ -16752,6 +16916,24 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
|
|
|
16752
16916
|
};
|
|
16753
16917
|
};
|
|
16754
16918
|
routes.get(`${path}/actions`, async () => Response.json(await listActions(), { headers: options.headers }));
|
|
16919
|
+
routes.get(`${path}/actions/:jobId`, async ({
|
|
16920
|
+
params,
|
|
16921
|
+
set
|
|
16922
|
+
}) => {
|
|
16923
|
+
const jobId = params.jobId ?? "";
|
|
16924
|
+
const job = await options.jobStore?.get(jobId);
|
|
16925
|
+
if (!job) {
|
|
16926
|
+
set.status = 404;
|
|
16927
|
+
return Response.json({
|
|
16928
|
+
jobId,
|
|
16929
|
+
message: `No real-call profile recovery job found for id: ${jobId}.`,
|
|
16930
|
+
ok: false
|
|
16931
|
+
}, { headers: options.headers });
|
|
16932
|
+
}
|
|
16933
|
+
return Response.json({ job, ok: job.ok ?? job.status !== "fail" }, {
|
|
16934
|
+
headers: options.headers
|
|
16935
|
+
});
|
|
16936
|
+
});
|
|
16755
16937
|
for (const actionId of Object.keys(realCallProfileActionPaths)) {
|
|
16756
16938
|
routes.post(actionPath(actionId), async ({ set }) => {
|
|
16757
16939
|
const result = await runAction(actionId);
|
|
@@ -23437,7 +23619,7 @@ import { Elysia as Elysia45 } from "elysia";
|
|
|
23437
23619
|
|
|
23438
23620
|
// src/telephony/plivo.ts
|
|
23439
23621
|
import { Buffer as Buffer5 } from "buffer";
|
|
23440
|
-
import { Database } from "bun:sqlite";
|
|
23622
|
+
import { Database as Database2 } from "bun:sqlite";
|
|
23441
23623
|
import { Elysia as Elysia41 } from "elysia";
|
|
23442
23624
|
|
|
23443
23625
|
// src/telephony/contract.ts
|
|
@@ -24564,7 +24746,7 @@ var resolvePlivoNonceTableName = (input) => {
|
|
|
24564
24746
|
};
|
|
24565
24747
|
var getPlivoNonceExpiresAt = (ttlSeconds) => typeof ttlSeconds === "number" && ttlSeconds > 0 ? Date.now() + Math.ceil(ttlSeconds * 1000) : null;
|
|
24566
24748
|
var createVoiceSQLitePlivoWebhookNonceStore = (options) => {
|
|
24567
|
-
const database = options.database ?? new
|
|
24749
|
+
const database = options.database ?? new Database2(options.path ?? ":memory:", {
|
|
24568
24750
|
create: true
|
|
24569
24751
|
});
|
|
24570
24752
|
const tableName = resolvePlivoNonceTableName({
|
|
@@ -24964,7 +25146,7 @@ var createPlivoVoiceRoutes = (options = {}) => {
|
|
|
24964
25146
|
|
|
24965
25147
|
// src/telephony/telnyx.ts
|
|
24966
25148
|
import { Buffer as Buffer6 } from "buffer";
|
|
24967
|
-
import { Database as
|
|
25149
|
+
import { Database as Database3 } from "bun:sqlite";
|
|
24968
25150
|
import { Elysia as Elysia42 } from "elysia";
|
|
24969
25151
|
var escapeXml4 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
24970
25152
|
var escapeHtml42 = (value) => value.replaceAll("&", "&").replaceAll('"', """).replaceAll("'", "'").replaceAll("<", "<").replaceAll(">", ">");
|
|
@@ -25164,7 +25346,7 @@ var resolveTelnyxEventTableName = (input) => {
|
|
|
25164
25346
|
};
|
|
25165
25347
|
var getTelnyxEventExpiresAt = (ttlSeconds) => typeof ttlSeconds === "number" && ttlSeconds > 0 ? Date.now() + Math.ceil(ttlSeconds * 1000) : null;
|
|
25166
25348
|
var createVoiceSQLiteTelnyxWebhookEventStore = (options) => {
|
|
25167
|
-
const database = options.database ?? new
|
|
25349
|
+
const database = options.database ?? new Database3(options.path ?? ":memory:", {
|
|
25168
25350
|
create: true
|
|
25169
25351
|
});
|
|
25170
25352
|
const tableName = resolveTelnyxEventTableName({
|
|
@@ -28895,7 +29077,7 @@ var createVoicePostgresRuntimeStorage = (options) => {
|
|
|
28895
29077
|
};
|
|
28896
29078
|
|
|
28897
29079
|
// src/sqliteStore.ts
|
|
28898
|
-
import { Database as
|
|
29080
|
+
import { Database as Database4 } from "bun:sqlite";
|
|
28899
29081
|
var normalizeTableNameSegment = (value) => value.trim().replace(/[^a-zA-Z0-9_]+/g, "_").replace(/^_+|_+$/g, "") || "voice";
|
|
28900
29082
|
var resolveTableName = (input) => {
|
|
28901
29083
|
if (input.options.tableName) {
|
|
@@ -28906,7 +29088,7 @@ var resolveTableName = (input) => {
|
|
|
28906
29088
|
return `${prefix}_${fallback}`;
|
|
28907
29089
|
};
|
|
28908
29090
|
var openVoiceSQLiteDatabase = (path) => {
|
|
28909
|
-
const database = new
|
|
29091
|
+
const database = new Database4(path, {
|
|
28910
29092
|
create: true
|
|
28911
29093
|
});
|
|
28912
29094
|
database.exec("PRAGMA journal_mode = WAL;");
|
|
@@ -29685,7 +29867,7 @@ var createVoiceOpsRecoveryRoutes = (options = {}) => {
|
|
|
29685
29867
|
|
|
29686
29868
|
// src/observabilityExport.ts
|
|
29687
29869
|
import { Elysia as Elysia53 } from "elysia";
|
|
29688
|
-
import { Database as
|
|
29870
|
+
import { Database as Database5 } from "bun:sqlite";
|
|
29689
29871
|
import { createHash } from "crypto";
|
|
29690
29872
|
import { mkdir as mkdir4, readFile as readFile2, stat, unlink } from "fs/promises";
|
|
29691
29873
|
import { join as join3 } from "path";
|
|
@@ -31304,7 +31486,7 @@ var loadVoiceObservabilityExportReplaySource = async (source) => {
|
|
|
31304
31486
|
if (!source.database && !source.path) {
|
|
31305
31487
|
throw new Error("SQLite observability export replay requires source.database or source.path.");
|
|
31306
31488
|
}
|
|
31307
|
-
const database = source.database ?? new
|
|
31489
|
+
const database = source.database ?? new Database5(source.path, { create: false });
|
|
31308
31490
|
const table2 = quoteObservabilityIdentifier(normalizeObservabilityIdentifier(source.tableName));
|
|
31309
31491
|
const row2 = database.query(`SELECT manifest_json, artifact_index_json, payload_json FROM ${table2} WHERE run_id = $runId`).get({ $runId: source.runId });
|
|
31310
31492
|
if (!row2) {
|
|
@@ -31381,7 +31563,7 @@ var deliverObservabilityExportToSQLite = async (input) => {
|
|
|
31381
31563
|
if (!input.destination.database && !input.destination.path) {
|
|
31382
31564
|
throw new Error("SQLite observability export delivery requires destination.database or destination.path.");
|
|
31383
31565
|
}
|
|
31384
|
-
const database = input.destination.database ?? new
|
|
31566
|
+
const database = input.destination.database ?? new Database5(input.destination.path, { create: true });
|
|
31385
31567
|
const table = quoteObservabilityIdentifier(normalizeObservabilityIdentifier(input.destination.tableName));
|
|
31386
31568
|
const record = buildObservabilityExportDatabaseRecord(input);
|
|
31387
31569
|
database.exec(`CREATE TABLE IF NOT EXISTS ${table} (
|
|
@@ -38813,6 +38995,7 @@ export {
|
|
|
38813
38995
|
createVoiceSQLiteSessionStore,
|
|
38814
38996
|
createVoiceSQLiteRuntimeStorage,
|
|
38815
38997
|
createVoiceSQLiteReviewStore,
|
|
38998
|
+
createVoiceSQLiteRealCallProfileRecoveryJobStore,
|
|
38816
38999
|
createVoiceSQLitePlivoWebhookNonceStore,
|
|
38817
39000
|
createVoiceSQLiteIntegrationEventStore,
|
|
38818
39001
|
createVoiceSQLiteExternalObjectMapStore,
|
|
@@ -38932,6 +39115,7 @@ export {
|
|
|
38932
39115
|
createVoiceIntegrationHTTPSink,
|
|
38933
39116
|
createVoiceIntegrationEvent,
|
|
38934
39117
|
createVoiceIncidentBundleRoutes,
|
|
39118
|
+
createVoiceInMemoryRealCallProfileRecoveryJobStore,
|
|
38935
39119
|
createVoiceHubSpotTaskUpdateSink,
|
|
38936
39120
|
createVoiceHubSpotTaskSyncSinks,
|
|
38937
39121
|
createVoiceHubSpotTaskSink,
|
package/dist/proofTrends.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Elysia } from 'elysia';
|
|
2
|
+
import { Database } from 'bun:sqlite';
|
|
2
3
|
import type { VoiceProductionReadinessAction, VoiceProductionReadinessCheck } from './productionReadiness';
|
|
3
4
|
import type { StoredVoiceTraceEvent, VoiceTraceEventStore } from './trace';
|
|
4
5
|
export type VoiceProofTrendStatus = 'empty' | 'fail' | 'pass' | 'stale';
|
|
@@ -384,14 +385,52 @@ export type VoiceRealCallProfileRecoveryActionHandlerInput = {
|
|
|
384
385
|
export type VoiceRealCallProfileRecoveryActionResult = {
|
|
385
386
|
actionId: VoiceRealCallProfileRecoveryActionId;
|
|
386
387
|
generatedAt: string;
|
|
388
|
+
job?: VoiceRealCallProfileRecoveryJob;
|
|
389
|
+
jobId?: string;
|
|
390
|
+
jobStatus?: VoiceRealCallProfileRecoveryJobStatus;
|
|
387
391
|
message?: string;
|
|
388
392
|
ok: boolean;
|
|
389
393
|
report?: VoiceRealCallProfileHistoryReport;
|
|
390
394
|
status: VoiceProofTrendStatus;
|
|
391
395
|
};
|
|
396
|
+
export type VoiceRealCallProfileRecoveryJobStatus = 'fail' | 'pass' | 'queued' | 'running';
|
|
397
|
+
export type VoiceRealCallProfileRecoveryJob = {
|
|
398
|
+
actionId: VoiceRealCallProfileRecoveryActionId;
|
|
399
|
+
completedAt?: string;
|
|
400
|
+
createdAt: string;
|
|
401
|
+
id: string;
|
|
402
|
+
message?: string;
|
|
403
|
+
ok?: boolean;
|
|
404
|
+
report?: VoiceRealCallProfileHistoryReport;
|
|
405
|
+
startedAt?: string;
|
|
406
|
+
status: VoiceRealCallProfileRecoveryJobStatus;
|
|
407
|
+
updatedAt: string;
|
|
408
|
+
};
|
|
409
|
+
export type VoiceRealCallProfileRecoveryJobCreateInput = {
|
|
410
|
+
actionId: VoiceRealCallProfileRecoveryActionId;
|
|
411
|
+
createdAt?: string;
|
|
412
|
+
id?: string;
|
|
413
|
+
message?: string;
|
|
414
|
+
status?: VoiceRealCallProfileRecoveryJobStatus;
|
|
415
|
+
};
|
|
416
|
+
export type VoiceRealCallProfileRecoveryJobUpdate = Partial<Pick<VoiceRealCallProfileRecoveryJob, 'completedAt' | 'message' | 'ok' | 'report' | 'startedAt' | 'status' | 'updatedAt'>>;
|
|
417
|
+
export type VoiceRealCallProfileRecoveryJobStore = {
|
|
418
|
+
create(input: VoiceRealCallProfileRecoveryJobCreateInput): Promise<VoiceRealCallProfileRecoveryJob> | VoiceRealCallProfileRecoveryJob;
|
|
419
|
+
get(id: string): Promise<VoiceRealCallProfileRecoveryJob | undefined> | VoiceRealCallProfileRecoveryJob | undefined;
|
|
420
|
+
update(id: string, update: VoiceRealCallProfileRecoveryJobUpdate): Promise<VoiceRealCallProfileRecoveryJob | undefined> | VoiceRealCallProfileRecoveryJob | undefined;
|
|
421
|
+
};
|
|
422
|
+
export type VoiceSQLiteRealCallProfileRecoveryJobStoreOptions = {
|
|
423
|
+
database?: Database;
|
|
424
|
+
idPrefix?: string;
|
|
425
|
+
now?: () => Date;
|
|
426
|
+
path?: string;
|
|
427
|
+
tableName?: string;
|
|
428
|
+
};
|
|
392
429
|
export type VoiceRealCallProfileRecoveryActionHandler = (input: VoiceRealCallProfileRecoveryActionHandlerInput) => Promise<Partial<VoiceRealCallProfileRecoveryActionResult> | void> | Partial<VoiceRealCallProfileRecoveryActionResult> | void;
|
|
393
430
|
export type VoiceRealCallProfileRecoveryActionRoutesOptions = VoiceRealCallProfileRecoveryActionOptions & Omit<VoiceRealCallProfileHistoryRoutesOptions, 'htmlPath' | 'markdownPath'> & {
|
|
431
|
+
asyncActionIds?: readonly VoiceRealCallProfileRecoveryActionId[];
|
|
394
432
|
handlers?: Partial<Record<VoiceRealCallProfileRecoveryActionId, VoiceRealCallProfileRecoveryActionHandler>>;
|
|
433
|
+
jobStore?: VoiceRealCallProfileRecoveryJobStore;
|
|
395
434
|
};
|
|
396
435
|
export declare const DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS: number;
|
|
397
436
|
export declare const DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS: ({
|
|
@@ -427,6 +466,11 @@ export declare const buildVoiceProofTrendProfileSummaries: (input: VoiceProofTre
|
|
|
427
466
|
export declare const buildVoiceProofTrendReportFromRealCallProfiles: (options: VoiceProofTrendRealCallProfileReportOptions) => VoiceProofTrendReport;
|
|
428
467
|
export declare const buildVoiceRealCallProfileDefaults: (input: VoiceRealCallProfileHistoryReport | VoiceProofTrendReport, options?: VoiceRealCallProfileDefaultsOptions) => VoiceRealCallProfileDefaultsReport;
|
|
429
468
|
export declare const buildVoiceRealCallProfileRecoveryActions: (report: VoiceRealCallProfileHistoryReport, options?: VoiceRealCallProfileRecoveryActionOptions) => VoiceRealCallProfileRecoveryAction[];
|
|
469
|
+
export declare const createVoiceInMemoryRealCallProfileRecoveryJobStore: (options?: {
|
|
470
|
+
idPrefix?: string;
|
|
471
|
+
now?: () => Date;
|
|
472
|
+
}) => VoiceRealCallProfileRecoveryJobStore;
|
|
473
|
+
export declare const createVoiceSQLiteRealCallProfileRecoveryJobStore: (options?: VoiceSQLiteRealCallProfileRecoveryJobStoreOptions) => VoiceRealCallProfileRecoveryJobStore;
|
|
430
474
|
export declare const buildVoiceRealCallProfileReadinessCheck: (report: VoiceRealCallProfileHistoryReport, options?: VoiceRealCallProfileReadinessCheckOptions) => VoiceProductionReadinessCheck;
|
|
431
475
|
export declare const resolveVoiceRealCallProfileProviderRoute: <TProvider extends string = string>(options: VoiceRealCallProfileProviderRouteOptions<TProvider>) => TProvider | undefined;
|
|
432
476
|
export declare const buildVoiceRealCallProfileHistoryReport: (options?: VoiceRealCallProfileHistoryOptions) => VoiceRealCallProfileHistoryReport;
|
package/dist/react/index.js
CHANGED
|
@@ -1494,6 +1494,7 @@ var useVoiceProofTrends = (path = "/api/voice/proof-trends", options = {}) => {
|
|
|
1494
1494
|
|
|
1495
1495
|
// src/proofTrends.ts
|
|
1496
1496
|
import { Elysia } from "elysia";
|
|
1497
|
+
import { Database } from "bun:sqlite";
|
|
1497
1498
|
var DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
1498
1499
|
var DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS = [
|
|
1499
1500
|
{
|
|
@@ -2214,6 +2215,98 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
|
|
|
2214
2215
|
}
|
|
2215
2216
|
return uniqueRealCallProfileActions(actions);
|
|
2216
2217
|
};
|
|
2218
|
+
var createVoiceInMemoryRealCallProfileRecoveryJobStore = (options = {}) => {
|
|
2219
|
+
const jobs = new Map;
|
|
2220
|
+
const now = () => (options.now ?? (() => new Date))().toISOString();
|
|
2221
|
+
const createId = () => `${options.idPrefix ?? "voice-recovery-job"}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
2222
|
+
return {
|
|
2223
|
+
create(input) {
|
|
2224
|
+
const createdAt = input.createdAt ?? now();
|
|
2225
|
+
const job = {
|
|
2226
|
+
actionId: input.actionId,
|
|
2227
|
+
createdAt,
|
|
2228
|
+
id: input.id ?? createId(),
|
|
2229
|
+
message: input.message,
|
|
2230
|
+
status: input.status ?? "queued",
|
|
2231
|
+
updatedAt: createdAt
|
|
2232
|
+
};
|
|
2233
|
+
jobs.set(job.id, job);
|
|
2234
|
+
return job;
|
|
2235
|
+
},
|
|
2236
|
+
get(id) {
|
|
2237
|
+
return jobs.get(id);
|
|
2238
|
+
},
|
|
2239
|
+
update(id, update) {
|
|
2240
|
+
const existing = jobs.get(id);
|
|
2241
|
+
if (!existing) {
|
|
2242
|
+
return;
|
|
2243
|
+
}
|
|
2244
|
+
const next = {
|
|
2245
|
+
...existing,
|
|
2246
|
+
...update,
|
|
2247
|
+
updatedAt: update.updatedAt ?? now()
|
|
2248
|
+
};
|
|
2249
|
+
jobs.set(id, next);
|
|
2250
|
+
return next;
|
|
2251
|
+
}
|
|
2252
|
+
};
|
|
2253
|
+
};
|
|
2254
|
+
var normalizeRealCallRecoveryJobTableName = (value) => value.trim().replace(/[^a-zA-Z0-9_]+/g, "_").replace(/^_+|_+$/g, "") || "voice_real_call_profile_recovery_jobs";
|
|
2255
|
+
var createVoiceSQLiteRealCallProfileRecoveryJobStore = (options = {}) => {
|
|
2256
|
+
const database = options.database ?? new Database(options.path ?? ":memory:", {
|
|
2257
|
+
create: true
|
|
2258
|
+
});
|
|
2259
|
+
const tableName = normalizeRealCallRecoveryJobTableName(options.tableName ?? "voice_real_call_profile_recovery_jobs");
|
|
2260
|
+
const now = () => (options.now ?? (() => new Date))().toISOString();
|
|
2261
|
+
const createId = () => `${options.idPrefix ?? "voice-recovery-job"}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
2262
|
+
database.exec("PRAGMA journal_mode = WAL;");
|
|
2263
|
+
database.exec("PRAGMA synchronous = NORMAL;");
|
|
2264
|
+
database.exec("PRAGMA busy_timeout = 5000;");
|
|
2265
|
+
database.exec(`CREATE TABLE IF NOT EXISTS "${tableName}" (
|
|
2266
|
+
id TEXT PRIMARY KEY,
|
|
2267
|
+
sort_at INTEGER NOT NULL,
|
|
2268
|
+
payload TEXT NOT NULL
|
|
2269
|
+
)`);
|
|
2270
|
+
const selectStatement = database.query(`SELECT payload FROM "${tableName}" WHERE id = ?1 LIMIT 1`);
|
|
2271
|
+
const upsertStatement = database.query(`INSERT INTO "${tableName}" (id, sort_at, payload)
|
|
2272
|
+
VALUES (?1, ?2, ?3)
|
|
2273
|
+
ON CONFLICT(id) DO UPDATE SET sort_at = excluded.sort_at, payload = excluded.payload`);
|
|
2274
|
+
const writeJob = (job) => {
|
|
2275
|
+
upsertStatement.run(job.id, Date.parse(job.updatedAt) || Date.now(), JSON.stringify(job));
|
|
2276
|
+
return job;
|
|
2277
|
+
};
|
|
2278
|
+
const readJob = (id) => {
|
|
2279
|
+
const row = selectStatement.get(id);
|
|
2280
|
+
return row ? JSON.parse(row.payload) : undefined;
|
|
2281
|
+
};
|
|
2282
|
+
return {
|
|
2283
|
+
create(input) {
|
|
2284
|
+
const createdAt = input.createdAt ?? now();
|
|
2285
|
+
return writeJob({
|
|
2286
|
+
actionId: input.actionId,
|
|
2287
|
+
createdAt,
|
|
2288
|
+
id: input.id ?? createId(),
|
|
2289
|
+
message: input.message,
|
|
2290
|
+
status: input.status ?? "queued",
|
|
2291
|
+
updatedAt: createdAt
|
|
2292
|
+
});
|
|
2293
|
+
},
|
|
2294
|
+
get(id) {
|
|
2295
|
+
return readJob(id);
|
|
2296
|
+
},
|
|
2297
|
+
update(id, update) {
|
|
2298
|
+
const existing = readJob(id);
|
|
2299
|
+
if (!existing) {
|
|
2300
|
+
return;
|
|
2301
|
+
}
|
|
2302
|
+
return writeJob({
|
|
2303
|
+
...existing,
|
|
2304
|
+
...update,
|
|
2305
|
+
updatedAt: update.updatedAt ?? now()
|
|
2306
|
+
});
|
|
2307
|
+
}
|
|
2308
|
+
};
|
|
2309
|
+
};
|
|
2217
2310
|
var buildVoiceRealCallProfileReadinessCheck = (report, options = {}) => {
|
|
2218
2311
|
const { issues, warnings } = buildRealCallProfileReadinessIssues(report, options);
|
|
2219
2312
|
const status = issues.length > 0 ? "fail" : warnings.length > 0 && options.failOnWarnings === true ? "fail" : warnings.length > 0 ? "warn" : "pass";
|
|
@@ -2832,6 +2925,7 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
|
|
|
2832
2925
|
});
|
|
2833
2926
|
const actionPath = (actionId) => `${path}${realCallProfileActionPaths[actionId]}`;
|
|
2834
2927
|
const loadReport = () => loadVoiceRealCallProfileHistoryRouteReport(options);
|
|
2928
|
+
const asyncActionIds = new Set(options.asyncActionIds ?? []);
|
|
2835
2929
|
const listActions = async () => {
|
|
2836
2930
|
const report = await loadReport();
|
|
2837
2931
|
const actions = buildVoiceRealCallProfileRecoveryActions(report, {
|
|
@@ -2847,6 +2941,67 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
|
|
|
2847
2941
|
}));
|
|
2848
2942
|
return { actions, generatedAt: new Date().toISOString(), report };
|
|
2849
2943
|
};
|
|
2944
|
+
const runActionHandler = async (actionId, report) => {
|
|
2945
|
+
const handler = options.handlers?.[actionId];
|
|
2946
|
+
if (!handler) {
|
|
2947
|
+
return;
|
|
2948
|
+
}
|
|
2949
|
+
return await handler({ actionId, report });
|
|
2950
|
+
};
|
|
2951
|
+
const runActionAsJob = async (actionId, report) => {
|
|
2952
|
+
const job = await options.jobStore?.create({
|
|
2953
|
+
actionId,
|
|
2954
|
+
message: `Queued real-call profile recovery action: ${actionId}.`,
|
|
2955
|
+
status: "queued"
|
|
2956
|
+
});
|
|
2957
|
+
if (!job) {
|
|
2958
|
+
return;
|
|
2959
|
+
}
|
|
2960
|
+
queueMicrotask(() => {
|
|
2961
|
+
(async () => {
|
|
2962
|
+
const startedAt = new Date().toISOString();
|
|
2963
|
+
await options.jobStore?.update(job.id, {
|
|
2964
|
+
message: `Running real-call profile recovery action: ${actionId}.`,
|
|
2965
|
+
startedAt,
|
|
2966
|
+
status: "running",
|
|
2967
|
+
updatedAt: startedAt
|
|
2968
|
+
});
|
|
2969
|
+
try {
|
|
2970
|
+
const result = await runActionHandler(actionId, report);
|
|
2971
|
+
const completedAt = new Date().toISOString();
|
|
2972
|
+
const ok = result?.ok ?? true;
|
|
2973
|
+
const status = result?.jobStatus ?? (result?.status === "fail" || ok === false ? "fail" : "pass");
|
|
2974
|
+
await options.jobStore?.update(job.id, {
|
|
2975
|
+
completedAt,
|
|
2976
|
+
message: result?.message ?? `Completed real-call profile recovery action: ${actionId}.`,
|
|
2977
|
+
ok,
|
|
2978
|
+
report: result?.report,
|
|
2979
|
+
status,
|
|
2980
|
+
updatedAt: completedAt
|
|
2981
|
+
});
|
|
2982
|
+
} catch (error) {
|
|
2983
|
+
const completedAt = new Date().toISOString();
|
|
2984
|
+
await options.jobStore?.update(job.id, {
|
|
2985
|
+
completedAt,
|
|
2986
|
+
message: error instanceof Error ? error.message : `Failed real-call profile recovery action: ${actionId}.`,
|
|
2987
|
+
ok: false,
|
|
2988
|
+
status: "fail",
|
|
2989
|
+
updatedAt: completedAt
|
|
2990
|
+
});
|
|
2991
|
+
}
|
|
2992
|
+
})();
|
|
2993
|
+
});
|
|
2994
|
+
return {
|
|
2995
|
+
actionId,
|
|
2996
|
+
generatedAt: new Date().toISOString(),
|
|
2997
|
+
job,
|
|
2998
|
+
jobId: job.id,
|
|
2999
|
+
jobStatus: job.status,
|
|
3000
|
+
message: job.message,
|
|
3001
|
+
ok: true,
|
|
3002
|
+
status: "pass"
|
|
3003
|
+
};
|
|
3004
|
+
};
|
|
2850
3005
|
const runAction = async (actionId) => {
|
|
2851
3006
|
const report = await loadReport();
|
|
2852
3007
|
const handler = options.handlers?.[actionId];
|
|
@@ -2859,10 +3014,19 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
|
|
|
2859
3014
|
status: "fail"
|
|
2860
3015
|
};
|
|
2861
3016
|
}
|
|
2862
|
-
|
|
3017
|
+
if (options.jobStore && asyncActionIds.has(actionId)) {
|
|
3018
|
+
const queued = await runActionAsJob(actionId, report);
|
|
3019
|
+
if (queued) {
|
|
3020
|
+
return queued;
|
|
3021
|
+
}
|
|
3022
|
+
}
|
|
3023
|
+
const result = await runActionHandler(actionId, report);
|
|
2863
3024
|
return {
|
|
2864
3025
|
actionId,
|
|
2865
3026
|
generatedAt: new Date().toISOString(),
|
|
3027
|
+
job: result?.job,
|
|
3028
|
+
jobId: result?.jobId,
|
|
3029
|
+
jobStatus: result?.jobStatus,
|
|
2866
3030
|
message: result?.message,
|
|
2867
3031
|
ok: result?.ok ?? true,
|
|
2868
3032
|
report: result?.report,
|
|
@@ -2870,6 +3034,24 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
|
|
|
2870
3034
|
};
|
|
2871
3035
|
};
|
|
2872
3036
|
routes.get(`${path}/actions`, async () => Response.json(await listActions(), { headers: options.headers }));
|
|
3037
|
+
routes.get(`${path}/actions/:jobId`, async ({
|
|
3038
|
+
params,
|
|
3039
|
+
set
|
|
3040
|
+
}) => {
|
|
3041
|
+
const jobId = params.jobId ?? "";
|
|
3042
|
+
const job = await options.jobStore?.get(jobId);
|
|
3043
|
+
if (!job) {
|
|
3044
|
+
set.status = 404;
|
|
3045
|
+
return Response.json({
|
|
3046
|
+
jobId,
|
|
3047
|
+
message: `No real-call profile recovery job found for id: ${jobId}.`,
|
|
3048
|
+
ok: false
|
|
3049
|
+
}, { headers: options.headers });
|
|
3050
|
+
}
|
|
3051
|
+
return Response.json({ job, ok: job.ok ?? job.status !== "fail" }, {
|
|
3052
|
+
headers: options.headers
|
|
3053
|
+
});
|
|
3054
|
+
});
|
|
2873
3055
|
for (const actionId of Object.keys(realCallProfileActionPaths)) {
|
|
2874
3056
|
routes.post(actionPath(actionId), async ({ set }) => {
|
|
2875
3057
|
const result = await runAction(actionId);
|
package/dist/vue/index.js
CHANGED
|
@@ -1415,6 +1415,7 @@ import { defineComponent as defineComponent5, h as h5 } from "vue";
|
|
|
1415
1415
|
|
|
1416
1416
|
// src/proofTrends.ts
|
|
1417
1417
|
import { Elysia } from "elysia";
|
|
1418
|
+
import { Database } from "bun:sqlite";
|
|
1418
1419
|
var DEFAULT_VOICE_PROOF_TRENDS_MAX_AGE_MS = 24 * 60 * 60 * 1000;
|
|
1419
1420
|
var DEFAULT_VOICE_PROOF_TREND_PROFILE_DEFINITIONS = [
|
|
1420
1421
|
{
|
|
@@ -2135,6 +2136,98 @@ var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
|
|
|
2135
2136
|
}
|
|
2136
2137
|
return uniqueRealCallProfileActions(actions);
|
|
2137
2138
|
};
|
|
2139
|
+
var createVoiceInMemoryRealCallProfileRecoveryJobStore = (options = {}) => {
|
|
2140
|
+
const jobs = new Map;
|
|
2141
|
+
const now = () => (options.now ?? (() => new Date))().toISOString();
|
|
2142
|
+
const createId = () => `${options.idPrefix ?? "voice-recovery-job"}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
2143
|
+
return {
|
|
2144
|
+
create(input) {
|
|
2145
|
+
const createdAt = input.createdAt ?? now();
|
|
2146
|
+
const job = {
|
|
2147
|
+
actionId: input.actionId,
|
|
2148
|
+
createdAt,
|
|
2149
|
+
id: input.id ?? createId(),
|
|
2150
|
+
message: input.message,
|
|
2151
|
+
status: input.status ?? "queued",
|
|
2152
|
+
updatedAt: createdAt
|
|
2153
|
+
};
|
|
2154
|
+
jobs.set(job.id, job);
|
|
2155
|
+
return job;
|
|
2156
|
+
},
|
|
2157
|
+
get(id) {
|
|
2158
|
+
return jobs.get(id);
|
|
2159
|
+
},
|
|
2160
|
+
update(id, update) {
|
|
2161
|
+
const existing = jobs.get(id);
|
|
2162
|
+
if (!existing) {
|
|
2163
|
+
return;
|
|
2164
|
+
}
|
|
2165
|
+
const next = {
|
|
2166
|
+
...existing,
|
|
2167
|
+
...update,
|
|
2168
|
+
updatedAt: update.updatedAt ?? now()
|
|
2169
|
+
};
|
|
2170
|
+
jobs.set(id, next);
|
|
2171
|
+
return next;
|
|
2172
|
+
}
|
|
2173
|
+
};
|
|
2174
|
+
};
|
|
2175
|
+
var normalizeRealCallRecoveryJobTableName = (value) => value.trim().replace(/[^a-zA-Z0-9_]+/g, "_").replace(/^_+|_+$/g, "") || "voice_real_call_profile_recovery_jobs";
|
|
2176
|
+
var createVoiceSQLiteRealCallProfileRecoveryJobStore = (options = {}) => {
|
|
2177
|
+
const database = options.database ?? new Database(options.path ?? ":memory:", {
|
|
2178
|
+
create: true
|
|
2179
|
+
});
|
|
2180
|
+
const tableName = normalizeRealCallRecoveryJobTableName(options.tableName ?? "voice_real_call_profile_recovery_jobs");
|
|
2181
|
+
const now = () => (options.now ?? (() => new Date))().toISOString();
|
|
2182
|
+
const createId = () => `${options.idPrefix ?? "voice-recovery-job"}-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
|
|
2183
|
+
database.exec("PRAGMA journal_mode = WAL;");
|
|
2184
|
+
database.exec("PRAGMA synchronous = NORMAL;");
|
|
2185
|
+
database.exec("PRAGMA busy_timeout = 5000;");
|
|
2186
|
+
database.exec(`CREATE TABLE IF NOT EXISTS "${tableName}" (
|
|
2187
|
+
id TEXT PRIMARY KEY,
|
|
2188
|
+
sort_at INTEGER NOT NULL,
|
|
2189
|
+
payload TEXT NOT NULL
|
|
2190
|
+
)`);
|
|
2191
|
+
const selectStatement = database.query(`SELECT payload FROM "${tableName}" WHERE id = ?1 LIMIT 1`);
|
|
2192
|
+
const upsertStatement = database.query(`INSERT INTO "${tableName}" (id, sort_at, payload)
|
|
2193
|
+
VALUES (?1, ?2, ?3)
|
|
2194
|
+
ON CONFLICT(id) DO UPDATE SET sort_at = excluded.sort_at, payload = excluded.payload`);
|
|
2195
|
+
const writeJob = (job) => {
|
|
2196
|
+
upsertStatement.run(job.id, Date.parse(job.updatedAt) || Date.now(), JSON.stringify(job));
|
|
2197
|
+
return job;
|
|
2198
|
+
};
|
|
2199
|
+
const readJob = (id) => {
|
|
2200
|
+
const row = selectStatement.get(id);
|
|
2201
|
+
return row ? JSON.parse(row.payload) : undefined;
|
|
2202
|
+
};
|
|
2203
|
+
return {
|
|
2204
|
+
create(input) {
|
|
2205
|
+
const createdAt = input.createdAt ?? now();
|
|
2206
|
+
return writeJob({
|
|
2207
|
+
actionId: input.actionId,
|
|
2208
|
+
createdAt,
|
|
2209
|
+
id: input.id ?? createId(),
|
|
2210
|
+
message: input.message,
|
|
2211
|
+
status: input.status ?? "queued",
|
|
2212
|
+
updatedAt: createdAt
|
|
2213
|
+
});
|
|
2214
|
+
},
|
|
2215
|
+
get(id) {
|
|
2216
|
+
return readJob(id);
|
|
2217
|
+
},
|
|
2218
|
+
update(id, update) {
|
|
2219
|
+
const existing = readJob(id);
|
|
2220
|
+
if (!existing) {
|
|
2221
|
+
return;
|
|
2222
|
+
}
|
|
2223
|
+
return writeJob({
|
|
2224
|
+
...existing,
|
|
2225
|
+
...update,
|
|
2226
|
+
updatedAt: update.updatedAt ?? now()
|
|
2227
|
+
});
|
|
2228
|
+
}
|
|
2229
|
+
};
|
|
2230
|
+
};
|
|
2138
2231
|
var buildVoiceRealCallProfileReadinessCheck = (report, options = {}) => {
|
|
2139
2232
|
const { issues, warnings } = buildRealCallProfileReadinessIssues(report, options);
|
|
2140
2233
|
const status = issues.length > 0 ? "fail" : warnings.length > 0 && options.failOnWarnings === true ? "fail" : warnings.length > 0 ? "warn" : "pass";
|
|
@@ -2753,6 +2846,7 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
|
|
|
2753
2846
|
});
|
|
2754
2847
|
const actionPath = (actionId) => `${path}${realCallProfileActionPaths[actionId]}`;
|
|
2755
2848
|
const loadReport = () => loadVoiceRealCallProfileHistoryRouteReport(options);
|
|
2849
|
+
const asyncActionIds = new Set(options.asyncActionIds ?? []);
|
|
2756
2850
|
const listActions = async () => {
|
|
2757
2851
|
const report = await loadReport();
|
|
2758
2852
|
const actions = buildVoiceRealCallProfileRecoveryActions(report, {
|
|
@@ -2768,6 +2862,67 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
|
|
|
2768
2862
|
}));
|
|
2769
2863
|
return { actions, generatedAt: new Date().toISOString(), report };
|
|
2770
2864
|
};
|
|
2865
|
+
const runActionHandler = async (actionId, report) => {
|
|
2866
|
+
const handler = options.handlers?.[actionId];
|
|
2867
|
+
if (!handler) {
|
|
2868
|
+
return;
|
|
2869
|
+
}
|
|
2870
|
+
return await handler({ actionId, report });
|
|
2871
|
+
};
|
|
2872
|
+
const runActionAsJob = async (actionId, report) => {
|
|
2873
|
+
const job = await options.jobStore?.create({
|
|
2874
|
+
actionId,
|
|
2875
|
+
message: `Queued real-call profile recovery action: ${actionId}.`,
|
|
2876
|
+
status: "queued"
|
|
2877
|
+
});
|
|
2878
|
+
if (!job) {
|
|
2879
|
+
return;
|
|
2880
|
+
}
|
|
2881
|
+
queueMicrotask(() => {
|
|
2882
|
+
(async () => {
|
|
2883
|
+
const startedAt = new Date().toISOString();
|
|
2884
|
+
await options.jobStore?.update(job.id, {
|
|
2885
|
+
message: `Running real-call profile recovery action: ${actionId}.`,
|
|
2886
|
+
startedAt,
|
|
2887
|
+
status: "running",
|
|
2888
|
+
updatedAt: startedAt
|
|
2889
|
+
});
|
|
2890
|
+
try {
|
|
2891
|
+
const result = await runActionHandler(actionId, report);
|
|
2892
|
+
const completedAt = new Date().toISOString();
|
|
2893
|
+
const ok = result?.ok ?? true;
|
|
2894
|
+
const status = result?.jobStatus ?? (result?.status === "fail" || ok === false ? "fail" : "pass");
|
|
2895
|
+
await options.jobStore?.update(job.id, {
|
|
2896
|
+
completedAt,
|
|
2897
|
+
message: result?.message ?? `Completed real-call profile recovery action: ${actionId}.`,
|
|
2898
|
+
ok,
|
|
2899
|
+
report: result?.report,
|
|
2900
|
+
status,
|
|
2901
|
+
updatedAt: completedAt
|
|
2902
|
+
});
|
|
2903
|
+
} catch (error) {
|
|
2904
|
+
const completedAt = new Date().toISOString();
|
|
2905
|
+
await options.jobStore?.update(job.id, {
|
|
2906
|
+
completedAt,
|
|
2907
|
+
message: error instanceof Error ? error.message : `Failed real-call profile recovery action: ${actionId}.`,
|
|
2908
|
+
ok: false,
|
|
2909
|
+
status: "fail",
|
|
2910
|
+
updatedAt: completedAt
|
|
2911
|
+
});
|
|
2912
|
+
}
|
|
2913
|
+
})();
|
|
2914
|
+
});
|
|
2915
|
+
return {
|
|
2916
|
+
actionId,
|
|
2917
|
+
generatedAt: new Date().toISOString(),
|
|
2918
|
+
job,
|
|
2919
|
+
jobId: job.id,
|
|
2920
|
+
jobStatus: job.status,
|
|
2921
|
+
message: job.message,
|
|
2922
|
+
ok: true,
|
|
2923
|
+
status: "pass"
|
|
2924
|
+
};
|
|
2925
|
+
};
|
|
2771
2926
|
const runAction = async (actionId) => {
|
|
2772
2927
|
const report = await loadReport();
|
|
2773
2928
|
const handler = options.handlers?.[actionId];
|
|
@@ -2780,10 +2935,19 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
|
|
|
2780
2935
|
status: "fail"
|
|
2781
2936
|
};
|
|
2782
2937
|
}
|
|
2783
|
-
|
|
2938
|
+
if (options.jobStore && asyncActionIds.has(actionId)) {
|
|
2939
|
+
const queued = await runActionAsJob(actionId, report);
|
|
2940
|
+
if (queued) {
|
|
2941
|
+
return queued;
|
|
2942
|
+
}
|
|
2943
|
+
}
|
|
2944
|
+
const result = await runActionHandler(actionId, report);
|
|
2784
2945
|
return {
|
|
2785
2946
|
actionId,
|
|
2786
2947
|
generatedAt: new Date().toISOString(),
|
|
2948
|
+
job: result?.job,
|
|
2949
|
+
jobId: result?.jobId,
|
|
2950
|
+
jobStatus: result?.jobStatus,
|
|
2787
2951
|
message: result?.message,
|
|
2788
2952
|
ok: result?.ok ?? true,
|
|
2789
2953
|
report: result?.report,
|
|
@@ -2791,6 +2955,24 @@ var createVoiceRealCallProfileRecoveryActionRoutes = (options = {}) => {
|
|
|
2791
2955
|
};
|
|
2792
2956
|
};
|
|
2793
2957
|
routes.get(`${path}/actions`, async () => Response.json(await listActions(), { headers: options.headers }));
|
|
2958
|
+
routes.get(`${path}/actions/:jobId`, async ({
|
|
2959
|
+
params,
|
|
2960
|
+
set
|
|
2961
|
+
}) => {
|
|
2962
|
+
const jobId = params.jobId ?? "";
|
|
2963
|
+
const job = await options.jobStore?.get(jobId);
|
|
2964
|
+
if (!job) {
|
|
2965
|
+
set.status = 404;
|
|
2966
|
+
return Response.json({
|
|
2967
|
+
jobId,
|
|
2968
|
+
message: `No real-call profile recovery job found for id: ${jobId}.`,
|
|
2969
|
+
ok: false
|
|
2970
|
+
}, { headers: options.headers });
|
|
2971
|
+
}
|
|
2972
|
+
return Response.json({ job, ok: job.ok ?? job.status !== "fail" }, {
|
|
2973
|
+
headers: options.headers
|
|
2974
|
+
});
|
|
2975
|
+
});
|
|
2794
2976
|
for (const actionId of Object.keys(realCallProfileActionPaths)) {
|
|
2795
2977
|
routes.post(actionPath(actionId), async ({ set }) => {
|
|
2796
2978
|
const result = await runAction(actionId);
|