hostdb 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +131 -0
- package/README.md +228 -0
- package/bin/cli.js +75 -0
- package/cli/bin.ts +527 -0
- package/databases.json +943 -0
- package/downloads.json +1766 -0
- package/lib/checksums.ts +98 -0
- package/lib/databases.ts +82 -0
- package/package.json +67 -0
- package/releases.json +658 -0
package/lib/checksums.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared checksum utilities for fetching and parsing checksums.txt files
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
type GitHubAsset = {
|
|
6
|
+
id: number
|
|
7
|
+
name: string
|
|
8
|
+
browser_download_url: string
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
type GitHubRelease = {
|
|
12
|
+
assets: GitHubAsset[]
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Parse checksums.txt content into a record of filename -> hash
|
|
17
|
+
*/
|
|
18
|
+
export function parseChecksums(content: string): Record<string, string> {
|
|
19
|
+
const checksums: Record<string, string> = {}
|
|
20
|
+
|
|
21
|
+
for (const line of content.split('\n')) {
|
|
22
|
+
// Format: "hash filename" or "hash *filename" (binary mode)
|
|
23
|
+
const match = line.match(/^([a-f0-9]{64})\s+\*?(.+)$/)
|
|
24
|
+
if (match) {
|
|
25
|
+
checksums[match[2]] = match[1]
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
return checksums
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Fetch checksums.txt from a GitHub release using the API (avoids CDN caching issues)
|
|
34
|
+
*
|
|
35
|
+
* @param repo - Repository in "owner/repo" format
|
|
36
|
+
* @param tag - Release tag name
|
|
37
|
+
* @returns Record of filename -> SHA256 hash, or empty object if not found
|
|
38
|
+
*/
|
|
39
|
+
export async function fetchChecksums(
|
|
40
|
+
repo: string,
|
|
41
|
+
tag: string,
|
|
42
|
+
): Promise<Record<string, string>> {
|
|
43
|
+
// First try to get the asset URL from the API
|
|
44
|
+
const apiUrl = `https://api.github.com/repos/${repo}/releases/tags/${tag}`
|
|
45
|
+
const apiResponse = await fetch(apiUrl, {
|
|
46
|
+
headers: {
|
|
47
|
+
Accept: 'application/vnd.github.v3+json',
|
|
48
|
+
'User-Agent': 'hostdb-checksums',
|
|
49
|
+
...(process.env.GITHUB_TOKEN
|
|
50
|
+
? { Authorization: `Bearer ${process.env.GITHUB_TOKEN}` }
|
|
51
|
+
: {}),
|
|
52
|
+
},
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
if (!apiResponse.ok) {
|
|
56
|
+
return {}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const release = (await apiResponse.json()) as GitHubRelease
|
|
60
|
+
const checksumAsset = release.assets.find((a) => a.name === 'checksums.txt')
|
|
61
|
+
|
|
62
|
+
if (!checksumAsset) {
|
|
63
|
+
return {}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// Fetch the actual checksums.txt content using the asset's download URL
|
|
67
|
+
const assetResponse = await fetch(checksumAsset.browser_download_url, {
|
|
68
|
+
headers: {
|
|
69
|
+
'User-Agent': 'hostdb-checksums',
|
|
70
|
+
},
|
|
71
|
+
redirect: 'follow',
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
if (!assetResponse.ok) {
|
|
75
|
+
// Fallback: try GitHub API asset download
|
|
76
|
+
const assetApiUrl = `https://api.github.com/repos/${repo}/releases/assets/${checksumAsset.id}`
|
|
77
|
+
const assetApiResponse = await fetch(assetApiUrl, {
|
|
78
|
+
headers: {
|
|
79
|
+
Accept: 'application/octet-stream',
|
|
80
|
+
'User-Agent': 'hostdb-checksums',
|
|
81
|
+
...(process.env.GITHUB_TOKEN
|
|
82
|
+
? { Authorization: `Bearer ${process.env.GITHUB_TOKEN}` }
|
|
83
|
+
: {}),
|
|
84
|
+
},
|
|
85
|
+
redirect: 'follow',
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
if (!assetApiResponse.ok) {
|
|
89
|
+
return {}
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
const content = await assetApiResponse.text()
|
|
93
|
+
return parseChecksums(content)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const content = await assetResponse.text()
|
|
97
|
+
return parseChecksums(content)
|
|
98
|
+
}
|
package/lib/databases.ts
ADDED
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs'
|
|
2
|
+
import { dirname, join } from 'node:path'
|
|
3
|
+
import { fileURLToPath } from 'node:url'
|
|
4
|
+
|
|
5
|
+
const __dirname = dirname(fileURLToPath(import.meta.url))
|
|
6
|
+
const ROOT = join(__dirname, '..')
|
|
7
|
+
|
|
8
|
+
// Canonical platform type
|
|
9
|
+
export type Platform =
|
|
10
|
+
| 'linux-x64'
|
|
11
|
+
| 'linux-arm64'
|
|
12
|
+
| 'darwin-x64'
|
|
13
|
+
| 'darwin-arm64'
|
|
14
|
+
| 'win32-x64'
|
|
15
|
+
|
|
16
|
+
// Database entry from databases.json
|
|
17
|
+
export type DatabaseEntry = {
|
|
18
|
+
displayName?: string
|
|
19
|
+
description?: string
|
|
20
|
+
type?: string
|
|
21
|
+
license?: string
|
|
22
|
+
commercialUse?: boolean
|
|
23
|
+
status?: 'completed' | 'in-progress' | 'pending' | 'unsupported'
|
|
24
|
+
latestLts?: string
|
|
25
|
+
versions: Record<string, boolean>
|
|
26
|
+
platforms?: Record<string, boolean>
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// databases.json structure
|
|
30
|
+
export type DatabasesJson = {
|
|
31
|
+
$schema?: string
|
|
32
|
+
databases: Record<string, DatabaseEntry>
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
// Platform asset from releases.json
|
|
36
|
+
export type PlatformAsset = {
|
|
37
|
+
url: string
|
|
38
|
+
sha256: string
|
|
39
|
+
size: number
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Version release from releases.json
|
|
43
|
+
export type VersionRelease = {
|
|
44
|
+
version: string
|
|
45
|
+
releaseTag: string
|
|
46
|
+
releasedAt: string
|
|
47
|
+
platforms: Partial<Record<Platform, PlatformAsset>>
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// releases.json structure
|
|
51
|
+
export type ReleasesJson = {
|
|
52
|
+
$schema?: string
|
|
53
|
+
repository: string
|
|
54
|
+
lastUpdated: string | null
|
|
55
|
+
databases: Record<string, Record<string, VersionRelease>>
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export function loadDatabasesJson(): DatabasesJson {
|
|
59
|
+
const filePath = join(ROOT, 'databases.json')
|
|
60
|
+
return JSON.parse(readFileSync(filePath, 'utf-8')) as DatabasesJson
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
export function loadReleasesJson(): ReleasesJson {
|
|
64
|
+
const filePath = join(ROOT, 'releases.json')
|
|
65
|
+
return JSON.parse(readFileSync(filePath, 'utf-8')) as ReleasesJson
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function getEnabledVersions(database: string): Set<string> {
|
|
69
|
+
try {
|
|
70
|
+
const data = loadDatabasesJson()
|
|
71
|
+
const dbEntry = data.databases[database]
|
|
72
|
+
if (!dbEntry) return new Set()
|
|
73
|
+
|
|
74
|
+
return new Set(
|
|
75
|
+
Object.entries(dbEntry.versions)
|
|
76
|
+
.filter(([, enabled]) => enabled === true)
|
|
77
|
+
.map(([version]) => version),
|
|
78
|
+
)
|
|
79
|
+
} catch {
|
|
80
|
+
return new Set()
|
|
81
|
+
}
|
|
82
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "hostdb",
|
|
3
|
+
"version": "0.10.0",
|
|
4
|
+
"description": "Source and download pre-built database binaries for multiple platforms, distributed via GitHub Releases",
|
|
5
|
+
"private": false,
|
|
6
|
+
"type": "module",
|
|
7
|
+
"bin": {
|
|
8
|
+
"hostdb": "./bin/cli.js"
|
|
9
|
+
},
|
|
10
|
+
"author": "Bob Bass",
|
|
11
|
+
"license": "PolyForm-Noncommercial-1.0.0",
|
|
12
|
+
"repository": {
|
|
13
|
+
"type": "git",
|
|
14
|
+
"url": "https://github.com/robertjbass/hostdb.git"
|
|
15
|
+
},
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"files": [
|
|
20
|
+
"bin",
|
|
21
|
+
"cli",
|
|
22
|
+
"lib",
|
|
23
|
+
"databases.json",
|
|
24
|
+
"releases.json",
|
|
25
|
+
"downloads.json"
|
|
26
|
+
],
|
|
27
|
+
"scripts": {
|
|
28
|
+
"start": "tsx cli/bin.ts",
|
|
29
|
+
"add:engine": "tsx scripts/add-engine.ts",
|
|
30
|
+
"checksums:populate": "tsx scripts/populate-checksums.ts",
|
|
31
|
+
"dbs": "tsx scripts/list-databases.ts",
|
|
32
|
+
"download:clickhouse": "tsx builds/clickhouse/download.ts",
|
|
33
|
+
"download:mariadb": "tsx builds/mariadb/download.ts",
|
|
34
|
+
"download:mongodb": "tsx builds/mongodb/download.ts",
|
|
35
|
+
"download:mysql": "tsx builds/mysql/download.ts",
|
|
36
|
+
"download:postgresql": "tsx builds/postgresql/download.ts",
|
|
37
|
+
"download:redis": "tsx builds/redis/download.ts",
|
|
38
|
+
"download:sqlite": "tsx builds/sqlite/download.ts",
|
|
39
|
+
"download:valkey": "tsx builds/valkey/download.ts",
|
|
40
|
+
"edb:fileids": "tsx scripts/fetch-edb-fileids.ts",
|
|
41
|
+
"format": "prettier --write .",
|
|
42
|
+
"lint": "tsc --noEmit && eslint .",
|
|
43
|
+
"prep": "tsx scripts/prep.ts",
|
|
44
|
+
"reconcile:releases": "tsx scripts/reconcile-releases.ts",
|
|
45
|
+
"sync:versions": "tsx scripts/sync-versions.ts",
|
|
46
|
+
"update:releases": "tsx scripts/update-releases.ts",
|
|
47
|
+
"repair:checksums": "tsx scripts/repair-checksums.ts"
|
|
48
|
+
},
|
|
49
|
+
"dependencies": {
|
|
50
|
+
"tsx": "^4.19.0"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@eslint/js": "^9.17.0",
|
|
54
|
+
"@types/node": "^22.10.0",
|
|
55
|
+
"chalk": "^5.6.2",
|
|
56
|
+
"cli-table3": "^0.6.5",
|
|
57
|
+
"eslint": "^9.17.0",
|
|
58
|
+
"prettier": "^3.4.0",
|
|
59
|
+
"typescript": "^5.7.0",
|
|
60
|
+
"typescript-eslint": "^8.18.0",
|
|
61
|
+
"yaml": "^2.8.2"
|
|
62
|
+
},
|
|
63
|
+
"packageManager": "pnpm@9.15.0",
|
|
64
|
+
"engines": {
|
|
65
|
+
"node": ">=20"
|
|
66
|
+
}
|
|
67
|
+
}
|