Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions apps/web/src/app/api/cron/minimax-token-health/route.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
jest.mock('@/lib/config.server', () => ({ CRON_SECRET: 'cron-secret' }));
jest.mock('@/lib/coding-plans/minimax-token-health', () => ({
sendMiniMaxTokenHealthSlackSummary: jest.fn(),
}));
jest.mock('@sentry/nextjs', () => ({ captureException: jest.fn() }));

import { captureException } from '@sentry/nextjs';
import { sendMiniMaxTokenHealthSlackSummary } from '@/lib/coding-plans/minimax-token-health';
import { GET } from './route';

const mockSendSummary = jest.mocked(sendMiniMaxTokenHealthSlackSummary);
const mockCaptureException = jest.mocked(captureException);

function request(authorization?: string) {
return new Request('http://localhost:3000/api/cron/minimax-token-health', {
headers: authorization ? { authorization } : undefined,
});
}

describe('GET /api/cron/minimax-token-health', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('rejects invalid cron authorization', async () => {
const response = await GET(request('Bearer wrong-secret'));

expect(response.status).toBe(401);
await expect(response.json()).resolves.toEqual({ error: 'Unauthorized' });
expect(mockSendSummary).not.toHaveBeenCalled();
});

it('sends the current token health summary for valid cron authorization', async () => {
mockSendSummary.mockResolvedValue({
checked: 160,
healthy: 155,
badResponse: 3,
denied: 1,
unreachable: 1,
configuration: 0,
needsFollowUp: 4,
});

const response = await GET(request('Bearer cron-secret'));

expect(response.status).toBe(200);
await expect(response.json()).resolves.toMatchObject({
success: true,
totals: { checked: 160, healthy: 155, needsFollowUp: 4 },
});
expect(mockSendSummary).toHaveBeenCalledTimes(1);
});

it('returns a failed cron response when the sweep fails', async () => {
const error = new Error('Slack unavailable');
mockSendSummary.mockRejectedValue(error);

const response = await GET(request('Bearer cron-secret'));

expect(response.status).toBe(500);
await expect(response.json()).resolves.toEqual({
success: false,
error: 'Failed to send MiniMax token health summary',
});
expect(mockCaptureException).toHaveBeenCalledWith(error, {
tags: { endpoint: 'cron/minimax-token-health' },
});
});
});
44 changes: 44 additions & 0 deletions apps/web/src/app/api/cron/minimax-token-health/route.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { captureException } from '@sentry/nextjs';
import { NextResponse } from 'next/server';

import { CRON_SECRET } from '@/lib/config.server';
import { isCronAuthorizationValid } from '@/lib/cron-auth';
import { sendMiniMaxTokenHealthSlackSummary } from '@/lib/coding-plans/minimax-token-health';

if (!CRON_SECRET) {
throw new Error('CRON_SECRET is not configured in environment variables');
}

// Fans out to every assigned MiniMax key at bounded concurrency
// (MINIMAX_TOKEN_HEALTH_CONCURRENCY); size the duration for that fan-out
// rather than the platform default, matching usage-daily-rollup-repairs.
export const maxDuration = 300;

export async function GET(request: Request) {
if (!isCronAuthorizationValid(request.headers.get('authorization'), CRON_SECRET)) {
return NextResponse.json({ error: 'Unauthorized' }, { status: 401 });
}

try {
const totals = await sendMiniMaxTokenHealthSlackSummary();
console.info('[cron/minimax-token-health] sent', totals);

return NextResponse.json({
success: true,
totals,
timestamp: new Date().toISOString(),
});
} catch (error) {
console.error('[cron/minimax-token-health] failed', {
errorName: error instanceof Error ? error.name : 'UnknownError',
});
captureException(error, {
tags: { endpoint: 'cron/minimax-token-health' },
});

return NextResponse.json(
{ success: false, error: 'Failed to send MiniMax token health summary' },
{ status: 500 }
);
}
}
266 changes: 266 additions & 0 deletions apps/web/src/lib/coding-plans/minimax-token-health.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
jest.mock('@/lib/ai-gateway/byok/encryption', () => ({
decryptApiKey: jest.fn(() => 'plaintext-api-key'),
}));

const mockOrderBy = jest.fn<Promise<unknown[]>, []>();
jest.mock('@/lib/drizzle', () => ({
db: {
select: jest.fn(() => ({
from: jest.fn(() => ({
leftJoin: jest.fn(() => ({
where: jest.fn(() => ({
orderBy: mockOrderBy,
})),
})),
})),
})),
},
}));

import { describe, expect, it } from '@jest/globals';

import type { AdminSlackNotification } from '@/lib/slack/admin-notifications';
import {
buildMiniMaxTokenHealthSlackNotification,
checkAllMiniMaxTokenHealth,
getMiniMaxTokenHealthTargets,
needsImmediateFollowUp,
sendMiniMaxTokenHealthSlackSummary,
type MiniMaxTokenHealthEntry,
type MiniMaxTokenHealthTarget,
} from './minimax-token-health';

function target(overrides: Partial<MiniMaxTokenHealthTarget> = {}): MiniMaxTokenHealthTarget {
return {
inventoryId: 'inv-1',
planId: 'minimax-token-plan-plus',
upstreamPlanId: '522927812420526084',
encryptedApiKey: { iv: 'iv', data: 'data', authTag: 'tag' },
subscriptionId: 'sub-1',
userId: 'user-1',
subscriptionStatus: 'active',
...overrides,
};
}

function entry(overrides: Partial<MiniMaxTokenHealthEntry> = {}): MiniMaxTokenHealthEntry {
return {
inventoryId: 'inv-1',
planId: 'minimax-token-plan-plus',
upstreamPlanId: '522927812420526084',
subscriptionId: 'sub-1',
userId: 'user-1',
subscriptionStatus: 'active',
category: 'healthy',
reason: 'ok',
...overrides,
};
}

describe('getMiniMaxTokenHealthTargets', () => {
it('keeps the most recently created live subscription when a key has more than one', async () => {
mockOrderBy.mockResolvedValueOnce([
{
inventoryId: 'inv-1',
planId: 'minimax-token-plan-plus',
upstreamPlanId: '522927812420526084',
encryptedApiKey: null,
subscriptionId: 'sub-old',
userId: 'user-old',
subscriptionStatus: 'active',
subscriptionCreatedAt: '2026-01-01T00:00:00.000Z',
},
{
inventoryId: 'inv-1',
planId: 'minimax-token-plan-plus',
upstreamPlanId: '522927812420526084',
encryptedApiKey: null,
subscriptionId: 'sub-new',
userId: 'user-new',
subscriptionStatus: 'past_due',
subscriptionCreatedAt: '2026-02-01T00:00:00.000Z',
},
{
inventoryId: 'inv-2',
planId: 'minimax-token-plan-plus',
upstreamPlanId: '522937595127087110',
encryptedApiKey: null,
subscriptionId: 'sub-2',
userId: 'user-2',
subscriptionStatus: 'active',
subscriptionCreatedAt: '2026-01-15T00:00:00.000Z',
},
]);

const targets = await getMiniMaxTokenHealthTargets();

expect(targets).toHaveLength(2);
expect(targets[0]).toMatchObject({ inventoryId: 'inv-1', subscriptionId: 'sub-new' });
expect(targets[0]).not.toHaveProperty('subscriptionCreatedAt');
expect(targets[1]).toMatchObject({ inventoryId: 'inv-2', subscriptionId: 'sub-2' });
});
});

describe('needsImmediateFollowUp', () => {
it('flags non-healthy categories only for active or past_due subscriptions', () => {
expect(
needsImmediateFollowUp(entry({ category: 'denied', subscriptionStatus: 'active' }))
).toBe(true);
expect(
needsImmediateFollowUp(entry({ category: 'bad_response', subscriptionStatus: 'past_due' }))
).toBe(true);
expect(
needsImmediateFollowUp(entry({ category: 'denied', subscriptionStatus: 'canceled' }))
).toBe(false);
expect(needsImmediateFollowUp(entry({ category: 'denied', subscriptionStatus: null }))).toBe(
false
);
expect(
needsImmediateFollowUp(entry({ category: 'healthy', subscriptionStatus: 'active' }))
).toBe(false);
});
});

describe('checkAllMiniMaxTokenHealth', () => {
it('probes each target with the decrypted key and reports totals-relevant fields', async () => {
const getTargets = jest.fn(async () => [
target({ inventoryId: 'inv-1' }),
target({ inventoryId: 'inv-2', encryptedApiKey: null, subscriptionStatus: 'past_due' }),
]);
const probe = jest.fn(async (_apiKey: string) => ({
category: 'healthy' as const,
reason: 'ok',
}));

const results = await checkAllMiniMaxTokenHealth({ getTargets, probe });

expect(results).toHaveLength(2);
expect(results[0]).toMatchObject({ inventoryId: 'inv-1', category: 'healthy', reason: 'ok' });
expect(probe).toHaveBeenCalledTimes(1);
expect(probe).toHaveBeenCalledWith('plaintext-api-key');
expect(results[1]).toMatchObject({
inventoryId: 'inv-2',
category: 'configuration',
reason: 'missing_api_key',
});
});

it('reports a configuration failure when decryption throws', async () => {
const encryption = jest.requireMock<{ decryptApiKey: jest.Mock }>(
'@/lib/ai-gateway/byok/encryption'
);
encryption.decryptApiKey.mockImplementationOnce(() => {
throw new Error('bad key');
});
const getTargets = jest.fn(async () => [target()]);
const probe = jest.fn(async (_apiKey: string) => ({
category: 'healthy' as const,
reason: 'ok',
}));

const results = await checkAllMiniMaxTokenHealth({ getTargets, probe });

expect(results).toEqual([
expect.objectContaining({ category: 'configuration', reason: 'decryption_failed' }),
]);
expect(probe).not.toHaveBeenCalled();
});
});

describe('buildMiniMaxTokenHealthSlackNotification', () => {
it('summarizes totals and reports no follow-up needed when everything is healthy', () => {
const result = buildMiniMaxTokenHealthSlackNotification(
[entry({ inventoryId: 'inv-1' }), entry({ inventoryId: 'inv-2' })],
new Date('2026-09-17T12:00:00.000Z')
);

expect(result.totals).toEqual({
checked: 2,
healthy: 2,
badResponse: 0,
denied: 0,
unreachable: 0,
configuration: 0,
needsFollowUp: 0,
});
expect(result.notification.text).toContain('`2` checked');
expect(result.notification.text).toContain('`0` active subscriptions need follow-up');
expect(JSON.stringify(result.notification.blocks)).toContain(
'No active subscriptions need follow-up.'
);
});

it('lists active subscriptions that need immediate follow-up', () => {
const result = buildMiniMaxTokenHealthSlackNotification([
entry({ inventoryId: 'inv-1', category: 'healthy', reason: 'ok' }),
entry({
inventoryId: 'inv-2',
subscriptionId: 'sub-2',
upstreamPlanId: '522937595127087110',
category: 'bad_response',
reason: 'provider_plan_inactive',
subscriptionStatus: 'active',
}),
entry({
inventoryId: 'inv-3',
subscriptionId: 'sub-3',
upstreamPlanId: '522937971515547655',
category: 'denied',
reason: 'http_429',
httpStatus: 429,
subscriptionStatus: 'past_due',
}),
// Not counted: no live subscription attached to this key.
entry({
inventoryId: 'inv-4',
subscriptionId: null,
category: 'denied',
reason: 'http_429',
subscriptionStatus: null,
}),
]);

expect(result.totals).toMatchObject({ checked: 4, needsFollowUp: 2 });
const rendered = JSON.stringify(result.notification.blocks);
expect(rendered).toContain('522937595127087110');
expect(rendered).toContain('provider_plan_inactive');
expect(rendered).toContain('522937971515547655');
expect(rendered).toContain('http_429 (HTTP 429)');
expect(rendered).not.toContain('inv-4');
expect(result.notification.text).toContain('`2` active subscriptions need follow-up');
});

it('truncates the follow-up list and reports the omitted count', () => {
const entries = Array.from({ length: 45 }, (_, index) =>
entry({
inventoryId: `inv-${index}`,
subscriptionId: `sub-${index}`,
upstreamPlanId: `plan-${index}`,
category: 'denied',
reason: 'http_429',
})
);

const result = buildMiniMaxTokenHealthSlackNotification(entries);

expect(result.totals.needsFollowUp).toBe(45);
const rendered = JSON.stringify(result.notification.blocks);
expect(rendered).toContain('5 additional entries not shown.');
});
});

describe('sendMiniMaxTokenHealthSlackSummary', () => {
it('runs the sweep and sends the generated notification', async () => {
const checkAll = jest.fn(async () => [entry()]);
const sendNotification = jest.fn(async (_notification: AdminSlackNotification) => undefined);

await expect(
sendMiniMaxTokenHealthSlackSummary({ checkAll, sendNotification })
).resolves.toMatchObject({ checked: 1, healthy: 1 });

expect(checkAll).toHaveBeenCalledWith();
expect(sendNotification).toHaveBeenCalledWith(
expect.objectContaining({ text: expect.stringContaining('`1` checked') })
);
});
});
Loading
Loading