@provenonce/sdk 0.5.0 → 0.8.0
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/README.md +28 -3
- package/dist/index.d.mts +151 -8
- package/dist/index.d.ts +151 -8
- package/dist/index.js +372 -31
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +370 -31
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/beat-sdk.ts"],"sourcesContent":["export { BeatAgent, computeBeat, computeBeatsLite } from './beat-sdk';\nexport type { BeatAgentConfig, Beat } from './beat-sdk';\n","/**\n * ═══════════════════════════════════════════════════════════\n * PROVENONCE BEAT SDK — Agent Heartbeat Client\n * ═══════════════════════════════════════════════════════════\n * \n * \"NIST tells you what time it is.\n * Provenonce tells the agent at what speed it is allowed to exist.\"\n * \n * Usage:\n * \n * import { BeatAgent } from './beat-sdk';\n * \n * const agent = new BeatAgent({\n * apiKey: 'pvn_...',\n * registryUrl: 'https://provenonce.vercel.app',\n * });\n * \n * await agent.init(); // Birth in Beat time\n * await agent.pulse(50); // Compute 50 beats\n * await agent.checkin(); // Report to registry\n * \n * // Or run the autonomous heartbeat:\n * agent.startHeartbeat(); // Computes + checks in continuously\n * // ... do your agent work ...\n * agent.stopHeartbeat();\n * \n * ═══════════════════════════════════════════════════════════\n */\n\nimport { createHash } from 'crypto';\n\n// ============ VDF ENGINE (LOCAL) ============\n\nexport interface Beat {\n index: number;\n hash: string;\n prev: string;\n timestamp: number;\n nonce?: string;\n}\n\nfunction computeBeat(prevHash: string, beatIndex: number, difficulty: number, nonce?: string): Beat {\n const timestamp = Date.now();\n \n let current = createHash('sha256')\n .update(`${prevHash}:${beatIndex}:${nonce || ''}`)\n .digest('hex');\n\n for (let i = 0; i < difficulty; i++) {\n current = createHash('sha256')\n .update(current)\n .digest('hex');\n }\n\n return { index: beatIndex, hash: current, prev: prevHash, timestamp, nonce };\n}\n\n// ============ SDK CONFIG ============\n\nexport interface BeatAgentConfig {\n /** API key from registration (pvn_...) */\n apiKey: string;\n \n /** Provenonce registry URL */\n registryUrl: string;\n \n /** Beats to compute per pulse (default: 10) */\n beatsPerPulse?: number;\n \n /** Seconds between automatic check-ins (default: 300 = 5min) */\n checkinIntervalSec?: number;\n \n /** Callback when heartbeat ticks */\n onPulse?: (beats: Beat[], totalBeats: number) => void;\n \n /** Callback when check-in completes */\n onCheckin?: (result: any) => void;\n \n /** Callback on error */\n onError?: (error: Error, context: string) => void;\n \n /** Callback when status changes */\n onStatusChange?: (status: string, details: any) => void;\n \n /** Enable verbose logging */\n verbose?: boolean;\n}\n\n// ============ BEAT AGENT ============\n\nexport class BeatAgent {\n private config: Required<BeatAgentConfig>;\n private chain: Beat[] = [];\n private difficulty: number = 1000;\n private genesisHash: string = '';\n private latestBeat: Beat | null = null;\n private totalBeats: number = 0;\n private lastCheckinBeat: number = 0;\n private status: 'uninitialized' | 'active' | 'frozen' | 'revoked' = 'uninitialized';\n private heartbeatInterval: ReturnType<typeof setInterval> | null = null;\n private globalBeat: number = 0;\n \n constructor(config: BeatAgentConfig) {\n this.config = {\n beatsPerPulse: 10,\n checkinIntervalSec: 300,\n onPulse: () => {},\n onCheckin: () => {},\n onError: () => {},\n onStatusChange: () => {},\n verbose: false,\n ...config,\n };\n }\n\n // ── INITIALIZATION ──\n\n /**\n * Initialize the agent's Beat chain.\n * This is the agent's \"birth\" in Logical Time.\n * Must be called once before computing beats.\n */\n async init(): Promise<{ ok: boolean; genesis?: string; error?: string }> {\n try {\n this.log('Initializing Beat chain...');\n\n const res = await this.api('POST', '/api/v1/agent/init');\n\n if (res.genesis) {\n this.genesisHash = res.genesis.hash;\n this.difficulty = res.difficulty || 1000;\n this.latestBeat = {\n index: 0,\n hash: res.genesis.hash,\n prev: res.genesis.prev,\n timestamp: res.genesis.timestamp,\n };\n this.chain = [this.latestBeat];\n this.totalBeats = 0;\n this.status = 'active';\n this.config.onStatusChange('active', { genesis: this.genesisHash });\n this.log(`Born in Beat time. Genesis: ${this.genesisHash.slice(0, 16)}...`);\n } else if (res.already_initialized) {\n // Restore from existing state\n this.genesisHash = res.genesis_hash;\n this.totalBeats = res.total_beats;\n this.status = res.status as any;\n this.log(`Already initialized. Restoring state (${res.total_beats} beats).`);\n \n // Fetch full state to get latest hash\n await this.refreshState();\n }\n\n // Sync global anchor\n await this.syncGlobal();\n\n return { ok: true, genesis: this.genesisHash };\n\n } catch (err: any) {\n this.config.onError(err, 'init');\n return { ok: false, error: err.message };\n }\n }\n\n // ── PULSE (COMPUTE BEATS) ──\n\n /**\n * Compute N beats locally (VDF hash chain).\n * This is the \"heartbeat\" — proof that the agent has lived \n * through a specific window of computational time.\n */\n pulse(count?: number): Beat[] {\n const n = count || this.config.beatsPerPulse;\n \n if (!this.latestBeat) {\n throw new Error('Beat chain not initialized. Call init() first.');\n }\n\n if (this.status !== 'active') {\n throw new Error(`Cannot pulse in status '${this.status}'. Use resync() if frozen.`);\n }\n\n const newBeats: Beat[] = [];\n let prevHash = this.latestBeat.hash;\n let startIndex = this.latestBeat.index + 1;\n\n const t0 = Date.now();\n \n for (let i = 0; i < n; i++) {\n const beat = computeBeat(prevHash, startIndex + i, this.difficulty);\n newBeats.push(beat);\n prevHash = beat.hash;\n }\n\n const elapsed = Date.now() - t0;\n\n // Update state\n this.chain.push(...newBeats);\n this.latestBeat = newBeats[newBeats.length - 1];\n this.totalBeats += n;\n\n // Keep chain bounded (only last 1000 beats in memory)\n if (this.chain.length > 1000) {\n this.chain = this.chain.slice(-500);\n }\n\n this.config.onPulse(newBeats, this.totalBeats);\n this.log(`Pulse: ${n} beats in ${elapsed}ms (${(elapsed / n).toFixed(1)}ms/beat, D=${this.difficulty})`);\n\n return newBeats;\n }\n\n // ── CHECK-IN ──\n\n /**\n * Submit a Beat proof to the registry.\n * \n * \"To remain on the Whitelist, an agent must periodically \n * submit a proof of its Local Beats to the Registry.\"\n */\n async checkin(): Promise<{ ok: boolean; total_beats?: number; error?: string }> {\n if (!this.latestBeat || this.totalBeats === this.lastCheckinBeat) {\n return { ok: true, total_beats: this.totalBeats }; // Nothing new to report\n }\n\n try {\n // Build spot checks from our local chain\n // prev and nonce are required for the server to recompute VDF\n const spotChecks: { index: number; hash: string; prev: string; nonce?: string }[] = [];\n const available = this.chain.filter(b => b.index > this.lastCheckinBeat);\n const sampleCount = Math.min(5, available.length);\n\n for (let i = 0; i < sampleCount; i++) {\n const idx = Math.floor(Math.random() * available.length);\n const beat = available[idx];\n spotChecks.push({ index: beat.index, hash: beat.hash, prev: beat.prev, nonce: beat.nonce });\n available.splice(idx, 1);\n }\n\n // Find the boundary hashes\n const fromBeat = this.lastCheckinBeat;\n const toBeat = this.latestBeat.index;\n const fromHash = this.chain.find(b => b.index === fromBeat)?.hash \n || this.genesisHash;\n const toHash = this.latestBeat.hash;\n\n const res = await this.api('POST', '/api/v1/agent/checkin', {\n proof: {\n from_beat: fromBeat,\n to_beat: toBeat,\n from_hash: fromHash,\n to_hash: toHash,\n beats_computed: toBeat - fromBeat,\n global_anchor: this.globalBeat,\n spot_checks: spotChecks,\n },\n });\n\n if (res.ok) {\n this.lastCheckinBeat = toBeat;\n this.totalBeats = res.total_beats;\n this.config.onCheckin(res);\n this.log(`Check-in accepted: ${res.beats_accepted} beats, total=${res.total_beats}, global=${res.global_beat}`);\n \n if (res.status === 'warning_overdue') {\n this.config.onStatusChange('warning', { beats_behind: res.beats_behind });\n this.log(`⚠ WARNING: ${res.beats_behind} anchors behind. Check in more frequently.`);\n }\n }\n\n return { ok: res.ok, total_beats: res.total_beats };\n\n } catch (err: any) {\n this.config.onError(err, 'checkin');\n return { ok: false, error: err.message };\n }\n }\n\n // ── AUTONOMOUS HEARTBEAT ──\n\n /**\n * Start the autonomous heartbeat loop.\n * Computes beats continuously and checks in periodically.\n * This is \"keeping the agent alive\" in Beat time.\n */\n startHeartbeat(): void {\n if (this.heartbeatInterval) {\n this.log('Heartbeat already running.');\n return;\n }\n\n if (this.status !== 'active') {\n throw new Error(`Cannot start heartbeat in status '${this.status}'.`);\n }\n\n this.log('♡ Starting heartbeat...');\n\n this.heartbeatInterval = setInterval(async () => {\n try {\n // Compute a pulse\n this.pulse();\n \n // Check if it's time to report\n const beatsSinceCheckin = this.latestBeat!.index - this.lastCheckinBeat;\n const shouldCheckin = beatsSinceCheckin >= this.config.beatsPerPulse * 5;\n\n if (shouldCheckin) {\n await this.checkin();\n await this.syncGlobal(); // Stay synced with global time\n }\n } catch (err: any) {\n this.config.onError(err, 'heartbeat');\n }\n }, this.config.checkinIntervalSec * 1000 / 10); // pulse 10x per check-in interval\n }\n\n /**\n * Stop the heartbeat. Agent's time \"freezes.\"\n * Must call resync() when waking up.\n */\n stopHeartbeat(): void {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = null;\n this.log('♡ Heartbeat stopped. Time frozen.');\n }\n }\n\n // ── RE-SYNC ──\n\n /**\n * Re-sync after being offline/frozen.\n * \n * \"When an agent powers down, its time 'freezes.' Upon waking,\n * it must perform a Re-Sync Challenge with the Registry to \n * fill the 'Temporal Gap' and re-establish its provenance.\"\n */\n async resync(): Promise<{ ok: boolean; beats_required?: number; error?: string }> {\n try {\n this.log('Requesting re-sync challenge...');\n\n // Phase 1: Get challenge\n const challenge = await this.api('POST', '/api/v1/agent/resync', {\n action: 'challenge',\n });\n\n if (!challenge.challenge) {\n return { ok: false, error: 'Failed to get challenge' };\n }\n\n const required = challenge.challenge.required_beats;\n this.difficulty = challenge.challenge.difficulty;\n this.log(`Re-sync challenge: compute ${required} beats at D=${this.difficulty}`);\n\n // Compute the required beats\n const startHash = challenge.challenge.start_from_hash;\n const startBeat = challenge.challenge.start_from_beat;\n \n // Reset chain from the known point\n this.latestBeat = { index: startBeat, hash: startHash, prev: '', timestamp: Date.now() };\n this.chain = [this.latestBeat];\n \n const t0 = Date.now();\n this.pulse(required);\n const elapsed = Date.now() - t0;\n this.log(`Re-sync beats computed in ${elapsed}ms`);\n\n // Phase 2: Submit proof\n const proof = await this.api('POST', '/api/v1/agent/resync', {\n action: 'prove',\n proof: {\n from_beat: startBeat,\n to_beat: this.latestBeat!.index,\n from_hash: startHash,\n to_hash: this.latestBeat!.hash,\n beats_computed: required,\n global_anchor: challenge.challenge.sync_to_global,\n spot_checks: this.chain\n .filter((_, i) => i % Math.ceil(required / 5) === 0)\n .slice(0, 5)\n .map(b => ({ index: b.index, hash: b.hash, prev: b.prev, nonce: b.nonce })),\n },\n });\n\n if (proof.ok) {\n this.status = 'active';\n this.totalBeats = proof.total_beats;\n this.lastCheckinBeat = this.latestBeat!.index;\n this.config.onStatusChange('active', { resynced: true });\n this.log('✓ Re-synced. Agent is alive again in Beat time.');\n }\n\n return { ok: proof.ok, beats_required: required };\n\n } catch (err: any) {\n this.config.onError(err, 'resync');\n return { ok: false, error: err.message };\n }\n }\n\n // ── SPAWN ──\n\n /**\n * Request to spawn a child agent.\n * Requires sufficient accumulated beats (Temporal Gestation).\n */\n async requestSpawn(childName?: string, childHash?: string): Promise<any> {\n try {\n const res = await this.api('POST', '/api/v1/agent/spawn', {\n child_name: childName,\n child_hash: childHash,\n });\n\n if (res.eligible === false) {\n this.log(`Gestation incomplete: ${res.progress_pct}% (need ${res.deficit} more beats)`);\n } else if (res.ok) {\n this.log(`Child spawned: ${res.child_hash?.slice(0, 16)}...`);\n }\n\n return res;\n } catch (err: any) {\n this.config.onError(err, 'spawn');\n throw err;\n }\n }\n\n // ── STATUS ──\n\n /**\n * Get this agent's full beat status from the registry.\n */\n async getStatus(): Promise<any> {\n try {\n // We need the agent hash, but we may not have it directly.\n // The status endpoint uses the hash from the API key verification.\n // For now, use the init endpoint which returns status.\n return await this.refreshState();\n } catch (err: any) {\n this.config.onError(err, 'status');\n throw err;\n }\n }\n\n /**\n * Get local state (no network call).\n */\n getLocalState(): {\n status: string;\n totalBeats: number;\n latestBeat: number;\n latestHash: string;\n difficulty: number;\n globalBeat: number;\n chainLength: number;\n } {\n return {\n status: this.status,\n totalBeats: this.totalBeats,\n latestBeat: this.latestBeat?.index || 0,\n latestHash: this.latestBeat?.hash.slice(0, 24) + '...' || '',\n difficulty: this.difficulty,\n globalBeat: this.globalBeat,\n chainLength: this.chain.length,\n };\n }\n\n // ── INTERNALS ──\n\n private async syncGlobal(): Promise<void> {\n try {\n const res = await fetch(`${this.config.registryUrl}/api/v1/beat/anchor`);\n const data: any = await res.json();\n if (data.anchor) {\n this.globalBeat = data.anchor.beat_index;\n if (data.anchor.difficulty) this.difficulty = data.anchor.difficulty;\n this.log(`Synced to global beat ${this.globalBeat} (D=${this.difficulty})`);\n }\n } catch {\n this.log('Failed to sync global anchor (offline mode continues)');\n }\n }\n\n private async refreshState(): Promise<any> {\n const res = await this.api('POST', '/api/v1/agent/init');\n if (res.already_initialized) {\n this.totalBeats = res.total_beats;\n this.genesisHash = res.genesis_hash;\n this.status = res.status as any;\n }\n return res;\n }\n\n private async api(method: string, path: string, body?: any): Promise<any> {\n const res = await fetch(`${this.config.registryUrl}${path}`, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.config.apiKey}`,\n },\n body: body ? JSON.stringify(body) : undefined,\n });\n\n const data: any = await res.json();\n\n if (!res.ok && !data.ok && !data.already_initialized && !data.eligible) {\n throw new Error(data.error || `API ${res.status}: ${res.statusText}`);\n }\n\n return data;\n }\n\n private log(msg: string): void {\n if (this.config.verbose) {\n console.log(`[Beat] ${msg}`);\n }\n }\n}\n\n// ============ STANDALONE VDF HELPER ============\n// For agents that want to compute beats without the full SDK\n\nexport { computeBeat };\n\n/**\n * Compute N sequential VDF beats.\n * Returns only the last beat (for lightweight usage).\n */\nexport function computeBeatsLite(\n startHash: string, \n startIndex: number, \n count: number, \n difficulty: number = 1000\n): { lastBeat: Beat; elapsed: number } {\n const t0 = Date.now();\n let prev = startHash;\n let lastBeat: Beat | null = null;\n\n for (let i = 0; i < count; i++) {\n lastBeat = computeBeat(prev, startIndex + i, difficulty);\n prev = lastBeat.hash;\n }\n\n return { lastBeat: lastBeat!, elapsed: Date.now() - t0 };\n}\n"],"mappings":"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","names":[]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/beat-sdk.ts"],"sourcesContent":["export { BeatAgent, computeBeat, computeBeatsLite, register, generateWalletKeypair } from './beat-sdk';\nexport type { BeatAgentConfig, Beat, CheckinResult, SpawnResult, AgentStatus, RegistrationResult, WalletInfo } from './beat-sdk';\n","/**\n * ═══════════════════════════════════════════════════════════\n * PROVENONCE BEAT SDK — Agent Heartbeat Client\n * ═══════════════════════════════════════════════════════════\n * \n * \"NIST tells you what time it is.\n * Provenonce tells the agent at what speed it is allowed to exist.\"\n * \n * Usage:\n * \n * import { BeatAgent } from './beat-sdk';\n * \n * const agent = new BeatAgent({\n * apiKey: 'pvn_...',\n * registryUrl: 'https://provenonce.io',\n * });\n * \n * await agent.init(); // Birth in Beat time\n * await agent.pulse(50); // Compute 50 beats\n * await agent.checkin(); // Report to registry\n * \n * // Or run the autonomous heartbeat:\n * agent.startHeartbeat(); // Computes + checks in continuously\n * // ... do your agent work ...\n * agent.stopHeartbeat();\n * \n * ═══════════════════════════════════════════════════════════\n */\n\nimport { createHash, generateKeyPairSync, sign, createPrivateKey } from 'crypto';\n\n// ============ VDF ENGINE (LOCAL) ============\n\nexport interface Beat {\n index: number;\n hash: string;\n prev: string;\n timestamp: number;\n nonce?: string;\n anchor_hash?: string;\n}\n\nfunction computeBeat(prevHash: string, beatIndex: number, difficulty: number, nonce?: string, anchorHash?: string): Beat {\n const timestamp = Date.now();\n\n const seed = anchorHash\n ? `${prevHash}:${beatIndex}:${nonce || ''}:${anchorHash}`\n : `${prevHash}:${beatIndex}:${nonce || ''}`;\n\n let current = createHash('sha256')\n .update(seed)\n .digest('hex');\n\n for (let i = 0; i < difficulty; i++) {\n current = createHash('sha256')\n .update(current)\n .digest('hex');\n }\n\n return { index: beatIndex, hash: current, prev: prevHash, timestamp, nonce, anchor_hash: anchorHash };\n}\n\n// ============ SDK RESULT TYPES ============\n\n/** Result from a check-in submission */\nexport interface CheckinResult {\n ok: boolean;\n total_beats: number;\n beats_accepted: number;\n global_beat: number;\n status?: string;\n beats_behind?: number;\n}\n\n/** Result from a spawn request */\nexport interface SpawnResult {\n ok: boolean;\n eligible: boolean;\n child_hash?: string;\n progress_pct?: number;\n deficit?: number;\n}\n\n/** Agent status from the registry */\nexport interface AgentStatus {\n already_initialized: boolean;\n total_beats: number;\n genesis_hash: string;\n status: string;\n genesis?: { hash: string; prev: string; timestamp: number };\n difficulty?: number;\n}\n\n// ============ WALLET KEYPAIR GENERATION ============\n\n// DER prefix for Ed25519 PKCS8 private keys (16 bytes)\nconst ED25519_PKCS8_PREFIX = Buffer.from('302e020100300506032b657004220420', 'hex');\n\n/**\n * Generate an Ed25519 keypair for agent wallet identity.\n * Returns hex-encoded raw keys (32 bytes each).\n * Uses Node.js built-in crypto — zero external dependencies.\n */\nexport function generateWalletKeypair(): { publicKey: string; secretKey: string } {\n const { publicKey, privateKey } = generateKeyPairSync('ed25519');\n const pubRaw = publicKey.export({ type: 'spki', format: 'der' }).subarray(12); // 32 bytes\n const privRaw = privateKey.export({ type: 'pkcs8', format: 'der' }).subarray(16); // 32 bytes\n return {\n publicKey: Buffer.from(pubRaw).toString('hex'),\n secretKey: Buffer.from(privRaw).toString('hex'),\n };\n}\n\n/**\n * Sign a message with an Ed25519 private key (hex-encoded 32-byte seed).\n * Returns hex-encoded signature (64 bytes).\n */\nfunction signMessage(secretKeyHex: string, message: string): string {\n const privRaw = Buffer.from(secretKeyHex, 'hex');\n const privKeyDer = Buffer.concat([ED25519_PKCS8_PREFIX, privRaw]);\n const keyObject = createPrivateKey({ key: privKeyDer, format: 'der', type: 'pkcs8' });\n const sig = sign(null, Buffer.from(message), keyObject);\n return Buffer.from(sig).toString('hex');\n}\n\n// ============ REGISTRATION ============\n\n/** Wallet info returned from root registration */\nexport interface WalletInfo {\n /** Hex-encoded 32-byte Ed25519 public key (Solana self-custody only, empty otherwise) */\n public_key: string;\n /** Hex-encoded 32-byte Ed25519 secret seed — SAVE THIS for future fee signing (Solana self-custody only) */\n secret_key: string;\n /** Solana-compatible base58 address (Solana wallets only) */\n solana_address?: string;\n /** The wallet address (base58 for Solana, 0x for Ethereum) */\n address: string;\n /** Wallet chain: 'solana' or 'ethereum' */\n chain: string;\n}\n\n/** Result from registering an agent */\nexport interface RegistrationResult {\n hash: string;\n api_key: string;\n secret: string;\n type: 'root' | 'agent';\n parent: string | null;\n depth: number;\n name: string;\n metadata?: Record<string, unknown> | null;\n signature: string;\n explorer_url?: string;\n /** Wallet chain: 'solana', 'ethereum', or null (no wallet) */\n wallet_chain?: string | null;\n beat?: { genesis_hash: string; difficulty: number; status: string };\n /** Wallet info — only present for root agents with wallets */\n wallet?: WalletInfo;\n}\n\n/**\n * Register a new agent on the Provenonce registry.\n *\n * No wallet (default, single-phase):\n * const creds = await register('my-agent', { registryUrl: '...' });\n *\n * Solana self-custody wallet (Model A, two-phase):\n * const creds = await register('my-org', {\n * registryUrl: '...',\n * walletModel: 'self-custody',\n * });\n * // creds.wallet.secret_key = hex secret (SAVE THIS)\n * // creds.wallet.address = base58 Solana address\n *\n * Solana with existing key:\n * const creds = await register('my-org', {\n * registryUrl: '...',\n * walletSecretKey: '<hex-encoded-32-byte-seed>',\n * });\n *\n * Ethereum bring-your-own (two-phase):\n * const creds = await register('my-org', {\n * registryUrl: '...',\n * walletChain: 'ethereum',\n * walletAddress: '0x...',\n * walletSignFn: (msg) => wallet.signMessage(msg),\n * });\n *\n * Solana operator (Model B, two-phase):\n * const creds = await register('my-org', {\n * registryUrl: '...',\n * walletModel: 'operator',\n * operatorWalletAddress: '<base58>',\n * operatorSignFn: (msg) => signWithWallet(msg),\n * });\n *\n * Child agent (no wallet):\n * const creds = await register('worker-1', {\n * registryUrl: '...',\n * parentHash: parentCreds.hash,\n * parentApiKey: parentCreds.api_key,\n * });\n */\nexport async function register(\n name: string,\n options?: {\n registryUrl?: string;\n parentHash?: string;\n parentApiKey?: string;\n registrationSecret?: string;\n /** Hex-encoded 32-byte Ed25519 secret seed (bring-your-own Solana key) */\n walletSecretKey?: string;\n /** Wallet model: 'self-custody' (Model A) or 'operator' (Model B). Must be set explicitly to opt in. */\n walletModel?: 'self-custody' | 'operator';\n /** Wallet chain: 'solana' (default when wallet is used) or 'ethereum' (D-63) */\n walletChain?: 'solana' | 'ethereum';\n /** Wallet address for Ethereum bring-your-own (0x + 40 hex chars) */\n walletAddress?: string;\n /** Async function to sign a message with an Ethereum wallet (EIP-191 personal_sign). Returns 0x-prefixed 65-byte hex sig. */\n walletSignFn?: (message: string) => Promise<string>;\n /** Operator's Solana wallet address (base58). Required when walletModel='operator'. */\n operatorWalletAddress?: string;\n /** Function to sign a message with the operator's Solana wallet. Required when walletModel='operator'. */\n operatorSignFn?: (message: string) => Promise<string>;\n /** Optional agent metadata (arbitrary JSON object, max 4KB). Returned in /verify and /status. */\n metadata?: Record<string, unknown>;\n },\n): Promise<RegistrationResult> {\n // SDK-P1-07/P1-08: validate inputs\n if (!name || typeof name !== 'string' || name.trim().length === 0) {\n throw new Error('name is required (must be a non-empty string)');\n }\n if (name.length > 64) {\n throw new Error('name must be 64 characters or fewer');\n }\n\n const url = options?.registryUrl || 'https://provenonce.io';\n try {\n new URL(url);\n } catch {\n throw new Error('registryUrl is not a valid URL');\n }\n\n const headers: Record<string, string> = { 'Content-Type': 'application/json' };\n\n if (options?.registrationSecret) {\n headers['x-registration-secret'] = options.registrationSecret;\n }\n\n // ===== CHILD REGISTRATION (no wallet, single-phase) =====\n if (options?.parentHash) {\n if (options.parentApiKey) {\n headers['Authorization'] = `Bearer ${options.parentApiKey}`;\n }\n\n const res = await fetch(`${url}/api/v1/register`, {\n method: 'POST',\n headers,\n body: JSON.stringify({ name, parent: options.parentHash, ...(options.metadata && { metadata: options.metadata }) }),\n });\n\n let data: RegistrationResult & { error?: string };\n try {\n data = await res.json() as RegistrationResult & { error?: string };\n } catch {\n throw new Error(`Registration failed: ${res.status} ${res.statusText} (non-JSON response)`);\n }\n if (!res.ok) throw new Error(data.error || 'Registration failed');\n return data;\n }\n\n // ===== ETHEREUM BRING-YOUR-OWN (D-63, two-phase) =====\n if (options?.walletChain === 'ethereum') {\n if (!options.walletAddress || !options.walletSignFn) {\n throw new Error('Ethereum registration requires walletAddress and walletSignFn');\n }\n\n if (!/^0x[0-9a-fA-F]{40}$/.test(options.walletAddress)) {\n throw new Error('walletAddress must be a valid Ethereum address (0x + 40 hex chars)');\n }\n\n // Phase 1: Get challenge nonce from server\n const challengeRes = await fetch(`${url}/api/v1/register`, {\n method: 'POST',\n headers,\n body: JSON.stringify({ name, action: 'challenge', wallet_chain: 'ethereum' }),\n });\n\n let challengeData: { nonce?: string; error?: string };\n try {\n challengeData = await challengeRes.json() as { nonce?: string; error?: string };\n } catch {\n throw new Error(`Registration challenge failed: ${challengeRes.status} (non-JSON response)`);\n }\n if (!challengeRes.ok || !challengeData.nonce) {\n throw new Error(challengeData.error || 'Failed to get registration challenge');\n }\n\n // Phase 2: Sign with Ethereum wallet (EIP-191 personal_sign)\n const nonce = challengeData.nonce;\n const message = `provenonce-register-ethereum:${nonce}:${options.walletAddress}:${name}`;\n const walletSignature = await options.walletSignFn(message);\n\n const registerRes = await fetch(`${url}/api/v1/register`, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n name,\n wallet_chain: 'ethereum',\n wallet_address: options.walletAddress,\n wallet_signature: walletSignature,\n wallet_nonce: nonce,\n ...(options.metadata && { metadata: options.metadata }),\n }),\n });\n\n let data: RegistrationResult & { error?: string; wallet?: { address?: string; chain?: string } };\n try {\n data = await registerRes.json() as RegistrationResult & { error?: string; wallet?: { address?: string; chain?: string } };\n } catch {\n throw new Error(`Ethereum registration failed: ${registerRes.status} (non-JSON response)`);\n }\n if (!registerRes.ok) throw new Error(data.error || 'Registration failed');\n\n // Ethereum: wallet has address only (no keypair — user keeps custody externally)\n data.wallet = {\n public_key: '',\n secret_key: '',\n address: data.wallet?.address || options.walletAddress,\n chain: 'ethereum',\n };\n\n return data;\n }\n\n // ===== MODEL B: SOLANA OPERATOR WALLET REGISTRATION (two-phase) =====\n if (options?.walletModel === 'operator') {\n if (!options.operatorWalletAddress || !options.operatorSignFn) {\n throw new Error('Operator registration requires operatorWalletAddress and operatorSignFn');\n }\n\n // Phase 1: Get challenge nonce from server\n const challengeRes = await fetch(`${url}/api/v1/register`, {\n method: 'POST',\n headers,\n body: JSON.stringify({ name, action: 'challenge', wallet_model: 'operator' }),\n });\n\n let challengeData: { nonce?: string; error?: string };\n try {\n challengeData = await challengeRes.json() as { nonce?: string; error?: string };\n } catch {\n throw new Error(`Registration challenge failed: ${challengeRes.status} (non-JSON response)`);\n }\n if (!challengeRes.ok || !challengeData.nonce) {\n throw new Error(challengeData.error || 'Failed to get registration challenge');\n }\n\n // Phase 2: Operator signs challenge and register\n const nonce = challengeData.nonce;\n const message = `provenonce-register-operator:${nonce}:${options.operatorWalletAddress}:${name}`;\n const walletSignature = await options.operatorSignFn(message);\n\n const registerRes = await fetch(`${url}/api/v1/register`, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n name,\n wallet_model: 'operator',\n operator_wallet_address: options.operatorWalletAddress,\n wallet_signature: walletSignature,\n wallet_nonce: nonce,\n ...(options.metadata && { metadata: options.metadata }),\n }),\n });\n\n let data: RegistrationResult & { error?: string; wallet?: { address?: string; solana_address?: string } };\n try {\n data = await registerRes.json() as RegistrationResult & { error?: string; wallet?: { address?: string; solana_address?: string } };\n } catch {\n throw new Error(`Operator registration failed: ${registerRes.status} (non-JSON response)`);\n }\n if (!registerRes.ok) throw new Error(data.error || 'Registration failed');\n\n // Model B: wallet has address only (no secret_key/public_key — operator keeps custody)\n const addr = data.wallet?.address || data.wallet?.solana_address || options.operatorWalletAddress;\n data.wallet = {\n public_key: '',\n secret_key: '',\n solana_address: addr,\n address: addr,\n chain: 'solana',\n };\n\n return data;\n }\n\n // ===== MODEL A: SOLANA SELF-CUSTODY WALLET REGISTRATION (opt-in, two-phase) =====\n if (options?.walletModel === 'self-custody' || options?.walletSecretKey) {\n // Generate or use provided wallet keypair\n let walletKeys: { publicKey: string; secretKey: string };\n if (options?.walletSecretKey) {\n // Derive public key from provided secret\n const privRaw = Buffer.from(options.walletSecretKey, 'hex');\n const privKeyDer = Buffer.concat([ED25519_PKCS8_PREFIX, privRaw]);\n const keyObject = createPrivateKey({ key: privKeyDer, format: 'der', type: 'pkcs8' });\n const pubRaw = keyObject.export({ type: 'spki', format: 'der' }).subarray(12);\n walletKeys = {\n publicKey: Buffer.from(pubRaw).toString('hex'),\n secretKey: options.walletSecretKey,\n };\n } else {\n walletKeys = generateWalletKeypair();\n }\n\n // Phase 1: Get challenge nonce from server\n const challengeRes = await fetch(`${url}/api/v1/register`, {\n method: 'POST',\n headers,\n body: JSON.stringify({ name, action: 'challenge' }),\n });\n\n let challengeData: { nonce?: string; error?: string };\n try {\n challengeData = await challengeRes.json() as { nonce?: string; error?: string };\n } catch {\n throw new Error(`Registration challenge failed: ${challengeRes.status} (non-JSON response)`);\n }\n if (!challengeRes.ok || !challengeData.nonce) {\n // Attach wallet keys so caller can retry with the same keypair\n const err = new Error(challengeData.error || 'Failed to get registration challenge');\n (err as any).walletKeys = { publicKey: walletKeys.publicKey, secretKey: walletKeys.secretKey };\n throw err;\n }\n\n // Phase 2: Sign challenge and register\n const nonce = challengeData.nonce;\n const message = `provenonce-register:${nonce}:${walletKeys.publicKey}:${name}`;\n const walletSignature = signMessage(walletKeys.secretKey, message);\n\n const registerRes = await fetch(`${url}/api/v1/register`, {\n method: 'POST',\n headers,\n body: JSON.stringify({\n name,\n wallet_public_key: walletKeys.publicKey,\n wallet_signature: walletSignature,\n wallet_nonce: nonce,\n ...(options?.metadata && { metadata: options.metadata }),\n }),\n });\n\n let data: RegistrationResult & { error?: string; wallet?: { address?: string; solana_address?: string } };\n try {\n data = await registerRes.json() as RegistrationResult & { error?: string; wallet?: { address?: string; solana_address?: string } };\n } catch {\n // Attach wallet keys so caller can retry with the same keypair\n const err = new Error(`Registration failed: ${registerRes.status} (non-JSON response)`);\n (err as any).walletKeys = { publicKey: walletKeys.publicKey, secretKey: walletKeys.secretKey };\n throw err;\n }\n if (!registerRes.ok) {\n // Attach wallet keys so caller can retry with the same keypair via walletSecretKey option\n const err = new Error(data.error || 'Registration failed');\n (err as any).walletKeys = { publicKey: walletKeys.publicKey, secretKey: walletKeys.secretKey };\n throw err;\n }\n\n // Attach the wallet keys (secret is client-side only, never sent to server)\n const addr = data.wallet?.address || data.wallet?.solana_address || '';\n data.wallet = {\n public_key: walletKeys.publicKey,\n secret_key: walletKeys.secretKey,\n solana_address: addr,\n address: addr,\n chain: 'solana',\n };\n\n return data;\n }\n\n // ===== NO-WALLET REGISTRATION (D-62 default, single-phase) =====\n\n const res = await fetch(`${url}/api/v1/register`, {\n method: 'POST',\n headers,\n body: JSON.stringify({ name, ...(options?.metadata && { metadata: options.metadata }) }),\n });\n\n let data: RegistrationResult & { error?: string };\n try {\n data = await res.json() as RegistrationResult & { error?: string };\n } catch {\n throw new Error(`Registration failed: ${res.status} ${res.statusText} (non-JSON response)`);\n }\n if (!res.ok) throw new Error(data.error || 'Registration failed');\n return data;\n}\n\n// ============ SDK CONFIG ============\n\nexport interface BeatAgentConfig {\n /** API key from registration (pvn_...) */\n apiKey: string;\n \n /** Provenonce registry URL */\n registryUrl: string;\n \n /** Beats to compute per pulse (default: 10) */\n beatsPerPulse?: number;\n \n /** Seconds between automatic check-ins (default: 300 = 5min) */\n checkinIntervalSec?: number;\n \n /** Callback when heartbeat ticks */\n onPulse?: (beats: Beat[], totalBeats: number) => void;\n \n /** Callback when check-in completes */\n onCheckin?: (result: CheckinResult) => void;\n\n /** Callback on error */\n onError?: (error: Error, context: string) => void;\n\n /** Callback when status changes */\n onStatusChange?: (status: string, details: Record<string, unknown>) => void;\n \n /** Enable verbose logging */\n verbose?: boolean;\n}\n\n// ============ BEAT AGENT ============\n\nexport class BeatAgent {\n private config: Required<BeatAgentConfig>;\n private chain: Beat[] = [];\n private difficulty: number = 1000;\n private genesisHash: string = '';\n private latestBeat: Beat | null = null;\n private totalBeats: number = 0;\n private lastCheckinBeat: number = 0;\n private status: 'uninitialized' | 'active' | 'frozen' | 'revoked' = 'uninitialized';\n private heartbeatInterval: ReturnType<typeof setInterval> | null = null;\n private globalBeat: number = 0;\n private globalAnchorHash: string = '';\n\n constructor(config: BeatAgentConfig) {\n // SDK-P1-08: validate required config fields\n if (!config.apiKey || typeof config.apiKey !== 'string') {\n throw new Error('BeatAgentConfig.apiKey is required (must be a non-empty string)');\n }\n if (!config.registryUrl || typeof config.registryUrl !== 'string') {\n throw new Error('BeatAgentConfig.registryUrl is required (must be a non-empty string)');\n }\n // SDK-P1-07: validate registryUrl is a valid URL\n try {\n new URL(config.registryUrl);\n } catch {\n throw new Error('BeatAgentConfig.registryUrl is not a valid URL');\n }\n\n // SDK-P2: validate optional numeric config\n if (config.beatsPerPulse !== undefined && (!Number.isInteger(config.beatsPerPulse) || config.beatsPerPulse < 1 || config.beatsPerPulse > 10000)) {\n throw new Error('BeatAgentConfig.beatsPerPulse must be an integer between 1 and 10000');\n }\n if (config.checkinIntervalSec !== undefined && (!Number.isFinite(config.checkinIntervalSec) || config.checkinIntervalSec < 10 || config.checkinIntervalSec > 86400)) {\n throw new Error('BeatAgentConfig.checkinIntervalSec must be between 10 and 86400');\n }\n\n this.config = {\n beatsPerPulse: 10,\n checkinIntervalSec: 300,\n onPulse: () => {},\n onCheckin: () => {},\n onError: () => {},\n onStatusChange: () => {},\n verbose: false,\n ...config,\n };\n }\n\n // ── INITIALIZATION ──\n\n /**\n * Initialize the agent's Beat chain.\n * This is the agent's \"birth\" in Logical Time.\n * Must be called once before computing beats.\n */\n async init(): Promise<{ ok: boolean; genesis?: string; error?: string }> {\n try {\n this.log('Initializing Beat chain...');\n\n const res = await this.api('POST', '/api/v1/agent/init');\n\n if (res.genesis) {\n this.genesisHash = res.genesis.hash;\n this.difficulty = res.difficulty || 1000;\n this.latestBeat = {\n index: 0,\n hash: res.genesis.hash,\n prev: res.genesis.prev,\n timestamp: res.genesis.timestamp,\n };\n this.chain = [this.latestBeat];\n this.totalBeats = 0;\n this.status = 'active';\n this.config.onStatusChange('active', { genesis: this.genesisHash });\n this.log(`Born in Beat time. Genesis: ${this.genesisHash.slice(0, 16)}...`);\n } else if (res.already_initialized) {\n // Restore from existing state\n this.genesisHash = res.genesis_hash;\n this.totalBeats = res.total_beats;\n this.status = res.status as any;\n this.log(`Already initialized. Restoring state (${res.total_beats} beats).`);\n \n // Fetch full state to get latest hash\n await this.refreshState();\n }\n\n // Sync global anchor\n await this.syncGlobal();\n\n return { ok: true, genesis: this.genesisHash };\n\n } catch (err: any) {\n this.config.onError(err, 'init');\n return { ok: false, error: err.message };\n }\n }\n\n // ── PULSE (COMPUTE BEATS) ──\n\n /**\n * Compute N beats locally (VDF hash chain).\n * This is the \"heartbeat\" — proof that the agent has lived \n * through a specific window of computational time.\n */\n pulse(count?: number): Beat[] {\n if (this.status !== 'active') {\n throw new Error(`Cannot pulse: agent is ${this.status}. Use resync() if frozen.`);\n }\n // SDK-P2: validate count param\n if (count !== undefined && (!Number.isInteger(count) || count < 1 || count > 10000)) {\n throw new Error('pulse count must be an integer between 1 and 10000');\n }\n return this.computeBeats(count);\n }\n\n /** Internal beat computation — no status check. Used by both pulse() and resync(). */\n private computeBeats(count?: number, onProgress?: (computed: number, total: number) => void): Beat[] {\n const n = count || this.config.beatsPerPulse;\n\n if (!this.latestBeat) {\n throw new Error('Beat chain not initialized. Call init() first.');\n }\n\n const newBeats: Beat[] = [];\n let prevHash = this.latestBeat.hash;\n let startIndex = this.latestBeat.index + 1;\n\n const t0 = Date.now();\n // SDK-P2: report progress every 10% of beats\n const progressInterval = Math.max(1, Math.floor(n / 10));\n\n for (let i = 0; i < n; i++) {\n const beat = computeBeat(prevHash, startIndex + i, this.difficulty, undefined, this.globalAnchorHash || undefined);\n newBeats.push(beat);\n prevHash = beat.hash;\n if (onProgress && (i + 1) % progressInterval === 0) {\n onProgress(i + 1, n);\n }\n }\n\n const elapsed = Date.now() - t0;\n\n // Update state\n this.chain.push(...newBeats);\n this.latestBeat = newBeats[newBeats.length - 1];\n this.totalBeats += n;\n\n // Keep chain bounded (only last 1000 beats in memory)\n if (this.chain.length > 1000) {\n this.chain = this.chain.slice(-500);\n }\n\n this.config.onPulse(newBeats, this.totalBeats);\n this.log(`Pulse: ${n} beats in ${elapsed}ms (${(elapsed / n).toFixed(1)}ms/beat, D=${this.difficulty})`);\n\n return newBeats;\n }\n\n // ── CHECK-IN ──\n\n /**\n * Submit a Beat proof to the registry.\n * \n * \"To remain on the Whitelist, an agent must periodically \n * submit a proof of its Local Beats to the Registry.\"\n */\n async checkin(): Promise<{ ok: boolean; total_beats?: number; error?: string }> {\n // SDK-P1-02: fix guard to compare beat indices, not totalBeats vs lastCheckinBeat\n if (!this.latestBeat || this.latestBeat.index <= this.lastCheckinBeat) {\n this.log('No new beats since last check-in. Call pulse() first.');\n return { ok: true, total_beats: this.totalBeats }; // Nothing new to report\n }\n\n try {\n // Find the boundary hashes\n const fromBeat = this.lastCheckinBeat;\n const toBeat = this.latestBeat.index;\n\n // Build spot checks from our local chain\n // prev and nonce are required for the server to recompute VDF\n // Must always include to_beat (final beat) — server requires it for final hash verification\n const spotChecks: { index: number; hash: string; prev: string; nonce?: string }[] = [];\n\n // Always include the final beat\n const toBeatEntry = this.chain.find(b => b.index === toBeat);\n if (toBeatEntry) {\n spotChecks.push({ index: toBeatEntry.index, hash: toBeatEntry.hash, prev: toBeatEntry.prev, nonce: toBeatEntry.nonce });\n }\n\n // Sample up to 4 more from the rest\n const available = this.chain.filter(b => b.index > this.lastCheckinBeat && b.index !== toBeat);\n const sampleCount = Math.min(4, available.length);\n\n for (let i = 0; i < sampleCount; i++) {\n const idx = Math.floor(Math.random() * available.length);\n const beat = available[idx];\n spotChecks.push({ index: beat.index, hash: beat.hash, prev: beat.prev, nonce: beat.nonce });\n available.splice(idx, 1);\n }\n const fromHash = this.chain.find(b => b.index === fromBeat)?.hash \n || this.genesisHash;\n const toHash = this.latestBeat.hash;\n\n const res = await this.api('POST', '/api/v1/agent/checkin', {\n proof: {\n from_beat: fromBeat,\n to_beat: toBeat,\n from_hash: fromHash,\n to_hash: toHash,\n beats_computed: toBeat - fromBeat,\n global_anchor: this.globalBeat,\n anchor_hash: this.globalAnchorHash || undefined,\n spot_checks: spotChecks,\n },\n });\n\n if (res.ok) {\n this.lastCheckinBeat = toBeat;\n this.totalBeats = res.total_beats;\n this.config.onCheckin(res);\n this.log(`Check-in accepted: ${res.beats_accepted} beats, total=${res.total_beats}, global=${res.global_beat}`);\n \n if (res.status === 'warning_overdue') {\n this.config.onStatusChange('warning', { beats_behind: res.beats_behind });\n this.log(`⚠ WARNING: ${res.beats_behind} anchors behind. Check in more frequently.`);\n }\n }\n\n return { ok: res.ok, total_beats: res.total_beats };\n\n } catch (err: any) {\n this.config.onError(err, 'checkin');\n return { ok: false, error: err.message };\n }\n }\n\n // ── AUTONOMOUS HEARTBEAT ──\n\n /**\n * Start the autonomous heartbeat loop.\n * Computes beats continuously and checks in periodically.\n * This is \"keeping the agent alive\" in Beat time.\n */\n startHeartbeat(): void {\n if (this.heartbeatInterval) {\n this.log('Heartbeat already running.');\n return;\n }\n\n if (this.status !== 'active') {\n throw new Error(`Cannot start heartbeat in status '${this.status}'.`);\n }\n\n this.log('♡ Starting heartbeat...');\n\n // SDK-P1-03: exponential backoff on consecutive errors\n let consecutiveErrors = 0;\n let skipCount = 0;\n\n this.heartbeatInterval = setInterval(async () => {\n // Back off: skip ticks on consecutive errors\n if (skipCount > 0) {\n skipCount--;\n return;\n }\n\n try {\n // Compute a pulse\n this.pulse();\n\n // Check if it's time to report\n const beatsSinceCheckin = this.latestBeat!.index - this.lastCheckinBeat;\n const shouldCheckin = beatsSinceCheckin >= this.config.beatsPerPulse * 5;\n\n if (shouldCheckin) {\n await this.checkin();\n await this.syncGlobal(); // Stay synced with global time\n }\n consecutiveErrors = 0; // Reset on success\n } catch (err: any) {\n consecutiveErrors++;\n this.config.onError(err, 'heartbeat');\n // Exponential backoff: skip 2^(n-1) ticks, capped at 32\n skipCount = Math.min(32, Math.pow(2, consecutiveErrors - 1));\n this.log(`Heartbeat error #${consecutiveErrors}, backing off ${skipCount} ticks`);\n }\n }, this.config.checkinIntervalSec * 1000 / 10); // pulse 10x per check-in interval\n }\n\n /**\n * Stop the heartbeat. Agent's time \"freezes.\"\n * Must call resync() when waking up.\n */\n stopHeartbeat(): void {\n if (this.heartbeatInterval) {\n clearInterval(this.heartbeatInterval);\n this.heartbeatInterval = null;\n this.log('♡ Heartbeat stopped. Time frozen.');\n }\n }\n\n // ── RE-SYNC ──\n\n /**\n * Re-sync after being offline/frozen.\n * \n * \"When an agent powers down, its time 'freezes.' Upon waking,\n * it must perform a Re-Sync Challenge with the Registry to \n * fill the 'Temporal Gap' and re-establish its provenance.\"\n */\n async resync(): Promise<{ ok: boolean; beats_required?: number; error?: string }> {\n try {\n this.log('Requesting re-sync challenge...');\n\n // Phase 1: Get challenge\n const challenge = await this.api('POST', '/api/v1/agent/resync', {\n action: 'challenge',\n });\n\n if (!challenge.challenge) {\n return { ok: false, error: 'Failed to get challenge' };\n }\n\n const required = challenge.challenge.required_beats;\n this.difficulty = challenge.challenge.difficulty;\n this.log(`Re-sync challenge: compute ${required} beats at D=${this.difficulty}`);\n\n // Sync global anchor so beats are woven with a recent anchor hash\n await this.syncGlobal();\n\n // Compute the required beats\n const startHash = challenge.challenge.start_from_hash;\n const startBeat = challenge.challenge.start_from_beat;\n\n // Reset chain from the known point\n this.latestBeat = { index: startBeat, hash: startHash, prev: '', timestamp: Date.now() };\n this.chain = [this.latestBeat];\n\n const t0 = Date.now();\n this.computeBeats(required);\n const elapsed = Date.now() - t0;\n this.log(`Re-sync beats computed in ${elapsed}ms`);\n\n // Phase 2: Submit proof (include challenge_nonce for server verification)\n const proof = await this.api('POST', '/api/v1/agent/resync', {\n action: 'prove',\n challenge_nonce: challenge.challenge.nonce,\n proof: {\n from_beat: startBeat,\n to_beat: this.latestBeat!.index,\n from_hash: startHash,\n to_hash: this.latestBeat!.hash,\n beats_computed: required,\n global_anchor: challenge.challenge.sync_to_global,\n anchor_hash: this.globalAnchorHash || undefined,\n spot_checks: (() => {\n // Must include to_beat (final beat) — server requires it for final hash verification\n const toBeatEntry = this.chain.find(b => b.index === this.latestBeat!.index);\n // Sample from available chain beats (chain may be trimmed to 500 entries)\n const available = this.chain\n .filter(b => b.index !== this.latestBeat!.index && b.index > startBeat);\n const step = Math.max(1, Math.ceil(available.length / 5));\n const others = available\n .filter((_, i) => i % step === 0)\n .slice(0, 4);\n const checks = toBeatEntry ? [toBeatEntry, ...others] : others;\n return checks.map(b => ({ index: b.index, hash: b.hash, prev: b.prev, nonce: b.nonce }));\n })(),\n },\n });\n\n if (proof.ok) {\n this.status = 'active';\n this.totalBeats = proof.total_beats;\n this.lastCheckinBeat = this.latestBeat!.index;\n this.config.onStatusChange('active', { resynced: true });\n this.log('✓ Re-synced. Agent is alive again in Beat time.');\n }\n\n return { ok: proof.ok, beats_required: required };\n\n } catch (err: any) {\n this.config.onError(err, 'resync');\n return { ok: false, error: err.message };\n }\n }\n\n // ── SPAWN ──\n\n /**\n * Request to spawn a child agent.\n * Requires sufficient accumulated beats (Temporal Gestation).\n */\n async requestSpawn(childName?: string, childHash?: string): Promise<SpawnResult> {\n try {\n // SDK-P1-05: validate childName\n if (childName !== undefined) {\n if (typeof childName !== 'string' || childName.trim().length === 0) {\n throw new Error('childName must be a non-empty string');\n }\n if (childName.length > 64) {\n throw new Error('childName must be 64 characters or fewer');\n }\n }\n\n const res = await this.api('POST', '/api/v1/agent/spawn', {\n child_name: childName,\n child_hash: childHash,\n });\n\n if (res.eligible === false) {\n this.log(`Gestation incomplete: ${res.progress_pct}% (need ${res.deficit} more beats)`);\n } else if (res.ok) {\n this.log(`Child spawned: ${res.child_hash?.slice(0, 16)}...`);\n }\n\n return res;\n } catch (err: any) {\n this.config.onError(err, 'spawn');\n throw err;\n }\n }\n\n // ── STATUS ──\n\n /**\n * Get this agent's full beat status from the registry.\n */\n async getStatus(): Promise<AgentStatus> {\n try {\n // We need the agent hash, but we may not have it directly.\n // The status endpoint uses the hash from the API key verification.\n // For now, use the init endpoint which returns status.\n return await this.refreshState();\n } catch (err: any) {\n this.config.onError(err, 'status');\n throw err;\n }\n }\n\n /**\n * Get local state (no network call).\n */\n getLocalState(): {\n status: string;\n totalBeats: number;\n latestBeat: number;\n latestHash: string;\n difficulty: number;\n globalBeat: number;\n chainLength: number;\n } {\n return {\n status: this.status,\n totalBeats: this.totalBeats,\n latestBeat: this.latestBeat?.index || 0,\n latestHash: this.latestBeat?.hash.slice(0, 24) + '...' || '',\n difficulty: this.difficulty,\n globalBeat: this.globalBeat,\n chainLength: this.chain.length,\n };\n }\n\n // ── INTERNALS ──\n\n private async syncGlobal(): Promise<void> {\n try {\n // SDK-P1-01: add timeout to syncGlobal fetch\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 15_000);\n const res = await fetch(`${this.config.registryUrl}/api/v1/beat/anchor`, { signal: controller.signal });\n clearTimeout(timeout);\n const data: any = await res.json();\n if (data.anchor) {\n this.globalBeat = data.anchor.beat_index;\n this.globalAnchorHash = data.anchor.hash || '';\n if (data.anchor.difficulty) this.difficulty = data.anchor.difficulty;\n this.log(`Synced to global beat ${this.globalBeat} (D=${this.difficulty})`);\n }\n } catch {\n this.log('Failed to sync global anchor (offline mode continues)');\n }\n }\n\n private async refreshState(): Promise<any> {\n const res = await this.api('POST', '/api/v1/agent/init');\n if (res.already_initialized) {\n this.totalBeats = res.total_beats;\n this.genesisHash = res.genesis_hash;\n this.status = res.status as any;\n this.difficulty = res.difficulty || this.difficulty;\n this.lastCheckinBeat = res.last_checkin_beat || 0;\n\n // Restore latestBeat so pulse() can continue the chain\n if (!this.latestBeat && this.genesisHash) {\n this.latestBeat = {\n index: res.latest_beat || this.totalBeats,\n hash: res.latest_hash || this.genesisHash,\n prev: '0'.repeat(64),\n timestamp: Date.now(),\n };\n this.chain = [this.latestBeat];\n }\n }\n return res;\n }\n\n private async api(method: string, path: string, body?: any): Promise<any> {\n // SDK-P1-01: add 30s timeout to prevent indefinite hangs\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 30_000);\n\n try {\n const res = await fetch(`${this.config.registryUrl}${path}`, {\n method,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.config.apiKey}`,\n },\n body: body ? JSON.stringify(body) : undefined,\n signal: controller.signal,\n });\n\n let data: any;\n try {\n data = await res.json();\n } catch {\n throw new Error(`API error: ${res.status} non-JSON response from ${path}`);\n }\n\n if (!res.ok && !data.ok && !data.already_initialized && !data.eligible) {\n // SDK-P2: sanitize error — don't expose internal server details\n const serverMsg = typeof data.error === 'string' ? data.error : `API error ${res.status}`;\n throw new Error(serverMsg);\n }\n\n return data;\n } catch (err: any) {\n if (err.name === 'AbortError') {\n throw new Error(`Request timeout: ${method} ${path}`);\n }\n throw err;\n } finally {\n clearTimeout(timeout);\n }\n }\n\n private log(msg: string): void {\n if (this.config.verbose) {\n console.log(`[Beat] ${msg}`);\n }\n }\n}\n\n// ============ STANDALONE VDF HELPER ============\n// For agents that want to compute beats without the full SDK\n\nexport { computeBeat };\n\n/**\n * Compute N sequential VDF beats.\n * Returns only the last beat (for lightweight usage).\n */\nexport function computeBeatsLite(\n startHash: string,\n startIndex: number,\n count: number,\n difficulty: number = 1000,\n anchorHash?: string,\n): { lastBeat: Beat; elapsed: number } {\n // SDK-P2: validate inputs\n if (!startHash || typeof startHash !== 'string') {\n throw new Error('computeBeatsLite: startHash must be a non-empty string');\n }\n if (!Number.isInteger(count) || count < 1) {\n throw new Error('computeBeatsLite: count must be a positive integer');\n }\n\n const t0 = Date.now();\n let prev = startHash;\n let lastBeat: Beat | null = null;\n\n for (let i = 0; i < count; i++) {\n lastBeat = computeBeat(prev, startIndex + i, difficulty, undefined, anchorHash);\n prev = lastBeat.hash;\n }\n\n return { lastBeat: lastBeat!, elapsed: Date.now() - t0 };\n}\n"],"mappings":"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","names":["res","data"]}
|