@@ -124,27 +124,46 @@ export async function bumpAncestors(
124124 ` ) ;
125125}
126126
127+ type ResolvedNode = { id : number ; code : string ; referrerId : number | null ; localId : string } ;
128+
127129/** Resolve an existing node by localId (primary) then fingerprint (fallback). */
128130export async function resolveNode (
129131 localId : string ,
130132 fingerprint : string | null ,
131- ) : Promise < { id : number ; code : string ; referrerId : number | null } | null > {
133+ ) : Promise < ResolvedNode | null > {
132134 const byLocal = ( await db . execute ( sql `
133- SELECT id, code, referrer_id AS "referrerId" FROM nodes WHERE local_id = ${ localId } LIMIT 1;
134- ` ) ) as unknown as { rows : { id : number ; code : string ; referrerId : number | null } [ ] } ;
135+ SELECT id, code, referrer_id AS "referrerId", local_id AS "localId"
136+ FROM nodes WHERE local_id = ${ localId } LIMIT 1;
137+ ` ) ) as unknown as { rows : ResolvedNode [ ] } ;
135138 if ( byLocal . rows ?. [ 0 ] ) return byLocal . rows [ 0 ] ;
136139
137140 if ( fingerprint ) {
138141 const byFp = ( await db . execute ( sql `
139- SELECT id, code, referrer_id AS "referrerId" FROM nodes
142+ SELECT id, code, referrer_id AS "referrerId", local_id AS "localId"
143+ FROM nodes
140144 WHERE fingerprint = ${ fingerprint } AND class = 'human'
141145 ORDER BY created_at ASC LIMIT 1;
142- ` ) ) as unknown as { rows : { id : number ; code : string ; referrerId : number | null } [ ] } ;
146+ ` ) ) as unknown as { rows : ResolvedNode [ ] } ;
143147 if ( byFp . rows ?. [ 0 ] ) return byFp . rows [ 0 ] ;
144148 }
145149 return null ;
146150}
147151
152+ /**
153+ * Move a node onto a freshly issued client localId (DESIGN §2 fingerprint re-link).
154+ * Cookie and DB must agree so auth routes can resolve the node by wh_lid alone.
155+ */
156+ export async function relinkNodeLocalId ( nodeId : number , newLocalId : string ) : Promise < boolean > {
157+ const updated = ( await db . execute ( sql `
158+ UPDATE nodes SET local_id = ${ newLocalId }
159+ WHERE id = ${ nodeId }
160+ AND local_id <> ${ newLocalId }
161+ AND NOT EXISTS (SELECT 1 FROM nodes WHERE local_id = ${ newLocalId } )
162+ RETURNING id;
163+ ` ) ) as unknown as { rows : { id : number } [ ] } ;
164+ return ! ! updated . rows ?. [ 0 ] ;
165+ }
166+
148167/** Look up a node id by its share code (the ?ref target). */
149168export async function nodeByCode (
150169 code : string ,
0 commit comments