OverviewFilesCommitsIssuesDocsReleasesPeers

pgh-sidecar commits / b2ef701

0.2.56: reanchor-name RPC
Exposes the repair path for claims written before org #142, whose identityRoot holds this device's key rather than the identity root. The registry enforces authorisation (only the anchoring device, only to its own chain's root). The checks here exist so the caller gets a real error instead of an op that apply silently drops: not claimed, no attestation chain, or anchored to a key that is not this device. An already-root-anchored claim returns alreadyAnchored rather than erroring, so `pgh names reanchor --all` is idempotent. The handler re-resolves after appending and throws if the anchor did not move, rather than reporting success on a refused op — the failure mode release-name still has. Needs pgh 0.1.144. Forge org #142. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
b2ef701e5f0cb4ca8fbd4be674f4896287d58294
by plankatron <fleeky@gmail.com> · 2026-08-25T16:52:41.000Z

Changed files (2) +37 -1

lib/index.js +36 -0
……@@ -1623,6 +1623,42 @@ export class Sidecar {
16231623 return await this._nameRegistry.resolve(params.name)
16241624 })
16251625
1626 // Repair a claim written before org #142, whose identityRoot holds this
1627 // device's key instead of the root. Only the anchoring device can do it,
1628 // and only to its own chain's root — the registry enforces both; the
1629 // checks here exist to give a real error instead of an op that apply
1630 // silently drops.
1631 svc.handle('reanchor-name', async (ctx, params) => {
1632 if (!params || !params.name) throw new Error('reanchor-name requires { name }')
1633 if (!this._nameRegistry.writable) {
1634 throw new Error('name registry is not writable on this sidecar (join via invite first)')
1635 }
1636 const existing = await this._nameRegistry.resolve(params.name)
1637 if (!existing) throw new Error('name not claimed: ' + params.name)
1638
1639 const signer = this._nameSigner()
1640 if (typeof signer === 'string') {
1641 throw new Error('this identity has no attestation chain, so it cannot prove which root owns the name')
1642 }
1643 if (existing.publisher.identityRoot === signer.identityRoot) {
1644 return { ok: true, alreadyAnchored: true, entry: existing }
1645 }
1646 if (existing.publisher.identityRoot !== signer.devicePubkey) {
1647 throw new Error(
1648 'name "' + params.name + '" is anchored to ' +
1649 String(existing.publisher.identityRoot).slice(0, 12) + '… — this device is ' +
1650 String(signer.devicePubkey).slice(0, 12) + '…; only the anchoring key can re-anchor'
1651 )
1652 }
1653
1654 await this._nameRegistry.reanchor(params.name, signer)
1655 const entry = await this._nameRegistry.resolve(params.name)
1656 if (entry.publisher.identityRoot !== signer.identityRoot) {
1657 throw new Error('re-anchor did not apply for "' + params.name + '" (op refused)')
1658 }
1659 return { ok: true, entry }
1660 })
1661
16261662 svc.handle('release-name', async (ctx, params) => {
16271663 if (!params || !params.name) throw new Error('release-name requires { name }')
16281664 await this._nameRegistry.release(params.name, this._nameSigner())
package.json +1 -1
……@@ -1,6 +1,6 @@
11{
22 "name": "pgh-sidecar",
3 "version": "0.2.55",
3 "version": "0.2.56",
44 "description": "Small optional user-level daemon for pgh \u2014 shared identity vault, OTA polling, device linking, bootstrap seed, NameRegistry host",
55 "type": "module",
66 "main": "lib/index.js",