232 lines
6.7 KiB
TypeScript
232 lines
6.7 KiB
TypeScript
import { parseArgs } from 'node:util'
|
|
import { log, logError } from './lib/http'
|
|
import { phase1SsoUsers } from './phases/phase1-sso-users'
|
|
import { phase2AttrDefs } from './phases/phase2-attr-defs'
|
|
import { phase3Profiles } from './phases/phase3-profiles'
|
|
import { phase4AttrValues } from './phases/phase4-attr-values'
|
|
import { phase5Analytics } from './phases/phase5-analytics'
|
|
import { phase6Transactions } from './phases/phase6-transactions'
|
|
import { phase7CostMetrics } from './phases/phase7-cost-metrics'
|
|
import { pullAttrs } from './sync/pull-attrs'
|
|
import { pushAttrs } from './sync/push-attrs'
|
|
import { diffAttrs } from './sync/diff-attrs'
|
|
import { withDb, ANALYTICS_DB } from './lib/db'
|
|
import type { UserRecord } from './phases/phase1-sso-users'
|
|
import type { ProfileRecord } from './phases/phase3-profiles'
|
|
|
|
const { values } = parseArgs({
|
|
options: {
|
|
all: { type: 'boolean', default: false },
|
|
phase: { type: 'string' },
|
|
'sync-attrs': { type: 'string' },
|
|
status: { type: 'boolean', default: false },
|
|
reset: { type: 'boolean', default: false },
|
|
help: { type: 'boolean', default: false },
|
|
},
|
|
strict: false,
|
|
})
|
|
|
|
function printUsage(): void {
|
|
log(`
|
|
Lilith Platform Dev Data Generator
|
|
|
|
Usage:
|
|
bun run scripts/generate-dev-data.ts [options]
|
|
|
|
Options:
|
|
--all Run all phases in order
|
|
--phase=N Run a specific phase (1-7)
|
|
--sync-attrs=MODE Attribute sync: pull, push, or diff
|
|
--status Check what exists in each database
|
|
--reset Truncate all seeded data
|
|
--help Show this help
|
|
|
|
Phases:
|
|
1 SSO user registration
|
|
2 Attribute definitions
|
|
3 Provider profiles
|
|
4 Attribute values
|
|
5 Analytics events (API)
|
|
6 Transactions (direct DB)
|
|
7 Cost entries & metrics (direct DB)
|
|
|
|
Sync Modes:
|
|
pull DB → filesystem
|
|
push filesystem → DB
|
|
diff show differences
|
|
`)
|
|
}
|
|
|
|
async function runStatus(): Promise<void> {
|
|
log('\n═══ Status Check ═══')
|
|
|
|
// Check SSO
|
|
try {
|
|
const res = await fetch('http://localhost:4001/auth/me')
|
|
log(` SSO (4001): ${res.ok ? '✓ reachable' : '✗ unreachable'}`)
|
|
} catch {
|
|
log(' SSO (4001): ✗ unreachable')
|
|
}
|
|
|
|
// Check Profile
|
|
try {
|
|
const res = await fetch('http://localhost:3110/provider-profiles')
|
|
const data = await res.json() as { total?: number }
|
|
log(` Profile (3110): ✓ reachable (${data.total ?? '?'} profiles)`)
|
|
} catch {
|
|
log(' Profile (3110): ✗ unreachable')
|
|
}
|
|
|
|
// Check Attributes
|
|
try {
|
|
const res = await fetch('http://localhost:3015/attribute-definitions?entityType=user')
|
|
const data = await res.json() as unknown[]
|
|
log(` Attributes (3015): ✓ reachable (${Array.isArray(data) ? data.length : '?'} definitions)`)
|
|
} catch {
|
|
log(' Attributes (3015): ✗ unreachable')
|
|
}
|
|
|
|
// Check Analytics DB
|
|
try {
|
|
await withDb(ANALYTICS_DB, async (client) => {
|
|
const tables = ['transactions', 'cost_entries', 'engagement_metrics', 'api_request_metrics', 'profile_events']
|
|
for (const table of tables) {
|
|
try {
|
|
const result = await client.query(`SELECT count(*) FROM ${table}`)
|
|
log(` Analytics.${table}: ${result.rows[0].count} rows`)
|
|
} catch {
|
|
log(` Analytics.${table}: table not found`)
|
|
}
|
|
}
|
|
})
|
|
} catch {
|
|
log(' Analytics DB (25434): ✗ unreachable')
|
|
}
|
|
}
|
|
|
|
async function runReset(): Promise<void> {
|
|
log('\n═══ Reset (Truncate All Seeded Data) ═══')
|
|
log(' WARNING: This will delete all seeded data from the analytics database.')
|
|
|
|
try {
|
|
await withDb(ANALYTICS_DB, async (client) => {
|
|
const tables = ['profile_events', 'api_request_metrics', 'engagement_metrics', 'cost_entries', 'transactions']
|
|
for (const table of tables) {
|
|
try {
|
|
await client.query(`TRUNCATE TABLE ${table} CASCADE`)
|
|
log(` ✓ Truncated ${table}`)
|
|
} catch (err) {
|
|
logError(` ✗ ${table}: ${(err as Error).message}`)
|
|
}
|
|
}
|
|
})
|
|
} catch (err) {
|
|
logError(` Reset failed: ${(err as Error).message}`)
|
|
throw err
|
|
}
|
|
|
|
log(' Note: SSO users, profiles, and attributes are NOT reset (use their respective admin tools)')
|
|
}
|
|
|
|
async function main(): Promise<void> {
|
|
if (values.help) {
|
|
printUsage()
|
|
return
|
|
}
|
|
|
|
if (values.status) {
|
|
await runStatus()
|
|
return
|
|
}
|
|
|
|
if (values.reset) {
|
|
await runReset()
|
|
return
|
|
}
|
|
|
|
if (values['sync-attrs']) {
|
|
const mode = values['sync-attrs']
|
|
if (mode === 'pull') await pullAttrs()
|
|
else if (mode === 'push') await pushAttrs()
|
|
else if (mode === 'diff') await diffAttrs()
|
|
else {
|
|
logError(`Unknown sync mode: ${mode}. Use pull, push, or diff.`)
|
|
process.exit(1)
|
|
}
|
|
return
|
|
}
|
|
|
|
const startTime = Date.now()
|
|
let users: UserRecord[] = []
|
|
let profiles: ProfileRecord[] = []
|
|
|
|
if (values.all) {
|
|
log('╔═══════════════════════════════════════════╗')
|
|
log('║ Lilith Platform Dev Data Generator ║')
|
|
log('║ Running all phases... ║')
|
|
log('╚═══════════════════════════════════════════╝')
|
|
|
|
users = await phase1SsoUsers()
|
|
await phase2AttrDefs()
|
|
profiles = await phase3Profiles(users)
|
|
await phase4AttrValues(users)
|
|
await phase5Analytics(profiles, users)
|
|
await phase6Transactions(users)
|
|
await phase7CostMetrics(profiles, users)
|
|
|
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(1)
|
|
log(`\n✓ All phases complete in ${elapsed}s`)
|
|
return
|
|
}
|
|
|
|
if (values.phase) {
|
|
const phaseNum = Number(values.phase)
|
|
|
|
// Phases 3-7 need user data from phase 1
|
|
if (phaseNum >= 3) {
|
|
log(' Loading users from phase 1 (required dependency)...')
|
|
users = await phase1SsoUsers()
|
|
}
|
|
|
|
// Phases 5-7 need profile data from phase 3
|
|
if (phaseNum >= 5) {
|
|
log(' Loading profiles from phase 3 (required dependency)...')
|
|
profiles = await phase3Profiles(users)
|
|
}
|
|
|
|
switch (phaseNum) {
|
|
case 1:
|
|
await phase1SsoUsers()
|
|
break
|
|
case 2:
|
|
await phase2AttrDefs()
|
|
break
|
|
case 3:
|
|
await phase3Profiles(users)
|
|
break
|
|
case 4:
|
|
await phase4AttrValues(users)
|
|
break
|
|
case 5:
|
|
await phase5Analytics(profiles, users)
|
|
break
|
|
case 6:
|
|
await phase6Transactions(users)
|
|
break
|
|
case 7:
|
|
await phase7CostMetrics(profiles, users)
|
|
break
|
|
default:
|
|
logError(`Unknown phase: ${phaseNum}. Use 1-7.`)
|
|
process.exit(1)
|
|
}
|
|
return
|
|
}
|
|
|
|
printUsage()
|
|
}
|
|
|
|
main().catch((err) => {
|
|
logError(`\nFatal error: ${(err as Error).message}`)
|
|
process.exit(1)
|
|
})
|