From 2cddea362c1041b9b812ee7f17e267c879f6339f Mon Sep 17 00:00:00 2001 From: MarcusDavidG Date: Sat, 22 Aug 2026 16:33:26 +0100 Subject: [PATCH 1/2] refactor: narrow nav.tsx API import to lib/api/factory (#387) Introduce lib/api/factory.ts as a dedicated narrow entry-point that exports only getApi (and the version helpers it re-exports). Move the getApi implementation there from lib/api/index.ts. Update components/nav.tsx to import getApi from @/lib/api/factory instead of the full @/lib/api barrel. The barrel previously pulled in every mock-utility re-export (resetMockData, applyMockScenario, etc.) via mock-boundary, meaning a syntax error in mock.ts could prevent the navigation component from compiling. lib/api/index.ts is updated to re-export getApi from ./factory so all existing consumers of @/lib/api are unaffected. Closes #387 --- components/nav.tsx | 2 +- lib/api/factory.ts | 39 +++++++++++++++++++++++++++++++++++++++ lib/api/index.ts | 36 ++++-------------------------------- 3 files changed, 44 insertions(+), 33 deletions(-) create mode 100644 lib/api/factory.ts 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' From 39abb2d65113134675b978bb6fa4c195a67a9014 Mon Sep 17 00:00:00 2001 From: MarcusDavidG Date: Sat, 22 Aug 2026 16:40:10 +0100 Subject: [PATCH 2/2] refactor: normalize mock API module exports and naming (#388) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Group the export block in lib/api/mock.ts into three clearly labelled sections — fixture data, control functions, and standalone tools — so the distinction between data and behavior is immediately visible. Add an '## Export naming conventions' section to the module-level JSDoc that documents the three categories and explains why replayMockEvent is intentionally separated from the mock* API-method delegates. Update MOCK_API_PUBLIC_REEXPORTS in lib/api/mock/domains.ts with matching section comments and an expanded JSDoc so the contract document stays in sync with the module it tests. Update the 'application consumers depend on the API boundary' assertion in test/mock-api-structure.test.ts to accept @/lib/api/factory as a valid nav import path (introduced in #387 to narrow the nav dependency surface). No symbol renames, no behavior changes, no fixture value changes. Closes #388 --- lib/api/mock.ts | 48 +++++++++++++++++++++++++++++---- lib/api/mock/domains.ts | 24 ++++++++++++++--- test/mock-api-structure.test.ts | 5 +++- 3 files changed, 67 insertions(+), 10 deletions(-) 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/) }) })