/** * @module infra/graph-access * * The device's read/write access to its organization's durable graph. * * The graph is the koi's long-term memory of the world it works in — people, * projects, files, devices, conversations and the edges between them. It lives on * the platform (Postgres) and is written ONLY through signed device events, so the * device is the sole author and every change is attributable. * * This module is the plumbing under the koi's graph tools: * - {@link queryDurableGraph} reads it (POST /api/koi/:id/graph/query) * - {@link emitGraphEvents} writes it (sign → outbox → flush now) * * Writes go through the outbox rather than straight to the network so a graph edit * made while offline is never lost — it is signed, queued, and flushed on the next * heartbeat. We additionally flush immediately after appending, because a koi that * says "renamed it" should mean it, not "renamed it, visible within 30 seconds". */ import type { SKYKOIConfig } from "../config/config.js"; import { type GraphEventDraft, type SignedGraphEvent } from "./graph-event-outbox.js"; export type GraphIdentity = { platformUrl: string; koiId: string; gatewayToken: string; }; /** * The platform URL, koi id and gateway token, or null when this device is not * linked to the platform (in which case it has no graph to read or write). * * Same resolution the platform heartbeat uses (config first, env as fallback), and * re-read per call so a re-link takes effect without a restart. */ export declare function resolveGraphIdentity(cfg?: SKYKOIConfig | null): GraphIdentity | null; export type GraphQuery = { action: "search"; q?: string; kinds?: string[]; since?: string; limit?: number; } | { action: "neighbors"; stableId: string; depth?: number; edgeKinds?: string[]; limit?: number; } | { action: "node"; stableId: string; } | { action: "stats"; }; /** Runs one graph query. Throws with the platform's message on a non-2xx. */ export declare function queryDurableGraph(identity: GraphIdentity, query: GraphQuery, fetchImpl?: typeof fetch): Promise>; /** * Signs and queues graph events, then tries to push them immediately. * * The append is the durable part; the flush is best-effort. A flush failure is * reported (so the koi can say "queued, not yet synced") but is NOT an error: the * events are already safe and the heartbeat will retry. */ export declare function emitGraphEvents(identity: GraphIdentity, drafts: GraphEventDraft[], fetchImpl?: typeof fetch): Promise<{ queued: SignedGraphEvent[]; synced: number; syncError?: string; }>; /** * Deterministic stable id for an edge, so re-linking the same pair with the same * kind updates one edge instead of accumulating duplicates. */ export declare function edgeStableId(fromStableId: string, kind: string, toStableId: string): string;