diff --git a/components/nav.tsx b/components/nav.tsx index 4c985ea..df4ea28 100644 --- a/components/nav.tsx +++ b/components/nav.tsx @@ -3,7 +3,7 @@ import Link from "next/link"; import type { Route } from "next"; import { usePathname, useRouter, useParams } from "next/navigation"; import { useQuery } from "@tanstack/react-query"; -import { getApi } from "@/lib/api"; +import { getApi } from "@/lib/api/factory"; import { useAccount } from "wagmi"; import { cn } from "@/lib/utils"; import { ConnectButton } from "./wallet/connect-button"; diff --git a/lib/api/factory.ts b/lib/api/factory.ts new file mode 100644 index 0000000..303a6a5 --- /dev/null +++ b/lib/api/factory.ts @@ -0,0 +1,39 @@ +/** + * lib/api/factory.ts — narrow entry-point for `getApi`. + * + * This module exposes only the `getApi` factory so that components that + * need to call API methods do not transitively import the full barrel + * (`lib/api/index.ts`) with its mock-utility re-exports + * (`resetMockData`, `applyMockScenario`, etc.). + * + * Usage: + * import { getApi } from '@/lib/api/factory' + * + * The full barrel (`@/lib/api`) re-exports `getApi` from here, so + * existing consumers are unaffected. + */ + +import { config } from '../config' +import { LiveAccessApi } from './live' +import { createMockAccessApi } from './mock-boundary' +import type { AccessApi } from './types' + +export { checkVersionCompatibility } from './version' +export type { VersionCompatibility } from './version' + +/** + * Returns the appropriate API client based on the environment. + * + * @param address Connected wallet address (used for session/membership queries) + * @param token SIWE session token — pass this to authenticate admin mutations. + * Ignored by the mock client (mutations succeed unconditionally in mock mode). + * @param communityId Scoped community ID or slug + */ +export function getApi(address?: string, token?: string, communityId?: string): AccessApi { + if (config.apiMode === 'mock') return createMockAccessApi(address, communityId) + const api = new LiveAccessApi(address, token, communityId) + // Kick off the startup version compatibility check. It resolves in the + // background; callers can await api.checkVersion() for the result. + api.checkVersion() + return api +} diff --git a/lib/api/index.ts b/lib/api/index.ts index 7cdfa34..cef1ccf 100644 --- a/lib/api/index.ts +++ b/lib/api/index.ts @@ -1,35 +1,7 @@ -import { config } from '../config' -import { LiveAccessApi } from './live' -import { - createMockAccessApi, - resetMockData, - applyMockScenario, - replayMockEvent, - setMockRoleMutationFailure, - setMockMetaVersion, -} from './mock-boundary' -import { AccessApi } from './types' -import type { VersionCompatibility } from './version' - -export { checkVersionCompatibility } from './version' -export type { VersionCompatibility } - -/** - * Returns the appropriate API client based on the environment. - * - * @param address Connected wallet address (used for session/membership queries) - * @param token SIWE session token — pass this to authenticate admin mutations. - * Ignored by the mock client (mutations succeed unconditionally in mock mode). - * @param communityId Scoped community ID or slug - */ -export function getApi(address?: string, token?: string, communityId?: string): AccessApi { - if (config.apiMode === 'mock') return createMockAccessApi(address, communityId) - const api = new LiveAccessApi(address, token, communityId) - // Kick off the startup version compatibility check. It resolves in the - // background; callers can await api.checkVersion() for the result. - api.checkVersion() - return api -} +// Re-export getApi and version helpers from the narrow factory module so that +// existing consumers of `@/lib/api` continue to work unchanged. +export { getApi, checkVersionCompatibility } from './factory' +export type { VersionCompatibility } from './factory' export * from './types' export * from './mappers' diff --git a/lib/api/mock.ts b/lib/api/mock.ts index f459ed6..10079f5 100644 --- a/lib/api/mock.ts +++ b/lib/api/mock.ts @@ -26,6 +26,26 @@ * `lib/api/mock` (and `lib/api/index.ts`) relied on historically. * * All existing member/resource/policy data and mutation logic is preserved. + * + * ## Export naming conventions + * + * Exports are grouped into three categories: + * + * **Fixture data** (`mock*` camelCase) — mutable in-memory stores and their + * accessors (`communityStates`, `getCommunityState`, `mockConnections`, + * `mockPrivacySettings`, `mockReports`). Named with a lowercase `mock` + * prefix to distinguish live runtime state from the static `DEFAULT_*` / + * `MOCK_*` uppercase constants in `fixtures.ts`. + * + * **Controls** (`setMock*` / `resetMock*` / `applyMock*` / `MOCK_*`) — + * fault-injection toggles and scenario management functions. `setMock*` + * names toggle individual knobs; `resetMockData` / `applyMockScenario` + * operate at scenario level. + * + * **Standalone tools** — `replayMockEvent` is a dev-tool function that + * directly mutates the in-memory event store. It is not an `AccessApi` + * method delegate and intentionally does not follow the `mock*` method + * naming convention used for `MockAccessApi` internal delegates. */ import { config } from '../config' import { buildAnalyticsDataSource, mockGetAnalyticsSummary } from './mock/analytics' @@ -143,21 +163,39 @@ import type { WebhookEventUnsubscribe, } from './types' +// ── Exported fixture data (mutable in-memory stores) ────────────────────────── +// Named `mock*` (camelCase) to distinguish live fixtures from static `DEFAULT_*` +// and `MOCK_*` constants defined in lib/api/mock/fixtures.ts. export { - applyMockScenario, - communityStates, - getCommunityState, - MOCK_META_VERSION_OVERRIDE, + communityStates, // per-community runtime state map + getCommunityState, // accessor for per-community state mockConnections, mockPrivacySettings, mockReports, - replayMockEvent, +} + +// ── Exported control/setter functions ───────────────────────────────────────── +// Convention: `setMock*` for toggling fault-injection knobs; `resetMock*` / +// `applyMock*` for higher-level scenario management. +export { + MOCK_META_VERSION_OVERRIDE, + applyMockScenario, resetMockData, setMockMetaVersion, setMockResourceFetchDelay, setMockResourceFetchFailure, setMockRoleMutationFailure, } + +// ── Exported standalone tools ────────────────────────────────────────────────── +// `replayMockEvent` is a standalone dev-tool function (not an AccessApi method) +// that directly mutates the in-memory event store; it does not follow the +// `mock*` API-method naming convention used for MockAccessApi delegates. +export { + replayMockEvent, +} + +// ── Exported types ───────────────────────────────────────────────────────────── export type { CommunityState, MockApiContext } export class MockAccessApi implements AccessApi { diff --git a/lib/api/mock/domains.ts b/lib/api/mock/domains.ts index 17543c2..522358b 100644 --- a/lib/api/mock/domains.ts +++ b/lib/api/mock/domains.ts @@ -130,21 +130,37 @@ export const MOCK_API_DOMAINS = [ export type MockApiDomainFile = (typeof MOCK_API_DOMAINS)[number]['file'] -/** Public aggregator re-exports that existing `lib/api/mock` consumers rely on. */ +/** + * Public aggregator re-exports that existing `lib/api/mock` consumers rely on. + * + * Symbols are grouped by responsibility to make the distinction between + * data, controls, and standalone tools explicit: + * + * Fixture data — `mock*` (camelCase) mutable in-memory stores and + * their state-map accessors. + * Controls — `setMock*` fault-injection knobs; `resetMock*` / + * `applyMock*` for scenario management; the + * `MOCK_*` override constant. + * Standalone — `replayMockEvent` dev-tool that directly mutates + * the in-memory event store (not an AccessApi method). + */ export const MOCK_API_PUBLIC_REEXPORTS = [ - 'applyMockScenario', + // ── Fixture data ──────────────────────────────────────────────────────────── 'communityStates', 'getCommunityState', - 'MOCK_META_VERSION_OVERRIDE', 'mockConnections', 'mockPrivacySettings', 'mockReports', - 'replayMockEvent', + // ── Controls ──────────────────────────────────────────────────────────────── + 'MOCK_META_VERSION_OVERRIDE', + 'applyMockScenario', 'resetMockData', 'setMockMetaVersion', 'setMockResourceFetchDelay', 'setMockResourceFetchFailure', 'setMockRoleMutationFailure', + // ── Standalone tools ──────────────────────────────────────────────────────── + 'replayMockEvent', ] as const /** AccessApi methods that MockAccessApi must keep implementing. */ diff --git a/test/mock-api-structure.test.ts b/test/mock-api-structure.test.ts index 3ad6f8f..e32190b 100644 --- a/test/mock-api-structure.test.ts +++ b/test/mock-api-structure.test.ts @@ -164,7 +164,10 @@ describe('mock API domain module structure', () => { assert.match(indexSource, /from '\.\/mock-boundary'/) assert.doesNotMatch(indexSource, /from '\.\/mock\//) - assert.match(navSource, /from ["']@\/lib\/api["']/) + // nav.tsx may import from the top-level barrel (@/lib/api) or from the + // narrow factory module (@/lib/api/factory) — both are API-boundary + // imports that do not reach mock implementation details directly. + assert.match(navSource, /from ["']@\/lib\/api(\/factory)?["']/) assert.doesNotMatch(navSource, /from ["']@\/lib\/api\/mock/) }) })