chore(ops): add reminder trigger helper

This commit is contained in:
2026-03-12 00:29:52 +04:00
parent fa80474f6e
commit a20f0a2092
2 changed files with 110 additions and 1 deletions

View File

@@ -39,7 +39,8 @@
"test:e2e": "bun run scripts/e2e/billing-flow.ts", "test:e2e": "bun run scripts/e2e/billing-flow.ts",
"ops:deploy:smoke": "bun run scripts/ops/deploy-smoke.ts", "ops:deploy:smoke": "bun run scripts/ops/deploy-smoke.ts",
"ops:telegram:webhook": "bun run scripts/ops/telegram-webhook.ts", "ops:telegram:webhook": "bun run scripts/ops/telegram-webhook.ts",
"ops:telegram:commands": "bun run scripts/ops/telegram-commands.ts" "ops:telegram:commands": "bun run scripts/ops/telegram-commands.ts",
"ops:reminder": "bun run scripts/ops/trigger-reminder.ts"
}, },
"devDependencies": { "devDependencies": {
"@types/bun": "1.3.10", "@types/bun": "1.3.10",

View File

@@ -0,0 +1,108 @@
type ReminderType = 'utilities' | 'rent-warning' | 'rent-due'
function parseReminderType(raw: string | undefined): ReminderType {
const value = raw?.trim()
if (value === 'utilities' || value === 'rent-warning' || value === 'rent-due') {
return value
}
throw new Error(
'Usage: bun run ops:reminder <utilities|rent-warning|rent-due> [period] [--dry-run]'
)
}
function parseArgs(argv: readonly string[]) {
const reminderType = parseReminderType(argv[2])
const rawPeriod = argv[3]?.trim()
const dryRun = argv.includes('--dry-run')
return {
reminderType,
period: rawPeriod && rawPeriod.length > 0 ? rawPeriod : undefined,
dryRun
}
}
function readText(command: string[], name: string): string {
const result = Bun.spawnSync(command, {
stdout: 'pipe',
stderr: 'pipe'
})
if (result.exitCode !== 0) {
const stderr = result.stderr.toString().trim()
throw new Error(`${name} failed: ${stderr || `exit code ${result.exitCode}`}`)
}
const value = result.stdout.toString().trim()
if (!value) {
throw new Error(`${name} returned an empty value`)
}
return value
}
function resolveBotApiUrl(): string {
const envValue = process.env.BOT_API_URL?.trim()
if (envValue) {
return envValue
}
return readText(
['terraform', '-chdir=infra/terraform', 'output', '-raw', 'bot_api_service_url'],
'terraform output bot_api_service_url'
)
}
function resolveSchedulerSecret(): string {
const envValue = process.env.SCHEDULER_SHARED_SECRET?.trim()
if (envValue) {
return envValue
}
const projectId = process.env.GCP_PROJECT_ID?.trim() || 'gen-lang-client-0200379851'
return readText(
[
'gcloud',
'secrets',
'versions',
'access',
'latest',
'--secret=scheduler-shared-secret',
'--project',
projectId
],
'gcloud secrets versions access'
)
}
async function run() {
const { reminderType, period, dryRun } = parseArgs(process.argv)
const botApiUrl = resolveBotApiUrl().replace(/\/$/, '')
const schedulerSecret = resolveSchedulerSecret()
const response = await fetch(`${botApiUrl}/jobs/reminder/${reminderType}`, {
method: 'POST',
headers: {
'content-type': 'application/json',
'x-household-scheduler-secret': schedulerSecret
},
body: JSON.stringify({
...(period ? { period } : {}),
...(dryRun ? { dryRun: true } : {})
})
})
const text = await response.text()
if (!response.ok) {
throw new Error(`${response.status} ${response.statusText}: ${text}`)
}
console.log(text)
}
run().catch((error) => {
console.error(error instanceof Error ? error.message : String(error))
process.exitCode = 1
})