quilltap 3.1.0-dev.29 → 3.1.0-dev.30
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/quilltap.js +96 -9
- package/package.json +1 -1
package/bin/quilltap.js
CHANGED
|
@@ -114,6 +114,17 @@ function openBrowser(url) {
|
|
|
114
114
|
});
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
// Resolve a native module's directory, handling npm hoisting.
|
|
118
|
+
// Returns the directory containing package.json, or null if not found.
|
|
119
|
+
function resolveModuleDir(moduleName) {
|
|
120
|
+
try {
|
|
121
|
+
const pkgJson = require.resolve(moduleName + '/package.json');
|
|
122
|
+
return path.dirname(pkgJson);
|
|
123
|
+
} catch {
|
|
124
|
+
return null;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
117
128
|
// Check if native modules are compiled for the current Node.js version.
|
|
118
129
|
// This handles the case where npx caches the package but the user upgrades
|
|
119
130
|
// Node.js — the cached native modules will have a stale NODE_MODULE_VERSION.
|
|
@@ -123,10 +134,11 @@ function ensureNativeModules() {
|
|
|
123
134
|
// Check better-sqlite3: it lazy-loads the native .node binary only when you
|
|
124
135
|
// create a Database, so a bare require('better-sqlite3') always succeeds.
|
|
125
136
|
// We must load the native binding directly to detect NODE_MODULE_VERSION mismatches.
|
|
137
|
+
// Use require.resolve to find it regardless of npm hoisting.
|
|
126
138
|
try {
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
);
|
|
139
|
+
const modDir = resolveModuleDir('better-sqlite3');
|
|
140
|
+
if (!modDir) throw Object.assign(new Error('not found'), { code: 'MODULE_NOT_FOUND' });
|
|
141
|
+
const bindingsPath = path.join(modDir, 'build', 'Release', 'better_sqlite3.node');
|
|
130
142
|
require(bindingsPath);
|
|
131
143
|
} catch (err) {
|
|
132
144
|
if (err.message && err.message.includes('NODE_MODULE_VERSION')) {
|
|
@@ -167,6 +179,77 @@ function ensureNativeModules() {
|
|
|
167
179
|
}
|
|
168
180
|
}
|
|
169
181
|
|
|
182
|
+
// Symlink native modules into the standalone directory's node_modules
|
|
183
|
+
// so that standard Node.js resolution finds them without relying on NODE_PATH.
|
|
184
|
+
function linkNativeModules(standaloneDir) {
|
|
185
|
+
const standaloneNodeModules = path.join(standaloneDir, 'node_modules');
|
|
186
|
+
|
|
187
|
+
// Ensure top-level node_modules exists in standalone dir
|
|
188
|
+
if (!fs.existsSync(standaloneNodeModules)) {
|
|
189
|
+
fs.mkdirSync(standaloneNodeModules, { recursive: true });
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const symlinkType = process.platform === 'win32' ? 'junction' : 'dir';
|
|
193
|
+
|
|
194
|
+
// Link a single module directory into standaloneDir/node_modules/<name>
|
|
195
|
+
function linkModule(name, sourceDir) {
|
|
196
|
+
if (!sourceDir) return;
|
|
197
|
+
const targetPath = path.join(standaloneNodeModules, name);
|
|
198
|
+
|
|
199
|
+
// If already exists and points to the right place, skip
|
|
200
|
+
if (fs.existsSync(targetPath)) {
|
|
201
|
+
try {
|
|
202
|
+
const existing = fs.realpathSync(targetPath);
|
|
203
|
+
const source = fs.realpathSync(sourceDir);
|
|
204
|
+
if (existing === source) return; // already linked correctly
|
|
205
|
+
} catch {
|
|
206
|
+
// If we can't resolve, remove and re-link
|
|
207
|
+
}
|
|
208
|
+
// Remove stale link/dir
|
|
209
|
+
fs.rmSync(targetPath, { recursive: true, force: true });
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// Ensure parent directory exists (for scoped packages like @img/sharp-*)
|
|
213
|
+
const parentDir = path.dirname(targetPath);
|
|
214
|
+
if (!fs.existsSync(parentDir)) {
|
|
215
|
+
fs.mkdirSync(parentDir, { recursive: true });
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
try {
|
|
219
|
+
fs.symlinkSync(sourceDir, targetPath, symlinkType);
|
|
220
|
+
} catch (err) {
|
|
221
|
+
// If symlink fails (e.g. permissions), try copying as fallback
|
|
222
|
+
console.error(` Warning: Could not symlink ${name}: ${err.message}`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// Link better-sqlite3
|
|
227
|
+
const betterSqlite3Dir = resolveModuleDir('better-sqlite3');
|
|
228
|
+
linkModule('better-sqlite3', betterSqlite3Dir);
|
|
229
|
+
|
|
230
|
+
// Link sharp
|
|
231
|
+
const sharpDir = resolveModuleDir('sharp');
|
|
232
|
+
linkModule('sharp', sharpDir);
|
|
233
|
+
|
|
234
|
+
// Link sharp's @img platform packages — they live near sharp's location
|
|
235
|
+
if (sharpDir) {
|
|
236
|
+
const sharpParent = path.dirname(sharpDir);
|
|
237
|
+
|
|
238
|
+
// If sharp is in a scoped dir or regular node_modules, look for @img there
|
|
239
|
+
const imgDir = path.join(sharpParent, '@img');
|
|
240
|
+
if (fs.existsSync(imgDir)) {
|
|
241
|
+
try {
|
|
242
|
+
const imgPackages = fs.readdirSync(imgDir).filter(name => name.startsWith('sharp-'));
|
|
243
|
+
for (const pkg of imgPackages) {
|
|
244
|
+
linkModule(`@img/${pkg}`, path.join(imgDir, pkg));
|
|
245
|
+
}
|
|
246
|
+
} catch {
|
|
247
|
+
// Non-fatal — sharp may work without explicit @img links
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
|
|
170
253
|
// Main
|
|
171
254
|
async function main() {
|
|
172
255
|
const opts = parseArgs(process.argv);
|
|
@@ -206,6 +289,9 @@ async function main() {
|
|
|
206
289
|
// Ensure native modules are compiled for the current Node.js version
|
|
207
290
|
ensureNativeModules();
|
|
208
291
|
|
|
292
|
+
// Symlink native modules into standalone dir so standard resolution finds them
|
|
293
|
+
linkNativeModules(standaloneDir);
|
|
294
|
+
|
|
209
295
|
// Set up environment
|
|
210
296
|
const env = {
|
|
211
297
|
...process.env,
|
|
@@ -218,13 +304,14 @@ async function main() {
|
|
|
218
304
|
env.QUILLTAP_DATA_DIR = path.resolve(opts.dataDir);
|
|
219
305
|
}
|
|
220
306
|
|
|
221
|
-
// Set NODE_PATH
|
|
222
|
-
//
|
|
223
|
-
//
|
|
307
|
+
// Set NODE_PATH as a fallback — native modules are symlinked into standaloneDir
|
|
308
|
+
// but NODE_PATH covers any other dependencies. Include the parent node_modules
|
|
309
|
+
// to handle npm hoisting (e.g. npx installs where deps are hoisted up a level).
|
|
224
310
|
const packageNodeModules = path.join(PACKAGE_DIR, 'node_modules');
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
311
|
+
const parentNodeModules = path.resolve(PACKAGE_DIR, '..');
|
|
312
|
+
env.NODE_PATH = [packageNodeModules, parentNodeModules, env.NODE_PATH]
|
|
313
|
+
.filter(Boolean)
|
|
314
|
+
.join(path.delimiter);
|
|
228
315
|
|
|
229
316
|
const url = `http://localhost:${opts.port}`;
|
|
230
317
|
|