salvage: uncommitted work from /home/jwoltje/distrobox-homes/mosaic-dev/src/stack-p5a (disk cleanup #824, 2026-11-06)

This commit is contained in:
mos committed 2026-11-06 09:55:29 -06:00
1 parent 216cd72226
commit c0500a9b9b
47 files changed
+6359 -80

No files matched your search

+2 -4
View File
@@ -9,6 +9,7 @@ export interface AuthConfig {
db: Db;
baseURL?: string;
secret?: string;
trustedOrigins?: string[];
}
export function buildOAuthProviders(): GenericOAuthConfig[] {
@@ -16,7 +17,7 @@ export function buildOAuthProviders(): GenericOAuthConfig[] {
}
export function createAuth(config: AuthConfig) {
const { db, baseURL, secret } = config;
const { db, baseURL, secret, trustedOrigins } = config;
const oidcConfigs = buildOAuthProviders();
const plugins =
oidcConfigs.length > 0
@@ -27,9 +28,6 @@ export function createAuth(config: AuthConfig) {
]
: undefined;
const corsOrigin = process.env['GATEWAY_CORS_ORIGIN'] ?? 'http://localhost:3000';
const trustedOrigins = corsOrigin.split(',').map((o) => o.trim());
return betterAuth({
database: drizzleAdapter(db, {
provider: 'pg',
+1
View File
@@ -3,6 +3,7 @@ export {
buildGenericOidcProviderConfigs,
buildSsoDiscovery,
listSsoStartupWarnings,
SUPPORTED_SSO_PROVIDER_IDS,
type GenericOidcProviderConfig,
type SsoLoginMode,
type SsoProtocol,
+12 -4
View File
@@ -1,4 +1,14 @@
export type SupportedSsoProviderId = 'authentik' | 'workos' | 'keycloak';
/**
* Provider ids the Gateway consumes as SPA route inputs (see
* apps/gateway/src/web-ui.ts): each id widens unauthenticated history-fallback
* routing for its `/auth/provider/:id` callback path. The Gateway validates
* that entries are single lowercase URL segments, not that this package can
* complete a login for them — wire configuration and discovery for a new id
* (buildGenericOidcProviderConfigs / buildSsoDiscovery) in the same change
* that extends this list.
*/
export const SUPPORTED_SSO_PROVIDER_IDS = ['authentik', 'workos', 'keycloak'] as const;
export type SupportedSsoProviderId = (typeof SUPPORTED_SSO_PROVIDER_IDS)[number];
export type SsoProtocol = 'oidc' | 'saml';
export type SsoLoginMode = 'oidc' | 'saml' | null;
@@ -183,9 +193,7 @@ export function buildGenericOidcProviderConfigs(
}
export function listSsoStartupWarnings(env: EnvMap = process.env): string[] {
return ['authentik', 'workos', 'keycloak'].flatMap((provider) =>
collectWarnings(env, provider as SupportedSsoProviderId),
);
return SUPPORTED_SSO_PROVIDER_IDS.flatMap((provider) => collectWarnings(env, provider));
}
export function buildSsoDiscovery(env: EnvMap = process.env): SsoProviderDiscovery[] {
@@ -161,6 +161,9 @@ describe('gatewayConfigStage', () => {
expect(existsSync(daemonState.mosaicConfigFile)).toBe(true);
const envContents = readFileSync(daemonState.envFile, 'utf-8');
expect(envContents).toContain('GATEWAY_PORT=14242');
expect(envContents.split('\n').some((line) => line === 'GATEWAY_WEB_UI_MODE=disabled')).toBe(
true,
);
expect(envContents).toContain('BETTER_AUTH_SECRET=');
expect(daemonState.startCalled).toBe(1);
expect(daemonState.writeMetaCalls).toHaveLength(1);
@@ -545,6 +545,11 @@ async function collectAndWriteConfig(
const envLines = [
`GATEWAY_PORT=${port.toString()}`,
// P6 packaging obligation: migrate both this explicit P5a value and older
// installed .env files with no mode line to "required" before restarting a
// package that includes the Web UI bundle. Docker's build argument couples
// its payload automatically, but installed CLI configuration is persistent.
'GATEWAY_WEB_UI_MODE=disabled',
`BETTER_AUTH_SECRET=${authSecret}`,
`BETTER_AUTH_URL=http://${opts.host}:${port.toString()}`,
`GATEWAY_CORS_ORIGIN=${corsOrigin}`,
+1
View File
@@ -9,3 +9,4 @@ export * from './commands/index.js';
export * from './federation/index.js';
export * from './reflection/index.js';
export * from './harness/index.js';
export * from './web-ui-routes.js';
+39
View File
@@ -0,0 +1,39 @@
export type SpaGatewayMatch = 'exact' | 'project-id' | 'supported-auth-provider';
/**
* Shared browser-route contract for the Vite SPA and the Gateway history
* fallback. The Gateway exhaustively interprets every gatewayMatch category,
* while the SPA route-table test verifies that these same paths are mounted.
*/
export const SPA_ROUTES = {
root: { path: '/', gatewayMatch: 'exact' },
login: { path: '/login', gatewayMatch: 'exact' },
register: { path: '/register', gatewayMatch: 'exact' },
authProvider: {
path: '/auth/provider/:provider',
gatewayMatch: 'supported-auth-provider',
},
chat: { path: '/chat', gatewayMatch: 'exact' },
projects: { path: '/projects', gatewayMatch: 'exact' },
projectDetail: { path: '/projects/:id', gatewayMatch: 'project-id' },
tasks: { path: '/tasks', gatewayMatch: 'exact' },
settings: { path: '/settings', gatewayMatch: 'exact' },
admin: { path: '/admin', gatewayMatch: 'exact' },
} as const satisfies Record<
string,
{ readonly path: string; readonly gatewayMatch: SpaGatewayMatch }
>;
type RouteGatewayMatches = (typeof SPA_ROUTES)[keyof typeof SPA_ROUTES]['gatewayMatch'];
type AssertNever<T extends never> = T;
/**
* Compile-time assertion that every SpaGatewayMatch category is inhabited by
* at least one SPA_ROUTES entry. Without it, a union member could be added
* with no route using it, and the Gateway's exhaustive matcher would stay
* green over a vocabulary it never sees. If this type errors, either add a
* route using the new category or remove it from the union.
*/
export type EveryGatewayMatchIsInhabited = AssertNever<
Exclude<SpaGatewayMatch, RouteGatewayMatches>
>;