Skip to content

Commit 357ecee

Browse files
authored
Merge pull request #1 from Yashh56/db/sqlite
fix: packaged SQLite bridge bindings for release builds
2 parents 64a0f0b + 3d6a12e commit 357ecee

12 files changed

Lines changed: 474 additions & 64 deletions

File tree

.github/workflows/release.yml

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,13 @@ jobs:
3636
- name: Setup Node
3737
uses: actions/setup-node@v4
3838
with:
39-
node-version: lts/*
39+
node-version: 22
40+
cache: "pnpm"
4041

4142
- name: Setup pnpm
42-
uses: pnpm/action-setup@v2
43+
uses: pnpm/action-setup@v4
4344
with:
44-
version: 8
45+
version: 10
4546

4647
- name: Install Rust stable
4748
uses: dtolnay/rust-toolchain@stable
@@ -50,27 +51,10 @@ jobs:
5051
targets: ${{ matrix.platform == 'macos-latest' && 'aarch64-apple-darwin,x86_64-apple-darwin' || '' }}
5152

5253
- name: Install frontend dependencies
53-
run: pnpm install
54+
run: pnpm install --frozen-lockfile
5455

55-
- name: Build bridge (Windows)
56-
if: matrix.platform == 'windows-latest'
57-
run: |
58-
cd bridge
59-
pnpm install --frozen-lockfile=false
60-
npx esbuild src/index.ts --bundle --platform=node --outfile=dist/index.cjs --format=cjs --packages=external
61-
cd ..
62-
npm install -g pkg@5.8.1
63-
pkg ./bridge/dist/index.cjs --target node18-win-x64 --output ./src-tauri/resources/bridge-x86_64-pc-windows-msvc.exe
64-
65-
- name: Build bridge (Linux)
66-
if: matrix.platform == 'ubuntu-22.04'
67-
run: |
68-
cd bridge
69-
pnpm install --frozen-lockfile=false
70-
npx esbuild src/index.ts --bundle --platform=node --outfile=dist/index.cjs --format=cjs --packages=external
71-
cd ..
72-
npm install -g pkg@5.8.1
73-
pkg ./bridge/dist/index.cjs --target node18-linux-x64 --output ./src-tauri/resources/bridge-x86_64-unknown-linux-gnu
56+
- name: Install bridge dependencies
57+
run: pnpm --dir bridge install --frozen-lockfile
7458

7559
- name: Build and release
7660
uses: tauri-apps/tauri-action@v0

README.md

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -124,9 +124,7 @@ pnpm tauri dev
124124
**Windows:**
125125

126126
```bash
127-
cd bridge && pnpm build && cd ..
128-
npx pkg ./bridge/dist/index.cjs --target node18-win-x64 \
129-
--output ./src-tauri/resources/bridge-x86_64-pc-windows-msvc.exe
127+
pnpm run package-bridge
130128
pnpm tauri build
131129
```
132130

@@ -135,9 +133,7 @@ pnpm tauri build
135133
```bash
136134
sudo apt install libwebkit2gtk-4.1-dev libappindicator3-dev librsvg2-dev patchelf
137135

138-
cd bridge && pnpm build && cd ..
139-
npx pkg ./bridge/dist/index.cjs --target node18-linux-x64 \
140-
--output ./src-tauri/resources/bridge-x86_64-unknown-linux-gnu
136+
pnpm --dir bridge run build:pkg:linux
141137
pnpm tauri build
142138
```
143139

@@ -355,4 +351,4 @@ This project is licensed under the MIT License. See [LICENSE](LICENSE) for detai
355351

356352
[Star on GitHub](https://github.com/Relwave/relwave-app) · [Download](https://github.com/Relwave/relwave-app/releases) · [Report Issues](https://github.com/Relwave/relwave-app/issues) · [Request Features](https://github.com/Relwave/relwave-app/issues)
357353

358-
</div>
354+
</div>

bridge/package.json

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,18 @@
77
"dev": "ts-node-dev --respawn --transpile-only src/index.ts",
88
"start": "node dist/index.cjs",
99
"build": "esbuild src/index.ts --bundle --platform=node --outfile=dist/index.cjs --format=cjs --packages=external",
10-
"build:pkg": "pkg . --out-path exece",
11-
"postpkg": "node scripts/copy-native.js",
10+
"copy:native": "node scripts/copy-native.js",
11+
"build:pkg": "node scripts/build-pkg.js",
12+
"build:pkg:win": "pnpm run build && pnpm run copy:native && pnpm exec pkg . --target node18-win-x64 --output ../src-tauri/resources/bridge-x86_64-pc-windows-msvc.exe",
13+
"build:pkg:linux": "pnpm run build && pnpm run copy:native && pnpm exec pkg . --target node18-linux-x64 --output ../src-tauri/resources/bridge-x86_64-unknown-linux-gnu",
1214
"test": "jest",
1315
"test:watch": "jest --watchAll --detectOpenHandles"
1416
},
1517
"dependencies": {
1618
"@jest/globals": "^30.2.0",
1719
"@napi-rs/keyring": "^1.2.0",
1820
"bcryptjs": "^3.0.3",
19-
"better-sqlite3": "^12.6.2",
21+
"better-sqlite3": "^11.9.0",
2022
"dotenv": "^17.2.3",
2123
"mysql2": "^3.15.3",
2224
"pg": "^8.16.3",

bridge/pnpm-lock.yaml

Lines changed: 5 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

bridge/pnpm-workspace.yaml

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
packages: []
22

3-
ignoredBuiltDependencies:
4-
- better-sqlite3
5-
63
onlyBuiltDependencies:
7-
- keytar
4+
- better-sqlite3
5+
- "@napi-rs/keyring"

bridge/scripts/build-pkg.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
#!/usr/bin/env node
2+
3+
const { spawnSync } = require("child_process");
4+
5+
const targetScriptByPlatform = {
6+
win32: "build:pkg:win",
7+
linux: "build:pkg:linux",
8+
};
9+
10+
const targetScript = targetScriptByPlatform[process.platform];
11+
12+
if (!targetScript) {
13+
console.error(
14+
`ERROR: Unsupported platform for bridge packaging: ${process.platform}`,
15+
);
16+
process.exit(1);
17+
}
18+
19+
const pnpmCommand = process.platform === "win32" ? "pnpm.cmd" : "pnpm";
20+
const result = spawnSync(pnpmCommand, ["run", targetScript], {
21+
stdio: "inherit",
22+
});
23+
24+
if (result.error) {
25+
console.error(result.error.message);
26+
process.exit(1);
27+
}
28+
29+
process.exit(result.status ?? 1);

bridge/scripts/copy-native.js

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
#!/usr/bin/env node
2+
/**
3+
* Packaging helper: copy a better-sqlite3 native addon that matches the
4+
* packaged bridge runtime, not necessarily the host Node.js runtime.
5+
*
6+
* pkg 5.8.x embeds a Node 18.5.0 runtime for this project, so a host-built
7+
* Node 22 addon will load in development but fail inside the packaged bridge
8+
* with a NODE_MODULE_VERSION mismatch.
9+
*/
10+
11+
const { execFileSync } = require("child_process");
12+
const fs = require("fs");
13+
const os = require("os");
14+
const path = require("path");
15+
16+
const PKG_RUNTIME = {
17+
nodeVersion: "18.5.0",
18+
nodeModules: "108",
19+
platform: process.platform,
20+
arch: process.arch,
21+
};
22+
23+
function findFirstExisting(candidates) {
24+
return candidates.find((candidate) => fs.existsSync(candidate));
25+
}
26+
27+
function findFirstNodeBinary(rootDir) {
28+
const queue = [rootDir];
29+
30+
while (queue.length > 0) {
31+
const currentDir = queue.shift();
32+
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
33+
34+
for (const entry of entries) {
35+
const fullPath = path.join(currentDir, entry.name);
36+
if (entry.isDirectory()) {
37+
queue.push(fullPath);
38+
continue;
39+
}
40+
if (entry.isFile() && fullPath.endsWith(".node")) {
41+
return fullPath;
42+
}
43+
}
44+
}
45+
46+
return undefined;
47+
}
48+
49+
function downloadPkgRuntimeBinary(betterSqlite3Dir) {
50+
const packageJsonPath = path.join(betterSqlite3Dir, "package.json");
51+
const tempDir = fs.mkdtempSync(
52+
path.join(os.tmpdir(), "relwave-better-sqlite3-"),
53+
);
54+
const prebuildInstallBin = require.resolve("prebuild-install/bin.js", {
55+
paths: [betterSqlite3Dir],
56+
});
57+
58+
fs.copyFileSync(packageJsonPath, path.join(tempDir, "package.json"));
59+
60+
try {
61+
execFileSync(
62+
process.execPath,
63+
[
64+
prebuildInstallBin,
65+
"--target",
66+
PKG_RUNTIME.nodeVersion,
67+
"--runtime",
68+
"node",
69+
"--platform",
70+
PKG_RUNTIME.platform,
71+
"--arch",
72+
PKG_RUNTIME.arch,
73+
"--path",
74+
tempDir,
75+
],
76+
{
77+
cwd: betterSqlite3Dir,
78+
stdio: "inherit",
79+
},
80+
);
81+
} catch (error) {
82+
console.error(
83+
"ERROR: Failed to fetch a better-sqlite3 binary for the packaged bridge runtime.",
84+
);
85+
console.error(
86+
` Packaged bridge runtime: Node ${PKG_RUNTIME.nodeVersion} (NODE_MODULE_VERSION ${PKG_RUNTIME.nodeModules})`,
87+
);
88+
console.error(
89+
` Current build runtime: ${process.version} (NODE_MODULE_VERSION ${process.versions.modules})`,
90+
);
91+
console.error(
92+
" Re-run the build with internet access, or rebuild better-sqlite3 for Node 18 before packaging.",
93+
);
94+
process.exit(error.status || 1);
95+
}
96+
97+
const downloadedBinary = findFirstNodeBinary(tempDir);
98+
if (!downloadedBinary) {
99+
console.error(
100+
"ERROR: prebuild-install completed, but no better_sqlite3.node was extracted.",
101+
);
102+
process.exit(1);
103+
}
104+
105+
return downloadedBinary;
106+
}
107+
108+
function resolveNativeBinarySource(betterSqlite3Dir) {
109+
const runtimeSpecificCandidates = [
110+
path.join(
111+
betterSqlite3Dir,
112+
"lib",
113+
"binding",
114+
`node-v${PKG_RUNTIME.nodeModules}-${PKG_RUNTIME.platform}-${PKG_RUNTIME.arch}`,
115+
"better_sqlite3.node",
116+
),
117+
path.join(
118+
betterSqlite3Dir,
119+
"compiled",
120+
PKG_RUNTIME.nodeVersion,
121+
PKG_RUNTIME.platform,
122+
PKG_RUNTIME.arch,
123+
"better_sqlite3.node",
124+
),
125+
];
126+
127+
const runtimeSpecificBinary = findFirstExisting(runtimeSpecificCandidates);
128+
if (runtimeSpecificBinary) {
129+
return runtimeSpecificBinary;
130+
}
131+
132+
if (process.versions.modules === PKG_RUNTIME.nodeModules) {
133+
const localBuildBinary = findFirstExisting([
134+
path.join(betterSqlite3Dir, "build", "Release", "better_sqlite3.node"),
135+
path.join(betterSqlite3Dir, "build", "Debug", "better_sqlite3.node"),
136+
]);
137+
138+
if (localBuildBinary) {
139+
return localBuildBinary;
140+
}
141+
}
142+
143+
return downloadPkgRuntimeBinary(betterSqlite3Dir);
144+
}
145+
146+
const betterSqlite3Pkg = require.resolve("better-sqlite3/package.json");
147+
const betterSqlite3Dir = path.dirname(betterSqlite3Pkg);
148+
const src = resolveNativeBinarySource(betterSqlite3Dir);
149+
150+
if (!src || !fs.existsSync(src)) {
151+
console.error("ERROR: Could not resolve better_sqlite3.node for packaging.");
152+
process.exit(1);
153+
}
154+
155+
const repoRoot = path.resolve(__dirname, "..", "..");
156+
const dest = path.join(
157+
repoRoot,
158+
"src-tauri",
159+
"resources",
160+
"better_sqlite3.node",
161+
);
162+
163+
fs.mkdirSync(path.dirname(dest), { recursive: true });
164+
fs.copyFileSync(src, dest);
165+
console.log("Copied better_sqlite3.node");
166+
console.log(" from:", src);
167+
console.log(" to: ", dest);

0 commit comments

Comments
 (0)