@fahimadib01/db-snap 0.1.1

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/bin/db-snap.js ADDED
@@ -0,0 +1,27 @@
1
+ #!/usr/bin/env node
2
+
3
+ const fs = require("node:fs");
4
+ const path = require("node:path");
5
+ const { spawn } = require("node:child_process");
6
+
7
+ const binaryPath = path.join(__dirname, "db-snap-bin");
8
+
9
+ if (!fs.existsSync(binaryPath)) {
10
+ console.error("db-snap binary is missing. Reinstall with: npm install -g db-snap");
11
+ process.exit(1);
12
+ }
13
+
14
+ const child = spawn(binaryPath, process.argv.slice(2), { stdio: "inherit" });
15
+
16
+ child.on("error", (err) => {
17
+ console.error(`failed to run db-snap: ${err.message}`);
18
+ process.exit(1);
19
+ });
20
+
21
+ child.on("exit", (code, signal) => {
22
+ if (signal) {
23
+ process.kill(process.pid, signal);
24
+ return;
25
+ }
26
+ process.exit(code ?? 1);
27
+ });
package/package.json ADDED
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "@fahimadib01/db-snap",
3
+ "version": "0.1.1",
4
+ "description": "Installable db-snap CLI wrapper",
5
+ "bin": {
6
+ "db-snap": "bin/db-snap.js"
7
+ },
8
+ "scripts": {
9
+ "postinstall": "node scripts/postinstall.js"
10
+ },
11
+ "files": [
12
+ "bin/db-snap.js",
13
+ "scripts/postinstall.js"
14
+ ],
15
+ "os": [
16
+ "darwin",
17
+ "linux"
18
+ ],
19
+ "cpu": [
20
+ "x64",
21
+ "arm64"
22
+ ],
23
+ "preferGlobal": true,
24
+ "publishConfig": {
25
+ "access": "public"
26
+ },
27
+ "config": {
28
+ "repo": "FahimAdib/db-snap"
29
+ },
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/FahimAdib/db-snap.git"
33
+ },
34
+ "license": "MIT"
35
+ }
@@ -0,0 +1,137 @@
1
+ const fs = require("node:fs");
2
+ const os = require("node:os");
3
+ const path = require("node:path");
4
+ const https = require("node:https");
5
+ const crypto = require("node:crypto");
6
+ const { execFileSync } = require("node:child_process");
7
+
8
+ const pkg = require("../package.json");
9
+
10
+ const platformMap = {
11
+ darwin: "darwin",
12
+ linux: "linux",
13
+ };
14
+
15
+ const archMap = {
16
+ x64: "amd64",
17
+ arm64: "arm64",
18
+ };
19
+
20
+ function fail(message) {
21
+ console.error(`db-snap install failed: ${message}`);
22
+ process.exit(1);
23
+ }
24
+
25
+ function download(url, destination, redirects = 0) {
26
+ return new Promise((resolve, reject) => {
27
+ const req = https.get(
28
+ url,
29
+ {
30
+ headers: {
31
+ "User-Agent": "db-snap-npm-installer",
32
+ Accept: "application/octet-stream,text/plain,*/*",
33
+ },
34
+ },
35
+ (res) => {
36
+ if ([301, 302, 307, 308].includes(res.statusCode) && res.headers.location) {
37
+ if (redirects > 5) {
38
+ reject(new Error("too many redirects"));
39
+ return;
40
+ }
41
+ download(res.headers.location, destination, redirects + 1).then(resolve).catch(reject);
42
+ return;
43
+ }
44
+
45
+ if (res.statusCode !== 200) {
46
+ reject(new Error(`download failed (${res.statusCode})`));
47
+ return;
48
+ }
49
+
50
+ const out = fs.createWriteStream(destination);
51
+ res.pipe(out);
52
+ out.on("finish", () => out.close(resolve));
53
+ out.on("error", reject);
54
+ }
55
+ );
56
+
57
+ req.on("error", reject);
58
+ });
59
+ }
60
+
61
+ function sha256(filePath) {
62
+ const hash = crypto.createHash("sha256");
63
+ hash.update(fs.readFileSync(filePath));
64
+ return hash.digest("hex");
65
+ }
66
+
67
+ function findFile(root, name) {
68
+ const entries = fs.readdirSync(root, { withFileTypes: true });
69
+ for (const entry of entries) {
70
+ const full = path.join(root, entry.name);
71
+ if (entry.isDirectory()) {
72
+ const found = findFile(full, name);
73
+ if (found) {
74
+ return found;
75
+ }
76
+ continue;
77
+ }
78
+ if (entry.name === name) {
79
+ return full;
80
+ }
81
+ }
82
+ return null;
83
+ }
84
+
85
+ async function install() {
86
+ const platform = platformMap[os.platform()];
87
+ const arch = archMap[os.arch()];
88
+ if (!platform || !arch) {
89
+ fail(`unsupported platform/arch: ${os.platform()}/${os.arch()}`);
90
+ }
91
+
92
+ const repo = process.env.DB_SNAP_REPO || (pkg.config && pkg.config.repo);
93
+ if (!repo || !repo.includes("/")) {
94
+ fail("missing GitHub repo. Set package.json config.repo to owner/name.");
95
+ }
96
+
97
+ const version = pkg.version;
98
+ const assetName = `db-snap_${version}_${platform}_${arch}.tar.gz`;
99
+ const base = `https://github.com/${repo}/releases/download/v${version}`;
100
+ const archiveURL = `${base}/${assetName}`;
101
+ const checksumsURL = `${base}/checksums.txt`;
102
+
103
+ const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "db-snap-install-"));
104
+ const archivePath = path.join(tempDir, assetName);
105
+ const checksumsPath = path.join(tempDir, "checksums.txt");
106
+
107
+ try {
108
+ await download(archiveURL, archivePath);
109
+ await download(checksumsURL, checksumsPath);
110
+
111
+ const checksums = fs.readFileSync(checksumsPath, "utf8").split(/\r?\n/);
112
+ const line = checksums.find((item) => item.trim().endsWith(` ${assetName}`) || item.trim().endsWith(` ${assetName}`));
113
+ if (!line) {
114
+ fail(`checksum entry not found for ${assetName}`);
115
+ }
116
+ const expected = line.trim().split(/\s+/)[0];
117
+ const actual = sha256(archivePath);
118
+ if (expected !== actual) {
119
+ fail("checksum mismatch for downloaded archive");
120
+ }
121
+
122
+ execFileSync("tar", ["-xzf", archivePath, "-C", tempDir], { stdio: "ignore" });
123
+ const extractedBinary = findFile(tempDir, "db-snap");
124
+ if (!extractedBinary) {
125
+ fail("db-snap binary not found in release archive");
126
+ }
127
+
128
+ const targetPath = path.join(__dirname, "..", "bin", "db-snap-bin");
129
+ fs.copyFileSync(extractedBinary, targetPath);
130
+ fs.chmodSync(targetPath, 0o755);
131
+ console.log(`db-snap ${version} installed (${platform}/${arch}).`);
132
+ } finally {
133
+ fs.rmSync(tempDir, { recursive: true, force: true });
134
+ }
135
+ }
136
+
137
+ install().catch((err) => fail(err.message));