@absolutejs/voice 0.0.22-beta.387 → 0.0.22-beta.389
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/dist/client/index.js +71 -51
- package/dist/index.js +72 -52
- package/dist/proofTrends.d.ts +3 -0
- package/dist/react/index.js +71 -51
- package/dist/vue/index.js +71 -51
- package/package.json +1 -1
package/dist/client/index.js
CHANGED
|
@@ -6557,6 +6557,8 @@ var runVoiceRealCallProfileRecoveryLoop = async (options) => {
|
|
|
6557
6557
|
const requestTimeoutMs = options.requestTimeoutMs ?? 5000;
|
|
6558
6558
|
const jobPollMs = options.jobPollMs ?? 1200;
|
|
6559
6559
|
const jobTimeoutMs = options.jobTimeoutMs ?? 600000;
|
|
6560
|
+
const interPassDelayMs = typeof options.interPassDelayMs === "number" && Number.isFinite(options.interPassDelayMs) && options.interPassDelayMs > 0 ? options.interPassDelayMs : 5000;
|
|
6561
|
+
const maxPasses = typeof options.maxPasses === "number" && Number.isFinite(options.maxPasses) && options.maxPasses > 0 ? Math.floor(options.maxPasses) : 3;
|
|
6560
6562
|
const readinessCheckLabel = options.readinessCheckLabel ?? "Real-call profile history";
|
|
6561
6563
|
const fetchImpl = options.fetch ?? fetch;
|
|
6562
6564
|
const recoveryActionsHref = options.recoveryActionsHref ?? "/api/production-readiness/recovery-actions";
|
|
@@ -6598,70 +6600,88 @@ var runVoiceRealCallProfileRecoveryLoop = async (options) => {
|
|
|
6598
6600
|
actionCount: 0,
|
|
6599
6601
|
actions,
|
|
6600
6602
|
jobs: [],
|
|
6603
|
+
passes: 0,
|
|
6601
6604
|
ok: realCallProfileGate2?.status === "pass",
|
|
6602
6605
|
realCallProfileGate: realCallProfileGate2,
|
|
6603
6606
|
startFailures: []
|
|
6604
6607
|
};
|
|
6605
6608
|
}
|
|
6606
|
-
|
|
6607
|
-
|
|
6608
|
-
|
|
6609
|
-
|
|
6610
|
-
|
|
6611
|
-
|
|
6612
|
-
|
|
6613
|
-
|
|
6614
|
-
|
|
6615
|
-
|
|
6616
|
-
|
|
6617
|
-
|
|
6618
|
-
|
|
6619
|
-
|
|
6620
|
-
|
|
6621
|
-
|
|
6622
|
-
|
|
6623
|
-
|
|
6624
|
-
|
|
6625
|
-
|
|
6626
|
-
|
|
6627
|
-
|
|
6628
|
-
|
|
6629
|
-
|
|
6630
|
-
|
|
6631
|
-
|
|
6632
|
-
|
|
6633
|
-
|
|
6634
|
-
|
|
6635
|
-
|
|
6609
|
+
const allJobs = [];
|
|
6610
|
+
const allStartFailures = [];
|
|
6611
|
+
let realCallProfileGate = null;
|
|
6612
|
+
let passes = 0;
|
|
6613
|
+
for (let pass = 1;pass <= maxPasses; pass += 1) {
|
|
6614
|
+
passes = pass;
|
|
6615
|
+
options.logger?.log(`Running ${String(actions.length)} real-call profile recovery action(s) in parallel (pass ${String(pass)}/${String(maxPasses)}).`);
|
|
6616
|
+
for (const action of actions) {
|
|
6617
|
+
options.logger?.log(`- ${describeVoiceRealCallProfileRecoveryLoopAction(action)}`);
|
|
6618
|
+
}
|
|
6619
|
+
const starts = await Promise.allSettled(actions.map(async (action) => {
|
|
6620
|
+
if (!action.href) {
|
|
6621
|
+
throw new Error("Recovery action is missing href.");
|
|
6622
|
+
}
|
|
6623
|
+
const body = await fetchJson(action.href, { method: "POST" });
|
|
6624
|
+
return { action, ...body };
|
|
6625
|
+
}));
|
|
6626
|
+
const startedJobs = starts.flatMap((result) => {
|
|
6627
|
+
if (result.status === "rejected") {
|
|
6628
|
+
return [];
|
|
6629
|
+
}
|
|
6630
|
+
return result.value.jobId ? [result.value] : [];
|
|
6631
|
+
});
|
|
6632
|
+
const startFailures = starts.flatMap((result, index) => result.status === "rejected" ? [
|
|
6633
|
+
{
|
|
6634
|
+
action: describeVoiceRealCallProfileRecoveryLoopAction(actions[index] ?? {}),
|
|
6635
|
+
error: result.reason instanceof Error ? result.reason.message : String(result.reason)
|
|
6636
|
+
}
|
|
6637
|
+
] : []);
|
|
6638
|
+
allStartFailures.push(...startFailures);
|
|
6639
|
+
const pollJob = async (jobId) => {
|
|
6640
|
+
const deadline = Date.now() + jobTimeoutMs;
|
|
6641
|
+
while (Date.now() < deadline) {
|
|
6642
|
+
const body = await fetchJson(resolveJobHref(jobId));
|
|
6643
|
+
const job = body.job;
|
|
6644
|
+
if (!job) {
|
|
6645
|
+
throw new Error(`Recovery job ${jobId} was not found.`);
|
|
6646
|
+
}
|
|
6647
|
+
if (job.status === "pass" || job.status === "fail") {
|
|
6648
|
+
return job;
|
|
6649
|
+
}
|
|
6650
|
+
await sleepVoiceRealCallProfileRecoveryLoop(jobPollMs);
|
|
6636
6651
|
}
|
|
6637
|
-
|
|
6638
|
-
|
|
6652
|
+
throw new Error(`Timed out waiting ${String(jobTimeoutMs)}ms for recovery job ${jobId}.`);
|
|
6653
|
+
};
|
|
6654
|
+
options.logger?.log(`Polling ${String(startedJobs.length)} recovery job(s) in parallel.`);
|
|
6655
|
+
const jobResults = await Promise.allSettled(startedJobs.map((start) => pollJob(start.jobId)));
|
|
6656
|
+
const jobs = jobResults.map((result, index) => ({
|
|
6657
|
+
action: describeVoiceRealCallProfileRecoveryLoopAction(startedJobs[index]?.action ?? {}),
|
|
6658
|
+
jobId: startedJobs[index]?.jobId,
|
|
6659
|
+
result: result.status === "fulfilled" ? result.value : {
|
|
6660
|
+
error: result.reason instanceof Error ? result.reason.message : String(result.reason),
|
|
6661
|
+
status: "fail"
|
|
6639
6662
|
}
|
|
6640
|
-
|
|
6663
|
+
}));
|
|
6664
|
+
allJobs.push(...jobs);
|
|
6665
|
+
if (refreshHref !== false) {
|
|
6666
|
+
await fetchJson(refreshHref, { method: "POST" });
|
|
6641
6667
|
}
|
|
6642
|
-
|
|
6643
|
-
|
|
6644
|
-
|
|
6645
|
-
|
|
6646
|
-
|
|
6647
|
-
|
|
6648
|
-
|
|
6649
|
-
result: result.status === "fulfilled" ? result.value : {
|
|
6650
|
-
error: result.reason instanceof Error ? result.reason.message : String(result.reason),
|
|
6651
|
-
status: "fail"
|
|
6668
|
+
realCallProfileGate = await getGate(true);
|
|
6669
|
+
if (realCallProfileGate?.status === "pass") {
|
|
6670
|
+
break;
|
|
6671
|
+
}
|
|
6672
|
+
if (pass < maxPasses) {
|
|
6673
|
+
options.logger?.log(`Waiting ${String(interPassDelayMs)}ms before the next real-call profile recovery pass.`);
|
|
6674
|
+
await sleepVoiceRealCallProfileRecoveryLoop(interPassDelayMs);
|
|
6652
6675
|
}
|
|
6653
|
-
}));
|
|
6654
|
-
if (refreshHref !== false) {
|
|
6655
|
-
await fetchJson(refreshHref, { method: "POST" });
|
|
6656
6676
|
}
|
|
6657
|
-
const realCallProfileGate = await getGate(true);
|
|
6658
6677
|
return {
|
|
6659
|
-
actionCount: actions.length,
|
|
6678
|
+
actionCount: actions.length * passes,
|
|
6660
6679
|
actions,
|
|
6661
|
-
jobs,
|
|
6662
|
-
|
|
6680
|
+
jobs: allJobs,
|
|
6681
|
+
passes,
|
|
6682
|
+
ok: allStartFailures.length === 0 && allJobs.every((job) => job.result.status === "pass") && realCallProfileGate?.status === "pass",
|
|
6663
6683
|
realCallProfileGate,
|
|
6664
|
-
startFailures
|
|
6684
|
+
startFailures: allStartFailures
|
|
6665
6685
|
};
|
|
6666
6686
|
};
|
|
6667
6687
|
var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
|
package/dist/index.js
CHANGED
|
@@ -17076,6 +17076,8 @@ var runVoiceRealCallProfileRecoveryLoop = async (options) => {
|
|
|
17076
17076
|
const requestTimeoutMs = options.requestTimeoutMs ?? 5000;
|
|
17077
17077
|
const jobPollMs = options.jobPollMs ?? 1200;
|
|
17078
17078
|
const jobTimeoutMs = options.jobTimeoutMs ?? 600000;
|
|
17079
|
+
const interPassDelayMs = typeof options.interPassDelayMs === "number" && Number.isFinite(options.interPassDelayMs) && options.interPassDelayMs > 0 ? options.interPassDelayMs : 5000;
|
|
17080
|
+
const maxPasses = typeof options.maxPasses === "number" && Number.isFinite(options.maxPasses) && options.maxPasses > 0 ? Math.floor(options.maxPasses) : 3;
|
|
17079
17081
|
const readinessCheckLabel = options.readinessCheckLabel ?? "Real-call profile history";
|
|
17080
17082
|
const fetchImpl = options.fetch ?? fetch;
|
|
17081
17083
|
const recoveryActionsHref = options.recoveryActionsHref ?? "/api/production-readiness/recovery-actions";
|
|
@@ -17117,70 +17119,88 @@ var runVoiceRealCallProfileRecoveryLoop = async (options) => {
|
|
|
17117
17119
|
actionCount: 0,
|
|
17118
17120
|
actions,
|
|
17119
17121
|
jobs: [],
|
|
17122
|
+
passes: 0,
|
|
17120
17123
|
ok: realCallProfileGate2?.status === "pass",
|
|
17121
17124
|
realCallProfileGate: realCallProfileGate2,
|
|
17122
17125
|
startFailures: []
|
|
17123
17126
|
};
|
|
17124
17127
|
}
|
|
17125
|
-
|
|
17126
|
-
|
|
17127
|
-
|
|
17128
|
-
|
|
17129
|
-
|
|
17130
|
-
|
|
17131
|
-
|
|
17128
|
+
const allJobs = [];
|
|
17129
|
+
const allStartFailures = [];
|
|
17130
|
+
let realCallProfileGate = null;
|
|
17131
|
+
let passes = 0;
|
|
17132
|
+
for (let pass = 1;pass <= maxPasses; pass += 1) {
|
|
17133
|
+
passes = pass;
|
|
17134
|
+
options.logger?.log(`Running ${String(actions.length)} real-call profile recovery action(s) in parallel (pass ${String(pass)}/${String(maxPasses)}).`);
|
|
17135
|
+
for (const action of actions) {
|
|
17136
|
+
options.logger?.log(`- ${describeVoiceRealCallProfileRecoveryLoopAction(action)}`);
|
|
17137
|
+
}
|
|
17138
|
+
const starts = await Promise.allSettled(actions.map(async (action) => {
|
|
17139
|
+
if (!action.href) {
|
|
17140
|
+
throw new Error("Recovery action is missing href.");
|
|
17141
|
+
}
|
|
17142
|
+
const body = await fetchJson(action.href, { method: "POST" });
|
|
17143
|
+
return { action, ...body };
|
|
17144
|
+
}));
|
|
17145
|
+
const startedJobs = starts.flatMap((result) => {
|
|
17146
|
+
if (result.status === "rejected") {
|
|
17147
|
+
return [];
|
|
17148
|
+
}
|
|
17149
|
+
return result.value.jobId ? [result.value] : [];
|
|
17150
|
+
});
|
|
17151
|
+
const startFailures = starts.flatMap((result, index) => result.status === "rejected" ? [
|
|
17152
|
+
{
|
|
17153
|
+
action: describeVoiceRealCallProfileRecoveryLoopAction(actions[index] ?? {}),
|
|
17154
|
+
error: result.reason instanceof Error ? result.reason.message : String(result.reason)
|
|
17155
|
+
}
|
|
17156
|
+
] : []);
|
|
17157
|
+
allStartFailures.push(...startFailures);
|
|
17158
|
+
const pollJob = async (jobId) => {
|
|
17159
|
+
const deadline = Date.now() + jobTimeoutMs;
|
|
17160
|
+
while (Date.now() < deadline) {
|
|
17161
|
+
const body = await fetchJson(resolveJobHref(jobId));
|
|
17162
|
+
const job = body.job;
|
|
17163
|
+
if (!job) {
|
|
17164
|
+
throw new Error(`Recovery job ${jobId} was not found.`);
|
|
17165
|
+
}
|
|
17166
|
+
if (job.status === "pass" || job.status === "fail") {
|
|
17167
|
+
return job;
|
|
17168
|
+
}
|
|
17169
|
+
await sleepVoiceRealCallProfileRecoveryLoop(jobPollMs);
|
|
17170
|
+
}
|
|
17171
|
+
throw new Error(`Timed out waiting ${String(jobTimeoutMs)}ms for recovery job ${jobId}.`);
|
|
17172
|
+
};
|
|
17173
|
+
options.logger?.log(`Polling ${String(startedJobs.length)} recovery job(s) in parallel.`);
|
|
17174
|
+
const jobResults = await Promise.allSettled(startedJobs.map((start) => pollJob(start.jobId)));
|
|
17175
|
+
const jobs = jobResults.map((result, index) => ({
|
|
17176
|
+
action: describeVoiceRealCallProfileRecoveryLoopAction(startedJobs[index]?.action ?? {}),
|
|
17177
|
+
jobId: startedJobs[index]?.jobId,
|
|
17178
|
+
result: result.status === "fulfilled" ? result.value : {
|
|
17179
|
+
error: result.reason instanceof Error ? result.reason.message : String(result.reason),
|
|
17180
|
+
status: "fail"
|
|
17181
|
+
}
|
|
17182
|
+
}));
|
|
17183
|
+
allJobs.push(...jobs);
|
|
17184
|
+
if (refreshHref !== false) {
|
|
17185
|
+
await fetchJson(refreshHref, { method: "POST" });
|
|
17132
17186
|
}
|
|
17133
|
-
|
|
17134
|
-
|
|
17135
|
-
|
|
17136
|
-
const startedJobs = starts.flatMap((result) => {
|
|
17137
|
-
if (result.status === "rejected") {
|
|
17138
|
-
return [];
|
|
17187
|
+
realCallProfileGate = await getGate(true);
|
|
17188
|
+
if (realCallProfileGate?.status === "pass") {
|
|
17189
|
+
break;
|
|
17139
17190
|
}
|
|
17140
|
-
|
|
17141
|
-
|
|
17142
|
-
|
|
17143
|
-
{
|
|
17144
|
-
action: describeVoiceRealCallProfileRecoveryLoopAction(actions[index] ?? {}),
|
|
17145
|
-
error: result.reason instanceof Error ? result.reason.message : String(result.reason)
|
|
17146
|
-
}
|
|
17147
|
-
] : []);
|
|
17148
|
-
const pollJob = async (jobId) => {
|
|
17149
|
-
const deadline = Date.now() + jobTimeoutMs;
|
|
17150
|
-
while (Date.now() < deadline) {
|
|
17151
|
-
const body = await fetchJson(resolveJobHref(jobId));
|
|
17152
|
-
const job = body.job;
|
|
17153
|
-
if (!job) {
|
|
17154
|
-
throw new Error(`Recovery job ${jobId} was not found.`);
|
|
17155
|
-
}
|
|
17156
|
-
if (job.status === "pass" || job.status === "fail") {
|
|
17157
|
-
return job;
|
|
17158
|
-
}
|
|
17159
|
-
await sleepVoiceRealCallProfileRecoveryLoop(jobPollMs);
|
|
17160
|
-
}
|
|
17161
|
-
throw new Error(`Timed out waiting ${String(jobTimeoutMs)}ms for recovery job ${jobId}.`);
|
|
17162
|
-
};
|
|
17163
|
-
options.logger?.log(`Polling ${String(startedJobs.length)} recovery job(s) in parallel.`);
|
|
17164
|
-
const jobResults = await Promise.allSettled(startedJobs.map((start) => pollJob(start.jobId)));
|
|
17165
|
-
const jobs = jobResults.map((result, index) => ({
|
|
17166
|
-
action: describeVoiceRealCallProfileRecoveryLoopAction(startedJobs[index]?.action ?? {}),
|
|
17167
|
-
jobId: startedJobs[index]?.jobId,
|
|
17168
|
-
result: result.status === "fulfilled" ? result.value : {
|
|
17169
|
-
error: result.reason instanceof Error ? result.reason.message : String(result.reason),
|
|
17170
|
-
status: "fail"
|
|
17191
|
+
if (pass < maxPasses) {
|
|
17192
|
+
options.logger?.log(`Waiting ${String(interPassDelayMs)}ms before the next real-call profile recovery pass.`);
|
|
17193
|
+
await sleepVoiceRealCallProfileRecoveryLoop(interPassDelayMs);
|
|
17171
17194
|
}
|
|
17172
|
-
}));
|
|
17173
|
-
if (refreshHref !== false) {
|
|
17174
|
-
await fetchJson(refreshHref, { method: "POST" });
|
|
17175
17195
|
}
|
|
17176
|
-
const realCallProfileGate = await getGate(true);
|
|
17177
17196
|
return {
|
|
17178
|
-
actionCount: actions.length,
|
|
17197
|
+
actionCount: actions.length * passes,
|
|
17179
17198
|
actions,
|
|
17180
|
-
jobs,
|
|
17181
|
-
|
|
17199
|
+
jobs: allJobs,
|
|
17200
|
+
passes,
|
|
17201
|
+
ok: allStartFailures.length === 0 && allJobs.every((job) => job.result.status === "pass") && realCallProfileGate?.status === "pass",
|
|
17182
17202
|
realCallProfileGate,
|
|
17183
|
-
startFailures
|
|
17203
|
+
startFailures: allStartFailures
|
|
17184
17204
|
};
|
|
17185
17205
|
};
|
|
17186
17206
|
var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
|
package/dist/proofTrends.d.ts
CHANGED
|
@@ -492,6 +492,7 @@ export type VoiceRealCallProfileRecoveryLoopReport = {
|
|
|
492
492
|
actionCount: number;
|
|
493
493
|
actions: VoiceRealCallProfileRecoveryLoopAction[];
|
|
494
494
|
jobs: VoiceRealCallProfileRecoveryLoopJobResult[];
|
|
495
|
+
passes: number;
|
|
495
496
|
ok: boolean;
|
|
496
497
|
realCallProfileGate: VoiceProductionReadinessCheck | null;
|
|
497
498
|
startFailures: VoiceRealCallProfileRecoveryLoopStartFailure[];
|
|
@@ -500,10 +501,12 @@ export type VoiceRealCallProfileRecoveryLoopOptions = {
|
|
|
500
501
|
actionFilter?: (action: VoiceRealCallProfileRecoveryLoopAction) => boolean;
|
|
501
502
|
baseUrl: string;
|
|
502
503
|
fetch?: typeof fetch;
|
|
504
|
+
interPassDelayMs?: number;
|
|
503
505
|
jobHref?: string | ((jobId: string) => string);
|
|
504
506
|
jobPollMs?: number;
|
|
505
507
|
jobTimeoutMs?: number;
|
|
506
508
|
logger?: Pick<Console, 'log'>;
|
|
509
|
+
maxPasses?: number;
|
|
507
510
|
readinessCheckLabel?: string;
|
|
508
511
|
readinessHref?: string;
|
|
509
512
|
recoveryActionsHref?: string;
|
package/dist/react/index.js
CHANGED
|
@@ -4144,6 +4144,8 @@ var runVoiceRealCallProfileRecoveryLoop = async (options) => {
|
|
|
4144
4144
|
const requestTimeoutMs = options.requestTimeoutMs ?? 5000;
|
|
4145
4145
|
const jobPollMs = options.jobPollMs ?? 1200;
|
|
4146
4146
|
const jobTimeoutMs = options.jobTimeoutMs ?? 600000;
|
|
4147
|
+
const interPassDelayMs = typeof options.interPassDelayMs === "number" && Number.isFinite(options.interPassDelayMs) && options.interPassDelayMs > 0 ? options.interPassDelayMs : 5000;
|
|
4148
|
+
const maxPasses = typeof options.maxPasses === "number" && Number.isFinite(options.maxPasses) && options.maxPasses > 0 ? Math.floor(options.maxPasses) : 3;
|
|
4147
4149
|
const readinessCheckLabel = options.readinessCheckLabel ?? "Real-call profile history";
|
|
4148
4150
|
const fetchImpl = options.fetch ?? fetch;
|
|
4149
4151
|
const recoveryActionsHref = options.recoveryActionsHref ?? "/api/production-readiness/recovery-actions";
|
|
@@ -4185,70 +4187,88 @@ var runVoiceRealCallProfileRecoveryLoop = async (options) => {
|
|
|
4185
4187
|
actionCount: 0,
|
|
4186
4188
|
actions,
|
|
4187
4189
|
jobs: [],
|
|
4190
|
+
passes: 0,
|
|
4188
4191
|
ok: realCallProfileGate2?.status === "pass",
|
|
4189
4192
|
realCallProfileGate: realCallProfileGate2,
|
|
4190
4193
|
startFailures: []
|
|
4191
4194
|
};
|
|
4192
4195
|
}
|
|
4193
|
-
|
|
4194
|
-
|
|
4195
|
-
|
|
4196
|
-
|
|
4197
|
-
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4196
|
+
const allJobs = [];
|
|
4197
|
+
const allStartFailures = [];
|
|
4198
|
+
let realCallProfileGate = null;
|
|
4199
|
+
let passes = 0;
|
|
4200
|
+
for (let pass = 1;pass <= maxPasses; pass += 1) {
|
|
4201
|
+
passes = pass;
|
|
4202
|
+
options.logger?.log(`Running ${String(actions.length)} real-call profile recovery action(s) in parallel (pass ${String(pass)}/${String(maxPasses)}).`);
|
|
4203
|
+
for (const action of actions) {
|
|
4204
|
+
options.logger?.log(`- ${describeVoiceRealCallProfileRecoveryLoopAction(action)}`);
|
|
4205
|
+
}
|
|
4206
|
+
const starts = await Promise.allSettled(actions.map(async (action) => {
|
|
4207
|
+
if (!action.href) {
|
|
4208
|
+
throw new Error("Recovery action is missing href.");
|
|
4209
|
+
}
|
|
4210
|
+
const body = await fetchJson(action.href, { method: "POST" });
|
|
4211
|
+
return { action, ...body };
|
|
4212
|
+
}));
|
|
4213
|
+
const startedJobs = starts.flatMap((result) => {
|
|
4214
|
+
if (result.status === "rejected") {
|
|
4215
|
+
return [];
|
|
4216
|
+
}
|
|
4217
|
+
return result.value.jobId ? [result.value] : [];
|
|
4218
|
+
});
|
|
4219
|
+
const startFailures = starts.flatMap((result, index) => result.status === "rejected" ? [
|
|
4220
|
+
{
|
|
4221
|
+
action: describeVoiceRealCallProfileRecoveryLoopAction(actions[index] ?? {}),
|
|
4222
|
+
error: result.reason instanceof Error ? result.reason.message : String(result.reason)
|
|
4223
|
+
}
|
|
4224
|
+
] : []);
|
|
4225
|
+
allStartFailures.push(...startFailures);
|
|
4226
|
+
const pollJob = async (jobId) => {
|
|
4227
|
+
const deadline = Date.now() + jobTimeoutMs;
|
|
4228
|
+
while (Date.now() < deadline) {
|
|
4229
|
+
const body = await fetchJson(resolveJobHref(jobId));
|
|
4230
|
+
const job = body.job;
|
|
4231
|
+
if (!job) {
|
|
4232
|
+
throw new Error(`Recovery job ${jobId} was not found.`);
|
|
4233
|
+
}
|
|
4234
|
+
if (job.status === "pass" || job.status === "fail") {
|
|
4235
|
+
return job;
|
|
4236
|
+
}
|
|
4237
|
+
await sleepVoiceRealCallProfileRecoveryLoop(jobPollMs);
|
|
4223
4238
|
}
|
|
4224
|
-
|
|
4225
|
-
|
|
4239
|
+
throw new Error(`Timed out waiting ${String(jobTimeoutMs)}ms for recovery job ${jobId}.`);
|
|
4240
|
+
};
|
|
4241
|
+
options.logger?.log(`Polling ${String(startedJobs.length)} recovery job(s) in parallel.`);
|
|
4242
|
+
const jobResults = await Promise.allSettled(startedJobs.map((start) => pollJob(start.jobId)));
|
|
4243
|
+
const jobs = jobResults.map((result, index) => ({
|
|
4244
|
+
action: describeVoiceRealCallProfileRecoveryLoopAction(startedJobs[index]?.action ?? {}),
|
|
4245
|
+
jobId: startedJobs[index]?.jobId,
|
|
4246
|
+
result: result.status === "fulfilled" ? result.value : {
|
|
4247
|
+
error: result.reason instanceof Error ? result.reason.message : String(result.reason),
|
|
4248
|
+
status: "fail"
|
|
4226
4249
|
}
|
|
4227
|
-
|
|
4250
|
+
}));
|
|
4251
|
+
allJobs.push(...jobs);
|
|
4252
|
+
if (refreshHref !== false) {
|
|
4253
|
+
await fetchJson(refreshHref, { method: "POST" });
|
|
4228
4254
|
}
|
|
4229
|
-
|
|
4230
|
-
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
|
|
4234
|
-
|
|
4235
|
-
|
|
4236
|
-
result: result.status === "fulfilled" ? result.value : {
|
|
4237
|
-
error: result.reason instanceof Error ? result.reason.message : String(result.reason),
|
|
4238
|
-
status: "fail"
|
|
4255
|
+
realCallProfileGate = await getGate(true);
|
|
4256
|
+
if (realCallProfileGate?.status === "pass") {
|
|
4257
|
+
break;
|
|
4258
|
+
}
|
|
4259
|
+
if (pass < maxPasses) {
|
|
4260
|
+
options.logger?.log(`Waiting ${String(interPassDelayMs)}ms before the next real-call profile recovery pass.`);
|
|
4261
|
+
await sleepVoiceRealCallProfileRecoveryLoop(interPassDelayMs);
|
|
4239
4262
|
}
|
|
4240
|
-
}));
|
|
4241
|
-
if (refreshHref !== false) {
|
|
4242
|
-
await fetchJson(refreshHref, { method: "POST" });
|
|
4243
4263
|
}
|
|
4244
|
-
const realCallProfileGate = await getGate(true);
|
|
4245
4264
|
return {
|
|
4246
|
-
actionCount: actions.length,
|
|
4265
|
+
actionCount: actions.length * passes,
|
|
4247
4266
|
actions,
|
|
4248
|
-
jobs,
|
|
4249
|
-
|
|
4267
|
+
jobs: allJobs,
|
|
4268
|
+
passes,
|
|
4269
|
+
ok: allStartFailures.length === 0 && allJobs.every((job) => job.result.status === "pass") && realCallProfileGate?.status === "pass",
|
|
4250
4270
|
realCallProfileGate,
|
|
4251
|
-
startFailures
|
|
4271
|
+
startFailures: allStartFailures
|
|
4252
4272
|
};
|
|
4253
4273
|
};
|
|
4254
4274
|
var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
|
package/dist/vue/index.js
CHANGED
|
@@ -4065,6 +4065,8 @@ var runVoiceRealCallProfileRecoveryLoop = async (options) => {
|
|
|
4065
4065
|
const requestTimeoutMs = options.requestTimeoutMs ?? 5000;
|
|
4066
4066
|
const jobPollMs = options.jobPollMs ?? 1200;
|
|
4067
4067
|
const jobTimeoutMs = options.jobTimeoutMs ?? 600000;
|
|
4068
|
+
const interPassDelayMs = typeof options.interPassDelayMs === "number" && Number.isFinite(options.interPassDelayMs) && options.interPassDelayMs > 0 ? options.interPassDelayMs : 5000;
|
|
4069
|
+
const maxPasses = typeof options.maxPasses === "number" && Number.isFinite(options.maxPasses) && options.maxPasses > 0 ? Math.floor(options.maxPasses) : 3;
|
|
4068
4070
|
const readinessCheckLabel = options.readinessCheckLabel ?? "Real-call profile history";
|
|
4069
4071
|
const fetchImpl = options.fetch ?? fetch;
|
|
4070
4072
|
const recoveryActionsHref = options.recoveryActionsHref ?? "/api/production-readiness/recovery-actions";
|
|
@@ -4106,70 +4108,88 @@ var runVoiceRealCallProfileRecoveryLoop = async (options) => {
|
|
|
4106
4108
|
actionCount: 0,
|
|
4107
4109
|
actions,
|
|
4108
4110
|
jobs: [],
|
|
4111
|
+
passes: 0,
|
|
4109
4112
|
ok: realCallProfileGate2?.status === "pass",
|
|
4110
4113
|
realCallProfileGate: realCallProfileGate2,
|
|
4111
4114
|
startFailures: []
|
|
4112
4115
|
};
|
|
4113
4116
|
}
|
|
4114
|
-
|
|
4115
|
-
|
|
4116
|
-
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4120
|
-
|
|
4121
|
-
|
|
4122
|
-
|
|
4123
|
-
|
|
4124
|
-
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
4131
|
-
|
|
4132
|
-
|
|
4133
|
-
|
|
4134
|
-
|
|
4135
|
-
|
|
4136
|
-
|
|
4137
|
-
|
|
4138
|
-
|
|
4139
|
-
|
|
4140
|
-
|
|
4141
|
-
|
|
4142
|
-
|
|
4143
|
-
|
|
4117
|
+
const allJobs = [];
|
|
4118
|
+
const allStartFailures = [];
|
|
4119
|
+
let realCallProfileGate = null;
|
|
4120
|
+
let passes = 0;
|
|
4121
|
+
for (let pass = 1;pass <= maxPasses; pass += 1) {
|
|
4122
|
+
passes = pass;
|
|
4123
|
+
options.logger?.log(`Running ${String(actions.length)} real-call profile recovery action(s) in parallel (pass ${String(pass)}/${String(maxPasses)}).`);
|
|
4124
|
+
for (const action of actions) {
|
|
4125
|
+
options.logger?.log(`- ${describeVoiceRealCallProfileRecoveryLoopAction(action)}`);
|
|
4126
|
+
}
|
|
4127
|
+
const starts = await Promise.allSettled(actions.map(async (action) => {
|
|
4128
|
+
if (!action.href) {
|
|
4129
|
+
throw new Error("Recovery action is missing href.");
|
|
4130
|
+
}
|
|
4131
|
+
const body = await fetchJson(action.href, { method: "POST" });
|
|
4132
|
+
return { action, ...body };
|
|
4133
|
+
}));
|
|
4134
|
+
const startedJobs = starts.flatMap((result) => {
|
|
4135
|
+
if (result.status === "rejected") {
|
|
4136
|
+
return [];
|
|
4137
|
+
}
|
|
4138
|
+
return result.value.jobId ? [result.value] : [];
|
|
4139
|
+
});
|
|
4140
|
+
const startFailures = starts.flatMap((result, index) => result.status === "rejected" ? [
|
|
4141
|
+
{
|
|
4142
|
+
action: describeVoiceRealCallProfileRecoveryLoopAction(actions[index] ?? {}),
|
|
4143
|
+
error: result.reason instanceof Error ? result.reason.message : String(result.reason)
|
|
4144
|
+
}
|
|
4145
|
+
] : []);
|
|
4146
|
+
allStartFailures.push(...startFailures);
|
|
4147
|
+
const pollJob = async (jobId) => {
|
|
4148
|
+
const deadline = Date.now() + jobTimeoutMs;
|
|
4149
|
+
while (Date.now() < deadline) {
|
|
4150
|
+
const body = await fetchJson(resolveJobHref(jobId));
|
|
4151
|
+
const job = body.job;
|
|
4152
|
+
if (!job) {
|
|
4153
|
+
throw new Error(`Recovery job ${jobId} was not found.`);
|
|
4154
|
+
}
|
|
4155
|
+
if (job.status === "pass" || job.status === "fail") {
|
|
4156
|
+
return job;
|
|
4157
|
+
}
|
|
4158
|
+
await sleepVoiceRealCallProfileRecoveryLoop(jobPollMs);
|
|
4144
4159
|
}
|
|
4145
|
-
|
|
4146
|
-
|
|
4160
|
+
throw new Error(`Timed out waiting ${String(jobTimeoutMs)}ms for recovery job ${jobId}.`);
|
|
4161
|
+
};
|
|
4162
|
+
options.logger?.log(`Polling ${String(startedJobs.length)} recovery job(s) in parallel.`);
|
|
4163
|
+
const jobResults = await Promise.allSettled(startedJobs.map((start) => pollJob(start.jobId)));
|
|
4164
|
+
const jobs = jobResults.map((result, index) => ({
|
|
4165
|
+
action: describeVoiceRealCallProfileRecoveryLoopAction(startedJobs[index]?.action ?? {}),
|
|
4166
|
+
jobId: startedJobs[index]?.jobId,
|
|
4167
|
+
result: result.status === "fulfilled" ? result.value : {
|
|
4168
|
+
error: result.reason instanceof Error ? result.reason.message : String(result.reason),
|
|
4169
|
+
status: "fail"
|
|
4147
4170
|
}
|
|
4148
|
-
|
|
4171
|
+
}));
|
|
4172
|
+
allJobs.push(...jobs);
|
|
4173
|
+
if (refreshHref !== false) {
|
|
4174
|
+
await fetchJson(refreshHref, { method: "POST" });
|
|
4149
4175
|
}
|
|
4150
|
-
|
|
4151
|
-
|
|
4152
|
-
|
|
4153
|
-
|
|
4154
|
-
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
result: result.status === "fulfilled" ? result.value : {
|
|
4158
|
-
error: result.reason instanceof Error ? result.reason.message : String(result.reason),
|
|
4159
|
-
status: "fail"
|
|
4176
|
+
realCallProfileGate = await getGate(true);
|
|
4177
|
+
if (realCallProfileGate?.status === "pass") {
|
|
4178
|
+
break;
|
|
4179
|
+
}
|
|
4180
|
+
if (pass < maxPasses) {
|
|
4181
|
+
options.logger?.log(`Waiting ${String(interPassDelayMs)}ms before the next real-call profile recovery pass.`);
|
|
4182
|
+
await sleepVoiceRealCallProfileRecoveryLoop(interPassDelayMs);
|
|
4160
4183
|
}
|
|
4161
|
-
}));
|
|
4162
|
-
if (refreshHref !== false) {
|
|
4163
|
-
await fetchJson(refreshHref, { method: "POST" });
|
|
4164
4184
|
}
|
|
4165
|
-
const realCallProfileGate = await getGate(true);
|
|
4166
4185
|
return {
|
|
4167
|
-
actionCount: actions.length,
|
|
4186
|
+
actionCount: actions.length * passes,
|
|
4168
4187
|
actions,
|
|
4169
|
-
jobs,
|
|
4170
|
-
|
|
4188
|
+
jobs: allJobs,
|
|
4189
|
+
passes,
|
|
4190
|
+
ok: allStartFailures.length === 0 && allJobs.every((job) => job.result.status === "pass") && realCallProfileGate?.status === "pass",
|
|
4171
4191
|
realCallProfileGate,
|
|
4172
|
-
startFailures
|
|
4192
|
+
startFailures: allStartFailures
|
|
4173
4193
|
};
|
|
4174
4194
|
};
|
|
4175
4195
|
var buildVoiceRealCallProfileRecoveryActions = (report, options = {}) => {
|