run402-mcp
Version:
MCP server for Run402 — full-stack backend infrastructure for AI agents: Postgres, auth, storage, serverless functions and atomic deploys. Paid with x402/MPP. Includes $0.03 image generation.
162 lines • 8.59 kB
TypeScript
import type { Client } from "../kernel.js";
import { VAULT_MIRROR_KEYSTORE_STILL_REQUIRED_STATEMENT, VAULT_MIRROR_VALIDITY_NOT_FRESHNESS_STATEMENT } from "../namespaces/vault.crypto.js";
import { VaultKeystore } from "./vault-keystore.js";
import { type VaultMirrorBackend } from "./vault-mirror-backend.js";
/**
* REPO-RELATIVE — the `source/<repo_id>/` prefix has already been stripped
* (see the module doc's mirror-layout mapping). This is the shape every
* OTHER function in this module, `vault-recover.ts`, and the mirror
* backend interface all consume; nothing here ever sees the raw wire key
* except `listVaultObjectsAll` itself.
*
* `size_bytes` is an exact decimal string for EVERY kind, including the two
* generation-addressed chain kinds (`head`/`vault_genesis` at generation
* zero, `admission_record`) — never `null`.
*/
export interface VaultObjectEntry {
key: string;
object_kind: string;
sha256: string;
size_bytes: string;
}
/** Page through `GET /vaults/v1/:vault_id/objects`, collecting every entry, stripped to repo-relative keys. Store-and-echo cursor per D3a — never parsed here either. */
export declare function listVaultObjectsAll(client: Client, repoId: string): Promise<VaultObjectEntry[]>;
/** Read one object's bytes by key, using the same wire identity every stored kind already carries (§3 layout). `null` when the gateway reports the object absent. */
export declare function readVaultObjectBytes(client: Client, repoId: string, entry: VaultObjectEntry): Promise<Uint8Array | null>;
/** Exported for the key-shape conformance test (`vault-mirror-recover.test.ts`) — never called for its own sake outside this module. */
export declare function generationRouteForKey(key: string): {
route: "heads" | "admissions";
generation: string;
} | null;
/**
* `key_envelope` is path-addressed by `(epoch, recipient_fingerprint)`, not a
* plain object_id — every other kind uses its object_id, read straight from
* the key's own filename via an ANCHORED, kind-specific pattern (never a
* loose, unanchored fallback — see {@link NON_GENERATION_KEY_SPECS}).
* Exported for the key-shape conformance test.
*/
export declare function objectReadRequestForEntry(entry: VaultObjectEntry): {
object_kind: string;
object_id?: string;
epoch?: string;
recipient_fingerprint?: string;
};
export interface VaultMirrorWritePlan {
/** Every non-head, non-admission entry, in listing order — write these FIRST, in any order among themselves. */
objects: VaultObjectEntry[];
/** Then admission records and heads, interleaved, strictly ascending by generation (admission before its own head). */
admissionsAndHeads: VaultObjectEntry[];
}
/** Sort a flat listing into the admission-order write plan (module doc above). */
export declare function planMirrorWrite(entries: readonly VaultObjectEntry[]): VaultMirrorWritePlan;
export interface VaultMirrorCopyResult {
key: string;
outcome: "copied" | "already_present" | "skipped_foreign_recipient" | "failed";
size_bytes?: string;
error?: string;
}
export interface VaultMirrorSyncSummary {
repo_id: string;
destination: string;
/** Faithful counts of what ACTUALLY happened this call — never an estimate (design D3a rider (e)). */
objects_listed: number;
objects_copied: number;
objects_already_present: number;
/**
* Task 5.3 follow-up: a `key_envelope` wrapped for a DIFFERENT recipient
* than this machine's own identity — EXPECTED, not a problem. The
* recipient-only read gate means a mirror can only ever hold envelopes
* addressed to the local identity; a multi-recipient vault
* (vault-human-envelopes) makes this the norm. Never counted toward
* `objects_failed`, and never causes `mirror sync` to report anything but
* success — named per-key in `skipped_foreign_recipient_keys` so a reader
* can tell "expected skip" from "silent gap" without cross-referencing.
*/
objects_skipped_foreign_recipient: number;
skipped_foreign_recipient_keys: string[];
objects_failed: number;
bytes_copied: string;
errors: Array<{
key: string;
error: string;
}>;
validity_not_freshness: typeof VAULT_MIRROR_VALIDITY_NOT_FRESHNESS_STATEMENT;
keystore_still_required: typeof VAULT_MIRROR_KEYSTORE_STILL_REQUIRED_STATEMENT;
}
export interface VaultMirrorSyncOptions {
keystore?: VaultKeystore;
/** Test/advanced hook: an already-opened backend, bypassing config resolution. */
backend?: VaultMirrorBackend;
}
/**
* `run402 repos mirror sync` (task 2.3): list the vault's stored objects,
* diff against the mirror by key+size, fetch and hash-verify what's missing,
* write it in admission order. Resumable and idempotent — running it twice in
* a row with nothing new copies nothing the second time.
*/
export declare function mirrorSync(client: Client, repoId: string, options?: VaultMirrorSyncOptions): Promise<VaultMirrorSyncSummary>;
export interface VaultMirrorPushResult {
attempted: boolean;
outcome: "pushed" | "skipped_no_mirror" | "failed";
summary?: VaultMirrorSyncSummary;
error?: string;
}
/**
* Fires after an ordinary vault push/deploy produces a new generation. NEVER
* throws and NEVER alters the caller's deploy/push outcome (design D6) — a
* mirror is strictly extra durability, and its failure is reported BESIDE the
* vault result as a distinct line, not folded into it. Fires only when a
* mirror is configured for this vault; a vault with no mirror gets
* `skipped_no_mirror` (not an error) so callers can log it uniformly without
* branching on whether mirroring was ever opted into.
*
* Implemented as a full (but INCREMENTAL, idempotent) sync rather than a
* push-scoped upload: the objects listing + diff-by-size machinery already
* makes an all-caught-up sync cheap (one listing page, zero copies), and this
* keeps the admission-order write discipline in exactly one place instead of
* a second, push-scoped code path that could drift from it.
*/
export declare function mirrorPushForGeneration(client: Client, repoId: string, options?: VaultMirrorSyncOptions): Promise<VaultMirrorPushResult>;
/**
* `run402 repos create --byo`'s every-push dual-write (task 3.3, design
* D1): list the vault's stored objects, restrict to the signed CHAIN
* (never the payload kinds, which THIS SAME push already wrote directly to
* the destination — task 3.2), diff against the destination by key+size,
* fetch (from run402 — the chain stays run402-authoritative) and
* hash-verify what's missing, write it in admission order. Resumable and
* idempotent, reusing the SAME `reconcileOne` copy primitive and
* admission-order discipline the opt-in mirror uses — one implementation,
* not a second ordering to prove.
*/
export declare function byoChainCopySync(client: Client, repoId: string, options?: VaultMirrorSyncOptions): Promise<VaultMirrorSyncSummary>;
/**
* Fires after an ordinary vault push produces a new generation, mirroring
* {@link mirrorPushForGeneration}'s exact contract (NEVER throws, NEVER
* alters the caller's push outcome — the chain-copy is reported BESIDE it).
* Gated on a LOCAL BYO write config existing for this repo — a managed
* vault (the common case) pays zero extra network calls, `skipped_no_byo`.
*/
export declare function byoChainCopyPushForGeneration(client: Client, repoId: string, options?: VaultMirrorSyncOptions): Promise<VaultMirrorPushResult>;
export interface VaultByoMissingObject {
key: string;
object_kind: string;
}
export interface VaultByoPresenceReport {
repo_id: string;
destination: string;
checked: number;
missing: VaultByoMissingObject[];
}
/**
* Adjudicates the BYO destination against run402's signed chain (task 3.3's
* read half, D6): HEAD-checks (cheap, no data transfer) every object the
* vault's OWN listing names — payload AND chain alike, since for a BYO
* vault the destination is supposed to hold BOTH (payload via task 3.2's
* direct write, chain via this file's dual-write above) — against the
* destination, by key + size. Never throws on an absence; it REPORTS every
* missing object by name so the caller (`repos fsck`) can refuse with
* `VAULT_BYO_OBJECT_MISSING` naming exactly what the chain says should
* exist and does not.
*/
export declare function verifyByoObjectsPresent(client: Client, repoId: string, options?: VaultMirrorSyncOptions): Promise<VaultByoPresenceReport>;
//# sourceMappingURL=vault-mirror.d.ts.map