@absolutejs/voice 0.0.22-beta.152 → 0.0.22-beta.153
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 +2 -0
- package/dist/angular/index.js +126 -1
- package/dist/angular/voice-delivery-runtime.component.d.ts +3 -0
- package/dist/angular/voice-delivery-runtime.service.d.ts +4 -0
- package/dist/client/deliveryRuntime.d.ts +15 -0
- package/dist/client/deliveryRuntimeWidget.d.ts +3 -0
- package/dist/client/index.d.ts +2 -2
- package/dist/client/index.js +85 -1
- package/dist/deliveryRuntime.d.ts +13 -1
- package/dist/index.js +44 -1
- package/dist/react/VoiceDeliveryRuntime.d.ts +2 -1
- package/dist/react/index.js +114 -2
- package/dist/react/useVoiceDeliveryRuntime.d.ts +5 -0
- package/dist/svelte/createVoiceDeliveryRuntime.d.ts +2 -0
- package/dist/svelte/index.js +87 -2
- package/dist/vue/VoiceDeliveryRuntime.d.ts +9 -0
- package/dist/vue/index.js +116 -1
- package/dist/vue/useVoiceDeliveryRuntime.d.ts +4 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -653,6 +653,8 @@ export function DeliveryWorkers() {
|
|
|
653
653
|
}
|
|
654
654
|
```
|
|
655
655
|
|
|
656
|
+
The widget includes operator actions by default: `Tick workers` drains pending/failed deliveries, and `Requeue dead letters` moves reviewed dead-lettered audit/trace deliveries back into the live queues. Pass `includeActions={false}` when you only want a read-only status card.
|
|
657
|
+
|
|
656
658
|
```ts
|
|
657
659
|
import { VoiceDeliveryRuntime } from '@absolutejs/voice/vue';
|
|
658
660
|
import { createVoiceDeliveryRuntime } from '@absolutejs/voice/svelte';
|
package/dist/angular/index.js
CHANGED
|
@@ -197,6 +197,12 @@ let _VoiceOpsStatusService = VoiceOpsStatusService;
|
|
|
197
197
|
import { computed as computed2, Injectable as Injectable2, signal as signal2 } from "@angular/core";
|
|
198
198
|
|
|
199
199
|
// src/client/deliveryRuntime.ts
|
|
200
|
+
var getDefaultActionPath = (path, action, options) => {
|
|
201
|
+
if (action === "tick") {
|
|
202
|
+
return options.tickPath ?? `${path.replace(/\/$/, "")}/tick`;
|
|
203
|
+
}
|
|
204
|
+
return options.requeueDeadLettersPath ?? `${path.replace(/\/$/, "")}/requeue-dead-letters`;
|
|
205
|
+
};
|
|
200
206
|
var fetchVoiceDeliveryRuntime = async (path = "/api/voice-delivery-runtime", options = {}) => {
|
|
201
207
|
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
202
208
|
const response = await fetchImpl(path);
|
|
@@ -205,11 +211,29 @@ var fetchVoiceDeliveryRuntime = async (path = "/api/voice-delivery-runtime", opt
|
|
|
205
211
|
}
|
|
206
212
|
return await response.json();
|
|
207
213
|
};
|
|
214
|
+
var runVoiceDeliveryRuntimeAction = async (action, path = "/api/voice-delivery-runtime", options = {}) => {
|
|
215
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
216
|
+
const response = await fetchImpl(getDefaultActionPath(path, action, options), {
|
|
217
|
+
method: "POST"
|
|
218
|
+
});
|
|
219
|
+
if (!response.ok) {
|
|
220
|
+
throw new Error(`Voice delivery runtime ${action} failed: HTTP ${response.status}`);
|
|
221
|
+
}
|
|
222
|
+
const body = await response.json();
|
|
223
|
+
return {
|
|
224
|
+
action,
|
|
225
|
+
result: body.result,
|
|
226
|
+
summary: body.summary,
|
|
227
|
+
updatedAt: Date.now()
|
|
228
|
+
};
|
|
229
|
+
};
|
|
208
230
|
var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", options = {}) => {
|
|
209
231
|
const listeners = new Set;
|
|
210
232
|
let closed = false;
|
|
211
233
|
let timer;
|
|
212
234
|
let snapshot = {
|
|
235
|
+
actionError: null,
|
|
236
|
+
actionStatus: "idle",
|
|
213
237
|
error: null,
|
|
214
238
|
isLoading: false
|
|
215
239
|
};
|
|
@@ -231,6 +255,7 @@ var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", opt
|
|
|
231
255
|
try {
|
|
232
256
|
const report = await fetchVoiceDeliveryRuntime(path, options);
|
|
233
257
|
snapshot = {
|
|
258
|
+
...snapshot,
|
|
234
259
|
error: null,
|
|
235
260
|
isLoading: false,
|
|
236
261
|
report,
|
|
@@ -248,6 +273,37 @@ var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", opt
|
|
|
248
273
|
throw error;
|
|
249
274
|
}
|
|
250
275
|
};
|
|
276
|
+
const runAction = async (action) => {
|
|
277
|
+
if (closed) {
|
|
278
|
+
return snapshot.lastAction;
|
|
279
|
+
}
|
|
280
|
+
snapshot = {
|
|
281
|
+
...snapshot,
|
|
282
|
+
actionError: null,
|
|
283
|
+
actionStatus: "running"
|
|
284
|
+
};
|
|
285
|
+
emit();
|
|
286
|
+
try {
|
|
287
|
+
const result = await runVoiceDeliveryRuntimeAction(action, path, options);
|
|
288
|
+
snapshot = {
|
|
289
|
+
...snapshot,
|
|
290
|
+
actionError: null,
|
|
291
|
+
actionStatus: "completed",
|
|
292
|
+
lastAction: result
|
|
293
|
+
};
|
|
294
|
+
emit();
|
|
295
|
+
await refresh();
|
|
296
|
+
return result;
|
|
297
|
+
} catch (error) {
|
|
298
|
+
snapshot = {
|
|
299
|
+
...snapshot,
|
|
300
|
+
actionError: error instanceof Error ? error.message : String(error),
|
|
301
|
+
actionStatus: "failed"
|
|
302
|
+
};
|
|
303
|
+
emit();
|
|
304
|
+
throw error;
|
|
305
|
+
}
|
|
306
|
+
};
|
|
251
307
|
const close = () => {
|
|
252
308
|
closed = true;
|
|
253
309
|
if (timer) {
|
|
@@ -265,7 +321,9 @@ var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", opt
|
|
|
265
321
|
close,
|
|
266
322
|
getServerSnapshot: () => snapshot,
|
|
267
323
|
getSnapshot: () => snapshot,
|
|
324
|
+
requeueDeadLetters: () => runAction("requeue-dead-letters"),
|
|
268
325
|
refresh,
|
|
326
|
+
tick: () => runAction("tick"),
|
|
269
327
|
subscribe: (listener) => {
|
|
270
328
|
listeners.add(listener);
|
|
271
329
|
return () => {
|
|
@@ -284,12 +342,16 @@ var _init = __decoratorStart(undefined);
|
|
|
284
342
|
class VoiceDeliveryRuntimeService {
|
|
285
343
|
connect(path = "/api/voice-delivery-runtime", options = {}) {
|
|
286
344
|
const store = createVoiceDeliveryRuntimeStore(path, options);
|
|
345
|
+
const actionErrorSignal = signal2(null);
|
|
346
|
+
const actionStatusSignal = signal2("idle");
|
|
287
347
|
const errorSignal = signal2(null);
|
|
288
348
|
const isLoadingSignal = signal2(false);
|
|
289
349
|
const reportSignal = signal2(undefined);
|
|
290
350
|
const updatedAtSignal = signal2(undefined);
|
|
291
351
|
const sync = () => {
|
|
292
352
|
const snapshot = store.getSnapshot();
|
|
353
|
+
actionErrorSignal.set(snapshot.actionError);
|
|
354
|
+
actionStatusSignal.set(snapshot.actionStatus);
|
|
293
355
|
errorSignal.set(snapshot.error);
|
|
294
356
|
isLoadingSignal.set(snapshot.isLoading);
|
|
295
357
|
reportSignal.set(snapshot.report);
|
|
@@ -306,9 +368,13 @@ class VoiceDeliveryRuntimeService {
|
|
|
306
368
|
store.close();
|
|
307
369
|
},
|
|
308
370
|
error: computed2(() => errorSignal()),
|
|
371
|
+
actionError: computed2(() => actionErrorSignal()),
|
|
372
|
+
actionStatus: computed2(() => actionStatusSignal()),
|
|
309
373
|
isLoading: computed2(() => isLoadingSignal()),
|
|
374
|
+
requeueDeadLetters: store.requeueDeadLetters,
|
|
310
375
|
refresh: store.refresh,
|
|
311
376
|
report: computed2(() => reportSignal()),
|
|
377
|
+
tick: store.tick,
|
|
312
378
|
updatedAt: computed2(() => updatedAtSignal())
|
|
313
379
|
};
|
|
314
380
|
}
|
|
@@ -2817,6 +2883,8 @@ var createVoiceDeliveryRuntimeViewModel = (snapshot, options = {}) => {
|
|
|
2817
2883
|
return {
|
|
2818
2884
|
description: options.description ?? DEFAULT_DESCRIPTION,
|
|
2819
2885
|
error: snapshot.error,
|
|
2886
|
+
actionError: snapshot.actionError,
|
|
2887
|
+
actionStatus: snapshot.actionStatus,
|
|
2820
2888
|
isLoading: snapshot.isLoading,
|
|
2821
2889
|
isRunning: Boolean(report?.isRunning),
|
|
2822
2890
|
label: snapshot.error ? "Unavailable" : report ? report.isRunning ? "Running" : "Stopped" : "Checking",
|
|
@@ -2833,6 +2901,11 @@ var renderVoiceDeliveryRuntimeHTML = (snapshot, options = {}) => {
|
|
|
2833
2901
|
<strong>${escapeHtml(surface.detail)}</strong>
|
|
2834
2902
|
<small>${String(surface.failed)} failed · ${String(surface.deadLettered)} dead-lettered</small>
|
|
2835
2903
|
</li>`).join("");
|
|
2904
|
+
const actions = options.includeActions === false ? "" : `<div class="absolute-voice-delivery-runtime__actions">
|
|
2905
|
+
<button type="button" data-absolute-voice-delivery-runtime-action="tick">${model.actionStatus === "running" ? "Working..." : "Tick workers"}</button>
|
|
2906
|
+
<button type="button" data-absolute-voice-delivery-runtime-action="requeue-dead-letters"${model.surfaces.some((surface) => surface.deadLettered > 0) ? "" : " disabled"}>Requeue dead letters</button>
|
|
2907
|
+
</div>`;
|
|
2908
|
+
const actionError = model.actionError ? `<p class="absolute-voice-delivery-runtime__error">${escapeHtml(model.actionError)}</p>` : "";
|
|
2836
2909
|
return `<section class="absolute-voice-delivery-runtime absolute-voice-delivery-runtime--${escapeHtml(model.status)}">
|
|
2837
2910
|
<header class="absolute-voice-delivery-runtime__header">
|
|
2838
2911
|
<span class="absolute-voice-delivery-runtime__eyebrow">${escapeHtml(model.title)}</span>
|
|
@@ -2840,20 +2913,38 @@ var renderVoiceDeliveryRuntimeHTML = (snapshot, options = {}) => {
|
|
|
2840
2913
|
</header>
|
|
2841
2914
|
<p class="absolute-voice-delivery-runtime__description">${escapeHtml(model.description)}</p>
|
|
2842
2915
|
<ul class="absolute-voice-delivery-runtime__surfaces">${surfaces}</ul>
|
|
2916
|
+
${actions}
|
|
2917
|
+
${actionError}
|
|
2843
2918
|
${model.error ? `<p class="absolute-voice-delivery-runtime__error">${escapeHtml(model.error)}</p>` : ""}
|
|
2844
2919
|
</section>`;
|
|
2845
2920
|
};
|
|
2846
|
-
var getVoiceDeliveryRuntimeCSS = () => `.absolute-voice-delivery-runtime{border:1px solid #c9d8cf;border-radius:20px;background:#f6fff9;color:#0d1b12;padding:18px;box-shadow:0 18px 40px rgba(19,55,35,.12);font-family:inherit}.absolute-voice-delivery-runtime--warn,.absolute-voice-delivery-runtime--error{border-color:#f2b56b;background:#fff9ed}.absolute-voice-delivery-runtime__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-delivery-runtime__eyebrow{color:#4e6b59;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-delivery-runtime__label{font-size:28px;line-height:1}.absolute-voice-delivery-runtime__description{color:#33483b;margin:12px 0 0}.absolute-voice-delivery-runtime__surfaces{display:grid;gap:8px;list-style:none;margin:16px 0 0;padding:0}.absolute-voice-delivery-runtime__surface{background:#fff;border:1px solid #d9eadf;border-radius:14px;display:grid;gap:4px;padding:10px 12px}.absolute-voice-delivery-runtime__surface--warn{border-color:#f2b56b}.absolute-voice-delivery-runtime__surface--disabled{opacity:.72}.absolute-voice-delivery-runtime__surface span,.absolute-voice-delivery-runtime__surface small{color:#587063}.absolute-voice-delivery-runtime__error{color:#9f1239;font-weight:700}`;
|
|
2921
|
+
var getVoiceDeliveryRuntimeCSS = () => `.absolute-voice-delivery-runtime{border:1px solid #c9d8cf;border-radius:20px;background:#f6fff9;color:#0d1b12;padding:18px;box-shadow:0 18px 40px rgba(19,55,35,.12);font-family:inherit}.absolute-voice-delivery-runtime--warn,.absolute-voice-delivery-runtime--error{border-color:#f2b56b;background:#fff9ed}.absolute-voice-delivery-runtime__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-delivery-runtime__eyebrow{color:#4e6b59;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-delivery-runtime__label{font-size:28px;line-height:1}.absolute-voice-delivery-runtime__description{color:#33483b;margin:12px 0 0}.absolute-voice-delivery-runtime__surfaces{display:grid;gap:8px;list-style:none;margin:16px 0 0;padding:0}.absolute-voice-delivery-runtime__surface{background:#fff;border:1px solid #d9eadf;border-radius:14px;display:grid;gap:4px;padding:10px 12px}.absolute-voice-delivery-runtime__surface--warn{border-color:#f2b56b}.absolute-voice-delivery-runtime__surface--disabled{opacity:.72}.absolute-voice-delivery-runtime__surface span,.absolute-voice-delivery-runtime__surface small{color:#587063}.absolute-voice-delivery-runtime__actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px}.absolute-voice-delivery-runtime__actions button{background:#134e2d;border:0;border-radius:999px;color:#f6fff9;cursor:pointer;font:inherit;font-weight:800;padding:8px 12px}.absolute-voice-delivery-runtime__actions button:disabled{cursor:not-allowed;opacity:.48}.absolute-voice-delivery-runtime__error{color:#9f1239;font-weight:700}`;
|
|
2847
2922
|
var mountVoiceDeliveryRuntime = (element, path = "/api/voice-delivery-runtime", options = {}) => {
|
|
2848
2923
|
const store = createVoiceDeliveryRuntimeStore(path, options);
|
|
2849
2924
|
const render = () => {
|
|
2850
2925
|
element.innerHTML = renderVoiceDeliveryRuntimeHTML(store.getSnapshot(), options);
|
|
2851
2926
|
};
|
|
2852
2927
|
const unsubscribe = store.subscribe(render);
|
|
2928
|
+
const handleClick = (event) => {
|
|
2929
|
+
const target = event.target;
|
|
2930
|
+
if (!(target instanceof Element)) {
|
|
2931
|
+
return;
|
|
2932
|
+
}
|
|
2933
|
+
const action = target.closest("[data-absolute-voice-delivery-runtime-action]");
|
|
2934
|
+
const actionName = action?.getAttribute("data-absolute-voice-delivery-runtime-action");
|
|
2935
|
+
if (actionName === "tick") {
|
|
2936
|
+
store.tick().catch(() => {});
|
|
2937
|
+
}
|
|
2938
|
+
if (actionName === "requeue-dead-letters") {
|
|
2939
|
+
store.requeueDeadLetters().catch(() => {});
|
|
2940
|
+
}
|
|
2941
|
+
};
|
|
2942
|
+
element.addEventListener?.("click", handleClick);
|
|
2853
2943
|
render();
|
|
2854
2944
|
store.refresh().catch(() => {});
|
|
2855
2945
|
return {
|
|
2856
2946
|
close: () => {
|
|
2947
|
+
element.removeEventListener?.("click", handleClick);
|
|
2857
2948
|
unsubscribe();
|
|
2858
2949
|
store.close();
|
|
2859
2950
|
},
|
|
@@ -2932,6 +3023,29 @@ var _dec = [
|
|
|
2932
3023
|
</li>
|
|
2933
3024
|
}
|
|
2934
3025
|
</ul>
|
|
3026
|
+
<div class="absolute-voice-delivery-runtime__actions">
|
|
3027
|
+
<button
|
|
3028
|
+
type="button"
|
|
3029
|
+
[disabled]="model().actionStatus === 'running'"
|
|
3030
|
+
(click)="tick()"
|
|
3031
|
+
>
|
|
3032
|
+
{{ model().actionStatus === "running" ? "Working..." : "Tick workers" }}
|
|
3033
|
+
</button>
|
|
3034
|
+
<button
|
|
3035
|
+
type="button"
|
|
3036
|
+
[disabled]="
|
|
3037
|
+
model().actionStatus === 'running' || deadLettered() === 0
|
|
3038
|
+
"
|
|
3039
|
+
(click)="requeueDeadLetters()"
|
|
3040
|
+
>
|
|
3041
|
+
Requeue dead letters
|
|
3042
|
+
</button>
|
|
3043
|
+
</div>
|
|
3044
|
+
@if (model().actionError) {
|
|
3045
|
+
<p class="absolute-voice-delivery-runtime__error">
|
|
3046
|
+
{{ model().actionError }}
|
|
3047
|
+
</p>
|
|
3048
|
+
}
|
|
2935
3049
|
@if (model().error) {
|
|
2936
3050
|
<p class="absolute-voice-delivery-runtime__error">
|
|
2937
3051
|
{{ model().error }}
|
|
@@ -2969,6 +3083,8 @@ class VoiceDeliveryRuntimeComponent {
|
|
|
2969
3083
|
cleanup = () => {};
|
|
2970
3084
|
store;
|
|
2971
3085
|
model = signal13(createVoiceDeliveryRuntimeViewModel({
|
|
3086
|
+
actionError: null,
|
|
3087
|
+
actionStatus: "idle",
|
|
2972
3088
|
error: null,
|
|
2973
3089
|
isLoading: true
|
|
2974
3090
|
}));
|
|
@@ -2988,6 +3104,15 @@ class VoiceDeliveryRuntimeComponent {
|
|
|
2988
3104
|
this.cleanup();
|
|
2989
3105
|
this.store?.close();
|
|
2990
3106
|
}
|
|
3107
|
+
deadLettered() {
|
|
3108
|
+
return this.model().surfaces.reduce((total, surface) => total + surface.deadLettered, 0);
|
|
3109
|
+
}
|
|
3110
|
+
tick() {
|
|
3111
|
+
this.store?.tick().catch(() => {});
|
|
3112
|
+
}
|
|
3113
|
+
requeueDeadLetters() {
|
|
3114
|
+
this.store?.requeueDeadLetters().catch(() => {});
|
|
3115
|
+
}
|
|
2991
3116
|
options() {
|
|
2992
3117
|
return {
|
|
2993
3118
|
description: this.description,
|
|
@@ -10,5 +10,8 @@ export declare class VoiceDeliveryRuntimeComponent implements OnDestroy, OnInit
|
|
|
10
10
|
model: import("@angular/core").WritableSignal<VoiceDeliveryRuntimeViewModel>;
|
|
11
11
|
ngOnInit(): void;
|
|
12
12
|
ngOnDestroy(): void;
|
|
13
|
+
deadLettered(): number;
|
|
14
|
+
tick(): void;
|
|
15
|
+
requeueDeadLetters(): void;
|
|
13
16
|
private options;
|
|
14
17
|
}
|
|
@@ -4,9 +4,13 @@ export declare class VoiceDeliveryRuntimeService {
|
|
|
4
4
|
connect(path?: string, options?: VoiceDeliveryRuntimeClientOptions): {
|
|
5
5
|
close: () => void;
|
|
6
6
|
error: import("@angular/core").Signal<string | null>;
|
|
7
|
+
actionError: import("@angular/core").Signal<string | null>;
|
|
8
|
+
actionStatus: import("@angular/core").Signal<"completed" | "failed" | "idle" | "running">;
|
|
7
9
|
isLoading: import("@angular/core").Signal<boolean>;
|
|
10
|
+
requeueDeadLetters: () => Promise<import("../client").VoiceDeliveryRuntimeActionResult | undefined>;
|
|
8
11
|
refresh: () => Promise<VoiceDeliveryRuntimeReport | undefined>;
|
|
9
12
|
report: import("@angular/core").Signal<VoiceDeliveryRuntimeReport | undefined>;
|
|
13
|
+
tick: () => Promise<import("../client").VoiceDeliveryRuntimeActionResult | undefined>;
|
|
10
14
|
updatedAt: import("@angular/core").Signal<number | undefined>;
|
|
11
15
|
};
|
|
12
16
|
}
|
|
@@ -2,18 +2,33 @@ import type { VoiceDeliveryRuntimeReport } from '../deliveryRuntime';
|
|
|
2
2
|
export type VoiceDeliveryRuntimeClientOptions = {
|
|
3
3
|
fetch?: typeof fetch;
|
|
4
4
|
intervalMs?: number;
|
|
5
|
+
requeueDeadLettersPath?: string;
|
|
6
|
+
tickPath?: string;
|
|
5
7
|
};
|
|
6
8
|
export type VoiceDeliveryRuntimeSnapshot = {
|
|
9
|
+
actionError: string | null;
|
|
10
|
+
actionStatus: 'idle' | 'running' | 'completed' | 'failed';
|
|
7
11
|
error: string | null;
|
|
8
12
|
isLoading: boolean;
|
|
13
|
+
lastAction?: VoiceDeliveryRuntimeActionResult;
|
|
9
14
|
report?: VoiceDeliveryRuntimeReport;
|
|
10
15
|
updatedAt?: number;
|
|
11
16
|
};
|
|
17
|
+
export type VoiceDeliveryRuntimeAction = 'tick' | 'requeue-dead-letters';
|
|
18
|
+
export type VoiceDeliveryRuntimeActionResult = {
|
|
19
|
+
action: VoiceDeliveryRuntimeAction;
|
|
20
|
+
result?: unknown;
|
|
21
|
+
summary?: VoiceDeliveryRuntimeReport['summary'];
|
|
22
|
+
updatedAt: number;
|
|
23
|
+
};
|
|
12
24
|
export declare const fetchVoiceDeliveryRuntime: (path?: string, options?: Pick<VoiceDeliveryRuntimeClientOptions, "fetch">) => Promise<VoiceDeliveryRuntimeReport>;
|
|
25
|
+
export declare const runVoiceDeliveryRuntimeAction: (action: VoiceDeliveryRuntimeAction, path?: string, options?: VoiceDeliveryRuntimeClientOptions) => Promise<VoiceDeliveryRuntimeActionResult>;
|
|
13
26
|
export declare const createVoiceDeliveryRuntimeStore: (path?: string, options?: VoiceDeliveryRuntimeClientOptions) => {
|
|
14
27
|
close: () => void;
|
|
15
28
|
getServerSnapshot: () => VoiceDeliveryRuntimeSnapshot;
|
|
16
29
|
getSnapshot: () => VoiceDeliveryRuntimeSnapshot;
|
|
30
|
+
requeueDeadLetters: () => Promise<VoiceDeliveryRuntimeActionResult | undefined>;
|
|
17
31
|
refresh: () => Promise<VoiceDeliveryRuntimeReport | undefined>;
|
|
32
|
+
tick: () => Promise<VoiceDeliveryRuntimeActionResult | undefined>;
|
|
18
33
|
subscribe: (listener: () => void) => () => void;
|
|
19
34
|
};
|
|
@@ -12,6 +12,8 @@ export type VoiceDeliveryRuntimeSurfaceView = {
|
|
|
12
12
|
export type VoiceDeliveryRuntimeViewModel = {
|
|
13
13
|
description: string;
|
|
14
14
|
error: string | null;
|
|
15
|
+
actionError: string | null;
|
|
16
|
+
actionStatus: VoiceDeliveryRuntimeSnapshot['actionStatus'];
|
|
15
17
|
isLoading: boolean;
|
|
16
18
|
isRunning: boolean;
|
|
17
19
|
label: string;
|
|
@@ -22,6 +24,7 @@ export type VoiceDeliveryRuntimeViewModel = {
|
|
|
22
24
|
};
|
|
23
25
|
export type VoiceDeliveryRuntimeWidgetOptions = VoiceDeliveryRuntimeClientOptions & {
|
|
24
26
|
description?: string;
|
|
27
|
+
includeActions?: boolean;
|
|
25
28
|
title?: string;
|
|
26
29
|
};
|
|
27
30
|
export declare const createVoiceDeliveryRuntimeViewModel: (snapshot: VoiceDeliveryRuntimeSnapshot, options?: VoiceDeliveryRuntimeWidgetOptions) => VoiceDeliveryRuntimeViewModel;
|
package/dist/client/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export { createMicrophoneCapture } from './microphone';
|
|
|
8
8
|
export { createVoiceBargeInMonitor } from './bargeInMonitor';
|
|
9
9
|
export { createVoiceLiveTurnLatencyMonitor } from './liveTurnLatency';
|
|
10
10
|
export { createVoiceOpsStatusStore, fetchVoiceOpsStatus } from './opsStatus';
|
|
11
|
-
export { createVoiceDeliveryRuntimeStore, fetchVoiceDeliveryRuntime } from './deliveryRuntime';
|
|
11
|
+
export { createVoiceDeliveryRuntimeStore, fetchVoiceDeliveryRuntime, runVoiceDeliveryRuntimeAction } from './deliveryRuntime';
|
|
12
12
|
export { createVoiceOpsStatusViewModel, defineVoiceOpsStatusElement, getVoiceOpsStatusCSS, getVoiceOpsStatusLabel, mountVoiceOpsStatus, renderVoiceOpsStatusHTML } from './opsStatusWidget';
|
|
13
13
|
export { createVoiceDeliveryRuntimeViewModel, defineVoiceDeliveryRuntimeElement, getVoiceDeliveryRuntimeCSS, mountVoiceDeliveryRuntime, renderVoiceDeliveryRuntimeHTML } from './deliveryRuntimeWidget';
|
|
14
14
|
export { createVoiceRoutingStatusStore, fetchVoiceRoutingStatus } from './routingStatus';
|
|
@@ -28,7 +28,7 @@ export { createVoiceTurnLatencyViewModel, defineVoiceTurnLatencyElement, mountVo
|
|
|
28
28
|
export { createVoiceTraceTimelineViewModel, defineVoiceTraceTimelineElement, getVoiceTraceTimelineCSS, mountVoiceTraceTimeline, renderVoiceTraceTimelineWidgetHTML } from './traceTimelineWidget';
|
|
29
29
|
export { createVoiceWorkflowStatusStore, fetchVoiceWorkflowStatus } from './workflowStatus';
|
|
30
30
|
export type { VoiceOpsStatusClientOptions, VoiceOpsStatusSnapshot } from './opsStatus';
|
|
31
|
-
export type { VoiceDeliveryRuntimeClientOptions, VoiceDeliveryRuntimeSnapshot } from './deliveryRuntime';
|
|
31
|
+
export type { VoiceDeliveryRuntimeClientOptions, VoiceDeliveryRuntimeAction, VoiceDeliveryRuntimeActionResult, VoiceDeliveryRuntimeSnapshot } from './deliveryRuntime';
|
|
32
32
|
export type { VoiceBargeInMonitorOptions } from './bargeInMonitor';
|
|
33
33
|
export type { VoiceLiveTurnLatencyEvent, VoiceLiveTurnLatencyMonitorOptions, VoiceLiveTurnLatencySnapshot, VoiceLiveTurnLatencyStatus } from './liveTurnLatency';
|
|
34
34
|
export type { VoiceOpsStatusSurfaceView, VoiceOpsStatusViewModel, VoiceOpsStatusWidgetOptions } from './opsStatusWidget';
|
package/dist/client/index.js
CHANGED
|
@@ -2063,6 +2063,12 @@ var createVoiceOpsStatusStore = (path = "/api/voice/ops-status", options = {}) =
|
|
|
2063
2063
|
};
|
|
2064
2064
|
};
|
|
2065
2065
|
// src/client/deliveryRuntime.ts
|
|
2066
|
+
var getDefaultActionPath = (path, action, options) => {
|
|
2067
|
+
if (action === "tick") {
|
|
2068
|
+
return options.tickPath ?? `${path.replace(/\/$/, "")}/tick`;
|
|
2069
|
+
}
|
|
2070
|
+
return options.requeueDeadLettersPath ?? `${path.replace(/\/$/, "")}/requeue-dead-letters`;
|
|
2071
|
+
};
|
|
2066
2072
|
var fetchVoiceDeliveryRuntime = async (path = "/api/voice-delivery-runtime", options = {}) => {
|
|
2067
2073
|
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
2068
2074
|
const response = await fetchImpl(path);
|
|
@@ -2071,11 +2077,29 @@ var fetchVoiceDeliveryRuntime = async (path = "/api/voice-delivery-runtime", opt
|
|
|
2071
2077
|
}
|
|
2072
2078
|
return await response.json();
|
|
2073
2079
|
};
|
|
2080
|
+
var runVoiceDeliveryRuntimeAction = async (action, path = "/api/voice-delivery-runtime", options = {}) => {
|
|
2081
|
+
const fetchImpl = options.fetch ?? globalThis.fetch;
|
|
2082
|
+
const response = await fetchImpl(getDefaultActionPath(path, action, options), {
|
|
2083
|
+
method: "POST"
|
|
2084
|
+
});
|
|
2085
|
+
if (!response.ok) {
|
|
2086
|
+
throw new Error(`Voice delivery runtime ${action} failed: HTTP ${response.status}`);
|
|
2087
|
+
}
|
|
2088
|
+
const body = await response.json();
|
|
2089
|
+
return {
|
|
2090
|
+
action,
|
|
2091
|
+
result: body.result,
|
|
2092
|
+
summary: body.summary,
|
|
2093
|
+
updatedAt: Date.now()
|
|
2094
|
+
};
|
|
2095
|
+
};
|
|
2074
2096
|
var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", options = {}) => {
|
|
2075
2097
|
const listeners = new Set;
|
|
2076
2098
|
let closed = false;
|
|
2077
2099
|
let timer;
|
|
2078
2100
|
let snapshot = {
|
|
2101
|
+
actionError: null,
|
|
2102
|
+
actionStatus: "idle",
|
|
2079
2103
|
error: null,
|
|
2080
2104
|
isLoading: false
|
|
2081
2105
|
};
|
|
@@ -2097,6 +2121,7 @@ var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", opt
|
|
|
2097
2121
|
try {
|
|
2098
2122
|
const report = await fetchVoiceDeliveryRuntime(path, options);
|
|
2099
2123
|
snapshot = {
|
|
2124
|
+
...snapshot,
|
|
2100
2125
|
error: null,
|
|
2101
2126
|
isLoading: false,
|
|
2102
2127
|
report,
|
|
@@ -2114,6 +2139,37 @@ var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", opt
|
|
|
2114
2139
|
throw error;
|
|
2115
2140
|
}
|
|
2116
2141
|
};
|
|
2142
|
+
const runAction = async (action) => {
|
|
2143
|
+
if (closed) {
|
|
2144
|
+
return snapshot.lastAction;
|
|
2145
|
+
}
|
|
2146
|
+
snapshot = {
|
|
2147
|
+
...snapshot,
|
|
2148
|
+
actionError: null,
|
|
2149
|
+
actionStatus: "running"
|
|
2150
|
+
};
|
|
2151
|
+
emit();
|
|
2152
|
+
try {
|
|
2153
|
+
const result = await runVoiceDeliveryRuntimeAction(action, path, options);
|
|
2154
|
+
snapshot = {
|
|
2155
|
+
...snapshot,
|
|
2156
|
+
actionError: null,
|
|
2157
|
+
actionStatus: "completed",
|
|
2158
|
+
lastAction: result
|
|
2159
|
+
};
|
|
2160
|
+
emit();
|
|
2161
|
+
await refresh();
|
|
2162
|
+
return result;
|
|
2163
|
+
} catch (error) {
|
|
2164
|
+
snapshot = {
|
|
2165
|
+
...snapshot,
|
|
2166
|
+
actionError: error instanceof Error ? error.message : String(error),
|
|
2167
|
+
actionStatus: "failed"
|
|
2168
|
+
};
|
|
2169
|
+
emit();
|
|
2170
|
+
throw error;
|
|
2171
|
+
}
|
|
2172
|
+
};
|
|
2117
2173
|
const close = () => {
|
|
2118
2174
|
closed = true;
|
|
2119
2175
|
if (timer) {
|
|
@@ -2131,7 +2187,9 @@ var createVoiceDeliveryRuntimeStore = (path = "/api/voice-delivery-runtime", opt
|
|
|
2131
2187
|
close,
|
|
2132
2188
|
getServerSnapshot: () => snapshot,
|
|
2133
2189
|
getSnapshot: () => snapshot,
|
|
2190
|
+
requeueDeadLetters: () => runAction("requeue-dead-letters"),
|
|
2134
2191
|
refresh,
|
|
2192
|
+
tick: () => runAction("tick"),
|
|
2135
2193
|
subscribe: (listener) => {
|
|
2136
2194
|
listeners.add(listener);
|
|
2137
2195
|
return () => {
|
|
@@ -2303,6 +2361,8 @@ var createVoiceDeliveryRuntimeViewModel = (snapshot, options = {}) => {
|
|
|
2303
2361
|
return {
|
|
2304
2362
|
description: options.description ?? DEFAULT_DESCRIPTION2,
|
|
2305
2363
|
error: snapshot.error,
|
|
2364
|
+
actionError: snapshot.actionError,
|
|
2365
|
+
actionStatus: snapshot.actionStatus,
|
|
2306
2366
|
isLoading: snapshot.isLoading,
|
|
2307
2367
|
isRunning: Boolean(report?.isRunning),
|
|
2308
2368
|
label: snapshot.error ? "Unavailable" : report ? report.isRunning ? "Running" : "Stopped" : "Checking",
|
|
@@ -2319,6 +2379,11 @@ var renderVoiceDeliveryRuntimeHTML = (snapshot, options = {}) => {
|
|
|
2319
2379
|
<strong>${escapeHtml2(surface.detail)}</strong>
|
|
2320
2380
|
<small>${String(surface.failed)} failed · ${String(surface.deadLettered)} dead-lettered</small>
|
|
2321
2381
|
</li>`).join("");
|
|
2382
|
+
const actions = options.includeActions === false ? "" : `<div class="absolute-voice-delivery-runtime__actions">
|
|
2383
|
+
<button type="button" data-absolute-voice-delivery-runtime-action="tick">${model.actionStatus === "running" ? "Working..." : "Tick workers"}</button>
|
|
2384
|
+
<button type="button" data-absolute-voice-delivery-runtime-action="requeue-dead-letters"${model.surfaces.some((surface) => surface.deadLettered > 0) ? "" : " disabled"}>Requeue dead letters</button>
|
|
2385
|
+
</div>`;
|
|
2386
|
+
const actionError = model.actionError ? `<p class="absolute-voice-delivery-runtime__error">${escapeHtml2(model.actionError)}</p>` : "";
|
|
2322
2387
|
return `<section class="absolute-voice-delivery-runtime absolute-voice-delivery-runtime--${escapeHtml2(model.status)}">
|
|
2323
2388
|
<header class="absolute-voice-delivery-runtime__header">
|
|
2324
2389
|
<span class="absolute-voice-delivery-runtime__eyebrow">${escapeHtml2(model.title)}</span>
|
|
@@ -2326,20 +2391,38 @@ var renderVoiceDeliveryRuntimeHTML = (snapshot, options = {}) => {
|
|
|
2326
2391
|
</header>
|
|
2327
2392
|
<p class="absolute-voice-delivery-runtime__description">${escapeHtml2(model.description)}</p>
|
|
2328
2393
|
<ul class="absolute-voice-delivery-runtime__surfaces">${surfaces}</ul>
|
|
2394
|
+
${actions}
|
|
2395
|
+
${actionError}
|
|
2329
2396
|
${model.error ? `<p class="absolute-voice-delivery-runtime__error">${escapeHtml2(model.error)}</p>` : ""}
|
|
2330
2397
|
</section>`;
|
|
2331
2398
|
};
|
|
2332
|
-
var getVoiceDeliveryRuntimeCSS = () => `.absolute-voice-delivery-runtime{border:1px solid #c9d8cf;border-radius:20px;background:#f6fff9;color:#0d1b12;padding:18px;box-shadow:0 18px 40px rgba(19,55,35,.12);font-family:inherit}.absolute-voice-delivery-runtime--warn,.absolute-voice-delivery-runtime--error{border-color:#f2b56b;background:#fff9ed}.absolute-voice-delivery-runtime__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-delivery-runtime__eyebrow{color:#4e6b59;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-delivery-runtime__label{font-size:28px;line-height:1}.absolute-voice-delivery-runtime__description{color:#33483b;margin:12px 0 0}.absolute-voice-delivery-runtime__surfaces{display:grid;gap:8px;list-style:none;margin:16px 0 0;padding:0}.absolute-voice-delivery-runtime__surface{background:#fff;border:1px solid #d9eadf;border-radius:14px;display:grid;gap:4px;padding:10px 12px}.absolute-voice-delivery-runtime__surface--warn{border-color:#f2b56b}.absolute-voice-delivery-runtime__surface--disabled{opacity:.72}.absolute-voice-delivery-runtime__surface span,.absolute-voice-delivery-runtime__surface small{color:#587063}.absolute-voice-delivery-runtime__error{color:#9f1239;font-weight:700}`;
|
|
2399
|
+
var getVoiceDeliveryRuntimeCSS = () => `.absolute-voice-delivery-runtime{border:1px solid #c9d8cf;border-radius:20px;background:#f6fff9;color:#0d1b12;padding:18px;box-shadow:0 18px 40px rgba(19,55,35,.12);font-family:inherit}.absolute-voice-delivery-runtime--warn,.absolute-voice-delivery-runtime--error{border-color:#f2b56b;background:#fff9ed}.absolute-voice-delivery-runtime__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-delivery-runtime__eyebrow{color:#4e6b59;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-delivery-runtime__label{font-size:28px;line-height:1}.absolute-voice-delivery-runtime__description{color:#33483b;margin:12px 0 0}.absolute-voice-delivery-runtime__surfaces{display:grid;gap:8px;list-style:none;margin:16px 0 0;padding:0}.absolute-voice-delivery-runtime__surface{background:#fff;border:1px solid #d9eadf;border-radius:14px;display:grid;gap:4px;padding:10px 12px}.absolute-voice-delivery-runtime__surface--warn{border-color:#f2b56b}.absolute-voice-delivery-runtime__surface--disabled{opacity:.72}.absolute-voice-delivery-runtime__surface span,.absolute-voice-delivery-runtime__surface small{color:#587063}.absolute-voice-delivery-runtime__actions{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px}.absolute-voice-delivery-runtime__actions button{background:#134e2d;border:0;border-radius:999px;color:#f6fff9;cursor:pointer;font:inherit;font-weight:800;padding:8px 12px}.absolute-voice-delivery-runtime__actions button:disabled{cursor:not-allowed;opacity:.48}.absolute-voice-delivery-runtime__error{color:#9f1239;font-weight:700}`;
|
|
2333
2400
|
var mountVoiceDeliveryRuntime = (element, path = "/api/voice-delivery-runtime", options = {}) => {
|
|
2334
2401
|
const store = createVoiceDeliveryRuntimeStore(path, options);
|
|
2335
2402
|
const render = () => {
|
|
2336
2403
|
element.innerHTML = renderVoiceDeliveryRuntimeHTML(store.getSnapshot(), options);
|
|
2337
2404
|
};
|
|
2338
2405
|
const unsubscribe = store.subscribe(render);
|
|
2406
|
+
const handleClick = (event) => {
|
|
2407
|
+
const target = event.target;
|
|
2408
|
+
if (!(target instanceof Element)) {
|
|
2409
|
+
return;
|
|
2410
|
+
}
|
|
2411
|
+
const action = target.closest("[data-absolute-voice-delivery-runtime-action]");
|
|
2412
|
+
const actionName = action?.getAttribute("data-absolute-voice-delivery-runtime-action");
|
|
2413
|
+
if (actionName === "tick") {
|
|
2414
|
+
store.tick().catch(() => {});
|
|
2415
|
+
}
|
|
2416
|
+
if (actionName === "requeue-dead-letters") {
|
|
2417
|
+
store.requeueDeadLetters().catch(() => {});
|
|
2418
|
+
}
|
|
2419
|
+
};
|
|
2420
|
+
element.addEventListener?.("click", handleClick);
|
|
2339
2421
|
render();
|
|
2340
2422
|
store.refresh().catch(() => {});
|
|
2341
2423
|
return {
|
|
2342
2424
|
close: () => {
|
|
2425
|
+
element.removeEventListener?.("click", handleClick);
|
|
2343
2426
|
unsubscribe();
|
|
2344
2427
|
store.close();
|
|
2345
2428
|
},
|
|
@@ -3852,6 +3935,7 @@ var createVoiceWorkflowStatusStore = (path = "/evals/scenarios/json", options =
|
|
|
3852
3935
|
};
|
|
3853
3936
|
export {
|
|
3854
3937
|
runVoiceTurnLatencyProof,
|
|
3938
|
+
runVoiceDeliveryRuntimeAction,
|
|
3855
3939
|
runVoiceCampaignDialerProofAction,
|
|
3856
3940
|
renderVoiceTurnQualityHTML,
|
|
3857
3941
|
renderVoiceTurnLatencyHTML,
|
|
@@ -21,6 +21,11 @@ export type VoiceDeliveryRuntimeTickResult = {
|
|
|
21
21
|
audit?: VoiceAuditSinkDeliveryWorkerResult;
|
|
22
22
|
trace?: VoiceTraceSinkDeliveryWorkerResult;
|
|
23
23
|
};
|
|
24
|
+
export type VoiceDeliveryRuntimeRequeueDeadLettersResult = {
|
|
25
|
+
audit: number;
|
|
26
|
+
trace: number;
|
|
27
|
+
total: number;
|
|
28
|
+
};
|
|
24
29
|
export type VoiceDeliveryRuntimeSummary = {
|
|
25
30
|
audit?: VoiceAuditSinkDeliveryQueueSummary;
|
|
26
31
|
trace?: VoiceTraceSinkDeliveryQueueSummary;
|
|
@@ -28,6 +33,7 @@ export type VoiceDeliveryRuntimeSummary = {
|
|
|
28
33
|
export type VoiceDeliveryRuntime = {
|
|
29
34
|
audit?: ReturnType<typeof createVoiceAuditSinkDeliveryWorker>;
|
|
30
35
|
isRunning: () => boolean;
|
|
36
|
+
requeueDeadLetters: () => Promise<VoiceDeliveryRuntimeRequeueDeadLettersResult>;
|
|
31
37
|
start: () => void;
|
|
32
38
|
stop: () => void;
|
|
33
39
|
summarize: () => Promise<VoiceDeliveryRuntimeSummary>;
|
|
@@ -44,8 +50,13 @@ export type VoiceDeliveryRuntimeRoutesOptions = {
|
|
|
44
50
|
htmlPath?: false | string;
|
|
45
51
|
name?: string;
|
|
46
52
|
path?: string;
|
|
47
|
-
render?: (report: VoiceDeliveryRuntimeReport
|
|
53
|
+
render?: (report: VoiceDeliveryRuntimeReport, options: {
|
|
54
|
+
requeueDeadLettersPath?: false | string;
|
|
55
|
+
tickPath?: false | string;
|
|
56
|
+
title?: string;
|
|
57
|
+
}) => string | Promise<string>;
|
|
48
58
|
runtime: VoiceDeliveryRuntime;
|
|
59
|
+
requeueDeadLettersPath?: false | string;
|
|
49
60
|
tickPath?: false | string;
|
|
50
61
|
title?: string;
|
|
51
62
|
};
|
|
@@ -101,6 +112,7 @@ export declare const createVoiceDeliveryRuntimePresetConfig: (options: VoiceDeli
|
|
|
101
112
|
export declare const createVoiceDeliveryRuntime: <TAuditDelivery extends VoiceAuditSinkDeliveryRecord = VoiceAuditSinkDeliveryRecord, TTraceDelivery extends VoiceTraceSinkDeliveryRecord = VoiceTraceSinkDeliveryRecord>(config: VoiceDeliveryRuntimeConfig<TAuditDelivery, TTraceDelivery>) => VoiceDeliveryRuntime;
|
|
102
113
|
export declare const buildVoiceDeliveryRuntimeReport: (runtime: VoiceDeliveryRuntime) => Promise<VoiceDeliveryRuntimeReport>;
|
|
103
114
|
export declare const renderVoiceDeliveryRuntimeHTML: (report: VoiceDeliveryRuntimeReport, options?: {
|
|
115
|
+
requeueDeadLettersPath?: false | string;
|
|
104
116
|
tickPath?: false | string;
|
|
105
117
|
title?: string;
|
|
106
118
|
}) => string;
|
package/dist/index.js
CHANGED
|
@@ -11579,6 +11579,15 @@ var resolvePresetLeases = (leases) => ("claim" in leases) ? {
|
|
|
11579
11579
|
audit: leases,
|
|
11580
11580
|
trace: leases
|
|
11581
11581
|
} : leases;
|
|
11582
|
+
var requeueDelivery = (delivery) => ({
|
|
11583
|
+
...delivery,
|
|
11584
|
+
deliveredAt: undefined,
|
|
11585
|
+
deliveryAttempts: 0,
|
|
11586
|
+
deliveryError: undefined,
|
|
11587
|
+
deliveryStatus: "pending",
|
|
11588
|
+
sinkDeliveries: undefined,
|
|
11589
|
+
updatedAt: Date.now()
|
|
11590
|
+
});
|
|
11582
11591
|
var createDeliveryRuntimeFileSink = (input) => ({
|
|
11583
11592
|
deliver: async ({ events }) => {
|
|
11584
11593
|
const firstEvent = events[0];
|
|
@@ -11706,6 +11715,29 @@ var createVoiceDeliveryRuntime = (config) => {
|
|
|
11706
11715
|
return {
|
|
11707
11716
|
audit,
|
|
11708
11717
|
isRunning: () => Boolean(auditLoop?.isRunning() || traceLoop?.isRunning()),
|
|
11718
|
+
requeueDeadLetters: async () => {
|
|
11719
|
+
let audit2 = 0;
|
|
11720
|
+
let trace2 = 0;
|
|
11721
|
+
if (config.audit?.deadLetters) {
|
|
11722
|
+
for (const delivery of await config.audit.deadLetters.list()) {
|
|
11723
|
+
await config.audit.deliveries.set(delivery.id, requeueDelivery(delivery));
|
|
11724
|
+
await config.audit.deadLetters.remove(delivery.id);
|
|
11725
|
+
audit2 += 1;
|
|
11726
|
+
}
|
|
11727
|
+
}
|
|
11728
|
+
if (config.trace?.deadLetters) {
|
|
11729
|
+
for (const delivery of await config.trace.deadLetters.list()) {
|
|
11730
|
+
await config.trace.deliveries.set(delivery.id, requeueDelivery(delivery));
|
|
11731
|
+
await config.trace.deadLetters.remove(delivery.id);
|
|
11732
|
+
trace2 += 1;
|
|
11733
|
+
}
|
|
11734
|
+
}
|
|
11735
|
+
return {
|
|
11736
|
+
audit: audit2,
|
|
11737
|
+
trace: trace2,
|
|
11738
|
+
total: audit2 + trace2
|
|
11739
|
+
};
|
|
11740
|
+
},
|
|
11709
11741
|
start: () => {
|
|
11710
11742
|
if (config.audit?.autoStart) {
|
|
11711
11743
|
auditLoop?.start();
|
|
@@ -11753,15 +11785,18 @@ var buildVoiceDeliveryRuntimeReport = async (runtime) => ({
|
|
|
11753
11785
|
var renderVoiceDeliveryRuntimeHTML = (report, options = {}) => {
|
|
11754
11786
|
const title = options.title ?? "AbsoluteJS Voice Delivery Runtime";
|
|
11755
11787
|
const tickForm = options.tickPath === false ? "" : `<form method="post" action="${escapeHtml15(options.tickPath ?? "/api/voice-delivery-runtime/tick")}"><button type="submit">Tick delivery workers</button></form>`;
|
|
11756
|
-
|
|
11788
|
+
const requeueForm = options.requeueDeadLettersPath === false ? "" : `<form method="post" action="${escapeHtml15(options.requeueDeadLettersPath ?? "/api/voice-delivery-runtime/requeue-dead-letters")}"><button type="submit">Requeue dead letters</button></form>`;
|
|
11789
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml15(title)}</title><style>body{background:#0f1411;color:#f7f2df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1080px;padding:32px}a{color:#86efac;text-decoration:none}.hero{background:linear-gradient(135deg,rgba(34,197,94,.18),rgba(14,165,233,.13));border:1px solid #263a30;border-radius:28px;margin-bottom:18px;padding:28px}.eyebrow{color:#86efac;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.2rem,5vw,4.8rem);line-height:.92;margin:.2rem 0 1rem}.status{border:1px solid #64748b;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.status.running{border-color:rgba(34,197,94,.7);color:#bbf7d0}.muted{color:#b9c3b4}.grid{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));margin:18px 0}article,.card{background:#151d18;border:1px solid #263a30;border-radius:22px;padding:18px}article span{color:#b9c3b4;display:block;font-weight:800}article strong{display:block;font-size:2.3rem;margin-top:8px}.actions{display:flex;flex-wrap:wrap;gap:10px}button{background:#86efac;border:0;border-radius:999px;color:#07120b;cursor:pointer;font-weight:900;margin-top:12px;padding:10px 14px}pre{background:#09100c;border:1px solid #263a30;border-radius:18px;color:#dcfce7;overflow:auto;padding:16px}</style></head><body><main><p><a href="/delivery-sinks">Delivery sinks</a></p><section class="hero"><p class="eyebrow">Worker control plane</p><h1>${escapeHtml15(title)}</h1><p class="muted">Inspect queue summaries, manually tick failed/pending audit and trace deliveries, and requeue dead letters after operator review.</p><p class="status ${report.isRunning ? "running" : ""}">${report.isRunning ? "Running" : "Stopped"}</p><p class="muted">Checked ${escapeHtml15(new Date(report.checkedAt).toLocaleString())}</p><div class="actions">${tickForm}${requeueForm}</div></section><section class="grid">${renderSummaryCard("Audit", report.summary.audit)}${renderSummaryCard("Trace", report.summary.trace)}</section><section class="card"><h2>Runtime shape</h2><pre>const runtime = createVoiceDeliveryRuntime({ audit, trace })
|
|
11757
11790
|
|
|
11758
11791
|
await runtime.tick()
|
|
11792
|
+
await runtime.requeueDeadLetters()
|
|
11759
11793
|
await runtime.summarize()</pre></section></main></body></html>`;
|
|
11760
11794
|
};
|
|
11761
11795
|
var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
11762
11796
|
const path = options.path ?? "/api/voice-delivery-runtime";
|
|
11763
11797
|
const htmlPath = options.htmlPath === undefined ? "/delivery-runtime" : options.htmlPath;
|
|
11764
11798
|
const tickPath = options.tickPath === undefined ? "/api/voice-delivery-runtime/tick" : options.tickPath;
|
|
11799
|
+
const requeueDeadLettersPath = options.requeueDeadLettersPath === undefined ? "/api/voice-delivery-runtime/requeue-dead-letters" : options.requeueDeadLettersPath;
|
|
11765
11800
|
const routes = new Elysia12({
|
|
11766
11801
|
name: options.name ?? "absolutejs-voice-delivery-runtime"
|
|
11767
11802
|
}).get(path, () => buildVoiceDeliveryRuntimeReport(options.runtime));
|
|
@@ -11772,11 +11807,19 @@ var createVoiceDeliveryRuntimeRoutes = (options) => {
|
|
|
11772
11807
|
summary: await options.runtime.summarize()
|
|
11773
11808
|
}));
|
|
11774
11809
|
}
|
|
11810
|
+
if (requeueDeadLettersPath !== false) {
|
|
11811
|
+
routes.post(requeueDeadLettersPath, async () => ({
|
|
11812
|
+
requeuedAt: Date.now(),
|
|
11813
|
+
result: await options.runtime.requeueDeadLetters(),
|
|
11814
|
+
summary: await options.runtime.summarize()
|
|
11815
|
+
}));
|
|
11816
|
+
}
|
|
11775
11817
|
if (htmlPath !== false) {
|
|
11776
11818
|
routes.get(htmlPath, async () => {
|
|
11777
11819
|
const report = await buildVoiceDeliveryRuntimeReport(options.runtime);
|
|
11778
11820
|
const body = await (options.render ?? renderVoiceDeliveryRuntimeHTML)(report, {
|
|
11779
11821
|
tickPath,
|
|
11822
|
+
requeueDeadLettersPath,
|
|
11780
11823
|
title: options.title
|
|
11781
11824
|
});
|
|
11782
11825
|
return new Response(body, {
|