Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 1 addition & 1 deletion components/nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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";
Expand Down
39 changes: 39 additions & 0 deletions lib/api/factory.ts
Original file line number Diff line number Diff line change
@@ -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
}
36 changes: 4 additions & 32 deletions lib/api/index.ts
Original file line number Diff line number Diff line change
@@ -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'
Expand Down
48 changes: 43 additions & 5 deletions lib/api/mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down Expand Up @@ -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 {
Expand Down
24 changes: 20 additions & 4 deletions lib/api/mock/domains.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down
5 changes: 4 additions & 1 deletion test/mock-api-structure.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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/)
})
})