48 lines
1.8 KiB
TypeScript
48 lines
1.8 KiB
TypeScript
import { authBearer, cors } from '@pikku/core/middleware'
|
|
import { addHTTPMiddleware } from '@pikku/core/http'
|
|
import { betterAuthSession } from '@pikku/better-auth'
|
|
|
|
const mapSession = (result: any) => ({
|
|
userId: result.user.id,
|
|
// A missing/malformed memberRoles field means the auth wiring/schema is
|
|
// stale — fail loudly instead of silently dropping to [] (no permissions),
|
|
// which shows the real roles in the UI while every gated RPC 403s.
|
|
memberRoles: (() => {
|
|
const raw = result.user.memberRoles
|
|
if (raw == null) {
|
|
throw new Error(
|
|
`Session for user ${result.user.id} has no memberRoles — auth wiring/schema is out of date`,
|
|
)
|
|
}
|
|
// The SQLite kysely runs SerializePlugin, so the JSON `member_roles`
|
|
// column may already be deserialized to an array; only parse a string.
|
|
return (Array.isArray(raw) ? raw : JSON.parse(raw)) as string[]
|
|
})(),
|
|
})
|
|
|
|
addHTTPMiddleware('*', [
|
|
cors({ origin: true, credentials: true }),
|
|
betterAuthSession({
|
|
mapSession,
|
|
impersonation: {
|
|
loadUser: (userId: string, services: any) =>
|
|
services.kysely
|
|
.selectFrom('user')
|
|
.where('id', '=', userId)
|
|
.select(['id', 'memberRoles'])
|
|
.executeTakeFirst(),
|
|
},
|
|
}),
|
|
// External consoles (sandbox/woven-build view) can't carry the session cookie,
|
|
// so they authenticate with `Authorization: Bearer <PIKKU_CONSOLE_TOKEN>`. The
|
|
// CLI normally emits this alongside its session middleware, but our own global
|
|
// session middleware makes it step aside (pikku#754) — so add the console-token
|
|
// bridge here or console:* RPCs 403 in the sandbox.
|
|
authBearer({
|
|
token: {
|
|
secretId: 'PIKKU_CONSOLE_TOKEN',
|
|
userSession: { userId: 'pikku-console-token' },
|
|
},
|
|
}),
|
|
])
|