Compare commits

..

1 Commits

Author SHA1 Message Date
john 0d6a3b97df fix(auth): include subscription in auth status for balance ring
Memind CI / Test, build, and release guards (push) Failing after 5m54s
Refresh/login previously dropped active subscription from the client user
payload, so paid users saw a 0% balance ring despite valid plan quota.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-26 17:05:42 +08:00
4 changed files with 47 additions and 13 deletions
+1
View File
@@ -635,6 +635,7 @@ attachPortalCoreAuthRoutes({
resolveSkillRuntimeForClient,
resolveAgentCodeRunForClient,
resolveGoalRunForClient,
getSubscriptionService: () => subscriptionService,
getPlazaSeo: () => plazaSeo,
plazaClientIp,
logger: console,
+9 -1
View File
@@ -21,6 +21,7 @@ export function attachPortalCoreAuthRoutes({
resolveGoalRunForClient = async (userId) => ({
enabled: isGoalRunEnabledForUser(userId, process.env),
}),
getSubscriptionService = () => null,
getPlazaSeo = () => null,
plazaClientIp = (req) => req.ip,
logger = console,
@@ -64,9 +65,16 @@ export function attachPortalCoreAuthRoutes({
const agentCodeRun =
await resolveAgentCodeRunForClient(me.id);
const goalRun = await resolveGoalRunForClient(me.id);
const subscriptionService = getSubscriptionService();
const subscription = subscriptionService
? await subscriptionService.getActiveSubscription(me.id)
: null;
return res.json({
authenticated: true,
user: me,
user: {
...me,
subscription,
},
mode: 'user',
capabilities: capabilityState.capabilities,
grantedSkills:
+19 -1
View File
@@ -209,7 +209,7 @@ test('returns multi-user status and preserves capability projection', async () =
assert.equal(res.statusCode, 200);
assert.deepEqual(res.body, {
authenticated: true,
user: { id: 'user-1', username: 'john' },
user: { id: 'user-1', username: 'john', subscription: null },
mode: 'user',
capabilities: ['chat'],
grantedSkills: ['web'],
@@ -220,6 +220,24 @@ test('returns multi-user status and preserves capability projection', async () =
});
});
test('includes active subscription in auth status user payload', async () => {
const setup = createSetup({
getSubscriptionService: () => ({
async getActiveSubscription(userId) {
assert.equal(userId, 'user-1');
return {
planType: 'pro',
periodTokensLimit: 100_000_000,
periodTokensUsed: 0,
};
},
}),
});
const res = await invoke(setup, 'get', '/auth/status');
assert.equal(res.statusCode, 200);
assert.equal(res.body.user.subscription?.planType, 'pro');
});
test('preserves unavailable, legacy, and disabled status modes', async () => {
const unavailable = createSetup({
isDatabaseConfiguredFn: () => true,
+18 -11
View File
@@ -331,17 +331,24 @@ export async function checkAuth(): Promise<AuthStatus> {
}
if (status.authenticated) resetUnauthorizedGuard();
applyAgentCodeRunClientPolicy(status.agentCodeRun ?? null);
if (status.authenticated && status.mode === 'user' && !status.capabilities) {
try {
const me = await getMe();
return {
...status,
capabilities: me.capabilities,
grantedSkills: me.grantedSkills,
user: me.user,
};
} catch {
return status;
if (status.authenticated && status.mode === 'user') {
const needsMeHydration =
!status.capabilities
|| !status.user
|| !Object.prototype.hasOwnProperty.call(status.user, 'subscription');
if (needsMeHydration) {
try {
const me = await getMe();
return {
...status,
capabilities: me.capabilities ?? status.capabilities,
grantedSkills: me.grantedSkills ?? status.grantedSkills,
unrestricted: me.unrestricted ?? status.unrestricted,
user: me.user,
};
} catch {
return status;
}
}
}
return status;