-
-
Notifications
You must be signed in to change notification settings - Fork 270
Expand file tree
/
Copy pathconfig.server.ts
More file actions
114 lines (98 loc) · 3.26 KB
/
Copy pathconfig.server.ts
File metadata and controls
114 lines (98 loc) · 3.26 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import type { PublicDatabase } from './types'
// Multi-database configuration support
// Format: "name1=postgres://host1/db1|name2=postgres://host2/db2"
// Or simply: "postgres://host1/db1|postgres://host2/db2" (names derived from database)
export interface DatabaseConfig {
id: string; // URL-safe identifier
name: string; // Display name
url: string; // Connection string
schema: string; // pg-boss schema
}
/**
* Strip a database configuration down to what the browser is allowed to see.
*
* `url` is a connection string with a password in it. Anything a loader
* returns is serialized into the SSR payload and readable in page source, so
* the projection has to happen before the value leaves the server, not in the
* component that renders it.
*/
export function toPublicDatabase ({ id, name, schema }: DatabaseConfig): PublicDatabase {
return { id, name, schema }
}
const SEPARATOR = '|'
const DEFAULT_SCHEMA = 'pgboss'
/**
* Parse DATABASE_URL and PGBOSS_SCHEMA environment variables
* into a list of database configurations.
*/
export function parseDatabaseConfig (): DatabaseConfig[] {
const dbUrlEnv = process.env.DATABASE_URL || 'postgres://localhost/pgboss'
const schemaEnv = process.env.PGBOSS_SCHEMA || DEFAULT_SCHEMA
const urlParts = dbUrlEnv.split(SEPARATOR).map(s => s.trim()).filter(Boolean)
const schemaParts = schemaEnv.split(SEPARATOR).map(s => s.trim()).filter(Boolean)
return urlParts.map((part, index) => {
// Check for "name=url" format
const equalsIndex = part.indexOf('=')
let name: string
let url: string
// Only treat as name=url if = comes before :// (to avoid matching postgres://user:pass@)
const protocolIndex = part.indexOf('://')
if (equalsIndex > 0 && (protocolIndex === -1 || equalsIndex < protocolIndex)) {
name = part.substring(0, equalsIndex).trim()
url = part.substring(equalsIndex + 1).trim()
} else {
url = part
name = extractDatabaseName(url) || `Database ${index + 1}`
}
const schema = schemaParts[index] || DEFAULT_SCHEMA
const id = generateId(name, index)
return { id, name, url, schema }
})
}
/**
* Extract database name from connection string for display
*/
function extractDatabaseName (url: string): string | null {
try {
// Handle postgres:// URLs
const match = url.match(/\/([^/?]+)(?:\?|$)/)
if (match) {
return match[1]
}
return null
} catch {
return null
}
}
/**
* Generate a URL-safe ID from the name
*/
function generateId (name: string, index: number): string {
const sanitized = name
.toLowerCase()
.replace(/[^a-z0-9]+/g, '-')
.replace(/^-|-$/g, '')
return sanitized || `db-${index}`
}
/**
* Find a database config by ID
*/
export function findDatabaseById (
configs: DatabaseConfig[],
id: string | null
): DatabaseConfig | null {
if (!id) return configs[0] || null
return configs.find(c => c.id === id) || configs[0] || null
}
// Cached config to avoid re-parsing on every request
let cachedConfig: DatabaseConfig[] | null = null
export function getDatabaseConfigs (): DatabaseConfig[] {
if (!cachedConfig) {
cachedConfig = parseDatabaseConfig()
}
return cachedConfig
}
// For testing - reset cache
export function resetConfigCache (): void {
cachedConfig = null
}