diff --git a/apps/calendar/apps/web/src/hooks.server.ts b/apps/calendar/apps/web/src/hooks.server.ts index 5215d05b8..b63bf26fe 100644 --- a/apps/calendar/apps/web/src/hooks.server.ts +++ b/apps/calendar/apps/web/src/hooks.server.ts @@ -13,6 +13,10 @@ const PUBLIC_BACKEND_URL_CLIENT = process.env.PUBLIC_BACKEND_URL_CLIENT || process.env.PUBLIC_BACKEND_URL || ''; const PUBLIC_STT_URL = process.env.PUBLIC_STT_URL || 'https://stt-api.mana.how'; +// Cross-app integration URLs (for todo and contacts APIs) +const PUBLIC_TODO_BACKEND_URL = process.env.PUBLIC_TODO_BACKEND_URL || 'http://localhost:3018'; +const PUBLIC_CONTACTS_API_URL = process.env.PUBLIC_CONTACTS_API_URL || 'http://localhost:3015'; + export const handle: Handle = async ({ event, resolve }) => { return resolve(event, { transformPageChunk: ({ html }) => { @@ -22,6 +26,8 @@ export const handle: Handle = async ({ event, resolve }) => { window.__PUBLIC_MANA_CORE_AUTH_URL__ = "${PUBLIC_MANA_CORE_AUTH_URL_CLIENT}"; window.__PUBLIC_BACKEND_URL__ = "${PUBLIC_BACKEND_URL_CLIENT}"; window.__PUBLIC_STT_URL__ = "${PUBLIC_STT_URL}"; +window.__PUBLIC_TODO_BACKEND_URL__ = "${PUBLIC_TODO_BACKEND_URL}"; +window.__PUBLIC_CONTACTS_API_URL__ = "${PUBLIC_CONTACTS_API_URL}"; `; return html.replace('', `${envScript}`); }, diff --git a/apps/calendar/apps/web/src/lib/api/birthdays.ts b/apps/calendar/apps/web/src/lib/api/birthdays.ts index 9734a0cd8..224712a90 100644 --- a/apps/calendar/apps/web/src/lib/api/birthdays.ts +++ b/apps/calendar/apps/web/src/lib/api/birthdays.ts @@ -3,19 +3,44 @@ * Allows Calendar app to fetch contact birthdays for display */ +import { browser } from '$app/environment'; import { env } from '$env/dynamic/public'; import { createApiClient } from '@manacore/shared-api-client'; import { authStore } from '$lib/stores/auth.svelte'; -const CONTACTS_API_BASE = env.PUBLIC_CONTACTS_API_URL || 'http://localhost:3015'; +// Get contacts API base URL from injected window variable (browser) or env (SSR) +function getContactsApiBase(): string { + if (browser && typeof window !== 'undefined') { + const injectedUrl = (window as unknown as { __PUBLIC_CONTACTS_API_URL__?: string }) + .__PUBLIC_CONTACTS_API_URL__; + if (injectedUrl) return injectedUrl; + } + return env.PUBLIC_CONTACTS_API_URL || 'http://localhost:3015'; +} -const contactsClient = createApiClient({ - baseUrl: CONTACTS_API_BASE, - apiPrefix: '/api/v1', - getAuthToken: () => authStore.getValidToken(), - timeout: 30000, - debug: import.meta.env.DEV, -}); +let _contactsClient: ReturnType | null = null; + +function getContactsClient() { + if (!_contactsClient) { + _contactsClient = createApiClient({ + baseUrl: getContactsApiBase(), + apiPrefix: '/api/v1', + getAuthToken: () => authStore.getValidToken(), + timeout: 30000, + debug: import.meta.env.DEV, + }); + } + return _contactsClient; +} + +// For backwards compatibility +const contactsClient = { + get: (endpoint: string) => getContactsClient().get(endpoint), + post: (endpoint: string, body?: unknown) => getContactsClient().post(endpoint, body), + put: (endpoint: string, body?: unknown) => getContactsClient().put(endpoint, body), + patch: (endpoint: string, body?: unknown) => getContactsClient().patch(endpoint, body), + delete: (endpoint: string) => getContactsClient().delete(endpoint), +}; // ============================================ // Types for Birthday Integration diff --git a/apps/calendar/apps/web/src/lib/api/todos.ts b/apps/calendar/apps/web/src/lib/api/todos.ts index a7c3328b0..4dea3385b 100644 --- a/apps/calendar/apps/web/src/lib/api/todos.ts +++ b/apps/calendar/apps/web/src/lib/api/todos.ts @@ -3,19 +3,44 @@ * Allows Calendar app to fetch/manage todos from the Todo service */ +import { browser } from '$app/environment'; import { env } from '$env/dynamic/public'; import { createApiClient, buildQueryString, type ApiResult } from '@manacore/shared-api-client'; import { authStore } from '$lib/stores/auth.svelte'; -const TODO_API_BASE = env.PUBLIC_TODO_BACKEND_URL || 'http://localhost:3018'; +// Get todo API base URL from injected window variable (browser) or env (SSR) +function getTodoApiBase(): string { + if (browser && typeof window !== 'undefined') { + const injectedUrl = (window as unknown as { __PUBLIC_TODO_BACKEND_URL__?: string }) + .__PUBLIC_TODO_BACKEND_URL__; + if (injectedUrl) return injectedUrl; + } + return env.PUBLIC_TODO_BACKEND_URL || 'http://localhost:3018'; +} -const todoClient = createApiClient({ - baseUrl: TODO_API_BASE, - apiPrefix: '/api/v1', - getAuthToken: () => authStore.getValidToken(), - timeout: 30000, - debug: import.meta.env.DEV, -}); +let _todoClient: ReturnType | null = null; + +function getTodoClient() { + if (!_todoClient) { + _todoClient = createApiClient({ + baseUrl: getTodoApiBase(), + apiPrefix: '/api/v1', + getAuthToken: () => authStore.getValidToken(), + timeout: 30000, + debug: import.meta.env.DEV, + }); + } + return _todoClient; +} + +// For backwards compatibility +const todoClient = { + get: (endpoint: string) => getTodoClient().get(endpoint), + post: (endpoint: string, body?: unknown) => getTodoClient().post(endpoint, body), + put: (endpoint: string, body?: unknown) => getTodoClient().put(endpoint, body), + patch: (endpoint: string, body?: unknown) => getTodoClient().patch(endpoint, body), + delete: (endpoint: string) => getTodoClient().delete(endpoint), +}; // ============================================ // Types (mirrored from @todo/shared for cross-app use)