Skip to content

Commit 2e7cb4f

Browse files
dante01yoonampagent
andcommitted
fix(billing): ignore stale workspace status
Amp-Thread-ID: https://ampcode.com/threads/T-019fc8cd-b288-7161-a590-cd76d51212bf Co-authored-by: Amp <amp@ampcode.com>
1 parent 975e95f commit 2e7cb4f

2 files changed

Lines changed: 42 additions & 3 deletions

File tree

src/platform/cloud/subscription/composables/useSubscription.test.ts

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,15 @@ const {
1616
mockIsCloud,
1717
mockAuthStoreInitialized,
1818
mockGetBillingStatus,
19+
mockActiveWorkspaceId,
1920
mockSetWorkspaceBillingRail,
2021
mockLocalStorage
2122
} = vi.hoisted(() => ({
2223
mockIsLoggedIn: { value: false },
2324
mockIsCloud: { value: true },
2425
mockAuthStoreInitialized: { value: true },
2526
mockGetBillingStatus: vi.fn(),
27+
mockActiveWorkspaceId: { value: 'workspace-123' as string | null },
2628
mockSetWorkspaceBillingRail: vi.fn(),
2729
mockReportError: vi.fn(),
2830
mockAccessBillingPortal: vi.fn(),
@@ -146,7 +148,9 @@ vi.mock('@/platform/workspace/api/workspaceApi', () => ({
146148

147149
vi.mock('@/platform/workspace/stores/teamWorkspaceStore', () => ({
148150
useTeamWorkspaceStore: () => ({
149-
activeWorkspaceId: 'workspace-123',
151+
get activeWorkspaceId() {
152+
return mockActiveWorkspaceId.value
153+
},
150154
setWorkspaceBillingRail: mockSetWorkspaceBillingRail
151155
})
152156
}))
@@ -198,6 +202,7 @@ describe('useSubscription', () => {
198202
mockUserId.value = 'user-123'
199203
mockIsCloud.value = true
200204
mockAuthStoreInitialized.value = true
205+
mockActiveWorkspaceId.value = 'workspace-123'
201206
mockGetBillingStatus.mockResolvedValue({
202207
is_active: false,
203208
has_funds: false,
@@ -352,6 +357,31 @@ describe('useSubscription', () => {
352357
)
353358
})
354359

360+
it('does not apply status after the active workspace changes', async () => {
361+
let resolveStatus: (value: {
362+
is_active: boolean
363+
has_funds: boolean
364+
billing_rail: 'stripe'
365+
}) => void = () => {}
366+
mockGetBillingStatus.mockReturnValue(
367+
new Promise((resolve) => {
368+
resolveStatus = resolve
369+
})
370+
)
371+
372+
const { fetchStatus } = useSubscriptionWithScope()
373+
const statusRequest = fetchStatus()
374+
mockActiveWorkspaceId.value = 'workspace-456'
375+
resolveStatus({
376+
is_active: true,
377+
has_funds: true,
378+
billing_rail: 'stripe'
379+
})
380+
await statusRequest
381+
382+
expect(mockSetWorkspaceBillingRail).not.toHaveBeenCalled()
383+
})
384+
355385
it('coalesces concurrent callers into one fetch', async () => {
356386
let resolveStatus: (value: {
357387
is_active: boolean

src/platform/cloud/subscription/composables/useSubscription.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -315,6 +315,7 @@ function useSubscriptionInternal() {
315315

316316
// Coalesce concurrent callers so an auth/session-rotation burst mints one fetch.
317317
let inFlightStatusFetch: Promise<BillingStatusResponse | null> | null = null
318+
let latestStatusRequestId = 0
318319

319320
async function fetchSubscriptionStatus(): Promise<BillingStatusResponse | null> {
320321
if (inFlightStatusFetch) return inFlightStatusFetch
@@ -327,6 +328,8 @@ function useSubscriptionInternal() {
327328
async function performFetchSubscriptionStatus(): Promise<BillingStatusResponse | null> {
328329
if (!isCloud) return null
329330

331+
const requestId = ++latestStatusRequestId
332+
const workspaceId = workspaceStore.activeWorkspaceId
330333
let statusData: BillingStatusResponse
331334
try {
332335
statusData = await workspaceApi.getBillingStatus()
@@ -337,10 +340,16 @@ function useSubscriptionInternal() {
337340
})
338341
)
339342
}
343+
if (
344+
requestId !== latestStatusRequestId ||
345+
workspaceId !== workspaceStore.activeWorkspaceId
346+
) {
347+
return null
348+
}
340349
subscriptionStatus.value = statusData
341-
if (workspaceStore.activeWorkspaceId && statusData.billing_rail) {
350+
if (workspaceId && statusData.billing_rail) {
342351
workspaceStore.setWorkspaceBillingRail(
343-
workspaceStore.activeWorkspaceId,
352+
workspaceId,
344353
statusData.billing_rail
345354
)
346355
}

0 commit comments

Comments
 (0)