Skip to content

Commit 1b3d990

Browse files
refactor(zoo-code-auth): drop subscription-status helpers with telemetry
The only consumer of getCachedSubscriptionStatus / checkSubscriptionStatus was zoo-telemetry.ts, which gated extension-side LLM observability events on an active subscription. That telemetry was removed in the previous commit, so the helpers (and the /api/subscription/status fetch they wrap) now have no callers. Drop the helpers, the module-level _cachedSubscriptionStatus state and its 5-minute TTL, and the resets sprinkled through initZooCodeAuth / setZooCodeToken / clearZooCodeToken / handleAuthCallback. Tests for the removed surface are deleted; the unreachable / 5xx initZooCodeAuth tests keep their token-and-user-info preservation assertions, just without the subscription-status check. Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent dadaaa3 commit 1b3d990

2 files changed

Lines changed: 11 additions & 214 deletions

File tree

src/services/__tests__/zoo-code-auth.test.ts

Lines changed: 9 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"
22
import * as vscode from "vscode"
33

44
import {
5-
checkSubscriptionStatus,
65
clearZooCodeToken,
76
clearZooCodeUserInfo,
87
disconnectZooCode,
9-
getCachedSubscriptionStatus,
108
getCachedZooCodeToken,
119
getCachedZooCodeUserInfo,
1210
getZooCodeBaseUrl,
@@ -68,98 +66,6 @@ describe("zoo-code-auth", () => {
6866
vi.restoreAllMocks()
6967
})
7068

71-
describe("getCachedSubscriptionStatus", () => {
72-
it("returns unknown initially", () => {
73-
expect(getCachedSubscriptionStatus()).toBe("unknown")
74-
})
75-
})
76-
77-
describe("checkSubscriptionStatus", () => {
78-
it("returns inactive when no token is present", async () => {
79-
await initZooCodeAuth(mockContext)
80-
81-
const status = await checkSubscriptionStatus()
82-
83-
expect(status).toBe("inactive")
84-
expect(mockFetch).not.toHaveBeenCalled()
85-
})
86-
87-
it("returns active when the API reports an active subscriber", async () => {
88-
await initZooCodeAuth(mockContext)
89-
await setZooCodeToken("zoo_ext_test_token")
90-
91-
mockFetch.mockResolvedValueOnce({
92-
ok: true,
93-
json: async () => ({ isSubscriber: true, planId: "pro", status: "active" }),
94-
})
95-
96-
const status = await checkSubscriptionStatus()
97-
98-
expect(status).toBe("active")
99-
expect(mockFetch).toHaveBeenCalledWith(
100-
expect.stringContaining("/api/subscription/status"),
101-
expect.objectContaining({
102-
headers: { Authorization: "Bearer zoo_ext_test_token" },
103-
}),
104-
)
105-
})
106-
107-
it("returns inactive when the API reports a free user", async () => {
108-
await initZooCodeAuth(mockContext)
109-
await setZooCodeToken("zoo_ext_test_token")
110-
111-
mockFetch.mockResolvedValueOnce({
112-
ok: true,
113-
json: async () => ({ isSubscriber: false, planId: "free", status: "active" }),
114-
})
115-
116-
await expect(checkSubscriptionStatus()).resolves.toBe("inactive")
117-
})
118-
119-
it("returns unknown when the API request fails", async () => {
120-
await initZooCodeAuth(mockContext)
121-
await setZooCodeToken("zoo_ext_test_token")
122-
123-
mockFetch.mockResolvedValueOnce({
124-
ok: false,
125-
status: 500,
126-
statusText: "Internal Server Error",
127-
})
128-
129-
await expect(checkSubscriptionStatus()).resolves.toBe("unknown")
130-
})
131-
132-
it("returns unknown when the API throws", async () => {
133-
await initZooCodeAuth(mockContext)
134-
await setZooCodeToken("zoo_ext_test_token")
135-
mockFetch.mockRejectedValueOnce(new Error("Network error"))
136-
137-
await expect(checkSubscriptionStatus()).resolves.toBe("unknown")
138-
})
139-
140-
it("reuses the cached status when it was checked recently", async () => {
141-
await initZooCodeAuth(mockContext)
142-
await setZooCodeToken("zoo_ext_test_token")
143-
144-
mockFetch.mockResolvedValueOnce({
145-
ok: true,
146-
json: async () => ({ isSubscriber: true, planId: "pro", status: "active" }),
147-
})
148-
149-
expect(await checkSubscriptionStatus()).toBe("active")
150-
expect(await checkSubscriptionStatus()).toBe("active")
151-
expect(mockFetch).toHaveBeenCalledTimes(1)
152-
})
153-
154-
it("handles AbortSignal timeouts", async () => {
155-
await initZooCodeAuth(mockContext)
156-
await setZooCodeToken("zoo_ext_test_token")
157-
mockFetch.mockRejectedValueOnce(new DOMException("Aborted", "AbortError"))
158-
159-
await expect(checkSubscriptionStatus()).resolves.toBe("unknown")
160-
})
161-
})
162-
16369
describe("getCachedZooCodeToken", () => {
16470
it("returns an empty string when no token is set", async () => {
16571
await clearZooCodeToken()
@@ -169,15 +75,10 @@ describe("zoo-code-auth", () => {
16975

17076
it("preloads the cached token during initialization", async () => {
17177
await mockSecrets.store("zoo-code-session-token", "zoo_ext_cached_token")
172-
mockFetch
173-
.mockResolvedValueOnce({
174-
ok: true,
175-
json: async () => ({ valid: true }),
176-
})
177-
.mockResolvedValueOnce({
178-
ok: true,
179-
json: async () => ({ isSubscriber: true }),
180-
})
78+
mockFetch.mockResolvedValueOnce({
79+
ok: true,
80+
json: async () => ({ valid: true }),
81+
})
18182

18283
await initZooCodeAuth(mockContext)
18384
await Promise.resolve()
@@ -237,10 +138,8 @@ describe("zoo-code-auth", () => {
237138

238139
await initZooCodeAuth(mockContext)
239140

240-
// Token and user info should be kept; subscription status should be unknown
241141
expect(getCachedZooCodeToken()).toBe("zoo_ext_valid_token")
242142
expect(getCachedZooCodeUserInfo().name).toBe("Jane Doe")
243-
expect(getCachedSubscriptionStatus()).toBe("unknown")
244143
})
245144

246145
it("preserves token and user info when verify returns 5xx (transient backend error)", async () => {
@@ -257,39 +156,16 @@ describe("zoo-code-auth", () => {
257156

258157
expect(getCachedZooCodeToken()).toBe("zoo_ext_valid_token")
259158
expect(getCachedZooCodeUserInfo().name).toBe("Jane Doe")
260-
expect(getCachedSubscriptionStatus()).toBe("unknown")
261-
})
262-
})
263-
264-
describe("setZooCodeToken", () => {
265-
it("resets the cached subscription status when the token changes", async () => {
266-
await initZooCodeAuth(mockContext)
267-
await setZooCodeToken("zoo_ext_token1")
268-
mockFetch.mockResolvedValueOnce({
269-
ok: true,
270-
json: async () => ({ isSubscriber: true, planId: "pro", status: "active" }),
271-
})
272-
await checkSubscriptionStatus()
273-
274-
await setZooCodeToken("zoo_ext_token2")
275-
276-
expect(getCachedSubscriptionStatus()).toBe("unknown")
277159
})
278160
})
279161

280162
describe("clearZooCodeToken", () => {
281-
it("resets the cached subscription status when the token is cleared", async () => {
163+
it("clears the cached token", async () => {
282164
await initZooCodeAuth(mockContext)
283165
await setZooCodeToken("zoo_ext_test_token")
284-
mockFetch.mockResolvedValueOnce({
285-
ok: true,
286-
json: async () => ({ isSubscriber: true, planId: "pro", status: "active" }),
287-
})
288-
await checkSubscriptionStatus()
289166

290167
await clearZooCodeToken()
291168

292-
expect(getCachedSubscriptionStatus()).toBe("unknown")
293169
expect(getCachedZooCodeToken()).toBe("")
294170
})
295171
})
@@ -337,15 +213,10 @@ describe("zoo-code-auth", () => {
337213

338214
it("persists a token only after backend verification succeeds", async () => {
339215
await initZooCodeAuth(mockContext)
340-
mockFetch
341-
.mockResolvedValueOnce({
342-
ok: true,
343-
json: async () => ({ valid: true }),
344-
})
345-
.mockResolvedValueOnce({
346-
ok: true,
347-
json: async () => ({ isSubscriber: true }),
348-
})
216+
mockFetch.mockResolvedValueOnce({
217+
ok: true,
218+
json: async () => ({ valid: true }),
219+
})
349220

350221
const success = await handleAuthCallback("zoo_ext_real_token")
351222

src/services/zoo-code-auth.ts

Lines changed: 2 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@ let _sessionCleared = false
1515
let _cachedUserName: string | undefined = undefined
1616
let _cachedUserEmail: string | undefined = undefined
1717
let _cachedUserImage: string | undefined = undefined
18-
let _cachedSubscriptionStatus: "active" | "inactive" | "unknown" = "unknown"
19-
let _lastSubscriptionCheck: number = 0
20-
const SUBSCRIPTION_CHECK_INTERVAL_MS = 5 * 60 * 1000 // 5 minutes
2118

2219
export async function initZooCodeAuth(context: vscode.ExtensionContext): Promise<void> {
2320
if (!context.secrets) {
@@ -35,19 +32,13 @@ export async function initZooCodeAuth(context: vscode.ExtensionContext): Promise
3532
_cachedUserImage = await secretStorage.get(ZOO_CODE_USER_IMAGE_KEY)
3633

3734
// Validate persisted auth state on init before reporting the user as connected.
35+
// Network errors / 5xx ("unreachable") leave the cached session in place so a
36+
// transient backend blip doesn't force users to sign in again.
3837
if (_cachedToken) {
3938
const result = await verifyZooCodeToken()
4039
if (result === "invalid") {
41-
// Token is definitively rejected by the backend — clear everything.
4240
await clearZooCodeUserInfo()
4341
await clearZooCodeToken()
44-
} else if (result === "unreachable") {
45-
// Network is temporarily down; keep the cached session but mark subscription
46-
// status as unknown so callers know it hasn't been confirmed.
47-
_cachedSubscriptionStatus = "unknown"
48-
} else {
49-
// result === "valid"
50-
void checkSubscriptionStatus().catch(() => {})
5142
}
5243
}
5344

@@ -56,12 +47,6 @@ export async function initZooCodeAuth(context: vscode.ExtensionContext): Promise
5647
if (e.key === ZOO_CODE_TOKEN_KEY) {
5748
secretStorage?.get(ZOO_CODE_TOKEN_KEY).then((token) => {
5849
_cachedToken = token
59-
// Reset subscription status when token changes
60-
_cachedSubscriptionStatus = "unknown"
61-
_lastSubscriptionCheck = 0
62-
if (token) {
63-
checkSubscriptionStatus().catch(() => {})
64-
}
6550
})
6651
}
6752
if (e.key === ZOO_CODE_USER_NAME_KEY) {
@@ -110,57 +95,6 @@ export function getCachedZooCodeUserInfo(): { name?: string; email?: string; ima
11095
}
11196
}
11297

113-
/**
114-
* Get the cached subscription status. This is a synchronous getter that returns
115-
* the last known subscription status. Call checkSubscriptionStatus() to refresh.
116-
*/
117-
export function getCachedSubscriptionStatus(): "active" | "inactive" | "unknown" {
118-
return _cachedSubscriptionStatus
119-
}
120-
121-
/**
122-
* Check the subscription status from the backend API.
123-
* Updates the cached status and returns it.
124-
* Implements caching to avoid excessive API calls (5 minute cache).
125-
*/
126-
export async function checkSubscriptionStatus(): Promise<"active" | "inactive" | "unknown"> {
127-
const token = await getZooCodeToken()
128-
if (!token) {
129-
_cachedSubscriptionStatus = "inactive"
130-
return "inactive"
131-
}
132-
133-
// Return cached status if checked recently
134-
const now = Date.now()
135-
if (now - _lastSubscriptionCheck < SUBSCRIPTION_CHECK_INTERVAL_MS && _cachedSubscriptionStatus !== "unknown") {
136-
return _cachedSubscriptionStatus
137-
}
138-
139-
const baseUrl = getZooCodeBaseUrl()
140-
141-
try {
142-
const response = await fetch(`${baseUrl}/api/subscription/status`, {
143-
headers: { Authorization: `Bearer ${token}` },
144-
signal: AbortSignal.timeout(10_000),
145-
})
146-
147-
if (!response.ok) {
148-
_cachedSubscriptionStatus = "unknown"
149-
_lastSubscriptionCheck = now
150-
return "unknown"
151-
}
152-
153-
const data = (await response.json()) as { isSubscriber?: boolean }
154-
_cachedSubscriptionStatus = data.isSubscriber ? "active" : "inactive"
155-
_lastSubscriptionCheck = now
156-
return _cachedSubscriptionStatus
157-
} catch {
158-
_cachedSubscriptionStatus = "unknown"
159-
_lastSubscriptionCheck = now
160-
return "unknown"
161-
}
162-
}
163-
16498
export async function getZooCodeToken(): Promise<string | undefined> {
16599
if (!secretStorage) return undefined
166100
return secretStorage.get(ZOO_CODE_TOKEN_KEY)
@@ -171,9 +105,6 @@ export async function setZooCodeToken(token: string): Promise<void> {
171105
await secretStorage.store(ZOO_CODE_TOKEN_KEY, token)
172106
_cachedToken = token
173107
_sessionCleared = false
174-
// Reset subscription status when token is set
175-
_cachedSubscriptionStatus = "unknown"
176-
_lastSubscriptionCheck = 0
177108
}
178109

179110
export async function setZooCodeUserInfo(info: {
@@ -223,8 +154,6 @@ export async function clearZooCodeToken(): Promise<void> {
223154
await secretStorage.delete(ZOO_CODE_TOKEN_KEY)
224155
_cachedToken = undefined
225156
_sessionCleared = true
226-
_cachedSubscriptionStatus = "unknown"
227-
_lastSubscriptionCheck = 0
228157
}
229158

230159
export function getZooCodeBaseUrl(): string {
@@ -266,9 +195,6 @@ export async function handleAuthCallback(token: string): Promise<boolean> {
266195

267196
await setZooCodeToken(token)
268197

269-
// Check subscription status after successful auth
270-
await checkSubscriptionStatus().catch(() => {})
271-
272198
vscode.window.showInformationMessage(t("common:zooAuth.info.connected"))
273199
return true
274200
}

0 commit comments

Comments
 (0)