@ohos-ports/libsql-client 0.18.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,341 @@
1
+ import * as hrana from "@libsql/hrana-client";
2
+ import { LibsqlError, LibsqlBatchError } from "@libsql/core/api";
3
+ import { transactionModeToBegin, ResultSetImpl } from "@libsql/core/util";
4
+ export class HranaTransaction {
5
+ #mode;
6
+ #version;
7
+ // Promise that is resolved when the BEGIN statement completes, or `undefined` if we haven't executed the
8
+ // BEGIN statement yet.
9
+ #started;
10
+ /** @private */
11
+ constructor(mode, version) {
12
+ this.#mode = mode;
13
+ this.#version = version;
14
+ this.#started = undefined;
15
+ }
16
+ execute(stmt) {
17
+ return this.batch([stmt]).then((results) => results[0]);
18
+ }
19
+ async batch(stmts) {
20
+ const stream = this._getStream();
21
+ if (stream.closed) {
22
+ throw new LibsqlError("Cannot execute statements because the transaction is closed", "TRANSACTION_CLOSED");
23
+ }
24
+ try {
25
+ const hranaStmts = stmts.map(stmtToHrana);
26
+ let rowsPromises;
27
+ if (this.#started === undefined) {
28
+ // The transaction hasn't started yet, so we need to send the BEGIN statement in a batch with
29
+ // `hranaStmts`.
30
+ this._getSqlCache().apply(hranaStmts);
31
+ const batch = stream.batch(this.#version >= 3);
32
+ const beginStep = batch.step();
33
+ const beginPromise = beginStep.run(transactionModeToBegin(this.#mode));
34
+ // Execute the `hranaStmts` only if the BEGIN succeeded, to make sure that we don't execute it
35
+ // outside of a transaction.
36
+ let lastStep = beginStep;
37
+ rowsPromises = hranaStmts.map((hranaStmt) => {
38
+ const stmtStep = batch
39
+ .step()
40
+ .condition(hrana.BatchCond.ok(lastStep));
41
+ if (this.#version >= 3) {
42
+ // If the Hrana version supports it, make sure that we are still in a transaction
43
+ stmtStep.condition(hrana.BatchCond.not(hrana.BatchCond.isAutocommit(batch)));
44
+ }
45
+ const rowsPromise = stmtStep.query(hranaStmt);
46
+ rowsPromise.catch(() => undefined); // silence Node warning
47
+ lastStep = stmtStep;
48
+ return rowsPromise;
49
+ });
50
+ // `this.#started` is resolved successfully only if the batch and the BEGIN statement inside
51
+ // of the batch are both successful.
52
+ this.#started = batch
53
+ .execute()
54
+ .then(() => beginPromise)
55
+ .then(() => undefined);
56
+ try {
57
+ await this.#started;
58
+ }
59
+ catch (e) {
60
+ // If the BEGIN failed, the transaction is unusable and we must close it. However, if the
61
+ // BEGIN suceeds and `hranaStmts` fail, the transaction is _not_ closed.
62
+ this.close();
63
+ throw e;
64
+ }
65
+ }
66
+ else {
67
+ if (this.#version < 3) {
68
+ // The transaction has started, so we must wait until the BEGIN statement completed to make
69
+ // sure that we don't execute `hranaStmts` outside of a transaction.
70
+ await this.#started;
71
+ }
72
+ else {
73
+ // The transaction has started, but we will use `hrana.BatchCond.isAutocommit()` to make
74
+ // sure that we don't execute `hranaStmts` outside of a transaction, so we don't have to
75
+ // wait for `this.#started`
76
+ }
77
+ this._getSqlCache().apply(hranaStmts);
78
+ const batch = stream.batch(this.#version >= 3);
79
+ let lastStep = undefined;
80
+ rowsPromises = hranaStmts.map((hranaStmt) => {
81
+ const stmtStep = batch.step();
82
+ if (lastStep !== undefined) {
83
+ stmtStep.condition(hrana.BatchCond.ok(lastStep));
84
+ }
85
+ if (this.#version >= 3) {
86
+ stmtStep.condition(hrana.BatchCond.not(hrana.BatchCond.isAutocommit(batch)));
87
+ }
88
+ const rowsPromise = stmtStep.query(hranaStmt);
89
+ rowsPromise.catch(() => undefined); // silence Node warning
90
+ lastStep = stmtStep;
91
+ return rowsPromise;
92
+ });
93
+ await batch.execute();
94
+ }
95
+ const resultSets = [];
96
+ for (let i = 0; i < rowsPromises.length; i++) {
97
+ try {
98
+ const rows = await rowsPromises[i];
99
+ if (rows === undefined) {
100
+ throw new LibsqlBatchError("Statement in a transaction was not executed, " +
101
+ "probably because the transaction has been rolled back", i, "TRANSACTION_CLOSED");
102
+ }
103
+ resultSets.push(resultSetFromHrana(rows));
104
+ }
105
+ catch (e) {
106
+ if (e instanceof LibsqlBatchError) {
107
+ throw e;
108
+ }
109
+ // Map hrana errors to LibsqlError first, then wrap in LibsqlBatchError
110
+ const mappedError = mapHranaError(e);
111
+ if (mappedError instanceof LibsqlError) {
112
+ throw new LibsqlBatchError(mappedError.message, i, mappedError.code, mappedError.extendedCode, mappedError.rawCode, mappedError.cause instanceof Error
113
+ ? mappedError.cause
114
+ : undefined);
115
+ }
116
+ throw mappedError;
117
+ }
118
+ }
119
+ return resultSets;
120
+ }
121
+ catch (e) {
122
+ throw mapHranaError(e);
123
+ }
124
+ }
125
+ async executeMultiple(sql) {
126
+ const stream = this._getStream();
127
+ if (stream.closed) {
128
+ throw new LibsqlError("Cannot execute statements because the transaction is closed", "TRANSACTION_CLOSED");
129
+ }
130
+ try {
131
+ if (this.#started === undefined) {
132
+ // If the transaction hasn't started yet, start it now
133
+ this.#started = stream
134
+ .run(transactionModeToBegin(this.#mode))
135
+ .then(() => undefined);
136
+ try {
137
+ await this.#started;
138
+ }
139
+ catch (e) {
140
+ this.close();
141
+ throw e;
142
+ }
143
+ }
144
+ else {
145
+ // Wait until the transaction has started
146
+ await this.#started;
147
+ }
148
+ await stream.sequence(sql);
149
+ }
150
+ catch (e) {
151
+ throw mapHranaError(e);
152
+ }
153
+ }
154
+ async rollback() {
155
+ try {
156
+ const stream = this._getStream();
157
+ if (stream.closed) {
158
+ return;
159
+ }
160
+ if (this.#started !== undefined) {
161
+ // We don't have to wait for the BEGIN statement to complete. If the BEGIN fails, we will
162
+ // execute a ROLLBACK outside of an active transaction, which should be harmless.
163
+ }
164
+ else {
165
+ // We did nothing in the transaction, so there is nothing to rollback.
166
+ return;
167
+ }
168
+ // Pipeline the ROLLBACK statement and the stream close.
169
+ const promise = stream.run("ROLLBACK").catch((e) => {
170
+ throw mapHranaError(e);
171
+ });
172
+ stream.closeGracefully();
173
+ await promise;
174
+ }
175
+ catch (e) {
176
+ throw mapHranaError(e);
177
+ }
178
+ finally {
179
+ // `this.close()` may close the `hrana.Client`, which aborts all pending stream requests, so we
180
+ // must call it _after_ we receive the ROLLBACK response.
181
+ // Also note that the current stream should already be closed, but we need to call `this.close()`
182
+ // anyway, because it may need to do more cleanup.
183
+ this.close();
184
+ }
185
+ }
186
+ async commit() {
187
+ // (this method is analogous to `rollback()`)
188
+ try {
189
+ const stream = this._getStream();
190
+ if (stream.closed) {
191
+ throw new LibsqlError("Cannot commit the transaction because it is already closed", "TRANSACTION_CLOSED");
192
+ }
193
+ if (this.#started !== undefined) {
194
+ // Make sure to execute the COMMIT only if the BEGIN was successful.
195
+ await this.#started;
196
+ }
197
+ else {
198
+ return;
199
+ }
200
+ const promise = stream.run("COMMIT").catch((e) => {
201
+ throw mapHranaError(e);
202
+ });
203
+ stream.closeGracefully();
204
+ await promise;
205
+ }
206
+ catch (e) {
207
+ throw mapHranaError(e);
208
+ }
209
+ finally {
210
+ this.close();
211
+ }
212
+ }
213
+ }
214
+ export async function executeHranaBatch(mode, version, batch, hranaStmts, disableForeignKeys = false) {
215
+ if (disableForeignKeys) {
216
+ batch.step().run("PRAGMA foreign_keys=off");
217
+ }
218
+ const beginStep = batch.step();
219
+ const beginPromise = beginStep.run(transactionModeToBegin(mode));
220
+ let lastStep = beginStep;
221
+ const stmtPromises = hranaStmts.map((hranaStmt) => {
222
+ const stmtStep = batch.step().condition(hrana.BatchCond.ok(lastStep));
223
+ if (version >= 3) {
224
+ stmtStep.condition(hrana.BatchCond.not(hrana.BatchCond.isAutocommit(batch)));
225
+ }
226
+ const stmtPromise = stmtStep.query(hranaStmt);
227
+ lastStep = stmtStep;
228
+ return stmtPromise;
229
+ });
230
+ const commitStep = batch.step().condition(hrana.BatchCond.ok(lastStep));
231
+ if (version >= 3) {
232
+ commitStep.condition(hrana.BatchCond.not(hrana.BatchCond.isAutocommit(batch)));
233
+ }
234
+ const commitPromise = commitStep.run("COMMIT");
235
+ const rollbackStep = batch
236
+ .step()
237
+ .condition(hrana.BatchCond.not(hrana.BatchCond.ok(commitStep)));
238
+ rollbackStep.run("ROLLBACK").catch((_) => undefined);
239
+ if (disableForeignKeys) {
240
+ batch.step().run("PRAGMA foreign_keys=on");
241
+ }
242
+ await batch.execute();
243
+ const resultSets = [];
244
+ await beginPromise;
245
+ for (let i = 0; i < stmtPromises.length; i++) {
246
+ try {
247
+ const hranaRows = await stmtPromises[i];
248
+ if (hranaRows === undefined) {
249
+ throw new LibsqlBatchError("Statement in a batch was not executed, probably because the transaction has been rolled back", i, "TRANSACTION_CLOSED");
250
+ }
251
+ resultSets.push(resultSetFromHrana(hranaRows));
252
+ }
253
+ catch (e) {
254
+ if (e instanceof LibsqlBatchError) {
255
+ throw e;
256
+ }
257
+ // Map hrana errors to LibsqlError first, then wrap in LibsqlBatchError
258
+ const mappedError = mapHranaError(e);
259
+ if (mappedError instanceof LibsqlError) {
260
+ throw new LibsqlBatchError(mappedError.message, i, mappedError.code, mappedError.extendedCode, mappedError.rawCode, mappedError.cause instanceof Error
261
+ ? mappedError.cause
262
+ : undefined);
263
+ }
264
+ throw mappedError;
265
+ }
266
+ }
267
+ await commitPromise;
268
+ return resultSets;
269
+ }
270
+ export function stmtToHrana(stmt) {
271
+ let sql;
272
+ let args;
273
+ if (Array.isArray(stmt)) {
274
+ [sql, args] = stmt;
275
+ }
276
+ else if (typeof stmt === "string") {
277
+ sql = stmt;
278
+ }
279
+ else {
280
+ sql = stmt.sql;
281
+ args = stmt.args;
282
+ }
283
+ const hranaStmt = new hrana.Stmt(sql);
284
+ if (args) {
285
+ if (Array.isArray(args)) {
286
+ hranaStmt.bindIndexes(args);
287
+ }
288
+ else {
289
+ for (const [key, value] of Object.entries(args)) {
290
+ hranaStmt.bindName(key, value);
291
+ }
292
+ }
293
+ }
294
+ return hranaStmt;
295
+ }
296
+ export function resultSetFromHrana(hranaRows) {
297
+ const columns = hranaRows.columnNames.map((c) => c ?? "");
298
+ const columnTypes = hranaRows.columnDecltypes.map((c) => c ?? "");
299
+ const rows = hranaRows.rows;
300
+ const rowsAffected = hranaRows.affectedRowCount;
301
+ const lastInsertRowid = hranaRows.lastInsertRowid !== undefined
302
+ ? hranaRows.lastInsertRowid
303
+ : undefined;
304
+ return new ResultSetImpl(columns, columnTypes, rows, rowsAffected, lastInsertRowid);
305
+ }
306
+ export function mapHranaError(e) {
307
+ if (e instanceof hrana.ClientError) {
308
+ const code = mapHranaErrorCode(e);
309
+ // TODO: Parse extendedCode once the SQL over HTTP protocol supports it
310
+ return new LibsqlError(e.message, code, undefined, undefined, e);
311
+ }
312
+ return e;
313
+ }
314
+ function mapHranaErrorCode(e) {
315
+ if (e instanceof hrana.ResponseError && e.code !== undefined) {
316
+ return e.code;
317
+ }
318
+ else if (e instanceof hrana.ProtoError) {
319
+ return "HRANA_PROTO_ERROR";
320
+ }
321
+ else if (e instanceof hrana.ClosedError) {
322
+ return e.cause instanceof hrana.ClientError
323
+ ? mapHranaErrorCode(e.cause)
324
+ : "HRANA_CLOSED_ERROR";
325
+ }
326
+ else if (e instanceof hrana.WebSocketError) {
327
+ return "HRANA_WEBSOCKET_ERROR";
328
+ }
329
+ else if (e instanceof hrana.HttpServerError) {
330
+ return "SERVER_ERROR";
331
+ }
332
+ else if (e instanceof hrana.ProtocolVersionError) {
333
+ return "PROTOCOL_VERSION_ERROR";
334
+ }
335
+ else if (e instanceof hrana.InternalError) {
336
+ return "INTERNAL_ERROR";
337
+ }
338
+ else {
339
+ return "UNKNOWN";
340
+ }
341
+ }
@@ -0,0 +1,39 @@
1
+ /// <reference types="node" />
2
+ import * as hrana from "@libsql/hrana-client";
3
+ import type { Config, Client } from "@libsql/core/api";
4
+ import type { InStatement, ResultSet, Transaction, IntMode, InArgs, Replicated } from "@libsql/core/api";
5
+ import { TransactionMode } from "@libsql/core/api";
6
+ import type { ExpandedConfig } from "@libsql/core/config";
7
+ import { HranaTransaction } from "./hrana.js";
8
+ import { SqlCache } from "./sql_cache.js";
9
+ export * from "@libsql/core/api";
10
+ export declare function createClient(config: Config): Client;
11
+ /** @private */
12
+ export declare function _createClient(config: ExpandedConfig): Client;
13
+ export declare class HttpClient implements Client {
14
+ #private;
15
+ protocol: "http";
16
+ /** @private */
17
+ constructor(url: URL, authToken: string | undefined, intMode: IntMode, customFetch: Function | undefined, concurrency: number, remoteEncryptionKey: string | undefined);
18
+ private limit;
19
+ execute(stmtOrSql: InStatement | string, args?: InArgs): Promise<ResultSet>;
20
+ batch(stmts: Array<InStatement | [string, InArgs?]>, mode?: TransactionMode): Promise<Array<ResultSet>>;
21
+ migrate(stmts: Array<InStatement>): Promise<Array<ResultSet>>;
22
+ transaction(mode?: TransactionMode): Promise<HttpTransaction>;
23
+ executeMultiple(sql: string): Promise<void>;
24
+ sync(): Promise<Replicated>;
25
+ close(): void;
26
+ reconnect(): Promise<void>;
27
+ get closed(): boolean;
28
+ }
29
+ export declare class HttpTransaction extends HranaTransaction implements Transaction {
30
+ #private;
31
+ /** @private */
32
+ constructor(stream: hrana.HttpStream, mode: TransactionMode, version: hrana.ProtocolVersion);
33
+ /** @private */
34
+ _getStream(): hrana.Stream;
35
+ /** @private */
36
+ _getSqlCache(): SqlCache;
37
+ close(): void;
38
+ get closed(): boolean;
39
+ }
@@ -0,0 +1,232 @@
1
+ import * as hrana from "@libsql/hrana-client";
2
+ import { LibsqlError } from "@libsql/core/api";
3
+ import { expandConfig } from "@libsql/core/config";
4
+ import { HranaTransaction, executeHranaBatch, stmtToHrana, resultSetFromHrana, mapHranaError, } from "./hrana.js";
5
+ import { SqlCache } from "./sql_cache.js";
6
+ import { encodeBaseUrl } from "@libsql/core/uri";
7
+ import { supportedUrlLink } from "@libsql/core/util";
8
+ import promiseLimit from "promise-limit";
9
+ export * from "@libsql/core/api";
10
+ export function createClient(config) {
11
+ return _createClient(expandConfig(config, true));
12
+ }
13
+ /** @private */
14
+ export function _createClient(config) {
15
+ if (config.scheme !== "https" && config.scheme !== "http") {
16
+ throw new LibsqlError('The HTTP client supports only "libsql:", "https:" and "http:" URLs, ' +
17
+ `got ${JSON.stringify(config.scheme + ":")}. For more information, please read ${supportedUrlLink}`, "URL_SCHEME_NOT_SUPPORTED");
18
+ }
19
+ if (config.encryptionKey !== undefined) {
20
+ throw new LibsqlError("Encryption key is not supported by the remote client.", "ENCRYPTION_KEY_NOT_SUPPORTED");
21
+ }
22
+ if (config.scheme === "http" && config.tls) {
23
+ throw new LibsqlError(`A "http:" URL cannot opt into TLS by using ?tls=1`, "URL_INVALID");
24
+ }
25
+ else if (config.scheme === "https" && !config.tls) {
26
+ throw new LibsqlError(`A "https:" URL cannot opt out of TLS by using ?tls=0`, "URL_INVALID");
27
+ }
28
+ const url = encodeBaseUrl(config.scheme, config.authority, config.path);
29
+ return new HttpClient(url, config.authToken, config.intMode, config.fetch, config.concurrency, config.remoteEncryptionKey);
30
+ }
31
+ const sqlCacheCapacity = 30;
32
+ export class HttpClient {
33
+ #client;
34
+ protocol;
35
+ #url;
36
+ #intMode;
37
+ #customFetch;
38
+ #concurrency;
39
+ #authToken;
40
+ #remoteEncryptionKey;
41
+ #promiseLimitFunction;
42
+ /** @private */
43
+ constructor(url, authToken, intMode, customFetch, concurrency, remoteEncryptionKey) {
44
+ this.#url = url;
45
+ this.#authToken = authToken;
46
+ this.#intMode = intMode;
47
+ this.#customFetch = customFetch;
48
+ this.#concurrency = concurrency;
49
+ this.#remoteEncryptionKey = remoteEncryptionKey;
50
+ this.#client = hrana.openHttp(this.#url, this.#authToken, this.#customFetch, remoteEncryptionKey);
51
+ this.#client.intMode = this.#intMode;
52
+ this.protocol = "http";
53
+ this.#promiseLimitFunction = promiseLimit(this.#concurrency);
54
+ }
55
+ async limit(fn) {
56
+ return this.#promiseLimitFunction(fn);
57
+ }
58
+ async execute(stmtOrSql, args) {
59
+ let stmt;
60
+ if (typeof stmtOrSql === "string") {
61
+ stmt = {
62
+ sql: stmtOrSql,
63
+ args: args || [],
64
+ };
65
+ }
66
+ else {
67
+ stmt = stmtOrSql;
68
+ }
69
+ return this.limit(async () => {
70
+ try {
71
+ const hranaStmt = stmtToHrana(stmt);
72
+ // Pipeline all operations, so `hrana.HttpClient` can open the stream, execute the statement and
73
+ // close the stream in a single HTTP request.
74
+ let rowsPromise;
75
+ const stream = this.#client.openStream();
76
+ try {
77
+ rowsPromise = stream.query(hranaStmt);
78
+ }
79
+ finally {
80
+ stream.closeGracefully();
81
+ }
82
+ const rowsResult = await rowsPromise;
83
+ return resultSetFromHrana(rowsResult);
84
+ }
85
+ catch (e) {
86
+ throw mapHranaError(e);
87
+ }
88
+ });
89
+ }
90
+ async batch(stmts, mode = "deferred") {
91
+ return this.limit(async () => {
92
+ try {
93
+ const normalizedStmts = stmts.map((stmt) => {
94
+ if (Array.isArray(stmt)) {
95
+ return {
96
+ sql: stmt[0],
97
+ args: stmt[1] || [],
98
+ };
99
+ }
100
+ return stmt;
101
+ });
102
+ const hranaStmts = normalizedStmts.map(stmtToHrana);
103
+ const version = await this.#client.getVersion();
104
+ // Pipeline all operations, so `hrana.HttpClient` can open the stream, execute the batch and
105
+ // close the stream in a single HTTP request.
106
+ let resultsPromise;
107
+ const stream = this.#client.openStream();
108
+ try {
109
+ // It makes sense to use a SQL cache even for a single batch, because it may contain the same
110
+ // statement repeated multiple times.
111
+ const sqlCache = new SqlCache(stream, sqlCacheCapacity);
112
+ sqlCache.apply(hranaStmts);
113
+ // TODO: we do not use a cursor here, because it would cause three roundtrips:
114
+ // 1. pipeline request to store SQL texts
115
+ // 2. cursor request
116
+ // 3. pipeline request to close the stream
117
+ const batch = stream.batch(false);
118
+ resultsPromise = executeHranaBatch(mode, version, batch, hranaStmts);
119
+ }
120
+ finally {
121
+ stream.closeGracefully();
122
+ }
123
+ const results = await resultsPromise;
124
+ return results;
125
+ }
126
+ catch (e) {
127
+ throw mapHranaError(e);
128
+ }
129
+ });
130
+ }
131
+ async migrate(stmts) {
132
+ return this.limit(async () => {
133
+ try {
134
+ const hranaStmts = stmts.map(stmtToHrana);
135
+ const version = await this.#client.getVersion();
136
+ // Pipeline all operations, so `hrana.HttpClient` can open the stream, execute the batch and
137
+ // close the stream in a single HTTP request.
138
+ let resultsPromise;
139
+ const stream = this.#client.openStream();
140
+ try {
141
+ const batch = stream.batch(false);
142
+ resultsPromise = executeHranaBatch("deferred", version, batch, hranaStmts, true);
143
+ }
144
+ finally {
145
+ stream.closeGracefully();
146
+ }
147
+ const results = await resultsPromise;
148
+ return results;
149
+ }
150
+ catch (e) {
151
+ throw mapHranaError(e);
152
+ }
153
+ });
154
+ }
155
+ async transaction(mode = "write") {
156
+ return this.limit(async () => {
157
+ try {
158
+ const version = await this.#client.getVersion();
159
+ return new HttpTransaction(this.#client.openStream(), mode, version);
160
+ }
161
+ catch (e) {
162
+ throw mapHranaError(e);
163
+ }
164
+ });
165
+ }
166
+ async executeMultiple(sql) {
167
+ return this.limit(async () => {
168
+ try {
169
+ // Pipeline all operations, so `hrana.HttpClient` can open the stream, execute the sequence and
170
+ // close the stream in a single HTTP request.
171
+ let promise;
172
+ const stream = this.#client.openStream();
173
+ try {
174
+ promise = stream.sequence(sql);
175
+ }
176
+ finally {
177
+ stream.closeGracefully();
178
+ }
179
+ await promise;
180
+ }
181
+ catch (e) {
182
+ throw mapHranaError(e);
183
+ }
184
+ });
185
+ }
186
+ sync() {
187
+ throw new LibsqlError("sync not supported in http mode", "SYNC_NOT_SUPPORTED");
188
+ }
189
+ close() {
190
+ this.#client.close();
191
+ }
192
+ async reconnect() {
193
+ try {
194
+ if (!this.closed) {
195
+ // Abort in-flight ops and free resources
196
+ this.#client.close();
197
+ }
198
+ }
199
+ finally {
200
+ // Recreate the underlying hrana client
201
+ this.#client = hrana.openHttp(this.#url, this.#authToken, this.#customFetch, this.#remoteEncryptionKey);
202
+ this.#client.intMode = this.#intMode;
203
+ }
204
+ }
205
+ get closed() {
206
+ return this.#client.closed;
207
+ }
208
+ }
209
+ export class HttpTransaction extends HranaTransaction {
210
+ #stream;
211
+ #sqlCache;
212
+ /** @private */
213
+ constructor(stream, mode, version) {
214
+ super(mode, version);
215
+ this.#stream = stream;
216
+ this.#sqlCache = new SqlCache(stream, sqlCacheCapacity);
217
+ }
218
+ /** @private */
219
+ _getStream() {
220
+ return this.#stream;
221
+ }
222
+ /** @private */
223
+ _getSqlCache() {
224
+ return this.#sqlCache;
225
+ }
226
+ close() {
227
+ this.#stream.close();
228
+ }
229
+ get closed() {
230
+ return this.#stream.closed;
231
+ }
232
+ }
@@ -0,0 +1,7 @@
1
+ import type { Config, Client } from "@libsql/core/api";
2
+ export * from "@libsql/core/api";
3
+ /** Creates a {@link Client} object.
4
+ *
5
+ * You must pass at least an `url` in the {@link Config} object.
6
+ */
7
+ export declare function createClient(config: Config): Client;
@@ -0,0 +1,23 @@
1
+ import { expandConfig } from "@libsql/core/config";
2
+ import { _createClient as _createSqlite3Client } from "./sqlite3.js";
3
+ import { _createClient as _createWsClient } from "./ws.js";
4
+ import { _createClient as _createHttpClient } from "./http.js";
5
+ export * from "@libsql/core/api";
6
+ /** Creates a {@link Client} object.
7
+ *
8
+ * You must pass at least an `url` in the {@link Config} object.
9
+ */
10
+ export function createClient(config) {
11
+ return _createClient(expandConfig(config, true));
12
+ }
13
+ function _createClient(config) {
14
+ if (config.scheme === "wss" || config.scheme === "ws") {
15
+ return _createWsClient(config);
16
+ }
17
+ else if (config.scheme === "https" || config.scheme === "http") {
18
+ return _createHttpClient(config);
19
+ }
20
+ else {
21
+ return _createSqlite3Client(config);
22
+ }
23
+ }
@@ -0,0 +1,7 @@
1
+ import type * as hrana from "@libsql/hrana-client";
2
+ export declare class SqlCache {
3
+ #private;
4
+ capacity: number;
5
+ constructor(owner: hrana.SqlOwner, capacity: number);
6
+ apply(hranaStmts: Array<hrana.Stmt>): void;
7
+ }