@absolutejs/voice 0.0.22-beta.432 → 0.0.22-beta.434
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/incidentTimeline.d.ts +32 -0
- package/dist/index.d.ts +1 -1
- package/dist/index.js +142 -3
- package/package.json +1 -1
|
@@ -10,6 +10,30 @@ export type VoiceIncidentTimelineAction = {
|
|
|
10
10
|
label: string;
|
|
11
11
|
method?: 'GET' | 'POST';
|
|
12
12
|
};
|
|
13
|
+
export type VoiceIncidentRecoveryAction = {
|
|
14
|
+
detail?: string;
|
|
15
|
+
disabled?: boolean;
|
|
16
|
+
eventId?: string;
|
|
17
|
+
href?: string;
|
|
18
|
+
id: string;
|
|
19
|
+
label: string;
|
|
20
|
+
method?: 'GET' | 'POST';
|
|
21
|
+
sessionId?: string;
|
|
22
|
+
};
|
|
23
|
+
export type VoiceIncidentRecoveryActionResult = {
|
|
24
|
+
actionId: string;
|
|
25
|
+
detail?: string;
|
|
26
|
+
href?: string;
|
|
27
|
+
ok: boolean;
|
|
28
|
+
status?: string;
|
|
29
|
+
};
|
|
30
|
+
export type VoiceIncidentRecoveryActionHandlerInput = {
|
|
31
|
+
action: VoiceIncidentRecoveryAction;
|
|
32
|
+
actionId: string;
|
|
33
|
+
report: VoiceIncidentTimelineReport;
|
|
34
|
+
request: Request;
|
|
35
|
+
};
|
|
36
|
+
export type VoiceIncidentRecoveryActionHandler = (input: VoiceIncidentRecoveryActionHandlerInput) => Promise<VoiceIncidentRecoveryActionResult> | VoiceIncidentRecoveryActionResult;
|
|
13
37
|
export type VoiceIncidentTimelineEvent = {
|
|
14
38
|
action?: VoiceIncidentTimelineAction;
|
|
15
39
|
at: number;
|
|
@@ -24,6 +48,7 @@ export type VoiceIncidentTimelineEvent = {
|
|
|
24
48
|
value?: number | string;
|
|
25
49
|
};
|
|
26
50
|
export type VoiceIncidentTimelineReport = {
|
|
51
|
+
actions: VoiceIncidentRecoveryAction[];
|
|
27
52
|
events: VoiceIncidentTimelineEvent[];
|
|
28
53
|
generatedAt: number;
|
|
29
54
|
links: VoiceIncidentTimelineLinks;
|
|
@@ -57,9 +82,15 @@ export type VoiceIncidentTimelineOptions = {
|
|
|
57
82
|
operationalStatus?: VoiceIncidentTimelineValue<VoiceOperationalStatusReport>;
|
|
58
83
|
operationsRecords?: VoiceIncidentTimelineValue<readonly VoiceOperationsRecord[]>;
|
|
59
84
|
opsRecovery?: VoiceIncidentTimelineValue<VoiceOpsRecoveryReport>;
|
|
85
|
+
recoveryActions?: readonly VoiceIncidentRecoveryAction[] | ((input: {
|
|
86
|
+
events: readonly VoiceIncidentTimelineEvent[];
|
|
87
|
+
report: Omit<VoiceIncidentTimelineReport, 'actions'>;
|
|
88
|
+
}) => Promise<readonly VoiceIncidentRecoveryAction[]> | readonly VoiceIncidentRecoveryAction[]);
|
|
60
89
|
windowMs?: number;
|
|
61
90
|
};
|
|
62
91
|
export type VoiceIncidentTimelineRoutesOptions = VoiceIncidentTimelineOptions & {
|
|
92
|
+
actionHandlers?: Record<string, VoiceIncidentRecoveryActionHandler>;
|
|
93
|
+
actionPath?: false | string;
|
|
63
94
|
headers?: HeadersInit;
|
|
64
95
|
htmlPath?: false | string;
|
|
65
96
|
markdownPath?: false | string;
|
|
@@ -73,6 +104,7 @@ export declare const renderVoiceIncidentTimelineMarkdown: (report: VoiceIncident
|
|
|
73
104
|
title?: string;
|
|
74
105
|
}) => string;
|
|
75
106
|
export declare const renderVoiceIncidentTimelineHTML: (report: VoiceIncidentTimelineReport, options?: {
|
|
107
|
+
actionPath?: string;
|
|
76
108
|
title?: string;
|
|
77
109
|
}) => string;
|
|
78
110
|
export declare const createVoiceIncidentTimelineRoutes: (options: VoiceIncidentTimelineRoutesOptions) => Elysia<"", {
|
package/dist/index.d.ts
CHANGED
|
@@ -60,7 +60,7 @@ export type { VoiceDeliverySinkDescriptor, VoiceDeliverySinkDescriptorInput, Voi
|
|
|
60
60
|
export type { VoiceOpsActionAuditRecord, VoiceOpsActionAuditRoutesOptions, VoiceOpsActionHistoryEntry, VoiceOpsActionHistoryReport } from './opsActionAuditRoutes';
|
|
61
61
|
export type { VoiceDeliveryRuntime, VoiceDeliveryRuntimeAuditConfig, VoiceDeliveryRuntimeConfig, VoiceDeliveryRuntimeFilePresetOptions, VoiceDeliveryRuntimePresetLeaseConfig, VoiceDeliveryRuntimePresetMode, VoiceDeliveryRuntimePresetOptions, VoiceDeliveryRuntimeReport, VoiceDeliveryRuntimeRoutesOptions, VoiceDeliveryRuntimeS3PresetOptions, VoiceDeliveryRuntimeSummary, VoiceDeliveryRuntimeTickResult, VoiceDeliveryRuntimeTraceConfig, VoiceDeliveryRuntimeWebhookPresetOptions } from './deliveryRuntime';
|
|
62
62
|
export type { VoiceOperationalStatus, VoiceOperationalStatusCheck, VoiceOperationalStatusOptions, VoiceOperationalStatusReport, VoiceOperationalStatusRoutesOptions, VoiceOperationalStatusValue } from './operationalStatus';
|
|
63
|
-
export type { VoiceIncidentTimelineAction, VoiceIncidentTimelineEvent, VoiceIncidentTimelineLinks, VoiceIncidentTimelineOptions, VoiceIncidentTimelineReport, VoiceIncidentTimelineRoutesOptions, VoiceIncidentTimelineSeverity, VoiceIncidentTimelineStatus, VoiceIncidentTimelineValue } from './incidentTimeline';
|
|
63
|
+
export type { VoiceIncidentRecoveryAction, VoiceIncidentRecoveryActionHandler, VoiceIncidentRecoveryActionHandlerInput, VoiceIncidentRecoveryActionResult, VoiceIncidentTimelineAction, VoiceIncidentTimelineEvent, VoiceIncidentTimelineLinks, VoiceIncidentTimelineOptions, VoiceIncidentTimelineReport, VoiceIncidentTimelineRoutesOptions, VoiceIncidentTimelineSeverity, VoiceIncidentTimelineStatus, VoiceIncidentTimelineValue } from './incidentTimeline';
|
|
64
64
|
export { compareVoiceEvalBaseline, createVoiceFileEvalBaselineStore, createVoiceFileScenarioFixtureStore, createVoiceEvalRoutes, renderVoiceEvalBaselineHTML, renderVoiceEvalHTML, renderVoiceScenarioEvalHTML, renderVoiceScenarioFixtureEvalHTML, runVoiceScenarioEvals, runVoiceScenarioFixtureEvals, runVoiceSessionEvals } from './evalRoutes';
|
|
65
65
|
export { assertVoiceSimulationSuiteEvidence, createVoiceSimulationSuiteRoutes, evaluateVoiceSimulationSuiteEvidence, renderVoiceSimulationSuiteHTML, runVoiceSimulationSuite } from './simulationSuite';
|
|
66
66
|
export { createVoiceWorkflowContract, createVoiceWorkflowContractHandler, createVoiceWorkflowContractPreset, createVoiceWorkflowScenario, recordVoiceWorkflowContractTrace, validateVoiceWorkflowRouteResult } from './workflowContract';
|
package/dist/index.js
CHANGED
|
@@ -30127,6 +30127,61 @@ var statusToSeverity = (status) => status === "fail" || status === "failed" ? "c
|
|
|
30127
30127
|
var failureReplayStatusToSeverity = (status) => status === "failed" ? "critical" : status === "healthy" ? "info" : "warn";
|
|
30128
30128
|
var withinWindow = (event, now, windowMs) => !windowMs || event.at >= now - windowMs;
|
|
30129
30129
|
var eventStatus2 = (event) => event.severity === "critical" ? "fail" : event.severity === "warn" ? "warn" : "pass";
|
|
30130
|
+
var defaultIncidentRecoveryActions = (events, links) => {
|
|
30131
|
+
const actions = [];
|
|
30132
|
+
const add = (action) => {
|
|
30133
|
+
const key = `${action.id}:${action.sessionId ?? ""}:${action.href ?? ""}`;
|
|
30134
|
+
if (actions.some((existing) => `${existing.id}:${existing.sessionId ?? ""}:${existing.href ?? ""}` === key)) {
|
|
30135
|
+
return;
|
|
30136
|
+
}
|
|
30137
|
+
actions.push(action);
|
|
30138
|
+
};
|
|
30139
|
+
for (const event of events) {
|
|
30140
|
+
if (event.category === "delivery") {
|
|
30141
|
+
add({
|
|
30142
|
+
detail: "Ask the app to tick delivery workers or retry failed delivery queue work.",
|
|
30143
|
+
eventId: event.id,
|
|
30144
|
+
href: links.deliveryRuntime,
|
|
30145
|
+
id: "delivery.retry",
|
|
30146
|
+
label: "Retry delivery work",
|
|
30147
|
+
method: "POST",
|
|
30148
|
+
sessionId: event.sessionId
|
|
30149
|
+
});
|
|
30150
|
+
}
|
|
30151
|
+
if (event.category === "readiness" || event.category === "operational-status") {
|
|
30152
|
+
add({
|
|
30153
|
+
detail: "Refresh production readiness and proof freshness before declaring the incident resolved.",
|
|
30154
|
+
eventId: event.id,
|
|
30155
|
+
href: links.productionReadiness ?? links.operationalStatus,
|
|
30156
|
+
id: "readiness.refresh",
|
|
30157
|
+
label: "Refresh readiness proof",
|
|
30158
|
+
method: "POST",
|
|
30159
|
+
sessionId: event.sessionId
|
|
30160
|
+
});
|
|
30161
|
+
}
|
|
30162
|
+
if (event.sessionId) {
|
|
30163
|
+
add({
|
|
30164
|
+
detail: "Generate or open a support/debug artifact for the affected call.",
|
|
30165
|
+
eventId: event.id,
|
|
30166
|
+
href: linkForSession(links.supportBundle, event.sessionId) ?? linkForSession(links.callDebugger, event.sessionId),
|
|
30167
|
+
id: "support.bundle",
|
|
30168
|
+
label: "Generate support bundle",
|
|
30169
|
+
method: "POST",
|
|
30170
|
+
sessionId: event.sessionId
|
|
30171
|
+
});
|
|
30172
|
+
}
|
|
30173
|
+
}
|
|
30174
|
+
if (events.some((event) => event.severity !== "info")) {
|
|
30175
|
+
add({
|
|
30176
|
+
detail: "Rerun the app proof pack to confirm the current release evidence is fresh.",
|
|
30177
|
+
href: links.proofPack,
|
|
30178
|
+
id: "proof.rerun",
|
|
30179
|
+
label: "Rerun proof pack",
|
|
30180
|
+
method: "POST"
|
|
30181
|
+
});
|
|
30182
|
+
}
|
|
30183
|
+
return actions;
|
|
30184
|
+
};
|
|
30130
30185
|
var worstStatus3 = (statuses) => statuses.includes("fail") ? "fail" : statuses.includes("warn") ? "warn" : "pass";
|
|
30131
30186
|
var pushOperationalStatusEvents = (events, report, links) => {
|
|
30132
30187
|
if (!report) {
|
|
@@ -30304,7 +30359,7 @@ var buildVoiceIncidentTimelineReport = async (options) => {
|
|
|
30304
30359
|
total: filtered.length,
|
|
30305
30360
|
warn: filtered.filter((event) => event.severity === "warn").length
|
|
30306
30361
|
};
|
|
30307
|
-
|
|
30362
|
+
const baseReport = {
|
|
30308
30363
|
events: filtered,
|
|
30309
30364
|
generatedAt: now,
|
|
30310
30365
|
links,
|
|
@@ -30312,6 +30367,14 @@ var buildVoiceIncidentTimelineReport = async (options) => {
|
|
|
30312
30367
|
summary,
|
|
30313
30368
|
windowMs: options.windowMs
|
|
30314
30369
|
};
|
|
30370
|
+
const configuredActions = typeof options.recoveryActions === "function" ? await options.recoveryActions({
|
|
30371
|
+
events: filtered,
|
|
30372
|
+
report: baseReport
|
|
30373
|
+
}) : options.recoveryActions;
|
|
30374
|
+
return {
|
|
30375
|
+
...baseReport,
|
|
30376
|
+
actions: configuredActions === undefined ? defaultIncidentRecoveryActions(filtered, links) : [...configuredActions]
|
|
30377
|
+
};
|
|
30315
30378
|
};
|
|
30316
30379
|
var renderVoiceIncidentTimelineMarkdown = (report, options = {}) => {
|
|
30317
30380
|
const title = options.title ?? "AbsoluteJS Voice Incident Timeline";
|
|
@@ -30334,10 +30397,16 @@ Summary: ${report.summary.critical} critical, ${report.summary.warn} warn, ${rep
|
|
|
30334
30397
|
## Events
|
|
30335
30398
|
|
|
30336
30399
|
${rows || "- No incident timeline events."}
|
|
30400
|
+
|
|
30401
|
+
## Recovery Actions
|
|
30402
|
+
|
|
30403
|
+
${report.actions.map((action) => `- ${action.method ?? "GET"} ${action.id}: ${action.label}${action.href ? ` (${action.href})` : ""}${action.detail ? ` - ${action.detail}` : ""}`).join(`
|
|
30404
|
+
`) || "- No recovery actions."}
|
|
30337
30405
|
`;
|
|
30338
30406
|
};
|
|
30339
30407
|
var renderVoiceIncidentTimelineHTML = (report, options = {}) => {
|
|
30340
30408
|
const title = options.title ?? "AbsoluteJS Voice Incident Timeline";
|
|
30409
|
+
const actionPath = options.actionPath ?? "/api/voice/incident-timeline/actions";
|
|
30341
30410
|
const events = report.events.map((event) => `<article class="${escapeHtml43(event.severity)}">
|
|
30342
30411
|
<span>${escapeHtml43(event.severity.toUpperCase())} / ${escapeHtml43(event.category)}</span>
|
|
30343
30412
|
<h2>${escapeHtml43(event.label)}</h2>
|
|
@@ -30346,12 +30415,20 @@ var renderVoiceIncidentTimelineHTML = (report, options = {}) => {
|
|
|
30346
30415
|
${event.detail ? `<p>${escapeHtml43(event.detail)}</p>` : ""}
|
|
30347
30416
|
<div>${event.href ? `<a href="${escapeHtml43(event.href)}">Open source</a>` : ""}${event.action?.href ? `<a href="${escapeHtml43(event.action.href)}">${escapeHtml43(event.action.label)}</a>` : ""}</div>
|
|
30348
30417
|
</article>`).join("");
|
|
30349
|
-
|
|
30418
|
+
const actions = report.actions.map((action) => {
|
|
30419
|
+
const label = escapeHtml43(action.label);
|
|
30420
|
+
const detail = action.detail ? `<p>${escapeHtml43(action.detail)}</p>` : "";
|
|
30421
|
+
const href = action.href ? `<a href="${escapeHtml43(action.href)}">Open target</a>` : "";
|
|
30422
|
+
const control = action.method === "POST" ? `<button type="button" data-voice-incident-action="${escapeHtml43(action.id)}" ${action.disabled ? "disabled" : ""}>${label}</button>` : href;
|
|
30423
|
+
return `<article class="action"><span>${escapeHtml43(action.method ?? "GET")}</span><h2>${label}</h2>${detail}<div>${control}${href && action.method === "POST" ? href : ""}</div></article>`;
|
|
30424
|
+
}).join("");
|
|
30425
|
+
return `<!doctype html><html lang="en"><head><meta charset="utf-8" /><meta name="viewport" content="width=device-width, initial-scale=1" /><title>${escapeHtml43(title)}</title><style>body{background:#11110d;color:#faf4df;font-family:ui-sans-serif,system-ui,sans-serif;margin:0}main{margin:auto;max-width:1100px;padding:32px}.hero{background:linear-gradient(135deg,rgba(248,113,113,.2),rgba(245,158,11,.13),rgba(34,197,94,.12));border:1px solid #39301d;border-radius:30px;margin-bottom:18px;padding:28px}.eyebrow{color:#fcd34d;font-weight:900;letter-spacing:.12em;text-transform:uppercase}h1{font-size:clamp(2.4rem,6vw,5rem);letter-spacing:-.06em;line-height:.9;margin:.2rem 0 1rem}.status{border:1px solid #575030;border-radius:999px;display:inline-flex;font-weight:900;padding:8px 12px}.status.pass{border-color:rgba(34,197,94,.65)}.status.warn{border-color:rgba(245,158,11,.75)}.status.fail{border-color:rgba(239,68,68,.85)}.grid{display:grid;gap:14px}.actions{display:grid;gap:14px;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));margin:0 0 18px}.summary{display:flex;flex-wrap:wrap;gap:10px}.summary span{background:#181711;border:1px solid #39301d;border-radius:999px;padding:8px 12px}article{background:#181711;border:1px solid #39301d;border-radius:22px;padding:18px}article.critical{border-color:rgba(239,68,68,.85)}article.warn{border-color:rgba(245,158,11,.75)}article.info{border-color:rgba(34,197,94,.55)}article.action{border-color:#5b4a22}article span{color:#fcd34d;font-size:.78rem;font-weight:900;letter-spacing:.08em}article h2{margin:.35rem 0}.muted,article p{color:#cfc5a8}article strong{display:block;font-size:1.3rem;margin:.5rem 0}a{color:#fde68a;margin-right:12px}button{background:#fcd34d;border:0;border-radius:999px;color:#171307;cursor:pointer;font-weight:900;padding:10px 14px}button:disabled{cursor:not-allowed;opacity:.55}</style></head><body><main><section class="hero"><p class="eyebrow">Operational triage</p><h1>${escapeHtml43(title)}</h1><p class="status ${escapeHtml43(report.status)}">Overall: ${escapeHtml43(report.status.toUpperCase())}</p><p class="muted">Generated ${escapeHtml43(new Date(report.generatedAt).toLocaleString())}</p><div class="summary"><span>${String(report.summary.critical)} critical</span><span>${String(report.summary.warn)} warn</span><span>${String(report.summary.info)} info</span><span>${String(report.summary.total)} total</span></div></section><h2>Recovery actions</h2><section class="actions">${actions || '<article class="action"><span>NONE</span><h2>No recovery actions</h2><p>No executable actions are available for this report.</p></article>'}</section><h2>Timeline</h2><section class="grid">${events || '<article class="info"><span>INFO</span><h2>No incident events</h2><p>No non-pass operational events were found in this window.</p></article>'}</section></main><script>const voiceIncidentActionPath=${JSON.stringify(actionPath)};document.querySelectorAll("[data-voice-incident-action]").forEach((button)=>{button.addEventListener("click",async()=>{const id=button.getAttribute("data-voice-incident-action");if(!id)return;button.disabled=true;const original=button.textContent;button.textContent="Running...";try{const response=await fetch(voiceIncidentActionPath+"/"+encodeURIComponent(id),{method:"POST"});button.textContent=response.ok?"Done":"Failed";if(response.ok)setTimeout(()=>location.reload(),700)}catch{button.textContent="Failed"}finally{setTimeout(()=>{button.disabled=false;button.textContent=original},1600)}})});</script></body></html>`;
|
|
30350
30426
|
};
|
|
30351
30427
|
var createVoiceIncidentTimelineRoutes = (options) => {
|
|
30352
30428
|
const path = options.path ?? "/api/voice/incident-timeline";
|
|
30353
30429
|
const htmlPath = options.htmlPath === undefined ? "/voice/incident-timeline" : options.htmlPath;
|
|
30354
30430
|
const markdownPath = options.markdownPath === undefined ? "/voice/incident-timeline.md" : options.markdownPath;
|
|
30431
|
+
const actionPath = options.actionPath === undefined ? "/api/voice/incident-timeline/actions" : options.actionPath;
|
|
30355
30432
|
const routes = new Elysia46({
|
|
30356
30433
|
name: options.name ?? "absolutejs-voice-incident-timeline"
|
|
30357
30434
|
}).get(path, async () => {
|
|
@@ -30367,7 +30444,10 @@ var createVoiceIncidentTimelineRoutes = (options) => {
|
|
|
30367
30444
|
if (htmlPath !== false) {
|
|
30368
30445
|
routes.get(htmlPath, async () => {
|
|
30369
30446
|
const report = await buildVoiceIncidentTimelineReport(options);
|
|
30370
|
-
const body = await (options.render ?? ((input) => renderVoiceIncidentTimelineHTML(input, {
|
|
30447
|
+
const body = await (options.render ?? ((input) => renderVoiceIncidentTimelineHTML(input, {
|
|
30448
|
+
actionPath: actionPath === false ? undefined : actionPath,
|
|
30449
|
+
title: options.title
|
|
30450
|
+
})))(report);
|
|
30371
30451
|
return new Response(body, {
|
|
30372
30452
|
headers: {
|
|
30373
30453
|
"Content-Type": "text/html; charset=utf-8",
|
|
@@ -30389,6 +30469,65 @@ var createVoiceIncidentTimelineRoutes = (options) => {
|
|
|
30389
30469
|
});
|
|
30390
30470
|
});
|
|
30391
30471
|
}
|
|
30472
|
+
if (actionPath !== false) {
|
|
30473
|
+
routes.get(actionPath, async () => {
|
|
30474
|
+
const report = await buildVoiceIncidentTimelineReport(options);
|
|
30475
|
+
return new Response(JSON.stringify({
|
|
30476
|
+
actions: report.actions,
|
|
30477
|
+
generatedAt: report.generatedAt,
|
|
30478
|
+
status: report.status
|
|
30479
|
+
}), {
|
|
30480
|
+
headers: {
|
|
30481
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
30482
|
+
...options.headers
|
|
30483
|
+
}
|
|
30484
|
+
});
|
|
30485
|
+
}).post(`${actionPath}/:actionId`, async ({ params, request }) => {
|
|
30486
|
+
const actionId = params.actionId;
|
|
30487
|
+
const report = await buildVoiceIncidentTimelineReport(options);
|
|
30488
|
+
const action = report.actions.find((item) => item.id === actionId);
|
|
30489
|
+
const handler = options.actionHandlers?.[actionId];
|
|
30490
|
+
if (!action) {
|
|
30491
|
+
return new Response(JSON.stringify({
|
|
30492
|
+
actionId,
|
|
30493
|
+
ok: false,
|
|
30494
|
+
status: "not_found"
|
|
30495
|
+
}), {
|
|
30496
|
+
headers: {
|
|
30497
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
30498
|
+
...options.headers
|
|
30499
|
+
},
|
|
30500
|
+
status: 404
|
|
30501
|
+
});
|
|
30502
|
+
}
|
|
30503
|
+
if (action.disabled || action.method !== "POST" || !handler) {
|
|
30504
|
+
return new Response(JSON.stringify({
|
|
30505
|
+
actionId,
|
|
30506
|
+
ok: false,
|
|
30507
|
+
status: action.disabled ? "disabled" : "not_executable"
|
|
30508
|
+
}), {
|
|
30509
|
+
headers: {
|
|
30510
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
30511
|
+
...options.headers
|
|
30512
|
+
},
|
|
30513
|
+
status: 409
|
|
30514
|
+
});
|
|
30515
|
+
}
|
|
30516
|
+
const result = await handler({
|
|
30517
|
+
action,
|
|
30518
|
+
actionId,
|
|
30519
|
+
report,
|
|
30520
|
+
request
|
|
30521
|
+
});
|
|
30522
|
+
return new Response(JSON.stringify(result), {
|
|
30523
|
+
headers: {
|
|
30524
|
+
"Content-Type": "application/json; charset=utf-8",
|
|
30525
|
+
...options.headers
|
|
30526
|
+
},
|
|
30527
|
+
status: result.ok ? 200 : 500
|
|
30528
|
+
});
|
|
30529
|
+
});
|
|
30530
|
+
}
|
|
30392
30531
|
return routes;
|
|
30393
30532
|
};
|
|
30394
30533
|
// src/dataControl.ts
|