Merge branch 'cli-improvements-1' with @reviq/utils password hashing

- Use executeBootstrap helper from @reviq/db for CLI bootstrap
- Update @reviq/db to use @reviq/utils for PBKDF2-SHA256 password hashing
  (Cloudflare Workers compatible)
- Keep @scure/base for base58 token encoding
- Remove redundant password.ts from @reviq/db (import directly from @reviq/utils)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
RevIQ
2026-01-09 18:17:45 +08:00
19 changed files with 785 additions and 154 deletions

View File

@@ -8,6 +8,7 @@
import type {
APIContext,
AuthenticatedContext,
AuthInfo,
LoginRequestContext,
Session,
SessionUser,
@@ -109,23 +110,49 @@ export const authMiddleware = os.middleware(async ({ context, next }) => {
isSuperuser: user.is_superuser,
};
const sessionInfo: Session = session
? {
id: session.id,
trustedMode: session.trusted_mode,
createdAt: session.created_at,
}
: {
// For API token auth, create a synthetic session object
id: "0",
trustedMode: true,
createdAt: apiToken?.created_at ?? new Date(),
};
// Build session and auth info based on authentication method
let sessionInfo: Session;
let authInfo: AuthInfo;
if (session) {
sessionInfo = {
id: session.id,
trustedMode: session.trusted_mode,
createdAt: session.created_at,
};
authInfo = {
method: "session",
sessionId: session.id,
expiresAt: session.expires_at,
createdAt: session.created_at,
};
} else if (apiToken) {
sessionInfo = {
// For API token auth, create a synthetic session object
id: "0",
trustedMode: true,
createdAt: apiToken.created_at,
};
authInfo = {
method: "api_token",
tokenId: apiToken.id,
tokenName: apiToken.name,
expiresAt: apiToken.expires_at,
lastUsedAt: apiToken.last_used_at,
createdAt: apiToken.created_at,
};
} else {
// This should never happen since we checked userId above
throw new ORPCError("UNAUTHORIZED", {
message: "Invalid authentication state",
});
}
return next({
context: {
user: sessionUser,
session: sessionInfo,
auth: authInfo,
},
});
});