| … | … | @@ -114,7 +114,12 @@ export function peerClient (node) { |
| 114 | 114 | export function pickNode (hpp, credential = null) { |
| 115 | 115 | const nodes = (hpp && hpp.nodes) || [] |
| 116 | 116 | if (nodes.length === 0) return { node: null, error: 'this device has no booted atproto identity' } |
| 117 | if (credential && hpp.byDid && hpp.byDid[credential]) return { node: hpp.byDid[credential], error: null } | |
| 117 | // ⛔ hpp returns `byDid` as a MAP (device-node.js:879). Indexing it like an object never matched, so a | |
| 118 | // designated credential was ignored and a two-DID node refused every pass (tabertron, 2026-10-13). | |
| 119 | const designated = credential && hpp.byDid | |
| 120 | ? (typeof hpp.byDid.get === 'function' ? hpp.byDid.get(credential) : hpp.byDid[credential]) | |
| 121 | : null | |
| 122 | if (designated) return { node: designated, error: null } | |
| 118 | 123 | if (nodes.length === 1) return { node: nodes[0], error: null } |
| 119 | 124 | return { node: null, error: 'this device holds several identities and none is designated — choose one in settings' } |
| 120 | 125 | } |
| … | … | @@ -1,12 +1,12 @@ |
| 1 | 1 | { |
| 2 | 2 | "name": "favela-host", |
| 3 | "version": "0.1.2", | |
| 3 | "version": "0.1.3", | |
| 4 | 4 | "lockfileVersion": 3, |
| 5 | 5 | "requires": true, |
| 6 | 6 | "packages": { |
| 7 | 7 | "": { |
| 8 | 8 | "name": "favela-host", |
| 9 | "version": "0.1.2", | |
| 9 | "version": "0.1.3", | |
| 10 | 10 | "dependencies": { |
| 11 | 11 | "anproto": "file:../anproto", |
| 12 | 12 | "atproto-identity": "file:../atproto-identity", |
| … | … | @@ -1,6 +1,6 @@ |
| 1 | 1 | { |
| 2 | 2 | "name": "favela-host", |
| 3 | "version": "0.1.2", | |
| 3 | "version": "0.1.3", | |
| 4 | 4 | "description": "THE favela app on a desktop, home node or server: a favela-peer node, favela-surface rendering it, the atproto signer and the bsky projection, in one process.", |
| 5 | 5 | "type": "module", |
| 6 | 6 | "main": "index.js", |
| … | … | @@ -83,3 +83,16 @@ test('★★★ with several identities and none designated it refuses rather th |
| 83 | 83 | t.is(pickNode({ nodes: [a], byDid: { 'did:plc:aaa': a } }, null).node, a, 'one identity needs no designation') |
| 84 | 84 | t.ok(/no booted atproto identity/.test(pickNode({ nodes: [] }, null).error), 'and none is said plainly') |
| 85 | 85 | }) |
| 86 | ||
| 87 | // ⛔ hpp's bootMultiDevice returns `byDid` as a MAP (device-node.js:879). pickNode indexed it like an | |
| 88 | // object, so a designated credential never matched and a node with two DIDs refused every pass even after | |
| 89 | // the operator designated one (tabertron, 2026-10-13). | |
| 90 | test('pickNode honours the designated credential when byDid is a Map, as hpp returns it', async (t) => { | |
| 91 | const a = { did: 'did:plc:aaa' } | |
| 92 | const b = { did: 'did:plc:bbb' } | |
| 93 | const hpp = { nodes: [a, b], byDid: new Map([[a.did, a], [b.did, b]]) } | |
| 94 | const r = pickNode(hpp, 'did:plc:bbb') | |
| 95 | t.is(r.error, null) | |
| 96 | t.is(r.node, b, 'the designated identity, not a refusal') | |
| 97 | t.ok(pickNode(hpp, null).error, 'still refuses with several and none designated') | |
| 98 | }) |