Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
802b510
Generated with Hive: Fix graph-admin mock routing and extend mock cmd…
tomsmith8 Apr 7, 2026
d6618cf
Merge remote-tracking branch 'origin/master' into feature/cmnofnuqa00…
tomsmith8 Apr 7, 2026
e5bfae2
Merge origin/master - resolve double-encoded JSON comment conflict
tomsmith8 Apr 7, 2026
7a8323f
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 7, 2026
3614d5e
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 7, 2026
8e4daab
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 7, 2026
ae9e6f7
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 7, 2026
86e0abf
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 7, 2026
e53a450
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 7, 2026
6fd7b18
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 8, 2026
5db0e2e
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 8, 2026
1b0c89a
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 8, 2026
b7a5252
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 8, 2026
af3c56d
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 8, 2026
2d21db0
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 8, 2026
c505400
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 8, 2026
0a2129c
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 8, 2026
26a69ce
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 8, 2026
b97fbf5
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 9, 2026
7f60ada
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 9, 2026
1f8a032
fix: resolve merge conflict in mock swarm cmd route
tomsmith8 Apr 9, 2026
55241dc
Merge remote-tracking branch 'origin/master' into feature/cmnofnuqa00…
tomsmith8 Apr 9, 2026
80b7218
fix: update GetBotBalance test to match new response shape
tomsmith8 Apr 9, 2026
e71a82d
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 9, 2026
08d10a4
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 9, 2026
6742824
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 9, 2026
35170b9
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 9, 2026
59c7dc2
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 9, 2026
0140310
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 9, 2026
a3efe46
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 9, 2026
0ff0763
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 9, 2026
29b45d6
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 10, 2026
836c67a
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 10, 2026
0a23992
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 10, 2026
c82ba50
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 10, 2026
8434087
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 10, 2026
7faa462
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 10, 2026
9641881
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 10, 2026
a0caa91
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 10, 2026
02c2120
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 11, 2026
8c200e2
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 12, 2026
717f24b
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 12, 2026
42bb7c6
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 12, 2026
4c1794f
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 13, 2026
009b4b4
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 13, 2026
aeb527b
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 13, 2026
b18a071
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 13, 2026
b2634e3
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 13, 2026
9f70bc0
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 13, 2026
3368d1e
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 13, 2026
22191f2
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
d486d18
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
fe6fd37
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
3c34339
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
bc3bfa6
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
da22caa
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
58f03b5
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
18bb5de
Resolve merge conflict: add GetSecondBrainAboutDetails/UpdateSecondBr…
tomsmith8 Apr 14, 2026
c419567
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
50ee9ef
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
bf64eab
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
bc97098
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
2693f14
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
349674b
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
e9e4c8a
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
f6c85a2
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
6258aed
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
b86946d
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
0f27695
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
7645f28
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
ce151e3
Fix flaky test: wait for model select to render before asserting
tomsmith8 Apr 14, 2026
ee77a3c
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
c332a6f
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
3d54048
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
a64d32b
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 14, 2026
559c864
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 15, 2026
a17699f
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 15, 2026
2fa5269
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 15, 2026
17d2637
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 15, 2026
ba4d154
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 15, 2026
b19b246
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 15, 2026
a6d7d21
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 16, 2026
71bf6eb
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 16, 2026
ad8163e
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 16, 2026
bb112c8
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 16, 2026
bafdc7c
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 16, 2026
67e6b9b
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 16, 2026
cb427e2
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 16, 2026
feeea50
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 17, 2026
9591ad9
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 17, 2026
c1f93a1
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 17, 2026
3d1d7f8
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 17, 2026
2c1afc5
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 17, 2026
3887234
Merge branch 'master' into feature/cmnofnuqa00a8ky04t14fz7ed-fix-grap…
tomsmith8 Apr 17, 2026
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
109 changes: 108 additions & 1 deletion src/__tests__/unit/api/mock/swarm-credentials-and-cmd.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, it, expect, vi } from "vitest";
import { describe, it, expect, vi, beforeEach } from "vitest";

vi.mock("@/config/env", () => ({
env: {
Expand Down Expand Up @@ -246,3 +246,110 @@ describe("GET /api/mock/swarm-super-admin/api/cmd", () => {
expect(data).toMatchObject({ error: expect.stringContaining("Missing txt") });
});
});

// ---------------------------------------------------------------------------
// Boltwall stateful commands
// ---------------------------------------------------------------------------

describe("Boltwall stateful mock commands", () => {
// Reset state before each test to ensure isolation
beforeEach(async () => {
const { resetMockBoltwallState } = await import(
"@/app/api/mock/swarm-super-admin/api/cmd/state"
);
resetMockBoltwallState();
});

async function cmdRequest(cmd: object) {
const { GET } = await import(
"@/app/api/mock/swarm-super-admin/api/cmd/route"
);
const txt = encodeURIComponent(JSON.stringify(cmd));
return GET(
makeRequest(
`http://localhost/api/mock/swarm-super-admin/api/cmd?txt=${txt}`,
{ headers: { "x-jwt": "mock-jwt-token" } }
)
);
}

it("GetBoltwallAccessibility returns { isPublic: false } by default", async () => {
const res = await cmdRequest({ cmd: "GetBoltwallAccessibility" });
const data = await res.json();
expect(res.status).toBe(200);
expect(data).toEqual({ isPublic: false });
});

it("UpdateBoltwallAccessibility + GetBoltwallAccessibility round-trip", async () => {
// Set to true
const updateRes = await cmdRequest({
type: "Swarm",
data: { cmd: "UpdateBoltwallAccessibility", content: true },
});
expect(updateRes.status).toBe(200);
expect(await updateRes.json()).toEqual({ success: true });

// Confirm state persisted
const getRes = await cmdRequest({ cmd: "GetBoltwallAccessibility" });
expect(getRes.status).toBe(200);
expect(await getRes.json()).toEqual({ isPublic: true });
});

it("ListPaidEndpoint returns 2 endpoints by default", async () => {
const res = await cmdRequest({ cmd: "ListPaidEndpoint" });
const data = await res.json();
expect(res.status).toBe(200);
expect(data.endpoints).toHaveLength(2);
expect(data.endpoints[0]).toMatchObject({ id: 1, route: "v2/search" });
expect(data.endpoints[1]).toMatchObject({ id: 2, route: "node/content" });
});

it("UpdatePaidEndpoint mutates endpoint status", async () => {
// Disable endpoint id=1
const updateRes = await cmdRequest({
type: "Swarm",
data: { cmd: "UpdatePaidEndpoint", content: { id: 1, status: false } },
});
expect(updateRes.status).toBe(200);
expect(await updateRes.json()).toEqual({ success: true });

// Re-fetch and confirm
const listRes = await cmdRequest({ cmd: "ListPaidEndpoint" });
const data = await listRes.json();
const ep1 = data.endpoints.find((e: { id: number }) => e.id === 1);
expect(ep1.status).toBe(false);
// Other endpoint unchanged
const ep2 = data.endpoints.find((e: { id: number }) => e.id === 2);
expect(ep2.status).toBe(true);
});

it("GetBoltwallSuperAdmin returns { pubkey: null, name: null }", async () => {
const res = await cmdRequest({ cmd: "GetBoltwallSuperAdmin" });
const data = await res.json();
expect(res.status).toBe(200);
expect(data).toEqual({ pubkey: null, name: null });
});

it("GetBotBalance returns { success: true, data: { msat } }", async () => {
const res = await cmdRequest({ cmd: "GetBotBalance" });
const data = await res.json();
expect(res.status).toBe(200);
expect(data).toEqual({ success: true, message: "bot balance retrieved", data: { msat: 30000 } });
});

it("CreateBotInvoice returns an invoice string", async () => {
const res = await cmdRequest({
type: "Swarm",
data: { cmd: "CreateBotInvoice", content: { amt_msat: 1000 } },
});
const data = await res.json();
expect(res.status).toBe(200);
expect(typeof data.invoice).toBe("string");
});

it("state resets between tests (isPublic is false again)", async () => {
const res = await cmdRequest({ cmd: "GetBoltwallAccessibility" });
const data = await res.json();
expect(data).toEqual({ isPublic: false });
});
});
12 changes: 3 additions & 9 deletions src/__tests__/unit/components/features/CompactTasksList.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1611,18 +1611,12 @@ describe("CompactTasksList", () => {
/>
);

// Wait until the model select (data-value="") is present, meaning models have loaded
await waitFor(() => {
// Models should be loaded - find the model select by its empty value
const selects = screen.getAllByTestId("select");
expect(selects.length).toBeGreaterThanOrEqual(1);
const modelSelect = selects.find((s) => s.getAttribute("data-value") === "");
expect(modelSelect).toBeDefined();
});

// Simulate onValueChange being called with a model value
// The Select mock renders a div with data-testid="select" and data-value
// We need to find the model select - it's the one with value="" (task.model is null)
const selects = screen.getAllByTestId("select");
const modelSelect = selects.find((s) => s.getAttribute("data-value") === "");
expect(modelSelect).toBeDefined();
});

test("shows existing model value in selector", async () => {
Expand Down
59 changes: 55 additions & 4 deletions src/__tests__/unit/services/swarm/cmd.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { describe, test, expect, beforeEach, vi } from "vitest";
import { describe, test, expect, beforeEach, afterEach, vi } from "vitest";

// Mock fetch globally before importing
const mockFetch = vi.fn();
Expand All @@ -7,8 +7,21 @@ global.fetch = mockFetch;
const { getSwarmCmdJwt, swarmCmdRequest } = await import("@/services/swarm/cmd");

describe("getSwarmCmdJwt", () => {
let savedUseMocks: string | undefined;

beforeEach(() => {
vi.clearAllMocks();
// Ensure production routing (no mocks) for getSwarmCmdJwt tests
savedUseMocks = process.env.USE_MOCKS;
delete process.env.USE_MOCKS;
});

afterEach(() => {
if (savedUseMocks !== undefined) {
process.env.USE_MOCKS = savedUseMocks;
} else {
delete process.env.USE_MOCKS;
}
});

const swarmUrl = "https://swarm42.sphinx.chat";
Expand Down Expand Up @@ -114,14 +127,23 @@ describe("getSwarmCmdJwt", () => {
});
});

// ---------------------------------------------------------------------------
// swarmCmdRequest — USE_MOCKS routing + double-encoded JSON handling
// ---------------------------------------------------------------------------

describe("swarmCmdRequest", () => {
const swarmUrl = "https://swarm42.sphinx.chat";
const jwt = "test-jwt-token";
const cmd = { type: "Swarm" as const, data: { cmd: "GetBoltwallAccessibility" as const } };

beforeEach(() => {
vi.clearAllMocks();
delete process.env.USE_MOCKS;
});

const swarmUrl = "https://swarm42.sphinx.chat";
const jwt = "test-jwt-token";
const cmd = { type: "Swarm" as const, data: { cmd: "GetBoltwallAccessibility" as const } };
afterEach(() => {
delete process.env.USE_MOCKS;
});

test("parses normal (single-encoded) JSON correctly", async () => {
mockFetch.mockResolvedValue({
Expand Down Expand Up @@ -209,4 +231,33 @@ describe("swarmCmdRequest", () => {
const [, init] = mockFetch.mock.calls[0];
expect(init.headers["x-jwt"]).toBe(jwt);
});

test("routes to host:8800 in production (no USE_MOCKS)", async () => {
mockFetch.mockResolvedValue({
ok: true,
status: 200,
text: async () => JSON.stringify({ isPublic: false }),
});

await swarmCmdRequest({ swarmUrl, jwt, cmd });

const [url] = mockFetch.mock.calls[0];
expect(url).toContain("swarm42.sphinx.chat:8800/api/cmd");
});

test("routes to NEXTAUTH_URL mock endpoint when USE_MOCKS=true", async () => {
process.env.USE_MOCKS = "true";
process.env.NEXTAUTH_URL = "http://localhost:3000";

mockFetch.mockResolvedValue({
ok: true,
status: 200,
text: async () => JSON.stringify({ isPublic: false }),
});

await swarmCmdRequest({ swarmUrl, jwt, cmd });

const [url] = mockFetch.mock.calls[0];
expect(url).toContain("localhost:3000/api/mock/swarm-super-admin/api/cmd");
});
});
63 changes: 60 additions & 3 deletions src/app/api/mock/swarm-super-admin/api/cmd/route.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,20 @@
import { NextRequest, NextResponse } from "next/server";
import {
mockIsPublic,
mockEndpoints,
setMockIsPublic,
setMockEndpoints,
} from "./state";

const MOCK_CONTAINERS = [
{ name: "sphinx", status: "running", image: "sphinxlightning/sphinx-relay:latest" },
{ name: "neo4j", status: "running", image: "neo4j:5" },
{ name: "lnd", status: "stopped", image: "lightninglabs/lnd:v0.18" },
];

// ---------------------------------------------------------------------------
// Static responses
// ---------------------------------------------------------------------------
const MOCK_RESPONSES: Record<string, unknown> = {
ListContainers: { containers: MOCK_CONTAINERS },
StartContainer: { success: true },
Expand All @@ -25,6 +34,18 @@ const MOCK_RESPONSES: Record<string, unknown> = {
"lightninglabs/lnd": "v0.18",
},
},
// Boltwall admin
GetBoltwallSuperAdmin: { pubkey: null, name: null },
ListAdmins: { admins: [] },
GetBotBalance: { success: true, message: "bot balance retrieved", data: { msat: 30000 } },
CreateBotInvoice: { invoice: "lnbcrt1mock000000000" },
AddBoltwallUser: { success: true },
AddBoltwallAdminPubkey: { success: true },
DeleteSubAdmin: { success: true },
UpdateUser: { success: true },
GetEnrichedBoltwallUsers: { users: [] },
UpdateNeo4jConfig: { success: true },
UpdateEnv: { success: true },
GetBoltwallAccessibility: { isPublic: false },
UpdateBoltwallAccessibility: { success: true },
ListPaidEndpoint: {
Expand All @@ -34,7 +55,6 @@ const MOCK_RESPONSES: Record<string, unknown> = {
],
},
UpdatePaidEndpoint: { success: true },
GetBotBalance: { success: true, message: "bot balance retrieved", data: { msat: 30000 } },
GetSecondBrainAboutDetails: { title: "mock-graph", description: "" },
UpdateSecondBrainAbout: { success: true },
};
Expand All @@ -56,7 +76,7 @@ export async function GET(request: NextRequest) {
return NextResponse.json({ error: "Missing txt param" }, { status: 400 });
}

let parsed: { cmd?: string; data?: { cmd?: string } };
let parsed: { type?: string; cmd?: string; data?: { cmd?: string; content?: unknown }; content?: unknown };
try {
parsed = JSON.parse(txt);
} catch {
Expand All @@ -66,7 +86,44 @@ export async function GET(request: NextRequest) {
// SwarmCmd shape: { type: "Swarm", data: { cmd: "..." } }
// Fall back to top-level .cmd for legacy callers
const cmd = parsed.data?.cmd ?? parsed.cmd;
if (!cmd || !(cmd in MOCK_RESPONSES)) {
const content = parsed.data?.content ?? parsed.content;

if (!cmd) {
return NextResponse.json({ error: "Unknown cmd: undefined" }, { status: 400 });
}

// ---------------------------------------------------------------------------
// Stateful boltwall commands
// ---------------------------------------------------------------------------
if (cmd === "GetBoltwallAccessibility") {
return NextResponse.json({ isPublic: mockIsPublic });
}

if (cmd === "UpdateBoltwallAccessibility") {
setMockIsPublic(Boolean(content));
return NextResponse.json({ success: true });
}

if (cmd === "ListPaidEndpoint") {
return NextResponse.json({ endpoints: mockEndpoints });
}

if (cmd === "UpdatePaidEndpoint") {
const update = content as { id?: number; status?: boolean } | undefined;
if (update?.id !== undefined) {
setMockEndpoints(
mockEndpoints.map((ep) =>
ep.id === update.id ? { ...ep, status: Boolean(update.status) } : ep
)
);
}
return NextResponse.json({ success: true });
}

// ---------------------------------------------------------------------------
// Static responses
// ---------------------------------------------------------------------------
if (!(cmd in MOCK_RESPONSES)) {
return NextResponse.json({ error: `Unknown cmd: ${cmd}` }, { status: 400 });
}

Expand Down
32 changes: 32 additions & 0 deletions src/app/api/mock/swarm-super-admin/api/cmd/state.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
// ---------------------------------------------------------------------------
// Mutable boltwall state (reset between tests via resetMockBoltwallState)
// ---------------------------------------------------------------------------
export interface PaidEndpoint {
id: number;
route: string;
method: string;
status: boolean;
fee: number;
}

export let mockIsPublic = false;
export let mockEndpoints: PaidEndpoint[] = [
{ id: 1, route: "v2/search", method: "GET", status: true, fee: 10 },
{ id: 2, route: "node/content", method: "POST", status: true, fee: 10 },
];

export function resetMockBoltwallState() {
mockIsPublic = false;
mockEndpoints = [
{ id: 1, route: "v2/search", method: "GET", status: true, fee: 10 },
{ id: 2, route: "node/content", method: "POST", status: true, fee: 10 },
];
}

export function setMockIsPublic(value: boolean) {
mockIsPublic = value;
}

export function setMockEndpoints(endpoints: PaidEndpoint[]) {
mockEndpoints = endpoints;
}
13 changes: 12 additions & 1 deletion src/lib/auth/nextauth.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { db } from "@/lib/db";
import { EncryptionService } from "@/lib/encryption";
import { logger } from "@/lib/logger";
import { ensureMockWorkspaceForUser, ensureStakworkMockWorkspace, ensureMockOrgData } from "@/utils/mockSetup";
import { ensureMockWorkspaceForUser, ensureStakworkMockWorkspace, ensureMockOrgData, ensureGraphMindsetMockWorkspace } from "@/utils/mockSetup";
import { isSuperAdminUserId } from "@/config/env";
import { PrismaAdapter } from "@auth/prisma-adapter";
import axios from "axios";
Expand Down Expand Up @@ -271,6 +271,17 @@ export const authOptions: NextAuthOptions = {
error
);
}

// Create graph_mindset workspace for testing /graph-admin — non-fatal
try {
await ensureGraphMindsetMockWorkspace(user.id as string);
} catch (error) {
logger.authError(
"Failed to create graph_mindset mock workspace - continuing authentication",
"SIGNIN_GRAPH_MINDSET_FAILED",
error
);
}
} catch (error) {
logger.authError("Failed to handle mock authentication", "SIGNIN_MOCK", error);
return false;
Expand Down
Loading
Loading