import { beforeEach, describe, expect, test } from "bun:test"; import type { DenExternalMcpConnection } from "../src/app/lib/den"; import { clearCloudInventoryCache, loadConnectCapabilities, loadOrgMcpConnections, readCachedOrgMcpConnections, type OrgMcpConnectionClient, } from "../src/react-app/domains/connections/cloud-inventory-cache"; import type { ConnectCapabilityClient } from "../src/react-app/domains/session/surface/connect-capability-inventory"; const scope = { baseUrl: "https://den.example", organizationId: "org_1" }; function connection(id: string): DenExternalMcpConnection { return { id, organizationId: scope.organizationId, name: id, url: `https://${id}.example/mcp`, credentialMode: "per_member", connected: true, connectedForMe: true, status: "active", }; } function countingClient(result: DenExternalMcpConnection[]) { let calls = 0; const client: OrgMcpConnectionClient = { listMcpConnections: async () => { calls += 1; return result; }, }; return { client, calls: () => calls }; } describe("cloud inventory cache", () => { beforeEach(() => { clearCloudInventoryCache(); }); test("serves a fresh answer without going back to Den", async () => { const { client, calls } = countingClient([connection("notion")]); await loadOrgMcpConnections({ client, scope }); await loadOrgMcpConnections({ client, scope }); expect(calls()).toBe(1); expect(readCachedOrgMcpConnections(scope)?.map((entry) => entry.id)).toEqual(["notion"]); }); test("shares one request between callers that ask at the same time", async () => { const { client, calls } = countingClient([connection("linear")]); await Promise.all([ loadOrgMcpConnections({ client, scope }), loadOrgMcpConnections({ client, scope }), ]); expect(calls()).toBe(1); }); test("refetches when the caller asks for a fresher answer", async () => { const { client, calls } = countingClient([connection("notion")]); await loadOrgMcpConnections({ client, scope }); await loadOrgMcpConnections({ client, scope, maxAgeMs: 0 }); expect(calls()).toBe(2); }); test("keeps nothing for a different organization", async () => { const { client } = countingClient([connection("notion")]); await loadOrgMcpConnections({ client, scope }); expect(readCachedOrgMcpConnections({ ...scope, organizationId: "org_2" })).toBeNull(); }); test("keeps the last good answer when a refresh fails", async () => { const { client } = countingClient([connection("notion")]); await loadOrgMcpConnections({ client, scope }); const failing: OrgMcpConnectionClient = { listMcpConnections: async () => { throw new Error("den is down"); }, }; await expect(loadOrgMcpConnections({ client: failing, scope, maxAgeMs: 0 })).rejects.toThrow("den is down"); expect(readCachedOrgMcpConnections(scope)?.map((entry) => entry.id)).toEqual(["notion"]); }); test("does not keep an empty Connect inventory as fresh", async () => { let libraryRound = 0; const client: ConnectCapabilityClient = { listAssignedMarketplaceCapabilities: async () => [], listMeLibraryPlugins: async () => { libraryRound += 1; return libraryRound === 1 ? [] : [{ id: "plugin_mine", name: "Mine", description: null }]; }, listOrgMarketplaces: async () => [], getOrgMarketplaceResolved: async () => { throw new Error("unused"); }, getOrgPluginResolved: async (_organizationId, plugin) => ({ plugin, memberships: [ { id: "membership_1", pluginId: plugin.id, configObjectId: "skill_1", configObject: { id: "skill_1", objectType: "skill", title: "Mine skill", description: null, currentFileName: "SKILL.md", currentFileExtension: "md", currentRelativePath: "skills/mine/SKILL.md", status: "active", updatedAt: null, latestVersion: { id: "version_1", rawSourceText: "# Mine", normalizedPayloadJson: null, sourceRevisionRef: null, createdAt: null, }, }, }, ], }), }; await loadConnectCapabilities({ client, scope }); const second = await loadConnectCapabilities({ client, scope }); expect(libraryRound).toBe(2); expect(second.plugins.map((plugin) => plugin.pluginId)).toEqual(["plugin_mine"]); }); });