setup dual publish for commonjs/esm modules and properly route browser/node usages to the correct napi binary entrypoint

This commit is contained in:
Nikita Sivukhin
2025-08-07 15:46:30 +04:00
parent 1a2a1a9ca4
commit d1cd294e94
14 changed files with 177 additions and 94 deletions

View File

@@ -7,7 +7,7 @@
// The `params` parameter is an array of parameters.
//
// The function returns void.
function bindParams(stmt, params) {
export function bindParams(stmt, params) {
const len = params?.length;
if (len === 0) {
return;
@@ -65,6 +65,4 @@ function bindPositionalParams(stmt, params) {
function bindValue(stmt, index, value) {
stmt.bindAt(index, value);
}
module.exports = { bindParams };
}

View File

@@ -6,18 +6,26 @@
"url": "https://github.com/tursodatabase/turso"
},
"description": "The Turso database library",
"main": "promise.js",
"module": "./promise.mjs",
"main": "./promise.cjs",
"exports": {
".": "./promise.js",
"./sync": "./sync.js"
".": {
"require": "./promise.cjs",
"import": "./promise.mjs"
},
"./sync": {
"require": "./sync.cjs",
"import": "./sync.mjs"
}
},
"files": [
"bind.js",
"browser.js",
"index.js",
"promise.js",
"sqlite-error.js",
"sync.js"
"promise.cjs",
"promise.mjs",
"sync.cjs",
"sync.mjs",
"dist/**"
],
"types": "index.d.ts",
"napi": {
@@ -34,7 +42,9 @@
"@napi-rs/cli": "^3.0.4",
"@napi-rs/wasm-runtime": "^1.0.1",
"ava": "^6.0.1",
"better-sqlite3": "^11.9.1"
"better-sqlite3": "^11.9.1",
"tsc": "^2.0.4",
"typescript": "^5.9.2"
},
"ava": {
"timeout": "3m"
@@ -43,7 +53,7 @@
"node": ">= 10"
},
"scripts": {
"artifacts": "napi artifacts",
"artifacts": "napi artifacts && tsc -p tsconfig.cjs.json && tsc -p tsconfig.esm.json",
"build": "napi build --platform --release",
"build:debug": "napi build --platform",
"prepublishOnly": "napi prepublish -t npm",
@@ -51,5 +61,12 @@
"universal": "napi universalize",
"version": "napi version"
},
"packageManager": "yarn@4.9.2"
}
"packageManager": "yarn@4.9.2",
"imports": {
"#entry-point": {
"types": "./index.d.ts",
"browser": "./browser.js",
"node": "./index.js"
}
}
}

View File

@@ -0,0 +1,2 @@
const Database = require('./dist/cjs/promise');
module.exports = Database;

View File

@@ -0,0 +1,5 @@
import { SqliteError } from "./dist/esm/sqlite-error"
import { Database } from "./dist/esm/promise"
export default Database;
export { SqliteError }

View File

@@ -1,9 +1,7 @@
"use strict";
import { Database as NativeDB, Statement as NativeStatement } from "#entry-point";
import { bindParams } from "./bind.js";
const { Database: NativeDB } = require("./index.js");
const { bindParams } = require("./bind.js");
const SqliteError = require("./sqlite-error.js");
import { SqliteError } from "./sqlite-error.js";
// Step result constants
const STEP_ROW = 1;
@@ -36,7 +34,10 @@ function createErrorByName(name, message) {
/**
* Database represents a connection that can prepare and execute SQL statements.
*/
class Database {
export class Database {
static SqliteError = SqliteError;
db: NativeDB;
memory: boolean;
/**
* Creates a new database connection. If the database file pointed to by `path` does not exists, it will be created.
*
@@ -47,25 +48,25 @@ class Database {
* @param {boolean} [opts.fileMustExist=false] - If true, throws if database file does not exist.
* @param {number} [opts.timeout=0] - Timeout duration in milliseconds for database operations. Defaults to 0 (no timeout).
*/
constructor(path, opts = {}) {
constructor(path: string, opts: any = {}) {
opts.readonly = opts.readonly === undefined ? false : opts.readonly;
opts.fileMustExist =
opts.fileMustExist === undefined ? false : opts.fileMustExist;
opts.timeout = opts.timeout === undefined ? 0 : opts.timeout;
this.db = new NativeDB(path, opts);
const db = new NativeDB(path);
this.initialize(db, opts.path, opts.readonly);
}
static create() {
return Object.create(this.prototype);
}
initialize(db, name, readonly) {
initialize(db: NativeDB, name, readonly) {
this.db = db;
this.memory = db.memory;
Object.defineProperties(this, {
inTransaction: {
get() {
return db.inTransaction();
throw new Error("not implemented");
},
},
name: {
@@ -154,10 +155,10 @@ class Database {
throw new TypeError("Expected second argument to be an options object");
const pragma = `PRAGMA ${source}`;
const stmt = this.prepare(pragma);
const results = stmt.all();
return results;
}
@@ -182,7 +183,7 @@ class Database {
}
loadExtension(path) {
this.db.loadExtension(path);
throw new Error("not implemented");
}
maxWriteReplicationIndex() {
@@ -210,7 +211,7 @@ class Database {
* Interrupts the database connection.
*/
interrupt() {
this.db.interrupt();
throw new Error("not implemented");
}
/**
@@ -225,6 +226,8 @@ class Database {
* Statement represents a prepared SQL statement that can be executed.
*/
class Statement {
stmt: NativeStatement;
db: Database;
constructor(stmt, database) {
this.stmt = stmt;
this.db = database;
@@ -251,17 +254,13 @@ class Statement {
}
get source() {
return this.stmt.source;
throw new Error("not implemented");
}
get reader() {
throw new Error("not implemented");
}
get source() {
return this.stmt.source;
}
get database() {
return this.db;
}
@@ -271,10 +270,10 @@ class Statement {
*/
async run(...bindParameters) {
const totalChangesBefore = this.db.db.totalChanges();
this.stmt.reset();
bindParams(this.stmt, bindParameters);
while (true) {
const stepResult = this.stmt.step();
if (stepResult === STEP_IO) {
@@ -289,10 +288,10 @@ class Statement {
continue;
}
}
const lastInsertRowid = this.db.db.lastInsertRowid();
const changes = this.db.db.totalChanges() === totalChangesBefore ? 0 : this.db.db.changes();
return { changes, lastInsertRowid };
}
@@ -304,7 +303,7 @@ class Statement {
async get(...bindParameters) {
this.stmt.reset();
bindParams(this.stmt, bindParameters);
while (true) {
const stepResult = this.stmt.step();
if (stepResult === STEP_IO) {
@@ -352,8 +351,8 @@ class Statement {
async all(...bindParameters) {
this.stmt.reset();
bindParams(this.stmt, bindParameters);
const rows = [];
const rows: any[] = [];
while (true) {
const stepResult = this.stmt.step();
if (stepResult === STEP_IO) {
@@ -374,15 +373,14 @@ class Statement {
* Interrupts the statement.
*/
interrupt() {
this.stmt.interrupt();
return this;
throw new Error("not implemented");
}
/**
* Returns the columns in the result set returned by this prepared statement.
*/
columns() {
return this.stmt.columns();
throw new Error("not implemented");
}
/**
@@ -400,6 +398,3 @@ class Statement {
}
}
}
module.exports = Database;
module.exports.SqliteError = SqliteError;

View File

@@ -1,14 +0,0 @@
'use strict';
class SqliteError extends Error {
constructor(message, code, rawCode) {
super(message);
this.name = 'SqliteError';
this.code = code;
this.rawCode = rawCode;
Error.captureStackTrace(this, SqliteError);
}
}
module.exports = SqliteError;

View File

@@ -0,0 +1,13 @@
export class SqliteError extends Error {
name: string;
code: string;
rawCode: string;
constructor(message, code, rawCode) {
super(message);
this.name = 'SqliteError';
this.code = code;
this.rawCode = rawCode;
(Error as any).captureStackTrace(this, SqliteError);
}
}

View File

@@ -0,0 +1,2 @@
const { Database } = require('./dist/cjs/sync');
module.exports = Database;

View File

@@ -0,0 +1,5 @@
import { SqliteError } from "./dist/esm/sqlite-error"
import Database from "./dist/esm/sync"
export default Database;
export { SqliteError }

View File

@@ -1,9 +1,7 @@
"use strict";
import { Database as NativeDB, Statement as NativeStatement } from "#entry-point";
import { bindParams } from "./bind.js";
const { Database: NativeDB } = require("./index.js");
const { bindParams } = require("./bind.js");
const SqliteError = require("./sqlite-error.js");
import { SqliteError } from "./sqlite-error.js";
// Step result constants
const STEP_ROW = 1;
@@ -36,7 +34,11 @@ function createErrorByName(name, message) {
/**
* Database represents a connection that can prepare and execute SQL statements.
*/
class Database {
export class Database {
static SqliteError = SqliteError;
db: NativeDB;
memory: boolean;
/**
* Creates a new database connection. If the database file pointed to by `path` does not exists, it will be created.
*
@@ -47,20 +49,20 @@ class Database {
* @param {boolean} [opts.fileMustExist=false] - If true, throws if database file does not exist.
* @param {number} [opts.timeout=0] - Timeout duration in milliseconds for database operations. Defaults to 0 (no timeout).
*/
constructor(path, opts = {}) {
constructor(path: string, opts: any = {}) {
opts.readonly = opts.readonly === undefined ? false : opts.readonly;
opts.fileMustExist =
opts.fileMustExist === undefined ? false : opts.fileMustExist;
opts.timeout = opts.timeout === undefined ? 0 : opts.timeout;
this.db = new NativeDB(path, opts);
this.db = new NativeDB(path);
this.memory = this.db.memory;
const db = this.db;
Object.defineProperties(this, {
inTransaction: {
get() {
return db.inTransaction();
throw new Error("not implemented");
},
},
name: {
@@ -149,10 +151,10 @@ class Database {
throw new TypeError("Expected second argument to be an options object");
const pragma = `PRAGMA ${source}`;
const stmt = this.prepare(pragma);
const results = stmt.all();
return results;
}
@@ -177,7 +179,7 @@ class Database {
}
loadExtension(path) {
this.db.loadExtension(path);
throw new Error("not implemented");
}
maxWriteReplicationIndex() {
@@ -205,7 +207,7 @@ class Database {
* Interrupts the database connection.
*/
interrupt() {
this.db.interrupt();
throw new Error("not implemented");
}
/**
@@ -220,7 +222,10 @@ class Database {
* Statement represents a prepared SQL statement that can be executed.
*/
class Statement {
constructor(stmt, database) {
stmt: NativeStatement;
db: Database;
constructor(stmt: NativeStatement, database: Database) {
this.stmt = stmt;
this.db = database;
}
@@ -246,17 +251,13 @@ class Statement {
}
get source() {
return this.stmt.source;
throw new Error("not implemented");
}
get reader() {
throw new Error("not implemented");
}
get source() {
return this.stmt.source;
}
get database() {
return this.db;
}
@@ -266,10 +267,10 @@ class Statement {
*/
run(...bindParameters) {
const totalChangesBefore = this.db.db.totalChanges();
this.stmt.reset();
bindParams(this.stmt, bindParameters);
for (;;) {
for (; ;) {
const stepResult = this.stmt.step();
if (stepResult === STEP_IO) {
this.db.db.ioLoopSync();
@@ -283,10 +284,10 @@ class Statement {
continue;
}
}
const lastInsertRowid = this.db.db.lastInsertRowid();
const changes = this.db.db.totalChanges() === totalChangesBefore ? 0 : this.db.db.changes();
return { changes, lastInsertRowid };
}
@@ -298,7 +299,7 @@ class Statement {
get(...bindParameters) {
this.stmt.reset();
bindParams(this.stmt, bindParameters);
for (;;) {
for (; ;) {
const stepResult = this.stmt.step();
if (stepResult === STEP_IO) {
this.db.db.ioLoopSync();
@@ -345,8 +346,8 @@ class Statement {
all(...bindParameters) {
this.stmt.reset();
bindParams(this.stmt, bindParameters);
const rows = [];
for (;;) {
const rows: any[] = [];
for (; ;) {
const stepResult = this.stmt.step();
if (stepResult === STEP_IO) {
this.db.db.ioLoopSync();
@@ -366,15 +367,14 @@ class Statement {
* Interrupts the statement.
*/
interrupt() {
this.stmt.interrupt();
return this;
throw new Error("not implemented");
}
/**
* Returns the columns in the result set returned by this prepared statement.
*/
columns() {
return this.stmt.columns();
throw new Error("not implemented");
}
/**
@@ -391,7 +391,4 @@ class Statement {
throw convertError(err);
}
}
}
module.exports = Database;
module.exports.SqliteError = SqliteError;
}

View File

@@ -0,0 +1,16 @@
{
"compilerOptions": {
"skipLibCheck": true,
"module": "commonjs",
"target": "es2015",
"outDir": "dist/cjs",
"paths": {
"#entry-point": [
"./index.js"
]
}
},
"include": [
"*"
]
}

View File

@@ -0,0 +1,16 @@
{
"compilerOptions": {
"skipLibCheck": true,
"module": "esnext",
"target": "esnext",
"outDir": "dist/esm",
"paths": {
"#entry-point": [
"./index.js"
]
}
},
"include": [
"*"
]
}

View File

@@ -1076,6 +1076,8 @@ __metadata:
"@napi-rs/wasm-runtime": "npm:^1.0.1"
ava: "npm:^6.0.1"
better-sqlite3: "npm:^11.9.1"
tsc: "npm:^2.0.4"
typescript: "npm:^5.9.2"
languageName: unknown
linkType: soft
@@ -3100,6 +3102,15 @@ __metadata:
languageName: node
linkType: hard
"tsc@npm:^2.0.4":
version: 2.0.4
resolution: "tsc@npm:2.0.4"
bin:
tsc: bin/tsc
checksum: 10c0/4651d344891d995e62ab7ca64ce0a8597bbdc2d392886c9956d15caab4dc9bfe86e759d3385b3f97c49fb5294194a161d6812673e3f51e46357c82482f32c3ab
languageName: node
linkType: hard
"tslib@npm:^2.4.0":
version: 2.8.1
resolution: "tslib@npm:2.8.1"
@@ -3137,6 +3148,26 @@ __metadata:
languageName: node
linkType: hard
"typescript@npm:^5.9.2":
version: 5.9.2
resolution: "typescript@npm:5.9.2"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
checksum: 10c0/cd635d50f02d6cf98ed42de2f76289701c1ec587a363369255f01ed15aaf22be0813226bff3c53e99d971f9b540e0b3cc7583dbe05faded49b1b0bed2f638a18
languageName: node
linkType: hard
"typescript@patch:typescript@npm%3A^5.9.2#optional!builtin<compat/typescript>":
version: 5.9.2
resolution: "typescript@patch:typescript@npm%3A5.9.2#optional!builtin<compat/typescript>::version=5.9.2&hash=5786d5"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
checksum: 10c0/34d2a8e23eb8e0d1875072064d5e1d9c102e0bdce56a10a25c0b917b8aa9001a9cf5c225df12497e99da107dc379360bc138163c66b55b95f5b105b50578067e
languageName: node
linkType: hard
"unicorn-magic@npm:^0.1.0":
version: 0.1.0
resolution: "unicorn-magic@npm:0.1.0"