microsoft/TypeAgent

Public

mirrored from https://github.com/microsoft/TypeAgentAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
6d1b48d2ec96543e45536ee134daa90629a77d13

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

ts/tools/scripts/copy-better-sqlite3-node.js

145lines · modecode

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4// Save the Node.js-compatible better-sqlite3 native binary to a safe location.
5//
6// Problem: electron-builder's install-app-deps (in packages/shell postinstall)
7// rebuilds better-sqlite3 for Electron, wiping the entire build/ directory.
8// This runs in the root postinstall BEFORE electron-builder, so we save the
9// correct Node.js binary to prebuild-node/ (outside build/) where
10// electron-builder won't touch it.
11//
12// If the binary in build/Release/ is already for Electron (wrong ABI), we
13// re-download the correct Node.js prebuilt via prebuild-install.
14//
15// Works with pnpm's store layout on Windows, macOS, and Linux.
16
17const fs = require("fs");
18const path = require("path");
19const { execFileSync } = require("child_process");
20
21const expectedABI = process.versions.modules; // e.g. "127" for Node 22
22
23function isNodeCompatible(binaryPath) {
24 try {
25 process.dlopen({ exports: {} }, binaryPath);
26 return true;
27 } catch {
28 return false;
29 }
30}
31
32// Find all better-sqlite3 installations in the pnpm store
33const pnpmDir = path.resolve(__dirname, "..", "..", "node_modules", ".pnpm");
34const entries = fs
35 .readdirSync(pnpmDir)
36 .filter((e) => e.startsWith("better-sqlite3@"));
37
38if (entries.length === 0) {
39 console.error("No better-sqlite3 installations found in", pnpmDir);
40 process.exit(1);
41}
42
43let hasError = false;
44
45for (const entry of entries) {
46 const pkgDir = path.join(pnpmDir, entry, "node_modules", "better-sqlite3");
47 if (!fs.existsSync(path.join(pkgDir, "package.json"))) {
48 continue;
49 }
50
51 console.log(`\n📦 Processing ${entry}:`);
52 console.log(" ", pkgDir);
53
54 const dstDir = path.join(pkgDir, "prebuild-node");
55 const dst = path.join(dstDir, "better_sqlite3.node");
56
57 // If prebuild-node/ already has a compatible binary, skip
58 if (fs.existsSync(dst) && isNodeCompatible(dst)) {
59 console.log("✅ Already has compatible Node.js binary in prebuild-node/");
60 continue;
61 }
62
63 const releaseBinary = path.join(
64 pkgDir,
65 "build",
66 "Release",
67 "better_sqlite3.node",
68 );
69
70 // If build/Release/ has a compatible Node.js binary, just copy it
71 if (fs.existsSync(releaseBinary) && isNodeCompatible(releaseBinary)) {
72 fs.mkdirSync(dstDir, { recursive: true });
73 fs.copyFileSync(releaseBinary, dst);
74 console.log("✅ Copied compatible binary from build/Release/");
75 console.log(" → ", dst);
76 continue;
77 }
78
79 // Binary is missing or wrong ABI (e.g. Electron) — re-download for Node.js
80 console.log(
81 "⬇️ Downloading Node.js-compatible prebuilt via prebuild-install...",
82 );
83 const tempBuildDir = path.join(pkgDir, "build-node-temp");
84 try {
85 // prebuild-install writes to build/Release/, so use a temp dir
86 // to avoid disturbing any existing Electron binary
87 fs.rmSync(tempBuildDir, { recursive: true, force: true });
88 const origBuild = path.join(pkgDir, "build");
89 const hasBuild = fs.existsSync(origBuild);
90 if (hasBuild) {
91 fs.renameSync(origBuild, tempBuildDir);
92 }
93 try {
94 execFileSync(
95 process.execPath,
96 [
97 require.resolve("prebuild-install/bin"),
98 "--runtime",
99 "node",
100 "--target",
101 process.version,
102 ],
103 {
104 cwd: pkgDir,
105 stdio: "inherit",
106 },
107 );
108
109 const downloaded = path.join(
110 pkgDir,
111 "build",
112 "Release",
113 "better_sqlite3.node",
114 );
115 if (!fs.existsSync(downloaded)) {
116 throw new Error("prebuild-install did not produce a binary");
117 }
118
119 fs.mkdirSync(dstDir, { recursive: true });
120 fs.copyFileSync(downloaded, dst);
121 console.log("✅ Node.js binary saved to prebuild-node/");
122
123 // Remove the temp build dir created by prebuild-install
124 fs.rmSync(path.join(pkgDir, "build"), { recursive: true, force: true });
125 } finally {
126 // Restore original build dir (may contain Electron binary)
127 if (hasBuild) {
128 if (!fs.existsSync(origBuild)) {
129 fs.renameSync(tempBuildDir, origBuild);
130 } else {
131 fs.rmSync(tempBuildDir, { recursive: true, force: true });
132 }
133 }
134 }
135 } catch (e) {
136 console.error(`❌ Failed for ${entry}:`, e.message);
137 fs.rmSync(tempBuildDir, { recursive: true, force: true });
138 hasError = true;
139 continue;
140 }
141}
142
143if (hasError) {
144 process.exit(1);
145}