From 140f114674e4eae2b13b36c3b503f5c5c2bdaa05 Mon Sep 17 00:00:00 2001 From: Prabhu Subramanian Date: Sat, 29 Aug 2026 18:15:18 +0100 Subject: [PATCH 1/3] Bump typescript from ~5.9.3 to 7.0.2 Pinned exactly (like biome and electron): a ~7.0.2 range could resolve to a newer 7.0.x still inside pnpm-workspace.yaml's minimumReleaseAge window and get refused. The lockfile gains the 20 platform-specific @typescript/typescript-- optionalDependencies; they ship no install scripts, so onlyBuiltDependencies and strictDepBuilds needed no change. --- package.json | 2 +- pnpm-lock.yaml | 213 +++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 208 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index eab24db..37a4038 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,7 @@ "electron": "43.4.1", "prebuildify": "^6.0.1", "semver": "^7.8.5", - "typescript": "~5.9.3" + "typescript": "7.0.2" }, "peerDependencies": { "node-gyp": "13.x" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5f134af..7f200a3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -34,8 +34,8 @@ importers: specifier: ^7.8.5 version: 7.8.5 typescript: - specifier: ~5.9.3 - version: 5.9.3 + specifier: 7.0.2 + version: 7.0.2 optionalDependencies: node-gyp: specifier: 13.x @@ -147,6 +147,126 @@ packages: '@types/node@24.13.3': resolution: {integrity: sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q==, tarball: https://registry.npmjs.org/@types/node/-/node-24.13.3.tgz} + '@typescript/typescript-aix-ppc64@7.0.2': + resolution: {integrity: sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==, tarball: https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [aix] + + '@typescript/typescript-darwin-arm64@7.0.2': + resolution: {integrity: sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==, tarball: https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [darwin] + + '@typescript/typescript-darwin-x64@7.0.2': + resolution: {integrity: sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==, tarball: https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [darwin] + + '@typescript/typescript-freebsd-arm64@7.0.2': + resolution: {integrity: sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==, tarball: https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [freebsd] + + '@typescript/typescript-freebsd-x64@7.0.2': + resolution: {integrity: sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==, tarball: https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [freebsd] + + '@typescript/typescript-linux-arm64@7.0.2': + resolution: {integrity: sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==, tarball: https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [linux] + + '@typescript/typescript-linux-arm@7.0.2': + resolution: {integrity: sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==, tarball: https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [arm] + os: [linux] + + '@typescript/typescript-linux-loong64@7.0.2': + resolution: {integrity: sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==, tarball: https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [loong64] + os: [linux] + + '@typescript/typescript-linux-mips64el@7.0.2': + resolution: {integrity: sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==, tarball: https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [mips64el] + os: [linux] + + '@typescript/typescript-linux-ppc64@7.0.2': + resolution: {integrity: sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==, tarball: https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [linux] + + '@typescript/typescript-linux-riscv64@7.0.2': + resolution: {integrity: sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==, tarball: https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [riscv64] + os: [linux] + + '@typescript/typescript-linux-s390x@7.0.2': + resolution: {integrity: sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==, tarball: https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [s390x] + os: [linux] + + '@typescript/typescript-linux-x64@7.0.2': + resolution: {integrity: sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==, tarball: https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [linux] + + '@typescript/typescript-netbsd-arm64@7.0.2': + resolution: {integrity: sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==, tarball: https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [netbsd] + + '@typescript/typescript-netbsd-x64@7.0.2': + resolution: {integrity: sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==, tarball: https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [netbsd] + + '@typescript/typescript-openbsd-arm64@7.0.2': + resolution: {integrity: sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==, tarball: https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [openbsd] + + '@typescript/typescript-openbsd-x64@7.0.2': + resolution: {integrity: sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==, tarball: https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [openbsd] + + '@typescript/typescript-sunos-x64@7.0.2': + resolution: {integrity: sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==, tarball: https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [sunos] + + '@typescript/typescript-win32-arm64@7.0.2': + resolution: {integrity: sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==, tarball: https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [win32] + + '@typescript/typescript-win32-x64@7.0.2': + resolution: {integrity: sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==, tarball: https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [win32] + '@xmldom/xmldom@0.9.12': resolution: {integrity: sha512-5AXjrcMClTryPe9LgZrygpB1lj7s0S9E0+W+AHaVKAVyHanafK86iPSvG5xHVSp/jC+VH1UXu0TAEmY279xH7A==, tarball: https://registry.npmjs.org/@xmldom/xmldom/-/xmldom-0.9.12.tgz} engines: {node: '>=14.6'} @@ -430,9 +550,9 @@ packages: resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==, tarball: https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz} engines: {node: '>=12.0.0'} - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==, tarball: https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz} - engines: {node: '>=14.17'} + typescript@7.0.2: + resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==, tarball: https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz} + engines: {node: '>=16.20.0'} hasBin: true undici-types@7.18.2: @@ -598,6 +718,66 @@ snapshots: dependencies: undici-types: 7.18.2 + '@typescript/typescript-aix-ppc64@7.0.2': + optional: true + + '@typescript/typescript-darwin-arm64@7.0.2': + optional: true + + '@typescript/typescript-darwin-x64@7.0.2': + optional: true + + '@typescript/typescript-freebsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-freebsd-x64@7.0.2': + optional: true + + '@typescript/typescript-linux-arm64@7.0.2': + optional: true + + '@typescript/typescript-linux-arm@7.0.2': + optional: true + + '@typescript/typescript-linux-loong64@7.0.2': + optional: true + + '@typescript/typescript-linux-mips64el@7.0.2': + optional: true + + '@typescript/typescript-linux-ppc64@7.0.2': + optional: true + + '@typescript/typescript-linux-riscv64@7.0.2': + optional: true + + '@typescript/typescript-linux-s390x@7.0.2': + optional: true + + '@typescript/typescript-linux-x64@7.0.2': + optional: true + + '@typescript/typescript-netbsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-netbsd-x64@7.0.2': + optional: true + + '@typescript/typescript-openbsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-openbsd-x64@7.0.2': + optional: true + + '@typescript/typescript-sunos-x64@7.0.2': + optional: true + + '@typescript/typescript-win32-arm64@7.0.2': + optional: true + + '@typescript/typescript-win32-x64@7.0.2': + optional: true + '@xmldom/xmldom@0.9.12': {} abbrev@5.0.0: @@ -880,7 +1060,28 @@ snapshots: picomatch: 4.0.5 optional: true - typescript@5.9.3: {} + typescript@7.0.2: + optionalDependencies: + '@typescript/typescript-aix-ppc64': 7.0.2 + '@typescript/typescript-darwin-arm64': 7.0.2 + '@typescript/typescript-darwin-x64': 7.0.2 + '@typescript/typescript-freebsd-arm64': 7.0.2 + '@typescript/typescript-freebsd-x64': 7.0.2 + '@typescript/typescript-linux-arm': 7.0.2 + '@typescript/typescript-linux-arm64': 7.0.2 + '@typescript/typescript-linux-loong64': 7.0.2 + '@typescript/typescript-linux-mips64el': 7.0.2 + '@typescript/typescript-linux-ppc64': 7.0.2 + '@typescript/typescript-linux-riscv64': 7.0.2 + '@typescript/typescript-linux-s390x': 7.0.2 + '@typescript/typescript-linux-x64': 7.0.2 + '@typescript/typescript-netbsd-arm64': 7.0.2 + '@typescript/typescript-netbsd-x64': 7.0.2 + '@typescript/typescript-openbsd-arm64': 7.0.2 + '@typescript/typescript-openbsd-x64': 7.0.2 + '@typescript/typescript-sunos-x64': 7.0.2 + '@typescript/typescript-win32-arm64': 7.0.2 + '@typescript/typescript-win32-x64': 7.0.2 undici-types@7.18.2: {} From d5ac9db510a3b676785269fc2a7189c2b960610f Mon Sep 17 00:00:00 2001 From: Prabhu Subramanian Date: Sat, 29 Aug 2026 18:15:37 +0100 Subject: [PATCH 2/3] Make the type workflows pass under TypeScript 7 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The native compiler changes declaration emit and checks more of it, so three genuine new failures surfaced; none of them is a tsconfig problem (strict, skipLibCheck: false and checkJs stay as they are). lib/sqlite3.d.ts(105): TS8023 — the emitted JSDoc tag '@extends {NativeDatabase}' no longer matches the emitted extends clause. The tag referenced a module-local binding that does not even exist in the generated file's scope, and was redundant for checkJs (the extends clause in lib/sqlite3.js is explicit), so the tag is dropped from the source JSDoc. types/consumer.check.ts: TS 7 reports object-literal argument errors at the mismatched property instead of the whole call, so the '@ts-expect-error untrusted is boolean' directive moved inside the object literal to keep covering it. The negative still fails to compile, as intended. contrib/check-jsdoc.js: TS 5.9 renamed the class's materialized heritage-clause alias to 'DatabaseClass_base'; TS 7 keeps the source-local name 'NativeDatabase'. The skip rule now accepts both spellings; there is still no source doc comment the alias could carry. tools/gen-types.js: TS 7 no longer attaches a @typedef's summary text to the rendered 'export type' it produces (TS 5.9 did), and in lib/promises.js and lib/pool.js it drops the raw @typedef block too — every type summary would silently vanish from the shipped declarations. gen-types now re-attaches each typedef's summary from its lib/*.js source to the rendered alias, deterministically and under the existing CI regeneration diff. Regenerated lib/*.d.ts. Verified against a fresh TS 5.9.3 emit: every doc comment is byte-identical except the removed '@extends' line; the remaining differences are cosmetic (quote style, declaration ordering, 'export function' becoming 'declare function' plus an export list, the heritage alias rename) or an equivalent restatement (optional properties emitted as 'x?: T' instead of 'x?: T | undefined'). No exported name, type, or signature changed. --- contrib/check-jsdoc.js | 18 ++++-- lib/pool.d.ts | 113 ++++++++++++++++++------------------- lib/promises.d.ts | 121 ++++++++++++++++++++-------------------- lib/sqlite3.d.ts | 33 ++++++----- lib/sqlite3.js | 1 - lib/trace.d.ts | 5 +- tools/gen-types.js | 97 ++++++++++++++++++++++++++------ types/consumer.check.ts | 2 +- 8 files changed, 230 insertions(+), 160 deletions(-) diff --git a/contrib/check-jsdoc.js b/contrib/check-jsdoc.js index 465164f..51501b8 100644 --- a/contrib/check-jsdoc.js +++ b/contrib/check-jsdoc.js @@ -139,11 +139,19 @@ for (const file of FILES) { const name = m[1]; const where = `${file} ${name} (line ${i + 1})`; if (name === 'constructor' || seen.has(name)) return; - // tsc's declaration emit synthesizes `_base` aliases for - // heritage clauses in the generated entry (e.g. DatabaseClass_base - // for `class DatabaseClass extends NativeDatabase`); there is no - // source-level doc comment they could carry. - if (name.endsWith('_base') && file === 'lib/sqlite3.d.ts') return; + // tsc's declaration emit materializes the wrapper class's + // heritage clause as a module-local const in the generated entry + // (for `class DatabaseClass extends NativeDatabase`): TS 5.9 + // renamed the alias to `_base` (DatabaseClass_base), TS 7 + // keeps the source-local name (NativeDatabase). Either way it is + // compiler state, not a source declaration — there is no doc + // comment it could carry. + if ( + file === 'lib/sqlite3.d.ts' && + (name.endsWith('_base') || name === 'NativeDatabase') + ) { + return; + } seen.add(name); const doc = docFor(lines, i); diff --git a/lib/pool.d.ts b/lib/pool.d.ts index d172fd8..0755a8d 100644 --- a/lib/pool.d.ts +++ b/lib/pool.d.ts @@ -8,7 +8,7 @@ export type PoolOptions = { * with writes — the right shape for a write-heavy file or a * `:memory:` database. */ - readers?: number | undefined; + readers?: number; /** * set `PRAGMA journal_mode = WAL` on the * writer before readers connect (default true). WAL is what lets @@ -16,19 +16,19 @@ export type PoolOptions = { * filesystem that refuses WAL) readers can block on the writer and * rely on `busyTimeout`. */ - walMode?: boolean | undefined; + walMode?: boolean; /** * `PRAGMA busy_timeout` in milliseconds * for every connection (default 5000). */ - busyTimeout?: number | undefined; + busyTimeout?: number; /** * the integer * conversion mode for every connection (see * `configure('integerMode', …)`); the driver default (`'number'`) * applies when omitted. */ - integerMode?: "number" | "bigint" | "mixed" | undefined; + integerMode?: 'number' | 'bigint' | 'mixed'; }; /** * Options for a pool query. @@ -41,7 +41,7 @@ export type PoolQueryOptions = { * single-connection API, an abort that loses the race with a * completing query still rejects and drops the result. */ - signal?: AbortSignal | undefined; + signal?: AbortSignal; }; /** * The query surface inside {@link SqlitePool#transaction}, pinned to the @@ -52,49 +52,20 @@ export type PoolTransaction = { /** * runs a query on the writer, resolving every row. */ - read: (sql: string, params?: import("./native.js").BindParams) => Promise; + read: (sql: string, params?: import('./native.js').BindParams) => Promise; /** * runs a query on the writer, resolving the first row (or undefined). */ - get: (sql: string, params?: import("./native.js").BindParams) => Promise; + get: (sql: string, params?: import('./native.js').BindParams) => Promise; /** * runs a statement inside the transaction, resolving `{lastID, changes, lastIDBigInt}`. */ - write: (sql: string, params?: import("./native.js").BindParams) => Promise; + write: (sql: string, params?: import('./native.js').BindParams) => Promise; /** * runs raw SQL (DDL, pragmas) inside the transaction. */ exec: (sql: string) => Promise; }; -/** - * Creates a worker-thread pool over a database file: one writer - * connection plus `options.readers` read-only connections (default 4), - * each on its own worker. Writes serialize on the writer; reads fan out - * to the readers. All SQLite work happens off the calling thread. - * - * Requires a real file (or a `file:` URI): each connection is separate, - * so a plain `:memory:` database cannot be shared across the pool's - * workers — move in-memory data with `db.serializeToBytes()` + - * {@link sqlite3.deserializeFromBytes} in a worker instead (see - * docs/concurrency.md). With `readers: 0` a `:memory:` pool is fine: - * everything runs on the single writer. - * - * @param {string} filename the database file. - * @param {PoolOptions} [options] the pool options. - * @returns {Promise} the opened pool. - * @throws {TypeError} when the filename is missing or malformed, or an - * option is unknown/invalid. - * @since 9.0.0 - * @example - * const pool = await sqlite3.pool('app.db', { - * readers: 4, - * busyTimeout: 5000, - * }); - * const rows = await pool.read('SELECT * FROM t WHERE a = ?', [1]); - * await pool.write('INSERT INTO t (a) VALUES (?)', [2]); - * await pool.close(); - */ -export function pool(filename: string, options?: PoolOptions): Promise; /** * A worker-thread pool over one database file: a single writer * connection plus read-only reader connections, each on its own worker. @@ -111,7 +82,20 @@ export function pool(filename: string, options?: PoolOptions): Promise; - /** - * @param {string} filename the database file. - * @param {{ readers: number, walMode: boolean, busyTimeout: number, - * integerMode: ('number' | 'bigint' | 'mixed') | undefined }} options - * validated options. - */ - constructor(filename: string, options: { - readers: number; - walMode: boolean; - busyTimeout: number; - integerMode: ("number" | "bigint" | "mixed") | undefined; - }); /** * The database filename the pool was created with. * @@ -184,7 +156,7 @@ export class SqlitePool { * @example * const rows = await pool.read('SELECT id FROM users WHERE name = ?', ['alice']); */ - read(...args: any[]): Promise; + read(...args: any[]): Promise; /** * Runs a query on a reader connection, resolving the first row (or * `undefined`). Same routing and visibility rules as @@ -200,7 +172,7 @@ export class SqlitePool { * @example * const user = await pool.get('SELECT id FROM users WHERE name = ?', ['alice']); */ - get(...args: any[]): Promise; + get(...args: any[]): Promise; /** * Runs a statement on the writer connection, resolving * `{lastID, changes, lastIDBigInt}`. Writes serialize: concurrent @@ -217,7 +189,7 @@ export class SqlitePool { * @example * const result = await pool.write('INSERT INTO users (name) VALUES (?)', ['alice']); */ - write(...args: any[]): Promise; + write(...args: any[]): Promise; /** * Runs raw SQL on the writer connection: DDL, pragmas, * multi-statement scripts. Resolves once every statement has run. @@ -261,7 +233,7 @@ export class SqlitePool { * }); */ transaction(fn: (tx: PoolTransaction) => T | Promise, options?: { - mode?: "deferred" | "immediate" | "exclusive"; + mode?: 'deferred' | 'immediate' | 'exclusive'; }): Promise; /** * Closes the pool: refuses new work, waits for every in-flight @@ -285,5 +257,34 @@ export class SqlitePool { * @since 9.0.0 */ [Symbol.asyncDispose](): Promise; - #private; } +/** + * Creates a worker-thread pool over a database file: one writer + * connection plus `options.readers` read-only connections (default 4), + * each on its own worker. Writes serialize on the writer; reads fan out + * to the readers. All SQLite work happens off the calling thread. + * + * Requires a real file (or a `file:` URI): each connection is separate, + * so a plain `:memory:` database cannot be shared across the pool's + * workers — move in-memory data with `db.serializeToBytes()` + + * {@link sqlite3.deserializeFromBytes} in a worker instead (see + * docs/concurrency.md). With `readers: 0` a `:memory:` pool is fine: + * everything runs on the single writer. + * + * @param {string} filename the database file. + * @param {PoolOptions} [options] the pool options. + * @returns {Promise} the opened pool. + * @throws {TypeError} when the filename is missing or malformed, or an + * option is unknown/invalid. + * @since 9.0.0 + * @example + * const pool = await sqlite3.pool('app.db', { + * readers: 4, + * busyTimeout: 5000, + * }); + * const rows = await pool.read('SELECT * FROM t WHERE a = ?', [1]); + * await pool.write('INSERT INTO t (a) VALUES (?)', [2]); + * await pool.close(); + */ +declare function pool(filename: string, options?: PoolOptions): Promise; +export { pool, SqlitePool }; diff --git a/lib/promises.d.ts b/lib/promises.d.ts index 78552b4..1107834 100644 --- a/lib/promises.d.ts +++ b/lib/promises.d.ts @@ -1,49 +1,3 @@ -/** - * Installs the promise API onto the classes: dual-mode wrappers over the - * existing callback implementations, plus `open()`, `iterate()`, - * `stream()`, `transaction()` and dispose support. Called once from - * lib/sqlite3.js after every callback-mode method is in place. - * - * @param {import('./sqlite3.js').sqlite3} sqlite3 the binding's export - * object, carrying `Database`, `Statement` and `Backup`. - * @returns {void} - */ -export function installPromiseApi(sqlite3: import("./sqlite3.js").sqlite3): void; -/** - * Rewires `sqlite3.verbose()`: wraps the callback-mode cores with the - * long-stack-trace machinery, then reinstalls the dual-mode wrappers so - * promise rejections go through the same augmentation path. - * - * @param {(object: Record, property: string) => void} extendTrace the trace wrapper from lib/trace.js. - * @returns {void} - */ -export function retracePromiseApi(extendTrace: (object: Record, property: string) => void): void; -/** - * Options driving {@link createAsyncIterator}. - */ -export type IteratorOptions = { - /** - * bind parameters for the first fetch. - */ - params?: unknown[] | undefined; - /** - * whether the iterator finalizes (true) - * or merely resets (false) its statement on teardown. - */ - ownsStatement?: boolean | undefined; - /** - * abort the iteration mid-cursor. - */ - signal?: AbortSignal | undefined; - /** - * interrupt the connection on abort. - */ - interrupt?: (() => void) | undefined; - /** - * lazily create the statement (db.iterate). - */ - prepare?: ((callback: (err: Error | null) => void) => import("./sqlite3.js").Statement) | undefined; -}; /** * What promise-mode `run()` resolves to. * @@ -77,7 +31,7 @@ export type SignalOptions = { /** * Abort this operation by interrupting the connection. */ - signal?: AbortSignal | undefined; + signal?: AbortSignal; }; /** * Options for `Database#transaction`. @@ -86,26 +40,26 @@ export type TransactionOptions = { /** * Transaction start mode. */ - mode?: "deferred" | "immediate" | "exclusive" | undefined; + mode?: 'deferred' | 'immediate' | 'exclusive'; /** * Nest via SAVEPOINT even at the top level. */ - savepoint?: boolean | undefined; + savepoint?: boolean; /** * Run the body inside serialize() (strict * FIFO, at the cost of bypassing the statement cache). */ - serialize?: boolean | undefined; + serialize?: boolean; /** * Abort via `db.interrupt()` and reject with the signal's reason. */ - signal?: AbortSignal | undefined; + signal?: AbortSignal; }; /** * Callback of `Statement#fetch`: receives up to `count` rows and whether * the cursor is exhausted. */ -export type FetchCallback = (err: import("./native.js").SqliteError | null, rows: import("./native.js").Row[], done: boolean) => void; +export type FetchCallback = (err: import('./native.js').SqliteError | null, rows: import('./native.js').Row[], done: boolean) => void; /** * Opens a database and resolves once the connection is ready. The * `Database` constructor cannot return a promise; this is the @@ -113,13 +67,7 @@ export type FetchCallback = (err: import("./native.js").SqliteError | null, rows * argument is either open flags or a v9 options object (`mode`, * `untrusted`). */ -export type OpenFunction = (filename: string, modeOrOptions?: number | import("./sqlite3.js").OpenOptions) => Promise; -export type Installed = { - sqlite3: import("./sqlite3.js").sqlite3; - Database: typeof import("./sqlite3-binding.js").Database; - Statement: typeof import("./sqlite3-binding.js").Statement; - Backup: typeof import("./sqlite3-binding.js").Backup; -}; +export type OpenFunction = (filename: string, modeOrOptions?: number | import('./sqlite3.js').OpenOptions) => Promise; /** * Records which database owns a statement, so AbortSignal handling can * reach `db.interrupt()` from a statement method. @@ -128,4 +76,57 @@ export type Installed = { * @param {import('./sqlite3.js').Statement} statement the prepared statement. * @returns {import('./sqlite3.js').Statement} the statement, for inline use. */ -export function associateStatement(db: import("./sqlite3-binding.js").Database, statement: import("./sqlite3.js").Statement): import("./sqlite3.js").Statement; +declare function associateStatement(db: import('./sqlite3-binding.js').Database, statement: import('./sqlite3.js').Statement): import('./sqlite3.js').Statement; +/** + * Options driving {@link createAsyncIterator}. + */ +export type IteratorOptions = { + /** + * bind parameters for the first fetch. + */ + params?: unknown[]; + /** + * whether the iterator finalizes (true) + * or merely resets (false) its statement on teardown. + */ + ownsStatement?: boolean; + /** + * abort the iteration mid-cursor. + */ + signal?: AbortSignal; + /** + * interrupt the connection on abort. + */ + interrupt?: () => void; + /** + * lazily create the statement (db.iterate). + */ + prepare?: ((callback: (err: Error | null) => void) => import('./sqlite3.js').Statement); +}; +export type Installed = { + sqlite3: import('./sqlite3.js').sqlite3; + Database: typeof import('./sqlite3-binding.js').Database; + Statement: typeof import('./sqlite3-binding.js').Statement; + Backup: typeof import('./sqlite3-binding.js').Backup; +}; +/** + * Installs the promise API onto the classes: dual-mode wrappers over the + * existing callback implementations, plus `open()`, `iterate()`, + * `stream()`, `transaction()` and dispose support. Called once from + * lib/sqlite3.js after every callback-mode method is in place. + * + * @param {import('./sqlite3.js').sqlite3} sqlite3 the binding's export + * object, carrying `Database`, `Statement` and `Backup`. + * @returns {void} + */ +export declare function installPromiseApi(sqlite3: import('./sqlite3.js').sqlite3): void; +/** + * Rewires `sqlite3.verbose()`: wraps the callback-mode cores with the + * long-stack-trace machinery, then reinstalls the dual-mode wrappers so + * promise rejections go through the same augmentation path. + * + * @param {(object: Record, property: string) => void} extendTrace the trace wrapper from lib/trace.js. + * @returns {void} + */ +export declare function retracePromiseApi(extendTrace: (object: Record, property: string) => void): void; +export { associateStatement }; diff --git a/lib/sqlite3.d.ts b/lib/sqlite3.d.ts index ca856df..6735e0d 100644 --- a/lib/sqlite3.d.ts +++ b/lib/sqlite3.d.ts @@ -6,8 +6,6 @@ // lib/promises.d.ts and lib/trace.d.ts. // The three shipped .d.ts files together form the public types. -export default sqlite3; -export { DatabaseClass as Database }; /** * A native class (Database, Statement or Backup) before the EventEmitter * prototype is copied onto it. @@ -23,11 +21,11 @@ export type CachedRegistry = { /** * Open (or reuse) a connection, optionally with a callback. */ - Database: (filename: string, callback?: (this: import("./sqlite3-binding.js").Database, err: Error | null) => void) => import("./sqlite3-binding.js").Database; + Database: (filename: string, callback?: (this: import('./sqlite3-binding.js').Database, err: Error | null) => void) => import('./sqlite3-binding.js').Database; /** * The registry itself, keyed by resolved path. */ - objects: Record; + objects: Record; }; /** * The constructor type of the v9 `Database` wrapper: every pre-v9 @@ -36,7 +34,7 @@ export type CachedRegistry = { * below does not reference the module it lives in — that self-reference * is a type-resolution cycle. */ -export type DatabaseConstructor = new (filename: string, a?: number | OpenOptions | ((this: import("./sqlite3-binding.js").Database, err: import("./native.js").SqliteError | null) => void), b?: ((this: import("./sqlite3-binding.js").Database, err: import("./native.js").SqliteError | null) => void) | OpenOptions) => import("./sqlite3-binding.js").Database; +export type DatabaseConstructor = new (filename: string, a?: number | OpenOptions | ((this: import('./sqlite3-binding.js').Database, err: import('./native.js').SqliteError | null) => void), b?: ((this: import('./sqlite3-binding.js').Database, err: import('./native.js').SqliteError | null) => void) | OpenOptions) => import('./sqlite3-binding.js').Database; /** * The public `sqlite3` namespace object the package exports as its * default: the native binding (the five classes and every SQLite @@ -46,14 +44,16 @@ export type DatabaseConstructor = new (filename: string, a?: number | OpenOption * {@link OpenOptions} constructor forms typecheck; instances satisfy the * native type everywhere. */ -export type sqlite3 = import("./sqlite3-binding.js").NativeBinding & { +export type sqlite3 = import('./sqlite3-binding.js').NativeBinding & { Database: DatabaseConstructor; verbose: () => sqlite3; cached: CachedRegistry; - open: import("./promises.js").OpenFunction; - deserializeFromBytes: (bytes: Uint8Array | ArrayBuffer | DataView, options?: import("./native.js").DeserializeOptions) => Promise; - pool: typeof import("./pool.js").pool; + open: import('./promises.js').OpenFunction; + deserializeFromBytes: (bytes: Uint8Array | ArrayBuffer | DataView, options?: import('./native.js').DeserializeOptions) => Promise; + pool: typeof import('./pool.js').pool; }; +declare const sqlite3: sqlite3; +declare const NativeDatabase: typeof import("./native.js").Database & DatabaseConstructor; export type ExtensionPolicy = { /** * the connection was opened `{ untrusted: true }`. @@ -82,7 +82,7 @@ export type OpenOptions = { /** * open flags, e.g. `sqlite3.OPEN_READWRITE`. */ - mode?: number | undefined; + mode?: number; /** * harden the connection for an * attacker-supplied database file: defensive mode, untrusted schema, @@ -90,10 +90,8 @@ export type OpenOptions = { * conservative run-time limits and a deny-all ATTACH gate. See * docs/security.md#untrusted-database-files. */ - untrusted?: boolean | undefined; + untrusted?: boolean; }; -declare const sqlite3: sqlite3; -declare const DatabaseClass_base: typeof import("./native.js").Database & DatabaseConstructor; /** * A connection to a SQLite database — the v9 wrapper around the native * class. Adds the permission-model checks on every open path, the @@ -102,10 +100,9 @@ declare const DatabaseClass_base: typeof import("./native.js").Database & Databa * else, including all pre-v9 positional constructor forms, behaves * exactly as before. * - * @extends {NativeDatabase} * @since 9.0.0 */ -declare class DatabaseClass extends DatabaseClass_base { +declare class DatabaseClass extends NativeDatabase { /** * Opens a database connection. The open itself is asynchronous; the * callback fires (or the `'open'` event emits) once it completes. @@ -127,9 +124,11 @@ declare class DatabaseClass extends DatabaseClass_base { * the target is not permitted, naming the path and the remedy. * @throws {TypeError} when the arguments are malformed. */ - constructor(filename: string, a?: number | OpenOptions | ((this: import("./sqlite3-binding.js").Database, err: import("./native.js").SqliteError | null) => void), b?: ((this: import("./sqlite3-binding.js").Database, err: import("./native.js").SqliteError | null) => void) | OpenOptions); + constructor(filename: string, a?: number | OpenOptions | ((this: import('./sqlite3-binding.js').Database, err: import('./native.js').SqliteError | null) => void), b?: ((this: import('./sqlite3-binding.js').Database, err: import('./native.js').SqliteError | null) => void) | OpenOptions); } -export { Backup, Blob, Session, Statement } from "./sqlite3-binding.js"; +export default sqlite3; +export { Backup, Blob, Session, Statement } from './sqlite3-binding.js'; +export { DatabaseClass as Database }; import './augment.js'; export type { FetchCallback, diff --git a/lib/sqlite3.js b/lib/sqlite3.js index e69899d..fb541d9 100644 --- a/lib/sqlite3.js +++ b/lib/sqlite3.js @@ -739,7 +739,6 @@ function isOpenOptions(value) { * else, including all pre-v9 positional constructor forms, behaves * exactly as before. * - * @extends {NativeDatabase} * @since 9.0.0 */ class DatabaseClass extends NativeDatabase { diff --git a/lib/trace.d.ts b/lib/trace.d.ts index 4779f74..37ded73 100644 --- a/lib/trace.d.ts +++ b/lib/trace.d.ts @@ -22,11 +22,12 @@ export type Traceable = (this: unknown, ...args: unknown[]) => unknown; * @param {number} [pos=-1] position of the callback argument. * @returns {void} */ -export function extendTrace(object: Record, property: string, pos?: number): void; +declare function extendTrace(object: Record, property: string, pos?: number): void; /** * Drops this file's own frames from a stack string. * * @param {string | undefined} stackStr the stack to filter. * @returns {string[]} the surviving frames. */ -export function filter(stackStr: string | undefined): string[]; +declare function filter(stackStr: string | undefined): string[]; +export { extendTrace, filter }; diff --git a/tools/gen-types.js b/tools/gen-types.js index ca01d44..f2760c9 100644 --- a/tools/gen-types.js +++ b/tools/gen-types.js @@ -5,8 +5,17 @@ // Runs `tsc -p tsconfig.types.json`, which typechecks lib/*.js (checkJs) // against the hand-written native declarations in lib/native.d.ts and // emits declarations into the gitignored types-gen/ scratch directory. -// This script then copies them into lib/, post-processing the package's -// `types` entry (lib/sqlite3.d.ts) in three deterministic steps: +// This script then normalizes the emit with two deterministic steps +// before post-processing the package's `types` entry (lib/sqlite3.d.ts): +// +// 1. strip the raw `@typedef` blocks the JS emit copies verbatim, +// 2. re-attach each @typedef's summary text from its lib/*.js source +// to the rendered `export type` it produced. TS 5.9 attached this +// summary itself; TS 7 drops it (and, in lib/promises.js and +// lib/pool.js, drops the raw block too), which would silently +// strip every type summary from the shipped docs. +// +// The entry is then post-processed in three deterministic steps: // // 1. prepend the GENERATED header, // 2. append `import './augment.js'` so consumers of the package load @@ -24,7 +33,7 @@ // The result is committed; CI regenerates and fails on any diff, so a // declaration can neither drift from the JSDoc nor be silently dropped. import { execFileSync } from 'node:child_process'; -import { copyFileSync, readFileSync, rmSync, writeFileSync } from 'node:fs'; +import { readFileSync, rmSync, writeFileSync } from 'node:fs'; import path from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -47,14 +56,72 @@ const entry = path.join(root, 'lib', 'sqlite3.d.ts'); // tsc's JS emit attaches the original JSDoc verbatim, so a rendered // `export type X` can be followed by a second, raw copy of its @typedef -// block. Drop those: the rendered declaration carries the same docs. +// block. Drop those: the rendered declaration carries the same docs +// once the summaries below are re-attached. function stripRawTypedefComments(text) { return text.replace(/\/\*\*(?:[^*]|\*(?!\/))*?@typedef[\s\S]*?\*\/\n/g, ''); } -const emitted = stripRawTypedefComments( - readFileSync(path.join(emitDir, 'sqlite3.d.ts'), 'utf8'), -); +// The summary text of every `@typedef` in a source file: the comment +// lines before the first @tag (the @property/@since tags are rendered +// or dropped by tsc itself). Blocks without a summary — e.g. +// ExtensionPolicy, documented only through its @property tags — are +// skipped; there is nothing to re-attach for them. +function typedefSummaries(source) { + const summaries = new Map(); + for (const match of source.matchAll(/\/\*\*[\s\S]*?\*\//g)) { + const name = match[0].match( + /@typedef\s*\{[\s\S]*?\}\s*([A-Za-z_$][\w$]*)/, + )?.[1]; + if (!name || summaries.has(name)) continue; + const summary = []; + for (const line of match[0].split('\n').slice(1, -1)) { + const text = line.replace(/^\s*\/?\*+\s?/, '').replace(/\*\/$/, ''); + if (/^@\w/.test(text.trim())) break; + summary.push(text.trimEnd()); + } + while (summary.length && !summary.at(-1).trim()) summary.pop(); + if (summary.some((line) => line.trim())) summaries.set(name, summary); + } + return summaries; +} + +// Prepend each typedef's summary to the rendered `export type` it +// produced, unless the emit already documents that declaration (TS 7 +// keeps docs on functions and classes; only the rendered type aliases +// come out bare). +function attachTypedefSummaries(text, summaries) { + const out = []; + for (const line of text.split('\n')) { + const name = line.match(/^export type ([A-Za-z_$][\w$]*)\b/)?.[1]; + const summary = name === undefined ? undefined : summaries.get(name); + if (summary && out.at(-1) !== ' */') { + out.push('/**'); + for (const text of summary) out.push(` * ${text}`.trimEnd()); + out.push(' */'); + } + out.push(line); + } + return out.join('\n'); +} + +// The lib/*.js source each emitted declaration file is generated from. +const summarySources = { + 'sqlite3.d.ts': 'sqlite3.js', + 'promises.d.ts': 'promises.js', + 'trace.d.ts': 'trace.js', + 'pool.d.ts': 'pool.js', +}; + +const emitted = {}; +for (const [declaration, source] of Object.entries(summarySources)) { + let text = readFileSync(path.join(emitDir, declaration), 'utf8'); + if (declaration === 'sqlite3.d.ts') text = stripRawTypedefComments(text); + emitted[declaration] = attachTypedefSummaries( + text, + typedefSummaries(readFileSync(path.join(root, 'lib', source), 'utf8')), + ); +} // Every `export type X` / `export interface X` in the hand-written // island, keys sorted for a stable diff. Classes are re-exported by the @@ -102,24 +169,18 @@ const header = `// GENERATED FILE — DO NOT EDIT. writeFileSync( entry, - `${header}${emitted}${augmentImport}\n` + + `${header}${emitted['sqlite3.d.ts']}${augmentImport}\n` + block('promises.js', promisesPublicTypes) + block('pool.js', poolPublicTypes) + block('native.js', nativeTypes), ); -copyFileSync( - path.join(emitDir, 'promises.d.ts'), +writeFileSync( path.join(root, 'lib', 'promises.d.ts'), + emitted['promises.d.ts'], ); -copyFileSync( - path.join(emitDir, 'trace.d.ts'), - path.join(root, 'lib', 'trace.d.ts'), -); -copyFileSync( - path.join(emitDir, 'pool.d.ts'), - path.join(root, 'lib', 'pool.d.ts'), -); +writeFileSync(path.join(root, 'lib', 'trace.d.ts'), emitted['trace.d.ts']); +writeFileSync(path.join(root, 'lib', 'pool.d.ts'), emitted['pool.d.ts']); console.log( 'gen-types: lib/sqlite3.d.ts, lib/promises.d.ts, lib/trace.d.ts, lib/pool.d.ts regenerated.', diff --git a/types/consumer.check.ts b/types/consumer.check.ts index 5dd661d..222ee78 100644 --- a/types/consumer.check.ts +++ b/types/consumer.check.ts @@ -57,8 +57,8 @@ async function consumer(): Promise { const constructed = new sqlite3.Database(':memory:', { untrusted: true, }); - // @ts-expect-error untrusted is boolean const constructed2 = new sqlite3.Database(':memory:', { + // @ts-expect-error untrusted is boolean untrusted: 'yes', }); void constructed; From ac1c4e4d81216486e71e2682263a7274b94dff20 Mon Sep 17 00:00:00 2001 From: Prabhu Subramanian Date: Sat, 29 Aug 2026 18:18:03 +0100 Subject: [PATCH 3/3] Include lib/pool.d.ts in the CI regeneration diff Signed-off-by: Prabhu Subramanian --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 835bfba..d460f22 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,7 +58,7 @@ jobs: - name: Regenerated declarations must match the committed ones run: | pnpm run gen-types - git diff --exit-code -- lib/sqlite3.d.ts lib/promises.d.ts lib/trace.d.ts + git diff --exit-code -- lib/sqlite3.d.ts lib/promises.d.ts lib/trace.d.ts lib/pool.d.ts # Fast test feedback via a dev rebuild instead of a full prebuild.