jsql-neo 6.5.7 → 6.5.9
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/README.md +4 -1
- package/index.js +1 -1
- package/lib/btree.js +9 -9
- package/lib/cache.js +1 -1
- package/lib/database.js +1 -1
- package/lib/jsql_format.js +1 -1
- package/lib/mongo_server.js +19 -3
- package/lib/mysql_server.js +7 -4
- package/lib/native_client.js +1 -1
- package/lib/native_target.js +53 -0
- package/lib/nedb_compat.js +1 -1
- package/lib/pg_server.js +3 -2
- package/lib/query.js +1 -1
- package/lib/redis_server.js +1 -1
- package/lib/sql.js +25 -9
- package/lib/tui.js +3 -1
- package/package.json +1 -1
- package/postinstall.js +45 -15
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
> **One engine to rule them all** — a Rust-powered embedded database that speaks your language:
|
|
4
4
|
> MySQL, PostgreSQL, MongoDB, Redis, SQL, TypeScript, **and the browser**.
|
|
5
5
|
|
|
6
|
-
> **v6.5.
|
|
6
|
+
> **v6.5.9** — stable release · [github.com/vexify-org/JSQL-neo](https://github.com/vexify-org/JSQL-neo) · [jsql.vexify.top](https://jsql.vexify.top)
|
|
7
7
|
|
|
8
8
|

|
|
9
9
|

|
|
@@ -188,3 +188,6 @@ Apache-2.0 License — contributions welcome!
|
|
|
188
188
|
- **GitHub:** [vexify-org/JSQL-neo](https://github.com/vexify-org/JSQL-neo)
|
|
189
189
|
- **Issues:** [Open an issue](https://github.com/vexify-org/JSQL-neo/issues)
|
|
190
190
|
- **PRs:** Fork → branch → PR — thank you!
|
|
191
|
+
- **Contributing:** [CONTRIBUTING.md](CONTRIBUTING.md)
|
|
192
|
+
- **Code of Conduct:** [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md)
|
|
193
|
+
- **Security:** [SECURITY.md](SECURITY.md) — please report vulnerabilities privately
|
package/index.js
CHANGED
package/lib/btree.js
CHANGED
|
@@ -173,7 +173,7 @@ class BTree {
|
|
|
173
173
|
const s = k === undefined || k === null ? '' : String(k);
|
|
174
174
|
// 不能假设键按字典序排序(数字键按数值序),必须检查所有键
|
|
175
175
|
if (s.startsWith(p)) {
|
|
176
|
-
|
|
176
|
+
for (const __e of node.values[i]) result.push(__e);
|
|
177
177
|
}
|
|
178
178
|
}
|
|
179
179
|
node = node.next;
|
|
@@ -193,7 +193,7 @@ class BTree {
|
|
|
193
193
|
const k = node.keys[i];
|
|
194
194
|
if (k > max) return result;
|
|
195
195
|
if (k >= min) {
|
|
196
|
-
|
|
196
|
+
for (const __e of node.values[i]) result.push(__e);
|
|
197
197
|
}
|
|
198
198
|
}
|
|
199
199
|
node = node.next;
|
|
@@ -209,7 +209,7 @@ class BTree {
|
|
|
209
209
|
let node = this._findLeaf(min);
|
|
210
210
|
while (node) {
|
|
211
211
|
for (let i = 0; i < node.keys.length; i++) {
|
|
212
|
-
if (node.keys[i] > min)
|
|
212
|
+
if (node.keys[i] > min) for (const __e of node.values[i]) result.push(__e);
|
|
213
213
|
}
|
|
214
214
|
node = node.next;
|
|
215
215
|
}
|
|
@@ -221,7 +221,7 @@ class BTree {
|
|
|
221
221
|
let node = this._findLeaf(min);
|
|
222
222
|
while (node) {
|
|
223
223
|
for (let i = 0; i < node.keys.length; i++) {
|
|
224
|
-
if (node.keys[i] >= min)
|
|
224
|
+
if (node.keys[i] >= min) for (const __e of node.values[i]) result.push(__e);
|
|
225
225
|
}
|
|
226
226
|
node = node.next;
|
|
227
227
|
}
|
|
@@ -237,7 +237,7 @@ class BTree {
|
|
|
237
237
|
while (!node.leaf) node = node.children[0];
|
|
238
238
|
while (node) {
|
|
239
239
|
for (let i = 0; i < node.keys.length; i++) {
|
|
240
|
-
if (node.keys[i] < max)
|
|
240
|
+
if (node.keys[i] < max) for (const __e of node.values[i]) result.push(__e);
|
|
241
241
|
else return result;
|
|
242
242
|
}
|
|
243
243
|
node = node.next;
|
|
@@ -251,7 +251,7 @@ class BTree {
|
|
|
251
251
|
while (!node.leaf) node = node.children[0];
|
|
252
252
|
while (node) {
|
|
253
253
|
for (let i = 0; i < node.keys.length; i++) {
|
|
254
|
-
if (node.keys[i] <= max)
|
|
254
|
+
if (node.keys[i] <= max) for (const __e of node.values[i]) result.push(__e);
|
|
255
255
|
else return result;
|
|
256
256
|
}
|
|
257
257
|
node = node.next;
|
|
@@ -408,9 +408,9 @@ class BTree {
|
|
|
408
408
|
left.keys.push(midKey);
|
|
409
409
|
left.values.push(midVal);
|
|
410
410
|
}
|
|
411
|
-
left.keys.push(
|
|
412
|
-
left.values.push(
|
|
413
|
-
if (!left.leaf) left.children.push(
|
|
411
|
+
for (const __e of right.keys) left.keys.push(__e);
|
|
412
|
+
for (const __e of right.values) left.values.push(__e);
|
|
413
|
+
if (!left.leaf) for (const __e of right.children) left.children.push(__e);
|
|
414
414
|
if (left.leaf) left.next = right.next;
|
|
415
415
|
|
|
416
416
|
parent.keys.splice(index, 1);
|
package/lib/cache.js
CHANGED
|
@@ -152,7 +152,7 @@ class Cache {
|
|
|
152
152
|
throw new Error('WRONGTYPE Operation against a key holding the wrong kind of value');
|
|
153
153
|
}
|
|
154
154
|
if (!list) { list = []; this._getData().set(k, list); }
|
|
155
|
-
|
|
155
|
+
for (const __e of values.map(String)) list.push(__e);
|
|
156
156
|
this._dirty = true;
|
|
157
157
|
return list.length;
|
|
158
158
|
}
|
package/lib/database.js
CHANGED
|
@@ -566,7 +566,7 @@ class Database {
|
|
|
566
566
|
case 'insert': {
|
|
567
567
|
const t = op.table && this._tables[op.table];
|
|
568
568
|
if (!t || !Array.isArray(op.rows) || op.rows.length === 0) { failed++; break; }
|
|
569
|
-
t._rows.push(
|
|
569
|
+
for (const __e of op.rows) t._rows.push(__e);
|
|
570
570
|
touched.add(t);
|
|
571
571
|
replayed++;
|
|
572
572
|
break;
|
package/lib/jsql_format.js
CHANGED
package/lib/mongo_server.js
CHANGED
|
@@ -151,6 +151,7 @@ class MongoServer {
|
|
|
151
151
|
this.port = options.port ?? 27017;
|
|
152
152
|
this.host = options.host || '127.0.0.1';
|
|
153
153
|
this.dataDir = options.dataDir || null;
|
|
154
|
+
this.maxMessageSize = options.maxMessageSize || 48 * 1024 * 1024;
|
|
154
155
|
this._engine = null;
|
|
155
156
|
this._server = null;
|
|
156
157
|
this._sockets = new Set();
|
|
@@ -201,6 +202,10 @@ class MongoServer {
|
|
|
201
202
|
this._sockets.add(socket);
|
|
202
203
|
socket.on('close', () => this._sockets.delete(socket));
|
|
203
204
|
let buf = Buffer.isBuffer(existing) ? Buffer.from(existing) : Buffer.alloc(0);
|
|
205
|
+
if (buf.length > this.maxMessageSize) {
|
|
206
|
+
socket.destroy();
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
204
209
|
socket.on('error', () => {});
|
|
205
210
|
let processing = false;
|
|
206
211
|
let again = false;
|
|
@@ -211,7 +216,10 @@ class MongoServer {
|
|
|
211
216
|
for (;;) {
|
|
212
217
|
if (buf.length < 4) break;
|
|
213
218
|
const len = buf.readInt32LE(0);
|
|
214
|
-
if (len < 16 || len >
|
|
219
|
+
if (len < 16 || len > this.maxMessageSize) {
|
|
220
|
+
socket.destroy();
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
215
223
|
if (buf.length < len) break;
|
|
216
224
|
const msg = buf.slice(0, len);
|
|
217
225
|
buf = buf.slice(len);
|
|
@@ -227,6 +235,10 @@ class MongoServer {
|
|
|
227
235
|
}
|
|
228
236
|
};
|
|
229
237
|
socket.on('data', (chunk) => {
|
|
238
|
+
if (buf.length + chunk.length > this.maxMessageSize * 2) {
|
|
239
|
+
socket.destroy();
|
|
240
|
+
return;
|
|
241
|
+
}
|
|
230
242
|
buf = Buffer.concat([buf, chunk]);
|
|
231
243
|
processLoop();
|
|
232
244
|
});
|
|
@@ -635,10 +647,14 @@ class MongoServer {
|
|
|
635
647
|
doc[k] = vals.reduce((a, b) => a + b, 0) / vals.length;
|
|
636
648
|
} else if (v.$min !== undefined) {
|
|
637
649
|
const vals = grow.map(r => r[field]).filter(v => v != null);
|
|
638
|
-
|
|
650
|
+
let best = null;
|
|
651
|
+
for (const x of vals) if (best === null || x < best) best = x;
|
|
652
|
+
doc[k] = best;
|
|
639
653
|
} else if (v.$max !== undefined) {
|
|
640
654
|
const vals = grow.map(r => r[field]).filter(v => v != null);
|
|
641
|
-
|
|
655
|
+
let best = null;
|
|
656
|
+
for (const x of vals) if (best === null || x > best) best = x;
|
|
657
|
+
doc[k] = best;
|
|
642
658
|
} else if (v.$first !== undefined) {
|
|
643
659
|
doc[k] = grow[0] ? grow[0][field] : null;
|
|
644
660
|
} else if (v.$last !== undefined) {
|
package/lib/mysql_server.js
CHANGED
|
@@ -1297,11 +1297,14 @@ class MysqlServer {
|
|
|
1297
1297
|
);
|
|
1298
1298
|
friendly.code = 'EADDRINUSE';
|
|
1299
1299
|
friendly.cause = err;
|
|
1300
|
-
if (
|
|
1301
|
-
else
|
|
1302
|
-
|
|
1300
|
+
if (typeof this.options.onError === 'function') this.options.onError(friendly);
|
|
1301
|
+
else if (cb) cb(friendly);
|
|
1302
|
+
else console.error('[jsql-neo] mysql server error:', friendly.message);
|
|
1303
|
+
} else if (typeof this.options.onError === 'function') this.options.onError(err);
|
|
1304
|
+
else if (cb) cb(err);
|
|
1305
|
+
else console.error('[jsql-neo] mysql server error:', err.message);
|
|
1303
1306
|
});
|
|
1304
|
-
this._server.listen(this.port, this.host, cb
|
|
1307
|
+
this._server.listen(this.port, this.host, cb ? () => cb() : undefined);
|
|
1305
1308
|
}).catch(err => {
|
|
1306
1309
|
if (cb) cb(err);
|
|
1307
1310
|
else throw err;
|
package/lib/native_client.js
CHANGED
|
@@ -851,7 +851,7 @@ class JSQL {
|
|
|
851
851
|
}
|
|
852
852
|
if (!(await this._runHooks('beforeUpdate', [table, pairs]))) return;
|
|
853
853
|
if (!this._opBuffer.update[table]) this._opBuffer.update[table] = [];
|
|
854
|
-
this._opBuffer.update[table].push(
|
|
854
|
+
for (const __e of pairs) this._opBuffer.update[table].push(__e);
|
|
855
855
|
this._scheduleOpFlush();
|
|
856
856
|
}
|
|
857
857
|
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const fs = require('fs');
|
|
4
|
+
const { execFileSync } = require('child_process');
|
|
5
|
+
|
|
6
|
+
const MIN_NAPI_VERSION = 6;
|
|
7
|
+
|
|
8
|
+
function detectLibc(platform = process.platform) {
|
|
9
|
+
if (platform !== 'linux') return null;
|
|
10
|
+
try {
|
|
11
|
+
const report = process.report && typeof process.report.getReport === 'function'
|
|
12
|
+
? process.report.getReport()
|
|
13
|
+
: null;
|
|
14
|
+
if (report && report.header && report.header.glibcVersionRuntime) return 'gnu';
|
|
15
|
+
} catch (_) { /* ignore */ }
|
|
16
|
+
try {
|
|
17
|
+
if (fs.existsSync('/etc/alpine-release')) return 'musl';
|
|
18
|
+
} catch (_) { /* ignore */ }
|
|
19
|
+
try {
|
|
20
|
+
const out = execFileSync('ldd', ['--version'], {
|
|
21
|
+
encoding: 'utf8',
|
|
22
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
23
|
+
});
|
|
24
|
+
if (/musl/i.test(out)) return 'musl';
|
|
25
|
+
if (/glibc|GNU libc/i.test(out)) return 'gnu';
|
|
26
|
+
} catch (_) { /* ignore */ }
|
|
27
|
+
return 'gnu';
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function nativeTargetSuffix(platform = process.platform, arch = process.arch, libc = detectLibc(platform)) {
|
|
31
|
+
const p = platform === 'win32' ? 'win32' : platform === 'darwin' ? 'darwin' : 'linux';
|
|
32
|
+
const a = arch === 'x64' ? 'x64' : arch === 'arm64' ? 'arm64' : arch;
|
|
33
|
+
if (p === 'linux') return `${p}-${a}-${libc === 'musl' ? 'musl' : 'gnu'}`;
|
|
34
|
+
if (p === 'darwin') return `${p}-${a}`;
|
|
35
|
+
return `${p}-${a}-msvc`;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function nativeNapiVersion() {
|
|
39
|
+
const v = Number(process.versions && process.versions.napi);
|
|
40
|
+
return Number.isFinite(v) ? v : 0;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function supportsNativeNapi() {
|
|
44
|
+
return nativeNapiVersion() >= MIN_NAPI_VERSION;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
module.exports = {
|
|
48
|
+
MIN_NAPI_VERSION,
|
|
49
|
+
detectLibc,
|
|
50
|
+
nativeTargetSuffix,
|
|
51
|
+
nativeNapiVersion,
|
|
52
|
+
supportsNativeNapi,
|
|
53
|
+
};
|
package/lib/nedb_compat.js
CHANGED
|
@@ -170,7 +170,7 @@ function applyModifier(doc, update) {
|
|
|
170
170
|
for (const [k, v] of Object.entries(payload)) {
|
|
171
171
|
const cur = getPath(doc, k);
|
|
172
172
|
const arr = Array.isArray(cur) ? cur : [];
|
|
173
|
-
if (v && typeof v === 'object' && v.$each)
|
|
173
|
+
if (v && typeof v === 'object' && v.$each) for (const __e of v.$each) arr.push(__e);
|
|
174
174
|
else arr.push(v);
|
|
175
175
|
setPath(doc, k, arr);
|
|
176
176
|
}
|
package/lib/pg_server.js
CHANGED
|
@@ -845,11 +845,12 @@ class PgServer {
|
|
|
845
845
|
this._sockets.add(socket);
|
|
846
846
|
new PgConnection(socket, this);
|
|
847
847
|
});
|
|
848
|
-
this._server.listen(this.port, this.host, cb || (() => {}));
|
|
849
848
|
this._server.on('error', (err) => {
|
|
850
849
|
if (this.options.onError) this.options.onError(err);
|
|
851
|
-
else
|
|
850
|
+
else if (cb) cb(err);
|
|
851
|
+
else console.error('[jsql-neo] pg server error:', err.message);
|
|
852
852
|
});
|
|
853
|
+
this._server.listen(this.port, this.host, cb ? () => cb() : undefined);
|
|
853
854
|
return this;
|
|
854
855
|
}
|
|
855
856
|
|
package/lib/query.js
CHANGED
package/lib/redis_server.js
CHANGED
|
@@ -335,7 +335,7 @@ class RedisServer {
|
|
|
335
335
|
if (cmd === 'LPUSH') {
|
|
336
336
|
for (const val of args.slice(1)) list.unshift(val);
|
|
337
337
|
} else {
|
|
338
|
-
|
|
338
|
+
for (const __e of args.slice(1)) list.push(__e);
|
|
339
339
|
}
|
|
340
340
|
this.db.set(args[0], { type: 'list', val: list, ttl: v ? v.ttl : null });
|
|
341
341
|
this._scheduleSnapshot();
|
package/lib/sql.js
CHANGED
|
@@ -4114,13 +4114,25 @@ function applyScalarFunction(fnNode, row, ctx) {
|
|
|
4114
4114
|
}
|
|
4115
4115
|
function depth(obj) {
|
|
4116
4116
|
if (typeof obj !== 'object' || obj === null) return 0;
|
|
4117
|
-
|
|
4118
|
-
|
|
4119
|
-
|
|
4117
|
+
let max = 0;
|
|
4118
|
+
const stack = [{ o: obj, d: 1 }];
|
|
4119
|
+
while (stack.length) {
|
|
4120
|
+
const { o, d } = stack.pop();
|
|
4121
|
+
if (typeof o !== 'object' || o === null) continue;
|
|
4122
|
+
if (d > max) max = d;
|
|
4123
|
+
if (Array.isArray(o)) {
|
|
4124
|
+
for (const x of o) {
|
|
4125
|
+
if (x && typeof x === 'object') stack.push({ o: x, d: d + 1 });
|
|
4126
|
+
}
|
|
4127
|
+
} else {
|
|
4128
|
+
const ks = Object.keys(o);
|
|
4129
|
+
for (const k of ks) {
|
|
4130
|
+
const x = o[k];
|
|
4131
|
+
if (x && typeof x === 'object') stack.push({ o: x, d: d + 1 });
|
|
4132
|
+
}
|
|
4133
|
+
}
|
|
4120
4134
|
}
|
|
4121
|
-
|
|
4122
|
-
if (keys.length === 0) return 1;
|
|
4123
|
-
return 1 + Math.max(...keys.map(k => depth(obj[k])));
|
|
4135
|
+
return max;
|
|
4124
4136
|
}
|
|
4125
4137
|
return depth(data);
|
|
4126
4138
|
}
|
|
@@ -5915,7 +5927,7 @@ class SQLExecutor {
|
|
|
5915
5927
|
_rollupRow(groupReps) {
|
|
5916
5928
|
const all = [];
|
|
5917
5929
|
for (const rep of groupReps) {
|
|
5918
|
-
if (rep._group)
|
|
5930
|
+
if (rep._group) for (const __e of rep._group) all.push(__e);
|
|
5919
5931
|
else all.push(rep);
|
|
5920
5932
|
}
|
|
5921
5933
|
const out = {};
|
|
@@ -5979,8 +5991,12 @@ class SQLExecutor {
|
|
|
5979
5991
|
const numeric = (v) => typeof v === 'number' ||
|
|
5980
5992
|
(typeof v === 'string' && String(v).trim() !== '' && Number.isFinite(Number(v)));
|
|
5981
5993
|
if (vs.every(numeric)) {
|
|
5982
|
-
|
|
5983
|
-
|
|
5994
|
+
let best = Number(vs[0]);
|
|
5995
|
+
for (let i = 1; i < vs.length; i++) {
|
|
5996
|
+
const n = Number(vs[i]);
|
|
5997
|
+
if (fn === 'MIN' ? n < best : n > best) best = n;
|
|
5998
|
+
}
|
|
5999
|
+
return best;
|
|
5984
6000
|
}
|
|
5985
6001
|
let best = vs[0];
|
|
5986
6002
|
for (const v of vs.slice(1)) {
|
package/lib/tui.js
CHANGED
|
@@ -72,7 +72,9 @@ function renderTable(headers, rows, maxWidth) {
|
|
|
72
72
|
for (const w of widths) total += w + 3;
|
|
73
73
|
if (total > maxCol && widths.length > 1) {
|
|
74
74
|
let overshoot = total - maxCol;
|
|
75
|
-
let
|
|
75
|
+
let maxW = widths[0];
|
|
76
|
+
for (const w of widths) if (w > maxW) maxW = w;
|
|
77
|
+
let i = widths.indexOf(maxW);
|
|
76
78
|
while (overshoot > 0) {
|
|
77
79
|
if (i === -1 || widths[i] <= 3) break;
|
|
78
80
|
const cut = Math.min(widths[i] - 3, overshoot);
|
package/package.json
CHANGED
package/postinstall.js
CHANGED
|
@@ -4,6 +4,7 @@ const fs = require('fs');
|
|
|
4
4
|
const path = require('path');
|
|
5
5
|
const http = require('http');
|
|
6
6
|
const https = require('https');
|
|
7
|
+
const { detectLibc, nativeTargetSuffix, nativeNapiVersion, supportsNativeNapi, MIN_NAPI_VERSION } = require('./lib/native_target');
|
|
7
8
|
|
|
8
9
|
const ROOT = __dirname;
|
|
9
10
|
const pkg = JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8'));
|
|
@@ -69,13 +70,12 @@ const REPO = (pkg.repository && pkg.repository.url)
|
|
|
69
70
|
? pkg.repository.url.replace(/\.git$/, '').replace(/^.*github\.com\//i, '')
|
|
70
71
|
: 'vexify-org/JSQL-neo';
|
|
71
72
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return `${p}-${a}-msvc`;
|
|
73
|
+
function sameOrigin(a, b) {
|
|
74
|
+
try { return new URL(a).origin === new URL(b).origin; } catch (_) { return false; }
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function safeRedirect(next) {
|
|
78
|
+
return /^https?:/i.test(String(next || ''));
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
function download(url, dest, headers, redirects = 0) {
|
|
@@ -89,7 +89,11 @@ function download(url, dest, headers, redirects = 0) {
|
|
|
89
89
|
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
90
90
|
res.resume();
|
|
91
91
|
const next = new URL(res.headers.location, url).toString();
|
|
92
|
-
|
|
92
|
+
if (!safeRedirect(next)) {
|
|
93
|
+
reject(new Error(`invalid redirect target for ${url}`));
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
download(next, dest, sameOrigin(next, url) ? headers : undefined, redirects + 1).then(resolve, reject);
|
|
93
97
|
return;
|
|
94
98
|
}
|
|
95
99
|
if (res.statusCode !== 200) {
|
|
@@ -145,7 +149,11 @@ function fetchText(url, headers, redirects = 0) {
|
|
|
145
149
|
if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
|
|
146
150
|
res.resume();
|
|
147
151
|
const next = new URL(res.headers.location, url).toString();
|
|
148
|
-
|
|
152
|
+
if (!safeRedirect(next)) {
|
|
153
|
+
reject(new Error(`invalid redirect target for ${url}`));
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
fetchText(next, sameOrigin(next, url) ? headers : undefined, redirects + 1).then(resolve, reject);
|
|
149
157
|
return;
|
|
150
158
|
}
|
|
151
159
|
if (res.statusCode !== 200) {
|
|
@@ -262,7 +270,15 @@ function tryLoadNative() {
|
|
|
262
270
|
}
|
|
263
271
|
|
|
264
272
|
async function downloadAndVerify() {
|
|
265
|
-
|
|
273
|
+
if (!supportsNativeNapi()) {
|
|
274
|
+
console.warn(
|
|
275
|
+
`[jsql-neo] Node ${process.versions.node} provides N-API ${nativeNapiVersion() || 'unknown'}, ` +
|
|
276
|
+
`but the native module requires N-API >= ${MIN_NAPI_VERSION}; skipping native download.`
|
|
277
|
+
);
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
const libc = detectLibc();
|
|
281
|
+
const asset = process.env.JSQL_NATIVE_ASSET || `jsql-neo-native.${nativeTargetSuffix(process.platform, process.arch, libc)}.node`;
|
|
266
282
|
const raw = `https://github.com/${REPO}/releases/download/${TAG}/${asset}`;
|
|
267
283
|
|
|
268
284
|
let expected = null;
|
|
@@ -274,11 +290,18 @@ async function downloadAndVerify() {
|
|
|
274
290
|
|
|
275
291
|
const allowUnverified = process.env.JSQL_ALLOW_UNVERIFIED_NATIVE === '1';
|
|
276
292
|
if (!expected && !allowUnverified) {
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
293
|
+
if (libc === 'musl') {
|
|
294
|
+
console.warn(
|
|
295
|
+
`[jsql-neo] musl libc detected but this release has no native asset for ${asset}; ` +
|
|
296
|
+
'falling back to the WASM/JS engine. Set JSQL_NATIVE_ASSET to a compatible musl build if available.'
|
|
297
|
+
);
|
|
298
|
+
} else {
|
|
299
|
+
// fail closed:拿不到 SHA256SUMS 就不下载,绝不 require 未经校验的二进制
|
|
300
|
+
console.warn(
|
|
301
|
+
'[jsql-neo] no SHA256SUMS available for this release; refusing to download an unverified native module.\n' +
|
|
302
|
+
'[jsql-neo] set JSQL_NATIVE_SHA256=<64-hex> to pin a checksum, or JSQL_ALLOW_UNVERIFIED_NATIVE=1 to override (unsafe).'
|
|
303
|
+
);
|
|
304
|
+
}
|
|
282
305
|
return false;
|
|
283
306
|
}
|
|
284
307
|
if (!expected) {
|
|
@@ -323,6 +346,13 @@ async function ensureNativeNode() {
|
|
|
323
346
|
console.log('[jsql-neo] native module ready: native/jsql-neo-native.node');
|
|
324
347
|
return;
|
|
325
348
|
}
|
|
349
|
+
if (!supportsNativeNapi()) {
|
|
350
|
+
console.warn(
|
|
351
|
+
`[jsql-neo] Node ${process.versions.node} provides N-API ${nativeNapiVersion() || 'unknown'}, ` +
|
|
352
|
+
`but the native module requires N-API >= ${MIN_NAPI_VERSION}; using the WASM/JS engine.`
|
|
353
|
+
);
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
326
356
|
if (await downloadAndVerify()) return;
|
|
327
357
|
buildNativeFromSource();
|
|
328
358
|
}
|