Comparing version
700
index.js
@@ -1,439 +0,323 @@ | ||
"use strict"; | ||
/* tslint:disable */ | ||
/* eslint-disable */ | ||
/* prettier-ignore */ | ||
const { load, currentTarget } = require("@neon-rs/load"); | ||
const { familySync, GLIBC, MUSL } = require("detect-libc"); | ||
/* auto-generated by NAPI-RS */ | ||
function requireNative() { | ||
if (process.env.LIBSQL_JS_DEV) { | ||
return load(__dirname) | ||
} | ||
let target = currentTarget(); | ||
// Workaround for Bun, which reports a musl target, but really wants glibc... | ||
if (familySync() == GLIBC) { | ||
switch (target) { | ||
case "linux-x64-musl": | ||
target = "linux-x64-gnu"; | ||
break; | ||
case "linux-arm64-musl": | ||
target = "linux-arm64-gnu"; | ||
break; | ||
} | ||
} | ||
// @neon-rs/load doesn't detect arm musl | ||
if (target === "linux-arm-gnueabihf" && familySync() == MUSL) { | ||
target = "linux-arm-musleabihf"; | ||
} | ||
return require(`@libsql/${target}`); | ||
} | ||
const { existsSync, readFileSync } = require('fs') | ||
const { join } = require('path') | ||
const { | ||
databaseOpen, | ||
databaseOpenWithSync, | ||
databaseInTransaction, | ||
databaseInterrupt, | ||
databaseClose, | ||
databaseSyncSync, | ||
databaseSyncUntilSync, | ||
databaseExecSync, | ||
databasePrepareSync, | ||
databaseDefaultSafeIntegers, | ||
databaseAuthorizer, | ||
databaseLoadExtension, | ||
databaseMaxWriteReplicationIndex, | ||
statementRaw, | ||
statementIsReader, | ||
statementGet, | ||
statementRun, | ||
statementInterrupt, | ||
statementRowsSync, | ||
statementColumns, | ||
statementSafeIntegers, | ||
rowsNext, | ||
} = requireNative(); | ||
const { platform, arch } = process | ||
const Authorization = require("./auth"); | ||
const SqliteError = require("./sqlite-error"); | ||
let nativeBinding = null | ||
let localFileExisted = false | ||
let loadError = null | ||
function convertError(err) { | ||
if (err.libsqlError) { | ||
return new SqliteError(err.message, err.code, err.rawCode); | ||
function isMusl() { | ||
// For Node 10 | ||
if (!process.report || typeof process.report.getReport !== 'function') { | ||
try { | ||
const lddPath = require('child_process').execSync('which ldd').toString().trim() | ||
return readFileSync(lddPath, 'utf8').includes('musl') | ||
} catch (e) { | ||
return true | ||
} | ||
} else { | ||
const { glibcVersionRuntime } = process.report.getReport().header | ||
return !glibcVersionRuntime | ||
} | ||
return err; | ||
} | ||
/** | ||
* Database represents a connection that can prepare and execute SQL statements. | ||
*/ | ||
class Database { | ||
/** | ||
* Creates a new database connection. If the database file pointed to by `path` does not exists, it will be created. | ||
* | ||
* @constructor | ||
* @param {string} path - Path to the database file. | ||
*/ | ||
constructor(path, opts) { | ||
const encryptionCipher = opts?.encryptionCipher ?? "aes256cbc"; | ||
if (opts && opts.syncUrl) { | ||
var authToken = ""; | ||
if (opts.syncAuth) { | ||
console.warn("Warning: The `syncAuth` option is deprecated, please use `authToken` option instead."); | ||
authToken = opts.syncAuth; | ||
} else if (opts.authToken) { | ||
authToken = opts.authToken; | ||
} | ||
const encryptionKey = opts?.encryptionKey ?? ""; | ||
const syncPeriod = opts?.syncPeriod ?? 0.0; | ||
const readYourWrites = opts?.readYourWrites ?? true; | ||
const offline = opts?.offline ?? false; | ||
this.db = databaseOpenWithSync(path, opts.syncUrl, authToken, encryptionCipher, encryptionKey, syncPeriod, readYourWrites, offline); | ||
} else { | ||
const authToken = opts?.authToken ?? ""; | ||
const encryptionKey = opts?.encryptionKey ?? ""; | ||
const timeout = opts?.timeout ?? 0.0; | ||
this.db = databaseOpen(path, authToken, encryptionCipher, encryptionKey, timeout); | ||
} | ||
// TODO: Use a libSQL API for this? | ||
this.memory = path === ":memory:"; | ||
this.readonly = false; | ||
this.name = ""; | ||
this.open = true; | ||
const db = this.db; | ||
Object.defineProperties(this, { | ||
inTransaction: { | ||
get() { | ||
return databaseInTransaction(db); | ||
switch (platform) { | ||
case 'android': | ||
switch (arch) { | ||
case 'arm64': | ||
localFileExisted = existsSync(join(__dirname, 'libsql.android-arm64.node')) | ||
try { | ||
if (localFileExisted) { | ||
nativeBinding = require('./libsql.android-arm64.node') | ||
} else { | ||
nativeBinding = require('libsql-android-arm64') | ||
} | ||
} catch (e) { | ||
loadError = e | ||
} | ||
}, | ||
}); | ||
} | ||
sync() { | ||
return databaseSyncSync.call(this.db); | ||
} | ||
syncUntil(replicationIndex) { | ||
return databaseSyncUntilSync.call(this.db, replicationIndex); | ||
} | ||
/** | ||
* Prepares a SQL statement for execution. | ||
* | ||
* @param {string} sql - The SQL statement string to prepare. | ||
*/ | ||
prepare(sql) { | ||
try { | ||
const stmt = databasePrepareSync.call(this.db, sql); | ||
return new Statement(stmt); | ||
} catch (err) { | ||
throw convertError(err); | ||
break | ||
case 'arm': | ||
localFileExisted = existsSync(join(__dirname, 'libsql.android-arm-eabi.node')) | ||
try { | ||
if (localFileExisted) { | ||
nativeBinding = require('./libsql.android-arm-eabi.node') | ||
} else { | ||
nativeBinding = require('libsql-android-arm-eabi') | ||
} | ||
} catch (e) { | ||
loadError = e | ||
} | ||
break | ||
default: | ||
throw new Error(`Unsupported architecture on Android ${arch}`) | ||
} | ||
} | ||
/** | ||
* Returns a function that executes the given function in a transaction. | ||
* | ||
* @param {function} fn - The function to wrap in a transaction. | ||
*/ | ||
transaction(fn) { | ||
if (typeof fn !== "function") | ||
throw new TypeError("Expected first argument to be a function"); | ||
const db = this; | ||
const wrapTxn = (mode) => { | ||
return (...bindParameters) => { | ||
db.exec("BEGIN " + mode); | ||
break | ||
case 'win32': | ||
switch (arch) { | ||
case 'x64': | ||
localFileExisted = existsSync( | ||
join(__dirname, 'libsql.win32-x64-msvc.node') | ||
) | ||
try { | ||
const result = fn(...bindParameters); | ||
db.exec("COMMIT"); | ||
return result; | ||
} catch (err) { | ||
db.exec("ROLLBACK"); | ||
throw err; | ||
if (localFileExisted) { | ||
nativeBinding = require('./libsql.win32-x64-msvc.node') | ||
} else { | ||
nativeBinding = require('libsql-win32-x64-msvc') | ||
} | ||
} catch (e) { | ||
loadError = e | ||
} | ||
}; | ||
}; | ||
const properties = { | ||
default: { value: wrapTxn("") }, | ||
deferred: { value: wrapTxn("DEFERRED") }, | ||
immediate: { value: wrapTxn("IMMEDIATE") }, | ||
exclusive: { value: wrapTxn("EXCLUSIVE") }, | ||
database: { value: this, enumerable: true }, | ||
}; | ||
Object.defineProperties(properties.default.value, properties); | ||
Object.defineProperties(properties.deferred.value, properties); | ||
Object.defineProperties(properties.immediate.value, properties); | ||
Object.defineProperties(properties.exclusive.value, properties); | ||
return properties.default.value; | ||
} | ||
pragma(source, options) { | ||
if (options == null) options = {}; | ||
if (typeof source !== 'string') throw new TypeError('Expected first argument to be a string'); | ||
if (typeof options !== 'object') throw new TypeError('Expected second argument to be an options object'); | ||
const simple = options['simple']; | ||
const stmt = this.prepare(`PRAGMA ${source}`, this, true); | ||
return simple ? stmt.pluck().get() : stmt.all(); | ||
} | ||
backup(filename, options) { | ||
throw new Error("not implemented"); | ||
} | ||
serialize(options) { | ||
throw new Error("not implemented"); | ||
} | ||
function(name, options, fn) { | ||
// Apply defaults | ||
if (options == null) options = {}; | ||
if (typeof options === "function") { | ||
fn = options; | ||
options = {}; | ||
break | ||
case 'ia32': | ||
localFileExisted = existsSync( | ||
join(__dirname, 'libsql.win32-ia32-msvc.node') | ||
) | ||
try { | ||
if (localFileExisted) { | ||
nativeBinding = require('./libsql.win32-ia32-msvc.node') | ||
} else { | ||
nativeBinding = require('libsql-win32-ia32-msvc') | ||
} | ||
} catch (e) { | ||
loadError = e | ||
} | ||
break | ||
case 'arm64': | ||
localFileExisted = existsSync( | ||
join(__dirname, 'libsql.win32-arm64-msvc.node') | ||
) | ||
try { | ||
if (localFileExisted) { | ||
nativeBinding = require('./libsql.win32-arm64-msvc.node') | ||
} else { | ||
nativeBinding = require('libsql-win32-arm64-msvc') | ||
} | ||
} catch (e) { | ||
loadError = e | ||
} | ||
break | ||
default: | ||
throw new Error(`Unsupported architecture on Windows: ${arch}`) | ||
} | ||
// Validate arguments | ||
if (typeof name !== "string") | ||
throw new TypeError("Expected first argument to be a string"); | ||
if (typeof fn !== "function") | ||
throw new TypeError("Expected last argument to be a function"); | ||
if (typeof options !== "object") | ||
throw new TypeError("Expected second argument to be an options object"); | ||
if (!name) | ||
throw new TypeError( | ||
"User-defined function name cannot be an empty string" | ||
); | ||
throw new Error("not implemented"); | ||
} | ||
aggregate(name, options) { | ||
// Validate arguments | ||
if (typeof name !== "string") | ||
throw new TypeError("Expected first argument to be a string"); | ||
if (typeof options !== "object" || options === null) | ||
throw new TypeError("Expected second argument to be an options object"); | ||
if (!name) | ||
throw new TypeError( | ||
"User-defined function name cannot be an empty string" | ||
); | ||
throw new Error("not implemented"); | ||
} | ||
table(name, factory) { | ||
// Validate arguments | ||
if (typeof name !== "string") | ||
throw new TypeError("Expected first argument to be a string"); | ||
if (!name) | ||
throw new TypeError( | ||
"Virtual table module name cannot be an empty string" | ||
); | ||
throw new Error("not implemented"); | ||
} | ||
authorizer(rules) { | ||
databaseAuthorizer.call(this.db, rules); | ||
} | ||
loadExtension(...args) { | ||
databaseLoadExtension.call(this.db, ...args); | ||
} | ||
maxWriteReplicationIndex() { | ||
return databaseMaxWriteReplicationIndex.call(this.db) | ||
} | ||
/** | ||
* Executes a SQL statement. | ||
* | ||
* @param {string} sql - The SQL statement string to execute. | ||
*/ | ||
exec(sql) { | ||
break | ||
case 'darwin': | ||
localFileExisted = existsSync(join(__dirname, 'libsql.darwin-universal.node')) | ||
try { | ||
databaseExecSync.call(this.db, sql); | ||
} catch (err) { | ||
throw convertError(err); | ||
} | ||
} | ||
/** | ||
* Interrupts the database connection. | ||
*/ | ||
interrupt() { | ||
databaseInterrupt.call(this.db); | ||
} | ||
/** | ||
* Closes the database connection. | ||
*/ | ||
close() { | ||
databaseClose.call(this.db); | ||
this.open = false; | ||
} | ||
/** | ||
* Toggle 64-bit integer support. | ||
*/ | ||
defaultSafeIntegers(toggle) { | ||
databaseDefaultSafeIntegers.call(this.db, toggle ?? true); | ||
return this; | ||
} | ||
unsafeMode(...args) { | ||
throw new Error("not implemented"); | ||
} | ||
} | ||
/** | ||
* Statement represents a prepared SQL statement that can be executed. | ||
*/ | ||
class Statement { | ||
constructor(stmt) { | ||
this.stmt = stmt; | ||
this.pluckMode = false; | ||
} | ||
/** | ||
* Toggle raw mode. | ||
* | ||
* @param raw Enable or disable raw mode. If you don't pass the parameter, raw mode is enabled. | ||
*/ | ||
raw(raw) { | ||
statementRaw.call(this.stmt, raw ?? true); | ||
return this; | ||
} | ||
/** | ||
* Toggle pluck mode. | ||
* | ||
* @param pluckMode Enable or disable pluck mode. If you don't pass the parameter, pluck mode is enabled. | ||
*/ | ||
pluck(pluckMode) { | ||
this.pluckMode = pluckMode ?? true; | ||
return this; | ||
} | ||
get reader() { | ||
return statementIsReader.call(this.stmt); | ||
} | ||
/** | ||
* Executes the SQL statement and returns an info object. | ||
*/ | ||
run(...bindParameters) { | ||
try { | ||
if (bindParameters.length == 1 && typeof bindParameters[0] === "object") { | ||
return statementRun.call(this.stmt, bindParameters[0]); | ||
if (localFileExisted) { | ||
nativeBinding = require('./libsql.darwin-universal.node') | ||
} else { | ||
return statementRun.call(this.stmt, bindParameters.flat()); | ||
nativeBinding = require('libsql-darwin-universal') | ||
} | ||
} catch (err) { | ||
throw convertError(err); | ||
break | ||
} catch {} | ||
switch (arch) { | ||
case 'x64': | ||
localFileExisted = existsSync(join(__dirname, 'libsql.darwin-x64.node')) | ||
try { | ||
if (localFileExisted) { | ||
nativeBinding = require('./libsql.darwin-x64.node') | ||
} else { | ||
nativeBinding = require('libsql-darwin-x64') | ||
} | ||
} catch (e) { | ||
loadError = e | ||
} | ||
break | ||
case 'arm64': | ||
localFileExisted = existsSync( | ||
join(__dirname, 'libsql.darwin-arm64.node') | ||
) | ||
try { | ||
if (localFileExisted) { | ||
nativeBinding = require('./libsql.darwin-arm64.node') | ||
} else { | ||
nativeBinding = require('libsql-darwin-arm64') | ||
} | ||
} catch (e) { | ||
loadError = e | ||
} | ||
break | ||
default: | ||
throw new Error(`Unsupported architecture on macOS: ${arch}`) | ||
} | ||
} | ||
/** | ||
* Executes the SQL statement and returns the first row. | ||
* | ||
* @param bindParameters - The bind parameters for executing the statement. | ||
*/ | ||
get(...bindParameters) { | ||
break | ||
case 'freebsd': | ||
if (arch !== 'x64') { | ||
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`) | ||
} | ||
localFileExisted = existsSync(join(__dirname, 'libsql.freebsd-x64.node')) | ||
try { | ||
if (bindParameters.length == 1 && typeof bindParameters[0] === "object") { | ||
return statementGet.call(this.stmt, bindParameters[0]); | ||
if (localFileExisted) { | ||
nativeBinding = require('./libsql.freebsd-x64.node') | ||
} else { | ||
return statementGet.call(this.stmt, bindParameters.flat()); | ||
nativeBinding = require('libsql-freebsd-x64') | ||
} | ||
} catch (err) { | ||
throw convertError(err); | ||
} catch (e) { | ||
loadError = e | ||
} | ||
} | ||
/** | ||
* Executes the SQL statement and returns an iterator to the resulting rows. | ||
* | ||
* @param bindParameters - The bind parameters for executing the statement. | ||
*/ | ||
iterate(...bindParameters) { | ||
var rows = undefined; | ||
if (bindParameters.length == 1 && typeof bindParameters[0] === "object") { | ||
rows = statementRowsSync.call(this.stmt, bindParameters[0]); | ||
} else { | ||
rows = statementRowsSync.call(this.stmt, bindParameters.flat()); | ||
} | ||
const iter = { | ||
nextRows: Array(100), | ||
nextRowIndex: 100, | ||
next() { | ||
try { | ||
if (this.nextRowIndex === 100) { | ||
rowsNext.call(rows, this.nextRows); | ||
this.nextRowIndex = 0; | ||
break | ||
case 'linux': | ||
switch (arch) { | ||
case 'x64': | ||
if (isMusl()) { | ||
localFileExisted = existsSync( | ||
join(__dirname, 'libsql.linux-x64-musl.node') | ||
) | ||
try { | ||
if (localFileExisted) { | ||
nativeBinding = require('./libsql.linux-x64-musl.node') | ||
} else { | ||
nativeBinding = require('libsql-linux-x64-musl') | ||
} | ||
} catch (e) { | ||
loadError = e | ||
} | ||
const row = this.nextRows[this.nextRowIndex]; | ||
this.nextRows[this.nextRowIndex] = undefined; | ||
if (!row) { | ||
return { done: true }; | ||
} else { | ||
localFileExisted = existsSync( | ||
join(__dirname, 'libsql.linux-x64-gnu.node') | ||
) | ||
try { | ||
if (localFileExisted) { | ||
nativeBinding = require('./libsql.linux-x64-gnu.node') | ||
} else { | ||
nativeBinding = require('libsql-linux-x64-gnu') | ||
} | ||
} catch (e) { | ||
loadError = e | ||
} | ||
this.nextRowIndex++; | ||
return { value: row, done: false }; | ||
} catch (err) { | ||
throw convertError(err); | ||
} | ||
}, | ||
[Symbol.iterator]() { | ||
return this; | ||
}, | ||
}; | ||
return iter; | ||
} | ||
/** | ||
* Executes the SQL statement and returns an array of the resulting rows. | ||
* | ||
* @param bindParameters - The bind parameters for executing the statement. | ||
*/ | ||
all(...bindParameters) { | ||
try { | ||
const result = []; | ||
for (const row of this.iterate(...bindParameters)) { | ||
if (this.pluckMode) { | ||
result.push(row[Object.keys(row)[0]]); | ||
break | ||
case 'arm64': | ||
if (isMusl()) { | ||
localFileExisted = existsSync( | ||
join(__dirname, 'libsql.linux-arm64-musl.node') | ||
) | ||
try { | ||
if (localFileExisted) { | ||
nativeBinding = require('./libsql.linux-arm64-musl.node') | ||
} else { | ||
nativeBinding = require('libsql-linux-arm64-musl') | ||
} | ||
} catch (e) { | ||
loadError = e | ||
} | ||
} else { | ||
result.push(row); | ||
localFileExisted = existsSync( | ||
join(__dirname, 'libsql.linux-arm64-gnu.node') | ||
) | ||
try { | ||
if (localFileExisted) { | ||
nativeBinding = require('./libsql.linux-arm64-gnu.node') | ||
} else { | ||
nativeBinding = require('libsql-linux-arm64-gnu') | ||
} | ||
} catch (e) { | ||
loadError = e | ||
} | ||
} | ||
} | ||
return result; | ||
} catch (err) { | ||
throw convertError(err); | ||
break | ||
case 'arm': | ||
if (isMusl()) { | ||
localFileExisted = existsSync( | ||
join(__dirname, 'libsql.linux-arm-musleabihf.node') | ||
) | ||
try { | ||
if (localFileExisted) { | ||
nativeBinding = require('./libsql.linux-arm-musleabihf.node') | ||
} else { | ||
nativeBinding = require('libsql-linux-arm-musleabihf') | ||
} | ||
} catch (e) { | ||
loadError = e | ||
} | ||
} else { | ||
localFileExisted = existsSync( | ||
join(__dirname, 'libsql.linux-arm-gnueabihf.node') | ||
) | ||
try { | ||
if (localFileExisted) { | ||
nativeBinding = require('./libsql.linux-arm-gnueabihf.node') | ||
} else { | ||
nativeBinding = require('libsql-linux-arm-gnueabihf') | ||
} | ||
} catch (e) { | ||
loadError = e | ||
} | ||
} | ||
break | ||
case 'riscv64': | ||
if (isMusl()) { | ||
localFileExisted = existsSync( | ||
join(__dirname, 'libsql.linux-riscv64-musl.node') | ||
) | ||
try { | ||
if (localFileExisted) { | ||
nativeBinding = require('./libsql.linux-riscv64-musl.node') | ||
} else { | ||
nativeBinding = require('libsql-linux-riscv64-musl') | ||
} | ||
} catch (e) { | ||
loadError = e | ||
} | ||
} else { | ||
localFileExisted = existsSync( | ||
join(__dirname, 'libsql.linux-riscv64-gnu.node') | ||
) | ||
try { | ||
if (localFileExisted) { | ||
nativeBinding = require('./libsql.linux-riscv64-gnu.node') | ||
} else { | ||
nativeBinding = require('libsql-linux-riscv64-gnu') | ||
} | ||
} catch (e) { | ||
loadError = e | ||
} | ||
} | ||
break | ||
case 's390x': | ||
localFileExisted = existsSync( | ||
join(__dirname, 'libsql.linux-s390x-gnu.node') | ||
) | ||
try { | ||
if (localFileExisted) { | ||
nativeBinding = require('./libsql.linux-s390x-gnu.node') | ||
} else { | ||
nativeBinding = require('libsql-linux-s390x-gnu') | ||
} | ||
} catch (e) { | ||
loadError = e | ||
} | ||
break | ||
default: | ||
throw new Error(`Unsupported architecture on Linux: ${arch}`) | ||
} | ||
} | ||
break | ||
default: | ||
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`) | ||
} | ||
/** | ||
* Interrupts the statement. | ||
*/ | ||
interrupt() { | ||
statementInterrupt.call(this.stmt); | ||
if (!nativeBinding) { | ||
if (loadError) { | ||
throw loadError | ||
} | ||
throw new Error(`Failed to load native binding`) | ||
} | ||
/** | ||
* Returns the columns in the result set returned by this prepared statement. | ||
*/ | ||
columns() { | ||
return statementColumns.call(this.stmt); | ||
} | ||
const { SqliteError, Database, databasePrepareSync, databaseSyncSync, Statement, statementIterateSync, RowsIterator, iteratorNextSync, Record } = nativeBinding | ||
/** | ||
* Toggle 64-bit integer support. | ||
*/ | ||
safeIntegers(toggle) { | ||
statementSafeIntegers.call(this.stmt, toggle ?? true); | ||
return this; | ||
} | ||
} | ||
module.exports = Database; | ||
module.exports.Authorization = Authorization; | ||
module.exports.SqliteError = SqliteError; | ||
module.exports.SqliteError = SqliteError | ||
module.exports.Database = Database | ||
module.exports.databasePrepareSync = databasePrepareSync | ||
module.exports.databaseSyncSync = databaseSyncSync | ||
module.exports.Statement = Statement | ||
module.exports.statementIterateSync = statementIterateSync | ||
module.exports.RowsIterator = RowsIterator | ||
module.exports.iteratorNextSync = iteratorNextSync | ||
module.exports.Record = Record |
109
package.json
{ | ||
"name": "libsql", | ||
"version": "0.5.13", | ||
"version": "0.6.0-pre.1", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/tursodatabase/libsql-js" | ||
}, | ||
"description": "A better-sqlite3 compatible API for libSQL that supports Bun, Deno, and Node", | ||
@@ -16,78 +20,55 @@ "os": [ | ||
], | ||
"main": "index.js", | ||
"types": "types/index.d.ts", | ||
"files": [ | ||
"auth.js", | ||
"index.js", | ||
"sqlite-error.js", | ||
"promise.js", | ||
"types/index.d.ts", | ||
"types/promise.d.ts" | ||
], | ||
"main": "wrapper.js", | ||
"types": "index.d.ts", | ||
"exports": { | ||
".": { | ||
"types": "./types/index.d.ts", | ||
"default": "./index.js" | ||
"default": "./wrapper.js", | ||
"types": "./index.d.ts" | ||
}, | ||
"./promise": { | ||
"types": "./types/promise.d.ts", | ||
"default": "./promise.js" | ||
"default": "./promise.js", | ||
"types": "./promise.d.ts" | ||
} | ||
}, | ||
"scripts": { | ||
"test": "cargo test", | ||
"debug": "cargo build --message-format=json | npm exec neon dist", | ||
"build": "npx tsc && cargo build --message-format=json --release | npm exec neon dist -- --name libsql-js", | ||
"cross": "cross build --message-format=json --release | npm exec neon dist -- --name libsql-js -m /target", | ||
"pack-build": "neon pack-build", | ||
"prepack": "neon install-builds", | ||
"postversion": "git push --follow-tags" | ||
"napi": { | ||
"name": "libsql", | ||
"triples": { | ||
"additional": [ | ||
"aarch64-apple-darwin", | ||
"aarch64-unknown-linux-gnu", | ||
"aarch64-unknown-linux-musl", | ||
"x86_64-unknown-linux-musl" | ||
] | ||
} | ||
}, | ||
"author": "Pekka Enberg <penberg@iki.fi>", | ||
"license": "MIT", | ||
"neon": { | ||
"type": "source", | ||
"org": "@libsql", | ||
"targets": { | ||
"darwin-arm64": "aarch64-apple-darwin", | ||
"linux-arm64-gnu": "aarch64-unknown-linux-gnu", | ||
"linux-arm64-musl": "aarch64-unknown-linux-musl", | ||
"darwin-x64": "x86_64-apple-darwin", | ||
"win32-x64-msvc": "x86_64-pc-windows-msvc", | ||
"linux-x64-gnu": "x86_64-unknown-linux-gnu", | ||
"linux-x64-musl": "x86_64-unknown-linux-musl", | ||
"linux-arm-gnueabihf": "arm-unknown-linux-gnueabihf", | ||
"linux-arm-musleabihf": "arm-unknown-linux-musleabihf" | ||
} | ||
"devDependencies": { | ||
"@napi-rs/cli": "^2.18.4", | ||
"ava": "^6.0.1" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/tursodatabase/libsql-js.git" | ||
"ava": { | ||
"timeout": "3m" | ||
}, | ||
"keywords": [ | ||
"libsql" | ||
], | ||
"bugs": { | ||
"url": "https://github.com/tursodatabase/libsql-js/issues" | ||
"engines": { | ||
"node": ">= 10" | ||
}, | ||
"homepage": "https://github.com/tursodatabase/libsql-js", | ||
"devDependencies": { | ||
"@neon-rs/cli": "^0.0.165", | ||
"typescript": "^5.4.5" | ||
"scripts": { | ||
"artifacts": "napi artifacts", | ||
"build": "napi build --platform --release", | ||
"build:debug": "napi build --platform", | ||
"prepublishOnly": "napi prepublish -t npm", | ||
"test": "cd integration-tests && npm i && npm run test", | ||
"universal": "napi universal", | ||
"version": "napi version" | ||
}, | ||
"dependencies": { | ||
"@neon-rs/load": "^0.0.4", | ||
"detect-libc": "2.0.2" | ||
}, | ||
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e", | ||
"optionalDependencies": { | ||
"@libsql/darwin-arm64": "0.5.13", | ||
"@libsql/darwin-x64": "0.5.13", | ||
"@libsql/linux-arm-gnueabihf": "0.5.13", | ||
"@libsql/linux-arm-musleabihf": "0.5.13", | ||
"@libsql/linux-arm64-gnu": "0.5.13", | ||
"@libsql/linux-arm64-musl": "0.5.13", | ||
"@libsql/linux-x64-gnu": "0.5.13", | ||
"@libsql/linux-x64-musl": "0.5.13", | ||
"@libsql/win32-x64-msvc": "0.5.13" | ||
"libsql-win32-x64-msvc": "0.6.0-pre.1", | ||
"libsql-darwin-x64": "0.6.0-pre.1", | ||
"libsql-linux-x64-gnu": "0.6.0-pre.1", | ||
"libsql-darwin-arm64": "0.6.0-pre.1", | ||
"libsql-linux-arm64-gnu": "0.6.0-pre.1", | ||
"libsql-linux-arm64-musl": "0.6.0-pre.1", | ||
"libsql-linux-x64-musl": "0.6.0-pre.1" | ||
} | ||
} | ||
} |
318
promise.js
"use strict"; | ||
const { load, currentTarget } = require("@neon-rs/load"); | ||
const { familySync, GLIBC, MUSL } = require("detect-libc"); | ||
// Static requires for bundlers. | ||
if (0) { | ||
require("./.targets"); | ||
} | ||
const { Database: NativeDb } = require("./index.js"); | ||
const SqliteError = require("./sqlite-error.js"); | ||
const Authorization = require("./auth"); | ||
const SqliteError = require("./sqlite-error"); | ||
function convertError(err) { | ||
if (err.libsqlError) { | ||
return new SqliteError(err.message, err.code, err.rawCode); | ||
// Handle errors from Rust with JSON-encoded message | ||
if (typeof err.message === 'string') { | ||
try { | ||
const data = JSON.parse(err.message); | ||
if (data && data.libsqlError) { | ||
if (data.code === "SQLITE_AUTH") { | ||
// For SQLITE_AUTH, preserve the JSON string for the test | ||
return new SqliteError(err.message, data.code, data.rawCode); | ||
} else if (data.code === "SQLITE_NOTOPEN") { | ||
// Convert SQLITE_NOTOPEN to TypeError with expected message | ||
return new TypeError("The database connection is not open"); | ||
} else { | ||
// For all other errors, use the plain message string | ||
return new SqliteError(data.message, data.code, data.rawCode); | ||
} | ||
} | ||
} catch (_) { | ||
// Not JSON, ignore | ||
} | ||
} | ||
@@ -21,50 +31,2 @@ return err; | ||
function requireNative() { | ||
if (process.env.LIBSQL_JS_DEV) { | ||
return load(__dirname) | ||
} | ||
let target = currentTarget(); | ||
// Workaround for Bun, which reports a musl target, but really wants glibc... | ||
if (familySync() == GLIBC) { | ||
switch (target) { | ||
case "linux-x64-musl": | ||
target = "linux-x64-gnu"; | ||
break; | ||
case "linux-arm64-musl": | ||
target = "linux-arm64-gnu"; | ||
break; | ||
} | ||
} | ||
// @neon-rs/load doesn't detect arm musl | ||
if (target === "linux-arm-gnueabihf" && familySync() == MUSL) { | ||
target = "linux-arm-musleabihf"; | ||
} | ||
return require(`@libsql/${target}`); | ||
} | ||
const { | ||
databaseOpen, | ||
databaseOpenWithSync, | ||
databaseInTransaction, | ||
databaseInterrupt, | ||
databaseClose, | ||
databaseSyncAsync, | ||
databaseSyncUntilAsync, | ||
databaseExecAsync, | ||
databasePrepareAsync, | ||
databaseMaxWriteReplicationIndex, | ||
databaseDefaultSafeIntegers, | ||
databaseAuthorizer, | ||
databaseLoadExtension, | ||
statementRaw, | ||
statementIsReader, | ||
statementGet, | ||
statementRun, | ||
statementInterrupt, | ||
statementRowsAsync, | ||
statementColumns, | ||
statementSafeIntegers, | ||
rowsNext, | ||
} = requireNative(); | ||
/** | ||
@@ -81,27 +43,4 @@ * Database represents a connection that can prepare and execute SQL statements. | ||
constructor(path, opts) { | ||
const encryptionCipher = opts?.encryptionCipher ?? "aes256cbc"; | ||
if (opts && opts.syncUrl) { | ||
var authToken = ""; | ||
if (opts.syncAuth) { | ||
console.warn("Warning: The `syncAuth` option is deprecated, please use `authToken` option instead."); | ||
authToken = opts.syncAuth; | ||
} else if (opts.authToken) { | ||
authToken = opts.authToken; | ||
} | ||
const encryptionKey = opts?.encryptionKey ?? ""; | ||
const syncPeriod = opts?.syncPeriod ?? 0.0; | ||
const offline = opts?.offline ?? false; | ||
this.db = databaseOpenWithSync(path, opts.syncUrl, authToken, encryptionCipher, encryptionKey, syncPeriod, offline); | ||
} else { | ||
const authToken = opts?.authToken ?? ""; | ||
const encryptionKey = opts?.encryptionKey ?? ""; | ||
const timeout = opts?.timeout ?? 0.0; | ||
this.db = databaseOpen(path, authToken, encryptionCipher, encryptionKey, timeout); | ||
} | ||
// TODO: Use a libSQL API for this? | ||
this.memory = path === ":memory:"; | ||
this.readonly = false; | ||
this.name = ""; | ||
this.open = true; | ||
this.db = new NativeDb(path, opts); | ||
this.memory = this.db.memory | ||
const db = this.db; | ||
@@ -111,3 +50,3 @@ Object.defineProperties(this, { | ||
get() { | ||
return databaseInTransaction(db); | ||
return db.inTransaction(); | ||
} | ||
@@ -119,7 +58,11 @@ }, | ||
sync() { | ||
return databaseSyncAsync.call(this.db); | ||
try { | ||
return this.db.sync(); | ||
} catch (err) { | ||
throw convertError(err); | ||
} | ||
} | ||
syncUntil(replicationIndex) { | ||
return databaseSyncUntilAsync.call(this.db, replicationIndex); | ||
throw new Error("not implemented"); | ||
} | ||
@@ -132,8 +75,9 @@ | ||
*/ | ||
prepare(sql) { | ||
return databasePrepareAsync.call(this.db, sql).then((stmt) => { | ||
async prepare(sql) { | ||
try { | ||
const stmt = await this.db.prepare(sql); | ||
return new Statement(stmt); | ||
}).catch((err) => { | ||
} catch (err) { | ||
throw convertError(err); | ||
}); | ||
} | ||
} | ||
@@ -152,10 +96,10 @@ | ||
const wrapTxn = (mode) => { | ||
return async (...bindParameters) => { | ||
await db.exec("BEGIN " + mode); | ||
return (...bindParameters) => { | ||
db.exec("BEGIN " + mode); | ||
try { | ||
const result = fn(...bindParameters); | ||
await db.exec("COMMIT"); | ||
db.exec("COMMIT"); | ||
return result; | ||
} catch (err) { | ||
await db.exec("ROLLBACK"); | ||
db.exec("ROLLBACK"); | ||
throw err; | ||
@@ -179,3 +123,3 @@ } | ||
pragma(source, options) { | ||
async pragma(source, options) { | ||
if (options == null) options = {}; | ||
@@ -185,5 +129,4 @@ if (typeof source !== 'string') throw new TypeError('Expected first argument to be a string'); | ||
const simple = options['simple']; | ||
return this.prepare(`PRAGMA ${source}`, this, true).then(async (stmt) => { | ||
return simple ? await stmt.pluck().get() : await stmt.all(); | ||
}); | ||
const stmt = await this.prepare(`PRAGMA ${source}`, this, true); | ||
return simple ? stmt.pluck().get() : stmt.all(); | ||
} | ||
@@ -200,21 +143,2 @@ | ||
function(name, options, fn) { | ||
// Apply defaults | ||
if (options == null) options = {}; | ||
if (typeof options === "function") { | ||
fn = options; | ||
options = {}; | ||
} | ||
// Validate arguments | ||
if (typeof name !== "string") | ||
throw new TypeError("Expected first argument to be a string"); | ||
if (typeof fn !== "function") | ||
throw new TypeError("Expected last argument to be a function"); | ||
if (typeof options !== "object") | ||
throw new TypeError("Expected second argument to be an options object"); | ||
if (!name) | ||
throw new TypeError( | ||
"User-defined function name cannot be an empty string" | ||
); | ||
throw new Error("not implemented"); | ||
@@ -224,12 +148,2 @@ } | ||
aggregate(name, options) { | ||
// Validate arguments | ||
if (typeof name !== "string") | ||
throw new TypeError("Expected first argument to be a string"); | ||
if (typeof options !== "object" || options === null) | ||
throw new TypeError("Expected second argument to be an options object"); | ||
if (!name) | ||
throw new TypeError( | ||
"User-defined function name cannot be an empty string" | ||
); | ||
throw new Error("not implemented"); | ||
@@ -239,10 +153,2 @@ } | ||
table(name, factory) { | ||
// Validate arguments | ||
if (typeof name !== "string") | ||
throw new TypeError("Expected first argument to be a string"); | ||
if (!name) | ||
throw new TypeError( | ||
"Virtual table module name cannot be an empty string" | ||
); | ||
throw new Error("not implemented"); | ||
@@ -252,11 +158,23 @@ } | ||
authorizer(rules) { | ||
databaseAuthorizer.call(this.db, rules); | ||
try { | ||
this.db.authorizer(rules); | ||
} catch (err) { | ||
throw convertError(err); | ||
} | ||
} | ||
loadExtension(...args) { | ||
databaseLoadExtension.call(this.db, ...args); | ||
try { | ||
this.db.loadExtension(...args); | ||
} catch (err) { | ||
throw convertError(err); | ||
} | ||
} | ||
maxWriteReplicationIndex() { | ||
return databaseMaxWriteReplicationIndex.call(this.db) | ||
try { | ||
return this.db.maxWriteReplicationIndex(); | ||
} catch (err) { | ||
throw convertError(err); | ||
} | ||
} | ||
@@ -270,5 +188,7 @@ | ||
exec(sql) { | ||
return databaseExecAsync.call(this.db, sql).catch((err) => { | ||
try { | ||
this.db.exec(sql); | ||
} catch (err) { | ||
throw convertError(err); | ||
}); | ||
} | ||
} | ||
@@ -280,3 +200,3 @@ | ||
interrupt() { | ||
databaseInterrupt.call(this.db); | ||
this.db.interrupt(); | ||
} | ||
@@ -288,5 +208,10 @@ | ||
close() { | ||
databaseClose.call(this.db); | ||
this.db.close(); | ||
} | ||
authorizer(hook) { | ||
this.db.authorizer(hook); | ||
return this; | ||
} | ||
/** | ||
@@ -296,3 +221,3 @@ * Toggle 64-bit integer support. | ||
defaultSafeIntegers(toggle) { | ||
databaseDefaultSafeIntegers.call(this.db, toggle ?? true); | ||
this.db.defaultSafeIntegers(toggle); | ||
return this; | ||
@@ -312,3 +237,2 @@ } | ||
this.stmt = stmt; | ||
this.pluckMode = false; | ||
} | ||
@@ -322,3 +246,3 @@ | ||
raw(raw) { | ||
statementRaw.call(this.stmt, raw ?? true); | ||
this.stmt.raw(raw); | ||
return this; | ||
@@ -333,8 +257,18 @@ } | ||
pluck(pluckMode) { | ||
this.pluckMode = pluckMode ?? true; | ||
this.stmt.pluck(pluckMode); | ||
return this; | ||
} | ||
/** | ||
* Toggle query timing. | ||
* | ||
* @param timing Enable or disable query timing. If you don't pass the parameter, query timing is enabled. | ||
*/ | ||
timing(timingMode) { | ||
this.stmt.timing(timingMode); | ||
return this; | ||
} | ||
get reader() { | ||
return statementIsReader.call(this.stmt); | ||
throw new Error("not implemented"); | ||
} | ||
@@ -347,7 +281,3 @@ | ||
try { | ||
if (bindParameters.length == 1 && typeof bindParameters[0] === "object") { | ||
return statementRun.call(this.stmt, bindParameters[0]); | ||
} else { | ||
return statementRun.call(this.stmt, bindParameters.flat()); | ||
} | ||
return this.stmt.run(...bindParameters); | ||
} catch (err) { | ||
@@ -365,9 +295,5 @@ throw convertError(err); | ||
try { | ||
if (bindParameters.length == 1 && typeof bindParameters[0] === "object") { | ||
return statementGet.call(this.stmt, bindParameters[0]); | ||
} else { | ||
return statementGet.call(this.stmt, bindParameters.flat()); | ||
} | ||
} catch (e) { | ||
throw convertError(e); | ||
return this.stmt.get(...bindParameters); | ||
} catch (err) { | ||
throw convertError(err); | ||
} | ||
@@ -382,34 +308,19 @@ } | ||
async iterate(...bindParameters) { | ||
var rows = undefined; | ||
if (bindParameters.length == 1 && typeof bindParameters[0] === "object") { | ||
rows = await statementRowsAsync.call(this.stmt, bindParameters[0]); | ||
} else { | ||
rows = await statementRowsAsync.call(this.stmt, bindParameters.flat()); | ||
try { | ||
const it = await this.stmt.iterate(...bindParameters); | ||
return { | ||
next() { | ||
return it.next(); | ||
}, | ||
[Symbol.asyncIterator]() { | ||
return { | ||
next() { | ||
return it.next(); | ||
} | ||
}; | ||
} | ||
}; | ||
} catch (err) { | ||
throw convertError(err); | ||
} | ||
const iter = { | ||
nextRows: Array(100), | ||
nextRowIndex: 100, | ||
next() { | ||
try { | ||
if (this.nextRowIndex === 100) { | ||
this.nextRows.fill(null); | ||
rowsNext.call(rows, this.nextRows); | ||
this.nextRowIndex = 0; | ||
} | ||
const row = this.nextRows[this.nextRowIndex]; | ||
this.nextRows[this.nextRowIndex] = null; | ||
if (!row) { | ||
return { done: true }; | ||
} | ||
this.nextRowIndex++; | ||
return { value: row, done: false }; | ||
} catch (e) { | ||
throw convertError(e); | ||
} | ||
}, | ||
[Symbol.iterator]() { | ||
return this; | ||
}, | ||
}; | ||
return iter; | ||
} | ||
@@ -425,13 +336,10 @@ | ||
const result = []; | ||
const it = await this.iterate(...bindParameters); | ||
for (const row of it) { | ||
if (this.pluckMode) { | ||
result.push(row[Object.keys(row)[0]]); | ||
} else { | ||
result.push(row); | ||
} | ||
const iterator = await this.iterate(...bindParameters); | ||
let next; | ||
while (!(next = await iterator.next()).done) { | ||
result.push(next.value); | ||
} | ||
return result; | ||
} catch (e) { | ||
throw convertError(e); | ||
} catch (err) { | ||
throw convertError(err); | ||
} | ||
@@ -444,3 +352,4 @@ } | ||
interrupt() { | ||
statementInterrupt.call(this.stmt); | ||
this.stmt.interrupt(); | ||
return this; | ||
} | ||
@@ -452,3 +361,3 @@ | ||
columns() { | ||
return statementColumns.call(this.stmt); | ||
return this.stmt.columns(); | ||
} | ||
@@ -460,10 +369,9 @@ | ||
safeIntegers(toggle) { | ||
statementSafeIntegers.call(this.stmt, toggle ?? true); | ||
this.stmt.safeIntegers(toggle); | ||
return this; | ||
} | ||
} | ||
module.exports = Database; | ||
module.exports.SqliteError = SqliteError; | ||
module.exports.Authorization = Authorization; | ||
module.exports.SqliteError = SqliteError; |
Native code
Supply chain riskContains native code (e.g., compiled binaries or shared libraries). Including native code can obscure malicious behavior.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
Shell access
Supply chain riskThis module accesses the system shell. Accessing the system shell increases the risk of executing arbitrary code.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 9 instances in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
Mixed license
License(Experimental) Package contains multiple licenses.
Found 1 instance in 1 package
No contributors or author data
MaintenancePackage does not specify a list of contributors or an author in package.json.
Found 1 instance in 1 package
No bug tracker
MaintenancePackage does not have a linked bug tracker in package.json.
Found 1 instance in 1 package
No website
QualityPackage does not have a website.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
Environment variable access
Supply chain riskPackage accesses environment variables, which may be a sign of credential stuffing or data theft.
Found 1 instance in 1 package
253790378
589918.08%7
-36.36%74
722.22%9178
779.96%1
Infinity%2
Infinity%2
100%20
400%23
Infinity%- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed
- Removed