learning_ai_common_plat/services/mcp-server/src/lib/peakpulse-client.ts
saravanakumardb1 3f296a8e72 feat(mcp-server): fill 12 DOMAIN_PRODUCTS.md MCP tool gaps + client fn additions
Bug fix (committed separately):
  social-fast-coordinator: stage_transition used non-existent currentStage

New client functions:
  nomgap-client: nomgapFastingCreateSession, nomgapProtocolGet,
                 nomgapSocialListGroupFasts (+ GroupFastDoc)
  peakpulse-client: peakpulseRoutesList, peakpulseSyncStatus
  lysnrai-client: lysnraiApiTokenCreate, lysnraiSessionsStats,
                  lysnraiTranscriptsExportBatch
  chronomind-client: chronomindRoutineGet, chronomindSharedTimerShare

New MCP tools (12):
  mindlyst.briefs.generate        — trigger daily brief via mindlystBriefCreate
  mindlyst.memory.getTriageResult — extract TriageResult sub-doc only
  nomgap.fasting.createSession    — start new fast with protocolId
  nomgap.protocols.get            — single protocol lookup
  nomgap.social.listGroupFasts    — list group fast sessions
  peakpulse.routes.list           — list GPS r
Bug fix (committed separately):
  social-fast-coordinator: stage_transition used non-existent currentStage
ats  social-fast-coordinator: staon
New client functions:
  nomgap-client: nomgapFastingCreateSession, nomgarai  nomgaens.rotate                      nomgapSocialListGroupFasts (+ GroupFastDoc)
 d.  peakpulse-client: peakpulseRoutesList, peakpulseSyncStaturg  lysnrai-client: lysnraiApiTokenCreate, lysnraiSessionsStati                  lysnraiTranscriptsExpor                    us  chronomind-client: chronomindRoutineGet, chrerver total: 126 tools across 17 namespaces
2026-03-05 18:19:04 -08:00

174 lines
5.3 KiB
TypeScript

/**
* PeakPulse backend client — typed HTTP wrappers for the peakpulse-backend (port 4010).
*
* Auth: Bearer token from the caller's JWT (same JWT_SECRET as platform-service).
*/
import { config } from './config.js';
export interface PeakPulseClientOptions {
token?: string;
requestId?: string;
productId?: string;
}
async function peakpulseFetch<T>(
path: string,
init: RequestInit,
opts: PeakPulseClientOptions
): Promise<T> {
const headers: Record<string, string> = {
'Content-Type': 'application/json',
...(opts.token ? { Authorization: `Bearer ${opts.token}` } : {}),
...(opts.requestId ? { 'x-request-id': opts.requestId } : {}),
...(opts.productId ? { 'x-product-id': opts.productId } : { 'x-product-id': 'peakpulse' }),
};
const res = await fetch(`${config.PEAKPULSE_BACKEND_URL}/api${path}`, {
...init,
headers: { ...((init.headers as Record<string, string>) ?? {}), ...headers },
signal: AbortSignal.timeout(15_000),
});
if (!res.ok) {
const body = await res.text().catch(() => '');
throw new Error(`peakpulse-backend ${init.method ?? 'GET'} ${path}${res.status}: ${body}`);
}
return res.json() as Promise<T>;
}
// ── Sessions ───────────────────────────────────────────────────────────────
export interface PeakSessionDoc {
id: string;
clientId?: string;
userId: string;
productId: string;
activityType: 'hiking' | 'skiing' | 'cycling' | 'running';
status: 'active' | 'completed' | 'paused';
startTime: string;
endTime?: string;
durationSeconds?: number;
distanceMeters?: number;
maxSpeedMps?: number;
averageSpeedMps?: number;
elevationGainMeters?: number;
elevationLossMeters?: number;
maxElevationMeters?: number;
locationName?: string;
startLatitude?: number;
startLongitude?: number;
unitPreference?: string;
weather?: {
tempCelsius?: number;
conditionCode?: string;
windSpeedKph?: number;
uvIndex?: number;
};
skiMetrics?: {
runCount?: number;
verticalDescentMeters?: number;
liftTimeSeconds?: number;
skiTimeSeconds?: number;
};
trackPointCount?: number;
hapticMilestoneCount?: number;
savedToHealthKit?: boolean;
notes?: string;
createdAt: string;
updatedAt: string;
}
export interface PeakSessionExport {
exportVersion: string;
productId: string;
session: Omit<
PeakSessionDoc,
'userId' | 'clientId' | 'savedToHealthKit' | 'createdAt' | 'updatedAt'
>;
exportedAt: string;
}
export function peakpulseSessionsList(
params: {
activityType?: string;
status?: string;
limit?: number;
offset?: number;
},
opts: PeakPulseClientOptions
): Promise<{ items: PeakSessionDoc[]; total: number }> {
const qs = new URLSearchParams();
if (params.activityType) qs.set('activityType', params.activityType);
if (params.status) qs.set('status', params.status);
if (params.limit !== undefined) qs.set('limit', String(params.limit));
if (params.offset !== undefined) qs.set('offset', String(params.offset));
const q = qs.toString();
return peakpulseFetch(`/peak/sessions${q ? `?${q}` : ''}`, { method: 'GET' }, opts);
}
export function peakpulseSessionGet(
sessionId: string,
opts: PeakPulseClientOptions
): Promise<PeakSessionDoc> {
return peakpulseFetch(`/peak/sessions/${sessionId}`, { method: 'GET' }, opts);
}
export function peakpulseSessionExport(
sessionId: string,
opts: PeakPulseClientOptions
): Promise<PeakSessionExport> {
return peakpulseFetch(`/peak/sessions/${sessionId}/export`, { method: 'GET' }, opts);
}
export function peakpulseGetStats(opts: PeakPulseClientOptions): Promise<Record<string, unknown>> {
return peakpulseFetch('/peak/stats', { method: 'GET' }, opts);
}
// ── Routes ─────────────────────────────────────────────────────────────────
export interface PeakRouteDoc {
id: string;
sessionId: string;
userId: string;
productId: string;
trackPoints: unknown[];
hapticEvents: unknown[];
trackPointCount: number;
hapticEventCount: number;
boundingBox?: {
minLat: number;
maxLat: number;
minLon: number;
maxLon: number;
};
createdAt: string;
updatedAt: string;
}
export function peakpulseRoutesList(
params: { limit?: number; offset?: number },
opts: PeakPulseClientOptions
): Promise<{ items: PeakRouteDoc[]; total: number }> {
const qs = new URLSearchParams();
if (params.limit !== undefined) qs.set('limit', String(params.limit));
if (params.offset !== undefined) qs.set('offset', String(params.offset));
const q = qs.toString();
return peakpulseFetch(`/peak/routes${q ? `?${q}` : ''}`, { method: 'GET' }, opts);
}
export function peakpulseRouteGet(
sessionId: string,
opts: PeakPulseClientOptions
): Promise<PeakRouteDoc> {
return peakpulseFetch(`/peak/routes/${sessionId}`, { method: 'GET' }, opts);
}
export function peakpulseSyncStatus(opts: PeakPulseClientOptions): Promise<{
userId: string;
productId: string;
pendingUploadCount: number;
lastSyncedAt: string | null;
oldestPendingAt: string | null;
}> {
return peakpulseFetch('/peak/sync/status', { method: 'GET' }, opts);
}