/** * Module API path conventions shared by Host, dev, and remote modules. * * - module.json `api.prefix` = mount prefix (e.g. `/insight`) * - defineApiRouter optional handler segment under mount prefix (default empty) * - Host injects full `apiBaseUrl` = mount prefix (e.g. `/insight`) * - Module code calls `request('/sprints')`; platform.http prepends apiBaseUrl */ /** Default handler segment under module mount prefix (empty = no extra /api segment) */ export const MODULE_HANDLER_API_PREFIX = ''; export interface ModuleApiResult { success: boolean; data?: T; error?: { code?: string; message?: string; }; } /** Normalize business path to leading slash (e.g. `sprints` → `/sprints`). */ export function normalizeModuleApiPath(path: string): string { if (path.startsWith('http://') || path.startsWith('https://')) return path; return path.startsWith('/') ? path : `/${path}`; } /** * Join apiBaseUrl with a business path (for direct fetch or debugging). * Platform http clients should prepend apiBaseUrl internally; modules normally * pass only the normalized path to http.get/post. */ export function joinModuleApiPath(apiBaseUrl: string, path: string): string { if (path.startsWith('http://') || path.startsWith('https://')) return path; const normalized = normalizeModuleApiPath(path); const base = apiBaseUrl.replace(/\/$/, ''); if (!base) return normalized; return `${base}${normalized}`; } /** * Resolve the full API base URL injected into ModuleContext.config.apiBaseUrl. * * @param mountPrefix - module.json `api.prefix` (e.g. `/insight`), empty in standalone dev */ export function resolveModuleApiBaseUrl(mountPrefix?: string): string { const mount = (mountPrefix ?? '').replace(/\/$/, ''); const handler = MODULE_HANDLER_API_PREFIX; if (!mount) return handler; if (!handler) return mount; if (mount === handler) return mount; if (mount.endsWith(handler)) return mount; return `${mount}${handler}`; } /** * Merge module mount prefix with handler prefix for server route registration. * Avoids duplicate segments when both are `/api` (→ `/api`, not `/api/api`). */ export function resolveModuleRouteBase(modulePrefix: string, handlerPrefix: string): string { if (!handlerPrefix) return modulePrefix; if (!modulePrefix) return handlerPrefix; if (modulePrefix === handlerPrefix) return modulePrefix; if (modulePrefix.endsWith(handlerPrefix)) return modulePrefix; return `${modulePrefix}${handlerPrefix}`; }