Skip to content

Commit 42b28cd

Browse files
committed
fix(telemetry): sync.Once for identity stitch, rename constant, add tests
- Wrap StitchLogin callback in sync.Once to prevent duplicate $alias calls if concurrent API responses both carry X-Gotrue-Id - Rename HeaderGotrueId → HeaderGotrueID per Go naming conventions - Add tests for nil callback and inner transport error paths
1 parent 2be0b48 commit 42b28cd

3 files changed

Lines changed: 40 additions & 5 deletions

File tree

cmd/root.go

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"os"
1010
"os/signal"
1111
"strings"
12+
"sync"
1213
"time"
1314

1415
"github.com/getsentry/sentry-go"
@@ -141,11 +142,14 @@ var (
141142
ctx = telemetry.WithService(ctx, service)
142143
}
143144
if service != nil {
145+
var stitchOnce sync.Once
144146
utils.OnGotrueID = func(gotrueID string) {
145147
if service.NeedsIdentityStitch() {
146-
if err := service.StitchLogin(gotrueID); err != nil {
147-
fmt.Fprintln(utils.GetDebugLogger(), err)
148-
}
148+
stitchOnce.Do(func() {
149+
if err := service.StitchLogin(gotrueID); err != nil {
150+
fmt.Fprintln(utils.GetDebugLogger(), err)
151+
}
152+
})
149153
}
150154
}
151155
}

internal/utils/identity_transport.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ package utils
22

33
import "net/http"
44

5-
const HeaderGotrueId = "X-Gotrue-Id"
5+
const HeaderGotrueID = "X-Gotrue-Id"
66

77
type identityTransport struct {
88
http.RoundTripper
@@ -14,7 +14,7 @@ func (t *identityTransport) RoundTrip(req *http.Request) (*http.Response, error)
1414
if err != nil {
1515
return resp, err
1616
}
17-
if id := resp.Header.Get(HeaderGotrueId); id != "" && t.onGotrueID != nil {
17+
if id := resp.Header.Get(HeaderGotrueID); id != "" && t.onGotrueID != nil {
1818
t.onGotrueID(id)
1919
}
2020
return resp, err

internal/utils/identity_transport_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,37 @@ func TestIdentityTransport_IgnoresWhenHeaderMissing(t *testing.T) {
4242
assert.Empty(t, captured)
4343
}
4444

45+
func TestIdentityTransport_NilCallbackDoesNotPanic(t *testing.T) {
46+
transport := &identityTransport{
47+
RoundTripper: roundTripFunc(func(req *http.Request) (*http.Response, error) {
48+
return &http.Response{
49+
StatusCode: 200,
50+
Header: http.Header{"X-Gotrue-Id": []string{"user-abc-123"}},
51+
}, nil
52+
}),
53+
onGotrueID: nil,
54+
}
55+
req, _ := http.NewRequest("GET", "https://api.supabase.io/v1/projects", nil)
56+
resp, err := transport.RoundTrip(req)
57+
assert.NoError(t, err)
58+
assert.Equal(t, 200, resp.StatusCode)
59+
}
60+
61+
func TestIdentityTransport_InnerTransportError(t *testing.T) {
62+
var captured string
63+
transport := &identityTransport{
64+
RoundTripper: roundTripFunc(func(req *http.Request) (*http.Response, error) {
65+
return nil, assert.AnError
66+
}),
67+
onGotrueID: func(id string) { captured = id },
68+
}
69+
req, _ := http.NewRequest("GET", "https://api.supabase.io/v1/projects", nil)
70+
resp, err := transport.RoundTrip(req)
71+
assert.Error(t, err)
72+
assert.Nil(t, resp)
73+
assert.Empty(t, captured)
74+
}
75+
4576
// roundTripFunc is a test helper to create inline RoundTrippers.
4677
type roundTripFunc func(*http.Request) (*http.Response, error)
4778

0 commit comments

Comments
 (0)