@absolutejs/voice 0.0.22-beta.50 → 0.0.22-beta.52

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/vue/index.js CHANGED
@@ -69,8 +69,8 @@ var __decorateElement = (array, flags, name, decorators, target, extra) => {
69
69
  return k || __decoratorMetadata(array, target), desc && __defProp(target, name, desc), p ? k ^ 4 ? extra : desc : target;
70
70
  };
71
71
 
72
- // src/vue/useVoiceAppKitStatus.ts
73
- import { onUnmounted, ref, shallowRef } from "vue";
72
+ // src/vue/VoiceOpsStatus.ts
73
+ import { defineComponent, h } from "vue";
74
74
 
75
75
  // src/client/appKitStatus.ts
76
76
  var fetchVoiceAppKitStatus = async (path = "/app-kit/status", options = {}) => {
@@ -151,7 +151,112 @@ var createVoiceAppKitStatusStore = (path = "/app-kit/status", options = {}) => {
151
151
  };
152
152
  };
153
153
 
154
+ // src/client/opsStatusWidget.ts
155
+ var DEFAULT_TITLE = "Voice Ops Status";
156
+ var DEFAULT_DESCRIPTION = "Certified workflow, provider, and handoff readiness from the AbsoluteJS voice app kit.";
157
+ var SURFACE_LABELS = {
158
+ handoffs: "Handoffs",
159
+ providers: "Providers",
160
+ quality: "Quality",
161
+ sessions: "Sessions",
162
+ workflows: "Workflows"
163
+ };
164
+ var escapeHtml = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll('"', "&quot;").replaceAll("'", "&#39;");
165
+ var readNumber = (value, key) => value && typeof value === "object" && (key in value) ? Number(value[key] ?? 0) : 0;
166
+ var surfaceDetail = (surface) => {
167
+ const total = readNumber(surface, "total");
168
+ const failed = readNumber(surface, "failed");
169
+ const degraded = readNumber(surface, "degraded");
170
+ const source = surface && typeof surface === "object" && "source" in surface && typeof surface.source === "string" ? ` from ${surface.source}` : "";
171
+ if (degraded > 0) {
172
+ return `${degraded} degraded of ${total}`;
173
+ }
174
+ if (failed > 0) {
175
+ return `${failed} failing of ${total}${source}`;
176
+ }
177
+ return total > 0 ? `${total} passing${source}` : `No failures${source}`;
178
+ };
179
+ var getVoiceOpsStatusLabel = (report, error) => {
180
+ if (error) {
181
+ return "Unavailable";
182
+ }
183
+ if (!report) {
184
+ return "Checking";
185
+ }
186
+ return report.status === "pass" ? "Passing" : "Needs attention";
187
+ };
188
+ var createVoiceOpsStatusViewModel = (snapshot, options = {}) => {
189
+ const report = snapshot.report;
190
+ const surfaces = Object.entries(report?.surfaces ?? {}).map(([id, surface]) => {
191
+ const failed = readNumber(surface, "failed") || readNumber(surface, "degraded");
192
+ const total = readNumber(surface, "total");
193
+ const status = surface && typeof surface === "object" && "status" in surface ? surface.status ?? "pass" : "pass";
194
+ return {
195
+ detail: surfaceDetail(surface),
196
+ failed,
197
+ id,
198
+ label: SURFACE_LABELS[id] ?? id,
199
+ status,
200
+ total
201
+ };
202
+ });
203
+ return {
204
+ description: options.description ?? DEFAULT_DESCRIPTION,
205
+ error: snapshot.error,
206
+ isLoading: snapshot.isLoading,
207
+ label: getVoiceOpsStatusLabel(report, snapshot.error),
208
+ links: options.includeLinks === false ? [] : report?.links ?? [],
209
+ passed: report?.passed ?? 0,
210
+ status: snapshot.error ? "error" : report ? report.status : snapshot.isLoading ? "loading" : "loading",
211
+ surfaces,
212
+ title: options.title ?? DEFAULT_TITLE,
213
+ total: report?.total ?? 0,
214
+ updatedAt: snapshot.updatedAt
215
+ };
216
+ };
217
+ var renderVoiceOpsStatusHTML = (snapshot, options = {}) => {
218
+ const model = createVoiceOpsStatusViewModel(snapshot, options);
219
+ const surfaces = model.surfaces.length ? model.surfaces.map((surface) => `<li class="absolute-voice-ops-status__surface absolute-voice-ops-status__surface--${escapeHtml(surface.status)}">
220
+ <span>${escapeHtml(surface.label)}</span>
221
+ <strong>${escapeHtml(surface.detail)}</strong>
222
+ </li>`).join("") : '<li class="absolute-voice-ops-status__surface"><span>Status</span><strong>Waiting for first check</strong></li>';
223
+ const links = model.links.length ? `<nav class="absolute-voice-ops-status__links">${model.links.slice(0, 4).map((link) => `<a href="${escapeHtml(link.href)}">${escapeHtml(link.label)}</a>`).join("")}</nav>` : "";
224
+ return `<section class="absolute-voice-ops-status absolute-voice-ops-status--${escapeHtml(model.status)}">
225
+ <header class="absolute-voice-ops-status__header">
226
+ <span class="absolute-voice-ops-status__eyebrow">${escapeHtml(model.title)}</span>
227
+ <strong class="absolute-voice-ops-status__label">${escapeHtml(model.label)}</strong>
228
+ </header>
229
+ <p class="absolute-voice-ops-status__description">${escapeHtml(model.description)}</p>
230
+ <div class="absolute-voice-ops-status__summary">
231
+ <span>${model.passed} passing</span>
232
+ <span>${Math.max(model.total - model.passed, 0)} failing</span>
233
+ <span>${model.total} checks</span>
234
+ </div>
235
+ <ul class="absolute-voice-ops-status__surfaces">${surfaces}</ul>
236
+ ${model.error ? `<p class="absolute-voice-ops-status__error">${escapeHtml(model.error)}</p>` : ""}
237
+ ${links}
238
+ </section>`;
239
+ };
240
+ var getVoiceOpsStatusCSS = () => `.absolute-voice-ops-status{border:1px solid #d8d2c4;border-radius:20px;background:#fffaf0;color:#16130d;padding:18px;box-shadow:0 18px 40px rgba(47,37,18,.12);font-family:inherit}.absolute-voice-ops-status--fail,.absolute-voice-ops-status--error{border-color:#f2a7a7;background:#fff5f3}.absolute-voice-ops-status__header{align-items:start;display:flex;gap:12px;justify-content:space-between}.absolute-voice-ops-status__eyebrow{color:#73664f;font-size:12px;font-weight:800;letter-spacing:.08em;text-transform:uppercase}.absolute-voice-ops-status__label{font-size:28px;line-height:1}.absolute-voice-ops-status__description{color:#514733;margin:12px 0 0}.absolute-voice-ops-status__summary,.absolute-voice-ops-status__links{display:flex;flex-wrap:wrap;gap:8px;margin-top:14px}.absolute-voice-ops-status__summary span,.absolute-voice-ops-status__links a{border:1px solid #e6ddca;border-radius:999px;color:inherit;padding:6px 10px;text-decoration:none}.absolute-voice-ops-status__surfaces{display:grid;gap:8px;list-style:none;margin:16px 0 0;padding:0}.absolute-voice-ops-status__surface{align-items:center;background:#fff;border:1px solid #eee4d2;border-radius:14px;display:flex;gap:12px;justify-content:space-between;padding:10px 12px}.absolute-voice-ops-status__surface--fail{border-color:#f2a7a7}.absolute-voice-ops-status__surface span{color:#655944}.absolute-voice-ops-status__error{color:#9f1239;font-weight:700}`;
241
+ var mountVoiceOpsStatus = (element, path = "/app-kit/status", options = {}) => {
242
+ const store = createVoiceAppKitStatusStore(path, options);
243
+ const render = () => {
244
+ element.innerHTML = renderVoiceOpsStatusHTML(store.getSnapshot(), options);
245
+ };
246
+ const unsubscribe = store.subscribe(render);
247
+ render();
248
+ store.refresh().catch(() => {});
249
+ return {
250
+ close: () => {
251
+ unsubscribe();
252
+ store.close();
253
+ },
254
+ refresh: store.refresh
255
+ };
256
+ };
257
+
154
258
  // src/vue/useVoiceAppKitStatus.ts
259
+ import { onUnmounted, ref, shallowRef } from "vue";
155
260
  var useVoiceAppKitStatus = (path = "/app-kit/status", options = {}) => {
156
261
  const store = createVoiceAppKitStatusStore(path, options);
157
262
  const error = ref(null);
@@ -182,6 +287,72 @@ var useVoiceAppKitStatus = (path = "/app-kit/status", options = {}) => {
182
287
  updatedAt
183
288
  };
184
289
  };
290
+
291
+ // src/vue/VoiceOpsStatus.ts
292
+ var VoiceOpsStatus = defineComponent({
293
+ name: "VoiceOpsStatus",
294
+ props: {
295
+ description: String,
296
+ includeLinks: {
297
+ default: true,
298
+ type: Boolean
299
+ },
300
+ intervalMs: Number,
301
+ path: {
302
+ default: "/app-kit/status",
303
+ type: String
304
+ },
305
+ title: String
306
+ },
307
+ setup(props) {
308
+ const options = {
309
+ description: props.description,
310
+ includeLinks: props.includeLinks,
311
+ intervalMs: props.intervalMs,
312
+ title: props.title
313
+ };
314
+ const status = useVoiceAppKitStatus(props.path, options);
315
+ return () => {
316
+ const model = createVoiceOpsStatusViewModel({
317
+ error: status.error.value,
318
+ isLoading: status.isLoading.value,
319
+ report: status.report.value,
320
+ updatedAt: status.updatedAt.value
321
+ }, options);
322
+ return h("section", {
323
+ class: [
324
+ "absolute-voice-ops-status",
325
+ `absolute-voice-ops-status--${model.status}`
326
+ ]
327
+ }, [
328
+ h("header", { class: "absolute-voice-ops-status__header" }, [
329
+ h("span", { class: "absolute-voice-ops-status__eyebrow" }, model.title),
330
+ h("strong", { class: "absolute-voice-ops-status__label" }, model.label)
331
+ ]),
332
+ h("p", { class: "absolute-voice-ops-status__description" }, model.description),
333
+ h("div", { class: "absolute-voice-ops-status__summary" }, [
334
+ h("span", `${model.passed} passing`),
335
+ h("span", `${Math.max(model.total - model.passed, 0)} failing`),
336
+ h("span", `${model.total} checks`)
337
+ ]),
338
+ h("ul", { class: "absolute-voice-ops-status__surfaces" }, model.surfaces.length > 0 ? model.surfaces.map((surface) => h("li", {
339
+ class: [
340
+ "absolute-voice-ops-status__surface",
341
+ `absolute-voice-ops-status__surface--${surface.status}`
342
+ ],
343
+ key: surface.id
344
+ }, [h("span", surface.label), h("strong", surface.detail)])) : [
345
+ h("li", { class: "absolute-voice-ops-status__surface" }, [
346
+ h("span", "Status"),
347
+ h("strong", "Waiting for first check")
348
+ ])
349
+ ]),
350
+ model.error ? h("p", { class: "absolute-voice-ops-status__error" }, model.error) : null,
351
+ model.links.length > 0 ? h("nav", { class: "absolute-voice-ops-status__links" }, model.links.slice(0, 4).map((link) => h("a", { href: link.href, key: link.href }, link.label))) : null
352
+ ]);
353
+ };
354
+ }
355
+ });
185
356
  // src/vue/useVoiceStream.ts
186
357
  import { onUnmounted as onUnmounted2, ref as ref2, shallowRef as shallowRef2 } from "vue";
187
358
 
@@ -1659,5 +1830,6 @@ export {
1659
1830
  useVoiceStream,
1660
1831
  useVoiceProviderStatus,
1661
1832
  useVoiceController,
1662
- useVoiceAppKitStatus
1833
+ useVoiceAppKitStatus,
1834
+ VoiceOpsStatus
1663
1835
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@absolutejs/voice",
3
- "version": "0.0.22-beta.50",
3
+ "version": "0.0.22-beta.52",
4
4
  "description": "Voice primitives and Elysia plugin for AbsoluteJS",
5
5
  "repository": {
6
6
  "type": "git",