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.
@@ -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
+ }
@@ -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
+ }