Files
DevRunbook-Public/apps/worker/src/operator/password-reset.ts
T
DevRunbook release export cfd2804e27
Managed validation / full (push) Successful in 3m18s
Publish DevRunbook source
2026-09-03 04:09:17 +02:00

73 lines
2.0 KiB
TypeScript

import { pathToFileURL } from 'node:url'
import {
issueOperatorPasswordResetToken,
TokenDigester,
type IssueOperatorPasswordResetRequest,
type IssuedPasswordReset,
} from '@devrunbook/application'
import { closeDatabase, DrizzlePasswordResetStore } from '@devrunbook/db'
type IssueReset = (
request: IssueOperatorPasswordResetRequest,
) => Promise<IssuedPasswordReset>
export async function runOperatorPasswordReset(
arguments_: readonly string[],
environment: Record<string, string | undefined>,
writeOutput: (value: string) => void,
issueReset?: IssueReset,
): Promise<void> {
if (arguments_.length !== 1 || !arguments_[0]) {
throw new Error(
'Usage: pnpm --filter @devrunbook/worker operator:password-reset -- <user-email>',
)
}
const sessionSecret = environment.SESSION_SECRET
const publicBaseUrl = environment.PUBLIC_BASE_URL
if (!sessionSecret || sessionSecret.length < 32) {
throw new Error('SESSION_SECRET must contain at least 32 characters')
}
if (!publicBaseUrl) throw new Error('PUBLIC_BASE_URL is required')
const issue =
issueReset ??
((request) =>
issueOperatorPasswordResetToken(
{
store: new DrizzlePasswordResetStore(),
digester: new TokenDigester(Buffer.from(sessionSecret, 'utf8')),
},
request,
))
const result = await issue({
email: arguments_[0],
publicBaseUrl,
})
// Successful stdout is deliberately one line containing only the reset URL.
writeOutput(result.resetUrl)
}
async function main() {
try {
await runOperatorPasswordReset(
process.argv.slice(2),
process.env,
(value) => console.log(value),
)
} catch (error) {
const message =
error instanceof Error ? error.message : 'Password reset failed'
console.error(message)
process.exitCode = 1
} finally {
await closeDatabase()
}
}
const entryPoint = process.argv[1]
if (entryPoint && import.meta.url === pathToFileURL(entryPoint).href) {
await main()
}