salvage: uncommitted work from /home/jwoltje/distrobox-homes/mosaic-dev/src/stack-p5a (disk cleanup #824, 2026-11-06)
This commit is contained in:
1 parent
216cd72226
commit
c0500a9b9b
47 files changed
+6359
-80
No files matched your search
@@ -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',
|
||||
|
||||
@@ -3,6 +3,7 @@ export {
|
||||
buildGenericOidcProviderConfigs,
|
||||
buildSsoDiscovery,
|
||||
listSsoStartupWarnings,
|
||||
SUPPORTED_SSO_PROVIDER_IDS,
|
||||
type GenericOidcProviderConfig,
|
||||
type SsoLoginMode,
|
||||
type SsoProtocol,
|
||||
|
||||
@@ -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}`,
|
||||
|
||||
@@ -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';
|
||||
@@ -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>
|
||||
>;
|
||||
Reference in new issue
Block a user