import Ajv, { type ErrorObject } from "ajv"; import addFormats from "ajv-formats"; import { Type, type Static } from "@sinclair/typebox"; import { DashboardDocumentSchema, DatasourceReferenceSchema, ServiceEntrySchema, TelemetryCardSchema, ThresholdSchema, validateDashboardDocument, type DashboardDocument, type DashboardModule, type DashboardValidationFailure, type DatasourceReference, type ServiceEntry, type ServiceGroup, type StatusItem, type TelemetryCard, } from "$lib/model"; import { createDashboardStore, DashboardRevisionNotFoundError, type DashboardRevision, type DashboardStore, type DashboardWriteMetadata, } from "$lib/server/db/dashboard-store"; const IdentifierSchema = Type.String({ minLength: 1, pattern: "^[a-z0-9][a-z0-9-_.:]*$", }); const PositionSchema = Type.Object( { index: Type.Optional(Type.Integer({ minimum: 0 })), beforeId: Type.Optional(IdentifierSchema), afterId: Type.Optional(IdentifierSchema), }, { additionalProperties: false, minProperties: 1 }, ); const AgentTargetSchema = Type.Union([ Type.Object( { kind: Type.Literal("telemetry"), id: IdentifierSchema, }, { additionalProperties: false }, ), Type.Object( { kind: Type.Literal("service"), groupId: Type.Optional(IdentifierSchema), id: IdentifierSchema, }, { additionalProperties: false }, ), Type.Object( { kind: Type.Literal("serviceGroup"), id: IdentifierSchema, }, { additionalProperties: false }, ), Type.Object( { kind: Type.Literal("statusItem"), stripId: Type.Optional(IdentifierSchema), id: IdentifierSchema, }, { additionalProperties: false }, ), Type.Object( { kind: Type.Literal("module"), id: IdentifierSchema, }, { additionalProperties: false }, ), ]); const AddSectionOperationSchema = Type.Object( { type: Type.Literal("add_section"), section: Type.Object( { id: IdentifierSchema, title: Type.String({ minLength: 1 }), layout: Type.Optional(Type.Union([Type.Literal("list"), Type.Literal("grid")])), }, { additionalProperties: false }, ), position: Type.Optional(PositionSchema), }, { additionalProperties: false }, ); const AddServiceOperationSchema = Type.Object( { type: Type.Literal("add_service"), groupId: IdentifierSchema, service: ServiceEntrySchema, position: Type.Optional(PositionSchema), }, { additionalProperties: false }, ); const AddMetricCardOperationSchema = Type.Object( { type: Type.Literal("add_metric_card"), card: TelemetryCardSchema, position: Type.Optional(PositionSchema), }, { additionalProperties: false }, ); const ConnectDatasourceOperationSchema = Type.Object( { type: Type.Literal("connect_datasource"), target: AgentTargetSchema, datasource: DatasourceReferenceSchema, }, { additionalProperties: false }, ); const SetStatusRuleOperationSchema = Type.Object( { type: Type.Literal("set_status_rule"), target: AgentTargetSchema, thresholds: Type.Optional(ThresholdSchema), severity: Type.Optional( Type.Union([ Type.Literal("neutral"), Type.Literal("ok"), Type.Literal("warning"), Type.Literal("danger"), Type.Literal("stale"), Type.Literal("unavailable"), ]), ), detail: Type.Optional(Type.String()), value: Type.Optional(Type.String()), }, { additionalProperties: false, minProperties: 3 }, ); const ArrangeItemOperationSchema = Type.Object( { type: Type.Literal("arrange_item"), area: Type.Union([ Type.Literal("telemetry"), Type.Literal("serviceGroups"), Type.Literal("statusStrips"), Type.Literal("modules"), ]), id: IdentifierSchema, index: Type.Integer({ minimum: 0 }), }, { additionalProperties: false }, ); const RemoveItemOperationSchema = Type.Object( { type: Type.Literal("remove_item"), target: AgentTargetSchema, }, { additionalProperties: false }, ); const NestedDashboardDocumentSchema = Type.Unsafe( schemaWithoutRootId(DashboardDocumentSchema), ); const CreateDashboardOperationSchema = Type.Object( { type: Type.Literal("create_dashboard"), document: NestedDashboardDocumentSchema, }, { additionalProperties: false }, ); export const AgentDashboardOperationSchema = Type.Union([ CreateDashboardOperationSchema, AddSectionOperationSchema, AddServiceOperationSchema, AddMetricCardOperationSchema, ConnectDatasourceOperationSchema, SetStatusRuleOperationSchema, ArrangeItemOperationSchema, RemoveItemOperationSchema, ]); export const AgentDashboardOperationsSchema = Type.Array(AgentDashboardOperationSchema, { minItems: 1, }); const PreviewRequestSchema = Type.Object( { action: Type.Literal("preview_changes"), operations: AgentDashboardOperationsSchema, }, { additionalProperties: false }, ); const PublishRequestSchema = Type.Object( { action: Type.Literal("publish_changes"), actor: Type.Optional(Type.String({ minLength: 1 })), message: Type.Optional(Type.String({ minLength: 1 })), operations: AgentDashboardOperationsSchema, }, { additionalProperties: false }, ); const RollbackRequestSchema = Type.Object( { action: Type.Literal("rollback_revision"), actor: Type.Optional(Type.String({ minLength: 1 })), message: Type.Optional(Type.String({ minLength: 1 })), revisionId: Type.String({ minLength: 1 }), }, { additionalProperties: false }, ); export const AgentDashboardRequestSchema = Type.Union([ PreviewRequestSchema, PublishRequestSchema, RollbackRequestSchema, ]); export type AgentDashboardOperation = Static; export type AgentDashboardRequest = Static; export interface JsonPatchAddOperation { op: "add"; path: string; value: unknown; } export interface JsonPatchRemoveOperation { op: "remove"; path: string; } export interface JsonPatchReplaceOperation { op: "replace"; path: string; value: unknown; } export type JsonPatchOperation = | JsonPatchAddOperation | JsonPatchRemoveOperation | JsonPatchReplaceOperation; export interface AgentConfigError { code: string; message: string; operationIndex?: number; path: string; details?: unknown; } export type AgentPreviewResult = | { ok: true; document: DashboardDocument; patch: JsonPatchOperation[]; } | { ok: false; errors: AgentConfigError[]; }; export type AgentPublishResult = | { ok: true; document: DashboardDocument; patch: JsonPatchOperation[]; previousRevisionId: string | null; revision: DashboardRevision; } | { ok: false; errors: AgentConfigError[]; }; export interface AgentDashboardHandlerOptions { store?: DashboardStore; token?: string; } export class AgentConfigAuthorizationError extends Error { constructor() { super("Unauthorized dashboard configuration request"); this.name = "AgentConfigAuthorizationError"; } } const validateOperations = createAjv().compile( AgentDashboardOperationsSchema, ); const validateRequest = createAjv().compile( AgentDashboardRequestSchema, ); function schemaWithoutRootId(schema: T): T { const clone = JSON.parse(JSON.stringify(schema)) as T & { $id?: string }; delete clone.$id; return clone; } function createAjv() { return addFormats( new Ajv({ allErrors: true, strict: false, strictNumbers: true, }), ); } export function previewDashboardChanges( document: DashboardDocument, operations: AgentDashboardOperation[], ): AgentPreviewResult { const operationValidation = validateAgentOperations(operations); if (operationValidation.length) return { ok: false, errors: operationValidation }; const before = structuredClone(document); let next = structuredClone(document); const errors: AgentConfigError[] = []; operations.forEach((operation, operationIndex) => { if (errors.length) return; const result = applyOperation(next, operation, operationIndex); if (result.ok) { next = result.document; } else { errors.push(...result.errors); } }); if (errors.length) return { ok: false, errors }; const validation = validateDashboardDocument(next); if (!validation.valid) { return { ok: false, errors: dashboardValidationErrors(validation), }; } return { ok: true, document: validation.data, patch: createJsonPatch(before, validation.data), }; } export function publishDashboardChanges( store: DashboardStore, operations: AgentDashboardOperation[], metadata: DashboardWriteMetadata = {}, ): AgentPublishResult { const active = store.getActiveDashboard(); if (!active) { const create = operations[0]; if (!create || create.type !== "create_dashboard") { return { ok: false, errors: [ { code: "no_active_dashboard", message: "No active dashboard exists; start with create_dashboard", path: "/", }, ], }; } } const base = active?.document || emptyDashboardDocument(); const preview = previewDashboardChanges(base, operations); if (!preview.ok) return preview; const revision = store.commitDashboard(preview.document, metadata); return { ok: true, document: revision.document, patch: preview.patch, previousRevisionId: active?.currentRevisionId || null, revision, }; } export function rollbackDashboardRevision( store: DashboardStore, revisionId: string, metadata: DashboardWriteMetadata = {}, ) { return store.rollbackToRevision(revisionId, metadata); } export function authorizeAgentConfigRequest( request: Request, token = process.env.AGENT_CONFIG_TOKEN, ): { ok: true } { if (!token) throw new AgentConfigAuthorizationError(); const authorization = request.headers.get("authorization") || ""; const bearer = authorization.match(/^Bearer\s+(.+)$/i)?.[1]; const headerToken = request.headers.get("x-agent-config-token"); if (bearer === token || headerToken === token) return { ok: true }; throw new AgentConfigAuthorizationError(); } export async function handleAgentDashboardRequest( request: Request, options: AgentDashboardHandlerOptions = {}, ): Promise { const ownsStore = !options.store; const store = options.store || createDashboardStore(); try { authorizeAgentConfigRequest(request, options.token); const body = await parseRequestBody(request); const requestValidationErrors = validateAgentRequest(body); if (requestValidationErrors.length) { return Response.json( { ok: false, errors: requestValidationErrors }, { status: 400 }, ); } const agentRequest = body as AgentDashboardRequest; if (agentRequest.action === "rollback_revision") { const revision = rollbackDashboardRevision(store, agentRequest.revisionId, { actor: agentRequest.actor || "agent", message: agentRequest.message, }); return Response.json({ ok: true, action: agentRequest.action, revision: serializeRevision(revision), }); } if (agentRequest.action === "preview_changes") { const active = store.getActiveDashboard(); const base = active?.document || previewBaseDocument(agentRequest.operations); if (!base) { return Response.json( { ok: false, errors: [ { code: "no_active_dashboard", message: "No active dashboard exists to preview against", path: "/", }, ], }, { status: 409 }, ); } const preview = previewDashboardChanges(base, agentRequest.operations); return Response.json( { ...preview, action: agentRequest.action, }, { status: preview.ok ? 200 : 422 }, ); } const publish = publishDashboardChanges(store, agentRequest.operations, { actor: agentRequest.actor || "agent", message: agentRequest.message, }); return Response.json( { ...publish, action: agentRequest.action, revision: publish.ok ? serializeRevision(publish.revision) : undefined, }, { status: publish.ok ? 200 : 422 }, ); } catch (error) { if (error instanceof AgentConfigAuthorizationError) { return Response.json( { ok: false, errors: [ { code: "unauthorized", message: error.message, path: "/", }, ], }, { status: 401 }, ); } if (error instanceof SyntaxError) { return Response.json( { ok: false, errors: [ { code: "invalid_json", message: error.message, path: "/", }, ], }, { status: 400 }, ); } if (error instanceof DashboardRevisionNotFoundError) { return Response.json( { ok: false, errors: [ { code: "revision_not_found", message: error.message, path: "/revisionId", }, ], }, { status: 404 }, ); } throw error; } finally { if (ownsStore) store.close(); } } function validateAgentOperations(operations: unknown): AgentConfigError[] { if (!validateOperations(operations)) { return schemaErrors(validateOperations.errors || [], "invalid_operation_schema"); } const createDashboardIndices = operations.flatMap((operation, index) => operation.type === "create_dashboard" ? [index] : [], ); if (createDashboardIndices.length > 1) { const operationIndex = createDashboardIndices[1]; return [ { code: "invalid_operation_sequence", message: "create_dashboard can only appear once", operationIndex, path: `/${operationIndex}`, }, ]; } if (createDashboardIndices[0] !== undefined && createDashboardIndices[0] !== 0) { const operationIndex = createDashboardIndices[0]; return [ { code: "invalid_operation_sequence", message: "create_dashboard must be the first operation", operationIndex, path: `/${operationIndex}`, }, ]; } return []; } function validateAgentRequest(value: unknown): AgentConfigError[] { if (validateRequest(value)) return []; return schemaErrors(validateRequest.errors || [], "invalid_request_schema"); } function schemaErrors(errors: ErrorObject[], code: string): AgentConfigError[] { return errors.map((error) => ({ code, message: error.message || "is invalid", operationIndex: operationIndexFromPath(error.instancePath), path: error.instancePath || "/", details: error.params, })); } function dashboardValidationErrors( failure: DashboardValidationFailure, ): AgentConfigError[] { return failure.errors.map((message, index) => ({ code: "dashboard_validation_failed", message, path: failure.details[index]?.instancePath || "/", details: failure.details[index]?.params, })); } function operationIndexFromPath(path: string): number | undefined { const segments = path.split("/").filter(Boolean); const operationsIndex = segments.indexOf("operations"); const candidate = operationsIndex >= 0 ? segments[operationsIndex + 1] : segments[0]; const index = Number(candidate); return Number.isInteger(index) ? index : undefined; } type ApplyResult = | { ok: true; document: DashboardDocument } | { ok: false; errors: AgentConfigError[] }; function applyOperation( document: DashboardDocument, operation: AgentDashboardOperation, operationIndex: number, ): ApplyResult { const next = structuredClone(document); switch (operation.type) { case "create_dashboard": return { ok: true, document: structuredClone(operation.document) }; case "add_section": return addSection(next, operation, operationIndex); case "add_service": return addService(next, operation, operationIndex); case "add_metric_card": return addMetricCard(next, operation, operationIndex); case "connect_datasource": return connectDatasource(next, operation, operationIndex); case "set_status_rule": return setStatusRule(next, operation, operationIndex); case "arrange_item": return arrangeItem(next, operation, operationIndex); case "remove_item": return removeItem(next, operation, operationIndex); } } type AddSectionOperation = Extract; type AddServiceOperation = Extract; type AddMetricCardOperation = Extract; type ConnectDatasourceOperation = Extract; type SetStatusRuleOperation = Extract; type ArrangeItemOperation = Extract; type RemoveItemOperation = Extract; function addSection( document: DashboardDocument, operation: AddSectionOperation, operationIndex: number, ): ApplyResult { if (document.serviceGroups.some((group) => group.id === operation.section.id)) { return failure( "duplicate_id", `Service group already exists: ${operation.section.id}`, operationIndex, "/serviceGroups", ); } const group: ServiceGroup = { ...operation.section, services: [], }; document.serviceGroups.push(group); document.layout.serviceGroups = insertId( document.layout.serviceGroups, group.id, operation.position, ); return { ok: true, document }; } function addService( document: DashboardDocument, operation: AddServiceOperation, operationIndex: number, ): ApplyResult { const group = document.serviceGroups.find((item) => item.id === operation.groupId); if (!group) { return failure( "group_not_found", `Service group not found: ${operation.groupId}`, operationIndex, "/serviceGroups", ); } if ( document.serviceGroups.some((item) => item.services.some((service) => service.id === operation.service.id), ) ) { return failure( "duplicate_id", `Service already exists: ${operation.service.id}`, operationIndex, "/serviceGroups", ); } group.services = insertItem(group.services, operation.service, operation.position); return { ok: true, document }; } function addMetricCard( document: DashboardDocument, operation: AddMetricCardOperation, operationIndex: number, ): ApplyResult { if (document.telemetry.some((card) => card.id === operation.card.id)) { return failure( "duplicate_id", `Telemetry card already exists: ${operation.card.id}`, operationIndex, "/telemetry", ); } document.telemetry.push(operation.card); document.layout.telemetry = insertId( document.layout.telemetry, operation.card.id, operation.position, ); return { ok: true, document }; } function connectDatasource( document: DashboardDocument, operation: ConnectDatasourceOperation, operationIndex: number, ): ApplyResult { if (!supportsDatasource(operation.target.kind)) { return failure( "unsupported_target", `Target does not support datasources: ${operation.target.kind}`, operationIndex, targetPath(operation.target), ); } const targetResolution = resolveTarget(document, operation.target, operationIndex); if (!targetResolution.ok) { return { ok: false, errors: targetResolution.errors }; } const target = targetResolution.target; (target as DatasourceAgentTarget).datasource = operation.datasource; return { ok: true, document }; } function setStatusRule( document: DashboardDocument, operation: SetStatusRuleOperation, operationIndex: number, ): ApplyResult { if (operation.target.kind === "serviceGroup") { return failure( "unsupported_target", `Target does not support status rules: ${operation.target.kind}`, operationIndex, targetPath(operation.target), ); } if (operation.thresholds && operation.target.kind !== "telemetry") { return failure( "unsupported_target", "Thresholds can only be set on telemetry targets", operationIndex, targetPath(operation.target), ); } if (operation.detail !== undefined && !supportsDetail(operation.target.kind)) { return failure( "unsupported_target", "Detail can only be set on telemetry, service, or module targets", operationIndex, targetPath(operation.target), ); } if (operation.value !== undefined && !supportsStringValue(operation.target.kind)) { return failure( "unsupported_target", "String values can only be set on status item or module targets", operationIndex, targetPath(operation.target), ); } const targetResolution = resolveTarget(document, operation.target, operationIndex); if (!targetResolution.ok) { return { ok: false, errors: targetResolution.errors }; } const target = targetResolution.target; if (operation.thresholds && operation.target.kind === "telemetry") { (target as TelemetryCard).thresholds = operation.thresholds; } if (operation.severity) { target.severity = operation.severity; } if (operation.detail !== undefined && supportsDetail(operation.target.kind)) { (target as DetailAgentTarget).detail = operation.detail; } if (operation.value !== undefined && supportsStringValue(operation.target.kind)) { (target as StringValueAgentTarget).value = operation.value; } return { ok: true, document }; } function arrangeItem( document: DashboardDocument, operation: ArrangeItemOperation, operationIndex: number, ): ApplyResult { const list = layoutList(document, operation.area); if (!list.includes(operation.id)) { return failure( "item_not_found", `Layout item not found: ${operation.id}`, operationIndex, `/layout/${operation.area}`, ); } const without = list.filter((id) => id !== operation.id); const index = Math.min(operation.index, without.length); without.splice(index, 0, operation.id); setLayoutList(document, operation.area, without); syncCollectionOrder(document, operation.area, without); return { ok: true, document }; } function removeItem( document: DashboardDocument, operation: RemoveItemOperation, operationIndex: number, ): ApplyResult { if (operation.target.kind === "telemetry") { if (!document.telemetry.some((card) => card.id === operation.target.id)) { return failure( "item_not_found", `Telemetry card not found: ${operation.target.id}`, operationIndex, "/telemetry", ); } document.telemetry = document.telemetry.filter((card) => card.id !== operation.target.id); document.layout.telemetry = document.layout.telemetry.filter((id) => id !== operation.target.id); return { ok: true, document }; } if (operation.target.kind === "serviceGroup") { if (!document.serviceGroups.some((group) => group.id === operation.target.id)) { return failure( "item_not_found", `Service group not found: ${operation.target.id}`, operationIndex, "/serviceGroups", ); } document.serviceGroups = document.serviceGroups.filter((group) => group.id !== operation.target.id); document.layout.serviceGroups = document.layout.serviceGroups.filter((id) => id !== operation.target.id); return { ok: true, document }; } if (operation.target.kind === "service") { const matches = findServices(document, operation.target.id, operation.target.groupId); if (!matches.length) { return failure( "item_not_found", `Service not found: ${operation.target.id}`, operationIndex, "/serviceGroups", ); } if (!operation.target.groupId && matches.length > 1) { return failure( "ambiguous_target", `Service exists in multiple groups: ${operation.target.id}`, operationIndex, "/serviceGroups", ); } const match = matches[0]; match.group.services = match.group.services.filter((service) => service.id !== operation.target.id); return { ok: true, document }; } if (operation.target.kind === "module") { if (!(document.modules || []).some((module) => module.id === operation.target.id)) { return failure( "item_not_found", `Module not found: ${operation.target.id}`, operationIndex, "/modules", ); } document.modules = (document.modules || []).filter((module) => module.id !== operation.target.id); document.layout.modules = (document.layout.modules || []).filter((id) => id !== operation.target.id); return { ok: true, document }; } if (operation.target.kind === "statusItem") { const matches = findStatusItems(document, operation.target.id, operation.target.stripId); if (!matches.length) { return failure( "item_not_found", `Status item not found: ${operation.target.id}`, operationIndex, "/statusStrips", ); } if (!operation.target.stripId && matches.length > 1) { return failure( "ambiguous_target", `Status item exists in multiple strips: ${operation.target.id}`, operationIndex, "/statusStrips", ); } const [match] = matches; match.strip.items = match.strip.items.filter((item) => item.id !== operation.target.id); return { ok: true, document }; } return failure("unsupported_target", "Cannot remove target kind", operationIndex, "/"); } function resolveTarget( document: DashboardDocument, target: ConnectDatasourceOperation["target"], operationIndex: number, ): ResolveTargetResult { if (target.kind === "telemetry") { const card = document.telemetry.find((item) => item.id === target.id); if (!card) { return resolutionFailure( "item_not_found", `Telemetry card not found: ${target.id}`, operationIndex, "/telemetry", ); } return { ok: true, target: card }; } if (target.kind === "service") { const matches = findServices(document, target.id, target.groupId); if (!matches.length) { return resolutionFailure( "item_not_found", `Service not found: ${target.id}`, operationIndex, "/serviceGroups", ); } if (!target.groupId && matches.length > 1) { return resolutionFailure( "ambiguous_target", `Service exists in multiple groups: ${target.id}`, operationIndex, "/serviceGroups", ); } return { ok: true, target: matches[0].service }; } if (target.kind === "statusItem") { const matches = findStatusItems(document, target.id, target.stripId); if (!matches.length) { return resolutionFailure( "item_not_found", `Status item not found: ${target.id}`, operationIndex, "/statusStrips", ); } if (!target.stripId && matches.length > 1) { return resolutionFailure( "ambiguous_target", `Status item exists in multiple strips: ${target.id}`, operationIndex, "/statusStrips", ); } return { ok: true, target: matches[0].item }; } if (target.kind === "module") { const module = (document.modules || []).find((item) => item.id === target.id); if (!module) { return resolutionFailure( "item_not_found", `Module not found: ${target.id}`, operationIndex, "/modules", ); } return { ok: true, target: module }; } return resolutionFailure( "item_not_found", `Target not found: ${target.id}`, operationIndex, targetPath(target), ); } type ResolveTargetResult = | { ok: true; target: ResolvedAgentTarget } | { ok: false; errors: AgentConfigError[] }; type ResolvedAgentTarget = TelemetryCard | ServiceEntry | StatusItem | DashboardModule; type DatasourceAgentTarget = TelemetryCard | ServiceEntry | DashboardModule; type DetailAgentTarget = TelemetryCard | ServiceEntry | DashboardModule; type StringValueAgentTarget = StatusItem | DashboardModule; type DatasourceTargetKind = Extract< ConnectDatasourceOperation["target"]["kind"], "telemetry" | "service" | "module" >; function supportsDatasource( kind: ConnectDatasourceOperation["target"]["kind"], ): kind is DatasourceTargetKind { return kind === "telemetry" || kind === "service" || kind === "module"; } type DetailTargetKind = Extract< SetStatusRuleOperation["target"]["kind"], "telemetry" | "service" | "module" >; function supportsDetail( kind: SetStatusRuleOperation["target"]["kind"], ): kind is DetailTargetKind { return kind === "telemetry" || kind === "service" || kind === "module"; } type StringValueTargetKind = Extract< SetStatusRuleOperation["target"]["kind"], "statusItem" | "module" >; function supportsStringValue( kind: SetStatusRuleOperation["target"]["kind"], ): kind is StringValueTargetKind { return kind === "statusItem" || kind === "module"; } function findServices(document: DashboardDocument, id: string, groupId?: string) { const groups = groupId ? document.serviceGroups.filter((group) => group.id === groupId) : document.serviceGroups; return groups.flatMap((group) => group.services.flatMap((service) => service.id === id ? [{ group, service }] : [], ), ); } function findStatusItems(document: DashboardDocument, id: string, stripId?: string) { const strips = stripId ? document.statusStrips.filter((strip) => strip.id === stripId) : document.statusStrips; return strips.flatMap((strip) => strip.items.flatMap((item) => (item.id === id ? [{ strip, item }] : [])), ); } function resolutionFailure( code: string, message: string, operationIndex: number, path: string, ): ResolveTargetResult { return { ok: false, errors: [ { code, message, operationIndex, path, }, ], }; } function targetPath(target: ConnectDatasourceOperation["target"]): string { if (target.kind === "telemetry") return "/telemetry"; if (target.kind === "service") return "/serviceGroups"; if (target.kind === "serviceGroup") return "/serviceGroups"; if (target.kind === "statusItem") return "/statusStrips"; return "/modules"; } function layoutList(document: DashboardDocument, area: ArrangeItemOperation["area"]) { if (area === "modules") return document.layout.modules || []; return document.layout[area]; } function setLayoutList( document: DashboardDocument, area: ArrangeItemOperation["area"], value: string[], ) { if (area === "modules") { document.layout.modules = value; return; } document.layout[area] = value; } function syncCollectionOrder( document: DashboardDocument, area: ArrangeItemOperation["area"], orderedIds: string[], ) { if (area === "telemetry") { document.telemetry = orderByIds(document.telemetry, orderedIds); return; } if (area === "serviceGroups") { document.serviceGroups = orderByIds(document.serviceGroups, orderedIds); return; } if (area === "statusStrips") { document.statusStrips = orderByIds(document.statusStrips, orderedIds); return; } document.modules = orderByIds(document.modules || [], orderedIds); } function orderByIds(items: T[], orderedIds: string[]): T[] { const order = new Map(orderedIds.map((id, index) => [id, index])); return [...items].sort( (left, right) => (order.get(left.id) ?? Number.MAX_SAFE_INTEGER) - (order.get(right.id) ?? Number.MAX_SAFE_INTEGER), ); } function insertItem( items: T[], item: T, position?: Static, ): T[] { const next = [...items]; next.splice(resolveInsertionIndex(next.map((entry) => entry.id), position), 0, item); return next; } function insertId( ids: string[], id: string, position?: Static, ): string[] { const next = [...ids]; next.splice(resolveInsertionIndex(next, position), 0, id); return next; } function resolveInsertionIndex(ids: string[], position?: Static) { if (!position) return ids.length; if (typeof position.index === "number") return Math.min(position.index, ids.length); if (position.beforeId) { const beforeIndex = ids.indexOf(position.beforeId); return beforeIndex >= 0 ? beforeIndex : ids.length; } if (position.afterId) { const afterIndex = ids.indexOf(position.afterId); return afterIndex >= 0 ? afterIndex + 1 : ids.length; } return ids.length; } function failure( code: string, message: string, operationIndex: number, path: string, ): ApplyResult { return { ok: false, errors: [ { code, message, operationIndex, path, }, ], }; } function createJsonPatch( before: unknown, after: unknown, path = "", ): JsonPatchOperation[] { if (before === undefined) return [{ op: "add", path: path || "/", value: after }]; if (after === undefined) return [{ op: "remove", path: path || "/" }]; if (Object.is(before, after)) return []; if (!isObjectLike(before) || !isObjectLike(after)) { return [{ op: "replace", path: path || "/", value: after }]; } if (Array.isArray(before) || Array.isArray(after)) { if (!Array.isArray(before) || !Array.isArray(after)) { return [{ op: "replace", path: path || "/", value: after }]; } const operations: JsonPatchOperation[] = []; const sharedLength = Math.min(before.length, after.length); for (let index = 0; index < sharedLength; index += 1) { operations.push( ...createJsonPatch(before[index], after[index], `${path}/${index}`), ); } for (let index = before.length - 1; index >= after.length; index -= 1) { operations.push({ op: "remove", path: `${path}/${index}` }); } for (let index = before.length; index < after.length; index += 1) { operations.push({ op: "add", path: `${path}/${index}`, value: after[index] }); } return operations; } const beforeObject = before as Record; const afterObject = after as Record; const keys = new Set([...Object.keys(beforeObject), ...Object.keys(afterObject)]); return [...keys].flatMap((key) => createJsonPatch(beforeObject[key], afterObject[key], `${path}/${escapeJsonPointer(key)}`), ); } function isObjectLike(value: unknown): value is Record | unknown[] { return typeof value === "object" && value !== null; } function escapeJsonPointer(value: string): string { return value.replace(/~/g, "~0").replace(/\//g, "~1"); } async function parseRequestBody(request: Request): Promise { const text = await request.text(); return text ? JSON.parse(text) : {}; } function previewBaseDocument(operations: AgentDashboardOperation[]): DashboardDocument | null { return operations[0]?.type === "create_dashboard" ? emptyDashboardDocument() : null; } function serializeRevision(revision: DashboardRevision) { return { id: revision.id, dashboardId: revision.dashboardId, schemaVersion: revision.schemaVersion, actor: revision.actor, message: revision.message, operation: revision.operation, sourceRevisionId: revision.sourceRevisionId, createdAt: revision.createdAt.toISOString(), }; } function emptyDashboardDocument(): DashboardDocument { return { schemaVersion: "dashboard.v1", metadata: { title: "Untitled Dashboard", }, layout: { telemetry: [], serviceGroups: [], statusStrips: [], modules: [], }, telemetry: [], serviceGroups: [], statusStrips: [], modules: [], }; }