fix(web): point credits/sync API client at credits.mana.how

The frontend was calling /api/v1/credits/* and /api/v1/sync/* on
auth.mana.how, but those routes live on credits.mana.how (mana-credits
service). Add getManaCreditsUrl() helper, inject the URL via
hooks.server.ts, allow it in the CSP connect-src, and update both API
clients (credits.ts + sync.ts) to use it.

Also: pass MANA_CREDITS_URL + MANA_SERVICE_KEY to mana-sync so its
billing middleware can reach mana-credits at http://mana-credits:3002.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Till JS 2026-04-11 17:12:36 +02:00
parent c47ce83e83
commit 1c94234996
5 changed files with 26 additions and 5 deletions

View file

@ -45,6 +45,8 @@ const PUBLIC_MANA_EVENTS_URL_CLIENT =
process.env.PUBLIC_MANA_EVENTS_URL_CLIENT || process.env.PUBLIC_MANA_EVENTS_URL || '';
const PUBLIC_MANA_API_URL_CLIENT =
process.env.PUBLIC_MANA_API_URL_CLIENT || process.env.PUBLIC_MANA_API_URL || '';
const PUBLIC_MANA_CREDITS_URL_CLIENT =
process.env.PUBLIC_MANA_CREDITS_URL_CLIENT || process.env.PUBLIC_MANA_CREDITS_URL || '';
// Map of app subdomains to internal paths
const APP_SUBDOMAINS = new Set([
@ -95,6 +97,7 @@ window.__PUBLIC_MANA_MEDIA_URL__ = ${JSON.stringify(PUBLIC_MANA_MEDIA_URL_CLIENT
window.__PUBLIC_MANA_LLM_URL__ = ${JSON.stringify(PUBLIC_MANA_LLM_URL_CLIENT)};
window.__PUBLIC_MANA_EVENTS_URL__ = ${JSON.stringify(PUBLIC_MANA_EVENTS_URL_CLIENT)};
window.__PUBLIC_MANA_API_URL__ = ${JSON.stringify(PUBLIC_MANA_API_URL_CLIENT)};
window.__PUBLIC_MANA_CREDITS_URL__ = ${JSON.stringify(PUBLIC_MANA_CREDITS_URL_CLIENT)};
window.__PUBLIC_GLITCHTIP_DSN__ = ${JSON.stringify(PUBLIC_GLITCHTIP_DSN)};
</script>`;
return injectUmamiAnalytics(html.replace('<head>', `<head>${envScript}`));
@ -123,6 +126,7 @@ window.__PUBLIC_GLITCHTIP_DSN__ = ${JSON.stringify(PUBLIC_GLITCHTIP_DSN)};
PUBLIC_MANA_LLM_URL_CLIENT,
PUBLIC_MANA_EVENTS_URL_CLIENT,
PUBLIC_MANA_API_URL_CLIENT,
PUBLIC_MANA_CREDITS_URL_CLIENT,
'wss://sync.mana.how',
// transformers.js *also* fetch()es the .wasm binary and the .mjs
// loader factory directly to pre-warm the runtime — those go

View file

@ -46,3 +46,16 @@ export function getManaApiUrl(): string {
}
return process.env.PUBLIC_MANA_API_URL || 'http://localhost:3060';
}
/**
* Get the mana-credits service URL.
* Hosts credit balance, packages, transactions, gift codes, sync billing.
*/
export function getManaCreditsUrl(): string {
if (browser && typeof window !== 'undefined') {
const injected = (window as unknown as { __PUBLIC_MANA_CREDITS_URL__?: string })
.__PUBLIC_MANA_CREDITS_URL__;
return injected || 'http://localhost:3061';
}
return process.env.PUBLIC_MANA_CREDITS_URL || 'http://localhost:3061';
}

View file

@ -4,7 +4,7 @@
*/
import { authStore } from '$lib/stores/auth.svelte';
import { getManaAuthUrl } from './config';
import { getManaCreditsUrl } from './config';
// Types
export interface CreditBalance {
@ -58,7 +58,7 @@ export interface CreditPurchase {
async function fetchWithAuth<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
const token = await authStore.getAccessToken();
const response = await fetch(`${getManaAuthUrl()}${endpoint}`, {
const response = await fetch(`${getManaCreditsUrl()}${endpoint}`, {
...options,
headers: {
'Content-Type': 'application/json',
@ -104,7 +104,7 @@ export const creditsService = {
* Get available credit packages (public endpoint)
*/
async getPackages(): Promise<CreditPackage[]> {
const response = await fetch(`${getManaAuthUrl()}/api/v1/credits/packages`);
const response = await fetch(`${getManaCreditsUrl()}/api/v1/credits/packages`);
if (!response.ok) {
throw new Error('Failed to fetch packages');
}

View file

@ -4,7 +4,7 @@
*/
import { authStore } from '$lib/stores/auth.svelte';
import { getManaAuthUrl } from './config';
import { getManaCreditsUrl } from './config';
// Types
export type BillingInterval = 'monthly' | 'quarterly' | 'yearly';
@ -28,7 +28,7 @@ export interface SyncActivateResponse {
async function fetchWithAuth<T>(endpoint: string, options: RequestInit = {}): Promise<T> {
const token = await authStore.getAccessToken();
const response = await fetch(`${getManaAuthUrl()}${endpoint}`, {
const response = await fetch(`${getManaCreditsUrl()}${endpoint}`, {
...options,
headers: {
'Content-Type': 'application/json',

View file

@ -583,6 +583,8 @@ services:
DATABASE_URL: postgresql://postgres:${POSTGRES_PASSWORD:-mana123}@postgres:5432/mana_sync?sslmode=disable
JWKS_URL: http://mana-auth:3001/api/v1/auth/jwks
CORS_ORIGINS: "https://mana.how,https://*.mana.how"
MANA_CREDITS_URL: http://mana-credits:3002
MANA_SERVICE_KEY: ${MANA_SERVICE_KEY}
ports:
- "3010:3010"
healthcheck:
@ -800,6 +802,8 @@ services:
# mana-api.* subdomain is the unambiguous new home.
PUBLIC_MANA_API_URL: http://mana-api:3060
PUBLIC_MANA_API_URL_CLIENT: https://mana-api.mana.how
PUBLIC_MANA_CREDITS_URL: http://mana-credits:3002
PUBLIC_MANA_CREDITS_URL_CLIENT: https://credits.mana.how
# Per-app HTTP backend URLs (todo-api, calendar-api, contacts-api,
# chat-api, storage-api, cards-api, music-api, nutriphi-api,
# picture-api, presi-api, zitare-api, clock-api, context-api) and