@dangao/bun-server 3.0.0 → 3.0.2

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.
@@ -10932,8 +10932,14 @@ class ConnectionPool {
10932
10932
  const { Database } = await import("bun:sqlite");
10933
10933
  return new Database(config.path);
10934
10934
  }
10935
- const BetterSqlite3 = __require("better-sqlite3");
10936
- return BetterSqlite3(config.path);
10935
+ let sqlite3;
10936
+ try {
10937
+ sqlite3 = __require("@vscode/sqlite3");
10938
+ } catch {
10939
+ throw new Error(`[bun-server] SQLite on Node.js requires @vscode/sqlite3.
10940
+ Install it with: bun add @vscode/sqlite3@5.1.12-vscode`);
10941
+ }
10942
+ return new sqlite3.Database(config.path);
10937
10943
  }
10938
10944
  async createPostgresConnection(config) {
10939
10945
  const url = `postgres://${config.user}:${config.password}@${config.host}:${config.port}/${config.database}`;
@@ -11099,11 +11105,25 @@ class DatabaseConnectionManager {
11099
11105
  }
11100
11106
  async healthCheckSqlite(connection) {
11101
11107
  try {
11102
- if (connection && typeof connection === "object" && "query" in connection && typeof connection.query === "function") {
11108
+ if (!connection || typeof connection !== "object") {
11109
+ return false;
11110
+ }
11111
+ if ("query" in connection && typeof connection.query === "function" && !(("all" in connection) && ("run" in connection))) {
11103
11112
  const db = connection;
11104
11113
  db.query("SELECT 1").all();
11105
11114
  return true;
11106
11115
  }
11116
+ if ("all" in connection && typeof connection.all === "function") {
11117
+ await new Promise((resolve2, reject) => {
11118
+ connection.all("SELECT 1", [], (err) => {
11119
+ if (err)
11120
+ reject(err);
11121
+ else
11122
+ resolve2();
11123
+ });
11124
+ });
11125
+ return true;
11126
+ }
11107
11127
  return false;
11108
11128
  } catch (_error) {
11109
11129
  return false;
@@ -11213,12 +11233,22 @@ class DatabaseService2 {
11213
11233
  throw new Error(`Query not supported for database type: ${dbType}`);
11214
11234
  }
11215
11235
  querySqlite(connection, sql, params) {
11216
- if (connection && typeof connection === "object" && "query" in connection && typeof connection.query === "function") {
11236
+ if (connection && typeof connection === "object" && "query" in connection && typeof connection.query === "function" && !(("all" in connection) && ("run" in connection))) {
11217
11237
  const db = connection;
11218
11238
  const statement = db.query(sql);
11219
11239
  const result = params && params.length > 0 ? statement.all(...params) : statement.all();
11220
11240
  return result;
11221
11241
  }
11242
+ if (connection && typeof connection === "object" && "all" in connection && typeof connection.all === "function") {
11243
+ return new Promise((resolve2, reject) => {
11244
+ connection.all(sql, params ?? [], (err, rows) => {
11245
+ if (err)
11246
+ reject(err);
11247
+ else
11248
+ resolve2(rows ?? []);
11249
+ });
11250
+ });
11251
+ }
11222
11252
  throw new Error("Invalid SQLite connection");
11223
11253
  }
11224
11254
  async queryBunSQL(connection, sql, params) {
@@ -11389,24 +11419,35 @@ class SqliteAdapter {
11389
11419
  }
11390
11420
  this.db = db;
11391
11421
  } else {
11392
- const BetterSqlite3 = __require("better-sqlite3");
11393
- const db = BetterSqlite3(config.database);
11422
+ let sqlite3;
11423
+ try {
11424
+ sqlite3 = __require("@vscode/sqlite3");
11425
+ } catch {
11426
+ throw new Error(`[bun-server] SQLite on Node.js requires @vscode/sqlite3.
11427
+ ` + "Install it with: bun add @vscode/sqlite3@5.1.12-vscode");
11428
+ }
11429
+ const db = new sqlite3.Database(config.database);
11394
11430
  if (config.wal !== false) {
11395
- db.exec("PRAGMA journal_mode = WAL;");
11431
+ db.run("PRAGMA journal_mode = WAL;");
11396
11432
  }
11397
11433
  this.db = db;
11398
11434
  }
11399
11435
  this.semaphore = new Semaphore(config.maxWriteConcurrency ?? 1);
11400
11436
  }
11401
- query(sql, params = []) {
11437
+ async query(sql, params = []) {
11402
11438
  if (this.isBun) {
11403
- const db2 = this.db;
11404
- const stmt2 = db2.query(sql);
11405
- return stmt2.all(...params);
11439
+ const db = this.db;
11440
+ const stmt = db.query(sql);
11441
+ return stmt.all(...params);
11406
11442
  }
11407
- const db = this.db;
11408
- const stmt = db.prepare(sql);
11409
- return stmt.all(...params);
11443
+ return new Promise((resolve2, reject) => {
11444
+ this.db.all(sql, params, (err, rows) => {
11445
+ if (err)
11446
+ reject(err);
11447
+ else
11448
+ resolve2(rows ?? []);
11449
+ });
11450
+ });
11410
11451
  }
11411
11452
  async execute(sql, params = []) {
11412
11453
  if (this.isBun) {
@@ -11414,9 +11455,14 @@ class SqliteAdapter {
11414
11455
  const stmt = db.query(sql);
11415
11456
  stmt.run(...params);
11416
11457
  } else {
11417
- const db = this.db;
11418
- const stmt = db.prepare(sql);
11419
- stmt.run(...params);
11458
+ return new Promise((resolve2, reject) => {
11459
+ this.db.run(sql, params, (err) => {
11460
+ if (err)
11461
+ reject(err);
11462
+ else
11463
+ resolve2();
11464
+ });
11465
+ });
11420
11466
  }
11421
11467
  }
11422
11468
  close() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dangao/bun-server",
3
- "version": "3.0.0",
3
+ "version": "3.0.2",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -50,7 +50,7 @@
50
50
  "test:platform": "bun run test:bun && bun run test:node",
51
51
  "type-check": "tsc --noEmit",
52
52
  "clean": "rm -rf dist",
53
- "bundle": "bun build src/index.ts --target=bun --format=esm --outfile=dist/index.js --external reflect-metadata --external @dangao/logsmith --external @dangao/nacos-client",
53
+ "bundle": "bun build src/index.ts --target=bun --format=esm --outfile=dist/index.js --external reflect-metadata --external @dangao/logsmith --external @dangao/nacos-client --external @vscode/sqlite3",
54
54
  "bundle:node": "bun build src/index.ts --target=node --packages=external --outfile=dist/index.node.mjs",
55
55
  "dts": "tsc -p tsconfig.build.json",
56
56
  "build": "bun run clean && bun run bundle && bun run bundle:node && bun run dts",
@@ -59,17 +59,23 @@
59
59
  "publish:package:github": "cp -r ../../README.md ../../LICENSE ../../docs . && bun pm pack --access public && npm publish *.tgz --provenance --access public && rm -rf ./README.md ./LICENSE ./docs"
60
60
  },
61
61
  "devDependencies": {
62
- "@types/better-sqlite3": "^7.6.13",
63
62
  "@types/bun": "^1.3.10",
64
63
  "@types/mime-types": "^3.0.1",
65
64
  "@types/ws": "^8.18.1",
66
65
  "typescript": "^5.9.3",
67
66
  "vitest": "^4.1.4"
68
67
  },
68
+ "peerDependencies": {
69
+ "@vscode/sqlite3": "5.1.12-vscode"
70
+ },
71
+ "peerDependenciesMeta": {
72
+ "@vscode/sqlite3": {
73
+ "optional": true
74
+ }
75
+ },
69
76
  "dependencies": {
70
77
  "@dangao/logsmith": "0.2.0",
71
78
  "@dangao/nacos-client": "0.1.1",
72
- "better-sqlite3": "^12.8.0",
73
79
  "json5": "^2.2.3",
74
80
  "jsonc-parser": "^3.3.1",
75
81
  "marked": "^18.0.0",
@@ -160,21 +160,28 @@ export class DatabaseConnectionManager {
160
160
  */
161
161
  private async healthCheckSqlite(connection: unknown): Promise<boolean> {
162
162
  try {
163
- if (
164
- connection &&
165
- typeof connection === 'object' &&
166
- 'query' in connection &&
167
- typeof connection.query === 'function'
168
- ) {
169
- // 执行简单的查询来检查连接
170
- const db = connection as {
171
- query: (sql: string) => {
172
- all: () => unknown[];
173
- };
174
- };
163
+ if (!connection || typeof connection !== 'object') {
164
+ return false;
165
+ }
166
+
167
+ // bun:sqlite Database(有 .query() 但没有 callback-based .all())
168
+ if ('query' in connection && typeof (connection as any).query === 'function' && !('all' in connection && 'run' in connection)) {
169
+ const db = connection as { query: (sql: string) => { all: () => unknown[] } };
175
170
  db.query('SELECT 1').all();
176
171
  return true;
177
172
  }
173
+
174
+ // @vscode/sqlite3 Database(callback-based .all())
175
+ if ('all' in connection && typeof (connection as any).all === 'function') {
176
+ await new Promise<void>((resolve, reject) => {
177
+ (connection as any).all('SELECT 1', [], (err: Error | null) => {
178
+ if (err) reject(err);
179
+ else resolve();
180
+ });
181
+ });
182
+ return true;
183
+ }
184
+
178
185
  return false;
179
186
  } catch (_error) {
180
187
  return false;
@@ -185,9 +185,18 @@ export class ConnectionPool {
185
185
  const { Database } = await import('bun:sqlite');
186
186
  return new Database(config.path);
187
187
  }
188
- // Node.js:使用 better-sqlite3
189
- const BetterSqlite3 = require('better-sqlite3') as typeof import('better-sqlite3');
190
- return BetterSqlite3(config.path);
188
+ // Node.js:使用 @vscode/sqlite3(可选对等依赖,需用户自行安装)
189
+ let sqlite3: any;
190
+ try {
191
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
192
+ sqlite3 = require('@vscode/sqlite3');
193
+ } catch {
194
+ throw new Error(
195
+ '[bun-server] SQLite on Node.js requires @vscode/sqlite3.\n' +
196
+ 'Install it with: bun add @vscode/sqlite3@5.1.12-vscode',
197
+ );
198
+ }
199
+ return new sqlite3.Database(config.path);
191
200
  }
192
201
 
193
202
  /**
@@ -113,7 +113,7 @@ export class DatabaseService {
113
113
 
114
114
  /**
115
115
  * 执行 SQL 查询
116
- * SQLite 返回同步结果,PostgreSQL/MySQL 返回异步结果
116
+ * SQLite (bun:sqlite) 返回同步结果;@vscode/sqlite3 / PostgreSQL / MySQL 返回异步结果
117
117
  */
118
118
  public query<T = unknown>(sql: string, params?: unknown[]): T[] | Promise<T[]> {
119
119
  const session = getCurrentSession();
@@ -139,18 +139,20 @@ export class DatabaseService {
139
139
 
140
140
  /**
141
141
  * SQLite 查询实现
142
+ * bun:sqlite 使用同步 .query().all();@vscode/sqlite3 使用异步 callback .all()
142
143
  */
143
144
  private querySqlite<T = unknown>(
144
145
  connection: unknown,
145
146
  sql: string,
146
147
  params?: unknown[],
147
- ): T[] {
148
- // Bun SQLite Database 对象
148
+ ): T[] | Promise<T[]> {
149
+ // bun:sqlite Database 对象(有 .query() 方法)
149
150
  if (
150
151
  connection &&
151
152
  typeof connection === 'object' &&
152
153
  'query' in connection &&
153
- typeof connection.query === 'function'
154
+ typeof (connection as any).query === 'function' &&
155
+ !('all' in connection && 'run' in connection)
154
156
  ) {
155
157
  const db = connection as {
156
158
  query: (sql: string) => {
@@ -160,12 +162,26 @@ export class DatabaseService {
160
162
  };
161
163
 
162
164
  const statement = db.query(sql);
163
- // Bun SQLite 的 all() 方法接受参数
164
165
  const result =
165
166
  params && params.length > 0 ? statement.all(...params) : statement.all();
166
167
  return result;
167
168
  }
168
169
 
170
+ // @vscode/sqlite3 Database 对象(有 .all() callback 方法)
171
+ if (
172
+ connection &&
173
+ typeof connection === 'object' &&
174
+ 'all' in connection &&
175
+ typeof (connection as any).all === 'function'
176
+ ) {
177
+ return new Promise<T[]>((resolve, reject) => {
178
+ (connection as any).all(sql, params ?? [], (err: Error | null, rows: T[]) => {
179
+ if (err) reject(err);
180
+ else resolve(rows ?? []);
181
+ });
182
+ });
183
+ }
184
+
169
185
  throw new Error('Invalid SQLite connection');
170
186
  }
171
187
 
@@ -40,7 +40,7 @@ export class Semaphore {
40
40
 
41
41
  /**
42
42
  * SQLite 适配器(自动感知运行时)
43
- * Bun 平台下使用 bun:sqlite,Node.js 平台下使用 better-sqlite3
43
+ * Bun 平台下使用 bun:sqlite,Node.js 平台下使用 @vscode/sqlite3
44
44
  */
45
45
  export class SqliteAdapter {
46
46
  private readonly db: unknown;
@@ -58,10 +58,20 @@ export class SqliteAdapter {
58
58
  }
59
59
  this.db = db;
60
60
  } else {
61
- const BetterSqlite3 = require('better-sqlite3') as typeof import('better-sqlite3');
62
- const db = BetterSqlite3(config.database);
61
+ let sqlite3: any;
62
+ try {
63
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
64
+ sqlite3 = require('@vscode/sqlite3');
65
+ } catch {
66
+ throw new Error(
67
+ '[bun-server] SQLite on Node.js requires @vscode/sqlite3.\n' +
68
+ 'Install it with: bun add @vscode/sqlite3@5.1.12-vscode',
69
+ );
70
+ }
71
+ const db: any = new sqlite3.Database(config.database);
63
72
  if (config.wal !== false) {
64
- db.exec('PRAGMA journal_mode = WAL;');
73
+ // Operations are serialized internally; WAL is queued before any query runs
74
+ db.run('PRAGMA journal_mode = WAL;');
65
75
  }
66
76
  this.db = db;
67
77
  }
@@ -69,15 +79,18 @@ export class SqliteAdapter {
69
79
  this.semaphore = new Semaphore(config.maxWriteConcurrency ?? 1);
70
80
  }
71
81
 
72
- public query<T = unknown>(sql: string, params: unknown[] = []): T[] {
82
+ public async query<T = unknown>(sql: string, params: unknown[] = []): Promise<T[]> {
73
83
  if (this.isBun) {
74
84
  const db = this.db as import('bun:sqlite').Database;
75
85
  const stmt = db.query(sql);
76
86
  return stmt.all(...params as Parameters<typeof stmt.all>) as T[];
77
87
  }
78
- const db = this.db as import('better-sqlite3').Database;
79
- const stmt = db.prepare(sql);
80
- return stmt.all(...params) as T[];
88
+ return new Promise<T[]>((resolve, reject) => {
89
+ (this.db as any).all(sql, params, (err: Error | null, rows: T[]) => {
90
+ if (err) reject(err);
91
+ else resolve(rows ?? []);
92
+ });
93
+ });
81
94
  }
82
95
 
83
96
  public async execute(sql: string, params: unknown[] = []): Promise<void> {
@@ -86,9 +99,12 @@ export class SqliteAdapter {
86
99
  const stmt = db.query(sql);
87
100
  stmt.run(...params as Parameters<typeof stmt.run>);
88
101
  } else {
89
- const db = this.db as import('better-sqlite3').Database;
90
- const stmt = db.prepare(sql);
91
- stmt.run(...params);
102
+ return new Promise<void>((resolve, reject) => {
103
+ (this.db as any).run(sql, params, (err: Error | null) => {
104
+ if (err) reject(err);
105
+ else resolve();
106
+ });
107
+ });
92
108
  }
93
109
  }
94
110
 
@@ -7,22 +7,22 @@ import { SqliteManager } from '../../../src/database/sqlite-adapter';
7
7
  export function runDatabaseCases(suite: TestSuite, engine: PlatformEngine): void {
8
8
  const { test, expect } = suite;
9
9
 
10
- // better-sqlite3 is not supported when running Node-platform tests under Bun runtime
11
- const skipBetterSqlite = engine === 'node' && typeof (globalThis as any).Bun !== 'undefined';
10
+ // @vscode/sqlite3 is a native Node.js addon; skip when Node-platform tests run under Bun runtime
11
+ const skipNodeSqlite = engine === 'node' && typeof (globalThis as any).Bun !== 'undefined';
12
12
 
13
- test('SqliteAdapter: create table, insert and query', () => {
14
- if (skipBetterSqlite) {
15
- // better-sqlite3 is not supported in Bun — this test must run under Node.js
16
- console.log('[skip] better-sqlite3 not available in Bun runtime; run with vitest for Node platform');
13
+ test('SqliteAdapter: create table, insert and query', async () => {
14
+ if (skipNodeSqlite) {
15
+ // @vscode/sqlite3 is not available in Bun — this test must run under Node.js
16
+ console.log('[skip] @vscode/sqlite3 not available in Bun runtime; run with vitest for Node platform');
17
17
  return;
18
18
  }
19
19
  const dbPath = join(tmpdir(), `platform-db-test-${engine}-${Date.now()}.db`);
20
20
  const manager = new SqliteManager();
21
21
  const adapter = manager.getOrCreate('test', { database: dbPath, wal: false });
22
22
 
23
- adapter.query('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)');
24
- adapter.query("INSERT INTO users (name) VALUES ('Alice')");
25
- const rows = adapter.query<{ id: number; name: string }>('SELECT * FROM users');
23
+ await adapter.query('CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT)');
24
+ await adapter.query("INSERT INTO users (name) VALUES ('Alice')");
25
+ const rows = await adapter.query<{ id: number; name: string }>('SELECT * FROM users');
26
26
 
27
27
  expect(rows.length).toBeGreaterThanOrEqual(1);
28
28
  expect(rows[0]!.name).toBe('Alice');