/** * Claim-code store — scoped remote access for Photon MCP sessions. * * ────────────────────────────────────────────────────────────────────────── * What problem this solves * ────────────────────────────────────────────────────────────────────────── * By default a Photon daemon exposes every installed photon to every * connected MCP client. That is fine on a developer's own machine, but * breaks down the moment you want to give a *remote* agent access to a * subset of photons — say, pairing a phone-side Claude Code session with * Beam running on your laptop but only letting that session see photons * under a single project directory. * * A "claim code" is a short opaque token the owner generates locally * (`photon claim`), prints, and gives to the remote agent. The agent * includes the code in the initialize handshake of its MCP connection * (`Mcp-Claim-Code` header on Streamable HTTP) and from that point on * the server's `tools/list` is filtered to the photons that live under * the claim's `scopeDir`. * * ────────────────────────────────────────────────────────────────────────── * Design * ────────────────────────────────────────────────────────────────────────── * - Codes are **6 chars, base32 (Crockford) without lookalikes** → looks * like `R3K9QZ`. Formatted for display as `R3K-9QZ` but stored raw. * - Codes are **disk-persisted** under `{baseDir}/.data/claims.json` so * daemon restarts don't invalidate them. * - Codes carry a **ttl** (default 24h). Expired codes are garbage- * collected on every read — lazy cleanup, no background timer. * - Scope is a **directory prefix**. Photons whose source file resolves * under this dir are visible; everything else is filtered out. * - Validation is a pure function of the on-disk file, so Beam (in a * separate process from the daemon) can validate without IPC. * * ────────────────────────────────────────────────────────────────────────── * What this module is NOT * ────────────────────────────────────────────────────────────────────────── * - Not an authentication system. Claim codes are bearer tokens; anyone * holding a valid code gets the scoped access. Treat them like API * keys: short ttls, revoke when done. * - Not a per-tool authorization layer. Scope is directory-based; a * claim grants access to *all* photons under that directory or none. */ export declare const DEFAULT_TTL_MS: number; export interface ClaimRecord { /** 6-char code, uppercase, no dashes when stored */ code: string; /** Absolute path — only photons whose source resolves under this are visible */ scopeDir: string; /** ISO timestamp */ createdAt: string; /** Unix ms — compared against Date.now() */ expiresAt: number; /** Optional human-readable label, shown in `photon claim list` */ label?: string; } export interface CreateClaimParams { scopeDir: string; ttlMs?: number; label?: string; } export interface ValidationResult { ok: true; claim: ClaimRecord; } export interface ValidationFailure { ok: false; reason: 'unknown' | 'expired' | 'malformed'; } /** Path to the claims file, derived from the active base dir. */ export declare function getClaimsFilePath(baseDir?: string): string; /** Generate a new 6-char code using the restricted alphabet. */ export declare function generateCode(): string; /** Format a code for display: `ABC-123`. */ export declare function formatCode(code: string): string; /** Normalize a user-entered code: strip dashes/whitespace, uppercase. */ export declare function normalizeCode(raw: string): string; /** Create and persist a new claim. Returns the stored record. */ export declare function createClaim(params: CreateClaimParams, baseDir?: string): Promise; /** * List all non-expired claims. Writes the purged list back if anything * was removed, so `photon claim list` also acts as a passive GC step. */ export declare function listClaims(baseDir?: string): Promise; /** Remove a claim by code. Returns true if something was deleted. */ export declare function revokeClaim(rawCode: string, baseDir?: string): Promise; /** * Validate a code. Returns the record on success or a structured failure. * Synchronous so transport-layer code (HTTP init handler) can call it * without turning every request into a promise chain. */ export declare function validateClaimSync(rawCode: string, baseDir?: string): ValidationResult | ValidationFailure; /** * Does this photon source path fall under the claim's scopeDir? * Returns true if no claim is provided (unclaimed sessions have full access). */ export declare function isPhotonInScope(photonSourcePath: string | undefined, claim: ClaimRecord | undefined): boolean; /** * Lower-level helper that takes a bare scopeDir rather than a full * claim record — the transport layer only carries the dir on the * session, and loading the full record on every `tools/list` call * would be needless I/O. * * Returns true when `scopeDir` is unset (unclaimed sessions get full * access — the default, backward-compatible behavior). */ export declare function isPathInScope(photonSourcePath: string | undefined, scopeDir: string | undefined): boolean; //# sourceMappingURL=claims.d.ts.map