package authgate import ( "context" "database/sql" "errors" "fmt" "atcr.io/pkg/atproto" ) // holdResolver resolves a user's default hold DID, preferring the // Jetstream-cached `users.default_hold_did` and falling back to the // AppView's configured default. Embedded into types in this package // (Authorizer, ServiceAuthFetcher) so they share one implementation. type holdResolver struct { db *sql.DB defaultHoldDID string } // resolveHoldDID returns the normalized hold DID for userDID, or "" if no // hold is configured anywhere (caller decides how to degrade). func (h *holdResolver) resolveHoldDID(ctx context.Context, userDID string) (string, error) { var cached sql.NullString err := h.db.QueryRowContext(ctx, "SELECT default_hold_did FROM users WHERE did = ?", userDID, ).Scan(&cached) if err != nil && !errors.Is(err, sql.ErrNoRows) { return "", fmt.Errorf("look up default hold: %w", err) } holdDID := "" if cached.Valid { holdDID = cached.String } if holdDID == "" { holdDID = h.defaultHoldDID } if holdDID == "" { return "", nil } resolved, err := atproto.ResolveHoldDID(ctx, holdDID) if err != nil { return "", fmt.Errorf("resolve hold DID %s: %w", holdDID, err) } return resolved, nil }