Skip to content

Commit 6791e2e

Browse files
authored
Merge pull request #65 from spacesprotocol/releases
fix: resolve() should return null/nil across all clients when handle …
2 parents c8b6cea + 2ae64d1 commit 6791e2e

5 files changed

Lines changed: 36 additions & 42 deletions

File tree

fabric/go/fabric.go

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -428,25 +428,26 @@ func (f *Fabric) updateAnchors(trustID string, kind trustKind) error {
428428
return nil
429429
}
430430

431-
// Resolve a single handle. Supports dotted names like "hello.alice@bitcoin".
432-
func (f *Fabric) Resolve(handle string) (Resolved, error) {
431+
// Resolve a single handle. Returns nil if not found. Supports dotted names like "hello.alice@bitcoin".
432+
func (f *Fabric) Resolve(handle string) (*Resolved, error) {
433433
batch, err := f.ResolveAll([]string{handle})
434434
if err != nil {
435-
return Resolved{}, err
435+
return nil, err
436436
}
437437
for _, z := range batch.Zones {
438438
if z.Handle == handle {
439-
return Resolved{Zone: z, Roots: batch.Roots}, nil
439+
return &Resolved{Zone: z, Roots: batch.Roots}, nil
440440
}
441441
}
442-
return Resolved{}, &FabricError{Code: "decode", Message: handle + " not found"}
442+
return nil, nil
443443
}
444444

445445
// ResolveById resolves a numeric ID to a handle by querying relays
446446
// for the reverse mapping, then verifying via forward resolution.
447-
func (f *Fabric) ResolveById(numId string) (Resolved, error) {
447+
// Returns nil if not found.
448+
func (f *Fabric) ResolveById(numId string) (*Resolved, error) {
448449
if err := f.Bootstrap(); err != nil {
449-
return Resolved{}, err
450+
return nil, err
450451
}
451452
urls := f.pool.ShuffledURLs(4)
452453
var lastErr error = &FabricError{Code: "no_peers", Message: "reverse resolution failed"}
@@ -486,6 +487,9 @@ func (f *Fabric) ResolveById(numId string) (Resolved, error) {
486487
lastErr = err
487488
continue
488489
}
490+
if resolved == nil {
491+
continue
492+
}
489493

490494
if resolved.Zone.NumId == nil || *resolved.Zone.NumId != numId {
491495
lastErr = &FabricError{Code: "verify", Message: fmt.Sprintf("reverse mismatch: expected %s", numId)}
@@ -494,7 +498,7 @@ func (f *Fabric) ResolveById(numId string) (Resolved, error) {
494498

495499
return resolved, nil
496500
}
497-
return Resolved{}, lastErr
501+
return nil, lastErr
498502
}
499503

500504
// SearchAddr searches for handles by address record, verifies via forward resolution.

fabric/js/fabric-core/src/fabric.ts

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -427,12 +427,12 @@ export class Fabric {
427427

428428
// ── Resolution ──
429429

430-
/** Resolve a single handle. Supports nested names like `hello.alice@bitcoin`. */
431-
async resolve(handle: string): Promise<Resolved> {
430+
/** Resolve a single handle. Returns null if not found. Supports nested names like `hello.alice@bitcoin`. */
431+
async resolve(handle: string): Promise<Resolved | null> {
432432
const batch = await this.resolveAll([handle]);
433433
const zone = batch.zones.find((z) => z.handle === handle);
434434
if (!zone) {
435-
throw new FabricError(`${handle} not found`, "decode");
435+
return null;
436436
}
437437
return { zone, roots: batch.roots };
438438
}
@@ -451,13 +451,14 @@ export class Fabric {
451451
const entry = records.find(r => r.id === numId);
452452
if (!entry) continue;
453453

454-
let resolved: Resolved;
454+
let resolved: Resolved | null;
455455
try {
456456
resolved = await this.resolve(entry.name);
457457
} catch (e) {
458458
lastErr = e instanceof Error ? e : new FabricError(String(e), "decode");
459459
continue;
460460
}
461+
if (!resolved) continue;
461462

462463
const json = resolved.zone.toJson();
463464
if (json?.num_id !== numId) {

fabric/kotlin/src/main/kotlin/org/spacesprotocol/fabric/Fabric.kt

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -199,14 +199,13 @@ class Fabric(
199199

200200
// -- Resolution --
201201

202-
fun resolve(handle: String): Resolved {
202+
fun resolve(handle: String): Resolved? {
203203
val batch = resolveAll(listOf(handle))
204-
val zone = batch.zones.find { it.handle == handle }
205-
?: throw FabricError("decode", "$handle not found")
204+
val zone = batch.zones.find { it.handle == handle } ?: return null
206205
return Resolved(zone, batch.roots)
207206
}
208207

209-
fun resolveById(numId: String): Resolved {
208+
fun resolveById(numId: String): Resolved? {
210209
bootstrap()
211210
val urls = pool.shuffledUrls(4)
212211
var lastErr: Exception = FabricError("no_peers", "reverse resolution failed")
@@ -231,12 +230,7 @@ class Fabric(
231230

232231
val entry = entries.find { it.id == numId } ?: continue
233232

234-
val resolved = try {
235-
resolve(entry.name)
236-
} catch (e: Exception) {
237-
lastErr = e
238-
continue
239-
}
233+
val resolved = resolve(entry.name) ?: continue
240234

241235
if (resolved.zone.numId != numId) {
242236
lastErr = FabricError("verify", "reverse mismatch: expected $numId, got ${resolved.zone.numId}")
@@ -246,7 +240,7 @@ class Fabric(
246240
return resolved
247241
}
248242

249-
throw lastErr
243+
return null
250244
}
251245

252246
fun searchAddr(name: String, addr: String): ResolvedBatch {

fabric/python/fabric/client.py

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -219,15 +219,15 @@ def badge_for(self, sovereignty: str, roots: list[str]) -> str:
219219
return BADGE_UNVERIFIED
220220
return BADGE_NONE
221221

222-
def resolve(self, handle: str) -> Resolved:
222+
def resolve(self, handle: str) -> Resolved | None:
223223
batch = self.resolve_all([handle])
224224
zone = next((z for z in batch.zones if z.handle == handle), None)
225225
if zone is None:
226-
raise FabricError("decode", f"{handle} not found")
226+
return None
227227
return Resolved(zone=zone, roots=batch.roots)
228228

229-
def resolve_by_id(self, num_id: str) -> Resolved:
230-
"""Resolve a numeric ID to a verified handle."""
229+
def resolve_by_id(self, num_id: str) -> Resolved | None:
230+
"""Resolve a numeric ID to a verified handle. Returns None if not found."""
231231
self.bootstrap()
232232
urls = self._pool.shuffled_urls(4)
233233
last_err: Exception = FabricError("no_peers", "reverse resolution failed")
@@ -249,10 +249,8 @@ def resolve_by_id(self, num_id: str) -> Resolved:
249249
if entry is None:
250250
continue
251251

252-
try:
253-
resolved = self.resolve(entry["name"])
254-
except Exception as e:
255-
last_err = e
252+
resolved = self.resolve(entry["name"])
253+
if resolved is None:
256254
continue
257255

258256
if getattr(resolved.zone, "num_id", None) != num_id:
@@ -262,7 +260,7 @@ def resolve_by_id(self, num_id: str) -> Resolved:
262260
self._pool.mark_alive(u)
263261
return resolved
264262

265-
raise last_err
263+
return None
266264

267265
def search_addr(self, name: str, addr: str) -> ResolvedBatch:
268266
"""Search for handles by address record, verify via forward resolution."""

fabric/swift/Sources/Fabric/Fabric.swift

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -322,17 +322,17 @@ public final class Fabric: @unchecked Sendable {
322322

323323
// MARK: - Resolution
324324

325-
/// Resolve a single handle. Supports dotted names like `hello.alice@bitcoin`.
326-
public func resolve(_ handle: String) async throws -> Resolved {
325+
/// Resolve a single handle. Returns nil if not found. Supports dotted names like `hello.alice@bitcoin`.
326+
public func resolve(_ handle: String) async throws -> Resolved? {
327327
let batch = try await resolveAll([handle])
328328
guard let zone = batch.zones.first(where: { $0.handle == handle }) else {
329-
throw FabricError.decode("\(handle) not found")
329+
return nil
330330
}
331331
return Resolved(zone: zone, roots: batch.roots)
332332
}
333333

334-
/// Resolve a numeric ID to a verified handle.
335-
public func resolveById(_ numId: String) async throws -> Resolved {
334+
/// Resolve a numeric ID to a verified handle. Returns nil if not found.
335+
public func resolveById(_ numId: String) async throws -> Resolved? {
336336
try await bootstrap()
337337
let relays = pool.shuffledUrls(4)
338338

@@ -347,16 +347,13 @@ public final class Fabric: @unchecked Sendable {
347347

348348
guard let entry = entries.first(where: { $0.id == numId }) else { continue }
349349

350-
let resolved: Resolved
351-
do {
352-
resolved = try await resolve(entry.name)
353-
} catch { continue }
350+
guard let resolved = try await resolve(entry.name) else { continue }
354351

355352
guard resolved.zone.numId == numId else { continue }
356353
return resolved
357354
}
358355

359-
throw FabricError.noPeers
356+
return nil
360357
}
361358

362359
/// Search for handles by address record, verify via forward resolution.

0 commit comments

Comments
 (0)