@provenonce/sdk 0.12.0 → 0.14.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/dist/index.js CHANGED
@@ -33,7 +33,6 @@ __export(index_exports, {
33
33
  ValidationError: () => ValidationError,
34
34
  computeBeat: () => computeBeat,
35
35
  computeBeatsLite: () => computeBeatsLite,
36
- generateWalletKeypair: () => generateWalletKeypair,
37
36
  register: () => register,
38
37
  verifyAnchorHash: () => verifyAnchorHash
39
38
  });
@@ -198,23 +197,6 @@ function verifyAnchorHash(anchor) {
198
197
  }
199
198
  return current === anchor.hash;
200
199
  }
201
- var ED25519_PKCS8_PREFIX = Buffer.from("302e020100300506032b657004220420", "hex");
202
- function generateWalletKeypair() {
203
- const { publicKey, privateKey } = (0, import_crypto.generateKeyPairSync)("ed25519");
204
- const pubRaw = publicKey.export({ type: "spki", format: "der" }).subarray(12);
205
- const privRaw = privateKey.export({ type: "pkcs8", format: "der" }).subarray(16);
206
- return {
207
- publicKey: Buffer.from(pubRaw).toString("hex"),
208
- secretKey: Buffer.from(privRaw).toString("hex")
209
- };
210
- }
211
- function signMessage(secretKeyHex, message) {
212
- const privRaw = Buffer.from(secretKeyHex, "hex");
213
- const privKeyDer = Buffer.concat([ED25519_PKCS8_PREFIX, privRaw]);
214
- const keyObject = (0, import_crypto.createPrivateKey)({ key: privKeyDer, format: "der", type: "pkcs8" });
215
- const sig = (0, import_crypto.sign)(null, Buffer.from(message), keyObject);
216
- return Buffer.from(sig).toString("hex");
217
- }
218
200
  async function register(name, options) {
219
201
  if (!name || typeof name !== "string" || name.trim().length === 0) {
220
202
  throw new ValidationError("name is required (must be a non-empty string)");
@@ -300,8 +282,6 @@ async function register(name, options) {
300
282
  }
301
283
  if (!registerRes.ok) throw mapApiError(registerRes.status, data2, "/api/v1/register");
302
284
  data2.wallet = {
303
- public_key: "",
304
- secret_key: "",
305
285
  address: data2.wallet?.address || options.walletAddress,
306
286
  chain: "ethereum"
307
287
  };
@@ -349,77 +329,6 @@ async function register(name, options) {
349
329
  if (!registerRes.ok) throw mapApiError(registerRes.status, data2, "/api/v1/register");
350
330
  const addr = data2.wallet?.address || data2.wallet?.solana_address || options.operatorWalletAddress;
351
331
  data2.wallet = {
352
- public_key: "",
353
- secret_key: "",
354
- solana_address: addr,
355
- address: addr,
356
- chain: "solana"
357
- };
358
- return data2;
359
- }
360
- if (options?.walletModel === "self-custody" || options?.walletSecretKey) {
361
- let walletKeys;
362
- if (options?.walletSecretKey) {
363
- const privRaw = Buffer.from(options.walletSecretKey, "hex");
364
- const privKeyDer = Buffer.concat([ED25519_PKCS8_PREFIX, privRaw]);
365
- const keyObject = (0, import_crypto.createPrivateKey)({ key: privKeyDer, format: "der", type: "pkcs8" });
366
- const pubRaw = keyObject.export({ type: "spki", format: "der" }).subarray(12);
367
- walletKeys = {
368
- publicKey: Buffer.from(pubRaw).toString("hex"),
369
- secretKey: options.walletSecretKey
370
- };
371
- } else {
372
- walletKeys = generateWalletKeypair();
373
- }
374
- const challengeRes = await fetch(`${url}/api/v1/register`, {
375
- method: "POST",
376
- headers,
377
- body: JSON.stringify({ name, action: "challenge" })
378
- });
379
- let challengeData;
380
- try {
381
- challengeData = await challengeRes.json();
382
- } catch {
383
- const err = new NetworkError(`Registration challenge failed: ${challengeRes.status} (non-JSON response)`);
384
- err.walletKeys = { publicKey: walletKeys.publicKey, secretKey: walletKeys.secretKey };
385
- throw err;
386
- }
387
- if (!challengeRes.ok || !challengeData.nonce) {
388
- const err = mapApiError(challengeRes.status, challengeData, "/api/v1/register");
389
- err.walletKeys = { publicKey: walletKeys.publicKey, secretKey: walletKeys.secretKey };
390
- throw err;
391
- }
392
- const nonce = challengeData.nonce;
393
- const message = `provenonce-register:${nonce}:${walletKeys.publicKey}:${name}`;
394
- const walletSignature = signMessage(walletKeys.secretKey, message);
395
- const registerRes = await fetch(`${url}/api/v1/register`, {
396
- method: "POST",
397
- headers,
398
- body: JSON.stringify({
399
- name,
400
- wallet_public_key: walletKeys.publicKey,
401
- wallet_signature: walletSignature,
402
- wallet_nonce: nonce,
403
- ...options?.metadata && { metadata: options.metadata }
404
- })
405
- });
406
- let data2;
407
- try {
408
- data2 = await registerRes.json();
409
- } catch {
410
- const err = new NetworkError(`Registration failed: ${registerRes.status} (non-JSON response)`);
411
- err.walletKeys = { publicKey: walletKeys.publicKey, secretKey: walletKeys.secretKey };
412
- throw err;
413
- }
414
- if (!registerRes.ok) {
415
- const err = mapApiError(registerRes.status, data2, "/api/v1/register");
416
- err.walletKeys = { publicKey: walletKeys.publicKey, secretKey: walletKeys.secretKey };
417
- throw err;
418
- }
419
- const addr = data2.wallet?.address || data2.wallet?.solana_address || "";
420
- data2.wallet = {
421
- public_key: walletKeys.publicKey,
422
- secret_key: walletKeys.secretKey,
423
332
  solana_address: addr,
424
333
  address: addr,
425
334
  chain: "solana"
@@ -488,6 +397,7 @@ var BeatAgent = class {
488
397
  },
489
398
  verbose: false,
490
399
  verifyAnchors: true,
400
+ beatsUrl: "https://beats.provenonce.dev",
491
401
  ...config
492
402
  };
493
403
  }
@@ -529,27 +439,7 @@ var BeatAgent = class {
529
439
  return { ok: false, error: err.message };
530
440
  }
531
441
  }
532
- // ── PULSE (COMPUTE BEATS) ──
533
- /**
534
- * @deprecated Phase 2: VDF computation retired (D-68). Payment is the liveness mechanism.
535
- * Use heartbeat() instead. This method will be removed in the next major version.
536
- *
537
- * Compute N beats locally (VDF hash chain).
538
- */
539
- pulse(count) {
540
- console.warn("[Provenonce SDK] pulse() is deprecated. Use heartbeat() instead (Phase 2).");
541
- if (this.status === "frozen") {
542
- throw new FrozenError("Cannot pulse: agent is frozen. Use resync() to re-establish provenance.");
543
- }
544
- if (this.status !== "active") {
545
- throw new StateError(`Cannot pulse: agent is ${this.status}.`, this.status);
546
- }
547
- if (count !== void 0 && (!Number.isInteger(count) || count < 1 || count > 1e4)) {
548
- throw new ValidationError("pulse count must be an integer between 1 and 10000");
549
- }
550
- return this.computeBeats(count);
551
- }
552
- /** Internal beat computation — no status check. Used by both pulse() and resync(). */
442
+ /** Internal beat computation — no status check. Used by resync(). */
553
443
  computeBeats(count, onProgress) {
554
444
  const n = count || this.config.beatsPerPulse;
555
445
  if (!this.latestBeat) {
@@ -579,63 +469,6 @@ var BeatAgent = class {
579
469
  this.log(`Pulse: ${n} beats in ${elapsed}ms (${(elapsed / n).toFixed(1)}ms/beat, D=${this.difficulty})`);
580
470
  return newBeats;
581
471
  }
582
- // ── CHECK-IN ──
583
- /**
584
- * @deprecated Phase 2: VDF check-in retired (D-68). Use heartbeat() instead.
585
- * This method will be removed in the next major version.
586
- */
587
- async checkin() {
588
- console.warn("[Provenonce SDK] checkin() is deprecated. Use heartbeat() instead (Phase 2).");
589
- if (!this.latestBeat || this.latestBeat.index <= this.lastCheckinBeat) {
590
- this.log("No new beats since last check-in. Call pulse() first.");
591
- return { ok: true, total_beats: this.totalBeats };
592
- }
593
- try {
594
- const fromBeat = this.lastCheckinBeat;
595
- const toBeat = this.latestBeat.index;
596
- const spotChecks = [];
597
- const toBeatEntry = this.chain.find((b) => b.index === toBeat);
598
- if (toBeatEntry) {
599
- spotChecks.push({ index: toBeatEntry.index, hash: toBeatEntry.hash, prev: toBeatEntry.prev, nonce: toBeatEntry.nonce });
600
- }
601
- const available = this.chain.filter((b) => b.index > this.lastCheckinBeat && b.index !== toBeat);
602
- const sampleCount = Math.min(4, available.length);
603
- for (let i = 0; i < sampleCount; i++) {
604
- const idx = Math.floor(Math.random() * available.length);
605
- const beat = available[idx];
606
- spotChecks.push({ index: beat.index, hash: beat.hash, prev: beat.prev, nonce: beat.nonce });
607
- available.splice(idx, 1);
608
- }
609
- const fromHash = this.chain.find((b) => b.index === fromBeat)?.hash || this.genesisHash;
610
- const toHash = this.latestBeat.hash;
611
- const res = await this.api("POST", "/api/v1/agent/checkin", {
612
- proof: {
613
- from_beat: fromBeat,
614
- to_beat: toBeat,
615
- from_hash: fromHash,
616
- to_hash: toHash,
617
- beats_computed: toBeat - fromBeat,
618
- global_anchor: this.globalBeat,
619
- anchor_hash: this.globalAnchorHash || void 0,
620
- spot_checks: spotChecks
621
- }
622
- });
623
- if (res.ok) {
624
- this.lastCheckinBeat = toBeat;
625
- this.totalBeats = res.total_beats;
626
- this.config.onCheckin(res);
627
- this.log(`Check-in accepted: ${res.beats_accepted} beats, total=${res.total_beats}, global=${res.global_beat}`);
628
- if (res.status === "warning_overdue") {
629
- this.config.onStatusChange("warning", { beats_behind: res.beats_behind });
630
- this.log(`\u26A0 WARNING: ${res.beats_behind} anchors behind. Check in more frequently.`);
631
- }
632
- }
633
- return { ok: res.ok, total_beats: res.total_beats };
634
- } catch (err) {
635
- this.config.onError(err, "checkin");
636
- return { ok: false, error: err.message };
637
- }
638
- }
639
472
  // ── AUTONOMOUS HEARTBEAT ──
640
473
  /**
641
474
  * Start the autonomous heartbeat loop.
@@ -685,60 +518,66 @@ var BeatAgent = class {
685
518
  }
686
519
  // ── RE-SYNC ──
687
520
  /**
688
- * @deprecated Phase 2: Resync retired (D-67). Dormancy resume is free just call heartbeat().
689
- * This method will be removed in the next major version.
521
+ * Re-Sync Challenge (D-67 reversal): reactivate a frozen agent by proving CPU work.
522
+ *
523
+ * When BEATS_REQUIRED=true on the server: requires a signed Beats work-proof
524
+ * receipt. This method computes the proof automatically using computeWorkProof().
525
+ *
526
+ * When BEATS_REQUIRED=false (devnet): no receipt needed — agent is reactivated freely.
527
+ *
528
+ * Gap formula: min(gap_anchors * 100, 10_000) beats required (matches Beats constants).
690
529
  */
691
530
  async resync() {
692
- console.warn("[Provenonce SDK] resync() is deprecated (D-67). Use heartbeat() to resume (Phase 2).");
693
531
  try {
694
- this.log("Requesting re-sync challenge...");
695
- const challenge = await this.api("POST", "/api/v1/agent/resync", {
696
- action: "challenge"
697
- });
698
- if (!challenge.challenge) {
699
- return { ok: false, error: "Failed to get challenge" };
700
- }
701
- const required = challenge.challenge.required_beats;
702
- this.difficulty = challenge.challenge.difficulty;
703
- this.log(`Re-sync challenge: compute ${required} beats at D=${this.difficulty}`);
532
+ this.log("Attempting resync...");
704
533
  await this.syncGlobal();
705
- const startHash = challenge.challenge.start_from_hash;
706
- const startBeat = challenge.challenge.start_from_beat;
707
- this.latestBeat = { index: startBeat, hash: startHash, prev: "", timestamp: Date.now() };
708
- this.chain = [this.latestBeat];
709
- const t0 = Date.now();
710
- this.computeBeats(required);
711
- const elapsed = Date.now() - t0;
712
- this.log(`Re-sync beats computed in ${elapsed}ms`);
713
- const proof = await this.api("POST", "/api/v1/agent/resync", {
714
- action: "prove",
715
- challenge_nonce: challenge.challenge.nonce,
716
- proof: {
717
- from_beat: startBeat,
718
- to_beat: this.latestBeat.index,
719
- from_hash: startHash,
720
- to_hash: this.latestBeat.hash,
721
- beats_computed: required,
722
- global_anchor: challenge.challenge.sync_to_global,
723
- anchor_hash: this.globalAnchorHash || void 0,
724
- spot_checks: (() => {
725
- const toBeatEntry = this.chain.find((b) => b.index === this.latestBeat.index);
726
- const available = this.chain.filter((b) => b.index !== this.latestBeat.index && b.index > startBeat);
727
- const step = Math.max(1, Math.ceil(available.length / 5));
728
- const others = available.filter((_, i) => i % step === 0).slice(0, 4);
729
- const checks = toBeatEntry ? [toBeatEntry, ...others] : others;
730
- return checks.map((b) => ({ index: b.index, hash: b.hash, prev: b.prev, nonce: b.nonce }));
731
- })()
732
- }
733
- });
734
- if (proof.ok) {
534
+ const controller = new AbortController();
535
+ const timeout = setTimeout(() => controller.abort(), 3e4);
536
+ let probeRes;
537
+ let probeData;
538
+ try {
539
+ probeRes = await fetch(`${this.config.registryUrl}/api/v1/agent/resync`, {
540
+ method: "POST",
541
+ headers: {
542
+ "Content-Type": "application/json",
543
+ "Authorization": `Bearer ${this.config.apiKey}`
544
+ },
545
+ body: JSON.stringify({}),
546
+ signal: controller.signal
547
+ });
548
+ probeData = await probeRes.json();
549
+ } finally {
550
+ clearTimeout(timeout);
551
+ }
552
+ if (probeData.ok && probeData.status === "active") {
735
553
  this.status = "active";
736
- this.totalBeats = proof.total_beats;
737
- this.lastCheckinBeat = this.latestBeat.index;
738
554
  this.config.onStatusChange("active", { resynced: true });
739
- this.log("\u2713 Re-synced. Agent is alive again in Beat time.");
555
+ this.log("\u2713 Re-synced (free). Agent is alive again in Beat time.");
556
+ return { ok: true, beats_required: 0 };
740
557
  }
741
- return { ok: proof.ok, beats_required: required };
558
+ if (probeRes.status === 402 || probeData.code === "RECEIPT_REQUIRED") {
559
+ const requiredBeats = probeData.required_beats ?? 1e3;
560
+ this.log(`Re-sync challenge: compute ${requiredBeats} beats at D=${this.difficulty}`);
561
+ const proofResult = await this.computeWorkProof({
562
+ beatsNeeded: requiredBeats,
563
+ anchorHash: this.globalAnchorHash,
564
+ anchorIndex: this.globalBeat
565
+ });
566
+ if (!proofResult.ok || !proofResult.receipt) {
567
+ return { ok: false, error: proofResult.error || "Failed to compute work proof for resync", beats_required: requiredBeats };
568
+ }
569
+ this.log(`Work proof computed: ${proofResult.beats_computed} beats in ${proofResult.elapsed_ms}ms`);
570
+ const result = await this.api("POST", "/api/v1/agent/resync", {
571
+ beats_receipt: proofResult.receipt
572
+ });
573
+ if (result.ok && result.status === "active") {
574
+ this.status = "active";
575
+ this.config.onStatusChange("active", { resynced: true });
576
+ this.log("\u2713 Re-synced with work proof. Agent is alive again in Beat time.");
577
+ }
578
+ return { ok: !!result.ok, beats_required: requiredBeats };
579
+ }
580
+ return { ok: false, error: probeData.error || `Resync failed (status ${probeRes.status})` };
742
581
  } catch (err) {
743
582
  this.config.onError(err, "resync");
744
583
  return { ok: false, error: err.message };
@@ -747,9 +586,13 @@ var BeatAgent = class {
747
586
  // ── SPAWN ──
748
587
  /**
749
588
  * Request to spawn a child agent.
750
- * Requires sufficient accumulated beats (Temporal Gestation).
589
+ * Requires sufficient accumulated beats (Temporal Gestation), OR a valid Beats work-proof receipt.
590
+ *
591
+ * @param childName Optional name for the child agent
592
+ * @param childHash Pre-registered child hash (Step 2 finalization)
593
+ * @param beatsReceipt Signed work-proof receipt from computeWorkProof() (receipt-based spawn)
751
594
  */
752
- async requestSpawn(childName, childHash) {
595
+ async requestSpawn(childName, childHash, beatsReceipt) {
753
596
  try {
754
597
  if (childName !== void 0) {
755
598
  if (typeof childName !== "string" || childName.trim().length === 0) {
@@ -761,12 +604,15 @@ var BeatAgent = class {
761
604
  }
762
605
  const res = await this.api("POST", "/api/v1/agent/spawn", {
763
606
  child_name: childName,
764
- child_hash: childHash
607
+ child_hash: childHash,
608
+ ...beatsReceipt && { beats_receipt: beatsReceipt }
765
609
  });
766
610
  if (res.eligible === false) {
767
611
  this.log(`Gestation incomplete: ${res.progress_pct}% (need ${res.deficit} more beats)`);
768
612
  } else if (res.ok) {
769
613
  this.log(`Child spawned: ${res.child_hash?.slice(0, 16)}...`);
614
+ } else if (res.spawn_authorization) {
615
+ this.log(`Spawn authorized${res.receipt_based ? " (receipt-based)" : ""}`);
770
616
  }
771
617
  return res;
772
618
  } catch (err) {
@@ -774,6 +620,132 @@ var BeatAgent = class {
774
620
  throw err;
775
621
  }
776
622
  }
623
+ /**
624
+ * Compute a Beats work-proof for spawn or resync authorization.
625
+ *
626
+ * Computes `beatsNeeded` sequential SHA-256 beats at `difficulty`, weaving in
627
+ * the given anchor hash, then submits to the Beats service and returns a signed receipt.
628
+ *
629
+ * @param opts.beatsNeeded Minimum beats required (from spawn/resync response.required_beats)
630
+ * @param opts.anchorHash Current global anchor hash (from syncGlobal or getAnchor)
631
+ * @param opts.anchorIndex Current global anchor index
632
+ * @param opts.difficulty Beat difficulty (default: agent's current difficulty)
633
+ */
634
+ async computeWorkProof(opts) {
635
+ const { beatsNeeded, anchorHash, anchorIndex } = opts;
636
+ const difficulty = opts.difficulty ?? this.difficulty;
637
+ if (!Number.isInteger(beatsNeeded) || beatsNeeded < 0) {
638
+ return { ok: false, error: "beatsNeeded must be a non-negative integer" };
639
+ }
640
+ const t0 = Date.now();
641
+ const genesisHash = (0, import_crypto.createHash)("sha256").update(`provenonce:work-proof-genesis:${this.config.apiKey.slice(0, 16)}:${Date.now()}`).digest("hex");
642
+ const beats = Math.max(beatsNeeded, 1);
643
+ let prevHash = genesisHash;
644
+ const spotCheckCount = Math.min(5, Math.max(1, Math.floor(beats / 100)));
645
+ const spotInterval = Math.max(1, Math.floor(beats / (spotCheckCount + 1)));
646
+ const spotChecks = [];
647
+ for (let i = 1; i <= beats; i++) {
648
+ const beat = computeBeat(prevHash, i, difficulty, void 0, anchorHash);
649
+ prevHash = beat.hash;
650
+ if (i % spotInterval === 0 && spotChecks.length < spotCheckCount) {
651
+ spotChecks.push({ index: beat.index, hash: beat.hash, prev: beat.prev });
652
+ }
653
+ }
654
+ const toHash = prevHash;
655
+ const elapsed_ms = Date.now() - t0;
656
+ this.log(`Work proof computed locally: ${beats} beats in ${elapsed_ms}ms`);
657
+ const beatsUrl = this.config.beatsUrl || "https://beats.provenonce.dev";
658
+ const controller = new AbortController();
659
+ const timeout = setTimeout(() => controller.abort(), 12e4);
660
+ try {
661
+ const res = await fetch(`${beatsUrl}/api/v1/beat/work-proof`, {
662
+ method: "POST",
663
+ headers: { "Content-Type": "application/json" },
664
+ body: JSON.stringify({
665
+ work_proof: {
666
+ from_hash: genesisHash,
667
+ to_hash: toHash,
668
+ beats_computed: beats,
669
+ difficulty,
670
+ anchor_index: anchorIndex,
671
+ anchor_hash: anchorHash,
672
+ spot_checks: spotChecks
673
+ }
674
+ }),
675
+ signal: controller.signal
676
+ });
677
+ let data;
678
+ try {
679
+ data = await res.json();
680
+ } catch {
681
+ return { ok: false, error: `Beats service returned non-JSON (status ${res.status})` };
682
+ }
683
+ if (!data.valid || !data.receipt) {
684
+ return { ok: false, error: data.reason || data.error || "Work proof rejected by Beats service" };
685
+ }
686
+ this.log(`Work proof receipt issued by Beats: ${data.receipt.beats_verified} beats verified`);
687
+ return { ok: true, receipt: data.receipt, beats_computed: beats, elapsed_ms };
688
+ } catch (err) {
689
+ if (err.name === "AbortError") {
690
+ return { ok: false, error: "Work proof submission timed out" };
691
+ }
692
+ return { ok: false, error: err.message };
693
+ } finally {
694
+ clearTimeout(timeout);
695
+ }
696
+ }
697
+ /**
698
+ * Compute a Beats work-proof and use it to request spawn authorization.
699
+ *
700
+ * Probes the spawn endpoint to determine required beats, computes the proof,
701
+ * and returns the spawn_authorization token. The caller still needs to:
702
+ * 1. Register the child via POST /api/v1/register with spawn_authorization
703
+ * 2. Finalize via POST /api/v1/agent/spawn with child_hash
704
+ *
705
+ * @param opts.childName Optional name for the child agent
706
+ * @param opts.beatsNeeded Override the required beats (default: auto-probed)
707
+ */
708
+ async requestSpawnWithBeatsProof(opts) {
709
+ try {
710
+ await this.syncGlobal();
711
+ let requiredBeats = opts?.beatsNeeded;
712
+ if (requiredBeats === void 0) {
713
+ const controller = new AbortController();
714
+ const timeout = setTimeout(() => controller.abort(), 3e4);
715
+ try {
716
+ const probeRes = await fetch(`${this.config.registryUrl}/api/v1/agent/spawn`, {
717
+ method: "POST",
718
+ headers: {
719
+ "Content-Type": "application/json",
720
+ "Authorization": `Bearer ${this.config.apiKey}`
721
+ },
722
+ body: JSON.stringify({ child_name: opts?.childName }),
723
+ signal: controller.signal
724
+ });
725
+ const probeData = await probeRes.json();
726
+ if (probeData.spawn_authorization && probeData.eligible) {
727
+ return probeData;
728
+ }
729
+ requiredBeats = probeData.required_beats ?? 1e3;
730
+ } finally {
731
+ clearTimeout(timeout);
732
+ }
733
+ }
734
+ const proofResult = await this.computeWorkProof({
735
+ beatsNeeded: requiredBeats,
736
+ anchorHash: this.globalAnchorHash,
737
+ anchorIndex: this.globalBeat
738
+ });
739
+ if (!proofResult.ok || !proofResult.receipt) {
740
+ return { ok: false, eligible: false, error: proofResult.error || "Failed to compute work proof" };
741
+ }
742
+ this.log(`Submitting spawn with work proof (${proofResult.beats_computed} beats)`);
743
+ return this.requestSpawn(opts?.childName, void 0, proofResult.receipt);
744
+ } catch (err) {
745
+ this.config.onError(err, "requestSpawnWithBeatsProof");
746
+ throw err;
747
+ }
748
+ }
777
749
  /**
778
750
  * Purchase a SIGIL (cryptographic identity) for this agent.
779
751
  * SIGILs gate heartbeating, lineage proofs, and offline verification.
@@ -1115,7 +1087,6 @@ function computeBeatsLite(startHash, startIndex, count, difficulty = 1e3, anchor
1115
1087
  ValidationError,
1116
1088
  computeBeat,
1117
1089
  computeBeatsLite,
1118
- generateWalletKeypair,
1119
1090
  register,
1120
1091
  verifyAnchorHash
1121
1092
  });