Move browser authentication behind a generated-contract BFF

This commit is contained in:
ms2k 2026-07-19 18:21:17 +09:00
commit fa7220ee33

61
web/server/config.mjs Normal file
View file

@ -0,0 +1,61 @@
export function loadConfig(environment = process.env) {
const publicOrigin = required(environment, 'REMORA_WEB_PUBLIC_ORIGIN')
const apiUpstream = required(environment, 'REMORA_WEB_API_UPSTREAM')
const oidcAuthority = required(environment, 'REMORA_WEB_OIDC_AUTHORITY')
return {
root: environment.REMORA_WEB_ROOT || '/app/dist',
port: port(environment.REMORA_WEB_PORT || '8080'),
publicOrigin: new URL(publicOrigin).origin,
apiUpstream: trailingSlash(new URL(apiUpstream)),
eventsUpstream: webSocketUrl(
environment.REMORA_WEB_EVENTS_UPSTREAM ||
new URL('events', trailingSlash(new URL(apiUpstream))).toString(),
),
oidcAuthority: oidcAuthority.replace(/\/$/, ''),
oidcClientId: required(environment, 'REMORA_WEB_OIDC_CLIENT_ID'),
oidcClientSecret: required(environment, 'REMORA_WEB_OIDC_CLIENT_SECRET'),
oidcScope: environment.REMORA_WEB_OIDC_SCOPE || 'openid profile',
sessionUrl: required(environment, 'REMORA_WEB_SESSION_URL'),
sessionNamespace:
environment.REMORA_WEB_SESSION_NAMESPACE || 'remora:web-session:',
sessionTtlSeconds: positiveInteger(
environment.REMORA_WEB_SESSION_TTL_SECONDS || '28800',
'REMORA_WEB_SESSION_TTL_SECONDS',
),
secureCookie: true,
}
}
function required(environment, name) {
const value = environment[name]
if (value === undefined || value === '')
throw new Error(`${name} is required`)
return value
}
function port(value) {
const parsed = positiveInteger(value, 'REMORA_WEB_PORT')
if (parsed > 65535) throw new Error('REMORA_WEB_PORT must be a valid port')
return parsed
}
function positiveInteger(value, name) {
const parsed = Number(value)
if (!Number.isSafeInteger(parsed) || parsed < 1)
throw new Error(`${name} must be a positive integer`)
return parsed
}
function trailingSlash(url) {
if (!url.pathname.endsWith('/')) url.pathname += '/'
return url
}
function webSocketUrl(value) {
const url = new URL(value)
if (url.protocol === 'http:') url.protocol = 'ws:'
else if (url.protocol === 'https:') url.protocol = 'wss:'
if (url.protocol !== 'ws:' && url.protocol !== 'wss:')
throw new Error('REMORA_WEB_EVENTS_UPSTREAM must use HTTP or WebSocket')
return url
}