Initial commit: New MoreminiMore website with fresh design
This commit is contained in:
126
node_modules/@libsql/client/README.md
generated
vendored
Normal file
126
node_modules/@libsql/client/README.md
generated
vendored
Normal file
@@ -0,0 +1,126 @@
|
||||
<p align="center">
|
||||
<a href="https://tur.so/turso-ts">
|
||||
<picture>
|
||||
<img src="/.github/cover.png" alt="libSQL TypeScript" />
|
||||
</picture>
|
||||
</a>
|
||||
<h1 align="center">libSQL TypeScript</h1>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
Databases for all TypeScript and JS multi-tenant apps.
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="https://tur.so/turso-ts"><strong>Turso</strong></a> ·
|
||||
<a href="https://docs.turso.tech"><strong>Docs</strong></a> ·
|
||||
<a href="https://docs.turso.tech/sdk/ts/quickstart"><strong>Quickstart</strong></a> ·
|
||||
<a href="https://docs.turso.tech/sdk/ts/reference"><strong>SDK Reference</strong></a> ·
|
||||
<a href="https://turso.tech/blog"><strong>Blog & Tutorials</strong></a>
|
||||
</p>
|
||||
|
||||
<p align="center">
|
||||
<a href="LICENSE">
|
||||
<picture>
|
||||
<img src="https://img.shields.io/github/license/tursodatabase/libsql-client-ts?color=0F624B" alt="MIT License" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://tur.so/discord-ts">
|
||||
<picture>
|
||||
<img src="https://img.shields.io/discord/933071162680958986?color=0F624B" alt="Discord" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="#contributors">
|
||||
<picture>
|
||||
<img src="https://img.shields.io/github/contributors/tursodatabase/libsql-client-ts?color=0F624B" alt="Contributors" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="https://www.npmjs.com/package/@libsql/client">
|
||||
<picture>
|
||||
<img src="https://img.shields.io/npm/dw/%40libsql%2Fclient?color=0F624B" alt="Weekly downloads" />
|
||||
</picture>
|
||||
</a>
|
||||
<a href="/examples">
|
||||
<picture>
|
||||
<img src="https://img.shields.io/badge/browse-examples-0F624B" alt="Examples" />
|
||||
</picture>
|
||||
</a>
|
||||
</p>
|
||||
|
||||
## Features
|
||||
|
||||
- 🔌 Works offline with [Embedded Replicas](https://docs.turso.tech/features/embedded-replicas/introduction)
|
||||
- 🌎 Works with remote Turso databases
|
||||
- ✨ Works with Turso [AI & Vector Search](https://docs.turso.tech/features/ai-and-embeddings)
|
||||
- 🔐 Supports [encryption at rest](https://docs.turso.tech/libsql#encryption-at-rest)
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install @libsql/client
|
||||
```
|
||||
|
||||
## Quickstart
|
||||
|
||||
The example below uses Embedded Replicas and syncs every minute from Turso.
|
||||
|
||||
```ts
|
||||
import { createClient } from "@libsql/client";
|
||||
|
||||
export const turso = createClient({
|
||||
url: "file:local.db",
|
||||
syncUrl: process.env.TURSO_DATABASE_URL,
|
||||
authToken: process.env.TURSO_AUTH_TOKEN,
|
||||
syncInterval: 60000,
|
||||
});
|
||||
|
||||
await turso.batch(
|
||||
[
|
||||
"CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT)",
|
||||
{
|
||||
sql: "INSERT INTO users(name) VALUES (?)",
|
||||
args: ["Iku"],
|
||||
},
|
||||
],
|
||||
"write",
|
||||
);
|
||||
|
||||
await turso.execute({
|
||||
sql: "SELECT * FROM users WHERE id = ?",
|
||||
args: [1],
|
||||
});
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
| Example | Description |
|
||||
| ------------------------------------- | --------------------------------------------------------------------------------------- |
|
||||
| [local](examples/local) | Uses libsql with a local SQLite file. Creates database, inserts data, and queries. |
|
||||
| [remote](examples/remote) | Connects to a remote database. Requires environment variables for URL and auth token. |
|
||||
| [sync](examples/sync) | Demonstrates synchronization between local and remote databases. |
|
||||
| [batch](examples/batch) | Executes multiple SQL statements in a single batch operation. |
|
||||
| [transactions](examples/transactions) | Shows transaction usage: starting, performing operations, and committing/rolling back. |
|
||||
| [memory](examples/memory) | Uses an in-memory SQLite database for temporary storage or fast access. |
|
||||
| [vector](examples/vector) | Works with vector embeddings, storing and querying for similarity search. |
|
||||
| [encryption](examples/encryption) | Creates and uses an encrypted SQLite database, demonstrating setup and data operations. |
|
||||
| [ollama](examples/ollama) | Similarity search with Ollama and Mistral. |
|
||||
|
||||
## Documentation
|
||||
|
||||
Visit our [official documentation](https://docs.turso.tech/sdk/ts).
|
||||
|
||||
## Support
|
||||
|
||||
Join us [on Discord](https://tur.so/discord-ts) to get help using this SDK. Report security issues [via email](mailto:security@turso.tech).
|
||||
|
||||
## Contributors
|
||||
|
||||
See the [contributing guide](CONTRIBUTING.md) to learn how to get involved.
|
||||
|
||||

|
||||
|
||||
<a href="https://github.com/tursodatabase/libsql-client-ts/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22">
|
||||
<picture>
|
||||
<img src="https://img.shields.io/github/issues-search/tursodatabase/libsql-client-ts?label=good%20first%20issue&query=label%3A%22good%20first%20issue%22%20&color=0F624B" alt="good first issue" />
|
||||
</picture>
|
||||
</a>
|
||||
341
node_modules/@libsql/client/lib-cjs/hrana.js
generated
vendored
Normal file
341
node_modules/@libsql/client/lib-cjs/hrana.js
generated
vendored
Normal file
@@ -0,0 +1,341 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.mapHranaError = exports.resultSetFromHrana = exports.stmtToHrana = exports.executeHranaBatch = exports.HranaTransaction = void 0;
|
||||
const hrana = __importStar(require("@libsql/hrana-client"));
|
||||
const api_1 = require("@libsql/core/api");
|
||||
const util_1 = require("@libsql/core/util");
|
||||
class HranaTransaction {
|
||||
#mode;
|
||||
#version;
|
||||
// Promise that is resolved when the BEGIN statement completes, or `undefined` if we haven't executed the
|
||||
// BEGIN statement yet.
|
||||
#started;
|
||||
/** @private */
|
||||
constructor(mode, version) {
|
||||
this.#mode = mode;
|
||||
this.#version = version;
|
||||
this.#started = undefined;
|
||||
}
|
||||
execute(stmt) {
|
||||
return this.batch([stmt]).then((results) => results[0]);
|
||||
}
|
||||
async batch(stmts) {
|
||||
const stream = this._getStream();
|
||||
if (stream.closed) {
|
||||
throw new api_1.LibsqlError("Cannot execute statements because the transaction is closed", "TRANSACTION_CLOSED");
|
||||
}
|
||||
try {
|
||||
const hranaStmts = stmts.map(stmtToHrana);
|
||||
let rowsPromises;
|
||||
if (this.#started === undefined) {
|
||||
// The transaction hasn't started yet, so we need to send the BEGIN statement in a batch with
|
||||
// `hranaStmts`.
|
||||
this._getSqlCache().apply(hranaStmts);
|
||||
const batch = stream.batch(this.#version >= 3);
|
||||
const beginStep = batch.step();
|
||||
const beginPromise = beginStep.run((0, util_1.transactionModeToBegin)(this.#mode));
|
||||
// Execute the `hranaStmts` only if the BEGIN succeeded, to make sure that we don't execute it
|
||||
// outside of a transaction.
|
||||
let lastStep = beginStep;
|
||||
rowsPromises = hranaStmts.map((hranaStmt) => {
|
||||
const stmtStep = batch
|
||||
.step()
|
||||
.condition(hrana.BatchCond.ok(lastStep));
|
||||
if (this.#version >= 3) {
|
||||
// If the Hrana version supports it, make sure that we are still in a transaction
|
||||
stmtStep.condition(hrana.BatchCond.not(hrana.BatchCond.isAutocommit(batch)));
|
||||
}
|
||||
const rowsPromise = stmtStep.query(hranaStmt);
|
||||
rowsPromise.catch(() => undefined); // silence Node warning
|
||||
lastStep = stmtStep;
|
||||
return rowsPromise;
|
||||
});
|
||||
// `this.#started` is resolved successfully only if the batch and the BEGIN statement inside
|
||||
// of the batch are both successful.
|
||||
this.#started = batch
|
||||
.execute()
|
||||
.then(() => beginPromise)
|
||||
.then(() => undefined);
|
||||
try {
|
||||
await this.#started;
|
||||
}
|
||||
catch (e) {
|
||||
// If the BEGIN failed, the transaction is unusable and we must close it. However, if the
|
||||
// BEGIN suceeds and `hranaStmts` fail, the transaction is _not_ closed.
|
||||
this.close();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this.#version < 3) {
|
||||
// The transaction has started, so we must wait until the BEGIN statement completed to make
|
||||
// sure that we don't execute `hranaStmts` outside of a transaction.
|
||||
await this.#started;
|
||||
}
|
||||
else {
|
||||
// The transaction has started, but we will use `hrana.BatchCond.isAutocommit()` to make
|
||||
// sure that we don't execute `hranaStmts` outside of a transaction, so we don't have to
|
||||
// wait for `this.#started`
|
||||
}
|
||||
this._getSqlCache().apply(hranaStmts);
|
||||
const batch = stream.batch(this.#version >= 3);
|
||||
let lastStep = undefined;
|
||||
rowsPromises = hranaStmts.map((hranaStmt) => {
|
||||
const stmtStep = batch.step();
|
||||
if (lastStep !== undefined) {
|
||||
stmtStep.condition(hrana.BatchCond.ok(lastStep));
|
||||
}
|
||||
if (this.#version >= 3) {
|
||||
stmtStep.condition(hrana.BatchCond.not(hrana.BatchCond.isAutocommit(batch)));
|
||||
}
|
||||
const rowsPromise = stmtStep.query(hranaStmt);
|
||||
rowsPromise.catch(() => undefined); // silence Node warning
|
||||
lastStep = stmtStep;
|
||||
return rowsPromise;
|
||||
});
|
||||
await batch.execute();
|
||||
}
|
||||
const resultSets = [];
|
||||
for (const rowsPromise of rowsPromises) {
|
||||
const rows = await rowsPromise;
|
||||
if (rows === undefined) {
|
||||
throw new api_1.LibsqlError("Statement in a transaction was not executed, " +
|
||||
"probably because the transaction has been rolled back", "TRANSACTION_CLOSED");
|
||||
}
|
||||
resultSets.push(resultSetFromHrana(rows));
|
||||
}
|
||||
return resultSets;
|
||||
}
|
||||
catch (e) {
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
}
|
||||
async executeMultiple(sql) {
|
||||
const stream = this._getStream();
|
||||
if (stream.closed) {
|
||||
throw new api_1.LibsqlError("Cannot execute statements because the transaction is closed", "TRANSACTION_CLOSED");
|
||||
}
|
||||
try {
|
||||
if (this.#started === undefined) {
|
||||
// If the transaction hasn't started yet, start it now
|
||||
this.#started = stream
|
||||
.run((0, util_1.transactionModeToBegin)(this.#mode))
|
||||
.then(() => undefined);
|
||||
try {
|
||||
await this.#started;
|
||||
}
|
||||
catch (e) {
|
||||
this.close();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Wait until the transaction has started
|
||||
await this.#started;
|
||||
}
|
||||
await stream.sequence(sql);
|
||||
}
|
||||
catch (e) {
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
}
|
||||
async rollback() {
|
||||
try {
|
||||
const stream = this._getStream();
|
||||
if (stream.closed) {
|
||||
return;
|
||||
}
|
||||
if (this.#started !== undefined) {
|
||||
// We don't have to wait for the BEGIN statement to complete. If the BEGIN fails, we will
|
||||
// execute a ROLLBACK outside of an active transaction, which should be harmless.
|
||||
}
|
||||
else {
|
||||
// We did nothing in the transaction, so there is nothing to rollback.
|
||||
return;
|
||||
}
|
||||
// Pipeline the ROLLBACK statement and the stream close.
|
||||
const promise = stream.run("ROLLBACK").catch((e) => {
|
||||
throw mapHranaError(e);
|
||||
});
|
||||
stream.closeGracefully();
|
||||
await promise;
|
||||
}
|
||||
catch (e) {
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
finally {
|
||||
// `this.close()` may close the `hrana.Client`, which aborts all pending stream requests, so we
|
||||
// must call it _after_ we receive the ROLLBACK response.
|
||||
// Also note that the current stream should already be closed, but we need to call `this.close()`
|
||||
// anyway, because it may need to do more cleanup.
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
async commit() {
|
||||
// (this method is analogous to `rollback()`)
|
||||
try {
|
||||
const stream = this._getStream();
|
||||
if (stream.closed) {
|
||||
throw new api_1.LibsqlError("Cannot commit the transaction because it is already closed", "TRANSACTION_CLOSED");
|
||||
}
|
||||
if (this.#started !== undefined) {
|
||||
// Make sure to execute the COMMIT only if the BEGIN was successful.
|
||||
await this.#started;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
const promise = stream.run("COMMIT").catch((e) => {
|
||||
throw mapHranaError(e);
|
||||
});
|
||||
stream.closeGracefully();
|
||||
await promise;
|
||||
}
|
||||
catch (e) {
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
finally {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.HranaTransaction = HranaTransaction;
|
||||
async function executeHranaBatch(mode, version, batch, hranaStmts, disableForeignKeys = false) {
|
||||
if (disableForeignKeys) {
|
||||
batch.step().run("PRAGMA foreign_keys=off");
|
||||
}
|
||||
const beginStep = batch.step();
|
||||
const beginPromise = beginStep.run((0, util_1.transactionModeToBegin)(mode));
|
||||
let lastStep = beginStep;
|
||||
const stmtPromises = hranaStmts.map((hranaStmt) => {
|
||||
const stmtStep = batch.step().condition(hrana.BatchCond.ok(lastStep));
|
||||
if (version >= 3) {
|
||||
stmtStep.condition(hrana.BatchCond.not(hrana.BatchCond.isAutocommit(batch)));
|
||||
}
|
||||
const stmtPromise = stmtStep.query(hranaStmt);
|
||||
lastStep = stmtStep;
|
||||
return stmtPromise;
|
||||
});
|
||||
const commitStep = batch.step().condition(hrana.BatchCond.ok(lastStep));
|
||||
if (version >= 3) {
|
||||
commitStep.condition(hrana.BatchCond.not(hrana.BatchCond.isAutocommit(batch)));
|
||||
}
|
||||
const commitPromise = commitStep.run("COMMIT");
|
||||
const rollbackStep = batch
|
||||
.step()
|
||||
.condition(hrana.BatchCond.not(hrana.BatchCond.ok(commitStep)));
|
||||
rollbackStep.run("ROLLBACK").catch((_) => undefined);
|
||||
if (disableForeignKeys) {
|
||||
batch.step().run("PRAGMA foreign_keys=on");
|
||||
}
|
||||
await batch.execute();
|
||||
const resultSets = [];
|
||||
await beginPromise;
|
||||
for (const stmtPromise of stmtPromises) {
|
||||
const hranaRows = await stmtPromise;
|
||||
if (hranaRows === undefined) {
|
||||
throw new api_1.LibsqlError("Statement in a batch was not executed, probably because the transaction has been rolled back", "TRANSACTION_CLOSED");
|
||||
}
|
||||
resultSets.push(resultSetFromHrana(hranaRows));
|
||||
}
|
||||
await commitPromise;
|
||||
return resultSets;
|
||||
}
|
||||
exports.executeHranaBatch = executeHranaBatch;
|
||||
function stmtToHrana(stmt) {
|
||||
let sql;
|
||||
let args;
|
||||
if (Array.isArray(stmt)) {
|
||||
[sql, args] = stmt;
|
||||
}
|
||||
else if (typeof stmt === "string") {
|
||||
sql = stmt;
|
||||
}
|
||||
else {
|
||||
sql = stmt.sql;
|
||||
args = stmt.args;
|
||||
}
|
||||
const hranaStmt = new hrana.Stmt(sql);
|
||||
if (args) {
|
||||
if (Array.isArray(args)) {
|
||||
hranaStmt.bindIndexes(args);
|
||||
}
|
||||
else {
|
||||
for (const [key, value] of Object.entries(args)) {
|
||||
hranaStmt.bindName(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return hranaStmt;
|
||||
}
|
||||
exports.stmtToHrana = stmtToHrana;
|
||||
function resultSetFromHrana(hranaRows) {
|
||||
const columns = hranaRows.columnNames.map((c) => c ?? "");
|
||||
const columnTypes = hranaRows.columnDecltypes.map((c) => c ?? "");
|
||||
const rows = hranaRows.rows;
|
||||
const rowsAffected = hranaRows.affectedRowCount;
|
||||
const lastInsertRowid = hranaRows.lastInsertRowid !== undefined
|
||||
? hranaRows.lastInsertRowid
|
||||
: undefined;
|
||||
return new util_1.ResultSetImpl(columns, columnTypes, rows, rowsAffected, lastInsertRowid);
|
||||
}
|
||||
exports.resultSetFromHrana = resultSetFromHrana;
|
||||
function mapHranaError(e) {
|
||||
if (e instanceof hrana.ClientError) {
|
||||
const code = mapHranaErrorCode(e);
|
||||
return new api_1.LibsqlError(e.message, code, undefined, e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
exports.mapHranaError = mapHranaError;
|
||||
function mapHranaErrorCode(e) {
|
||||
if (e instanceof hrana.ResponseError && e.code !== undefined) {
|
||||
return e.code;
|
||||
}
|
||||
else if (e instanceof hrana.ProtoError) {
|
||||
return "HRANA_PROTO_ERROR";
|
||||
}
|
||||
else if (e instanceof hrana.ClosedError) {
|
||||
return e.cause instanceof hrana.ClientError
|
||||
? mapHranaErrorCode(e.cause)
|
||||
: "HRANA_CLOSED_ERROR";
|
||||
}
|
||||
else if (e instanceof hrana.WebSocketError) {
|
||||
return "HRANA_WEBSOCKET_ERROR";
|
||||
}
|
||||
else if (e instanceof hrana.HttpServerError) {
|
||||
return "SERVER_ERROR";
|
||||
}
|
||||
else if (e instanceof hrana.ProtocolVersionError) {
|
||||
return "PROTOCOL_VERSION_ERROR";
|
||||
}
|
||||
else if (e instanceof hrana.InternalError) {
|
||||
return "INTERNAL_ERROR";
|
||||
}
|
||||
else {
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
266
node_modules/@libsql/client/lib-cjs/http.js
generated
vendored
Normal file
266
node_modules/@libsql/client/lib-cjs/http.js
generated
vendored
Normal file
@@ -0,0 +1,266 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.HttpTransaction = exports.HttpClient = exports._createClient = exports.createClient = void 0;
|
||||
const hrana = __importStar(require("@libsql/hrana-client"));
|
||||
const api_1 = require("@libsql/core/api");
|
||||
const config_1 = require("@libsql/core/config");
|
||||
const hrana_js_1 = require("./hrana.js");
|
||||
const sql_cache_js_1 = require("./sql_cache.js");
|
||||
const uri_1 = require("@libsql/core/uri");
|
||||
const util_1 = require("@libsql/core/util");
|
||||
const promise_limit_1 = __importDefault(require("promise-limit"));
|
||||
__exportStar(require("@libsql/core/api"), exports);
|
||||
function createClient(config) {
|
||||
return _createClient((0, config_1.expandConfig)(config, true));
|
||||
}
|
||||
exports.createClient = createClient;
|
||||
/** @private */
|
||||
function _createClient(config) {
|
||||
if (config.scheme !== "https" && config.scheme !== "http") {
|
||||
throw new api_1.LibsqlError('The HTTP client supports only "libsql:", "https:" and "http:" URLs, ' +
|
||||
`got ${JSON.stringify(config.scheme + ":")}. For more information, please read ${util_1.supportedUrlLink}`, "URL_SCHEME_NOT_SUPPORTED");
|
||||
}
|
||||
if (config.encryptionKey !== undefined) {
|
||||
throw new api_1.LibsqlError("Encryption key is not supported by the remote client.", "ENCRYPTION_KEY_NOT_SUPPORTED");
|
||||
}
|
||||
if (config.scheme === "http" && config.tls) {
|
||||
throw new api_1.LibsqlError(`A "http:" URL cannot opt into TLS by using ?tls=1`, "URL_INVALID");
|
||||
}
|
||||
else if (config.scheme === "https" && !config.tls) {
|
||||
throw new api_1.LibsqlError(`A "https:" URL cannot opt out of TLS by using ?tls=0`, "URL_INVALID");
|
||||
}
|
||||
const url = (0, uri_1.encodeBaseUrl)(config.scheme, config.authority, config.path);
|
||||
return new HttpClient(url, config.authToken, config.intMode, config.fetch, config.concurrency);
|
||||
}
|
||||
exports._createClient = _createClient;
|
||||
const sqlCacheCapacity = 30;
|
||||
class HttpClient {
|
||||
#client;
|
||||
protocol;
|
||||
#url;
|
||||
#intMode;
|
||||
#customFetch;
|
||||
#concurrency;
|
||||
#authToken;
|
||||
#promiseLimitFunction;
|
||||
/** @private */
|
||||
constructor(url, authToken, intMode, customFetch, concurrency) {
|
||||
this.#url = url;
|
||||
this.#authToken = authToken;
|
||||
this.#intMode = intMode;
|
||||
this.#customFetch = customFetch;
|
||||
this.#concurrency = concurrency;
|
||||
this.#client = hrana.openHttp(this.#url, this.#authToken, this.#customFetch);
|
||||
this.#client.intMode = this.#intMode;
|
||||
this.protocol = "http";
|
||||
this.#promiseLimitFunction = (0, promise_limit_1.default)(this.#concurrency);
|
||||
}
|
||||
async limit(fn) {
|
||||
return this.#promiseLimitFunction(fn);
|
||||
}
|
||||
async execute(stmtOrSql, args) {
|
||||
let stmt;
|
||||
if (typeof stmtOrSql === "string") {
|
||||
stmt = {
|
||||
sql: stmtOrSql,
|
||||
args: args || [],
|
||||
};
|
||||
}
|
||||
else {
|
||||
stmt = stmtOrSql;
|
||||
}
|
||||
return this.limit(async () => {
|
||||
try {
|
||||
const hranaStmt = (0, hrana_js_1.stmtToHrana)(stmt);
|
||||
// Pipeline all operations, so `hrana.HttpClient` can open the stream, execute the statement and
|
||||
// close the stream in a single HTTP request.
|
||||
let rowsPromise;
|
||||
const stream = this.#client.openStream();
|
||||
try {
|
||||
rowsPromise = stream.query(hranaStmt);
|
||||
}
|
||||
finally {
|
||||
stream.closeGracefully();
|
||||
}
|
||||
const rowsResult = await rowsPromise;
|
||||
return (0, hrana_js_1.resultSetFromHrana)(rowsResult);
|
||||
}
|
||||
catch (e) {
|
||||
throw (0, hrana_js_1.mapHranaError)(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
async batch(stmts, mode = "deferred") {
|
||||
return this.limit(async () => {
|
||||
try {
|
||||
const normalizedStmts = stmts.map((stmt) => {
|
||||
if (Array.isArray(stmt)) {
|
||||
return {
|
||||
sql: stmt[0],
|
||||
args: stmt[1] || [],
|
||||
};
|
||||
}
|
||||
return stmt;
|
||||
});
|
||||
const hranaStmts = normalizedStmts.map(hrana_js_1.stmtToHrana);
|
||||
const version = await this.#client.getVersion();
|
||||
// Pipeline all operations, so `hrana.HttpClient` can open the stream, execute the batch and
|
||||
// close the stream in a single HTTP request.
|
||||
let resultsPromise;
|
||||
const stream = this.#client.openStream();
|
||||
try {
|
||||
// It makes sense to use a SQL cache even for a single batch, because it may contain the same
|
||||
// statement repeated multiple times.
|
||||
const sqlCache = new sql_cache_js_1.SqlCache(stream, sqlCacheCapacity);
|
||||
sqlCache.apply(hranaStmts);
|
||||
// TODO: we do not use a cursor here, because it would cause three roundtrips:
|
||||
// 1. pipeline request to store SQL texts
|
||||
// 2. cursor request
|
||||
// 3. pipeline request to close the stream
|
||||
const batch = stream.batch(false);
|
||||
resultsPromise = (0, hrana_js_1.executeHranaBatch)(mode, version, batch, hranaStmts);
|
||||
}
|
||||
finally {
|
||||
stream.closeGracefully();
|
||||
}
|
||||
const results = await resultsPromise;
|
||||
return results;
|
||||
}
|
||||
catch (e) {
|
||||
throw (0, hrana_js_1.mapHranaError)(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
async migrate(stmts) {
|
||||
return this.limit(async () => {
|
||||
try {
|
||||
const hranaStmts = stmts.map(hrana_js_1.stmtToHrana);
|
||||
const version = await this.#client.getVersion();
|
||||
// Pipeline all operations, so `hrana.HttpClient` can open the stream, execute the batch and
|
||||
// close the stream in a single HTTP request.
|
||||
let resultsPromise;
|
||||
const stream = this.#client.openStream();
|
||||
try {
|
||||
const batch = stream.batch(false);
|
||||
resultsPromise = (0, hrana_js_1.executeHranaBatch)("deferred", version, batch, hranaStmts, true);
|
||||
}
|
||||
finally {
|
||||
stream.closeGracefully();
|
||||
}
|
||||
const results = await resultsPromise;
|
||||
return results;
|
||||
}
|
||||
catch (e) {
|
||||
throw (0, hrana_js_1.mapHranaError)(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
async transaction(mode = "write") {
|
||||
return this.limit(async () => {
|
||||
try {
|
||||
const version = await this.#client.getVersion();
|
||||
return new HttpTransaction(this.#client.openStream(), mode, version);
|
||||
}
|
||||
catch (e) {
|
||||
throw (0, hrana_js_1.mapHranaError)(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
async executeMultiple(sql) {
|
||||
return this.limit(async () => {
|
||||
try {
|
||||
// Pipeline all operations, so `hrana.HttpClient` can open the stream, execute the sequence and
|
||||
// close the stream in a single HTTP request.
|
||||
let promise;
|
||||
const stream = this.#client.openStream();
|
||||
try {
|
||||
promise = stream.sequence(sql);
|
||||
}
|
||||
finally {
|
||||
stream.closeGracefully();
|
||||
}
|
||||
await promise;
|
||||
}
|
||||
catch (e) {
|
||||
throw (0, hrana_js_1.mapHranaError)(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
sync() {
|
||||
throw new api_1.LibsqlError("sync not supported in http mode", "SYNC_NOT_SUPPORTED");
|
||||
}
|
||||
close() {
|
||||
this.#client.close();
|
||||
}
|
||||
async reconnect() {
|
||||
try {
|
||||
if (!this.closed) {
|
||||
// Abort in-flight ops and free resources
|
||||
this.#client.close();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
// Recreate the underlying hrana client
|
||||
this.#client = hrana.openHttp(this.#url, this.#authToken, this.#customFetch);
|
||||
this.#client.intMode = this.#intMode;
|
||||
}
|
||||
}
|
||||
get closed() {
|
||||
return this.#client.closed;
|
||||
}
|
||||
}
|
||||
exports.HttpClient = HttpClient;
|
||||
class HttpTransaction extends hrana_js_1.HranaTransaction {
|
||||
#stream;
|
||||
#sqlCache;
|
||||
/** @private */
|
||||
constructor(stream, mode, version) {
|
||||
super(mode, version);
|
||||
this.#stream = stream;
|
||||
this.#sqlCache = new sql_cache_js_1.SqlCache(stream, sqlCacheCapacity);
|
||||
}
|
||||
/** @private */
|
||||
_getStream() {
|
||||
return this.#stream;
|
||||
}
|
||||
/** @private */
|
||||
_getSqlCache() {
|
||||
return this.#sqlCache;
|
||||
}
|
||||
close() {
|
||||
this.#stream.close();
|
||||
}
|
||||
get closed() {
|
||||
return this.#stream.closed;
|
||||
}
|
||||
}
|
||||
exports.HttpTransaction = HttpTransaction;
|
||||
41
node_modules/@libsql/client/lib-cjs/node.js
generated
vendored
Normal file
41
node_modules/@libsql/client/lib-cjs/node.js
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.createClient = void 0;
|
||||
const config_1 = require("@libsql/core/config");
|
||||
const sqlite3_js_1 = require("./sqlite3.js");
|
||||
const ws_js_1 = require("./ws.js");
|
||||
const http_js_1 = require("./http.js");
|
||||
__exportStar(require("@libsql/core/api"), exports);
|
||||
/** Creates a {@link Client} object.
|
||||
*
|
||||
* You must pass at least an `url` in the {@link Config} object.
|
||||
*/
|
||||
function createClient(config) {
|
||||
return _createClient((0, config_1.expandConfig)(config, true));
|
||||
}
|
||||
exports.createClient = createClient;
|
||||
function _createClient(config) {
|
||||
if (config.scheme === "wss" || config.scheme === "ws") {
|
||||
return (0, ws_js_1._createClient)(config);
|
||||
}
|
||||
else if (config.scheme === "https" || config.scheme === "http") {
|
||||
return (0, http_js_1._createClient)(config);
|
||||
}
|
||||
else {
|
||||
return (0, sqlite3_js_1._createClient)(config);
|
||||
}
|
||||
}
|
||||
3
node_modules/@libsql/client/lib-cjs/package.json
generated
vendored
Normal file
3
node_modules/@libsql/client/lib-cjs/package.json
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"type": "commonjs"
|
||||
}
|
||||
91
node_modules/@libsql/client/lib-cjs/sql_cache.js
generated
vendored
Normal file
91
node_modules/@libsql/client/lib-cjs/sql_cache.js
generated
vendored
Normal file
@@ -0,0 +1,91 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.SqlCache = void 0;
|
||||
class SqlCache {
|
||||
#owner;
|
||||
#sqls;
|
||||
capacity;
|
||||
constructor(owner, capacity) {
|
||||
this.#owner = owner;
|
||||
this.#sqls = new Lru();
|
||||
this.capacity = capacity;
|
||||
}
|
||||
// Replaces SQL strings with cached `hrana.Sql` objects in the statements in `hranaStmts`. After this
|
||||
// function returns, we guarantee that all `hranaStmts` refer to valid (not closed) `hrana.Sql` objects,
|
||||
// but _we may invalidate any other `hrana.Sql` objects_ (by closing them, thus removing them from the
|
||||
// server).
|
||||
//
|
||||
// In practice, this means that after calling this function, you can use the statements only up to the
|
||||
// first `await`, because concurrent code may also use the cache and invalidate those statements.
|
||||
apply(hranaStmts) {
|
||||
if (this.capacity <= 0) {
|
||||
return;
|
||||
}
|
||||
const usedSqlObjs = new Set();
|
||||
for (const hranaStmt of hranaStmts) {
|
||||
if (typeof hranaStmt.sql !== "string") {
|
||||
continue;
|
||||
}
|
||||
const sqlText = hranaStmt.sql;
|
||||
// Stored SQL cannot exceed 5kb.
|
||||
// https://github.com/tursodatabase/libsql/blob/e9d637e051685f92b0da43849507b5ef4232fbeb/libsql-server/src/hrana/http/request.rs#L10
|
||||
if (sqlText.length >= 5000) {
|
||||
continue;
|
||||
}
|
||||
let sqlObj = this.#sqls.get(sqlText);
|
||||
if (sqlObj === undefined) {
|
||||
while (this.#sqls.size + 1 > this.capacity) {
|
||||
const [evictSqlText, evictSqlObj] = this.#sqls.peekLru();
|
||||
if (usedSqlObjs.has(evictSqlObj)) {
|
||||
// The SQL object that we are trying to evict is already in use in this batch, so we
|
||||
// must not evict and close it.
|
||||
break;
|
||||
}
|
||||
evictSqlObj.close();
|
||||
this.#sqls.delete(evictSqlText);
|
||||
}
|
||||
if (this.#sqls.size + 1 <= this.capacity) {
|
||||
sqlObj = this.#owner.storeSql(sqlText);
|
||||
this.#sqls.set(sqlText, sqlObj);
|
||||
}
|
||||
}
|
||||
if (sqlObj !== undefined) {
|
||||
hranaStmt.sql = sqlObj;
|
||||
usedSqlObjs.add(sqlObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.SqlCache = SqlCache;
|
||||
class Lru {
|
||||
// This maps keys to the cache values. The entries are ordered by their last use (entires that were used
|
||||
// most recently are at the end).
|
||||
#cache;
|
||||
constructor() {
|
||||
this.#cache = new Map();
|
||||
}
|
||||
get(key) {
|
||||
const value = this.#cache.get(key);
|
||||
if (value !== undefined) {
|
||||
// move the entry to the back of the Map
|
||||
this.#cache.delete(key);
|
||||
this.#cache.set(key, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
set(key, value) {
|
||||
this.#cache.set(key, value);
|
||||
}
|
||||
peekLru() {
|
||||
for (const entry of this.#cache.entries()) {
|
||||
return entry;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
delete(key) {
|
||||
this.#cache.delete(key);
|
||||
}
|
||||
get size() {
|
||||
return this.#cache.size;
|
||||
}
|
||||
}
|
||||
419
node_modules/@libsql/client/lib-cjs/sqlite3.js
generated
vendored
Normal file
419
node_modules/@libsql/client/lib-cjs/sqlite3.js
generated
vendored
Normal file
@@ -0,0 +1,419 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Sqlite3Transaction = exports.Sqlite3Client = exports._createClient = exports.createClient = void 0;
|
||||
const libsql_1 = __importDefault(require("libsql"));
|
||||
const node_buffer_1 = require("node:buffer");
|
||||
const api_1 = require("@libsql/core/api");
|
||||
const config_1 = require("@libsql/core/config");
|
||||
const util_1 = require("@libsql/core/util");
|
||||
__exportStar(require("@libsql/core/api"), exports);
|
||||
function createClient(config) {
|
||||
return _createClient((0, config_1.expandConfig)(config, true));
|
||||
}
|
||||
exports.createClient = createClient;
|
||||
/** @private */
|
||||
function _createClient(config) {
|
||||
if (config.scheme !== "file") {
|
||||
throw new api_1.LibsqlError(`URL scheme ${JSON.stringify(config.scheme + ":")} is not supported by the local sqlite3 client. ` +
|
||||
`For more information, please read ${util_1.supportedUrlLink}`, "URL_SCHEME_NOT_SUPPORTED");
|
||||
}
|
||||
const authority = config.authority;
|
||||
if (authority !== undefined) {
|
||||
const host = authority.host.toLowerCase();
|
||||
if (host !== "" && host !== "localhost") {
|
||||
throw new api_1.LibsqlError(`Invalid host in file URL: ${JSON.stringify(authority.host)}. ` +
|
||||
'A "file:" URL with an absolute path should start with one slash ("file:/absolute/path.db") ' +
|
||||
'or with three slashes ("file:///absolute/path.db"). ' +
|
||||
`For more information, please read ${util_1.supportedUrlLink}`, "URL_INVALID");
|
||||
}
|
||||
if (authority.port !== undefined) {
|
||||
throw new api_1.LibsqlError("File URL cannot have a port", "URL_INVALID");
|
||||
}
|
||||
if (authority.userinfo !== undefined) {
|
||||
throw new api_1.LibsqlError("File URL cannot have username and password", "URL_INVALID");
|
||||
}
|
||||
}
|
||||
let isInMemory = (0, config_1.isInMemoryConfig)(config);
|
||||
if (isInMemory && config.syncUrl) {
|
||||
throw new api_1.LibsqlError(`Embedded replica must use file for local db but URI with in-memory mode were provided instead: ${config.path}`, "URL_INVALID");
|
||||
}
|
||||
let path = config.path;
|
||||
if (isInMemory) {
|
||||
// note: we should prepend file scheme in order for SQLite3 to recognize :memory: connection query parameters
|
||||
path = `${config.scheme}:${config.path}`;
|
||||
}
|
||||
const options = {
|
||||
authToken: config.authToken,
|
||||
encryptionKey: config.encryptionKey,
|
||||
syncUrl: config.syncUrl,
|
||||
syncPeriod: config.syncInterval,
|
||||
readYourWrites: config.readYourWrites,
|
||||
offline: config.offline,
|
||||
};
|
||||
const db = new libsql_1.default(path, options);
|
||||
executeStmt(db, "SELECT 1 AS checkThatTheDatabaseCanBeOpened", config.intMode);
|
||||
return new Sqlite3Client(path, options, db, config.intMode);
|
||||
}
|
||||
exports._createClient = _createClient;
|
||||
class Sqlite3Client {
|
||||
#path;
|
||||
#options;
|
||||
#db;
|
||||
#intMode;
|
||||
closed;
|
||||
protocol;
|
||||
/** @private */
|
||||
constructor(path, options, db, intMode) {
|
||||
this.#path = path;
|
||||
this.#options = options;
|
||||
this.#db = db;
|
||||
this.#intMode = intMode;
|
||||
this.closed = false;
|
||||
this.protocol = "file";
|
||||
}
|
||||
async execute(stmtOrSql, args) {
|
||||
let stmt;
|
||||
if (typeof stmtOrSql === "string") {
|
||||
stmt = {
|
||||
sql: stmtOrSql,
|
||||
args: args || [],
|
||||
};
|
||||
}
|
||||
else {
|
||||
stmt = stmtOrSql;
|
||||
}
|
||||
this.#checkNotClosed();
|
||||
return executeStmt(this.#getDb(), stmt, this.#intMode);
|
||||
}
|
||||
async batch(stmts, mode = "deferred") {
|
||||
this.#checkNotClosed();
|
||||
const db = this.#getDb();
|
||||
try {
|
||||
executeStmt(db, (0, util_1.transactionModeToBegin)(mode), this.#intMode);
|
||||
const resultSets = stmts.map((stmt) => {
|
||||
if (!db.inTransaction) {
|
||||
throw new api_1.LibsqlError("The transaction has been rolled back", "TRANSACTION_CLOSED");
|
||||
}
|
||||
const normalizedStmt = Array.isArray(stmt)
|
||||
? { sql: stmt[0], args: stmt[1] || [] }
|
||||
: stmt;
|
||||
return executeStmt(db, normalizedStmt, this.#intMode);
|
||||
});
|
||||
executeStmt(db, "COMMIT", this.#intMode);
|
||||
return resultSets;
|
||||
}
|
||||
finally {
|
||||
if (db.inTransaction) {
|
||||
executeStmt(db, "ROLLBACK", this.#intMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
async migrate(stmts) {
|
||||
this.#checkNotClosed();
|
||||
const db = this.#getDb();
|
||||
try {
|
||||
executeStmt(db, "PRAGMA foreign_keys=off", this.#intMode);
|
||||
executeStmt(db, (0, util_1.transactionModeToBegin)("deferred"), this.#intMode);
|
||||
const resultSets = stmts.map((stmt) => {
|
||||
if (!db.inTransaction) {
|
||||
throw new api_1.LibsqlError("The transaction has been rolled back", "TRANSACTION_CLOSED");
|
||||
}
|
||||
return executeStmt(db, stmt, this.#intMode);
|
||||
});
|
||||
executeStmt(db, "COMMIT", this.#intMode);
|
||||
return resultSets;
|
||||
}
|
||||
finally {
|
||||
if (db.inTransaction) {
|
||||
executeStmt(db, "ROLLBACK", this.#intMode);
|
||||
}
|
||||
executeStmt(db, "PRAGMA foreign_keys=on", this.#intMode);
|
||||
}
|
||||
}
|
||||
async transaction(mode = "write") {
|
||||
const db = this.#getDb();
|
||||
executeStmt(db, (0, util_1.transactionModeToBegin)(mode), this.#intMode);
|
||||
this.#db = null; // A new connection will be lazily created on next use
|
||||
return new Sqlite3Transaction(db, this.#intMode);
|
||||
}
|
||||
async executeMultiple(sql) {
|
||||
this.#checkNotClosed();
|
||||
const db = this.#getDb();
|
||||
try {
|
||||
return executeMultiple(db, sql);
|
||||
}
|
||||
finally {
|
||||
if (db.inTransaction) {
|
||||
executeStmt(db, "ROLLBACK", this.#intMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
async sync() {
|
||||
this.#checkNotClosed();
|
||||
const rep = await this.#getDb().sync();
|
||||
return {
|
||||
frames_synced: rep.frames_synced,
|
||||
frame_no: rep.frame_no,
|
||||
};
|
||||
}
|
||||
async reconnect() {
|
||||
try {
|
||||
if (!this.closed && this.#db !== null) {
|
||||
this.#db.close();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.#db = new libsql_1.default(this.#path, this.#options);
|
||||
this.closed = false;
|
||||
}
|
||||
}
|
||||
close() {
|
||||
this.closed = true;
|
||||
if (this.#db !== null) {
|
||||
this.#db.close();
|
||||
this.#db = null;
|
||||
}
|
||||
}
|
||||
#checkNotClosed() {
|
||||
if (this.closed) {
|
||||
throw new api_1.LibsqlError("The client is closed", "CLIENT_CLOSED");
|
||||
}
|
||||
}
|
||||
// Lazily creates the database connection and returns it
|
||||
#getDb() {
|
||||
if (this.#db === null) {
|
||||
this.#db = new libsql_1.default(this.#path, this.#options);
|
||||
}
|
||||
return this.#db;
|
||||
}
|
||||
}
|
||||
exports.Sqlite3Client = Sqlite3Client;
|
||||
class Sqlite3Transaction {
|
||||
#database;
|
||||
#intMode;
|
||||
/** @private */
|
||||
constructor(database, intMode) {
|
||||
this.#database = database;
|
||||
this.#intMode = intMode;
|
||||
}
|
||||
async execute(stmtOrSql, args) {
|
||||
let stmt;
|
||||
if (typeof stmtOrSql === "string") {
|
||||
stmt = {
|
||||
sql: stmtOrSql,
|
||||
args: args || [],
|
||||
};
|
||||
}
|
||||
else {
|
||||
stmt = stmtOrSql;
|
||||
}
|
||||
this.#checkNotClosed();
|
||||
return executeStmt(this.#database, stmt, this.#intMode);
|
||||
}
|
||||
async batch(stmts) {
|
||||
return stmts.map((stmt) => {
|
||||
this.#checkNotClosed();
|
||||
const normalizedStmt = Array.isArray(stmt)
|
||||
? { sql: stmt[0], args: stmt[1] || [] }
|
||||
: stmt;
|
||||
return executeStmt(this.#database, normalizedStmt, this.#intMode);
|
||||
});
|
||||
}
|
||||
async executeMultiple(sql) {
|
||||
this.#checkNotClosed();
|
||||
return executeMultiple(this.#database, sql);
|
||||
}
|
||||
async rollback() {
|
||||
if (!this.#database.open) {
|
||||
return;
|
||||
}
|
||||
this.#checkNotClosed();
|
||||
executeStmt(this.#database, "ROLLBACK", this.#intMode);
|
||||
}
|
||||
async commit() {
|
||||
this.#checkNotClosed();
|
||||
executeStmt(this.#database, "COMMIT", this.#intMode);
|
||||
}
|
||||
close() {
|
||||
if (this.#database.inTransaction) {
|
||||
executeStmt(this.#database, "ROLLBACK", this.#intMode);
|
||||
}
|
||||
}
|
||||
get closed() {
|
||||
return !this.#database.inTransaction;
|
||||
}
|
||||
#checkNotClosed() {
|
||||
if (this.closed) {
|
||||
throw new api_1.LibsqlError("The transaction is closed", "TRANSACTION_CLOSED");
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.Sqlite3Transaction = Sqlite3Transaction;
|
||||
function executeStmt(db, stmt, intMode) {
|
||||
let sql;
|
||||
let args;
|
||||
if (typeof stmt === "string") {
|
||||
sql = stmt;
|
||||
args = [];
|
||||
}
|
||||
else {
|
||||
sql = stmt.sql;
|
||||
if (Array.isArray(stmt.args)) {
|
||||
args = stmt.args.map((value) => valueToSql(value, intMode));
|
||||
}
|
||||
else {
|
||||
args = {};
|
||||
for (const name in stmt.args) {
|
||||
const argName = name[0] === "@" || name[0] === "$" || name[0] === ":"
|
||||
? name.substring(1)
|
||||
: name;
|
||||
args[argName] = valueToSql(stmt.args[name], intMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
const sqlStmt = db.prepare(sql);
|
||||
sqlStmt.safeIntegers(true);
|
||||
let returnsData = true;
|
||||
try {
|
||||
sqlStmt.raw(true);
|
||||
}
|
||||
catch {
|
||||
// raw() throws an exception if the statement does not return data
|
||||
returnsData = false;
|
||||
}
|
||||
if (returnsData) {
|
||||
const columns = Array.from(sqlStmt.columns().map((col) => col.name));
|
||||
const columnTypes = Array.from(sqlStmt.columns().map((col) => col.type ?? ""));
|
||||
const rows = sqlStmt.all(args).map((sqlRow) => {
|
||||
return rowFromSql(sqlRow, columns, intMode);
|
||||
});
|
||||
// TODO: can we get this info from better-sqlite3?
|
||||
const rowsAffected = 0;
|
||||
const lastInsertRowid = undefined;
|
||||
return new util_1.ResultSetImpl(columns, columnTypes, rows, rowsAffected, lastInsertRowid);
|
||||
}
|
||||
else {
|
||||
const info = sqlStmt.run(args);
|
||||
const rowsAffected = info.changes;
|
||||
const lastInsertRowid = BigInt(info.lastInsertRowid);
|
||||
return new util_1.ResultSetImpl([], [], [], rowsAffected, lastInsertRowid);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
throw mapSqliteError(e);
|
||||
}
|
||||
}
|
||||
function rowFromSql(sqlRow, columns, intMode) {
|
||||
const row = {};
|
||||
// make sure that the "length" property is not enumerable
|
||||
Object.defineProperty(row, "length", { value: sqlRow.length });
|
||||
for (let i = 0; i < sqlRow.length; ++i) {
|
||||
const value = valueFromSql(sqlRow[i], intMode);
|
||||
Object.defineProperty(row, i, { value });
|
||||
const column = columns[i];
|
||||
if (!Object.hasOwn(row, column)) {
|
||||
Object.defineProperty(row, column, {
|
||||
value,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
return row;
|
||||
}
|
||||
function valueFromSql(sqlValue, intMode) {
|
||||
if (typeof sqlValue === "bigint") {
|
||||
if (intMode === "number") {
|
||||
if (sqlValue < minSafeBigint || sqlValue > maxSafeBigint) {
|
||||
throw new RangeError("Received integer which cannot be safely represented as a JavaScript number");
|
||||
}
|
||||
return Number(sqlValue);
|
||||
}
|
||||
else if (intMode === "bigint") {
|
||||
return sqlValue;
|
||||
}
|
||||
else if (intMode === "string") {
|
||||
return "" + sqlValue;
|
||||
}
|
||||
else {
|
||||
throw new Error("Invalid value for IntMode");
|
||||
}
|
||||
}
|
||||
else if (sqlValue instanceof node_buffer_1.Buffer) {
|
||||
return sqlValue.buffer;
|
||||
}
|
||||
return sqlValue;
|
||||
}
|
||||
const minSafeBigint = -9007199254740991n;
|
||||
const maxSafeBigint = 9007199254740991n;
|
||||
function valueToSql(value, intMode) {
|
||||
if (typeof value === "number") {
|
||||
if (!Number.isFinite(value)) {
|
||||
throw new RangeError("Only finite numbers (not Infinity or NaN) can be passed as arguments");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
else if (typeof value === "bigint") {
|
||||
if (value < minInteger || value > maxInteger) {
|
||||
throw new RangeError("bigint is too large to be represented as a 64-bit integer and passed as argument");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
else if (typeof value === "boolean") {
|
||||
switch (intMode) {
|
||||
case "bigint":
|
||||
return value ? 1n : 0n;
|
||||
case "string":
|
||||
return value ? "1" : "0";
|
||||
default:
|
||||
return value ? 1 : 0;
|
||||
}
|
||||
}
|
||||
else if (value instanceof ArrayBuffer) {
|
||||
return node_buffer_1.Buffer.from(value);
|
||||
}
|
||||
else if (value instanceof Date) {
|
||||
return value.valueOf();
|
||||
}
|
||||
else if (value === undefined) {
|
||||
throw new TypeError("undefined cannot be passed as argument to the database");
|
||||
}
|
||||
else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
const minInteger = -9223372036854775808n;
|
||||
const maxInteger = 9223372036854775807n;
|
||||
function executeMultiple(db, sql) {
|
||||
try {
|
||||
db.exec(sql);
|
||||
}
|
||||
catch (e) {
|
||||
throw mapSqliteError(e);
|
||||
}
|
||||
}
|
||||
function mapSqliteError(e) {
|
||||
if (e instanceof libsql_1.default.SqliteError) {
|
||||
return new api_1.LibsqlError(e.message, e.code, e.rawCode, e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
41
node_modules/@libsql/client/lib-cjs/web.js
generated
vendored
Normal file
41
node_modules/@libsql/client/lib-cjs/web.js
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports._createClient = exports.createClient = void 0;
|
||||
const api_1 = require("@libsql/core/api");
|
||||
const config_1 = require("@libsql/core/config");
|
||||
const util_1 = require("@libsql/core/util");
|
||||
const ws_js_1 = require("./ws.js");
|
||||
const http_js_1 = require("./http.js");
|
||||
__exportStar(require("@libsql/core/api"), exports);
|
||||
function createClient(config) {
|
||||
return _createClient((0, config_1.expandConfig)(config, true));
|
||||
}
|
||||
exports.createClient = createClient;
|
||||
/** @private */
|
||||
function _createClient(config) {
|
||||
if (config.scheme === "ws" || config.scheme === "wss") {
|
||||
return (0, ws_js_1._createClient)(config);
|
||||
}
|
||||
else if (config.scheme === "http" || config.scheme === "https") {
|
||||
return (0, http_js_1._createClient)(config);
|
||||
}
|
||||
else {
|
||||
throw new api_1.LibsqlError('The client that uses Web standard APIs supports only "libsql:", "wss:", "ws:", "https:" and "http:" URLs, ' +
|
||||
`got ${JSON.stringify(config.scheme + ":")}. For more information, please read ${util_1.supportedUrlLink}`, "URL_SCHEME_NOT_SUPPORTED");
|
||||
}
|
||||
}
|
||||
exports._createClient = _createClient;
|
||||
395
node_modules/@libsql/client/lib-cjs/ws.js
generated
vendored
Normal file
395
node_modules/@libsql/client/lib-cjs/ws.js
generated
vendored
Normal file
@@ -0,0 +1,395 @@
|
||||
"use strict";
|
||||
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
var desc = Object.getOwnPropertyDescriptor(m, k);
|
||||
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
||||
desc = { enumerable: true, get: function() { return m[k]; } };
|
||||
}
|
||||
Object.defineProperty(o, k2, desc);
|
||||
}) : (function(o, m, k, k2) {
|
||||
if (k2 === undefined) k2 = k;
|
||||
o[k2] = m[k];
|
||||
}));
|
||||
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
||||
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
||||
}) : function(o, v) {
|
||||
o["default"] = v;
|
||||
});
|
||||
var __importStar = (this && this.__importStar) || function (mod) {
|
||||
if (mod && mod.__esModule) return mod;
|
||||
var result = {};
|
||||
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
||||
__setModuleDefault(result, mod);
|
||||
return result;
|
||||
};
|
||||
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
||||
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
||||
};
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.WsTransaction = exports.WsClient = exports._createClient = exports.createClient = void 0;
|
||||
const hrana = __importStar(require("@libsql/hrana-client"));
|
||||
const api_1 = require("@libsql/core/api");
|
||||
const config_1 = require("@libsql/core/config");
|
||||
const hrana_js_1 = require("./hrana.js");
|
||||
const sql_cache_js_1 = require("./sql_cache.js");
|
||||
const uri_1 = require("@libsql/core/uri");
|
||||
const util_1 = require("@libsql/core/util");
|
||||
const promise_limit_1 = __importDefault(require("promise-limit"));
|
||||
__exportStar(require("@libsql/core/api"), exports);
|
||||
function createClient(config) {
|
||||
return _createClient((0, config_1.expandConfig)(config, false));
|
||||
}
|
||||
exports.createClient = createClient;
|
||||
/** @private */
|
||||
function _createClient(config) {
|
||||
if (config.scheme !== "wss" && config.scheme !== "ws") {
|
||||
throw new api_1.LibsqlError('The WebSocket client supports only "libsql:", "wss:" and "ws:" URLs, ' +
|
||||
`got ${JSON.stringify(config.scheme + ":")}. For more information, please read ${util_1.supportedUrlLink}`, "URL_SCHEME_NOT_SUPPORTED");
|
||||
}
|
||||
if (config.encryptionKey !== undefined) {
|
||||
throw new api_1.LibsqlError("Encryption key is not supported by the remote client.", "ENCRYPTION_KEY_NOT_SUPPORTED");
|
||||
}
|
||||
if (config.scheme === "ws" && config.tls) {
|
||||
throw new api_1.LibsqlError(`A "ws:" URL cannot opt into TLS by using ?tls=1`, "URL_INVALID");
|
||||
}
|
||||
else if (config.scheme === "wss" && !config.tls) {
|
||||
throw new api_1.LibsqlError(`A "wss:" URL cannot opt out of TLS by using ?tls=0`, "URL_INVALID");
|
||||
}
|
||||
const url = (0, uri_1.encodeBaseUrl)(config.scheme, config.authority, config.path);
|
||||
let client;
|
||||
try {
|
||||
client = hrana.openWs(url, config.authToken);
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof hrana.WebSocketUnsupportedError) {
|
||||
const suggestedScheme = config.scheme === "wss" ? "https" : "http";
|
||||
const suggestedUrl = (0, uri_1.encodeBaseUrl)(suggestedScheme, config.authority, config.path);
|
||||
throw new api_1.LibsqlError("This environment does not support WebSockets, please switch to the HTTP client by using " +
|
||||
`a "${suggestedScheme}:" URL (${JSON.stringify(suggestedUrl)}). ` +
|
||||
`For more information, please read ${util_1.supportedUrlLink}`, "WEBSOCKETS_NOT_SUPPORTED");
|
||||
}
|
||||
throw (0, hrana_js_1.mapHranaError)(e);
|
||||
}
|
||||
return new WsClient(client, url, config.authToken, config.intMode, config.concurrency);
|
||||
}
|
||||
exports._createClient = _createClient;
|
||||
const maxConnAgeMillis = 60 * 1000;
|
||||
const sqlCacheCapacity = 100;
|
||||
class WsClient {
|
||||
#url;
|
||||
#authToken;
|
||||
#intMode;
|
||||
// State of the current connection. The `hrana.WsClient` inside may be closed at any moment due to an
|
||||
// asynchronous error.
|
||||
#connState;
|
||||
// If defined, this is a connection that will be used in the future, once it is ready.
|
||||
#futureConnState;
|
||||
closed;
|
||||
protocol;
|
||||
#isSchemaDatabase;
|
||||
#promiseLimitFunction;
|
||||
/** @private */
|
||||
constructor(client, url, authToken, intMode, concurrency) {
|
||||
this.#url = url;
|
||||
this.#authToken = authToken;
|
||||
this.#intMode = intMode;
|
||||
this.#connState = this.#openConn(client);
|
||||
this.#futureConnState = undefined;
|
||||
this.closed = false;
|
||||
this.protocol = "ws";
|
||||
this.#promiseLimitFunction = (0, promise_limit_1.default)(concurrency);
|
||||
}
|
||||
async limit(fn) {
|
||||
return this.#promiseLimitFunction(fn);
|
||||
}
|
||||
async execute(stmtOrSql, args) {
|
||||
let stmt;
|
||||
if (typeof stmtOrSql === "string") {
|
||||
stmt = {
|
||||
sql: stmtOrSql,
|
||||
args: args || [],
|
||||
};
|
||||
}
|
||||
else {
|
||||
stmt = stmtOrSql;
|
||||
}
|
||||
return this.limit(async () => {
|
||||
const streamState = await this.#openStream();
|
||||
try {
|
||||
const hranaStmt = (0, hrana_js_1.stmtToHrana)(stmt);
|
||||
// Schedule all operations synchronously, so they will be pipelined and executed in a single
|
||||
// network roundtrip.
|
||||
streamState.conn.sqlCache.apply([hranaStmt]);
|
||||
const hranaRowsPromise = streamState.stream.query(hranaStmt);
|
||||
streamState.stream.closeGracefully();
|
||||
const hranaRowsResult = await hranaRowsPromise;
|
||||
return (0, hrana_js_1.resultSetFromHrana)(hranaRowsResult);
|
||||
}
|
||||
catch (e) {
|
||||
throw (0, hrana_js_1.mapHranaError)(e);
|
||||
}
|
||||
finally {
|
||||
this._closeStream(streamState);
|
||||
}
|
||||
});
|
||||
}
|
||||
async batch(stmts, mode = "deferred") {
|
||||
return this.limit(async () => {
|
||||
const streamState = await this.#openStream();
|
||||
try {
|
||||
const normalizedStmts = stmts.map((stmt) => {
|
||||
if (Array.isArray(stmt)) {
|
||||
return {
|
||||
sql: stmt[0],
|
||||
args: stmt[1] || [],
|
||||
};
|
||||
}
|
||||
return stmt;
|
||||
});
|
||||
const hranaStmts = normalizedStmts.map(hrana_js_1.stmtToHrana);
|
||||
const version = await streamState.conn.client.getVersion();
|
||||
// Schedule all operations synchronously, so they will be pipelined and executed in a single
|
||||
// network roundtrip.
|
||||
streamState.conn.sqlCache.apply(hranaStmts);
|
||||
const batch = streamState.stream.batch(version >= 3);
|
||||
const resultsPromise = (0, hrana_js_1.executeHranaBatch)(mode, version, batch, hranaStmts);
|
||||
const results = await resultsPromise;
|
||||
return results;
|
||||
}
|
||||
catch (e) {
|
||||
throw (0, hrana_js_1.mapHranaError)(e);
|
||||
}
|
||||
finally {
|
||||
this._closeStream(streamState);
|
||||
}
|
||||
});
|
||||
}
|
||||
async migrate(stmts) {
|
||||
return this.limit(async () => {
|
||||
const streamState = await this.#openStream();
|
||||
try {
|
||||
const hranaStmts = stmts.map(hrana_js_1.stmtToHrana);
|
||||
const version = await streamState.conn.client.getVersion();
|
||||
// Schedule all operations synchronously, so they will be pipelined and executed in a single
|
||||
// network roundtrip.
|
||||
const batch = streamState.stream.batch(version >= 3);
|
||||
const resultsPromise = (0, hrana_js_1.executeHranaBatch)("deferred", version, batch, hranaStmts, true);
|
||||
const results = await resultsPromise;
|
||||
return results;
|
||||
}
|
||||
catch (e) {
|
||||
throw (0, hrana_js_1.mapHranaError)(e);
|
||||
}
|
||||
finally {
|
||||
this._closeStream(streamState);
|
||||
}
|
||||
});
|
||||
}
|
||||
async transaction(mode = "write") {
|
||||
return this.limit(async () => {
|
||||
const streamState = await this.#openStream();
|
||||
try {
|
||||
const version = await streamState.conn.client.getVersion();
|
||||
// the BEGIN statement will be batched with the first statement on the transaction to save a
|
||||
// network roundtrip
|
||||
return new WsTransaction(this, streamState, mode, version);
|
||||
}
|
||||
catch (e) {
|
||||
this._closeStream(streamState);
|
||||
throw (0, hrana_js_1.mapHranaError)(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
async executeMultiple(sql) {
|
||||
return this.limit(async () => {
|
||||
const streamState = await this.#openStream();
|
||||
try {
|
||||
// Schedule all operations synchronously, so they will be pipelined and executed in a single
|
||||
// network roundtrip.
|
||||
const promise = streamState.stream.sequence(sql);
|
||||
streamState.stream.closeGracefully();
|
||||
await promise;
|
||||
}
|
||||
catch (e) {
|
||||
throw (0, hrana_js_1.mapHranaError)(e);
|
||||
}
|
||||
finally {
|
||||
this._closeStream(streamState);
|
||||
}
|
||||
});
|
||||
}
|
||||
sync() {
|
||||
throw new api_1.LibsqlError("sync not supported in ws mode", "SYNC_NOT_SUPPORTED");
|
||||
}
|
||||
async #openStream() {
|
||||
if (this.closed) {
|
||||
throw new api_1.LibsqlError("The client is closed", "CLIENT_CLOSED");
|
||||
}
|
||||
const now = new Date();
|
||||
const ageMillis = now.valueOf() - this.#connState.openTime.valueOf();
|
||||
if (ageMillis > maxConnAgeMillis &&
|
||||
this.#futureConnState === undefined) {
|
||||
// The existing connection is too old, let's open a new one.
|
||||
const futureConnState = this.#openConn();
|
||||
this.#futureConnState = futureConnState;
|
||||
// However, if we used `futureConnState` immediately, we would introduce additional latency,
|
||||
// because we would have to wait for the WebSocket handshake to complete, even though we may a
|
||||
// have perfectly good existing connection in `this.#connState`!
|
||||
//
|
||||
// So we wait until the `hrana.Client.getVersion()` operation completes (which happens when the
|
||||
// WebSocket hanshake completes), and only then we replace `this.#connState` with
|
||||
// `futureConnState`, which is stored in `this.#futureConnState` in the meantime.
|
||||
futureConnState.client.getVersion().then((_version) => {
|
||||
if (this.#connState !== futureConnState) {
|
||||
// We need to close `this.#connState` before we replace it. However, it is possible
|
||||
// that `this.#connState` has already been replaced: see the code below.
|
||||
if (this.#connState.streamStates.size === 0) {
|
||||
this.#connState.client.close();
|
||||
}
|
||||
else {
|
||||
// If there are existing streams on the connection, we must not close it, because
|
||||
// these streams would be broken. The last stream to be closed will also close the
|
||||
// connection in `_closeStream()`.
|
||||
}
|
||||
}
|
||||
this.#connState = futureConnState;
|
||||
this.#futureConnState = undefined;
|
||||
}, (_e) => {
|
||||
// If the new connection could not be established, let's just ignore the error and keep
|
||||
// using the existing connection.
|
||||
this.#futureConnState = undefined;
|
||||
});
|
||||
}
|
||||
if (this.#connState.client.closed) {
|
||||
// An error happened on this connection and it has been closed. Let's try to seamlessly reconnect.
|
||||
try {
|
||||
if (this.#futureConnState !== undefined) {
|
||||
// We are already in the process of opening a new connection, so let's just use it
|
||||
// immediately.
|
||||
this.#connState = this.#futureConnState;
|
||||
}
|
||||
else {
|
||||
this.#connState = this.#openConn();
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
throw (0, hrana_js_1.mapHranaError)(e);
|
||||
}
|
||||
}
|
||||
const connState = this.#connState;
|
||||
try {
|
||||
// Now we wait for the WebSocket handshake to complete (if it hasn't completed yet). Note that
|
||||
// this does not increase latency, because any messages that we would send on the WebSocket before
|
||||
// the handshake would be queued until the handshake is completed anyway.
|
||||
if (connState.useSqlCache === undefined) {
|
||||
connState.useSqlCache =
|
||||
(await connState.client.getVersion()) >= 2;
|
||||
if (connState.useSqlCache) {
|
||||
connState.sqlCache.capacity = sqlCacheCapacity;
|
||||
}
|
||||
}
|
||||
const stream = connState.client.openStream();
|
||||
stream.intMode = this.#intMode;
|
||||
const streamState = { conn: connState, stream };
|
||||
connState.streamStates.add(streamState);
|
||||
return streamState;
|
||||
}
|
||||
catch (e) {
|
||||
throw (0, hrana_js_1.mapHranaError)(e);
|
||||
}
|
||||
}
|
||||
#openConn(client) {
|
||||
try {
|
||||
client ??= hrana.openWs(this.#url, this.#authToken);
|
||||
return {
|
||||
client,
|
||||
useSqlCache: undefined,
|
||||
sqlCache: new sql_cache_js_1.SqlCache(client, 0),
|
||||
openTime: new Date(),
|
||||
streamStates: new Set(),
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
throw (0, hrana_js_1.mapHranaError)(e);
|
||||
}
|
||||
}
|
||||
async reconnect() {
|
||||
try {
|
||||
for (const st of Array.from(this.#connState.streamStates)) {
|
||||
try {
|
||||
st.stream.close();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
this.#connState.client.close();
|
||||
}
|
||||
catch { }
|
||||
if (this.#futureConnState) {
|
||||
try {
|
||||
this.#futureConnState.client.close();
|
||||
}
|
||||
catch { }
|
||||
this.#futureConnState = undefined;
|
||||
}
|
||||
const next = this.#openConn();
|
||||
const version = await next.client.getVersion();
|
||||
next.useSqlCache = version >= 2;
|
||||
if (next.useSqlCache) {
|
||||
next.sqlCache.capacity = sqlCacheCapacity;
|
||||
}
|
||||
this.#connState = next;
|
||||
this.closed = false;
|
||||
}
|
||||
_closeStream(streamState) {
|
||||
streamState.stream.close();
|
||||
const connState = streamState.conn;
|
||||
connState.streamStates.delete(streamState);
|
||||
if (connState.streamStates.size === 0 &&
|
||||
connState !== this.#connState) {
|
||||
// We are not using this connection anymore and this is the last stream that was using it, so we
|
||||
// must close it now.
|
||||
connState.client.close();
|
||||
}
|
||||
}
|
||||
close() {
|
||||
this.#connState.client.close();
|
||||
this.closed = true;
|
||||
if (this.#futureConnState) {
|
||||
try {
|
||||
this.#futureConnState.client.close();
|
||||
}
|
||||
catch { }
|
||||
this.#futureConnState = undefined;
|
||||
}
|
||||
this.closed = true;
|
||||
}
|
||||
}
|
||||
exports.WsClient = WsClient;
|
||||
class WsTransaction extends hrana_js_1.HranaTransaction {
|
||||
#client;
|
||||
#streamState;
|
||||
/** @private */
|
||||
constructor(client, state, mode, version) {
|
||||
super(mode, version);
|
||||
this.#client = client;
|
||||
this.#streamState = state;
|
||||
}
|
||||
/** @private */
|
||||
_getStream() {
|
||||
return this.#streamState.stream;
|
||||
}
|
||||
/** @private */
|
||||
_getSqlCache() {
|
||||
return this.#streamState.conn.sqlCache;
|
||||
}
|
||||
close() {
|
||||
this.#client._closeStream(this.#streamState);
|
||||
}
|
||||
get closed() {
|
||||
return this.#streamState.stream.closed;
|
||||
}
|
||||
}
|
||||
exports.WsTransaction = WsTransaction;
|
||||
23
node_modules/@libsql/client/lib-esm/hrana.d.ts
generated
vendored
Normal file
23
node_modules/@libsql/client/lib-esm/hrana.d.ts
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
import * as hrana from "@libsql/hrana-client";
|
||||
import type { InStatement, ResultSet, Transaction, TransactionMode, InArgs } from "@libsql/core/api";
|
||||
import type { SqlCache } from "./sql_cache.js";
|
||||
export declare abstract class HranaTransaction implements Transaction {
|
||||
#private;
|
||||
/** @private */
|
||||
constructor(mode: TransactionMode, version: hrana.ProtocolVersion);
|
||||
/** @private */
|
||||
abstract _getStream(): hrana.Stream;
|
||||
/** @private */
|
||||
abstract _getSqlCache(): SqlCache;
|
||||
abstract close(): void;
|
||||
abstract get closed(): boolean;
|
||||
execute(stmt: InStatement): Promise<ResultSet>;
|
||||
batch(stmts: Array<InStatement>): Promise<Array<ResultSet>>;
|
||||
executeMultiple(sql: string): Promise<void>;
|
||||
rollback(): Promise<void>;
|
||||
commit(): Promise<void>;
|
||||
}
|
||||
export declare function executeHranaBatch(mode: TransactionMode, version: hrana.ProtocolVersion, batch: hrana.Batch, hranaStmts: Array<hrana.Stmt>, disableForeignKeys?: boolean): Promise<Array<ResultSet>>;
|
||||
export declare function stmtToHrana(stmt: InStatement | [string, InArgs?]): hrana.Stmt;
|
||||
export declare function resultSetFromHrana(hranaRows: hrana.RowsResult): ResultSet;
|
||||
export declare function mapHranaError(e: unknown): unknown;
|
||||
310
node_modules/@libsql/client/lib-esm/hrana.js
generated
vendored
Normal file
310
node_modules/@libsql/client/lib-esm/hrana.js
generated
vendored
Normal file
@@ -0,0 +1,310 @@
|
||||
import * as hrana from "@libsql/hrana-client";
|
||||
import { LibsqlError } from "@libsql/core/api";
|
||||
import { transactionModeToBegin, ResultSetImpl } from "@libsql/core/util";
|
||||
export class HranaTransaction {
|
||||
#mode;
|
||||
#version;
|
||||
// Promise that is resolved when the BEGIN statement completes, or `undefined` if we haven't executed the
|
||||
// BEGIN statement yet.
|
||||
#started;
|
||||
/** @private */
|
||||
constructor(mode, version) {
|
||||
this.#mode = mode;
|
||||
this.#version = version;
|
||||
this.#started = undefined;
|
||||
}
|
||||
execute(stmt) {
|
||||
return this.batch([stmt]).then((results) => results[0]);
|
||||
}
|
||||
async batch(stmts) {
|
||||
const stream = this._getStream();
|
||||
if (stream.closed) {
|
||||
throw new LibsqlError("Cannot execute statements because the transaction is closed", "TRANSACTION_CLOSED");
|
||||
}
|
||||
try {
|
||||
const hranaStmts = stmts.map(stmtToHrana);
|
||||
let rowsPromises;
|
||||
if (this.#started === undefined) {
|
||||
// The transaction hasn't started yet, so we need to send the BEGIN statement in a batch with
|
||||
// `hranaStmts`.
|
||||
this._getSqlCache().apply(hranaStmts);
|
||||
const batch = stream.batch(this.#version >= 3);
|
||||
const beginStep = batch.step();
|
||||
const beginPromise = beginStep.run(transactionModeToBegin(this.#mode));
|
||||
// Execute the `hranaStmts` only if the BEGIN succeeded, to make sure that we don't execute it
|
||||
// outside of a transaction.
|
||||
let lastStep = beginStep;
|
||||
rowsPromises = hranaStmts.map((hranaStmt) => {
|
||||
const stmtStep = batch
|
||||
.step()
|
||||
.condition(hrana.BatchCond.ok(lastStep));
|
||||
if (this.#version >= 3) {
|
||||
// If the Hrana version supports it, make sure that we are still in a transaction
|
||||
stmtStep.condition(hrana.BatchCond.not(hrana.BatchCond.isAutocommit(batch)));
|
||||
}
|
||||
const rowsPromise = stmtStep.query(hranaStmt);
|
||||
rowsPromise.catch(() => undefined); // silence Node warning
|
||||
lastStep = stmtStep;
|
||||
return rowsPromise;
|
||||
});
|
||||
// `this.#started` is resolved successfully only if the batch and the BEGIN statement inside
|
||||
// of the batch are both successful.
|
||||
this.#started = batch
|
||||
.execute()
|
||||
.then(() => beginPromise)
|
||||
.then(() => undefined);
|
||||
try {
|
||||
await this.#started;
|
||||
}
|
||||
catch (e) {
|
||||
// If the BEGIN failed, the transaction is unusable and we must close it. However, if the
|
||||
// BEGIN suceeds and `hranaStmts` fail, the transaction is _not_ closed.
|
||||
this.close();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (this.#version < 3) {
|
||||
// The transaction has started, so we must wait until the BEGIN statement completed to make
|
||||
// sure that we don't execute `hranaStmts` outside of a transaction.
|
||||
await this.#started;
|
||||
}
|
||||
else {
|
||||
// The transaction has started, but we will use `hrana.BatchCond.isAutocommit()` to make
|
||||
// sure that we don't execute `hranaStmts` outside of a transaction, so we don't have to
|
||||
// wait for `this.#started`
|
||||
}
|
||||
this._getSqlCache().apply(hranaStmts);
|
||||
const batch = stream.batch(this.#version >= 3);
|
||||
let lastStep = undefined;
|
||||
rowsPromises = hranaStmts.map((hranaStmt) => {
|
||||
const stmtStep = batch.step();
|
||||
if (lastStep !== undefined) {
|
||||
stmtStep.condition(hrana.BatchCond.ok(lastStep));
|
||||
}
|
||||
if (this.#version >= 3) {
|
||||
stmtStep.condition(hrana.BatchCond.not(hrana.BatchCond.isAutocommit(batch)));
|
||||
}
|
||||
const rowsPromise = stmtStep.query(hranaStmt);
|
||||
rowsPromise.catch(() => undefined); // silence Node warning
|
||||
lastStep = stmtStep;
|
||||
return rowsPromise;
|
||||
});
|
||||
await batch.execute();
|
||||
}
|
||||
const resultSets = [];
|
||||
for (const rowsPromise of rowsPromises) {
|
||||
const rows = await rowsPromise;
|
||||
if (rows === undefined) {
|
||||
throw new LibsqlError("Statement in a transaction was not executed, " +
|
||||
"probably because the transaction has been rolled back", "TRANSACTION_CLOSED");
|
||||
}
|
||||
resultSets.push(resultSetFromHrana(rows));
|
||||
}
|
||||
return resultSets;
|
||||
}
|
||||
catch (e) {
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
}
|
||||
async executeMultiple(sql) {
|
||||
const stream = this._getStream();
|
||||
if (stream.closed) {
|
||||
throw new LibsqlError("Cannot execute statements because the transaction is closed", "TRANSACTION_CLOSED");
|
||||
}
|
||||
try {
|
||||
if (this.#started === undefined) {
|
||||
// If the transaction hasn't started yet, start it now
|
||||
this.#started = stream
|
||||
.run(transactionModeToBegin(this.#mode))
|
||||
.then(() => undefined);
|
||||
try {
|
||||
await this.#started;
|
||||
}
|
||||
catch (e) {
|
||||
this.close();
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Wait until the transaction has started
|
||||
await this.#started;
|
||||
}
|
||||
await stream.sequence(sql);
|
||||
}
|
||||
catch (e) {
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
}
|
||||
async rollback() {
|
||||
try {
|
||||
const stream = this._getStream();
|
||||
if (stream.closed) {
|
||||
return;
|
||||
}
|
||||
if (this.#started !== undefined) {
|
||||
// We don't have to wait for the BEGIN statement to complete. If the BEGIN fails, we will
|
||||
// execute a ROLLBACK outside of an active transaction, which should be harmless.
|
||||
}
|
||||
else {
|
||||
// We did nothing in the transaction, so there is nothing to rollback.
|
||||
return;
|
||||
}
|
||||
// Pipeline the ROLLBACK statement and the stream close.
|
||||
const promise = stream.run("ROLLBACK").catch((e) => {
|
||||
throw mapHranaError(e);
|
||||
});
|
||||
stream.closeGracefully();
|
||||
await promise;
|
||||
}
|
||||
catch (e) {
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
finally {
|
||||
// `this.close()` may close the `hrana.Client`, which aborts all pending stream requests, so we
|
||||
// must call it _after_ we receive the ROLLBACK response.
|
||||
// Also note that the current stream should already be closed, but we need to call `this.close()`
|
||||
// anyway, because it may need to do more cleanup.
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
async commit() {
|
||||
// (this method is analogous to `rollback()`)
|
||||
try {
|
||||
const stream = this._getStream();
|
||||
if (stream.closed) {
|
||||
throw new LibsqlError("Cannot commit the transaction because it is already closed", "TRANSACTION_CLOSED");
|
||||
}
|
||||
if (this.#started !== undefined) {
|
||||
// Make sure to execute the COMMIT only if the BEGIN was successful.
|
||||
await this.#started;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
const promise = stream.run("COMMIT").catch((e) => {
|
||||
throw mapHranaError(e);
|
||||
});
|
||||
stream.closeGracefully();
|
||||
await promise;
|
||||
}
|
||||
catch (e) {
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
finally {
|
||||
this.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
export async function executeHranaBatch(mode, version, batch, hranaStmts, disableForeignKeys = false) {
|
||||
if (disableForeignKeys) {
|
||||
batch.step().run("PRAGMA foreign_keys=off");
|
||||
}
|
||||
const beginStep = batch.step();
|
||||
const beginPromise = beginStep.run(transactionModeToBegin(mode));
|
||||
let lastStep = beginStep;
|
||||
const stmtPromises = hranaStmts.map((hranaStmt) => {
|
||||
const stmtStep = batch.step().condition(hrana.BatchCond.ok(lastStep));
|
||||
if (version >= 3) {
|
||||
stmtStep.condition(hrana.BatchCond.not(hrana.BatchCond.isAutocommit(batch)));
|
||||
}
|
||||
const stmtPromise = stmtStep.query(hranaStmt);
|
||||
lastStep = stmtStep;
|
||||
return stmtPromise;
|
||||
});
|
||||
const commitStep = batch.step().condition(hrana.BatchCond.ok(lastStep));
|
||||
if (version >= 3) {
|
||||
commitStep.condition(hrana.BatchCond.not(hrana.BatchCond.isAutocommit(batch)));
|
||||
}
|
||||
const commitPromise = commitStep.run("COMMIT");
|
||||
const rollbackStep = batch
|
||||
.step()
|
||||
.condition(hrana.BatchCond.not(hrana.BatchCond.ok(commitStep)));
|
||||
rollbackStep.run("ROLLBACK").catch((_) => undefined);
|
||||
if (disableForeignKeys) {
|
||||
batch.step().run("PRAGMA foreign_keys=on");
|
||||
}
|
||||
await batch.execute();
|
||||
const resultSets = [];
|
||||
await beginPromise;
|
||||
for (const stmtPromise of stmtPromises) {
|
||||
const hranaRows = await stmtPromise;
|
||||
if (hranaRows === undefined) {
|
||||
throw new LibsqlError("Statement in a batch was not executed, probably because the transaction has been rolled back", "TRANSACTION_CLOSED");
|
||||
}
|
||||
resultSets.push(resultSetFromHrana(hranaRows));
|
||||
}
|
||||
await commitPromise;
|
||||
return resultSets;
|
||||
}
|
||||
export function stmtToHrana(stmt) {
|
||||
let sql;
|
||||
let args;
|
||||
if (Array.isArray(stmt)) {
|
||||
[sql, args] = stmt;
|
||||
}
|
||||
else if (typeof stmt === "string") {
|
||||
sql = stmt;
|
||||
}
|
||||
else {
|
||||
sql = stmt.sql;
|
||||
args = stmt.args;
|
||||
}
|
||||
const hranaStmt = new hrana.Stmt(sql);
|
||||
if (args) {
|
||||
if (Array.isArray(args)) {
|
||||
hranaStmt.bindIndexes(args);
|
||||
}
|
||||
else {
|
||||
for (const [key, value] of Object.entries(args)) {
|
||||
hranaStmt.bindName(key, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
return hranaStmt;
|
||||
}
|
||||
export function resultSetFromHrana(hranaRows) {
|
||||
const columns = hranaRows.columnNames.map((c) => c ?? "");
|
||||
const columnTypes = hranaRows.columnDecltypes.map((c) => c ?? "");
|
||||
const rows = hranaRows.rows;
|
||||
const rowsAffected = hranaRows.affectedRowCount;
|
||||
const lastInsertRowid = hranaRows.lastInsertRowid !== undefined
|
||||
? hranaRows.lastInsertRowid
|
||||
: undefined;
|
||||
return new ResultSetImpl(columns, columnTypes, rows, rowsAffected, lastInsertRowid);
|
||||
}
|
||||
export function mapHranaError(e) {
|
||||
if (e instanceof hrana.ClientError) {
|
||||
const code = mapHranaErrorCode(e);
|
||||
return new LibsqlError(e.message, code, undefined, e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
function mapHranaErrorCode(e) {
|
||||
if (e instanceof hrana.ResponseError && e.code !== undefined) {
|
||||
return e.code;
|
||||
}
|
||||
else if (e instanceof hrana.ProtoError) {
|
||||
return "HRANA_PROTO_ERROR";
|
||||
}
|
||||
else if (e instanceof hrana.ClosedError) {
|
||||
return e.cause instanceof hrana.ClientError
|
||||
? mapHranaErrorCode(e.cause)
|
||||
: "HRANA_CLOSED_ERROR";
|
||||
}
|
||||
else if (e instanceof hrana.WebSocketError) {
|
||||
return "HRANA_WEBSOCKET_ERROR";
|
||||
}
|
||||
else if (e instanceof hrana.HttpServerError) {
|
||||
return "SERVER_ERROR";
|
||||
}
|
||||
else if (e instanceof hrana.ProtocolVersionError) {
|
||||
return "PROTOCOL_VERSION_ERROR";
|
||||
}
|
||||
else if (e instanceof hrana.InternalError) {
|
||||
return "INTERNAL_ERROR";
|
||||
}
|
||||
else {
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
39
node_modules/@libsql/client/lib-esm/http.d.ts
generated
vendored
Normal file
39
node_modules/@libsql/client/lib-esm/http.d.ts
generated
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
/// <reference types="node" />
|
||||
import * as hrana from "@libsql/hrana-client";
|
||||
import type { Config, Client } from "@libsql/core/api";
|
||||
import type { InStatement, ResultSet, Transaction, IntMode, InArgs, Replicated } from "@libsql/core/api";
|
||||
import { TransactionMode } from "@libsql/core/api";
|
||||
import type { ExpandedConfig } from "@libsql/core/config";
|
||||
import { HranaTransaction } from "./hrana.js";
|
||||
import { SqlCache } from "./sql_cache.js";
|
||||
export * from "@libsql/core/api";
|
||||
export declare function createClient(config: Config): Client;
|
||||
/** @private */
|
||||
export declare function _createClient(config: ExpandedConfig): Client;
|
||||
export declare class HttpClient implements Client {
|
||||
#private;
|
||||
protocol: "http";
|
||||
/** @private */
|
||||
constructor(url: URL, authToken: string | undefined, intMode: IntMode, customFetch: Function | undefined, concurrency: number);
|
||||
private limit;
|
||||
execute(stmtOrSql: InStatement | string, args?: InArgs): Promise<ResultSet>;
|
||||
batch(stmts: Array<InStatement | [string, InArgs?]>, mode?: TransactionMode): Promise<Array<ResultSet>>;
|
||||
migrate(stmts: Array<InStatement>): Promise<Array<ResultSet>>;
|
||||
transaction(mode?: TransactionMode): Promise<HttpTransaction>;
|
||||
executeMultiple(sql: string): Promise<void>;
|
||||
sync(): Promise<Replicated>;
|
||||
close(): void;
|
||||
reconnect(): Promise<void>;
|
||||
get closed(): boolean;
|
||||
}
|
||||
export declare class HttpTransaction extends HranaTransaction implements Transaction {
|
||||
#private;
|
||||
/** @private */
|
||||
constructor(stream: hrana.HttpStream, mode: TransactionMode, version: hrana.ProtocolVersion);
|
||||
/** @private */
|
||||
_getStream(): hrana.Stream;
|
||||
/** @private */
|
||||
_getSqlCache(): SqlCache;
|
||||
close(): void;
|
||||
get closed(): boolean;
|
||||
}
|
||||
230
node_modules/@libsql/client/lib-esm/http.js
generated
vendored
Normal file
230
node_modules/@libsql/client/lib-esm/http.js
generated
vendored
Normal file
@@ -0,0 +1,230 @@
|
||||
import * as hrana from "@libsql/hrana-client";
|
||||
import { LibsqlError } from "@libsql/core/api";
|
||||
import { expandConfig } from "@libsql/core/config";
|
||||
import { HranaTransaction, executeHranaBatch, stmtToHrana, resultSetFromHrana, mapHranaError, } from "./hrana.js";
|
||||
import { SqlCache } from "./sql_cache.js";
|
||||
import { encodeBaseUrl } from "@libsql/core/uri";
|
||||
import { supportedUrlLink } from "@libsql/core/util";
|
||||
import promiseLimit from "promise-limit";
|
||||
export * from "@libsql/core/api";
|
||||
export function createClient(config) {
|
||||
return _createClient(expandConfig(config, true));
|
||||
}
|
||||
/** @private */
|
||||
export function _createClient(config) {
|
||||
if (config.scheme !== "https" && config.scheme !== "http") {
|
||||
throw new LibsqlError('The HTTP client supports only "libsql:", "https:" and "http:" URLs, ' +
|
||||
`got ${JSON.stringify(config.scheme + ":")}. For more information, please read ${supportedUrlLink}`, "URL_SCHEME_NOT_SUPPORTED");
|
||||
}
|
||||
if (config.encryptionKey !== undefined) {
|
||||
throw new LibsqlError("Encryption key is not supported by the remote client.", "ENCRYPTION_KEY_NOT_SUPPORTED");
|
||||
}
|
||||
if (config.scheme === "http" && config.tls) {
|
||||
throw new LibsqlError(`A "http:" URL cannot opt into TLS by using ?tls=1`, "URL_INVALID");
|
||||
}
|
||||
else if (config.scheme === "https" && !config.tls) {
|
||||
throw new LibsqlError(`A "https:" URL cannot opt out of TLS by using ?tls=0`, "URL_INVALID");
|
||||
}
|
||||
const url = encodeBaseUrl(config.scheme, config.authority, config.path);
|
||||
return new HttpClient(url, config.authToken, config.intMode, config.fetch, config.concurrency);
|
||||
}
|
||||
const sqlCacheCapacity = 30;
|
||||
export class HttpClient {
|
||||
#client;
|
||||
protocol;
|
||||
#url;
|
||||
#intMode;
|
||||
#customFetch;
|
||||
#concurrency;
|
||||
#authToken;
|
||||
#promiseLimitFunction;
|
||||
/** @private */
|
||||
constructor(url, authToken, intMode, customFetch, concurrency) {
|
||||
this.#url = url;
|
||||
this.#authToken = authToken;
|
||||
this.#intMode = intMode;
|
||||
this.#customFetch = customFetch;
|
||||
this.#concurrency = concurrency;
|
||||
this.#client = hrana.openHttp(this.#url, this.#authToken, this.#customFetch);
|
||||
this.#client.intMode = this.#intMode;
|
||||
this.protocol = "http";
|
||||
this.#promiseLimitFunction = promiseLimit(this.#concurrency);
|
||||
}
|
||||
async limit(fn) {
|
||||
return this.#promiseLimitFunction(fn);
|
||||
}
|
||||
async execute(stmtOrSql, args) {
|
||||
let stmt;
|
||||
if (typeof stmtOrSql === "string") {
|
||||
stmt = {
|
||||
sql: stmtOrSql,
|
||||
args: args || [],
|
||||
};
|
||||
}
|
||||
else {
|
||||
stmt = stmtOrSql;
|
||||
}
|
||||
return this.limit(async () => {
|
||||
try {
|
||||
const hranaStmt = stmtToHrana(stmt);
|
||||
// Pipeline all operations, so `hrana.HttpClient` can open the stream, execute the statement and
|
||||
// close the stream in a single HTTP request.
|
||||
let rowsPromise;
|
||||
const stream = this.#client.openStream();
|
||||
try {
|
||||
rowsPromise = stream.query(hranaStmt);
|
||||
}
|
||||
finally {
|
||||
stream.closeGracefully();
|
||||
}
|
||||
const rowsResult = await rowsPromise;
|
||||
return resultSetFromHrana(rowsResult);
|
||||
}
|
||||
catch (e) {
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
async batch(stmts, mode = "deferred") {
|
||||
return this.limit(async () => {
|
||||
try {
|
||||
const normalizedStmts = stmts.map((stmt) => {
|
||||
if (Array.isArray(stmt)) {
|
||||
return {
|
||||
sql: stmt[0],
|
||||
args: stmt[1] || [],
|
||||
};
|
||||
}
|
||||
return stmt;
|
||||
});
|
||||
const hranaStmts = normalizedStmts.map(stmtToHrana);
|
||||
const version = await this.#client.getVersion();
|
||||
// Pipeline all operations, so `hrana.HttpClient` can open the stream, execute the batch and
|
||||
// close the stream in a single HTTP request.
|
||||
let resultsPromise;
|
||||
const stream = this.#client.openStream();
|
||||
try {
|
||||
// It makes sense to use a SQL cache even for a single batch, because it may contain the same
|
||||
// statement repeated multiple times.
|
||||
const sqlCache = new SqlCache(stream, sqlCacheCapacity);
|
||||
sqlCache.apply(hranaStmts);
|
||||
// TODO: we do not use a cursor here, because it would cause three roundtrips:
|
||||
// 1. pipeline request to store SQL texts
|
||||
// 2. cursor request
|
||||
// 3. pipeline request to close the stream
|
||||
const batch = stream.batch(false);
|
||||
resultsPromise = executeHranaBatch(mode, version, batch, hranaStmts);
|
||||
}
|
||||
finally {
|
||||
stream.closeGracefully();
|
||||
}
|
||||
const results = await resultsPromise;
|
||||
return results;
|
||||
}
|
||||
catch (e) {
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
async migrate(stmts) {
|
||||
return this.limit(async () => {
|
||||
try {
|
||||
const hranaStmts = stmts.map(stmtToHrana);
|
||||
const version = await this.#client.getVersion();
|
||||
// Pipeline all operations, so `hrana.HttpClient` can open the stream, execute the batch and
|
||||
// close the stream in a single HTTP request.
|
||||
let resultsPromise;
|
||||
const stream = this.#client.openStream();
|
||||
try {
|
||||
const batch = stream.batch(false);
|
||||
resultsPromise = executeHranaBatch("deferred", version, batch, hranaStmts, true);
|
||||
}
|
||||
finally {
|
||||
stream.closeGracefully();
|
||||
}
|
||||
const results = await resultsPromise;
|
||||
return results;
|
||||
}
|
||||
catch (e) {
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
async transaction(mode = "write") {
|
||||
return this.limit(async () => {
|
||||
try {
|
||||
const version = await this.#client.getVersion();
|
||||
return new HttpTransaction(this.#client.openStream(), mode, version);
|
||||
}
|
||||
catch (e) {
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
async executeMultiple(sql) {
|
||||
return this.limit(async () => {
|
||||
try {
|
||||
// Pipeline all operations, so `hrana.HttpClient` can open the stream, execute the sequence and
|
||||
// close the stream in a single HTTP request.
|
||||
let promise;
|
||||
const stream = this.#client.openStream();
|
||||
try {
|
||||
promise = stream.sequence(sql);
|
||||
}
|
||||
finally {
|
||||
stream.closeGracefully();
|
||||
}
|
||||
await promise;
|
||||
}
|
||||
catch (e) {
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
sync() {
|
||||
throw new LibsqlError("sync not supported in http mode", "SYNC_NOT_SUPPORTED");
|
||||
}
|
||||
close() {
|
||||
this.#client.close();
|
||||
}
|
||||
async reconnect() {
|
||||
try {
|
||||
if (!this.closed) {
|
||||
// Abort in-flight ops and free resources
|
||||
this.#client.close();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
// Recreate the underlying hrana client
|
||||
this.#client = hrana.openHttp(this.#url, this.#authToken, this.#customFetch);
|
||||
this.#client.intMode = this.#intMode;
|
||||
}
|
||||
}
|
||||
get closed() {
|
||||
return this.#client.closed;
|
||||
}
|
||||
}
|
||||
export class HttpTransaction extends HranaTransaction {
|
||||
#stream;
|
||||
#sqlCache;
|
||||
/** @private */
|
||||
constructor(stream, mode, version) {
|
||||
super(mode, version);
|
||||
this.#stream = stream;
|
||||
this.#sqlCache = new SqlCache(stream, sqlCacheCapacity);
|
||||
}
|
||||
/** @private */
|
||||
_getStream() {
|
||||
return this.#stream;
|
||||
}
|
||||
/** @private */
|
||||
_getSqlCache() {
|
||||
return this.#sqlCache;
|
||||
}
|
||||
close() {
|
||||
this.#stream.close();
|
||||
}
|
||||
get closed() {
|
||||
return this.#stream.closed;
|
||||
}
|
||||
}
|
||||
7
node_modules/@libsql/client/lib-esm/node.d.ts
generated
vendored
Normal file
7
node_modules/@libsql/client/lib-esm/node.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import type { Config, Client } from "@libsql/core/api";
|
||||
export * from "@libsql/core/api";
|
||||
/** Creates a {@link Client} object.
|
||||
*
|
||||
* You must pass at least an `url` in the {@link Config} object.
|
||||
*/
|
||||
export declare function createClient(config: Config): Client;
|
||||
23
node_modules/@libsql/client/lib-esm/node.js
generated
vendored
Normal file
23
node_modules/@libsql/client/lib-esm/node.js
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
import { expandConfig } from "@libsql/core/config";
|
||||
import { _createClient as _createSqlite3Client } from "./sqlite3.js";
|
||||
import { _createClient as _createWsClient } from "./ws.js";
|
||||
import { _createClient as _createHttpClient } from "./http.js";
|
||||
export * from "@libsql/core/api";
|
||||
/** Creates a {@link Client} object.
|
||||
*
|
||||
* You must pass at least an `url` in the {@link Config} object.
|
||||
*/
|
||||
export function createClient(config) {
|
||||
return _createClient(expandConfig(config, true));
|
||||
}
|
||||
function _createClient(config) {
|
||||
if (config.scheme === "wss" || config.scheme === "ws") {
|
||||
return _createWsClient(config);
|
||||
}
|
||||
else if (config.scheme === "https" || config.scheme === "http") {
|
||||
return _createHttpClient(config);
|
||||
}
|
||||
else {
|
||||
return _createSqlite3Client(config);
|
||||
}
|
||||
}
|
||||
7
node_modules/@libsql/client/lib-esm/sql_cache.d.ts
generated
vendored
Normal file
7
node_modules/@libsql/client/lib-esm/sql_cache.d.ts
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
import type * as hrana from "@libsql/hrana-client";
|
||||
export declare class SqlCache {
|
||||
#private;
|
||||
capacity: number;
|
||||
constructor(owner: hrana.SqlOwner, capacity: number);
|
||||
apply(hranaStmts: Array<hrana.Stmt>): void;
|
||||
}
|
||||
87
node_modules/@libsql/client/lib-esm/sql_cache.js
generated
vendored
Normal file
87
node_modules/@libsql/client/lib-esm/sql_cache.js
generated
vendored
Normal file
@@ -0,0 +1,87 @@
|
||||
export class SqlCache {
|
||||
#owner;
|
||||
#sqls;
|
||||
capacity;
|
||||
constructor(owner, capacity) {
|
||||
this.#owner = owner;
|
||||
this.#sqls = new Lru();
|
||||
this.capacity = capacity;
|
||||
}
|
||||
// Replaces SQL strings with cached `hrana.Sql` objects in the statements in `hranaStmts`. After this
|
||||
// function returns, we guarantee that all `hranaStmts` refer to valid (not closed) `hrana.Sql` objects,
|
||||
// but _we may invalidate any other `hrana.Sql` objects_ (by closing them, thus removing them from the
|
||||
// server).
|
||||
//
|
||||
// In practice, this means that after calling this function, you can use the statements only up to the
|
||||
// first `await`, because concurrent code may also use the cache and invalidate those statements.
|
||||
apply(hranaStmts) {
|
||||
if (this.capacity <= 0) {
|
||||
return;
|
||||
}
|
||||
const usedSqlObjs = new Set();
|
||||
for (const hranaStmt of hranaStmts) {
|
||||
if (typeof hranaStmt.sql !== "string") {
|
||||
continue;
|
||||
}
|
||||
const sqlText = hranaStmt.sql;
|
||||
// Stored SQL cannot exceed 5kb.
|
||||
// https://github.com/tursodatabase/libsql/blob/e9d637e051685f92b0da43849507b5ef4232fbeb/libsql-server/src/hrana/http/request.rs#L10
|
||||
if (sqlText.length >= 5000) {
|
||||
continue;
|
||||
}
|
||||
let sqlObj = this.#sqls.get(sqlText);
|
||||
if (sqlObj === undefined) {
|
||||
while (this.#sqls.size + 1 > this.capacity) {
|
||||
const [evictSqlText, evictSqlObj] = this.#sqls.peekLru();
|
||||
if (usedSqlObjs.has(evictSqlObj)) {
|
||||
// The SQL object that we are trying to evict is already in use in this batch, so we
|
||||
// must not evict and close it.
|
||||
break;
|
||||
}
|
||||
evictSqlObj.close();
|
||||
this.#sqls.delete(evictSqlText);
|
||||
}
|
||||
if (this.#sqls.size + 1 <= this.capacity) {
|
||||
sqlObj = this.#owner.storeSql(sqlText);
|
||||
this.#sqls.set(sqlText, sqlObj);
|
||||
}
|
||||
}
|
||||
if (sqlObj !== undefined) {
|
||||
hranaStmt.sql = sqlObj;
|
||||
usedSqlObjs.add(sqlObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
class Lru {
|
||||
// This maps keys to the cache values. The entries are ordered by their last use (entires that were used
|
||||
// most recently are at the end).
|
||||
#cache;
|
||||
constructor() {
|
||||
this.#cache = new Map();
|
||||
}
|
||||
get(key) {
|
||||
const value = this.#cache.get(key);
|
||||
if (value !== undefined) {
|
||||
// move the entry to the back of the Map
|
||||
this.#cache.delete(key);
|
||||
this.#cache.set(key, value);
|
||||
}
|
||||
return value;
|
||||
}
|
||||
set(key, value) {
|
||||
this.#cache.set(key, value);
|
||||
}
|
||||
peekLru() {
|
||||
for (const entry of this.#cache.entries()) {
|
||||
return entry;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
delete(key) {
|
||||
this.#cache.delete(key);
|
||||
}
|
||||
get size() {
|
||||
return this.#cache.size;
|
||||
}
|
||||
}
|
||||
35
node_modules/@libsql/client/lib-esm/sqlite3.d.ts
generated
vendored
Normal file
35
node_modules/@libsql/client/lib-esm/sqlite3.d.ts
generated
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
import Database from "libsql";
|
||||
import type { Config, IntMode, Client, Transaction, TransactionMode, ResultSet, InStatement, InArgs, Replicated } from "@libsql/core/api";
|
||||
import type { ExpandedConfig } from "@libsql/core/config";
|
||||
export * from "@libsql/core/api";
|
||||
export declare function createClient(config: Config): Client;
|
||||
/** @private */
|
||||
export declare function _createClient(config: ExpandedConfig): Client;
|
||||
export declare class Sqlite3Client implements Client {
|
||||
#private;
|
||||
closed: boolean;
|
||||
protocol: "file";
|
||||
/** @private */
|
||||
constructor(path: string, options: Database.Options, db: Database.Database, intMode: IntMode);
|
||||
execute(stmtOrSql: InStatement | string, args?: InArgs): Promise<ResultSet>;
|
||||
batch(stmts: Array<InStatement | [string, InArgs?]>, mode?: TransactionMode): Promise<Array<ResultSet>>;
|
||||
migrate(stmts: Array<InStatement>): Promise<Array<ResultSet>>;
|
||||
transaction(mode?: TransactionMode): Promise<Transaction>;
|
||||
executeMultiple(sql: string): Promise<void>;
|
||||
sync(): Promise<Replicated>;
|
||||
reconnect(): Promise<void>;
|
||||
close(): void;
|
||||
}
|
||||
export declare class Sqlite3Transaction implements Transaction {
|
||||
#private;
|
||||
/** @private */
|
||||
constructor(database: Database.Database, intMode: IntMode);
|
||||
execute(stmt: InStatement): Promise<ResultSet>;
|
||||
execute(sql: string, args?: InArgs): Promise<ResultSet>;
|
||||
batch(stmts: Array<InStatement | [string, InArgs?]>): Promise<Array<ResultSet>>;
|
||||
executeMultiple(sql: string): Promise<void>;
|
||||
rollback(): Promise<void>;
|
||||
commit(): Promise<void>;
|
||||
close(): void;
|
||||
get closed(): boolean;
|
||||
}
|
||||
395
node_modules/@libsql/client/lib-esm/sqlite3.js
generated
vendored
Normal file
395
node_modules/@libsql/client/lib-esm/sqlite3.js
generated
vendored
Normal file
@@ -0,0 +1,395 @@
|
||||
import Database from "libsql";
|
||||
import { Buffer } from "node:buffer";
|
||||
import { LibsqlError } from "@libsql/core/api";
|
||||
import { expandConfig, isInMemoryConfig } from "@libsql/core/config";
|
||||
import { supportedUrlLink, transactionModeToBegin, ResultSetImpl, } from "@libsql/core/util";
|
||||
export * from "@libsql/core/api";
|
||||
export function createClient(config) {
|
||||
return _createClient(expandConfig(config, true));
|
||||
}
|
||||
/** @private */
|
||||
export function _createClient(config) {
|
||||
if (config.scheme !== "file") {
|
||||
throw new LibsqlError(`URL scheme ${JSON.stringify(config.scheme + ":")} is not supported by the local sqlite3 client. ` +
|
||||
`For more information, please read ${supportedUrlLink}`, "URL_SCHEME_NOT_SUPPORTED");
|
||||
}
|
||||
const authority = config.authority;
|
||||
if (authority !== undefined) {
|
||||
const host = authority.host.toLowerCase();
|
||||
if (host !== "" && host !== "localhost") {
|
||||
throw new LibsqlError(`Invalid host in file URL: ${JSON.stringify(authority.host)}. ` +
|
||||
'A "file:" URL with an absolute path should start with one slash ("file:/absolute/path.db") ' +
|
||||
'or with three slashes ("file:///absolute/path.db"). ' +
|
||||
`For more information, please read ${supportedUrlLink}`, "URL_INVALID");
|
||||
}
|
||||
if (authority.port !== undefined) {
|
||||
throw new LibsqlError("File URL cannot have a port", "URL_INVALID");
|
||||
}
|
||||
if (authority.userinfo !== undefined) {
|
||||
throw new LibsqlError("File URL cannot have username and password", "URL_INVALID");
|
||||
}
|
||||
}
|
||||
let isInMemory = isInMemoryConfig(config);
|
||||
if (isInMemory && config.syncUrl) {
|
||||
throw new LibsqlError(`Embedded replica must use file for local db but URI with in-memory mode were provided instead: ${config.path}`, "URL_INVALID");
|
||||
}
|
||||
let path = config.path;
|
||||
if (isInMemory) {
|
||||
// note: we should prepend file scheme in order for SQLite3 to recognize :memory: connection query parameters
|
||||
path = `${config.scheme}:${config.path}`;
|
||||
}
|
||||
const options = {
|
||||
authToken: config.authToken,
|
||||
encryptionKey: config.encryptionKey,
|
||||
syncUrl: config.syncUrl,
|
||||
syncPeriod: config.syncInterval,
|
||||
readYourWrites: config.readYourWrites,
|
||||
offline: config.offline,
|
||||
};
|
||||
const db = new Database(path, options);
|
||||
executeStmt(db, "SELECT 1 AS checkThatTheDatabaseCanBeOpened", config.intMode);
|
||||
return new Sqlite3Client(path, options, db, config.intMode);
|
||||
}
|
||||
export class Sqlite3Client {
|
||||
#path;
|
||||
#options;
|
||||
#db;
|
||||
#intMode;
|
||||
closed;
|
||||
protocol;
|
||||
/** @private */
|
||||
constructor(path, options, db, intMode) {
|
||||
this.#path = path;
|
||||
this.#options = options;
|
||||
this.#db = db;
|
||||
this.#intMode = intMode;
|
||||
this.closed = false;
|
||||
this.protocol = "file";
|
||||
}
|
||||
async execute(stmtOrSql, args) {
|
||||
let stmt;
|
||||
if (typeof stmtOrSql === "string") {
|
||||
stmt = {
|
||||
sql: stmtOrSql,
|
||||
args: args || [],
|
||||
};
|
||||
}
|
||||
else {
|
||||
stmt = stmtOrSql;
|
||||
}
|
||||
this.#checkNotClosed();
|
||||
return executeStmt(this.#getDb(), stmt, this.#intMode);
|
||||
}
|
||||
async batch(stmts, mode = "deferred") {
|
||||
this.#checkNotClosed();
|
||||
const db = this.#getDb();
|
||||
try {
|
||||
executeStmt(db, transactionModeToBegin(mode), this.#intMode);
|
||||
const resultSets = stmts.map((stmt) => {
|
||||
if (!db.inTransaction) {
|
||||
throw new LibsqlError("The transaction has been rolled back", "TRANSACTION_CLOSED");
|
||||
}
|
||||
const normalizedStmt = Array.isArray(stmt)
|
||||
? { sql: stmt[0], args: stmt[1] || [] }
|
||||
: stmt;
|
||||
return executeStmt(db, normalizedStmt, this.#intMode);
|
||||
});
|
||||
executeStmt(db, "COMMIT", this.#intMode);
|
||||
return resultSets;
|
||||
}
|
||||
finally {
|
||||
if (db.inTransaction) {
|
||||
executeStmt(db, "ROLLBACK", this.#intMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
async migrate(stmts) {
|
||||
this.#checkNotClosed();
|
||||
const db = this.#getDb();
|
||||
try {
|
||||
executeStmt(db, "PRAGMA foreign_keys=off", this.#intMode);
|
||||
executeStmt(db, transactionModeToBegin("deferred"), this.#intMode);
|
||||
const resultSets = stmts.map((stmt) => {
|
||||
if (!db.inTransaction) {
|
||||
throw new LibsqlError("The transaction has been rolled back", "TRANSACTION_CLOSED");
|
||||
}
|
||||
return executeStmt(db, stmt, this.#intMode);
|
||||
});
|
||||
executeStmt(db, "COMMIT", this.#intMode);
|
||||
return resultSets;
|
||||
}
|
||||
finally {
|
||||
if (db.inTransaction) {
|
||||
executeStmt(db, "ROLLBACK", this.#intMode);
|
||||
}
|
||||
executeStmt(db, "PRAGMA foreign_keys=on", this.#intMode);
|
||||
}
|
||||
}
|
||||
async transaction(mode = "write") {
|
||||
const db = this.#getDb();
|
||||
executeStmt(db, transactionModeToBegin(mode), this.#intMode);
|
||||
this.#db = null; // A new connection will be lazily created on next use
|
||||
return new Sqlite3Transaction(db, this.#intMode);
|
||||
}
|
||||
async executeMultiple(sql) {
|
||||
this.#checkNotClosed();
|
||||
const db = this.#getDb();
|
||||
try {
|
||||
return executeMultiple(db, sql);
|
||||
}
|
||||
finally {
|
||||
if (db.inTransaction) {
|
||||
executeStmt(db, "ROLLBACK", this.#intMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
async sync() {
|
||||
this.#checkNotClosed();
|
||||
const rep = await this.#getDb().sync();
|
||||
return {
|
||||
frames_synced: rep.frames_synced,
|
||||
frame_no: rep.frame_no,
|
||||
};
|
||||
}
|
||||
async reconnect() {
|
||||
try {
|
||||
if (!this.closed && this.#db !== null) {
|
||||
this.#db.close();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
this.#db = new Database(this.#path, this.#options);
|
||||
this.closed = false;
|
||||
}
|
||||
}
|
||||
close() {
|
||||
this.closed = true;
|
||||
if (this.#db !== null) {
|
||||
this.#db.close();
|
||||
this.#db = null;
|
||||
}
|
||||
}
|
||||
#checkNotClosed() {
|
||||
if (this.closed) {
|
||||
throw new LibsqlError("The client is closed", "CLIENT_CLOSED");
|
||||
}
|
||||
}
|
||||
// Lazily creates the database connection and returns it
|
||||
#getDb() {
|
||||
if (this.#db === null) {
|
||||
this.#db = new Database(this.#path, this.#options);
|
||||
}
|
||||
return this.#db;
|
||||
}
|
||||
}
|
||||
export class Sqlite3Transaction {
|
||||
#database;
|
||||
#intMode;
|
||||
/** @private */
|
||||
constructor(database, intMode) {
|
||||
this.#database = database;
|
||||
this.#intMode = intMode;
|
||||
}
|
||||
async execute(stmtOrSql, args) {
|
||||
let stmt;
|
||||
if (typeof stmtOrSql === "string") {
|
||||
stmt = {
|
||||
sql: stmtOrSql,
|
||||
args: args || [],
|
||||
};
|
||||
}
|
||||
else {
|
||||
stmt = stmtOrSql;
|
||||
}
|
||||
this.#checkNotClosed();
|
||||
return executeStmt(this.#database, stmt, this.#intMode);
|
||||
}
|
||||
async batch(stmts) {
|
||||
return stmts.map((stmt) => {
|
||||
this.#checkNotClosed();
|
||||
const normalizedStmt = Array.isArray(stmt)
|
||||
? { sql: stmt[0], args: stmt[1] || [] }
|
||||
: stmt;
|
||||
return executeStmt(this.#database, normalizedStmt, this.#intMode);
|
||||
});
|
||||
}
|
||||
async executeMultiple(sql) {
|
||||
this.#checkNotClosed();
|
||||
return executeMultiple(this.#database, sql);
|
||||
}
|
||||
async rollback() {
|
||||
if (!this.#database.open) {
|
||||
return;
|
||||
}
|
||||
this.#checkNotClosed();
|
||||
executeStmt(this.#database, "ROLLBACK", this.#intMode);
|
||||
}
|
||||
async commit() {
|
||||
this.#checkNotClosed();
|
||||
executeStmt(this.#database, "COMMIT", this.#intMode);
|
||||
}
|
||||
close() {
|
||||
if (this.#database.inTransaction) {
|
||||
executeStmt(this.#database, "ROLLBACK", this.#intMode);
|
||||
}
|
||||
}
|
||||
get closed() {
|
||||
return !this.#database.inTransaction;
|
||||
}
|
||||
#checkNotClosed() {
|
||||
if (this.closed) {
|
||||
throw new LibsqlError("The transaction is closed", "TRANSACTION_CLOSED");
|
||||
}
|
||||
}
|
||||
}
|
||||
function executeStmt(db, stmt, intMode) {
|
||||
let sql;
|
||||
let args;
|
||||
if (typeof stmt === "string") {
|
||||
sql = stmt;
|
||||
args = [];
|
||||
}
|
||||
else {
|
||||
sql = stmt.sql;
|
||||
if (Array.isArray(stmt.args)) {
|
||||
args = stmt.args.map((value) => valueToSql(value, intMode));
|
||||
}
|
||||
else {
|
||||
args = {};
|
||||
for (const name in stmt.args) {
|
||||
const argName = name[0] === "@" || name[0] === "$" || name[0] === ":"
|
||||
? name.substring(1)
|
||||
: name;
|
||||
args[argName] = valueToSql(stmt.args[name], intMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
try {
|
||||
const sqlStmt = db.prepare(sql);
|
||||
sqlStmt.safeIntegers(true);
|
||||
let returnsData = true;
|
||||
try {
|
||||
sqlStmt.raw(true);
|
||||
}
|
||||
catch {
|
||||
// raw() throws an exception if the statement does not return data
|
||||
returnsData = false;
|
||||
}
|
||||
if (returnsData) {
|
||||
const columns = Array.from(sqlStmt.columns().map((col) => col.name));
|
||||
const columnTypes = Array.from(sqlStmt.columns().map((col) => col.type ?? ""));
|
||||
const rows = sqlStmt.all(args).map((sqlRow) => {
|
||||
return rowFromSql(sqlRow, columns, intMode);
|
||||
});
|
||||
// TODO: can we get this info from better-sqlite3?
|
||||
const rowsAffected = 0;
|
||||
const lastInsertRowid = undefined;
|
||||
return new ResultSetImpl(columns, columnTypes, rows, rowsAffected, lastInsertRowid);
|
||||
}
|
||||
else {
|
||||
const info = sqlStmt.run(args);
|
||||
const rowsAffected = info.changes;
|
||||
const lastInsertRowid = BigInt(info.lastInsertRowid);
|
||||
return new ResultSetImpl([], [], [], rowsAffected, lastInsertRowid);
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
throw mapSqliteError(e);
|
||||
}
|
||||
}
|
||||
function rowFromSql(sqlRow, columns, intMode) {
|
||||
const row = {};
|
||||
// make sure that the "length" property is not enumerable
|
||||
Object.defineProperty(row, "length", { value: sqlRow.length });
|
||||
for (let i = 0; i < sqlRow.length; ++i) {
|
||||
const value = valueFromSql(sqlRow[i], intMode);
|
||||
Object.defineProperty(row, i, { value });
|
||||
const column = columns[i];
|
||||
if (!Object.hasOwn(row, column)) {
|
||||
Object.defineProperty(row, column, {
|
||||
value,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
writable: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
return row;
|
||||
}
|
||||
function valueFromSql(sqlValue, intMode) {
|
||||
if (typeof sqlValue === "bigint") {
|
||||
if (intMode === "number") {
|
||||
if (sqlValue < minSafeBigint || sqlValue > maxSafeBigint) {
|
||||
throw new RangeError("Received integer which cannot be safely represented as a JavaScript number");
|
||||
}
|
||||
return Number(sqlValue);
|
||||
}
|
||||
else if (intMode === "bigint") {
|
||||
return sqlValue;
|
||||
}
|
||||
else if (intMode === "string") {
|
||||
return "" + sqlValue;
|
||||
}
|
||||
else {
|
||||
throw new Error("Invalid value for IntMode");
|
||||
}
|
||||
}
|
||||
else if (sqlValue instanceof Buffer) {
|
||||
return sqlValue.buffer;
|
||||
}
|
||||
return sqlValue;
|
||||
}
|
||||
const minSafeBigint = -9007199254740991n;
|
||||
const maxSafeBigint = 9007199254740991n;
|
||||
function valueToSql(value, intMode) {
|
||||
if (typeof value === "number") {
|
||||
if (!Number.isFinite(value)) {
|
||||
throw new RangeError("Only finite numbers (not Infinity or NaN) can be passed as arguments");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
else if (typeof value === "bigint") {
|
||||
if (value < minInteger || value > maxInteger) {
|
||||
throw new RangeError("bigint is too large to be represented as a 64-bit integer and passed as argument");
|
||||
}
|
||||
return value;
|
||||
}
|
||||
else if (typeof value === "boolean") {
|
||||
switch (intMode) {
|
||||
case "bigint":
|
||||
return value ? 1n : 0n;
|
||||
case "string":
|
||||
return value ? "1" : "0";
|
||||
default:
|
||||
return value ? 1 : 0;
|
||||
}
|
||||
}
|
||||
else if (value instanceof ArrayBuffer) {
|
||||
return Buffer.from(value);
|
||||
}
|
||||
else if (value instanceof Date) {
|
||||
return value.valueOf();
|
||||
}
|
||||
else if (value === undefined) {
|
||||
throw new TypeError("undefined cannot be passed as argument to the database");
|
||||
}
|
||||
else {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
const minInteger = -9223372036854775808n;
|
||||
const maxInteger = 9223372036854775807n;
|
||||
function executeMultiple(db, sql) {
|
||||
try {
|
||||
db.exec(sql);
|
||||
}
|
||||
catch (e) {
|
||||
throw mapSqliteError(e);
|
||||
}
|
||||
}
|
||||
function mapSqliteError(e) {
|
||||
if (e instanceof Database.SqliteError) {
|
||||
return new LibsqlError(e.message, e.code, e.rawCode, e);
|
||||
}
|
||||
return e;
|
||||
}
|
||||
6
node_modules/@libsql/client/lib-esm/web.d.ts
generated
vendored
Normal file
6
node_modules/@libsql/client/lib-esm/web.d.ts
generated
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
import type { Config, Client } from "@libsql/core/api";
|
||||
import type { ExpandedConfig } from "@libsql/core/config";
|
||||
export * from "@libsql/core/api";
|
||||
export declare function createClient(config: Config): Client;
|
||||
/** @private */
|
||||
export declare function _createClient(config: ExpandedConfig): Client;
|
||||
22
node_modules/@libsql/client/lib-esm/web.js
generated
vendored
Normal file
22
node_modules/@libsql/client/lib-esm/web.js
generated
vendored
Normal file
@@ -0,0 +1,22 @@
|
||||
import { LibsqlError } from "@libsql/core/api";
|
||||
import { expandConfig } from "@libsql/core/config";
|
||||
import { supportedUrlLink } from "@libsql/core/util";
|
||||
import { _createClient as _createWsClient } from "./ws.js";
|
||||
import { _createClient as _createHttpClient } from "./http.js";
|
||||
export * from "@libsql/core/api";
|
||||
export function createClient(config) {
|
||||
return _createClient(expandConfig(config, true));
|
||||
}
|
||||
/** @private */
|
||||
export function _createClient(config) {
|
||||
if (config.scheme === "ws" || config.scheme === "wss") {
|
||||
return _createWsClient(config);
|
||||
}
|
||||
else if (config.scheme === "http" || config.scheme === "https") {
|
||||
return _createHttpClient(config);
|
||||
}
|
||||
else {
|
||||
throw new LibsqlError('The client that uses Web standard APIs supports only "libsql:", "wss:", "ws:", "https:" and "http:" URLs, ' +
|
||||
`got ${JSON.stringify(config.scheme + ":")}. For more information, please read ${supportedUrlLink}`, "URL_SCHEME_NOT_SUPPORTED");
|
||||
}
|
||||
}
|
||||
50
node_modules/@libsql/client/lib-esm/ws.d.ts
generated
vendored
Normal file
50
node_modules/@libsql/client/lib-esm/ws.d.ts
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
/// <reference types="node" />
|
||||
import * as hrana from "@libsql/hrana-client";
|
||||
import type { Config, IntMode, Client, Transaction, ResultSet, InStatement, InArgs, Replicated } from "@libsql/core/api";
|
||||
import { TransactionMode } from "@libsql/core/api";
|
||||
import type { ExpandedConfig } from "@libsql/core/config";
|
||||
import { HranaTransaction } from "./hrana.js";
|
||||
import { SqlCache } from "./sql_cache.js";
|
||||
export * from "@libsql/core/api";
|
||||
export declare function createClient(config: Config): WsClient;
|
||||
/** @private */
|
||||
export declare function _createClient(config: ExpandedConfig): WsClient;
|
||||
interface ConnState {
|
||||
client: hrana.WsClient;
|
||||
useSqlCache: boolean | undefined;
|
||||
sqlCache: SqlCache;
|
||||
openTime: Date;
|
||||
streamStates: Set<StreamState>;
|
||||
}
|
||||
interface StreamState {
|
||||
conn: ConnState;
|
||||
stream: hrana.WsStream;
|
||||
}
|
||||
export declare class WsClient implements Client {
|
||||
#private;
|
||||
closed: boolean;
|
||||
protocol: "ws";
|
||||
/** @private */
|
||||
constructor(client: hrana.WsClient, url: URL, authToken: string | undefined, intMode: IntMode, concurrency: number | undefined);
|
||||
private limit;
|
||||
execute(stmtOrSql: InStatement | string, args?: InArgs): Promise<ResultSet>;
|
||||
batch(stmts: Array<InStatement | [string, InArgs?]>, mode?: TransactionMode): Promise<Array<ResultSet>>;
|
||||
migrate(stmts: Array<InStatement>): Promise<Array<ResultSet>>;
|
||||
transaction(mode?: TransactionMode): Promise<WsTransaction>;
|
||||
executeMultiple(sql: string): Promise<void>;
|
||||
sync(): Promise<Replicated>;
|
||||
reconnect(): Promise<void>;
|
||||
_closeStream(streamState: StreamState): void;
|
||||
close(): void;
|
||||
}
|
||||
export declare class WsTransaction extends HranaTransaction implements Transaction {
|
||||
#private;
|
||||
/** @private */
|
||||
constructor(client: WsClient, state: StreamState, mode: TransactionMode, version: hrana.ProtocolVersion);
|
||||
/** @private */
|
||||
_getStream(): hrana.Stream;
|
||||
/** @private */
|
||||
_getSqlCache(): SqlCache;
|
||||
close(): void;
|
||||
get closed(): boolean;
|
||||
}
|
||||
359
node_modules/@libsql/client/lib-esm/ws.js
generated
vendored
Normal file
359
node_modules/@libsql/client/lib-esm/ws.js
generated
vendored
Normal file
@@ -0,0 +1,359 @@
|
||||
import * as hrana from "@libsql/hrana-client";
|
||||
import { LibsqlError } from "@libsql/core/api";
|
||||
import { expandConfig } from "@libsql/core/config";
|
||||
import { HranaTransaction, executeHranaBatch, stmtToHrana, resultSetFromHrana, mapHranaError, } from "./hrana.js";
|
||||
import { SqlCache } from "./sql_cache.js";
|
||||
import { encodeBaseUrl } from "@libsql/core/uri";
|
||||
import { supportedUrlLink } from "@libsql/core/util";
|
||||
import promiseLimit from "promise-limit";
|
||||
export * from "@libsql/core/api";
|
||||
export function createClient(config) {
|
||||
return _createClient(expandConfig(config, false));
|
||||
}
|
||||
/** @private */
|
||||
export function _createClient(config) {
|
||||
if (config.scheme !== "wss" && config.scheme !== "ws") {
|
||||
throw new LibsqlError('The WebSocket client supports only "libsql:", "wss:" and "ws:" URLs, ' +
|
||||
`got ${JSON.stringify(config.scheme + ":")}. For more information, please read ${supportedUrlLink}`, "URL_SCHEME_NOT_SUPPORTED");
|
||||
}
|
||||
if (config.encryptionKey !== undefined) {
|
||||
throw new LibsqlError("Encryption key is not supported by the remote client.", "ENCRYPTION_KEY_NOT_SUPPORTED");
|
||||
}
|
||||
if (config.scheme === "ws" && config.tls) {
|
||||
throw new LibsqlError(`A "ws:" URL cannot opt into TLS by using ?tls=1`, "URL_INVALID");
|
||||
}
|
||||
else if (config.scheme === "wss" && !config.tls) {
|
||||
throw new LibsqlError(`A "wss:" URL cannot opt out of TLS by using ?tls=0`, "URL_INVALID");
|
||||
}
|
||||
const url = encodeBaseUrl(config.scheme, config.authority, config.path);
|
||||
let client;
|
||||
try {
|
||||
client = hrana.openWs(url, config.authToken);
|
||||
}
|
||||
catch (e) {
|
||||
if (e instanceof hrana.WebSocketUnsupportedError) {
|
||||
const suggestedScheme = config.scheme === "wss" ? "https" : "http";
|
||||
const suggestedUrl = encodeBaseUrl(suggestedScheme, config.authority, config.path);
|
||||
throw new LibsqlError("This environment does not support WebSockets, please switch to the HTTP client by using " +
|
||||
`a "${suggestedScheme}:" URL (${JSON.stringify(suggestedUrl)}). ` +
|
||||
`For more information, please read ${supportedUrlLink}`, "WEBSOCKETS_NOT_SUPPORTED");
|
||||
}
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
return new WsClient(client, url, config.authToken, config.intMode, config.concurrency);
|
||||
}
|
||||
const maxConnAgeMillis = 60 * 1000;
|
||||
const sqlCacheCapacity = 100;
|
||||
export class WsClient {
|
||||
#url;
|
||||
#authToken;
|
||||
#intMode;
|
||||
// State of the current connection. The `hrana.WsClient` inside may be closed at any moment due to an
|
||||
// asynchronous error.
|
||||
#connState;
|
||||
// If defined, this is a connection that will be used in the future, once it is ready.
|
||||
#futureConnState;
|
||||
closed;
|
||||
protocol;
|
||||
#isSchemaDatabase;
|
||||
#promiseLimitFunction;
|
||||
/** @private */
|
||||
constructor(client, url, authToken, intMode, concurrency) {
|
||||
this.#url = url;
|
||||
this.#authToken = authToken;
|
||||
this.#intMode = intMode;
|
||||
this.#connState = this.#openConn(client);
|
||||
this.#futureConnState = undefined;
|
||||
this.closed = false;
|
||||
this.protocol = "ws";
|
||||
this.#promiseLimitFunction = promiseLimit(concurrency);
|
||||
}
|
||||
async limit(fn) {
|
||||
return this.#promiseLimitFunction(fn);
|
||||
}
|
||||
async execute(stmtOrSql, args) {
|
||||
let stmt;
|
||||
if (typeof stmtOrSql === "string") {
|
||||
stmt = {
|
||||
sql: stmtOrSql,
|
||||
args: args || [],
|
||||
};
|
||||
}
|
||||
else {
|
||||
stmt = stmtOrSql;
|
||||
}
|
||||
return this.limit(async () => {
|
||||
const streamState = await this.#openStream();
|
||||
try {
|
||||
const hranaStmt = stmtToHrana(stmt);
|
||||
// Schedule all operations synchronously, so they will be pipelined and executed in a single
|
||||
// network roundtrip.
|
||||
streamState.conn.sqlCache.apply([hranaStmt]);
|
||||
const hranaRowsPromise = streamState.stream.query(hranaStmt);
|
||||
streamState.stream.closeGracefully();
|
||||
const hranaRowsResult = await hranaRowsPromise;
|
||||
return resultSetFromHrana(hranaRowsResult);
|
||||
}
|
||||
catch (e) {
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
finally {
|
||||
this._closeStream(streamState);
|
||||
}
|
||||
});
|
||||
}
|
||||
async batch(stmts, mode = "deferred") {
|
||||
return this.limit(async () => {
|
||||
const streamState = await this.#openStream();
|
||||
try {
|
||||
const normalizedStmts = stmts.map((stmt) => {
|
||||
if (Array.isArray(stmt)) {
|
||||
return {
|
||||
sql: stmt[0],
|
||||
args: stmt[1] || [],
|
||||
};
|
||||
}
|
||||
return stmt;
|
||||
});
|
||||
const hranaStmts = normalizedStmts.map(stmtToHrana);
|
||||
const version = await streamState.conn.client.getVersion();
|
||||
// Schedule all operations synchronously, so they will be pipelined and executed in a single
|
||||
// network roundtrip.
|
||||
streamState.conn.sqlCache.apply(hranaStmts);
|
||||
const batch = streamState.stream.batch(version >= 3);
|
||||
const resultsPromise = executeHranaBatch(mode, version, batch, hranaStmts);
|
||||
const results = await resultsPromise;
|
||||
return results;
|
||||
}
|
||||
catch (e) {
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
finally {
|
||||
this._closeStream(streamState);
|
||||
}
|
||||
});
|
||||
}
|
||||
async migrate(stmts) {
|
||||
return this.limit(async () => {
|
||||
const streamState = await this.#openStream();
|
||||
try {
|
||||
const hranaStmts = stmts.map(stmtToHrana);
|
||||
const version = await streamState.conn.client.getVersion();
|
||||
// Schedule all operations synchronously, so they will be pipelined and executed in a single
|
||||
// network roundtrip.
|
||||
const batch = streamState.stream.batch(version >= 3);
|
||||
const resultsPromise = executeHranaBatch("deferred", version, batch, hranaStmts, true);
|
||||
const results = await resultsPromise;
|
||||
return results;
|
||||
}
|
||||
catch (e) {
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
finally {
|
||||
this._closeStream(streamState);
|
||||
}
|
||||
});
|
||||
}
|
||||
async transaction(mode = "write") {
|
||||
return this.limit(async () => {
|
||||
const streamState = await this.#openStream();
|
||||
try {
|
||||
const version = await streamState.conn.client.getVersion();
|
||||
// the BEGIN statement will be batched with the first statement on the transaction to save a
|
||||
// network roundtrip
|
||||
return new WsTransaction(this, streamState, mode, version);
|
||||
}
|
||||
catch (e) {
|
||||
this._closeStream(streamState);
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
async executeMultiple(sql) {
|
||||
return this.limit(async () => {
|
||||
const streamState = await this.#openStream();
|
||||
try {
|
||||
// Schedule all operations synchronously, so they will be pipelined and executed in a single
|
||||
// network roundtrip.
|
||||
const promise = streamState.stream.sequence(sql);
|
||||
streamState.stream.closeGracefully();
|
||||
await promise;
|
||||
}
|
||||
catch (e) {
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
finally {
|
||||
this._closeStream(streamState);
|
||||
}
|
||||
});
|
||||
}
|
||||
sync() {
|
||||
throw new LibsqlError("sync not supported in ws mode", "SYNC_NOT_SUPPORTED");
|
||||
}
|
||||
async #openStream() {
|
||||
if (this.closed) {
|
||||
throw new LibsqlError("The client is closed", "CLIENT_CLOSED");
|
||||
}
|
||||
const now = new Date();
|
||||
const ageMillis = now.valueOf() - this.#connState.openTime.valueOf();
|
||||
if (ageMillis > maxConnAgeMillis &&
|
||||
this.#futureConnState === undefined) {
|
||||
// The existing connection is too old, let's open a new one.
|
||||
const futureConnState = this.#openConn();
|
||||
this.#futureConnState = futureConnState;
|
||||
// However, if we used `futureConnState` immediately, we would introduce additional latency,
|
||||
// because we would have to wait for the WebSocket handshake to complete, even though we may a
|
||||
// have perfectly good existing connection in `this.#connState`!
|
||||
//
|
||||
// So we wait until the `hrana.Client.getVersion()` operation completes (which happens when the
|
||||
// WebSocket hanshake completes), and only then we replace `this.#connState` with
|
||||
// `futureConnState`, which is stored in `this.#futureConnState` in the meantime.
|
||||
futureConnState.client.getVersion().then((_version) => {
|
||||
if (this.#connState !== futureConnState) {
|
||||
// We need to close `this.#connState` before we replace it. However, it is possible
|
||||
// that `this.#connState` has already been replaced: see the code below.
|
||||
if (this.#connState.streamStates.size === 0) {
|
||||
this.#connState.client.close();
|
||||
}
|
||||
else {
|
||||
// If there are existing streams on the connection, we must not close it, because
|
||||
// these streams would be broken. The last stream to be closed will also close the
|
||||
// connection in `_closeStream()`.
|
||||
}
|
||||
}
|
||||
this.#connState = futureConnState;
|
||||
this.#futureConnState = undefined;
|
||||
}, (_e) => {
|
||||
// If the new connection could not be established, let's just ignore the error and keep
|
||||
// using the existing connection.
|
||||
this.#futureConnState = undefined;
|
||||
});
|
||||
}
|
||||
if (this.#connState.client.closed) {
|
||||
// An error happened on this connection and it has been closed. Let's try to seamlessly reconnect.
|
||||
try {
|
||||
if (this.#futureConnState !== undefined) {
|
||||
// We are already in the process of opening a new connection, so let's just use it
|
||||
// immediately.
|
||||
this.#connState = this.#futureConnState;
|
||||
}
|
||||
else {
|
||||
this.#connState = this.#openConn();
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
}
|
||||
const connState = this.#connState;
|
||||
try {
|
||||
// Now we wait for the WebSocket handshake to complete (if it hasn't completed yet). Note that
|
||||
// this does not increase latency, because any messages that we would send on the WebSocket before
|
||||
// the handshake would be queued until the handshake is completed anyway.
|
||||
if (connState.useSqlCache === undefined) {
|
||||
connState.useSqlCache =
|
||||
(await connState.client.getVersion()) >= 2;
|
||||
if (connState.useSqlCache) {
|
||||
connState.sqlCache.capacity = sqlCacheCapacity;
|
||||
}
|
||||
}
|
||||
const stream = connState.client.openStream();
|
||||
stream.intMode = this.#intMode;
|
||||
const streamState = { conn: connState, stream };
|
||||
connState.streamStates.add(streamState);
|
||||
return streamState;
|
||||
}
|
||||
catch (e) {
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
}
|
||||
#openConn(client) {
|
||||
try {
|
||||
client ??= hrana.openWs(this.#url, this.#authToken);
|
||||
return {
|
||||
client,
|
||||
useSqlCache: undefined,
|
||||
sqlCache: new SqlCache(client, 0),
|
||||
openTime: new Date(),
|
||||
streamStates: new Set(),
|
||||
};
|
||||
}
|
||||
catch (e) {
|
||||
throw mapHranaError(e);
|
||||
}
|
||||
}
|
||||
async reconnect() {
|
||||
try {
|
||||
for (const st of Array.from(this.#connState.streamStates)) {
|
||||
try {
|
||||
st.stream.close();
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
this.#connState.client.close();
|
||||
}
|
||||
catch { }
|
||||
if (this.#futureConnState) {
|
||||
try {
|
||||
this.#futureConnState.client.close();
|
||||
}
|
||||
catch { }
|
||||
this.#futureConnState = undefined;
|
||||
}
|
||||
const next = this.#openConn();
|
||||
const version = await next.client.getVersion();
|
||||
next.useSqlCache = version >= 2;
|
||||
if (next.useSqlCache) {
|
||||
next.sqlCache.capacity = sqlCacheCapacity;
|
||||
}
|
||||
this.#connState = next;
|
||||
this.closed = false;
|
||||
}
|
||||
_closeStream(streamState) {
|
||||
streamState.stream.close();
|
||||
const connState = streamState.conn;
|
||||
connState.streamStates.delete(streamState);
|
||||
if (connState.streamStates.size === 0 &&
|
||||
connState !== this.#connState) {
|
||||
// We are not using this connection anymore and this is the last stream that was using it, so we
|
||||
// must close it now.
|
||||
connState.client.close();
|
||||
}
|
||||
}
|
||||
close() {
|
||||
this.#connState.client.close();
|
||||
this.closed = true;
|
||||
if (this.#futureConnState) {
|
||||
try {
|
||||
this.#futureConnState.client.close();
|
||||
}
|
||||
catch { }
|
||||
this.#futureConnState = undefined;
|
||||
}
|
||||
this.closed = true;
|
||||
}
|
||||
}
|
||||
export class WsTransaction extends HranaTransaction {
|
||||
#client;
|
||||
#streamState;
|
||||
/** @private */
|
||||
constructor(client, state, mode, version) {
|
||||
super(mode, version);
|
||||
this.#client = client;
|
||||
this.#streamState = state;
|
||||
}
|
||||
/** @private */
|
||||
_getStream() {
|
||||
return this.#streamState.stream;
|
||||
}
|
||||
/** @private */
|
||||
_getSqlCache() {
|
||||
return this.#streamState.conn.sqlCache;
|
||||
}
|
||||
close() {
|
||||
this.#client._closeStream(this.#streamState);
|
||||
}
|
||||
get closed() {
|
||||
return this.#streamState.stream.closed;
|
||||
}
|
||||
}
|
||||
123
node_modules/@libsql/client/package.json
generated
vendored
Normal file
123
node_modules/@libsql/client/package.json
generated
vendored
Normal file
@@ -0,0 +1,123 @@
|
||||
{
|
||||
"name": "@libsql/client",
|
||||
"version": "0.15.15",
|
||||
"keywords": [
|
||||
"libsql",
|
||||
"database",
|
||||
"sqlite",
|
||||
"serverless",
|
||||
"vercel",
|
||||
"netlify",
|
||||
"lambda"
|
||||
],
|
||||
"description": "libSQL driver for TypeScript and JavaScript",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/libsql/libsql-client-ts",
|
||||
"directory": "packages/libsql-client"
|
||||
},
|
||||
"authors": [
|
||||
"Jan Špaček <honza@chiselstrike.com>",
|
||||
"Pekka Enberg <penberg@chiselstrike.com>",
|
||||
"Jan Plhak <jp@chiselstrike.com>"
|
||||
],
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
"main": "lib-cjs/node.js",
|
||||
"types": "lib-esm/node.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"types": "./lib-esm/node.d.ts",
|
||||
"import": {
|
||||
"workerd": "./lib-esm/web.js",
|
||||
"deno": "./lib-esm/node.js",
|
||||
"edge-light": "./lib-esm/web.js",
|
||||
"netlify": "./lib-esm/web.js",
|
||||
"node": "./lib-esm/node.js",
|
||||
"browser": "./lib-esm/web.js",
|
||||
"default": "./lib-esm/node.js"
|
||||
},
|
||||
"require": "./lib-cjs/node.js"
|
||||
},
|
||||
"./node": {
|
||||
"types": "./lib-esm/node.d.ts",
|
||||
"import": "./lib-esm/node.js",
|
||||
"require": "./lib-cjs/node.js"
|
||||
},
|
||||
"./http": {
|
||||
"types": "./lib-esm/http.d.ts",
|
||||
"import": "./lib-esm/http.js",
|
||||
"require": "./lib-cjs/http.js"
|
||||
},
|
||||
"./ws": {
|
||||
"types": "./lib-esm/ws.d.ts",
|
||||
"import": "./lib-esm/ws.js",
|
||||
"require": "./lib-cjs/ws.js"
|
||||
},
|
||||
"./sqlite3": {
|
||||
"types": "./lib-esm/sqlite3.d.ts",
|
||||
"import": "./lib-esm/sqlite3.js",
|
||||
"require": "./lib-cjs/sqlite3.js"
|
||||
},
|
||||
"./web": {
|
||||
"types": "./lib-esm/web.d.ts",
|
||||
"import": "./lib-esm/web.js",
|
||||
"require": "./lib-cjs/web.js"
|
||||
}
|
||||
},
|
||||
"typesVersions": {
|
||||
"*": {
|
||||
".": [
|
||||
"./lib-esm/node.d.ts"
|
||||
],
|
||||
"http": [
|
||||
"./lib-esm/http.d.ts"
|
||||
],
|
||||
"hrana": [
|
||||
"./lib-esm/hrana.d.ts"
|
||||
],
|
||||
"sqlite3": [
|
||||
"./lib-esm/sqlite3.d.ts"
|
||||
],
|
||||
"web": [
|
||||
"./lib-esm/web.d.ts"
|
||||
]
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"lib-cjs/**",
|
||||
"lib-esm/**",
|
||||
"README.md"
|
||||
],
|
||||
"scripts": {
|
||||
"prepublishOnly": "npm run build",
|
||||
"prebuild": "rm -rf ./lib-cjs ./lib-esm",
|
||||
"build": "npm run build:cjs && npm run build:esm",
|
||||
"build:cjs": "tsc -p tsconfig.build-cjs.json",
|
||||
"build:esm": "tsc -p tsconfig.build-esm.json",
|
||||
"format:check": "prettier --check .",
|
||||
"postbuild": "cp package-cjs.json ./lib-cjs/package.json",
|
||||
"test": "jest --runInBand",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"typedoc": "rm -rf ./docs && typedoc",
|
||||
"lint-staged": "lint-staged"
|
||||
},
|
||||
"dependencies": {
|
||||
"@libsql/core": "^0.15.14",
|
||||
"@libsql/hrana-client": "^0.7.0",
|
||||
"js-base64": "^3.7.5",
|
||||
"libsql": "^0.5.22",
|
||||
"promise-limit": "^2.7.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.2.5",
|
||||
"@types/node": "^18.15.5",
|
||||
"jest": "^29.3.1",
|
||||
"lint-staged": "^15.2.2",
|
||||
"msw": "^2.3.0",
|
||||
"prettier": "3.2.5",
|
||||
"ts-jest": "^29.0.5",
|
||||
"typedoc": "^0.23.28",
|
||||
"typescript": "^4.9.4"
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user